appium 2.0.0-beta.46 → 2.0.0-beta.47

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 (138) hide show
  1. package/README.md +145 -44
  2. package/build/lib/appium.d.ts +3 -103
  3. package/build/lib/appium.d.ts.map +1 -1
  4. package/build/lib/appium.js +679 -549
  5. package/build/lib/appium.js.map +1 -1
  6. package/build/lib/cli/args.js +247 -127
  7. package/build/lib/cli/args.js.map +1 -1
  8. package/build/lib/cli/driver-command.js +63 -88
  9. package/build/lib/cli/driver-command.js.map +1 -1
  10. package/build/lib/cli/extension-command.d.ts +32 -23
  11. package/build/lib/cli/extension-command.d.ts.map +1 -1
  12. package/build/lib/cli/extension-command.js +730 -512
  13. package/build/lib/cli/extension-command.js.map +1 -1
  14. package/build/lib/cli/extension.d.ts +7 -6
  15. package/build/lib/cli/extension.d.ts.map +1 -1
  16. package/build/lib/cli/extension.js +68 -65
  17. package/build/lib/cli/extension.js.map +1 -1
  18. package/build/lib/cli/parser.d.ts +3 -3
  19. package/build/lib/cli/parser.d.ts.map +1 -1
  20. package/build/lib/cli/parser.js +234 -192
  21. package/build/lib/cli/parser.js.map +1 -1
  22. package/build/lib/cli/plugin-command.js +58 -87
  23. package/build/lib/cli/plugin-command.js.map +1 -1
  24. package/build/lib/cli/utils.js +66 -69
  25. package/build/lib/cli/utils.js.map +1 -1
  26. package/build/lib/config-file.d.ts.map +1 -1
  27. package/build/lib/config-file.js +189 -120
  28. package/build/lib/config-file.js.map +1 -1
  29. package/build/lib/config.d.ts.map +1 -1
  30. package/build/lib/config.js +254 -213
  31. package/build/lib/config.js.map +1 -1
  32. package/build/lib/constants.d.ts +5 -5
  33. package/build/lib/constants.d.ts.map +1 -1
  34. package/build/lib/constants.js +64 -59
  35. package/build/lib/constants.js.map +1 -1
  36. package/build/lib/extension/driver-config.js +199 -164
  37. package/build/lib/extension/driver-config.js.map +1 -1
  38. package/build/lib/extension/extension-config.d.ts +18 -16
  39. package/build/lib/extension/extension-config.d.ts.map +1 -1
  40. package/build/lib/extension/extension-config.js +523 -396
  41. package/build/lib/extension/extension-config.js.map +1 -1
  42. package/build/lib/extension/index.js +98 -68
  43. package/build/lib/extension/index.js.map +1 -1
  44. package/build/lib/extension/manifest-migrations.d.ts +27 -0
  45. package/build/lib/extension/manifest-migrations.d.ts.map +1 -0
  46. package/build/lib/extension/manifest-migrations.js +99 -0
  47. package/build/lib/extension/manifest-migrations.js.map +1 -0
  48. package/build/lib/extension/manifest.d.ts +7 -56
  49. package/build/lib/extension/manifest.d.ts.map +1 -1
  50. package/build/lib/extension/manifest.js +432 -240
  51. package/build/lib/extension/manifest.js.map +1 -1
  52. package/build/lib/extension/package-changed.js +57 -61
  53. package/build/lib/extension/package-changed.js.map +1 -1
  54. package/build/lib/extension/plugin-config.d.ts +2 -3
  55. package/build/lib/extension/plugin-config.d.ts.map +1 -1
  56. package/build/lib/extension/plugin-config.js +94 -70
  57. package/build/lib/extension/plugin-config.js.map +1 -1
  58. package/build/lib/grid-register.js +119 -137
  59. package/build/lib/grid-register.js.map +1 -1
  60. package/build/lib/logger.d.ts +1 -1
  61. package/build/lib/logger.d.ts.map +1 -1
  62. package/build/lib/logger.js +5 -15
  63. package/build/lib/logger.js.map +1 -1
  64. package/build/lib/logsink.d.ts.map +1 -1
  65. package/build/lib/logsink.js +189 -183
  66. package/build/lib/logsink.js.map +1 -1
  67. package/build/lib/main.d.ts +19 -12
  68. package/build/lib/main.d.ts.map +1 -1
  69. package/build/lib/main.js +330 -304
  70. package/build/lib/main.js.map +1 -1
  71. package/build/lib/schema/arg-spec.js +153 -108
  72. package/build/lib/schema/arg-spec.js.map +1 -1
  73. package/build/lib/schema/cli-args.js +203 -164
  74. package/build/lib/schema/cli-args.js.map +1 -1
  75. package/build/lib/schema/cli-transformers.js +117 -72
  76. package/build/lib/schema/cli-transformers.js.map +1 -1
  77. package/build/lib/schema/index.js +17 -32
  78. package/build/lib/schema/index.js.map +1 -1
  79. package/build/lib/schema/keywords.js +125 -67
  80. package/build/lib/schema/keywords.js.map +1 -1
  81. package/build/lib/schema/schema.d.ts.map +1 -1
  82. package/build/lib/schema/schema.js +582 -417
  83. package/build/lib/schema/schema.js.map +1 -1
  84. package/build/lib/utils.d.ts +41 -255
  85. package/build/lib/utils.d.ts.map +1 -1
  86. package/build/lib/utils.js +342 -193
  87. package/build/lib/utils.js.map +1 -1
  88. package/build/tsconfig.tsbuildinfo +1 -1
  89. package/build/types/cli.d.ts +45 -34
  90. package/build/types/cli.d.ts.map +1 -1
  91. package/build/types/cli.js +3 -0
  92. package/build/types/cli.js.map +1 -0
  93. package/build/types/index.d.ts +1 -2
  94. package/build/types/index.d.ts.map +1 -1
  95. package/build/types/index.js +19 -0
  96. package/build/types/index.js.map +1 -0
  97. package/build/types/manifest/base.d.ts +135 -0
  98. package/build/types/manifest/base.d.ts.map +1 -0
  99. package/build/types/manifest/base.js +3 -0
  100. package/build/types/manifest/base.js.map +1 -0
  101. package/build/types/manifest/index.d.ts +19 -0
  102. package/build/types/manifest/index.d.ts.map +1 -0
  103. package/build/types/manifest/index.js +40 -0
  104. package/build/types/manifest/index.js.map +1 -0
  105. package/build/types/manifest/v3.d.ts +139 -0
  106. package/build/types/manifest/v3.d.ts.map +1 -0
  107. package/build/types/manifest/v3.js +3 -0
  108. package/build/types/manifest/v3.js.map +1 -0
  109. package/lib/appium.js +1 -1
  110. package/lib/cli/args.js +1 -1
  111. package/lib/cli/extension-command.js +116 -61
  112. package/lib/cli/extension.js +9 -8
  113. package/lib/cli/parser.js +2 -2
  114. package/lib/config-file.js +2 -3
  115. package/lib/config.js +3 -2
  116. package/lib/constants.js +6 -5
  117. package/lib/extension/extension-config.js +24 -25
  118. package/lib/extension/manifest-migrations.js +99 -0
  119. package/lib/extension/manifest.js +79 -72
  120. package/lib/extension/plugin-config.js +1 -2
  121. package/lib/logsink.js +26 -5
  122. package/lib/main.js +58 -50
  123. package/lib/schema/schema.js +6 -1
  124. package/lib/utils.js +62 -0
  125. package/package.json +23 -24
  126. package/scripts/autoinstall-extensions.js +78 -26
  127. package/types/cli.ts +81 -42
  128. package/types/index.ts +1 -2
  129. package/types/manifest/README.md +30 -0
  130. package/types/manifest/base.ts +158 -0
  131. package/types/manifest/index.ts +27 -0
  132. package/types/manifest/v3.ts +161 -0
  133. package/build/types/appium-manifest.d.ts +0 -59
  134. package/build/types/appium-manifest.d.ts.map +0 -1
  135. package/build/types/extension-manifest.d.ts +0 -55
  136. package/build/types/extension-manifest.d.ts.map +0 -1
  137. package/types/appium-manifest.ts +0 -73
  138. package/types/extension-manifest.ts +0 -64
@@ -1,535 +1,753 @@
1
1
  "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = exports.ExtensionCommand = void 0;
