├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── CNAME
├── LICENSE
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── revision-hash.js
└── src
├── assets
├── favicon.png
├── favicon.svg
└── loading.gif
├── js
├── ErrorMessage.js
├── Filter.js
├── Leaderboard.js
├── LeaderboardControl.js
├── Loading.js
├── app.js
├── store.js
└── templates.js
└── styles.css
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Build and Deploy
2 | on:
3 | pull_request:
4 | branches: master
5 | types: [closed]
6 | jobs:
7 | build-and-deploy:
8 | runs-on: ubuntu-latest
9 | if: github.event.pull_request.merged == true
10 | steps:
11 | - name: Checkout 🛎️
12 | uses: actions/checkout@v2.3.1
13 | with:
14 | persist-credentials: false
15 |
16 | - name: Use Node.js
17 | uses: actions/setup-node@v1
18 | with:
19 | node-version: '12.x'
20 |
21 | - name: Install and Build 🔧
22 | run: |
23 | npm ci
24 | npm run dist
25 |
26 | - name: Deploy 🚀
27 | uses: JamesIves/github-pages-deploy-action@3.7.1
28 | with:
29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30 | BRANCH: gh-pages
31 | FOLDER: dist
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
106 | .DS_Store
107 |
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | vitals-leaderboard.pazguille.me
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Guille Paz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Web Vitals Leaderboard
2 | > The simplest way to understand how your site’s user experience compares to other major sites in your industry.
3 |
4 | ⚡️ https://web-vitals.pazguille.me/
5 |
6 | ## Development
7 |
8 | 1. Install [Git](http://git-scm.com/) and [Node](http://nodejs.org/).
9 |
10 | 2. Open your terminal and clone th repository by running:
11 |
12 | ```sh
13 | git clone git@github.com:pazguille/web-vitals-leaderboard.git
14 | ```
15 |
16 | 3. Go to folder `web-vitals-leaderboard`:
17 |
18 | ```sh
19 | cd web-vitals-leaderboard
20 | ```
21 |
22 | 5. Move to `develop` branch:
23 |
24 | ```sh
25 | git checkout develop
26 | ```
27 |
28 | 6. Install development dependencies:
29 |
30 | ```sh
31 | npm install
32 | ```
33 |
34 | 7. Run a local server:
35 |
36 | ```sh
37 | npm start
38 | ```
39 |
40 | 7. 👨💻 Code, code code!
41 |
42 | 8. Send a pull request if you wish.
43 |
44 | ## Made with ❤ by
45 |
46 | - Guille Paz (👨💻 Front End Web Developer | ⚡️ Web Performance Lover)
47 | - E-mail: [guille87paz@gmail.com](mailto:guille87paz@gmail.com)
48 | - Twitter: [@pazguille](https://twitter.com/pazguille)
49 | - Web: [https://pazguille.me](https://pazguille.me)
50 |
51 | ## License
52 |
53 | MIT license. Copyright © 2020.
54 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | Web Vitals Leaderboard
34 |
35 |
36 |
37 |
38 |
39 |
40 | Compare your speed against competitors
41 | Web Vitals Leaderboard
42 | The simplest way to understand how your website’s performance compares to other sites in your industry.
43 |
44 |
61 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | All devices
81 | Mobile
82 | Desktop
83 | Tablet
84 |
85 |
86 | Oops.. Chrome UX report data not found!
87 |
116 |
117 |
118 |
119 | Frequently Asked Questions
120 |
121 | What are Web Vitals?
122 | Web Vitals is an initiative by Google to provide unified guidance for quality signals that are essential to delivering a great user experience on the web. This metrics represent the best available signals developers have today to measure quality of experience across the web.
123 |
124 |
125 | Where does data come from?
126 | Web Vitals Leaderboard makes use of Chrome UX Report API that dataset represents how real-world Chrome users experience popular destinations on the web. CRUX aggregates user experience metrics by origin and url, for all websites that are known by Google's web crawlers.
127 |
128 |
129 | How frequently is data updated?
130 | The data in the Chrome UX Report is a 28-day rolling average of aggregated metrics. This means that the data presented in the Chrome UX Report at any given time is actually data for the past 28 days aggregated together.
131 |
132 |
133 | How rankings are determined?
134 | Largest Contentful Paint (LCP) measures when a user perceives that the largest content of a page is visible. The metric value for LCP represents the time duration between the user initiating the page load and the page rendering its primary content. Based on real website data, top-performing sites render LCP in about 1,2 sec, so this metric is the most important to represent a fast speed.
135 |
136 |
137 |
138 |
139 |
142 |
143 |
177 |
200 |
201 |
202 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-vitals-leaderboard",
3 | "version": "1.2.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@zeit/schemas": {
8 | "version": "2.6.0",
9 | "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz",
10 | "integrity": "sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==",
11 | "dev": true
12 | },
13 | "accepts": {
14 | "version": "1.3.7",
15 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
16 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
17 | "dev": true,
18 | "requires": {
19 | "mime-types": "~2.1.24",
20 | "negotiator": "0.6.2"
21 | }
22 | },
23 | "ajv": {
24 | "version": "6.5.3",
25 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz",
26 | "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==",
27 | "dev": true,
28 | "requires": {
29 | "fast-deep-equal": "^2.0.1",
30 | "fast-json-stable-stringify": "^2.0.0",
31 | "json-schema-traverse": "^0.4.1",
32 | "uri-js": "^4.2.2"
33 | }
34 | },
35 | "ansi-align": {
36 | "version": "2.0.0",
37 | "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
38 | "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
39 | "dev": true,
40 | "requires": {
41 | "string-width": "^2.0.0"
42 | }
43 | },
44 | "ansi-regex": {
45 | "version": "3.0.0",
46 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
47 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
48 | "dev": true
49 | },
50 | "ansi-styles": {
51 | "version": "3.2.1",
52 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
53 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
54 | "dev": true,
55 | "requires": {
56 | "color-convert": "^1.9.0"
57 | }
58 | },
59 | "arch": {
60 | "version": "2.1.2",
61 | "resolved": "https://registry.npmjs.org/arch/-/arch-2.1.2.tgz",
62 | "integrity": "sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ==",
63 | "dev": true
64 | },
65 | "arg": {
66 | "version": "2.0.0",
67 | "resolved": "https://registry.npmjs.org/arg/-/arg-2.0.0.tgz",
68 | "integrity": "sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==",
69 | "dev": true
70 | },
71 | "balanced-match": {
72 | "version": "1.0.0",
73 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
74 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
75 | "dev": true
76 | },
77 | "boxen": {
78 | "version": "1.3.0",
79 | "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
80 | "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==",
81 | "dev": true,
82 | "requires": {
83 | "ansi-align": "^2.0.0",
84 | "camelcase": "^4.0.0",
85 | "chalk": "^2.0.1",
86 | "cli-boxes": "^1.0.0",
87 | "string-width": "^2.0.0",
88 | "term-size": "^1.2.0",
89 | "widest-line": "^2.0.0"
90 | }
91 | },
92 | "brace-expansion": {
93 | "version": "1.1.11",
94 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
95 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
96 | "dev": true,
97 | "requires": {
98 | "balanced-match": "^1.0.0",
99 | "concat-map": "0.0.1"
100 | }
101 | },
102 | "buffer-from": {
103 | "version": "1.1.1",
104 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
105 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
106 | "dev": true
107 | },
108 | "bytes": {
109 | "version": "3.0.0",
110 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
111 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
112 | "dev": true
113 | },
114 | "camelcase": {
115 | "version": "4.1.0",
116 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
117 | "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
118 | "dev": true
119 | },
120 | "chalk": {
121 | "version": "2.4.1",
122 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
123 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
124 | "dev": true,
125 | "requires": {
126 | "ansi-styles": "^3.2.1",
127 | "escape-string-regexp": "^1.0.5",
128 | "supports-color": "^5.3.0"
129 | }
130 | },
131 | "clean-css": {
132 | "version": "4.2.3",
133 | "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
134 | "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==",
135 | "dev": true,
136 | "requires": {
137 | "source-map": "~0.6.0"
138 | }
139 | },
140 | "cli-boxes": {
141 | "version": "1.0.0",
142 | "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
143 | "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=",
144 | "dev": true
145 | },
146 | "clipboardy": {
147 | "version": "1.2.3",
148 | "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-1.2.3.tgz",
149 | "integrity": "sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA==",
150 | "dev": true,
151 | "requires": {
152 | "arch": "^2.1.0",
153 | "execa": "^0.8.0"
154 | },
155 | "dependencies": {
156 | "execa": {
157 | "version": "0.8.0",
158 | "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz",
159 | "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=",
160 | "dev": true,
161 | "requires": {
162 | "cross-spawn": "^5.0.1",
163 | "get-stream": "^3.0.0",
164 | "is-stream": "^1.1.0",
165 | "npm-run-path": "^2.0.0",
166 | "p-finally": "^1.0.0",
167 | "signal-exit": "^3.0.0",
168 | "strip-eof": "^1.0.0"
169 | }
170 | }
171 | }
172 | },
173 | "cliui": {
174 | "version": "7.0.4",
175 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
176 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
177 | "dev": true,
178 | "requires": {
179 | "string-width": "^4.2.0",
180 | "strip-ansi": "^6.0.0",
181 | "wrap-ansi": "^7.0.0"
182 | },
183 | "dependencies": {
184 | "ansi-regex": {
185 | "version": "5.0.0",
186 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
187 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
188 | "dev": true
189 | },
190 | "is-fullwidth-code-point": {
191 | "version": "3.0.0",
192 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
193 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
194 | "dev": true
195 | },
196 | "string-width": {
197 | "version": "4.2.2",
198 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
199 | "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
200 | "dev": true,
201 | "requires": {
202 | "emoji-regex": "^8.0.0",
203 | "is-fullwidth-code-point": "^3.0.0",
204 | "strip-ansi": "^6.0.0"
205 | }
206 | },
207 | "strip-ansi": {
208 | "version": "6.0.0",
209 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
210 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
211 | "dev": true,
212 | "requires": {
213 | "ansi-regex": "^5.0.0"
214 | }
215 | }
216 | }
217 | },
218 | "color-convert": {
219 | "version": "1.9.3",
220 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
221 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
222 | "dev": true,
223 | "requires": {
224 | "color-name": "1.1.3"
225 | }
226 | },
227 | "color-name": {
228 | "version": "1.1.3",
229 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
230 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
231 | "dev": true
232 | },
233 | "commander": {
234 | "version": "2.20.3",
235 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
236 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
237 | "dev": true
238 | },
239 | "compressible": {
240 | "version": "2.0.18",
241 | "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
242 | "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
243 | "dev": true,
244 | "requires": {
245 | "mime-db": ">= 1.43.0 < 2"
246 | }
247 | },
248 | "compression": {
249 | "version": "1.7.3",
250 | "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz",
251 | "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==",
252 | "dev": true,
253 | "requires": {
254 | "accepts": "~1.3.5",
255 | "bytes": "3.0.0",
256 | "compressible": "~2.0.14",
257 | "debug": "2.6.9",
258 | "on-headers": "~1.0.1",
259 | "safe-buffer": "5.1.2",
260 | "vary": "~1.1.2"
261 | }
262 | },
263 | "concat-map": {
264 | "version": "0.0.1",
265 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
266 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
267 | "dev": true
268 | },
269 | "content-disposition": {
270 | "version": "0.5.2",
271 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
272 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=",
273 | "dev": true
274 | },
275 | "core-util-is": {
276 | "version": "1.0.2",
277 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
278 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
279 | "dev": true
280 | },
281 | "cross-spawn": {
282 | "version": "5.1.0",
283 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
284 | "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
285 | "dev": true,
286 | "requires": {
287 | "lru-cache": "^4.0.1",
288 | "shebang-command": "^1.2.0",
289 | "which": "^1.2.9"
290 | }
291 | },
292 | "cssauron": {
293 | "version": "1.4.0",
294 | "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
295 | "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=",
296 | "dev": true,
297 | "requires": {
298 | "through": "X.X.X"
299 | }
300 | },
301 | "debug": {
302 | "version": "2.6.9",
303 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
304 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
305 | "dev": true,
306 | "requires": {
307 | "ms": "2.0.0"
308 | }
309 | },
310 | "deep-extend": {
311 | "version": "0.6.0",
312 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
313 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
314 | "dev": true
315 | },
316 | "dot-case": {
317 | "version": "3.0.3",
318 | "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz",
319 | "integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==",
320 | "dev": true,
321 | "requires": {
322 | "no-case": "^3.0.3",
323 | "tslib": "^1.10.0"
324 | },
325 | "dependencies": {
326 | "lower-case": {
327 | "version": "2.0.1",
328 | "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz",
329 | "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==",
330 | "dev": true,
331 | "requires": {
332 | "tslib": "^1.10.0"
333 | }
334 | },
335 | "no-case": {
336 | "version": "3.0.3",
337 | "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz",
338 | "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==",
339 | "dev": true,
340 | "requires": {
341 | "lower-case": "^2.0.1",
342 | "tslib": "^1.10.0"
343 | }
344 | }
345 | }
346 | },
347 | "duplexer2": {
348 | "version": "0.0.2",
349 | "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
350 | "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=",
351 | "dev": true,
352 | "requires": {
353 | "readable-stream": "~1.1.9"
354 | },
355 | "dependencies": {
356 | "readable-stream": {
357 | "version": "1.1.14",
358 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
359 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
360 | "dev": true,
361 | "requires": {
362 | "core-util-is": "~1.0.0",
363 | "inherits": "~2.0.1",
364 | "isarray": "0.0.1",
365 | "string_decoder": "~0.10.x"
366 | }
367 | }
368 | }
369 | },
370 | "emoji-regex": {
371 | "version": "8.0.0",
372 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
373 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
374 | "dev": true
375 | },
376 | "escalade": {
377 | "version": "3.1.1",
378 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
379 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
380 | "dev": true
381 | },
382 | "escape-string-regexp": {
383 | "version": "1.0.5",
384 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
385 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
386 | "dev": true
387 | },
388 | "execa": {
389 | "version": "0.7.0",
390 | "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
391 | "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
392 | "dev": true,
393 | "requires": {
394 | "cross-spawn": "^5.0.1",
395 | "get-stream": "^3.0.0",
396 | "is-stream": "^1.1.0",
397 | "npm-run-path": "^2.0.0",
398 | "p-finally": "^1.0.0",
399 | "signal-exit": "^3.0.0",
400 | "strip-eof": "^1.0.0"
401 | }
402 | },
403 | "fast-deep-equal": {
404 | "version": "2.0.1",
405 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
406 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
407 | "dev": true
408 | },
409 | "fast-json-stable-stringify": {
410 | "version": "2.1.0",
411 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
412 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
413 | "dev": true
414 | },
415 | "fast-url-parser": {
416 | "version": "1.1.3",
417 | "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
418 | "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=",
419 | "dev": true,
420 | "requires": {
421 | "punycode": "^1.3.2"
422 | },
423 | "dependencies": {
424 | "punycode": {
425 | "version": "1.4.1",
426 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
427 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
428 | "dev": true
429 | }
430 | }
431 | },
432 | "fs.realpath": {
433 | "version": "1.0.0",
434 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
435 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
436 | "dev": true
437 | },
438 | "get-caller-file": {
439 | "version": "2.0.5",
440 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
441 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
442 | "dev": true
443 | },
444 | "get-stream": {
445 | "version": "3.0.0",
446 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
447 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
448 | "dev": true
449 | },
450 | "glob": {
451 | "version": "7.1.7",
452 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
453 | "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
454 | "dev": true,
455 | "requires": {
456 | "fs.realpath": "^1.0.0",
457 | "inflight": "^1.0.4",
458 | "inherits": "2",
459 | "minimatch": "^3.0.4",
460 | "once": "^1.3.0",
461 | "path-is-absolute": "^1.0.0"
462 | }
463 | },
464 | "has-flag": {
465 | "version": "3.0.0",
466 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
467 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
468 | "dev": true
469 | },
470 | "he": {
471 | "version": "1.2.0",
472 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
473 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
474 | "dev": true
475 | },
476 | "html-inline": {
477 | "version": "1.2.0",
478 | "resolved": "https://registry.npmjs.org/html-inline/-/html-inline-1.2.0.tgz",
479 | "integrity": "sha1-eFSUam9cMSK5k7gdPTfWvQYAvsE=",
480 | "dev": true,
481 | "requires": {
482 | "minimist": "~1.1.0",
483 | "through2": "~0.6.3",
484 | "trumpet": "~1.7.0"
485 | },
486 | "dependencies": {
487 | "minimist": {
488 | "version": "1.1.3",
489 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.1.3.tgz",
490 | "integrity": "sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=",
491 | "dev": true
492 | }
493 | }
494 | },
495 | "html-minifier-terser": {
496 | "version": "5.1.1",
497 | "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
498 | "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==",
499 | "dev": true,
500 | "requires": {
501 | "camel-case": "^4.1.1",
502 | "clean-css": "^4.2.3",
503 | "commander": "^4.1.1",
504 | "he": "^1.2.0",
505 | "param-case": "^3.0.3",
506 | "relateurl": "^0.2.7",
507 | "terser": "^4.6.3"
508 | },
509 | "dependencies": {
510 | "camel-case": {
511 | "version": "4.1.1",
512 | "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz",
513 | "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==",
514 | "dev": true,
515 | "requires": {
516 | "pascal-case": "^3.1.1",
517 | "tslib": "^1.10.0"
518 | }
519 | },
520 | "commander": {
521 | "version": "4.1.1",
522 | "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
523 | "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
524 | "dev": true
525 | },
526 | "param-case": {
527 | "version": "3.0.3",
528 | "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz",
529 | "integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==",
530 | "dev": true,
531 | "requires": {
532 | "dot-case": "^3.0.3",
533 | "tslib": "^1.10.0"
534 | }
535 | },
536 | "terser": {
537 | "version": "4.8.0",
538 | "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
539 | "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
540 | "dev": true,
541 | "requires": {
542 | "commander": "^2.20.0",
543 | "source-map": "~0.6.1",
544 | "source-map-support": "~0.5.12"
545 | },
546 | "dependencies": {
547 | "commander": {
548 | "version": "2.20.3",
549 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
550 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
551 | "dev": true
552 | }
553 | }
554 | }
555 | }
556 | },
557 | "html-select": {
558 | "version": "2.3.24",
559 | "resolved": "https://registry.npmjs.org/html-select/-/html-select-2.3.24.tgz",
560 | "integrity": "sha1-Rq1tcS5zLPMcZznV0BEKX6vxdYU=",
561 | "dev": true,
562 | "requires": {
563 | "cssauron": "^1.1.0",
564 | "duplexer2": "~0.0.2",
565 | "inherits": "^2.0.1",
566 | "minimist": "~0.0.8",
567 | "readable-stream": "^1.0.27-1",
568 | "split": "~0.3.0",
569 | "stream-splicer": "^1.2.0",
570 | "through2": "^1.0.0"
571 | },
572 | "dependencies": {
573 | "minimist": {
574 | "version": "0.0.10",
575 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
576 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
577 | "dev": true
578 | },
579 | "through2": {
580 | "version": "1.1.1",
581 | "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz",
582 | "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=",
583 | "dev": true,
584 | "requires": {
585 | "readable-stream": ">=1.1.13-1 <1.2.0-0",
586 | "xtend": ">=4.0.0 <4.1.0-0"
587 | },
588 | "dependencies": {
589 | "readable-stream": {
590 | "version": "1.1.14",
591 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
592 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
593 | "dev": true,
594 | "requires": {
595 | "core-util-is": "~1.0.0",
596 | "inherits": "~2.0.1",
597 | "isarray": "0.0.1",
598 | "string_decoder": "~0.10.x"
599 | }
600 | }
601 | }
602 | }
603 | }
604 | },
605 | "html-tokenize": {
606 | "version": "1.2.5",
607 | "resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-1.2.5.tgz",
608 | "integrity": "sha1-flupnstR75Buyaf83ubKMmfHiX4=",
609 | "dev": true,
610 | "requires": {
611 | "inherits": "~2.0.1",
612 | "minimist": "~0.0.8",
613 | "readable-stream": "~1.0.27-1",
614 | "through2": "~0.4.1"
615 | },
616 | "dependencies": {
617 | "minimist": {
618 | "version": "0.0.10",
619 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
620 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
621 | "dev": true
622 | },
623 | "through2": {
624 | "version": "0.4.2",
625 | "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz",
626 | "integrity": "sha1-2/WGYDEVHsg1K7bE22SiKSqEC5s=",
627 | "dev": true,
628 | "requires": {
629 | "readable-stream": "~1.0.17",
630 | "xtend": "~2.1.1"
631 | }
632 | },
633 | "xtend": {
634 | "version": "2.1.2",
635 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz",
636 | "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=",
637 | "dev": true,
638 | "requires": {
639 | "object-keys": "~0.4.0"
640 | }
641 | }
642 | }
643 | },
644 | "indexof": {
645 | "version": "0.0.1",
646 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
647 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
648 | "dev": true
649 | },
650 | "inflight": {
651 | "version": "1.0.6",
652 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
653 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
654 | "dev": true,
655 | "requires": {
656 | "once": "^1.3.0",
657 | "wrappy": "1"
658 | }
659 | },
660 | "inherits": {
661 | "version": "2.0.4",
662 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
663 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
664 | "dev": true
665 | },
666 | "ini": {
667 | "version": "1.3.8",
668 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
669 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
670 | "dev": true
671 | },
672 | "is-fullwidth-code-point": {
673 | "version": "2.0.0",
674 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
675 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
676 | "dev": true
677 | },
678 | "is-stream": {
679 | "version": "1.1.0",
680 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
681 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
682 | "dev": true
683 | },
684 | "isarray": {
685 | "version": "0.0.1",
686 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
687 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
688 | "dev": true
689 | },
690 | "isexe": {
691 | "version": "2.0.0",
692 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
693 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
694 | "dev": true
695 | },
696 | "json-schema-traverse": {
697 | "version": "0.4.1",
698 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
699 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
700 | "dev": true
701 | },
702 | "lru-cache": {
703 | "version": "4.1.5",
704 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
705 | "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
706 | "dev": true,
707 | "requires": {
708 | "pseudomap": "^1.0.2",
709 | "yallist": "^2.1.2"
710 | }
711 | },
712 | "mime-db": {
713 | "version": "1.44.0",
714 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
715 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
716 | "dev": true
717 | },
718 | "mime-types": {
719 | "version": "2.1.27",
720 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
721 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
722 | "dev": true,
723 | "requires": {
724 | "mime-db": "1.44.0"
725 | }
726 | },
727 | "minimatch": {
728 | "version": "3.0.4",
729 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
730 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
731 | "dev": true,
732 | "requires": {
733 | "brace-expansion": "^1.1.7"
734 | }
735 | },
736 | "minimist": {
737 | "version": "1.2.5",
738 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
739 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
740 | "dev": true
741 | },
742 | "ms": {
743 | "version": "2.0.0",
744 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
745 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
746 | "dev": true
747 | },
748 | "negotiator": {
749 | "version": "0.6.2",
750 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
751 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
752 | "dev": true
753 | },
754 | "npm-run-path": {
755 | "version": "2.0.2",
756 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
757 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
758 | "dev": true,
759 | "requires": {
760 | "path-key": "^2.0.0"
761 | }
762 | },
763 | "object-keys": {
764 | "version": "0.4.0",
765 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz",
766 | "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=",
767 | "dev": true
768 | },
769 | "on-headers": {
770 | "version": "1.0.2",
771 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
772 | "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
773 | "dev": true
774 | },
775 | "once": {
776 | "version": "1.4.0",
777 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
778 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
779 | "dev": true,
780 | "requires": {
781 | "wrappy": "1"
782 | }
783 | },
784 | "p-finally": {
785 | "version": "1.0.0",
786 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
787 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
788 | "dev": true
789 | },
790 | "pascal-case": {
791 | "version": "3.1.1",
792 | "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz",
793 | "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==",
794 | "dev": true,
795 | "requires": {
796 | "no-case": "^3.0.3",
797 | "tslib": "^1.10.0"
798 | },
799 | "dependencies": {
800 | "lower-case": {
801 | "version": "2.0.1",
802 | "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz",
803 | "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==",
804 | "dev": true,
805 | "requires": {
806 | "tslib": "^1.10.0"
807 | }
808 | },
809 | "no-case": {
810 | "version": "3.0.3",
811 | "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz",
812 | "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==",
813 | "dev": true,
814 | "requires": {
815 | "lower-case": "^2.0.1",
816 | "tslib": "^1.10.0"
817 | }
818 | }
819 | }
820 | },
821 | "path-is-absolute": {
822 | "version": "1.0.1",
823 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
824 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
825 | "dev": true
826 | },
827 | "path-is-inside": {
828 | "version": "1.0.2",
829 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
830 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
831 | "dev": true
832 | },
833 | "path-key": {
834 | "version": "2.0.1",
835 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
836 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
837 | "dev": true
838 | },
839 | "path-to-regexp": {
840 | "version": "2.2.1",
841 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz",
842 | "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==",
843 | "dev": true
844 | },
845 | "pseudomap": {
846 | "version": "1.0.2",
847 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
848 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
849 | "dev": true
850 | },
851 | "punycode": {
852 | "version": "2.1.1",
853 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
854 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
855 | "dev": true
856 | },
857 | "range-parser": {
858 | "version": "1.2.0",
859 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
860 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=",
861 | "dev": true
862 | },
863 | "rc": {
864 | "version": "1.2.8",
865 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
866 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
867 | "dev": true,
868 | "requires": {
869 | "deep-extend": "^0.6.0",
870 | "ini": "~1.3.0",
871 | "minimist": "^1.2.0",
872 | "strip-json-comments": "~2.0.1"
873 | }
874 | },
875 | "readable-stream": {
876 | "version": "1.0.34",
877 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
878 | "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
879 | "dev": true,
880 | "requires": {
881 | "core-util-is": "~1.0.0",
882 | "inherits": "~2.0.1",
883 | "isarray": "0.0.1",
884 | "string_decoder": "~0.10.x"
885 | }
886 | },
887 | "readable-wrap": {
888 | "version": "1.0.0",
889 | "resolved": "https://registry.npmjs.org/readable-wrap/-/readable-wrap-1.0.0.tgz",
890 | "integrity": "sha1-O1ohHGMeEjA6VJkcgGwX564ga/8=",
891 | "dev": true,
892 | "requires": {
893 | "readable-stream": "^1.1.13-1"
894 | },
895 | "dependencies": {
896 | "readable-stream": {
897 | "version": "1.1.14",
898 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
899 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
900 | "dev": true,
901 | "requires": {
902 | "core-util-is": "~1.0.0",
903 | "inherits": "~2.0.1",
904 | "isarray": "0.0.1",
905 | "string_decoder": "~0.10.x"
906 | }
907 | }
908 | }
909 | },
910 | "registry-auth-token": {
911 | "version": "3.3.2",
912 | "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz",
913 | "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==",
914 | "dev": true,
915 | "requires": {
916 | "rc": "^1.1.6",
917 | "safe-buffer": "^5.0.1"
918 | }
919 | },
920 | "registry-url": {
921 | "version": "3.1.0",
922 | "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
923 | "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
924 | "dev": true,
925 | "requires": {
926 | "rc": "^1.0.1"
927 | }
928 | },
929 | "relateurl": {
930 | "version": "0.2.7",
931 | "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
932 | "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=",
933 | "dev": true
934 | },
935 | "replace-in-file": {
936 | "version": "6.2.0",
937 | "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-6.2.0.tgz",
938 | "integrity": "sha512-Im2AF9G/qgkYneOc9QwWwUS/efyyonTUBvzXS2VXuxPawE5yQIjT/e6x4CTijO0Quq48lfAujuo+S89RR2TP2Q==",
939 | "dev": true,
940 | "requires": {
941 | "chalk": "^4.1.0",
942 | "glob": "^7.1.6",
943 | "yargs": "^16.2.0"
944 | },
945 | "dependencies": {
946 | "ansi-styles": {
947 | "version": "4.3.0",
948 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
949 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
950 | "dev": true,
951 | "requires": {
952 | "color-convert": "^2.0.1"
953 | }
954 | },
955 | "chalk": {
956 | "version": "4.1.1",
957 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
958 | "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
959 | "dev": true,
960 | "requires": {
961 | "ansi-styles": "^4.1.0",
962 | "supports-color": "^7.1.0"
963 | }
964 | },
965 | "color-convert": {
966 | "version": "2.0.1",
967 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
968 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
969 | "dev": true,
970 | "requires": {
971 | "color-name": "~1.1.4"
972 | }
973 | },
974 | "color-name": {
975 | "version": "1.1.4",
976 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
977 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
978 | "dev": true
979 | },
980 | "has-flag": {
981 | "version": "4.0.0",
982 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
983 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
984 | "dev": true
985 | },
986 | "supports-color": {
987 | "version": "7.2.0",
988 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
989 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
990 | "dev": true,
991 | "requires": {
992 | "has-flag": "^4.0.0"
993 | }
994 | }
995 | }
996 | },
997 | "require-directory": {
998 | "version": "2.1.1",
999 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
1000 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
1001 | "dev": true
1002 | },
1003 | "rev-hash": {
1004 | "version": "3.0.0",
1005 | "resolved": "https://registry.npmjs.org/rev-hash/-/rev-hash-3.0.0.tgz",
1006 | "integrity": "sha512-s+87HfEKAu95TaTxnbCobn0/BkbzR23LHSwVdYvr8mn5+PPjzy+hTWyh92b5oaLgig9TKPe5d6ZcubsVBtUrZg==",
1007 | "dev": true
1008 | },
1009 | "safe-buffer": {
1010 | "version": "5.1.2",
1011 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
1012 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
1013 | "dev": true
1014 | },
1015 | "serve": {
1016 | "version": "11.3.2",
1017 | "resolved": "https://registry.npmjs.org/serve/-/serve-11.3.2.tgz",
1018 | "integrity": "sha512-yKWQfI3xbj/f7X1lTBg91fXBP0FqjJ4TEi+ilES5yzH0iKJpN5LjNb1YzIfQg9Rqn4ECUS2SOf2+Kmepogoa5w==",
1019 | "dev": true,
1020 | "requires": {
1021 | "@zeit/schemas": "2.6.0",
1022 | "ajv": "6.5.3",
1023 | "arg": "2.0.0",
1024 | "boxen": "1.3.0",
1025 | "chalk": "2.4.1",
1026 | "clipboardy": "1.2.3",
1027 | "compression": "1.7.3",
1028 | "serve-handler": "6.1.3",
1029 | "update-check": "1.5.2"
1030 | }
1031 | },
1032 | "serve-handler": {
1033 | "version": "6.1.3",
1034 | "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz",
1035 | "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==",
1036 | "dev": true,
1037 | "requires": {
1038 | "bytes": "3.0.0",
1039 | "content-disposition": "0.5.2",
1040 | "fast-url-parser": "1.1.3",
1041 | "mime-types": "2.1.18",
1042 | "minimatch": "3.0.4",
1043 | "path-is-inside": "1.0.2",
1044 | "path-to-regexp": "2.2.1",
1045 | "range-parser": "1.2.0"
1046 | },
1047 | "dependencies": {
1048 | "mime-db": {
1049 | "version": "1.33.0",
1050 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
1051 | "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==",
1052 | "dev": true
1053 | },
1054 | "mime-types": {
1055 | "version": "2.1.18",
1056 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
1057 | "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
1058 | "dev": true,
1059 | "requires": {
1060 | "mime-db": "~1.33.0"
1061 | }
1062 | }
1063 | }
1064 | },
1065 | "shebang-command": {
1066 | "version": "1.2.0",
1067 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
1068 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
1069 | "dev": true,
1070 | "requires": {
1071 | "shebang-regex": "^1.0.0"
1072 | }
1073 | },
1074 | "shebang-regex": {
1075 | "version": "1.0.0",
1076 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
1077 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
1078 | "dev": true
1079 | },
1080 | "signal-exit": {
1081 | "version": "3.0.3",
1082 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
1083 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
1084 | "dev": true
1085 | },
1086 | "source-map": {
1087 | "version": "0.6.1",
1088 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
1089 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
1090 | "dev": true
1091 | },
1092 | "source-map-support": {
1093 | "version": "0.5.19",
1094 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
1095 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
1096 | "dev": true,
1097 | "requires": {
1098 | "buffer-from": "^1.0.0",
1099 | "source-map": "^0.6.0"
1100 | }
1101 | },
1102 | "split": {
1103 | "version": "0.3.3",
1104 | "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
1105 | "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
1106 | "dev": true,
1107 | "requires": {
1108 | "through": "2"
1109 | }
1110 | },
1111 | "stream-splicer": {
1112 | "version": "1.3.2",
1113 | "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-1.3.2.tgz",
1114 | "integrity": "sha1-PARBvhW5v04iYnXm3IOWR0VUZmE=",
1115 | "dev": true,
1116 | "requires": {
1117 | "indexof": "0.0.1",
1118 | "inherits": "^2.0.1",
1119 | "isarray": "~0.0.1",
1120 | "readable-stream": "^1.1.13-1",
1121 | "readable-wrap": "^1.0.0",
1122 | "through2": "^1.0.0"
1123 | },
1124 | "dependencies": {
1125 | "readable-stream": {
1126 | "version": "1.1.14",
1127 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
1128 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
1129 | "dev": true,
1130 | "requires": {
1131 | "core-util-is": "~1.0.0",
1132 | "inherits": "~2.0.1",
1133 | "isarray": "0.0.1",
1134 | "string_decoder": "~0.10.x"
1135 | }
1136 | },
1137 | "through2": {
1138 | "version": "1.1.1",
1139 | "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz",
1140 | "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=",
1141 | "dev": true,
1142 | "requires": {
1143 | "readable-stream": ">=1.1.13-1 <1.2.0-0",
1144 | "xtend": ">=4.0.0 <4.1.0-0"
1145 | }
1146 | }
1147 | }
1148 | },
1149 | "string-width": {
1150 | "version": "2.1.1",
1151 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
1152 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
1153 | "dev": true,
1154 | "requires": {
1155 | "is-fullwidth-code-point": "^2.0.0",
1156 | "strip-ansi": "^4.0.0"
1157 | }
1158 | },
1159 | "string_decoder": {
1160 | "version": "0.10.31",
1161 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
1162 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
1163 | "dev": true
1164 | },
1165 | "strip-ansi": {
1166 | "version": "4.0.0",
1167 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
1168 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
1169 | "dev": true,
1170 | "requires": {
1171 | "ansi-regex": "^3.0.0"
1172 | }
1173 | },
1174 | "strip-eof": {
1175 | "version": "1.0.0",
1176 | "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
1177 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
1178 | "dev": true
1179 | },
1180 | "strip-json-comments": {
1181 | "version": "2.0.1",
1182 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
1183 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
1184 | "dev": true
1185 | },
1186 | "supports-color": {
1187 | "version": "5.5.0",
1188 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1189 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1190 | "dev": true,
1191 | "requires": {
1192 | "has-flag": "^3.0.0"
1193 | }
1194 | },
1195 | "term-size": {
1196 | "version": "1.2.0",
1197 | "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
1198 | "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=",
1199 | "dev": true,
1200 | "requires": {
1201 | "execa": "^0.7.0"
1202 | }
1203 | },
1204 | "terser": {
1205 | "version": "5.7.1",
1206 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz",
1207 | "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==",
1208 | "dev": true,
1209 | "requires": {
1210 | "commander": "^2.20.0",
1211 | "source-map": "~0.7.2",
1212 | "source-map-support": "~0.5.19"
1213 | },
1214 | "dependencies": {
1215 | "source-map": {
1216 | "version": "0.7.3",
1217 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
1218 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
1219 | "dev": true
1220 | }
1221 | }
1222 | },
1223 | "through": {
1224 | "version": "2.3.8",
1225 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
1226 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
1227 | "dev": true
1228 | },
1229 | "through2": {
1230 | "version": "0.6.5",
1231 | "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
1232 | "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
1233 | "dev": true,
1234 | "requires": {
1235 | "readable-stream": ">=1.0.33-1 <1.1.0-0",
1236 | "xtend": ">=4.0.0 <4.1.0-0"
1237 | }
1238 | },
1239 | "trumpet": {
1240 | "version": "1.7.2",
1241 | "resolved": "https://registry.npmjs.org/trumpet/-/trumpet-1.7.2.tgz",
1242 | "integrity": "sha1-sCxp5GXRcfVeRJJL+bW90gl0yDA=",
1243 | "dev": true,
1244 | "requires": {
1245 | "duplexer2": "~0.0.2",
1246 | "html-select": "^2.3.5",
1247 | "html-tokenize": "^1.1.1",
1248 | "inherits": "^2.0.0",
1249 | "readable-stream": "^1.0.27-1",
1250 | "through2": "^1.0.0"
1251 | },
1252 | "dependencies": {
1253 | "through2": {
1254 | "version": "1.1.1",
1255 | "resolved": "https://registry.npmjs.org/through2/-/through2-1.1.1.tgz",
1256 | "integrity": "sha1-CEfLxESfNAVXTb3M2buEG4OsNUU=",
1257 | "dev": true,
1258 | "requires": {
1259 | "readable-stream": ">=1.1.13-1 <1.2.0-0",
1260 | "xtend": ">=4.0.0 <4.1.0-0"
1261 | },
1262 | "dependencies": {
1263 | "readable-stream": {
1264 | "version": "1.1.14",
1265 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
1266 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
1267 | "dev": true,
1268 | "requires": {
1269 | "core-util-is": "~1.0.0",
1270 | "inherits": "~2.0.1",
1271 | "isarray": "0.0.1",
1272 | "string_decoder": "~0.10.x"
1273 | }
1274 | }
1275 | }
1276 | }
1277 | }
1278 | },
1279 | "tslib": {
1280 | "version": "1.13.0",
1281 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
1282 | "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
1283 | "dev": true
1284 | },
1285 | "update-check": {
1286 | "version": "1.5.2",
1287 | "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.2.tgz",
1288 | "integrity": "sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==",
1289 | "dev": true,
1290 | "requires": {
1291 | "registry-auth-token": "3.3.2",
1292 | "registry-url": "3.1.0"
1293 | }
1294 | },
1295 | "uri-js": {
1296 | "version": "4.2.2",
1297 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
1298 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
1299 | "dev": true,
1300 | "requires": {
1301 | "punycode": "^2.1.0"
1302 | }
1303 | },
1304 | "vary": {
1305 | "version": "1.1.2",
1306 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1307 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
1308 | "dev": true
1309 | },
1310 | "which": {
1311 | "version": "1.3.1",
1312 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
1313 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
1314 | "dev": true,
1315 | "requires": {
1316 | "isexe": "^2.0.0"
1317 | }
1318 | },
1319 | "widest-line": {
1320 | "version": "2.0.1",
1321 | "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz",
1322 | "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
1323 | "dev": true,
1324 | "requires": {
1325 | "string-width": "^2.1.1"
1326 | }
1327 | },
1328 | "wrap-ansi": {
1329 | "version": "7.0.0",
1330 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
1331 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
1332 | "dev": true,
1333 | "requires": {
1334 | "ansi-styles": "^4.0.0",
1335 | "string-width": "^4.1.0",
1336 | "strip-ansi": "^6.0.0"
1337 | },
1338 | "dependencies": {
1339 | "ansi-regex": {
1340 | "version": "5.0.0",
1341 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
1342 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
1343 | "dev": true
1344 | },
1345 | "ansi-styles": {
1346 | "version": "4.3.0",
1347 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
1348 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
1349 | "dev": true,
1350 | "requires": {
1351 | "color-convert": "^2.0.1"
1352 | }
1353 | },
1354 | "color-convert": {
1355 | "version": "2.0.1",
1356 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
1357 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
1358 | "dev": true,
1359 | "requires": {
1360 | "color-name": "~1.1.4"
1361 | }
1362 | },
1363 | "color-name": {
1364 | "version": "1.1.4",
1365 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
1366 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
1367 | "dev": true
1368 | },
1369 | "is-fullwidth-code-point": {
1370 | "version": "3.0.0",
1371 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
1372 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
1373 | "dev": true
1374 | },
1375 | "string-width": {
1376 | "version": "4.2.2",
1377 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
1378 | "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
1379 | "dev": true,
1380 | "requires": {
1381 | "emoji-regex": "^8.0.0",
1382 | "is-fullwidth-code-point": "^3.0.0",
1383 | "strip-ansi": "^6.0.0"
1384 | }
1385 | },
1386 | "strip-ansi": {
1387 | "version": "6.0.0",
1388 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
1389 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
1390 | "dev": true,
1391 | "requires": {
1392 | "ansi-regex": "^5.0.0"
1393 | }
1394 | }
1395 | }
1396 | },
1397 | "wrappy": {
1398 | "version": "1.0.2",
1399 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1400 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
1401 | "dev": true
1402 | },
1403 | "xtend": {
1404 | "version": "4.0.2",
1405 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
1406 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
1407 | "dev": true
1408 | },
1409 | "y18n": {
1410 | "version": "5.0.8",
1411 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
1412 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
1413 | "dev": true
1414 | },
1415 | "yallist": {
1416 | "version": "2.1.2",
1417 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
1418 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
1419 | "dev": true
1420 | },
1421 | "yargs": {
1422 | "version": "16.2.0",
1423 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
1424 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
1425 | "dev": true,
1426 | "requires": {
1427 | "cliui": "^7.0.2",
1428 | "escalade": "^3.1.1",
1429 | "get-caller-file": "^2.0.5",
1430 | "require-directory": "^2.1.1",
1431 | "string-width": "^4.2.0",
1432 | "y18n": "^5.0.5",
1433 | "yargs-parser": "^20.2.2"
1434 | },
1435 | "dependencies": {
1436 | "ansi-regex": {
1437 | "version": "5.0.0",
1438 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
1439 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
1440 | "dev": true
1441 | },
1442 | "is-fullwidth-code-point": {
1443 | "version": "3.0.0",
1444 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
1445 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
1446 | "dev": true
1447 | },
1448 | "string-width": {
1449 | "version": "4.2.2",
1450 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
1451 | "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
1452 | "dev": true,
1453 | "requires": {
1454 | "emoji-regex": "^8.0.0",
1455 | "is-fullwidth-code-point": "^3.0.0",
1456 | "strip-ansi": "^6.0.0"
1457 | }
1458 | },
1459 | "strip-ansi": {
1460 | "version": "6.0.0",
1461 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
1462 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
1463 | "dev": true,
1464 | "requires": {
1465 | "ansi-regex": "^5.0.0"
1466 | }
1467 | }
1468 | }
1469 | },
1470 | "yargs-parser": {
1471 | "version": "20.2.9",
1472 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
1473 | "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
1474 | "dev": true
1475 | }
1476 | }
1477 | }
1478 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-vitals-leaderboard",
3 | "version": "1.2.3",
4 | "description": "The simplest way to understand how your site’s user experience compares to other major sites in your industry.",
5 | "main": "index.js",
6 | "scripts": {
7 | "dev": "serve -p 3030",
8 | "inline": "html-inline --ignore-images --ignore-links --ignore-scripts -i ./index.html -o ./dist/index.html",
9 | "minify": "html-minifier-terser --collapse-whitespace --remove-comments --remove-optional-tags --remove-redundant-attributes --remove-script-type-attributes --remove-tag-whitespace --use-short-doctype --minify-css true --minify-js '{\"compress\":{\"drop_console\":\"true\"},\"mangle\":{\"toplevel\":\"true\"}}' --output ./dist/index.html ./dist/index.html",
10 | "copy": "rm -rf dist && mkdir -p dist && cp -rf ./src ./dist/src",
11 | "minify-js": "for filename in ./dist/src/js/*.js; do terser \"${filename}\" --compress --mangle --output \"${filename}\"; done",
12 | "dist": "npm run copy && npm run inline && npm run minify && npm run minify-js && node revision-hash.js"
13 | },
14 | "repository": {
15 | "type": "git",
16 | "url": "git+https://github.com/pazguille/web-vitals-leaderboard.git"
17 | },
18 | "author": "Guille Paz ",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/pazguille/web-vitals-leaderboard/issues"
22 | },
23 | "homepage": "https://vitals-leaderboard.pazguill.me",
24 | "devDependencies": {
25 | "html-inline": "^1.2.0",
26 | "html-minifier-terser": "^5.1.1",
27 | "replace-in-file": "^6.2.0",
28 | "rev-hash": "^3.0.0",
29 | "serve": "^11.3.2",
30 | "terser": "^5.7.1"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/revision-hash.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const revisionHash = require('rev-hash');
3 | const replace = require('replace-in-file');
4 |
5 | const map = {};
6 | const dir = './dist/src/js';
7 | const files = fs.readdirSync(dir);
8 |
9 | files.forEach((file) => {
10 | if (file.endsWith('.js')) {
11 | const hash = revisionHash(fs.readFileSync(`${dir}/${file}`));
12 | map[file] = hash;
13 | fs.renameSync(
14 | `${dir}/${file}`,
15 | `${dir}/${file.replace('.js', `.${hash}.js`)}`
16 | );
17 | }
18 | });
19 |
20 | replace.sync({
21 | files: [
22 | `${dir}/*.js`,
23 | './dist/index.html',
24 | ],
25 | from: /[A-Za-z]+\.js/gi,
26 | to: (match) => {
27 | if (map[match]) {
28 | return match.replace('.js', `.${map[match]}.js`);
29 | }
30 | return match;
31 | },
32 | });
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pazguille/web-vitals-leaderboard/c0d63e2772eb3a090b612597691000cd9923de2d/src/assets/favicon.png
--------------------------------------------------------------------------------
/src/assets/favicon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pazguille/web-vitals-leaderboard/c0d63e2772eb3a090b612597691000cd9923de2d/src/assets/loading.gif
--------------------------------------------------------------------------------
/src/js/ErrorMessage.js:
--------------------------------------------------------------------------------
1 | import store from './store.js';
2 |
3 | export default class ErrorMessage {
4 | constructor() {
5 | this.$node = document.querySelector('#error-message');
6 | }
7 |
8 | toggleVisibility() {
9 | const { leaderboardError, leaderboardLoaded } = store.getState();
10 | if (leaderboardError) {
11 | this.$node.removeAttribute('hidden');
12 | } else if (!leaderboardLoaded) {
13 | this.$node.setAttribute('hidden', 'hidden');
14 | }
15 | }
16 |
17 | init() {
18 | store.subscribe(this.toggleVisibility.bind(this))
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/js/Filter.js:
--------------------------------------------------------------------------------
1 | import store from './store.js';
2 |
3 | export default class Filter {
4 | constructor() {
5 | this.$node = document.querySelector('#filters');
6 | this.$device = document.querySelector('#device-filter');
7 | }
8 |
9 | toggleVisibility() {
10 | const { leaderboardLoaded, running, leaderboardError } = store.getState();
11 | if (leaderboardLoaded && running) {
12 | this.$node.setAttribute('hidden', 'hidden');
13 | return;
14 | }
15 |
16 | if (leaderboardLoaded && !leaderboardError) {
17 | this.$node.removeAttribute('hidden');
18 | return;
19 | }
20 |
21 | if (leaderboardLoaded === false) {
22 | this.$node.setAttribute('hidden', 'hidden');
23 | return;
24 | }
25 | }
26 |
27 | addEvents() {
28 | this.$device.addEventListener('change', function() {
29 | store.dispatch({
30 | type: 'CHANGE_DEVICE',
31 | value: this.value,
32 | });
33 | });
34 | }
35 |
36 | init() {
37 | this.addEvents();
38 | store.subscribe(this.toggleVisibility.bind(this))
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/js/Leaderboard.js:
--------------------------------------------------------------------------------
1 | import store from './store.js';
2 | import { resultTemplate, skeletonTemplate } from './templates.js';
3 |
4 | export default class LeaderboardResults {
5 | constructor() {
6 | this.$node = document.querySelector('table');
7 | this.$results = document.querySelector('#content');
8 | }
9 |
10 | sortBy(metric) {
11 | return (a, b) => {
12 | if ( a.metrics === null) {
13 | return 1;
14 | }
15 | if (b.metrics === null) {
16 | return -1;
17 | }
18 | if (a.metrics[metric].value < b.metrics[metric].value) {
19 | return -1;
20 | }
21 | if (a.metrics[metric].value > b.metrics[metric].value) {
22 | return 1;
23 | }
24 | return 0;
25 | }
26 | }
27 |
28 | fetchData(data) {
29 | if (data.urls) {
30 | data.urls = data.urls.map((url) => encodeURIComponent(url)).join(',');
31 | } else if (data.origins) {
32 | data.origins = data.origins.map((url) => encodeURIComponent(url)).join(',');
33 | }
34 | const query = Object.keys(data).map(key => key + '=' + data[key]).join('&');
35 | return fetch(`https://crux.pazguille.me/api/web-vitals?${query}`)
36 | .then(res => res.json())
37 | .then((results) => {
38 | if (results.code) {
39 | store.dispatch({ type: 'LEADERBOARD_LOADED', error: true });
40 | return;
41 | }
42 | store.dispatch({ type: 'LEADERBOARD_LOADED', results });
43 | })
44 | .catch(() => {
45 | store.dispatch({ type: 'LEADERBOARD_LOADED', error: true });
46 | })
47 | }
48 |
49 | toggleVisibility() {
50 | const { running, from, urls, filters, leaderboardLoaded, results } = store.getState();
51 |
52 | if (running) {
53 | this.fetchData({
54 | [from]: urls,
55 | device: filters.device,
56 | });
57 | this.$node.setAttribute('hidden', 'hidden');
58 | return;
59 | }
60 |
61 | if (leaderboardLoaded && results) {
62 | const html = results
63 | .sort(this.sortBy('LCP'))
64 | .map((result, index) => resultTemplate(result, index+=1));
65 | this.$node.removeAttribute('hidden');
66 | this.$results.innerHTML = '';
67 | this.$results.insertAdjacentHTML('beforeend', html.join(''));
68 | this.$node.removeAttribute('hidden');
69 | return;
70 | }
71 |
72 | if (leaderboardLoaded === false && urls.length > 0) {
73 | this.$node.removeAttribute('hidden');
74 | this.$results.insertAdjacentHTML('beforeend', skeletonTemplate(urls[urls.length-1]));
75 | return;
76 | }
77 |
78 | if (leaderboardLoaded === false && urls.length === 0) {
79 | this.$results.innerHTML = '';
80 | this.$node.setAttribute('hidden', 'hidden');
81 | window.history.replaceState({}, '', `${location.pathname}`);
82 | return;
83 | }
84 | }
85 |
86 | init() {
87 | store.subscribe(this.toggleVisibility.bind(this))
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/js/LeaderboardControl.js:
--------------------------------------------------------------------------------
1 | import store from './store.js';
2 |
3 | export default class LeaderboardControl {
4 | constructor() {
5 | this.$node = document.querySelector('form');
6 | this.$from = document.querySelector('#from');
7 | this.$input = document.querySelector('#url');
8 | this.$run = document.querySelector('#run');
9 | this.$reset = document.querySelector('#reset');
10 | }
11 |
12 | toggleDisabled() {
13 | const { leaderboardLoaded, urls } = store.getState();
14 | if (leaderboardLoaded === false && urls.length >= 1) {
15 | this.$run.removeAttribute('disabled');
16 | this.$reset.removeAttribute('disabled');
17 | return;
18 | }
19 |
20 | if (leaderboardLoaded === false) {
21 | this.$run.setAttribute('disabled', 'disabled');
22 | this.$reset.setAttribute('disabled', 'disabled');
23 | return;
24 | }
25 | }
26 |
27 | addEvents() {
28 | this.$node.addEventListener('submit', (eve) => {
29 | eve.preventDefault();
30 |
31 | if (eve.submitter.id === 'add') {
32 | const { leaderboardLoaded } = store.getState();
33 |
34 | if (leaderboardLoaded) {
35 | store.dispatch({ type: 'RESET' });
36 | }
37 |
38 | store.dispatch({
39 | type: 'ADD_URL',
40 | value: this.$input.value,
41 | });
42 |
43 | } else if (eve.submitter.id === 'run') {
44 | store.dispatch({ type: 'LEADERBOARD_UPDATE' });
45 |
46 | const { from, urls } = store.getState();
47 | const encodedUrls = urls.map((url) => encodeURIComponent(url)).join(',');
48 | const params = new URLSearchParams(`from=${from}&competitors=${encodedUrls}`);
49 | window.history.replaceState({}, '', `${location.pathname}?${params}`);
50 |
51 | ga('send', {
52 | hitType: 'event',
53 | eventCategory: 'Leaderboard',
54 | eventAction: 'run',
55 | eventLabel: urls.join(','),
56 | });
57 | }
58 | this.$input.value = '';
59 | });
60 |
61 | this.$reset.addEventListener('click', () => store.dispatch({ type: 'RESET' }));
62 | this.$from.addEventListener('change', function () {
63 | store.dispatch({ type: 'CHANGE_FROM', value: this.value });
64 | });
65 | }
66 |
67 | init() {
68 | this.addEvents();
69 | store.subscribe(this.toggleDisabled.bind(this))
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/js/Loading.js:
--------------------------------------------------------------------------------
1 | import store from './store.js';
2 |
3 | export default class Loading {
4 | constructor() {
5 | this.$node = document.querySelector('#loading');
6 | }
7 |
8 | toggleVisibility() {
9 | const { running, leaderboardLoaded } = store.getState();
10 | if (running) {
11 | this.$node.removeAttribute('hidden');
12 | } else if (leaderboardLoaded) {
13 | this.$node.setAttribute('hidden', 'hidden');
14 | }
15 | }
16 |
17 | init() {
18 | store.subscribe(this.toggleVisibility.bind(this))
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/js/app.js:
--------------------------------------------------------------------------------
1 | import store from './store.js';
2 | import LeaderboardResults from './Leaderboard.js';
3 | import Loading from './Loading.js';
4 | import LeaderboardControl from './LeaderboardControl.js';
5 | import Filter from './Filter.js';
6 | import ErrorMessage from './ErrorMessage.js';
7 |
8 | const demoUrls = [
9 | 'https://www.cnn.com',
10 | 'https://www.nytimes.com',
11 | 'https://www.foxnews.com',
12 | 'https://www.theguardian.com/international',
13 | 'https://www.washingtonpost.com',
14 | ];
15 |
16 | export default function bootApp() {
17 | new LeaderboardResults().init();
18 | new Loading().init();
19 |
20 | requestIdleCallback(() => {
21 | new LeaderboardControl().init();
22 | new Filter().init();
23 | new ErrorMessage().init();
24 | });
25 |
26 | const url = new URL(window.location.href);
27 | const params = new URLSearchParams(url.search);
28 |
29 | if (params.has('competitors')) {
30 | store.dispatch({
31 | type: 'LEADERBOARD_UPDATE',
32 | urls: params.get('competitors').split(','),
33 | from: params.get('from'),
34 | });
35 | const { urls } = store.getState();
36 | requestIdleCallback(() => {
37 | ga('send', {
38 | hitType: 'event',
39 | eventCategory: 'Leaderboard',
40 | eventAction: 'share',
41 | eventLabel: urls.join(','),
42 | });
43 | });
44 | } else {
45 | store.dispatch({
46 | type: 'LEADERBOARD_UPDATE',
47 | urls: demoUrls,
48 | });
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/js/store.js:
--------------------------------------------------------------------------------
1 | import unistore from 'https://unpkg.com/unistore@3.5.2/dist/unistore.es.js';
2 |
3 | const initialState = {
4 | urls: [],
5 | from: 'urls',
6 | running: false,
7 | results: null,
8 | leaderboardLoaded: false,
9 | leaderboardError: false,
10 | filters: {
11 | device: 'PHONE',
12 | }
13 | };
14 |
15 | function leaderboard(state = {}, action) {
16 | const newState = { ...state };
17 |
18 | switch (action.type) {
19 | case 'LEADERBOARD_UPDATE':
20 | newState.running = true;
21 |
22 | if (action.urls) {
23 | newState.urls = action.urls;
24 | }
25 | if (action.from) {
26 | newState.from = action.from;
27 | }
28 | return newState;
29 |
30 | case 'LEADERBOARD_LOADED':
31 | newState.running = false;
32 | newState.leaderboardLoaded = true;
33 | newState.results = action.results || null;
34 | newState.leaderboardError = action.error || false;
35 | return newState;
36 |
37 | case 'CHANGE_DEVICE':
38 | newState.running = true;
39 | newState.results = null;
40 | newState.filters.device = action.value;
41 | return newState;
42 |
43 | case 'CHANGE_FROM':
44 | return {
45 | ...initialState,
46 | from: action.value,
47 | };
48 |
49 | case 'ADD_URL':
50 | const value = Array.isArray(action.value) ? action.value : [action.value];
51 | newState.urls = [...state.urls, ...value];
52 | newState.running = false;
53 | newState.results = null;
54 | newState.leaderboardLoaded = false;
55 | return newState;
56 |
57 | case 'REMOVE_URL':
58 | newState.urls = state.urls.filter(url => url !== action.value);
59 | newState.running = false;
60 | newState.results = null;
61 | newState.leaderboardLoaded = false;
62 | return newState;
63 |
64 | case 'RESET':
65 | return initialState;
66 |
67 | default:
68 | return newState;
69 | }
70 | }
71 |
72 | const store = unistore(initialState);
73 |
74 | // Create a dispatch method like Redux
75 | store.dispatch = store.action(leaderboard);
76 |
77 | export default store;
78 |
--------------------------------------------------------------------------------
/src/js/templates.js:
--------------------------------------------------------------------------------
1 | const positions = ['🥇', '🥈', '🥉'];
2 | const healthy = {
3 | FCP: (value) => value <= 1.8 ? 'fast' : (value >= 3 ? 'fail' : 'average'),
4 | LCP: (value) => value <= 2.5 ? 'fast' : (value >= 4 ? 'fail' : 'average'),
5 | INP: (value) => value <= 200 ? 'fast' : (value >= 500 ? 'fail' : 'average'),
6 | CLS: (value) => value <= 0.1 ? 'fast' : (value >= 0.25 ? 'fail' : 'average'),
7 | };
8 |
9 | function getSiteInfo(url) {
10 | const { host } = new URL(url);
11 | return `
12 |
13 |
14 |
${host.split('.')[1].toUpperCase()}
15 |
${url}
16 |
17 | `
18 | }
19 |
20 | export function resultTemplate(site, position) {
21 | const url = site.origin || site.url;
22 |
23 | if (site.metrics === null) {
24 | return noDataTemplate(url, site.error);
25 | }
26 |
27 | const fcp = site.metrics.FCP && (site.metrics.FCP.value/1000).toFixed(2) || '-';
28 | const lcp = site.metrics.LCP && (site.metrics.LCP.value/1000).toFixed(2) || '-';
29 | const cls = site.metrics.CLS && site.metrics.CLS.value || '-';
30 | const inp = site.metrics.INP && site.metrics.INP.value || '-';
31 |
32 | return (`
33 |
34 | ${positions[position-1] || position}
35 | ${getSiteInfo(url)}
36 | ${fcp}s
37 | ${lcp}s
38 | ${cls}
39 | ${inp}ms
40 |
41 | `);
42 | }
43 |
44 | export function skeletonTemplate(url) {
45 | return (`
46 |
47 | -
48 | ${getSiteInfo(url)}
49 | -
50 | -
51 | -
52 | -
53 | -
54 |
55 | `);
56 | }
57 |
58 | export function noDataTemplate(url, message) {
59 | return (`
60 |
61 | -
62 | ${getSiteInfo(url)}
63 | ${message}
64 |
65 | `);
66 | }
67 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
3 | table-layout: fixed;
4 | border-collapse: collapse;
5 | margin: 0 auto;
6 | text-align: center;
7 | min-height: 100vh;
8 | color: #333333;
9 | font-size: 16px;
10 | }
11 |
12 | abbr {
13 | text-decoration: none;
14 | }
15 |
16 | a {
17 | color: #616161;
18 | }
19 |
20 | h1 {
21 | margin: 0;
22 | font-size: 64px;
23 | line-height: 1em;
24 | margin: 25px 0;
25 | font-weight: 500;
26 | }
27 |
28 | h1 span {
29 | color: #6ACDC0;
30 | }
31 |
32 | h2 {
33 | font-size: 24px;
34 | font-weight: 300;
35 | max-width: 700px;
36 | margin: 20px auto 40px;
37 | padding: 0 10px;
38 | }
39 |
40 | input,
41 | select,
42 | button {
43 | display: inline-block;
44 | vertical-align: middle;
45 | border: 1px solid transparent;
46 | }
47 |
48 | select {
49 | appearance: none;
50 | border: none;
51 | padding: 0.6em 1.2em;
52 | color: #333333;
53 | font-size: 16px;
54 | text-transform: uppercase;
55 | border-radius: 3px;
56 | background-color: transparent;
57 | background-image: url("data:image/svg+xml;utf8, ");
58 | background-size: 12px;
59 | background-position: 95% .9em;
60 | background-repeat: no-repeat;
61 | }
62 |
63 | button {
64 | font-size: 16px;
65 | text-transform: uppercase;
66 | cursor: pointer;
67 | border-radius: 3px;
68 | height: auto;
69 | line-height: 23px;
70 | text-decoration: none;
71 | white-space: nowrap;
72 | box-sizing: border-box;
73 | padding: 0.5em 1em;
74 | background-color: #322241;
75 | border-color: #664584;
76 | color: white;
77 | }
78 |
79 | button[type="reset"] {
80 | background-color: transparent;
81 | border-color: #664584;
82 | }
83 |
84 | button[disabled] {
85 | background-color: #251931;
86 | border-color: #322241;
87 | color: #C1A9D8;
88 | cursor: not-allowed;
89 | }
90 |
91 | input[type="url"] {
92 | border-left-color: #D4D4D4;
93 | color: #333333;
94 | font-size: 18px;
95 | height: 58px;
96 | text-align: 58px;
97 | padding: 0 20px;
98 | }
99 |
100 | :focus {
101 | outline-color: #664584;
102 | }
103 |
104 | button:focus,
105 | input:focus,
106 | select:focus {
107 | outline: 0;
108 | box-shadow: 0 0 10px 5px #664584;
109 | }
110 |
111 | .heroo {
112 | background-color: #2B2B52;
113 | color: lightgray;
114 | padding: 20px 0px 150px;
115 | }
116 |
117 | .heroo a {
118 | color: lightgray;
119 | }
120 |
121 | .heroo h3 {
122 | font-weight: 400;
123 | }
124 |
125 | .primary-controls {
126 | background-color: white;
127 | box-shadow: 0px 3px 24px rgba(0, 0, 0, 0.36);
128 | border-radius: 32px;
129 | max-width: 700px;
130 | padding: 5px 0;
131 | margin: 0 auto;
132 | }
133 |
134 | .add-button {
135 | width: 58px;
136 | height: 58px;
137 | border-radius: 100%;
138 | border: none;
139 | padding: 0;
140 | position: relative;
141 | right: -3px;
142 | }
143 |
144 | .results {
145 | position: relative;
146 | top: -120px;
147 | padding: 10px 0 30px;
148 |
149 | box-shadow: 0px 4px 28px rgba(0, 0, 0, 0.12);
150 | border-radius: 6px;
151 | background: white;
152 | max-width: 95%;
153 | margin: 0 auto;
154 |
155 | min-height: 170px;
156 | z-index: 1;
157 | }
158 |
159 | .loading {
160 | position: absolute;
161 | top: 0;
162 | left: 50%;
163 | margin-left: -100px;
164 | z-index: -1;
165 | }
166 |
167 | .filters {
168 | margin: 15px 0;
169 | }
170 |
171 | table {
172 | border-spacing: 0;
173 | border-collapse: collapse;
174 | margin: 30px auto 10px;
175 | width: 90%;
176 | }
177 |
178 | tbody {
179 | text-align: left;
180 | }
181 |
182 | tbody tr {
183 | background-color: #ffffff;
184 | }
185 |
186 | tbody tr:nth-child(even) {
187 | background-color: #f6f6f6;
188 | }
189 |
190 | th {
191 | font-size: 12px;
192 | text-transform: uppercase;
193 | padding: 5px 0 15px;
194 | }
195 |
196 | td {
197 | padding: 1rem 1rem 1rem 2rem;
198 | }
199 |
200 | .logo {
201 | border-radius: 4px;
202 | float: left;
203 | display: block;
204 | }
205 |
206 | .site {
207 | margin-left: 40px;
208 | min-width: 300px;
209 | }
210 |
211 | .site strong {
212 | margin: 0 0 3px;
213 | font-size: 12px;
214 | }
215 |
216 | .url {
217 | white-space: nowrap;
218 | max-width: 400px;
219 | text-overflow: ellipsis;
220 | overflow: hidden;
221 | display: block;
222 | font-weight: 400;
223 | }
224 |
225 | .ranking {
226 | text-align: center;
227 | }
228 |
229 | .rank-1 {
230 | font-size: 3em;
231 | }
232 |
233 | .rank-2 {
234 | font-size: 2.5em;
235 | }
236 |
237 | .rank-3 {
238 | font-size: 2em;
239 | }
240 |
241 | .fast,
242 | .average,
243 | .fail {
244 | font-weight: 500;
245 | border-style: inset;
246 | text-align: right;
247 | font-size: 15px;
248 | border: 3px solid white !important;
249 | }
250 |
251 | .fast {
252 | background-color: #6ACDC0;
253 | border-color: #6ACDC0;
254 | }
255 | .average {
256 | background-color: #FFF292;
257 | border-color: #FFF292;
258 | }
259 | .fail {
260 | background-color: #FF8484;
261 | border-color: #FF8484;
262 | }
263 |
264 | .data-not-found {
265 | text-align: center;
266 | text-transform: capitalize;
267 | }
268 |
269 | hr {
270 | width: 50%;
271 | margin: 20px auto;
272 | border: none;
273 | border-top: 1px solid #f5f5f5;
274 | }
275 |
276 | .faq {
277 | position: relative;
278 | top: -50px;
279 | padding: 10px 50px 30px;
280 | margin: 0 auto;
281 | background-color: #f9f9f9;
282 | }
283 |
284 | .faq h2 {
285 | text-align: center;
286 | margin-bottom: 15px;
287 | }
288 |
289 | .faq details {
290 | display: inline-block;
291 | text-align: left;
292 | width: 49%;
293 | vertical-align: top;
294 | margin: 20px 0;
295 | }
296 |
297 | .faq summary {
298 | font-size: 18px;
299 | font-weight: 300;
300 | margin: 10px 0;
301 | }
302 |
303 | .faq p {
304 | color: #616161;
305 | font-size: 14px;
306 | line-height: 1.6em;
307 | margin: 0;
308 | width: 75%;
309 | }
310 |
311 | footer {
312 | margin-top: 20px;
313 | font-size: 12px;
314 | }
315 |
316 | .copyright {
317 | font-size: 9px;
318 | position: absolute;
319 | top: 5px;
320 | right: 5px;
321 | }
322 |
323 | .copyright,
324 | .copyright a {
325 | color:lightgray;
326 | }
327 |
328 | /*
329 | * Media queries
330 | */
331 | @media (min-width: 320px) and (max-width: 480px) {
332 | h1 {
333 | font-size: 36px;
334 | margin: auto;
335 | }
336 |
337 | h2 {
338 | font-size: 20px;
339 | }
340 |
341 | td {
342 | padding: .8rem;
343 | }
344 |
345 | table th:nth-child(1),
346 | .ranking,
347 | .site {
348 | display: none;
349 | }
350 |
351 | .faq details,
352 | .faq p {
353 | width: 100%;
354 | }
355 |
356 | input[type="url"] {
357 | width: 170px;
358 | }
359 |
360 | }
361 |
--------------------------------------------------------------------------------