selenium-webdriver 3.1.0 → 3.6.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.
Files changed (65) hide show
  1. package/CHANGES.md +112 -0
  2. package/NOTICE +1 -1
  3. package/README.md +5 -11
  4. package/chrome.js +122 -33
  5. package/edge.js +2 -2
  6. package/example/async_await_test.js +69 -0
  7. package/example/chrome_android.js +2 -3
  8. package/example/chrome_mobile_emulation.js +3 -4
  9. package/example/firefox_channels.js +3 -3
  10. package/example/google_search.js +3 -3
  11. package/example/google_search_generator.js +2 -5
  12. package/example/google_search_test.js +5 -6
  13. package/example/headless.js +55 -0
  14. package/example/logging.js +3 -3
  15. package/example/parallel_flows.js +4 -7
  16. package/firefox/binary.js +3 -0
  17. package/firefox/extension.js +118 -81
  18. package/firefox/index.js +117 -263
  19. package/firefox/profile.js +18 -137
  20. package/ie.js +2 -2
  21. package/index.js +4 -1
  22. package/io/index.js +59 -0
  23. package/io/zip.js +214 -0
  24. package/lib/atoms/get-attribute.js +9 -0
  25. package/lib/atoms/is-displayed.js +73 -78
  26. package/lib/by.js +8 -0
  27. package/lib/capabilities.js +61 -22
  28. package/lib/command.js +2 -0
  29. package/lib/error.js +32 -2
  30. package/lib/http.js +53 -44
  31. package/lib/promise.js +72 -25
  32. package/lib/test/data/click_tests/disabled_element.html +12 -0
  33. package/lib/test/data/content-editable.html +10 -0
  34. package/lib/test/data/firefox/webextension.xpi +0 -0
  35. package/lib/test/data/key_logger.html +34 -0
  36. package/lib/test/data/nestedElements.html +10 -1
  37. package/lib/test/data/scrolling_tests/page_with_partially_hidden_element.html +14 -0
  38. package/lib/test/data/single_text_input.html +12 -0
  39. package/lib/test/index.js +4 -36
  40. package/lib/webdriver.js +147 -55
  41. package/net/portprober.js +1 -1
  42. package/opera.js +1 -1
  43. package/package.json +2 -2
  44. package/phantomjs.js +2 -2
  45. package/remote/index.js +21 -14
  46. package/safari.js +2 -2
  47. package/test/firefox/extension_test.js +41 -17
  48. package/test/firefox/firefox_test.js +37 -19
  49. package/test/firefox/profile_test.js +14 -59
  50. package/test/http/http_test.js +18 -0
  51. package/test/{io_test.js → io/io_test.js} +40 -1
  52. package/test/io/zip_test.js +128 -0
  53. package/test/lib/by_test.js +21 -0
  54. package/test/lib/error_test.js +21 -1
  55. package/test/lib/http_test.js +11 -3
  56. package/test/lib/webdriver_test.js +107 -3
  57. package/test/page_loading_test.js +0 -6
  58. package/test/remote_test.js +3 -3
  59. package/test/session_test.js +68 -23
  60. package/testing/index.js +2 -3
  61. package/lib/atoms/getAttribute.js +0 -12
  62. package/lib/firefox/amd64/libnoblur64.so +0 -0
  63. package/lib/firefox/i386/libnoblur.so +0 -0
  64. package/lib/firefox/webdriver.json +0 -69
  65. package/lib/firefox/webdriver.xpi +0 -0
@@ -22,50 +22,17 @@
22
22
 
23
23
  'use strict';
24
24
 
25
- const AdmZip = require('adm-zip'),
26
- fs = require('fs'),
25
+ const fs = require('fs'),
27
26
  path = require('path'),
28
27
  vm = require('vm');
29
28
 
30
29
  const isDevMode = require('../lib/devmode'),
31
30
  Symbols = require('../lib/symbols'),
32
31
  io = require('../io'),
32
+ {Zip, unzip} = require('../io/zip'),
33
33
  extension = require('./extension');
34
34
 
35
35
 
