Merge pull request #3870 from concourse/issue/3748

ci, web: fix dashboard preview performance
This commit is contained in:
Alex Suraci 2019-05-17 13:43:50 -04:00 committed by GitHub
commit dd22b95513
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 494 additions and 19 deletions

View File

@ -323,6 +323,10 @@ even some automated fixes!
Run `yarn format` to format the elm code according to the official Elm Style
Guide. Powered by [elm-format](https://github.com/avh4/elm-format).
### Elm benchmarking
Run `yarn benchmark`.
### Running the acceptance tests (`testflight`)
The `testflight` package contains tests that run against a real live Concourse.

View File

@ -86,6 +86,11 @@ jobs:
file: concourse-pr/ci/tasks/yarn-test.yml
input_mapping: {concourse: concourse-pr}
tags: [pr]
- task: yarn-benchmark
attempts: 3
file: concourse-pr/ci/tasks/yarn-benchmark.yml
input_mapping: {concourse: concourse-pr}
tags: [pr]
- task: unit
attempts: 3
timeout: 1h

11
ci/tasks/scripts/yarn-benchmark Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
# vim: set ft=sh
set -e -u
# for better yarn output
stty columns 80
cd concourse
yarn install
yarn benchmark

View File

@ -0,0 +1,16 @@
---
platform: linux
image_resource:
type: registry-image
source: {repository: concourse/unit}
inputs:
- name: concourse
caches:
- path: concourse/node_modules
- path: concourse/web/elm/elm-stuff
run:
path: concourse/ci/tasks/scripts/yarn-benchmark

View File

@ -6,6 +6,7 @@
"license": "Apache-2.0",
"dependencies": {},
"devDependencies": {
"child-process-promise": "^2.2.1",
"chokidar-cli": "^1.2.1",
"elm": "^0.19.0-bugfix6",
"elm-analyse": "^0.16.2",
@ -15,6 +16,7 @@
"less-plugin-autoprefix": "^1.5.1",
"less-plugin-clean-css": "^1.5.1",
"@mdi/svg": "^3.5.95",
"puppeteer": "^1.12.2",
"uglify-js": "^3.3.22"
},
"scripts": {
@ -27,6 +29,7 @@
"build-elm": "cd web/elm && elm make --optimize --output ../public/elm.js src/Main.elm && uglifyjs < ../public/elm.js > ../public/elm.min.js",
"build-elm-debug": "cd web/elm && elm make --output ../public/elm.js src/Main.elm && uglifyjs < ../public/elm.js > ../public/elm.min.js",
"watch": "chokidar -i elm-stuff 'web/elm/src/**/*.elm' 'web/assets/css/*.less' -c 'yarn run build-debug' --initial",
"update-mdi-svg": "./hack/update-mdi-svg \"node_modules/@mdi/svg/svg\" > web/public/mdi-svg.js && uglifyjs < web/public/mdi-svg.js > web/public/mdi-svg.min.js"
"update-mdi-svg": "./hack/update-mdi-svg \"node_modules/@mdi/svg/svg\" > web/public/mdi-svg.js && uglifyjs < web/public/mdi-svg.js > web/public/mdi-svg.min.js",
"benchmark": "cd web/elm && elm make --output /tmp/benchmark.html benchmarks/Benchmarks.elm && node benchmarks/benchmark.js /tmp/benchmark.html"
}
}

View File

