├── .env.sample ├── .eslintrc.json ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── .glitch-assets ├── .lesshst ├── .yamllint.yml ├── README.md ├── package-lock.json ├── package.json ├── shrinkwrap.yaml └── src ├── config.js ├── datastore.js └── server.js /.env.sample: -------------------------------------------------------------------------------- 1 | # Environment Config 2 | # Reference these in your code with process.env.SECRET 3 | 4 | SLACK_BOT_TOKEN=xoxb-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx 5 | SLACK_SIGNING_SECRET=xxxxxxxxxxxxx 6 | 7 | DRUPAL_ORG_NODE_ID=xxxxxxx 8 | 9 | # Only needed if you are using the external trigger. 10 | ORG_TOKEN=xxxxxxx 11 | DEFAULT_CHANNEL_ID=ZZZZZZZZ 12 | # Set this to Slack channel ID to send test messages when debug mode is enabled. 13 | SANDBOX_CHANNEL_ID=ZZZZZZZZ 14 | 15 | # Optional overrides. 16 | SLACK_NOTIFICATION_TEXT="" 17 | SLACK_NOTIFICATION_TRACKED_HIGH_TEXT="" 18 | SLACK_NOTIFICATION_DOWN_FROM_TRACKED_HIGH_TEXT="" 19 | 20 | DEBUG_MODE=false 21 | VERBOSE_MODE=true 22 | 23 | # note: .env is a shell file so there can't be spaces around = 24 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "rules": { 4 | "no-console": "off", 5 | "no-unused-vars": ["error", { "args": "none" }] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: npm 5 | directory: "/" 6 | schedule: 7 | interval: daily 8 | open-pull-requests-limit: 10 9 | versioning-strategy: auto 10 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 3 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 4 | 5 | name: Continuous Integration 6 | 7 | on: # yamllint disable-line rule:truthy 8 | push: 9 | branches: main 10 | pull_request: 11 | branches: main 12 | 13 | jobs: 14 | build: 15 | 16 | runs-on: ubuntu-latest 17 | 18 | strategy: 19 | matrix: 20 | node-version: [16.x, 18.x] 21 | 22 | steps: 23 | - uses: actions/checkout@v2 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v1 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | - run: npm ci 29 | - run: npm run build --if-present 30 | - run: npm test 31 | 32 | yaml-lint: 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@v2 36 | 37 | - name: YAML lint 38 | uses: ibiqlik/action-yamllint@v1.0.0 39 | with: 40 | config_file: .yamllint.yml 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.glitch-assets: -------------------------------------------------------------------------------- 1 | {"name":"drag-in-files.svg","date":"2016-10-22T16:17:49.954Z","url":"https://cdn.hyperdev.com/drag-in-files.svg","type":"image/svg","size":7646,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/drag-in-files.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(102, 153, 205)","uuid":"adSBq97hhhpFNUna"} 2 | {"name":"click-me.svg","date":"2016-10-23T16:17:49.954Z","url":"https://cdn.hyperdev.com/click-me.svg","type":"image/svg","size":7116,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/click-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(243, 185, 186)","uuid":"adSBq97hhhpFNUnb"} 3 | {"name":"paste-me.svg","date":"2016-10-24T16:17:49.954Z","url":"https://cdn.hyperdev.com/paste-me.svg","type":"image/svg","size":7242,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/paste-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(42, 179, 185)","uuid":"adSBq97hhhpFNUnc"} 4 | {"uuid":"adSBq97hhhpFNUna","deleted":true} 5 | -------------------------------------------------------------------------------- /.lesshst: -------------------------------------------------------------------------------- 1 | .less-history-file: 2 | .search 3 | -------------------------------------------------------------------------------- /.yamllint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | rules: 5 | line-length: disable 6 | 7 | ignore: | 8 | node_modules/ 9 | shrinkwrap.yaml 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Drupal.org / Slack App 2 | 3 | [![Remix on 4 | Glitch](https://cdn.glitch.com/2703baf2-b643-4da7-ab91-7ee2a2d00b5b%2Fremix-button.svg)](https://glitch.com/edit/#!/remix/drupalorg-slack) 5 | 6 | The `drupalorg-slack` Slack app uses Drupal.org's API to retrieve several 7 | data points that are relevant to an organization's [Drupal 8 | Marketplace](http://drupal.org/marketplace) rank and report it into your Slack 9 | workspace. The data points include issue credit count, number of projects 10 | supported, and case studies submitted, as well as the marketplace rank itself. 11 | It also keeps track of the "high scores" for each of these values. 12 | 13 | The functionality is composed of two pieces, the slash command, and an external 14 | trigger: 15 | 16 | * The slash command is triggered from within Slack by any user with permission 17 | and will result in an ephemeral message sent back to Slack with the response. 18 | Only the requesting user can see this response. 19 | * The external trigger allows for a request from outside of Slack to trigger the 20 | app. This is useful for scheduling the app to notify a channel regularly. 21 | 22 | ![drupalorg-slack app screenshot](https://user-images.githubusercontent.com/20355/205161865-662e0a19-b284-42ea-836a-55d381524dde.png) 23 | 24 | ## Getting Started 25 | 26 | 1. [Remix on Glitch](https://glitch.com/edit/#!/remix/drupalorg-slack) (easiest 27 | for a quick start since Glitch will host your app and provide a URL for 28 | Slack to talk directly to; [more info on Glitch](https://glitch.com/about)). 29 | Alternatively, and more traditionally, you may clone this repo and get the app 30 | running somewhere that it will be accessible on the web. 31 | 1. Copy [`.env.sample`](.env.sample) to `.env`. 32 | 1. Create a new app in the [Slack "Your Apps" 33 | dashboard](https://api.slack.com/apps). 34 | 1. In your newly created Slack app configuration, Create a slash command via the 35 | "Slash Commands" tab in the sidebar and set the request URL to your app: 36 | `https://your-app-name-here.glitch.me/slack/events` 37 | 1. Configure the required environment variables in `.env`: 38 | 1. `SLACK_SIGNING_SECRET`: Navigate to the "Basic Information" tab and use 39 | the "Signing Secret". 40 | 1. `SLACK_BOT_TOKEN`: Navigate to the "Install App" tab and use the "Bot 41 | User OAuth Access Token" value. 42 | 1. `DRUPAL_ORG_NODE_ID`: Your organization's node ID from Drupal.org. 43 | 1. Configure the optional environment variables in `.env`. These values are 44 | utilized when the app is triggered from an external source such as a cron or 45 | Jenkins job as opposed to a "slash command" from within Slack. 46 | 1. `DEFAULT_CHANNEL_ID` / `SANDBOX_CHANNEL_ID` (optional): Populate these 47 | values with the Slack channel ID's where you want the app to post 48 | notifications. The easiest way to get these values is to load your Slack 49 | workspace in a web browser (as opposed to the Slack app) and grab the 50 | channel IDs from the address bar. 51 | 1. `ORG_TOKEN`: A secure value used to validate a request. 52 | 1. Customize default values: 53 | 1. `DEBUG_MODE`: Setting this value to `true` results in the 54 | `SANDBOX_CHANNEL_ID` being used instead of the `DEFAULT_CHANNEL_ID`. 55 | 1. `VERBOSE_MODE`: Set to `true` to enable verbose console logging. 56 | 57 | ## Example Trigger Request 58 | 59 | To trigger the app from outside of Slack: 60 | 61 | 1. Ensure `DEFAULT_CHANNEL_ID`, `SANDBOX_CHANNEL_ID`, and `ORG_TOKEN` are 62 | configured as described above. 63 | 1. Make a POST request with your token in the following format: 64 | 65 | ```bash 66 | curl --fail -X POST \ 67 | 'https://your-app-name-here.glitch.me/triggers?token=YOUR_ORG_TOKEN_HERE' 68 | ``` 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "drupalorg-slack", 3 | "version": "1.0.1", 4 | "description": "App to pull an organization's data from Drupal.org and send to Slack.", 5 | "author": { 6 | "name": "Mark Dorison", 7 | "email": "mark@chromatichq.com", 8 | "url": "https://chromatichq.com" 9 | }, 10 | "license": "MIT", 11 | "keywords": [ 12 | "node", 13 | "glitch", 14 | "express", 15 | "slack", 16 | "drupal" 17 | ], 18 | "homepage": "https://github.com/ChromaticHQ/drupalorg-slack#readme", 19 | "bugs": "https://github.com/ChromaticHQ/drupalorg-slack/issues", 20 | "repository": { 21 | "url": "https://github.com/ChromaticHQ/drupalorg-slack" 22 | }, 23 | "main": "server.js", 24 | "scripts": { 25 | "start": "node src/server.js", 26 | "lint": "eslint '**/*.js'", 27 | "lint:fix": "eslint --fix '**/*.js'", 28 | "test": "npm run lint" 29 | }, 30 | "engines": { 31 | "node": "18.x" 32 | }, 33 | "dependencies": { 34 | "@slack/bolt": "^2.6.1", 35 | "axios": "^0.27.2", 36 | "cheerio": "^1.0.0-rc.10", 37 | "lowdb": "^1.0.0" 38 | }, 39 | "devDependencies": { 40 | "eslint": "^6.8.0", 41 | "eslint-config-airbnb-base": "^14.2.1", 42 | "eslint-plugin-import": "^2.26.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /shrinkwrap.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | '@slack/bolt': 2.7.0 3 | axios: 0.27.2 4 | cheerio: 1.0.0-rc.10 5 | lowdb: 1.0.0 6 | devDependencies: 7 | eslint: 6.8.0 8 | eslint-config-airbnb-base: 14.2.1 9 | eslint-plugin-import: 2.26.0 10 | packages: 11 | /@babel/code-frame/7.16.7: 12 | dependencies: 13 | '@babel/highlight': 7.17.9 14 | dev: true 15 | engines: 16 | node: '>=6.9.0' 17 | resolution: 18 | integrity: sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== 19 | /@babel/helper-validator-identifier/7.16.7: 20 | dev: true 21 | engines: 22 | node: '>=6.9.0' 23 | resolution: 24 | integrity: sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== 25 | /@babel/highlight/7.17.9: 26 | dependencies: 27 | '@babel/helper-validator-identifier': 7.16.7 28 | chalk: 2.4.2 29 | js-tokens: 4.0.0 30 | dev: true 31 | engines: 32 | node: '>=6.9.0' 33 | resolution: 34 | integrity: sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg== 35 | /@slack/bolt/2.7.0: 36 | dependencies: 37 | '@slack/logger': 2.0.0 38 | '@slack/oauth': 1.4.0 39 | '@slack/types': 1.10.0 40 | '@slack/web-api': 5.15.0 41 | '@types/express': 4.17.13 42 | '@types/node': 17.0.33 43 | '@types/promise.allsettled': 1.0.3 44 | axios: 0.21.4 45 | express: 4.18.1 46 | please-upgrade-node: 3.2.0 47 | promise.allsettled: 1.0.5 48 | raw-body: 2.5.1 49 | tsscmp: 1.0.6 50 | dev: false 51 | engines: 52 | node: '>=10.13.0' 53 | npm: '>=6.4.1' 54 | resolution: 55 | integrity: sha512-bGCOlhp92wuG+wsQmy7qCtdaNjcuU/yy8dMsm4TWJ/ZHzZ7SqmStUVaou4n3LcJq0+Q/Xmg7gc117zYOCx/MiA== 56 | /@slack/logger/2.0.0: 57 | dependencies: 58 | '@types/node': 17.0.33 59 | dev: false 60 | engines: 61 | node: '>= 8.9.0' 62 | npm: '>= 5.5.1' 63 | resolution: 64 | integrity: sha512-OkIJpiU2fz6HOJujhlhfIGrc8hB4ibqtf7nnbJQDerG0BqwZCfmgtK5sWzZ0TkXVRBKD5MpLrTmCYyMxoMCgPw== 65 | /@slack/oauth/1.4.0: 66 | dependencies: 67 | '@slack/logger': 2.0.0 68 | '@slack/web-api': 5.15.0 69 | '@types/jsonwebtoken': 8.5.8 70 | '@types/node': 17.0.33 71 | jsonwebtoken: 8.5.1 72 | lodash.isstring: 4.0.1 73 | dev: false 74 | engines: 75 | node: '>=10.0.0' 76 | resolution: 77 | integrity: sha512-wTREPfNfkFqTy7ql4V7bHYBZ62miLyqMvcvnJFQ1W6CTbGaha8BU1aTQaVHhKQuFgR5YztnN5d66bsxSImtBDA== 78 | /@slack/types/1.10.0: 79 | dev: false 80 | engines: 81 | node: '>= 8.9.0' 82 | npm: '>= 5.5.1' 83 | resolution: 84 | integrity: sha512-tA7GG7Tj479vojfV3AoxbckalA48aK6giGjNtgH6ihpLwTyHE3fIgRrvt8TWfLwW8X8dyu7vgmAsGLRG7hWWOg== 85 | /@slack/web-api/5.15.0: 86 | dependencies: 87 | '@slack/logger': 2.0.0 88 | '@slack/types': 1.10.0 89 | '@types/is-stream': 1.1.0 90 | '@types/node': 17.0.33 91 | axios: 0.21.4 92 | eventemitter3: 3.1.2 93 | form-data: 2.5.1 94 | is-stream: 1.1.0 95 | p-queue: 6.6.2 96 | p-retry: 4.6.2 97 | dev: false 98 | engines: 99 | node: '>= 8.9.0' 100 | npm: '>= 5.5.1' 101 | resolution: 102 | integrity: sha512-tjQ8Zqv/Fmj9SOL9yIEd7IpTiKfKHi9DKAkfRVeotoX0clMr3SqQtBqO+KZMX27gm7dmgJsQaDKlILyzdCO+IA== 103 | /@types/body-parser/1.19.2: 104 | dependencies: 105 | '@types/connect': 3.4.35 106 | '@types/node': 17.0.33 107 | dev: false 108 | resolution: 109 | integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== 110 | /@types/connect/3.4.35: 111 | dependencies: 112 | '@types/node': 17.0.33 113 | dev: false 114 | resolution: 115 | integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== 116 | /@types/express-serve-static-core/4.17.28: 117 | dependencies: 118 | '@types/node': 17.0.33 119 | '@types/qs': 6.9.7 120 | '@types/range-parser': 1.2.4 121 | dev: false 122 | resolution: 123 | integrity: sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== 124 | /@types/express/4.17.13: 125 | dependencies: 126 | '@types/body-parser': 1.19.2 127 | '@types/express-serve-static-core': 4.17.28 128 | '@types/qs': 6.9.7 129 | '@types/serve-static': 1.13.10 130 | dev: false 131 | resolution: 132 | integrity: sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== 133 | /@types/is-stream/1.1.0: 134 | dependencies: 135 | '@types/node': 17.0.33 136 | dev: false 137 | resolution: 138 | integrity: sha512-jkZatu4QVbR60mpIzjINmtS1ZF4a/FqdTUTBeQDVOQ2PYyidtwFKr0B5G6ERukKwliq+7mIXvxyppwzG5EgRYg== 139 | /@types/json5/0.0.29: 140 | dev: true 141 | resolution: 142 | integrity: sha1-7ihweulOEdK4J7y+UnC86n8+ce4= 143 | /@types/jsonwebtoken/8.5.8: 144 | dependencies: 145 | '@types/node': 17.0.33 146 | dev: false 147 | resolution: 148 | integrity: sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A== 149 | /@types/mime/1.3.2: 150 | dev: false 151 | resolution: 152 | integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== 153 | /@types/node/17.0.33: 154 | dev: false 155 | resolution: 156 | integrity: sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ== 157 | /@types/promise.allsettled/1.0.3: 158 | dev: false 159 | resolution: 160 | integrity: sha512-b/IFHHTkYkTqu41IH9UtpICwqrpKj2oNlb4KHPzFQDMiz+h1BgAeATeO0/XTph4+UkH9W2U0E4B4j64KWOovag== 161 | /@types/qs/6.9.7: 162 | dev: false 163 | resolution: 164 | integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== 165 | /@types/range-parser/1.2.4: 166 | dev: false 167 | resolution: 168 | integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== 169 | /@types/retry/0.12.0: 170 | dev: false 171 | resolution: 172 | integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== 173 | /@types/serve-static/1.13.10: 174 | dependencies: 175 | '@types/mime': 1.3.2 176 | '@types/node': 17.0.33 177 | dev: false 178 | resolution: 179 | integrity: sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== 180 | /accepts/1.3.8: 181 | dependencies: 182 | mime-types: 2.1.35 183 | negotiator: 0.6.3 184 | dev: false 185 | engines: 186 | node: '>= 0.6' 187 | resolution: 188 | integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== 189 | /acorn-jsx/5.3.2/acorn@7.4.1: 190 | dependencies: 191 | acorn: 7.4.1 192 | dev: true 193 | id: registry.npmjs.org/acorn-jsx/5.3.2 194 | peerDependencies: 195 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 196 | resolution: 197 | integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== 198 | /acorn/7.4.1: 199 | dev: true 200 | engines: 201 | node: '>=0.4.0' 202 | hasBin: true 203 | resolution: 204 | integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== 205 | /ajv/6.12.6: 206 | dependencies: 207 | fast-deep-equal: 3.1.3 208 | fast-json-stable-stringify: 2.1.0 209 | json-schema-traverse: 0.4.1 210 | uri-js: 4.4.1 211 | dev: true 212 | resolution: 213 | integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 214 | /ansi-escapes/4.3.2: 215 | dependencies: 216 | type-fest: 0.21.3 217 | dev: true 218 | engines: 219 | node: '>=8' 220 | resolution: 221 | integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== 222 | /ansi-regex/4.1.1: 223 | dev: true 224 | engines: 225 | node: '>=6' 226 | resolution: 227 | integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== 228 | /ansi-regex/5.0.1: 229 | dev: true 230 | engines: 231 | node: '>=8' 232 | resolution: 233 | integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 234 | /ansi-styles/3.2.1: 235 | dependencies: 236 | color-convert: 1.9.3 237 | dev: true 238 | engines: 239 | node: '>=4' 240 | resolution: 241 | integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 242 | /ansi-styles/4.3.0: 243 | dependencies: 244 | color-convert: 2.0.1 245 | dev: true 246 | engines: 247 | node: '>=8' 248 | resolution: 249 | integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 250 | /argparse/1.0.10: 251 | dependencies: 252 | sprintf-js: 1.0.3 253 | dev: true 254 | resolution: 255 | integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 256 | /array-flatten/1.1.1: 257 | dev: false 258 | resolution: 259 | integrity: sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 260 | /array-includes/3.1.5: 261 | dependencies: 262 | call-bind: 1.0.2 263 | define-properties: 1.1.4 264 | es-abstract: 1.20.0 265 | get-intrinsic: 1.1.1 266 | is-string: 1.0.7 267 | dev: true 268 | engines: 269 | node: '>= 0.4' 270 | resolution: 271 | integrity: sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ== 272 | /array.prototype.flat/1.3.0: 273 | dependencies: 274 | call-bind: 1.0.2 275 | define-properties: 1.1.4 276 | es-abstract: 1.20.0 277 | es-shim-unscopables: 1.0.0 278 | dev: true 279 | engines: 280 | node: '>= 0.4' 281 | resolution: 282 | integrity: sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw== 283 | /array.prototype.map/1.0.4: 284 | dependencies: 285 | call-bind: 1.0.2 286 | define-properties: 1.1.4 287 | es-abstract: 1.20.0 288 | es-array-method-boxes-properly: 1.0.0 289 | is-string: 1.0.7 290 | dev: false 291 | engines: 292 | node: '>= 0.4' 293 | resolution: 294 | integrity: sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA== 295 | /astral-regex/1.0.0: 296 | dev: true 297 | engines: 298 | node: '>=4' 299 | resolution: 300 | integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== 301 | /asynckit/0.4.0: 302 | dev: false 303 | resolution: 304 | integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k= 305 | /axios/0.21.4: 306 | dependencies: 307 | follow-redirects: 1.15.0 308 | dev: false 309 | resolution: 310 | integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== 311 | /axios/0.27.2: 312 | dependencies: 313 | follow-redirects: 1.15.0 314 | form-data: 4.0.0 315 | dev: false 316 | resolution: 317 | integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== 318 | /balanced-match/1.0.2: 319 | dev: true 320 | resolution: 321 | integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 322 | /body-parser/1.20.0: 323 | dependencies: 324 | bytes: 3.1.2 325 | content-type: 1.0.4 326 | debug: 2.6.9 327 | depd: 2.0.0 328 | destroy: 1.2.0 329 | http-errors: 2.0.0 330 | iconv-lite: 0.4.24 331 | on-finished: 2.4.1 332 | qs: 6.10.3 333 | raw-body: 2.5.1 334 | type-is: 1.6.18 335 | unpipe: 1.0.0 336 | dev: false 337 | engines: 338 | node: '>= 0.8' 339 | npm: 1.2.8000 || >= 1.4.16 340 | resolution: 341 | integrity: sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg== 342 | /boolbase/1.0.0: 343 | dev: false 344 | resolution: 345 | integrity: sha1-aN/1++YMUes3cl6p4+0xDcwed24= 346 | /brace-expansion/1.1.11: 347 | dependencies: 348 | balanced-match: 1.0.2 349 | concat-map: 0.0.1 350 | dev: true 351 | resolution: 352 | integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 353 | /buffer-equal-constant-time/1.0.1: 354 | dev: false 355 | resolution: 356 | integrity: sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= 357 | /bytes/3.1.2: 358 | dev: false 359 | engines: 360 | node: '>= 0.8' 361 | resolution: 362 | integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== 363 | /call-bind/1.0.2: 364 | dependencies: 365 | function-bind: 1.1.1 366 | get-intrinsic: 1.1.1 367 | resolution: 368 | integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== 369 | /callsites/3.1.0: 370 | dev: true 371 | engines: 372 | node: '>=6' 373 | resolution: 374 | integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== 375 | /chalk/2.4.2: 376 | dependencies: 377 | ansi-styles: 3.2.1 378 | escape-string-regexp: 1.0.5 379 | supports-color: 5.5.0 380 | dev: true 381 | engines: 382 | node: '>=4' 383 | resolution: 384 | integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 385 | /chalk/4.1.2: 386 | dependencies: 387 | ansi-styles: 4.3.0 388 | supports-color: 7.2.0 389 | dev: true 390 | engines: 391 | node: '>=10' 392 | resolution: 393 | integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 394 | /chardet/0.7.0: 395 | dev: true 396 | resolution: 397 | integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== 398 | /cheerio-select/1.6.0: 399 | dependencies: 400 | css-select: 4.3.0 401 | css-what: 6.1.0 402 | domelementtype: 2.3.0 403 | domhandler: 4.3.1 404 | domutils: 2.8.0 405 | dev: false 406 | resolution: 407 | integrity: sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g== 408 | /cheerio/1.0.0-rc.10: 409 | dependencies: 410 | cheerio-select: 1.6.0 411 | dom-serializer: 1.4.1 412 | domhandler: 4.3.1 413 | htmlparser2: 6.1.0 414 | parse5: 6.0.1 415 | parse5-htmlparser2-tree-adapter: 6.0.1 416 | tslib: 2.4.0 417 | dev: false 418 | engines: 419 | node: '>= 6' 420 | resolution: 421 | integrity: sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw== 422 | /cli-cursor/3.1.0: 423 | dependencies: 424 | restore-cursor: 3.1.0 425 | dev: true 426 | engines: 427 | node: '>=8' 428 | resolution: 429 | integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== 430 | /cli-width/3.0.0: 431 | dev: true 432 | engines: 433 | node: '>= 10' 434 | resolution: 435 | integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== 436 | /color-convert/1.9.3: 437 | dependencies: 438 | color-name: 1.1.3 439 | dev: true 440 | resolution: 441 | integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 442 | /color-convert/2.0.1: 443 | dependencies: 444 | color-name: 1.1.4 445 | dev: true 446 | engines: 447 | node: '>=7.0.0' 448 | resolution: 449 | integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 450 | /color-name/1.1.3: 451 | dev: true 452 | resolution: 453 | integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 454 | /color-name/1.1.4: 455 | dev: true 456 | resolution: 457 | integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 458 | /combined-stream/1.0.8: 459 | dependencies: 460 | delayed-stream: 1.0.0 461 | dev: false 462 | engines: 463 | node: '>= 0.8' 464 | resolution: 465 | integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 466 | /concat-map/0.0.1: 467 | dev: true 468 | resolution: 469 | integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 470 | /confusing-browser-globals/1.0.11: 471 | dev: true 472 | resolution: 473 | integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== 474 | /content-disposition/0.5.4: 475 | dependencies: 476 | safe-buffer: 5.2.1 477 | dev: false 478 | engines: 479 | node: '>= 0.6' 480 | resolution: 481 | integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== 482 | /content-type/1.0.4: 483 | dev: false 484 | engines: 485 | node: '>= 0.6' 486 | resolution: 487 | integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 488 | /cookie-signature/1.0.6: 489 | dev: false 490 | resolution: 491 | integrity: sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 492 | /cookie/0.5.0: 493 | dev: false 494 | engines: 495 | node: '>= 0.6' 496 | resolution: 497 | integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== 498 | /cross-spawn/6.0.5: 499 | dependencies: 500 | nice-try: 1.0.5 501 | path-key: 2.0.1 502 | semver: 5.7.1 503 | shebang-command: 1.2.0 504 | which: 1.3.1 505 | dev: true 506 | engines: 507 | node: '>=4.8' 508 | resolution: 509 | integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== 510 | /css-select/4.3.0: 511 | dependencies: 512 | boolbase: 1.0.0 513 | css-what: 6.1.0 514 | domhandler: 4.3.1 515 | domutils: 2.8.0 516 | nth-check: 2.0.1 517 | dev: false 518 | resolution: 519 | integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== 520 | /css-what/6.1.0: 521 | dev: false 522 | engines: 523 | node: '>= 6' 524 | resolution: 525 | integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== 526 | /debug/2.6.9: 527 | dependencies: 528 | ms: 2.0.0 529 | resolution: 530 | integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 531 | /debug/3.2.7: 532 | dependencies: 533 | ms: 2.1.3 534 | dev: true 535 | resolution: 536 | integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== 537 | /debug/4.3.4: 538 | dependencies: 539 | ms: 2.1.2 540 | dev: true 541 | engines: 542 | node: '>=6.0' 543 | resolution: 544 | integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 545 | /deep-is/0.1.4: 546 | dev: true 547 | resolution: 548 | integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== 549 | /define-properties/1.1.4: 550 | dependencies: 551 | has-property-descriptors: 1.0.0 552 | object-keys: 1.1.1 553 | engines: 554 | node: '>= 0.4' 555 | resolution: 556 | integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== 557 | /delayed-stream/1.0.0: 558 | dev: false 559 | engines: 560 | node: '>=0.4.0' 561 | resolution: 562 | integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk= 563 | /depd/2.0.0: 564 | dev: false 565 | engines: 566 | node: '>= 0.8' 567 | resolution: 568 | integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== 569 | /destroy/1.2.0: 570 | dev: false 571 | engines: 572 | node: '>= 0.8' 573 | npm: 1.2.8000 || >= 1.4.16 574 | resolution: 575 | integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== 576 | /doctrine/2.1.0: 577 | dependencies: 578 | esutils: 2.0.3 579 | dev: true 580 | engines: 581 | node: '>=0.10.0' 582 | resolution: 583 | integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== 584 | /doctrine/3.0.0: 585 | dependencies: 586 | esutils: 2.0.3 587 | dev: true 588 | engines: 589 | node: '>=6.0.0' 590 | resolution: 591 | integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== 592 | /dom-serializer/1.4.1: 593 | dependencies: 594 | domelementtype: 2.3.0 595 | domhandler: 4.3.1 596 | entities: 2.2.0 597 | dev: false 598 | resolution: 599 | integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== 600 | /domelementtype/2.3.0: 601 | dev: false 602 | resolution: 603 | integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== 604 | /domhandler/4.3.1: 605 | dependencies: 606 | domelementtype: 2.3.0 607 | dev: false 608 | engines: 609 | node: '>= 4' 610 | resolution: 611 | integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== 612 | /domutils/2.8.0: 613 | dependencies: 614 | dom-serializer: 1.4.1 615 | domelementtype: 2.3.0 616 | domhandler: 4.3.1 617 | dev: false 618 | resolution: 619 | integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== 620 | /ecdsa-sig-formatter/1.0.11: 621 | dependencies: 622 | safe-buffer: 5.2.1 623 | dev: false 624 | resolution: 625 | integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== 626 | /ee-first/1.1.1: 627 | dev: false 628 | resolution: 629 | integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 630 | /emoji-regex/7.0.3: 631 | dev: true 632 | resolution: 633 | integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 634 | /emoji-regex/8.0.0: 635 | dev: true 636 | resolution: 637 | integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 638 | /encodeurl/1.0.2: 639 | dev: false 640 | engines: 641 | node: '>= 0.8' 642 | resolution: 643 | integrity: sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 644 | /entities/2.2.0: 645 | dev: false 646 | resolution: 647 | integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== 648 | /es-abstract/1.20.0: 649 | dependencies: 650 | call-bind: 1.0.2 651 | es-to-primitive: 1.2.1 652 | function-bind: 1.1.1 653 | function.prototype.name: 1.1.5 654 | get-intrinsic: 1.1.1 655 | get-symbol-description: 1.0.0 656 | has: 1.0.3 657 | has-property-descriptors: 1.0.0 658 | has-symbols: 1.0.3 659 | internal-slot: 1.0.3 660 | is-callable: 1.2.4 661 | is-negative-zero: 2.0.2 662 | is-regex: 1.1.4 663 | is-shared-array-buffer: 1.0.2 664 | is-string: 1.0.7 665 | is-weakref: 1.0.2 666 | object-inspect: 1.12.0 667 | object-keys: 1.1.1 668 | object.assign: 4.1.2 669 | regexp.prototype.flags: 1.4.3 670 | string.prototype.trimend: 1.0.5 671 | string.prototype.trimstart: 1.0.5 672 | unbox-primitive: 1.0.2 673 | engines: 674 | node: '>= 0.4' 675 | resolution: 676 | integrity: sha512-URbD8tgRthKD3YcC39vbvSDrX23upXnPcnGAjQfgxXF5ID75YcENawc9ZX/9iTP9ptUyfCLIxTTuMYoRfiOVKA== 677 | /es-array-method-boxes-properly/1.0.0: 678 | dev: false 679 | resolution: 680 | integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== 681 | /es-get-iterator/1.1.2: 682 | dependencies: 683 | call-bind: 1.0.2 684 | get-intrinsic: 1.1.1 685 | has-symbols: 1.0.3 686 | is-arguments: 1.1.1 687 | is-map: 2.0.2 688 | is-set: 2.0.2 689 | is-string: 1.0.7 690 | isarray: 2.0.5 691 | dev: false 692 | resolution: 693 | integrity: sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== 694 | /es-shim-unscopables/1.0.0: 695 | dependencies: 696 | has: 1.0.3 697 | dev: true 698 | resolution: 699 | integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== 700 | /es-to-primitive/1.2.1: 701 | dependencies: 702 | is-callable: 1.2.4 703 | is-date-object: 1.0.5 704 | is-symbol: 1.0.4 705 | engines: 706 | node: '>= 0.4' 707 | resolution: 708 | integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== 709 | /escape-html/1.0.3: 710 | dev: false 711 | resolution: 712 | integrity: sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 713 | /escape-string-regexp/1.0.5: 714 | dev: true 715 | engines: 716 | node: '>=0.8.0' 717 | resolution: 718 | integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 719 | /eslint-config-airbnb-base/14.2.1: 720 | dependencies: 721 | confusing-browser-globals: 1.0.11 722 | object.assign: 4.1.2 723 | object.entries: 1.1.5 724 | dev: true 725 | engines: 726 | node: '>= 6' 727 | peerDependencies: 728 | eslint: ^5.16.0 || ^6.8.0 || ^7.2.0 729 | eslint-plugin-import: ^2.22.1 730 | resolution: 731 | integrity: sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA== 732 | /eslint-import-resolver-node/0.3.6: 733 | dependencies: 734 | debug: 3.2.7 735 | resolve: 1.22.0 736 | dev: true 737 | resolution: 738 | integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== 739 | /eslint-module-utils/2.7.3: 740 | dependencies: 741 | debug: 3.2.7 742 | find-up: 2.1.0 743 | dev: true 744 | engines: 745 | node: '>=4' 746 | resolution: 747 | integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== 748 | /eslint-plugin-import/2.26.0: 749 | dependencies: 750 | array-includes: 3.1.5 751 | array.prototype.flat: 1.3.0 752 | debug: 2.6.9 753 | doctrine: 2.1.0 754 | eslint-import-resolver-node: 0.3.6 755 | eslint-module-utils: 2.7.3 756 | has: 1.0.3 757 | is-core-module: 2.9.0 758 | is-glob: 4.0.3 759 | minimatch: 3.1.2 760 | object.values: 1.1.5 761 | resolve: 1.22.0 762 | tsconfig-paths: 3.14.1 763 | dev: true 764 | engines: 765 | node: '>=4' 766 | peerDependencies: 767 | eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 768 | resolution: 769 | integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== 770 | /eslint-scope/5.1.1: 771 | dependencies: 772 | esrecurse: 4.3.0 773 | estraverse: 4.3.0 774 | dev: true 775 | engines: 776 | node: '>=8.0.0' 777 | resolution: 778 | integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== 779 | /eslint-utils/1.4.3: 780 | dependencies: 781 | eslint-visitor-keys: 1.3.0 782 | dev: true 783 | engines: 784 | node: '>=6' 785 | resolution: 786 | integrity: sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== 787 | /eslint-visitor-keys/1.3.0: 788 | dev: true 789 | engines: 790 | node: '>=4' 791 | resolution: 792 | integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== 793 | /eslint/6.8.0: 794 | dependencies: 795 | '@babel/code-frame': 7.16.7 796 | ajv: 6.12.6 797 | chalk: 2.4.2 798 | cross-spawn: 6.0.5 799 | debug: 4.3.4 800 | doctrine: 3.0.0 801 | eslint-scope: 5.1.1 802 | eslint-utils: 1.4.3 803 | eslint-visitor-keys: 1.3.0 804 | espree: 6.2.1 805 | esquery: 1.4.0 806 | esutils: 2.0.3 807 | file-entry-cache: 5.0.1 808 | functional-red-black-tree: 1.0.1 809 | glob-parent: 5.1.2 810 | globals: 12.4.0 811 | ignore: 4.0.6 812 | import-fresh: 3.3.0 813 | imurmurhash: 0.1.4 814 | inquirer: 7.3.3 815 | is-glob: 4.0.3 816 | js-yaml: 3.14.1 817 | json-stable-stringify-without-jsonify: 1.0.1 818 | levn: 0.3.0 819 | lodash: 4.17.21 820 | minimatch: 3.1.2 821 | mkdirp: 0.5.6 822 | natural-compare: 1.4.0 823 | optionator: 0.8.3 824 | progress: 2.0.3 825 | regexpp: 2.0.1 826 | semver: 6.3.0 827 | strip-ansi: 5.2.0 828 | strip-json-comments: 3.1.1 829 | table: 5.4.6 830 | text-table: 0.2.0 831 | v8-compile-cache: 2.3.0 832 | dev: true 833 | engines: 834 | node: ^8.10.0 || ^10.13.0 || >=11.10.1 835 | hasBin: true 836 | resolution: 837 | integrity: sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== 838 | /espree/6.2.1: 839 | dependencies: 840 | acorn: 7.4.1 841 | acorn-jsx: /acorn-jsx/5.3.2/acorn@7.4.1 842 | eslint-visitor-keys: 1.3.0 843 | dev: true 844 | engines: 845 | node: '>=6.0.0' 846 | resolution: 847 | integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== 848 | /esprima/4.0.1: 849 | dev: true 850 | engines: 851 | node: '>=4' 852 | hasBin: true 853 | resolution: 854 | integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 855 | /esquery/1.4.0: 856 | dependencies: 857 | estraverse: 5.3.0 858 | dev: true 859 | engines: 860 | node: '>=0.10' 861 | resolution: 862 | integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== 863 | /esrecurse/4.3.0: 864 | dependencies: 865 | estraverse: 5.3.0 866 | dev: true 867 | engines: 868 | node: '>=4.0' 869 | resolution: 870 | integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== 871 | /estraverse/4.3.0: 872 | dev: true 873 | engines: 874 | node: '>=4.0' 875 | resolution: 876 | integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== 877 | /estraverse/5.3.0: 878 | dev: true 879 | engines: 880 | node: '>=4.0' 881 | resolution: 882 | integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== 883 | /esutils/2.0.3: 884 | dev: true 885 | engines: 886 | node: '>=0.10.0' 887 | resolution: 888 | integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 889 | /etag/1.8.1: 890 | dev: false 891 | engines: 892 | node: '>= 0.6' 893 | resolution: 894 | integrity: sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 895 | /eventemitter3/3.1.2: 896 | dev: false 897 | resolution: 898 | integrity: sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== 899 | /eventemitter3/4.0.7: 900 | dev: false 901 | resolution: 902 | integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== 903 | /express/4.18.1: 904 | dependencies: 905 | accepts: 1.3.8 906 | array-flatten: 1.1.1 907 | body-parser: 1.20.0 908 | content-disposition: 0.5.4 909 | content-type: 1.0.4 910 | cookie: 0.5.0 911 | cookie-signature: 1.0.6 912 | debug: 2.6.9 913 | depd: 2.0.0 914 | encodeurl: 1.0.2 915 | escape-html: 1.0.3 916 | etag: 1.8.1 917 | finalhandler: 1.2.0 918 | fresh: 0.5.2 919 | http-errors: 2.0.0 920 | merge-descriptors: 1.0.1 921 | methods: 1.1.2 922 | on-finished: 2.4.1 923 | parseurl: 1.3.3 924 | path-to-regexp: 0.1.7 925 | proxy-addr: 2.0.7 926 | qs: 6.10.3 927 | range-parser: 1.2.1 928 | safe-buffer: 5.2.1 929 | send: 0.18.0 930 | serve-static: 1.15.0 931 | setprototypeof: 1.2.0 932 | statuses: 2.0.1 933 | type-is: 1.6.18 934 | utils-merge: 1.0.1 935 | vary: 1.1.2 936 | dev: false 937 | engines: 938 | node: '>= 0.10.0' 939 | resolution: 940 | integrity: sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q== 941 | /external-editor/3.1.0: 942 | dependencies: 943 | chardet: 0.7.0 944 | iconv-lite: 0.4.24 945 | tmp: 0.0.33 946 | dev: true 947 | engines: 948 | node: '>=4' 949 | resolution: 950 | integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== 951 | /fast-deep-equal/3.1.3: 952 | dev: true 953 | resolution: 954 | integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 955 | /fast-json-stable-stringify/2.1.0: 956 | dev: true 957 | resolution: 958 | integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 959 | /fast-levenshtein/2.0.6: 960 | dev: true 961 | resolution: 962 | integrity: sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= 963 | /figures/3.2.0: 964 | dependencies: 965 | escape-string-regexp: 1.0.5 966 | dev: true 967 | engines: 968 | node: '>=8' 969 | resolution: 970 | integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== 971 | /file-entry-cache/5.0.1: 972 | dependencies: 973 | flat-cache: 2.0.1 974 | dev: true 975 | engines: 976 | node: '>=4' 977 | resolution: 978 | integrity: sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== 979 | /finalhandler/1.2.0: 980 | dependencies: 981 | debug: 2.6.9 982 | encodeurl: 1.0.2 983 | escape-html: 1.0.3 984 | on-finished: 2.4.1 985 | parseurl: 1.3.3 986 | statuses: 2.0.1 987 | unpipe: 1.0.0 988 | dev: false 989 | engines: 990 | node: '>= 0.8' 991 | resolution: 992 | integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== 993 | /find-up/2.1.0: 994 | dependencies: 995 | locate-path: 2.0.0 996 | dev: true 997 | engines: 998 | node: '>=4' 999 | resolution: 1000 | integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c= 1001 | /flat-cache/2.0.1: 1002 | dependencies: 1003 | flatted: 2.0.2 1004 | rimraf: 2.6.3 1005 | write: 1.0.3 1006 | dev: true 1007 | engines: 1008 | node: '>=4' 1009 | resolution: 1010 | integrity: sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== 1011 | /flatted/2.0.2: 1012 | dev: true 1013 | resolution: 1014 | integrity: sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== 1015 | /follow-redirects/1.15.0: 1016 | dev: false 1017 | engines: 1018 | node: '>=4.0' 1019 | resolution: 1020 | integrity: sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ== 1021 | /form-data/2.5.1: 1022 | dependencies: 1023 | asynckit: 0.4.0 1024 | combined-stream: 1.0.8 1025 | mime-types: 2.1.35 1026 | dev: false 1027 | engines: 1028 | node: '>= 0.12' 1029 | resolution: 1030 | integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== 1031 | /form-data/4.0.0: 1032 | dependencies: 1033 | asynckit: 0.4.0 1034 | combined-stream: 1.0.8 1035 | mime-types: 2.1.35 1036 | dev: false 1037 | engines: 1038 | node: '>= 6' 1039 | resolution: 1040 | integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== 1041 | /forwarded/0.2.0: 1042 | dev: false 1043 | engines: 1044 | node: '>= 0.6' 1045 | resolution: 1046 | integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== 1047 | /fresh/0.5.2: 1048 | dev: false 1049 | engines: 1050 | node: '>= 0.6' 1051 | resolution: 1052 | integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 1053 | /fs.realpath/1.0.0: 1054 | dev: true 1055 | resolution: 1056 | integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 1057 | /function-bind/1.1.1: 1058 | resolution: 1059 | integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 1060 | /function.prototype.name/1.1.5: 1061 | dependencies: 1062 | call-bind: 1.0.2 1063 | define-properties: 1.1.4 1064 | es-abstract: 1.20.0 1065 | functions-have-names: 1.2.3 1066 | engines: 1067 | node: '>= 0.4' 1068 | resolution: 1069 | integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== 1070 | /functional-red-black-tree/1.0.1: 1071 | dev: true 1072 | resolution: 1073 | integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= 1074 | /functions-have-names/1.2.3: 1075 | resolution: 1076 | integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== 1077 | /get-intrinsic/1.1.1: 1078 | dependencies: 1079 | function-bind: 1.1.1 1080 | has: 1.0.3 1081 | has-symbols: 1.0.3 1082 | resolution: 1083 | integrity: sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== 1084 | /get-symbol-description/1.0.0: 1085 | dependencies: 1086 | call-bind: 1.0.2 1087 | get-intrinsic: 1.1.1 1088 | engines: 1089 | node: '>= 0.4' 1090 | resolution: 1091 | integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== 1092 | /glob-parent/5.1.2: 1093 | dependencies: 1094 | is-glob: 4.0.3 1095 | dev: true 1096 | engines: 1097 | node: '>= 6' 1098 | resolution: 1099 | integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 1100 | /glob/7.2.0: 1101 | dependencies: 1102 | fs.realpath: 1.0.0 1103 | inflight: 1.0.6 1104 | inherits: 2.0.4 1105 | minimatch: 3.1.2 1106 | once: 1.4.0 1107 | path-is-absolute: 1.0.1 1108 | dev: true 1109 | resolution: 1110 | integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== 1111 | /globals/12.4.0: 1112 | dependencies: 1113 | type-fest: 0.8.1 1114 | dev: true 1115 | engines: 1116 | node: '>=8' 1117 | resolution: 1118 | integrity: sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== 1119 | /graceful-fs/4.2.10: 1120 | dev: false 1121 | resolution: 1122 | integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== 1123 | /has-bigints/1.0.2: 1124 | resolution: 1125 | integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== 1126 | /has-flag/3.0.0: 1127 | dev: true 1128 | engines: 1129 | node: '>=4' 1130 | resolution: 1131 | integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 1132 | /has-flag/4.0.0: 1133 | dev: true 1134 | engines: 1135 | node: '>=8' 1136 | resolution: 1137 | integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 1138 | /has-property-descriptors/1.0.0: 1139 | dependencies: 1140 | get-intrinsic: 1.1.1 1141 | resolution: 1142 | integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== 1143 | /has-symbols/1.0.3: 1144 | engines: 1145 | node: '>= 0.4' 1146 | resolution: 1147 | integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== 1148 | /has-tostringtag/1.0.0: 1149 | dependencies: 1150 | has-symbols: 1.0.3 1151 | engines: 1152 | node: '>= 0.4' 1153 | resolution: 1154 | integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== 1155 | /has/1.0.3: 1156 | dependencies: 1157 | function-bind: 1.1.1 1158 | engines: 1159 | node: '>= 0.4.0' 1160 | resolution: 1161 | integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 1162 | /htmlparser2/6.1.0: 1163 | dependencies: 1164 | domelementtype: 2.3.0 1165 | domhandler: 4.3.1 1166 | domutils: 2.8.0 1167 | entities: 2.2.0 1168 | dev: false 1169 | resolution: 1170 | integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== 1171 | /http-errors/2.0.0: 1172 | dependencies: 1173 | depd: 2.0.0 1174 | inherits: 2.0.4 1175 | setprototypeof: 1.2.0 1176 | statuses: 2.0.1 1177 | toidentifier: 1.0.1 1178 | dev: false 1179 | engines: 1180 | node: '>= 0.8' 1181 | resolution: 1182 | integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== 1183 | /iconv-lite/0.4.24: 1184 | dependencies: 1185 | safer-buffer: 2.1.2 1186 | engines: 1187 | node: '>=0.10.0' 1188 | resolution: 1189 | integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 1190 | /ignore/4.0.6: 1191 | dev: true 1192 | engines: 1193 | node: '>= 4' 1194 | resolution: 1195 | integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== 1196 | /import-fresh/3.3.0: 1197 | dependencies: 1198 | parent-module: 1.0.1 1199 | resolve-from: 4.0.0 1200 | dev: true 1201 | engines: 1202 | node: '>=6' 1203 | resolution: 1204 | integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== 1205 | /imurmurhash/0.1.4: 1206 | dev: true 1207 | engines: 1208 | node: '>=0.8.19' 1209 | resolution: 1210 | integrity: sha1-khi5srkoojixPcT7a21XbyMUU+o= 1211 | /inflight/1.0.6: 1212 | dependencies: 1213 | once: 1.4.0 1214 | wrappy: 1.0.2 1215 | dev: true 1216 | resolution: 1217 | integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 1218 | /inherits/2.0.4: 1219 | resolution: 1220 | integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 1221 | /inquirer/7.3.3: 1222 | dependencies: 1223 | ansi-escapes: 4.3.2 1224 | chalk: 4.1.2 1225 | cli-cursor: 3.1.0 1226 | cli-width: 3.0.0 1227 | external-editor: 3.1.0 1228 | figures: 3.2.0 1229 | lodash: 4.17.21 1230 | mute-stream: 0.0.8 1231 | run-async: 2.4.1 1232 | rxjs: 6.6.7 1233 | string-width: 4.2.3 1234 | strip-ansi: 6.0.1 1235 | through: 2.3.8 1236 | dev: true 1237 | engines: 1238 | node: '>=8.0.0' 1239 | resolution: 1240 | integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== 1241 | /internal-slot/1.0.3: 1242 | dependencies: 1243 | get-intrinsic: 1.1.1 1244 | has: 1.0.3 1245 | side-channel: 1.0.4 1246 | engines: 1247 | node: '>= 0.4' 1248 | resolution: 1249 | integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== 1250 | /ipaddr.js/1.9.1: 1251 | dev: false 1252 | engines: 1253 | node: '>= 0.10' 1254 | resolution: 1255 | integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== 1256 | /is-arguments/1.1.1: 1257 | dependencies: 1258 | call-bind: 1.0.2 1259 | has-tostringtag: 1.0.0 1260 | dev: false 1261 | engines: 1262 | node: '>= 0.4' 1263 | resolution: 1264 | integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== 1265 | /is-bigint/1.0.4: 1266 | dependencies: 1267 | has-bigints: 1.0.2 1268 | resolution: 1269 | integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== 1270 | /is-boolean-object/1.1.2: 1271 | dependencies: 1272 | call-bind: 1.0.2 1273 | has-tostringtag: 1.0.0 1274 | engines: 1275 | node: '>= 0.4' 1276 | resolution: 1277 | integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== 1278 | /is-callable/1.2.4: 1279 | engines: 1280 | node: '>= 0.4' 1281 | resolution: 1282 | integrity: sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== 1283 | /is-core-module/2.9.0: 1284 | dependencies: 1285 | has: 1.0.3 1286 | dev: true 1287 | resolution: 1288 | integrity: sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== 1289 | /is-date-object/1.0.5: 1290 | dependencies: 1291 | has-tostringtag: 1.0.0 1292 | engines: 1293 | node: '>= 0.4' 1294 | resolution: 1295 | integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== 1296 | /is-extglob/2.1.1: 1297 | dev: true 1298 | engines: 1299 | node: '>=0.10.0' 1300 | resolution: 1301 | integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 1302 | /is-fullwidth-code-point/2.0.0: 1303 | dev: true 1304 | engines: 1305 | node: '>=4' 1306 | resolution: 1307 | integrity: sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 1308 | /is-fullwidth-code-point/3.0.0: 1309 | dev: true 1310 | engines: 1311 | node: '>=8' 1312 | resolution: 1313 | integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 1314 | /is-glob/4.0.3: 1315 | dependencies: 1316 | is-extglob: 2.1.1 1317 | dev: true 1318 | engines: 1319 | node: '>=0.10.0' 1320 | resolution: 1321 | integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 1322 | /is-map/2.0.2: 1323 | dev: false 1324 | resolution: 1325 | integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== 1326 | /is-negative-zero/2.0.2: 1327 | engines: 1328 | node: '>= 0.4' 1329 | resolution: 1330 | integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== 1331 | /is-number-object/1.0.7: 1332 | dependencies: 1333 | has-tostringtag: 1.0.0 1334 | engines: 1335 | node: '>= 0.4' 1336 | resolution: 1337 | integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== 1338 | /is-promise/2.2.2: 1339 | dev: false 1340 | resolution: 1341 | integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== 1342 | /is-regex/1.1.4: 1343 | dependencies: 1344 | call-bind: 1.0.2 1345 | has-tostringtag: 1.0.0 1346 | engines: 1347 | node: '>= 0.4' 1348 | resolution: 1349 | integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== 1350 | /is-set/2.0.2: 1351 | dev: false 1352 | resolution: 1353 | integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== 1354 | /is-shared-array-buffer/1.0.2: 1355 | dependencies: 1356 | call-bind: 1.0.2 1357 | resolution: 1358 | integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== 1359 | /is-stream/1.1.0: 1360 | dev: false 1361 | engines: 1362 | node: '>=0.10.0' 1363 | resolution: 1364 | integrity: sha1-EtSj3U5o4Lec6428hBc66A2RykQ= 1365 | /is-string/1.0.7: 1366 | dependencies: 1367 | has-tostringtag: 1.0.0 1368 | engines: 1369 | node: '>= 0.4' 1370 | resolution: 1371 | integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== 1372 | /is-symbol/1.0.4: 1373 | dependencies: 1374 | has-symbols: 1.0.3 1375 | engines: 1376 | node: '>= 0.4' 1377 | resolution: 1378 | integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== 1379 | /is-weakref/1.0.2: 1380 | dependencies: 1381 | call-bind: 1.0.2 1382 | resolution: 1383 | integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== 1384 | /isarray/2.0.5: 1385 | dev: false 1386 | resolution: 1387 | integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== 1388 | /isexe/2.0.0: 1389 | dev: true 1390 | resolution: 1391 | integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 1392 | /iterate-iterator/1.0.2: 1393 | dev: false 1394 | resolution: 1395 | integrity: sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw== 1396 | /iterate-value/1.0.2: 1397 | dependencies: 1398 | es-get-iterator: 1.1.2 1399 | iterate-iterator: 1.0.2 1400 | dev: false 1401 | resolution: 1402 | integrity: sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ== 1403 | /js-tokens/4.0.0: 1404 | dev: true 1405 | resolution: 1406 | integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 1407 | /js-yaml/3.14.1: 1408 | dependencies: 1409 | argparse: 1.0.10 1410 | esprima: 4.0.1 1411 | dev: true 1412 | hasBin: true 1413 | resolution: 1414 | integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== 1415 | /json-schema-traverse/0.4.1: 1416 | dev: true 1417 | resolution: 1418 | integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 1419 | /json-stable-stringify-without-jsonify/1.0.1: 1420 | dev: true 1421 | resolution: 1422 | integrity: sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= 1423 | /json5/1.0.1: 1424 | dependencies: 1425 | minimist: 1.2.6 1426 | dev: true 1427 | hasBin: true 1428 | resolution: 1429 | integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== 1430 | /jsonwebtoken/8.5.1: 1431 | dependencies: 1432 | jws: 3.2.2 1433 | lodash.includes: 4.3.0 1434 | lodash.isboolean: 3.0.3 1435 | lodash.isinteger: 4.0.4 1436 | lodash.isnumber: 3.0.3 1437 | lodash.isplainobject: 4.0.6 1438 | lodash.isstring: 4.0.1 1439 | lodash.once: 4.1.1 1440 | ms: 2.1.3 1441 | semver: 5.7.1 1442 | dev: false 1443 | engines: 1444 | node: '>=4' 1445 | npm: '>=1.4.28' 1446 | resolution: 1447 | integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== 1448 | /jwa/1.4.1: 1449 | dependencies: 1450 | buffer-equal-constant-time: 1.0.1 1451 | ecdsa-sig-formatter: 1.0.11 1452 | safe-buffer: 5.2.1 1453 | dev: false 1454 | resolution: 1455 | integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== 1456 | /jws/3.2.2: 1457 | dependencies: 1458 | jwa: 1.4.1 1459 | safe-buffer: 5.2.1 1460 | dev: false 1461 | resolution: 1462 | integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== 1463 | /levn/0.3.0: 1464 | dependencies: 1465 | prelude-ls: 1.1.2 1466 | type-check: 0.3.2 1467 | dev: true 1468 | engines: 1469 | node: '>= 0.8.0' 1470 | resolution: 1471 | integrity: sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= 1472 | /locate-path/2.0.0: 1473 | dependencies: 1474 | p-locate: 2.0.0 1475 | path-exists: 3.0.0 1476 | dev: true 1477 | engines: 1478 | node: '>=4' 1479 | resolution: 1480 | integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= 1481 | /lodash.includes/4.3.0: 1482 | dev: false 1483 | resolution: 1484 | integrity: sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= 1485 | /lodash.isboolean/3.0.3: 1486 | dev: false 1487 | resolution: 1488 | integrity: sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= 1489 | /lodash.isinteger/4.0.4: 1490 | dev: false 1491 | resolution: 1492 | integrity: sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= 1493 | /lodash.isnumber/3.0.3: 1494 | dev: false 1495 | resolution: 1496 | integrity: sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= 1497 | /lodash.isplainobject/4.0.6: 1498 | dev: false 1499 | resolution: 1500 | integrity: sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= 1501 | /lodash.isstring/4.0.1: 1502 | dev: false 1503 | resolution: 1504 | integrity: sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= 1505 | /lodash.once/4.1.1: 1506 | dev: false 1507 | resolution: 1508 | integrity: sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= 1509 | /lodash/4.17.21: 1510 | resolution: 1511 | integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 1512 | /lowdb/1.0.0: 1513 | dependencies: 1514 | graceful-fs: 4.2.10 1515 | is-promise: 2.2.2 1516 | lodash: 4.17.21 1517 | pify: 3.0.0 1518 | steno: 0.4.4 1519 | dev: false 1520 | engines: 1521 | node: '>=4' 1522 | resolution: 1523 | integrity: sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ== 1524 | /media-typer/0.3.0: 1525 | dev: false 1526 | engines: 1527 | node: '>= 0.6' 1528 | resolution: 1529 | integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 1530 | /merge-descriptors/1.0.1: 1531 | dev: false 1532 | resolution: 1533 | integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 1534 | /methods/1.1.2: 1535 | dev: false 1536 | engines: 1537 | node: '>= 0.6' 1538 | resolution: 1539 | integrity: sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 1540 | /mime-db/1.52.0: 1541 | dev: false 1542 | engines: 1543 | node: '>= 0.6' 1544 | resolution: 1545 | integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 1546 | /mime-types/2.1.35: 1547 | dependencies: 1548 | mime-db: 1.52.0 1549 | dev: false 1550 | engines: 1551 | node: '>= 0.6' 1552 | resolution: 1553 | integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 1554 | /mime/1.6.0: 1555 | dev: false 1556 | engines: 1557 | node: '>=4' 1558 | hasBin: true 1559 | resolution: 1560 | integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 1561 | /mimic-fn/2.1.0: 1562 | dev: true 1563 | engines: 1564 | node: '>=6' 1565 | resolution: 1566 | integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== 1567 | /minimatch/3.1.2: 1568 | dependencies: 1569 | brace-expansion: 1.1.11 1570 | dev: true 1571 | resolution: 1572 | integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 1573 | /minimist/1.2.6: 1574 | dev: true 1575 | resolution: 1576 | integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== 1577 | /mkdirp/0.5.6: 1578 | dependencies: 1579 | minimist: 1.2.6 1580 | dev: true 1581 | hasBin: true 1582 | resolution: 1583 | integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== 1584 | /ms/2.0.0: 1585 | resolution: 1586 | integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 1587 | /ms/2.1.2: 1588 | dev: true 1589 | resolution: 1590 | integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 1591 | /ms/2.1.3: 1592 | resolution: 1593 | integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 1594 | /mute-stream/0.0.8: 1595 | dev: true 1596 | resolution: 1597 | integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== 1598 | /natural-compare/1.4.0: 1599 | dev: true 1600 | resolution: 1601 | integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= 1602 | /negotiator/0.6.3: 1603 | dev: false 1604 | engines: 1605 | node: '>= 0.6' 1606 | resolution: 1607 | integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== 1608 | /nice-try/1.0.5: 1609 | dev: true 1610 | resolution: 1611 | integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== 1612 | /nth-check/2.0.1: 1613 | dependencies: 1614 | boolbase: 1.0.0 1615 | dev: false 1616 | resolution: 1617 | integrity: sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== 1618 | /object-inspect/1.12.0: 1619 | resolution: 1620 | integrity: sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== 1621 | /object-keys/1.1.1: 1622 | engines: 1623 | node: '>= 0.4' 1624 | resolution: 1625 | integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 1626 | /object.assign/4.1.2: 1627 | dependencies: 1628 | call-bind: 1.0.2 1629 | define-properties: 1.1.4 1630 | has-symbols: 1.0.3 1631 | object-keys: 1.1.1 1632 | engines: 1633 | node: '>= 0.4' 1634 | resolution: 1635 | integrity: sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== 1636 | /object.entries/1.1.5: 1637 | dependencies: 1638 | call-bind: 1.0.2 1639 | define-properties: 1.1.4 1640 | es-abstract: 1.20.0 1641 | dev: true 1642 | engines: 1643 | node: '>= 0.4' 1644 | resolution: 1645 | integrity: sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== 1646 | /object.values/1.1.5: 1647 | dependencies: 1648 | call-bind: 1.0.2 1649 | define-properties: 1.1.4 1650 | es-abstract: 1.20.0 1651 | dev: true 1652 | engines: 1653 | node: '>= 0.4' 1654 | resolution: 1655 | integrity: sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== 1656 | /on-finished/2.4.1: 1657 | dependencies: 1658 | ee-first: 1.1.1 1659 | dev: false 1660 | engines: 1661 | node: '>= 0.8' 1662 | resolution: 1663 | integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== 1664 | /once/1.4.0: 1665 | dependencies: 1666 | wrappy: 1.0.2 1667 | dev: true 1668 | resolution: 1669 | integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 1670 | /onetime/5.1.2: 1671 | dependencies: 1672 | mimic-fn: 2.1.0 1673 | dev: true 1674 | engines: 1675 | node: '>=6' 1676 | resolution: 1677 | integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== 1678 | /optionator/0.8.3: 1679 | dependencies: 1680 | deep-is: 0.1.4 1681 | fast-levenshtein: 2.0.6 1682 | levn: 0.3.0 1683 | prelude-ls: 1.1.2 1684 | type-check: 0.3.2 1685 | word-wrap: 1.2.3 1686 | dev: true 1687 | engines: 1688 | node: '>= 0.8.0' 1689 | resolution: 1690 | integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== 1691 | /os-tmpdir/1.0.2: 1692 | dev: true 1693 | engines: 1694 | node: '>=0.10.0' 1695 | resolution: 1696 | integrity: sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= 1697 | /p-finally/1.0.0: 1698 | dev: false 1699 | engines: 1700 | node: '>=4' 1701 | resolution: 1702 | integrity: sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= 1703 | /p-limit/1.3.0: 1704 | dependencies: 1705 | p-try: 1.0.0 1706 | dev: true 1707 | engines: 1708 | node: '>=4' 1709 | resolution: 1710 | integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== 1711 | /p-locate/2.0.0: 1712 | dependencies: 1713 | p-limit: 1.3.0 1714 | dev: true 1715 | engines: 1716 | node: '>=4' 1717 | resolution: 1718 | integrity: sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= 1719 | /p-queue/6.6.2: 1720 | dependencies: 1721 | eventemitter3: 4.0.7 1722 | p-timeout: 3.2.0 1723 | dev: false 1724 | engines: 1725 | node: '>=8' 1726 | resolution: 1727 | integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== 1728 | /p-retry/4.6.2: 1729 | dependencies: 1730 | '@types/retry': 0.12.0 1731 | retry: 0.13.1 1732 | dev: false 1733 | engines: 1734 | node: '>=8' 1735 | resolution: 1736 | integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== 1737 | /p-timeout/3.2.0: 1738 | dependencies: 1739 | p-finally: 1.0.0 1740 | dev: false 1741 | engines: 1742 | node: '>=8' 1743 | resolution: 1744 | integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== 1745 | /p-try/1.0.0: 1746 | dev: true 1747 | engines: 1748 | node: '>=4' 1749 | resolution: 1750 | integrity: sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= 1751 | /parent-module/1.0.1: 1752 | dependencies: 1753 | callsites: 3.1.0 1754 | dev: true 1755 | engines: 1756 | node: '>=6' 1757 | resolution: 1758 | integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== 1759 | /parse5-htmlparser2-tree-adapter/6.0.1: 1760 | dependencies: 1761 | parse5: 6.0.1 1762 | dev: false 1763 | resolution: 1764 | integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== 1765 | /parse5/6.0.1: 1766 | dev: false 1767 | resolution: 1768 | integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== 1769 | /parseurl/1.3.3: 1770 | dev: false 1771 | engines: 1772 | node: '>= 0.8' 1773 | resolution: 1774 | integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 1775 | /path-exists/3.0.0: 1776 | dev: true 1777 | engines: 1778 | node: '>=4' 1779 | resolution: 1780 | integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= 1781 | /path-is-absolute/1.0.1: 1782 | dev: true 1783 | engines: 1784 | node: '>=0.10.0' 1785 | resolution: 1786 | integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 1787 | /path-key/2.0.1: 1788 | dev: true 1789 | engines: 1790 | node: '>=4' 1791 | resolution: 1792 | integrity: sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= 1793 | /path-parse/1.0.7: 1794 | dev: true 1795 | resolution: 1796 | integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 1797 | /path-to-regexp/0.1.7: 1798 | dev: false 1799 | resolution: 1800 | integrity: sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 1801 | /pify/3.0.0: 1802 | dev: false 1803 | engines: 1804 | node: '>=4' 1805 | resolution: 1806 | integrity: sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= 1807 | /please-upgrade-node/3.2.0: 1808 | dependencies: 1809 | semver-compare: 1.0.0 1810 | dev: false 1811 | resolution: 1812 | integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== 1813 | /prelude-ls/1.1.2: 1814 | dev: true 1815 | engines: 1816 | node: '>= 0.8.0' 1817 | resolution: 1818 | integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= 1819 | /progress/2.0.3: 1820 | dev: true 1821 | engines: 1822 | node: '>=0.4.0' 1823 | resolution: 1824 | integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== 1825 | /promise.allsettled/1.0.5: 1826 | dependencies: 1827 | array.prototype.map: 1.0.4 1828 | call-bind: 1.0.2 1829 | define-properties: 1.1.4 1830 | es-abstract: 1.20.0 1831 | get-intrinsic: 1.1.1 1832 | iterate-value: 1.0.2 1833 | dev: false 1834 | engines: 1835 | node: '>= 0.4' 1836 | resolution: 1837 | integrity: sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ== 1838 | /proxy-addr/2.0.7: 1839 | dependencies: 1840 | forwarded: 0.2.0 1841 | ipaddr.js: 1.9.1 1842 | dev: false 1843 | engines: 1844 | node: '>= 0.10' 1845 | resolution: 1846 | integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== 1847 | /punycode/2.1.1: 1848 | dev: true 1849 | engines: 1850 | node: '>=6' 1851 | resolution: 1852 | integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 1853 | /qs/6.10.3: 1854 | dependencies: 1855 | side-channel: 1.0.4 1856 | dev: false 1857 | engines: 1858 | node: '>=0.6' 1859 | resolution: 1860 | integrity: sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== 1861 | /range-parser/1.2.1: 1862 | dev: false 1863 | engines: 1864 | node: '>= 0.6' 1865 | resolution: 1866 | integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 1867 | /raw-body/2.5.1: 1868 | dependencies: 1869 | bytes: 3.1.2 1870 | http-errors: 2.0.0 1871 | iconv-lite: 0.4.24 1872 | unpipe: 1.0.0 1873 | dev: false 1874 | engines: 1875 | node: '>= 0.8' 1876 | resolution: 1877 | integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== 1878 | /regexp.prototype.flags/1.4.3: 1879 | dependencies: 1880 | call-bind: 1.0.2 1881 | define-properties: 1.1.4 1882 | functions-have-names: 1.2.3 1883 | engines: 1884 | node: '>= 0.4' 1885 | resolution: 1886 | integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== 1887 | /regexpp/2.0.1: 1888 | dev: true 1889 | engines: 1890 | node: '>=6.5.0' 1891 | resolution: 1892 | integrity: sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== 1893 | /resolve-from/4.0.0: 1894 | dev: true 1895 | engines: 1896 | node: '>=4' 1897 | resolution: 1898 | integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== 1899 | /resolve/1.22.0: 1900 | dependencies: 1901 | is-core-module: 2.9.0 1902 | path-parse: 1.0.7 1903 | supports-preserve-symlinks-flag: 1.0.0 1904 | dev: true 1905 | hasBin: true 1906 | resolution: 1907 | integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== 1908 | /restore-cursor/3.1.0: 1909 | dependencies: 1910 | onetime: 5.1.2 1911 | signal-exit: 3.0.7 1912 | dev: true 1913 | engines: 1914 | node: '>=8' 1915 | resolution: 1916 | integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== 1917 | /retry/0.13.1: 1918 | dev: false 1919 | engines: 1920 | node: '>= 4' 1921 | resolution: 1922 | integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== 1923 | /rimraf/2.6.3: 1924 | dependencies: 1925 | glob: 7.2.0 1926 | dev: true 1927 | hasBin: true 1928 | resolution: 1929 | integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== 1930 | /run-async/2.4.1: 1931 | dev: true 1932 | engines: 1933 | node: '>=0.12.0' 1934 | resolution: 1935 | integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== 1936 | /rxjs/6.6.7: 1937 | dependencies: 1938 | tslib: 1.14.1 1939 | dev: true 1940 | engines: 1941 | npm: '>=2.0.0' 1942 | resolution: 1943 | integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== 1944 | /safe-buffer/5.2.1: 1945 | dev: false 1946 | resolution: 1947 | integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1948 | /safer-buffer/2.1.2: 1949 | resolution: 1950 | integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 1951 | /semver-compare/1.0.0: 1952 | dev: false 1953 | resolution: 1954 | integrity: sha1-De4hahyUGrN+nvsXiPavxf9VN/w= 1955 | /semver/5.7.1: 1956 | hasBin: true 1957 | resolution: 1958 | integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1959 | /semver/6.3.0: 1960 | dev: true 1961 | hasBin: true 1962 | resolution: 1963 | integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== 1964 | /send/0.18.0: 1965 | dependencies: 1966 | debug: 2.6.9 1967 | depd: 2.0.0 1968 | destroy: 1.2.0 1969 | encodeurl: 1.0.2 1970 | escape-html: 1.0.3 1971 | etag: 1.8.1 1972 | fresh: 0.5.2 1973 | http-errors: 2.0.0 1974 | mime: 1.6.0 1975 | ms: 2.1.3 1976 | on-finished: 2.4.1 1977 | range-parser: 1.2.1 1978 | statuses: 2.0.1 1979 | dev: false 1980 | engines: 1981 | node: '>= 0.8.0' 1982 | resolution: 1983 | integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== 1984 | /serve-static/1.15.0: 1985 | dependencies: 1986 | encodeurl: 1.0.2 1987 | escape-html: 1.0.3 1988 | parseurl: 1.3.3 1989 | send: 0.18.0 1990 | dev: false 1991 | engines: 1992 | node: '>= 0.8.0' 1993 | resolution: 1994 | integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== 1995 | /setprototypeof/1.2.0: 1996 | dev: false 1997 | resolution: 1998 | integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== 1999 | /shebang-command/1.2.0: 2000 | dependencies: 2001 | shebang-regex: 1.0.0 2002 | dev: true 2003 | engines: 2004 | node: '>=0.10.0' 2005 | resolution: 2006 | integrity: sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= 2007 | /shebang-regex/1.0.0: 2008 | dev: true 2009 | engines: 2010 | node: '>=0.10.0' 2011 | resolution: 2012 | integrity: sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= 2013 | /side-channel/1.0.4: 2014 | dependencies: 2015 | call-bind: 1.0.2 2016 | get-intrinsic: 1.1.1 2017 | object-inspect: 1.12.0 2018 | resolution: 2019 | integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== 2020 | /signal-exit/3.0.7: 2021 | dev: true 2022 | resolution: 2023 | integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== 2024 | /slice-ansi/2.1.0: 2025 | dependencies: 2026 | ansi-styles: 3.2.1 2027 | astral-regex: 1.0.0 2028 | is-fullwidth-code-point: 2.0.0 2029 | dev: true 2030 | engines: 2031 | node: '>=6' 2032 | resolution: 2033 | integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== 2034 | /sprintf-js/1.0.3: 2035 | dev: true 2036 | resolution: 2037 | integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 2038 | /statuses/2.0.1: 2039 | dev: false 2040 | engines: 2041 | node: '>= 0.8' 2042 | resolution: 2043 | integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== 2044 | /steno/0.4.4: 2045 | dependencies: 2046 | graceful-fs: 4.2.10 2047 | dev: false 2048 | resolution: 2049 | integrity: sha1-BxEFvfwobmYVwEA8J+nXtdy4Vcs= 2050 | /string-width/3.1.0: 2051 | dependencies: 2052 | emoji-regex: 7.0.3 2053 | is-fullwidth-code-point: 2.0.0 2054 | strip-ansi: 5.2.0 2055 | dev: true 2056 | engines: 2057 | node: '>=6' 2058 | resolution: 2059 | integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 2060 | /string-width/4.2.3: 2061 | dependencies: 2062 | emoji-regex: 8.0.0 2063 | is-fullwidth-code-point: 3.0.0 2064 | strip-ansi: 6.0.1 2065 | dev: true 2066 | engines: 2067 | node: '>=8' 2068 | resolution: 2069 | integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 2070 | /string.prototype.trimend/1.0.5: 2071 | dependencies: 2072 | call-bind: 1.0.2 2073 | define-properties: 1.1.4 2074 | es-abstract: 1.20.0 2075 | resolution: 2076 | integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog== 2077 | /string.prototype.trimstart/1.0.5: 2078 | dependencies: 2079 | call-bind: 1.0.2 2080 | define-properties: 1.1.4 2081 | es-abstract: 1.20.0 2082 | resolution: 2083 | integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg== 2084 | /strip-ansi/5.2.0: 2085 | dependencies: 2086 | ansi-regex: 4.1.1 2087 | dev: true 2088 | engines: 2089 | node: '>=6' 2090 | resolution: 2091 | integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 2092 | /strip-ansi/6.0.1: 2093 | dependencies: 2094 | ansi-regex: 5.0.1 2095 | dev: true 2096 | engines: 2097 | node: '>=8' 2098 | resolution: 2099 | integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 2100 | /strip-bom/3.0.0: 2101 | dev: true 2102 | engines: 2103 | node: '>=4' 2104 | resolution: 2105 | integrity: sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= 2106 | /strip-json-comments/3.1.1: 2107 | dev: true 2108 | engines: 2109 | node: '>=8' 2110 | resolution: 2111 | integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 2112 | /supports-color/5.5.0: 2113 | dependencies: 2114 | has-flag: 3.0.0 2115 | dev: true 2116 | engines: 2117 | node: '>=4' 2118 | resolution: 2119 | integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 2120 | /supports-color/7.2.0: 2121 | dependencies: 2122 | has-flag: 4.0.0 2123 | dev: true 2124 | engines: 2125 | node: '>=8' 2126 | resolution: 2127 | integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 2128 | /supports-preserve-symlinks-flag/1.0.0: 2129 | dev: true 2130 | engines: 2131 | node: '>= 0.4' 2132 | resolution: 2133 | integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 2134 | /table/5.4.6: 2135 | dependencies: 2136 | ajv: 6.12.6 2137 | lodash: 4.17.21 2138 | slice-ansi: 2.1.0 2139 | string-width: 3.1.0 2140 | dev: true 2141 | engines: 2142 | node: '>=6.0.0' 2143 | resolution: 2144 | integrity: sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== 2145 | /text-table/0.2.0: 2146 | dev: true 2147 | resolution: 2148 | integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= 2149 | /through/2.3.8: 2150 | dev: true 2151 | resolution: 2152 | integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= 2153 | /tmp/0.0.33: 2154 | dependencies: 2155 | os-tmpdir: 1.0.2 2156 | dev: true 2157 | engines: 2158 | node: '>=0.6.0' 2159 | resolution: 2160 | integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== 2161 | /toidentifier/1.0.1: 2162 | dev: false 2163 | engines: 2164 | node: '>=0.6' 2165 | resolution: 2166 | integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== 2167 | /tsconfig-paths/3.14.1: 2168 | dependencies: 2169 | '@types/json5': 0.0.29 2170 | json5: 1.0.1 2171 | minimist: 1.2.6 2172 | strip-bom: 3.0.0 2173 | dev: true 2174 | resolution: 2175 | integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== 2176 | /tslib/1.14.1: 2177 | dev: true 2178 | resolution: 2179 | integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== 2180 | /tslib/2.4.0: 2181 | dev: false 2182 | resolution: 2183 | integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== 2184 | /tsscmp/1.0.6: 2185 | dev: false 2186 | engines: 2187 | node: '>=0.6.x' 2188 | resolution: 2189 | integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA== 2190 | /type-check/0.3.2: 2191 | dependencies: 2192 | prelude-ls: 1.1.2 2193 | dev: true 2194 | engines: 2195 | node: '>= 0.8.0' 2196 | resolution: 2197 | integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= 2198 | /type-fest/0.21.3: 2199 | dev: true 2200 | engines: 2201 | node: '>=10' 2202 | resolution: 2203 | integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== 2204 | /type-fest/0.8.1: 2205 | dev: true 2206 | engines: 2207 | node: '>=8' 2208 | resolution: 2209 | integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== 2210 | /type-is/1.6.18: 2211 | dependencies: 2212 | media-typer: 0.3.0 2213 | mime-types: 2.1.35 2214 | dev: false 2215 | engines: 2216 | node: '>= 0.6' 2217 | resolution: 2218 | integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 2219 | /unbox-primitive/1.0.2: 2220 | dependencies: 2221 | call-bind: 1.0.2 2222 | has-bigints: 1.0.2 2223 | has-symbols: 1.0.3 2224 | which-boxed-primitive: 1.0.2 2225 | resolution: 2226 | integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== 2227 | /unpipe/1.0.0: 2228 | dev: false 2229 | engines: 2230 | node: '>= 0.8' 2231 | resolution: 2232 | integrity: sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 2233 | /uri-js/4.4.1: 2234 | dependencies: 2235 | punycode: 2.1.1 2236 | dev: true 2237 | resolution: 2238 | integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== 2239 | /utils-merge/1.0.1: 2240 | dev: false 2241 | engines: 2242 | node: '>= 0.4.0' 2243 | resolution: 2244 | integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 2245 | /v8-compile-cache/2.3.0: 2246 | dev: true 2247 | resolution: 2248 | integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== 2249 | /vary/1.1.2: 2250 | dev: false 2251 | engines: 2252 | node: '>= 0.8' 2253 | resolution: 2254 | integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 2255 | /which-boxed-primitive/1.0.2: 2256 | dependencies: 2257 | is-bigint: 1.0.4 2258 | is-boolean-object: 1.1.2 2259 | is-number-object: 1.0.7 2260 | is-string: 1.0.7 2261 | is-symbol: 1.0.4 2262 | resolution: 2263 | integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== 2264 | /which/1.3.1: 2265 | dependencies: 2266 | isexe: 2.0.0 2267 | dev: true 2268 | hasBin: true 2269 | resolution: 2270 | integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 2271 | /word-wrap/1.2.3: 2272 | dev: true 2273 | engines: 2274 | node: '>=0.10.0' 2275 | resolution: 2276 | integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== 2277 | /wrappy/1.0.2: 2278 | dev: true 2279 | resolution: 2280 | integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 2281 | /write/1.0.3: 2282 | dependencies: 2283 | mkdirp: 0.5.6 2284 | dev: true 2285 | engines: 2286 | node: '>=4' 2287 | resolution: 2288 | integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== 2289 | registry: 'https://registry.npmjs.org/' 2290 | shrinkwrapMinorVersion: 9 2291 | shrinkwrapVersion: 3 2292 | specifiers: 2293 | '@slack/bolt': ^2.6.1 2294 | axios: ^0.27.2 2295 | cheerio: ^1.0.0-rc.10 2296 | eslint: ^6.8.0 2297 | eslint-config-airbnb-base: ^14.2.1 2298 | eslint-plugin-import: ^2.26.0 2299 | lowdb: ^1.0.0 2300 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | verboseMode: process.env.VERBOSE_MODE === 'true', 3 | slackBotToken: process.env.SLACK_BOT_TOKEN, 4 | slackSigningSecret: process.env.SLACK_SIGNING_SECRET, 5 | orgToken: process.env.ORG_TOKEN, 6 | channelId: process.env.DEBUG_MODE === 'true' ? process.env.SANDBOX_CHANNEL_ID : process.env.DEFAULT_CHANNEL_ID, 7 | drupalOrganizationNodeId: process.env.DRUPAL_ORG_NODE_ID, 8 | drupalOrgBaseUrl: 'https://www.drupal.org', 9 | drupalOrgMarketplacePath: '/drupal-services', 10 | slackNotificationText: { 11 | primaryText: process.env.SLACK_NOTIFICATION_TEXT || 'Drupal.org Organization Statistics :zap:', 12 | trackedHighText: process.env.SLACK_NOTIFICATION_TRACKED_HIGH_TEXT || ':chart_with_upwards_trend: _An all-time tracked high_. :sports_medal:', 13 | trackedWeeklyIncreasingText: process.env.SLACK_NOTIFICATION_TRACKED_WEEKLY_INCREASING_TEXT || ':chart_with_upwards_trend: _Trending up from last week\'s count of_', 14 | trackedWeeklyDecreasingText: process.env.SLACK_NOTIFICATION_TRACKED_WEEKLY_DECREASING_TEXT || ':chart_with_downwards_trend: _Trending down from last week\'s count of_', 15 | downFromTrackedHighText: process.env.SLACK_NOTIFICATION_DOWN_FROM_TRACKED_HIGH_TEXT || ':chart_with_downwards_trend: Down from a tracked high of', 16 | }, 17 | keyValueDefaults: { 18 | weeklyTimestamp: 'org_data_weekly_timestamp', 19 | issueCreditCountMaxVarKey: 'org_issue_credit_count_max', 20 | issueCreditCountLastWeekVarKey: 'org_issue_credit_count_last_week', 21 | marketplaceRankMinVarKey: 'org_marketplace_rank_min', 22 | projectsSupportedMaxVarKey: 'org_projects_supported_max', 23 | caseStudiesPublishedMaxVarKey: 'org_case_studies_max', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /src/datastore.js: -------------------------------------------------------------------------------- 1 | const low = require('lowdb'); 2 | const FileSync = require('lowdb/adapters/FileSync'); 3 | const config = require('./config'); 4 | 5 | // Setup a new database. 6 | // Persisted using async file storage. 7 | // Security note: the database is saved to the file `db.json` on the local filesystem. 8 | // It's deliberately placed in the `.data` directory which doesn't get copied if 9 | // someone remixes the project. 10 | const adapter = new FileSync('.data/db.json'); 11 | const db = low(adapter); 12 | 13 | // Add "upsert" functionality to lowdb. 14 | // This checks if a value exists, update it if so, or inserts it if it does not. 15 | // @see https://github.com/typicode/lowdb/issues/348 16 | db._.mixin({ 17 | upsert: (collection, obj, key = 'id') => { 18 | for (let i = 0; i < collection.length; i += 1) { 19 | const el = collection[i]; 20 | if (el[key] === obj[key]) { 21 | // eslint-disable-next-line no-param-reassign 22 | collection[i] = obj; 23 | return collection; 24 | } 25 | } 26 | collection.push(obj); 27 | return collection; 28 | }, 29 | }); 30 | 31 | // Default data. 32 | db.defaults({ 33 | keyvalues: [ 34 | { name: config.keyValueDefaults.weeklyTimestamp, value: null }, 35 | { name: config.keyValueDefaults.issueCreditCountMaxVarKey, value: null }, 36 | { name: config.keyValueDefaults.issueCreditCountLastWeekVarKey, value: null }, 37 | { name: config.keyValueDefaults.marketplaceRankMinVarKey, value: null }, 38 | { name: config.keyValueDefaults.projectsSupportedMaxVarKey, value: null }, 39 | { name: config.keyValueDefaults.caseStudiesPublishedMaxVarKey, value: null }, 40 | ], 41 | }).write(); 42 | 43 | /** 44 | * Get variable from the lowdb datastore. 45 | * 46 | * @param {string} variableName 47 | * Variable name to retrieve. 48 | * @param {string} collectionName 49 | * Collection to retrieve the specified variable from. 50 | * @return {mixed} 51 | * The retrieved variable value. 52 | */ 53 | const variableGet = (variableName, collectionName = 'keyvalues') => { 54 | const retrievedVariable = db.get(collectionName).find({ name: variableName }); 55 | if (retrievedVariable.value() === undefined) { 56 | return null; 57 | } 58 | 59 | const { value } = retrievedVariable.value(); 60 | if (config.verboseMode) { 61 | console.log(`${variableName}: ${value}`); 62 | } 63 | return value; 64 | }; 65 | 66 | /** 67 | * Get variable from the lowdb datastore. 68 | * 69 | * @param {string} variableName 70 | * Name of the variable to save. 71 | * @param {string} variableValue 72 | * Value of the variable to save. 73 | * @param {string} collectionName 74 | * Name of the collection to save the variable to. 75 | */ 76 | const variableSet = (variableName, variableValue, collectionName = 'keyvalues') => { 77 | if (config.verboseMode) { 78 | console.log(`Updating ${variableName}: ${variableValue}`); 79 | } 80 | db.get(collectionName) 81 | .upsert({ name: variableName, value: variableValue }, 'name') 82 | .write(); 83 | }; 84 | 85 | module.exports = { 86 | variableGet, 87 | variableSet, 88 | }; 89 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | /* eslint-env es6 */ 2 | 3 | const { App, LogLevel, ExpressReceiver } = require('@slack/bolt'); 4 | const axios = require('axios'); 5 | const cheerio = require('cheerio'); 6 | 7 | const config = require('./config'); 8 | const datastore = require('./datastore'); 9 | 10 | const receiver = new ExpressReceiver({ 11 | signingSecret: process.env.SLACK_SIGNING_SECRET, 12 | }); 13 | const app = new App({ 14 | receiver, 15 | token: config.slackBotToken, 16 | logLevel: LogLevel.DEBUG, 17 | }); 18 | 19 | /** 20 | * Navigate Drupal.org marketplace pages until the specified organization is 21 | * found, then calculates the organization's rank and return it. 22 | * 23 | * @param {string} marketplaceUrl URL of marketplace URL to 24 | * search for the orgnization. 25 | * @param {int} rankCount A running counter for determining an organization's rank 26 | * across multiple pages. 27 | * 28 | * @return {object} An object containing the organization's marketplace rank 29 | * and the index of the page it was found on. 30 | */ 31 | function getDrupalMarketplaceData(marketplaceUrl, rankCount = 0) { 32 | return axios.get(marketplaceUrl) 33 | .then((marketplaceResponse) => { 34 | const html = marketplaceResponse.data; 35 | const $ = cheerio.load(html, { xmlMode: false }); 36 | const orgsOnPage = $('.view-drupalorg-organizations .view-content').children().length; 37 | const orgNodeHtmlElement = $(`#node-${config.drupalOrganizationNodeId}`); 38 | // Determine if the organization node id is listed on the current page. 39 | if (orgNodeHtmlElement.length) { 40 | // Find the position of the organization node id on the page. 41 | const foundRank = rankCount + orgNodeHtmlElement.parent().prevAll().length + 1; 42 | return { 43 | rank: foundRank, 44 | page: Math.floor(foundRank / orgsOnPage), 45 | }; 46 | } 47 | // The specified organization is not on the current page, go to the next page. 48 | const nextPageUrl = config.drupalOrgBaseUrl + $('.pager .pager-next a').attr('href'); 49 | const updatedRank = rankCount + orgsOnPage; 50 | return getDrupalMarketplaceData(nextPageUrl, updatedRank); 51 | }) 52 | .catch((error) => { 53 | console.error(error); 54 | }); 55 | } 56 | 57 | /** 58 | * Prepare Slack block payload with marketplace data. 59 | * 60 | * @param {object} marketplaceData Object containing organization 61 | * marketplace data including rank and page. 62 | * 63 | * @return {object} Slack payload block object. 64 | */ 65 | const marketplaceRankPayloadBlock = (marketplaceData) => { 66 | const { rank: marketplaceRank, page: marketplacePage } = marketplaceData; 67 | 68 | const marketplaceMin = datastore.variableGet(config.keyValueDefaults.marketplaceRankMinVarKey); 69 | if (marketplaceMin === null || marketplaceRank < marketplaceMin) { 70 | datastore.variableSet(config.keyValueDefaults.marketplaceRankMinVarKey, marketplaceRank); 71 | } 72 | 73 | const marketplaceTextBase = `:shopping_trolley: * rank: _${marketplaceRank}:_*`; 74 | const marketplaceText = marketplaceRank <= marketplaceMin 75 | ? `${marketplaceTextBase} ${config.slackNotificationText.trackedHighText}` 76 | : `${marketplaceTextBase} ${config.slackNotificationText.downFromTrackedHighText} _${marketplaceMin}_.`; 77 | return { 78 | type: 'section', 79 | text: { 80 | type: 'mrkdwn', 81 | text: marketplaceText, 82 | }, 83 | }; 84 | }; 85 | 86 | /** 87 | * Prepare Slack block payload with supported project data. 88 | * 89 | * @param {int} orgDrupalIssueCreditCountInt The number of credits attributed to the org. 90 | * @param {int} creditCountMax The highest number of credits tracked for the organization. 91 | * @param {int} creditCountLastWeek The number of credits attributed to the org last week. 92 | * 93 | * @return string Text payload for Slack message detailing credit counts. 94 | */ 95 | const creditCountText = (orgDrupalIssueCreditCountInt, creditCountMax, creditCountLastWeek) => { 96 | const creditCountTextBase = `:female-technologist: *Issue credit count: _${orgDrupalIssueCreditCountInt}:_*`; 97 | let creditText = `${creditCountTextBase}`; 98 | 99 | if (orgDrupalIssueCreditCountInt < creditCountLastWeek) { 100 | creditText += ` ${config.slackNotificationText.trackedWeeklyDecreasingText} _${creditCountLastWeek}._`; 101 | } else if (orgDrupalIssueCreditCountInt === creditCountLastWeek) { 102 | creditText += ' Holding steady from last week.'; 103 | } else { 104 | creditText += ` ${config.slackNotificationText.trackedWeeklyIncreasingText} _${creditCountLastWeek}._`; 105 | } 106 | if (orgDrupalIssueCreditCountInt < creditCountMax) { 107 | creditText += ` ${config.slackNotificationText.downFromTrackedHighText} _${creditCountMax}._`; 108 | } else { 109 | creditText += ` ${config.slackNotificationText.trackedHighText}`; 110 | } 111 | return creditText; 112 | }; 113 | 114 | /** 115 | * Prepare Slack block payload with issue credit data. 116 | * 117 | * @param {int} orgDrupalIssueCreditCount The number of issues credited to 118 | * an orgnization. 119 | * 120 | * @return {object} Slack payload block object. 121 | */ 122 | const issueCreditPayloadBlock = (orgDrupalIssueCreditCount) => { 123 | const orgDrupalIssueCreditCountInt = parseInt(orgDrupalIssueCreditCount, 10); 124 | const creditCountMax = parseInt( 125 | datastore.variableGet(config.keyValueDefaults.issueCreditCountMaxVarKey), 10, 126 | ); 127 | // If we don't have a record for issue credits, or the new value from the API is 128 | // larger, we have a new high; update the record. 129 | if (creditCountMax === null || orgDrupalIssueCreditCountInt > creditCountMax) { 130 | if (config.verboseMode) { 131 | console.log(`Updating creditCountMax to new value: ${orgDrupalIssueCreditCountInt}`); 132 | } 133 | 134 | datastore.variableSet( 135 | config.keyValueDefaults.issueCreditCountMaxVarKey, 136 | orgDrupalIssueCreditCountInt, 137 | ); 138 | } 139 | 140 | const creditCountLastWeek = parseInt( 141 | datastore.variableGet(config.keyValueDefaults.issueCreditCountLastWeekVarKey), 10, 142 | ); 143 | console.log(datastore.variableGet(config.keyValueDefaults.weeklyTimestamp)); 144 | const weeklyTimestamp = parseInt( 145 | datastore.variableGet(config.keyValueDefaults.weeklyTimestamp), 10, 146 | ) || 0; 147 | const currentDateTime = Date.now(); 148 | const lastStoredCheckPlusOneWeek = weeklyTimestamp + 604800; 149 | console.log(currentDateTime > lastStoredCheckPlusOneWeek); 150 | if (creditCountLastWeek === null || currentDateTime > lastStoredCheckPlusOneWeek) { 151 | if (config.verboseMode) { 152 | console.log(`Updating weeklyTimestamp to new value: ${currentDateTime}`); 153 | } 154 | 155 | datastore.variableSet( 156 | config.keyValueDefaults.weeklyTimestamp, 157 | currentDateTime, 158 | ); 159 | datastore.variableSet( 160 | config.keyValueDefaults.issueCreditCountLastWeekVarKey, 161 | orgDrupalIssueCreditCountInt, 162 | ); 163 | } 164 | 165 | const creditCountTextGenerated = creditCountText(orgDrupalIssueCreditCountInt, creditCountMax, 166 | creditCountLastWeek); 167 | return { 168 | type: 'section', 169 | text: { 170 | type: 'mrkdwn', 171 | text: creditCountTextGenerated, 172 | }, 173 | }; 174 | }; 175 | 176 | /** 177 | * Prepare Slack block payload with supported project data. 178 | * 179 | * @param {int} orgDrupalProjectsSupported The number of supported projects 180 | * credited to an organization. 181 | * 182 | * @return {object} Slack payload block object. 183 | */ 184 | const projectsSupportedPayloadBlock = (orgDrupalProjectsSupported) => { 185 | const projectsSupportedMax = datastore.variableGet( 186 | config.keyValueDefaults.projectsSupportedMaxVarKey, 187 | ); 188 | // If we don't have a record for projects supported, or the new value from the API is 189 | // larger, we have a new high; update the record. 190 | if (projectsSupportedMax === null || orgDrupalProjectsSupported > projectsSupportedMax) { 191 | datastore.variableSet( 192 | config.keyValueDefaults.projectsSupportedMaxVarKey, 193 | orgDrupalProjectsSupported, 194 | ); 195 | } 196 | 197 | const projectsSupportedTextBase = `:female-construction-worker: *Projects supported: _${orgDrupalProjectsSupported}:_*`; 198 | const projectsSupportedText = orgDrupalProjectsSupported < projectsSupportedMax 199 | ? `${projectsSupportedTextBase} ${config.slackNotificationText.downFromTrackedHighText} _${projectsSupportedMax}_.` 200 | : `${projectsSupportedTextBase} ${config.slackNotificationText.trackedHighText}`; 201 | return { 202 | type: 'section', 203 | text: { 204 | type: 'mrkdwn', 205 | text: projectsSupportedText, 206 | }, 207 | }; 208 | }; 209 | 210 | /** 211 | * Prepare Slack block payload with case study data. 212 | * 213 | * @param {int} caseStudiesCount The number of case studies credited to an 214 | * organization. 215 | * 216 | * @return {object} Slack payload block object. 217 | */ 218 | const caseStudiesPayloadBlock = (caseStudiesCount) => { 219 | const caseStudiesPublishedMax = datastore.variableGet( 220 | config.keyValueDefaults.caseStudiesPublishedMaxVarKey, 221 | ); 222 | // If we don't have a record for case studies, or the new value from the API is 223 | // larger, we have a new high; update the record. 224 | if (caseStudiesPublishedMax === null || caseStudiesCount > caseStudiesPublishedMax) { 225 | datastore.variableSet( 226 | config.keyValueDefaults.caseStudiesPublishedMaxVarKey, 227 | caseStudiesCount, 228 | ); 229 | } 230 | 231 | const caseStudiesTextBase = `:blue_book: *Case studies published: _${caseStudiesCount}:_*`; 232 | const caseStudiesText = caseStudiesCount < caseStudiesPublishedMax 233 | ? `${caseStudiesTextBase} ${config.slackNotificationText.downFromTrackedHighText} _${caseStudiesPublishedMax}_.` 234 | : `${caseStudiesTextBase} ${config.slackNotificationText.trackedHighText}`; 235 | return { 236 | type: 'section', 237 | text: { 238 | type: 'mrkdwn', 239 | text: caseStudiesText, 240 | }, 241 | }; 242 | }; 243 | 244 | /** 245 | * Compiles all payload blocks for inclusion in a Slack message attachment. 246 | * 247 | * @param {object} orgNode A drupal.org organization node object. 248 | * @param {object} marketplaceData The HTML contents of a Drupal.org 249 | * marketplace page. 250 | * @param {object} caseStudiesResponse Response data from Drupal.org's 251 | * API containing case studies. 252 | * 253 | * @return {object} An object containing multiple Slack Block Kit blocks to 254 | * attach to a message object. 255 | */ 256 | const drupalOrgPayloadBlocks = (orgNode, marketplaceData, caseStudiesResponse) => { 257 | const blocks = []; 258 | // Header. 259 | blocks.push({ 260 | type: 'section', 261 | text: { 262 | type: 'mrkdwn', 263 | text: config.slackNotificationText.primaryText, 264 | }, 265 | }); 266 | blocks.push({ 267 | type: 'divider', 268 | }); 269 | 270 | // Content. 271 | blocks.push(marketplaceRankPayloadBlock(marketplaceData)); 272 | blocks.push(issueCreditPayloadBlock(orgNode.field_org_issue_credit_count)); 273 | blocks.push(projectsSupportedPayloadBlock(orgNode.projects_supported.length)); 274 | blocks.push(caseStudiesPayloadBlock(caseStudiesResponse.list.length)); 275 | 276 | // Footer. 277 | blocks.push({ 278 | type: 'divider', 279 | }); 280 | blocks.push({ 281 | type: 'context', 282 | elements: [ 283 | { 284 | type: 'mrkdwn', 285 | text: `For more info, see ${orgNode.url}.`, 286 | }, 287 | ], 288 | }); 289 | return blocks; 290 | }; 291 | 292 | /** 293 | * Generate a Slack message payload object. 294 | * 295 | * @param {string} channelId A Slack channel ID. 296 | * @param {string} userId A user ID from the requesting Slack user, if 297 | * applicable. 298 | * @param {string} responseType A Slack message type, either 'in_channel', 299 | * or 'ephemeral'. 300 | * 301 | * @return {object} A fully completed object to send a message to Slack. 302 | */ 303 | const slackNotificationPayload = async (channelId, userId, responseType) => { 304 | const [orgNodeResponse, marketplaceData, caseStudiesResponse] = await Promise.all([ 305 | axios.get(`https://www.drupal.org/api-d7/node/${config.drupalOrganizationNodeId}.json`), 306 | getDrupalMarketplaceData(`${config.drupalOrgBaseUrl}${config.drupalOrgMarketplacePath}`), 307 | axios.get(`https://www.drupal.org/api-d7/node.json?type=casestudy&taxonomy_vocabulary_5=20236&field_case_organizations=${config.drupalOrganizationNodeId}`), 308 | ]); 309 | 310 | return { 311 | token: config.slackBotToken, 312 | channel: channelId, 313 | user: userId, 314 | response_type: responseType, 315 | text: '', 316 | attachments: [ 317 | { 318 | blocks: drupalOrgPayloadBlocks( 319 | orgNodeResponse.data, 320 | marketplaceData, 321 | caseStudiesResponse.data, 322 | ), 323 | }, 324 | ], 325 | }; 326 | }; 327 | 328 | /** 329 | * Generates a payload to send a descriptive error to Slack. 330 | * 331 | * @param {string} channelId A Slack channel ID. 332 | * @param {string} userId A user ID from the requesting Slack user, if 333 | * applicable. 334 | * @param {string} responseType A Slack message type, either 'in_channel', 335 | * or 'ephemeral'. 336 | * @param {string} error An error message. 337 | * 338 | * @return {object} A fully completed object to send a message to Slack. 339 | */ 340 | const slackErrorPayload = (channelId, userId, responseType, error) => { 341 | const payload = { 342 | token: config.slackBotToken, 343 | channel: channelId, 344 | user: userId, 345 | response_type: responseType, 346 | text: `An error has occurred: \`${error}\``, 347 | }; 348 | return payload; 349 | }; 350 | 351 | /** 352 | * Listens for a Slack 'slash' command. 353 | */ 354 | app.command('/dorank', async ({ command, ack, respond }) => { 355 | // Acknowledge Slack command request. 356 | await ack(); 357 | 358 | if (config.verboseMode) { 359 | console.log(command); 360 | } 361 | 362 | let payload; 363 | try { 364 | payload = await slackNotificationPayload(command.channel_id, command.user_id, 'ephemeral'); 365 | return await respond(payload); 366 | } catch (error) { 367 | console.error(error); 368 | payload = await slackErrorPayload(command.channel_id, command.user_id, 'ephemeral', error); 369 | return respond(payload).catch(console.error); 370 | } 371 | }); 372 | 373 | /** 374 | * Endpoint that listens for a trigger by a non-Slack event like a Jenkins job 375 | * for a weekly notification in the configured channel. 376 | */ 377 | receiver.app.post('/triggers', async (request, response, next) => { 378 | let status = 200; 379 | let message = 'OK'; 380 | 381 | if (request.query.token !== config.orgToken) { 382 | response.status(403); 383 | return response.send(); 384 | } 385 | try { 386 | const payload = await slackNotificationPayload(config.channelId, null, 'in_channel'); 387 | await app.client.chat.postMessage(payload); 388 | } catch (error) { 389 | status = 500; 390 | message = error.message; 391 | console.error(error); 392 | } 393 | response.status(status); 394 | return response.send(message); 395 | }); 396 | 397 | receiver.app.get('/', (_, res) => { 398 | // Respond 200 OK to the default health check method. 399 | res.status(200).send(); 400 | }); 401 | 402 | (async () => { 403 | // Start the app 404 | await app.start(process.env.PORT || 3000); 405 | 406 | console.log('⚡️ Bolt app is running!'); 407 | })(); 408 | --------------------------------------------------------------------------------