36
- /** @const */
37
- const WEBDRIVER_PREFERENCES_PATH = isDevMode
38
- ? path.join(__dirname, '../../../firefox-driver/webdriver.json')
39
- : path.join(__dirname, '../lib/firefox/webdriver.json');
40
-
41
- /** @const */
42
- const WEBDRIVER_EXTENSION_PATH = isDevMode
43
- ? path.join(__dirname,
44
- '../../../../build/javascript/firefox-driver/webdriver.xpi')
45
- : path.join(__dirname, '../lib/firefox/webdriver.xpi');
46
-
47
- /** @const */
48
- const WEBDRIVER_EXTENSION_NAME = 'fxdriver@googlecode.com';
49
-
50
-
51
-
52
- /** @type {Object} */
53
- var defaultPreferences = null;
54
-
55
- /**
56
- * Synchronously loads the default preferences used for the FirefoxDriver.
57
- * @return {!Object} The default preferences JSON object.
58
- */
59
- function getDefaultPreferences() {
60
- if (!defaultPreferences) {
61
- var contents = /** @type {string} */(
62
- fs.readFileSync(WEBDRIVER_PREFERENCES_PATH, 'utf8'));
63
- defaultPreferences = /** @type {!Object} */(JSON.parse(contents));
64
- }
65
- return defaultPreferences;
66
- }
67
-
68
-
69
36
  /**
70
37
  * Parses a user.js file in a Firefox profile directory.
71
38
  * @param {string} f Path to the file to parse.
@@ -107,9 +74,13 @@ function writeUserPrefs(prefs, dir) {
107
74
  var userPrefs = path.join(dir, 'user.js');
108
75
  return loadUserPrefs(userPrefs).then(function(overrides) {
109
76
  Object.assign(prefs, overrides);
110
- Object.assign(prefs, getDefaultPreferences()['frozen']);
111
77
 
112
- var contents = Object.keys(prefs).map(function(key) {
78
+ let keys = Object.keys(prefs);
79
+ if (!keys.length) {
80
+ return dir;
81
+ }
82
+
83
+ let contents = Object.keys(prefs).map(function(key) {
113
84
  return 'user_pref(' + JSON.stringify(key) + ', ' +
114
85
  JSON.stringify(prefs[key]) + ');';
115
86
  }).join('\n');
@@ -130,13 +101,10 @@ function writeUserPrefs(prefs, dir) {
130
101
  * @param {!Array.<string>} extensions The extensions to install, as a
131
102
  * path to an unpacked extension directory or a path to a xpi file.
132
103
  * @param {string} dir The profile directory to install to.
133
- * @param {boolean=} opt_excludeWebDriverExt Whether to skip installation of
134
- * the default WebDriver extension.
135
104
  * @return {!Promise<string>} A promise for the main profile directory
136
105
  * once all extensions have been installed.
137
106
  */