@ -0,0 +1,201 @@
module Benchmarks exposing (main)
import Benchmark
import Benchmark.Runner exposing (BenchmarkProgram, program)
import Concourse
import Concourse.BuildStatus
import Dashboard.DashboardPreview as DP
import Dict exposing (Dict)
import Html exposing (Html)
import Html.Attributes exposing (attribute, class, classList, href)
import Routes
main : BenchmarkProgram
main =
program <|
Benchmark.compare "view"
"with topological sort"
(\_ -> DP.view sampleJobs)
"straight recursion"
(\_ -> view sampleJobs)
sampleJob : String -> List String -> Concourse.Job
sampleJob name passed =
{ pipeline = pipelineId
, name = name
, pipelineName = "pipeline"
, teamName = "team"
, nextBuild = Nothing
, finishedBuild = Nothing
, transitionBuild = Nothing
, paused = False
, disableManualTrigger = False
, inputs =
[ { name = "input"
, resource = "resource"
, passed = passed
, trigger = True
}
]
, outputs = []
, groups = []
}
sampleJobs : List Concourse.Job
sampleJobs =
[ sampleJob "job1" []
, sampleJob "job2a" [ "job1" ]
, sampleJob "job2b" [ "job1" ]
, sampleJob "job3" [ "job2a" ]
, sampleJob "job4" [ "job3" ]
]
pipelineId : Concourse.PipelineIdentifier
pipelineId =
{ pipelineName = "pipeline", teamName = "team" }
view : List Concourse.Job -> Html msg
view jobs =
let
groups =
jobGroups jobs
width =
Dict.size groups
height =
Maybe.withDefault 0 <| List.maximum (List.map List.length (Dict.values groups))
in
Html.div
[ classList
[ ( "pipeline-grid", True )
, ( "pipeline-grid-wide", width > 12 )
, ( "pipeline-grid-tall", height > 12 )
, ( "pipeline-grid-super-wide", width > 24 )
, ( "pipeline-grid-super-tall", height > 24 )
]
]
<|
List.map
(\js ->
List.map viewJob js
|> Html.div [ class "parallel-grid" ]
)
(Dict.values groups)
viewJob : Concourse.Job -> Html msg
viewJob job =
let
jobStatus =
case job.finishedBuild of
Just fb ->
Concourse.BuildStatus.show fb.status
Nothing ->
"no-builds"
isJobRunning =
job.nextBuild /= Nothing
latestBuild =
if job.nextBuild == Nothing then
job.finishedBuild
else
job.nextBuild
in
Html.div
[ classList
[ ( "node " ++ jobStatus, True )
, ( "running", isJobRunning )
, ( "paused", job.paused )
]
, attribute "data-tooltip" job.name
]
<|
case latestBuild of
Nothing ->
[ Html.a [ href <| Routes.toString <| Routes.jobRoute job ] [ Html.text "" ] ]
Just build ->
[ Html.a [ href <| Routes.toString <| Routes.buildRoute build ] [ Html.text "" ] ]
jobGroups : List Concourse.Job -> Dict Int (List Concourse.Job)
jobGroups jobs =
let
jobLookup =
jobByName <| List.foldl (\job byName -> Dict.insert job.name job byName) Dict.empty jobs
in
Dict.foldl
(\jobName depth byDepth ->
Dict.update depth
(\jobsA ->
Just (jobLookup jobName :: Maybe.withDefault [] jobsA)
)
byDepth
)
Dict.empty
(jobDepths jobs Dict.empty)
jobByName : Dict String Concourse.Job -> String -> Concourse.Job
jobByName jobs job =
case Dict.get job jobs of
Just a ->
a
Nothing ->
{ pipeline = { pipelineName = "", teamName = "" }
, name = ""
, pipelineName = ""
, teamName = ""
, nextBuild = Nothing
, finishedBuild = Nothing
, transitionBuild = Nothing
, paused = False
, disableManualTrigger = False
, inputs = []
, outputs = []
, groups = []
}
jobDepths : List Concourse.Job -> Dict String Int -> Dict String Int
jobDepths jobs dict =
case jobs of
[] ->
dict
job :: otherJobs ->
let
passedJobs =
List.concatMap .passed job.inputs
in
case List.length passedJobs of
0 ->
jobDepths otherJobs <| Dict.insert job.name 0 dict
_ ->
let
passedJobDepths =
List.map (\passedJob -> Dict.get passedJob dict) passedJobs
in
if List.member Nothing passedJobDepths then
jobDepths (List.append otherJobs [ job ]) dict
else
let
depths =
List.map (\depth -> Maybe.withDefault 0 depth) passedJobDepths
maxPassedJobDepth =
Maybe.withDefault 0 <| List.maximum depths
in
jobDepths otherJobs <| Dict.insert job.name (maxPassedJobDepth + 1) dict

View File

@ -0,0 +1,25 @@
const Web = require('../../wats/test/helpers/web');
class Benchmark {
constructor() {
this.url = `file://${process.argv[2] || '/tmp/benchmark.html'}`;
this.web = new Web(this.url);
}
async run() {
await this.web.init();
await this.web.page.goto(this.url);
await this.web.waitForText('Benchmark Report');
const bodyHandle = await this.web.page.$('body > div > div');
const html = await this.web.page.evaluate(body => body.innerText, bodyHandle);
await bodyHandle.dispose();
console.log(html);
}
}
async function main() {
await new Benchmark().run();
process.exit(0);
}
main();

View File

