aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Beltran del Rio <ruben@unlimited.pizza>2021-04-04 00:45:50 +0200
committerRuben Beltran del Rio <ruben@unlimited.pizza>2021-04-04 00:45:50 +0200
commit07d8db2bb758686466d4643f575b4b5280cc4791 (patch)
tree32dcdc9595a7679cf4b0a05490a9298addf3b9fd
Add project
-rw-r--r--.gitignore1
-rwxr-xr-xbin/corona-regeln28
-rw-r--r--config/index.js7
-rw-r--r--lib/corona-regeln.js17
-rw-r--r--lib/rule_generator.js49
-rw-r--r--package-lock.json864
-rw-r--r--package.json20
-rw-r--r--rules/business.js74
-rw-r--r--rules/curfew.js69
-rw-r--r--rules/group.js51
-rw-r--r--templates/index.eta84
11 files changed, 1264 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules
diff --git a/bin/corona-regeln b/bin/corona-regeln
new file mode 100755
index 0000000..2a0fbfb
--- /dev/null
+++ b/bin/corona-regeln
@@ -0,0 +1,28 @@
+#!/usr/bin/env node
+
+const Fastify = require('fastify')({ logger: true })
+const PointOfView = require('point-of-view');
+const Eta = require('eta');
+const { join } = require('path');
+
+const CoronaRegeln = require('../lib/corona-regeln.js');
+const Config = require('../config');
+
+Fastify.register(PointOfView, {
+ engine: {
+ eta: Eta
+ },
+ root: join(__dirname, '../templates'),
+});
+
+Fastify.get('/', async (request, reply) => {
+
+ return reply.view('/index.eta', { rules: await CoronaRegeln.run(Config) });
+});
+
+Fastify.listen(Config.port)
+ .catch((error) => {
+
+ console.error(error.stack || error.message || error);
+ process.exit(1);
+ })
diff --git a/config/index.js b/config/index.js
new file mode 100644
index 0000000..8199cbc
--- /dev/null
+++ b/config/index.js
@@ -0,0 +1,7 @@
+const Getenv = require('getenv');
+
+module.exports = {
+
+ port: Getenv.int('CORONA_REGELN_PORT', 4949),
+ ruleCount: Getenv.int('CORONA_REGELN_RULE_COUNT', 4)
+};
diff --git a/lib/corona-regeln.js b/lib/corona-regeln.js
new file mode 100644
index 0000000..5036e47
--- /dev/null
+++ b/lib/corona-regeln.js
@@ -0,0 +1,17 @@
+'use strict';
+
+const RuleGenerator = require('./rule_generator');
+
+module.exports = {
+ async run({
+ ruleCount
+ }) {
+
+ const rules = [];
+ for (let i = 0; i < ruleCount; ++i) {
+ rules.push(await RuleGenerator.generate());
+ }
+
+ return rules.sort(() => Math.random() - 0.5);
+ }
+}
diff --git a/lib/rule_generator.js b/lib/rule_generator.js
new file mode 100644
index 0000000..5db5240
--- /dev/null
+++ b/lib/rule_generator.js
@@ -0,0 +1,49 @@
+const { readdir } = require('fs/promises');
+const { join, resolve } = require('path');
+
+const internals = {
+
+ dates: [
+ 'today',
+ 'tomorrow',
+ 'next friday',
+ 'next wednesday',
+ 'last thursday',
+ 'last tuesday',
+ 'the next day divisible by 7',
+ 'this afternoon',
+ 'next fiscal quarter',
+ ],
+
+ rules: null,
+ currentIndex: 0,
+
+ kRulesDirectory: resolve(process.cwd(), 'rules'),
+
+ async readRules() {
+
+ const ruleFiles = await readdir(internals.kRulesDirectory);
+ const rules = ruleFiles
+ .filter((file) => file.match(/.js$/))
+ .map((file) => require(join(internals.kRulesDirectory, file)));
+
+ internals.rules = rules.sort(() => Math.random() - 0.5)
+ }
+}
+
+module.exports = {
+ async generate() {
+
+ if (!internals.rules) {
+ await internals.readRules();
+ }
+
+ const rule = internals.rules[internals.currentIndex];
+ const time = internals.dates[Math.floor(Math.random() * internals.dates.length)];
+ internals.currentIndex = (internals.currentIndex + 1) % internals.rules.length
+ return {
+ rule: rule(),
+ time
+ }
+ }
+}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..ea0e8b4
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,864 @@
+{
+ "name": "corona-regeln",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "version": "1.0.0",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "eta": "^1.12.1",
+ "fastify": "^3.14.1",
+ "getenv": "^1.0.0",
+ "point-of-view": "^4.14.0"
+ }
+ },
+ "node_modules/@fastify/forwarded": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@fastify/forwarded/-/forwarded-1.0.0.tgz",
+ "integrity": "sha512-VoO+6WD0aRz8bwgJZ8pkkxjq7o/782cQ1j945HWg0obZMgIadYW3Pew0+an+k1QL7IPZHM3db5WF6OP6x4ymMA==",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@fastify/proxy-addr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@fastify/proxy-addr/-/proxy-addr-3.0.0.tgz",
+ "integrity": "sha512-ty7wnUd/GeSqKTC2Jozsl5xGbnxUnEFC0On2/zPv/8ixywipQmVZwuWvNGnBoitJ2wixwVqofwXNua8j6Y62lQ==",
+ "dependencies": {
+ "@fastify/forwarded": "^1.0.0",
+ "ipaddr.js": "^2.0.0"
+ }
+ },
+ "node_modules/abstract-logging": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
+ "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/archy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
+ "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA="
+ },
+ "node_modules/atomic-sleep": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
+ "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/avvio": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/avvio/-/avvio-7.2.1.tgz",
+ "integrity": "sha512-b+gox68dqD6c3S3t+bZBKN6rYbVWdwpN12sHQLFTiacDT2rcq7fm07Ww+IKt/AvAkyCIe1f5ArP1bC/vAlx97A==",
+ "dependencies": {
+ "archy": "^1.0.0",
+ "debug": "^4.0.0",
+ "fastq": "^1.6.1",
+ "queue-microtask": "^1.1.2"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
+ "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deepmerge": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
+ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/eta": {
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/eta/-/eta-1.12.1.tgz",
+ "integrity": "sha512-H8npoci2J/7XiPnVcCVulBSPsTNGvGaINyMjQDU8AFqp9LGsEYS88g2CiU+d01Sg44WtX7o4nb8wUJ9vnI+tiA==",
+ "engines": {
+ "node": ">=6.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/eta-dev/eta?sponsor=1"
+ }
+ },
+ "node_modules/fast-decode-uri-component": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
+ "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
+ },
+ "node_modules/fast-json-stringify": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.5.3.tgz",
+ "integrity": "sha512-wOE0YeqnhwOPqaZNvRxsgnq8Puc2vAQIlxSlcpRUInm0yf4+H/YqQ8ijBmzkUg384p0JBzjR9XBNkU5jLWSCwQ==",
+ "dependencies": {
+ "ajv": "^6.11.0",
+ "deepmerge": "^4.2.2",
+ "rfdc": "^1.2.0",
+ "string-similarity": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/fast-redact": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.0.0.tgz",
+ "integrity": "sha512-a/S/Hp6aoIjx7EmugtzLqXmcNsyFszqbt6qQ99BdG61QjBZF6shNis0BYR6TsZOQ1twYc0FN2Xdhwwbv6+KD0w==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/fast-safe-stringify": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz",
+ "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA=="
+ },
+ "node_modules/fastify": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/fastify/-/fastify-3.14.1.tgz",
+ "integrity": "sha512-9hoK1vvopsUJnUJpge90t8PZIqNQhGM54yDrd2veCZLkxh8eipnaHrXe2+f7tIt6UScUZ92JZQavxFGB4HX7xA==",
+ "dependencies": {
+ "@fastify/proxy-addr": "^3.0.0",
+ "abstract-logging": "^2.0.0",
+ "ajv": "^6.12.2",
+ "avvio": "^7.1.2",
+ "fast-json-stringify": "^2.5.2",
+ "fastify-error": "^0.3.0",
+ "fastify-warning": "^0.2.0",
+ "find-my-way": "^4.0.0",
+ "flatstr": "^1.0.12",
+ "light-my-request": "^4.2.0",
+ "pino": "^6.2.1",
+ "readable-stream": "^3.4.0",
+ "rfdc": "^1.1.4",
+ "secure-json-parse": "^2.0.0",
+ "semver": "^7.3.2",
+ "tiny-lru": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=10.16.0"
+ }
+ },
+ "node_modules/fastify-error": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/fastify-error/-/fastify-error-0.3.0.tgz",
+ "integrity": "sha512-Jm2LMTB5rsJqlS1+cmgqqM9tTs0UrlgYR7TvDT3ZgXsUI5ib1NjQlqZHf+tDK5tVPdFGwyq02wAoJtyYIRSiFA=="
+ },
+ "node_modules/fastify-plugin": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz",
+ "integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w=="
+ },
+ "node_modules/fastify-warning": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/fastify-warning/-/fastify-warning-0.2.0.tgz",
+ "integrity": "sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw=="
+ },
+ "node_modules/fastq": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
+ "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/find-my-way": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-4.1.0.tgz",
+ "integrity": "sha512-UBD94MdO6cBi6E97XA0fBA9nwqw+xG5x1TYIPHats33gEi/kNqy7BWHAWx8QHCQQRSU5Txc0JiD8nzba39gvMQ==",
+ "dependencies": {
+ "fast-decode-uri-component": "^1.0.1",
+ "fast-deep-equal": "^3.1.3",
+ "safe-regex2": "^2.0.0",
+ "semver-store": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/flatstr": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz",
+ "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw=="
+ },
+ "node_modules/getenv": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/getenv/-/getenv-1.0.0.tgz",
+ "integrity": "sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/hashlru": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/hashlru/-/hashlru-2.3.0.tgz",
+ "integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A=="
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/ipaddr.js": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.0.tgz",
+ "integrity": "sha512-S54H9mIj0rbxRIyrDMEuuER86LdlgUg9FSeZ8duQb6CUG2iRrA36MYVQBSprTF/ZeAwvyQ5mDGuNvIPM0BIl3w==",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "node_modules/light-my-request": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-4.4.1.tgz",
+ "integrity": "sha512-FDNRF2mYjthIRWE7O8d/X7AzDx4otQHl4/QXbu3Q/FRwBFcgb+ZoDaUd5HwN53uQXLAiw76osN+Va0NEaOW6rQ==",
+ "dependencies": {
+ "ajv": "^6.12.2",
+ "cookie": "^0.4.0",
+ "fastify-warning": "^0.2.0",
+ "readable-stream": "^3.6.0",
+ "set-cookie-parser": "^2.4.1"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/pino": {
+ "version": "6.11.2",
+ "resolved": "https://registry.npmjs.org/pino/-/pino-6.11.2.tgz",
+ "integrity": "sha512-bmzxwbrIPxQUlAuMkF4PWVErUGERU4z37HazlhflKFg08crsNE3fACGN6gPwg5xtKOK47Ux5cZm8YCuLV4wWJg==",
+ "dependencies": {
+ "fast-redact": "^3.0.0",
+ "fast-safe-stringify": "^2.0.7",
+ "flatstr": "^1.0.12",
+ "pino-std-serializers": "^3.1.0",
+ "quick-format-unescaped": "4.0.1",
+ "sonic-boom": "^1.0.2"
+ },
+ "bin": {
+ "pino": "bin.js"
+ }
+ },
+ "node_modules/pino-std-serializers": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz",
+ "integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg=="
+ },
+ "node_modules/point-of-view": {
+ "version": "4.14.0",
+ "resolved": "https://registry.npmjs.org/point-of-view/-/point-of-view-4.14.0.tgz",
+ "integrity": "sha512-NaWn3oqCWnRj4SvKtYBAwWf2MI1d9/rY5wF93PAdnYq4AzdLqi/IAwTHTf1+Ul3Toi2JMqg6caSCd+eQnwqT3Q==",
+ "dependencies": {
+ "fastify-plugin": "^3.0.0",
+ "hashlru": "^2.3.0"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "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/quick-format-unescaped": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.1.tgz",
+ "integrity": "sha512-RyYpQ6Q5/drsJyOhrWHYMWTedvjTIat+FTwv0K4yoUxzvekw2aRHMQJLlnvt8UantkZg2++bEzD9EdxXqkWf4A=="
+ },
+ "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==",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/ret": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz",
+ "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rfdc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
+ "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safe-regex2": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz",
+ "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==",
+ "dependencies": {
+ "ret": "~0.2.0"
+ }
+ },
+ "node_modules/secure-json-parse": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.3.2.tgz",
+ "integrity": "sha512-4oUSFU0w2d8/XQb7NO9dbMYyp/hxIwZPcZcGAlAAEziMRHs+NbUcx2Z5dda/z8o+avyQ8gpuYnTMlGh8SVwg9g=="
+ },
+ "node_modules/semver": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/semver-store": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz",
+ "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg=="
+ },
+ "node_modules/set-cookie-parser": {
+ "version": "2.4.8",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz",
+ "integrity": "sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg=="
+ },
+ "node_modules/sonic-boom": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz",
+ "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==",
+ "dependencies": {
+ "atomic-sleep": "^1.0.0",
+ "flatstr": "^1.0.12"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string-similarity": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.4.tgz",
+ "integrity": "sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ=="
+ },
+ "node_modules/tiny-lru": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz",
+ "integrity": "sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ }
+ },
+ "dependencies": {
+ "@fastify/forwarded": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@fastify/forwarded/-/forwarded-1.0.0.tgz",
+ "integrity": "sha512-VoO+6WD0aRz8bwgJZ8pkkxjq7o/782cQ1j945HWg0obZMgIadYW3Pew0+an+k1QL7IPZHM3db5WF6OP6x4ymMA=="
+ },
+ "@fastify/proxy-addr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@fastify/proxy-addr/-/proxy-addr-3.0.0.tgz",
+ "integrity": "sha512-ty7wnUd/GeSqKTC2Jozsl5xGbnxUnEFC0On2/zPv/8ixywipQmVZwuWvNGnBoitJ2wixwVqofwXNua8j6Y62lQ==",
+ "requires": {
+ "@fastify/forwarded": "^1.0.0",
+ "ipaddr.js": "^2.0.0"
+ }
+ },
+ "abstract-logging": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
+ "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="
+ },
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "archy": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
+ "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA="
+ },
+ "atomic-sleep": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
+ "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="
+ },
+ "avvio": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/avvio/-/avvio-7.2.1.tgz",
+ "integrity": "sha512-b+gox68dqD6c3S3t+bZBKN6rYbVWdwpN12sHQLFTiacDT2rcq7fm07Ww+IKt/AvAkyCIe1f5ArP1bC/vAlx97A==",
+ "requires": {
+ "archy": "^1.0.0",
+ "debug": "^4.0.0",
+ "fastq": "^1.6.1",
+ "queue-microtask": "^1.1.2"
+ }
+ },
+ "cookie": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz",
+ "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
+ },
+ "debug": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+ "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "deepmerge": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
+ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
+ },
+ "eta": {
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/eta/-/eta-1.12.1.tgz",
+ "integrity": "sha512-H8npoci2J/7XiPnVcCVulBSPsTNGvGaINyMjQDU8AFqp9LGsEYS88g2CiU+d01Sg44WtX7o4nb8wUJ9vnI+tiA=="
+ },
+ "fast-decode-uri-component": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
+ "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="
+ },
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
+ },
+ "fast-json-stringify": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.5.3.tgz",
+ "integrity": "sha512-wOE0YeqnhwOPqaZNvRxsgnq8Puc2vAQIlxSlcpRUInm0yf4+H/YqQ8ijBmzkUg384p0JBzjR9XBNkU5jLWSCwQ==",
+ "requires": {
+ "ajv": "^6.11.0",
+ "deepmerge": "^4.2.2",
+ "rfdc": "^1.2.0",
+ "string-similarity": "^4.0.1"
+ }
+ },
+ "fast-redact": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.0.0.tgz",
+ "integrity": "sha512-a/S/Hp6aoIjx7EmugtzLqXmcNsyFszqbt6qQ99BdG61QjBZF6shNis0BYR6TsZOQ1twYc0FN2Xdhwwbv6+KD0w=="
+ },
+ "fast-safe-stringify": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz",
+ "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA=="
+ },
+ "fastify": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/fastify/-/fastify-3.14.1.tgz",
+ "integrity": "sha512-9hoK1vvopsUJnUJpge90t8PZIqNQhGM54yDrd2veCZLkxh8eipnaHrXe2+f7tIt6UScUZ92JZQavxFGB4HX7xA==",
+ "requires": {
+ "@fastify/proxy-addr": "^3.0.0",
+ "abstract-logging": "^2.0.0",
+ "ajv": "^6.12.2",
+ "avvio": "^7.1.2",
+ "fast-json-stringify": "^2.5.2",
+ "fastify-error": "^0.3.0",
+ "fastify-warning": "^0.2.0",
+ "find-my-way": "^4.0.0",
+ "flatstr": "^1.0.12",
+ "light-my-request": "^4.2.0",
+ "pino": "^6.2.1",
+ "readable-stream": "^3.4.0",
+ "rfdc": "^1.1.4",
+ "secure-json-parse": "^2.0.0",
+ "semver": "^7.3.2",
+ "tiny-lru": "^7.0.0"
+ }
+ },
+ "fastify-error": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/fastify-error/-/fastify-error-0.3.0.tgz",
+ "integrity": "sha512-Jm2LMTB5rsJqlS1+cmgqqM9tTs0UrlgYR7TvDT3ZgXsUI5ib1NjQlqZHf+tDK5tVPdFGwyq02wAoJtyYIRSiFA=="
+ },
+ "fastify-plugin": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz",
+ "integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w=="
+ },
+ "fastify-warning": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/fastify-warning/-/fastify-warning-0.2.0.tgz",
+ "integrity": "sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw=="
+ },
+ "fastq": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
+ "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
+ "requires": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "find-my-way": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-4.1.0.tgz",
+ "integrity": "sha512-UBD94MdO6cBi6E97XA0fBA9nwqw+xG5x1TYIPHats33gEi/kNqy7BWHAWx8QHCQQRSU5Txc0JiD8nzba39gvMQ==",
+ "requires": {
+ "fast-decode-uri-component": "^1.0.1",
+ "fast-deep-equal": "^3.1.3",
+ "safe-regex2": "^2.0.0",
+ "semver-store": "^0.3.0"
+ }
+ },
+ "flatstr": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz",
+ "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw=="
+ },
+ "getenv": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/getenv/-/getenv-1.0.0.tgz",
+ "integrity": "sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg=="
+ },
+ "hashlru": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/hashlru/-/hashlru-2.3.0.tgz",
+ "integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A=="
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "ipaddr.js": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.0.tgz",
+ "integrity": "sha512-S54H9mIj0rbxRIyrDMEuuER86LdlgUg9FSeZ8duQb6CUG2iRrA36MYVQBSprTF/ZeAwvyQ5mDGuNvIPM0BIl3w=="
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "light-my-request": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-4.4.1.tgz",
+ "integrity": "sha512-FDNRF2mYjthIRWE7O8d/X7AzDx4otQHl4/QXbu3Q/FRwBFcgb+ZoDaUd5HwN53uQXLAiw76osN+Va0NEaOW6rQ==",
+ "requires": {
+ "ajv": "^6.12.2",
+ "cookie": "^0.4.0",
+ "fastify-warning": "^0.2.0",
+ "readable-stream": "^3.6.0",
+ "set-cookie-parser": "^2.4.1"
+ }
+ },
+ "lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "requires": {
+ "yallist": "^4.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "pino": {
+ "version": "6.11.2",
+ "resolved": "https://registry.npmjs.org/pino/-/pino-6.11.2.tgz",
+ "integrity": "sha512-bmzxwbrIPxQUlAuMkF4PWVErUGERU4z37HazlhflKFg08crsNE3fACGN6gPwg5xtKOK47Ux5cZm8YCuLV4wWJg==",
+ "requires": {
+ "fast-redact": "^3.0.0",
+ "fast-safe-stringify": "^2.0.7",
+ "flatstr": "^1.0.12",
+ "pino-std-serializers": "^3.1.0",
+ "quick-format-unescaped": "4.0.1",
+ "sonic-boom": "^1.0.2"
+ }
+ },
+ "pino-std-serializers": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz",
+ "integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg=="
+ },
+ "point-of-view": {
+ "version": "4.14.0",
+ "resolved": "https://registry.npmjs.org/point-of-view/-/point-of-view-4.14.0.tgz",
+ "integrity": "sha512-NaWn3oqCWnRj4SvKtYBAwWf2MI1d9/rY5wF93PAdnYq4AzdLqi/IAwTHTf1+Ul3Toi2JMqg6caSCd+eQnwqT3Q==",
+ "requires": {
+ "fastify-plugin": "^3.0.0",
+ "hashlru": "^2.3.0"
+ }
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ },
+ "queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
+ },
+ "quick-format-unescaped": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.1.tgz",
+ "integrity": "sha512-RyYpQ6Q5/drsJyOhrWHYMWTedvjTIat+FTwv0K4yoUxzvekw2aRHMQJLlnvt8UantkZg2++bEzD9EdxXqkWf4A=="
+ },
+ "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==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "ret": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz",
+ "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ=="
+ },
+ "reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
+ },
+ "rfdc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
+ "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
+ },
+ "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=="
+ },
+ "safe-regex2": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz",
+ "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==",
+ "requires": {
+ "ret": "~0.2.0"
+ }
+ },
+ "secure-json-parse": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.3.2.tgz",
+ "integrity": "sha512-4oUSFU0w2d8/XQb7NO9dbMYyp/hxIwZPcZcGAlAAEziMRHs+NbUcx2Z5dda/z8o+avyQ8gpuYnTMlGh8SVwg9g=="
+ },
+ "semver": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ },
+ "semver-store": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz",
+ "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg=="
+ },
+ "set-cookie-parser": {
+ "version": "2.4.8",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz",
+ "integrity": "sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg=="
+ },
+ "sonic-boom": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz",
+ "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==",
+ "requires": {
+ "atomic-sleep": "^1.0.0",
+ "flatstr": "^1.0.12"
+ }
+ },
+ "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==",
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "string-similarity": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.4.tgz",
+ "integrity": "sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ=="
+ },
+ "tiny-lru": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz",
+ "integrity": "sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow=="
+ },
+ "uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..b5e618f
--- /dev/null
+++ b/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "corona-regeln",
+ "version": "1.0.0",
+ "description": "Generator for Corona Guidelines",
+ "main": "lib/corona-regeln.js",
+ "directories": {
+ "lib": "lib"
+ },
+ "scripts": {
+ "test": "echo 'sorry'"
+ },
+ "author": "Rubén Beltrán del Río <subscriptions@unlimited.pizza>",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "eta": "^1.12.1",
+ "fastify": "^3.14.1",
+ "getenv": "^1.0.0",
+ "point-of-view": "^4.14.0"
+ }
+}
diff --git a/rules/business.js b/rules/business.js
new file mode 100644
index 0000000..bc12866
--- /dev/null
+++ b/rules/business.js
@@ -0,0 +1,74 @@
+const internals ={
+
+ businesses: [
+ 'butcher shops',
+ 'plant shops',
+ 'balloon factories',
+ 'pet hotels',
+ 'sex shops',
+ 'clothes incineration facilities',
+ 'city dumps',
+ 'glass factories',
+ 'roads',
+ 'windfarm analysis consultancies',
+ 'peanut depots',
+ 'glue factories',
+ 'bürgeramts',
+ 'chiropractors',
+ 'gong bath facilities',
+ 'wrestling rings',
+ 'cat cafés',
+ 'paint your own pottery centers',
+ 'dungeons',
+ 'television sets',
+ 'nasa offices',
+ 'toilet factories',
+ 'condom inspection facilities',
+ 'high school newspapers',
+ 'dog spas',
+ 'mink breeding centers',
+ 'ngos',
+ 'yoga cults',
+ 'mi6 safehouses',
+ 'döner shops',
+ 'hospitals'
+ ],
+
+ restrictions: [
+ 'are required to work from home',
+ 'require mandatory testing',
+ 'must remain closed',
+ 'must remain open',
+ 'must offer 50% covid discounts',
+ 'must become vaccination centers',
+ 'must pay staff 3x on thursdays',
+ 'can only meet with one other household',
+ 'must share facilities',
+ 'are exempt from mask rules',
+ ],
+
+ join(array) {
+
+ const firstPart = array.slice(0, -1).join(', ')
+ const lastPart = array.slice(-1)
+
+ const conjunction = array.length <= 1 ? '' : ', and '
+
+ return [firstPart, lastPart].join(conjunction)
+ }
+};
+
+module.exports = () => {
+
+ const businesses = internals.businesses
+ .filter(() => true)
+ .sort(() => Math.random() - 0.5)
+ .slice(0, Math.floor(Math.random() * 3) + 1)
+ const restriction = internals.restrictions[Math.floor(Math.random() * internals.restrictions.length)];
+ const text = `${internals.join(businesses)} ${restriction}`
+
+ return {
+ emoji: '🏢',
+ text: text.charAt(0).toUpperCase() + text.slice(1)
+ };
+}
diff --git a/rules/curfew.js b/rules/curfew.js
new file mode 100644
index 0000000..9fc697f
--- /dev/null
+++ b/rules/curfew.js
@@ -0,0 +1,69 @@
+const internals ={
+
+ activities: [
+ 'sex',
+ 'skinny dipping',
+ 'playing chess',
+ 'debating',
+ 'dancing',
+ 'breeding horses',
+ 'laughing',
+ 'sneezing',
+ 'cat wrestling',
+ 'ordering food',
+ 'remote work',
+ 'internet usage',
+ 'sleeping',
+ 'eating',
+ 'vacuuming',
+ 'using a blender',
+ 'having a party',
+ 'theft',
+ 'engaging in economic activity',
+ 'using ketchup',
+ 'tailgating',
+ 'embezzelment',
+ 'taking the U-Bahn',
+ 'cutting your hair',
+ 'using recreational drugs',
+ 'tipping',
+ 'interpretive dancing',
+ 'origami',
+ 'whittling',
+ 'going for a walk',
+ 'working'
+ ],
+
+ restrictions: [
+ 'is not allowed',
+ 'is mandatory',
+ 'is optional',
+ 'requires a mask',
+ 'is only allowed indoors',
+ 'is only allowed outdoors',
+ 'is only allowed in groups larger than seven',
+ 'requires a license',
+ 'is allowed under police supervision',
+ 'is allowed following social distancing rules',
+ 'is only allowed in Neukölln',
+ 'is only allowed in Kreuzberg',
+ 'is only allowed in Charlottenburg',
+ 'is only allowed in Wedding',
+ 'is only allowed in Mitte',
+ 'is only allowed in Prenzlauer Berg',
+ 'is only allowed in Friedrichshain',
+ ]
+};
+
+module.exports = () => {
+
+ const startTime = Math.floor(Math.random() * 23) + 1;
+ const endTtime = Math.floor(Math.random() * 23) + 1;
+ const activity = internals.activities[Math.floor(Math.random() * internals.activities.length)];
+ const restriction = internals.restrictions[Math.floor(Math.random() * internals.restrictions.length)];
+
+ return {
+ emoji: '🕚',
+ text: `From ${startTime}:00 to ${endTtime}:00 ${activity} ${restriction}`
+ };
+}
diff --git a/rules/group.js b/rules/group.js
new file mode 100644
index 0000000..909c378
--- /dev/null
+++ b/rules/group.js
@@ -0,0 +1,51 @@
+const internals ={
+
+ groups: [
+ 'teenagers',
+ 'influencers',
+ 'vegans',
+ 'tik-tok users',
+ 'lactose intolerants',
+ 'households',
+ 'ice cream vendors',
+ 'babies',
+ 'police officers',
+ 'drug dealers',
+ 'tech workers',
+ 'cryptocurrency miners',
+ 'mexicans',
+ 'smokers',
+ 'drug users',
+ 'octogenarians',
+ 'public officials',
+ 'atheists',
+ 'god fearing parishioners',
+ 'b-list actors',
+ 'jugglers',
+ 'seagulls',
+ 'lighthouse operators',
+ 'tram drivers',
+ 'psychics',
+ 'magicians',
+ 'classically trained musicians',
+ 'food delivery drivers',
+ 'librarians',
+ 'doctors',
+ 'vaccinated cats',
+ 'balloon artists'
+ ],
+};
+
+module.exports = () => {
+
+ const countA = Math.floor(Math.random() * 8) + 2;
+ const magnitude = Math.random() > 0.5 ? 99 : 5;
+ const countB = Math.floor(Math.random() * magnitude) + 1;
+ const groupA = internals.groups[Math.floor(Math.random() * internals.groups.length)];
+ const groupB = internals.groups[Math.floor(Math.random() * internals.groups.length)];
+
+ return {
+ emoji: '👨',
+ text: `No more than ${countA} ${groupA} + ${countB} ${groupB} are allowed to meet`
+ };
+}
diff --git a/templates/index.eta b/templates/index.eta
new file mode 100644
index 0000000..1fced66
--- /dev/null
+++ b/templates/index.eta
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML>
+
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="author" content="Rubén Beltrán del Río">
+ <meta name="description" content="New corona regulations for Berlin">
+
+ <meta name="theme-color" content="#db5945">
+
+ <style>
+ body {
+ background: linear-gradient(270deg, #fff 0%, #ccc 100%);
+ font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ padding: 2em;
+ }
+
+ h1 {
+ background: linear-gradient(104deg, rgba(229,19,34,1) 95%, rgba(229,19,34,0) 95%);
+ color: #fff;
+ padding: 0.5em 1em;
+ text-transform: uppercase;
+ }
+
+ul {
+ list-style: none;
+}
+
+li {
+ margin: 1em;
+}
+
+li h2 {
+ font-size: 1.4em;
+ margin: 0;
+ background: linear-gradient(104deg, rgba(229,19,34,1) 95%, rgba(229,19,34,0) 95%);
+ color: #fff;
+ padding: 0.2em 1em 0.2em 0.5em;
+ width: max-content;
+}
+
+li p {
+ margin: 0;
+}
+
+li span {
+ display: inline-block;
+}
+
+li .emoji {
+ position: absolute;
+ font-size: 4em;
+ margin-left: -1.1em;
+}
+
+li .text {
+ font-size: 2em;
+ padding: 0.5em 1em;
+ margin-left: 0.5em;
+ background: #fff;
+}
+ </style>
+
+ <title>New Corona Regulations for Berlin</title>
+ </head>
+ <body>
+ <h1>
+ New Corona Regulations Berlin
+ </h1>
+ <ul>
+ <% for (const rule of it.rules) { %>
+ <li>
+ <h2>Starting <%= rule.time %></h2>
+ <p>
+ <span class="emoji"><%= rule.rule.emoji %></span>
+ <span class="text"><%= rule.rule.text %></span>
+ </p>
+ </li>
+ <% } %>
+ </ul>
+ </body>
+</html>
+