138
- function installExtensions(extensions, dir, opt_excludeWebDriverExt) {
139
- var hasWebDriver = !!opt_excludeWebDriverExt;
107
+ function installExtensions(extensions, dir) {
140
108
  var next = 0;
141
109
  var extensionDir = path.join(dir, 'extensions');
142
110
 
@@ -145,11 +113,7 @@ function installExtensions(extensions, dir, opt_excludeWebDriverExt) {
145
113
 
146
114
  function installNext() {
147
115
  if (next >= extensions.length) {
148
- if (hasWebDriver) {
149
- fulfill(dir);
150
- } else {
151
- install(WEBDRIVER_EXTENSION_PATH);
152
- }
116
+ fulfill(dir);
153
117
  } else {
154
118
  install(extensions[next++]);
155
119
  }
@@ -157,7 +121,6 @@ function installExtensions(extensions, dir, opt_excludeWebDriverExt) {
157
121
 
158
122
  function install(ext) {
159
123
  extension.install(ext, extensionDir).then(function(id) {
160
- hasWebDriver = hasWebDriver || (id === WEBDRIVER_EXTENSION_NAME);
161
124
  installNext();
162
125
  }, reject);
163
126
  }
@@ -165,26 +128,6 @@ function installExtensions(extensions, dir, opt_excludeWebDriverExt) {
165
128
  }
166
129
 
167
130
 
168
- /**
169
- * Decodes a base64 encoded profile.
170
- * @param {string} data The base64 encoded string.
171
- * @return {!Promise<string>} A promise for the path to the decoded profile
172
- * directory.
173
- */
174
- function decode(data) {
175
- return io.tmpFile().then(function(file) {
176
- var buf = new Buffer(data, 'base64');
177
- return io.write(file, buf)
178
- .then(io.tmpDir)
179
- .then(function(dir) {
180
- var zip = new AdmZip(file);
181
- zip.extractAllTo(dir); // Sync only? Why?? :-(
182
- return dir;
183
- });
184
- });
185
- }
186
-
187
-
188
131
 
189
132
  /**
190
133
  * Models a Firefox profile directory for use with the FirefoxDriver. The
@@ -201,15 +144,9 @@ class Profile {
201
144
  /** @private {!Object} */
202
145
  this.preferences_ = {};
203
146
 
204
- /** @private {boolean} */
205
- this.nativeEventsEnabled_ = true;
206
-
207
147
  /** @private {(string|undefined)} */
208
148
  this.template_ = opt_dir;
209
149
 
210
- /** @private {number} */
211
- this.port_ = 0;
212
-
213
150
  /** @private {!Array<string>} */
214
151
  this.extensions_ = [];
215
152
  }
@@ -245,12 +182,6 @@ class Profile {
245
182
  * @throws {Error} If attempting to set a frozen preference.
246
183
  */
247
184
  setPreference(key, value) {
248
- var frozen = getDefaultPreferences()['frozen'];
249
- if (frozen.hasOwnProperty(key) && frozen[key] !== value) {
250
- throw Error('You may not set ' + key + '=' + JSON.stringify(value)
251
- + '; value is frozen for proper WebDriver functionality ('
252
- + key + '=' + JSON.stringify(frozen[key]) + ')');
253
- }
254
185
  this.preferences_[key] = value;
255
186
  }
256
187
 
@@ -285,23 +216,6 @@ class Profile {
285
216
  this.preferences_['webdriver_firefox_allowed_hosts'] = host;
286
217
  }
287
218
 
288
- /**
289
- * @return {number} The port this profile is currently configured to use, or
290
- * 0 if the port will be selected at random when the profile is written
291
- * to disk.
292
- */
293
- getPort() {
294
- return this.port_;
295
- }
296
-
297
- /**
298
- * Sets the port to use for the WebDriver extension loaded by this profile.
299
- * @param {number} port The desired port, or 0 to use any free port.
300
- */
301
- setPort(port) {
302
- this.port_ = port;
303
- }
304
-
305
219
  /**
306
220
  * @return {boolean} Whether the FirefoxDriver is configured to automatically
307
221
  * accept untrusted SSL certificates.
@@ -335,32 +249,12 @@ class Profile {
335
249
  return !!this.preferences_['webdriver_assume_untrusted_issuer'];
336
250
  }
337
251
 
338
- /**
339
- * Sets whether to use native events with this profile.
340
- * @param {boolean} enabled .
341
- */
342
- setNativeEventsEnabled(enabled) {
343
- this.nativeEventsEnabled_ = enabled;
344
- }
345
-
346
- /**
347
- * Returns whether native events are enabled in this profile.
348
- * @return {boolean} .
349
- */
350
- nativeEventsEnabled() {
351
- return this.nativeEventsEnabled_;
352
- }
353
-
354
252
  /**
355
253
  * Writes this profile to disk.
356
- * @param {boolean=} opt_excludeWebDriverExt Whether to exclude the WebDriver
357
- * extension from the generated profile. Used to reduce the size of an
358
- * {@link #encode() encoded profile} since the server will always install
359
- * the extension itself.
360
254
  * @return {!Promise<string>} A promise for the path to the new profile
361
255
  * directory.
362
256
  */
363
- writeToDisk(opt_excludeWebDriverExt) {
257
+ writeToDisk() {
364
258
  var profileDir = io.tmpDir();
365
259
  if (this.template_) {
366
260
  profileDir = profileDir.then(function(dir) {
@@ -371,10 +265,7 @@ class Profile {
371
265
  }
372
266
 
373
267
  // Freeze preferences for async operations.
374
- var prefs = {};
375
- Object.assign(prefs, getDefaultPreferences()['mutable']);
376
- Object.assign(prefs, getDefaultPreferences()['frozen']);
377
- Object.assign(prefs, this.preferences_);
268
+ let prefs = Object.assign({}, this.preferences_);
378
269
 
379
270
  // Freeze extensions for async operations.
380
271
  var extensions = this.extensions_.concat();
@@ -382,7 +273,7 @@ class Profile {
382
273
  return profileDir.then(function(dir) {
383
274
  return writeUserPrefs(prefs, dir);
384
275
  }).then(function(dir) {
385
- return installExtensions(extensions, dir, !!opt_excludeWebDriverExt);
276
+ return installExtensions(extensions, dir);
386
277
  });
387
278
  }
388
279
 
@@ -395,20 +286,11 @@ class Profile {
395
286
  *
396
287
  */
397
288
  encode() {
398
- return this.writeToDisk(true).then(function(dir) {
399
- var zip = new AdmZip();
400
- zip.addLocalFolder(dir, '');
401
- // Stored compression, see https://en.wikipedia.org/wiki/Zip_(file_format)
402
- zip.getEntries().forEach(function(entry) {
403
- entry.header.method = 0;
404
- });
405
-
406
- return io.tmpFile().then(function(file) {
407
- zip.writeZip(file); // Sync! Why oh why :-(
408
- return io.read(file);
409
- });
410
- }).then(function(data) {
411
- return data.toString('base64');
289
+ return this.writeToDisk().then(function(dir) {
290
+ let zip = new Zip;
291
+ return zip.addDir(dir)
292
+ .then(() => zip.toBuffer())
293
+ .then(buf => buf.toString('base64'));
412
294
  });
413
295
  }
414
296
 
@@ -426,5 +308,4 @@ class Profile {
426
308
 
427
309
 
428
310
  exports.Profile = Profile;
429
- exports.decode = decode;
430
311
  exports.loadUserPrefs = loadUserPrefs;
package/ie.js CHANGED
@@ -420,8 +420,8 @@ class Driver extends webdriver.WebDriver {
420
420
  var client = service.start().then(url => new http.HttpClient(url));
421
421
  var executor = new http.Executor(client);
422
422
 
423
- return /** @type {!Driver} */(webdriver.WebDriver.createSession(
424
- executor, caps, opt_flow, this, () => service.kill()));
423
+ return /** @type {!Driver} */(super.createSession(
424
+ executor, caps, opt_flow, () => service.kill()));
425
425
  }
426
426
 
427
427
  /**
package/index.js CHANGED
@@ -131,7 +131,10 @@ const THENABLE_DRIVERS = new Map;
131
131
  function createDriver(ctor, ...args) {
132
132
  let thenableWebDriverProxy = THENABLE_DRIVERS.get(ctor);
133
133
  if (!thenableWebDriverProxy) {
134
- /** @implements {ThenableWebDriver} */
134
+ /**
135
+ * @extends {WebDriver} // Needed since `ctor` is dynamically typed.
136
+ * @implements {ThenableWebDriver}
137
+ */
135
138
  thenableWebDriverProxy = class extends ctor {
136
139
  /**
137
140
  * @param {!IThenable<!Session>} session
package/io/index.js CHANGED
@@ -298,3 +298,62 @@ exports.mkdir = function(aPath) {
298
298
  });
299
299
  });
300
300
  };
301
+
302
+
303
+ /**
304
+ * Recursively creates a directory and any ancestors that do not yet exist.
305
+ *
306
+ * @param {string} dir The directory path to create.
307
+ * @return {!Promise<string>} A promise that will resolve with the path of the
308
+ * created directory.
309
+ */
310
+ exports.mkdirp = function mkdirp(dir) {
311
+ return checkedCall(callback => {
312
+ fs.mkdir(dir, undefined, err => {
313
+ if (!err) {
314
+ callback(null, dir);
315
+ return;
316
+ }
317
+
318
+ switch (err.code) {
319
+ case 'EEXIST':
320
+ callback(null, dir);
321
+ return;
322
+ case 'ENOENT':
323
+ return mkdirp(path.dirname(dir))
324
+ .then(() => mkdirp(dir))
325
+ .then(() => callback(null, dir), err => callback(err));
326
+ default:
327
+ callback(err);
328
+ return;
329
+ }
330
+ });
331
+ });
332
+ };
333
+
334
+
335
+ /**
336
+ * Recursively walks a directory, returning a promise that will resolve with
337
+ * a list of all files/directories seen.
338
+ *
339
+ * @param {string} rootPath the directory to walk.
340
+ * @return {!Promise<!Array<{path: string, dir: boolean}>>} a promise that will
341
+ * resolve with a list of entries seen. For each entry, the recorded path
342
+ * will be relative to `rootPath`.
343
+ */
344
+ exports.walkDir = function(rootPath) {
345
+ let seen = [];
346
+ return (function walk(dir) {
347
+ return checkedCall(callback => fs.readdir(dir, callback))
348
+ .then(files => Promise.all(files.map(file => {
349
+ file = path.join(dir, file);
350
+ return checkedCall(cb => fs.stat(file, cb)).then(stats => {
351
+ seen.push({
352
+ path: path.relative(rootPath, file),
353
+ dir: stats.isDirectory()
354
+ });
355
+ return stats.isDirectory() && walk(file);
356
+ });
357
+ })));
358
+ })(rootPath).then(() => seen);
359
+ };
package/io/zip.js ADDED
@@ -0,0 +1,214 @@
1
+ // Licensed to the Software Freedom Conservancy (SFC) under one
2
+ // or more contributor license agreements. See the NOTICE file
3
+ // distributed with this work for additional information
4
+ // regarding copyright ownership. The SFC licenses this file
5
+ // to you under the Apache License, Version 2.0 (the
6
+ // "License"); you may not use this file except in compliance
7
+ // with the License. You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing,
12
+ // software distributed under the License is distributed on an
13
+ // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ // KIND, either express or implied. See the License for the
15
+ // specific language governing permissions and limitations
16
+ // under the License.
17
+
18
+ 'use strict';
19
+
20
+ const jszip = require('jszip');
21
+ const path = require('path');
22
+
23
+ const io = require('./index');
24
+ const {InvalidArgumentError} = require('../lib/error');
25
+
26
+ /**
27
+ * Manages a zip archive.
28
+ */
29
+ class Zip {
30
+ constructor() {
31
+ /** @private @const */
32
+ this.z_ = new jszip;
33
+
34
+ /** @private @const {!Set<!Promise<?>>} */
35
+ this.pendingAdds_ = new Set;
36
+ }
37
+
38
+ /**
39
+ * Adds a file to this zip.
40
+ *
41
+ * @param {string} filePath path to the file to add.
42
+ * @param {string=} zipPath path to the file in the zip archive, defaults
43
+ * to the basename of `filePath`.
44
+ * @return {!Promise<?>} a promise that will resolve when added.
45
+ */
46
+ addFile(filePath, zipPath = path.basename(filePath)) {
47
+ let add = io.read(filePath)
48
+ .then(buffer => this.z_.file(/** @type {string} */(zipPath), buffer));
49
+ this.pendingAdds_.add(add);
50
+ return add.then(
51
+ () => this.pendingAdds_.delete(add),
52
+ (e) => {
53
+ this.pendingAdds_.delete(add);
54
+ throw e;
55
+ });
56
+ }
57
+
58
+ /**
59
+ * Recursively adds a directory and all of its contents to this archive.
60
+ *
61
+ * @param {string} dirPath path to the directory to add.
62
+ * @param {string=} zipPath path to the folder in the archive to add the
63
+ * directory contents to. Defaults to the root folder.
64
+ * @return {!Promise<?>} returns a promise that will resolve when the
65
+ * the operation is complete.
66
+ */
67
+ addDir(dirPath, zipPath = '') {
68
+ return io.walkDir(dirPath).then(entries => {
69
+ let archive = this.z_;
70
+ if (zipPath) {
71
+ archive = archive.folder(zipPath);
72
+ }
73
+
74
+ let files = [];
75
+ entries.forEach(spec => {
76
+ if (spec.dir) {
77
+ archive.folder(spec.path);
78
+ } else {
79
+ files.push(
80
+ this.addFile(
81
+ path.join(dirPath, spec.path),
82
+ path.join(zipPath, spec.path)));
83
+ }
84
+ });
85
+
86
+ return Promise.all(files);
87
+ });
88
+ }
89
+
90
+ /**
91
+ * @param {string} path File path to test for within the archive.
92
+ * @return {boolean} Whether this zip archive contains an entry with the given
93
+ * path.
94
+ */
95
+ has(path) {
96
+ return this.z_.file(path) !== null;
97
+ }
98
+
99
+ /**
100
+ * Returns the contents of the file in this zip archive with the given `path`.
101
+ * The returned promise will be rejected with an {@link InvalidArgumentError}
102
+ * if either `path` does not exist within the archive, or if `path` refers
103
+ * to a directory.
104
+ *
105
+ * @param {string} path the path to the file whose contents to return.
106
+ * @return {!Promise<!Buffer>} a promise that will be resolved with the file's
107
+ * contents as a buffer.
108
+ */
109
+ getFile(path) {
110
+ let file = this.z_.file(path);
111
+ if (!file) {
112
+ return Promise.reject(
113
+ new InvalidArgumentError(`No such file in zip archive: ${path}`));
114
+ }
115
+
116
+ if (file.dir) {
117
+ return Promise.reject(
118
+ new InvalidArgumentError(
119
+ `The requested file is a directory: ${path}`));
120
+ }
121
+
122
+ return Promise.resolve(file.async('nodebuffer'));
123
+ }
124
+
125
+ /**
126
+ * Returns the compressed data for this archive in a buffer. _This method will
127
+ * not wait for any outstanding {@link #addFile add}
128
+ * {@link #addDir operations} before encoding the archive._
129
+ *
130
+ * @param {string} compression The desired compression.
131
+ * Must be `STORE` (the default) or `DEFLATE`.
132
+ * @return {!Promise<!Buffer>} a promise that will resolve with this archive
133
+ * as a buffer.
134
+ */
135
+ toBuffer(compression = 'STORE') {
136
+ if (compression !== 'STORE' && compression !== 'DEFLATE') {
137
+ return Promise.reject(
138
+ new InvalidArgumentError(
139
+ `compression must be one of {STORE, DEFLATE}, got ${compression}`));
140
+ }
141
+ return Promise.resolve(
142
+ this.z_.generateAsync({compression, type: 'nodebuffer'}));
143
+ }
144
+ }
145
+
146
+
147
+ /**
148
+ * Asynchronously opens a zip archive.
149
+ *
150
+ * @param {string} path to the zip archive to load.
151
+ * @return {!Promise<!Zip>} a promise that will resolve with the opened
152
+ * archive.
153
+ */
154
+ function load(path) {
155
+ return io.read(path).then(data => {
156
+ let zip = new Zip;
157
+ return zip.z_.loadAsync(data).then(() => zip);
158
+ });
159
+ }
160
+
161
+
162
+ /**
163
+ * Asynchronously unzips an archive file.
164
+ *
165
+ * @param {string} src path to the source file to unzip.
166
+ * @param {string} dst path to the destination directory.
167
+ * @return {!Promise<string>} a promise that will resolve with `dst` once the
168
+ * archive has been unzipped.
169
+ */
170
+ function unzip(src, dst) {
171
+ return load(src).then(zip => {
172
+ let promisedDirs = new Map;
173
+ let promises = [];
174
+
175
+ zip.z_.forEach((relPath, file) => {
176
+ let p;
177
+ if (file.dir) {
178
+ p = createDir(relPath);
179
+ } else {
180
+ let dirname = path.dirname(relPath);
181
+ if (dirname === '.') {
182
+ p = writeFile(relPath, file);
183
+ } else {
184
+ p = createDir(dirname).then(() => writeFile(relPath, file));
185
+ }
186
+ }
187
+ promises.push(p);
188
+ });
189
+
190
+ return Promise.all(promises).then(() => dst);
191
+
192
+ function createDir(dir) {
193
+ let p = promisedDirs.get(dir);
194
+ if (!p) {
195
+ p = io.mkdirp(path.join(dst, dir));
196
+ promisedDirs.set(dir, p);
197
+ }
198
+ return p;
199
+ }
200
+
201
+ function writeFile(relPath, file) {
202
+ return file.async('nodebuffer')
203
+ .then(buffer => io.write(path.join(dst, relPath), buffer));
204
+ }
205
+ });
206
+ }
207
+
208
+
209
+ // PUBLIC API
210
+
211
+
212
+ exports.Zip = Zip;
213
+ exports.load = load;
214
+ exports.unzip = unzip;
@@ -0,0 +1,9 @@
1
+ // GENERATED CODE - DO NOT EDIT
2
+ module.exports = function(){return function(){var d=this;function f(a){return"string"==typeof a};function h(a,b){this.code=a;this.a=l[a]||m;this.message=b||"";a=this.a.replace(/((?:^|\s+)[a-z])/g,function(a){return a.toUpperCase().replace(/^[\s\xa0]+/g,"")});b=a.length-5;if(0>b||a.indexOf("Error",b)!=b)a+="Error";this.name=a;a=Error(this.message);a.name=this.name;this.stack=a.stack||""}
3
+ (function(){var a=Error;function b(){}b.prototype=a.prototype;h.b=a.prototype;h.prototype=new b;h.prototype.constructor=h;h.a=function(b,c,g){for(var e=Array(arguments.length-2),k=2;k<arguments.length;k++)e[k-2]=arguments[k];return a.prototype[c].apply(b,e)}})();var m="unknown error",l={15:"element not selectable",11:"element not visible"};l[31]=m;l[30]=m;l[24]="invalid cookie domain";l[29]="invalid element coordinates";l[12]="invalid element state";l[32]="invalid selector";l[51]="invalid selector";
4
+ l[52]="invalid selector";l[17]="javascript error";l[405]="unsupported operation";l[34]="move target out of bounds";l[27]="no such alert";l[7]="no such element";l[8]="no such frame";l[23]="no such window";l[28]="script timeout";l[33]="session not created";l[10]="stale element reference";l[21]="timeout";l[25]="unable to set cookie";l[26]="unexpected alert open";l[13]=m;l[9]="unknown command";h.prototype.toString=function(){return this.name+": "+this.message};var n;a:{var p=d.navigator;if(p){var q=p.userAgent;if(q){n=q;break a}}n=""}function r(a){return-1!=n.indexOf(a)};function t(a,b){for(var e=a.length,c=f(a)?a.split(""):a,g=0;g<e;g++)g in c&&b.call(void 0,c[g],g,a)};function v(){return r("iPhone")&&!r("iPod")&&!r("iPad")};function w(){return(r("Chrome")||r("CriOS"))&&!r("Edge")};var x=r("Opera"),y=r("Trident")||r("MSIE"),z=r("Edge"),A=r("Gecko")&&!(-1!=n.toLowerCase().indexOf("webkit")&&!r("Edge"))&&!(r("Trident")||r("MSIE"))&&!r("Edge"),aa=-1!=n.toLowerCase().indexOf("webkit")&&!r("Edge");function B(){var a=d.document;return a?a.documentMode:void 0}var C;
5
+ a:{var D="",E=function(){var a=n;if(A)return/rv\:([^\);]+)(\)|;)/.exec(a);if(z)return/Edge\/([\d\.]+)/.exec(a);if(y)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(aa)return/WebKit\/(\S+)/.exec(a);if(x)return/(?:Version)[ \/]?(\S+)/.exec(a)}();E&&(D=E?E[1]:"");if(y){var F=B();if(null!=F&&F>parseFloat(D)){C=String(F);break a}}C=D}var G;var H=d.document;G=H&&y?B()||("CSS1Compat"==H.compatMode?parseInt(C,10):5):void 0;var ba=r("Firefox"),ca=v()||r("iPod"),da=r("iPad"),I=r("Android")&&!(w()||r("Firefox")||r("Opera")||r("Silk")),ea=w(),J=r("Safari")&&!(w()||r("Coast")||r("Opera")||r("Edge")||r("Silk")||r("Android"))&&!(v()||r("iPad")||r("iPod"));function K(a){return(a=a.exec(n))?a[1]:""}(function(){if(ba)return K(/Firefox\/([0-9.]+)/);if(y||z||x)return C;if(ea)return v()||r("iPad")||r("iPod")?K(/CriOS\/([0-9.]+)/):K(/Chrome\/([0-9.]+)/);if(J&&!(v()||r("iPad")||r("iPod")))return K(/Version\/([0-9.]+)/);if(ca||da){var a=/Version\/(\S+).*Mobile\/(\S+)/.exec(n);if(a)return a[1]+"."+a[2]}else if(I)return(a=K(/Android\s+([0-9.]+)/))?a:K(/Version\/([0-9.]+)/);return""})();var L,M=function(){if(!A)return!1;var a=d.Components;if(!a)return!1;try{if(!a.classes)return!1}catch(g){return!1}var b=a.classes,a=a.interfaces,e=b["@mozilla.org/xpcom/version-comparator;1"].getService(a.nsIVersionComparator),c=b["@mozilla.org/xre/app-info;1"].getService(a.nsIXULAppInfo).version;L=function(a){e.compare(c,""+a)};return!0}(),N=y&&!(8<=Number(G)),fa=y&&!(9<=Number(G));I&&M&&L(2.3);I&&M&&L(4);J&&M&&L(6);var ga={SCRIPT:1,STYLE:1,HEAD:1,IFRAME:1,OBJECT:1},O={IMG:" ",BR:"\n"};function P(a,b,e){if(!(a.nodeName in ga))if(3==a.nodeType)e?b.push(String(a.nodeValue).replace(/(\r\n|\r|\n)/g,"")):b.push(a.nodeValue);else if(a.nodeName in O)b.push(O[a.nodeName]);else for(a=a.firstChild;a;)P(a,b,e),a=a.nextSibling};function Q(a,b){b=b.toLowerCase();return"style"==b?ha(a.style.cssText):N&&"value"==b&&R(a,"INPUT")?a.value:fa&&!0===a[b]?String(a.getAttribute(b)):(a=a.getAttributeNode(b))&&a.specified?a.value:null}var ia=/[;]+(?=(?:(?:[^"]*"){2})*[^"]*$)(?=(?:(?:[^']*'){2})*[^']*$)(?=(?:[^()]*\([^()]*\))*[^()]*$)/;
6
+ function ha(a){var b=[];t(a.split(ia),function(a){var c=a.indexOf(":");0<c&&(a=[a.slice(0,c),a.slice(c+1)],2==a.length&&b.push(a[0].toLowerCase(),":",a[1],";"))});b=b.join("");return b=";"==b.charAt(b.length-1)?b:b+";"}function S(a,b){N&&"value"==b&&R(a,"OPTION")&&null===Q(a,"value")?(b=[],P(a,b,!1),a=b.join("")):a=a[b];return a}function R(a,b){b&&"string"!==typeof b&&(b=b.toString());return!!a&&1==a.nodeType&&(!b||a.tagName.toUpperCase()==b)}
7
+ function T(a){return R(a,"OPTION")?!0:R(a,"INPUT")?(a=a.type.toLowerCase(),"checkbox"==a||"radio"==a):!1};var ja={"class":"className",readonly:"readOnly"},U="async autofocus autoplay checked compact complete controls declare defaultchecked defaultselected defer disabled draggable ended formnovalidate hidden indeterminate iscontenteditable ismap itemscope loop multiple muted nohref noresize noshade novalidate nowrap open paused pubdate readonly required reversed scoped seamless seeking selected spellcheck truespeed willvalidate".split(" ");function V(a,b){var e=null,c=b.toLowerCase();if("style"==c)return(e=a.style)&&!f(e)&&(e=e.cssText),e;if(("selected"==c||"checked"==c)&&T(a)){if(!T(a))throw new h(15,"Element is not selectable");b="selected";e=a.type&&a.type.toLowerCase();if("checkbox"==e||"radio"==e)b="checked";return S(a,b)?"true":null}var g=R(a,"A");if(R(a,"IMG")&&"src"==c||g&&"href"==c)return(e=Q(a,c))&&(e=S(a,c)),e;if("spellcheck"==c){e=Q(a,c);if(null!==e){if("false"==e.toLowerCase())return"false";if("true"==e.toLowerCase())return"true"}return S(a,
8
+ c)+""}g=ja[b]||b;a:if(f(U))c=f(c)&&1==c.length?U.indexOf(c,0):-1;else{for(var u=0;u<U.length;u++)if(u in U&&U[u]===c){c=u;break a}c=-1}if(0<=c)return(e=null!==Q(a,b)||S(a,g))?"true":null;try{var k=S(a,g)}catch(ka){}(c=null==k)||(c=typeof k,c="object"==c&&null!=k||"function"==c);c?e=Q(a,b):e=k;return null!=e?e.toString():null}var W=["_"],X=d;W[0]in X||!X.execScript||X.execScript("var "+W[0]);
9
+ for(var Y;W.length&&(Y=W.shift());){var Z;if(Z=!W.length)Z=void 0!==V;Z?X[Y]=V:X[Y]&&X[Y]!==Object.prototype[Y]?X=X[Y]:X=X[Y]={}};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null,document:typeof window!='undefined'?window.document:null}, arguments);};