From a78d74c35ae3445b71d7ce6f7cc6abccef3a78a4 Mon Sep 17 00:00:00 2001 From: Michael Lange Date: Wed, 12 Jun 2019 17:36:45 -0700 Subject: [PATCH] New script for automatically capturing UI screenshots to use for guides and docs --- website/scripts/.gitignore | 2 + website/scripts/screenshots/src/index.js | 180 ++++++++++++ website/scripts/screenshots/src/package.json | 15 + website/scripts/screenshots/src/utils.js | 90 ++++++ website/scripts/screenshots/src/yarn.lock | 287 +++++++++++++++++++ 5 files changed, 574 insertions(+) create mode 100644 website/scripts/.gitignore create mode 100644 website/scripts/screenshots/src/index.js create mode 100644 website/scripts/screenshots/src/package.json create mode 100644 website/scripts/screenshots/src/utils.js create mode 100644 website/scripts/screenshots/src/yarn.lock diff --git a/website/scripts/.gitignore b/website/scripts/.gitignore new file mode 100644 index 000000000..b6a89553b --- /dev/null +++ b/website/scripts/.gitignore @@ -0,0 +1,2 @@ +screenshots/screenshots/* +screenshots/src/node_modules \ No newline at end of file diff --git a/website/scripts/screenshots/src/index.js b/website/scripts/screenshots/src/index.js new file mode 100644 index 000000000..ad24f757e --- /dev/null +++ b/website/scripts/screenshots/src/index.js @@ -0,0 +1,180 @@ +const puppeteer = require("puppeteer"); +const { + capture, + wait, + error, + click, + clickJob, + clickTab, + clickMainMenu, + clickX +} = require("./utils"); + +const HOST = process.env.EMBER_HOST || "http://localhost:4200"; +console.log(`Using host ${HOST}...`); + +(async () => { + const startTime = Date.now(); + console.log("Preparing puppeteer..."); + + // Create a new browser and tab + const browser = await puppeteer.launch({ + // Docker related chrome flags + args: [ + "--no-sandbox", + "--disable-setuid-sandbox", + "--disable-dev-shm-usage" + ] + }); + const page = await browser.newPage(); + + // Make sure the page is 4K is high-dpi scaling + page.setViewport({ width: 1920, height: 1080, deviceScaleFactor: 2 }); + console.log("Loading Nomad UI..."); + + try { + await page.goto(`${HOST}/ui/`); + } catch (err) { + await error( + browser, + "Could not load the Nomad UI. Is the Ember server running?" + ); + } + + // Give Mirage a chance to settle + console.log("Waiting for Mirage..."); + await wait(5000); + console.log("Starting capture sequence!\n"); + + // DEBUG: log the URL on all navigations + monitorURL(page); + + await capture(page, "jobs-list"); + + await clickJob(page, "service"); + await capture(page, "job-detail-service"); + await page.goBack(); + + await clickJob(page, "batch"); + await capture(page, "job-detail-batch"); + await page.goBack(); + + await clickJob(page, "system"); + await capture(page, "job-detail-system"); + await page.goBack(); + + await clickJob(page, "periodic"); + await capture(page, "job-detail-periodic"); + await click(page, "tr.job-row"); + await capture(page, "job-detail-periodic-child"); + await page.goBack(); + await page.goBack(); + + await clickJob(page, "parameterized"); + await capture(page, "job-detail-parameterized"); + await click(page, "tr.job-row"); + await capture(page, "job-detail-parameterized-child"); + await page.goBack(); + await page.goBack(); + + await clickJob(page, "service"); + + await clickTab(page, "Definition"); + await capture(page, "job-detail-tab-definition"); + await page.click(".boxed-section .button.is-light.is-compact.pull-right"); + await capture(page, "job-detail-tab-definition-editing"); + + await clickTab(page, "Versions"); + await capture(page, "job-detail-tab-versions"); + await page.click(".timeline-object .button.is-light.is-compact.pull-right"); + await capture(page, "job-detail-tab-versions-expanded"); + + await clickTab(page, "Deployments"); + await capture(page, "job-detail-tab-deployments"); + await page.click(".timeline-object .button.is-light.is-compact.pull-right"); + await capture(page, "job-detail-tab-deployments-expanded"); + + await clickTab(page, "Allocations"); + await capture(page, "job-detail-tab-allocations"); + + await clickTab(page, "Evaluations"); + await capture(page, "job-detail-tab-evaluations"); + + await clickMainMenu(page, "Jobs"); + await page.click(".toolbar-item .button.is-primary"); + await capture(page, "job-run-empty"); + // Fill in the code editor somehow + // Capture the plan stage + + await clickMainMenu(page, "Jobs"); + await clickJob(page, "service"); + await click(page, ".task-group-row"); + await capture(page, "task-group"); + + await clickMainMenu(page, "Jobs"); + await clickJob(page, "service"); + + const allocCount = await page.$$eval(".allocation-row", s => s.length); + for (let i = 1; i <= allocCount; i++) { + await click(page, `.allocation-row:nth-of-type(${i}) a.is-primary`); + await capture(page, `allocation-${i}`); + await page.goBack(); + await wait(2000); + } + + await click(page, ".allocation-row a.is-primary"); + await click(page, ".task-row"); + await capture(page, "task-detail"); + + await clickTab(page, "Logs"); + await capture(page, "task-logs"); + + await clickMainMenu(page, "Clients"); + await capture(page, "clients-list"); + + const clientCount = await page.$$eval(".client-node-row", s => s.length); + for (let i = 1; i <= clientCount; i++) { + await click(page, `.client-node-row:nth-of-type(${i})`); + await capture(page, `client-detail-${i}`); + await page.goBack(); + await wait(500); + } + + await clickMainMenu(page, "Servers"); + await capture(page, "servers-list"); + + await click(page, `.server-agent-row:nth-of-type(2)`); + await capture(page, "server-detail"); + + await clickX(page, '//a[contains(text(), "ACL Tokens")]'); + await capture(page, "acl-tokens"); + + console.log(`All done! ${humanDuration(Date.now() - startTime)}`); + process.exit(); +})(); + +async function* watchURL(page) { + while (true) { + await page.waitForNavigation(); + yield page.url(); + } +} + +async function monitorURL(page) { + for await (let url of watchURL(page)) { + console.log(`=> ${url}`); + } +} + +function humanDuration(duration) { + const ms = duration % 1000; + const s = Math.floor((duration / 1000) % 60); + const m = Math.floor(duration / 1000 / 60); + + const fs = s < 10 ? `0${s}` : `${s}`; + const fms = ms < 10 ? `00${ms}` : ms < 100 ? `0${ms}` : `${ms}`; + + if (m) return `${m}m ${fs}s ${fms}ms`; + else if (s) return `${fs}s ${fms}ms`; + return `${fms}ms`; +} diff --git a/website/scripts/screenshots/src/package.json b/website/scripts/screenshots/src/package.json new file mode 100644 index 000000000..34c7c0253 --- /dev/null +++ b/website/scripts/screenshots/src/package.json @@ -0,0 +1,15 @@ +{ + "name": "nomad-ui-screenshots", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "puppeteer": "^1.16.0" + } +} diff --git a/website/scripts/screenshots/src/utils.js b/website/scripts/screenshots/src/utils.js new file mode 100644 index 000000000..fe448ecaf --- /dev/null +++ b/website/scripts/screenshots/src/utils.js @@ -0,0 +1,90 @@ +async function error(browser, message = "Something went wrong.") { + console.error(message); + await browser.close(); + process.exit(); +} + +async function capture(page, name, options = {}) { + console.log(`Capturing ${name}`); + const dir = process.env.SCREENSHOTS_DIR || "screenshots"; + await page.screenshot( + Object.assign({ path: `${dir}/${name}.png`, fullPage: true }, options) + ); +} + +async function wait(time) { + return new Promise(resolve => { + setTimeout(resolve, time); + }); +} + +async function click(page, selector, options) { + const [response] = await Promise.all([ + page.waitForNavigation(), + page.click(selector, options) + ]); + + // Allow for render + await wait(500); + + return response; +} + +async function clickX(page, path) { + const [element] = await page.$x(path); + const [response] = await Promise.all([ + page.waitForNavigation(), + element.click() + ]); + + // Allow for render + await wait(500); + + return response; +} + +async function clickJob(page, type) { + let jobIndex = await page.$$eval( + "tr.job-row", + (rows, type) => + rows.findIndex( + row => row.querySelector("td:nth-child(3)").textContent.trim() === type + ), + type + ); + jobIndex++; + + await clickX(page, `//tr[contains(@class, "job-row")][${jobIndex}]`); +} + +async function clickTab(page, label) { + let tabIndex = await page.$$eval( + ".tabs.is-subnav a", + (tabs, label) => tabs.findIndex(tab => tab.textContent.trim() === label), + label + ); + tabIndex++; + + await clickX( + page, + `//div[contains(@class, "is-subnav")]//ul//li[${tabIndex}]//a` + ); +} + +async function clickMainMenu(page, label) { + await clickX( + page, + `//div[contains(@class, "page-column is-left")]//a[contains(text(), "${label}")]` + ); +} + +module.exports = { + error, + capture, + wait, + click, + clickX, + clickJob, + clickTab, + clickMainMenu +}; diff --git a/website/scripts/screenshots/src/yarn.lock b/website/scripts/screenshots/src/yarn.lock new file mode 100644 index 000000000..0a412b8a6 --- /dev/null +++ b/website/scripts/screenshots/src/yarn.lock @@ -0,0 +1,287 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +agent-base@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + +extract-zip@^1.6.6: + version "1.6.7" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" + integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k= + dependencies: + concat-stream "1.6.2" + debug "2.6.9" + mkdirp "0.5.1" + yauzl "2.4.1" + +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU= + dependencies: + pend "~1.2.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +glob@^7.1.3: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +mime@^2.0.3: + version "2.4.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" + integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +mkdirp@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + +progress@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +proxy-from-env@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4= + +puppeteer@^1.16.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.17.0.tgz#371957d227a2f450fa74b78e78a2dadb2be7f14f" + integrity sha512-3EXZSximCzxuVKpIHtyec8Wm2dWZn1fc5tQi34qWfiUgubEVYHjUvr0GOJojqf3mifI6oyKnCdrGxaOI+lWReA== + dependencies: + debug "^4.1.0" + extract-zip "^1.6.6" + https-proxy-agent "^2.2.1" + mime "^2.0.3" + progress "^2.0.1" + proxy-from-env "^1.0.0" + rimraf "^2.6.1" + ws "^6.1.0" + +readable-stream@^2.2.2: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +rimraf@^2.6.1: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +ws@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" + integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + dependencies: + async-limiter "~1.0.0" + +yauzl@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU= + dependencies: + fd-slicer "~1.0.1"