@appium/base-driver 8.7.3 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/lib/basedriver/capabilities.d.ts +11 -163
- package/build/lib/basedriver/capabilities.d.ts.map +1 -1
- package/build/lib/basedriver/capabilities.js +354 -236
- package/build/lib/basedriver/capabilities.js.map +1 -1
- package/build/lib/basedriver/commands/event.d.ts +7 -6
- package/build/lib/basedriver/commands/event.d.ts.map +1 -1
- package/build/lib/basedriver/commands/event.js +55 -35
- package/build/lib/basedriver/commands/event.js.map +1 -1
- package/build/lib/basedriver/commands/execute.d.ts +7 -6
- package/build/lib/basedriver/commands/execute.d.ts.map +1 -1
- package/build/lib/basedriver/commands/execute.js +66 -58
- package/build/lib/basedriver/commands/execute.js.map +1 -1
- package/build/lib/basedriver/commands/find.d.ts +9 -7
- package/build/lib/basedriver/commands/find.d.ts.map +1 -1
- package/build/lib/basedriver/commands/find.js +102 -54
- package/build/lib/basedriver/commands/find.js.map +1 -1
- package/build/lib/basedriver/commands/index.d.ts +3 -7
- package/build/lib/basedriver/commands/index.d.ts.map +1 -1
- package/build/lib/basedriver/commands/index.js +30 -33
- package/build/lib/basedriver/commands/index.js.map +1 -1
- package/build/lib/basedriver/commands/log.d.ts +8 -9
- package/build/lib/basedriver/commands/log.d.ts.map +1 -1
- package/build/lib/basedriver/commands/log.js +54 -38
- package/build/lib/basedriver/commands/log.js.map +1 -1
- package/build/lib/basedriver/commands/session.d.ts +7 -6
- package/build/lib/basedriver/commands/session.d.ts.map +1 -1
- package/build/lib/basedriver/commands/session.js +46 -39
- package/build/lib/basedriver/commands/session.js.map +1 -1
- package/build/lib/basedriver/commands/settings.d.ts +7 -7
- package/build/lib/basedriver/commands/settings.d.ts.map +1 -1
- package/build/lib/basedriver/commands/settings.js +35 -28
- package/build/lib/basedriver/commands/settings.js.map +1 -1
- package/build/lib/basedriver/commands/timeout.d.ts +7 -5
- package/build/lib/basedriver/commands/timeout.d.ts.map +1 -1
- package/build/lib/basedriver/commands/timeout.js +144 -162
- package/build/lib/basedriver/commands/timeout.js.map +1 -1
- package/build/lib/basedriver/core.d.ts +6 -157
- package/build/lib/basedriver/core.d.ts.map +1 -1
- package/build/lib/basedriver/core.js +361 -230
- package/build/lib/basedriver/core.js.map +1 -1
- package/build/lib/basedriver/desired-caps.js +80 -110
- package/build/lib/basedriver/desired-caps.js.map +1 -1
- package/build/lib/basedriver/device-settings.js +57 -62
- package/build/lib/basedriver/device-settings.js.map +1 -1
- package/build/lib/basedriver/driver.d.ts +11 -262
- package/build/lib/basedriver/driver.d.ts.map +1 -1
- package/build/lib/basedriver/driver.js +362 -262
- package/build/lib/basedriver/driver.js.map +1 -1
- package/build/lib/basedriver/helpers.js +500 -495
- package/build/lib/basedriver/helpers.js.map +1 -1
- package/build/lib/basedriver/logger.d.ts +1 -1
- package/build/lib/basedriver/logger.d.ts.map +1 -1
- package/build/lib/basedriver/logger.js +5 -15
- package/build/lib/basedriver/logger.js.map +1 -1
- package/build/lib/constants.js +14 -14
- package/build/lib/constants.js.map +1 -1
- package/build/lib/express/crash.js +8 -15
- package/build/lib/express/crash.js.map +1 -1
- package/build/lib/express/express-logging.js +49 -59
- package/build/lib/express/express-logging.js.map +1 -1
- package/build/lib/express/idempotency.js +125 -177
- package/build/lib/express/idempotency.js.map +1 -1
- package/build/lib/express/logger.d.ts +1 -1
- package/build/lib/express/logger.d.ts.map +1 -1
- package/build/lib/express/logger.js +5 -15
- package/build/lib/express/logger.js.map +1 -1
- package/build/lib/express/middleware.js +82 -107
- package/build/lib/express/middleware.js.map +1 -1
- package/build/lib/express/server.d.ts +17 -5
- package/build/lib/express/server.d.ts.map +1 -1
- package/build/lib/express/server.js +259 -224
- package/build/lib/express/server.js.map +1 -1
- package/build/lib/express/static.js +64 -81
- package/build/lib/express/static.js.map +1 -1
- package/build/lib/express/websocket.js +115 -87
- package/build/lib/express/websocket.js.map +1 -1
- package/build/lib/helpers/capabilities.d.ts +1 -59
- package/build/lib/helpers/capabilities.d.ts.map +1 -1
- package/build/lib/helpers/capabilities.js +72 -69
- package/build/lib/helpers/capabilities.js.map +1 -1
- package/build/lib/index.js +64 -180
- package/build/lib/index.js.map +1 -1
- package/build/lib/jsonwp-proxy/protocol-converter.js +215 -227
- package/build/lib/jsonwp-proxy/protocol-converter.js.map +1 -1
- package/build/lib/jsonwp-proxy/proxy.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/proxy.js +355 -393
- package/build/lib/jsonwp-proxy/proxy.js.map +1 -1
- package/build/lib/jsonwp-status/status.js +119 -130
- package/build/lib/jsonwp-status/status.js.map +1 -1
- package/build/lib/protocol/errors.d.ts +135 -32
- package/build/lib/protocol/errors.d.ts.map +1 -1
- package/build/lib/protocol/errors.js +871 -919
- package/build/lib/protocol/errors.js.map +1 -1
- package/build/lib/protocol/helpers.js +37 -37
- package/build/lib/protocol/helpers.js.map +1 -1
- package/build/lib/protocol/index.js +22 -109
- package/build/lib/protocol/index.js.map +1 -1
- package/build/lib/protocol/protocol.js +394 -350
- package/build/lib/protocol/protocol.js.map +1 -1
- package/build/lib/protocol/routes.d.ts +1238 -4
- package/build/lib/protocol/routes.d.ts.map +1 -1
- package/build/lib/protocol/routes.js +964 -1327
- package/build/lib/protocol/routes.js.map +1 -1
- package/build/lib/protocol/validators.js +32 -39
- package/build/lib/protocol/validators.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/lib/basedriver/capabilities.js +80 -39
- package/lib/basedriver/commands/event.js +10 -5
- package/lib/basedriver/commands/execute.js +14 -9
- package/lib/basedriver/commands/find.js +18 -12
- package/lib/basedriver/commands/index.js +21 -16
- package/lib/basedriver/commands/log.js +24 -18
- package/lib/basedriver/commands/session.js +10 -5
- package/lib/basedriver/commands/settings.js +9 -6
- package/lib/basedriver/commands/timeout.js +10 -4
- package/lib/basedriver/core.js +2 -3
- package/lib/basedriver/driver.js +12 -16
- package/lib/express/server.js +6 -3
- package/lib/protocol/errors.js +155 -44
- package/lib/protocol/routes.js +11 -7
- package/package.json +14 -16
|
@@ -1,394 +1,438 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
});
|
|
6
|
-
exports.GET_STATUS_COMMAND = exports.DELETE_SESSION_COMMAND = exports.CREATE_SESSION_COMMAND = void 0;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
require("
|
|
15
|
-
|
|
16
|
-
var _lodash = _interopRequireDefault(require("lodash"));
|
|
17
|
-
|
|
18
|
-
var _support = require("@appium/support");
|
|
19
|
-
|
|
20
|
-
var _validators = require("./validators");
|
|
21
|
-
|
|
22
|
-
var _errors = require("./errors");
|
|
23
|
-
|
|
24
|
-
var _routes = require("./routes");
|
|
25
|
-
|
|
26
|
-
var _bluebird = _interopRequireDefault(require("bluebird"));
|
|
27
|
-
|
|
28
|
-
var _helpers = require("./helpers");
|
|
29
|
-
|
|
30
|
-
var _constants = require("../constants");
|
|
31
|
-
|
|
32
|
-
var _capabilities = require("../helpers/capabilities");
|
|
33
|
-
|
|
34
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
35
|
-
|
|
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.GET_STATUS_COMMAND = exports.DELETE_SESSION_COMMAND = exports.CREATE_SESSION_COMMAND = exports.determineProtocol = exports.driverShouldDoJwpProxy = exports.isSessionCommand = exports.routeConfiguringFunction = exports.makeArgs = exports.checkParams = void 0;
|
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
+
const support_1 = require("@appium/support");
|
|
9
|
+
const validators_1 = require("./validators");
|
|
10
|
+
const errors_1 = require("./errors");
|
|
11
|
+
const routes_1 = require("./routes");
|
|
12
|
+
const bluebird_1 = __importDefault(require("bluebird"));
|
|
13
|
+
const helpers_1 = require("./helpers");
|
|
14
|
+
const constants_1 = require("../constants");
|
|
15
|
+
const capabilities_1 = require("../helpers/capabilities");
|
|
36
16
|
const CREATE_SESSION_COMMAND = 'createSession';
|
|
37
17
|
exports.CREATE_SESSION_COMMAND = CREATE_SESSION_COMMAND;
|
|
38
18
|
const DELETE_SESSION_COMMAND = 'deleteSession';
|
|
39
19
|
exports.DELETE_SESSION_COMMAND = DELETE_SESSION_COMMAND;
|
|
40
20
|
const GET_STATUS_COMMAND = 'getStatus';
|
|
41
21
|
exports.GET_STATUS_COMMAND = GET_STATUS_COMMAND;
|
|
42
|
-
|
|
43
22
|
function determineProtocol(createSessionArgs) {
|
|
44
|
-
|
|
23
|
+
return lodash_1.default.some(createSessionArgs, capabilities_1.isW3cCaps) ? constants_1.PROTOCOLS.W3C : constants_1.PROTOCOLS.MJSONWP;
|
|
45
24
|
}
|
|
46
|
-
|
|
25
|
+
exports.determineProtocol = determineProtocol;
|
|
47
26
|
function extractProtocol(driver, sessionId = null) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
27
|
+
const dstDriver = lodash_1.default.isFunction(driver.driverForSession)
|
|
28
|
+
? driver.driverForSession(sessionId)
|
|
29
|
+
: driver;
|
|
30
|
+
if (dstDriver === driver) {
|
|
31
|
+
// Shortcircuit if the driver instance is not an umbrella driver
|
|
32
|
+
// or it is Fake driver instance, where `driver.driverForSession`
|
|
33
|
+
// always returns self instance
|
|
34
|
+
return driver.protocol;
|
|
35
|
+
}
|
|
36
|
+
// Extract the protocol for the current session if the given driver is the umbrella one
|
|
37
|
+
return dstDriver?.protocol ?? constants_1.PROTOCOLS.W3C;
|
|
55
38
|
}
|
|
56
|
-
|
|
57
39
|
function isSessionCommand(command) {
|
|
58
|
-
|
|
40
|
+
return !lodash_1.default.includes(routes_1.NO_SESSION_ID_COMMANDS, command);
|
|
59
41
|
}
|
|
60
|
-
|
|
42
|
+
exports.isSessionCommand = isSessionCommand;
|
|
43
|
+
/**
|
|
44
|
+
*
|
|
45
|
+
* @param {import('@appium/types').ExternalDriver} driver
|
|
46
|
+
* @param {string?} [sessionId]
|
|
47
|
+
* @returns {import('@appium/types').AppiumLogger}
|
|
48
|
+
*/
|
|
61
49
|
function getLogger(driver, sessionId = null) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return _support.logger.getLogger(logPrefix);
|
|
50
|
+
const dstDriver = sessionId && lodash_1.default.isFunction(driver.driverForSession)
|
|
51
|
+
? driver.driverForSession(sessionId) ?? driver
|
|
52
|
+
: driver;
|
|
53
|
+
if (lodash_1.default.isFunction(dstDriver.log?.info)) {
|
|
54
|
+
return dstDriver.log;
|
|
55
|
+
}
|
|
56
|
+
let logPrefix = dstDriver.constructor
|
|
57
|
+
? `${dstDriver.constructor.name}@${support_1.node.getObjectId(dstDriver).substring(0, 8)}`
|
|
58
|
+
: 'AppiumDriver';
|
|
59
|
+
if (sessionId) {
|
|
60
|
+
logPrefix += ` (${sessionId.substring(0, 8)})`;
|
|
61
|
+
}
|
|
62
|
+
return support_1.logger.getLogger(logPrefix);
|
|
77
63
|
}
|
|
78
|
-
|
|
79
64
|
function wrapParams(paramSets, jsonObj) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
65
|
+
/* There are commands like performTouch which take a single parameter (primitive type or array).
|
|
66
|
+
* Some drivers choose to pass this parameter as a value (eg. [action1, action2...]) while others to
|
|
67
|
+
* wrap it within an object(eg' {gesture: [action1, action2...]}), which makes it hard to validate.
|
|
68
|
+
* The wrap option in the spec enforce wrapping before validation, so that all params are wrapped at
|
|
69
|
+
* the time they are validated and later passed to the commands.
|
|
70
|
+
*/
|
|
71
|
+
let res = jsonObj;
|
|
72
|
+
if (lodash_1.default.isArray(jsonObj) || !lodash_1.default.isObject(jsonObj)) {
|
|
73
|
+
res = {};
|
|
74
|
+
res[paramSets.wrap] = jsonObj;
|
|
75
|
+
}
|
|
76
|
+
return res;
|
|
88
77
|
}
|
|
89
|
-
|
|
90
78
|
function unwrapParams(paramSets, jsonObj) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
79
|
+
/* There are commands like setNetworkConnection which send parameters wrapped inside a key such as
|
|
80
|
+
* "parameters". This function unwraps them (eg. {"parameters": {"type": 1}} becomes {"type": 1}).
|
|
81
|
+
*/
|
|
82
|
+
let res = jsonObj;
|
|
83
|
+
if (lodash_1.default.isObject(jsonObj)) {
|
|
84
|
+
// some clients, like ruby, don't wrap
|
|
85
|
+
if (jsonObj[paramSets.unwrap]) {
|
|
86
|
+
res = jsonObj[paramSets.unwrap];
|
|
87
|
+
}
|
|
96
88
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return res;
|
|
89
|
+
return res;
|
|
100
90
|
}
|
|
101
|
-
|
|
102
91
|
function checkParams(paramSets, jsonObj, protocol) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
92
|
+
let requiredParams = [];
|
|
93
|
+
let optionalParams = [];
|
|
94
|
+
let receivedParams = lodash_1.default.keys(jsonObj);
|
|
95
|
+
if (paramSets) {
|
|
96
|
+
if (paramSets.required) {
|
|
97
|
+
// we might have an array of parameters,
|
|
98
|
+
// or an array of arrays of parameters, so standardize
|
|
99
|
+
if (!lodash_1.default.isArray(lodash_1.default.first(paramSets.required))) {
|
|
100
|
+
requiredParams = [paramSets.required];
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
requiredParams = paramSets.required;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// optional parameters are just an array
|
|
107
|
+
if (paramSets.optional) {
|
|
108
|
+
optionalParams = paramSets.optional;
|
|
109
|
+
}
|
|
110
|
+
// If a function was provided as the 'validate' key, it will here be called with
|
|
111
|
+
// jsonObj as the param. If it returns something falsy, verification will be
|
|
112
|
+
// considered to have passed. If it returns something else, that will be the
|
|
113
|
+
// argument to an error which is thrown to the user
|
|
114
|
+
if (paramSets.validate) {
|
|
115
|
+
let message = paramSets.validate(jsonObj, protocol);
|
|
116
|
+
if (message) {
|
|
117
|
+
throw new errors_1.errors.BadParametersError(message, jsonObj);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
115
120
|
}
|
|
116
|
-
|
|
117
|
-
if (
|
|
118
|
-
|
|
121
|
+
// if we have no required parameters, all is well
|
|
122
|
+
if (requiredParams.length === 0) {
|
|
123
|
+
return;
|
|
119
124
|
}
|
|
120
|
-
|
|
121
|
-
if (
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (message) {
|
|
125
|
-
throw new _errors.errors.BadParametersError(message, jsonObj);
|
|
126
|
-
}
|
|
125
|
+
// some clients pass in the session id in the params
|
|
126
|
+
if (optionalParams.indexOf('sessionId') === -1) {
|
|
127
|
+
optionalParams.push('sessionId');
|
|
127
128
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (optionalParams.indexOf('sessionId') === -1) {
|
|
135
|
-
optionalParams.push('sessionId');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (optionalParams.indexOf('id') === -1) {
|
|
139
|
-
optionalParams.push('id');
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
for (let params of requiredParams) {
|
|
143
|
-
if (_lodash.default.difference(receivedParams, params, optionalParams).length === 0 && _lodash.default.difference(params, receivedParams).length === 0) {
|
|
144
|
-
return;
|
|
129
|
+
// some clients pass in an element id in the params
|
|
130
|
+
if (optionalParams.indexOf('id') === -1) {
|
|
131
|
+
optionalParams.push('id');
|
|
145
132
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
133
|
+
// go through the required parameters and check against our arguments
|
|
134
|
+
for (let params of requiredParams) {
|
|
135
|
+
if (lodash_1.default.difference(receivedParams, params, optionalParams).length === 0 &&
|
|
136
|
+
lodash_1.default.difference(params, receivedParams).length === 0) {
|
|
137
|
+
// we have a set of parameters that is correct
|
|
138
|
+
// so short-circuit
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
throw new errors_1.errors.BadParametersError(paramSets, receivedParams);
|
|
149
143
|
}
|
|
150
|
-
|
|
144
|
+
exports.checkParams = checkParams;
|
|
145
|
+
/*
|
|
146
|
+
* This method takes 3 pieces of data: request parameters ('requestParams'),
|
|
147
|
+
* a request JSON body ('jsonObj'), and 'payloadParams', which is the section
|
|
148
|
+
* from the route definition for a particular endpoint which has instructions
|
|
149
|
+
* on handling parameters. This method returns an array of arguments which will
|
|
150
|
+
* be applied to a command.
|
|
151
|
+
*/
|
|
151
152
|
function makeArgs(requestParams, jsonObj, payloadParams, protocol) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
153
|
+
// We want to pass the "url" parameters to the commands in reverse order
|
|
154
|
+
// since the command will sometimes want to ignore, say, the sessionId.
|
|
155
|
+
// This has the effect of putting sessionId last, which means in JS we can
|
|
156
|
+
// omit it from the function signature if we're not going to use it.
|
|
157
|
+
let urlParams = lodash_1.default.keys(requestParams).reverse();
|
|
158
|
+
// In the simple case, the required parameters are a basic array in
|
|
159
|
+
// payloadParams.required, so start there. It's possible that there are
|
|
160
|
+
// multiple optional sets of required params, though, so handle that case
|
|
161
|
+
// too.
|
|
162
|
+
let requiredParams = payloadParams.required;
|
|
163
|
+
if (lodash_1.default.isArray(lodash_1.default.first(payloadParams.required))) {
|
|
164
|
+
// If there are optional sets of required params, then we will have an
|
|
165
|
+
// array of arrays in payloadParams.required, so loop through each set and
|
|
166
|
+
// pick the one that matches which JSON params were actually sent. We've
|
|
167
|
+
// already been through validation so we're guaranteed to find a match.
|
|
168
|
+
let keys = lodash_1.default.keys(jsonObj);
|
|
169
|
+
for (let params of payloadParams.required) {
|
|
170
|
+
if (lodash_1.default.without(params, ...keys).length === 0) {
|
|
171
|
+
requiredParams = params;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Now we construct our list of arguments which will be passed to the command
|
|
177
|
+
let args;
|
|
178
|
+
if (lodash_1.default.isFunction(payloadParams.makeArgs)) {
|
|
179
|
+
// In the route spec, a particular route might define a 'makeArgs' function
|
|
180
|
+
// if it wants full control over how to turn JSON parameters into command
|
|
181
|
+
// arguments. So we pass it the JSON parameters and it returns an array
|
|
182
|
+
// which will be applied to the handling command. For example if it returns
|
|
183
|
+
// [1, 2, 3], we will call `command(1, 2, 3, ...)` (url params are separate
|
|
184
|
+
// from JSON params and get concatenated below).
|
|
185
|
+
args = payloadParams.makeArgs(jsonObj, protocol);
|
|
164
186
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
args = _lodash.default.flatten(requiredParams).map(p => jsonObj[p]);
|
|
173
|
-
|
|
174
|
-
if (payloadParams.optional) {
|
|
175
|
-
args = args.concat(_lodash.default.flatten(payloadParams.optional).map(p => jsonObj[p]));
|
|
187
|
+
else {
|
|
188
|
+
// Otherwise, collect all the required and optional params and flatten them
|
|
189
|
+
// into an argument array
|
|
190
|
+
args = lodash_1.default.flatten(requiredParams).map((p) => jsonObj[p]);
|
|
191
|
+
if (payloadParams.optional) {
|
|
192
|
+
args = args.concat(lodash_1.default.flatten(payloadParams.optional).map((p) => jsonObj[p]));
|
|
193
|
+
}
|
|
176
194
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
195
|
+
// Finally, get our url params (session id, element id, etc...) on the end of
|
|
196
|
+
// the list
|
|
197
|
+
args = args.concat(urlParams.map((u) => requestParams[u]));
|
|
198
|
+
return args;
|
|
181
199
|
}
|
|
182
|
-
|
|
200
|
+
exports.makeArgs = makeArgs;
|
|
201
|
+
/**
|
|
202
|
+
*
|
|
203
|
+
* @param {import('@appium/types').Core} driver
|
|
204
|
+
* @returns {import('../express/server').RouteConfiguringFunction}
|
|
205
|
+
*/
|
|
183
206
|
function routeConfiguringFunction(driver) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (!(driver.executeCommand || driver.execute)) {
|
|
189
|
-
throw new Error('Drivers must implement `executeCommand` or `execute` method');
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return function addRoutes(app, {
|
|
193
|
-
basePath = _constants.DEFAULT_BASE_PATH,
|
|
194
|
-
extraMethodMap = {}
|
|
195
|
-
} = {}) {
|
|
196
|
-
driver.basePath = basePath;
|
|
197
|
-
const allMethods = { ..._routes.METHOD_MAP,
|
|
198
|
-
...extraMethodMap
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
for (const [path, methods] of _lodash.default.toPairs(allMethods)) {
|
|
202
|
-
for (const [method, spec] of _lodash.default.toPairs(methods)) {
|
|
203
|
-
buildHandler(app, method, `${basePath}${path}`, spec, driver, isSessionCommand(spec.command));
|
|
204
|
-
}
|
|
207
|
+
if (!driver.sessionExists) {
|
|
208
|
+
throw new Error('Drivers must implement `sessionExists` property');
|
|
205
209
|
}
|
|
206
|
-
|
|
210
|
+
// "execute" isn't defined anywhere
|
|
211
|
+
// @ts-expect-error
|
|
212
|
+
if (!(driver.executeCommand || driver.execute)) {
|
|
213
|
+
throw new Error('Drivers must implement `executeCommand` or `execute` method');
|
|
214
|
+
}
|
|
215
|
+
// return a function which will add all the routes to the driver. Here extraMethods might be
|
|
216
|
+
// passed in as defined by Appium plugins, so we need to add those to the default list
|
|
217
|
+
return function addRoutes(app, { basePath = constants_1.DEFAULT_BASE_PATH, extraMethodMap = {} } = {}) {
|
|
218
|
+
// store basePath on the driver instance so it can use it if necessary
|
|
219
|
+
// for example in determining proxy avoidance
|
|
220
|
+
driver.basePath = basePath;
|
|
221
|
+
const allMethods = { ...routes_1.METHOD_MAP, ...extraMethodMap };
|
|
222
|
+
for (const [path, methods] of lodash_1.default.toPairs(allMethods)) {
|
|
223
|
+
for (const [method, spec] of lodash_1.default.toPairs(methods)) {
|
|
224
|
+
// set up the express route handler
|
|
225
|
+
buildHandler(app, method, `${basePath}${path}`, spec, driver, isSessionCommand(spec.command));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
};
|
|
207
229
|
}
|
|
208
|
-
|
|
230
|
+
exports.routeConfiguringFunction = routeConfiguringFunction;
|
|
209
231
|
function buildHandler(app, method, path, spec, driver, isSessCmd) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
232
|
+
let asyncHandler = async (req, res) => {
|
|
233
|
+
let jsonObj = req.body;
|
|
234
|
+
let httpResBody = {};
|
|
235
|
+
let httpStatus = 200;
|
|
236
|
+
let newSessionId;
|
|
237
|
+
let currentProtocol = extractProtocol(driver, req.params.sessionId);
|
|
238
|
+
try {
|
|
239
|
+
// if this is a session command but we don't have a session,
|
|
240
|
+
// error out early (especially before proxying)
|
|
241
|
+
if (isSessCmd && !driver.sessionExists(req.params.sessionId)) {
|
|
242
|
+
throw new errors_1.errors.NoSuchDriverError();
|
|
243
|
+
}
|
|
244
|
+
// if the driver is currently proxying commands to another JSONWP server, bypass all our
|
|
245
|
+
// checks and assume the upstream server knows what it's doing. But keep this in the
|
|
246
|
+
// try/catch block so if proxying itself fails, we give a message to the client. Of course we
|
|
247
|
+
// only want to do these when we have a session command; the Appium driver must be
|
|
248
|
+
// responsible for start/stop session, etc... We also allow the command spec to declare that
|
|
249
|
+
// this command should never be proxied (which is useful for plugin developers who add
|
|
250
|
+
// commands and generally would not want that command to be proxied instead of handled by the
|
|
251
|
+
// plugin)
|
|
252
|
+
let didPluginOverrideProxy = false;
|
|
253
|
+
if (isSessCmd && !spec.neverProxy && driverShouldDoJwpProxy(driver, req, spec.command)) {
|
|
254
|
+
if (!driver.pluginsToHandleCmd ||
|
|
255
|
+
driver.pluginsToHandleCmd(spec.command, req.params.sessionId).length === 0) {
|
|
256
|
+
await doJwpProxy(driver, req, res);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
getLogger(driver, req.params.sessionId).debug(`Would have proxied ` +
|
|
260
|
+
`command directly, but a plugin exists which might require its value, so will let ` +
|
|
261
|
+
`its value be collected internally and made part of plugin chain`);
|
|
262
|
+
didPluginOverrideProxy = true;
|
|
263
|
+
}
|
|
264
|
+
// if a command is not in our method map, it's because we
|
|
265
|
+
// have no plans to ever implement it
|
|
266
|
+
if (!spec.command) {
|
|
267
|
+
throw new errors_1.errors.NotImplementedError();
|
|
268
|
+
}
|
|
269
|
+
// wrap params if necessary
|
|
270
|
+
if (spec.payloadParams && spec.payloadParams.wrap) {
|
|
271
|
+
jsonObj = wrapParams(spec.payloadParams, jsonObj);
|
|
272
|
+
}
|
|
273
|
+
// unwrap params if necessary
|
|
274
|
+
if (spec.payloadParams && spec.payloadParams.unwrap) {
|
|
275
|
+
jsonObj = unwrapParams(spec.payloadParams, jsonObj);
|
|
276
|
+
}
|
|
277
|
+
if (spec.command === CREATE_SESSION_COMMAND) {
|
|
278
|
+
// try to determine protocol by session creation args, so we can throw a
|
|
279
|
+
// properly formatted error if arguments validation fails
|
|
280
|
+
currentProtocol = determineProtocol(makeArgs(req.params, jsonObj, spec.payloadParams || {}));
|
|
281
|
+
}
|
|
282
|
+
// ensure that the json payload conforms to the spec
|
|
283
|
+
checkParams(spec.payloadParams, jsonObj, currentProtocol);
|
|
284
|
+
// turn the command and json payload into an argument list for
|
|
285
|
+
// the driver methods
|
|
286
|
+
let args = makeArgs(req.params, jsonObj, spec.payloadParams || {}, currentProtocol);
|
|
287
|
+
let driverRes;
|
|
288
|
+
// validate command args according to MJSONWP
|
|
289
|
+
if (validators_1.validators[spec.command]) {
|
|
290
|
+
validators_1.validators[spec.command](...args);
|
|
291
|
+
}
|
|
292
|
+
// run the driver command wrapped inside the argument validators
|
|
293
|
+
getLogger(driver, req.params.sessionId).debug(`Calling ` +
|
|
294
|
+
`${driver.constructor.name}.${spec.command}() with args: ` +
|
|
295
|
+
lodash_1.default.truncate(JSON.stringify(args), { length: constants_1.MAX_LOG_BODY_LENGTH }));
|
|
296
|
+
if (didPluginOverrideProxy) {
|
|
297
|
+
// TODO for now we add this information on the args list, but that's mixing purposes here.
|
|
298
|
+
// We really should add another 'options' parameter to 'executeCommand', but this would be
|
|
299
|
+
// a breaking change for all drivers so would need to be handled carefully.
|
|
300
|
+
args.push({ reqForProxy: req });
|
|
301
|
+
}
|
|
302
|
+
driverRes = await driver.executeCommand(spec.command, ...args);
|
|
303
|
+
// Get the protocol after executeCommand
|
|
304
|
+
currentProtocol = extractProtocol(driver, req.params.sessionId) || currentProtocol;
|
|
305
|
+
// If `executeCommand` was overridden and the method returns an object
|
|
306
|
+
// with a protocol and value/error property, re-assign the protocol
|
|
307
|
+
if (lodash_1.default.isPlainObject(driverRes) && lodash_1.default.has(driverRes, 'protocol')) {
|
|
308
|
+
currentProtocol = driverRes.protocol || currentProtocol;
|
|
309
|
+
if (driverRes.error) {
|
|
310
|
+
throw driverRes.error;
|
|
311
|
+
}
|
|
312
|
+
driverRes = driverRes.value;
|
|
313
|
+
}
|
|
314
|
+
// unpack createSession response
|
|
315
|
+
if (spec.command === CREATE_SESSION_COMMAND) {
|
|
316
|
+
newSessionId = driverRes[0];
|
|
317
|
+
getLogger(driver, newSessionId).debug(`Cached the protocol value '${currentProtocol}' for the new session ${newSessionId}`);
|
|
318
|
+
if (currentProtocol === constants_1.PROTOCOLS.MJSONWP) {
|
|
319
|
+
driverRes = driverRes[1];
|
|
320
|
+
}
|
|
321
|
+
else if (currentProtocol === constants_1.PROTOCOLS.W3C) {
|
|
322
|
+
driverRes = {
|
|
323
|
+
capabilities: driverRes[1],
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
driverRes = (0, helpers_1.formatResponseValue)(driverRes);
|
|
328
|
+
// delete should not return anything even if successful
|
|
329
|
+
if (spec.command === DELETE_SESSION_COMMAND) {
|
|
330
|
+
getLogger(driver, req.params.sessionId).debug(`Received response: ${lodash_1.default.truncate(JSON.stringify(driverRes), {
|
|
331
|
+
length: constants_1.MAX_LOG_BODY_LENGTH,
|
|
332
|
+
})}`);
|
|
333
|
+
getLogger(driver, req.params.sessionId).debug('But deleting session, so not returning');
|
|
334
|
+
driverRes = null;
|
|
335
|
+
}
|
|
336
|
+
// if the status is not 0, throw the appropriate error for status code.
|
|
337
|
+
if (support_1.util.hasValue(driverRes)) {
|
|
338
|
+
if (support_1.util.hasValue(driverRes.status) &&
|
|
339
|
+
!isNaN(driverRes.status) &&
|
|
340
|
+
parseInt(driverRes.status, 10) !== 0) {
|
|
341
|
+
throw (0, errors_1.errorFromMJSONWPStatusCode)(driverRes.status, driverRes.value);
|
|
342
|
+
}
|
|
343
|
+
else if (lodash_1.default.isPlainObject(driverRes.value) && driverRes.value.error) {
|
|
344
|
+
throw (0, errors_1.errorFromW3CJsonCode)(driverRes.value.error, driverRes.value.message, driverRes.value.stacktrace);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
httpResBody.value = driverRes;
|
|
348
|
+
getLogger(driver, req.params.sessionId || newSessionId).debug(`Responding ` +
|
|
349
|
+
`to client with driver.${spec.command}() result: ${lodash_1.default.truncate(JSON.stringify(driverRes), {
|
|
350
|
+
length: constants_1.MAX_LOG_BODY_LENGTH,
|
|
351
|
+
})}`);
|
|
228
352
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
checkParams(spec.payloadParams, jsonObj, currentProtocol);
|
|
251
|
-
let args = makeArgs(req.params, jsonObj, spec.payloadParams || {}, currentProtocol);
|
|
252
|
-
let driverRes;
|
|
253
|
-
|
|
254
|
-
if (_validators.validators[spec.command]) {
|
|
255
|
-
_validators.validators[spec.command](...args);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
getLogger(driver, req.params.sessionId).debug(`Calling ` + `${driver.constructor.name}.${spec.command}() with args: ` + _lodash.default.truncate(JSON.stringify(args), {
|
|
259
|
-
length: _constants.MAX_LOG_BODY_LENGTH
|
|
260
|
-
}));
|
|
261
|
-
|
|
262
|
-
if (didPluginOverrideProxy) {
|
|
263
|
-
args.push({
|
|
264
|
-
reqForProxy: req
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
driverRes = await driver.executeCommand(spec.command, ...args);
|
|
269
|
-
currentProtocol = extractProtocol(driver, req.params.sessionId) || currentProtocol;
|
|
270
|
-
|
|
271
|
-
if (_lodash.default.isPlainObject(driverRes) && _lodash.default.has(driverRes, 'protocol')) {
|
|
272
|
-
currentProtocol = driverRes.protocol || currentProtocol;
|
|
273
|
-
|
|
274
|
-
if (driverRes.error) {
|
|
275
|
-
throw driverRes.error;
|
|
353
|
+
catch (err) {
|
|
354
|
+
// if anything goes wrong, figure out what our response should be
|
|
355
|
+
// based on the type of error that we encountered
|
|
356
|
+
let actualErr = err;
|
|
357
|
+
currentProtocol =
|
|
358
|
+
currentProtocol || extractProtocol(driver, req.params.sessionId || newSessionId);
|
|
359
|
+
let errMsg = err.stacktrace || err.stack;
|
|
360
|
+
if (!lodash_1.default.includes(errMsg, err.message)) {
|
|
361
|
+
// if the message has more information, add it. but often the message
|
|
362
|
+
// is the first part of the stack trace
|
|
363
|
+
errMsg = `${err.message}${errMsg ? '\n' + errMsg : ''}`;
|
|
364
|
+
}
|
|
365
|
+
if ((0, errors_1.isErrorType)(err, errors_1.errors.ProxyRequestError)) {
|
|
366
|
+
actualErr = err.getActualError();
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
getLogger(driver, req.params.sessionId || newSessionId).debug(`Encountered internal error running command: ${errMsg}`);
|
|
370
|
+
}
|
|
371
|
+
[httpStatus, httpResBody] = (0, errors_1.getResponseForW3CError)(actualErr);
|
|
276
372
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if (spec.command === CREATE_SESSION_COMMAND) {
|
|
282
|
-
newSessionId = driverRes[0];
|
|
283
|
-
getLogger(driver, newSessionId).debug(`Cached the protocol value '${currentProtocol}' for the new session ${newSessionId}`);
|
|
284
|
-
|
|
285
|
-
if (currentProtocol === _constants.PROTOCOLS.MJSONWP) {
|
|
286
|
-
driverRes = driverRes[1];
|
|
287
|
-
} else if (currentProtocol === _constants.PROTOCOLS.W3C) {
|
|
288
|
-
driverRes = {
|
|
289
|
-
capabilities: driverRes[1]
|
|
290
|
-
};
|
|
373
|
+
// decode the response, which is either a string or json
|
|
374
|
+
if (lodash_1.default.isString(httpResBody)) {
|
|
375
|
+
res.status(httpStatus).send(httpResBody);
|
|
291
376
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
377
|
+
else {
|
|
378
|
+
if (newSessionId) {
|
|
379
|
+
if (currentProtocol === constants_1.PROTOCOLS.W3C) {
|
|
380
|
+
httpResBody.value.sessionId = newSessionId;
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
httpResBody.sessionId = newSessionId;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
httpResBody.sessionId = req.params.sessionId || null;
|
|
388
|
+
}
|
|
389
|
+
// Don't include sessionId in W3C responses
|
|
390
|
+
if (currentProtocol === constants_1.PROTOCOLS.W3C) {
|
|
391
|
+
delete httpResBody.sessionId;
|
|
392
|
+
}
|
|
393
|
+
httpResBody = (0, helpers_1.formatStatus)(httpResBody);
|
|
394
|
+
res.status(httpStatus).json(httpResBody);
|
|
309
395
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
})}`);
|
|
316
|
-
} catch (err) {
|
|
317
|
-
let actualErr = err;
|
|
318
|
-
currentProtocol = currentProtocol || extractProtocol(driver, req.params.sessionId || newSessionId);
|
|
319
|
-
let errMsg = err.stacktrace || err.stack;
|
|
320
|
-
|
|
321
|
-
if (!_lodash.default.includes(errMsg, err.message)) {
|
|
322
|
-
errMsg = `${err.message}${errMsg ? '\n' + errMsg : ''}`;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if ((0, _errors.isErrorType)(err, _errors.errors.ProxyRequestError)) {
|
|
326
|
-
actualErr = err.getActualError();
|
|
327
|
-
} else {
|
|
328
|
-
getLogger(driver, req.params.sessionId || newSessionId).debug(`Encountered internal error running command: ${errMsg}`);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
[httpStatus, httpResBody] = (0, _errors.getResponseForW3CError)(actualErr);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
if (_lodash.default.isString(httpResBody)) {
|
|
335
|
-
res.status(httpStatus).send(httpResBody);
|
|
336
|
-
} else {
|
|
337
|
-
if (newSessionId) {
|
|
338
|
-
if (currentProtocol === _constants.PROTOCOLS.W3C) {
|
|
339
|
-
httpResBody.value.sessionId = newSessionId;
|
|
340
|
-
} else {
|
|
341
|
-
httpResBody.sessionId = newSessionId;
|
|
342
|
-
}
|
|
343
|
-
} else {
|
|
344
|
-
httpResBody.sessionId = req.params.sessionId || null;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
if (currentProtocol === _constants.PROTOCOLS.W3C) {
|
|
348
|
-
delete httpResBody.sessionId;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
httpResBody = (0, _helpers.formatStatus)(httpResBody);
|
|
352
|
-
res.status(httpStatus).json(httpResBody);
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
app[method.toLowerCase()](path, (req, res) => {
|
|
357
|
-
_bluebird.default.resolve(asyncHandler(req, res)).done();
|
|
358
|
-
});
|
|
396
|
+
};
|
|
397
|
+
// add the method to the app
|
|
398
|
+
app[method.toLowerCase()](path, (req, res) => {
|
|
399
|
+
bluebird_1.default.resolve(asyncHandler(req, res)).done();
|
|
400
|
+
});
|
|
359
401
|
}
|
|
360
|
-
|
|
361
402
|
function driverShouldDoJwpProxy(driver, req, command) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
403
|
+
// drivers need to explicitly say when the proxy is active
|
|
404
|
+
if (!driver.proxyActive(req.params.sessionId)) {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
// we should never proxy deleteSession because we need to give the containing
|
|
408
|
+
// driver an opportunity to clean itself up
|
|
409
|
+
if (command === DELETE_SESSION_COMMAND) {
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
// validate avoidance schema, and say we shouldn't proxy if anything in the
|
|
413
|
+
// avoid list matches our req
|
|
414
|
+
if (driver.proxyRouteIsAvoided(req.params.sessionId, req.method, req.originalUrl, req.body)) {
|
|
415
|
+
return false;
|
|
416
|
+
}
|
|
417
|
+
return true;
|
|
375
418
|
}
|
|
376
|
-
|
|
419
|
+
exports.driverShouldDoJwpProxy = driverShouldDoJwpProxy;
|
|
377
420
|
async function doJwpProxy(driver, req, res) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
421
|
+
getLogger(driver, req.params.sessionId).info('Driver proxy active, passing request on via HTTP proxy');
|
|
422
|
+
// check that the inner driver has a proxy function
|
|
423
|
+
if (!driver.canProxy(req.params.sessionId)) {
|
|
424
|
+
throw new Error('Trying to proxy to a server but the driver is unable to proxy');
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
await driver.executeCommand('proxyReqRes', req, res, req.params.sessionId);
|
|
428
|
+
}
|
|
429
|
+
catch (err) {
|
|
430
|
+
if ((0, errors_1.isErrorType)(err, errors_1.errors.ProxyRequestError)) {
|
|
431
|
+
throw err;
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
throw new Error(`Could not proxy. Proxy error: ${err.message}`);
|
|
435
|
+
}
|
|
391
436
|
}
|
|
392
|
-
}
|
|
393
437
|
}
|
|
394
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJDUkVBVEVfU0VTU0lPTl9DT01NQU5EIiwiREVMRVRFX1NFU1NJT05fQ09NTUFORCIsIkdFVF9TVEFUVVNfQ09NTUFORCIsImRldGVybWluZVByb3RvY29sIiwiY3JlYXRlU2Vzc2lvbkFyZ3MiLCJfIiwic29tZSIsImlzVzNjQ2FwcyIsIlBST1RPQ09MUyIsIlczQyIsIk1KU09OV1AiLCJleHRyYWN0UHJvdG9jb2wiLCJkcml2ZXIiLCJzZXNzaW9uSWQiLCJkc3REcml2ZXIiLCJpc0Z1bmN0aW9uIiwiZHJpdmVyRm9yU2Vzc2lvbiIsInByb3RvY29sIiwiaXNTZXNzaW9uQ29tbWFuZCIsImNvbW1hbmQiLCJpbmNsdWRlcyIsIk5PX1NFU1NJT05fSURfQ09NTUFORFMiLCJnZXRMb2dnZXIiLCJsb2ciLCJpbmZvIiwibG9nUHJlZml4IiwiY29uc3RydWN0b3IiLCJuYW1lIiwibm9kZSIsImdldE9iamVjdElkIiwic3Vic3RyaW5nIiwibG9nZ2VyIiwid3JhcFBhcmFtcyIsInBhcmFtU2V0cyIsImpzb25PYmoiLCJyZXMiLCJpc0FycmF5IiwiaXNPYmplY3QiLCJ3cmFwIiwidW53cmFwUGFyYW1zIiwidW53cmFwIiwiY2hlY2tQYXJhbXMiLCJyZXF1aXJlZFBhcmFtcyIsIm9wdGlvbmFsUGFyYW1zIiwicmVjZWl2ZWRQYXJhbXMiLCJrZXlzIiwicmVxdWlyZWQiLCJmaXJzdCIsIm9wdGlvbmFsIiwidmFsaWRhdGUiLCJtZXNzYWdlIiwiZXJyb3JzIiwiQmFkUGFyYW1ldGVyc0Vycm9yIiwibGVuZ3RoIiwiaW5kZXhPZiIsInB1c2giLCJwYXJhbXMiLCJkaWZmZXJlbmNlIiwibWFrZUFyZ3MiLCJyZXF1ZXN0UGFyYW1zIiwicGF5bG9hZFBhcmFtcyIsInVybFBhcmFtcyIsInJldmVyc2UiLCJ3aXRob3V0IiwiYXJncyIsImZsYXR0ZW4iLCJtYXAiLCJwIiwiY29uY2F0IiwidSIsInJvdXRlQ29uZmlndXJpbmdGdW5jdGlvbiIsInNlc3Npb25FeGlzdHMiLCJFcnJvciIsImV4ZWN1dGVDb21tYW5kIiwiZXhlY3V0ZSIsImFkZFJvdXRlcyIsImFwcCIsImJhc2VQYXRoIiwiREVGQVVMVF9CQVNFX1BBVEgiLCJleHRyYU1ldGhvZE1hcCIsImFsbE1ldGhvZHMiLCJNRVRIT0RfTUFQIiwicGF0aCIsIm1ldGhvZHMiLCJ0b1BhaXJzIiwibWV0aG9kIiwic3BlYyIsImJ1aWxkSGFuZGxlciIsImlzU2Vzc0NtZCIsImFzeW5jSGFuZGxlciIsInJlcSIsImJvZHkiLCJodHRwUmVzQm9keSIsImh0dHBTdGF0dXMiLCJuZXdTZXNzaW9uSWQiLCJjdXJyZW50UHJvdG9jb2wiLCJOb1N1Y2hEcml2ZXJFcnJvciIsImRpZFBsdWdpbk92ZXJyaWRlUHJveHkiLCJuZXZlclByb3h5IiwiZHJpdmVyU2hvdWxkRG9Kd3BQcm94eSIsInBsdWdpbnNUb0hhbmRsZUNtZCIsImRvSndwUHJveHkiLCJkZWJ1ZyIsIk5vdEltcGxlbWVudGVkRXJyb3IiLCJkcml2ZXJSZXMiLCJ2YWxpZGF0b3JzIiwidHJ1bmNhdGUiLCJKU09OIiwic3RyaW5naWZ5IiwiTUFYX0xPR19CT0RZX0xFTkdUSCIsInJlcUZvclByb3h5IiwiaXNQbGFpbk9iamVjdCIsImhhcyIsImVycm9yIiwidmFsdWUiLCJjYXBhYmlsaXRpZXMiLCJmb3JtYXRSZXNwb25zZVZhbHVlIiwidXRpbCIsImhhc1ZhbHVlIiwic3RhdHVzIiwiaXNOYU4iLCJwYXJzZUludCIsImVycm9yRnJvbU1KU09OV1BTdGF0dXNDb2RlIiwiZXJyb3JGcm9tVzNDSnNvbkNvZGUiLCJzdGFja3RyYWNlIiwiZXJyIiwiYWN0dWFsRXJyIiwiZXJyTXNnIiwic3RhY2siLCJpc0Vycm9yVHlwZSIsIlByb3h5UmVxdWVzdEVycm9yIiwiZ2V0QWN0dWFsRXJyb3IiLCJnZXRSZXNwb25zZUZvclczQ0Vycm9yIiwiaXNTdHJpbmciLCJzZW5kIiwiZm9ybWF0U3RhdHVzIiwianNvbiIsInRvTG93ZXJDYXNlIiwiQiIsInJlc29sdmUiLCJkb25lIiwicHJveHlBY3RpdmUiLCJwcm94eVJvdXRlSXNBdm9pZGVkIiwib3JpZ2luYWxVcmwiLCJjYW5Qcm94eSJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2xpYi9wcm90b2NvbC9wcm90b2NvbC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHt1dGlsLCBsb2dnZXIsIG5vZGV9IGZyb20gJ0BhcHBpdW0vc3VwcG9ydCc7XG5pbXBvcnQge3ZhbGlkYXRvcnN9IGZyb20gJy4vdmFsaWRhdG9ycyc7XG5pbXBvcnQge1xuICBlcnJvcnMsXG4gIGlzRXJyb3JUeXBlLFxuICBnZXRSZXNwb25zZUZvclczQ0Vycm9yLFxuICBlcnJvckZyb21NSlNPTldQU3RhdHVzQ29kZSxcbiAgZXJyb3JGcm9tVzNDSnNvbkNvZGUsXG59IGZyb20gJy4vZXJyb3JzJztcbmltcG9ydCB7TUVUSE9EX01BUCwgTk9fU0VTU0lPTl9JRF9DT01NQU5EU30gZnJvbSAnLi9yb3V0ZXMnO1xuaW1wb3J0IEIgZnJvbSAnYmx1ZWJpcmQnO1xuaW1wb3J0IHtmb3JtYXRSZXNwb25zZVZhbHVlLCBmb3JtYXRTdGF0dXN9IGZyb20gJy4vaGVscGVycyc7XG5pbXBvcnQge01BWF9MT0dfQk9EWV9MRU5HVEgsIFBST1RPQ09MUywgREVGQVVMVF9CQVNFX1BBVEh9IGZyb20gJy4uL2NvbnN0YW50cyc7XG5pbXBvcnQge2lzVzNjQ2Fwc30gZnJvbSAnLi4vaGVscGVycy9jYXBhYmlsaXRpZXMnO1xuXG5jb25zdCBDUkVBVEVfU0VTU0lPTl9DT01NQU5EID0gJ2NyZWF0ZVNlc3Npb24nO1xuY29uc3QgREVMRVRFX1NFU1NJT05fQ09NTUFORCA9ICdkZWxldGVTZXNzaW9uJztcbmNvbnN0IEdFVF9TVEFUVVNfQ09NTUFORCA9ICdnZXRTdGF0dXMnO1xuXG5mdW5jdGlvbiBkZXRlcm1pbmVQcm90b2NvbChjcmVhdGVTZXNzaW9uQXJncykge1xuICByZXR1cm4gXy5zb21lKGNyZWF0ZVNlc3Npb25BcmdzLCBpc1czY0NhcHMpID8gUFJPVE9DT0xTLlczQyA6IFBST1RPQ09MUy5NSlNPTldQO1xufVxuXG5mdW5jdGlvbiBleHRyYWN0UHJvdG9jb2woZHJpdmVyLCBzZXNzaW9uSWQgPSBudWxsKSB7XG4gIGNvbnN0IGRzdERyaXZlciA9IF8uaXNGdW5jdGlvbihkcml2ZXIuZHJpdmVyRm9yU2Vzc2lvbilcbiAgICA/IGRyaXZlci5kcml2ZXJGb3JTZXNzaW9uKHNlc3Npb25JZClcbiAgICA6IGRyaXZlcjtcbiAgaWYgKGRzdERyaXZlciA9PT0gZHJpdmVyKSB7XG4gICAgLy8gU2hvcnRjaXJjdWl0IGlmIHRoZSBkcml2ZXIgaW5zdGFuY2UgaXMgbm90IGFuIHVtYnJlbGxhIGRyaXZlclxuICAgIC8vIG9yIGl0IGlzIEZha2UgZHJpdmVyIGluc3RhbmNlLCB3aGVyZSBgZHJpdmVyLmRyaXZlckZvclNlc3Npb25gXG4gICAgLy8gYWx3YXlzIHJldHVybnMgc2VsZiBpbnN0YW5jZVxuICAgIHJldHVybiBkcml2ZXIucHJvdG9jb2w7XG4gIH1cblxuICAvLyBFeHRyYWN0IHRoZSBwcm90b2NvbCBmb3IgdGhlIGN1cnJlbnQgc2Vzc2lvbiBpZiB0aGUgZ2l2ZW4gZHJpdmVyIGlzIHRoZSB1bWJyZWxsYSBvbmVcbiAgcmV0dXJuIGRzdERyaXZlcj8ucHJvdG9jb2wgPz8gUFJPVE9DT0xTLlczQztcbn1cblxuZnVuY3Rpb24gaXNTZXNzaW9uQ29tbWFuZChjb21tYW5kKSB7XG4gIHJldHVybiAhXy5pbmNsdWRlcyhOT19TRVNTSU9OX0lEX0NPTU1BTkRTLCBjb21tYW5kKTtcbn1cblxuLyoqXG4gKlxuICogQHBhcmFtIHtpbXBvcnQoJ0BhcHBpdW0vdHlwZXMnKS5FeHRlcm5hbERyaXZlcn0gZHJpdmVyXG4gKiBAcGFyYW0ge3N0cmluZz99IFtzZXNzaW9uSWRdXG4gKiBAcmV0dXJucyB7aW1wb3J0KCdAYXBwaXVtL3R5cGVzJykuQXBwaXVtTG9nZ2VyfVxuICovXG5mdW5jdGlvbiBnZXRMb2dnZXIoZHJpdmVyLCBzZXNzaW9uSWQgPSBudWxsKSB7XG4gIGNvbnN0IGRzdERyaXZlciA9XG4gICAgc2Vzc2lvbklkICYmIF8uaXNGdW5jdGlvbihkcml2ZXIuZHJpdmVyRm9yU2Vzc2lvbilcbiAgICAgID8gZHJpdmVyLmRyaXZlckZvclNlc3Npb24oc2Vzc2lvbklkKSA/PyBkcml2ZXJcbiAgICAgIDogZHJpdmVyO1xuICBpZiAoXy5pc0Z1bmN0aW9uKGRzdERyaXZlci5sb2c/LmluZm8pKSB7XG4gICAgcmV0dXJuIGRzdERyaXZlci5sb2c7XG4gIH1cblxuICBsZXQgbG9nUHJlZml4ID0gZHN0RHJpdmVyLmNvbnN0cnVjdG9yXG4gICAgPyBgJHtkc3REcml2ZXIuY29uc3RydWN0b3IubmFtZX1AJHtub2RlLmdldE9iamVjdElkKGRzdERyaXZlcikuc3Vic3RyaW5nKDAsIDgpfWBcbiAgICA6ICdBcHBpdW1Ecml2ZXInO1xuICBpZiAoc2Vzc2lvbklkKSB7XG4gICAgbG9nUHJlZml4ICs9IGAgKCR7c2Vzc2lvbklkLnN1YnN0cmluZygwLCA4KX0pYDtcbiAgfVxuICByZXR1cm4gbG9nZ2VyLmdldExvZ2dlcihsb2dQcmVmaXgpO1xufVxuXG5mdW5jdGlvbiB3cmFwUGFyYW1zKHBhcmFtU2V0cywganNvbk9iaikge1xuICAvKiBUaGVyZSBhcmUgY29tbWFuZHMgbGlrZSBwZXJmb3JtVG91Y2ggd2hpY2ggdGFrZSBhIHNpbmdsZSBwYXJhbWV0ZXIgKHByaW1pdGl2ZSB0eXBlIG9yIGFycmF5KS5cbiAgICogU29tZSBkcml2ZXJzIGNob29zZSB0byBwYXNzIHRoaXMgcGFyYW1ldGVyIGFzIGEgdmFsdWUgKGVnLiBbYWN0aW9uMSwgYWN0aW9uMi4uLl0pIHdoaWxlIG90aGVycyB0b1xuICAgKiB3cmFwIGl0IHdpdGhpbiBhbiBvYmplY3QoZWcnIHtnZXN0dXJlOiAgW2FjdGlvbjEsIGFjdGlvbjIuLi5dfSksIHdoaWNoIG1ha2VzIGl0IGhhcmQgdG8gdmFsaWRhdGUuXG4gICAqIFRoZSB3cmFwIG9wdGlvbiBpbiB0aGUgc3BlYyBlbmZvcmNlIHdyYXBwaW5nIGJlZm9yZSB2YWxpZGF0aW9uLCBzbyB0aGF0IGFsbCBwYXJhbXMgYXJlIHdyYXBwZWQgYXRcbiAgICogdGhlIHRpbWUgdGhleSBhcmUgdmFsaWRhdGVkIGFuZCBsYXRlciBwYXNzZWQgdG8gdGhlIGNvbW1hbmRzLlxuICAgKi9cbiAgbGV0IHJlcyA9IGpzb25PYmo7XG4gIGlmIChfLmlzQXJyYXkoanNvbk9iaikgfHwgIV8uaXNPYmplY3QoanNvbk9iaikpIHtcbiAgICByZXMgPSB7fTtcbiAgICByZXNbcGFyYW1TZXRzLndyYXBdID0ganNvbk9iajtcbiAgfVxuICByZXR1cm4gcmVzO1xufVxuXG5mdW5jdGlvbiB1bndyYXBQYXJhbXMocGFyYW1TZXRzLCBqc29uT2JqKSB7XG4gIC8qIFRoZXJlIGFyZSBjb21tYW5kcyBsaWtlIHNldE5ldHdvcmtDb25uZWN0aW9uIHdoaWNoIHNlbmQgcGFyYW1ldGVycyB3cmFwcGVkIGluc2lkZSBhIGtleSBzdWNoIGFzXG4gICAqIFwicGFyYW1ldGVyc1wiLiBUaGlzIGZ1bmN0aW9uIHVud3JhcHMgdGhlbSAoZWcuIHtcInBhcmFtZXRlcnNcIjoge1widHlwZVwiOiAxfX0gYmVjb21lcyB7XCJ0eXBlXCI6IDF9KS5cbiAgICovXG4gIGxldCByZXMgPSBqc29uT2JqO1xuICBpZiAoXy5pc09iamVjdChqc29uT2JqKSkge1xuICAgIC8vIHNvbWUgY2xpZW50cywgbGlrZSBydWJ5LCBkb24ndCB3cmFwXG4gICAgaWYgKGpzb25PYmpbcGFyYW1TZXRzLnVud3JhcF0pIHtcbiAgICAgIHJlcyA9IGpzb25PYmpbcGFyYW1TZXRzLnVud3JhcF07XG4gICAgfVxuICB9XG4gIHJldHVybiByZXM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjaGVja1BhcmFtcyhwYXJhbVNldHMsIGpzb25PYmosIHByb3RvY29sKSB7XG4gIGxldCByZXF1aXJlZFBhcmFtcyA9IFtdO1xuICBsZXQgb3B0aW9uYWxQYXJhbXMgPSBbXTtcbiAgbGV0IHJlY2VpdmVkUGFyYW1zID0gXy5rZXlzKGpzb25PYmopO1xuXG4gIGlmIChwYXJhbVNldHMpIHtcbiAgICBpZiAocGFyYW1TZXRzLnJlcXVpcmVkKSB7XG4gICAgICAvLyB3ZSBtaWdodCBoYXZlIGFuIGFycmF5IG9mIHBhcmFtZXRlcnMsXG4gICAgICAvLyBvciBhbiBhcnJheSBvZiBhcnJheXMgb2YgcGFyYW1ldGVycywgc28gc3RhbmRhcmRpemVcbiAgICAgIGlmICghXy5pc0FycmF5KF8uZmlyc3QocGFyYW1TZXRzLnJlcXVpcmVkKSkpIHtcbiAgICAgICAgcmVxdWlyZWRQYXJhbXMgPSBbcGFyYW1TZXRzLnJlcXVpcmVkXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlcXVpcmVkUGFyYW1zID0gcGFyYW1TZXRzLnJlcXVpcmVkO1xuICAgICAgfVxuICAgIH1cbiAgICAvLyBvcHRpb25hbCBwYXJhbWV0ZXJzIGFyZSBqdXN0IGFuIGFycmF5XG4gICAgaWYgKHBhcmFtU2V0cy5vcHRpb25hbCkge1xuICAgICAgb3B0aW9uYWxQYXJhbXMgPSBwYXJhbVNldHMub3B0aW9uYWw7XG4gICAgfVxuXG4gICAgLy8gSWYgYSBmdW5jdGlvbiB3YXMgcHJvdmlkZWQgYXMgdGhlICd2YWxpZGF0ZScga2V5LCBpdCB3aWxsIGhlcmUgYmUgY2FsbGVkIHdpdGhcbiAgICAvLyBqc29uT2JqIGFzIHRoZSBwYXJhbS4gSWYgaXQgcmV0dXJucyBzb21ldGhpbmcgZmFsc3ksIHZlcmlmaWNhdGlvbiB3aWxsIGJlXG4gICAgLy8gY29uc2lkZXJlZCB0byBoYXZlIHBhc3NlZC4gSWYgaXQgcmV0dXJucyBzb21ldGhpbmcgZWxzZSwgdGhhdCB3aWxsIGJlIHRoZVxuICAgIC8vIGFyZ3VtZW50IHRvIGFuIGVycm9yIHdoaWNoIGlzIHRocm93biB0byB0aGUgdXNlclxuICAgIGlmIChwYXJhbVNldHMudmFsaWRhdGUpIHtcbiAgICAgIGxldCBtZXNzYWdlID0gcGFyYW1TZXRzLnZhbGlkYXRlKGpzb25PYmosIHByb3RvY29sKTtcbiAgICAgIGlmIChtZXNzYWdlKSB7XG4gICAgICAgIHRocm93IG5ldyBlcnJvcnMuQmFkUGFyYW1ldGVyc0Vycm9yKG1lc3NhZ2UsIGpzb25PYmopO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIGlmIHdlIGhhdmUgbm8gcmVxdWlyZWQgcGFyYW1ldGVycywgYWxsIGlzIHdlbGxcbiAgaWYgKHJlcXVpcmVkUGFyYW1zLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIHNvbWUgY2xpZW50cyBwYXNzIGluIHRoZSBzZXNzaW9uIGlkIGluIHRoZSBwYXJhbXNcbiAgaWYgKG9wdGlvbmFsUGFyYW1zLmluZGV4T2YoJ3Nlc3Npb25JZCcpID09PSAtMSkge1xuICAgIG9wdGlvbmFsUGFyYW1zLnB1c2goJ3Nlc3Npb25JZCcpO1xuICB9XG5cbiAgLy8gc29tZSBjbGllbnRzIHBhc3MgaW4gYW4gZWxlbWVudCBpZCBpbiB0aGUgcGFyYW1zXG4gIGlmIChvcHRpb25hbFBhcmFtcy5pbmRleE9mKCdpZCcpID09PSAtMSkge1xuICAgIG9wdGlvbmFsUGFyYW1zLnB1c2goJ2lkJyk7XG4gIH1cblxuICAvLyBnbyB0aHJvdWdoIHRoZSByZXF1aXJlZCBwYXJhbWV0ZXJzIGFuZCBjaGVjayBhZ2FpbnN0IG91ciBhcmd1bWVudHNcbiAgZm9yIChsZXQgcGFyYW1zIG9mIHJlcXVpcmVkUGFyYW1zKSB7XG4gICAgaWYgKFxuICAgICAgXy5kaWZmZXJlbmNlKHJlY2VpdmVkUGFyYW1zLCBwYXJhbXMsIG9wdGlvbmFsUGFyYW1zKS5sZW5ndGggPT09IDAgJiZcbiAgICAgIF8uZGlmZmVyZW5jZShwYXJhbXMsIHJlY2VpdmVkUGFyYW1zKS5sZW5ndGggPT09IDBcbiAgICApIHtcbiAgICAgIC8vIHdlIGhhdmUgYSBzZXQgb2YgcGFyYW1ldGVycyB0aGF0IGlzIGNvcnJlY3RcbiAgICAgIC8vIHNvIHNob3J0LWNpcmN1aXRcbiAgICAgIHJldHVybjtcbiAgICB9XG4gIH1cbiAgdGhyb3cgbmV3IGVycm9ycy5CYWRQYXJhbWV0ZXJzRXJyb3IocGFyYW1TZXRzLCByZWNlaXZlZFBhcmFtcyk7XG59XG5cbi8qXG4gKiBUaGlzIG1ldGhvZCB0YWtlcyAzIHBpZWNlcyBvZiBkYXRhOiByZXF1ZXN0IHBhcmFtZXRlcnMgKCdyZXF1ZXN0UGFyYW1zJyksXG4gKiBhIHJlcXVlc3QgSlNPTiBib2R5ICgnanNvbk9iaicpLCBhbmQgJ3BheWxvYWRQYXJhbXMnLCB3aGljaCBpcyB0aGUgc2VjdGlvblxuICogZnJvbSB0aGUgcm91dGUgZGVmaW5pdGlvbiBmb3IgYSBwYXJ0aWN1bGFyIGVuZHBvaW50IHdoaWNoIGhhcyBpbnN0cnVjdGlvbnNcbiAqIG9uIGhhbmRsaW5nIHBhcmFtZXRlcnMuIFRoaXMgbWV0aG9kIHJldHVybnMgYW4gYXJyYXkgb2YgYXJndW1lbnRzIHdoaWNoIHdpbGxcbiAqIGJlIGFwcGxpZWQgdG8gYSBjb21tYW5kLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbWFrZUFyZ3MocmVxdWVzdFBhcmFtcywganNvbk9iaiwgcGF5bG9hZFBhcmFtcywgcHJvdG9jb2wpIHtcbiAgLy8gV2Ugd2FudCB0byBwYXNzIHRoZSBcInVybFwiIHBhcmFtZXRlcnMgdG8gdGhlIGNvbW1hbmRzIGluIHJldmVyc2Ugb3JkZXJcbiAgLy8gc2luY2UgdGhlIGNvbW1hbmQgd2lsbCBzb21ldGltZXMgd2FudCB0byBpZ25vcmUsIHNheSwgdGhlIHNlc3Npb25JZC5cbiAgLy8gVGhpcyBoYXMgdGhlIGVmZmVjdCBvZiBwdXR0aW5nIHNlc3Npb25JZCBsYXN0LCB3aGljaCBtZWFucyBpbiBKUyB3ZSBjYW5cbiAgLy8gb21pdCBpdCBmcm9tIHRoZSBmdW5jdGlvbiBzaWduYXR1cmUgaWYgd2UncmUgbm90IGdvaW5nIHRvIHVzZSBpdC5cbiAgbGV0IHVybFBhcmFtcyA9IF8ua2V5cyhyZXF1ZXN0UGFyYW1zKS5yZXZlcnNlKCk7XG5cbiAgLy8gSW4gdGhlIHNpbXBsZSBjYXNlLCB0aGUgcmVxdWlyZWQgcGFyYW1ldGVycyBhcmUgYSBiYXNpYyBhcnJheSBpblxuICAvLyBwYXlsb2FkUGFyYW1zLnJlcXVpcmVkLCBzbyBzdGFydCB0aGVyZS4gSXQncyBwb3NzaWJsZSB0aGF0IHRoZXJlIGFyZVxuICAvLyBtdWx0aXBsZSBvcHRpb25hbCBzZXRzIG9mIHJlcXVpcmVkIHBhcmFtcywgdGhvdWdoLCBzbyBoYW5kbGUgdGhhdCBjYXNlXG4gIC8vIHRvby5cbiAgbGV0IHJlcXVpcmVkUGFyYW1zID0gcGF5bG9hZFBhcmFtcy5yZXF1aXJlZDtcbiAgaWYgKF8uaXNBcnJheShfLmZpcnN0KHBheWxvYWRQYXJhbXMucmVxdWlyZWQpKSkge1xuICAgIC8vIElmIHRoZXJlIGFyZSBvcHRpb25hbCBzZXRzIG9mIHJlcXVpcmVkIHBhcmFtcywgdGhlbiB3ZSB3aWxsIGhhdmUgYW5cbiAgICAvLyBhcnJheSBvZiBhcnJheXMgaW4gcGF5bG9hZFBhcmFtcy5yZXF1aXJlZCwgc28gbG9vcCB0aHJvdWdoIGVhY2ggc2V0IGFuZFxuICAgIC8vIHBpY2sgdGhlIG9uZSB0aGF0IG1hdGNoZXMgd2hpY2ggSlNPTiBwYXJhbXMgd2VyZSBhY3R1YWxseSBzZW50LiBXZSd2ZVxuICAgIC8vIGFscmVhZHkgYmVlbiB0aHJvdWdoIHZhbGlkYXRpb24gc28gd2UncmUgZ3VhcmFudGVlZCB0byBmaW5kIGEgbWF0Y2guXG4gICAgbGV0IGtleXMgPSBfLmtleXMoanNvbk9iaik7XG4gICAgZm9yIChsZXQgcGFyYW1zIG9mIHBheWxvYWRQYXJhbXMucmVxdWlyZWQpIHtcbiAgICAgIGlmIChfLndpdGhvdXQocGFyYW1zLCAuLi5rZXlzKS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmVxdWlyZWRQYXJhbXMgPSBwYXJhbXM7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIE5vdyB3ZSBjb25zdHJ1Y3Qgb3VyIGxpc3Qgb2YgYXJndW1lbnRzIHdoaWNoIHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBjb21tYW5kXG4gIGxldCBhcmdzO1xuICBpZiAoXy5pc0Z1bmN0aW9uKHBheWxvYWRQYXJhbXMubWFrZUFyZ3MpKSB7XG4gICAgLy8gSW4gdGhlIHJvdXRlIHNwZWMsIGEgcGFydGljdWxhciByb3V0ZSBtaWdodCBkZWZpbmUgYSAnbWFrZUFyZ3MnIGZ1bmN0aW9uXG4gICAgLy8gaWYgaXQgd2FudHMgZnVsbCBjb250cm9sIG92ZXIgaG93IHRvIHR1cm4gSlNPTiBwYXJhbWV0ZXJzIGludG8gY29tbWFuZFxuICAgIC8vIGFyZ3VtZW50cy4gU28gd2UgcGFzcyBpdCB0aGUgSlNPTiBwYXJhbWV0ZXJzIGFuZCBpdCByZXR1cm5zIGFuIGFycmF5XG4gICAgLy8gd2hpY2ggd2lsbCBiZSBhcHBsaWVkIHRvIHRoZSBoYW5kbGluZyBjb21tYW5kLiBGb3IgZXhhbXBsZSBpZiBpdCByZXR1cm5zXG4gICAgLy8gWzEsIDIsIDNdLCB3ZSB3aWxsIGNhbGwgYGNvbW1hbmQoMSwgMiwgMywgLi4uKWAgKHVybCBwYXJhbXMgYXJlIHNlcGFyYXRlXG4gICAgLy8gZnJvbSBKU09OIHBhcmFtcyBhbmQgZ2V0IGNvbmNhdGVuYXRlZCBiZWxvdykuXG4gICAgYXJncyA9IHBheWxvYWRQYXJhbXMubWFrZUFyZ3MoanNvbk9iaiwgcHJvdG9jb2wpO1xuICB9IGVsc2Uge1xuICAgIC8vIE90aGVyd2lzZSwgY29sbGVjdCBhbGwgdGhlIHJlcXVpcmVkIGFuZCBvcHRpb25hbCBwYXJhbXMgYW5kIGZsYXR0ZW4gdGhlbVxuICAgIC8vIGludG8gYW4gYXJndW1lbnQgYXJyYXlcbiAgICBhcmdzID0gXy5mbGF0dGVuKHJlcXVpcmVkUGFyYW1zKS5tYXAoKHApID0+IGpzb25PYmpbcF0pO1xuICAgIGlmIChwYXlsb2FkUGFyYW1zLm9wdGlvbmFsKSB7XG4gICAgICBhcmdzID0gYXJncy5jb25jYXQoXy5mbGF0dGVuKHBheWxvYWRQYXJhbXMub3B0aW9uYWwpLm1hcCgocCkgPT4ganNvbk9ialtwXSkpO1xuICAgIH1cbiAgfVxuICAvLyBGaW5hbGx5LCBnZXQgb3VyIHVybCBwYXJhbXMgKHNlc3Npb24gaWQsIGVsZW1lbnQgaWQsIGV0Yy4uLikgb24gdGhlIGVuZCBvZlxuICAvLyB0aGUgbGlzdFxuICBhcmdzID0gYXJncy5jb25jYXQodXJsUGFyYW1zLm1hcCgodSkgPT4gcmVxdWVzdFBhcmFtc1t1XSkpO1xuICByZXR1cm4gYXJncztcbn1cblxuLyoqXG4gKlxuICogQHBhcmFtIHtpbXBvcnQoJ0BhcHBpdW0vdHlwZXMnKS5Db3JlfSBkcml2ZXJcbiAqIEByZXR1cm5zIHtpbXBvcnQoJy4uL2V4cHJlc3Mvc2VydmVyJykuUm91dGVDb25maWd1cmluZ0Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiByb3V0ZUNvbmZpZ3VyaW5nRnVuY3Rpb24oZHJpdmVyKSB7XG4gIGlmICghZHJpdmVyLnNlc3Npb25FeGlzdHMpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0RyaXZlcnMgbXVzdCBpbXBsZW1lbnQgYHNlc3Npb25FeGlzdHNgIHByb3BlcnR5Jyk7XG4gIH1cblxuICAvLyBcImV4ZWN1dGVcIiBpc24ndCBkZWZpbmVkIGFueXdoZXJlXG4gIC8vIEB0cy1leHBlY3QtZXJyb3JcbiAgaWYgKCEoZHJpdmVyLmV4ZWN1dGVDb21tYW5kIHx8IGRyaXZlci5leGVjdXRlKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignRHJpdmVycyBtdXN0IGltcGxlbWVudCBgZXhlY3V0ZUNvbW1hbmRgIG9yIGBleGVjdXRlYCBtZXRob2QnKTtcbiAgfVxuXG4gIC8vIHJldHVybiBhIGZ1bmN0aW9uIHdoaWNoIHdpbGwgYWRkIGFsbCB0aGUgcm91dGVzIHRvIHRoZSBkcml2ZXIuIEhlcmUgZXh0cmFNZXRob2RzIG1pZ2h0IGJlXG4gIC8vIHBhc3NlZCBpbiBhcyBkZWZpbmVkIGJ5IEFwcGl1bSBwbHVnaW5zLCBzbyB3ZSBuZWVkIHRvIGFkZCB0aG9zZSB0byB0aGUgZGVmYXVsdCBsaXN0XG4gIHJldHVybiBmdW5jdGlvbiBhZGRSb3V0ZXMoYXBwLCB7YmFzZVBhdGggPSBERUZBVUxUX0JBU0VfUEFUSCwgZXh0cmFNZXRob2RNYXAgPSB7fX0gPSB7fSkge1xuICAgIC8vIHN0b3JlIGJhc2VQYXRoIG9uIHRoZSBkcml2ZXIgaW5zdGFuY2Ugc28gaXQgY2FuIHVzZSBpdCBpZiBuZWNlc3NhcnlcbiAgICAvLyBmb3IgZXhhbXBsZSBpbiBkZXRlcm1pbmluZyBwcm94eSBhdm9pZGFuY2VcbiAgICBkcml2ZXIuYmFzZVBhdGggPSBiYXNlUGF0aDtcblxuICAgIGNvbnN0IGFsbE1ldGhvZHMgPSB7Li4uTUVUSE9EX01BUCwgLi4uZXh0cmFNZXRob2RNYXB9O1xuXG4gICAgZm9yIChjb25zdCBbcGF0aCwgbWV0aG9kc10gb2YgXy50b1BhaXJzKGFsbE1ldGhvZHMpKSB7XG4gICAgICBmb3IgKGNvbnN0IFttZXRob2QsIHNwZWNdIG9mIF8udG9QYWlycyhtZXRob2RzKSkge1xuICAgICAgICAvLyBzZXQgdXAgdGhlIGV4cHJlc3Mgcm91dGUgaGFuZGxlclxuICAgICAgICBidWlsZEhhbmRsZXIoXG4gICAgICAgICAgYXBwLFxuICAgICAgICAgIG1ldGhvZCxcbiAgICAgICAgICBgJHtiYXNlUGF0aH0ke3BhdGh9YCxcbiAgICAgICAgICBzcGVjLFxuICAgICAgICAgIGRyaXZlcixcbiAgICAgICAgICBpc1Nlc3Npb25Db21tYW5kKHNwZWMuY29tbWFuZClcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG59XG5cbmZ1bmN0aW9uIGJ1aWxkSGFuZGxlcihhcHAsIG1ldGhvZCwgcGF0aCwgc3BlYywgZHJpdmVyLCBpc1Nlc3NDbWQpIHtcbiAgbGV0IGFzeW5jSGFuZGxlciA9IGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICAgIGxldCBqc29uT2JqID0gcmVxLmJvZHk7XG4gICAgbGV0IGh0dHBSZXNCb2R5ID0ge307XG4gICAgbGV0IGh0dHBTdGF0dXMgPSAyMDA7XG4gICAgbGV0IG5ld1Nlc3Npb25JZDtcbiAgICBsZXQgY3VycmVudFByb3RvY29sID0gZXh0cmFjdFByb3RvY29sKGRyaXZlciwgcmVxLnBhcmFtcy5zZXNzaW9uSWQpO1xuXG4gICAgdHJ5IHtcbiAgICAgIC8vIGlmIHRoaXMgaXMgYSBzZXNzaW9uIGNvbW1hbmQgYnV0IHdlIGRvbid0IGhhdmUgYSBzZXNzaW9uLFxuICAgICAgLy8gZXJyb3Igb3V0IGVhcmx5IChlc3BlY2lhbGx5IGJlZm9yZSBwcm94eWluZylcbiAgICAgIGlmIChpc1Nlc3NDbWQgJiYgIWRyaXZlci5zZXNzaW9uRXhpc3RzKHJlcS5wYXJhbXMuc2Vzc2lvbklkKSkge1xuICAgICAgICB0aHJvdyBuZXcgZXJyb3JzLk5vU3VjaERyaXZlckVycm9yKCk7XG4gICAgICB9XG5cbiAgICAgIC8vIGlmIHRoZSBkcml2ZXIgaXMgY3VycmVudGx5IHByb3h5aW5nIGNvbW1hbmRzIHRvIGFub3RoZXIgSlNPTldQIHNlcnZlciwgYnlwYXNzIGFsbCBvdXJcbiAgICAgIC8vIGNoZWNrcyBhbmQgYXNzdW1lIHRoZSB1cHN0cmVhbSBzZXJ2ZXIga25vd3Mgd2hhdCBpdCdzIGRvaW5nLiBCdXQga2VlcCB0aGlzIGluIHRoZVxuICAgICAgLy8gdHJ5L2NhdGNoIGJsb2NrIHNvIGlmIHByb3h5aW5nIGl0c2VsZiBmYWlscywgd2UgZ2l2ZSBhIG1lc3NhZ2UgdG8gdGhlIGNsaWVudC4gT2YgY291cnNlIHdlXG4gICAgICAvLyBvbmx5IHdhbnQgdG8gZG8gdGhlc2Ugd2hlbiB3ZSBoYXZlIGEgc2Vzc2lvbiBjb21tYW5kOyB0aGUgQXBwaXVtIGRyaXZlciBtdXN0IGJlXG4gICAgICAvLyByZXNwb25zaWJsZSBmb3Igc3RhcnQvc3RvcCBzZXNzaW9uLCBldGMuLi4gV2UgYWxzbyBhbGxvdyB0aGUgY29tbWFuZCBzcGVjIHRvIGRlY2xhcmUgdGhhdFxuICAgICAgLy8gdGhpcyBjb21tYW5kIHNob3VsZCBuZXZlciBiZSBwcm94aWVkICh3aGljaCBpcyB1c2VmdWwgZm9yIHBsdWdpbiBkZXZlbG9wZXJzIHdobyBhZGRcbiAgICAgIC8vIGNvbW1hbmRzIGFuZCBnZW5lcmFsbHkgd291bGQgbm90IHdhbnQgdGhhdCBjb21tYW5kIHRvIGJlIHByb3hpZWQgaW5zdGVhZCBvZiBoYW5kbGVkIGJ5IHRoZVxuICAgICAgLy8gcGx1Z2luKVxuICAgICAgbGV0IGRpZFBsdWdpbk92ZXJyaWRlUHJveHkgPSBmYWxzZTtcbiAgICAgIGlmIChpc1Nlc3NDbWQgJiYgIXNwZWMubmV2ZXJQcm94eSAmJiBkcml2ZXJTaG91bGREb0p3cFByb3h5KGRyaXZlciwgcmVxLCBzcGVjLmNvbW1hbmQpKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAhZHJpdmVyLnBsdWdpbnNUb0hhbmRsZUNtZCB8fFxuICAgICAgICAgIGRyaXZlci5wbHVnaW5zVG9IYW5kbGVDbWQoc3BlYy5jb21tYW5kLCByZXEucGFyYW1zLnNlc3Npb25JZCkubGVuZ3RoID09PSAwXG4gICAgICAgICkge1xuICAgICAgICAgIGF3YWl0IGRvSndwUHJveHkoZHJpdmVyLCByZXEsIHJlcyk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGdldExvZ2dlcihkcml2ZXIsIHJlcS5wYXJhbXMuc2Vzc2lvbklkKS5kZWJ1ZyhcbiAgICAgICAgICBgV291bGQgaGF2ZSBwcm94aWVkIGAgK1xuICAgICAgICAgICAgYGNvbW1hbmQgZGlyZWN0bHksIGJ1dCBhIHBsdWdpbiBleGlzdHMgd2hpY2ggbWlnaHQgcmVxdWlyZSBpdHMgdmFsdWUsIHNvIHdpbGwgbGV0IGAgK1xuICAgICAgICAgICAgYGl0cyB2YWx1ZSBiZSBjb2xsZWN0ZWQgaW50ZXJuYWxseSBhbmQgbWFkZSBwYXJ0IG9mIHBsdWdpbiBjaGFpbmBcbiAgICAgICAgKTtcbiAgICAgICAgZGlkUGx1Z2luT3ZlcnJpZGVQcm94eSA9IHRydWU7XG4gICAgICB9XG5cbiAgICAgIC8vIGlmIGEgY29tbWFuZCBpcyBub3QgaW4gb3VyIG1ldGhvZCBtYXAsIGl0J3MgYmVjYXVzZSB3ZVxuICAgICAgLy8gaGF2ZSBubyBwbGFucyB0byBldmVyIGltcGxlbWVudCBpdFxuICAgICAgaWYgKCFzcGVjLmNvbW1hbmQpIHtcbiAgICAgICAgdGhyb3cgbmV3IGVycm9ycy5Ob3RJbXBsZW1lbnRlZEVycm9yKCk7XG4gICAgICB9XG5cbiAgICAgIC8vIHdyYXAgcGFyYW1zIGlmIG5lY2Vzc2FyeVxuICAgICAgaWYgKHNwZWMucGF5bG9hZFBhcmFtcyAmJiBzcGVjLnBheWxvYWRQYXJhbXMud3JhcCkge1xuICAgICAgICBqc29uT2JqID0gd3JhcFBhcmFtcyhzcGVjLnBheWxvYWRQYXJhbXMsIGpzb25PYmopO1xuICAgICAgfVxuXG4gICAgICAvLyB1bndyYXAgcGFyYW1zIGlmIG5lY2Vzc2FyeVxuICAgICAgaWYgKHNwZWMucGF5bG9hZFBhcmFtcyAmJiBzcGVjLnBheWxvYWRQYXJhbXMudW53cmFwKSB7XG4gICAgICAgIGpzb25PYmogPSB1bndyYXBQYXJhbXMoc3BlYy5wYXlsb2FkUGFyYW1zLCBqc29uT2JqKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHNwZWMuY29tbWFuZCA9PT0gQ1JFQVRFX1NFU1NJT05fQ09NTUFORCkge1xuICAgICAgICAvLyB0cnkgdG8gZGV0ZXJtaW5lIHByb3RvY29sIGJ5IHNlc3Npb24gY3JlYXRpb24gYXJncywgc28gd2UgY2FuIHRocm93IGFcbiAgICAgICAgLy8gcHJvcGVybHkgZm9ybWF0dGVkIGVycm9yIGlmIGFyZ3VtZW50cyB2YWxpZGF0aW9uIGZhaWxzXG4gICAgICAgIGN1cnJlbnRQcm90b2NvbCA9IGRldGVybWluZVByb3RvY29sKFxuICAgICAgICAgIG1ha2VBcmdzKHJlcS5wYXJhbXMsIGpzb25PYmosIHNwZWMucGF5bG9hZFBhcmFtcyB8fCB7fSlcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgLy8gZW5zdXJlIHRoYXQgdGhlIGpzb24gcGF5bG9hZCBjb25mb3JtcyB0byB0aGUgc3BlY1xuICAgICAgY2hlY2tQYXJhbXMoc3BlYy5wYXlsb2FkUGFyYW1zLCBqc29uT2JqLCBjdXJyZW50UHJvdG9jb2wpO1xuXG4gICAgICAvLyB0dXJuIHRoZSBjb21tYW5kIGFuZCBqc29uIHBheWxvYWQgaW50byBhbiBhcmd1bWVudCBsaXN0IGZvclxuICAgICAgLy8gdGhlIGRyaXZlciBtZXRob2RzXG4gICAgICBsZXQgYXJncyA9IG1ha2VBcmdzKHJlcS5wYXJhbXMsIGpzb25PYmosIHNwZWMucGF5bG9hZFBhcmFtcyB8fCB7fSwgY3VycmVudFByb3RvY29sKTtcbiAgICAgIGxldCBkcml2ZXJSZXM7XG4gICAgICAvLyB2YWxpZGF0ZSBjb21tYW5kIGFyZ3MgYWNjb3JkaW5nIHRvIE1KU09OV1BcbiAgICAgIGlmICh2YWxpZGF0b3JzW3NwZWMuY29tbWFuZF0pIHtcbiAgICAgICAgdmFsaWRhdG9yc1tzcGVjLmNvbW1hbmRdKC4uLmFyZ3MpO1xuICAgICAgfVxuXG4gICAgICAvLyBydW4gdGhlIGRyaXZlciBjb21tYW5kIHdyYXBwZWQgaW5zaWRlIHRoZSBhcmd1bWVudCB2YWxpZGF0b3JzXG4gICAgICBnZXRMb2dnZXIoZHJpdmVyLCByZXEucGFyYW1zLnNlc3Npb25JZCkuZGVidWcoXG4gICAgICAgIGBDYWxsaW5nIGAgK1xuICAgICAgICAgIGAke2RyaXZlci5jb25zdHJ1Y3Rvci5uYW1lfS4ke3NwZWMuY29tbWFuZH0oKSB3aXRoIGFyZ3M6IGAgK1xuICAgICAgICAgIF8udHJ1bmNhdGUoSlNPTi5zdHJpbmdpZnkoYXJncyksIHtsZW5ndGg6IE1BWF9MT0dfQk9EWV9MRU5HVEh9KVxuICAgICAgKTtcblxuICAgICAgaWYgKGRpZFBsdWdpbk92ZXJyaWRlUHJveHkpIHtcbiAgICAgICAgLy8gVE9ETyBmb3Igbm93IHdlIGFkZCB0aGlzIGluZm9ybWF0aW9uIG9uIHRoZSBhcmdzIGxpc3QsIGJ1dCB0aGF0J3MgbWl4aW5nIHB1cnBvc2VzIGhlcmUuXG4gICAgICAgIC8vIFdlIHJlYWxseSBzaG91bGQgYWRkIGFub3RoZXIgJ29wdGlvbnMnIHBhcmFtZXRlciB0byAnZXhlY3V0ZUNvbW1hbmQnLCBidXQgdGhpcyB3b3VsZCBiZVxuICAgICAgICAvLyBhIGJyZWFraW5nIGNoYW5nZSBmb3IgYWxsIGRyaXZlcnMgc28gd291bGQgbmVlZCB0byBiZSBoYW5kbGVkIGNhcmVmdWxseS5cbiAgICAgICAgYXJncy5wdXNoKHtyZXFGb3JQcm94eTogcmVxfSk7XG4gICAgICB9XG5cbiAgICAgIGRyaXZlclJlcyA9IGF3YWl0IGRyaXZlci5leGVjdXRlQ29tbWFuZChzcGVjLmNvbW1hbmQsIC4uLmFyZ3MpO1xuXG4gICAgICAvLyBHZXQgdGhlIHByb3RvY29sIGFmdGVyIGV4ZWN1dGVDb21tYW5kXG4gICAgICBjdXJyZW50UHJvdG9jb2wgPSBleHRyYWN0UHJvdG9jb2woZHJpdmVyLCByZXEucGFyYW1zLnNlc3Npb25JZCkgfHwgY3VycmVudFByb3RvY29sO1xuXG4gICAgICAvLyBJZiBgZXhlY3V0ZUNvbW1hbmRgIHdhcyBvdmVycmlkZGVuIGFuZCB0aGUgbWV0aG9kIHJldHVybnMgYW4gb2JqZWN0XG4gICAgICAvLyB3aXRoIGEgcHJvdG9jb2wgYW5kIHZhbHVlL2Vycm9yIHByb3BlcnR5LCByZS1hc3NpZ24gdGhlIHByb3RvY29sXG4gICAgICBpZiAoXy5pc1BsYWluT2JqZWN0KGRyaXZlclJlcykgJiYgXy5oYXMoZHJpdmVyUmVzLCAncHJvdG9jb2wnKSkge1xuICAgICAgICBjdXJyZW50UHJvdG9jb2wgPSBkcml2ZXJSZXMucHJvdG9jb2wgfHwgY3VycmVudFByb3RvY29sO1xuICAgICAgICBpZiAoZHJpdmVyUmVzLmVycm9yKSB7XG4gICAgICAgICAgdGhyb3cgZHJpdmVyUmVzLmVycm9yO1xuICAgICAgICB9XG4gICAgICAgIGRyaXZlclJlcyA9IGRyaXZlclJlcy52YWx1ZTtcbiAgICAgIH1cblxuICAgICAgLy8gdW5wYWNrIGNyZWF0ZVNlc3Npb24gcmVzcG9uc2VcbiAgICAgIGlmIChzcGVjLmNvbW1hbmQgPT09IENSRUFURV9TRVNTSU9OX0NPTU1BTkQpIHtcbiAgICAgICAgbmV3U2Vzc2lvbklkID0gZHJpdmVyUmVzWzBdO1xuICAgICAgICBnZXRMb2dnZXIoZHJpdmVyLCBuZXdTZXNzaW9uSWQpLmRlYnVnKFxuICAgICAgICAgIGBDYWNoZWQgdGhlIHByb3RvY29sIHZhbHVlICcke2N1cnJlbnRQcm90b2NvbH0nIGZvciB0aGUgbmV3IHNlc3Npb24gJHtuZXdTZXNzaW9uSWR9YFxuICAgICAgICApO1xuICAgICAgICBpZiAoY3VycmVudFByb3RvY29sID09PSBQUk9UT0NPTFMuTUpTT05XUCkge1xuICAgICAgICAgIGRyaXZlclJlcyA9IGRyaXZlclJlc1sxXTtcbiAgICAgICAgfSBlbHNlIGlmIChjdXJyZW50UHJvdG9jb2wgPT09IFBST1RPQ09MUy5XM0MpIHtcbiAgICAgICAgICBkcml2ZXJSZXMgPSB7XG4gICAgICAgICAgICBjYXBhYmlsaXRpZXM6IGRyaXZlclJlc1sxXSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGRyaXZlclJlcyA9IGZvcm1hdFJlc3BvbnNlVmFsdWUoZHJpdmVyUmVzKTtcblxuICAgICAgLy8gZGVsZXRlIHNob3VsZCBub3QgcmV0dXJuIGFueXRoaW5nIGV2ZW4gaWYgc3VjY2Vzc2Z1bFxuICAgICAgaWYgKHNwZWMuY29tbWFuZCA9PT0gREVMRVRFX1NFU1NJT05fQ09NTUFORCkge1xuICAgICAgICBnZXRMb2dnZXIoZHJpdmVyLCByZXEucGFyYW1zLnNlc3Npb25JZCkuZGVidWcoXG4gICAgICAgICAgYFJlY2VpdmVkIHJlc3BvbnNlOiAke18udHJ1bmNhdGUoSlNPTi5zdHJpbmdpZnkoZHJpdmVyUmVzKSwge1xuICAgICAgICAgICAgbGVuZ3RoOiBNQVhfTE9HX0JPRFlfTEVOR1RILFxuICAgICAgICAgIH0pfWBcbiAgICAgICAgKTtcbiAgICAgICAgZ2V0TG9nZ2VyKGRyaXZlciwgcmVxLnBhcmFtcy5zZXNzaW9uSWQpLmRlYnVnKCdCdXQgZGVsZXRpbmcgc2Vzc2lvbiwgc28gbm90IHJldHVybmluZycpO1xuICAgICAgICBkcml2ZXJSZXMgPSBudWxsO1xuICAgICAgfVxuXG4gICAgICAvLyBpZiB0aGUgc3RhdHVzIGlzIG5vdCAwLCAgdGhyb3cgdGhlIGFwcHJvcHJpYXRlIGVycm9yIGZvciBzdGF0dXMgY29kZS5cbiAgICAgIGlmICh1dGlsLmhhc1ZhbHVlKGRyaXZlclJlcykpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIHV0aWwuaGFzVmFsdWUoZHJpdmVyUmVzLnN0YXR1cykgJiZcbiAgICAgICAgICAhaXNOYU4oZHJpdmVyUmVzLnN0YXR1cykgJiZcbiAgICAgICAgICBwYXJzZUludChkcml2ZXJSZXMuc3RhdHVzLCAxMCkgIT09IDBcbiAgICAgICAgKSB7XG4gICAgICAgICAgdGhyb3cgZXJyb3JGcm9tTUpTT05XUFN0YXR1c0NvZGUoZHJpdmVyUmVzLnN0YXR1cywgZHJpdmVyUmVzLnZhbHVlKTtcbiAgICAgICAgfSBlbHNlIGlmIChfLmlzUGxhaW5PYmplY3QoZHJpdmVyUmVzLnZhbHVlKSAmJiBkcml2ZXJSZXMudmFsdWUuZXJyb3IpIHtcbiAgICAgICAgICB0aHJvdyBlcnJvckZyb21XM0NKc29uQ29kZShcbiAgICAgICAgICAgIGRyaXZlclJlcy52YWx1ZS5lcnJvcixcbiAgICAgICAgICAgIGRyaXZlclJlcy52YWx1ZS5tZXNzYWdlLFxuICAgICAgICAgICAgZHJpdmVyUmVzLnZhbHVlLnN0YWNrdHJhY2VcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGh0dHBSZXNCb2R5LnZhbHVlID0gZHJpdmVyUmVzO1xuICAgICAgZ2V0TG9nZ2VyKGRyaXZlciwgcmVxLnBhcmFtcy5zZXNzaW9uSWQgfHwgbmV3U2Vzc2lvbklkKS5kZWJ1ZyhcbiAgICAgICAgYFJlc3BvbmRpbmcgYCArXG4gICAgICAgICAgYHRvIGNsaWVudCB3aXRoIGRyaXZlci4ke3NwZWMuY29tbWFuZH0oKSByZXN1bHQ6ICR7Xy50cnVuY2F0ZShKU09OLnN0cmluZ2lmeShkcml2ZXJSZXMpLCB7XG4gICAgICAgICAgICBsZW5ndGg6IE1BWF9MT0dfQk9EWV9MRU5HVEgsXG4gICAgICAgICAgfSl9YFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIC8vIGlmIGFueXRoaW5nIGdvZXMgd3JvbmcsIGZpZ3VyZSBvdXQgd2hhdCBvdXIgcmVzcG9uc2Ugc2hvdWxkIGJlXG4gICAgICAvLyBiYXNlZCBvbiB0aGUgdHlwZSBvZiBlcnJvciB0aGF0IHdlIGVuY291bnRlcmVkXG4gICAgICBsZXQgYWN0dWFsRXJyID0gZXJyO1xuXG4gICAgICBjdXJyZW50UHJvdG9jb2wgPVxuICAgICAgICBjdXJyZW50UHJvdG9jb2wgfHwgZXh0cmFjdFByb3RvY29sKGRyaXZlciwgcmVxLnBhcmFtcy5zZXNzaW9uSWQgfHwgbmV3U2Vzc2lvbklkKTtcblxuICAgICAgbGV0IGVyck1zZyA9IGVyci5zdGFja3RyYWNlIHx8IGVyci5zdGFjaztcbiAgICAgIGlmICghXy5pbmNsdWRlcyhlcnJNc2csIGVyci5tZXNzYWdlKSkge1xuICAgICAgICAvLyBpZiB0aGUgbWVzc2FnZSBoYXMgbW9yZSBpbmZvcm1hdGlvbiwgYWRkIGl0LiBidXQgb2Z0ZW4gdGhlIG1lc3NhZ2VcbiAgICAgICAgLy8gaXMgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIHN0YWNrIHRyYWNlXG4gICAgICAgIGVyck1zZyA9IGAke2Vyci5tZXNzYWdlfSR7ZXJyTXNnID8gJ1xcbicgKyBlcnJNc2cgOiAnJ31gO1xuICAgICAgfVxuICAgICAgaWYgKGlzRXJyb3JUeXBlKGVyciwgZXJyb3JzLlByb3h5UmVxdWVzdEVycm9yKSkge1xuICAgICAgICBhY3R1YWxFcnIgPSBlcnIuZ2V0QWN0dWFsRXJyb3IoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGdldExvZ2dlcihkcml2ZXIsIHJlcS5wYXJhbXMuc2Vzc2lvbklkIHx8IG5ld1Nlc3Npb25JZCkuZGVidWcoXG4gICAgICAgICAgYEVuY291bnRlcmVkIGludGVybmFsIGVycm9yIHJ1bm5pbmcgY29tbWFuZDogJHtlcnJNc2d9YFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBbaHR0cFN0YXR1cywgaHR0cFJlc0JvZHldID0gZ2V0UmVzcG9uc2VGb3JXM0NFcnJvcihhY3R1YWxFcnIpO1xuICAgIH1cblxuICAgIC8vIGRlY29kZSB0aGUgcmVzcG9uc2UsIHdoaWNoIGlzIGVpdGhlciBhIHN0cmluZyBvciBqc29uXG4gICAgaWYgKF8uaXNTdHJpbmcoaHR0cFJlc0JvZHkpKSB7XG4gICAgICByZXMuc3RhdHVzKGh0dHBTdGF0dXMpLnNlbmQoaHR0cFJlc0JvZHkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAobmV3U2Vzc2lvbklkKSB7XG4gICAgICAgIGlmIChjdXJyZW50UHJvdG9jb2wgPT09IFBST1RPQ09MUy5XM0MpIHtcbiAgICAgICAgICBodHRwUmVzQm9keS52YWx1ZS5zZXNzaW9uSWQgPSBuZXdTZXNzaW9uSWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaHR0cFJlc0JvZHkuc2Vzc2lvbklkID0gbmV3U2Vzc2lvbklkO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBodHRwUmVzQm9keS5zZXNzaW9uSWQgPSByZXEucGFyYW1zLnNlc3Npb25JZCB8fCBudWxsO1xuICAgICAgfVxuICAgICAgLy8gRG9uJ3QgaW5jbHVkZSBzZXNzaW9uSWQgaW4gVzNDIHJlc3BvbnNlc1xuICAgICAgaWYgKGN1cnJlbnRQcm90b2NvbCA9PT0gUFJPVE9DT0xTLlczQykge1xuICAgICAgICBkZWxldGUgaHR0cFJlc0JvZHkuc2Vzc2lvbklkO1xuICAgICAgfVxuXG4gICAgICBodHRwUmVzQm9keSA9IGZvcm1hdFN0YXR1cyhodHRwUmVzQm9keSk7XG4gICAgICByZXMuc3RhdHVzKGh0dHBTdGF0dXMpLmpzb24oaHR0cFJlc0JvZHkpO1xuICAgIH1cbiAgfTtcbiAgLy8gYWRkIHRoZSBtZXRob2QgdG8gdGhlIGFwcFxuICBhcHBbbWV0aG9kLnRvTG93ZXJDYXNlKCldKHBhdGgsIChyZXEsIHJlcykgPT4ge1xuICAgIEIucmVzb2x2ZShhc3luY0hhbmRsZXIocmVxLCByZXMpKS5kb25lKCk7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBkcml2ZXJTaG91bGREb0p3cFByb3h5KGRyaXZlciwgcmVxLCBjb21tYW5kKSB7XG4gIC8vIGRyaXZlcnMgbmVlZCB0byBleHBsaWNpdGx5IHNheSB3aGVuIHRoZSBwcm94eSBpcyBhY3RpdmVcbiAgaWYgKCFkcml2ZXIucHJveHlBY3RpdmUocmVxLnBhcmFtcy5zZXNzaW9uSWQpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gd2Ugc2hvdWxkIG5ldmVyIHByb3h5IGRlbGV0ZVNlc3Npb24gYmVjYXVzZSB3ZSBuZWVkIHRvIGdpdmUgdGhlIGNvbnRhaW5pbmdcbiAgLy8gZHJpdmVyIGFuIG9wcG9ydHVuaXR5IHRvIGNsZWFuIGl0c2VsZiB1cFxuICBpZiAoY29tbWFuZCA9PT0gREVMRVRFX1NFU1NJT05fQ09NTUFORCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIHZhbGlkYXRlIGF2b2lkYW5jZSBzY2hlbWEsIGFuZCBzYXkgd2Ugc2hvdWxkbid0IHByb3h5IGlmIGFueXRoaW5nIGluIHRoZVxuICAvLyBhdm9pZCBsaXN0IG1hdGNoZXMgb3VyIHJlcVxuICBpZiAoZHJpdmVyLnByb3h5Um91dGVJc0F2b2lkZWQocmVxLnBhcmFtcy5zZXNzaW9uSWQsIHJlcS5tZXRob2QsIHJlcS5vcmlnaW5hbFVybCwgcmVxLmJvZHkpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgcmV0dXJuIHRydWU7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGRvSndwUHJveHkoZHJpdmVyLCByZXEsIHJlcykge1xuICBnZXRMb2dnZXIoZHJpdmVyLCByZXEucGFyYW1zLnNlc3Npb25JZCkuaW5mbyhcbiAgICAnRHJpdmVyIHByb3h5IGFjdGl2ZSwgcGFzc2luZyByZXF1ZXN0IG9uIHZpYSBIVFRQIHByb3h5J1xuICApO1xuXG4gIC8vIGNoZWNrIHRoYXQgdGhlIGlubmVyIGRyaXZlciBoYXMgYSBwcm94eSBmdW5jdGlvblxuICBpZiAoIWRyaXZlci5jYW5Qcm94eShyZXEucGFyYW1zLnNlc3Npb25JZCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1RyeWluZyB0byBwcm94eSB0byBhIHNlcnZlciBidXQgdGhlIGRyaXZlciBpcyB1bmFibGUgdG8gcHJveHknKTtcbiAgfVxuICB0cnkge1xuICAgIGF3YWl0IGRyaXZlci5leGVjdXRlQ29tbWFuZCgncHJveHlSZXFSZXMnLCByZXEsIHJlcywgcmVxLnBhcmFtcy5zZXNzaW9uSWQpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBpZiAoaXNFcnJvclR5cGUoZXJyLCBlcnJvcnMuUHJveHlSZXF1ZXN0RXJyb3IpKSB7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IHByb3h5LiBQcm94eSBlcnJvcjogJHtlcnIubWVzc2FnZX1gKTtcbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IHtcbiAgcm91dGVDb25maWd1cmluZ0Z1bmN0aW9uLFxuICBpc1Nlc3Npb25Db21tYW5kLFxuICBkcml2ZXJTaG91bGREb0p3cFByb3h5LFxuICBkZXRlcm1pbmVQcm90b2NvbCxcbiAgQ1JFQVRFX1NFU1NJT05fQ09NTUFORCxcbiAgREVMRVRFX1NFU1NJT05fQ09NTUFORCxcbiAgR0VUX1NUQVRVU19DT01NQU5ELFxufTtcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBT0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7Ozs7QUFFQSxNQUFNQSxzQkFBc0IsR0FBRyxlQUEvQjs7QUFDQSxNQUFNQyxzQkFBc0IsR0FBRyxlQUEvQjs7QUFDQSxNQUFNQyxrQkFBa0IsR0FBRyxXQUEzQjs7O0FBRUEsU0FBU0MsaUJBQVQsQ0FBMkJDLGlCQUEzQixFQUE4QztFQUM1QyxPQUFPQyxlQUFBLENBQUVDLElBQUYsQ0FBT0YsaUJBQVAsRUFBMEJHLHVCQUExQixJQUF1Q0Msb0JBQUEs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
|
|
438
|
+
//# sourceMappingURL=protocol.js.map
|