appium 2.0.0-beta.25 → 2.0.0-beta.26

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 (124) hide show
  1. package/build/lib/appium-config.schema.json +278 -0
  2. package/build/lib/appium.js +45 -66
  3. package/build/lib/cli/args.js +19 -39
  4. package/build/lib/cli/driver-command.js +5 -9
  5. package/build/lib/cli/extension-command.js +73 -64
  6. package/build/lib/cli/extension.js +10 -23
  7. package/build/lib/cli/parser.js +9 -19
  8. package/build/lib/cli/plugin-command.js +5 -9
  9. package/build/lib/cli/utils.js +2 -4
  10. package/build/lib/config-file.js +2 -4
  11. package/build/lib/config.js +7 -6
  12. package/build/lib/constants.js +60 -0
  13. package/build/lib/extension/driver-config.js +190 -0
  14. package/build/lib/extension/extension-config.js +297 -0
  15. package/build/lib/extension/index.js +77 -0
  16. package/build/lib/extension/manifest.js +246 -0
  17. package/build/lib/extension/package-changed.js +68 -0
  18. package/build/lib/extension/plugin-config.js +87 -0
  19. package/build/lib/grid-register.js +2 -4
  20. package/build/lib/logger.js +2 -4
  21. package/build/lib/logsink.js +2 -4
  22. package/build/lib/main.js +40 -68
  23. package/build/lib/schema/appium-config-schema.js +2 -4
  24. package/build/lib/schema/arg-spec.js +11 -14
  25. package/build/lib/schema/cli-args.js +2 -4
  26. package/build/lib/schema/cli-transformers.js +2 -4
  27. package/build/lib/schema/index.js +2 -4
  28. package/build/lib/schema/keywords.js +2 -4
  29. package/build/lib/schema/schema.js +55 -37
  30. package/build/lib/utils.js +1 -32
  31. package/lib/appium.js +50 -68
  32. package/lib/cli/args.js +19 -23
  33. package/lib/cli/driver-command.js +10 -2
  34. package/lib/cli/extension-command.js +216 -135
  35. package/lib/cli/extension.js +7 -15
  36. package/lib/cli/parser.js +6 -14
  37. package/lib/cli/plugin-command.js +1 -2
  38. package/lib/config-file.js +3 -3
  39. package/lib/config.js +5 -4
  40. package/lib/constants.js +79 -0
  41. package/lib/extension/driver-config.js +230 -0
  42. package/lib/extension/extension-config.js +459 -0
  43. package/lib/extension/index.js +103 -0
  44. package/lib/extension/manifest.js +590 -0
  45. package/lib/extension/package-changed.js +64 -0
  46. package/lib/extension/plugin-config.js +111 -0
  47. package/lib/grid-register.js +4 -4
  48. package/lib/main.js +51 -88
  49. package/lib/schema/arg-spec.js +2 -2
  50. package/lib/schema/cli-args.js +1 -0
  51. package/lib/schema/keywords.js +1 -1
  52. package/lib/schema/schema.js +60 -28
  53. package/lib/utils.js +2 -32
  54. package/package.json +29 -21
  55. package/{postinstall.js → scripts/postinstall.js} +1 -1
  56. package/types/types.d.ts +70 -31
  57. package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
  58. package/build/check-npm-pack-files.js +0 -23
  59. package/build/commands-yml/parse.js +0 -319
  60. package/build/commands-yml/validator.js +0 -130
  61. package/build/index.js +0 -19
  62. package/build/lib/cli/npm.js +0 -220
  63. package/build/lib/driver-config.js +0 -100
  64. package/build/lib/drivers.js +0 -100
  65. package/build/lib/ext-config-io.js +0 -165
  66. package/build/lib/extension-config.js +0 -320
  67. package/build/lib/plugin-config.js +0 -69
  68. package/build/lib/plugins.js +0 -18
  69. package/build/postinstall.js +0 -90
  70. package/build/test/cli/cli-e2e-specs.js +0 -221
  71. package/build/test/cli/cli-helpers.js +0 -86
  72. package/build/test/cli/cli-specs.js +0 -71
  73. package/build/test/cli/fixtures/test-driver/package.json +0 -27
  74. package/build/test/cli/schema-args-specs.js +0 -48
  75. package/build/test/cli/schema-e2e-specs.js +0 -47
  76. package/build/test/config-e2e-specs.js +0 -112
  77. package/build/test/config-file-e2e-specs.js +0 -191
  78. package/build/test/config-file-specs.js +0 -281
  79. package/build/test/config-specs.js +0 -258
  80. package/build/test/driver-e2e-specs.js +0 -435
  81. package/build/test/driver-specs.js +0 -386
  82. package/build/test/ext-config-io-specs.js +0 -181
  83. package/build/test/extension-config-specs.js +0 -365
  84. package/build/test/fixtures/allow-feat.txt +0 -5
  85. package/build/test/fixtures/caps.json +0 -3
  86. package/build/test/fixtures/config/allow-insecure.txt +0 -3
  87. package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +0 -5
  88. package/build/test/fixtures/config/appium.config.bad.json +0 -32
  89. package/build/test/fixtures/config/appium.config.ext-good.json +0 -9
  90. package/build/test/fixtures/config/appium.config.ext-unknown-props.json +0 -10
  91. package/build/test/fixtures/config/appium.config.good.js +0 -40
  92. package/build/test/fixtures/config/appium.config.good.json +0 -33
  93. package/build/test/fixtures/config/appium.config.good.yaml +0 -30
  94. package/build/test/fixtures/config/appium.config.invalid.json +0 -31
  95. package/build/test/fixtures/config/appium.config.security-array.json +0 -5
  96. package/build/test/fixtures/config/appium.config.security-delimited.json +0 -5
  97. package/build/test/fixtures/config/appium.config.security-path.json +0 -5
  98. package/build/test/fixtures/config/driver-fake.config.json +0 -8
  99. package/build/test/fixtures/config/nodeconfig.json +0 -3
  100. package/build/test/fixtures/config/plugin-fake.config.json +0 -0
  101. package/build/test/fixtures/default-args.js +0 -35
  102. package/build/test/fixtures/deny-feat.txt +0 -5
  103. package/build/test/fixtures/driver.schema.js +0 -20
  104. package/build/test/fixtures/extensions.yaml +0 -27
  105. package/build/test/fixtures/flattened-schema.js +0 -532
  106. package/build/test/fixtures/plugin.schema.js +0 -20
  107. package/build/test/fixtures/schema-with-extensions.js +0 -28
  108. package/build/test/grid-register-specs.js +0 -74
  109. package/build/test/helpers.js +0 -75
  110. package/build/test/logger-specs.js +0 -76
  111. package/build/test/npm-specs.js +0 -20
  112. package/build/test/parser-specs.js +0 -319
  113. package/build/test/plugin-e2e-specs.js +0 -316
  114. package/build/test/schema/arg-spec-specs.js +0 -70
  115. package/build/test/schema/cli-args-specs.js +0 -408
  116. package/build/test/schema/schema-specs.js +0 -407
  117. package/build/test/utils-specs.js +0 -288
  118. package/lib/cli/npm.js +0 -251
  119. package/lib/driver-config.js +0 -101
  120. package/lib/drivers.js +0 -84
  121. package/lib/ext-config-io.js +0 -287
  122. package/lib/extension-config.js +0 -366
  123. package/lib/plugin-config.js +0 -63
  124. package/lib/plugins.js +0 -13