@ -1,7 +1,8 @@
{
"type": "application",
"source-directories": [
"src"
"src",
"benchmarks"
],
"elm-version": "0.19.0",
"dependencies": {
@ -20,6 +21,7 @@
"elm-community/json-extra": "4.0.0",
"elm-community/list-extra": "8.1.0",
"elm-community/maybe-extra": "5.0.0",
"elm-explorations/benchmark": "1.0.1",
"fapian/elm-html-aria": "1.4.0",
"krisajenkins/remotedata": "5.0.0",
"lukewestby/elm-http-builder": "6.0.0",
@ -29,11 +31,11 @@
"vito/elm-ansi": "9.0.1"
},
"indirect": {
"BrianHicks/elm-trend": "2.1.2",
"Skinney/murmur3": "2.0.8",
"avh4/elm-fifo": "1.0.4",
"elm/virtual-dom": "1.0.2",
"rtfeldman/elm-hex": "1.0.0",
"elm/regex": "1.0.0",
"elm/virtual-dom": "1.0.2",
"mdgriffith/style-elements": "5.0.1",
"rtfeldman/elm-iso8601-date-strings": "1.1.2"
}
},
@ -42,7 +44,9 @@
"elm-explorations/test": "1.2.1"
},
"indirect": {
"elm/random": "1.0.0"
"avh4/elm-fifo": "1.0.4",
"elm/random": "1.0.0",
"rtfeldman/elm-hex": "1.0.0"
}
}
}
}

View File

@ -2,25 +2,21 @@ module Dashboard.DashboardPreview exposing (view)
import Concourse
import Concourse.BuildStatus
import Dict exposing (Dict)
import Html exposing (Html)
import Html.Attributes exposing (attribute, class, classList, href)
import List.Extra exposing (find)
import List.Extra
import Maybe.Extra
import Routes
import TopologicalSort exposing (flattenToLayers)
import Set exposing (Set)
view : List Concourse.Job -> Html msg
view jobs =
let
jobDependencies : Concourse.Job -> List Concourse.Job
jobDependencies job =
job.inputs
|> List.concatMap .passed
|> List.filterMap (\name -> find (\j -> j.name == name) jobs)
layers : List (List Concourse.Job)
layers =
flattenToLayers (List.map (\j -> ( j, jobDependencies j )) jobs)
groupByRank jobs
width : Int
width =
@ -86,3 +82,60 @@ viewJob job =
, attribute "data-tooltip" job.name
]
[ Html.a [ href <| Routes.toString buildRoute ] [ Html.text "" ] ]
groupByRank : List Concourse.Job -> List (List Concourse.Job)
groupByRank jobs =
let
depths =
jobs
|> jobDepths Set.empty Dict.empty
in
jobs
|> List.Extra.gatherEqualsBy (\job -> Dict.get job.name depths)
|> List.map (\( h, t ) -> h :: t)
jobDepths : Set String -> Dict String Int -> List Concourse.Job -> Dict String Int
jobDepths visited depths jobs =
case jobs of
[] ->
depths
job :: otherJobs ->
case
( List.concatMap .passed job.inputs
|> List.map (\jobName -> Dict.get jobName depths)
|> calculate List.maximum
, Set.member job.name visited
)
of
( Nothing, _ ) ->
jobDepths visited (Dict.insert job.name 0 depths) otherJobs
( Just (Confident depth), _ ) ->
jobDepths visited (Dict.insert job.name (depth + 1) depths) otherJobs
( Just (Speculative depth), True ) ->
jobDepths visited (Dict.insert job.name (depth + 1) depths) otherJobs
( Just (Speculative _), False ) ->
jobDepths (Set.insert job.name visited) depths (otherJobs ++ [ job ])
type Calculation a
= Confident a
| Speculative a
calculate : (List a -> Maybe b) -> List (Maybe a) -> Maybe (Calculation b)
calculate f xs =
case ( List.any ((==) Nothing) xs, f (Maybe.Extra.values xs) ) of
( True, Just value ) ->
Just (Speculative value)
( False, Just value ) ->
Just (Confident value)
( _, Nothing ) ->
Nothing

159
yarn.lock
View File

