Dhalang 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }