@appium/base-driver 8.7.3 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/build/lib/basedriver/capabilities.d.ts +11 -163
  2. package/build/lib/basedriver/capabilities.d.ts.map +1 -1
  3. package/build/lib/basedriver/capabilities.js +355 -236
  4. package/build/lib/basedriver/capabilities.js.map +1 -1
  5. package/build/lib/basedriver/commands/event.d.ts +7 -6
  6. package/build/lib/basedriver/commands/event.d.ts.map +1 -1
  7. package/build/lib/basedriver/commands/event.js +55 -35
  8. package/build/lib/basedriver/commands/event.js.map +1 -1
  9. package/build/lib/basedriver/commands/execute.d.ts +7 -6
  10. package/build/lib/basedriver/commands/execute.d.ts.map +1 -1
  11. package/build/lib/basedriver/commands/execute.js +66 -58
  12. package/build/lib/basedriver/commands/execute.js.map +1 -1
  13. package/build/lib/basedriver/commands/find.d.ts +9 -7
  14. package/build/lib/basedriver/commands/find.d.ts.map +1 -1
  15. package/build/lib/basedriver/commands/find.js +102 -54
  16. package/build/lib/basedriver/commands/find.js.map +1 -1
  17. package/build/lib/basedriver/commands/index.d.ts +3 -7
  18. package/build/lib/basedriver/commands/index.d.ts.map +1 -1
  19. package/build/lib/basedriver/commands/index.js +30 -33
  20. package/build/lib/basedriver/commands/index.js.map +1 -1
  21. package/build/lib/basedriver/commands/log.d.ts +8 -9
  22. package/build/lib/basedriver/commands/log.d.ts.map +1 -1
  23. package/build/lib/basedriver/commands/log.js +54 -38
  24. package/build/lib/basedriver/commands/log.js.map +1 -1
  25. package/build/lib/basedriver/commands/session.d.ts +7 -6
  26. package/build/lib/basedriver/commands/session.d.ts.map +1 -1
  27. package/build/lib/basedriver/commands/session.js +46 -39
  28. package/build/lib/basedriver/commands/session.js.map +1 -1
  29. package/build/lib/basedriver/commands/settings.d.ts +7 -7
  30. package/build/lib/basedriver/commands/settings.d.ts.map +1 -1
  31. package/build/lib/basedriver/commands/settings.js +35 -28
  32. package/build/lib/basedriver/commands/settings.js.map +1 -1
  33. package/build/lib/basedriver/commands/timeout.d.ts +7 -5
  34. package/build/lib/basedriver/commands/timeout.d.ts.map +1 -1
  35. package/build/lib/basedriver/commands/timeout.js +144 -162
  36. package/build/lib/basedriver/commands/timeout.js.map +1 -1
  37. package/build/lib/basedriver/core.d.ts +6 -157
  38. package/build/lib/basedriver/core.d.ts.map +1 -1
  39. package/build/lib/basedriver/core.js +361 -230
  40. package/build/lib/basedriver/core.js.map +1 -1
  41. package/build/lib/basedriver/desired-caps.js +80 -110
  42. package/build/lib/basedriver/desired-caps.js.map +1 -1
  43. package/build/lib/basedriver/device-settings.js +57 -62
  44. package/build/lib/basedriver/device-settings.js.map +1 -1
  45. package/build/lib/basedriver/driver.d.ts +11 -262
  46. package/build/lib/basedriver/driver.d.ts.map +1 -1
  47. package/build/lib/basedriver/driver.js +362 -262
  48. package/build/lib/basedriver/driver.js.map +1 -1
  49. package/build/lib/basedriver/helpers.js +500 -495
  50. package/build/lib/basedriver/helpers.js.map +1 -1
  51. package/build/lib/basedriver/logger.d.ts +1 -1
  52. package/build/lib/basedriver/logger.d.ts.map +1 -1
  53. package/build/lib/basedriver/logger.js +5 -15
  54. package/build/lib/basedriver/logger.js.map +1 -1
  55. package/build/lib/constants.js +14 -14
  56. package/build/lib/constants.js.map +1 -1
  57. package/build/lib/express/crash.js +8 -15
  58. package/build/lib/express/crash.js.map +1 -1
  59. package/build/lib/express/express-logging.js +49 -59
  60. package/build/lib/express/express-logging.js.map +1 -1
  61. package/build/lib/express/idempotency.js +125 -177
  62. package/build/lib/express/idempotency.js.map +1 -1
  63. package/build/lib/express/logger.d.ts +1 -1
  64. package/build/lib/express/logger.d.ts.map +1 -1
  65. package/build/lib/express/logger.js +5 -15
  66. package/build/lib/express/logger.js.map +1 -1
  67. package/build/lib/express/middleware.js +82 -107
  68. package/build/lib/express/middleware.js.map +1 -1
  69. package/build/lib/express/server.d.ts +17 -5
  70. package/build/lib/express/server.d.ts.map +1 -1
  71. package/build/lib/express/server.js +259 -224
  72. package/build/lib/express/server.js.map +1 -1
  73. package/build/lib/express/static.js +64 -81
  74. package/build/lib/express/static.js.map +1 -1
  75. package/build/lib/express/websocket.js +115 -87
  76. package/build/lib/express/websocket.js.map +1 -1
  77. package/build/lib/helpers/capabilities.d.ts +1 -59
  78. package/build/lib/helpers/capabilities.d.ts.map +1 -1
  79. package/build/lib/helpers/capabilities.js +72 -69
  80. package/build/lib/helpers/capabilities.js.map +1 -1
  81. package/build/lib/index.js +64 -180
  82. package/build/lib/index.js.map +1 -1
  83. package/build/lib/jsonwp-proxy/protocol-converter.js +215 -227
  84. package/build/lib/jsonwp-proxy/protocol-converter.js.map +1 -1
  85. package/build/lib/jsonwp-proxy/proxy.d.ts.map +1 -1
  86. package/build/lib/jsonwp-proxy/proxy.js +355 -393
  87. package/build/lib/jsonwp-proxy/proxy.js.map +1 -1
  88. package/build/lib/jsonwp-status/status.js +119 -130
  89. package/build/lib/jsonwp-status/status.js.map +1 -1
  90. package/build/lib/protocol/errors.d.ts +135 -32
  91. package/build/lib/protocol/errors.d.ts.map +1 -1
  92. package/build/lib/protocol/errors.js +871 -919
  93. package/build/lib/protocol/errors.js.map +1 -1
  94. package/build/lib/protocol/helpers.js +37 -37
  95. package/build/lib/protocol/helpers.js.map +1 -1
  96. package/build/lib/protocol/index.js +22 -109
  97. package/build/lib/protocol/index.js.map +1 -1
  98. package/build/lib/protocol/protocol.js +394 -350
  99. package/build/lib/protocol/protocol.js.map +1 -1
  100. package/build/lib/protocol/routes.d.ts +1248 -4
  101. package/build/lib/protocol/routes.d.ts.map +1 -1
  102. package/build/lib/protocol/routes.js +972 -1327
  103. package/build/lib/protocol/routes.js.map +1 -1
  104. package/build/lib/protocol/validators.js +32 -39
  105. package/build/lib/protocol/validators.js.map +1 -1
  106. package/build/tsconfig.tsbuildinfo +1 -1
  107. package/lib/basedriver/capabilities.js +83 -39
  108. package/lib/basedriver/commands/event.js +10 -5
  109. package/lib/basedriver/commands/execute.js +14 -9
  110. package/lib/basedriver/commands/find.js +18 -12
  111. package/lib/basedriver/commands/index.js +21 -16
  112. package/lib/basedriver/commands/log.js +24 -18
  113. package/lib/basedriver/commands/session.js +10 -5
  114. package/lib/basedriver/commands/settings.js +9 -6
  115. package/lib/basedriver/commands/timeout.js +10 -4
  116. package/lib/basedriver/core.js +2 -3
  117. package/lib/basedriver/driver.js +12 -16
  118. package/lib/express/server.js +6 -3
  119. package/lib/protocol/errors.js +155 -44
  120. package/lib/protocol/routes.js +19 -7
  121. package/package.json +16 -18