@@ -1,288 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
-
5
- require("source-map-support/register");
6
-
7
- var _utils = require("../lib/utils");
8
-
9
- var _helpers = require("./helpers");
10
-
11
- var _lodash = _interopRequireDefault(require("lodash"));
12
-
13
- var _colors = require("@dabh/colors");
14
-
15
- var _sinon = _interopRequireDefault(require("sinon"));
16
-
17
- var _logger = _interopRequireDefault(require("../lib/logger"));
18
-
19
- describe('utils', function () {
20
- describe('parseCapsForInnerDriver()', function () {
21
- it('should return an error if only JSONWP provided', function () {
22
- let {
23
- error,
24
- protocol
25
- } = (0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS);
26
- protocol.should.equal('W3C');
27
- error.message.should.match(/W3C/);
28
- });
29
- it('should return W3C caps unchanged if only W3C caps were provided', function () {
30
- let {
31
- desiredCaps,
32
- processedJsonwpCapabilities,
33
- processedW3CCapabilities,
34
- protocol
35
- } = (0, _utils.parseCapsForInnerDriver)(undefined, _helpers.W3C_CAPS);
36
- desiredCaps.should.deep.equal(_helpers.BASE_CAPS);
37
- should.not.exist(processedJsonwpCapabilities);
38
- processedW3CCapabilities.should.deep.equal(_helpers.W3C_CAPS);
39
- protocol.should.equal('W3C');
40
- });
41
- it('should return JSONWP and W3C caps if both were provided', function () {
42
- let {
43
- desiredCaps,
44
- processedJsonwpCapabilities,
45
- processedW3CCapabilities,
46
- protocol
47
- } = (0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS, _helpers.W3C_CAPS);
48
- desiredCaps.should.deep.equal(_helpers.BASE_CAPS);
49
- processedJsonwpCapabilities.should.deep.equal(_helpers.BASE_CAPS);
50
- processedW3CCapabilities.should.deep.equal(_helpers.W3C_CAPS);
51
- protocol.should.equal('W3C');
52
- });
53
- it('should include default capabilities in results', function () {
54
- const defaultW3CCaps = {
55
- 'appium:foo': 'bar',
56
- 'appium:baz': 'bla'
57
- };
58
- const expectedDefaultCaps = {
59
- foo: 'bar',
60
- baz: 'bla'
61
- };
62
- const {
63
- desiredCaps,
64
- processedJsonwpCapabilities,
65
- processedW3CCapabilities
66
- } = (0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS, _helpers.W3C_CAPS, {}, defaultW3CCaps);
67
- desiredCaps.should.deep.equal({ ...expectedDefaultCaps,
68
- ..._helpers.BASE_CAPS
69
- });
70
- processedJsonwpCapabilities.should.deep.equal({ ...expectedDefaultCaps,
71
- ..._helpers.BASE_CAPS
72
- });
73
- processedW3CCapabilities.alwaysMatch.should.deep.equal({ ...(0, _utils.insertAppiumPrefixes)(expectedDefaultCaps),
74
- ...(0, _utils.insertAppiumPrefixes)(_helpers.BASE_CAPS)
75
- });
76
- });
77
- it('should allow valid default capabilities', function () {
78
- const res = (0, _utils.parseCapsForInnerDriver)(null, _helpers.W3C_CAPS, {}, {
79
- 'appium:foo': 'bar2'
80
- });
81
- res.processedW3CCapabilities.alwaysMatch['appium:foo'].should.eql('bar2');
82
- });
83
- it('should not allow invalid default capabilities', function () {
84
- const res = (0, _utils.parseCapsForInnerDriver)(null, _helpers.W3C_CAPS, {}, {
85
- foo: 'bar',
86
- 'appium:foo2': 'bar2'
87
- });
88
- res.error.should.eql({
89
- jsonwpCode: 61,
90
- error: 'invalid argument',
91
- w3cStatus: 400,
92
- _stacktrace: null
93
- });
94
- });
95
- it('should reject if W3C caps are not passing constraints', function () {
96
- const err = (0, _utils.parseCapsForInnerDriver)(undefined, _helpers.W3C_CAPS, {
97
- hello: {
98
- presence: true
99
- }
100
- }).error;
101
- err.message.should.match(/'hello' can't be blank/);
102
- _lodash.default.isError(err).should.be.true;
103
- });
104
- it('should only accept W3C caps that have passing constraints', function () {
105
- let w3cCaps = { ..._helpers.W3C_CAPS,
106
- firstMatch: [{
107
- foo: 'bar'
108
- }, {
109
- 'appium:hello': 'world'
110
- }]
111
- };
112
- (0, _utils.parseCapsForInnerDriver)(_helpers.BASE_CAPS, w3cCaps, {
113
- hello: {
114
- presence: true
115
- }
116
- }).error.should.eql({
117
- jsonwpCode: 61,
118
- error: 'invalid argument',
119
- w3cStatus: 400,
120
- _stacktrace: null
121
- });
122
- });
123
- it('should add appium prefixes to W3C caps that are not standard in W3C', function () {
124
- (0, _utils.parseCapsForInnerDriver)(undefined, {
125
- alwaysMatch: {
126
- platformName: 'Fake',
127
- propertyName: 'PROP_NAME'
128
- }
129
- }).error.error.should.includes('invalid argument');
130
- });
131
- });
132
- describe('removeAppiumPrefixes()', function () {
133
- it('should remove appium prefixes from cap names', function () {
134
- (0, _utils.removeAppiumPrefixes)({
135
- 'appium:cap1': 'value1',
136
- 'ms:cap2': 'value2',
137
- someCap: 'someCap'
138
- }).should.eql({
139
- 'cap1': 'value1',
140
- 'ms:cap2': 'value2',
141
- someCap: 'someCap'
142
- });
143
- });
144
- });
145
- describe('insertAppiumPrefixes()', function () {
146
- it('should apply prefixes to non-standard capabilities', function () {
147
- (0, _utils.insertAppiumPrefixes)({
148
- someCap: 'someCap'
149
- }).should.deep.equal({
150
- 'appium:someCap': 'someCap'
151
- });
152
- });
153
- it('should not apply prefixes to standard capabilities', function () {
154
- (0, _utils.insertAppiumPrefixes)({
155
- browserName: 'BrowserName',
156
- platformName: 'PlatformName'
157
- }).should.deep.equal({
158
- browserName: 'BrowserName',
159
- platformName: 'PlatformName'
160
- });
161
- });
162
- it('should not apply prefixes to capabilities that already have a prefix', function () {
163
- (0, _utils.insertAppiumPrefixes)({
164
- 'appium:someCap': 'someCap',
165
- 'moz:someOtherCap': 'someOtherCap'
166
- }).should.deep.equal({
167
- 'appium:someCap': 'someCap',
168
- 'moz:someOtherCap': 'someOtherCap'
169
- });
170
- });
171
- it('should apply prefixes to non-prefixed, non-standard capabilities; should not apply prefixes to any other capabilities', function () {
172
- (0, _utils.insertAppiumPrefixes)({
173
- 'appium:someCap': 'someCap',
174
- 'moz:someOtherCap': 'someOtherCap',
175
- browserName: 'BrowserName',
176
- platformName: 'PlatformName',
177
- someOtherCap: 'someOtherCap',
178
- yetAnotherCap: 'yetAnotherCap'
179
- }).should.deep.equal({
180
- 'appium:someCap': 'someCap',
181
- 'moz:someOtherCap': 'someOtherCap',
182
- browserName: 'BrowserName',
183
- platformName: 'PlatformName',
184
- 'appium:someOtherCap': 'someOtherCap',
185
- 'appium:yetAnotherCap': 'yetAnotherCap'
186
- });
187
- });
188
- });
189
- describe('pullSettings()', function () {
190
- it('should pull settings from caps', function () {
191
- const caps = {
192
- platformName: 'foo',
193
- browserName: 'bar',
194
- 'settings[settingName]': 'baz',
195
- 'settings[settingName2]': 'baz2'
196
- };
197
- const settings = (0, _utils.pullSettings)(caps);
198
- settings.should.eql({
199
- settingName: 'baz',
200
- settingName2: 'baz2'
201
- });
202
- caps.should.eql({
203
- platformName: 'foo',
204
- browserName: 'bar'
205
- });
206
- });
207
- it('should pull settings dict if object values are present in caps', function () {
208
- const caps = {
209
- platformName: 'foo',
210
- browserName: 'bar',
211
- 'settings[settingName]': {
212
- key: 'baz'
213
- }
214
- };
215
- const settings = (0, _utils.pullSettings)(caps);
216
- settings.should.eql({
217
- settingName: {
218
- key: 'baz'
219
- }
220
- });
221
- caps.should.eql({
222
- platformName: 'foo',
223
- browserName: 'bar'
224
- });
225
- });
226
- it('should pull empty dict if no settings are present in caps', function () {
227
- const caps = {
228
- platformName: 'foo',
229
- browserName: 'bar',
230
- 'setting[settingName]': 'baz'
231
- };
232
- const settings = (0, _utils.pullSettings)(caps);
233
- settings.should.eql({});
234
- caps.should.eql({
235
- platformName: 'foo',
236
- browserName: 'bar',
237
- 'setting[settingName]': 'baz'
238
- });
239
- });
240
- it('should pull empty dict if caps are empty', function () {
241
- const caps = {};
242
- const settings = (0, _utils.pullSettings)(caps);
243
- settings.should.eql({});
244
- caps.should.eql({});
245
- });
246
- });
247
- describe('ReadonlyMap', function () {
248
- it('should allow writing', function () {
249
- const map = new _utils.ReadonlyMap();
250
- (() => map.set('foo', 'bar')).should.not.throw();
251
- });
252
- it('should allow reading', function () {
253
- const map = new _utils.ReadonlyMap([['foo', 'bar']]);
254
- (() => map.get('foo')).should.not.throw();
255
- });
256
- it('should not allow deletion', function () {
257
- const map = new _utils.ReadonlyMap([['foo', 'bar']]);
258
- map.delete('foo').should.be.false;
259
- });
260
- it('should not allow clearing', function () {
261
- const map = new _utils.ReadonlyMap([['foo', 'bar']]);
262
- (() => map.clear()).should.throw();
263
- });
264
- it('should not allow updating', function () {
265
- const map = new _utils.ReadonlyMap([['foo', 'bar']]);
266
- (() => map.set('foo', 'baz')).should.throw();
267
- });
268
- });
269
- describe('inspect()', function () {
270
- let sandbox;
271
- beforeEach(function () {
272
- sandbox = _sinon.default.createSandbox();
273
- sandbox.spy(_logger.default, 'info');
274
- });
275
- afterEach(function () {
276
- sandbox.restore();
277
- });
278
- it('should log the result of inspecting a value', function () {
279
- (0, _utils.inspect)({
280
- foo: 'bar'
281
- });
282
- (0, _colors.stripColors)(_logger.default.info.firstCall.firstArg).should.equal('{ foo: \'bar\' }');
283
- });
284
- });
285
- });require('source-map-support').install();
286
-
287
-
288
- //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvdXRpbHMtc3BlY3MuanMiXSwibmFtZXMiOlsiZGVzY3JpYmUiLCJpdCIsImVycm9yIiwicHJvdG9jb2wiLCJCQVNFX0NBUFMiLCJzaG91bGQiLCJlcXVhbCIsIm1lc3NhZ2UiLCJtYXRjaCIsImRlc2lyZWRDYXBzIiwicHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzIiwicHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzIiwidW5kZWZpbmVkIiwiVzNDX0NBUFMiLCJkZWVwIiwibm90IiwiZXhpc3QiLCJkZWZhdWx0VzNDQ2FwcyIsImV4cGVjdGVkRGVmYXVsdENhcHMiLCJmb28iLCJiYXoiLCJhbHdheXNNYXRjaCIsInJlcyIsImVxbCIsImpzb253cENvZGUiLCJ3M2NTdGF0dXMiLCJfc3RhY2t0cmFjZSIsImVyciIsImhlbGxvIiwicHJlc2VuY2UiLCJfIiwiaXNFcnJvciIsImJlIiwidHJ1ZSIsInczY0NhcHMiLCJmaXJzdE1hdGNoIiwicGxhdGZvcm1OYW1lIiwicHJvcGVydHlOYW1lIiwiaW5jbHVkZXMiLCJzb21lQ2FwIiwiYnJvd3Nlck5hbWUiLCJzb21lT3RoZXJDYXAiLCJ5ZXRBbm90aGVyQ2FwIiwiY2FwcyIsInNldHRpbmdzIiwic2V0dGluZ05hbWUiLCJzZXR0aW5nTmFtZTIiLCJrZXkiLCJtYXAiLCJSZWFkb25seU1hcCIsInNldCIsInRocm93IiwiZ2V0IiwiZGVsZXRlIiwiZmFsc2UiLCJjbGVhciIsInNhbmRib3giLCJiZWZvcmVFYWNoIiwic2lub24iLCJjcmVhdGVTYW5kYm94Iiwic3B5IiwibG9nZ2VyIiwiYWZ0ZXJFYWNoIiwicmVzdG9yZSIsImluZm8iLCJmaXJzdENhbGwiLCJmaXJzdEFyZyJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7O0FBSUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBRUFBLFFBQVEsQ0FBQyxPQUFELEVBQVUsWUFBWTtBQUM1QkEsRUFBQUEsUUFBUSxDQUFDLDJCQUFELEVBQThCLFlBQVk7QUFD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QywyQkFBRCxFQUE4QixZQUFZO0FBQzFDLFlBQU0rQyxHQUFHLEdBQUcsSUFBSUMsa0JBQUosQ0FBZ0IsQ0FBQyxDQUFDLEtBQUQsRUFBUSxLQUFSLENBQUQsQ0FBaEIsQ0FBWjtBQUNBLE9BQUMsTUFBTUQsR0FBRyxDQUFDRSxHQUFKLENBQVEsS0FBUixFQUFlLEtBQWYsQ0FBUCxFQUE4QjdDLE1BQTlCLENBQXFDOEMsS0FBckM7QUFDRCxLQUhDLENBQUY7QUFJRCxHQTFCTyxDQUFSO0FBNEJBbkQsRUFBQUEsUUFBUSxDQUFDLFdBQUQsRUFBYyxZQUFZO0FBS2hDLFFBQUl3RCxPQUFKO0FBQ0FDLElBQUFBLFVBQVUsQ0FBQyxZQUFZO0FBQ3JCRCxNQUFBQSxPQUFPLEdBQUdFLGVBQU1DLGFBQU4sRUFBVjtBQUNBSCxNQUFBQSxPQUFPLENBQUNJLEdBQVIsQ0FBWUMsZUFBWixFQUFvQixNQUFwQjtBQUNELEtBSFMsQ0FBVjtBQUtBQyxJQUFBQSxTQUFTLENBQUMsWUFBWTtBQUNwQk4sTUFBQUEsT0FBTyxDQUFDTyxPQUFSO0FBQ0QsS0FGUSxDQUFUO0FBSUE5RCxJQUFBQSxFQUFFLENBQUMsNkNBQUQsRUFBZ0QsWUFBWTtBQUM1RCwwQkFBUTtBQUFDa0IsUUFBQUEsR0FBRyxFQUFFO0FBQU4sT0FBUjtBQUNBLCtCQUFxRDBDLGdCQUFPRyxJQUFSLENBQWNDLFNBQWQsQ0FBd0JDLFFBQTVFLEVBQ0c3RCxNQURILENBQ1VDLEtBRFYsQ0FDZ0Isa0JBRGhCO0FBRUQsS0FKQyxDQUFGO0FBS0QsR0FwQk8sQ0FBUjtBQXFCRCxDQTdQTyxDQUFSIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIsIGluc2VydEFwcGl1bVByZWZpeGVzLCBwdWxsU2V0dGluZ3MsXG4gIHJlbW92ZUFwcGl1bVByZWZpeGVzLCBSZWFkb25seU1hcCwgaW5zcGVjdFxufSBmcm9tICcuLi9saWIvdXRpbHMnO1xuaW1wb3J0IHsgQkFTRV9DQVBTLCBXM0NfQ0FQUyB9IGZyb20gJy4vaGVscGVycyc7XG5pbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgc3RyaXBDb2xvcnMgfSBmcm9tICdAZGFiaC9jb2xvcnMnO1xuaW1wb3J0IHNpbm9uIGZyb20gJ3Npbm9uJztcbmltcG9ydCBsb2dnZXIgZnJvbSAnLi4vbGliL2xvZ2dlcic7XG5cbmRlc2NyaWJlKCd1dGlscycsIGZ1bmN0aW9uICgpIHtcbiAgZGVzY3JpYmUoJ3BhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gYW4gZXJyb3IgaWYgb25seSBKU09OV1AgcHJvdmlkZWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQge2Vycm9yLCBwcm90b2NvbH0gPSBwYXJzZUNhcHNGb3JJbm5lckRyaXZlcihCQVNFX0NBUFMpO1xuICAgICAgcHJvdG9jb2wuc2hvdWxkLmVxdWFsKCdXM0MnKTtcbiAgICAgIGVycm9yLm1lc3NhZ2Uuc2hvdWxkLm1hdGNoKC9XM0MvKTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIHJldHVybiBXM0MgY2FwcyB1bmNoYW5nZWQgaWYgb25seSBXM0MgY2FwcyB3ZXJlIHByb3ZpZGVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHtkZXNpcmVkQ2FwcywgcHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzLCBwcm9jZXNzZWRXM0NDYXBhYmlsaXRpZXMsIHByb3RvY29sfSA9IHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKHVuZGVmaW5lZCwgVzNDX0NBUFMpO1xuICAgICAgZGVzaXJlZENhcHMuc2hvdWxkLmRlZXAuZXF1YWwoQkFTRV9DQVBTKTtcbiAgICAgIHNob3VsZC5ub3QuZXhpc3QocHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzKTtcbiAgICAgIHByb2Nlc3NlZFczQ0NhcGFiaWxpdGllcy5zaG91bGQuZGVlcC5lcXVhbChXM0NfQ0FQUyk7XG4gICAgICBwcm90b2NvbC5zaG91bGQuZXF1YWwoJ1czQycpO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgcmV0dXJuIEpTT05XUCBhbmQgVzNDIGNhcHMgaWYgYm90aCB3ZXJlIHByb3ZpZGVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHtkZXNpcmVkQ2FwcywgcHJvY2Vzc2VkSnNvbndwQ2FwYWJpbGl0aWVzLCBwcm9jZXNzZWRXM0NDYXBhYmlsaXRpZXMsIHByb3RvY29sfSA9IHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKEJBU0VfQ0FQUywgVzNDX0NBUFMpO1xuICAgICAgZGVzaXJlZENhcHMuc2hvdWxkLmRlZXAuZXF1YWwoQkFTRV9DQVBTKTtcbiAgICAgIHByb2Nlc3NlZEpzb253cENhcGFiaWxpdGllcy5zaG91bGQuZGVlcC5lcXVhbChCQVNFX0NBUFMpO1xuICAgICAgcHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzLnNob3VsZC5kZWVwLmVxdWFsKFczQ19DQVBTKTtcbiAgICAgIHByb3RvY29sLnNob3VsZC5lcXVhbCgnVzNDJyk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBpbmNsdWRlIGRlZmF1bHQgY2FwYWJpbGl0aWVzIGluIHJlc3VsdHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBkZWZhdWx0VzNDQ2FwcyA9IHtcbiAgICAgICAgJ2FwcGl1bTpmb28nOiAnYmFyJyxcbiAgICAgICAgJ2FwcGl1bTpiYXonOiAnYmxhJyxcbiAgICAgIH07XG4gICAgICBjb25zdCBleHBlY3RlZERlZmF1bHRDYXBzID0ge1xuICAgICAgICBmb286ICdiYXInLFxuICAgICAgICBiYXo6ICdibGEnLFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgZGVzaXJlZENhcHMsXG4gICAgICAgIHByb2Nlc3NlZEpzb253cENhcGFiaWxpdGllcyxcbiAgICAgICAgcHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzXG4gICAgICB9ID0gcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIoQkFTRV9DQVBTLCBXM0NfQ0FQUywge30sIGRlZmF1bHRXM0NDYXBzKTtcbiAgICAgIGRlc2lyZWRDYXBzLnNob3VsZC5kZWVwLmVxdWFsKHtcbiAgICAgICAgLi4uZXhwZWN0ZWREZWZhdWx0Q2FwcyxcbiAgICAgICAgLi4uQkFTRV9DQVBTLFxuICAgICAgfSk7XG4gICAgICBwcm9jZXNzZWRKc29ud3BDYXBhYmlsaXRpZXMuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICAuLi5leHBlY3RlZERlZmF1bHRDYXBzLFxuICAgICAgICAuLi5CQVNFX0NBUFNcbiAgICAgIH0pO1xuICAgICAgcHJvY2Vzc2VkVzNDQ2FwYWJpbGl0aWVzLmFsd2F5c01hdGNoLnNob3VsZC5kZWVwLmVxdWFsKHtcbiAgICAgICAgLi4uaW5zZXJ0QXBwaXVtUHJlZml4ZXMoZXhwZWN0ZWREZWZhdWx0Q2FwcyksXG4gICAgICAgIC4uLmluc2VydEFwcGl1bVByZWZpeGVzKEJBU0VfQ0FQUylcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgYWxsb3cgdmFsaWQgZGVmYXVsdCBjYXBhYmlsaXRpZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCByZXMgPSBwYXJzZUNhcHNGb3JJbm5lckRyaXZlcihudWxsLCBXM0NfQ0FQUywge30sIHtcbiAgICAgICAgJ2FwcGl1bTpmb28nOiAnYmFyMicsXG4gICAgICB9KTtcbiAgICAgIHJlcy5wcm9jZXNzZWRXM0NDYXBhYmlsaXRpZXMuYWx3YXlzTWF0Y2hbJ2FwcGl1bTpmb28nXS5zaG91bGQuZXFsKCdiYXIyJyk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBub3QgYWxsb3cgaW52YWxpZCBkZWZhdWx0IGNhcGFiaWxpdGllcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJlcyA9IHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKG51bGwsIFczQ19DQVBTLCB7fSwge1xuICAgICAgICBmb286ICdiYXInLCAnYXBwaXVtOmZvbzInOiAnYmFyMicsXG4gICAgICB9KTtcbiAgICAgIHJlcy5lcnJvci5zaG91bGQuZXFsKHtcbiAgICAgICAganNvbndwQ29kZTogNjEsIGVycm9yOiAnaW52YWxpZCBhcmd1bWVudCcsIHczY1N0YXR1czogNDAwLCBfc3RhY2t0cmFjZTogbnVsbFxuICAgICAgfSk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCByZWplY3QgaWYgVzNDIGNhcHMgYXJlIG5vdCBwYXNzaW5nIGNvbnN0cmFpbnRzJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZXJyID0gcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIodW5kZWZpbmVkLCBXM0NfQ0FQUywge2hlbGxvOiB7cHJlc2VuY2U6IHRydWV9fSkuZXJyb3I7XG4gICAgICBlcnIubWVzc2FnZS5zaG91bGQubWF0Y2goLydoZWxsbycgY2FuJ3QgYmUgYmxhbmsvKTtcbiAgICAgIF8uaXNFcnJvcihlcnIpLnNob3VsZC5iZS50cnVlO1xuXG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBvbmx5IGFjY2VwdCBXM0MgY2FwcyB0aGF0IGhhdmUgcGFzc2luZyBjb25zdHJhaW50cycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCB3M2NDYXBzID0ge1xuICAgICAgICAuLi5XM0NfQ0FQUyxcbiAgICAgICAgZmlyc3RNYXRjaDogW1xuICAgICAgICAgIHtmb286ICdiYXInfSxcbiAgICAgICAgICB7J2FwcGl1bTpoZWxsbyc6ICd3b3JsZCd9LFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICAgIHBhcnNlQ2Fwc0ZvcklubmVyRHJpdmVyKEJBU0VfQ0FQUywgdzNjQ2Fwcywge2hlbGxvOiB7cHJlc2VuY2U6IHRydWV9fSkuZXJyb3Iuc2hvdWxkLmVxbCh7XG4gICAgICAgIGpzb253cENvZGU6IDYxLCBlcnJvcjogJ2ludmFsaWQgYXJndW1lbnQnLCB3M2NTdGF0dXM6IDQwMCwgX3N0YWNrdHJhY2U6IG51bGxcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgYWRkIGFwcGl1bSBwcmVmaXhlcyB0byBXM0MgY2FwcyB0aGF0IGFyZSBub3Qgc3RhbmRhcmQgaW4gVzNDJywgZnVuY3Rpb24gKCkge1xuICAgICAgcGFyc2VDYXBzRm9ySW5uZXJEcml2ZXIodW5kZWZpbmVkLCB7XG4gICAgICAgIGFsd2F5c01hdGNoOiB7XG4gICAgICAgICAgcGxhdGZvcm1OYW1lOiAnRmFrZScsXG4gICAgICAgICAgcHJvcGVydHlOYW1lOiAnUFJPUF9OQU1FJyxcbiAgICAgICAgfSxcbiAgICAgIH0pLmVycm9yLmVycm9yLnNob3VsZC5pbmNsdWRlcygnaW52YWxpZCBhcmd1bWVudCcpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgncmVtb3ZlQXBwaXVtUHJlZml4ZXMoKScsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIHJlbW92ZSBhcHBpdW0gcHJlZml4ZXMgZnJvbSBjYXAgbmFtZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICByZW1vdmVBcHBpdW1QcmVmaXhlcyh7XG4gICAgICAgICdhcHBpdW06Y2FwMSc6ICd2YWx1ZTEnLFxuICAgICAgICAnbXM6Y2FwMic6ICd2YWx1ZTInLFxuICAgICAgICBzb21lQ2FwOiAnc29tZUNhcCcsXG4gICAgICB9KS5zaG91bGQuZXFsKHtcbiAgICAgICAgJ2NhcDEnOiAndmFsdWUxJyxcbiAgICAgICAgJ21zOmNhcDInOiAndmFsdWUyJyxcbiAgICAgICAgc29tZUNhcDogJ3NvbWVDYXAnLFxuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdpbnNlcnRBcHBpdW1QcmVmaXhlcygpJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgYXBwbHkgcHJlZml4ZXMgdG8gbm9uLXN0YW5kYXJkIGNhcGFiaWxpdGllcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGluc2VydEFwcGl1bVByZWZpeGVzKHtcbiAgICAgICAgc29tZUNhcDogJ3NvbWVDYXAnLFxuICAgICAgfSkuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICAnYXBwaXVtOnNvbWVDYXAnOiAnc29tZUNhcCcsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIG5vdCBhcHBseSBwcmVmaXhlcyB0byBzdGFuZGFyZCBjYXBhYmlsaXRpZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpbnNlcnRBcHBpdW1QcmVmaXhlcyh7XG4gICAgICAgIGJyb3dzZXJOYW1lOiAnQnJvd3Nlck5hbWUnLFxuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdQbGF0Zm9ybU5hbWUnLFxuICAgICAgfSkuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICBicm93c2VyTmFtZTogJ0Jyb3dzZXJOYW1lJyxcbiAgICAgICAgcGxhdGZvcm1OYW1lOiAnUGxhdGZvcm1OYW1lJyxcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgbm90IGFwcGx5IHByZWZpeGVzIHRvIGNhcGFiaWxpdGllcyB0aGF0IGFscmVhZHkgaGF2ZSBhIHByZWZpeCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGluc2VydEFwcGl1bVByZWZpeGVzKHtcbiAgICAgICAgJ2FwcGl1bTpzb21lQ2FwJzogJ3NvbWVDYXAnLFxuICAgICAgICAnbW96OnNvbWVPdGhlckNhcCc6ICdzb21lT3RoZXJDYXAnLFxuICAgICAgfSkuc2hvdWxkLmRlZXAuZXF1YWwoe1xuICAgICAgICAnYXBwaXVtOnNvbWVDYXAnOiAnc29tZUNhcCcsXG4gICAgICAgICdtb3o6c29tZU90aGVyQ2FwJzogJ3NvbWVPdGhlckNhcCcsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIGFwcGx5IHByZWZpeGVzIHRvIG5vbi1wcmVmaXhlZCwgbm9uLXN0YW5kYXJkIGNhcGFiaWxpdGllczsgc2hvdWxkIG5vdCBhcHBseSBwcmVmaXhlcyB0byBhbnkgb3RoZXIgY2FwYWJpbGl0aWVzJywgZnVuY3Rpb24gKCkge1xuICAgICAgaW5zZXJ0QXBwaXVtUHJlZml4ZXMoe1xuICAgICAgICAnYXBwaXVtOnNvbWVDYXAnOiAnc29tZUNhcCcsXG4gICAgICAgICdtb3o6c29tZU90aGVyQ2FwJzogJ3NvbWVPdGhlckNhcCcsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnQnJvd3Nlck5hbWUnLFxuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdQbGF0Zm9ybU5hbWUnLFxuICAgICAgICBzb21lT3RoZXJDYXA6ICdzb21lT3RoZXJDYXAnLFxuICAgICAgICB5ZXRBbm90aGVyQ2FwOiAneWV0QW5vdGhlckNhcCcsXG4gICAgICB9KS5zaG91bGQuZGVlcC5lcXVhbCh7XG4gICAgICAgICdhcHBpdW06c29tZUNhcCc6ICdzb21lQ2FwJyxcbiAgICAgICAgJ21vejpzb21lT3RoZXJDYXAnOiAnc29tZU90aGVyQ2FwJyxcbiAgICAgICAgYnJvd3Nlck5hbWU6ICdCcm93c2VyTmFtZScsXG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ1BsYXRmb3JtTmFtZScsXG4gICAgICAgICdhcHBpdW06c29tZU90aGVyQ2FwJzogJ3NvbWVPdGhlckNhcCcsXG4gICAgICAgICdhcHBpdW06eWV0QW5vdGhlckNhcCc6ICd5ZXRBbm90aGVyQ2FwJyxcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgncHVsbFNldHRpbmdzKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBwdWxsIHNldHRpbmdzIGZyb20gY2FwcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGNhcHMgPSB7XG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ2ZvbycsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnYmFyJyxcbiAgICAgICAgJ3NldHRpbmdzW3NldHRpbmdOYW1lXSc6ICdiYXonLFxuICAgICAgICAnc2V0dGluZ3Nbc2V0dGluZ05hbWUyXSc6ICdiYXoyJyxcbiAgICAgIH07XG4gICAgICBjb25zdCBzZXR0aW5ncyA9IHB1bGxTZXR0aW5ncyhjYXBzKTtcbiAgICAgIHNldHRpbmdzLnNob3VsZC5lcWwoe1xuICAgICAgICBzZXR0aW5nTmFtZTogJ2JheicsXG4gICAgICAgIHNldHRpbmdOYW1lMjogJ2JhejInLFxuICAgICAgfSk7XG4gICAgICBjYXBzLnNob3VsZC5lcWwoe1xuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdmb28nLFxuICAgICAgICBicm93c2VyTmFtZTogJ2JhcicsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIHB1bGwgc2V0dGluZ3MgZGljdCBpZiBvYmplY3QgdmFsdWVzIGFyZSBwcmVzZW50IGluIGNhcHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBjYXBzID0ge1xuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdmb28nLFxuICAgICAgICBicm93c2VyTmFtZTogJ2JhcicsXG4gICAgICAgICdzZXR0aW5nc1tzZXR0aW5nTmFtZV0nOiB7a2V5OiAnYmF6J30sXG4gICAgICB9O1xuICAgICAgY29uc3Qgc2V0dGluZ3MgPSBwdWxsU2V0dGluZ3MoY2Fwcyk7XG4gICAgICBzZXR0aW5ncy5zaG91bGQuZXFsKHtcbiAgICAgICAgc2V0dGluZ05hbWU6IHtrZXk6ICdiYXonfSxcbiAgICAgIH0pO1xuICAgICAgY2Fwcy5zaG91bGQuZXFsKHtcbiAgICAgICAgcGxhdGZvcm1OYW1lOiAnZm9vJyxcbiAgICAgICAgYnJvd3Nlck5hbWU6ICdiYXInLFxuICAgICAgfSk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBwdWxsIGVtcHR5IGRpY3QgaWYgbm8gc2V0dGluZ3MgYXJlIHByZXNlbnQgaW4gY2FwcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGNhcHMgPSB7XG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ2ZvbycsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnYmFyJyxcbiAgICAgICAgJ3NldHRpbmdbc2V0dGluZ05hbWVdJzogJ2JheicsXG4gICAgICB9O1xuICAgICAgY29uc3Qgc2V0dGluZ3MgPSBwdWxsU2V0dGluZ3MoY2Fwcyk7XG4gICAgICBzZXR0aW5ncy5zaG91bGQuZXFsKHt9KTtcbiAgICAgIGNhcHMuc2hvdWxkLmVxbCh7XG4gICAgICAgIHBsYXRmb3JtTmFtZTogJ2ZvbycsXG4gICAgICAgIGJyb3dzZXJOYW1lOiAnYmFyJyxcbiAgICAgICAgJ3NldHRpbmdbc2V0dGluZ05hbWVdJzogJ2JheicsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIHB1bGwgZW1wdHkgZGljdCBpZiBjYXBzIGFyZSBlbXB0eScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGNhcHMgPSB7fTtcbiAgICAgIGNvbnN0IHNldHRpbmdzID0gcHVsbFNldHRpbmdzKGNhcHMpO1xuICAgICAgc2V0dGluZ3Muc2hvdWxkLmVxbCh7fSk7XG4gICAgICBjYXBzLnNob3VsZC5lcWwoe30pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnUmVhZG9ubHlNYXAnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBhbGxvdyB3cml0aW5nJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgbWFwID0gbmV3IFJlYWRvbmx5TWFwKCk7XG4gICAgICAoKCkgPT4gbWFwLnNldCgnZm9vJywgJ2JhcicpKS5zaG91bGQubm90LnRocm93KCk7XG5cbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYWxsb3cgcmVhZGluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IG1hcCA9IG5ldyBSZWFkb25seU1hcChbWydmb28nLCAnYmFyJ11dKTtcbiAgICAgICgoKSA9PiBtYXAuZ2V0KCdmb28nKSkuc2hvdWxkLm5vdC50aHJvdygpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBub3QgYWxsb3cgZGVsZXRpb24nLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBtYXAgPSBuZXcgUmVhZG9ubHlNYXAoW1snZm9vJywgJ2JhciddXSk7XG4gICAgICBtYXAuZGVsZXRlKCdmb28nKS5zaG91bGQuYmUuZmFsc2U7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG5vdCBhbGxvdyBjbGVhcmluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IG1hcCA9IG5ldyBSZWFkb25seU1hcChbWydmb28nLCAnYmFyJ11dKTtcbiAgICAgICgoKSA9PiBtYXAuY2xlYXIoKSkuc2hvdWxkLnRocm93KCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG5vdCBhbGxvdyB1cGRhdGluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IG1hcCA9IG5ldyBSZWFkb25seU1hcChbWydmb28nLCAnYmFyJ11dKTtcbiAgICAgICgoKSA9PiBtYXAuc2V0KCdmb28nLCAnYmF6JykpLnNob3VsZC50aHJvdygpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnaW5zcGVjdCgpJywgZnVuY3Rpb24gKCkge1xuXG4gICAgLyoqXG4gICAgICogQHR5cGUge2ltcG9ydCgnc2lub24nKS5TaW5vblNhbmRib3h9XG4gICAgICovXG4gICAgbGV0IHNhbmRib3g7XG4gICAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICBzYW5kYm94ID0gc2lub24uY3JlYXRlU2FuZGJveCgpO1xuICAgICAgc2FuZGJveC5zcHkobG9nZ2VyLCAnaW5mbycpO1xuICAgIH0pO1xuXG4gICAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHNhbmRib3gucmVzdG9yZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBsb2cgdGhlIHJlc3VsdCBvZiBpbnNwZWN0aW5nIGEgdmFsdWUnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpbnNwZWN0KHtmb286ICdiYXInfSk7XG4gICAgICBzdHJpcENvbG9ycygvKiogQHR5cGUge2ltcG9ydCgnc2lub24nKS5TaW5vblN0dWJ9ICovKGxvZ2dlci5pbmZvKS5maXJzdENhbGwuZmlyc3RBcmcpXG4gICAgICAgIC5zaG91bGQuZXF1YWwoJ3sgZm9vOiBcXCdiYXJcXCcgfScpO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl0sImZpbGUiOiJ0ZXN0L3V0aWxzLXNwZWNzLmpzIiwic291cmNlUm9vdCI6Ii4uLy4uIn0=
package/lib/cli/npm.js DELETED
@@ -1,251 +0,0 @@
1
- // @ts-check
2
-
3
- import path from 'path';
4
- import semver from 'semver';
5
- import { exec } from 'teen_process';
6
- import { fs, mkdirp, util, system } from '@appium/support';
7
-
8
- const INSTALL_LOCKFILE = '.appium.install.lock';
9
- const LINK_LOCKFILE = '.appium.link.lock';
10
-
11
- export default class NPM {
12
-
13
- /**
14
- * @param {string} appiumHome
15
- */
16
- constructor (appiumHome) {
17
- /** @type {string} */
18
- this.appiumHome = appiumHome;
19
- }
20
-
21
- /**
22
- * Execute `npm` with given args.
23
- *
24
- * If the process exits with a nonzero code, the contents of `STDOUT` and `STDERR` will be in the
25
- * `message` of the {@link TeenProcessExecError} rejected.
26
- * @param {string} cmd
27
- * @param {string[]} args
28
- * @param {{ json?: boolean; cwd?: string; lockFile?: string; }} opts
29
- */
30
- async exec (cmd, args, opts, execOpts = {}) {
31
- let { cwd, json, lockFile } = opts;
32
- if (!cwd) {
33
- cwd = this.appiumHome;
34
- }
35
- // ensure the directory we want to install inside of exists
36
- await mkdirp(cwd);
37
-
38
- // not only this, this directory needs a 'package.json' inside of it, otherwise, if any
39
- // directory in the filesystem tree ABOVE cwd happens to have a package.json or a node_modules
40
- // dir in it, NPM will install the module up there instead (silly NPM)
41
- const dummyPkgJson = path.resolve(cwd, 'package.json');
42
- if (!await fs.exists(dummyPkgJson)) {
43
- await fs.writeFile(dummyPkgJson, '{}');
44
- }
45
-
46
- // make sure we perform the current operation in cwd
47
- execOpts = {...execOpts, cwd};
48
-
49
- args.unshift(cmd);
50
- if (json) {
51
- args.push('--json');
52
- }
53
- const npmCmd = system.isWindows() ? 'npm.cmd' : 'npm';
54
- let runner = async () => await exec(npmCmd, args, execOpts);
55
- if (lockFile) {
56
- const acquireLock = util.getLockFileGuard(path.resolve(cwd, lockFile));
57
- const _runner = runner;
58
- runner = async () => await acquireLock(_runner);
59
- }
60
-
61
- let ret;
62
- try {
63
- const {stdout, stderr, code} = await runner();
64
- ret = /** @type {TeenProcessExecResult} */({stdout, stderr, code});
65
- // if possible, parse NPM's json output. During NPM install 3rd-party
66
- // packages can write to stdout, so sometimes the json output can't be
67
- // guaranteed to be parseable
68
- try {
69
- ret.json = JSON.parse(stdout);
70
- } catch (ign) {}
71
- } catch (e) {
72
- const {stdout, stderr, code} = /** @type {TeenProcessExecError} */(e);
73
- const err = new Error(`npm command '${cmd} ${args.join(' ')}' failed with code ${code}.\n\nSTDOUT:\n${stdout.trim()}\n\nSTDERR:\n${stderr.trim()}`);
74
- throw err;
75
- }
76
- return ret;
77
- }
78
-
79
- /**
80
- * @param {string} pkg
81
- */
82
- async getLatestVersion (pkg) {
83
- return (await this.exec('view', [pkg, 'dist-tags'], {
84
- json: true
85
- })).json?.latest;
86
- }
87
-
88
- /**
89
- * @param {string} pkg
90
- * @param {string} curVersion
91
- */
92
- async getLatestSafeUpgradeVersion (pkg, curVersion) {
93
- const allVersions = (await this.exec('view', [pkg, 'versions'], {
94
- json: true
95
- })).json;
96
- return this.getLatestSafeUpgradeFromVersions(curVersion, allVersions);
97
- }
98
-
99
- /**
100
- * Given a current version and a list of all versions for a package, return the version which is
101
- * the highest safely-upgradable version (meaning not crossing any major revision boundaries, and
102
- * not including any alpha/beta/rc versions)
103
- *
104
- * @param {string} curVersion - the current version of a package
105
- * @param {Array<string>} allVersions - a list of version strings
106
- *
107
- * @return {string|null} - the highest safely-upgradable version, or null if there isn't one
108
- */
109
- getLatestSafeUpgradeFromVersions (curVersion, allVersions) {
110
- let safeUpgradeVer = null;
111
- const curSemver = semver.parse(curVersion);
112
- if (curSemver === null) {
113
- throw new Error(`Could not parse current version '${curVersion}'`);
114
- }
115
- for (const testVer of allVersions) {
116
- const testSemver = semver.parse(testVer);
117
- if (testSemver === null) {
118
- throw new Error(`Could not parse version to test against: '${testVer}'`);
119
- }
120
- // if the test version is a prerelease, ignore it
121
- if (testSemver.prerelease.length > 0) {
122
- continue;
123
- }
124
- // if the current version is later than the test version, skip this test version
125
- if (curSemver.compare(testSemver) === 1) {
126
- continue;
127
- }
128
- // if the test version is newer, but crosses a major revision boundary, also skip it
129
- if (testSemver.major > curSemver.major) {
130
- continue;
131
- }
132
- // otherwise this version is safe to upgrade to. But there might be multiple ones of this
133
- // kind, so keep iterating and keeping the highest
134
- if (safeUpgradeVer === null || testSemver.compare(safeUpgradeVer) === 1) {
135
- safeUpgradeVer = testSemver;
136
- }
137
- }
138
- if (safeUpgradeVer) {
139
- safeUpgradeVer = safeUpgradeVer.format();
140
- }
141
- return safeUpgradeVer;
142
- }
143
-
144
- /**
145
- *
146
- * @param {{pkgDir: string, pkgName: string, pkgVer?: string}} param0
147
- * @returns {Promise<import('type-fest').PackageJson>}
148
- */
149
- async installPackage ({pkgDir, pkgName, pkgVer}) {
150
- const res = await this.exec('install', [
151
- '--no-save',
152
- '--no-package-lock',
153
- pkgVer ? `${pkgName}@${pkgVer}` : pkgName
154
- ], {
155
- cwd: pkgDir,
156
- json: true,
157
- lockFile: INSTALL_LOCKFILE
158
- });
159
-
160
- if (res.json) {
161
- // we parsed a valid json response, so if we got an error here, return that
162
- // message straightaway
163
- if (res.json.error) {
164
- throw new Error(res.json.error);
165
- }
166
- }
167
-
168
- // Now read package data from the installed package to return, and make sure
169
- // everything got installed ok. Remember, pkgName might end up with a / in it due to an npm
170
- // org, so if so, that will get correctly exploded into multiple directories, by path.resolve here
171
- // (even on Windows!)
172
- const pkgJson = path.resolve(pkgDir, 'node_modules', pkgName, 'package.json');
173
- try {
174
- return require(pkgJson);
175
- } catch {
176
- throw new Error('The package was not downloaded correctly; its package.json ' +
177
- 'did not exist or was unreadable. We looked for it at ' +
178
- pkgJson);
179
- }
180
- }
181
-
182
- /**
183
- * @param {string} pkgPath
184
- */
185
- async linkPackage (pkgPath) {
186
- // from the path alone we don't know the npm package name, so we need to
187
- // look in package.json
188
- let pkgName;
189
- try {
190
- pkgName = require(path.resolve(pkgPath, 'package.json')).name;
191
- } catch {
192
- throw new Error('Could not find package.json inside the package path ' +
193
- `provided: ${pkgPath}`);
194
- }
195
-
196
- // this is added to handle commands with relative paths
197
- // ie: "node . driver install --source=local ../fake-driver"
198
- pkgPath = path.resolve(process.cwd(), pkgPath);
199
-
200
- const pkgHome = path.resolve(this.appiumHome, pkgName);
201
-
202
- // call link with --no-package-lock to ensure no corruption while installing local packages
203
- const res = await this.exec('link', ['--no-package-lock', pkgPath], {cwd: pkgHome, lockFile: LINK_LOCKFILE});
204
- if (res.json && res.json.error) {
205
- throw new Error(res.json.error);
206
- }
207
-
208
- // now ensure it was linked to the correct place
209
- try {
210
- return require(path.resolve(pkgHome, 'node_modules', pkgName, 'package.json'));
211
- } catch {
212
- throw new Error('The package was not linked correctly; its package.json ' +
213
- 'did not exist or was unreadable');
214
- }
215
- }
216
-
217
- /**
218
- * @param {string} pkgDir
219
- * @param {string} pkg
220
- */
221
- async uninstallPackage (pkgDir, pkg) {
222
- await this.exec('uninstall', [pkg], {
223
- cwd: pkgDir,
224
- lockFile: INSTALL_LOCKFILE
225
- });
226
- }
227
- }
228
-
229
-
230
- /**
231
- * Result from a non-zero-exit execution of `appium`
232
- * @typedef {Object} TeenProcessExecResult
233
- * @property {string} stdout - Stdout
234
- * @property {string} stderr - Stderr
235
- * @property {number?} code - Exit code
236
- * @property {any} json - JSON parsed from stdout
237
- */
238
-
239
- /**
240
- * Extra props `teen_process.exec` adds to its error objects
241
- * @typedef {Object} TeenProcessExecErrorProps
242
- * @property {string} stdout - STDOUT
243
- * @property {string} stderr - STDERR
244
- * @property {number?} code - Exit code
245
- */
246
-
247
-
248
- /**
249
- * Error thrown by `teen_process.exec`
250
- * @typedef {Error & TeenProcessExecErrorProps} TeenProcessExecError
251
- */
@@ -1,101 +0,0 @@
1
- // @ts-check
2
-
3
- import _ from 'lodash';
4
- import ExtensionConfig from './extension-config';
5
- import { DRIVER_TYPE } from './ext-config-io';
6
-
7
- export default class DriverConfig extends ExtensionConfig {
8
- /**
9
- * A mapping of `APPIUM_HOME` values to {@link DriverConfig} instances.
10
- * Each `APPIUM_HOME` should only have one associated `DriverConfig` instance.
11
- * @type {Record<string,DriverConfig>}
12
- * @private
13
- */
14
- static _instances = {};
15
-
16
- /**
17
- * Call {@link DriverConfig.getInstance} instead.
18
- * @private
19
- * @param {string} appiumHome
20
- * @param {(...args: any[]) => void} [logFn]
21
- */
22
- constructor (appiumHome, logFn) {
23
- super(appiumHome, DRIVER_TYPE, logFn);
24
- /** @type {Set<string>} */
25
- this.knownAutomationNames = new Set();
26
- }
27
-
28
- async read () {
29
- this.knownAutomationNames.clear();
30
- return await super.read();
31
- }
32
-
33
- /**
34
- * Creates or gets an instance of {@link DriverConfig} based value of `appiumHome`
35
- * @param {string} appiumHome - `APPIUM_HOME` path
36
- * @param {(...args: any[]) => void} [logFn] - Optional logging function
37
- * @returns {DriverConfig}
38
- */
39
- static getInstance (appiumHome, logFn) {
40
- const instance = DriverConfig._instances[appiumHome] ?? new DriverConfig(appiumHome, logFn);
41
- DriverConfig._instances[appiumHome] = instance;
42
- return instance;
43
- }
44
-
45
- /**
46
- *
47
- * @param {object} extData
48
- * @param {string} extName
49
- * @returns {import('./extension-config').Problem[]}
50
- */
51
- // eslint-disable-next-line no-unused-vars
52
- getConfigProblems (extData, extName) {
53
- const problems = [];
54
- const {platformNames, automationName} = extData;
55
-
56
- if (!_.isArray(platformNames)) {
57
- problems.push({
58
- err: 'Missing or incorrect supported platformNames list.',
59
- val: platformNames
60
- });
61
- } else {
62
- if (_.isEmpty(platformNames)) {
63
- problems.push({
64
- err: 'Empty platformNames list.',
65
- val: platformNames
66
- });
67
- } else {
68
- for (const pName of platformNames) {
69
- if (!_.isString(pName)) {
70
- problems.push({err: 'Incorrectly formatted platformName.', val: pName});
71
- }
72
- }
73
- }
74
- }
75
-
76
- if (!_.isString(automationName)) {
77
- problems.push({err: 'Missing or incorrect automationName', val: automationName});
78
- }
79
-
80
- if (this.knownAutomationNames.has(automationName)) {
81
- problems.push({
82
- err: 'Multiple drivers claim support for the same automationName',
83
- val: automationName
84
- });
85
- }
86
-
87
- // should we retain the name at the end of this function, once we've checked there are no problems?
88
- this.knownAutomationNames.add(automationName);
89
-
90
- return problems;
91
- }
92
-
93
- /**
94
- * @param {string} driverName
95
- * @param {object} extData
96
- */
97
- extensionDesc (driverName, {version, automationName}) {
98
- return `${driverName}@${version} (automationName '${automationName}')`;
99
- }
100
- }
101
-