Dhalang 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,11 @@
1
- module Dhalang
2
- require 'PDF'
3
- require 'Screenshot'
1
+ module Dhalang
2
+ require_relative 'PDF'
3
+ require_relative 'Screenshot'
4
+ require_relative 'Dhalang/version'
5
+ require_relative 'Dhalang/url_utils'
6
+ require_relative 'Dhalang/file_utils'
7
+ require_relative 'Dhalang/puppeteer'
8
+ require 'uri'
9
+ require 'tempfile'
10
+ require 'shellwords'
4
11
  end
@@ -0,0 +1,37 @@
1
+ module Dhalang
2
+ # Contains common logic for files.
3
+ class FileUtils
4
+
5
+ # Reads the file under the given filepath as a binary.
6
+ #
7
+ # @param [String] file_path The absolute path of the file to read.
8
+ #
9
+ # @return [String] The binary content under the file_path.
10
+ def self.read_binary(file_path)
11
+ IO.binread(file_path)
12
+ end
13
+
14
+ # Creates a new temp file.
15
+ #
16
+ # @param [String] extension The extension of the file.
17
+ # @param [String] content The content of the file. (Optional)
18
+ #
19
+ # @return [Tempfile] The created temp file.
20
+ def self.create_temp_file(extension, content = nil)
21
+ temp_file = Tempfile.new(["dhalang",".#{extension}"])
22
+ unless(content == nil)
23
+ temp_file.write(content)
24
+ temp_file.rewind
25
+ end
26
+ temp_file
27
+ end
28
+
29
+ # Deletes the given file.
30
+ #
31
+ # @param [File] file The file to delete.
32
+ def self.delete(file)
33
+ file.close unless file.closed?
34
+ file.unlink
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ module Dhalang
2
+ # Contains common logic for interacting with Puppeteer.
3
+ class Puppeteer
4
+ NODE_MODULES_PATH = Dir.pwd + '/node_modules/'.freeze
5
+ private_constant :NODE_MODULES_PATH
6
+
7
+ # Launches a new Node process, executing the (Puppeteer) script under the given script_path.
8
+ #
9
+ # @param [String] page_url The url to pass to the goTo method of Puppeteer.
10
+ # @param [String] script_path The absolute path of the JS script to execute.
11
+ # @param [String] temp_file_path The absolute path of the temp file to use to write any actions tom from Puppeteer.
12
+ # @param [String] temp_file_extension The extension of the temp file.
13
+ def self.visit(page_url, script_path, temp_file_path, temp_file_extension)
14
+ system("node #{script_path} #{Shellwords.escape(NODE_MODULES_PATH)} #{page_url} #{Shellwords.escape(temp_file_path)} #{Shellwords.escape(temp_file_extension)}")
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ module Dhalang
2
+ # Contains common logic for URL's.
3
+ class UrlUtils
4
+
5
+ # Raises an error if the given URL cannot be used for navigation with Puppeteer.
6
+ #
7
+ # @param [String] url The url to validate
8
+ def self.validate(url)
9
+ if (url !~ URI::DEFAULT_PARSER.regexp[:ABS_URI])
10
+ raise URI::InvalidURIError, 'The given url was invalid, use format http://www.example.com'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
- module Dhalang
2
- VERSION = "0.2.0"
3
- end
1
+ module Dhalang
2
+ VERSION = "0.3.0"
3
+ end
data/lib/PDF.rb CHANGED
@@ -1,65 +1,51 @@
1
- require "Dhalang/version"
2
- require 'uri'
3
- require 'tempfile'
4
-
5
- module Dhalang
6
- class PDF
7
- PDF_GENERATOR_JS_PATH = File.expand_path('../js/pdfgenerator.js', __FILE__)
8
- PROJECT_PATH = Dir.pwd + '/node_modules/'
9
-
10
- def self.get_from_url(url)
11
- validate_url(url)
12
- temporary_pdf_save_file = create_temporary_pdf_file
13
- begin
14
- visit_page_with_puppeteer(url, temporary_pdf_save_file.path)
15
- binary_pdf_content = get_file_content_as_binary_string(temporary_pdf_save_file)
16
- ensure
17
- temporary_pdf_save_file.close unless temporary_pdf_save_file.closed?
18
- temporary_pdf_save_file.unlink
19
- end
20
- return binary_pdf_content
21
- end
22
-
23
- def self.get_from_html(html)
24
- html_file = create_temporary_html_file(html)
25
- temporary_pdf_save_file = create_temporary_pdf_file
26
- begin
27
- visit_page_with_puppeteer("file://" + html_file.path, temporary_pdf_save_file.path)
28
- binary_pdf_content = get_file_content_as_binary_string(temporary_pdf_save_file)
29
- ensure
30
- temporary_pdf_save_file.close unless temporary_pdf_save_file.closed?
31
- html_file.close unless html_file.closed?
32
- temporary_pdf_save_file.unlink
33
- html_file.unlink
34
- end
35
- return binary_pdf_content
36
- end
37
-
38
- private
39
- def self.validate_url(url)
40
- if (url !~ URI::DEFAULT_PARSER.regexp[:ABS_URI])
41
- raise URI::InvalidURIError, 'The given url was invalid, use format http://www.example.com'
42
- end
43
- end
44
-
45
- def self.create_temporary_pdf_file
46
- Tempfile.new("pdf")
47
- end
48
-
49
- ## Creates a temp .html file which can be browsed to by puppeteer for creating a pdf
50
- def self.create_temporary_html_file(content)
51
- html_file = Tempfile.new(['page', '.html'])
52
- html_file.write(content)
53
- html_file.rewind
54
- return html_file
55
- end
56
-
57
- def self.visit_page_with_puppeteer(page_to_visit, path_to_save_pdf_to)
58
- system("node #{PDF_GENERATOR_JS_PATH} #{page_to_visit} #{Shellwords.escape(path_to_save_pdf_to)} #{Shellwords.escape(PROJECT_PATH)}")
59
- end
60
-
61
- def self.get_file_content_as_binary_string(file)
62
- IO.binread(file.path)
63
- end
64
- end
65
- end
1
+ module Dhalang
2
+ # Allows consumers of this library to create PDFs with Puppeteer.
3
+ class PDF
4
+ PUPPETEER_SCRIPT_PATH = File.expand_path('../js/pdf-generator.js', __FILE__).freeze
5
+ private_constant :PUPPETEER_SCRIPT_PATH
6
+
7
+ # Captures the full webpage under the given url as PDF.
8
+ #
9
+ # @param [String] url The url to get as PDF.
10
+ #
11
+ # @return [String] The PDF that was created as binary.
12
+ def self.get_from_url(url)
13
+ UrlUtils.validate(url)
14
+ get(url)
15
+ end
16
+
17
+ # Captures the full HTML as PDF.
18
+ # Useful when creating dynamic content, for example invoices.
19
+ #
20
+ # @param [String] html The html to get as PDF.
21
+ #
22
+ # @return [String] The PDF that was created as binary.
23
+ def self.get_from_html(html)
24
+ html_file = FileUtils.create_temp_file("html", html)
25
+ url = "file://" + html_file.path
26
+ begin
27
+ binary_pdf_content = get(url)
28
+ ensure
29
+ FileUtils.delete(html_file)
30
+ end
31
+ return binary_pdf_content
32
+ end
33
+
34
+
35
+ # Groups and executes the logic for creating a PDF of a webpage.
36
+ #
37
+ # @param [String] url The url to create a PDF for.
38
+ #
39
+ # @return [String] The PDF that was created as binary.
40
+ private_class_method def self.get(url)
41
+ temp_file = FileUtils.create_temp_file("pdf")
42
+ begin
43
+ Puppeteer.visit(url, PUPPETEER_SCRIPT_PATH, temp_file.path, "pdf")
44
+ binary_pdf_content = FileUtils.read_binary(temp_file.path)
45
+ ensure
46
+ FileUtils.delete(temp_file)
47
+ end
48
+ return binary_pdf_content
49
+ end
50
+ end
51
+ end
@@ -1,51 +1,43 @@
1
- require "Dhalang/version"
2
- require 'uri'
3
- require 'tempfile'
4
-
5
- module Dhalang
6
- class Screenshot
7
- SCREENSHOT_GENERATOR_JS_PATH = File.expand_path('../js/screenshotgenerator.js', __FILE__)
8
- PROJECT_PATH = Dir.pwd + '/node_modules/'
9
-
10
- def self.get_from_url_as_jpeg(url)
11
- validate_url(url)
12
- get_image(url, :jpeg)
13
- end
14
-
15
- def self.get_from_url_as_png(url)
16
- validate_url(url)
17
- get_image(url, :png)
18
- end
19
-
20
- private
21
- def self.validate_url(url)
22
- if (url !~ URI::DEFAULT_PARSER.regexp[:ABS_URI])
23
- raise URI::InvalidURIError, 'The given url was invalid, use format http://www.example.com'
24
- end
25
- end
26
-
27
- def self.create_temporary_screenshot_file
28
- Tempfile.new("png")
29
- end
30
-
31
- def self.get_image(url, type)
32
- temporary_screenshot_save_file = create_temporary_screenshot_file
33
- begin
34
- visit_page_with_puppeteer(url, temporary_screenshot_save_file.path, type)
35
- binary_image_content = get_file_content_as_binary_string(temporary_screenshot_save_file)
36
- ensure
37
- temporary_screenshot_save_file.close unless temporary_screenshot_save_file.closed?
38
- temporary_screenshot_save_file.unlink
39
- end
40
- return binary_image_content
41
- end
42
-
43
- def self.visit_page_with_puppeteer(page_to_visit, path_to_save_pdf_to, image_save_type)
44
- system("node #{SCREENSHOT_GENERATOR_JS_PATH} #{page_to_visit} #{Shellwords.escape(path_to_save_pdf_to)} #{Shellwords.escape(PROJECT_PATH)} #{Shellwords.escape(image_save_type)}")
45
- end
46
-
47
- def self.get_file_content_as_binary_string(file)
48
- IO.binread(file.path)
49
- end
50
- end
51
- end
1
+ module Dhalang
2
+ # Allows consumers of this library to take screenshots with Puppeteer.
3
+ class Screenshot
4
+ PUPPETEER_SCRIPT_PATH = File.expand_path('../js/screenshot-generator.js', __FILE__).freeze
5
+ private_constant :PUPPETEER_SCRIPT_PATH
6
+
7
+ # Captures a full JPEG screenshot of the webpage under the given url.
8
+ #
9
+ # @param [String] url The url to take a screenshot of.
10
+ #
11
+ # @return [String] the screenshot that was taken as binary.
12
+ def self.get_from_url_as_jpeg(url)
13
+ get(url, "jpeg")
14
+ end
15
+
16
+ # Captures a full PNG screenshot of the webpage under the given url.
17
+ #
18
+ # @param [String] url The url to take a screenshot of.
19
+ #
20
+ # @return [String] The screenshot that was taken as binary.
21
+ def self.get_from_url_as_png(url)
22
+ get(url, "png")
23
+ end
24
+
25
+ # Groups and executes the logic for taking a screenhot of a webpage.
26
+ #
27
+ # @param [String] url The url to take a screenshot of.
28
+ # @param [String] image_type The image type to use for storing the screenshot.
29
+ #
30
+ # @return [String] The screenshot that was taken as binary.
31
+ private_class_method def self.get(url, image_type)
32
+ UrlUtils.validate(url)
33
+ temp_file = FileUtils.create_temp_file(image_type)
34
+ begin
35
+ Puppeteer.visit(url, PUPPETEER_SCRIPT_PATH, temp_file.path, image_type)
36
+ binary_image_content = FileUtils.read_binary(temp_file.path)
37
+ ensure
38
+ FileUtils.delete(temp_file)
39
+ end
40
+ return binary_image_content
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @typedef {Object} Configuration
3
+ * @property {string} webPageUrl - The url of the webpage to visit.
4
+ * @property {string} tempFilePath - The path of the tempfile to write the screenshot/pdf to.
5
+ * @property {string} puppeteerModulePath - The path of the Puppeteer module.
6
+ * @property {string} imageType - The type of image to save ( undefined for pdfgenerator ).
7
+ */
8
+
9
+ /**
10
+ * @typedef {Object} NavigationParameters
11
+ * @property {number} timeout - Maximum in milliseconds until navigation times out, we use a default of 10 seconds as timeout.
12
+ * @property {string} waituntil - Determines when the navigation was finished, we wait here until the Window.load event is fired ( meaning all images, stylesheet, etc was loaded ).
13
+ */
14
+
15
+ /**
16
+ * Generates a configuration object based on the given process arguments from Ruby.
17
+ * @param {Boolean} isForScreenshotGenerator - Indicates if this configuration is for a screenshot generator.
18
+ * @returns {Configuration}
19
+ * The generated configuration object.
20
+ */
21
+ exports.getConfiguration = function (isForScreenshotGenerator) {
22
+ return {
23
+ puppeteerPath: process.argv[2],
24
+ webPageUrl: process.argv[3],
25
+ tempFilePath: process.argv[4],
26
+ imageType: isForScreenshotGenerator ? process.argv[5] : undefined
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Launches Puppeteer and returns its instance.
32
+ * @param {string} puppeteerModulePath - The path puppeteer is under.
33
+ * @returns {Promise<Object>}
34
+ * The launched instance of Puppeteer.
35
+ */
36
+ exports.launchPuppeteer = async function (puppeteerModulePath) {
37
+ module.paths.push(puppeteerModulePath);
38
+ const puppeteer = require('puppeteer');
39
+ return await puppeteer.launch({
40
+ args: ['--no-sandbox', '--disable-setuid-sandbox']
41
+ });
42
+ }
43
+
44
+ /**
45
+ * Returns a new object containing the navigation parameters to use when navigating with Puppeteer to web pages.
46
+ * @returns {NavigationParameters}
47
+ * The navigation parameters to use.
48
+ */
49
+ exports.getNavigationParameters = function () {
50
+ return {
51
+ timeout: 10000,
52
+ waitUntil: 'load'
53
+ }
54
+ }
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+ const dhalang = require('./dhalang');
3
+
4
+ const createPdf = async () => {
5
+ const configuration = dhalang.getConfiguration(false);
6
+
7
+ let browser;
8
+ try {
9
+ browser = await dhalang.launchPuppeteer(configuration.puppeteerModulePath);
10
+ const page = await browser.newPage();
11
+ await page.goto(configuration.webPageUrl, dhalang.getNavigationParameters());
12
+ await page.waitFor(250);
13
+ await page.pdf({
14
+ path: configuration.tempFilePath,
15
+ format: 'A4',
16
+ margin: {
17
+ top: 36,
18
+ right: 36,
19
+ bottom: 20,
20
+ left: 36
21
+ },
22
+ printBackground: true
23
+ });
24
+ } catch (error) {
25
+ console.log(error.message);
26
+ } finally {
27
+ if (browser) {
28
+ browser.close();
29
+ }
30
+ process.exit();
31
+ }
32
+ };
33
+ createPdf();
@@ -0,0 +1,27 @@
1
+ 'use strict';
2
+ const dhalang = require('./dhalang')
3
+
4
+ const createPdf = async () => {
5
+ const configuration = dhalang.getConfiguration(true);
6
+
7
+ let browser;
8
+ try {
9
+ browser = await dhalang.launchPuppeteer(configuration.puppeteerModulePath);
10
+ const page = await browser.newPage();
11
+ await page.goto(configuration.webPageUrl, dhalang.getNavigationParameters());
12
+ await page.waitFor(250);
13
+ await page.screenshot({
14
+ path: configuration.tempFilePath,
15
+ type: configuration.imageType,
16
+ fullPage: true
17
+ });
18
+ } catch (error) {
19
+ console.log(error.message);
20
+ } finally {
21
+ if (browser) {
22
+ browser.close();
23
+ }
24
+ process.exit();
25
+ }
26
+ };
27
+ createPdf();
@@ -0,0 +1,367 @@
1
+ {
2
+ "name": "dhalang",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 1,
5
+ "requires": true,
6
+ "dependencies": {
7
+ "agent-base": {
8
+ "version": "4.3.0",
9
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
10
+ "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
11
+ "dev": true,
12
+ "requires": {
13
+ "es6-promisify": "^5.0.0"
14
+ }
15
+ },
16
+ "async-limiter": {
17
+ "version": "1.0.1",
18
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
19
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
20
+ "dev": true
21
+ },
22
+ "balanced-match": {
23
+ "version": "1.0.0",
24
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
25
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
26
+ "dev": true
27
+ },
28
+ "brace-expansion": {
29
+ "version": "1.1.11",
30
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
31
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
32
+ "dev": true,
33
+ "requires": {
34
+ "balanced-match": "^1.0.0",
35
+ "concat-map": "0.0.1"
36
+ }
37
+ },
38
+ "buffer-crc32": {
39
+ "version": "0.2.13",
40
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
41
+ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
42
+ "dev": true
43
+ },
44
+ "buffer-from": {
45
+ "version": "1.1.1",
46
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
47
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
48
+ "dev": true
49
+ },
50
+ "concat-map": {
51
+ "version": "0.0.1",
52
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
53
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
54
+ "dev": true
55
+ },
56
+ "concat-stream": {
57
+ "version": "1.6.2",
58
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
59
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
60
+ "dev": true,
61
+ "requires": {
62
+ "buffer-from": "^1.0.0",
63
+ "inherits": "^2.0.3",
64
+ "readable-stream": "^2.2.2",
65
+ "typedarray": "^0.0.6"
66
+ }
67
+ },
68
+ "core-util-is": {
69
+ "version": "1.0.2",
70
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
71
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
72
+ "dev": true
73
+ },
74
+ "debug": {
75
+ "version": "4.1.1",
76
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
77
+ "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
78
+ "dev": true,
79
+ "requires": {
80
+ "ms": "^2.1.1"
81
+ }
82
+ },
83
+ "es6-promise": {
84
+ "version": "4.2.8",
85
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
86
+ "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
87
+ "dev": true
88
+ },
89
+ "es6-promisify": {
90
+ "version": "5.0.0",
91
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
92
+ "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
93
+ "dev": true,
94
+ "requires": {
95
+ "es6-promise": "^4.0.3"
96
+ }
97
+ },
98
+ "extract-zip": {
99
+ "version": "1.7.0",
100
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
101
+ "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==",
102
+ "dev": true,
103
+ "requires": {
104
+ "concat-stream": "^1.6.2",
105
+ "debug": "^2.6.9",
106
+ "mkdirp": "^0.5.4",
107
+ "yauzl": "^2.10.0"
108
+ },
109
+ "dependencies": {
110
+ "debug": {
111
+ "version": "2.6.9",
112
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
113
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
114
+ "dev": true,
115
+ "requires": {
116
+ "ms": "2.0.0"
117
+ }
118
+ },
119
+ "ms": {
120
+ "version": "2.0.0",
121
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
122
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
123
+ "dev": true
124
+ }
125
+ }
126
+ },
127
+ "fd-slicer": {
128
+ "version": "1.1.0",
129
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
130
+ "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
131
+ "dev": true,
132
+ "requires": {
133
+ "pend": "~1.2.0"
134
+ }
135
+ },
136
+ "fs.realpath": {
137
+ "version": "1.0.0",
138
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
139
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
140
+ "dev": true
141
+ },
142
+ "glob": {
143
+ "version": "7.1.6",
144
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
145
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
146
+ "dev": true,
147
+ "requires": {
148
+ "fs.realpath": "^1.0.0",
149
+ "inflight": "^1.0.4",
150
+ "inherits": "2",
151
+ "minimatch": "^3.0.4",
152
+ "once": "^1.3.0",
153
+ "path-is-absolute": "^1.0.0"
154
+ }
155
+ },
156
+ "https-proxy-agent": {
157
+ "version": "2.2.4",
158
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
159
+ "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
160
+ "dev": true,
161
+ "requires": {
162
+ "agent-base": "^4.3.0",
163
+ "debug": "^3.1.0"
164
+ },
165
+ "dependencies": {
166
+ "debug": {
167
+ "version": "3.2.6",
168
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
169
+ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
170
+ "dev": true,
171
+ "requires": {
172
+ "ms": "^2.1.1"
173
+ }
174
+ }
175
+ }
176
+ },
177
+ "inflight": {
178
+ "version": "1.0.6",
179
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
180
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
181
+ "dev": true,
182
+ "requires": {
183
+ "once": "^1.3.0",
184
+ "wrappy": "1"
185
+ }
186
+ },
187
+ "inherits": {
188
+ "version": "2.0.4",
189
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
190
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
191
+ "dev": true
192
+ },
193
+ "isarray": {
194
+ "version": "1.0.0",
195
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
196
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
197
+ "dev": true
198
+ },
199
+ "mime": {
200
+ "version": "2.4.6",
201
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
202
+ "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==",
203
+ "dev": true
204
+ },
205
+ "minimatch": {
206
+ "version": "3.0.4",
207
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
208
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
209
+ "dev": true,
210
+ "requires": {
211
+ "brace-expansion": "^1.1.7"
212
+ }
213
+ },
214
+ "minimist": {
215
+ "version": "1.2.5",
216
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
217
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
218
+ "dev": true
219
+ },
220
+ "mkdirp": {
221
+ "version": "0.5.5",
222
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
223
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
224
+ "dev": true,
225
+ "requires": {
226
+ "minimist": "^1.2.5"
227
+ }
228
+ },
229
+ "ms": {
230
+ "version": "2.1.2",
231
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
232
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
233
+ "dev": true
234
+ },
235
+ "once": {
236
+ "version": "1.4.0",
237
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
238
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
239
+ "dev": true,
240
+ "requires": {
241
+ "wrappy": "1"
242
+ }
243
+ },
244
+ "path-is-absolute": {
245
+ "version": "1.0.1",
246
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
247
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
248
+ "dev": true
249
+ },
250
+ "pend": {
251
+ "version": "1.2.0",
252
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
253
+ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
254
+ "dev": true
255
+ },
256
+ "process-nextick-args": {
257
+ "version": "2.0.1",
258
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
259
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
260
+ "dev": true
261
+ },
262
+ "progress": {
263
+ "version": "2.0.3",
264
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
265
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
266
+ "dev": true
267
+ },
268
+ "proxy-from-env": {
269
+ "version": "1.1.0",
270
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
271
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
272
+ "dev": true
273
+ },
274
+ "puppeteer": {
275
+ "version": "1.20.0",
276
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.20.0.tgz",
277
+ "integrity": "sha512-bt48RDBy2eIwZPrkgbcwHtb51mj2nKvHOPMaSH2IsWiv7lOG9k9zhaRzpDZafrk05ajMc3cu+lSQYYOfH2DkVQ==",
278
+ "dev": true,
279
+ "requires": {
280
+ "debug": "^4.1.0",
281
+ "extract-zip": "^1.6.6",
282
+ "https-proxy-agent": "^2.2.1",
283
+ "mime": "^2.0.3",
284
+ "progress": "^2.0.1",
285
+ "proxy-from-env": "^1.0.0",
286
+ "rimraf": "^2.6.1",
287
+ "ws": "^6.1.0"
288
+ }
289
+ },
290
+ "readable-stream": {
291
+ "version": "2.3.7",
292
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
293
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
294
+ "dev": true,
295
+ "requires": {
296
+ "core-util-is": "~1.0.0",
297
+ "inherits": "~2.0.3",
298
+ "isarray": "~1.0.0",
299
+ "process-nextick-args": "~2.0.0",
300
+ "safe-buffer": "~5.1.1",
301
+ "string_decoder": "~1.1.1",
302
+ "util-deprecate": "~1.0.1"
303
+ }
304
+ },
305
+ "rimraf": {
306
+ "version": "2.7.1",
307
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
308
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
309
+ "dev": true,
310
+ "requires": {
311
+ "glob": "^7.1.3"
312
+ }
313
+ },
314
+ "safe-buffer": {
315
+ "version": "5.1.2",
316
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
317
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
318
+ "dev": true
319
+ },
320
+ "string_decoder": {
321
+ "version": "1.1.1",
322
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
323
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
324
+ "dev": true,
325
+ "requires": {
326
+ "safe-buffer": "~5.1.0"
327
+ }
328
+ },
329
+ "typedarray": {
330
+ "version": "0.0.6",
331
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
332
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
333
+ "dev": true
334
+ },
335
+ "util-deprecate": {
336
+ "version": "1.0.2",
337
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
338
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
339
+ "dev": true
340
+ },
341
+ "wrappy": {
342
+ "version": "1.0.2",
343
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
344
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
345
+ "dev": true
346
+ },
347
+ "ws": {
348
+ "version": "6.2.1",
349
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
350
+ "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
351
+ "dev": true,
352
+ "requires": {
353
+ "async-limiter": "~1.0.0"
354
+ }
355
+ },
356
+ "yauzl": {
357
+ "version": "2.10.0",
358
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
359
+ "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
360
+ "dev": true,
361
+ "requires": {
362
+ "buffer-crc32": "~0.2.3",
363
+ "fd-slicer": "~1.1.0"
364
+ }
365
+ }
366
+ }
367
+ }