@@ -1,394 +1,438 @@
1
1
  "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.GET_STATUS_COMMAND = exports.DELETE_SESSION_COMMAND = exports.CREATE_SESSION_COMMAND = void 0;
7
- exports.checkParams = checkParams;
8
- exports.determineProtocol = determineProtocol;
9
- exports.driverShouldDoJwpProxy = driverShouldDoJwpProxy;
10
- exports.isSessionCommand = isSessionCommand;
11
- exports.makeArgs = makeArgs;
12
- exports.routeConfiguringFunction = routeConfiguringFunction;
13
-
14
- require("source-map-support/register");
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
- return _lodash.default.some(createSessionArgs, _capabilities.isW3cCaps) ? _constants.PROTOCOLS.W3C : _constants.PROTOCOLS.MJSONWP;
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
- const dstDriver = _lodash.default.isFunction(driver.driverForSession) ? driver.driverForSession(sessionId) : driver;
49
-
50
- if (dstDriver === driver) {
51
- return driver.protocol;
52
- }
53
-
54
- return (dstDriver === null || dstDriver === void 0 ? void 0 : dstDriver.protocol) ?? _constants.PROTOCOLS.W3C;
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
- return !_lodash.default.includes(_routes.NO_SESSION_ID_COMMANDS, command);
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
- var _dstDriver$log;
63
-
64
- const dstDriver = sessionId && _lodash.default.isFunction(driver.driverForSession) ? driver.driverForSession(sessionId) ?? driver : driver;
65
-
66
- if (_lodash.default.isFunction((_dstDriver$log = dstDriver.log) === null || _dstDriver$log === void 0 ? void 0 : _dstDriver$log.info)) {
67
- return dstDriver.log;
68
- }
69
-
70
- let logPrefix = dstDriver.constructor ? `${dstDriver.constructor.name}@${_support.node.getObjectId(dstDriver).substring(0, 8)}` : 'AppiumDriver';
71
-
72
- if (sessionId) {
73
- logPrefix += ` (${sessionId.substring(0, 8)})`;
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
- let res = jsonObj;
81
-
82
- if (_lodash.default.isArray(jsonObj) || !_lodash.default.isObject(jsonObj)) {
83
- res = {};
84
- res[paramSets.wrap] = jsonObj;
85
- }
86
-
87
- return res;
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
- let res = jsonObj;
92
-
93
- if (_lodash.default.isObject(jsonObj)) {
94
- if (jsonObj[paramSets.unwrap]) {
95
- res = jsonObj[paramSets.unwrap];
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
- let requiredParams = [];
104
- let optionalParams = [];
105
-
106
- let receivedParams = _lodash.default.keys(jsonObj);
107
-
108
- if (paramSets) {
109
- if (paramSets.required) {
110
- if (!_lodash.default.isArray(_lodash.default.first(paramSets.required))) {
111
- requiredParams = [paramSets.required];
112
- } else {
113
- requiredParams = paramSets.required;
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 (paramSets.optional) {
118
- optionalParams = paramSets.optional;
121
+ // if we have no required parameters, all is well
122
+ if (requiredParams.length === 0) {
123
+ return;
119
124
  }
120
-
121
- if (paramSets.validate) {
122
- let message = paramSets.validate(jsonObj, protocol);
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
- if (requiredParams.length === 0) {
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
- throw new _errors.errors.BadParametersError(paramSets, receivedParams);
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
- let urlParams = _lodash.default.keys(requestParams).reverse();
153
-
154
- let requiredParams = payloadParams.required;
155
-
156
- if (_lodash.default.isArray(_lodash.default.first(payloadParams.required))) {
157
- let keys = _lodash.default.keys(jsonObj);
158
-
159
- for (let params of payloadParams.required) {
160
- if (_lodash.default.without(params, ...keys).length === 0) {
161
- requiredParams = params;
162
- break;
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
- let args;
168
-
169
- if (_lodash.default.isFunction(payloadParams.makeArgs)) {
170
- args = payloadParams.makeArgs(jsonObj, protocol);
171
- } else {
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
- args = args.concat(urlParams.map(u => requestParams[u]));
180
- return args;
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
- if (!driver.sessionExists) {
185
- throw new Error('Drivers must implement `sessionExists` property');
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
- let asyncHandler = async (req, res) => {
211
- let jsonObj = req.body;
212
- let httpResBody = {};
213
- let httpStatus = 200;
214
- let newSessionId;
215
- let currentProtocol = extractProtocol(driver, req.params.sessionId);
216
-
217
- try {
218
- if (isSessCmd && !driver.sessionExists(req.params.sessionId)) {
219
- throw new _errors.errors.NoSuchDriverError();
220
- }
221
-
222
- let didPluginOverrideProxy = false;
223
-
224
- if (isSessCmd && !spec.neverProxy && driverShouldDoJwpProxy(driver, req, spec.command)) {
225
- if (!driver.pluginsToHandleCmd || driver.pluginsToHandleCmd(spec.command, req.params.sessionId).length === 0) {
226
- await doJwpProxy(driver, req, res);
227
- return;
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
- getLogger(driver, req.params.sessionId).debug(`Would have proxied ` + `command directly, but a plugin exists which might require its value, so will let ` + `its value be collected internally and made part of plugin chain`);
231
- didPluginOverrideProxy = true;
232
- }
233
-
234
- if (!spec.command) {
235
- throw new _errors.errors.NotImplementedError();
236
- }
237
-
238
- if (spec.payloadParams && spec.payloadParams.wrap) {
239
- jsonObj = wrapParams(spec.payloadParams, jsonObj);
240
- }
241
-
242
- if (spec.payloadParams && spec.payloadParams.unwrap) {
243
- jsonObj = unwrapParams(spec.payloadParams, jsonObj);
244
- }
245
-
246
- if (spec.command === CREATE_SESSION_COMMAND) {
247
- currentProtocol = determineProtocol(makeArgs(req.params, jsonObj, spec.payloadParams || {}));
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
- driverRes = driverRes.value;
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
- driverRes = (0, _helpers.formatResponseValue)(driverRes);
295
-
296
- if (spec.command === DELETE_SESSION_COMMAND) {
297
- getLogger(driver, req.params.sessionId).debug(`Received response: ${_lodash.default.truncate(JSON.stringify(driverRes), {
298
- length: _constants.MAX_LOG_BODY_LENGTH
299
- })}`);
300
- getLogger(driver, req.params.sessionId).debug('But deleting session, so not returning');
301
- driverRes = null;
302
- }
303
-
304
- if (_support.util.hasValue(driverRes)) {
305
- if (_support.util.hasValue(driverRes.status) && !isNaN(driverRes.status) && parseInt(driverRes.status, 10) !== 0) {
306
- throw (0, _errors.errorFromMJSONWPStatusCode)(driverRes.status, driverRes.value);
307
- } else if (_lodash.default.isPlainObject(driverRes.value) && driverRes.value.error) {
308
- throw (0, _errors.errorFromW3CJsonCode)(driverRes.value.error, driverRes.value.message, driverRes.value.stacktrace);
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
- httpResBody.value = driverRes;
313
- getLogger(driver, req.params.sessionId || newSessionId).debug(`Responding ` + `to client with driver.${spec.command}() result: ${_lodash.default.truncate(JSON.stringify(driverRes), {
314
- length: _constants.MAX_LOG_BODY_LENGTH
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
- if (!driver.proxyActive(req.params.sessionId)) {
363
- return false;
364
- }
365
-
366
- if (command === DELETE_SESSION_COMMAND) {
367
- return false;
368
- }
369
-
370
- if (driver.proxyRouteIsAvoided(req.params.sessionId, req.method, req.originalUrl, req.body)) {
371
- return false;
372
- }
373
-
374
- return true;
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
- getLogger(driver, req.params.sessionId).info('Driver proxy active, passing request on via HTTP proxy');
379
-
380
- if (!driver.canProxy(req.params.sessionId)) {
381
- throw new Error('Trying to proxy to a server but the driver is unable to proxy');
382
- }
383
-
384
- try {
385
- await driver.executeCommand('proxyReqRes', req, res, req.params.sessionId);
386
- } catch (err) {
387
- if ((0, _errors.isErrorType)(err, _errors.errors.ProxyRequestError)) {
388
- throw err;
389
- } else {
390
- throw new Error(`Could not proxy. Proxy error: ${err.message}`);
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