@ -20,6 +20,13 @@ accepts@~1.3.5:
mime-types "~2.1.18"
negotiator "0.6.1"
agent-base@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==
dependencies:
es6-promisify "^5.0.0"
ajv@^5.1.0, ajv@^5.3.0:
version "5.5.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
@ -306,6 +313,11 @@ browserslist@^1.7.6:
caniuse-db "^1.0.30000639"
electron-to-chromium "^1.2.7"
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==
buffers@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb"
@ -373,6 +385,15 @@ chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
child-process-promise@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/child-process-promise/-/child-process-promise-2.2.1.tgz#4730a11ef610fad450b8f223c79d31d7bdad8074"
integrity sha1-RzChHvYQ+tRQuPIjx50x172tgHQ=
dependencies:
cross-spawn "^4.0.2"
node-version "^1.0.0"
promise-polyfill "^6.0.1"
chokidar-cli@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/chokidar-cli/-/chokidar-cli-1.2.1.tgz#50574a63414174c5ac62f495abe09ae3cb6cb8b5"
@ -529,6 +550,16 @@ concat-stream@1.5.2:
readable-stream "~2.0.0"
typedarray "~0.0.5"
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"
console-control-strings@^1.0.0, console-control-strings@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
@ -577,6 +608,14 @@ cross-spawn@4.0.0:
lru-cache "^4.0.1"
which "^1.2.9"
cross-spawn@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41"
integrity sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=
dependencies:
lru-cache "^4.0.1"
which "^1.2.9"
cross-spawn@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@ -607,6 +646,20 @@ debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3:
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"
decamelize@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7"
@ -769,6 +822,18 @@ errno@^0.1.1:
dependencies:
prr "~1.0.1"
es6-promise@^4.0.3:
version "4.2.6"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f"
integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==
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"
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@ -892,6 +957,16 @@ extglob@^2.0.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
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"
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
@ -912,6 +987,13 @@ fast-json-stable-stringify@^2.0.0:
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
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"
fill-range@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
@ -1261,6 +1343,14 @@ http-signature@~1.2.0:
jsprim "^1.2.2"
sshpk "^1.7.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"
iconv-lite@0.4.19:
version "0.4.19"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
@ -1714,6 +1804,11 @@ mime@^1.4.1:
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
mime@^2.0.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe"
integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==
mimic-fn@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
@ -1759,7 +1854,7 @@ mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"
"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
@ -1771,6 +1866,11 @@ ms@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.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
murmur-hash-js@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/murmur-hash-js/-/murmur-hash-js-1.0.0.tgz#5041049269c96633c866386960b2f4289e75e5b0"
@ -1843,6 +1943,11 @@ node-pre-gyp@^0.10.0:
semver "^5.3.0"
tar "^4"
node-version@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/node-version/-/node-version-1.2.0.tgz#34fde3ffa8e1149bd323983479dda620e1b5060d"
integrity sha512-ma6oU4Sk0qOoKEAymVoTvk8EdXEobdS7m/mAGhDJ8Rouugho48crHBORAmy5BoOcv8wraPM6xumapQp5hl4iIQ==
node-watch@0.5.5:
version "0.5.5"
resolved "https://registry.yarnpkg.com/node-watch/-/node-watch-0.5.5.tgz#34865ba8bc6861ab086acdcc3403e40ed55c3274"
@ -2063,6 +2168,11 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
pend@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
@ -2098,6 +2208,16 @@ process-nextick-args@~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==
promise-polyfill@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-6.1.0.tgz#dfa96943ea9c121fca4de9b5868cb39d3472e057"
integrity sha1-36lpQ+qcEh/KTem1hoyznTRy4Fc=
promise@^7.1.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
@ -2113,6 +2233,11 @@ proxy-addr@~2.0.3:
forwarded "~0.1.2"
ipaddr.js "1.8.0"
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=
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@ -2133,6 +2258,20 @@ punycode@^1.4.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
puppeteer@^1.12.2:
version "1.16.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.16.0.tgz#4b763d9ff4e69a4bb7a031c3393534214d54f27e"
integrity sha512-7hcmbUw+6INffSPBdnO8KSjJRg2bLRoI7EeZMf5MHdV5kpyYMeoMR5w8AIiZbKIhYGwrXlbgvO7gFTsXNHShuQ==
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"
qs@6.5.1, qs@~6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
@ -2168,7 +2307,7 @@ rc@^1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
readable-stream@^2.0.2, readable-stream@^2.0.6:
readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2:
version "2.3.6"
resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
@ -2783,7 +2922,7 @@ type-is@~1.6.15, type-is@~1.6.16:
media-typer "0.3.0"
mime-types "~2.1.18"
typedarray@~0.0.5:
typedarray@^0.0.6, typedarray@~0.0.5:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
@ -2940,6 +3079,13 @@ ws@^1.0.0:
options ">=0.0.5"
ultron "1.0.x"
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"
xmlbuilder@^8.2.2:
version "8.2.2"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"
@ -2994,3 +3140,10 @@ yargs@12.0.1:
which-module "^2.0.0"
y18n "^3.2.1 || ^4.0.0"
yargs-parser "^10.1.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"