7
-
8
- require("source-map-support/register");
9
-
10
- var _bluebird = _interopRequireDefault(require("bluebird"));
11
-
12
- var _lodash = _interopRequireDefault(require("lodash"));
13
-
14
- var _path = _interopRequireDefault(require("path"));
15
-
16
- var _support = require("@appium/support");
17
-
18
- var _utils = require("./utils");
19
-
20
- var _teen_process = require("teen_process");
21
-
22
- var _extensionConfig = require("../extension/extension-config");
23
-
24
- var _packageChanged = require("../extension/package-changed");
25
-
26
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
27
-
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ExtensionCommand = void 0;
7
+ /* eslint-disable no-console */
8
+ const bluebird_1 = __importDefault(require("bluebird"));
9
+ const lodash_1 = __importDefault(require("lodash"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const support_1 = require("@appium/support");
12
+ const utils_1 = require("./utils");
13
+ const teen_process_1 = require("teen_process");
14
+ const extension_config_1 = require("../extension/extension-config");
15
+ const package_changed_1 = require("../extension/package-changed");
28
16
  const UPDATE_ALL = 'installed';
29
-
30
- class NotUpdatableError extends Error {}
31
-
32
- class NoUpdatesAvailableError extends Error {}
33
-
17
+ class NotUpdatableError extends Error {
18
+ }
19
+ class NoUpdatesAvailableError extends Error {
20
+ }
21
+ /**
22
+ * Omits `driverName`/`pluginName` props from the receipt to make a {@linkcode ExtManifest}
23
+ * @template {ExtensionType} ExtType
24
+ * @param {ExtInstallReceipt<ExtType>} receipt
25
+ * @returns {ExtManifest<ExtType>}
26
+ */
27
+ function receiptToManifest(receipt) {
28
+ return /** @type {ExtManifest<ExtType>} */ (lodash_1.default.omit(receipt, 'driverName', 'pluginName'));
29
+ }
30
+ /**
31
+ * @template {ExtensionType} ExtType
32
+ */
34
33
  class ExtensionCommand {
35
- config;
36
- knownExtensions;
37
- isJsonOutput;
38
-
39
- constructor({
40
- config,
41
- json
42
- }) {
43
- this.config = config;
44
- this.log = new _support.console.CliConsole({
45
- jsonMode: json
46
- });
47
- this.isJsonOutput = Boolean(json);
48
- }
49
-
50
- get type() {
51
- return this.config.extensionType;
52
- }
53
-
54
- _createFatalError(message) {
55
- return new Error(this.log.decorate(message, 'error'));
56
- }
57
-
58
- async execute(args) {
59
- const cmd = args[`${this.type}Command`];
60
-
61
- if (!_lodash.default.isFunction(this[cmd])) {
62
- throw this._createFatalError(`Cannot handle ${this.type} command ${cmd}`);
63
- }
64
-
65
- const executeCmd = this[cmd].bind(this);
66
- return await executeCmd(args);
67
- }
68
-
69
- async list({
70
- showInstalled,
71
- showUpdates
72
- }) {
73
- const lsMsg = `Listing ${showInstalled ? 'installed' : 'available'} ${this.type}s`;
74
- const installedNames = Object.keys(this.config.installedExtensions);
75
- const knownNames = Object.keys(this.knownExtensions);
76
- const exts = [...installedNames, ...knownNames].reduce((acc, name) => {
77
- if (!acc[name]) {
78
- if (installedNames.includes(name)) {
79
- acc[name] = { ...this.config.installedExtensions[name],
80
- installed: true
81
- };
82
- } else if (!showInstalled) {
83
- acc[name] = {
84
- pkgName: this.knownExtensions[name],
85
- installed: false
86
- };
87
- }
88
- }
89
-
90
- return acc;
91
- }, {});
92
- await (0, _utils.spinWith)(this.isJsonOutput, lsMsg, async () => {
93
- if (!showUpdates) {
94
- return;
95
- }
96
-
97
- for (const [ext, data] of _lodash.default.toPairs(exts)) {
98
- if (!data.installed || data.installType !== _extensionConfig.INSTALL_TYPE_NPM) {
99
- continue;
100
- }
101
-
102
- const updates = await this.checkForExtensionUpdate(ext);
103
- data.updateVersion = updates.safeUpdate;
104
- data.unsafeUpdateVersion = updates.unsafeUpdate;
105
- data.upToDate = updates.safeUpdate === null && updates.unsafeUpdate === null;
106
- }
107
- });
108
- const listData = exts;
109
-
110
- if (this.isJsonOutput) {
111
- return listData;
112
- }
113
-
114
- for (const [name, data] of _lodash.default.toPairs(listData)) {
115
- let installTxt = ' [not installed]'.grey;
116
- let updateTxt = '';
117
- let upToDateTxt = '';
118
- let unsafeUpdateTxt = '';
119
-
120
- if (data.installed) {
121
- const {
122
- installType,
123
- installSpec,
124
- updateVersion,
125
- unsafeUpdateVersion,
126
- version,
127
- upToDate
128
- } = data;
129
- let typeTxt;
130
-
131
- switch (installType) {
132
- case _extensionConfig.INSTALL_TYPE_GIT:
133
- case _extensionConfig.INSTALL_TYPE_GITHUB:
134
- typeTxt = `(cloned from ${installSpec})`.yellow;
135
- break;
136
-
137
- case _extensionConfig.INSTALL_TYPE_LOCAL:
138
- typeTxt = `(linked from ${installSpec})`.magenta;
139
- break;
140
-
141
- default:
142
- typeTxt = '(NPM)';
143
- }
144
-
145
- installTxt = `@${version.yellow} ${('[installed ' + typeTxt + ']').green}`;
146
-
147
- if (showUpdates) {
148
- if (updateVersion) {
149
- updateTxt = ` [${updateVersion} available]`.magenta;
150
- }
151
-
152
- if (upToDate) {
153
- upToDateTxt = ` [Up to date]`.green;
154
- }
155
-
156
- if (unsafeUpdateVersion) {
157
- unsafeUpdateTxt = ` [${unsafeUpdateVersion} available (potentially unsafe)]`.cyan;
158
- }
159
- }
160
- }
161
-
162
- this.log.log(`- ${name.yellow}${installTxt}${updateTxt}${upToDateTxt}${unsafeUpdateTxt}`);
163
- }
164
-
165
- return listData;
166
- }
167
-
168
- async _install({
169
- installSpec,
170
- installType,
171
- packageName
172
- }) {
173
- let extData;
174
-
175
- if (packageName && [_extensionConfig.INSTALL_TYPE_LOCAL, _extensionConfig.INSTALL_TYPE_NPM].includes(installType)) {
176
- throw this._createFatalError(`When using --source=${installType}, cannot also use --package`);
177
- }
178
-
179
- if (!packageName && [_extensionConfig.INSTALL_TYPE_GIT, _extensionConfig.INSTALL_TYPE_GITHUB].includes(installType)) {
180
- throw this._createFatalError(`When using --source=${installType}, must also use --package`);
34
+ /**
35
+ * Build an ExtensionCommand
36
+ * @param {ExtensionCommandOptions<ExtType>} opts
37
+ */
38
+ constructor({ config, json }) {
39
+ this.config = config;
40
+ this.log = new support_1.console.CliConsole({ jsonMode: json });
41
+ this.isJsonOutput = Boolean(json);
181
42
  }
182
-
183
- let installOpts;
184
- let probableExtName = '';
185
-
186
- if (installType === _extensionConfig.INSTALL_TYPE_GITHUB) {
187
- if (installSpec.split('/').length !== 2) {
188
- throw this._createFatalError(`Github ${this.type} spec ${installSpec} appeared to be invalid; ` + 'it should be of the form <org>/<repo>');
189
- }
190
-
191
- installOpts = {
192
- installSpec,
193
- pkgName: packageName
194
- };
195
- probableExtName = installSpec;
196
- } else if (installType === _extensionConfig.INSTALL_TYPE_GIT) {
197
- installSpec = installSpec.replace(/\.git$/, '');
198
- installOpts = {
199
- installSpec,
200
- pkgName: packageName
201
- };
202
- probableExtName = installSpec;
203
- } else {
204
- let pkgName, pkgVer;
205
-
206
- if (installType === _extensionConfig.INSTALL_TYPE_LOCAL) {
207
- pkgName = _path.default.isAbsolute(installSpec) ? installSpec : _path.default.resolve(installSpec);
208
- } else {
209
- let name;
210
- const splits = installSpec.split('@');
211
-
212
- if (installSpec[0] === '@') {
213
- [name, pkgVer] = [`@${splits[1]}`, splits[2]];
214
- } else {
215
- [name, pkgVer] = splits;
216
- }
217
-
218
- if (installType === _extensionConfig.INSTALL_TYPE_NPM) {
219
- pkgName = name;
220
- } else {
221
- const knownNames = Object.keys(this.knownExtensions);
222
-
223
- if (!_lodash.default.includes(knownNames, name)) {
224
- const msg = `Could not resolve ${this.type}; are you sure it's in the list ` + `of supported ${this.type}s? ${JSON.stringify(knownNames)}`;
225
- throw this._createFatalError(msg);
226
- }
227
-
228
- probableExtName = name;
229
- pkgName = this.knownExtensions[name];
230
- installType = _extensionConfig.INSTALL_TYPE_NPM;
231
- }
232
- }
233
-
234
- installOpts = {
235
- installSpec,
236
- pkgName,
237
- pkgVer
238
- };
43
+ /**
44
+ * `driver` or `plugin`, depending on the `ExtensionConfig`.
45
+ */
46
+ get type() {
47
+ return this.config.extensionType;
239
48
  }
240
-
241
- if (probableExtName && this.config.isInstalled(probableExtName)) {
242
- throw this._createFatalError(`A ${this.type} named "${probableExtName}" is already installed. ` + `Did you mean to update? Run "appium ${this.type} update". See ` + `installed ${this.type}s with "appium ${this.type} list --installed".`);
49
+ /**
50
+ * Logs a message and returns an {@linkcode Error} to throw.
51
+ *
52
+ * For TS to understand that a function throws an exception, it must actually throw an exception--
53
+ * in other words, _calling_ a function which is guaranteed to throw an exception is not enough--
54
+ * nor is something like `@returns {never}` which does not imply a thrown exception.
55
+ * @param {string} message
56
+ * @protected
57
+ * @returns {Error}
58
+ */
59
+ _createFatalError(message) {
60
+ return new Error(this.log.decorate(message, 'error'));
243
61
  }
244
-
245
- extData = await this.installViaNpm(installOpts);
246
- const extName = extData[`${this.type}Name`];
247
-
248
- if (this.config.isInstalled(extName)) {
249
- throw this._createFatalError(`A ${this.type} named "${extName}" is already installed. ` + `Did you mean to update? Run "appium ${this.type} update". See ` + `installed ${this.type}s with "appium ${this.type} list --installed".`);
250
- }
251
-
252
- delete extData[`${this.type}Name`];
253
- const extManifest = { ...extData,
254
- installType,
255
- installSpec
256
- };
257
- const [errors, warnings] = await _bluebird.default.all([this.config.getProblems(extName, extManifest), this.config.getWarnings(extName, extManifest)]);
258
- const errorMap = new Map([[extName, errors]]);
259
- const warningMap = new Map([[extName, warnings]]);
260
- const {
261
- errorSummaries,
262
- warningSummaries
263
- } = this.config.getValidationResultSummaries(errorMap, warningMap);
264
-
265
- if (!_lodash.default.isEmpty(errorSummaries)) {
266
- throw this._createFatalError(errorSummaries.join('\n'));
267
- }
268
-
269
- if (!_lodash.default.isEmpty(warningSummaries)) {
270
- this.log.warn(warningSummaries.join('\n'));
271
- }
272
-
273
- await this.config.addExtension(extName, extManifest);
274
-
275
- if (await _support.env.hasAppiumDependency(this.config.appiumHome)) {
276
- await (0, _packageChanged.packageDidChange)(this.config.appiumHome);
62
+ /**
63
+ * Take a CLI parse and run an extension command based on its type
64
+ *
65
+ * @param {object} args - a key/value object with CLI flags and values
66
+ * @return {Promise<object>} the result of the specific command which is executed
67
+ */
68
+ async execute(args) {
69
+ const cmd = args[`${this.type}Command`];
70
+ if (!lodash_1.default.isFunction(this[cmd])) {
71
+ throw this._createFatalError(`Cannot handle ${this.type} command ${cmd}`);
72
+ }
73
+ const executeCmd = this[cmd].bind(this);
74
+ return await executeCmd(args);
277
75
  }
278
-
279
- this.log.info(this.getPostInstallText({
280
- extName,
281
- extData
282
- }));
283
- return this.config.installedExtensions;
284
- }
285
-
286
- async installViaNpm({
287
- installSpec,
288
- pkgName,
289
- pkgVer
290
- }) {
291
- const npmSpec = `${pkgName}${pkgVer ? '@' + pkgVer : ''}`;
292
- const specMsg = npmSpec === installSpec ? '' : ` using NPM install spec '${npmSpec}'`;
293
- const msg = `Installing '${installSpec}'${specMsg}`;
294
-
295
- try {
296
- const pkgJsonData = await (0, _utils.spinWith)(this.isJsonOutput, msg, async () => {
297
- const pkgJsonData = await _support.npm.installPackage(this.config.appiumHome, pkgName, {
298
- pkgVer
76
+ /**
77
+ * List extensions
78
+ *
79
+ * @param {ListOptions} opts
80
+ * @return {Promise<ExtensionListData>} map of extension names to extension data
81
+ */
82
+ async list({ showInstalled, showUpdates }) {
83
+ const lsMsg = `Listing ${showInstalled ? 'installed' : 'available'} ${this.type}s`;
84
+ const installedNames = Object.keys(this.config.installedExtensions);
85
+ const knownNames = Object.keys(this.knownExtensions);
86
+ const exts = [...installedNames, ...knownNames].reduce((acc, name) => {
87
+ if (!acc[name]) {
88
+ if (installedNames.includes(name)) {
89
+ acc[name] = {
90
+ ...this.config.installedExtensions[name],
91
+ installed: true,
92
+ };
93
+ }
94
+ else if (!showInstalled) {
95
+ acc[name] = { pkgName: this.knownExtensions[name], installed: false };
96
+ }
97
+ }
98
+ return acc;
99
+ },
100
+ /**
101
+ * This accumulator contains either {@linkcode UninstalledExtensionLIstData} _or_
102
+ * {@linkcode InstalledExtensionListData} without upgrade information (which is added by the below code block)
103
+ * @type {Record<string,Partial<InstalledExtensionListData>|UninstalledExtensionListData>}
104
+ */ ({}));
105
+ // if we want to show whether updates are available, put that behind a spinner
106
+ await (0, utils_1.spinWith)(this.isJsonOutput, lsMsg, async () => {
107
+ if (!showUpdates) {
108
+ return;
109
+ }
110
+ for (const [ext, data] of lodash_1.default.toPairs(exts)) {
111
+ if (!data.installed || data.installType !== extension_config_1.INSTALL_TYPE_NPM) {
112
+ // don't need to check for updates on exts that aren't installed
113
+ // also don't need to check for updates on non-npm exts
114
+ continue;
115
+ }
116
+ try {
117
+ const updates = await this.checkForExtensionUpdate(ext);
118
+ data.updateVersion = updates.safeUpdate;
119
+ data.unsafeUpdateVersion = updates.unsafeUpdate;
120
+ data.upToDate = updates.safeUpdate === null && updates.unsafeUpdate === null;
121
+ }
122
+ catch (e) {
123
+ data.updateError = e.message;
124
+ }
125
+ }
299
126
  });
300
- this.validatePackageJson(pkgJsonData, installSpec);
301
- return pkgJsonData;
302
- });
303
- return this.getExtensionFields(pkgJsonData);
304
- } catch (err) {
305
- throw this._createFatalError(`Encountered an error when installing package: ${err.message}`);
306
- }
307
- }
308
-
309
- getPostInstallText(args) {
310
- throw this._createFatalError('Must be implemented in final class');
311
- }
312
-
313
- getExtensionFields(pkgJson) {
314
- const {
315
- appium,
316
- name,
317
- version,
318
- peerDependencies
319
- } = pkgJson;
320
- const result = { ...appium,
321
- pkgName: name,
322
- version,
323
- appiumVersion: peerDependencies === null || peerDependencies === void 0 ? void 0 : peerDependencies.appium
324
- };
325
- return result;
326
- }
327
-
328
- validatePackageJson(pkgJson, installSpec) {
329
- const {
330
- appium,
331
- name,
332
- version
333
- } = pkgJson;
334
-
335
- const createMissingFieldError = field => new ReferenceError(`${this.type} "${installSpec}" invalid; missing a \`${field}\` field of its \`package.json\``);
336
-
337
- if (!name) {
338
- throw createMissingFieldError('name');
339
- }
340
-
341
- if (!version) {
342
- throw createMissingFieldError('version');
127
+ const listData = /** @type {ExtensionListData} */ (exts);
128
+ // if we're just getting the data, short circuit return here since we don't need to do any
129
+ // formatting logic
130
+ if (this.isJsonOutput) {
131
+ return listData;
132
+ }
133
+ for (const [name, data] of lodash_1.default.toPairs(listData)) {
134
+ let installTxt = ' [not installed]'.grey;
135
+ let updateTxt = '';
136
+ let upToDateTxt = '';
137
+ let unsafeUpdateTxt = '';
138
+ if (data.installed) {
139
+ const { installType, installSpec, updateVersion, unsafeUpdateVersion, version, upToDate, updateError, } = data;
140
+ let typeTxt;
141
+ switch (installType) {
142
+ case extension_config_1.INSTALL_TYPE_GIT:
143
+ case extension_config_1.INSTALL_TYPE_GITHUB:
144
+ typeTxt = `(cloned from ${installSpec})`.yellow;
145
+ break;
146
+ case extension_config_1.INSTALL_TYPE_LOCAL:
147
+ typeTxt = `(linked from ${installSpec})`.magenta;
148
+ break;
149
+ default:
150
+ typeTxt = '(NPM)';
151
+ }
152
+ installTxt = `@${version.yellow} ${('[installed ' + typeTxt + ']').green}`;
153
+ if (showUpdates) {
154
+ if (updateError) {
155
+ updateTxt = ` [Cannot check for updates: ${updateError}]`.red;
156
+ }
157
+ else {
158
+ if (updateVersion) {
159
+ updateTxt = ` [${updateVersion} available]`.magenta;
160
+ }
161
+ if (upToDate) {
162
+ upToDateTxt = ` [Up to date]`.green;
163
+ }
164
+ if (unsafeUpdateVersion) {
165
+ unsafeUpdateTxt = ` [${unsafeUpdateVersion} available (potentially unsafe)]`.cyan;
166
+ }
167
+ }
168
+ }
169
+ }
170
+ this.log.log(`- ${name.yellow}${installTxt}${updateTxt}${upToDateTxt}${unsafeUpdateTxt}`);
171
+ }
172
+ return listData;
343
173
  }
344
-
345
- if (!appium) {
346
- throw createMissingFieldError('appium');
174
+ /**
175
+ * Install an extension
176
+ *
177
+ * @param {InstallOpts} opts
178
+ * @return {Promise<ExtRecord<ExtType>>} map of all installed extension names to extension data
179
+ */
180
+ async _install({ installSpec, installType, packageName }) {
181
+ /** @type {ExtInstallReceipt<ExtType>} */
182
+ let receipt;
183
+ if (packageName && [extension_config_1.INSTALL_TYPE_LOCAL, extension_config_1.INSTALL_TYPE_NPM].includes(installType)) {
184
+ throw this._createFatalError(`When using --source=${installType}, cannot also use --package`);
185
+ }
186
+ if (!packageName && [extension_config_1.INSTALL_TYPE_GIT, extension_config_1.INSTALL_TYPE_GITHUB].includes(installType)) {
187
+ throw this._createFatalError(`When using --source=${installType}, must also use --package`);
188
+ }
189
+ /**
190
+ * @type {InstallViaNpmArgs}
191
+ */
192
+ let installViaNpmOpts;
193
+ /**
194
+ * The probable (?) name of the extension derived from the install spec.
195
+ *
196
+ * If using a local install type, this will remain empty.
197
+ * @type {string}
198
+ */
199
+ let probableExtName = '';
200
+ // depending on `installType`, build the options to pass into `installViaNpm`
201
+ if (installType === extension_config_1.INSTALL_TYPE_GITHUB) {
202
+ if (installSpec.split('/').length !== 2) {
203
+ throw this._createFatalError(`Github ${this.type} spec ${installSpec} appeared to be invalid; ` +
204
+ 'it should be of the form <org>/<repo>');
205
+ }
206
+ installViaNpmOpts = {
207
+ installSpec,
208
+ installType,
209
+ pkgName: /** @type {string} */ (packageName),
210
+ };
211
+ probableExtName = installSpec;
212
+ }
213
+ else if (installType === extension_config_1.INSTALL_TYPE_GIT) {
214
+ // git urls can have '.git' at the end, but this is not necessary and would complicate the
215
+ // way we download and name directories, so we can just remove it
216
+ installSpec = installSpec.replace(/\.git$/, '');
217
+ installViaNpmOpts = {
218
+ installSpec,
219
+ installType,
220
+ pkgName: /** @type {string} */ (packageName),
221
+ };
222
+ probableExtName = installSpec;
223
+ }
224
+ else {
225
+ let pkgName, pkgVer;
226
+ if (installType === extension_config_1.INSTALL_TYPE_LOCAL) {
227
+ pkgName = path_1.default.isAbsolute(installSpec) ? installSpec : path_1.default.resolve(installSpec);
228
+ }
229
+ else {
230
+ // at this point we have either an npm package or an appium verified extension
231
+ // name or a local path. both of which will be installed via npm.
232
+ // extensions installed via npm can include versions or tags after the '@'
233
+ // sign, so check for that. We also need to be careful that package names themselves can
234
+ // contain the '@' symbol, as in `npm install @appium/fake-driver@1.2.0`
235
+ let name;
236
+ const splits = installSpec.split('@');
237
+ if (installSpec[0] === '@') {
238
+ // this is the case where we have an npm org included in the package name
239
+ [name, pkgVer] = [`@${splits[1]}`, splits[2]];
240
+ }
241
+ else {
242
+ // this is the case without an npm org
243
+ [name, pkgVer] = splits;
244
+ }
245
+ if (installType === extension_config_1.INSTALL_TYPE_NPM) {
246
+ // if we're installing a named package from npm, we don't need to check
247
+ // against the appium extension list; just use the installSpec as is
248
+ pkgName = name;
249
+ }
250
+ else {
251
+ // if we're installing a named appium driver (like 'xcuitest') we need to
252
+ // dereference the actual npm package ('appiupm-xcuitest-driver'), so
253
+ // check it exists and get the correct package
254
+ const knownNames = Object.keys(this.knownExtensions);
255
+ if (!lodash_1.default.includes(knownNames, name)) {
256
+ const msg = `Could not resolve ${this.type}; are you sure it's in the list ` +
257
+ `of supported ${this.type}s? ${JSON.stringify(knownNames)}`;
258
+ throw this._createFatalError(msg);
259
+ }
260
+ probableExtName = name;
261
+ pkgName = this.knownExtensions[name];
262
+ // given that we'll use the install type in the driver json, store it as
263
+ // 'npm' now
264
+ installType = extension_config_1.INSTALL_TYPE_NPM;
265
+ }
266
+ }
267
+ installViaNpmOpts = { installSpec, pkgName, pkgVer, installType };
268
+ }
269
+ // fail fast here if we can
270
+ if (probableExtName && this.config.isInstalled(probableExtName)) {
271
+ throw this._createFatalError(`A ${this.type} named "${probableExtName}" is already installed. ` +
272
+ `Did you mean to update? Run "appium ${this.type} update". See ` +
273
+ `installed ${this.type}s with "appium ${this.type} list --installed".`);
274
+ }
275
+ receipt = await this.installViaNpm(installViaNpmOpts);
276
+ // this _should_ be the same as `probablyExtName` as the one derived above unless
277
+ // install type is local.
278
+ const extName = receipt[ /** @type {string} */(`${this.type}Name`)];
279
+ // check _a second time_ with the more-accurate extName
280
+ if (this.config.isInstalled(extName)) {
281
+ throw this._createFatalError(`A ${this.type} named "${extName}" is already installed. ` +
282
+ `Did you mean to update? Run "appium ${this.type} update". See ` +
283
+ `installed ${this.type}s with "appium ${this.type} list --installed".`);
284
+ }
285
+ // this field does not exist as such in the manifest (it's used as a property name instead)
286
+ // so that's why it's being removed here.
287
+ /** @type {ExtManifest<ExtType>} */
288
+ const extManifest = receiptToManifest(receipt);
289
+ const [errors, warnings] = await bluebird_1.default.all([
290
+ this.config.getProblems(extName, extManifest),
291
+ this.config.getWarnings(extName, extManifest),
292
+ ]);
293
+ const errorMap = new Map([[extName, errors]]);
294
+ const warningMap = new Map([[extName, warnings]]);
295
+ const { errorSummaries, warningSummaries } = this.config.getValidationResultSummaries(errorMap, warningMap);
296
+ if (!lodash_1.default.isEmpty(errorSummaries)) {
297
+ throw this._createFatalError(errorSummaries.join('\n'));
298
+ }
299
+ // note that we won't show any warnings if there were errors.
300
+ if (!lodash_1.default.isEmpty(warningSummaries)) {
301
+ this.log.warn(warningSummaries.join('\n'));
302
+ }
303
+ await this.config.addExtension(extName, extManifest);
304
+ // update the if we've changed the local `package.json`
305
+ if (await support_1.env.hasAppiumDependency(this.config.appiumHome)) {
306
+ await (0, package_changed_1.packageDidChange)(this.config.appiumHome);
307
+ }
308
+ // log info for the user
309
+ this.log.info(this.getPostInstallText({ extName, extData: receipt }));
310
+ return this.config.installedExtensions;
347
311
  }
348
-
349
- this.validateExtensionFields(appium, installSpec);
350
- return true;
351
- }
352
-
353
- validateExtensionFields(extMetadata, installSpec) {
354
- throw this._createFatalError('Must be implemented in final class');
355
- }
356
-
357
- async _uninstall({
358
- installSpec
359
- }) {
360
- if (!this.config.isInstalled(installSpec)) {
361
- throw this._createFatalError(`Can't uninstall ${this.type} '${installSpec}'; it is not installed`);
312
+ /**
313
+ * Install an extension via NPM
314
+ *
315
+ * @param {InstallViaNpmArgs} args
316
+ * @returns {Promise<ExtInstallReceipt<ExtType>>}
317
+ */
318
+ async installViaNpm({ installSpec, pkgName, pkgVer, installType }) {
319
+ const npmSpec = `${pkgName}${pkgVer ? '@' + pkgVer : ''}`;
320
+ const specMsg = npmSpec === installSpec ? '' : ` using NPM install spec '${npmSpec}'`;
321
+ const msg = `Installing '${installSpec}'${specMsg}`;
322
+ try {
323
+ const { pkg, path } = await (0, utils_1.spinWith)(this.isJsonOutput, msg, async () => {
324
+ const { pkg, installPath: path } = await support_1.npm.installPackage(this.config.appiumHome, pkgName, {
325
+ pkgVer,
326
+ installType,
327
+ });
328
+ this.validatePackageJson(pkg, installSpec);
329
+ return { pkg, path };
330
+ });
331
+ return this.getInstallationReceipt({
332
+ pkg,
333
+ installPath: path,
334
+ installType,
335
+ installSpec,
336
+ });
337
+ }
338
+ catch (err) {
339
+ throw this._createFatalError(`Encountered an error when installing package: ${err.message}`);
340
+ }
362
341
  }
363
-
364
- const pkgName = this.config.installedExtensions[installSpec].pkgName;
365
- await _support.npm.uninstallPackage(this.config.appiumHome, pkgName);
366
- await this.config.removeExtension(installSpec);
367
- this.log.ok(`Successfully uninstalled ${this.type} '${installSpec}'`.green);
368
- return this.config.installedExtensions;
369
- }
370
-
371
- async _update({
372
- installSpec,
373
- unsafe
374
- }) {
375
- const shouldUpdateAll = installSpec === UPDATE_ALL;
376
-
377
- if (!shouldUpdateAll && !this.config.isInstalled(installSpec)) {
378
- throw this._createFatalError(`The ${this.type} "${installSpec}" was not installed, so can't be updated`);
342
+ /**
343
+ * Get the text which should be displayed to the user after an extension has been installed. This
344
+ * is designed to be overridden by drivers/plugins with their own particular text.
345
+ *
346
+ * @param {ExtensionArgs} args
347
+ * @returns {string}
348
+ */
349
+ // eslint-disable-next-line no-unused-vars
350
+ getPostInstallText(args) {
351
+ throw this._createFatalError('Must be implemented in final class');
379
352
  }
380
-
381
- const extsToUpdate = shouldUpdateAll ? Object.keys(this.config.installedExtensions) : [installSpec];
382
- const errors = {};
383
- const updates = {};
384
-
385
- for (const e of extsToUpdate) {
386
- try {
387
- await (0, _utils.spinWith)(this.isJsonOutput, `Checking if ${this.type} '${e}' is updatable`, () => {
388
- if (this.config.installedExtensions[e].installType !== _extensionConfig.INSTALL_TYPE_NPM) {
389
- throw new NotUpdatableError();
390
- }
391
- });
392
- const update = await (0, _utils.spinWith)(this.isJsonOutput, `Checking if ${this.type} '${e}' needs an update`, async () => {
393
- const update = await this.checkForExtensionUpdate(e);
394
-
395
- if (!(update.safeUpdate || update.unsafeUpdate)) {
396
- throw new NoUpdatesAvailableError();
397
- }
398
-
399
- return update;
400
- });
401
-
402
- if (!unsafe && !update.safeUpdate) {
403
- throw this._createFatalError(`The ${this.type} '${e}' has a major revision update ` + `(${update.current} => ${update.unsafeUpdate}), which could include ` + `breaking changes. If you want to apply this update, re-run with --unsafe`);
404
- }
405
-
406
- const updateVer = unsafe && update.unsafeUpdate ? update.unsafeUpdate : update.safeUpdate;
407
- await (0, _utils.spinWith)(this.isJsonOutput, `Updating driver '${e}' from ${update.current} to ${updateVer}`, async () => await this.updateExtension(e, updateVer));
408
- updates[e] = {
409
- from: update.current,
410
- to: updateVer
353
+ /**
354
+ * Once a package is installed on-disk, this gathers some necessary metadata for validation.
355
+ *
356
+ * @param {GetInstallationReceiptOpts<ExtType>} opts
357
+ * @returns {ExtInstallReceipt<ExtType>}
358
+ */
359
+ getInstallationReceipt({ pkg, installPath, installType, installSpec }) {
360
+ const { appium, name, version, peerDependencies } = pkg;
361
+ /** @type {import('appium/types').InternalMetadata} */
362
+ const internal = {
363
+ pkgName: name,
364
+ version,
365
+ installType,
366
+ installSpec,
367
+ installPath,
368
+ appiumVersion: peerDependencies?.appium,
369
+ };
370
+ /** @type {ExtMetadata<ExtType>} */
371
+ const extMetadata = appium;
372
+ return {
373
+ ...internal,
374
+ ...extMetadata,
411
375
  };
412
- } catch (err) {
413
- errors[e] = err;
414
- }
415
- }
416
-
417
- this.log.info('Update report:');
418
-
419
- for (const [e, update] of _lodash.default.toPairs(updates)) {
420
- this.log.ok(` - ${this.type} ${e} updated: ${update.from} => ${update.to}`.green);
421
- }
422
-
423
- for (const [e, err] of _lodash.default.toPairs(errors)) {
424
- if (err instanceof NotUpdatableError) {
425
- this.log.warn(` - '${e}' was not installed via npm, so we could not check ` + `for updates`.yellow);
426
- } else if (err instanceof NoUpdatesAvailableError) {
427
- this.log.info(` - '${e}' had no updates available`.yellow);
428
- } else {
429
- this.log.error(` - '${e}' failed to update: ${err}`.red);
430
- }
431
- }
432
-
433
- return {
434
- updates,
435
- errors
436
- };
437
- }
438
-
439
- async checkForExtensionUpdate(ext) {
440
- const {
441
- version,
442
- pkgName
443
- } = this.config.installedExtensions[ext];
444
- let unsafeUpdate = await _support.npm.getLatestVersion(this.config.appiumHome, pkgName);
445
- let safeUpdate = await _support.npm.getLatestSafeUpgradeVersion(this.config.appiumHome, pkgName, version);
446
-
447
- if (unsafeUpdate !== null && !_support.util.compareVersions(unsafeUpdate, '>', version)) {
448
- unsafeUpdate = null;
449
- safeUpdate = null;
450
376
  }
451
-
452
- if (unsafeUpdate && unsafeUpdate === safeUpdate) {
453
- unsafeUpdate = null;
377
+ /**
378
+ * Validates the _required_ root fields of an extension's `package.json` file.
379
+ *
380
+ * These required fields are:
381
+ * - `name`
382
+ * - `version`
383
+ * - `appium`
384
+ * @param {import('type-fest').PackageJson} pkg - `package.json` of extension
385
+ * @param {string} installSpec - Extension name/spec
386
+ * @throws {ReferenceError} If `package.json` has a missing or invalid field
387
+ * @returns {pkg is ExtPackageJson<ExtType>}
388
+ */
389
+ validatePackageJson(pkg, installSpec) {
390
+ const { appium, name, version } = /** @type {ExtPackageJson<ExtType>} */ (pkg);
391
+ /**
392
+ *
393
+ * @param {string} field
394
+ * @returns {ReferenceError}
395
+ */
396
+ const createMissingFieldError = (field) => new ReferenceError(`${this.type} "${installSpec}" invalid; missing a \`${field}\` field of its \`package.json\``);
397
+ if (!name) {
398
+ throw createMissingFieldError('name');
399
+ }
400
+ if (!version) {
401
+ throw createMissingFieldError('version');
402
+ }
403
+ if (!appium) {
404
+ throw createMissingFieldError('appium');
405
+ }
406
+ this.validateExtensionFields(appium, installSpec);
407
+ return true;
454
408
  }
455
-
456
- if (safeUpdate && !_support.util.compareVersions(safeUpdate, '>', version)) {
457
- safeUpdate = null;
409
+ /**
410
+ * For any `package.json` fields which a particular type of extension requires, validate the
411
+ * presence and form of those fields on the `package.json` data, throwing an error if anything is
412
+ * amiss.
413
+ *
414
+ * @param {ExtMetadata<ExtType>} extMetadata - the data in the "appium" field of `package.json` for an extension
415
+ * @param {string} installSpec - Extension name/spec
416
+ */
417
+ // eslint-disable-next-line no-unused-vars
418
+ validateExtensionFields(extMetadata, installSpec) {
419
+ throw this._createFatalError('Must be implemented in final class');
458
420
  }
459
-
460
- return {
461
- current: version,
462
- safeUpdate,
463
- unsafeUpdate
464
- };
465
- }
466
-
467
- async updateExtension(installSpec, version) {
468
- const {
469
- pkgName
470
- } = this.config.installedExtensions[installSpec];
471
- const extData = await this.installViaNpm({
472
- installSpec,
473
- pkgName,
474
- pkgVer: version
475
- });
476
- delete extData[`${this.type}Name`];
477
- await this.config.updateExtension(installSpec, extData);
478
- }
479
-
480
- async _run({
481
- installSpec,
482
- scriptName,
483
- extraArgs = []
484
- }) {
485
- if (!this.config.isInstalled(installSpec)) {
486
- throw this._createFatalError(`The ${this.type} "${installSpec}" is not installed`);
421
+ /**
422
+ * Uninstall an extension.
423
+ *
424
+ * First tries to do this via `npm uninstall`, but if that fails, just `rm -rf`'s the extension dir.
425
+ *
426
+ * Will only remove the extension from the manifest if it has been successfully removed.
427
+ *
428
+ * @param {UninstallOpts} opts
429
+ * @return {Promise<ExtRecord<ExtType>>} map of all installed extension names to extension data (without the extension just uninstalled)
430
+ */
431
+ async _uninstall({ installSpec }) {
432
+ if (!this.config.isInstalled(installSpec)) {
433
+ throw this._createFatalError(`Can't uninstall ${this.type} '${installSpec}'; it is not installed`);
434
+ }
435
+ const pkgName = this.config.installedExtensions[installSpec].pkgName;
436
+ await support_1.npm.uninstallPackage(this.config.appiumHome, pkgName);
437
+ await this.config.removeExtension(installSpec);
438
+ this.log.ok(`Successfully uninstalled ${this.type} '${installSpec}'`.green);
439
+ return this.config.installedExtensions;
487
440
  }
488
-
489
- const extConfig = this.config.installedExtensions[installSpec];
490
-
491
- if (!extConfig.scripts) {
492
- throw this._createFatalError(`The ${this.type} named '${installSpec}' does not contain the ` + `"scripts" field underneath the "appium" field in its package.json`);
441
+ /**
442
+ * Attempt to update one or more drivers using NPM
443
+ *
444
+ * @param {ExtensionUpdateOpts} updateSpec
445
+ * @return {Promise<ExtensionUpdateResult>}
446
+ */
447
+ async _update({ installSpec, unsafe }) {
448
+ const shouldUpdateAll = installSpec === UPDATE_ALL;
449
+ // if we're specifically requesting an update for an extension, make sure it's installed
450
+ if (!shouldUpdateAll && !this.config.isInstalled(installSpec)) {
451
+ throw this._createFatalError(`The ${this.type} "${installSpec}" was not installed, so can't be updated`);
452
+ }
453
+ const extsToUpdate = shouldUpdateAll
454
+ ? Object.keys(this.config.installedExtensions)
455
+ : [installSpec];
456
+ // 'errors' will have ext names as keys and error objects as values
457
+ /** @type {Record<string,Error>} */
458
+ const errors = {};
459
+ // 'updates' will have ext names as keys and update objects as values, where an update
460
+ // object is of the form {from: versionString, to: versionString}
461
+ /** @type {Record<string,UpdateReport>} */
462
+ const updates = {};
463
+ for (const e of extsToUpdate) {
464
+ try {
465
+ await (0, utils_1.spinWith)(this.isJsonOutput, `Checking if ${this.type} '${e}' is updatable`, () => {
466
+ if (this.config.installedExtensions[e].installType !== extension_config_1.INSTALL_TYPE_NPM) {
467
+ throw new NotUpdatableError();
468
+ }
469
+ });
470
+ const update = await (0, utils_1.spinWith)(this.isJsonOutput, `Checking if ${this.type} '${e}' needs an update`, async () => {
471
+ const update = await this.checkForExtensionUpdate(e);
472
+ if (!(update.safeUpdate || update.unsafeUpdate)) {
473
+ throw new NoUpdatesAvailableError();
474
+ }
475
+ return update;
476
+ });
477
+ if (!unsafe && !update.safeUpdate) {
478
+ throw this._createFatalError(`The ${this.type} '${e}' has a major revision update ` +
479
+ `(${update.current} => ${update.unsafeUpdate}), which could include ` +
480
+ `breaking changes. If you want to apply this update, re-run with --unsafe`);
481
+ }
482
+ const updateVer = unsafe && update.unsafeUpdate ? update.unsafeUpdate : update.safeUpdate;
483
+ await (0, utils_1.spinWith)(this.isJsonOutput, `Updating driver '${e}' from ${update.current} to ${updateVer}`, async () => await this.updateExtension(e, updateVer));
484
+ updates[e] = { from: update.current, to: updateVer };
485
+ }
486
+ catch (err) {
487
+ errors[e] = err;
488
+ }
489
+ }
490
+ this.log.info('Update report:');
491
+ for (const [e, update] of lodash_1.default.toPairs(updates)) {
492
+ this.log.ok(` - ${this.type} ${e} updated: ${update.from} => ${update.to}`.green);
493
+ }
494
+ for (const [e, err] of lodash_1.default.toPairs(errors)) {
495
+ if (err instanceof NotUpdatableError) {
496
+ this.log.warn(` - '${e}' was not installed via npm, so we could not check ` + `for updates`.yellow);
497
+ }
498
+ else if (err instanceof NoUpdatesAvailableError) {
499
+ this.log.info(` - '${e}' had no updates available`.yellow);
500
+ }
501
+ else {
502
+ // otherwise, make it pop with red!
503
+ this.log.error(` - '${e}' failed to update: ${err}`.red);
504
+ }
505
+ }
506
+ return { updates, errors };
493
507
  }
494
-
495
- const extScripts = extConfig.scripts;
496
-
497
- if (!_lodash.default.isPlainObject(extScripts)) {
498
- throw this._createFatalError(`The ${this.type} named '${installSpec}' "scripts" field must be a plain object`);
508
+ /**
509
+ * Given an extension name, figure out what its highest possible version upgrade is, and also the
510
+ * highest possible safe upgrade.
511
+ *
512
+ * @param {string} ext - name of extension
513
+ * @return {Promise<PossibleUpdates>}
514
+ */
515
+ async checkForExtensionUpdate(ext) {
516
+ // TODO decide how we want to handle beta versions?
517
+ // this is a helper method, 'ext' is assumed to already be installed here, and of the npm
518
+ // install type
519
+ const { version, pkgName } = this.config.installedExtensions[ext];
520
+ /** @type {string?} */
521
+ let unsafeUpdate = await support_1.npm.getLatestVersion(this.config.appiumHome, pkgName);
522
+ let safeUpdate = await support_1.npm.getLatestSafeUpgradeVersion(this.config.appiumHome, pkgName, version);
523
+ if (unsafeUpdate !== null && !support_1.util.compareVersions(unsafeUpdate, '>', version)) {
524
+ // the latest version is not greater than the current version, so there's no possible update
525
+ unsafeUpdate = null;
526
+ safeUpdate = null;
527
+ }
528
+ if (unsafeUpdate && unsafeUpdate === safeUpdate) {
529
+ // the latest update is the same as the safe update, which means it's not actually unsafe
530
+ unsafeUpdate = null;
531
+ }
532
+ if (safeUpdate && !support_1.util.compareVersions(safeUpdate, '>', version)) {
533
+ // even the safe update is not later than the current, so it is not actually an update
534
+ safeUpdate = null;
535
+ }
536
+ return { current: version, safeUpdate, unsafeUpdate };
499
537
  }
500
-
501
- if (!_lodash.default.has(extScripts, scriptName)) {
502
- throw this._createFatalError(`The ${this.type} named '${installSpec}' does not support the script: '${scriptName}'`);
538
+ /**
539
+ * Actually update an extension installed by NPM, using the NPM cli. And update the installation
540
+ * manifest.
541
+ *
542
+ * @param {string} installSpec - name of extension to update
543
+ * @param {string} version - version string identifier to update extension to
544
+ * @returns {Promise<void>}
545
+ */
546
+ async updateExtension(installSpec, version) {
547
+ const { pkgName, installType } = this.config.installedExtensions[installSpec];
548
+ const extData = await this.installViaNpm({
549
+ installSpec,
550
+ installType,
551
+ pkgName,
552
+ pkgVer: version,
553
+ });
554
+ delete extData[ /** @type {string} */(`${this.type}Name`)];
555
+ await this.config.updateExtension(installSpec, extData);
503
556
  }
504
-
505
- const runner = new _teen_process.SubProcess(process.execPath, [extScripts[scriptName], ...extraArgs], {
506
- cwd: this.config.getInstallPath(installSpec)
507
- });
508
- const output = new _utils.RingBuffer(50);
509
- runner.on('stream-line', line => {
510
- output.enqueue(line);
511
- this.log.log(line);
512
- });
513
- await runner.start(0);
514
-
515
- try {
516
- await runner.join();
517
- this.log.ok(`${scriptName} successfully ran`.green);
518
- return {
519
- output: output.getBuff()
520
- };
521
- } catch (err) {
522
- this.log.error(`Encountered an error when running '${scriptName}': ${err.message}`.red);
523
- return {
524
- error: err.message,
525
- output: output.getBuff()
526
- };
557
+ /**
558
+ * Runs a script cached inside the "scripts" field under "appium"
559
+ * inside of the driver/plugins "package.json" file. Will throw
560
+ * an error if the driver/plugin does not contain a "scripts" field
561
+ * underneath the "appium" field in its package.json, if the
562
+ * "scripts" field is not a plain object, or if the scriptName is
563
+ * not found within "scripts" object.
564
+ *
565
+ * @param {RunOptions} opts
566
+ * @return {Promise<RunOutput>}
567
+ */
568
+ async _run({ installSpec, scriptName, extraArgs = [] }) {
569
+ if (!this.config.isInstalled(installSpec)) {
570
+ throw this._createFatalError(`The ${this.type} "${installSpec}" is not installed`);
571
+ }
572
+ const extConfig = this.config.installedExtensions[installSpec];
573
+ // note: TS cannot understand that _.has() is a type guard
574
+ if (!('scripts' in extConfig)) {
575
+ throw this._createFatalError(`The ${this.type} named '${installSpec}' does not contain the ` +
576
+ `"scripts" field underneath the "appium" field in its package.json`);
577
+ }
578
+ const extScripts = extConfig.scripts;
579
+ if (!extScripts || !lodash_1.default.isPlainObject(extScripts)) {
580
+ throw this._createFatalError(`The ${this.type} named '${installSpec}' "scripts" field must be a plain object`);
581
+ }
582
+ if (!(scriptName in extScripts)) {
583
+ throw this._createFatalError(`The ${this.type} named '${installSpec}' does not support the script: '${scriptName}'`);
584
+ }
585
+ const runner = new teen_process_1.SubProcess(process.execPath, [extScripts[scriptName], ...extraArgs], {
586
+ cwd: this.config.getInstallPath(installSpec),
587
+ });
588
+ const output = new utils_1.RingBuffer(50);
589
+ runner.on('stream-line', (line) => {
590
+ output.enqueue(line);
591
+ this.log.log(line);
592
+ });
593
+ await runner.start(0);
594
+ try {
595
+ await runner.join();
596
+ this.log.ok(`${scriptName} successfully ran`.green);
597
+ return { output: output.getBuff() };
598
+ }
599
+ catch (err) {
600
+ this.log.error(`Encountered an error when running '${scriptName}': ${err.message}`.red);
601
+ return { error: err.message, output: output.getBuff() };
602
+ }
527
603
  }
528
- }
529
-
530
604
  }
531
-
532
605
  exports.ExtensionCommand = ExtensionCommand;
533
- var _default = ExtensionCommand;
534
- exports.default = _default;
535
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJVUERBVEVfQUxMIiwiTm90VXBkYXRhYmxlRXJyb3IiLCJFcnJvciIsIk5vVXBkYXRlc0F2YWlsYWJsZUVycm9yIiwiRXh0ZW5zaW9uQ29tbWFuZCIsImNvbmZpZyIsImtub3duRXh0ZW5zaW9ucyIsImlzSnNvbk91dHB1dCIsImNvbnN0cnVjdG9yIiwianNvbiIsImxvZyIsImNvbnNvbGUiLCJDbGlDb25zb2xlIiwianNvbk1vZGUiLCJCb29sZWFuIiwidHlwZSIsImV4dGVuc2lvblR5cGUiLCJfY3JlYXRlRmF0YWxFcnJvciIsIm1lc3NhZ2UiLCJkZWNvcmF0ZSIsImV4ZWN1dGUiLCJhcmdzIiwiY21kIiwiXyIsImlzRnVuY3Rpb24iLCJleGVjdXRlQ21kIiwiYmluZCIsImxpc3QiLCJzaG93SW5zdGFsbGVkIiwic2hvd1VwZGF0ZXMiLCJsc01zZyIsImluc3RhbGxlZE5hbWVzIiwiT2JqZWN0Iiwia2V5cyIsImluc3RhbGxlZEV4dGVuc2lvbnMiLCJrbm93bk5hbWVzIiwiZXh0cyIsInJlZHVjZSIsImFjYyIsIm5hbWUiLCJpbmNsdWRlcyIsImluc3RhbGxlZCIsInBrZ05hbWUiLCJzcGluV2l0aCIsImV4dCIsImRhdGEiLCJ0b1BhaXJzIiwiaW5zdGFsbFR5cGUiLCJJTlNUQUxMX1RZUEVfTlBNIiwidXBkYXRlcyIsImNoZWNrRm9yRXh0ZW5zaW9uVXBkYXRlIiwidXBkYXRlVmVyc2lvbiIsInNhZmVVcGRhdGUiLCJ1bnNhZmVVcGRhdGVWZXJzaW9uIiwidW5zYWZlVXBkYXRlIiwidXBUb0RhdGUiLCJsaXN0RGF0YSIsImluc3RhbGxUeHQiLCJncmV5IiwidXBkYXRlVHh0IiwidXBUb0RhdGVUeHQiLCJ1bnNhZmVVcGRhdGVUeHQiLCJpbnN0YWxsU3BlYyIsInZlcnNpb24iLCJ0eXBlVHh0IiwiSU5TVEFMTF9UWVBFX0dJVCIsIklOU1RBTExfVFlQRV9HSVRIVUIiLCJ5ZWxsb3ciLCJJTlNUQUxMX1RZUEVfTE9DQUwiLCJtYWdlbnRhIiwiZ3JlZW4iLCJjeWFuIiwiX2luc3RhbGwiLCJwYWNrYWdlTmFtZSIsImV4dERhdGEiLCJpbnN0YWxsT3B0cyIsInByb2JhYmxlRXh0TmFtZSIsInNwbGl0IiwibGVuZ3RoIiwicmVwbGFjZSIsInBrZ1ZlciIsInBhdGgiLCJpc0Fic29sdXRlIiwicmVzb2x2ZSIsInNwbGl0cyIsIm1zZyIsIkpTT04iLCJzdHJpbmdpZnkiLCJpc0luc3RhbGxlZCIsImluc3RhbGxWaWFOcG0iLCJleHROYW1lIiwiZXh0TWFuaWZlc3QiLCJlcnJvcnMiLCJ3YXJuaW5ncyIsIkIiLCJhbGwiLCJnZXRQcm9ibGVtcyIsImdldFdhcm5pbmdzIiwiZXJyb3JNYXAiLCJNYXAiLCJ3YXJuaW5nTWFwIiwiZXJyb3JTdW1tYXJpZXMiLCJ3YXJuaW5nU3VtbWFyaWVzIiwiZ2V0VmFsaWRhdGlvblJlc3VsdFN1bW1hcmllcyIsImlzRW1wdHkiLCJqb2luIiwid2FybiIsImFkZEV4dGVuc2lvbiIsImVudiIsImhhc0FwcGl1bURlcGVuZGVuY3kiLCJhcHBpdW1Ib21lIiwicGFja2FnZURpZENoYW5nZSIsImluZm8iLCJnZXRQb3N0SW5zdGFsbFRleHQiLCJucG1TcGVjIiwic3BlY01zZyIsInBrZ0pzb25EYXRhIiwibnBtIiwiaW5zdGFsbFBhY2thZ2UiLCJ2YWxpZGF0ZVBhY2thZ2VKc29uIiwiZ2V0RXh0ZW5zaW9uRmllbGRzIiwiZXJyIiwicGtnSnNvbiIsImFwcGl1bSIsInBlZXJEZXBlbmRlbmNpZXMiLCJyZXN1bHQiLCJhcHBpdW1WZXJzaW9uIiwiY3JlYXRlTWlzc2luZ0ZpZWxkRXJyb3IiLCJmaWVsZCIsIlJlZmVyZW5jZUVycm9yIiwidmFsaWRhdGVFeHRlbnNpb25GaWVsZHMiLCJleHRNZXRhZGF0YSIsIl91bmluc3RhbGwiLCJ1bmluc3RhbGxQYWNrYWdlIiwicmVtb3ZlRXh0ZW5zaW9uIiwib2siLCJfdXBkYXRlIiwidW5zYWZlIiwic2hvdWxkVXBkYXRlQWxsIiwiZXh0c1RvVXBkYXRlIiwiZSIsInVwZGF0ZSIsImN1cnJlbnQiLCJ1cGRhdGVWZXIiLCJ1cGRhdGVFeHRlbnNpb24iLCJmcm9tIiwidG8iLCJlcnJvciIsInJlZCIsImdldExhdGVzdFZlcnNpb24iLCJnZXRMYXRlc3RTYWZlVXBncmFkZVZlcnNpb24iLCJ1dGlsIiwiY29tcGFyZVZlcnNpb25zIiwiX3J1biIsInNjcmlwdE5hbWUiLCJleHRyYUFyZ3MiLCJleHRDb25maWciLCJzY3JpcHRzIiwiZXh0U2NyaXB0cyIsImlzUGxhaW5PYmplY3QiLCJoYXMiLCJydW5uZXIiLCJTdWJQcm9jZXNzIiwicHJvY2VzcyIsImV4ZWNQYXRoIiwiY3dkIiwiZ2V0SW5zdGFsbFBhdGgiLCJvdXRwdXQiLCJSaW5nQnVmZmVyIiwib24iLCJsaW5lIiwiZW5xdWV1ZSIsInN0YXJ0IiwiZ2V0QnVmZiJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2xpYi9jbGkvZXh0ZW5zaW9uLWNvbW1hbmQuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgbm8tY29uc29sZSAqL1xuaW1wb3J0IEIgZnJvbSAnYmx1ZWJpcmQnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHtucG0sIHV0aWwsIGVudiwgY29uc29sZX0gZnJvbSAnQGFwcGl1bS9zdXBwb3J0JztcbmltcG9ydCB7c3BpbldpdGgsIFJpbmdCdWZmZXJ9IGZyb20gJy4vdXRpbHMnO1xuaW1wb3J0IHtTdWJQcm9jZXNzfSBmcm9tICd0ZWVuX3Byb2Nlc3MnO1xuaW1wb3J0IHtcbiAgSU5TVEFMTF9UWVBFX05QTSxcbiAgSU5TVEFMTF9UWVBFX0dJVCxcbiAgSU5TVEFMTF9UWVBFX0dJVEhVQixcbiAgSU5TVEFMTF9UWVBFX0xPQ0FMLFxufSBmcm9tICcuLi9leHRlbnNpb24vZXh0ZW5zaW9uLWNvbmZpZyc7XG5pbXBvcnQge3BhY2thZ2VEaWRDaGFuZ2V9IGZyb20gJy4uL2V4dGVuc2lvbi9wYWNrYWdlLWNoYW5nZWQnO1xuXG5jb25zdCBVUERBVEVfQUxMID0gJ2luc3RhbGxlZCc7XG5cbmNsYXNzIE5vdFVwZGF0YWJsZUVycm9yIGV4dGVuZHMgRXJyb3Ige31cbmNsYXNzIE5vVXBkYXRlc0F2YWlsYWJsZUVycm9yIGV4dGVuZHMgRXJyb3Ige31cblxuLyoqXG4gKiBAdGVtcGxhdGUge0V4dGVuc2lvblR5cGV9IEV4dFR5cGVcbiAqL1xuY2xhc3MgRXh0ZW5zaW9uQ29tbWFuZCB7XG4gIC8qKlxuICAgKiBUaGlzIGlzIHRoZSBgRHJpdmVyQ29uZmlnYCBvciBgUGx1Z2luQ29uZmlnYCwgZGVwZW5kaW5nIG9uIGBFeHRUeXBlYC5cbiAgICogQHR5cGUge0V4dGVuc2lvbkNvbmZpZzxFeHRUeXBlPn1cbiAgICovXG4gIGNvbmZpZztcblxuICAvKipcbiAgICoge0BsaW5rY29kZSBSZWNvcmR9IG9mIG9mZmljaWFsIHBsdWdpbnMgb3IgZHJpdmVycy5cbiAgICogQHR5cGUge0tub3duRXh0ZW5zaW9uczxFeHRUeXBlPn1cbiAgICovXG4gIGtub3duRXh0ZW5zaW9ucztcblxuICAvKipcbiAgICogSWYgYHRydWVgLCBjb21tYW5kIG91dHB1dCBoYXMgYmVlbiByZXF1ZXN0ZWQgYXMgSlNPTi5cbiAgICogQHR5cGUge2Jvb2xlYW59XG4gICAqL1xuICBpc0pzb25PdXRwdXQ7XG5cbiAgLyoqXG4gICAqIEJ1aWxkIGFuIEV4dGVuc2lvbkNvbW1hbmRcbiAgICogQHBhcmFtIHtFeHRlbnNpb25Db21tYW5kT3B0aW9uczxFeHRUeXBlPn0gb3B0c1xuICAgKi9cbiAgY29uc3RydWN0b3Ioe2NvbmZpZywganNvbn0pIHtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICB0aGlzLmxvZyA9IG5ldyBjb25zb2xlLkNsaUNvbnNvbGUoe2pzb25Nb2RlOiBqc29ufSk7XG4gICAgdGhpcy5pc0pzb25PdXRwdXQgPSBCb29sZWFuKGpzb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIGBkcml2ZXJgIG9yIGBwbHVnaW5gLCBkZXBlbmRpbmcgb24gdGhlIGBFeHRlbnNpb25Db25maWdgLlxuICAgKi9cbiAgZ2V0IHR5cGUoKSB7XG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLmV4dGVuc2lvblR5cGU7XG4gIH1cblxuICAvKipcbiAgICogTG9ncyBhIG1lc3NhZ2UgYW5kIHJldHVybnMgYW4ge0BsaW5rY29kZSBFcnJvcn0gdG8gdGhyb3cuXG4gICAqXG4gICAqIEZvciBUUyB0byB1bmRlcnN0YW5kIHRoYXQgYSBmdW5jdGlvbiB0aHJvd3MgYW4gZXhjZXB0aW9uLCBpdCBtdXN0IGFjdHVhbGx5IHRocm93IGFuIGV4Y2VwdGlvbi0tXG4gICAqIGluIG90aGVyIHdvcmRzLCBfY2FsbGluZ18gYSBmdW5jdGlvbiB3aGljaCBpcyBndWFyYW50ZWVkIHRvIHRocm93IGFuIGV4Y2VwdGlvbiBpcyBub3QgZW5vdWdoLS1cbiAgICogbm9yIGlzIHNvbWV0aGluZyBsaWtlIGBAcmV0dXJucyB7bmV2ZXJ9YCB3aGljaCBkb2VzIG5vdCBpbXBseSBhIHRocm93biBleGNlcHRpb24uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXG4gICAqIEBwcm90ZWN0ZWRcbiAgICogQHJldHVybnMge0Vycm9yfVxuICAgKi9cbiAgX2NyZWF0ZUZhdGFsRXJyb3IobWVzc2FnZSkge1xuICAgIHJldHVybiBuZXcgRXJyb3IodGhpcy5sb2cuZGVjb3JhdGUobWVzc2FnZSwgJ2Vycm9yJykpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRha2UgYSBDTEkgcGFyc2UgYW5kIHJ1biBhbiBleHRlbnNpb24gY29tbWFuZCBiYXNlZCBvbiBpdHMgdHlwZVxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIGEga2V5L3ZhbHVlIG9iamVjdCB3aXRoIENMSSBmbGFncyBhbmQgdmFsdWVzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8b2JqZWN0Pn0gdGhlIHJlc3VsdCBvZiB0aGUgc3BlY2lmaWMgY29tbWFuZCB3aGljaCBpcyBleGVjdXRlZFxuICAgKi9cbiAgYXN5bmMgZXhlY3V0ZShhcmdzKSB7XG4gICAgY29uc3QgY21kID0gYXJnc1tgJHt0aGlzLnR5cGV9Q29tbWFuZGBdO1xuICAgIGlmICghXy5pc0Z1bmN0aW9uKHRoaXNbY21kXSkpIHtcbiAgICAgIHRocm93IHRoaXMuX2NyZWF0ZUZhdGFsRXJyb3IoYENhbm5vdCBoYW5kbGUgJHt0aGlzLnR5cGV9IGNvbW1hbmQgJHtjbWR9YCk7XG4gICAgfVxuICAgIGNvbnN0IGV4ZWN1dGVDbWQgPSB0aGlzW2NtZF0uYmluZCh0aGlzKTtcbiAgICByZXR1cm4gYXdhaXQgZXhlY3V0ZUNtZChhcmdzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMaXN0IGV4dGVuc2lvbnNcbiAgICpcbiAgICogQHBhcmFtIHtMaXN0T3B0aW9uc30gb3B0c1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPEV4dGVuc2lvbkxpc3REYXRhPn0gbWFwIG9mIGV4dGVuc2lvbiBuYW1lcyB0byBleHRlbnNpb24gZGF0YVxuICAgKi9cbiAgYXN5bmMgbGlzdCh7c2hvd0luc3RhbGxlZCwgc2hvd1VwZGF0ZXN9KSB7XG4gICAgY29uc3QgbHNNc2cgPSBgTGlzdGluZyAke3Nob3dJbnN0YWxsZWQgPyAnaW5zdGFsbGVkJyA6ICdhdmFpbGFibGUnfSAke3RoaXMudHlwZX1zYDtcbiAgICBjb25zdCBpbnN0YWxsZWROYW1lcyA9IE9iamVjdC5rZXlzKHRoaXMuY29uZmlnLmluc3RhbGxlZEV4dGVuc2lvbnMpO1xuICAgIGNvbnN0IGtub3duTmFtZXMgPSBPYmplY3Qua2V5cyh0aGlzLmtub3duRXh0ZW5zaW9ucyk7XG4gICAgY29uc3QgZXh0cyA9IFsuLi5pbnN0YWxsZWROYW1lcywgLi4ua25vd25OYW1lc10ucmVkdWNlKFxuICAgICAgKGFjYywgbmFtZSkgPT4ge1xuICAgICAgICBpZiAoIWFjY1tuYW1lXSkge1xuICAgICAgICAgIGlmIChpbnN0YWxsZWROYW1lcy5pbmNsdWRlcyhuYW1lKSkge1xuICAgICAgICAgICAgYWNjW25hbWVdID0ge1xuICAgICAgICAgICAgICAuLi50aGlzLmNvbmZpZy5pbnN0YWxsZWRFeHRlbnNpb25zW25hbWVdLFxuICAgICAgICAgICAgICBpbnN0YWxsZWQ6IHRydWUsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0gZWxzZSBpZiAoIXNob3dJbnN0YWxsZWQpIHtcbiAgICAgICAgICAgIGFjY1tuYW1lXSA9IHtwa2dOYW1lOiB0aGlzLmtub3duRXh0ZW5zaW9uc1tuYW1lXSwgaW5zdGFsbGVkOiBmYWxzZX07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhY2M7XG4gICAgICB9LFxuICAgICAgLyoqXG4gICAgICAgKiBUaGlzIGFjY3VtdWxhdG9yIGNvbnRhaW5zIGVpdGhlciB7QGxpbmtjb2RlIFVuaW5zdGFsbGVkRXh0ZW5zaW9uTElzdERhdGF9IF9vcl9cbiAgICAgICAqIHtAbGlua2NvZGUgSW5zdGFsbGVkRXh0ZW5zaW9uTGlzdERhdGF9IHdpdGhvdXQgdXBncmFkZSBpbmZvcm1hdGlvbiAod2hpY2ggaXMgYWRkZWQgYnkgdGhlIGJlbG93IGNvZGUgYmxvY2spXG4gICAgICAgKiBAdHlwZSB7UmVjb3JkPHN0cmluZyxQYXJ0aWFsPEluc3RhbGxlZEV4dGVuc2lvbkxpc3REYXRhPnxVbmluc3RhbGxlZEV4dGVuc2lvbkxpc3REYXRhPn1cbiAgICAgICAqLyAoe30pXG4gICAgKTtcblxuICAgIC8vIGlmIHdlIHdhbnQgdG8gc2hvdyB3aGV0aGVyIHVwZGF0ZXMgYXJlIGF2YWlsYWJsZSwgcHV0IHRoYXQgYmVoaW5kIGEgc3Bpbm5lclxuICAgIGF3YWl0IHNwaW5XaXRoKHRoaXMuaXNKc29uT3V0cHV0LCBsc01zZywgYXN5bmMgKCkgPT4ge1xuICAgICAgaWYgKCFzaG93VXBkYXRlcykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBmb3IgKGNvbnN0IFtleHQsIGRhdGFdIG9mIF8udG9QYWlycyhleHRzKSkge1xuICAgICAgICBpZiAoIWRhdGEuaW5zdGFsbGVkIHx8IGRhdGEuaW5zdGFsbFR5cGUgIT09IElOU1RBTExfVFlQRV9OUE0pIHtcbiAgICAgICAgICAvLyBkb24ndCBuZWVkIHRvIGNoZWNrIGZvciB1cGRhdGVzIG9uIGV4dHMgdGhhdCBhcmVuJ3QgaW5zdGFsbGVkXG4gICAgICAgICAgLy8gYWxzbyBkb24ndCBuZWVkIHRvIGNoZWNrIGZvciB1cGRhdGVzIG9uIG5vbi1ucG0gZXh0c1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHVwZGF0ZXMgPSBhd2FpdCB0aGlzLmNoZWNrRm9yRXh0ZW5zaW9uVXBkYXRlKGV4dCk7XG4gICAgICAgIGRhdGEudXBkYXRlVmVyc2lvbiA9IHVwZGF0ZXMuc2FmZVVwZGF0ZTtcbiAgICAgICAgZGF0YS51bnNhZmVVcGRhdGVWZXJzaW9uID0gdXBkYXRlcy51bnNhZmVVcGRhdGU7XG4gICAgICAgIGRhdGEudXBUb0RhdGUgPSB1cGRhdGVzLnNhZmVVcGRhdGUgPT09IG51bGwgJiYgdXBkYXRlcy51bnNhZmVVcGRhdGUgPT09IG51bGw7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBjb25zdCBsaXN0RGF0YSA9IC8qKiBAdHlwZSB7RXh0ZW5zaW9uTGlzdERhdGF9ICovIChleHRzKTtcblxuICAgIC8vIGlmIHdlJ3JlIGp1c3QgZ2V0dGluZyB0aGUgZGF0YSwgc2hvcnQgY2lyY3VpdCByZXR1cm4gaGVyZSBzaW5jZSB3ZSBkb24ndCBuZWVkIHRvIGRvIGFueVxuICAgIC8vIGZvcm1hdHRpbmcgbG9naWNcbiAgICBpZiAodGhpcy5pc0pzb25PdXRwdXQpIHtcbiAgICAgIHJldHVybiBsaXN0RGF0YTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBkYXRhXSBvZiBfLnRvUGFpcnMobGlzdERhdGEpKSB7XG4gICAgICBsZXQgaW5zdGFsbFR4dCA9ICcgW25vdCBpbnN0YWxsZWRdJy5ncmV5O1xuICAgICAgbGV0IHVwZGF0ZVR4dCA9ICcnO1xuICAgICAgbGV0IHVwVG9EYXRlVHh0ID0gJyc7XG4gICAgICBsZXQgdW5zYWZlVXBkYXRlVHh0ID0gJyc7XG4gICAgICBpZiAoZGF0YS5pbnN0YWxsZWQpIHtcbiAgICAgICAgY29uc3Qge2luc3RhbGxUeXBlLCBpbnN0YWxsU3BlYywgdXBkYXRlVmVyc2lvbiwgdW5zYWZlVXBkYXRlVmVyc2lvbiwgdmVyc2lvbiwgdXBUb0RhdGV9ID1cbiAgICAgICAgICBkYXRhO1xuICAgICAgICBsZXQgdHlwZVR4dDtcbiAgICAgICAgc3dpdGNoIChpbnN0YWxsVHlwZSkge1xuICAgICAgICAgIGNhc2UgSU5TVEFMTF9UWVBFX0dJVDpcbiAgICAgICAgICBjYXNlIElOU1RBTExfVFlQRV9HSVRIVUI6XG4gICAgICAgICAgICB0eXBlVHh0ID0gYChjbG9uZWQgZnJvbSAke2luc3RhbGxTcGVjfSlgLnllbGxvdztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIGNhc2UgSU5TVEFMTF9UWVBFX0xPQ0FMOlxuICAgICAgICAgICAgdHlwZVR4dCA9IGAobGlua2VkIGZyb20gJHtpbnN0YWxsU3BlY30pYC5tYWdlbnRhO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIHR5cGVUeHQgPSAnKE5QTSknO1xuICAgICAgICB9XG4gICAgICAgIGluc3RhbGxUeHQgPSBgQCR7dmVyc2lvbi55ZWxsb3d9ICR7KCdbaW5zdGFsbGVkICcgKyB0eXBlVHh0ICsgJ10nKS5ncmVlbn1gO1xuXG4gICAgICAgIGlmIChzaG93VXBkYXRlcykge1xuICAgICAgICAgIGlmICh1cGRhdGVWZXJzaW9uKSB7XG4gICAgICAgICAgICB1cGRhdGVUeHQgPSBgIFske3VwZGF0ZVZlcnNpb259IGF2YWlsYWJsZV1gLm1hZ2VudGE7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICh1cFRvRGF0ZSkge1xuICAgICAgICAgICAgdXBUb0RhdGVUeHQgPSBgIFtVcCB0byBkYXRlXWAuZ3JlZW47XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICh1bnNhZmVVcGRhdGVWZXJzaW9uKSB7XG4gICAgICAgICAgICB1bnNhZmVVcGRhdGVUeHQgPSBgIFske3Vuc2FmZVVwZGF0ZVZlcnNpb259IGF2YWlsYWJsZSAocG90ZW50aWFsbHkgdW5zYWZlKV1gLmN5YW47XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHRoaXMubG9nLmxvZyhgLSAke25hbWUueWVsbG93fSR7aW5zdGFsbFR4dH0ke3VwZGF0ZVR4dH0ke3VwVG9EYXRlVHh0fSR7dW5zYWZlVXBkYXRlVHh0fWApO1xuICAgIH1cblxuICAgIHJldHVybiBsaXN0RGF0YTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnN0YWxsIGFuIGV4dGVuc2lvblxuICAgKlxuICAgKiBAcGFyYW0ge0luc3RhbGxBcmdzfSBhcmdzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8RXh0UmVjb3JkPEV4dFR5cGU+Pn0gbWFwIG9mIGFsbCBpbnN0YWxsZWQgZXh0ZW5zaW9uIG5hbWVzIHRvIGV4dGVuc2lvbiBkYXRhXG4gICAqL1xuICBhc3luYyBfaW5zdGFsbCh7aW5zdGFsbFNwZWMsIGluc3RhbGxUeXBlLCBwYWNrYWdlTmFtZX0pIHtcbiAgICAvKiogQHR5cGUge0V4dGVuc2lvbkZpZWxkczxFeHRUeXBlPn0gKi9cbiAgICBsZXQgZXh0RGF0YTtcblxuICAgIGlmIChwYWNrYWdlTmFtZSAmJiBbSU5TVEFMTF9UWVBFX0xPQ0FMLCBJTlNUQUxMX1RZUEVfTlBNXS5pbmNsdWRlcyhpbnN0YWxsVHlwZSkpIHtcbiAgICAgIHRocm93IHRoaXMuX2NyZWF0ZUZhdGFsRXJyb3IoYFdoZW4gdXNpbmcgLS1zb3VyY2U9JHtpbnN0YWxsVHlwZX0sIGNhbm5vdCBhbHNvIHVzZSAtLXBhY2thZ2VgKTtcbiAgICB9XG5cbiAgICBpZiAoIXBhY2thZ2VOYW1lICYmIFtJTlNUQUxMX1RZUEVfR0lULCBJTlNUQUxMX1RZUEVfR0lUSFVCXS5pbmNsdWRlcyhpbnN0YWxsVHlwZSkpIHtcbiAgICAgIHRocm93IHRoaXMuX2NyZWF0ZUZhdGFsRXJyb3IoYFdoZW4gdXNpbmcgLS1zb3VyY2U9JHtpbnN0YWxsVHlwZX0sIG11c3QgYWxzbyB1c2UgLS1wYWNrYWdlYCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHR5cGUge0luc3RhbGxWaWFOcG1BcmdzfVxuICAgICAqL1xuICAgIGxldCBpbnN0YWxsT3B0cztcblxuICAgIC8qKlxuICAgICAqIFRoZSBwcm9iYWJsZSAoPykgbmFtZSBvZiB0aGUgZXh0ZW5zaW9uIGRlcml2ZWQgZnJvbSB0aGUgaW5zdGFsbCBzcGVjLlxuICAgICAqXG4gICAgICogSWYgdXNpbmcgYSBsb2NhbCBpbnN0YWxsIHR5cGUsIHRoaXMgd2lsbCByZW1haW4gZW1wdHkuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBsZXQgcHJvYmFibGVFeHROYW1lID0gJyc7XG5cbiAgICAvLyBkZXBlbmRpbmcgb24gYGluc3RhbGxUeXBlYCwgYnVpbGQgdGhlIG9wdGlvbnMgdG8gcGFzcyBpbnRvIGBpbnN0YWxsVmlhTnBtYFxuICAgIGlmIChpbnN0YWxsVHlwZSA9PT0gSU5TVEFMTF9UWVBFX0dJVEhVQikge1xuICAgICAgaWYgKGluc3RhbGxTcGVjLnNwbGl0KCcvJykubGVuZ3RoICE9PSAyKSB7XG4gICAgICAgIHRocm93IHRoaXMuX2NyZWF0ZUZhdGFsRXJyb3IoXG4gICAgICAgICAgYEdpdGh1YiAke3RoaXMudHlwZX0gc3BlYyAke2luc3RhbGxTcGVjfSBhcHBlYXJlZCB0byBiZSBpbnZhbGlkOyBgICtcbiAgICAgICAgICAgICdpdCBzaG91bGQgYmUgb2YgdGhlIGZvcm0gPG9yZz4vPHJlcG8+J1xuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaW5zdGFsbE9wdHMgPSB7XG4gICAgICAgIGluc3RhbGxTcGVjLFxuICAgICAgICBwa2dOYW1lOiAvKiogQHR5cGUge3N0cmluZ30gKi8gKHBhY2thZ2VOYW1lKSxcbiAgICAgIH07XG4gICAgICBwcm9iYWJsZUV4dE5hbWUgPSBpbnN0YWxsU3BlYztcbiAgICB9IGVsc2UgaWYgKGluc3RhbGxUeXBlID09PSBJTlNUQUxMX1RZUEVfR0lUKSB7XG4gICAgICAvLyBnaXQgdXJscyBjYW4gaGF2ZSAnLmdpdCcgYXQgdGhlIGVuZCwgYnV0IHRoaXMgaXMgbm90IG5lY2Vzc2FyeSBhbmQgd291bGQgY29tcGxpY2F0ZSB0aGVcbiAgICAgIC8vIHdheSB3ZSBkb3dubG9hZCBhbmQgbmFtZSBkaXJlY3Rvcmllcywgc28gd2UgY2FuIGp1c3QgcmVtb3ZlIGl0XG4gICAgICBpbnN0YWxsU3BlYyA9IGluc3RhbGxTcGVjLnJlcGxhY2UoL1xcLmdpdCQvLCAnJyk7XG4gICAgICBpbnN0YWxsT3B0cyA9IHtcbiAgICAgICAgaW5zdGFsbFNwZWMsXG4gICAgICAgIHBrZ05hbWU6IC8qKiBAdHlwZSB7c3RyaW5nfSAqLyAocGFja2FnZU5hbWUpLFxuICAgICAgfTtcbiAgICAgIHByb2JhYmxlRXh0TmFtZSA9IGluc3RhbGxTcGVjO1xuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgcGtnTmFtZSwgcGtnVmVyO1xuICAgICAgaWYgKGluc3RhbGxUeXBlID09PSBJTlNUQUxMX1RZUEVfTE9DQUwpIHtcbiAgICAgICAgcGtnTmFtZSA9IHBhdGguaXNBYnNvbHV0ZShpbnN0YWxsU3BlYykgPyBpbnN0YWxsU3BlYyA6IHBhdGgucmVzb2x2ZShpbnN0YWxsU3BlYyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBhdCB0aGlzIHBvaW50IHdlIGhhdmUgZWl0aGVyIGFuIG5wbSBwYWNrYWdlIG9yIGFuIGFwcGl1bSB2ZXJpZmllZCBleHRlbnNpb25cbiAgICAgICAgLy8gbmFtZSBvciBhIGxvY2FsIHBhdGguIGJvdGggb2Ygd2hpY2ggd2lsbCBiZSBpbnN0YWxsZWQgdmlhIG5wbS5cbiAgICAgICAgLy8gZXh0ZW5zaW9ucyBpbnN0YWxsZWQgdmlhIG5wbSBjYW4gaW5jbHVkZSB2ZXJzaW9ucyBvciB0YWdzIGFmdGVyIHRoZSAnQCdcbiAgICAgICAgLy8gc2lnbiwgc28gY2hlY2sgZm9yIHRoYXQuIFdlIGFsc28gbmVlZCB0byBiZSBjYXJlZnVsIHRoYXQgcGFja2FnZSBuYW1lcyB0aGVtc2VsdmVzIGNhblxuICAgICAgICAvLyBjb250YWluIHRoZSAnQCcgc3ltYm9sLCBhcyBpbiBgbnBtIGluc3RhbGwgQGFwcGl1bS9mYWtlLWRyaXZlckAxLjIuMGBcbiAgICAgICAgbGV0IG5hbWU7XG4gICAgICAgIGNvbnN0IHNwbGl0cyA9IGluc3RhbGxTcGVjLnNwbGl0KCdAJyk7XG4gICAgICAgIGlmIChpbnN0YWxsU3BlY1swXSA9PT0gJ0AnKSB7XG4gICAgICAgICAgLy8gdGhpcyBpcyB0aGUgY2FzZSB3aGVyZSB3ZSBoYXZlIGFuIG5wbSBvcmcgaW5jbHVkZWQgaW4gdGhlIHBhY2thZ2UgbmFtZVxuICAgICAgICAgIFtuYW1lLCBwa2dWZXJdID0gW2BAJHtzcGxpdHNbMV19YCwgc3BsaXRzWzJdXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyB0aGlzIGlzIHRoZSBjYXNlIHdpdGhvdXQgYW4gbnBtIG9yZ1xuICAgICAgICAgIFtuYW1lLCBwa2dWZXJdID0gc3BsaXRzO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGluc3RhbGxUeXBlID09PSBJTlNUQUxMX1RZUEVfTlBNKSB7XG4gICAgICAgICAgLy8gaWYgd2UncmUgaW5zdGFsbGluZyBhIG5hbWVkIHBhY2thZ2UgZnJvbSBucG0sIHdlIGRvbid0IG5lZWQgdG8gY2hlY2tcbiAgICAgICAgICAvLyBhZ2FpbnN0IHRoZSBhcHBpdW0gZXh0ZW5zaW9uIGxpc3Q7IGp1c3QgdXNlIHRoZSBpbnN0YWxsU3BlYyBhcyBpc1xuICAgICAgICAgIHBrZ05hbWUgPSBuYW1lO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIGlmIHdlJ3JlIGluc3RhbGxpbmcgYSBuYW1lZCBhcHBpdW0gZHJpdmVyIChsaWtlICd4Y3VpdGVzdCcpIHdlIG5lZWQgdG9cbiAgICAgICAgICAvLyBkZXJlZmVyZW5jZSB0aGUgYWN0dWFsIG5wbSBwYWNrYWdlICgnYXBwaXVwbS14Y3VpdGVzdC1kcml2ZXInKSwgc29cbiAgICAgICAgICAvLyBjaGVjayBpdCBleGlzdHMgYW5kIGdldCB0aGUgY29ycmVjdCBwYWNrYWdlXG4gICAgICAgICAgY29uc3Qga25vd25OYW1lcyA9IE9iamVjdC5rZXlzKHRoaXMua25vd25FeHRlbnNpb25zKTtcbiAgICAgICAgICBpZiAoIV8uaW5jbHVkZXMoa25vd25OYW1lcywgbmFtZSkpIHtcbiAgICAgICAgICAgIGNvbnN0IG1zZyA9XG4gICAgICAgICAgICAgIGBDb3VsZCBub3QgcmVzb2x2ZSAke3RoaXMudHlwZX07IGFyZSB5b3Ugc3VyZSBpdCdzIGluIHRoZSBsaXN0IGAgK1xuICAgICAgICAgICAgICBgb2Ygc3VwcG9ydGVkICR7dGhpcy50eXBlfXM/ICR7SlNPTi5zdHJpbmdpZnkoa25vd25OYW1lcyl9YDtcbiAgICAgICAgICAgIHRocm93IHRoaXMuX2NyZWF0ZUZhdGFsRXJyb3IobXNnKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcHJvYmFibGVFeHROYW1lID0gbmFtZTtcbiAgICAgICAgICBwa2dOYW1lID0gdGhpcy5rbm93bkV4dGVuc2lvbnNbbmFtZV07XG4gICAgICAgICAgLy8gZ2l2ZW4gdGhhdCB3ZSdsbCB1c2UgdGhlIGluc3RhbGwgdHlwZSBpbiB0aGUgZHJpdmVyIGpzb24sIHN0b3JlIGl0IGFzXG4gICAgICAgICAgLy8gJ25wbScgbm93XG4gICAgICAgICAgaW5zdGFsbFR5cGUgPSBJTlNUQUxMX1RZUEVfTlBNO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpbnN0YWxsT3B0cyA9IHtpbnN0YWxsU3BlYywgcGtnTmFtZSwgcGtnVmVyfTtcbiAgICB9XG5cbiAgICAvLyBmYWlsIGZhc3QgaGVyZSBpZiB3ZSBjYW5cbiAgICBpZiAocHJvYmFibGVFeHROYW1lICYmIHRoaXMuY29uZmlnLmlzSW5zdGFsbGVkKHByb2JhYmxlRXh0TmFtZSkpIHtcbiAgICAgIHRocm93IHRoaXMuX2NyZWF0ZUZhdGFsRXJyb3IoXG4gICAgICAgIGBBICR7dGhpcy50eXBlfSBuYW1lZCBcIiR7cHJvYmFibGVFeHROYW1lfVwiIGlzIGFscmVhZHkgaW5zdGFsbGVkLiBgICtcbiAgICAgICAgICBgRGlkIHlvdSBtZWFuIHRvIHVwZGF0ZT8gUnVuIFwiYXBwaXVtICR7dGhpcy50eXBlfSB1cGRhdGVcIi4gU2VlIGAgK1xuICAgICAgICAgIGBpbnN0YWxsZWQgJHt0aGlzLnR5cGV9cyB3aXRoIFwiYXBwaXVtICR7dGhpcy50eXBlfSBsaXN0IC0taW5zdGFsbGVkXCIuYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBleHREYXRhID0gYXdhaXQgdGhpcy5pbnN0YWxsVmlhTnBtKGluc3RhbGxPcHRzKTtcblxuICAgIC8vIHRoaXMgX3Nob3VsZF8gYmUgdGhlIHNhbWUgYXMgYHByb2JhYmx5RXh0TmFtZWAgYXMgdGhlIG9uZSBkZXJpdmVkIGFib3ZlIHVubGVzc1xuICAgIC8vIGluc3RhbGwgdHlwZSBpcyBsb2NhbC5cbiAgICBjb25zdCBleHROYW1lID0gZXh0RGF0YVsvKiogQHR5cGUge3N0cmluZ30gKi8gKGAke3RoaXMudHlwZX1OYW1lYCldO1xuXG4gICAgLy8gY2hlY2sgX2Egc2Vjb25kIHRpbWVfIHdpdGggdGhlIG1vcmUtYWNjdXJhdGUgZXh0TmFtZVxuICAgIGlmICh0aGlzLmNvbmZpZy5pc0luc3RhbGxlZChleHROYW1lKSkge1xuICAgICAgdGhyb3cgdGhpcy5fY3JlYXRlRmF0YWxFcnJvcihcbiAgICAgICAgYEEgJHt0aGlzLnR5cGV9IG5hbWVkIFwiJHtleHROYW1lfVwiIGlzIGFscmVhZHkgaW5zdGFsbGVkLiBgICtcbiAgICAgICAgICBgRGlkIHlvdSBtZWFuIHRvIHVwZGF0ZT8gUnVuIFwiYXBwaXVtICR7dGhpcy50eXBlfSB1cGRhdGVcIi4gU2VlIGAgK1xuICAgICAgICAgIGBpbnN0YWxsZWQgJHt0aGlzLnR5cGV9cyB3aXRoIFwiYXBwaXVtICR7dGhpcy50eXBlfSBsaXN0IC0taW5zdGFsbGVkXCIuYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyB0aGlzIGZpZWxkIGRvZXMgbm90IGV4aXN0IGFzIHN1Y2ggaW4gdGhlIG1hbmlmZXN0IChpdCdzIHVzZWQgYXMgYSBwcm9wZXJ0eSBuYW1lIGluc3RlYWQpXG4gICAgLy8gc28gdGhhdCdzIHdoeSBpdCdzIGJlaW5nIHJlbW92ZWQgaGVyZS5cbiAgICBkZWxldGUgZXh0RGF0YVsvKiogQHR5cGUge3N0cmluZ30gKi8gKGAke3RoaXMudHlwZX1OYW1lYCldO1xuXG4gICAgLyoqIEB0eXBlIHtFeHRNYW5pZmVzdDxFeHRUeXBlPn0gKi9cbiAgICBjb25zdCBleHRNYW5pZmVzdCA9IHsuLi5leHREYXRhLCBpbnN0YWxsVHlwZSwgaW5zdGFsbFNwZWN9O1xuICAgIGNvbnN0IFtlcnJvcnMsIHdhcm5pbmdzXSA9IGF3YWl0IEIuYWxsKFtcbiAgICAgIHRoaXMuY29uZmlnLmdldFByb2JsZW1zKGV4dE5hbWUsIGV4dE1hbmlmZXN0KSxcbiAgICAgIHRoaXMuY29uZmlnLmdldFdhcm5pbmdzKGV4dE5hbWUsIGV4dE1hbmlmZXN0KSxcbiAgICBdKTtcbiAgICBjb25zdCBlcnJvck1hcCA9IG5ldyBNYXAoW1tleHROYW1lLCBlcnJvcnNdXSk7XG4gICAgY29uc3Qgd2FybmluZ01hcCA9IG5ldyBNYXAoW1tleHROYW1lLCB3YXJuaW5nc11dKTtcbiAgICBjb25zdCB7ZXJyb3JTdW1tYXJpZXMsIHdhcm5pbmdTdW1tYXJpZXN9ID0gdGhpcy5jb25maWcuZ2V0VmFsaWRhdGlvblJlc3VsdFN1bW1hcmllcyhcbiAgICAgIGVycm9yTWFwLFxuICAgICAgd2FybmluZ01hcFxuICAgICk7XG5cbiAgICBpZiAoIV8uaXNFbXB0eShlcnJvclN1bW1hcmllcykpIHtcbiAgICAgIHRocm93IHRoaXMuX2NyZWF0ZUZhdGFsRXJyb3IoZXJyb3JTdW1tYXJpZXMuam9pbignXFxuJykpO1xuICAgIH1cblxuICAgIC8vIG5vdGUgdGhhdCB3ZSB3b24ndCBzaG93IGFueSB3YXJuaW5ncyBpZiB0aGVyZSB3ZXJlIGVycm9ycy5cbiAgICBpZiAoIV8uaXNFbXB0eSh3YXJuaW5nU3VtbWFyaWVzKSkge1xuICAgICAgdGhpcy5sb2cud2Fybih3YXJuaW5nU3VtbWFyaWVzLmpvaW4oJ1xcbicpKTtcbiAgICB9XG5cbiAgICBhd2FpdCB0aGlzLmNvbmZpZy5hZGRFeHRlbnNpb24oZXh0TmFtZSwgZXh0TWFuaWZlc3QpO1xuXG4gICAgLy8gdXBkYXRlIHRoZSBpZiB3ZSd2ZSBjaGFuZ2VkIHRoZSBsb2NhbCBgcGFja2FnZS5qc29uYFxuICAgIGlmIChhd2FpdCBlbnYuaGFzQXBwaXVtRGVwZW5kZW5jeSh0aGlzLmNvbmZpZy5hcHBpdW1Ib21lKSkge1xuICAgICAgYXdhaXQgcGFja2FnZURpZENoYW5nZSh0aGlzLmNvbmZpZy5hcHBpdW1Ib21lKTtcbiAgICB9XG5cbiAgICAvLyBsb2cgaW5mbyBmb3IgdGhlIHVzZXJcbiAgICB0aGlzLmxvZy5pbmZvKHRoaXMuZ2V0UG9zdEluc3RhbGxUZXh0KHtleHROYW1lLCBleHREYXRhfSkpO1xuXG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLmluc3RhbGxlZEV4dGVuc2lvbnM7XG4gIH1cblxuICAvKipcbiAgICogSW5zdGFsbCBhbiBleHRlbnNpb24gdmlhIE5QTVxuICAgKlxuICAgKiBAcGFyYW0ge0luc3RhbGxWaWFOcG1BcmdzfSBhcmdzXG4gICAqL1xuICBhc3luYyBpbnN0YWxsVmlhTnBtKHtpbnN0YWxsU3BlYywgcGtnTmFtZSwgcGtnVmVyfSkge1xuICAgIGNvbnN0IG5wbVNwZWMgPSBgJHtwa2dOYW1lfSR7cGtnVmVyID8gJ0AnICsgcGtnVmVyIDogJyd9YDtcbiAgICBjb25zdCBzcGVjTXNnID0gbnBtU3BlYyA9PT0gaW5zdGFsbFNwZWMgPyAnJyA6IGAgdXNpbmcgTlBNIGluc3RhbGwgc3BlYyAnJHtucG1TcGVjfSdgO1xuICAgIGNvbnN0IG1zZyA9IGBJbnN0YWxsaW5nICcke2luc3RhbGxTcGVjfScke3NwZWNNc2d9YDtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcGtnSnNvbkRhdGEgPSBhd2FpdCBzcGluV2l0aCh0aGlzLmlzSnNvbk91dHB1dCwgbXNnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHBrZ0pzb25EYXRhID0gYXdhaXQgbnBtLmluc3RhbGxQYWNrYWdlKHRoaXMuY29uZmlnLmFwcGl1bUhvbWUsIHBrZ05hbWUsIHtcbiAgICAgICAgICBwa2dWZXIsXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnZhbGlkYXRlUGFja2FnZUpzb24ocGtnSnNvbkRhdGEsIGluc3RhbGxTcGVjKTtcbiAgICAgICAgcmV0dXJuIHBrZ0pzb25EYXRhO1xuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiB0aGlzLmdldEV4dGVuc2lvbkZpZWxkcyhwa2dKc29uRGF0YSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aHJvdyB0aGlzLl9jcmVhdGVGYXRhbEVycm9yKGBFbmNvdW50ZXJlZCBhbiBlcnJvciB3aGVuIGluc3RhbGxpbmcgcGFja2FnZTogJHtlcnIubWVzc2FnZX1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSB0ZXh0IHdoaWNoIHNob3VsZCBiZSBkaXNwbGF5ZWQgdG8gdGhlIHVzZXIgYWZ0ZXIgYW4gZXh0ZW5zaW9uIGhhcyBiZWVuIGluc3RhbGxlZC4gVGhpc1xuICAgKiBpcyBkZXNpZ25lZCB0byBiZSBvdmVycmlkZGVuIGJ5IGRyaXZlcnMvcGx1Z2lucyB3aXRoIHRoZWlyIG93biBwYXJ0aWN1bGFyIHRleHQuXG4gICAqXG4gICAqIEBwYXJhbSB7RXh0ZW5zaW9uQXJnc30gYXJnc1xuICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgKi9cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVudXNlZC12YXJzXG4gIGdldFBvc3RJbnN0YWxsVGV4dChhcmdzKSB7XG4gICAgdGhyb3cgdGhpcy5fY3JlYXRlRmF0YWxFcnJvcignTXVzdCBiZSBpbXBsZW1lbnRlZCBpbiBmaW5hbCBjbGFzcycpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRha2UgYW4gTlBNIG1vZHVsZSdzIHBhY2thZ2UuanNvbiBhbmQgZXh0cmFjdCBBcHBpdW0gZHJpdmVyIGluZm9ybWF0aW9uIGZyb20gYSBzcGVjaWFsXG4gICAqICdhcHBpdW0nIGZpZWxkIGluIHRoZSBKU09OIGRhdGEuIFdlIG5lZWQgdGhpcyBpbmZvcm1hdGlvbiB0byBlLmcuIGRldGVybWluZSB3aGljaCBjbGFzcyB0b1xuICAgKiBsb2FkIGFzIHRoZSBtYWluIGRyaXZlciBjbGFzcywgb3IgdG8gYmUgYWJsZSB0byBkZXRlY3QgaW5jb21wYXRpYmlsaXRpZXMgYmV0d2VlbiBkcml2ZXIgYW5kXG4gICAqIGFwcGl1bSB2ZXJzaW9ucy5cbiAgICpcbiAgICogQHBhcmFtIHtFeHRQYWNrYWdlSnNvbjxFeHRUeXBlPn0gcGtnSnNvbiAtIHRoZSBwYWNrYWdlLmpzb24gZGF0YSBmb3IgYSBkcml2ZXIgbW9kdWxlLCBhcyBpZiBpdCBoYWQgYmVlbiBzdHJhaWdodGZvcndhcmRseSAncmVxdWlyZSdkXG4gICAqIEByZXR1cm5zIHtFeHRlbnNpb25GaWVsZHM8RXh0VHlwZT59XG4gICAqL1xuICBnZXRFeHRlbnNpb25GaWVsZHMocGtnSnNvbikge1xuICAgIGNvbnN0IHthcHBpdW0sIG5hbWUsIHZlcnNpb24sIHBlZXJEZXBlbmRlbmNpZXN9ID0gcGtnSnNvbjtcblxuICAgIC8qKiBAdHlwZSB7dW5rbm93bn0gKi9cbiAgICBjb25zdCByZXN1bHQgPSB7XG4gICAgICAuLi5hcHBpdW0sXG4gICAgICBwa2dOYW1lOiBuYW1lLFxuICAgICAgdmVyc2lvbixcbiAgICAgIGFwcGl1bVZlcnNpb246IHBlZXJEZXBlbmRlbmNpZXM/LmFwcGl1bSxcbiAgICB9O1xuICAgIHJldHVybiAvKiogQHR5cGUge0V4dGVuc2lvbkZpZWxkczxFeHRUeXBlPn0gKi8gKHJlc3VsdCk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIHRoZSBfcmVxdWlyZWRfIHJvb3QgZmllbGRzIG9mIGFuIGV4dGVuc2lvbidzIGBwYWNrYWdlLmpzb25gIGZpbGUuXG4gICAqXG4gICAqIFRoZXNlIHJlcXVpcmVkIGZpZWxkcyBhcmU6XG4gICAqIC0gYG5hbWVgXG4gICAqIC0gYHZlcnNpb25gXG4gICAqIC0gYGFwcGl1bWBcbiAgICogQHBhcmFtIHtpbXBvcnQoJ3R5cGUtZmVzdCcpLlBhY2thZ2VKc29ufSBwa2dKc29uIC0gYHBhY2thZ2UuanNvbmAgb2YgZXh0ZW5zaW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YWxsU3BlYyAtIEV4dGVuc2lvbiBuYW1lL3NwZWNcbiAgICogQHRocm93cyB7UmVmZXJlbmNlRXJyb3J9IElmIGBwYWNrYWdlLmpzb25gIGhhcyBhIG1pc3Npbmcgb3IgaW52YWxpZCBmaWVsZFxuICAgKiBAcmV0dXJucyB7cGtnSnNvbiBpcyBFeHRQYWNrYWdlSnNvbjxFeHRUeXBlPn1cbiAgICovXG4gIHZhbGlkYXRlUGFja2FnZUpzb24ocGtnSnNvbiwgaW5zdGFsbFNwZWMpIHtcbiAgICBjb25zdCB7YXBwaXVtLCBuYW1lLCB2ZXJzaW9ufSA9IC8qKiBAdHlwZSB7RXh0UGFja2FnZUpzb248RXh0VHlwZT59ICovIChwa2dKc29uKTtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGZpZWxkXG4gICAgICogQHJldHVybnMge1JlZmVyZW5jZUVycm9yfVxuICAgICAqL1xuICAgIGNvbnN0IGNyZWF0ZU1pc3NpbmdGaWVsZEVycm9yID0gKGZpZWxkKSA9PlxuICAgICAgbmV3IFJlZmVyZW5jZUVycm9yKFxuICAgICAgICBgJHt0aGlzLnR5cGV9IFwiJHtpbnN0YWxsU3BlY31cIiBpbnZhbGlkOyBtaXNzaW5nIGEgXFxgJHtmaWVsZH1cXGAgZmllbGQgb2YgaXRzIFxcYHBhY2thZ2UuanNvblxcYGBcbiAgICAgICk7XG5cbiAgICBpZiAoIW5hbWUpIHtcbiAgICAgIHRocm93IGNyZWF0ZU1pc3NpbmdGaWVsZEVycm9yKCduYW1lJyk7XG4gICAgfVxuICAgIGlmICghdmVyc2lvbikge1xuICAgICAgdGhyb3cgY3JlYXRlTWlzc2luZ0ZpZWxkRXJyb3IoJ3ZlcnNpb24nKTtcbiAgICB9XG4gICAgaWYgKCFhcHBpdW0pIHtcbiAgICAgIHRocm93IGNyZWF0ZU1pc3NpbmdGaWVsZEVycm9yKCdhcHBpdW0nKTtcbiAgICB9XG5cbiAgICB0aGlzLnZhbGlkYXRlRXh0ZW5zaW9uRmllbGRzKGFwcGl1bSwgaW5zdGFsbFNwZWMpO1xuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogRm9yIGFueSBgcGFja2FnZS5qc29uYCBmaWVsZHMgd2hpY2ggYSBwYXJ0aWN1bGFyIHR5cGUgb2YgZXh0ZW5zaW9uIHJlcXVpcmVzLCB2YWxpZGF0ZSB0aGVcbiAgICogcHJlc2VuY2UgYW5kIGZvcm0gb2YgdGhvc2UgZmllbGRzIG9uIHRoZSBgcGFja2FnZS5qc29uYCBkYXRhLCB0aHJvd2luZyBhbiBlcnJvciBpZiBhbnl0aGluZyBpc1xuICAgKiBhbWlzcy5cbiAgICpcbiAgICogQHBhcmFtIHtFeHRNZXRhZGF0YTxFeHRUeXBlPn0gZXh0TWV0YWRhdGEgLSB0aGUgZGF0YSBpbiB0aGUgXCJhcHBpdW1cIiBmaWVsZCBvZiBgcGFja2FnZS5qc29uYCBmb3IgYW4gZXh0ZW5zaW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YWxsU3BlYyAtIEV4dGVuc2lvbiBuYW1lL3NwZWNcbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bnVzZWQtdmFyc1xuICB2YWxpZGF0ZUV4dGVuc2lvbkZpZWxkcyhleHRNZXRhZGF0YSwgaW5zdGFsbFNwZWMpIHtcbiAgICB0aHJvdyB0aGlzLl9jcmVhdGVGYXRhbEVycm9yKCdNdXN0IGJlIGltcGxlbWVudGVkIGluIGZpbmFsIGNsYXNzJyk7XG4gIH1cblxuICAvKipcbiAgICogVW5pbnN0YWxsIGFuIGV4dGVuc2lvbi5cbiAgICpcbiAgICogRmlyc3QgdHJpZXMgdG8gZG8gdGhpcyB2aWEgYG5wbSB1bmluc3RhbGxgLCBidXQgaWYgdGhhdCBmYWlscywganVzdCBgcm0gLXJmYCdzIHRoZSBleHRlbnNpb24gZGlyLlxuICAgKlxuICAgKiBXaWxsIG9ubHkgcmVtb3ZlIHRoZSBleHRlbnNpb24gZnJvbSB0aGUgbWFuaWZlc3QgaWYgaXQgaGFzIGJlZW4gc3VjY2Vzc2Z1bGx5IHJlbW92ZWQuXG4gICAqXG4gICAqIEBwYXJhbSB7VW5pbnN0YWxsT3B0c30gb3B0c1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPEV4dFJlY29yZDxFeHRUeXBlPj59IG1hcCBvZiBhbGwgaW5zdGFsbGVkIGV4dGVuc2lvbiBuYW1lcyB0byBleHRlbnNpb24gZGF0YSAod2l0aG91dCB0aGUgZXh0ZW5zaW9uIGp1c3QgdW5pbnN0YWxsZWQpXG4gICAqL1xuICBhc3luYyBfdW5pbnN0YWxsKHtpbnN0YWxsU3BlY30pIHtcbiAgICBpZiAoIXRoaXMuY29uZmlnLmlzSW5zdGFsbGVkKGluc3RhbGxTcGVjKSkge1xuICAgICAgdGhyb3cgdGhpcy5fY3JlYXRlRmF0YWxFcnJvcihcbiAgICAgICAgYENhbid0IHVuaW5zdGFsbCAke3RoaXMudHlwZX0gJyR7aW5zdGFsbFNwZWN9JzsgaXQgaXMgbm90IGluc3RhbGxlZGBcbiAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IHBrZ05hbWUgPSB0aGlzLmNvbmZpZy5pbnN0YWxsZWRFeHRlbnNpb25zW2luc3RhbGxTcGVjXS5wa2dOYW1lO1xuICAgIGF3YWl0IG5wbS51bmluc3RhbGxQYWNrYWdlKHRoaXMuY29uZmlnLmFwcGl1bUhvbWUsIHBrZ05hbWUpO1xuICAgIGF3YWl0IHRoaXMuY29uZmlnLnJlbW92ZUV4dGVuc2lvbihpbnN0YWxsU3BlYyk7XG4gICAgdGhpcy5sb2cub2soYFN1Y2Nlc3NmdWxseSB1bmluc3RhbGxlZCAke3RoaXMudHlwZX0gJyR7aW5zdGFsbFNwZWN9J2AuZ3JlZW4pO1xuICAgIHJldHVybiB0aGlzLmNvbmZpZy5pbnN0YWxsZWRFeHRlbnNpb25zO1xuICB9XG5cbiAgLyoqXG4gICAqIEF0dGVtcHQgdG8gdXBkYXRlIG9uZSBvciBtb3JlIGRyaXZlcnMgdXNpbmcgTlBNXG4gICAqXG4gICAqIEBwYXJhbSB7RXh0ZW5zaW9uVXBkYXRlT3B0c30gdXBkYXRlU3BlY1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPEV4dGVuc2lvblVwZGF0ZVJlc3VsdD59XG4gICAqL1xuICBhc3luYyBfdXBkYXRlKHtpbnN0YWxsU3BlYywgdW5zYWZlfSkge1xuICAgIGNvbnN0IHNob3VsZFVwZGF0ZUFsbCA9IGluc3RhbGxTcGVjID09PSBVUERBVEVfQUxMO1xuICAgIC8vIGlmIHdlJ3JlIHNwZWNpZmljYWxseSByZXF1ZXN0aW5nIGFuIHVwZGF0ZSBmb3IgYW4gZXh0ZW5zaW9uLCBtYWtlIHN1cmUgaXQncyBpbnN0YWxsZWRcbiAgICBpZiAoIXNob3VsZFVwZGF0ZUFsbCAmJiAhdGhpcy5jb25maWcuaXNJbnN0YWxsZWQoaW5zdGFsbFNwZWMpKSB7XG4gICAgICB0aHJvdyB0aGlzLl9jcmVhdGVGYXRhbEVycm9yKFxuICAgICAgICBgVGhlICR7dGhpcy50eXBlfSBcIiR7aW5zdGFsbFNwZWN9XCIgd2FzIG5vdCBpbnN0YWxsZWQsIHNvIGNhbid0IGJlIHVwZGF0ZWRgXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCBleHRzVG9VcGRhdGUgPSBzaG91bGRVcGRhdGVBbGxcbiAgICAgID8gT2JqZWN0LmtleXModGhpcy5jb25maWcuaW5zdGFsbGVkRXh0ZW5zaW9ucylcbiAgICAgIDogW2luc3RhbGxTcGVjXTtcblxuICAgIC8vICdlcnJvcnMnIHdpbGwgaGF2ZSBleHQgbmFtZXMgYXMga2V5cyBhbmQgZXJyb3Igb2JqZWN0cyBhcyB2YWx1ZXNcbiAgICAvKiogQHR5cGUge1JlY29yZDxzdHJpbmcsRXJyb3I+fSAqL1xuICAgIGNvbnN0IGVycm9ycyA9IHt9O1xuXG4gICAgLy8gJ3VwZGF0ZXMnIHdpbGwgaGF2ZSBleHQgbmFtZXMgYXMga2V5cyBhbmQgdXBkYXRlIG9iamVjdHMgYXMgdmFsdWVzLCB3aGVyZSBhbiB1cGRhdGVcbiAgICAvLyBvYmplY3QgaXMgb2YgdGhlIGZvcm0ge2Zyb206IHZlcnNpb25TdHJpbmcsIHRvOiB2ZXJzaW9uU3RyaW5nfVxuICAgIC8qKiBAdHlwZSB7UmVjb3JkPHN0cmluZyxVcGRhdGVSZXBvcnQ+fSAqL1xuICAgIGNvbnN0IHVwZGF0ZXMgPSB7fTtcblxuICAgIGZvciAoY29uc3QgZSBvZiBleHRzVG9VcGRhdGUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHNwaW5XaXRoKHRoaXMuaXNKc29uT3V0cHV0LCBgQ2hlY2tpbmcgaWYgJHt0aGlzLnR5cGV9ICcke2V9JyBpcyB1cGRhdGFibGVgLCAoKSA9PiB7XG4gICAgICAgICAgaWYgKHRoaXMuY29uZmlnLmluc3RhbGxlZEV4dGVuc2lvbnNbZV0uaW5zdGFsbFR5cGUgIT09IElOU1RBTExfVFlQRV9OUE0pIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBOb3RVcGRhdGFibGVFcnJvcigpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHVwZGF0ZSA9IGF3YWl0IHNwaW5XaXRoKFxuICAgICAgICAgIHRoaXMuaXNKc29uT3V0cHV0LFxuICAgICAgICAgIGBDaGVja2luZyBpZiAke3RoaXMudHlwZX0gJyR7ZX0nIG5lZWRzIGFuIHVwZGF0ZWAsXG4gICAgICAgICAgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgdXBkYXRlID0gYXdhaXQgdGhpcy5jaGVja0ZvckV4dGVuc2lvblVwZGF0ZShlKTtcbiAgICAgICAgICAgIGlmICghKHVwZGF0ZS5zYWZlVXBkYXRlIHx8IHVwZGF0ZS51bnNhZmVVcGRhdGUpKSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBOb1VwZGF0ZXNBdmFpbGFibGVFcnJvcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHVwZGF0ZTtcbiAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgICAgIGlmICghdW5zYWZlICYmICF1cGRhdGUuc2FmZVVwZGF0ZSkge1xuICAgICAgICAgIHRocm93IHRoaXMuX2NyZWF0ZUZhdGFsRXJyb3IoXG4gICAgICAgICAgICBgVGhlICR7dGhpcy50eXBlfSAnJHtlfScgaGFzIGEgbWFqb3IgcmV2aXNpb24gdXBkYXRlIGAgK1xuICAgICAgICAgICAgICBgKCR7dXBkYXRlLmN1cnJlbnR9ID0+ICR7dXBkYXRlLnVuc2FmZVVwZGF0ZX0pLCB3aGljaCBjb3VsZCBpbmNsdWRlIGAgK1xuICAgICAgICAgICAgICBgYnJlYWtpbmcgY2hhbmdlcy4gSWYgeW91IHdhbnQgdG8gYXBwbHkgdGhpcyB1cGRhdGUsIHJlLXJ1biB3aXRoIC0tdW5zYWZlYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdXBkYXRlVmVyID0gdW5zYWZlICYmIHVwZGF0ZS51bnNhZmVVcGRhdGUgPyB1cGRhdGUudW5zYWZlVXBkYXRlIDogdXBkYXRlLnNhZmVVcGRhdGU7XG4gICAgICAgIGF3YWl0IHNwaW5XaXRoKFxuICAgICAgICAgIHRoaXMuaXNKc29uT3V0cHV0LFxuICAgICAgICAgIGBVcGRhdGluZyBkcml2ZXIgJyR7ZX0nIGZyb20gJHt1cGRhdGUuY3VycmVudH0gdG8gJHt1cGRhdGVWZXJ9YCxcbiAgICAgICAgICBhc3luYyAoKSA9PiBhd2FpdCB0aGlzLnVwZGF0ZUV4dGVuc2lvbihlLCB1cGRhdGVWZXIpXG4gICAgICAgICk7XG4gICAgICAgIHVwZGF0ZXNbZV0gPSB7ZnJvbTogdXBkYXRlLmN1cnJlbnQsIHRvOiB1cGRhdGVWZXJ9O1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGVycm9yc1tlXSA9IGVycjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmxvZy5pbmZvKCdVcGRhdGUgcmVwb3J0OicpO1xuXG4gICAgZm9yIChjb25zdCBbZSwgdXBkYXRlXSBvZiBfLnRvUGFpcnModXBkYXRlcykpIHtcbiAgICAgIHRoaXMubG9nLm9rKGAgIC0gJHt0aGlzLnR5cGV9ICR7ZX0gdXBkYXRlZDogJHt1cGRhdGUuZnJvbX0gPT4gJHt1cGRhdGUudG99YC5ncmVlbik7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbZSwgZXJyXSBvZiBfLnRvUGFpcnMoZXJyb3JzKSkge1xuICAgICAgaWYgKGVyciBpbnN0YW5jZW9mIE5vdFVwZGF0YWJsZUVycm9yKSB7XG4gICAgICAgIHRoaXMubG9nLndhcm4oXG4gICAgICAgICAgYCAgLSAnJHtlfScgd2FzIG5vdCBpbnN0YWxsZWQgdmlhIG5wbSwgc28gd2UgY291bGQgbm90IGNoZWNrIGAgKyBgZm9yIHVwZGF0ZXNgLnllbGxvd1xuICAgICAgICApO1xuICAgICAgfSBlbHNlIGlmIChlcnIgaW5zdGFuY2VvZiBOb1VwZGF0ZXNBdmFpbGFibGVFcnJvcikge1xuICAgICAgICB0aGlzLmxvZy5pbmZvKGAgIC0gJyR7ZX0nIGhhZCBubyB1cGRhdGVzIGF2YWlsYWJsZWAueWVsbG93KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIG90aGVyd2lzZSwgbWFrZSBpdCBwb3Agd2l0aCByZWQhXG4gICAgICAgIHRoaXMubG9nLmVycm9yKGAgIC0gJyR7ZX0nIGZhaWxlZCB0byB1cGRhdGU6ICR7ZXJyfWAucmVkKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHt1cGRhdGVzLCBlcnJvcnN9O1xuICB9XG5cbiAgLyoqXG4gICAqIEdpdmVuIGFuIGV4dGVuc2lvbiBuYW1lLCBmaWd1cmUgb3V0IHdoYXQgaXRzIGhpZ2hlc3QgcG9zc2libGUgdmVyc2lvbiB1cGdyYWRlIGlzLCBhbmQgYWxzbyB0aGVcbiAgICogaGlnaGVzdCBwb3NzaWJsZSBzYWZlIHVwZ3JhZGUuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBleHQgLSBuYW1lIG9mIGV4dGVuc2lvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPFBvc3NpYmxlVXBkYXRlcz59XG4gICAqL1xuICBhc3luYyBjaGVja0ZvckV4dGVuc2lvblVwZGF0ZShleHQpIHtcbiAgICAvLyBUT0RPIGRlY2lkZSBob3cgd2Ugd2FudCB0byBoYW5kbGUgYmV0YSB2ZXJzaW9ucz9cbiAgICAvLyB0aGlzIGlzIGEgaGVscGVyIG1ldGhvZCwgJ2V4dCcgaXMgYXNzdW1lZCB0byBhbHJlYWR5IGJlIGluc3RhbGxlZCBoZXJlLCBhbmQgb2YgdGhlIG5wbVxuICAgIC8vIGluc3RhbGwgdHlwZVxuICAgIGNvbnN0IHt2ZXJzaW9uLCBwa2dOYW1lfSA9IHRoaXMuY29uZmlnLmluc3RhbGxlZEV4dGVuc2lvbnNbZXh0XTtcbiAgICAvKiogQHR5cGUge3N0cmluZz99ICovXG4gICAgbGV0IHVuc2FmZVVwZGF0ZSA9IGF3YWl0IG5wbS5nZXRMYXRlc3RWZXJzaW9uKHRoaXMuY29uZmlnLmFwcGl1bUhvbWUsIHBrZ05hbWUpO1xuICAgIGxldCBzYWZlVXBkYXRlID0gYXdhaXQgbnBtLmdldExhdGVzdFNhZmVVcGdyYWRlVmVyc2lvbihcbiAgICAgIHRoaXMuY29uZmlnLmFwcGl1bUhvbWUsXG4gICAgICBwa2dOYW1lLFxuICAgICAgdmVyc2lvblxuICAgICk7XG4gICAgaWYgKHVuc2FmZVVwZGF0ZSAhPT0gbnVsbCAmJiAhdXRpbC5jb21wYXJlVmVyc2lvbnModW5zYWZlVXBkYXRlLCAnPicsIHZlcnNpb24pKSB7XG4gICAgICAvLyB0aGUgbGF0ZXN0IHZlcnNpb24gaXMgbm90IGdyZWF0ZXIgdGhhbiB0aGUgY3VycmVudCB2ZXJzaW9uLCBzbyB0aGVyZSdzIG5vIHBvc3NpYmxlIHVwZGF0ZVxuICAgICAgdW5zYWZlVXBkYXRlID0gbnVsbDtcbiAgICAgIHNhZmVVcGRhdGUgPSBudWxsO1xuICAgIH1cbiAgICBpZiAodW5zYWZlVXBkYXRlICYmIHVuc2FmZVVwZGF0ZSA9PT0gc2FmZVVwZGF0ZSkge1xuICAgICAgLy8gdGhlIGxhdGVzdCB1cGRhdGUgaXMgdGhlIHNhbWUgYXMgdGhlIHNhZmUgdXBkYXRlLCB3aGljaCBtZWFucyBpdCdzIG5vdCBhY3R1YWxseSB1bnNhZmVcbiAgICAgIHVuc2FmZVVwZGF0ZSA9IG51bGw7XG4gICAgfVxuICAgIGlmIChzYWZlVXBkYXRlICYmICF1dGlsLmNvbXBhcmVWZXJzaW9ucyhzYWZlVXBkYXRlLCAnPicsIHZlcnNpb24pKSB7XG4gICAgICAvLyBldmVuIHRoZSBzYWZlIHVwZGF0ZSBpcyBub3QgbGF0ZXIgdGhhbiB0aGUgY3VycmVudCwgc28gaXQgaXMgbm90IGFjdHVhbGx5IGFuIHVwZGF0ZVxuICAgICAgc2FmZVVwZGF0ZSA9IG51bGw7XG4gICAgfVxuICAgIHJldHVybiB7Y3VycmVudDogdmVyc2lvbiwgc2FmZVVwZGF0ZSwgdW5zYWZlVXBkYXRlfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBY3R1YWxseSB1cGRhdGUgYW4gZXh0ZW5zaW9uIGluc3RhbGxlZCBieSBOUE0sIHVzaW5nIHRoZSBOUE0gY2xpLiBBbmQgdXBkYXRlIHRoZSBpbnN0YWxsYXRpb25cbiAgICogbWFuaWZlc3QuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YWxsU3BlYyAtIG5hbWUgb2YgZXh0ZW5zaW9uIHRvIHVwZGF0ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdmVyc2lvbiAtIHZlcnNpb24gc3RyaW5nIGlkZW50aWZpZXIgdG8gdXBkYXRlIGV4dGVuc2lvbiB0b1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHVwZGF0ZUV4dGVuc2lvbihpbnN0YWxsU3BlYywgdmVyc2lvbikge1xuICAgIGNvbnN0IHtwa2dOYW1lfSA9IHRoaXMuY29uZmlnLmluc3RhbGxlZEV4dGVuc2lvbnNbaW5zdGFsbFNwZWNdO1xuICAgIGNvbnN0IGV4dERhdGEgPSBhd2FpdCB0aGlzLmluc3RhbGxWaWFOcG0oe1xuICAgICAgaW5zdGFsbFNwZWMsXG4gICAgICBwa2dOYW1lLFxuICAgICAgcGtnVmVyOiB2ZXJzaW9uLFxuICAgIH0pO1xuICAgIGRlbGV0ZSBleHREYXRhWy8qKiBAdHlwZSB7c3RyaW5nfSAqLyAoYCR7dGhpcy50eXBlfU5hbWVgKV07XG4gICAgYXdhaXQgdGhpcy5jb25maWcudXBkYXRlRXh0ZW5zaW9uKGluc3RhbGxTcGVjLCBleHREYXRhKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGEgc2NyaXB0IGNhY2hlZCBpbnNpZGUgdGhlIFwic2NyaXB0c1wiIGZpZWxkIHVuZGVyIFwiYXBwaXVtXCJcbiAgICogaW5zaWRlIG9mIHRoZSBkcml2ZXIvcGx1Z2lucyBcInBhY2thZ2UuanNvblwiIGZpbGUuIFdpbGwgdGhyb3dcbiAgICogYW4gZXJyb3IgaWYgdGhlIGRyaXZlci9wbHVnaW4gZG9lcyBub3QgY29udGFpbiBhIFwic2NyaXB0c1wiIGZpZWxkXG4gICAqIHVuZGVybmVhdGggdGhlIFwiYXBwaXVtXCIgZmllbGQgaW4gaXRzIHBhY2thZ2UuanNvbiwgaWYgdGhlXG4gICAqIFwic2NyaXB0c1wiIGZpZWxkIGlzIG5vdCBhIHBsYWluIG9iamVjdCwgb3IgaWYgdGhlIHNjcmlwdE5hbWUgaXNcbiAgICogbm90IGZvdW5kIHdpdGhpbiBcInNjcmlwdHNcIiBvYmplY3QuXG4gICAqXG4gICAqIEBwYXJhbSB7UnVuT3B0aW9uc30gb3B0c1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJ1bk91dHB1dD59XG4gICAqL1xuICBhc3luYyBfcnVuKHtpbnN0YWxsU3BlYywgc2NyaXB0TmFtZSwgZXh0cmFBcmdzID0gW119KSB7XG4gICAgaWYgKCF0aGlzLmNvbmZpZy5pc0luc3RhbGxlZChpbnN0YWxsU3BlYykpIHtcbiAgICAgIHRocm93IHRoaXMuX2NyZWF0ZUZhdGFsRXJyb3IoYFRoZSAke3RoaXMudHlwZX0gXCIke2luc3RhbGxTcGVjfVwiIGlzIG5vdCBpbnN0YWxsZWRgKTtcbiAgICB9XG5cbiAgICBjb25zdCBleHRDb25maWcgPSB0aGlzLmNvbmZpZy5pbnN0YWxsZWRFeHRlbnNpb25zW2luc3RhbGxTcGVjXTtcblxuICAgIC8vIG5vdGU6IFRTIGNhbm5vdCB1bmRlcnN0YW5kIHRoYXQgXy5oYXMoKSBpcyBhIHR5cGUgZ3VhcmRcbiAgICBpZiAoIWV4dENvbmZpZy5zY3JpcHRzKSB7XG4gICAgICB0aHJvdyB0aGlzLl9jcmVhdGVGYXRhbEVycm9yKFxuICAgICAgICBgVGhlICR7dGhpcy50eXBlfSBuYW1lZCAnJHtpbnN0YWxsU3BlY30nIGRvZXMgbm90IGNvbnRhaW4gdGhlIGAgK1xuICAgICAgICAgIGBcInNjcmlwdHNcIiBmaWVsZCB1bmRlcm5lYXRoIHRoZSBcImFwcGl1bVwiIGZpZWxkIGluIGl0cyBwYWNrYWdlLmpzb25gXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGV4dFNjcmlwdHMgPSBleHRDb25maWcuc2NyaXB0cztcblxuICAgIGlmICghXy5pc1BsYWluT2JqZWN0KGV4dFNjcmlwdHMpKSB7XG4gICAgICB0aHJvdyB0aGlzLl9jcmVhdGVGYXRhbEVycm9yKFxuICAgICAgICBgVGhlICR7dGhpcy50eXBlfSBuYW1lZCAnJHtpbnN0YWxsU3BlY30nIFwic2NyaXB0c1wiIGZpZWxkIG11c3QgYmUgYSBwbGFpbiBvYmplY3RgXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICghXy5oYXMoZXh0U2NyaXB0cywgc2NyaXB0TmFtZSkpIHtcbiAgICAgIHRocm93IHRoaXMuX2NyZWF0ZUZhdGFsRXJyb3IoXG4gICAgICAgIGBUaGUgJHt0aGlzLnR5cGV9IG5hbWVkICcke2luc3RhbGxTcGVjfScgZG9lcyBub3Qgc3VwcG9ydCB0aGUgc2NyaXB0OiAnJHtzY3JpcHROYW1lfSdgXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHJ1bm5lciA9IG5ldyBTdWJQcm9jZXNzKHByb2Nlc3MuZXhlY1BhdGgsIFtleHRTY3JpcHRzW3NjcmlwdE5hbWVdLCAuLi5leHRyYUFyZ3NdLCB7XG4gICAgICBjd2Q6IHRoaXMuY29uZmlnLmdldEluc3RhbGxQYXRoKGluc3RhbGxTcGVjKSxcbiAgICB9KTtcblxuICAgIGNvbnN0IG91dHB1dCA9IG5ldyBSaW5nQnVmZmVyKDUwKTtcblxuICAgIHJ1bm5lci5vbignc3RyZWFtLWxpbmUnLCAobGluZSkgPT4ge1xuICAgICAgb3V0cHV0LmVucXVldWUobGluZSk7XG4gICAgICB0aGlzLmxvZy5sb2cobGluZSk7XG4gICAgfSk7XG5cbiAgICBhd2FpdCBydW5uZXIuc3RhcnQoMCk7XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgcnVubmVyLmpvaW4oKTtcbiAgICAgIHRoaXMubG9nLm9rKGAke3NjcmlwdE5hbWV9IHN1Y2Nlc3NmdWxseSByYW5gLmdyZWVuKTtcbiAgICAgIHJldHVybiB7b3V0cHV0OiBvdXRwdXQuZ2V0QnVmZigpfTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMubG9nLmVycm9yKGBFbmNvdW50ZXJlZCBhbiBlcnJvciB3aGVuIHJ1bm5pbmcgJyR7c2NyaXB0TmFtZX0nOiAke2Vyci5tZXNzYWdlfWAucmVkKTtcbiAgICAgIHJldHVybiB7ZXJyb3I6IGVyci5tZXNzYWdlLCBvdXRwdXQ6IG91dHB1dC5nZXRCdWZmKCl9O1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBFeHRlbnNpb25Db21tYW5kO1xuZXhwb3J0IHtFeHRlbnNpb25Db21tYW5kfTtcblxuLyoqXG4gKiBPcHRpb25zIGZvciB0aGUge0BsaW5rY29kZSBFeHRlbnNpb25Db21tYW5kfSBjb25zdHJ1Y3RvclxuICogQHRlbXBsYXRlIHtFeHRlbnNpb25UeXBlfSBFeHRUeXBlXG4gKiBAdHlwZWRlZiBFeHRlbnNpb25Db21tYW5kT3B0aW9uc1xuICogQHByb3BlcnR5IHtFeHRlbnNpb25Db25maWc8RXh0VHlwZT59IGNvbmZpZyAtIHRoZSBgRHJpdmVyQ29uZmlnYCBvciBgUGx1Z2luQ29uZmlnYCBpbnN0YW5jZSB1c2VkIGZvciB0aGlzIGNvbW1hbmRcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0ganNvbiAtIHdoZXRoZXIgdGhlIG91dHB1dCBvZiB0aGlzIGNvbW1hbmQgc2hvdWxkIGJlIEpTT04gb3IgdGV4dFxuICovXG5cbi8qKlxuICogRXh0cmEgc3R1ZmYgYWJvdXQgZXh0ZW5zaW9uczsgdXNlZCBpbmRpcmVjdGx5IGJ5IHtAbGlua2NvZGUgRXh0ZW5zaW9uQ29tbWFuZC5saXN0fS5cbiAqXG4gKiBAdHlwZWRlZiBFeHRlbnNpb25NZXRhZGF0YVxuICogQHByb3BlcnR5IHtib29sZWFufSBpbnN0YWxsZWQgLSBJZiBgdHJ1ZWAsIHRoZSBleHRlbnNpb24gaXMgaW5zdGFsbGVkXG4gKiBAcHJvcGVydHkge3N0cmluZz99IHVwZGF0ZVZlcnNpb24gLSBJZiB0aGUgZXh0ZW5zaW9uIGlzIGluc3RhbGxlZCwgdGhlIHZlcnNpb24gaXQgY2FuIGJlIHVwZGF0ZWQgdG9cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nP30gdW5zYWZlVXBkYXRlVmVyc2lvbiAtIFNhbWUgYXMgYWJvdmUsIGJ1dCBhIG1ham9yIHZlcnNpb24gYnVtcFxuICogQHByb3BlcnR5IHtib29sZWFufSB1cFRvRGF0ZSAtIElmIHRoZSBleHRlbnNpb24gaXMgaW5zdGFsbGVkIGFuZCB0aGUgbGF0ZXN0XG4gKi9cblxuLyoqXG4gKiBAdHlwZWRlZiB7aW1wb3J0KCdAYXBwaXVtL3R5cGVzJykuRXh0ZW5zaW9uVHlwZX0gRXh0ZW5zaW9uVHlwZVxuICogQHR5cGVkZWYge2ltcG9ydCgnQGFwcGl1bS90eXBlcycpLkRyaXZlclR5cGV9IERyaXZlclR5cGVcbiAqIEB0eXBlZGVmIHtpbXBvcnQoJ0BhcHBpdW0vdHlwZXMnKS5QbHVnaW5UeXBlfSBQbHVnaW5UeXBlXG4gKi9cblxuLyoqXG4gKiBAdGVtcGxhdGUge0V4dGVuc2lvblR5cGV9IEV4dFR5cGVcbiAqIEB0eXBlZGVmIHtpbXBvcnQoJ2FwcGl1bS90eXBlcycpLkV4dFJlY29yZDxFeHRUeXBlPn0gRXh0UmVjb3JkXG4gKi9cblxuLyoqXG4gKiBAdGVtcGxhdGUge0V4dGVuc2lvblR5cGV9IEV4dFR5cGVcbiAqIEB0eXBlZGVmIHtpbXBvcnQoJy4uL2V4dGVuc2lvbi9leHRlbnNpb24tY29uZmlnJykuRXh0ZW5zaW9uQ29uZmlnPEV4dFR5cGU+fSBFeHRlbnNpb25Db25maWdcbiAqL1xuXG4vKipcbiAqIEB0ZW1wbGF0ZSB7RXh0ZW5zaW9uVHlwZX0gRXh0VHlwZVxuICogQHR5cGVkZWYge2ltcG9ydCgnYXBwaXVtL3R5cGVzJykuRXh0TWV0YWRhdGE8RXh0VHlwZT59IEV4dE1ldGFkYXRhXG4gKi9cblxuLyoqXG4gKiBAdGVtcGxhdGUge0V4dGVuc2lvblR5cGV9IEV4dFR5cGVcbiAqIEB0eXBlZGVmIHtpbXBvcnQoJ2FwcGl1bS90eXBlcycpLkV4dE1hbmlmZXN0PEV4dFR5cGU+fSBFeHRNYW5pZmVzdFxuICovXG5cbi8qKlxuICogQHRlbXBsYXRlIHtFeHRlbnNpb25UeXBlfSBFeHRUeXBlXG4gKiBAdHlwZWRlZiB7aW1wb3J0KCdhcHBpdW0vdHlwZXMnKS5FeHRQYWNrYWdlSnNvbjxFeHRUeXBlPn0gRXh0UGFja2FnZUpzb25cbiAqL1xuXG4vKipcbiAqIFBvc3NpYmxlIHJldHVybiB2YWx1ZSBmb3Ige0BsaW5rY29kZSBFeHRlbnNpb25Db21tYW5kLmxpc3R9XG4gKiBAdHlwZWRlZiBVbmluc3RhbGxlZEV4dGVuc2lvbkxpc3REYXRhXG4gKiBAcHJvcGVydHkge3N0cmluZ30gcGtnTmFtZVxuICogQHByb3BlcnR5IHtmYWxzZX0gaW5zdGFsbGVkXG4gKi9cblxuLyoqXG4gKiBQb3NzaWJsZSByZXR1cm4gdmFsdWUgZm9yIHtAbGlua2NvZGUgRXh0ZW5zaW9uQ29tbWFuZC5saXN0fVxuICogQHR5cGVkZWYge2ltcG9ydCgnYXBwaXVtL3R5cGVzJykuSW50ZXJuYWxNZXRhZGF0YSAmIEV4dGVuc2lvbk1ldGFkYXRhfSBJbnN0YWxsZWRFeHRlbnNpb25MaXN0RGF0YVxuICovXG5cbi8qKlxuICogUmV0dXJuIHZhbHVlIG9mIHtAbGlua2NvZGUgRXh0ZW5zaW9uQ29tbWFuZC5saXN0fS5cbiAqIEB0eXBlZGVmIHtSZWNvcmQ8c3RyaW5nLEluc3RhbGxlZEV4dGVuc2lvbkxpc3REYXRhfFVuaW5zdGFsbGVkRXh0ZW5zaW9uTGlzdERhdGE+fSBFeHRlbnNpb25MaXN0RGF0YVxuICovXG5cbi8qKlxuICogT3B0aW9ucyBmb3Ige0BsaW5rY29kZSBFeHRlbnNpb25Db21tYW5kLl9ydW59LlxuICogQHR5cGVkZWYgUnVuT3B0aW9uc1xuICogQHByb3BlcnR5IHtzdHJpbmd9IGluc3RhbGxTcGVjIC0gbmFtZSBvZiB0aGUgZXh0ZW5zaW9uIHRvIHJ1biBhIHNjcmlwdCBmcm9tXG4gKiBAcHJvcGVydHkge3N0cmluZ30gc2NyaXB0TmFtZSAtIG5hbWUgb2YgdGhlIHNjcmlwdCB0byBydW5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IFtleHRyYUFyZ3NdIC0gYXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIHNjcmlwdFxuICovXG5cbi8qKlxuICogUmV0dXJuIHZhbHVlIG9mIHtAbGlua2NvZGUgRXh0ZW5zaW9uQ29tbWFuZC5fcnVufVxuICpcbiAqIEB0eXBlZGVmIFJ1bk91dHB1dFxuICogQHByb3BlcnR5IHtzdHJpbmd9IFtlcnJvcl0gLSBlcnJvciBtZXNzYWdlIGlmIHNjcmlwdCByYW4gdW5zdWNjZXNzZnVsbHksIG90aGVyd2lzZSB1bmRlZmluZWRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nW119IG91dHB1dCAtIHNjcmlwdCBvdXRwdXRcbiAqL1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHtAbGlua2NvZGUgRXh0ZW5zaW9uQ29tbWFuZC5fdXBkYXRlfS5cbiAqIEB0eXBlZGVmIEV4dGVuc2lvblVwZGF0ZU9wdHNcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBpbnN0YWxsU3BlYyAtIHRoZSBuYW1lIG9mIHRoZSBleHRlbnNpb24gdG8gdXBkYXRlXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IHVuc2FmZSAtIGlmIHRydWUsIHdpbGwgcGVyZm9ybSB1bnNhZmUgdXBkYXRlcyBwYXN0IG1ham9yIHJldmlzaW9uIGJvdW5kYXJpZXNcbiAqL1xuXG4vKipcbiAqIFJldHVybiB2YWx1ZSBvZiB7QGxpbmtjb2RlIEV4dGVuc2lvbkNvbW1hbmQuX3VwZGF0ZX0uXG4gKiBAdHlwZWRlZiBFeHRlbnNpb25VcGRhdGVSZXN1bHRcbiAqIEBwcm9wZXJ0eSB7UmVjb3JkPHN0cmluZyxFcnJvcj59IGVycm9ycyAtIG1hcCBvZiBleHQgbmFtZXMgdG8gZXJyb3Igb2JqZWN0c1xuICogQHByb3BlcnR5IHtSZWNvcmQ8c3RyaW5nLFVwZGF0ZVJlcG9ydD59IHVwZGF0ZXMgLSBtYXAgb2YgZXh0IG5hbWVzIHRvIHtAbGlua2NvZGUgVXBkYXRlUmVwb3J0fXNcbiAqL1xuXG4vKipcbiAqIFBhcnQgb2YgcmVzdWx0IG9mIHtAbGlua2NvZGUgRXh0ZW5zaW9uQ29tbWFuZC5fdXBkYXRlfS5cbiAqIEB0eXBlZGVmIFVwZGF0ZVJlcG9ydFxuICogQHByb3BlcnR5IHtzdHJpbmd9IGZyb20gLSB2ZXJzaW9uIHRoZSBleHRlbnNpb24gd2FzIHVwZGF0ZWQgZnJvbVxuICogQHByb3BlcnR5IHtzdHJpbmd9IHRvIC0gdmVyc2lvbiB0aGUgZXh0ZW5zaW9uIHdhcyB1cGRhdGVkIHRvXG4gKi9cblxuLyoqXG4gKiBPcHRpb25zIGZvciB7QGxpbmtjb2RlIEV4dGVuc2lvbkNvbW1hbmQuX3VuaW5zdGFsbH0uXG4gKiBAdHlwZWRlZiBVbmluc3RhbGxPcHRzXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaW5zdGFsbFNwZWMgLSB0aGUgbmFtZSBvciBzcGVjIG9mIGFuIGV4dGVuc2lvbiB0byB1bmluc3RhbGxcbiAqL1xuXG4vKipcbiAqIFVzZWQgYnkge0BsaW5rY29kZSBFeHRlbnNpb25Db21tYW5kLmdldFBvc3RJbnN0YWxsVGV4dH1cbiAqIEB0eXBlZGVmIEV4dGVuc2lvbkFyZ3NcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBleHROYW1lIC0gdGhlIG5hbWUgb2YgYW4gZXh0ZW5zaW9uXG4gKiBAcHJvcGVydHkge29iamVjdH0gZXh0RGF0YSAtIHRoZSBkYXRhIGZvciBhbiBpbnN0YWxsZWQgZXh0ZW5zaW9uXG4gKi9cblxuLyoqXG4gKiBPcHRpb25zIGZvciB7QGxpbmtjb2RlIEV4dGVuc2lvbkNvbW1hbmQuaW5zdGFsbFZpYU5wbX1cbiAqIEB0eXBlZGVmIEluc3RhbGxWaWFOcG1BcmdzXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaW5zdGFsbFNwZWMgLSB0aGUgbmFtZSBvciBzcGVjIG9mIGFuIGV4dGVuc2lvbiB0byBpbnN0YWxsXG4gKiBAcHJvcGVydHkge3N0cmluZ30gcGtnTmFtZSAtIHRoZSBOUE0gcGFja2FnZSBuYW1lIG9mIHRoZSBleHRlbnNpb25cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBbcGtnVmVyXSAtIHRoZSBzcGVjaWZpYyB2ZXJzaW9uIG9mIHRoZSBOUE0gcGFja2FnZVxuICovXG5cbi8qKlxuICogT2JqZWN0IHJldHVybmVkIGJ5IHtAbGlua2NvZGUgRXh0ZW5zaW9uQ29tbWFuZC5jaGVja0ZvckV4dGVuc2lvblVwZGF0ZX1cbiAqIEB0eXBlZGVmIFBvc3NpYmxlVXBkYXRlc1xuICogQHByb3BlcnR5IHtzdHJpbmd9IGN1cnJlbnQgLSBjdXJyZW50IHZlcnNpb25cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nP30gc2FmZVVwZGF0ZSAtIHZlcnNpb24gd2UgY2FuIHNhZmVseSB1cGRhdGUgdG8gaWYgaXQgZXhpc3RzLCBvciBudWxsXG4gKiBAcHJvcGVydHkge3N0cmluZz99IHVuc2FmZVVwZGF0ZSAtIHZlcnNpb24gd2UgY2FuIHVuc2FmZWx5IHVwZGF0ZSB0byBpZiBpdCBleGlzdHMsIG9yIG51bGxcbiAqL1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHtAbGlua2NvZGUgRXh0ZW5zaW9uQ29tbWFuZC5faW5zdGFsbH1cbiAqIEB0eXBlZGVmIEluc3RhbGxBcmdzXG4gKiBAcHJvcGVydHkge3N0cmluZ30gaW5zdGFsbFNwZWMgLSB0aGUgbmFtZSBvciBzcGVjIG9mIGFuIGV4dGVuc2lvbiB0byBpbnN0YWxsXG4gKiBAcHJvcGVydHkge2ltcG9ydCgnYXBwaXVtL3R5cGVzJykuSW5zdGFsbFR5cGV9IGluc3RhbGxUeXBlIC0gaG93IHRvIGluc3RhbGwgdGhpcyBleHRlbnNpb24uIE9uZSBvZiB0aGUgSU5TVEFMTF9UWVBFU1xuICogQHByb3BlcnR5IHtzdHJpbmd9IFtwYWNrYWdlTmFtZV0gLSBmb3IgZ2l0L2dpdGh1YiBpbnN0YWxscywgdGhlIGV4dGVuc2lvbiBub2RlIHBhY2thZ2UgbmFtZVxuICovXG5cbi8qKlxuICogUmV0dXJuZWQgYnkge0BsaW5rY29kZSBFeHRlbnNpb25Db21tYW5kLmdldEV4dGVuc2lvbkZpZWxkc31cbiAqIEB0ZW1wbGF0ZSB7RXh0ZW5zaW9uVHlwZX0gRXh0VHlwZVxuICogQHR5cGVkZWYge0V4dE1ldGFkYXRhPEV4dFR5cGU+ICYgeyBwa2dOYW1lOiBzdHJpbmcsIHZlcnNpb246IHN0cmluZywgYXBwaXVtVmVyc2lvbjogc3RyaW5nIH0gJiBpbXBvcnQoJ2FwcGl1bS90eXBlcycpLkNvbW1vbkV4dE1ldGFkYXRhfSBFeHRlbnNpb25GaWVsZHNcbiAqL1xuXG4vKipcbiAqIEB0ZW1wbGF0ZSB7RXh0ZW5zaW9uVHlwZX0gRXh0VHlwZVxuICogQHR5cGVkZWYge0V4dFR5cGUgZXh0ZW5kcyBEcml2ZXJUeXBlID8gdHlwZW9mIGltcG9ydCgnLi4vY29uc3RhbnRzJykuS05PV05fRFJJVkVSUyA6IEV4dFR5cGUgZXh0ZW5kcyBQbHVnaW5UeXBlID8gdHlwZW9mIGltcG9ydCgnLi4vY29uc3RhbnRzJykuS05PV05fUExVR0lOUyA6IG5ldmVyfSBLbm93bkV4dGVuc2lvbnNcbiAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIExpc3RPcHRpb25zXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IHNob3dJbnN0YWxsZWQgLSB3aGV0aGVyIHNob3VsZCBzaG93IG9ubHkgaW5zdGFsbGVkIGV4dGVuc2lvbnNcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gc2hvd1VwZGF0ZXMgLSB3aGV0aGVyIHNob3VsZCBzaG93IGF2YWlsYWJsZSB1cGRhdGVzXG4gKi9cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBTUE7Ozs7QUFFQSxNQUFN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
606
+ exports.default = ExtensionCommand;
607
+ /**
608
+ * Options for the {@linkcode ExtensionCommand} constructor
609
+ * @template {ExtensionType} ExtType
610
+ * @typedef ExtensionCommandOptions
611
+ * @property {ExtensionConfig<ExtType>} config - the `DriverConfig` or `PluginConfig` instance used for this command
612
+ * @property {boolean} json - whether the output of this command should be JSON or text
613
+ */
614
+ /**
615
+ * Extra stuff about extensions; used indirectly by {@linkcode ExtensionCommand.list}.
616
+ *
617
+ * @typedef ExtensionMetadata
618
+ * @property {boolean} installed - If `true`, the extension is installed
619
+ * @property {string?} updateVersion - If the extension is installed, the version it can be updated to
620
+ * @property {string?} unsafeUpdateVersion - Same as above, but a major version bump
621
+ * @property {boolean} upToDate - If the extension is installed and the latest
622
+ * @property {string?} updateError - Update check error message (if present)
623
+ */
624
+ /**
625
+ * @typedef {import('@appium/types').ExtensionType} ExtensionType
626
+ * @typedef {import('@appium/types').DriverType} DriverType
627
+ * @typedef {import('@appium/types').PluginType} PluginType
628
+ */
629
+ /**
630
+ * @template {ExtensionType} ExtType
631
+ * @typedef {import('appium/types').ExtRecord<ExtType>} ExtRecord
632
+ */
633
+ /**
634
+ * @template {ExtensionType} ExtType
635
+ * @typedef {import('../extension/extension-config').ExtensionConfig<ExtType>} ExtensionConfig
636
+ */
637
+ /**
638
+ * @template {ExtensionType} ExtType
639
+ * @typedef {import('appium/types').ExtMetadata<ExtType>} ExtMetadata
640
+ */
641
+ /**
642
+ * @template {ExtensionType} ExtType
643
+ * @typedef {import('appium/types').ExtManifest<ExtType>} ExtManifest
644
+ */
645
+ /**
646
+ * @template {ExtensionType} ExtType
647
+ * @typedef {import('appium/types').ExtPackageJson<ExtType>} ExtPackageJson
648
+ */
649
+ /**
650
+ * @template {ExtensionType} ExtType
651
+ * @typedef {import('appium/types').ExtInstallReceipt<ExtType>} ExtInstallReceipt
652
+ */
653
+ /**
654
+ * Possible return value for {@linkcode ExtensionCommand.list}
655
+ * @typedef UninstalledExtensionListData
656
+ * @property {string} pkgName
657
+ * @property {false} installed
658
+ */
659
+ /**
660
+ * Possible return value for {@linkcode ExtensionCommand.list}
661
+ * @typedef {import('appium/types').InternalMetadata & ExtensionMetadata} InstalledExtensionListData
662
+ */
663
+ /**
664
+ * Return value of {@linkcode ExtensionCommand.list}.
665
+ * @typedef {Record<string,InstalledExtensionListData|UninstalledExtensionListData>} ExtensionListData
666
+ */
667
+ /**
668
+ * Options for {@linkcode ExtensionCommand._run}.
669
+ * @typedef RunOptions
670
+ * @property {string} installSpec - name of the extension to run a script from
671
+ * @property {string} scriptName - name of the script to run
672
+ * @property {string[]} [extraArgs] - arguments to pass to the script
673
+ */
674
+ /**
675
+ * Return value of {@linkcode ExtensionCommand._run}
676
+ *
677
+ * @typedef RunOutput
678
+ * @property {string} [error] - error message if script ran unsuccessfully, otherwise undefined
679
+ * @property {string[]} output - script output
680
+ */
681
+ /**
682
+ * Options for {@linkcode ExtensionCommand._update}.
683
+ * @typedef ExtensionUpdateOpts
684
+ * @property {string} installSpec - the name of the extension to update
685
+ * @property {boolean} unsafe - if true, will perform unsafe updates past major revision boundaries
686
+ */
687
+ /**
688
+ * Return value of {@linkcode ExtensionCommand._update}.
689
+ * @typedef ExtensionUpdateResult
690
+ * @property {Record<string,Error>} errors - map of ext names to error objects
691
+ * @property {Record<string,UpdateReport>} updates - map of ext names to {@linkcode UpdateReport}s
692
+ */
693
+ /**
694
+ * Part of result of {@linkcode ExtensionCommand._update}.
695
+ * @typedef UpdateReport
696
+ * @property {string} from - version the extension was updated from
697
+ * @property {string} to - version the extension was updated to
698
+ */
699
+ /**
700
+ * Options for {@linkcode ExtensionCommand._uninstall}.
701
+ * @typedef UninstallOpts
702
+ * @property {string} installSpec - the name or spec of an extension to uninstall
703
+ */
704
+ /**
705
+ * Used by {@linkcode ExtensionCommand.getPostInstallText}
706
+ * @typedef ExtensionArgs
707
+ * @property {string} extName - the name of an extension
708
+ * @property {object} extData - the data for an installed extension
709
+ */
710
+ /**
711
+ * Options for {@linkcode ExtensionCommand.installViaNpm}
712
+ * @typedef InstallViaNpmArgs
713
+ * @property {string} installSpec - the name or spec of an extension to install
714
+ * @property {string} pkgName - the NPM package name of the extension
715
+ * @property {import('appium/types').InstallType} installType - type of install
716
+ * @property {string} [pkgVer] - the specific version of the NPM package
717
+ */
718
+ /**
719
+ * Object returned by {@linkcode ExtensionCommand.checkForExtensionUpdate}
720
+ * @typedef PossibleUpdates
721
+ * @property {string} current - current version
722
+ * @property {string?} safeUpdate - version we can safely update to if it exists, or null
723
+ * @property {string?} unsafeUpdate - version we can unsafely update to if it exists, or null
724
+ */
725
+ /**
726
+ * Options for {@linkcode ExtensionCommand._install}
727
+ * @typedef InstallOpts
728
+ * @property {string} installSpec - the name or spec of an extension to install
729
+ * @property {InstallType} installType - how to install this extension. One of the INSTALL_TYPES
730
+ * @property {string} [packageName] - for git/github installs, the extension node package name
731
+ */
732
+ /**
733
+ * @template {ExtensionType} ExtType
734
+ * @typedef {ExtType extends DriverType ? typeof import('../constants').KNOWN_DRIVERS : ExtType extends PluginType ? typeof import('../constants').KNOWN_PLUGINS : never} KnownExtensions
735
+ */
736
+ /**
737
+ * @typedef ListOptions
738
+ * @property {boolean} showInstalled - whether should show only installed extensions
739
+ * @property {boolean} showUpdates - whether should show available updates
740
+ */
741
+ /**
742
+ * Opts for {@linkcode ExtensionCommand.getInstallationReceipt}
743
+ * @template {ExtensionType} ExtType
744
+ * @typedef GetInstallationReceiptOpts
745
+ * @property {string} installPath
746
+ * @property {string} installSpec
747
+ * @property {ExtPackageJson<ExtType>} pkg
748
+ * @property {InstallType} installType
749
+ */
750
+ /**
751
+ * @typedef {import('appium/types').InstallType} InstallType
752
+ */
753
+ //# sourceMappingURL=extension-command.js.map