@automagik/omni 2.260326.1 → 2.260331.1

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/dist/index.js CHANGED
@@ -29524,7 +29524,7 @@ var require_node3 = __commonJS((exports, module) => {
29524
29524
  var tty3 = __require("tty");
29525
29525
  var util3 = __require("util");
29526
29526
  exports.init = init;
29527
- exports.log = log19;
29527
+ exports.log = log18;
29528
29528
  exports.formatArgs = formatArgs;
29529
29529
  exports.save = save;
29530
29530
  exports.load = load2;
@@ -29656,7 +29656,7 @@ var require_node3 = __commonJS((exports, module) => {
29656
29656
  }
29657
29657
  return new Date().toISOString() + " ";
29658
29658
  }
29659
- function log19(...args) {
29659
+ function log18(...args) {
29660
29660
  return process.stderr.write(util3.formatWithOptions(exports.inspectOpts, ...args) + `
29661
29661
  `);
29662
29662
  }
@@ -29891,14 +29891,14 @@ var require_require_in_the_middle = __commonJS((exports, module) => {
29891
29891
  moduleName = parsedPath.name;
29892
29892
  basedir = parsedPath.dir;
29893
29893
  } else {
29894
- const stat2 = moduleDetailsFromPath(filename);
29895
- if (stat2 === undefined) {
29894
+ const stat = moduleDetailsFromPath(filename);
29895
+ if (stat === undefined) {
29896
29896
  debug("could not parse filename: %s", filename);
29897
29897
  return exports2;
29898
29898
  }
29899
- moduleName = stat2.name;
29900
- basedir = stat2.basedir;
29901
- const fullModuleName = resolveModuleName(stat2);
29899
+ moduleName = stat.name;
29900
+ basedir = stat.basedir;
29901
+ const fullModuleName = resolveModuleName(stat);
29902
29902
  debug("resolved filename to module: %s (id: %s, resolved: %s, basedir: %s)", moduleName, id, fullModuleName, basedir);
29903
29903
  let matchFound = false;
29904
29904
  if (hasWhitelist) {
@@ -29960,9 +29960,9 @@ var require_require_in_the_middle = __commonJS((exports, module) => {
29960
29960
  }
29961
29961
  }
29962
29962
  };
29963
- function resolveModuleName(stat2) {
29964
- const normalizedPath = path.sep !== "/" ? stat2.path.split(path.sep).join("/") : stat2.path;
29965
- return path.posix.join(stat2.name, normalizedPath).replace(normalize, "");
29963
+ function resolveModuleName(stat) {
29964
+ const normalizedPath = path.sep !== "/" ? stat.path.split(path.sep).join("/") : stat.path;
29965
+ return path.posix.join(stat.name, normalizedPath).replace(normalize, "");
29966
29966
  }
29967
29967
  });
29968
29968
 
@@ -32156,7 +32156,7 @@ var require_debug_logger = __commonJS((exports) => {
32156
32156
  function isEnabled() {
32157
32157
  return _getLoggerSettings().enabled;
32158
32158
  }
32159
- function log19(...args) {
32159
+ function log18(...args) {
32160
32160
  _maybeLog("log", ...args);
32161
32161
  }
32162
32162
  function warn2(...args) {
@@ -32185,7 +32185,7 @@ var require_debug_logger = __commonJS((exports) => {
32185
32185
  enable,
32186
32186
  disable,
32187
32187
  isEnabled,
32188
- log: log19,
32188
+ log: log18,
32189
32189
  warn: warn2,
32190
32190
  error: error2
32191
32191
  };
@@ -37184,13 +37184,13 @@ var require_internal = __commonJS((exports) => {
37184
37184
  setLogAttribute(processedLogAttributes, "sentry.trace.parent_span_id", span?.spanContext().spanId);
37185
37185
  const processedLog = { ...beforeLog, attributes: processedLogAttributes };
37186
37186
  client.emit("beforeCaptureLog", processedLog);
37187
- const log19 = beforeSendLog ? debugLogger.consoleSandbox(() => beforeSendLog(processedLog)) : processedLog;
37188
- if (!log19) {
37187
+ const log18 = beforeSendLog ? debugLogger.consoleSandbox(() => beforeSendLog(processedLog)) : processedLog;
37188
+ if (!log18) {
37189
37189
  client.recordDroppedEvent("before_send", "log_item", 1);
37190
37190
  debugBuild.DEBUG_BUILD && debugLogger.debug.warn("beforeSendLog returned null, log will not be captured.");
37191
37191
  return;
37192
37192
  }
37193
- const { level, message: message2, attributes: logAttributes = {}, severityNumber } = log19;
37193
+ const { level, message: message2, attributes: logAttributes = {}, severityNumber } = log18;
37194
37194
  const serializedLog = {
37195
37195
  timestamp: time.timestampInSeconds(),
37196
37196
  level,
@@ -37203,7 +37203,7 @@ var require_internal = __commonJS((exports) => {
37203
37203
  }
37204
37204
  };
37205
37205
  captureSerializedLog(client, serializedLog);
37206
- client.emit("afterCaptureLog", log19);
37206
+ client.emit("afterCaptureLog", log18);
37207
37207
  }
37208
37208
  function _INTERNAL_flushLogsBuffer(client, maybeLogBuffer) {
37209
37209
  const logBuffer = maybeLogBuffer ?? _INTERNAL_getLogBuffer(client) ?? [];
@@ -38241,12 +38241,12 @@ Reason: ${reason}`);
38241
38241
  weight += 8;
38242
38242
  return weight + estimateAttributesSizeInBytes(metric.attributes);
38243
38243
  }
38244
- function estimateLogSizeInBytes(log19) {
38244
+ function estimateLogSizeInBytes(log18) {
38245
38245
  let weight = 0;
38246
- if (log19.message) {
38247
- weight += log19.message.length * 2;
38246
+ if (log18.message) {
38247
+ weight += log18.message.length * 2;
38248
38248
  }
38249
- return weight + estimateAttributesSizeInBytes(log19.attributes);
38249
+ return weight + estimateAttributesSizeInBytes(log18.attributes);
38250
38250
  }
38251
38251
  function estimateAttributesSizeInBytes(attributes) {
38252
38252
  if (!attributes) {
@@ -38647,7 +38647,7 @@ var require_offline = __commonJS((exports) => {
38647
38647
  var START_DELAY = 5000;
38648
38648
  var MAX_DELAY = 3600000;
38649
38649
  function makeOfflineTransport(createTransport) {
38650
- function log19(...args) {
38650
+ function log18(...args) {
38651
38651
  debugBuild.DEBUG_BUILD && debugLogger.debug.log("[Offline]:", ...args);
38652
38652
  }
38653
38653
  return (options3) => {
@@ -38675,10 +38675,10 @@ var require_offline = __commonJS((exports) => {
38675
38675
  flushTimer = undefined;
38676
38676
  const found = await store.shift();
38677
38677
  if (found) {
38678
- log19("Attempting to send previously queued event");
38678
+ log18("Attempting to send previously queued event");
38679
38679
  found[0].sent_at = new Date().toISOString();
38680
38680
  send(found, true).catch((e) => {
38681
- log19("Failed to retry sending", e);
38681
+ log18("Failed to retry sending", e);
38682
38682
  });
38683
38683
  }
38684
38684
  }, delay));
@@ -38722,7 +38722,7 @@ var require_offline = __commonJS((exports) => {
38722
38722
  await store.push(envelope$1);
38723
38723
  }
38724
38724
  flushWithBackOff();
38725
- log19("Error sending. Event queued.", e);
38725
+ log18("Error sending. Event queued.", e);
38726
38726
  return {};
38727
38727
  } else {
38728
38728
  throw e;
@@ -40063,8 +40063,8 @@ var require_console = __commonJS((exports) => {
40063
40063
  return function(...args) {
40064
40064
  const handlerData = { args, level };
40065
40065
  handlers.triggerHandlers("console", handlerData);
40066
- const log19 = debugLogger.originalConsoleMethods[level];
40067
- log19?.apply(worldwide.GLOBAL_OBJ.console, args);
40066
+ const log18 = debugLogger.originalConsoleMethods[level];
40067
+ log18?.apply(worldwide.GLOBAL_OBJ.console, args);
40068
40068
  };
40069
40069
  });
40070
40070
  });
@@ -54273,7 +54273,7 @@ var require_local_variables_async = __commonJS((exports) => {
54273
54273
  var debug = require_debug();
54274
54274
  var common2 = require_common2();
54275
54275
  var base64WorkerScript = "LyohIEBzZW50cnkvbm9kZS1jb3JlIDEwLjQzLjAgKDNmYjgxMDIpIHwgaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdCAqLwppbXBvcnR7U2Vzc2lvbiBhcyBlfWZyb20ibm9kZTppbnNwZWN0b3IvcHJvbWlzZXMiO2ltcG9ydHt3b3JrZXJEYXRhIGFzIHR9ZnJvbSJub2RlOndvcmtlcl90aHJlYWRzIjtjb25zdCBuPWdsb2JhbFRoaXMsaT17fTtjb25zdCBvPSJfX1NFTlRSWV9FUlJPUl9MT0NBTF9WQVJJQUJMRVNfXyI7Y29uc3QgYT10O2Z1bmN0aW9uIHMoLi4uZSl7YS5kZWJ1ZyYmZnVuY3Rpb24oZSl7aWYoISgiY29uc29sZSJpbiBuKSlyZXR1cm4gZSgpO2NvbnN0IHQ9bi5jb25zb2xlLG89e30sYT1PYmplY3Qua2V5cyhpKTthLmZvckVhY2goZT0+e2NvbnN0IG49aVtlXTtvW2VdPXRbZV0sdFtlXT1ufSk7dHJ5e3JldHVybiBlKCl9ZmluYWxseXthLmZvckVhY2goZT0+e3RbZV09b1tlXX0pfX0oKCk9PmNvbnNvbGUubG9nKCJbTG9jYWxWYXJpYWJsZXMgV29ya2VyXSIsLi4uZSkpfWFzeW5jIGZ1bmN0aW9uIGMoZSx0LG4saSl7Y29uc3Qgbz1hd2FpdCBlLnBvc3QoIlJ1bnRpbWUuZ2V0UHJvcGVydGllcyIse29iamVjdElkOnQsb3duUHJvcGVydGllczohMH0pO2lbbl09by5yZXN1bHQuZmlsdGVyKGU9PiJsZW5ndGgiIT09ZS5uYW1lJiYhaXNOYU4ocGFyc2VJbnQoZS5uYW1lLDEwKSkpLnNvcnQoKGUsdCk9PnBhcnNlSW50KGUubmFtZSwxMCktcGFyc2VJbnQodC5uYW1lLDEwKSkubWFwKGU9PmUudmFsdWU/LnZhbHVlKX1hc3luYyBmdW5jdGlvbiByKGUsdCxuLGkpe2NvbnN0IG89YXdhaXQgZS5wb3N0KCJSdW50aW1lLmdldFByb3BlcnRpZXMiLHtvYmplY3RJZDp0LG93blByb3BlcnRpZXM6ITB9KTtpW25dPW8ucmVzdWx0Lm1hcChlPT5bZS5uYW1lLGUudmFsdWU/LnZhbHVlXSkucmVkdWNlKChlLFt0LG5dKT0+KGVbdF09bixlKSx7fSl9ZnVuY3Rpb24gdShlLHQpe2UudmFsdWUmJigidmFsdWUiaW4gZS52YWx1ZT92b2lkIDA9PT1lLnZhbHVlLnZhbHVlfHxudWxsPT09ZS52YWx1ZS52YWx1ZT90W2UubmFtZV09YDwke2UudmFsdWUudmFsdWV9PmA6dFtlLm5hbWVdPWUudmFsdWUudmFsdWU6ImRlc2NyaXB0aW9uImluIGUudmFsdWUmJiJmdW5jdGlvbiIhPT1lLnZhbHVlLnR5cGU/dFtlLm5hbWVdPWA8JHtlLnZhbHVlLmRlc2NyaXB0aW9ufT5gOiJ1bmRlZmluZWQiPT09ZS52YWx1ZS50eXBlJiYodFtlLm5hbWVdPSI8dW5kZWZpbmVkPiIpKX1hc3luYyBmdW5jdGlvbiBsKGUsdCl7Y29uc3Qgbj1hd2FpdCBlLnBvc3QoIlJ1bnRpbWUuZ2V0UHJvcGVydGllcyIse29iamVjdElkOnQsb3duUHJvcGVydGllczohMH0pLGk9e307Zm9yKGNvbnN0IHQgb2Ygbi5yZXN1bHQpaWYodC52YWx1ZT8ub2JqZWN0SWQmJiJBcnJheSI9PT10LnZhbHVlLmNsYXNzTmFtZSl7Y29uc3Qgbj10LnZhbHVlLm9iamVjdElkO2F3YWl0IGMoZSxuLHQubmFtZSxpKX1lbHNlIGlmKHQudmFsdWU/Lm9iamVjdElkJiYiT2JqZWN0Ij09PXQudmFsdWUuY2xhc3NOYW1lKXtjb25zdCBuPXQudmFsdWUub2JqZWN0SWQ7YXdhaXQgcihlLG4sdC5uYW1lLGkpfWVsc2UgdC52YWx1ZSYmdSh0LGkpO3JldHVybiBpfWxldCBmOyhhc3luYyBmdW5jdGlvbigpe2NvbnN0IHQ9bmV3IGU7dC5jb25uZWN0VG9NYWluVGhyZWFkKCkscygiQ29ubmVjdGVkIHRvIG1haW4gdGhyZWFkIik7bGV0IG49ITE7dC5vbigiRGVidWdnZXIucmVzdW1lZCIsKCk9PntuPSExfSksdC5vbigiRGVidWdnZXIucGF1c2VkIixlPT57bj0hMCxhc3luYyBmdW5jdGlvbihlLHtyZWFzb246dCxkYXRhOntvYmplY3RJZDpufSxjYWxsRnJhbWVzOml9KXtpZigiZXhjZXB0aW9uIiE9PXQmJiJwcm9taXNlUmVqZWN0aW9uIiE9PXQpcmV0dXJuO2lmKGY/LigpLG51bGw9PW4pcmV0dXJuO2NvbnN0IGE9W107Zm9yKGxldCB0PTA7dDxpLmxlbmd0aDt0Kyspe2NvbnN0e3Njb3BlQ2hhaW46bixmdW5jdGlvbk5hbWU6byx0aGlzOnN9PWlbdF0sYz1uLmZpbmQoZT0+ImxvY2FsIj09PWUudHlwZSkscj0iZ2xvYmFsIiE9PXMuY2xhc3NOYW1lJiZzLmNsYXNzTmFtZT9gJHtzLmNsYXNzTmFtZX0uJHtvfWA6bztpZih2b2lkIDA9PT1jPy5vYmplY3Qub2JqZWN0SWQpYVt0XT17ZnVuY3Rpb246cn07ZWxzZXtjb25zdCBuPWF3YWl0IGwoZSxjLm9iamVjdC5vYmplY3RJZCk7YVt0XT17ZnVuY3Rpb246cix2YXJzOm59fX1hd2FpdCBlLnBvc3QoIlJ1bnRpbWUuY2FsbEZ1bmN0aW9uT24iLHtmdW5jdGlvbkRlY2xhcmF0aW9uOmBmdW5jdGlvbigpIHsgdGhpcy4ke299ID0gdGhpcy4ke299IHx8ICR7SlNPTi5zdHJpbmdpZnkoYSl9OyB9YCxzaWxlbnQ6ITAsb2JqZWN0SWQ6bn0pLGF3YWl0IGUucG9zdCgiUnVudGltZS5yZWxlYXNlT2JqZWN0Iix7b2JqZWN0SWQ6bn0pfSh0LGUucGFyYW1zKS50aGVuKGFzeW5jKCk9PntuJiZhd2FpdCB0LnBvc3QoIkRlYnVnZ2VyLnJlc3VtZSIpfSxhc3luYyBlPT57biYmYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKX0pfSksYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5lbmFibGUiKTtjb25zdCBpPSExIT09YS5jYXB0dXJlQWxsRXhjZXB0aW9ucztpZihhd2FpdCB0LnBvc3QoIkRlYnVnZ2VyLnNldFBhdXNlT25FeGNlcHRpb25zIix7c3RhdGU6aT8iYWxsIjoidW5jYXVnaHQifSksaSl7Y29uc3QgZT1hLm1heEV4Y2VwdGlvbnNQZXJTZWNvbmR8fDUwO2Y9ZnVuY3Rpb24oZSx0LG4pe2xldCBpPTAsbz01LGE9MDtyZXR1cm4gc2V0SW50ZXJ2YWwoKCk9PnswPT09YT9pPmUmJihvKj0yLG4obyksbz44NjQwMCYmKG89ODY0MDApLGE9byk6KGEtPTEsMD09PWEmJnQoKSksaT0wfSwxZTMpLnVucmVmKCksKCk9PntpKz0xfX0oZSxhc3luYygpPT57cygiUmF0ZS1saW1pdCBsaWZ0ZWQuIiksYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5zZXRQYXVzZU9uRXhjZXB0aW9ucyIse3N0YXRlOiJhbGwifSl9LGFzeW5jIGU9PntzKGBSYXRlLWxpbWl0IGV4Y2VlZGVkLiBEaXNhYmxpbmcgY2FwdHVyaW5nIG9mIGNhdWdodCBleGNlcHRpb25zIGZvciAke2V9IHNlY29uZHMuYCksYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5zZXRQYXVzZU9uRXhjZXB0aW9ucyIse3N0YXRlOiJ1bmNhdWdodCJ9KX0pfX0pKCkuY2F0Y2goZT0+e3MoIkZhaWxlZCB0byBzdGFydCBkZWJ1Z2dlciIsZSl9KSxzZXRJbnRlcnZhbCgoKT0+e30sMWU0KTs=";
54276
- function log19(...args) {
54276
+ function log18(...args) {
54277
54277
  core.debug.log("[LocalVariables]", ...args);
54278
54278
  }
54279
54279
  var localVariablesAsyncIntegration = core.defineIntegration((integrationOptions = {}) => {
@@ -54317,10 +54317,10 @@ var require_local_variables_async = __commonJS((exports) => {
54317
54317
  worker.terminate();
54318
54318
  });
54319
54319
  worker.once("error", (err) => {
54320
- log19("Worker error", err);
54320
+ log18("Worker error", err);
54321
54321
  });
54322
54322
  worker.once("exit", (code) => {
54323
- log19("Worker exit", code);
54323
+ log18("Worker exit", code);
54324
54324
  });
54325
54325
  worker.unref();
54326
54326
  }
@@ -55330,10 +55330,10 @@ var require_proxy = __commonJS((exports) => {
55330
55330
  const proxyResponsePromise = parseProxyResponse.parseProxyResponse(socket);
55331
55331
  socket.write(`${payload}\r
55332
55332
  `);
55333
- const { connect: connect2, buffered } = await proxyResponsePromise;
55334
- req.emit("proxyConnect", connect2);
55335
- this.emit("proxyConnect", connect2, req);
55336
- if (connect2.statusCode === 200) {
55333
+ const { connect: connect3, buffered } = await proxyResponsePromise;
55334
+ req.emit("proxyConnect", connect3);
55335
+ this.emit("proxyConnect", connect3, req);
55336
+ if (connect3.statusCode === 200) {
55337
55337
  req.once("socket", resume);
55338
55338
  if (opts.secureEndpoint) {
55339
55339
  debugLog("Upgrading socket connection to TLS");
@@ -55574,9 +55574,9 @@ var require_client2 = __commonJS((exports) => {
55574
55574
  core._INTERNAL_flushLogsBuffer(this);
55575
55575
  };
55576
55576
  if (serverName) {
55577
- this.on("beforeCaptureLog", (log19) => {
55578
- log19.attributes = {
55579
- ...log19.attributes,
55577
+ this.on("beforeCaptureLog", (log18) => {
55578
+ log18.attributes = {
55579
+ ...log18.attributes,
55580
55580
  "server.address": serverName
55581
55581
  };
55582
55582
  });
@@ -55901,7 +55901,7 @@ var require_anr2 = __commonJS((exports) => {
55901
55901
  var base64WorkerScript = "LyohIEBzZW50cnkvbm9kZS1jb3JlIDEwLjQzLjAgKDNmYjgxMDIpIHwgaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdCAqLwppbXBvcnR7U2Vzc2lvbiBhcyB0fWZyb20ibm9kZTppbnNwZWN0b3IiO2ltcG9ydHt3b3JrZXJEYXRhIGFzIG4scGFyZW50UG9ydCBhcyBlfWZyb20ibm9kZTp3b3JrZXJfdGhyZWFkcyI7aW1wb3J0e3Bvc2l4IGFzIHIsc2VwIGFzIG99ZnJvbSJub2RlOnBhdGgiO2ltcG9ydCphcyBpIGZyb20ibm9kZTpodHRwIjtpbXBvcnQqYXMgcyBmcm9tIm5vZGU6aHR0cHMiO2ltcG9ydHtSZWFkYWJsZSBhcyBjfWZyb20ibm9kZTpzdHJlYW0iO2ltcG9ydHtjcmVhdGVHemlwIGFzIHV9ZnJvbSJub2RlOnpsaWIiO2ltcG9ydCphcyBhIGZyb20ibm9kZTpuZXQiO2ltcG9ydCphcyBmIGZyb20ibm9kZTp0bHMiO2NvbnN0IGg9InVuZGVmaW5lZCI9PXR5cGVvZiBfX1NFTlRSWV9ERUJVR19ffHxfX1NFTlRSWV9ERUJVR19fLHA9Z2xvYmFsVGhpcyxkPSIxMC40My4wIjtmdW5jdGlvbiBsKCl7cmV0dXJuIG0ocCkscH1mdW5jdGlvbiBtKHQpe2NvbnN0IG49dC5fX1NFTlRSWV9fPXQuX19TRU5UUllfX3x8e307cmV0dXJuIG4udmVyc2lvbj1uLnZlcnNpb258fGQsbltkXT1uW2RdfHx7fX1mdW5jdGlvbiBnKHQsbixlPXApe2NvbnN0IHI9ZS5fX1NFTlRSWV9fPWUuX19TRU5UUllfX3x8e30sbz1yW2RdPXJbZF18fHt9O3JldHVybiBvW3RdfHwob1t0XT1uKCkpfWNvbnN0IHk9e307ZnVuY3Rpb24gYih0KXtpZighKCJjb25zb2xlImluIHApKXJldHVybiB0KCk7Y29uc3Qgbj1wLmNvbnNvbGUsZT17fSxyPU9iamVjdC5rZXlzKHkpO3IuZm9yRWFjaCh0PT57Y29uc3Qgcj15W3RdO2VbdF09blt0XSxuW3RdPXJ9KTt0cnl7cmV0dXJuIHQoKX1maW5hbGx5e3IuZm9yRWFjaCh0PT57blt0XT1lW3RdfSl9fWZ1bmN0aW9uIHYoKXtyZXR1cm4gdygpLmVuYWJsZWR9ZnVuY3Rpb24gXyh0LC4uLm4pe2gmJnYoKSYmYigoKT0+e3AuY29uc29sZVt0XShgU2VudHJ5IExvZ2dlciBbJHt0fV06YCwuLi5uKX0pfWZ1bmN0aW9uIHcoKXtyZXR1cm4gaD9nKCJsb2dnZXJTZXR0aW5ncyIsKCk9Pih7ZW5hYmxlZDohMX0pKTp7ZW5hYmxlZDohMX19Y29uc3QgUz17ZW5hYmxlOmZ1bmN0aW9uKCl7dygpLmVuYWJsZWQ9ITB9LGRpc2FibGU6ZnVuY3Rpb24oKXt3KCkuZW5hYmxlZD0hMX0saXNFbmFibGVkOnYsbG9nOmZ1bmN0aW9uKC4uLnQpe18oImxvZyIsLi4udCl9LHdhcm46ZnVuY3Rpb24oLi4udCl7Xygid2FybiIsLi4udCl9LGVycm9yOmZ1bmN0aW9uKC4uLnQpe18oImVycm9yIiwuLi50KX19LCQ9L2NhcHR1cmVNZXNzYWdlfGNhcHR1cmVFeGNlcHRpb24vO2Z1bmN0aW9uIEUodCl7cmV0dXJuIHRbdC5sZW5ndGgtMV18fHt9fWNvbnN0IHg9Ijxhbm9ueW1vdXM+Ijtjb25zdCBOPU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmc7ZnVuY3Rpb24gQyh0LG4pe3JldHVybiBOLmNhbGwodCk9PT1gW29iamVjdCAke259XWB9ZnVuY3Rpb24gQSh0KXtyZXR1cm4gQyh0LCJTdHJpbmciKX1mdW5jdGlvbiBqKHQpe3JldHVybiBDKHQsIk9iamVjdCIpfWZ1bmN0aW9uIGsodCl7cmV0dXJuIEJvb2xlYW4odD8udGhlbiYmImZ1bmN0aW9uIj09dHlwZW9mIHQudGhlbil9ZnVuY3Rpb24gVCh0LG4pe3RyeXtyZXR1cm4gdCBpbnN0YW5jZW9mIG59Y2F0Y2h7cmV0dXJuITF9fWNvbnN0IEk9cDtmdW5jdGlvbiBSKHQsbil7Y29uc3QgZT10LHI9W107aWYoIWU/LnRhZ05hbWUpcmV0dXJuIiI7aWYoSS5IVE1MRWxlbWVudCYmZSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50JiZlLmRhdGFzZXQpe2lmKGUuZGF0YXNldC5zZW50cnlDb21wb25lbnQpcmV0dXJuIGUuZGF0YXNldC5zZW50cnlDb21wb25lbnQ7aWYoZS5kYXRhc2V0LnNlbnRyeUVsZW1lbnQpcmV0dXJuIGUuZGF0YXNldC5zZW50cnlFbGVtZW50fXIucHVzaChlLnRhZ05hbWUudG9Mb3dlckNhc2UoKSk7Y29uc3Qgbz1uPy5sZW5ndGg/bi5maWx0ZXIodD0+ZS5nZXRBdHRyaWJ1dGUodCkpLm1hcCh0PT5bdCxlLmdldEF0dHJpYnV0ZSh0KV0pOm51bGw7aWYobz8ubGVuZ3RoKW8uZm9yRWFjaCh0PT57ci5wdXNoKGBbJHt0WzBdfT0iJHt0WzFdfSJdYCl9KTtlbHNle2UuaWQmJnIucHVzaChgIyR7ZS5pZH1gKTtjb25zdCB0PWUuY2xhc3NOYW1lO2lmKHQmJkEodCkpe2NvbnN0IG49dC5zcGxpdCgvXHMrLyk7Zm9yKGNvbnN0IHQgb2YgbilyLnB1c2goYC4ke3R9YCl9fWNvbnN0IGk9WyJhcmlhLWxhYmVsIiwidHlwZSIsIm5hbWUiLCJ0aXRsZSIsImFsdCJdO2Zvcihjb25zdCB0IG9mIGkpe2NvbnN0IG49ZS5nZXRBdHRyaWJ1dGUodCk7biYmci5wdXNoKGBbJHt0fT0iJHtufSJdYCl9cmV0dXJuIHIuam9pbigiIil9ZnVuY3Rpb24gTyh0KXtpZihmdW5jdGlvbih0KXtzd2l0Y2goTi5jYWxsKHQpKXtjYXNlIltvYmplY3QgRXJyb3JdIjpjYXNlIltvYmplY3QgRXhjZXB0aW9uXSI6Y2FzZSJbb2JqZWN0IERPTUV4Y2VwdGlvbl0iOmNhc2UiW29iamVjdCBXZWJBc3NlbWJseS5FeGNlcHRpb25dIjpyZXR1cm4hMDtkZWZhdWx0OnJldHVybiBUKHQsRXJyb3IpfX0odCkpcmV0dXJue21lc3NhZ2U6dC5tZXNzYWdlLG5hbWU6dC5uYW1lLHN0YWNrOnQuc3RhY2ssLi4uRCh0KX07aWYobj10LCJ1bmRlZmluZWQiIT10eXBlb2YgRXZlbnQmJlQobixFdmVudCkpe2NvbnN0IG49e3R5cGU6dC50eXBlLHRhcmdldDpQKHQudGFyZ2V0KSxjdXJyZW50VGFyZ2V0OlAodC5jdXJyZW50VGFyZ2V0KSwuLi5EKHQpfTtyZXR1cm4idW5kZWZpbmVkIiE9dHlwZW9mIEN1c3RvbUV2ZW50JiZUKHQsQ3VzdG9tRXZlbnQpJiYobi5kZXRhaWw9dC5kZXRhaWwpLG59cmV0dXJuIHQ7dmFyIG59ZnVuY3Rpb24gUCh0KXt0cnl7cmV0dXJuIG49dCwidW5kZWZpbmVkIiE9dHlwZW9mIEVsZW1lbnQmJlQobixFbGVtZW50KT9mdW5jdGlvbih0LG49e30pe2lmKCF0KXJldHVybiI8dW5rbm93bj4iO3RyeXtsZXQgZT10O2NvbnN0IHI9NSxvPVtdO2xldCBpPTAscz0wO2NvbnN0IGM9IiA+ICIsdT1jLmxlbmd0aDtsZXQgYTtjb25zdCBmPUFycmF5LmlzQXJyYXkobik/bjpuLmtleUF0dHJzLGg9IUFycmF5LmlzQXJyYXkobikmJm4ubWF4U3RyaW5nTGVuZ3RofHw4MDtmb3IoO2UmJmkrKzxyJiYoYT1SKGUsZiksISgiaHRtbCI9PT1hfHxpPjEmJnMrby5sZW5ndGgqdSthLmxlbmd0aD49aCkpOylvLnB1c2goYSkscys9YS5sZW5ndGgsZT1lLnBhcmVudE5vZGU7cmV0dXJuIG8ucmV2ZXJzZSgpLmpvaW4oYyl9Y2F0Y2h7cmV0dXJuIjx1bmtub3duPiJ9fSh0KTpPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodCl9Y2F0Y2h7cmV0dXJuIjx1bmtub3duPiJ9dmFyIG59ZnVuY3Rpb24gRCh0KXtpZigib2JqZWN0Ij09dHlwZW9mIHQmJm51bGwhPT10KXtjb25zdCBuPXt9O2Zvcihjb25zdCBlIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQsZSkmJihuW2VdPXRbZV0pO3JldHVybiBufXJldHVybnt9fWxldCBVLE07ZnVuY3Rpb24gTCh0KXtpZih2b2lkIDAhPT1VKXJldHVybiBVP1UodCk6dCgpO2NvbnN0IG49U3ltYm9sLmZvcigiX19TRU5UUllfU0FGRV9SQU5ET01fSURfV1JBUFBFUl9fIiksZT1wO3JldHVybiBuIGluIGUmJiJmdW5jdGlvbiI9PXR5cGVvZiBlW25dPyhVPWVbbl0sVSh0KSk6KFU9bnVsbCx0KCkpfWZ1bmN0aW9uIEIoKXtyZXR1cm4gTCgoKT0+TWF0aC5yYW5kb20oKSl9ZnVuY3Rpb24gVygpe3JldHVybiBMKCgpPT5EYXRlLm5vdygpKX1mdW5jdGlvbiB6KHQsbj0wKXtyZXR1cm4ic3RyaW5nIiE9dHlwZW9mIHR8fDA9PT1ufHx0Lmxlbmd0aDw9bj90OmAke3Quc2xpY2UoMCxuKX0uLi5gfWZ1bmN0aW9uIEYodD1mdW5jdGlvbigpe2NvbnN0IHQ9cDtyZXR1cm4gdC5jcnlwdG98fHQubXNDcnlwdG99KCkpe3RyeXtpZih0Py5yYW5kb21VVUlEKXJldHVybiBMKCgpPT50LnJhbmRvbVVVSUQoKSkucmVwbGFjZSgvLS9nLCIiKX1jYXRjaHt9cmV0dXJuIE18fChNPVsxZTddKzFlMys0ZTMrOGUzKzFlMTEpLE0ucmVwbGFjZSgvWzAxOF0vZyx0PT4odF4oMTYqQigpJjE1KT4+dC80KS50b1N0cmluZygxNikpfWZ1bmN0aW9uIEcoKXtyZXR1cm4gVygpLzFlM31sZXQgSDtmdW5jdGlvbiBKKCl7cmV0dXJuKEg/PyhIPWZ1bmN0aW9uKCl7Y29uc3R7cGVyZm9ybWFuY2U6dH09cDtpZighdD8ubm93fHwhdC50aW1lT3JpZ2luKXJldHVybiBHO2NvbnN0IG49dC50aW1lT3JpZ2luO3JldHVybigpPT4obitMKCgpPT50Lm5vdygpKSkvMWUzfSgpKSkoKX1mdW5jdGlvbiBZKHQpe2NvbnN0IG49SigpLGU9e3NpZDpGKCksaW5pdDohMCx0aW1lc3RhbXA6bixzdGFydGVkOm4sZHVyYXRpb246MCxzdGF0dXM6Im9rIixlcnJvcnM6MCxpZ25vcmVEdXJhdGlvbjohMSx0b0pTT046KCk9PmZ1bmN0aW9uKHQpe3JldHVybntzaWQ6YCR7dC5zaWR9YCxpbml0OnQuaW5pdCxzdGFydGVkOm5ldyBEYXRlKDFlMyp0LnN0YXJ0ZWQpLnRvSVNPU3RyaW5nKCksdGltZXN0YW1wOm5ldyBEYXRlKDFlMyp0LnRpbWVzdGFtcCkudG9JU09TdHJpbmcoKSxzdGF0dXM6dC5zdGF0dXMsZXJyb3JzOnQuZXJyb3JzLGRpZDoibnVtYmVyIj09dHlwZW9mIHQuZGlkfHwic3RyaW5nIj09dHlwZW9mIHQuZGlkP2Ake3QuZGlkfWA6dm9pZCAwLGR1cmF0aW9uOnQuZHVyYXRpb24sYWJub3JtYWxfbWVjaGFuaXNtOnQuYWJub3JtYWxfbWVjaGFuaXNtLGF0dHJzOntyZWxlYXNlOnQucmVsZWFzZSxlbnZpcm9ubWVudDp0LmVudmlyb25tZW50LGlwX2FkZHJlc3M6dC5pcEFkZHJlc3MsdXNlcl9hZ2VudDp0LnVzZXJBZ2VudH19fShlKX07cmV0dXJuIHQmJlYoZSx0KSxlfWZ1bmN0aW9uIFYodCxuPXt9KXtpZihuLnVzZXImJighdC5pcEFkZHJlc3MmJm4udXNlci5pcF9hZGRyZXNzJiYodC5pcEFkZHJlc3M9bi51c2VyLmlwX2FkZHJlc3MpLHQuZGlkfHxuLmRpZHx8KHQuZGlkPW4udXNlci5pZHx8bi51c2VyLmVtYWlsfHxuLnVzZXIudXNlcm5hbWUpKSx0LnRpbWVzdGFtcD1uLnRpbWVzdGFtcHx8SigpLG4uYWJub3JtYWxfbWVjaGFuaXNtJiYodC5hYm5vcm1hbF9tZWNoYW5pc209bi5hYm5vcm1hbF9tZWNoYW5pc20pLG4uaWdub3JlRHVyYXRpb24mJih0Lmlnbm9yZUR1cmF0aW9uPW4uaWdub3JlRHVyYXRpb24pLG4uc2lkJiYodC5zaWQ9MzI9PT1uLnNpZC5sZW5ndGg/bi5zaWQ6RigpKSx2b2lkIDAhPT1uLmluaXQmJih0LmluaXQ9bi5pbml0KSwhdC5kaWQmJm4uZGlkJiYodC5kaWQ9YCR7bi5kaWR9YCksIm51bWJlciI9PXR5cGVvZiBuLnN0YXJ0ZWQmJih0LnN0YXJ0ZWQ9bi5zdGFydGVkKSx0Lmlnbm9yZUR1cmF0aW9uKXQuZHVyYXRpb249dm9pZCAwO2Vsc2UgaWYoIm51bWJlciI9PXR5cGVvZiBuLmR1cmF0aW9uKXQuZHVyYXRpb249bi5kdXJhdGlvbjtlbHNle2NvbnN0IG49dC50aW1lc3RhbXAtdC5zdGFydGVkO3QuZHVyYXRpb249bj49MD9uOjB9bi5yZWxlYXNlJiYodC5yZWxlYXNlPW4ucmVsZWFzZSksbi5lbnZpcm9ubWVudCYmKHQuZW52aXJvbm1lbnQ9bi5lbnZpcm9ubWVudCksIXQuaXBBZGRyZXNzJiZuLmlwQWRkcmVzcyYmKHQuaXBBZGRyZXNzPW4uaXBBZGRyZXNzKSwhdC51c2VyQWdlbnQmJm4udXNlckFnZW50JiYodC51c2VyQWdlbnQ9bi51c2VyQWdlbnQpLCJudW1iZXIiPT10eXBlb2Ygbi5lcnJvcnMmJih0LmVycm9ycz1uLmVycm9ycyksbi5zdGF0dXMmJih0LnN0YXR1cz1uLnN0YXR1cyl9ZnVuY3Rpb24gSyh0LG4sZT0yKXtpZighbnx8Im9iamVjdCIhPXR5cGVvZiBufHxlPD0wKXJldHVybiBuO2lmKHQmJjA9PT1PYmplY3Qua2V5cyhuKS5sZW5ndGgpcmV0dXJuIHQ7Y29uc3Qgcj17Li4udH07Zm9yKGNvbnN0IHQgaW4gbilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobix0KSYmKHJbdF09SyhyW3RdLG5bdF0sZS0xKSk7cmV0dXJuIHJ9ZnVuY3Rpb24gWigpe3JldHVybiBGKCl9ZnVuY3Rpb24gcSgpe3JldHVybiBGKCkuc3Vic3RyaW5nKDE2KX1jb25zdCBRPSJfc2VudHJ5U3BhbiI7ZnVuY3Rpb24gWCh0LG4pe24/ZnVuY3Rpb24odCxuLGUpe3RyeXtPYmplY3QuZGVmaW5lUHJvcGVydHkodCxuLHt2YWx1ZTplLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pfWNhdGNoe2gmJlMubG9nKGBGYWlsZWQgdG8gYWRkIG5vbi1lbnVtZXJhYmxlIHByb3BlcnR5ICIke259IiB0byBvYmplY3RgLHQpfX0odCxRLG4pOmRlbGV0ZSB0W1FdfWZ1bmN0aW9uIHR0KHQpe3JldHVybiB0W1FdfWNsYXNzIG50e2NvbnN0cnVjdG9yKCl7dGhpcy50PSExLHRoaXMubz1bXSx0aGlzLmk9W10sdGhpcy51PVtdLHRoaXMuaD1bXSx0aGlzLnA9e30sdGhpcy5sPXt9LHRoaXMubT17fSx0aGlzLnY9e30sdGhpcy5fPXt9LHRoaXMuUz17fSx0aGlzLk49e3RyYWNlSWQ6WigpLHNhbXBsZVJhbmQ6QigpfX1jbG9uZSgpe2NvbnN0IHQ9bmV3IG50O3JldHVybiB0LnU9Wy4uLnRoaXMudV0sdC5sPXsuLi50aGlzLmx9LHQubT17Li4udGhpcy5tfSx0LnY9ey4uLnRoaXMudn0sdC5fPXsuLi50aGlzLl99LHRoaXMuXy5mbGFncyYmKHQuXy5mbGFncz17dmFsdWVzOlsuLi50aGlzLl8uZmxhZ3MudmFsdWVzXX0pLHQucD10aGlzLnAsdC5DPXRoaXMuQyx0LkE9dGhpcy5BLHQuaj10aGlzLmosdC5rPXRoaXMuayx0Lmk9Wy4uLnRoaXMuaV0sdC5oPVsuLi50aGlzLmhdLHQuUz17Li4udGhpcy5TfSx0Lk49ey4uLnRoaXMuTn0sdC5UPXRoaXMuVCx0Lkk9dGhpcy5JLHQuUj10aGlzLlIsWCh0LHR0KHRoaXMpKSx0fXNldENsaWVudCh0KXt0aGlzLlQ9dH1zZXRMYXN0RXZlbnRJZCh0KXt0aGlzLkk9dH1nZXRDbGllbnQoKXtyZXR1cm4gdGhpcy5UfWxhc3RFdmVudElkKCl7cmV0dXJuIHRoaXMuSX1hZGRTY29wZUxpc3RlbmVyKHQpe3RoaXMuby5wdXNoKHQpfWFkZEV2ZW50UHJvY2Vzc29yKHQpe3JldHVybiB0aGlzLmkucHVzaCh0KSx0aGlzfXNldFVzZXIodCl7cmV0dXJuIHRoaXMucD10fHx7ZW1haWw6dm9pZCAwLGlkOnZvaWQgMCxpcF9hZGRyZXNzOnZvaWQgMCx1c2VybmFtZTp2b2lkIDB9LHRoaXMuQSYmVih0aGlzLkEse3VzZXI6dH0pLHRoaXMuTygpLHRoaXN9Z2V0VXNlcigpe3JldHVybiB0aGlzLnB9c2V0Q29udmVyc2F0aW9uSWQodCl7cmV0dXJuIHRoaXMuUj10fHx2b2lkIDAsdGhpcy5PKCksdGhpc31zZXRUYWdzKHQpe3JldHVybiB0aGlzLmw9ey4uLnRoaXMubCwuLi50fSx0aGlzLk8oKSx0aGlzfXNldFRhZyh0LG4pe3JldHVybiB0aGlzLnNldFRhZ3Moe1t0XTpufSl9c2V0QXR0cmlidXRlcyh0KXtyZXR1cm4gdGhpcy5tPXsuLi50aGlzLm0sLi4udH0sdGhpcy5PKCksdGhpc31zZXRBdHRyaWJ1dGUodCxuKXtyZXR1cm4gdGhpcy5zZXRBdHRyaWJ1dGVzKHtbdF06bn0pfXJlbW92ZUF0dHJpYnV0ZSh0KXtyZXR1cm4gdCBpbiB0aGlzLm0mJihkZWxldGUgdGhpcy5tW3RdLHRoaXMuTygpKSx0aGlzfXNldEV4dHJhcyh0KXtyZXR1cm4gdGhpcy52PXsuLi50aGlzLnYsLi4udH0sdGhpcy5PKCksdGhpc31zZXRFeHRyYSh0LG4pe3JldHVybiB0aGlzLnY9ey4uLnRoaXMudixbdF06bn0sdGhpcy5PKCksdGhpc31zZXRGaW5nZXJwcmludCh0KXtyZXR1cm4gdGhpcy5rPXQsdGhpcy5PKCksdGhpc31zZXRMZXZlbCh0KXtyZXR1cm4gdGhpcy5DPXQsdGhpcy5PKCksdGhpc31zZXRUcmFuc2FjdGlvbk5hbWUodCl7cmV0dXJuIHRoaXMuaj10LHRoaXMuTygpLHRoaXN9c2V0Q29udGV4dCh0LG4pe3JldHVybiBudWxsPT09bj9kZWxldGUgdGhpcy5fW3RdOnRoaXMuX1t0XT1uLHRoaXMuTygpLHRoaXN9c2V0U2Vzc2lvbih0KXtyZXR1cm4gdD90aGlzLkE9dDpkZWxldGUgdGhpcy5BLHRoaXMuTygpLHRoaXN9Z2V0U2Vzc2lvbigpe3JldHVybiB0aGlzLkF9dXBkYXRlKHQpe2lmKCF0KXJldHVybiB0aGlzO2NvbnN0IG49ImZ1bmN0aW9uIj09dHlwZW9mIHQ/dCh0aGlzKTp0LGU9biBpbnN0YW5jZW9mIG50P24uZ2V0U2NvcGVEYXRhKCk6aihuKT90OnZvaWQgMCx7dGFnczpyLGF0dHJpYnV0ZXM6byxleHRyYTppLHVzZXI6cyxjb250ZXh0czpjLGxldmVsOnUsZmluZ2VycHJpbnQ6YT1bXSxwcm9wYWdhdGlvbkNvbnRleHQ6Zixjb252ZXJzYXRpb25JZDpofT1lfHx7fTtyZXR1cm4gdGhpcy5sPXsuLi50aGlzLmwsLi4ucn0sdGhpcy5tPXsuLi50aGlzLm0sLi4ub30sdGhpcy52PXsuLi50aGlzLnYsLi4uaX0sdGhpcy5fPXsuLi50aGlzLl8sLi4uY30scyYmT2JqZWN0LmtleXMocykubGVuZ3RoJiYodGhpcy5wPXMpLHUmJih0aGlzLkM9dSksYS5sZW5ndGgmJih0aGlzLms9YSksZiYmKHRoaXMuTj1mKSxoJiYodGhpcy5SPWgpLHRoaXN9Y2xlYXIoKXtyZXR1cm4gdGhpcy51PVtdLHRoaXMubD17fSx0aGlzLm09e30sdGhpcy52PXt9LHRoaXMucD17fSx0aGlzLl89e30sdGhpcy5DPXZvaWQgMCx0aGlzLmo9dm9pZCAwLHRoaXMuaz12b2lkIDAsdGhpcy5BPXZvaWQgMCx0aGlzLlI9dm9pZCAwLFgodGhpcyx2b2lkIDApLHRoaXMuaD1bXSx0aGlzLnNldFByb3BhZ2F0aW9uQ29udGV4dCh7dHJhY2VJZDpaKCksc2FtcGxlUmFuZDpCKCl9KSx0aGlzLk8oKSx0aGlzfWFkZEJyZWFkY3J1bWIodCxuKXtjb25zdCBlPSJudW1iZXIiPT10eXBlb2Ygbj9uOjEwMDtpZihlPD0wKXJldHVybiB0aGlzO2NvbnN0IHI9e3RpbWVzdGFtcDpHKCksLi4udCxtZXNzYWdlOnQubWVzc2FnZT96KHQubWVzc2FnZSwyMDQ4KTp0Lm1lc3NhZ2V9O3JldHVybiB0aGlzLnUucHVzaChyKSx0aGlzLnUubGVuZ3RoPmUmJih0aGlzLnU9dGhpcy51LnNsaWNlKC1lKSx0aGlzLlQ/LnJlY29yZERyb3BwZWRFdmVudCgiYnVmZmVyX292ZXJmbG93IiwibG9nX2l0ZW0iKSksdGhpcy5PKCksdGhpc31nZXRMYXN0QnJlYWRjcnVtYigpe3JldHVybiB0aGlzLnVbdGhpcy51Lmxlbmd0aC0xXX1jbGVhckJyZWFkY3J1bWJzKCl7cmV0dXJuIHRoaXMudT1bXSx0aGlzLk8oKSx0aGlzfWFkZEF0dGFjaG1lbnQodCl7cmV0dXJuIHRoaXMuaC5wdXNoKHQpLHRoaXN9Y2xlYXJBdHRhY2htZW50cygpe3JldHVybiB0aGlzLmg9W10sdGhpc31nZXRTY29wZURhdGEoKXtyZXR1cm57YnJlYWRjcnVtYnM6dGhpcy51LGF0dGFjaG1lbnRzOnRoaXMuaCxjb250ZXh0czp0aGlzLl8sdGFnczp0aGlzLmwsYXR0cmlidXRlczp0aGlzLm0sZXh0cmE6dGhpcy52LHVzZXI6dGhpcy5wLGxldmVsOnRoaXMuQyxmaW5nZXJwcmludDp0aGlzLmt8fFtdLGV2ZW50UHJvY2Vzc29yczp0aGlzLmkscHJvcGFnYXRpb25Db250ZXh0OnRoaXMuTixzZGtQcm9jZXNzaW5nTWV0YWRhdGE6dGhpcy5TLHRyYW5zYWN0aW9uTmFtZTp0aGlzLmosc3Bhbjp0dCh0aGlzKSxjb252ZXJzYXRpb25JZDp0aGlzLlJ9fXNldFNES1Byb2Nlc3NpbmdNZXRhZGF0YSh0KXtyZXR1cm4gdGhpcy5TPUsodGhpcy5TLHQsMiksdGhpc31zZXRQcm9wYWdhdGlvbkNvbnRleHQodCl7cmV0dXJuIHRoaXMuTj10LHRoaXN9Z2V0UHJvcGFnYXRpb25Db250ZXh0KCl7cmV0dXJuIHRoaXMuTn1jYXB0dXJlRXhjZXB0aW9uKHQsbil7Y29uc3QgZT1uPy5ldmVudF9pZHx8RigpO2lmKCF0aGlzLlQpcmV0dXJuIGgmJlMud2FybigiTm8gY2xpZW50IGNvbmZpZ3VyZWQgb24gc2NvcGUgLSB3aWxsIG5vdCBjYXB0dXJlIGV4Y2VwdGlvbiEiKSxlO2NvbnN0IHI9bmV3IEVycm9yKCJTZW50cnkgc3ludGhldGljRXhjZXB0aW9uIik7cmV0dXJuIHRoaXMuVC5jYXB0dXJlRXhjZXB0aW9uKHQse29yaWdpbmFsRXhjZXB0aW9uOnQsc3ludGhldGljRXhjZXB0aW9uOnIsLi4ubixldmVudF9pZDplfSx0aGlzKSxlfWNhcHR1cmVNZXNzYWdlKHQsbixlKXtjb25zdCByPWU/LmV2ZW50X2lkfHxGKCk7aWYoIXRoaXMuVClyZXR1cm4gaCYmUy53YXJuKCJObyBjbGllbnQgY29uZmlndXJlZCBvbiBzY29wZSAtIHdpbGwgbm90IGNhcHR1cmUgbWVzc2FnZSEiKSxyO2NvbnN0IG89ZT8uc3ludGhldGljRXhjZXB0aW9uPz9uZXcgRXJyb3IodCk7cmV0dXJuIHRoaXMuVC5jYXB0dXJlTWVzc2FnZSh0LG4se29yaWdpbmFsRXhjZXB0aW9uOnQsc3ludGhldGljRXhjZXB0aW9uOm8sLi4uZSxldmVudF9pZDpyfSx0aGlzKSxyfWNhcHR1cmVFdmVudCh0LG4pe2NvbnN0IGU9dC5ldmVudF9pZHx8bj8uZXZlbnRfaWR8fEYoKTtyZXR1cm4gdGhpcy5UPyh0aGlzLlQuY2FwdHVyZUV2ZW50KHQsey4uLm4sZXZlbnRfaWQ6ZX0sdGhpcyksZSk6KGgmJlMud2FybigiTm8gY2xpZW50IGNvbmZpZ3VyZWQgb24gc2NvcGUgLSB3aWxsIG5vdCBjYXB0dXJlIGV2ZW50ISIpLGUpfU8oKXt0aGlzLnR8fCh0aGlzLnQ9ITAsdGhpcy5vLmZvckVhY2godD0+e3QodGhpcyl9KSx0aGlzLnQ9ITEpfX1jbGFzcyBldHtjb25zdHJ1Y3Rvcih0LG4pe2xldCBlLHI7ZT10fHxuZXcgbnQscj1ufHxuZXcgbnQsdGhpcy5QPVt7c2NvcGU6ZX1dLHRoaXMuRD1yfXdpdGhTY29wZSh0KXtjb25zdCBuPXRoaXMuVSgpO2xldCBlO3RyeXtlPXQobil9Y2F0Y2godCl7dGhyb3cgdGhpcy5NKCksdH1yZXR1cm4gayhlKT9lLnRoZW4odD0+KHRoaXMuTSgpLHQpLHQ9Pnt0aHJvdyB0aGlzLk0oKSx0fSk6KHRoaXMuTSgpLGUpfWdldENsaWVudCgpe3JldHVybiB0aGlzLmdldFN0YWNrVG9wKCkuY2xpZW50fWdldFNjb3BlKCl7cmV0dXJuIHRoaXMuZ2V0U3RhY2tUb3AoKS5zY29wZX1nZXRJc29sYXRpb25TY29wZSgpe3JldHVybiB0aGlzLkR9Z2V0U3RhY2tUb3AoKXtyZXR1cm4gdGhpcy5QW3RoaXMuUC5sZW5ndGgtMV19VSgpe2NvbnN0IHQ9dGhpcy5nZXRTY29wZSgpLmNsb25lKCk7cmV0dXJuIHRoaXMuUC5wdXNoKHtjbGllbnQ6dGhpcy5nZXRDbGllbnQoKSxzY29wZTp0fSksdH1NKCl7cmV0dXJuISh0aGlzLlAubGVuZ3RoPD0xKSYmISF0aGlzLlAucG9wKCl9fWZ1bmN0aW9uIHJ0KCl7Y29uc3QgdD1tKGwoKSk7cmV0dXJuIHQuc3RhY2s9dC5zdGFja3x8bmV3IGV0KGcoImRlZmF1bHRDdXJyZW50U2NvcGUiLCgpPT5uZXcgbnQpLGcoImRlZmF1bHRJc29sYXRpb25TY29wZSIsKCk9Pm5ldyBudCkpfWZ1bmN0aW9uIG90KHQpe3JldHVybiBydCgpLndpdGhTY29wZSh0KX1mdW5jdGlvbiBpdCh0LG4pe2NvbnN0IGU9cnQoKTtyZXR1cm4gZS53aXRoU2NvcGUoKCk9PihlLmdldFN0YWNrVG9wKCkuc2NvcGU9dCxuKHQpKSl9ZnVuY3Rpb24gc3QodCl7cmV0dXJuIHJ0KCkud2l0aFNjb3BlKCgpPT50KHJ0KCkuZ2V0SXNvbGF0aW9uU2NvcGUoKSkpfWZ1bmN0aW9uIGN0KHQpe2NvbnN0IG49bSh0KTtyZXR1cm4gbi5hY3M/bi5hY3M6e3dpdGhJc29sYXRpb25TY29wZTpzdCx3aXRoU2NvcGU6b3Qsd2l0aFNldFNjb3BlOml0LHdpdGhTZXRJc29sYXRpb25TY29wZToodCxuKT0+c3QobiksZ2V0Q3VycmVudFNjb3BlOigpPT5ydCgpLmdldFNjb3BlKCksZ2V0SXNvbGF0aW9uU2NvcGU6KCk9PnJ0KCkuZ2V0SXNvbGF0aW9uU2NvcGUoKX19ZnVuY3Rpb24gdXQoKXtyZXR1cm4gY3QobCgpKS5nZXRDdXJyZW50U2NvcGUoKS5nZXRDbGllbnQoKX1mdW5jdGlvbiBhdCh0KXtpZih0KXtpZigib2JqZWN0Ij09dHlwZW9mIHQmJiJkZXJlZiJpbiB0JiYiZnVuY3Rpb24iPT10eXBlb2YgdC5kZXJlZil0cnl7cmV0dXJuIHQuZGVyZWYoKX1jYXRjaHtyZXR1cm59cmV0dXJuIHR9fWZ1bmN0aW9uIGZ0KHQpe2NvbnN0IG49dDtyZXR1cm57c2NvcGU6bi5fc2VudHJ5U2NvcGUsaXNvbGF0aW9uU2NvcGU6YXQobi5fc2VudHJ5SXNvbGF0aW9uU2NvcGUpfX1jb25zdCBodD0vXnNlbnRyeS0vO2Z1bmN0aW9uIHB0KHQpe2NvbnN0IG49ZnVuY3Rpb24odCl7aWYoIXR8fCFBKHQpJiYhQXJyYXkuaXNBcnJheSh0KSlyZXR1cm47aWYoQXJyYXkuaXNBcnJheSh0KSlyZXR1cm4gdC5yZWR1Y2UoKHQsbik9Pntjb25zdCBlPWR0KG4pO3JldHVybiBPYmplY3QuZW50cmllcyhlKS5mb3JFYWNoKChbbixlXSk9Pnt0W25dPWV9KSx0fSx7fSk7cmV0dXJuIGR0KHQpfSh0KTtpZighbilyZXR1cm47Y29uc3QgZT1PYmplY3QuZW50cmllcyhuKS5yZWR1Y2UoKHQsW24sZV0pPT57aWYobi5tYXRjaChodCkpe3Rbbi5zbGljZSg3KV09ZX1yZXR1cm4gdH0se30pO3JldHVybiBPYmplY3Qua2V5cyhlKS5sZW5ndGg+MD9lOnZvaWQgMH1mdW5jdGlvbiBkdCh0KXtyZXR1cm4gdC5zcGxpdCgiLCIpLm1hcCh0PT57Y29uc3Qgbj10LmluZGV4T2YoIj0iKTtpZigtMT09PW4pcmV0dXJuW107cmV0dXJuW3Quc2xpY2UoMCxuKSx0LnNsaWNlKG4rMSldLm1hcCh0PT57dHJ5e3JldHVybiBkZWNvZGVVUklDb21wb25lbnQodC50cmltKCkpfWNhdGNoe3JldHVybn19KX0pLnJlZHVjZSgodCxbbixlXSk9PihuJiZlJiYodFtuXT1lKSx0KSx7fSl9Y29uc3QgbHQ9L15vKFxkKylcLi87ZnVuY3Rpb24gbXQodCxuPSExKXtjb25zdHtob3N0OmUscGF0aDpyLHBhc3M6byxwb3J0OmkscHJvamVjdElkOnMscHJvdG9jb2w6YyxwdWJsaWNLZXk6dX09dDtyZXR1cm5gJHtjfTovLyR7dX0ke24mJm8/YDoke299YDoiIn1AJHtlfSR7aT9gOiR7aX1gOiIifS8ke3I/YCR7cn0vYDpyfSR7c31gfWZ1bmN0aW9uIGd0KHQpe2NvbnN0IG49dC5nZXRPcHRpb25zKCkse2hvc3Q6ZX09dC5nZXREc24oKXx8e307bGV0IHI7cmV0dXJuIG4ub3JnSWQ/cj1TdHJpbmcobi5vcmdJZCk6ZSYmKHI9ZnVuY3Rpb24odCl7Y29uc3Qgbj10Lm1hdGNoKGx0KTtyZXR1cm4gbj8uWzFdfShlKSkscn1mdW5jdGlvbiB5dCh0KXtjb25zdHtzcGFuSWQ6bix0cmFjZUlkOmUsaXNSZW1vdGU6cn09dC5zcGFuQ29udGV4dCgpLG89cj9uOnd0KHQpLnBhcmVudF9zcGFuX2lkLGk9ZnQodCkuc2NvcGU7cmV0dXJue3BhcmVudF9zcGFuX2lkOm8sc3Bhbl9pZDpyP2k/LmdldFByb3BhZ2F0aW9uQ29udGV4dCgpLnByb3BhZ2F0aW9uU3BhbklkfHxxKCk6bix0cmFjZV9pZDplfX1mdW5jdGlvbiBidCh0KXtyZXR1cm4gdCYmdC5sZW5ndGg+MD90Lm1hcCgoe2NvbnRleHQ6e3NwYW5JZDp0LHRyYWNlSWQ6bix0cmFjZUZsYWdzOmUsLi4ucn0sYXR0cmlidXRlczpvfSk9Pih7c3Bhbl9pZDp0LHRyYWNlX2lkOm4sc2FtcGxlZDoxPT09ZSxhdHRyaWJ1dGVzOm8sLi4ucn0pKTp2b2lkIDB9ZnVuY3Rpb24gdnQodCl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiB0P190KHQpOkFycmF5LmlzQXJyYXkodCk/dFswXSt0WzFdLzFlOTp0IGluc3RhbmNlb2YgRGF0ZT9fdCh0LmdldFRpbWUoKSk6SigpfWZ1bmN0aW9uIF90KHQpe3JldHVybiB0Pjk5OTk5OTk5OTk/dC8xZTM6dH1mdW5jdGlvbiB3dCh0KXtpZihmdW5jdGlvbih0KXtyZXR1cm4iZnVuY3Rpb24iPT10eXBlb2YgdC5nZXRTcGFuSlNPTn0odCkpcmV0dXJuIHQuZ2V0U3BhbkpTT04oKTtjb25zdHtzcGFuSWQ6bix0cmFjZUlkOmV9PXQuc3BhbkNvbnRleHQoKTtpZihmdW5jdGlvbih0KXtjb25zdCBuPXQ7cmV0dXJuISEobi5hdHRyaWJ1dGVzJiZuLnN0YXJ0VGltZSYmbi5uYW1lJiZuLmVuZFRpbWUmJm4uc3RhdHVzKX0odCkpe2NvbnN0e2F0dHJpYnV0ZXM6cixzdGFydFRpbWU6byxuYW1lOmksZW5kVGltZTpzLHN0YXR1czpjLGxpbmtzOnV9PXQ7cmV0dXJue3NwYW5faWQ6bix0cmFjZV9pZDplLGRhdGE6cixkZXNjcmlwdGlvbjppLHBhcmVudF9zcGFuX2lkOiJwYXJlbnRTcGFuSWQiaW4gdD90LnBhcmVudFNwYW5JZDoicGFyZW50U3BhbkNvbnRleHQiaW4gdD90LnBhcmVudFNwYW5Db250ZXh0Py5zcGFuSWQ6dm9pZCAwLHN0YXJ0X3RpbWVzdGFtcDp2dChvKSx0aW1lc3RhbXA6dnQocyl8fHZvaWQgMCxzdGF0dXM6U3QoYyksb3A6clsic2VudHJ5Lm9wIl0sb3JpZ2luOnJbInNlbnRyeS5vcmlnaW4iXSxsaW5rczpidCh1KX19cmV0dXJue3NwYW5faWQ6bix0cmFjZV9pZDplLHN0YXJ0X3RpbWVzdGFtcDowLGRhdGE6e319fWZ1bmN0aW9uIFN0KHQpe2lmKHQmJjAhPT10LmNvZGUpcmV0dXJuIDE9PT10LmNvZGU/Im9rIjp0Lm1lc3NhZ2V8fCJpbnRlcm5hbF9lcnJvciJ9ZnVuY3Rpb24gJHQodCl7cmV0dXJuIHQuX3NlbnRyeVJvb3RTcGFufHx0fWZ1bmN0aW9uIEV0KHQpe2NvbnN0IG49dXQoKTtpZighbilyZXR1cm57fTtjb25zdCBlPSR0KHQpLHI9d3QoZSksbz1yLmRhdGEsaT1lLnNwYW5Db250ZXh0KCkudHJhY2VTdGF0ZSxzPWk/LmdldCgic2VudHJ5LnNhbXBsZV9yYXRlIik/P29bInNlbnRyeS5zYW1wbGVfcmF0ZSJdPz9vWyJzZW50cnkucHJldmlvdXNfdHJhY2Vfc2FtcGxlX3JhdGUiXTtmdW5jdGlvbiBjKHQpe3JldHVybiJudW1iZXIiIT10eXBlb2YgcyYmInN0cmluZyIhPXR5cGVvZiBzfHwodC5zYW1wbGVfcmF0ZT1gJHtzfWApLHR9Y29uc3QgdT1lLl9mcm96ZW5Ec2M7aWYodSlyZXR1cm4gYyh1KTtjb25zdCBhPWk/LmdldCgic2VudHJ5LmRzYyIpLGY9YSYmcHQoYSk7aWYoZilyZXR1cm4gYyhmKTtjb25zdCBoPWZ1bmN0aW9uKHQsbil7Y29uc3QgZT1uLmdldE9wdGlvbnMoKSx7cHVibGljS2V5OnJ9PW4uZ2V0RHNuKCl8fHt9LG89e2Vudmlyb25tZW50OmUuZW52aXJvbm1lbnR8fCJwcm9kdWN0aW9uIixyZWxlYXNlOmUucmVsZWFzZSxwdWJsaWNfa2V5OnIsdHJhY2VfaWQ6dCxvcmdfaWQ6Z3Qobil9O3JldHVybiBuLmVtaXQoImNyZWF0ZURzYyIsbyksb30odC5zcGFuQ29udGV4dCgpLnRyYWNlSWQsbikscD1vWyJzZW50cnkuc291cmNlIl0sZD1yLmRlc2NyaXB0aW9uO3JldHVybiJ1cmwiIT09cCYmZCYmKGgudHJhbnNhY3Rpb249ZCksZnVuY3Rpb24oKXtpZigiYm9vbGVhbiI9PXR5cGVvZiBfX1NFTlRSWV9UUkFDSU5HX18mJiFfX1NFTlRSWV9UUkFDSU5HX18pcmV0dXJuITE7Y29uc3QgdD11dCgpPy5nZXRPcHRpb25zKCk7cmV0dXJuISghdHx8bnVsbD09dC50cmFjZXNTYW1wbGVSYXRlJiYhdC50cmFjZXNTYW1wbGVyKX0oKSYmKGguc2FtcGxlZD1TdHJpbmcoZnVuY3Rpb24odCl7Y29uc3R7dHJhY2VGbGFnczpufT10LnNwYW5Db250ZXh0KCk7cmV0dXJuIDE9PT1ufShlKSksaC5zYW1wbGVfcmFuZD1pPy5nZXQoInNlbnRyeS5zYW1wbGVfcmFuZCIpPz9mdChlKS5zY29wZT8uZ2V0UHJvcGFnYXRpb25Db250ZXh0KCkuc2FtcGxlUmFuZC50b1N0cmluZygpKSxjKGgpLG4uZW1pdCgiY3JlYXRlRHNjIixoLGUpLGh9ZnVuY3Rpb24geHQodCxuPTEwMCxlPTEvMCl7dHJ5e3JldHVybiBOdCgiIix0LG4sZSl9Y2F0Y2godCl7cmV0dXJue0VSUk9SOmAqKm5vbi1zZXJpYWxpemFibGUqKiAoJHt0fSlgfX19ZnVuY3Rpb24gTnQodCxuLGU9MS8wLHI9MS8wLG89ZnVuY3Rpb24oKXtjb25zdCB0PW5ldyBXZWFrU2V0O2Z1bmN0aW9uIG4obil7cmV0dXJuISF0LmhhcyhuKXx8KHQuYWRkKG4pLCExKX1mdW5jdGlvbiBlKG4pe3QuZGVsZXRlKG4pfXJldHVybltuLGVdfSgpKXtjb25zdFtpLHNdPW87aWYobnVsbD09bnx8WyJib29sZWFuIiwic3RyaW5nIl0uaW5jbHVkZXModHlwZW9mIG4pfHwibnVtYmVyIj09dHlwZW9mIG4mJk51bWJlci5pc0Zpbml0ZShuKSlyZXR1cm4gbjtjb25zdCBjPWZ1bmN0aW9uKHQsbil7dHJ5e2lmKCJkb21haW4iPT09dCYmbiYmIm9iamVjdCI9PXR5cGVvZiBuJiZuLkwpcmV0dXJuIltEb21haW5dIjtpZigiZG9tYWluRW1pdHRlciI9PT10KXJldHVybiJbRG9tYWluRW1pdHRlcl0iO2lmKCJ1bmRlZmluZWQiIT10eXBlb2YgZ2xvYmFsJiZuPT09Z2xvYmFsKXJldHVybiJbR2xvYmFsXSI7aWYoInVuZGVmaW5lZCIhPXR5cGVvZiB3aW5kb3cmJm49PT13aW5kb3cpcmV0dXJuIltXaW5kb3ddIjtpZigidW5kZWZpbmVkIiE9dHlwZW9mIGRvY3VtZW50JiZuPT09ZG9jdW1lbnQpcmV0dXJuIltEb2N1bWVudF0iO2lmKCJvYmplY3QiPT10eXBlb2YoZT1uKSYmbnVsbCE9PWUmJihlLl9faXNWdWV8fGUuQnx8ZS5fX3ZfaXNWTm9kZSkpcmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiJfX3ZfaXNWTm9kZSJpbiB0JiZ0Ll9fdl9pc1ZOb2RlPyJbVnVlVk5vZGVdIjoiW1Z1ZVZpZXdNb2RlbF0ifShuKTtpZihmdW5jdGlvbih0KXtyZXR1cm4gaih0KSYmIm5hdGl2ZUV2ZW50ImluIHQmJiJwcmV2ZW50RGVmYXVsdCJpbiB0JiYic3RvcFByb3BhZ2F0aW9uImluIHR9KG4pKXJldHVybiJbU3ludGhldGljRXZlbnRdIjtpZigibnVtYmVyIj09dHlwZW9mIG4mJiFOdW1iZXIuaXNGaW5pdGUobikpcmV0dXJuYFske259XWA7aWYoImZ1bmN0aW9uIj09dHlwZW9mIG4pcmV0dXJuYFtGdW5jdGlvbjogJHtmdW5jdGlvbih0KXt0cnl7cmV0dXJuIHQmJiJmdW5jdGlvbiI9PXR5cGVvZiB0JiZ0Lm5hbWV8fHh9Y2F0Y2h7cmV0dXJuIHh9fShuKX1dYDtpZigic3ltYm9sIj09dHlwZW9mIG4pcmV0dXJuYFske1N0cmluZyhuKX1dYDtpZigiYmlnaW50Ij09dHlwZW9mIG4pcmV0dXJuYFtCaWdJbnQ6ICR7U3RyaW5nKG4pfV1gO2NvbnN0IHI9ZnVuY3Rpb24odCl7Y29uc3Qgbj1PYmplY3QuZ2V0UHJvdG90eXBlT2YodCk7cmV0dXJuIG4/LmNvbnN0cnVjdG9yP24uY29uc3RydWN0b3IubmFtZToibnVsbCBwcm90b3R5cGUifShuKTtyZXR1cm4vXkhUTUwoXHcqKUVsZW1lbnQkLy50ZXN0KHIpP2BbSFRNTEVsZW1lbnQ6ICR7cn1dYDpgW29iamVjdCAke3J9XWB9Y2F0Y2godCl7cmV0dXJuYCoqbm9uLXNlcmlhbGl6YWJsZSoqICgke3R9KWB9dmFyIGV9KHQsbik7aWYoIWMuc3RhcnRzV2l0aCgiW29iamVjdCAiKSlyZXR1cm4gYztpZihuLl9fc2VudHJ5X3NraXBfbm9ybWFsaXphdGlvbl9fKXJldHVybiBuO2NvbnN0IHU9Im51bWJlciI9PXR5cGVvZiBuLl9fc2VudHJ5X292ZXJyaWRlX25vcm1hbGl6YXRpb25fZGVwdGhfXz9uLl9fc2VudHJ5X292ZXJyaWRlX25vcm1hbGl6YXRpb25fZGVwdGhfXzplO2lmKDA9PT11KXJldHVybiBjLnJlcGxhY2UoIm9iamVjdCAiLCIiKTtpZihpKG4pKXJldHVybiJbQ2lyY3VsYXIgfl0iO2NvbnN0IGE9bjtpZihhJiYiZnVuY3Rpb24iPT10eXBlb2YgYS50b0pTT04pdHJ5e3JldHVybiBOdCgiIixhLnRvSlNPTigpLHUtMSxyLG8pfWNhdGNoe31jb25zdCBmPUFycmF5LmlzQXJyYXkobik/W106e307bGV0IGg9MDtjb25zdCBwPU8obik7Zm9yKGNvbnN0IHQgaW4gcCl7aWYoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChwLHQpKWNvbnRpbnVlO2lmKGg+PXIpe2ZbdF09IltNYXhQcm9wZXJ0aWVzIH5dIjticmVha31jb25zdCBuPXBbdF07Zlt0XT1OdCh0LG4sdS0xLHIsbyksaCsrfXJldHVybiBzKG4pLGZ9ZnVuY3Rpb24gQ3QodCxuKXtjb25zdCBlPW4ucmVwbGFjZSgvXFwvZywiLyIpLnJlcGxhY2UoL1t8XFx7fSgpW1xdXiQrKj8uXS9nLCJcXCQmIik7bGV0IHI9dDt0cnl7cj1kZWNvZGVVUkkodCl9Y2F0Y2h7fXJldHVybiByLnJlcGxhY2UoL1xcL2csIi8iKS5yZXBsYWNlKC93ZWJwYWNrOlwvPy9nLCIiKS5yZXBsYWNlKG5ldyBSZWdFeHAoYChmaWxlOi8vKT8vKiR7ZX0vKmAsImlnIiksImFwcDovLy8iKX1mdW5jdGlvbiBBdCh0LG49W10pe3JldHVyblt0LG5dfWZ1bmN0aW9uIGp0KHQsbil7Y29uc3QgZT10WzFdO2Zvcihjb25zdCB0IG9mIGUpe2lmKG4odCx0WzBdLnR5cGUpKXJldHVybiEwfXJldHVybiExfWZ1bmN0aW9uIGt0KHQpe2NvbnN0IG49bShwKTtyZXR1cm4gbi5lbmNvZGVQb2x5ZmlsbD9uLmVuY29kZVBvbHlmaWxsKHQpOihuZXcgVGV4dEVuY29kZXIpLmVuY29kZSh0KX1mdW5jdGlvbiBUdCh0KXtjb25zdFtuLGVdPXQ7bGV0IHI9SlNPTi5zdHJpbmdpZnkobik7ZnVuY3Rpb24gbyh0KXsic3RyaW5nIj09dHlwZW9mIHI/cj0ic3RyaW5nIj09dHlwZW9mIHQ/cit0OltrdChyKSx0XTpyLnB1c2goInN0cmluZyI9PXR5cGVvZiB0P2t0KHQpOnQpfWZvcihjb25zdCB0IG9mIGUpe2NvbnN0W24sZV09dDtpZihvKGBcbiR7SlNPTi5zdHJpbmdpZnkobil9XG5gKSwic3RyaW5nIj09dHlwZW9mIGV8fGUgaW5zdGFuY2VvZiBVaW50OEFycmF5KW8oZSk7ZWxzZXtsZXQgdDt0cnl7dD1KU09OLnN0cmluZ2lmeShlKX1jYXRjaHt0PUpTT04uc3RyaW5naWZ5KHh0KGUpKX1vKHQpfX1yZXR1cm4ic3RyaW5nIj09dHlwZW9mIHI/cjpmdW5jdGlvbih0KXtjb25zdCBuPXQucmVkdWNlKCh0LG4pPT50K24ubGVuZ3RoLDApLGU9bmV3IFVpbnQ4QXJyYXkobik7bGV0IHI9MDtmb3IoY29uc3QgbiBvZiB0KWUuc2V0KG4scikscis9bi5sZW5ndGg7cmV0dXJuIGV9KHIpfWNvbnN0IEl0PXtzZXNzaW9uOiJzZXNzaW9uIixzZXNzaW9uczoic2Vzc2lvbiIsYXR0YWNobWVudDoiYXR0YWNobWVudCIsdHJhbnNhY3Rpb246InRyYW5zYWN0aW9uIixldmVudDoiZXJyb3IiLGNsaWVudF9yZXBvcnQ6ImludGVybmFsIix1c2VyX3JlcG9ydDoiZGVmYXVsdCIscHJvZmlsZToicHJvZmlsZSIscHJvZmlsZV9jaHVuazoicHJvZmlsZSIscmVwbGF5X2V2ZW50OiJyZXBsYXkiLHJlcGxheV9yZWNvcmRpbmc6InJlcGxheSIsY2hlY2tfaW46Im1vbml0b3IiLGZlZWRiYWNrOiJmZWVkYmFjayIsc3Bhbjoic3BhbiIscmF3X3NlY3VyaXR5OiJzZWN1cml0eSIsbG9nOiJsb2dfaXRlbSIsbWV0cmljOiJtZXRyaWMiLHRyYWNlX21ldHJpYzoibWV0cmljIn07ZnVuY3Rpb24gUnQodCl7aWYoIXQ/LnNkaylyZXR1cm47Y29uc3R7bmFtZTpuLHZlcnNpb246ZX09dC5zZGs7cmV0dXJue25hbWU6bix2ZXJzaW9uOmV9fWZ1bmN0aW9uIE90KHQsbixlLHIpe2NvbnN0IG89UnQoZSksaT10LnR5cGUmJiJyZXBsYXlfZXZlbnQiIT09dC50eXBlP3QudHlwZToiZXZlbnQiOyFmdW5jdGlvbih0LG4pe2lmKCFuKXJldHVybiB0O2NvbnN0IGU9dC5zZGt8fHt9O3Quc2RrPXsuLi5lLG5hbWU6ZS5uYW1lfHxuLm5hbWUsdmVyc2lvbjplLnZlcnNpb258fG4udmVyc2lvbixpbnRlZ3JhdGlvbnM6Wy4uLnQuc2RrPy5pbnRlZ3JhdGlvbnN8fFtdLC4uLm4uaW50ZWdyYXRpb25zfHxbXV0scGFja2FnZXM6Wy4uLnQuc2RrPy5wYWNrYWdlc3x8W10sLi4ubi5wYWNrYWdlc3x8W11dLHNldHRpbmdzOnQuc2RrPy5zZXR0aW5nc3x8bi5zZXR0aW5ncz97Li4udC5zZGs/LnNldHRpbmdzLC4uLm4uc2V0dGluZ3N9OnZvaWQgMH19KHQsZT8uc2RrKTtjb25zdCBzPWZ1bmN0aW9uKHQsbixlLHIpe2NvbnN0IG89dC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE/LmR5bmFtaWNTYW1wbGluZ0NvbnRleHQ7cmV0dXJue2V2ZW50X2lkOnQuZXZlbnRfaWQsc2VudF9hdDoobmV3IERhdGUpLnRvSVNPU3RyaW5nKCksLi4ubiYme3NkazpufSwuLi4hIWUmJnImJntkc246bXQocil9LC4uLm8mJnt0cmFjZTpvfX19KHQsbyxyLG4pO2RlbGV0ZSB0LnNka1Byb2Nlc3NpbmdNZXRhZGF0YTtyZXR1cm4gQXQocyxbW3t0eXBlOml9LHRdXSl9Y29uc3QgUHQ9Il9fU0VOVFJZX1NVUFBSRVNTX1RSQUNJTkdfXyI7ZnVuY3Rpb24gRHQodCl7Y29uc3Qgbj1jdChsKCkpO3JldHVybiBuLnN1cHByZXNzVHJhY2luZz9uLnN1cHByZXNzVHJhY2luZyh0KTpmdW5jdGlvbiguLi50KXtjb25zdCBuPWN0KGwoKSk7aWYoMj09PXQubGVuZ3RoKXtjb25zdFtlLHJdPXQ7cmV0dXJuIGU/bi53aXRoU2V0U2NvcGUoZSxyKTpuLndpdGhTY29wZShyKX1yZXR1cm4gbi53aXRoU2NvcGUodFswXSl9KG49PntuLnNldFNES1Byb2Nlc3NpbmdNZXRhZGF0YSh7W1B0XTohMH0pO2NvbnN0IGU9dCgpO3JldHVybiBuLnNldFNES1Byb2Nlc3NpbmdNZXRhZGF0YSh7W1B0XTp2b2lkIDB9KSxlfSl9Y2xhc3MgVXR7Y29uc3RydWN0b3IodCl7dGhpcy5XPTAsdGhpcy5GPVtdLHRoaXMuRyh0KX10aGVuKHQsbil7cmV0dXJuIG5ldyBVdCgoZSxyKT0+e3RoaXMuRi5wdXNoKFshMSxuPT57aWYodCl0cnl7ZSh0KG4pKX1jYXRjaCh0KXtyKHQpfWVsc2UgZShuKX0sdD0+e2lmKG4pdHJ5e2Uobih0KSl9Y2F0Y2godCl7cih0KX1lbHNlIHIodCl9XSksdGhpcy5IKCl9KX1jYXRjaCh0KXtyZXR1cm4gdGhpcy50aGVuKHQ9PnQsdCl9ZmluYWxseSh0KXtyZXR1cm4gbmV3IFV0KChuLGUpPT57bGV0IHIsbztyZXR1cm4gdGhpcy50aGVuKG49PntvPSExLHI9bix0JiZ0KCl9LG49PntvPSEwLHI9bix0JiZ0KCl9KS50aGVuKCgpPT57bz9lKHIpOm4ocil9KX0pfUgoKXtpZigwPT09dGhpcy5XKXJldHVybjtjb25zdCB0PXRoaXMuRi5zbGljZSgpO3RoaXMuRj1bXSx0LmZvckVhY2godD0+e3RbMF18fCgxPT09dGhpcy5XJiZ0WzFdKHRoaXMuSiksMj09PXRoaXMuVyYmdFsyXSh0aGlzLkopLHRbMF09ITApfSl9Ryh0KXtjb25zdCBuPSh0LG4pPT57MD09PXRoaXMuVyYmKGsobik/bi50aGVuKGUscik6KHRoaXMuVz10LHRoaXMuSj1uLHRoaXMuSCgpKSl9LGU9dD0+e24oMSx0KX0scj10PT57bigyLHQpfTt0cnl7dChlLHIpfWNhdGNoKHQpe3IodCl9fX1mdW5jdGlvbiBNdCh0LG4pe2NvbnN0e2ZpbmdlcnByaW50OmUsc3BhbjpyLGJyZWFkY3J1bWJzOm8sc2RrUHJvY2Vzc2luZ01ldGFkYXRhOml9PW47IWZ1bmN0aW9uKHQsbil7Y29uc3R7ZXh0cmE6ZSx0YWdzOnIsdXNlcjpvLGNvbnRleHRzOmksbGV2ZWw6cyx0cmFuc2FjdGlvbk5hbWU6Y309bjtPYmplY3Qua2V5cyhlKS5sZW5ndGgmJih0LmV4dHJhPXsuLi5lLC4uLnQuZXh0cmF9KTtPYmplY3Qua2V5cyhyKS5sZW5ndGgmJih0LnRhZ3M9ey4uLnIsLi4udC50YWdzfSk7T2JqZWN0LmtleXMobykubGVuZ3RoJiYodC51c2VyPXsuLi5vLC4uLnQudXNlcn0pO09iamVjdC5rZXlzKGkpLmxlbmd0aCYmKHQuY29udGV4dHM9ey4uLmksLi4udC5jb250ZXh0c30pO3MmJih0LmxldmVsPXMpO2MmJiJ0cmFuc2FjdGlvbiIhPT10LnR5cGUmJih0LnRyYW5zYWN0aW9uPWMpfSh0LG4pLHImJmZ1bmN0aW9uKHQsbil7dC5jb250ZXh0cz17dHJhY2U6eXQobiksLi4udC5jb250ZXh0c30sdC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE9e2R5bmFtaWNTYW1wbGluZ0NvbnRleHQ6RXQobiksLi4udC5zZGtQcm9jZXNzaW5nTWV0YWRhdGF9O2NvbnN0IGU9JHQobikscj13dChlKS5kZXNjcmlwdGlvbjtyJiYhdC50cmFuc2FjdGlvbiYmInRyYW5zYWN0aW9uIj09PXQudHlwZSYmKHQudHJhbnNhY3Rpb249cil9KHQsciksZnVuY3Rpb24odCxuKXt0LmZpbmdlcnByaW50PXQuZmluZ2VycHJpbnQ/QXJyYXkuaXNBcnJheSh0LmZpbmdlcnByaW50KT90LmZpbmdlcnByaW50Olt0LmZpbmdlcnByaW50XTpbXSxuJiYodC5maW5nZXJwcmludD10LmZpbmdlcnByaW50LmNvbmNhdChuKSk7dC5maW5nZXJwcmludC5sZW5ndGh8fGRlbGV0ZSB0LmZpbmdlcnByaW50fSh0LGUpLGZ1bmN0aW9uKHQsbil7Y29uc3QgZT1bLi4udC5icmVhZGNydW1ic3x8W10sLi4ubl07dC5icmVhZGNydW1icz1lLmxlbmd0aD9lOnZvaWQgMH0odCxvKSxmdW5jdGlvbih0LG4pe3Quc2RrUHJvY2Vzc2luZ01ldGFkYXRhPXsuLi50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YSwuLi5ufX0odCxpKX1jb25zdCBMdD1TeW1ib2wuZm9yKCJTZW50cnlCdWZmZXJGdWxsRXJyb3IiKTtmdW5jdGlvbiBCdCh0PTEwMCl7Y29uc3Qgbj1uZXcgU2V0O2Z1bmN0aW9uIGUodCl7bi5kZWxldGUodCl9cmV0dXJue2dldCAkKCl7cmV0dXJuIEFycmF5LmZyb20obil9LGFkZDpmdW5jdGlvbihyKXtpZighKG4uc2l6ZTx0KSlyZXR1cm4gbz1MdCxuZXcgVXQoKHQsbik9PntuKG8pfSk7dmFyIG87Y29uc3QgaT1yKCk7cmV0dXJuIG4uYWRkKGkpLGkudGhlbigoKT0+ZShpKSwoKT0+ZShpKSksaX0sZHJhaW46ZnVuY3Rpb24odCl7aWYoIW4uc2l6ZSlyZXR1cm4gZT0hMCxuZXcgVXQodD0+e3QoZSl9KTt2YXIgZTtjb25zdCByPVByb21pc2UuYWxsU2V0dGxlZChBcnJheS5mcm9tKG4pKS50aGVuKCgpPT4hMCk7aWYoIXQpcmV0dXJuIHI7Y29uc3Qgbz1bcixuZXcgUHJvbWlzZShuPT57cmV0dXJuIm9iamVjdCI9PXR5cGVvZihlPXNldFRpbWVvdXQoKCk9Pm4oITEpLHQpKSYmImZ1bmN0aW9uIj09dHlwZW9mIGUudW5yZWYmJmUudW5yZWYoKSxlO3ZhciBlfSldO3JldHVybiBQcm9taXNlLnJhY2Uobyl9fX1mdW5jdGlvbiBXdCh0LHtzdGF0dXNDb2RlOm4saGVhZGVyczplfSxyPVcoKSl7Y29uc3Qgbz17Li4udH0saT1lPy5bIngtc2VudHJ5LXJhdGUtbGltaXRzIl0scz1lPy5bInJldHJ5LWFmdGVyIl07aWYoaSlmb3IoY29uc3QgdCBvZiBpLnRyaW0oKS5zcGxpdCgiLCIpKXtjb25zdFtuLGUsLCxpXT10LnNwbGl0KCI6Iiw1KSxzPXBhcnNlSW50KG4sMTApLGM9MWUzKihpc05hTihzKT82MDpzKTtpZihlKWZvcihjb25zdCB0IG9mIGUuc3BsaXQoIjsiKSkibWV0cmljX2J1Y2tldCI9PT10JiZpJiYhaS5zcGxpdCgiOyIpLmluY2x1ZGVzKCJjdXN0b20iKXx8KG9bdF09citjKTtlbHNlIG8uYWxsPXIrY31lbHNlIHM/by5hbGw9citmdW5jdGlvbih0LG49VygpKXtjb25zdCBlPXBhcnNlSW50KGAke3R9YCwxMCk7aWYoIWlzTmFOKGUpKXJldHVybiAxZTMqZTtjb25zdCByPURhdGUucGFyc2UoYCR7dH1gKTtyZXR1cm4gaXNOYU4ocik/NmU0OnItbn0ocyxyKTo0Mjk9PT1uJiYoby5hbGw9cis2ZTQpO3JldHVybiBvfWZ1bmN0aW9uIHp0KHQsbixlPUJ0KHQuYnVmZmVyU2l6ZXx8NjQpKXtsZXQgcj17fTtyZXR1cm57c2VuZDpmdW5jdGlvbih0KXtjb25zdCBvPVtdO2lmKGp0KHQsKHQsbik9Pntjb25zdCBlPWZ1bmN0aW9uKHQpe3JldHVybiBJdFt0XX0obik7KGZ1bmN0aW9uKHQsbixlPVcoKSl7cmV0dXJuIGZ1bmN0aW9uKHQsbil7cmV0dXJuIHRbbl18fHQuYWxsfHwwfSh0LG4pPmV9KShyLGUpfHxvLnB1c2godCl9KSwwPT09by5sZW5ndGgpcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7fSk7Y29uc3QgaT1BdCh0WzBdLG8pLHM9dD0+eyFmdW5jdGlvbih0LG4pe3JldHVybiBqdCh0LCh0LGUpPT5uLmluY2x1ZGVzKGUpKX0oaSxbImNsaWVudF9yZXBvcnQiXSk/anQoaSwodCxuKT0+e30pOmgmJlMud2FybihgRHJvcHBpbmcgY2xpZW50IHJlcG9ydC4gV2lsbCBub3Qgc2VuZCBvdXRjb21lcyAocmVhc29uOiAke3R9KS5gKX07cmV0dXJuIGUuYWRkKCgpPT5uKHtib2R5OlR0KGkpfSkudGhlbih0PT40MTM9PT10LnN0YXR1c0NvZGU/KGgmJlMuZXJyb3IoIlNlbnRyeSByZXNwb25kZWQgd2l0aCBzdGF0dXMgY29kZSA0MTMuIEVudmVsb3BlIHdhcyBkaXNjYXJkZWQgZHVlIHRvIGV4Y2VlZGluZyBzaXplIGxpbWl0cy4iKSxzKCJzZW5kX2Vycm9yIiksdCk6KGgmJnZvaWQgMCE9PXQuc3RhdHVzQ29kZSYmKHQuc3RhdHVzQ29kZTwyMDB8fHQuc3RhdHVzQ29kZT49MzAwKSYmUy53YXJuKGBTZW50cnkgcmVzcG9uZGVkIHdpdGggc3RhdHVzIGNvZGUgJHt0LnN0YXR1c0NvZGV9IHRvIHNlbnQgZXZlbnQuYCkscj1XdChyLHQpLHQpLHQ9Pnt0aHJvdyBzKCJuZXR3b3JrX2Vycm9yIiksaCYmUy5lcnJvcigiRW5jb3VudGVyZWQgZXJyb3IgcnVubmluZyB0cmFuc3BvcnQgcmVxdWVzdDoiLHQpLHR9KSkudGhlbih0PT50LHQ9PntpZih0PT09THQpcmV0dXJuIGgmJlMuZXJyb3IoIlNraXBwZWQgc2VuZGluZyBldmVudCBiZWNhdXNlIGJ1ZmZlciBpcyBmdWxsLiIpLHMoInF1ZXVlX292ZXJmbG93IiksUHJvbWlzZS5yZXNvbHZlKHt9KTt0aHJvdyB0fSl9LGZsdXNoOnQ9PmUuZHJhaW4odCl9fWNvbnN0IEZ0PS9eKFxTKzpcXHxcLz8pKFtcc1xTXSo/KSgoPzpcLnsxLDJ9fFteL1xcXSs/fCkoXC5bXi4vXFxdKnwpKSg/OlsvXFxdKikkLztmdW5jdGlvbiBHdCh0KXtjb25zdCBuPWZ1bmN0aW9uKHQpe2NvbnN0IG49dC5sZW5ndGg+MTAyND9gPHRydW5jYXRlZD4ke3Quc2xpY2UoLTEwMjQpfWA6dCxlPUZ0LmV4ZWMobik7cmV0dXJuIGU/ZS5zbGljZSgxKTpbXX0odCksZT1uWzBdfHwiIjtsZXQgcj1uWzFdO3JldHVybiBlfHxyPyhyJiYocj1yLnNsaWNlKDAsci5sZW5ndGgtMSkpLGUrcik6Ii4ifWZ1bmN0aW9uIEh0KHQsbj0hMSl7cmV0dXJuIShufHx0JiYhdC5zdGFydHNXaXRoKCIvIikmJiF0Lm1hdGNoKC9eW0EtWl06LykmJiF0LnN0YXJ0c1dpdGgoIi4iKSYmIXQubWF0Y2goL15bYS16QS1aXShbYS16QS1aMC05LlwtK10pKjpcL1wvLykpJiZ2b2lkIDAhPT10JiYhdC5pbmNsdWRlcygibm9kZV9tb2R1bGVzLyIpfWNvbnN0IEp0PVN5bWJvbCgiQWdlbnRCYXNlSW50ZXJuYWxTdGF0ZSIpO2NsYXNzIFl0IGV4dGVuZHMgaS5BZ2VudHtjb25zdHJ1Y3Rvcih0KXtzdXBlcih0KSx0aGlzW0p0XT17fX1pc1NlY3VyZUVuZHBvaW50KHQpe2lmKHQpe2lmKCJib29sZWFuIj09dHlwZW9mIHQuc2VjdXJlRW5kcG9pbnQpcmV0dXJuIHQuc2VjdXJlRW5kcG9pbnQ7aWYoInN0cmluZyI9PXR5cGVvZiB0LnByb3RvY29sKXJldHVybiJodHRwczoiPT09dC5wcm90b2NvbH1jb25zdHtzdGFjazpufT1uZXcgRXJyb3I7cmV0dXJuInN0cmluZyI9PXR5cGVvZiBuJiZuLnNwbGl0KCJcbiIpLnNvbWUodD0+LTEhPT10LmluZGV4T2YoIihodHRwcy5qczoiKXx8LTEhPT10LmluZGV4T2YoIm5vZGU6aHR0cHM6IikpfWNyZWF0ZVNvY2tldCh0LG4sZSl7Y29uc3Qgcj17Li4ubixzZWN1cmVFbmRwb2ludDp0aGlzLmlzU2VjdXJlRW5kcG9pbnQobil9O1Byb21pc2UucmVzb2x2ZSgpLnRoZW4oKCk9PnRoaXMuY29ubmVjdCh0LHIpKS50aGVuKG89PntpZihvIGluc3RhbmNlb2YgaS5BZ2VudClyZXR1cm4gby5hZGRSZXF1ZXN0KHQscik7dGhpc1tKdF0uY3VycmVudFNvY2tldD1vLHN1cGVyLmNyZWF0ZVNvY2tldCh0LG4sZSl9LGUpfWNyZWF0ZUNvbm5lY3Rpb24oKXtjb25zdCB0PXRoaXNbSnRdLmN1cnJlbnRTb2NrZXQ7aWYodGhpc1tKdF0uY3VycmVudFNvY2tldD12b2lkIDAsIXQpdGhyb3cgbmV3IEVycm9yKCJObyBzb2NrZXQgd2FzIHJldHVybmVkIGluIHRoZSBgY29ubmVjdCgpYCBmdW5jdGlvbiIpO3JldHVybiB0fWdldCBkZWZhdWx0UG9ydCgpe3JldHVybiB0aGlzW0p0XS5kZWZhdWx0UG9ydD8/KCJodHRwczoiPT09dGhpcy5wcm90b2NvbD80NDM6ODApfXNldCBkZWZhdWx0UG9ydCh0KXt0aGlzW0p0XSYmKHRoaXNbSnRdLmRlZmF1bHRQb3J0PXQpfWdldCBwcm90b2NvbCgpe3JldHVybiB0aGlzW0p0XS5wcm90b2NvbD8/KHRoaXMuaXNTZWN1cmVFbmRwb2ludCgpPyJodHRwczoiOiJodHRwOiIpfXNldCBwcm90b2NvbCh0KXt0aGlzW0p0XSYmKHRoaXNbSnRdLnByb3RvY29sPXQpfX1mdW5jdGlvbiBWdCguLi50KXtTLmxvZygiW2h0dHBzLXByb3h5LWFnZW50OnBhcnNlLXByb3h5LXJlc3BvbnNlXSIsLi4udCl9ZnVuY3Rpb24gS3QodCl7cmV0dXJuIG5ldyBQcm9taXNlKChuLGUpPT57bGV0IHI9MDtjb25zdCBvPVtdO2Z1bmN0aW9uIGkoKXtjb25zdCBjPXQucmVhZCgpO2M/ZnVuY3Rpb24oYyl7by5wdXNoKGMpLHIrPWMubGVuZ3RoO2NvbnN0IHU9QnVmZmVyLmNvbmNhdChvLHIpLGE9dS5pbmRleE9mKCJcclxuXHJcbiIpO2lmKC0xPT09YSlyZXR1cm4gVnQoImhhdmUgbm90IHJlY2VpdmVkIGVuZCBvZiBIVFRQIGhlYWRlcnMgeWV0Li4uIiksdm9pZCBpKCk7Y29uc3QgZj11LnN1YmFycmF5KDAsYSkudG9TdHJpbmcoImFzY2lpIikuc3BsaXQoIlxyXG4iKSxoPWYuc2hpZnQoKTtpZighaClyZXR1cm4gdC5kZXN0cm95KCksZShuZXcgRXJyb3IoIk5vIGhlYWRlciByZWNlaXZlZCBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2UiKSk7Y29uc3QgcD1oLnNwbGl0KCIgIiksZD0rKHBbMV18fDApLGw9cC5zbGljZSgyKS5qb2luKCIgIiksbT17fTtmb3IoY29uc3QgbiBvZiBmKXtpZighbiljb250aW51ZTtjb25zdCByPW4uaW5kZXhPZigiOiIpO2lmKC0xPT09cilyZXR1cm4gdC5kZXN0cm95KCksZShuZXcgRXJyb3IoYEludmFsaWQgaGVhZGVyIGZyb20gcHJveHkgQ09OTkVDVCByZXNwb25zZTogIiR7bn0iYCkpO2NvbnN0IG89bi5zbGljZSgwLHIpLnRvTG93ZXJDYXNlKCksaT1uLnNsaWNlKHIrMSkudHJpbVN0YXJ0KCkscz1tW29dOyJzdHJpbmciPT10eXBlb2Ygcz9tW29dPVtzLGldOkFycmF5LmlzQXJyYXkocyk/cy5wdXNoKGkpOm1bb109aX1WdCgiZ290IHByb3h5IHNlcnZlciByZXNwb25zZTogJW8gJW8iLGgsbSkscygpLG4oe2Nvbm5lY3Q6e3N0YXR1c0NvZGU6ZCxzdGF0dXNUZXh0OmwsaGVhZGVyczptfSxidWZmZXJlZDp1fSl9KGMpOnQub25jZSgicmVhZGFibGUiLGkpfWZ1bmN0aW9uIHMoKXt0LnJlbW92ZUxpc3RlbmVyKCJlbmQiLGMpLHQucmVtb3ZlTGlzdGVuZXIoImVycm9yIix1KSx0LnJlbW92ZUxpc3RlbmVyKCJyZWFkYWJsZSIsaSl9ZnVuY3Rpb24gYygpe3MoKSxWdCgib25lbmQiKSxlKG5ldyBFcnJvcigiUHJveHkgY29ubmVjdGlvbiBlbmRlZCBiZWZvcmUgcmVjZWl2aW5nIENPTk5FQ1QgcmVzcG9uc2UiKSl9ZnVuY3Rpb24gdSh0KXtzKCksVnQoIm9uZXJyb3IgJW8iLHQpLGUodCl9dC5vbigiZXJyb3IiLHUpLHQub24oImVuZCIsYyksaSgpfSl9ZnVuY3Rpb24gWnQoLi4udCl7Uy5sb2coIltodHRwcy1wcm94eS1hZ2VudF0iLC4uLnQpfWNsYXNzIHF0IGV4dGVuZHMgWXR7c3RhdGljIF9faW5pdFN0YXRpYygpe3RoaXMucHJvdG9jb2xzPVsiaHR0cCIsImh0dHBzIl19Y29uc3RydWN0b3IodCxuKXtzdXBlcihuKSx0aGlzLm9wdGlvbnM9e30sdGhpcy5wcm94eT0ic3RyaW5nIj09dHlwZW9mIHQ/bmV3IFVSTCh0KTp0LHRoaXMucHJveHlIZWFkZXJzPW4/LmhlYWRlcnM/P3t9LFp0KCJDcmVhdGluZyBuZXcgSHR0cHNQcm94eUFnZW50IGluc3RhbmNlOiAlbyIsdGhpcy5wcm94eS5ocmVmKTtjb25zdCBlPSh0aGlzLnByb3h5Lmhvc3RuYW1lfHx0aGlzLnByb3h5Lmhvc3QpLnJlcGxhY2UoL15cW3xcXSQvZywiIikscj10aGlzLnByb3h5LnBvcnQ/cGFyc2VJbnQodGhpcy5wcm94eS5wb3J0LDEwKToiaHR0cHM6Ij09PXRoaXMucHJveHkucHJvdG9jb2w/NDQzOjgwO3RoaXMuY29ubmVjdE9wdHM9e0FMUE5Qcm90b2NvbHM6WyJodHRwLzEuMSJdLC4uLm4/WHQobiwiaGVhZGVycyIpOm51bGwsaG9zdDplLHBvcnQ6cn19YXN5bmMgY29ubmVjdCh0LG4pe2NvbnN0e3Byb3h5OmV9PXRoaXM7aWYoIW4uaG9zdCl0aHJvdyBuZXcgVHlwZUVycm9yKCdObyAiaG9zdCIgcHJvdmlkZWQnKTtsZXQgcjtpZigiaHR0cHM6Ij09PWUucHJvdG9jb2wpe1p0KCJDcmVhdGluZyBgdGxzLlNvY2tldGA6ICVvIix0aGlzLmNvbm5lY3RPcHRzKTtjb25zdCB0PXRoaXMuY29ubmVjdE9wdHMuc2VydmVybmFtZXx8dGhpcy5jb25uZWN0T3B0cy5ob3N0O3I9Zi5jb25uZWN0KHsuLi50aGlzLmNvbm5lY3RPcHRzLHNlcnZlcm5hbWU6dCYmYS5pc0lQKHQpP3ZvaWQgMDp0fSl9ZWxzZSBadCgiQ3JlYXRpbmcgYG5ldC5Tb2NrZXRgOiAlbyIsdGhpcy5jb25uZWN0T3B0cykscj1hLmNvbm5lY3QodGhpcy5jb25uZWN0T3B0cyk7Y29uc3Qgbz0iZnVuY3Rpb24iPT10eXBlb2YgdGhpcy5wcm94eUhlYWRlcnM/dGhpcy5wcm94eUhlYWRlcnMoKTp7Li4udGhpcy5wcm94eUhlYWRlcnN9LGk9YS5pc0lQdjYobi5ob3N0KT9gWyR7bi5ob3N0fV1gOm4uaG9zdDtsZXQgcz1gQ09OTkVDVCAke2l9OiR7bi5wb3J0fSBIVFRQLzEuMVxyXG5gO2lmKGUudXNlcm5hbWV8fGUucGFzc3dvcmQpe2NvbnN0IHQ9YCR7ZGVjb2RlVVJJQ29tcG9uZW50KGUudXNlcm5hbWUpfToke2RlY29kZVVSSUNvbXBvbmVudChlLnBhc3N3b3JkKX1gO29bIlByb3h5LUF1dGhvcml6YXRpb24iXT1gQmFzaWMgJHtCdWZmZXIuZnJvbSh0KS50b1N0cmluZygiYmFzZTY0Iil9YH1vLkhvc3Q9YCR7aX06JHtuLnBvcnR9YCxvWyJQcm94eS1Db25uZWN0aW9uIl18fChvWyJQcm94eS1Db25uZWN0aW9uIl09dGhpcy5rZWVwQWxpdmU/IktlZXAtQWxpdmUiOiJjbG9zZSIpO2Zvcihjb25zdCB0IG9mIE9iamVjdC5rZXlzKG8pKXMrPWAke3R9OiAke29bdF19XHJcbmA7Y29uc3QgYz1LdChyKTtyLndyaXRlKGAke3N9XHJcbmApO2NvbnN0e2Nvbm5lY3Q6dSxidWZmZXJlZDpofT1hd2FpdCBjO2lmKHQuZW1pdCgicHJveHlDb25uZWN0Iix1KSx0aGlzLmVtaXQoInByb3h5Q29ubmVjdCIsdSx0KSwyMDA9PT11LnN0YXR1c0NvZGUpe2lmKHQub25jZSgic29ja2V0IixRdCksbi5zZWN1cmVFbmRwb2ludCl7WnQoIlVwZ3JhZGluZyBzb2NrZXQgY29ubmVjdGlvbiB0byBUTFMiKTtjb25zdCB0PW4uc2VydmVybmFtZXx8bi5ob3N0O3JldHVybiBmLmNvbm5lY3Qoey4uLlh0KG4sImhvc3QiLCJwYXRoIiwicG9ydCIpLHNvY2tldDpyLHNlcnZlcm5hbWU6YS5pc0lQKHQpP3ZvaWQgMDp0fSl9cmV0dXJuIHJ9ci5kZXN0cm95KCk7Y29uc3QgcD1uZXcgYS5Tb2NrZXQoe3dyaXRhYmxlOiExfSk7cmV0dXJuIHAucmVhZGFibGU9ITAsdC5vbmNlKCJzb2NrZXQiLHQ9PntadCgiUmVwbGF5aW5nIHByb3h5IGJ1ZmZlciBmb3IgZmFpbGVkIHJlcXVlc3QiKSx0LnB1c2goaCksdC5wdXNoKG51bGwpfSkscH19ZnVuY3Rpb24gUXQodCl7dC5yZXN1bWUoKX1mdW5jdGlvbiBYdCh0LC4uLm4pe2NvbnN0IGU9e307bGV0IHI7Zm9yKHIgaW4gdCluLmluY2x1ZGVzKHIpfHwoZVtyXT10W3JdKTtyZXR1cm4gZX1xdC5fX2luaXRTdGF0aWMoKTtmdW5jdGlvbiB0bih0KXtyZXR1cm4gdC5yZXBsYWNlKC9eW0EtWl06LywiIikucmVwbGFjZSgvXFwvZywiLyIpfWNvbnN0IG5uPW47bGV0IGVuLHJuPTAsb249e307ZnVuY3Rpb24gc24odCl7bm4uZGVidWcmJmNvbnNvbGUubG9nKGBbQU5SIFdvcmtlcl0gJHt0fWApfXZhciBjbix1bixhbjtjb25zdCBmbj1mdW5jdGlvbih0KXtsZXQgbjt0cnl7bj1uZXcgVVJMKHQudXJsKX1jYXRjaChuKXtyZXR1cm4gYigoKT0+e2NvbnNvbGUud2FybigiW0BzZW50cnkvbm9kZV06IEludmFsaWQgZHNuIG9yIHR1bm5lbCBvcHRpb24sIHdpbGwgbm90IHNlbmQgYW55IGV2ZW50cy4gVGhlIHR1bm5lbCBvcHRpb24gbXVzdCBiZSBhIGZ1bGwgVVJMIHdoZW4gdXNlZC4iKX0pLHp0KHQsKCk9PlByb21pc2UucmVzb2x2ZSh7fSkpfWNvbnN0IGU9Imh0dHBzOiI9PT1uLnByb3RvY29sLHI9ZnVuY3Rpb24odCxuKXtjb25zdHtub19wcm94eTplfT1wcm9jZXNzLmVudixyPWU/LnNwbGl0KCIsIikuc29tZShuPT50Lmhvc3QuZW5kc1dpdGgobil8fHQuaG9zdG5hbWUuZW5kc1dpdGgobikpO3JldHVybiByP3ZvaWQgMDpufShuLHQucHJveHl8fChlP3Byb2Nlc3MuZW52Lmh0dHBzX3Byb3h5OnZvaWQgMCl8fHByb2Nlc3MuZW52Lmh0dHBfcHJveHkpLG89ZT9zOmksYT12b2lkIDAhPT10LmtlZXBBbGl2ZSYmdC5rZWVwQWxpdmUsZj1yP25ldyBxdChyKTpuZXcgby5BZ2VudCh7a2VlcEFsaXZlOmEsbWF4U29ja2V0czozMCx0aW1lb3V0OjJlM30pLGg9ZnVuY3Rpb24odCxuLGUpe2NvbnN0e2hvc3RuYW1lOnIscGF0aG5hbWU6byxwb3J0OmkscHJvdG9jb2w6cyxzZWFyY2g6YX09bmV3IFVSTCh0LnVybCk7cmV0dXJuIGZ1bmN0aW9uKGYpe3JldHVybiBuZXcgUHJvbWlzZSgoaCxwKT0+e0R0KCgpPT57bGV0IGQ9ZnVuY3Rpb24odCl7cmV0dXJuIG5ldyBjKHtyZWFkKCl7dGhpcy5wdXNoKHQpLHRoaXMucHVzaChudWxsKX19KX0oZi5ib2R5KTtjb25zdCBsPXsuLi50LmhlYWRlcnN9O2YuYm9keS5sZW5ndGg+MzI3NjgmJihsWyJjb250ZW50LWVuY29kaW5nIl09Imd6aXAiLGQ9ZC5waXBlKHUoKSkpO2NvbnN0IG09ci5zdGFydHNXaXRoKCJbIiksZz1uLnJlcXVlc3Qoe21ldGhvZDoiUE9TVCIsYWdlbnQ6ZSxoZWFkZXJzOmwsaG9zdG5hbWU6bT9yLnNsaWNlKDEsLTEpOnIscGF0aDpgJHtvfSR7YX1gLHBvcnQ6aSxwcm90b2NvbDpzLGNhOnQuY2FDZXJ0c30sdD0+e3Qub24oImRhdGEiLCgpPT57fSksdC5vbigiZW5kIiwoKT0+e30pLHQuc2V0RW5jb2RpbmcoInV0ZjgiKTtjb25zdCBuPXQuaGVhZGVyc1sicmV0cnktYWZ0ZXIiXT8/bnVsbCxlPXQuaGVhZGVyc1sieC1zZW50cnktcmF0ZS1saW1pdHMiXT8/bnVsbDtoKHtzdGF0dXNDb2RlOnQuc3RhdHVzQ29kZSxoZWFkZXJzOnsicmV0cnktYWZ0ZXIiOm4sIngtc2VudHJ5LXJhdGUtbGltaXRzIjpBcnJheS5pc0FycmF5KGUpP2VbMF18fG51bGw6ZX19KX0pO2cub24oImVycm9yIixwKSxkLnBpcGUoZyl9KX0pfX0odCx0Lmh0dHBNb2R1bGU/P28sZik7cmV0dXJuIHp0KHQsaCl9KHt1cmw6KGNuPW5uLmRzbix1bj1ubi50dW5uZWwsYW49bm4uc2RrTWV0YWRhdGEuc2RrLHVufHxgJHtmdW5jdGlvbih0KXtyZXR1cm5gJHtmdW5jdGlvbih0KXtjb25zdCBuPXQucHJvdG9jb2w/YCR7dC5wcm90b2NvbH06YDoiIixlPXQucG9ydD9gOiR7dC5wb3J0fWA6IiI7cmV0dXJuYCR7bn0vLyR7dC5ob3N0fSR7ZX0ke3QucGF0aD9gLyR7dC5wYXRofWA6IiJ9L2FwaS9gfSh0KX0ke3QucHJvamVjdElkfS9lbnZlbG9wZS9gfShjbil9PyR7ZnVuY3Rpb24odCxuKXtjb25zdCBlPXtzZW50cnlfdmVyc2lvbjoiNyJ9O3JldHVybiB0LnB1YmxpY0tleSYmKGUuc2VudHJ5X2tleT10LnB1YmxpY0tleSksbiYmKGUuc2VudHJ5X2NsaWVudD1gJHtuLm5hbWV9LyR7bi52ZXJzaW9ufWApLG5ldyBVUkxTZWFyY2hQYXJhbXMoZSkudG9TdHJpbmcoKX0oY24sYW4pfWApfSk7YXN5bmMgZnVuY3Rpb24gaG4oKXtpZihlbil7c24oIlNlbmRpbmcgYWJub3JtYWwgc2Vzc2lvbiIpLFYoZW4se3N0YXR1czoiYWJub3JtYWwiLGFibm9ybWFsX21lY2hhbmlzbToiYW5yX2ZvcmVncm91bmQiLHJlbGVhc2U6bm4ucmVsZWFzZSxlbnZpcm9ubWVudDpubi5lbnZpcm9ubWVudH0pO2NvbnN0IHQ9ZnVuY3Rpb24odCxuLGUscil7Y29uc3Qgbz1SdChlKTtyZXR1cm4gQXQoe3NlbnRfYXQ6KG5ldyBEYXRlKS50b0lTT1N0cmluZygpLC4uLm8mJntzZGs6b30sLi4uISFyJiZuJiZ7ZHNuOm10KG4pfX0sWyJhZ2dyZWdhdGVzImluIHQ/W3t0eXBlOiJzZXNzaW9ucyJ9LHRdOlt7dHlwZToic2Vzc2lvbiJ9LHQudG9KU09OKCldXSl9KGVuLG5uLmRzbixubi5zZGtNZXRhZGF0YSxubi50dW5uZWwpO3NuKEpTT04uc3RyaW5naWZ5KHQpKSxhd2FpdCBmbi5zZW5kKHQpO3RyeXtlPy5wb3N0TWVzc2FnZSgic2Vzc2lvbi1lbmRlZCIpfWNhdGNoe319fWZ1bmN0aW9uIHBuKHQpe2lmKCF0KXJldHVybjtjb25zdCBuPWZ1bmN0aW9uKHQpe2lmKCF0Lmxlbmd0aClyZXR1cm5bXTtjb25zdCBuPUFycmF5LmZyb20odCk7cmV0dXJuL3NlbnRyeVdyYXBwZWQvLnRlc3QoRShuKS5mdW5jdGlvbnx8IiIpJiZuLnBvcCgpLG4ucmV2ZXJzZSgpLCQudGVzdChFKG4pLmZ1bmN0aW9ufHwiIikmJihuLnBvcCgpLCQudGVzdChFKG4pLmZ1bmN0aW9ufHwiIikmJm4ucG9wKCkpLG4uc2xpY2UoMCw1MCkubWFwKHQ9Pih7Li4udCxmaWxlbmFtZTp0LmZpbGVuYW1lfHxFKG4pLmZpbGVuYW1lLGZ1bmN0aW9uOnQuZnVuY3Rpb258fCI/In0pKX0odCk7aWYobm4uYXBwUm9vdFBhdGgpZm9yKGNvbnN0IHQgb2Ygbil0LmZpbGVuYW1lJiYodC5maWxlbmFtZT1DdCh0LmZpbGVuYW1lLG5uLmFwcFJvb3RQYXRoKSk7cmV0dXJuIG59YXN5bmMgZnVuY3Rpb24gZG4odCxuKXtpZihybj49bm4ubWF4QW5yRXZlbnRzKXJldHVybjtybis9MSxhd2FpdCBobigpLHNuKCJTZW5kaW5nIGV2ZW50Iik7Y29uc3QgZT17ZXZlbnRfaWQ6RigpLGNvbnRleHRzOm5uLmNvbnRleHRzLHJlbGVhc2U6bm4ucmVsZWFzZSxlbnZpcm9ubWVudDpubi5lbnZpcm9ubWVudCxkaXN0Om5uLmRpc3QscGxhdGZvcm06Im5vZGUiLGxldmVsOiJlcnJvciIsZXhjZXB0aW9uOnt2YWx1ZXM6W3t0eXBlOiJBcHBsaWNhdGlvbk5vdFJlc3BvbmRpbmciLHZhbHVlOmBBcHBsaWNhdGlvbiBOb3QgUmVzcG9uZGluZyBmb3IgYXQgbGVhc3QgJHtubi5hbnJUaHJlc2hvbGR9IG1zYCxzdGFja3RyYWNlOntmcmFtZXM6cG4odCl9LG1lY2hhbmlzbTp7dHlwZToiQU5SIn19XX0sdGFnczpubi5zdGF0aWNUYWdzfTtuJiZmdW5jdGlvbih0LG4pe2lmKE10KHQsbiksIXQuY29udGV4dHM/LnRyYWNlKXtjb25zdHt0cmFjZUlkOmUscGFyZW50U3BhbklkOnIscHJvcGFnYXRpb25TcGFuSWQ6b309bi5wcm9wYWdhdGlvbkNvbnRleHQ7dC5jb250ZXh0cz17dHJhY2U6e3RyYWNlX2lkOmUsc3Bhbl9pZDpvfHxxKCkscGFyZW50X3NwYW5faWQ6cn0sLi4udC5jb250ZXh0c319fShlLG4pLGZ1bmN0aW9uKHQpe2lmKDA9PT1PYmplY3Qua2V5cyhvbikubGVuZ3RoKXJldHVybjtjb25zdCBuPW5uLmFwcFJvb3RQYXRoP3t9Om9uO2lmKG5uLmFwcFJvb3RQYXRoKWZvcihjb25zdFt0LGVdb2YgT2JqZWN0LmVudHJpZXMob24pKW5bQ3QodCxubi5hcHBSb290UGF0aCldPWU7Y29uc3QgZT1uZXcgTWFwO2Zvcihjb25zdCByIG9mIHQuZXhjZXB0aW9uPy52YWx1ZXN8fFtdKWZvcihjb25zdCB0IG9mIHIuc3RhY2t0cmFjZT8uZnJhbWVzfHxbXSl7Y29uc3Qgcj10LmFic19wYXRofHx0LmZpbGVuYW1lO3ImJm5bcl0mJmUuc2V0KHIsbltyXSl9aWYoZS5zaXplPjApe2NvbnN0IG49W107Zm9yKGNvbnN0W3Qscl1vZiBlLmVudHJpZXMoKSluLnB1c2goe3R5cGU6InNvdXJjZW1hcCIsY29kZV9maWxlOnQsZGVidWdfaWQ6cn0pO3QuZGVidWdfbWV0YT17aW1hZ2VzOm59fX0oZSk7Y29uc3Qgcj1PdChlLG5uLmRzbixubi5zZGtNZXRhZGF0YSxubi50dW5uZWwpO3NuKEpTT04uc3RyaW5naWZ5KHIpKSxhd2FpdCBmbi5zZW5kKHIpLGF3YWl0IGZuLmZsdXNoKDJlMykscm4+PW5uLm1heEFuckV2ZW50cyYmc2V0VGltZW91dCgoKT0+e3Byb2Nlc3MuZXhpdCgwKX0sNWUzKX1sZXQgbG47aWYoc24oIlN0YXJ0ZWQiKSxubi5jYXB0dXJlU3RhY2tUcmFjZSl7c24oIkNvbm5lY3RpbmcgdG8gZGVidWdnZXIiKTtjb25zdCBuPW5ldyB0O24uY29ubmVjdFRvTWFpblRocmVhZCgpLHNuKCJDb25uZWN0ZWQgdG8gZGVidWdnZXIiKTtjb25zdCBlPW5ldyBNYXA7bi5vbigiRGVidWdnZXIuc2NyaXB0UGFyc2VkIix0PT57ZS5zZXQodC5wYXJhbXMuc2NyaXB0SWQsdC5wYXJhbXMudXJsKX0pLG4ub24oIkRlYnVnZ2VyLnBhdXNlZCIsdD0+e2lmKCJvdGhlciI9PT10LnBhcmFtcy5yZWFzb24pdHJ5e3NuKCJEZWJ1Z2dlciBwYXVzZWQiKTtjb25zdCBpPVsuLi50LnBhcmFtcy5jYWxsRnJhbWVzXSxzPW5uLmFwcFJvb3RQYXRoP2Z1bmN0aW9uKHQ9KHByb2Nlc3MuYXJndlsxXT9HdChwcm9jZXNzLmFyZ3ZbMV0pOnByb2Nlc3MuY3dkKCkpLG49IlxcIj09PW8pe2NvbnN0IGU9bj90bih0KTp0O3JldHVybiB0PT57aWYoIXQpcmV0dXJuO2NvbnN0IG89bj90bih0KTp0O2xldHtkaXI6aSxiYXNlOnMsZXh0OmN9PXIucGFyc2Uobyk7Ii5qcyIhPT1jJiYiLm1qcyIhPT1jJiYiLmNqcyIhPT1jfHwocz1zLnNsaWNlKDAsLTEqYy5sZW5ndGgpKTtjb25zdCB1PWRlY29kZVVSSUNvbXBvbmVudChzKTtpfHwoaT0iLiIpO2NvbnN0IGE9aS5sYXN0SW5kZXhPZigiL25vZGVfbW9kdWxlcyIpO2lmKGE+LTEpcmV0dXJuYCR7aS5zbGljZShhKzE0KS5yZXBsYWNlKC9cLy9nLCIuIil9OiR7dX1gO2lmKGkuc3RhcnRzV2l0aChlKSl7Y29uc3QgdD1pLnNsaWNlKGUubGVuZ3RoKzEpLnJlcGxhY2UoL1wvL2csIi4iKTtyZXR1cm4gdD9gJHt0fToke3V9YDp1fXJldHVybiB1fX0obm4uYXBwUm9vdFBhdGgpOigpPT57fSxjPWkubWFwKHQ9PmZ1bmN0aW9uKHQsbixlKXtjb25zdCByPW4/bi5yZXBsYWNlKC9eZmlsZTpcL1wvLywiIik6dm9pZCAwLG89dC5sb2NhdGlvbi5jb2x1bW5OdW1iZXI/dC5sb2NhdGlvbi5jb2x1bW5OdW1iZXIrMTp2b2lkIDAsaT10LmxvY2F0aW9uLmxpbmVOdW1iZXI/dC5sb2NhdGlvbi5saW5lTnVtYmVyKzE6dm9pZCAwO3JldHVybntmaWxlbmFtZTpyLG1vZHVsZTplKHIpLGZ1bmN0aW9uOnQuZnVuY3Rpb25OYW1lfHwiPyIsY29sbm86byxsaW5lbm86aSxpbl9hcHA6cj9IdChyKTp2b2lkIDB9fSh0LGUuZ2V0KHQubG9jYXRpb24uc2NyaXB0SWQpLHMpKSx1PXNldFRpbWVvdXQoKCk9PntkbihjKS50aGVuKG51bGwsKCk9PntzbigiU2VuZGluZyBBTlIgZXZlbnQgZmFpbGVkLiIpfSl9LDVlMyk7bi5wb3N0KCJSdW50aW1lLmV2YWx1YXRlIix7ZXhwcmVzc2lvbjoiZ2xvYmFsLl9fU0VOVFJZX0dFVF9TQ09QRVNfXygpOyIsc2lsZW50OiEwLHJldHVybkJ5VmFsdWU6ITB9LCh0LGUpPT57dCYmc24oYEVycm9yIGV4ZWN1dGluZyBzY3JpcHQ6ICcke3QubWVzc2FnZX0nYCksY2xlYXJUaW1lb3V0KHUpO2NvbnN0IHI9ZT8ucmVzdWx0P2UucmVzdWx0LnZhbHVlOnZvaWQgMDtuLnBvc3QoIkRlYnVnZ2VyLnJlc3VtZSIpLG4ucG9zdCgiRGVidWdnZXIuZGlzYWJsZSIpLGRuKGMscikudGhlbihudWxsLCgpPT57c24oIlNlbmRpbmcgQU5SIGV2ZW50IGZhaWxlZC4iKX0pfSl9Y2F0Y2godCl7dGhyb3cgbi5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKSxuLnBvc3QoIkRlYnVnZ2VyLmRpc2FibGUiKSx0fX0pLGxuPSgpPT57dHJ5e24ucG9zdCgiRGVidWdnZXIuZW5hYmxlIiwoKT0+e24ucG9zdCgiRGVidWdnZXIucGF1c2UiKX0pfWNhdGNoe319fWNvbnN0e3BvbGw6bW59PWZ1bmN0aW9uKHQsbixlLHIpe2NvbnN0IG89dCgpO2xldCBpPSExLHM9ITA7cmV0dXJuIHNldEludGVydmFsKCgpPT57Y29uc3QgdD1vLmdldFRpbWVNcygpOyExPT09aSYmdD5uK2UmJihpPSEwLHMmJnIoKSksdDxuK2UmJihpPSExKX0sMjApLHtwb2xsOigpPT57by5yZXNldCgpfSxlbmFibGVkOnQ9PntzPXR9fX0oZnVuY3Rpb24oKXtsZXQgdD1wcm9jZXNzLmhydGltZSgpO3JldHVybntnZXRUaW1lTXM6KCk9Pntjb25zdFtuLGVdPXByb2Nlc3MuaHJ0aW1lKHQpO3JldHVybiBNYXRoLmZsb29yKDFlMypuK2UvMWU2KX0scmVzZXQ6KCk9Pnt0PXByb2Nlc3MuaHJ0aW1lKCl9fX0sbm4ucG9sbEludGVydmFsLG5uLmFuclRocmVzaG9sZCxmdW5jdGlvbigpe3NuKCJXYXRjaGRvZyB0aW1lb3V0IiksbG4/KHNuKCJQYXVzaW5nIGRlYnVnZ2VyIHRvIGNhcHR1cmUgc3RhY2sgdHJhY2UiKSxsbigpKTooc24oIkNhcHR1cmluZyBldmVudCB3aXRob3V0IGEgc3RhY2sgdHJhY2UiKSxkbigpLnRoZW4obnVsbCwoKT0+e3NuKCJTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQgb24gd2F0Y2hkb2cgdGltZW91dC4iKX0pKX0pO2U/Lm9uKCJtZXNzYWdlIix0PT57dC5zZXNzaW9uJiYoZW49WSh0LnNlc3Npb24pKSx0LmRlYnVnSW1hZ2VzJiYob249dC5kZWJ1Z0ltYWdlcyksbW4oKX0pOw==";
55902
55902
  var DEFAULT_INTERVAL = 50;
55903
55903
  var DEFAULT_HANG_THRESHOLD = 5000;
55904
- function log19(message2, ...args) {
55904
+ function log18(message2, ...args) {
55905
55905
  core.debug.log(`[ANR] ${message2}`, ...args);
55906
55906
  }
55907
55907
  function globalWithScopeFetchFn() {
@@ -56014,17 +56014,17 @@ var require_anr2 = __commonJS((exports) => {
56014
56014
  timer.unref();
56015
56015
  worker.on("message", (msg) => {
56016
56016
  if (msg === "session-ended") {
56017
- log19("ANR event sent from ANR worker. Clearing session in this thread.");
56017
+ log18("ANR event sent from ANR worker. Clearing session in this thread.");
56018
56018
  core.getIsolationScope().setSession(undefined);
56019
56019
  }
56020
56020
  });
56021
56021
  worker.once("error", (err) => {
56022
56022
  clearInterval(timer);
56023
- log19("ANR worker error", err);
56023
+ log18("ANR worker error", err);
56024
56024
  });
56025
56025
  worker.once("exit", (code) => {
56026
56026
  clearInterval(timer);
56027
- log19("ANR worker exit", code);
56027
+ log18("ANR worker exit", code);
56028
56028
  });
56029
56029
  worker.unref();
56030
56030
  return () => {
@@ -61142,10 +61142,10 @@ globstar while`, file, fr, pattern, pr, swallowee);
61142
61142
  }
61143
61143
  return filtered.join("/");
61144
61144
  }).join("|");
61145
- const [open2, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
61146
- re = "^" + open2 + re + close + "$";
61145
+ const [open, close] = set.length > 1 ? ["(?:", ")"] : ["", ""];
61146
+ re = "^" + open + re + close + "$";
61147
61147
  if (this.partial) {
61148
- re = "^(?:\\/|" + open2 + re.slice(1, -1) + close + ")$";
61148
+ re = "^(?:\\/|" + open + re.slice(1, -1) + close + ")$";
61149
61149
  }
61150
61150
  if (this.negate)
61151
61151
  re = "^(?!" + re + ").+$";
@@ -66880,7 +66880,7 @@ var require_instrumentation17 = __commonJS((exports) => {
66880
66880
  _getClientConnectPatch() {
66881
66881
  const plugin = this;
66882
66882
  return (original) => {
66883
- return function connect2(callback) {
66883
+ return function connect3(callback) {
66884
66884
  const config2 = plugin.getConfig();
66885
66885
  if (utils.shouldSkipInstrumentation(config2) || config2.ignoreConnectSpans) {
66886
66886
  return original.call(this, callback);
@@ -67067,7 +67067,7 @@ var require_instrumentation17 = __commonJS((exports) => {
67067
67067
  _getPoolConnectPatch() {
67068
67068
  const plugin = this;
67069
67069
  return (originalConnect) => {
67070
- return function connect2(callback) {
67070
+ return function connect3(callback) {
67071
67071
  const config2 = plugin.getConfig();
67072
67072
  if (utils.shouldSkipInstrumentation(config2)) {
67073
67073
  return originalConnect.call(this, callback);
@@ -73240,7 +73240,7 @@ var require_tracing2 = __commonJS((exports) => {
73240
73240
  var http = require_http4();
73241
73241
  var amqplib = require_amqplib2();
73242
73242
  var index$6 = require_anthropic_ai2();
73243
- var connect2 = require_connect2();
73243
+ var connect3 = require_connect2();
73244
73244
  var express = require_express();
73245
73245
  var index = require_fastify();
73246
73246
  var firebase = require_firebase();
@@ -73280,7 +73280,7 @@ var require_tracing2 = __commonJS((exports) => {
73280
73280
  prisma.prismaIntegration(),
73281
73281
  index$1.hapiIntegration(),
73282
73282
  koa.koaIntegration(),
73283
- connect2.connectIntegration(),
73283
+ connect3.connectIntegration(),
73284
73284
  tedious.tediousIntegration(),
73285
73285
  genericPool.genericPoolIntegration(),
73286
73286
  kafka.kafkaIntegration(),
@@ -73301,7 +73301,7 @@ var require_tracing2 = __commonJS((exports) => {
73301
73301
  http.instrumentSentryHttp,
73302
73302
  http.instrumentOtelHttp,
73303
73303
  express.instrumentExpress,
73304
- connect2.instrumentConnect,
73304
+ connect3.instrumentConnect,
73305
73305
  index.instrumentFastify,
73306
73306
  index.instrumentFastifyV3,
73307
73307
  index$1.instrumentHapi,
@@ -73486,7 +73486,7 @@ var require_cjs4 = __commonJS((exports) => {
73486
73486
  var index$5 = require_hapi();
73487
73487
  var index$6 = require_hono();
73488
73488
  var koa = require_koa();
73489
- var connect2 = require_connect2();
73489
+ var connect3 = require_connect2();
73490
73490
  var knex = require_knex();
73491
73491
  var tedious = require_tedious();
73492
73492
  var genericPool = require_genericPool();
@@ -73535,8 +73535,8 @@ var require_cjs4 = __commonJS((exports) => {
73535
73535
  exports.setupHonoErrorHandler = index$6.setupHonoErrorHandler;
73536
73536
  exports.koaIntegration = koa.koaIntegration;
73537
73537
  exports.setupKoaErrorHandler = koa.setupKoaErrorHandler;
73538
- exports.connectIntegration = connect2.connectIntegration;
73539
- exports.setupConnectErrorHandler = connect2.setupConnectErrorHandler;
73538
+ exports.connectIntegration = connect3.connectIntegration;
73539
+ exports.setupConnectErrorHandler = connect3.setupConnectErrorHandler;
73540
73540
  exports.knexIntegration = knex.knexIntegration;
73541
73541
  exports.tediousIntegration = tedious.tediousIntegration;
73542
73542
  exports.genericPoolIntegration = genericPool.genericPoolIntegration;
@@ -75335,6 +75335,13 @@ function createOmniClient(config) {
75335
75335
  throw OmniApiError.from(json, resp.status);
75336
75336
  return { items: json?.items ?? [], meta: json?.meta ?? { totalFetched: 0, hasMore: false } };
75337
75337
  },
75338
+ async listGroupMembers(id, groupJid) {
75339
+ const resp = await apiFetch(`${baseUrl}/api/v2/instances/${id}/groups/${encodeURIComponent(groupJid)}/members`, {});
75340
+ const json = await resp.json();
75341
+ if (!resp.ok)
75342
+ throw OmniApiError.from(json, resp.status);
75343
+ return { members: json?.members ?? [] };
75344
+ },
75338
75345
  async getUserProfile(id, userId) {
75339
75346
  const resp = await apiFetch(`${baseUrl}/api/v2/instances/${id}/users/${userId}/profile`, {});
75340
75347
  const json = await resp.json();
@@ -76643,8 +76650,8 @@ import { fileURLToPath } from "url";
76643
76650
  // package.json
76644
76651
  var package_default = {
76645
76652
  name: "@automagik/omni",
76646
- version: "2.260326.1",
76647
- description: "LLM-optimized CLI for Omni v2",
76653
+ version: "2.260331.1",
76654
+ description: "LLM-optimized CLI for Omni",
76648
76655
  type: "module",
76649
76656
  bin: {
76650
76657
  omni: "./bin/omni"
@@ -78314,6 +78321,221 @@ function createBatchCommand() {
78314
78321
  return batch;
78315
78322
  }
78316
78323
 
78324
+ // src/commands/channels.ts
78325
+ import * as readline from "readline";
78326
+ init_config();
78327
+ async function apiCall(path, method = "GET", body) {
78328
+ const config = loadConfig();
78329
+ const baseUrl = (config.apiUrl ?? "http://localhost:8882").replace(/\/$/, "");
78330
+ const apiKey = config.apiKey ?? "";
78331
+ const headers = { "x-api-key": apiKey };
78332
+ if (body)
78333
+ headers["Content-Type"] = "application/json";
78334
+ const resp = await fetch(`${baseUrl}/api/v2/${path}`, {
78335
+ method,
78336
+ headers,
78337
+ body: body ? JSON.stringify(body) : undefined
78338
+ });
78339
+ if (!resp.ok) {
78340
+ const err = await resp.json();
78341
+ throw new Error(err?.error?.message ?? `API error: ${resp.status}`);
78342
+ }
78343
+ return resp.json();
78344
+ }
78345
+ function promptUser(question) {
78346
+ const rl = readline.createInterface({
78347
+ input: process.stdin,
78348
+ output: process.stderr
78349
+ });
78350
+ return new Promise((resolve) => {
78351
+ rl.question(question, (answer) => {
78352
+ rl.close();
78353
+ resolve(answer.trim());
78354
+ });
78355
+ });
78356
+ }
78357
+ function buildStatusItems(instances) {
78358
+ return instances.map((inst) => ({
78359
+ channel: inst.channel,
78360
+ name: inst.name,
78361
+ active: inst.isActive ? "yes" : "no",
78362
+ profile: inst.profileName ?? "-"
78363
+ }));
78364
+ }
78365
+ function createChannelsCommand() {
78366
+ const channels = new Command("channels").description("Channel management \u2014 list types, add instances, check status");
78367
+ channels.command("list").description("Show available channel types and instance counts").action(async () => {
78368
+ const client = getClient();
78369
+ try {
78370
+ const supported = await apiCall("instances/supported-channels");
78371
+ const instanceResult = await client.instances.list({ limit: 100 });
78372
+ const instancesByChannel = new Map;
78373
+ const connectedByChannel = new Map;
78374
+ for (const inst of instanceResult.items) {
78375
+ const ch = inst.channel;
78376
+ instancesByChannel.set(ch, (instancesByChannel.get(ch) ?? 0) + 1);
78377
+ if (inst.isActive) {
78378
+ connectedByChannel.set(ch, (connectedByChannel.get(ch) ?? 0) + 1);
78379
+ }
78380
+ }
78381
+ const items = supported.items.map((ch) => {
78382
+ const total = instancesByChannel.get(ch.id) ?? 0;
78383
+ const connected = connectedByChannel.get(ch.id) ?? 0;
78384
+ return {
78385
+ channel: ch.id,
78386
+ name: ch.name,
78387
+ status: ch.loaded ? "loaded" : "not loaded",
78388
+ instances: total > 0 ? `${total} (${connected} active)` : "0"
78389
+ };
78390
+ });
78391
+ list(items, { emptyMessage: "No channels available." });
78392
+ } catch (err) {
78393
+ const message = err instanceof Error ? err.message : "Unknown error";
78394
+ error(`Failed to list channels: ${message}`);
78395
+ }
78396
+ });
78397
+ channels.command("add <type>").description("Add a new channel instance (interactive setup)").option("--token <token>", "Bot token (for Telegram, Discord, Slack)").option("--name <name>", "Instance name (auto-generated if not provided)").action(async (type, options) => {
78398
+ const validTypes = ["telegram", "discord", "slack", "whatsapp-baileys", "whatsapp-cloud"];
78399
+ if (!validTypes.includes(type)) {
78400
+ error(`Unknown channel type: ${type}. Available: ${validTypes.join(", ")}`);
78401
+ }
78402
+ try {
78403
+ if (type === "telegram") {
78404
+ await addTelegram(options);
78405
+ } else if (type === "discord") {
78406
+ await addTokenChannel("discord", "Discord", options, "Get one from https://discord.com/developers");
78407
+ } else if (type === "slack") {
78408
+ await addTokenChannel("slack", "Slack", options, "Get one from https://api.slack.com/apps");
78409
+ } else if (type.startsWith("whatsapp")) {
78410
+ await addWhatsApp(type, options);
78411
+ } else {
78412
+ error(`Channel type "${type}" is not yet supported for interactive setup. Use: omni instances create --channel ${type} --name <name>`);
78413
+ }
78414
+ } catch (err) {
78415
+ const message = err instanceof Error ? err.message : "Unknown error";
78416
+ error(`Failed to add ${type} channel: ${message}`);
78417
+ }
78418
+ });
78419
+ channels.command("status").description("Overview of all channels and their connection states").action(async () => {
78420
+ const client = getClient();
78421
+ try {
78422
+ const result = await client.instances.list({ limit: 100 });
78423
+ if (result.items.length === 0) {
78424
+ info("No instances configured. Run: omni channels add <type>");
78425
+ return;
78426
+ }
78427
+ const items = buildStatusItems(result.items);
78428
+ list(items, { emptyMessage: "No instances found." });
78429
+ } catch (err) {
78430
+ const message = err instanceof Error ? err.message : "Unknown error";
78431
+ error(`Failed to get channel status: ${message}`);
78432
+ }
78433
+ });
78434
+ return channels;
78435
+ }
78436
+ async function addTelegram(options) {
78437
+ let token = options.token;
78438
+ if (!token) {
78439
+ if (!process.stdin.isTTY) {
78440
+ error(`Token required. Use: omni channels add telegram --token <token>
78441
+ Get one from @BotFather: https://t.me/BotFather`);
78442
+ }
78443
+ info(`Get a bot token from @BotFather: https://t.me/BotFather
78444
+ `);
78445
+ token = await promptUser("Paste your Telegram bot token: ");
78446
+ if (!token) {
78447
+ error("No token provided. Aborting.");
78448
+ }
78449
+ }
78450
+ if (!token.includes(":")) {
78451
+ error(`Invalid token format. Telegram bot tokens look like: 123456789:ABCDefGhIjKlMnOpQrStUvWxYz
78452
+ Get one from @BotFather: https://t.me/BotFather`);
78453
+ }
78454
+ const name = options.name ?? `telegram-${Date.now().toString(36)}`;
78455
+ info(`Creating Telegram instance "${name}"...`);
78456
+ const client = getClient();
78457
+ const instance = await client.instances.create({
78458
+ name,
78459
+ channel: "telegram",
78460
+ token
78461
+ });
78462
+ await new Promise((r) => setTimeout(r, 2000));
78463
+ try {
78464
+ const status = await client.instances.status(instance.id);
78465
+ if (status.isConnected) {
78466
+ const botUsername = status.ownerIdentifier ?? status.profileName ?? "unknown";
78467
+ const botName = status.profileName ?? "unknown";
78468
+ success(`Connected as ${botUsername} (${botName})`, {
78469
+ instanceId: instance.id,
78470
+ name: instance.name,
78471
+ channel: "telegram",
78472
+ botUsername,
78473
+ botName
78474
+ });
78475
+ } else {
78476
+ success(`Instance created: ${instance.id}`, {
78477
+ instanceId: instance.id,
78478
+ name: instance.name,
78479
+ channel: "telegram",
78480
+ state: status.state,
78481
+ message: status.message ?? "Connecting..."
78482
+ });
78483
+ info(`Connection in progress. Check: omni instances status ${instance.id}`);
78484
+ }
78485
+ } catch {
78486
+ success(`Instance created: ${instance.id}`, {
78487
+ instanceId: instance.id,
78488
+ name: instance.name,
78489
+ channel: "telegram"
78490
+ });
78491
+ info(`Check status: omni instances status ${instance.id}`);
78492
+ }
78493
+ }
78494
+ async function addTokenChannel(type, displayName, options, tokenHelp) {
78495
+ let token = options.token;
78496
+ if (!token) {
78497
+ if (!process.stdin.isTTY) {
78498
+ error(`Token required. Use: omni channels add ${type} --token <token>
78499
+ ${tokenHelp}`);
78500
+ }
78501
+ info(`${tokenHelp}
78502
+ `);
78503
+ token = await promptUser(`Paste your ${displayName} bot token: `);
78504
+ if (!token) {
78505
+ error("No token provided. Aborting.");
78506
+ }
78507
+ }
78508
+ const name = options.name ?? `${type}-${Date.now().toString(36)}`;
78509
+ info(`Creating ${displayName} instance "${name}"...`);
78510
+ const client = getClient();
78511
+ const instance = await client.instances.create({
78512
+ name,
78513
+ channel: type,
78514
+ token
78515
+ });
78516
+ success(`Instance created: ${instance.id}`, {
78517
+ instanceId: instance.id,
78518
+ name: instance.name,
78519
+ channel: type
78520
+ });
78521
+ info(`Check status: omni instances status ${instance.id}`);
78522
+ }
78523
+ async function addWhatsApp(channel, options) {
78524
+ const name = options.name ?? `whatsapp-${Date.now().toString(36)}`;
78525
+ info(`Creating WhatsApp instance "${name}"...`);
78526
+ const client = getClient();
78527
+ const instance = await client.instances.create({
78528
+ name,
78529
+ channel
78530
+ });
78531
+ success(`Instance created: ${instance.id}`, {
78532
+ instanceId: instance.id,
78533
+ name: instance.name,
78534
+ channel
78535
+ });
78536
+ info(`Scan QR code: omni instances qr ${instance.id} --watch`);
78537
+ }
78538
+
78317
78539
  // src/commands/chats.ts
78318
78540
  var VALID_CHANNELS = ["whatsapp-baileys", "whatsapp-cloud", "discord", "slack", "telegram"];
78319
78541
  async function buildInstanceNameMap(client) {
@@ -79396,6 +79618,105 @@ function createConfigCommand() {
79396
79618
  return config;
79397
79619
  }
79398
79620
 
79621
+ // src/commands/connect.ts
79622
+ import { execFileSync } from "child_process";
79623
+ async function findOrCreateProvider(client, agentName, agentEntry, natsUrl) {
79624
+ try {
79625
+ const provider = await client.providers.create({
79626
+ name: `nats-genie-${agentName}`,
79627
+ schema: "nats-genie",
79628
+ baseUrl: `nats://${natsUrl}`,
79629
+ schemaConfig: { agentName: agentEntry.name, agentDir: agentEntry.dir, natsUrl }
79630
+ });
79631
+ return provider.id;
79632
+ } catch {
79633
+ try {
79634
+ const providers = await client.providers.list();
79635
+ const existing = providers.find((p) => p.name === `nats-genie-${agentName}` && p.schema === "nats-genie");
79636
+ if (existing) {
79637
+ info(`Using existing provider: ${existing.id}`);
79638
+ return existing.id;
79639
+ }
79640
+ } catch {}
79641
+ error("Failed to create provider. Check API connection.");
79642
+ return null;
79643
+ }
79644
+ }
79645
+ async function findOrCreateAgent(client, agentName, providerId) {
79646
+ try {
79647
+ const agent = await client.agents.create({
79648
+ name: agentName,
79649
+ agentProviderId: providerId,
79650
+ agentType: "assistant",
79651
+ provider: "custom",
79652
+ capabilities: [],
79653
+ isInternal: false,
79654
+ isActive: true
79655
+ });
79656
+ return agent.id;
79657
+ } catch {
79658
+ try {
79659
+ const { items } = await client.agents.list();
79660
+ const existing = items.find((a) => a.name === agentName && a.agentProviderId === providerId);
79661
+ if (existing) {
79662
+ info(`Using existing agent: ${existing.id}`);
79663
+ return existing.id;
79664
+ }
79665
+ } catch {}
79666
+ error("Failed to create agent record. Check API connection.");
79667
+ return null;
79668
+ }
79669
+ }
79670
+ function createConnectCommand() {
79671
+ return new Command("connect").description("Connect an Omni instance to a Genie agent via NATS").argument("<instance-id>", "Omni instance ID").argument("<agent-name>", "Genie agent name (from genie directory)").option("--nats-url <url>", "NATS server URL", "localhost:4222").action(async (instanceId, agentName, options) => {
79672
+ const client = getClient();
79673
+ info(`Discovering agent "${agentName}" from genie directory...`);
79674
+ let agentEntry;
79675
+ try {
79676
+ const stdout = execFileSync("genie", ["dir", "get", agentName, "--json"], {
79677
+ encoding: "utf-8",
79678
+ env: process.env,
79679
+ timeout: 1e4
79680
+ });
79681
+ agentEntry = JSON.parse(stdout.trim());
79682
+ } catch {
79683
+ error(`Failed to discover agent "${agentName}" from genie directory.
79684
+ Make sure genie is installed and the agent is registered:
79685
+ genie dir add ${agentName} --dir /path/to/agent`);
79686
+ return;
79687
+ }
79688
+ info(`Found agent: ${agentEntry.name} (dir: ${agentEntry.dir})`);
79689
+ try {
79690
+ await client.instances.get(instanceId);
79691
+ } catch {
79692
+ error(`Instance "${instanceId}" not found. Run: omni instances list`);
79693
+ return;
79694
+ }
79695
+ info("Creating NATS Genie provider...");
79696
+ const providerId = await findOrCreateProvider(client, agentName, agentEntry, options.natsUrl);
79697
+ if (!providerId)
79698
+ return;
79699
+ info("Creating agent record...");
79700
+ const agentId = await findOrCreateAgent(client, agentName, providerId);
79701
+ if (!agentId)
79702
+ return;
79703
+ info("Updating instance agent assignment...");
79704
+ try {
79705
+ await client.instances.update(instanceId, { agentProviderId: providerId });
79706
+ } catch {
79707
+ warn("Could not update instance agent assignment automatically.");
79708
+ info(`Set manually: omni instances update ${instanceId} --agent-provider-id ${providerId}`);
79709
+ }
79710
+ success(`Connected instance "${instanceId}" to genie agent "${agentName}".
79711
+ NATS topics:
79712
+ Inbound: omni.message.${instanceId}.*
79713
+ Outbound: omni.reply.${instanceId}.*
79714
+
79715
+ Next: Start the genie bridge:
79716
+ genie omni start`);
79717
+ });
79718
+ }
79719
+
79399
79720
  // src/commands/dead-letters.ts
79400
79721
  function createDeadLettersCommand() {
79401
79722
  const deadLetters = new Command("dead-letters").description("Manage failed events (dead letters)");
@@ -79726,7 +80047,7 @@ function createEventsCommand() {
79726
80047
  import { chmodSync, existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
79727
80048
  import { homedir as homedir2 } from "os";
79728
80049
  import { join as join4 } from "path";
79729
- import { createInterface } from "readline";
80050
+ import { createInterface as createInterface2 } from "readline";
79730
80051
 
79731
80052
  // ../../node_modules/.bun/ora@8.2.0/node_modules/ora/index.js
79732
80053
  import process9 from "process";
@@ -80779,7 +81100,7 @@ async function downloadNats() {
80779
81100
  }
80780
81101
  }
80781
81102
  async function promptLine(question, defaultValue = "") {
80782
- const rl = createInterface({
81103
+ const rl = createInterface2({
80783
81104
  input: process.stdin,
80784
81105
  output: process.stdout
80785
81106
  });
@@ -80792,7 +81113,7 @@ async function promptLine(question, defaultValue = "") {
80792
81113
  });
80793
81114
  }
80794
81115
  async function promptYesNo(question, defaultYes = true) {
80795
- const rl = createInterface({
81116
+ const rl = createInterface2({
80796
81117
  input: process.stdin,
80797
81118
  output: process.stdout
80798
81119
  });
@@ -81193,7 +81514,7 @@ async function resolveBase64Image(options) {
81193
81514
  const buffer = await resp.arrayBuffer();
81194
81515
  return Buffer.from(buffer).toString("base64");
81195
81516
  }
81196
- async function apiCall(path, method = "GET", body) {
81517
+ async function apiCall2(path, method = "GET", body) {
81197
81518
  const config = (await Promise.resolve().then(() => (init_config(), exports_config))).loadConfig();
81198
81519
  const baseUrl = config.apiUrl ?? "http://localhost:8882";
81199
81520
  const apiKey = config.apiKey ?? "";
@@ -81266,7 +81587,7 @@ function createInstancesCommand() {
81266
81587
  body.name = options.name;
81267
81588
  body.channel = channel;
81268
81589
  setBool(body, "isDefault", options.isDefault);
81269
- const response = await apiCall("instances", "POST", body);
81590
+ const response = await apiCall2("instances", "POST", body);
81270
81591
  const instance = response.data ?? response;
81271
81592
  success(`Instance created: ${instance.id}`, {
81272
81593
  id: instance.id,
@@ -81598,6 +81919,21 @@ function createInstancesCommand() {
81598
81919
  error(`Failed to list groups: ${message}`);
81599
81920
  }
81600
81921
  });
81922
+ instances.command("group-members <id> <jid>").description("List members of a group").action(async (rawId, jid) => {
81923
+ try {
81924
+ const id = await resolveInstanceId(rawId);
81925
+ const result = await apiCall2(`instances/${id}/groups/${encodeURIComponent(jid)}/members`);
81926
+ const items = result.members.map((m) => ({
81927
+ id: m.id,
81928
+ name: m.name ?? "-",
81929
+ role: m.role ?? "member"
81930
+ }));
81931
+ list(items, { emptyMessage: "No members found.", rawData: result.members });
81932
+ } catch (err) {
81933
+ const message = err instanceof Error ? err.message : "Unknown error";
81934
+ error(`Failed to list group members: ${message}`);
81935
+ }
81936
+ });
81601
81937
  instances.command("profile <id> <userId>").description("Get user profile from the channel").action(async (rawId, userId) => {
81602
81938
  const client = getClient();
81603
81939
  try {
@@ -81735,7 +82071,7 @@ function createInstancesCommand() {
81735
82071
  try {
81736
82072
  const id = await resolveInstanceId(rawId);
81737
82073
  const base64Data = await resolveBase64Image(options);
81738
- await apiCall(`instances/${id}/profile/picture`, "PUT", { base64: base64Data });
82074
+ await apiCall2(`instances/${id}/profile/picture`, "PUT", { base64: base64Data });
81739
82075
  success("Profile picture updated");
81740
82076
  } catch (err) {
81741
82077
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -81745,7 +82081,7 @@ function createInstancesCommand() {
81745
82081
  instances.command("remove-picture <id>").description("Remove instance profile picture").action(async (rawId) => {
81746
82082
  try {
81747
82083
  const id = await resolveInstanceId(rawId);
81748
- await apiCall(`instances/${id}/profile/picture`, "DELETE");
82084
+ await apiCall2(`instances/${id}/profile/picture`, "DELETE");
81749
82085
  success("Profile picture removed");
81750
82086
  } catch (err) {
81751
82087
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -81760,7 +82096,7 @@ function createInstancesCommand() {
81760
82096
  try {
81761
82097
  const id = await resolveInstanceId(rawId);
81762
82098
  const base64Data = await resolveBase64Image(options);
81763
- await apiCall(`instances/${id}/groups/${options.group}/picture`, "PUT", { base64: base64Data });
82099
+ await apiCall2(`instances/${id}/groups/${options.group}/picture`, "PUT", { base64: base64Data });
81764
82100
  success(`Group picture updated for ${options.group}`);
81765
82101
  } catch (err) {
81766
82102
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -81770,7 +82106,7 @@ function createInstancesCommand() {
81770
82106
  instances.command("group-create <id>").description("Create a new WhatsApp group").requiredOption("--subject <name>", "Group name/subject").requiredOption("--participants <phones...>", "Phone numbers or JIDs to add (space-separated)").action(async (rawId, opts) => {
81771
82107
  try {
81772
82108
  const id = await resolveInstanceId(rawId);
81773
- const result = await apiCall(`instances/${id}/groups`, "POST", {
82109
+ const result = await apiCall2(`instances/${id}/groups`, "POST", {
81774
82110
  subject: opts.subject,
81775
82111
  participants: opts.participants
81776
82112
  });
@@ -81783,7 +82119,7 @@ function createInstancesCommand() {
81783
82119
  instances.command("group-invite <id> <groupJid>").description("Get group invite link").action(async (rawId, groupJid) => {
81784
82120
  try {
81785
82121
  const id = await resolveInstanceId(rawId);
81786
- const result = await apiCall(`instances/${id}/groups/${encodeURIComponent(groupJid)}/invite`);
82122
+ const result = await apiCall2(`instances/${id}/groups/${encodeURIComponent(groupJid)}/invite`);
81787
82123
  data(result.data);
81788
82124
  } catch (err) {
81789
82125
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -81793,7 +82129,7 @@ function createInstancesCommand() {
81793
82129
  instances.command("group-revoke-invite <id> <groupJid>").description("Revoke group invite link and generate new one").action(async (rawId, groupJid) => {
81794
82130
  try {
81795
82131
  const id = await resolveInstanceId(rawId);
81796
- const result = await apiCall(`instances/${id}/groups/${encodeURIComponent(groupJid)}/invite/revoke`, "POST");
82132
+ const result = await apiCall2(`instances/${id}/groups/${encodeURIComponent(groupJid)}/invite/revoke`, "POST");
81797
82133
  success("Invite link revoked", result.data);
81798
82134
  } catch (err) {
81799
82135
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -81803,7 +82139,7 @@ function createInstancesCommand() {
81803
82139
  instances.command("group-join <id> <code>").description("Join a group via invite code").action(async (rawId, code) => {
81804
82140
  try {
81805
82141
  const id = await resolveInstanceId(rawId);
81806
- const result = await apiCall(`instances/${id}/groups/join`, "POST", { code });
82142
+ const result = await apiCall2(`instances/${id}/groups/join`, "POST", { code });
81807
82143
  success(`Joined group: ${result.data.groupJid}`, result.data);
81808
82144
  } catch (err) {
81809
82145
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -81813,7 +82149,7 @@ function createInstancesCommand() {
81813
82149
  instances.command("privacy <id>").description("Fetch privacy settings").action(async (rawId) => {
81814
82150
  try {
81815
82151
  const id = await resolveInstanceId(rawId);
81816
- const result = await apiCall(`instances/${id}/privacy`);
82152
+ const result = await apiCall2(`instances/${id}/privacy`);
81817
82153
  data(result.data);
81818
82154
  } catch (err) {
81819
82155
  const message = err instanceof Error ? err.message : "Unknown error";
@@ -81823,7 +82159,7 @@ function createInstancesCommand() {
81823
82159
  instances.command("reject-call <id>").description("Reject an incoming call").requiredOption("--call-id <callId>", "Call ID from the call event").requiredOption("--from <jid>", "Caller JID").action(async (rawId, options) => {
81824
82160
  try {
81825
82161
  const id = await resolveInstanceId(rawId);
81826
- await apiCall(`instances/${id}/calls/reject`, "POST", {
82162
+ await apiCall2(`instances/${id}/calls/reject`, "POST", {
81827
82163
  callId: options.callId,
81828
82164
  callFrom: options.from
81829
82165
  });
@@ -82284,7 +82620,7 @@ function parseErrorMessage(err) {
82284
82620
  return err.error?.message;
82285
82621
  return;
82286
82622
  }
82287
- async function apiCall2(path, method = "GET", body, query) {
82623
+ async function apiCall3(path, method = "GET", body, query) {
82288
82624
  const config = loadConfig();
82289
82625
  const baseUrl = (config.apiUrl ?? "http://localhost:8882").replace(/\/$/, "");
82290
82626
  const apiKey = config.apiKey ?? "";
@@ -82430,7 +82766,7 @@ async function handleLs(options) {
82430
82766
  query.since = options.since;
82431
82767
  if (options.until)
82432
82768
  query.until = options.until;
82433
- const result = await apiCall2("messages", "GET", undefined, query);
82769
+ const result = await apiCall3("messages", "GET", undefined, query);
82434
82770
  const items = applyFilters(result.items ?? [], options);
82435
82771
  if (items.length === 0) {
82436
82772
  info("No media items found.");
@@ -82488,7 +82824,7 @@ async function handleDownload(options) {
82488
82824
  chat: chatId,
82489
82825
  external: options.external
82490
82826
  });
82491
- const response = await apiCall2("messages/media/download", "POST", body);
82827
+ const response = await apiCall3("messages/media/download", "POST", body);
82492
82828
  const result = response.data;
82493
82829
  const config = loadConfig();
82494
82830
  const baseUrl = (config.apiUrl ?? "http://localhost:8882").replace(/\/$/, "");
@@ -83125,6 +83461,7 @@ var CORE_EVENT_TYPES = [
83125
83461
  "access.allowed",
83126
83462
  "access.denied",
83127
83463
  "access.pairing_requested",
83464
+ "access.pairing_approved",
83128
83465
  "presence.typing",
83129
83466
  "presence.online",
83130
83467
  "presence.offline",
@@ -88307,7 +88644,7 @@ var AUTO_RETRY_DELAYS_MS = [
88307
88644
  24 * 60 * 60 * 1000
88308
88645
  ];
88309
88646
  // ../core/src/types/agent.ts
88310
- var PROVIDER_SCHEMAS = ["agno", "webhook", "openclaw", "ag-ui", "claude-code", "a2a", "genie"];
88647
+ var PROVIDER_SCHEMAS = ["agno", "webhook", "openclaw", "ag-ui", "claude-code", "a2a", "nats-genie"];
88311
88648
 
88312
88649
  // ../core/src/schemas/common.ts
88313
88650
  var UuidSchema = exports_external.string().uuid();
@@ -90634,334 +90971,14 @@ class InMemorySessionActivityStore {
90634
90971
  this.activities.clear();
90635
90972
  }
90636
90973
  }
90637
- // ../core/src/providers/types.ts
90638
- class ProviderError extends Error {
90639
- code;
90640
- statusCode;
90641
- details;
90642
- constructor(message2, code, statusCode, details) {
90643
- super(message2);
90644
- this.code = code;
90645
- this.statusCode = statusCode;
90646
- this.details = details;
90647
- this.name = "ProviderError";
90648
- }
90649
- }
90650
90974
  // ../core/src/providers/claude-code-client.ts
90651
90975
  var log6 = createLogger("provider:claude-code");
90652
- // ../core/src/providers/genie-client.ts
90653
- import { execFile } from "child_process";
90654
- import { mkdir, open, readFile, rename, stat, unlink, writeFile } from "fs/promises";
90655
- import { homedir as homedir3 } from "os";
90656
- import { join as join5 } from "path";
90657
- var log7 = createLogger("providers:genie-client");
90658
- var CACHE_TTL_MS = 5 * 60 * 1000;
90659
- var CACHE_MAX_SIZE = 100;
90660
- function sanitize(value) {
90661
- return value.replace(/[^a-zA-Z0-9_-]/g, "").replace(/-+$/, "");
90662
- }
90663
- function execFilePromise(file, args) {
90664
- return new Promise((resolve2, reject) => {
90665
- execFile(file, args, {}, (error2, stdout) => {
90666
- if (error2)
90667
- reject(error2);
90668
- else
90669
- resolve2(String(stdout));
90670
- });
90671
- });
90672
- }
90673
- function interpolateTemplate(template, vars) {
90674
- return template.replace(/\{(\w+)\}/g, (_match, key) => {
90675
- const value = vars[key];
90676
- return value ?? "";
90677
- });
90678
- }
90679
- function extractTemplateVars(request) {
90680
- return {
90681
- thread_id: request.chat?.threadId,
90682
- chat_id: request.chat?.id,
90683
- sender_id: request.userId,
90684
- channel: request.platform?.channel,
90685
- instance_id: request.platform?.instanceId
90686
- };
90687
- }
90688
-
90689
- class GenieClient {
90690
- teamNameTemplate;
90691
- agentNameTemplate;
90692
- targetAgentTemplate;
90693
- hasTemplates;
90694
- autoSpawn;
90695
- autoSpawnDir;
90696
- sessionName;
90697
- agentRole;
90698
- knownTeams = new Map;
90699
- pendingTeams = new Set;
90700
- constructor(config2) {
90701
- this.teamNameTemplate = config2.teamName ?? "genie";
90702
- this.agentNameTemplate = config2.agentName;
90703
- this.targetAgentTemplate = config2.targetAgent;
90704
- this.agentRole = config2.agentRole;
90705
- this.autoSpawn = config2.autoSpawn ?? true;
90706
- this.autoSpawnDir = config2.autoSpawnDir ?? "";
90707
- this.sessionName = config2.sessionName ?? "";
90708
- this.hasTemplates = /\{\w+\}/.test(this.teamNameTemplate) || /\{\w+\}/.test(this.agentNameTemplate) || /\{\w+\}/.test(this.targetAgentTemplate);
90709
- }
90710
- isTeamKnown(teamName) {
90711
- const cachedAt = this.knownTeams.get(teamName);
90712
- if (cachedAt === undefined)
90713
- return false;
90714
- if (Date.now() - cachedAt > CACHE_TTL_MS) {
90715
- this.knownTeams.delete(teamName);
90716
- return false;
90717
- }
90718
- return true;
90719
- }
90720
- markTeamKnown(teamName) {
90721
- if (this.knownTeams.size >= CACHE_MAX_SIZE && !this.knownTeams.has(teamName)) {
90722
- const oldest = this.knownTeams.keys().next().value;
90723
- if (oldest !== undefined)
90724
- this.knownTeams.delete(oldest);
90725
- }
90726
- this.knownTeams.set(teamName, Date.now());
90727
- }
90728
- resolveConfig(request) {
90729
- let teamName;
90730
- let agentName;
90731
- let targetAgent;
90732
- if (this.hasTemplates) {
90733
- const vars = extractTemplateVars(request);
90734
- teamName = sanitize(interpolateTemplate(this.teamNameTemplate, vars));
90735
- agentName = sanitize(interpolateTemplate(this.agentNameTemplate, vars));
90736
- targetAgent = sanitize(interpolateTemplate(this.targetAgentTemplate, vars));
90737
- } else {
90738
- teamName = sanitize(this.teamNameTemplate);
90739
- agentName = sanitize(this.agentNameTemplate);
90740
- targetAgent = sanitize(this.targetAgentTemplate);
90741
- }
90742
- if (!teamName) {
90743
- throw new ProviderError(`Team name resolved to empty string (template: "${this.teamNameTemplate}"). Ensure the template variable (e.g. {thread_id}) is populated in the request.`, "INVALID_RESPONSE");
90744
- }
90745
- if (!agentName) {
90746
- throw new ProviderError(`Agent name resolved to empty string (template: "${this.agentNameTemplate}"). Ensure the template variable is populated in the request.`, "INVALID_RESPONSE");
90747
- }
90748
- if (!targetAgent) {
90749
- throw new ProviderError(`Target agent resolved to empty string (template: "${this.targetAgentTemplate}"). Ensure the template variable is populated in the request.`, "INVALID_RESPONSE");
90750
- }
90751
- const inboxDir = join5(homedir3(), ".claude", "teams", teamName, "inboxes");
90752
- const inboxPath = join5(inboxDir, `${targetAgent}.json`);
90753
- return { teamName, agentName, targetAgent, inboxDir, inboxPath };
90754
- }
90755
- ensureTeamExists(teamName) {
90756
- if (!this.autoSpawn)
90757
- return;
90758
- if (this.isTeamKnown(teamName))
90759
- return;
90760
- if (this.pendingTeams.has(teamName))
90761
- return;
90762
- this.pendingTeams.add(teamName);
90763
- this.checkAndSpawnTeam(teamName).catch((error2) => {
90764
- log7.warn("Auto-spawn failed", {
90765
- teamName,
90766
- error: error2 instanceof Error ? error2.message : String(error2)
90767
- });
90768
- this.pendingTeams.delete(teamName);
90769
- });
90770
- }
90771
- async checkAndSpawnTeam(teamName) {
90772
- await this.spawnAgentSession(teamName);
90773
- }
90774
- async spawnAgentSession(teamName) {
90775
- const args = ["spawn", this.agentRole, "--team", teamName];
90776
- if (this.autoSpawnDir) {
90777
- args.push("--cwd", this.autoSpawnDir);
90778
- }
90779
- if (this.sessionName) {
90780
- args.push("--session", this.sessionName);
90781
- }
90782
- log7.info("Auto-spawning agent session", { teamName, agentRole: this.agentRole, args });
90783
- try {
90784
- await execFilePromise("genie", args);
90785
- log7.info("Agent session spawned successfully", { teamName });
90786
- this.markTeamKnown(teamName);
90787
- } catch (error2) {
90788
- log7.warn("Agent session spawn failed", {
90789
- teamName,
90790
- error: error2 instanceof Error ? error2.message : String(error2)
90791
- });
90792
- } finally {
90793
- this.pendingTeams.delete(teamName);
90794
- }
90795
- }
90796
- buildMetadataHeader(request) {
90797
- const tags = [];
90798
- if (request.platform) {
90799
- tags.push(`channel:${request.platform.channel}`);
90800
- tags.push(`instance:${request.platform.instanceId}`);
90801
- }
90802
- if (request.chat?.id)
90803
- tags.push(`chat:${request.chat.id}`);
90804
- if (request.chat?.threadId)
90805
- tags.push(`thread:${request.chat.threadId}`);
90806
- if (request.messageId)
90807
- tags.push(`msg:${request.messageId}`);
90808
- if (request.sender?.displayName)
90809
- tags.push(`from:${request.sender.displayName}`);
90810
- if (request.chat?.type)
90811
- tags.push(`type:${request.chat.type}`);
90812
- if (request.replyToMessageId)
90813
- tags.push(`replyTo:${request.replyToMessageId}`);
90814
- return tags.length > 0 ? `[${tags.join(" ")}]` : "";
90815
- }
90816
- async acquireLock(lockPath) {
90817
- try {
90818
- return await open(lockPath, "wx");
90819
- } catch {
90820
- await new Promise((r) => setTimeout(r, 100));
90821
- }
90822
- try {
90823
- return await open(lockPath, "wx");
90824
- } catch {}
90825
- try {
90826
- const lockStat = await stat(lockPath);
90827
- const ageMs = Date.now() - lockStat.mtimeMs;
90828
- if (ageMs > 30000) {
90829
- log7.warn("Removing stale lock file", { lockPath, ageMs });
90830
- await unlink(lockPath);
90831
- return await open(lockPath, "wx");
90832
- }
90833
- log7.error("Lock file is fresh, another process is active", { lockPath, ageMs });
90834
- } catch (error2) {
90835
- if (error2 instanceof ProviderError)
90836
- throw error2;
90837
- log7.error("Could not recover from lock contention", { lockPath, error: error2 });
90838
- }
90839
- throw new ProviderError("Failed to acquire lock on team inbox, message not delivered", "SERVER_ERROR");
90840
- }
90841
- async run(request) {
90842
- const startMs = Date.now();
90843
- const { teamName, agentName, targetAgent, inboxDir, inboxPath } = this.resolveConfig(request);
90844
- const header2 = this.buildMetadataHeader(request);
90845
- const replyInstruction = `\u26A1 REPLY NOW via SendMessage to "${agentName}". Include the routing header from the first line of this message in your reply. Do not proceed with other tasks until you respond.`;
90846
- const text = header2 ? `${header2}
90847
- ${request.message}
90848
- ${replyInstruction}` : `${request.message}
90849
- ${replyInstruction}`;
90850
- const summary = request.message.length > 50 ? `${request.message.substring(0, 50)}...` : request.message;
90851
- const inboxMessage = {
90852
- from: agentName,
90853
- text,
90854
- summary,
90855
- timestamp: new Date().toISOString(),
90856
- read: false
90857
- };
90858
- await mkdir(inboxDir, { recursive: true });
90859
- const lockPath = `${inboxPath}.lock`;
90860
- const lockFd = await this.acquireLock(lockPath);
90861
- try {
90862
- let inbox = [];
90863
- try {
90864
- const data2 = await readFile(inboxPath, "utf-8");
90865
- inbox = JSON.parse(data2);
90866
- if (!Array.isArray(inbox))
90867
- inbox = [];
90868
- } catch {
90869
- inbox = [];
90870
- }
90871
- inbox.push(inboxMessage);
90872
- const tmpPath = `${inboxPath}.tmp`;
90873
- await writeFile(tmpPath, JSON.stringify(inbox, null, 2), "utf-8");
90874
- await rename(tmpPath, inboxPath);
90875
- } finally {
90876
- await lockFd.close();
90877
- try {
90878
- await unlink(lockPath);
90879
- } catch {}
90880
- }
90881
- this.ensureTeamExists(teamName);
90882
- const durationMs = Date.now() - startMs;
90883
- log7.info("Message delivered to team inbox", {
90884
- agent: agentName,
90885
- team: teamName,
90886
- target: targetAgent,
90887
- messageLength: text.length,
90888
- durationMs,
90889
- hasTemplates: this.hasTemplates
90890
- });
90891
- return {
90892
- content: "",
90893
- runId: `genie-${agentName}-${Date.now()}`,
90894
- sessionId: request.sessionId ?? "",
90895
- status: "completed",
90896
- metrics: {
90897
- inputTokens: 0,
90898
- outputTokens: 0,
90899
- durationMs
90900
- }
90901
- };
90902
- }
90903
- async* stream(_request) {
90904
- throw new ProviderError("Genie client does not support streaming", "STREAM_ERROR");
90905
- }
90906
- async checkHealth() {
90907
- const startMs = Date.now();
90908
- try {
90909
- if (this.hasTemplates) {
90910
- const teamsRoot = join5(homedir3(), ".claude", "teams");
90911
- try {
90912
- await stat(teamsRoot);
90913
- } catch {
90914
- return {
90915
- healthy: false,
90916
- latencyMs: Date.now() - startMs,
90917
- error: `Teams root directory does not exist: ${teamsRoot}`
90918
- };
90919
- }
90920
- return {
90921
- healthy: true,
90922
- latencyMs: Date.now() - startMs
90923
- };
90924
- }
90925
- const teamName = sanitize(this.teamNameTemplate);
90926
- const teamDir = join5(homedir3(), ".claude", "teams", teamName);
90927
- const inboxDir = join5(teamDir, "inboxes");
90928
- try {
90929
- await stat(teamDir);
90930
- } catch {
90931
- return {
90932
- healthy: false,
90933
- latencyMs: Date.now() - startMs,
90934
- error: `Team directory does not exist: ${teamDir}`
90935
- };
90936
- }
90937
- try {
90938
- await stat(inboxDir);
90939
- } catch {
90940
- return {
90941
- healthy: false,
90942
- latencyMs: Date.now() - startMs,
90943
- error: `Inbox directory does not exist: ${inboxDir}`
90944
- };
90945
- }
90946
- return {
90947
- healthy: true,
90948
- latencyMs: Date.now() - startMs
90949
- };
90950
- } catch (error2) {
90951
- return {
90952
- healthy: false,
90953
- latencyMs: Date.now() - startMs,
90954
- error: error2 instanceof Error ? error2.message : String(error2)
90955
- };
90956
- }
90957
- }
90958
- }
90959
90976
  // ../core/src/providers/agno-provider.ts
90960
- var log8 = createLogger("provider:agno");
90977
+ var log7 = createLogger("provider:agno");
90961
90978
  // ../core/src/providers/claude-code-provider.ts
90962
- var log9 = createLogger("provider:claude-code");
90979
+ var log8 = createLogger("provider:claude-code");
90963
90980
  // ../core/src/providers/webhook-provider.ts
90964
- var log10 = createLogger("provider:webhook");
90981
+ var log9 = createLogger("provider:webhook");
90965
90982
  // ../core/src/providers/openclaw/client.ts
90966
90983
  import * as nodeCrypto from "crypto";
90967
90984
 
@@ -90985,7 +91002,7 @@ function generateDeviceKeypair() {
90985
91002
  }
90986
91003
 
90987
91004
  // ../core/src/providers/openclaw/client.ts
90988
- var log11 = createLogger("openclaw:client");
91005
+ var log10 = createLogger("openclaw:client");
90989
91006
 
90990
91007
  class OpenClawClient {
90991
91008
  ws = null;
@@ -91007,7 +91024,7 @@ class OpenClawClient {
91007
91024
  const urlObj = new URL(config2.url);
91008
91025
  const host = urlObj.hostname;
91009
91026
  if (host !== "localhost" && host !== "127.0.0.1" && host !== "::1") {
91010
- log11.warn("Connecting over unencrypted WebSocket to non-localhost", {
91027
+ log10.warn("Connecting over unencrypted WebSocket to non-localhost", {
91011
91028
  providerId: config2.providerId,
91012
91029
  host
91013
91030
  });
@@ -91046,7 +91063,7 @@ class OpenClawClient {
91046
91063
  this.flushAccumulations(new Error("Client stopped"));
91047
91064
  this.flushAgentAccumulations(new Error("Client stopped"));
91048
91065
  this.setState("disconnected");
91049
- log11.info("Client stopped", {
91066
+ log10.info("Client stopped", {
91050
91067
  providerId: this.config.providerId,
91051
91068
  pendingRequests: this.pending.size
91052
91069
  });
@@ -91133,7 +91150,7 @@ class OpenClawClient {
91133
91150
  try {
91134
91151
  this.ws = new WebSocket(this.config.url);
91135
91152
  } catch (err) {
91136
- log11.error("WebSocket construction failed", {
91153
+ log10.error("WebSocket construction failed", {
91137
91154
  providerId: this.config.providerId,
91138
91155
  error: String(err)
91139
91156
  });
@@ -91190,7 +91207,7 @@ class OpenClawClient {
91190
91207
  try {
91191
91208
  listener(event);
91192
91209
  } catch (err) {
91193
- log11.error("Event listener error", {
91210
+ log10.error("Event listener error", {
91194
91211
  providerId: this.config.providerId,
91195
91212
  event: event.event,
91196
91213
  error: String(err)
@@ -91207,7 +91224,7 @@ class OpenClawClient {
91207
91224
  try {
91208
91225
  callback(chatEvent);
91209
91226
  } catch (err) {
91210
- log11.error("Accumulation callback error", {
91227
+ log10.error("Accumulation callback error", {
91211
91228
  providerId: this.config.providerId,
91212
91229
  runId: chatEvent.runId,
91213
91230
  error: String(err)
@@ -91224,7 +91241,7 @@ class OpenClawClient {
91224
91241
  try {
91225
91242
  callback(payload);
91226
91243
  } catch (err) {
91227
- log11.error("Agent accumulation callback error", {
91244
+ log10.error("Agent accumulation callback error", {
91228
91245
  providerId: this.config.providerId,
91229
91246
  runId,
91230
91247
  error: String(err)
@@ -91280,7 +91297,7 @@ class OpenClawClient {
91280
91297
  nonce
91281
91298
  };
91282
91299
  authToken = dev.token;
91283
- log11.debug("Using device keypair for operator scopes", {
91300
+ log10.debug("Using device keypair for operator scopes", {
91284
91301
  providerId: this.config.providerId,
91285
91302
  deviceId: dev.id,
91286
91303
  scopes
@@ -91303,7 +91320,7 @@ class OpenClawClient {
91303
91320
  userAgent: "omni-v2/1.0.0",
91304
91321
  device: deviceField
91305
91322
  };
91306
- log11.debug("Sending connect handshake", {
91323
+ log10.debug("Sending connect handshake", {
91307
91324
  providerId: this.config.providerId,
91308
91325
  auth: params.auth ? { token: "[REDACTED]" } : undefined,
91309
91326
  scopes: params.scopes,
@@ -91316,13 +91333,13 @@ class OpenClawClient {
91316
91333
  this.reconnectAttempt = 0;
91317
91334
  this.setState("connected");
91318
91335
  this.startHealthPing();
91319
- log11.info("Connected to OpenClaw gateway", {
91336
+ log10.info("Connected to OpenClaw gateway", {
91320
91337
  providerId: this.config.providerId,
91321
91338
  protocol: payload.protocol,
91322
91339
  defaultAgentId: payload.snapshot?.sessionDefaults?.defaultAgentId
91323
91340
  });
91324
91341
  } catch (err) {
91325
- log11.error("Connect handshake failed", {
91342
+ log10.error("Connect handshake failed", {
91326
91343
  providerId: this.config.providerId,
91327
91344
  error: String(err)
91328
91345
  });
@@ -91350,13 +91367,13 @@ class OpenClawClient {
91350
91367
  backoffMs: Math.round(this.backoffMs)
91351
91368
  };
91352
91369
  if (this.reconnectAttempt < 3) {
91353
- log11.warn("Connection lost, reconnecting", ctx);
91370
+ log10.warn("Connection lost, reconnecting", ctx);
91354
91371
  } else if (this.reconnectAttempt % 10 === 0) {
91355
- log11.warn("Still reconnecting (periodic)", ctx);
91372
+ log10.warn("Still reconnecting (periodic)", ctx);
91356
91373
  } else if (this.reconnectAttempt < 10) {
91357
- log11.info("Reconnecting", ctx);
91374
+ log10.info("Reconnecting", ctx);
91358
91375
  } else {
91359
- log11.debug("Reconnecting", ctx);
91376
+ log10.debug("Reconnecting", ctx);
91360
91377
  }
91361
91378
  }
91362
91379
  startHealthPing() {
@@ -91364,7 +91381,7 @@ class OpenClawClient {
91364
91381
  this.healthPingTimer = setInterval(() => {
91365
91382
  if (this.ws && this.ws.readyState === WebSocket.OPEN) {
91366
91383
  this.request("health").then(() => {}).catch(() => {
91367
- log11.warn("Health ping failed, connection may be stale", {
91384
+ log10.warn("Health ping failed, connection may be stale", {
91368
91385
  providerId: this.config.providerId
91369
91386
  });
91370
91387
  });
@@ -91418,22 +91435,193 @@ class OpenClawClient {
91418
91435
  }
91419
91436
  }
91420
91437
  // ../core/src/providers/openclaw/provider.ts
91421
- var log12 = createLogger("openclaw:provider");
91438
+ var log11 = createLogger("openclaw:provider");
91422
91439
  var MAX_MESSAGE_BYTES = 100 * 1024;
91423
91440
  var MAX_ACCUMULATION_BYTES = 1 * 1024 * 1024;
91424
91441
  var MAX_DELTA_CONTENT_BYTES = 256 * 1024;
91425
91442
  // ../core/src/providers/ag-ui-client.ts
91426
- var log13 = createLogger("providers:ag-ui-client");
91443
+ var log12 = createLogger("providers:ag-ui-client");
91427
91444
 
91428
91445
  // ../core/src/providers/ag-ui-provider.ts
91429
- var log14 = createLogger("provider:ag-ui");
91446
+ var log13 = createLogger("provider:ag-ui");
91430
91447
  // ../core/src/providers/a2a-client.ts
91431
- var log15 = createLogger("providers:a2a-client");
91448
+ var log14 = createLogger("providers:a2a-client");
91432
91449
 
91433
91450
  // ../core/src/providers/a2a-provider.ts
91434
- var log16 = createLogger("provider:a2a");
91435
- // ../core/src/providers/genie-provider.ts
91436
- var log17 = createLogger("provider:genie");
91451
+ var log15 = createLogger("provider:a2a");
91452
+ // ../core/src/providers/nats-genie-provider.ts
91453
+ var import_nats4 = __toESM(require_mod4(), 1);
91454
+ import { mkdir, writeFile } from "fs/promises";
91455
+ import { homedir as homedir3 } from "os";
91456
+ import { join as join5 } from "path";
91457
+ var log16 = createLogger("provider:nats-genie");
91458
+
91459
+ class NatsGenieProvider {
91460
+ id;
91461
+ name;
91462
+ config;
91463
+ schema = "nats-genie";
91464
+ mode = "fire-and-forget";
91465
+ nc = null;
91466
+ sc = import_nats4.StringCodec();
91467
+ replySubscription = null;
91468
+ constructor(id, name, config2) {
91469
+ this.id = id;
91470
+ this.name = name;
91471
+ this.config = config2;
91472
+ }
91473
+ canHandle(_trigger) {
91474
+ return true;
91475
+ }
91476
+ async trigger(context) {
91477
+ const startTime = Date.now();
91478
+ const message2 = this.buildMessage(context);
91479
+ if (!message2) {
91480
+ log16.debug("No content to send", { traceId: context.traceId });
91481
+ return {
91482
+ parts: [],
91483
+ metadata: { runId: "", providerId: this.id, durationMs: Date.now() - startTime }
91484
+ };
91485
+ }
91486
+ const topic = `omni.message.${this.config.instanceId}.${context.source.chatId}`;
91487
+ const payload = {
91488
+ content: message2,
91489
+ sender: context.sender.displayName ?? context.sender.platformUserId,
91490
+ instanceId: this.config.instanceId,
91491
+ chatId: context.source.chatId,
91492
+ agent: this.config.agentName,
91493
+ timestamp: new Date().toISOString(),
91494
+ traceId: context.traceId,
91495
+ messageId: context.source.messageId,
91496
+ files: context.content.files
91497
+ };
91498
+ try {
91499
+ await this.ensureConnected();
91500
+ this.nc?.publish(topic, this.sc.encode(JSON.stringify(payload)));
91501
+ log16.info("Published to NATS", {
91502
+ topic,
91503
+ agent: this.config.agentName,
91504
+ chatId: context.source.chatId,
91505
+ traceId: context.traceId
91506
+ });
91507
+ } catch (error2) {
91508
+ log16.error("Failed to publish to NATS, writing to dead-letter queue", {
91509
+ topic,
91510
+ error: error2 instanceof Error ? error2.message : String(error2),
91511
+ traceId: context.traceId
91512
+ });
91513
+ await this.writeDeadLetter(payload, error2);
91514
+ }
91515
+ const durationMs = Date.now() - startTime;
91516
+ return {
91517
+ parts: [],
91518
+ metadata: {
91519
+ runId: `nats-genie-${Date.now()}`,
91520
+ providerId: this.id,
91521
+ durationMs
91522
+ }
91523
+ };
91524
+ }
91525
+ async startReplySubscription() {
91526
+ if (!this.config.onReply)
91527
+ return;
91528
+ if (this.replySubscription)
91529
+ return;
91530
+ await this.ensureConnected();
91531
+ if (!this.nc)
91532
+ return;
91533
+ const topic = `omni.reply.${this.config.instanceId}.*`;
91534
+ const sub = this.nc.subscribe(topic);
91535
+ this.replySubscription = sub;
91536
+ log16.info("Subscribed to agent replies", { topic });
91537
+ (async () => {
91538
+ for await (const msg of sub) {
91539
+ try {
91540
+ const data2 = JSON.parse(this.sc.decode(msg.data));
91541
+ const chatId = data2.chat_id || msg.subject.split(".").pop() || "";
91542
+ if (data2.content && this.config.onReply) {
91543
+ await this.config.onReply(chatId, data2.content, {
91544
+ agent: data2.agent,
91545
+ auto_reply: data2.auto_reply,
91546
+ timestamp: data2.timestamp
91547
+ });
91548
+ }
91549
+ } catch (error2) {
91550
+ log16.error("Error processing reply", {
91551
+ subject: msg.subject,
91552
+ error: error2 instanceof Error ? error2.message : String(error2)
91553
+ });
91554
+ }
91555
+ }
91556
+ })();
91557
+ }
91558
+ async checkHealth() {
91559
+ const startMs = Date.now();
91560
+ try {
91561
+ await this.ensureConnected();
91562
+ return { healthy: this.nc !== null, latencyMs: Date.now() - startMs };
91563
+ } catch (error2) {
91564
+ return {
91565
+ healthy: false,
91566
+ latencyMs: Date.now() - startMs,
91567
+ error: error2 instanceof Error ? error2.message : String(error2)
91568
+ };
91569
+ }
91570
+ }
91571
+ async dispose() {
91572
+ if (this.replySubscription) {
91573
+ this.replySubscription.unsubscribe();
91574
+ this.replySubscription = null;
91575
+ }
91576
+ if (this.nc) {
91577
+ try {
91578
+ await this.nc.drain();
91579
+ } catch {}
91580
+ this.nc = null;
91581
+ }
91582
+ }
91583
+ async ensureConnected() {
91584
+ if (this.nc)
91585
+ return;
91586
+ this.nc = await import_nats4.connect({
91587
+ servers: this.config.natsUrl,
91588
+ name: `omni-nats-genie-${this.config.instanceId}`,
91589
+ reconnect: true,
91590
+ maxReconnectAttempts: -1,
91591
+ reconnectTimeWait: 2000
91592
+ });
91593
+ log16.info("Connected to NATS", { url: this.config.natsUrl });
91594
+ }
91595
+ buildMessage(context) {
91596
+ let message2 = "";
91597
+ if (context.content.text) {
91598
+ message2 = context.content.text;
91599
+ } else if (context.content.emoji) {
91600
+ message2 = `[Reaction: ${context.content.emoji} on message ${context.content.referencedMessageId ?? context.source.messageId}]`;
91601
+ }
91602
+ if (message2 && this.config.prefixSenderName !== false && context.sender.displayName) {
91603
+ message2 = `[${context.sender.displayName}]: ${message2}`;
91604
+ }
91605
+ return message2;
91606
+ }
91607
+ async writeDeadLetter(payload, error2) {
91608
+ try {
91609
+ const dlDir = join5(homedir3(), ".omni", "dead-letters");
91610
+ await mkdir(dlDir, { recursive: true });
91611
+ const filename = `nats-genie-${Date.now()}-${payload.chatId}.json`;
91612
+ await writeFile(join5(dlDir, filename), JSON.stringify({
91613
+ payload,
91614
+ error: error2 instanceof Error ? error2.message : String(error2),
91615
+ timestamp: new Date().toISOString()
91616
+ }, null, 2));
91617
+ log16.warn("Dead letter written", { filename });
91618
+ } catch (dlError) {
91619
+ log16.error("Failed to write dead letter", {
91620
+ error: dlError instanceof Error ? dlError.message : String(dlError)
91621
+ });
91622
+ }
91623
+ }
91624
+ }
91437
91625
  // ../core/src/tracing/journey-tracker.ts
91438
91626
  var LATENCY_PAIRS = [
91439
91627
  { key: "channelProcessing", from: "T0", to: "T1" },
@@ -91762,17 +91950,17 @@ class HookRegistry {
91762
91950
  }
91763
91951
  }
91764
91952
  // ../core/src/hooks/executor.ts
91765
- var log18 = createLogger("hooks:executor");
91953
+ var log17 = createLogger("hooks:executor");
91766
91954
  // src/commands/providers-setup.ts
91767
- import { execFileSync, execSync } from "child_process";
91955
+ import { execFileSync as execFileSync2, execSync } from "child_process";
91768
91956
  import * as nodeCrypto2 from "crypto";
91769
91957
  import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
91770
91958
  import { homedir as homedir4 } from "os";
91771
91959
  import { dirname as dirname4, resolve as resolve2 } from "path";
91772
- import { createInterface as createInterface2 } from "readline";
91960
+ import { createInterface as createInterface3 } from "readline";
91773
91961
  init_config();
91774
91962
  async function promptLine2(question, defaultValue = "") {
91775
- const rl = createInterface2({
91963
+ const rl = createInterface3({
91776
91964
  input: process.stdin,
91777
91965
  output: process.stdout
91778
91966
  });
@@ -92045,7 +92233,7 @@ function resolvePluginPath(explicit) {
92045
92233
  function registerPlugin(config2, pluginPath, configPath) {
92046
92234
  if (hasOpenClawCli()) {
92047
92235
  try {
92048
- execFileSync("openclaw", ["plugins", "install", "--link", pluginPath], { stdio: "ignore" });
92236
+ execFileSync2("openclaw", ["plugins", "install", "--link", pluginPath], { stdio: "ignore" });
92049
92237
  try {
92050
92238
  return { config: readOpenClawConfig(configPath), registered: true };
92051
92239
  } catch {
@@ -92211,136 +92399,6 @@ async function runOpenClawSetup(opts) {
92211
92399
  error(`OpenClaw provider setup failed: ${message2}`);
92212
92400
  }
92213
92401
  }
92214
- var GENIE_TEMPLATE_VARS = `
92215
- Template variables (resolved per-message at runtime):
92216
- {chat_id} - Conversation ID (1 session per chat)
92217
- {thread_id} - Thread ID (1 session per thread)
92218
- {sender_id} - Sender user ID (1 session per person)
92219
- {channel} - Channel type (telegram, whatsapp, etc.)
92220
- {instance_id} - Omni instance ID
92221
- Examples:
92222
- "workspace" \u2192 Single shared session
92223
- "genie-{chat_id}" \u2192 One session per conversation
92224
- "genie-{chat_id}-{thread_id}" \u2192 Per-thread isolation`;
92225
- async function collectGenieOptions(options) {
92226
- const agentName = options.agentName ?? await promptLine2('Agent name (your identity / "from" field): ');
92227
- const targetAgent = options.targetAgent ?? await promptLine2("Target agent (inbox to deliver to): ");
92228
- const agentRole = options.agentRole ?? await promptLine2('Agent role (registered genie dir agent, e.g. "omni-pm") [team-lead]: ', "team-lead");
92229
- if (!options.teamName) {
92230
- info(GENIE_TEMPLATE_VARS);
92231
- }
92232
- const teamName = options.teamName ?? await promptLine2(`Team name template [${agentName}-{chat_id}]: `, `${agentName}-{chat_id}`);
92233
- const defaultName = `genie-${agentName}`;
92234
- const name = options.name ?? await promptLine2(`Provider name [${defaultName}]: `, defaultName);
92235
- const baseUrl = options.baseUrl ?? await promptLine2("Base URL [file:///home/genie/.claude/teams]: ", "file:///home/genie/.claude/teams");
92236
- let instanceId = options.instanceId;
92237
- if (!instanceId) {
92238
- instanceId = await promptLine2("Instance ID (Omni instance UUID, leave blank to skip): ") || undefined;
92239
- }
92240
- return {
92241
- agentName,
92242
- targetAgent,
92243
- teamName,
92244
- agentRole,
92245
- name,
92246
- baseUrl,
92247
- instanceId,
92248
- nonInteractive: options.nonInteractive
92249
- };
92250
- }
92251
- async function runGenieSetup(opts) {
92252
- const spinner = ora();
92253
- try {
92254
- spinner.start("Creating Genie provider...");
92255
- const client = getClient();
92256
- const provider = await client.providers.create({
92257
- name: opts.name,
92258
- schema: "genie",
92259
- baseUrl: opts.baseUrl,
92260
- schemaConfig: {
92261
- agentName: opts.agentName,
92262
- targetAgent: opts.targetAgent,
92263
- teamName: opts.teamName,
92264
- agentRole: opts.agentRole
92265
- }
92266
- });
92267
- spinner.succeed(`Provider created: ${provider.id}`);
92268
- spinner.start("Testing provider health...");
92269
- const health = await client.providers.checkHealth(provider.id);
92270
- if (health.healthy) {
92271
- spinner.succeed(`Provider is healthy (latency: ${health.latency}ms)`);
92272
- } else {
92273
- spinner.warn(`Provider created but health check failed: ${health.error ?? "unknown"}`);
92274
- info(" The provider was created. Re-test later with:");
92275
- info(` omni providers test ${provider.id}`);
92276
- }
92277
- info("");
92278
- success("Genie provider setup complete");
92279
- info(` Provider ID: ${provider.id}`);
92280
- info(` Provider name: ${opts.name}`);
92281
- info(` Agent name: ${opts.agentName}`);
92282
- info(` Target agent: ${opts.targetAgent}`);
92283
- info(` Agent role: ${opts.agentRole}`);
92284
- info(` Team template: ${opts.teamName}`);
92285
- info(` Base URL: ${opts.baseUrl}`);
92286
- info("");
92287
- info("How it works:");
92288
- info(" 1. Incoming messages are written to ~/.claude/teams/<team>/inboxes/<target>.json");
92289
- info(" 2. Claude Code agent picks up messages natively from its team inbox");
92290
- info(" 3. Agent replies via `omni send` (fire-and-forget, no polling)");
92291
- info("");
92292
- info("Next steps:");
92293
- if (opts.instanceId) {
92294
- info(` 1. Assign to instance: omni instances update ${opts.instanceId} --agent-provider ${provider.id}`);
92295
- } else {
92296
- info(` 1. Assign to instance: omni instances update <instance-id> --agent-provider ${provider.id}`);
92297
- }
92298
- info(` 2. Test connectivity: omni providers test ${provider.id}`);
92299
- info(` 3. Update template: omni providers update ${provider.id} --team-name "new-{chat_id}"`);
92300
- } catch (err) {
92301
- spinner.fail("Setup failed");
92302
- const message2 = err instanceof Error ? err.message : "Unknown error";
92303
- error(`Genie provider setup failed: ${message2}`);
92304
- }
92305
- }
92306
- function resolveGenieNonInteractive(options) {
92307
- if (!options.agentName)
92308
- return "Missing required flag: --agent-name";
92309
- if (!options.targetAgent)
92310
- return "Missing required flag: --target-agent";
92311
- return {
92312
- agentName: options.agentName,
92313
- targetAgent: options.targetAgent,
92314
- teamName: options.teamName ?? `${options.agentName}-{chat_id}`,
92315
- agentRole: options.agentRole ?? "team-lead",
92316
- name: options.name ?? `genie-${options.agentName}`,
92317
- baseUrl: options.baseUrl ?? "file:///home/genie/.claude/teams",
92318
- instanceId: options.instanceId,
92319
- nonInteractive: true
92320
- };
92321
- }
92322
- async function handleGenieSetup(options) {
92323
- if (options.instanceId && !isValidUuid(options.instanceId)) {
92324
- error(`Invalid --instance-id: must be a valid UUID. Got: ${options.instanceId}`);
92325
- return;
92326
- }
92327
- let resolved;
92328
- if (options.nonInteractive) {
92329
- const result = resolveGenieNonInteractive(options);
92330
- if (typeof result === "string") {
92331
- error(result);
92332
- return;
92333
- }
92334
- resolved = result;
92335
- } else {
92336
- resolved = await collectGenieOptions(options);
92337
- }
92338
- if (resolved.instanceId && !isValidUuid(resolved.instanceId)) {
92339
- error(`Invalid instance ID: must be a valid UUID. Got: ${resolved.instanceId}`);
92340
- return;
92341
- }
92342
- await runGenieSetup(resolved);
92343
- }
92344
92402
  function createSetupCommand() {
92345
92403
  const setup = new Command("setup").description("Interactive setup wizards for providers");
92346
92404
  setup.command("openclaw").description("Set up an OpenClaw provider (keypair generation + device pairing + provider creation)").option("--gateway-url <url>", "Gateway WebSocket URL (ws:// or wss://)").option("--gateway-token <token>", "Gateway authentication token").option("--agent-id <agentId>", "Default agent ID").option("--name <name>", "Provider name (default: openclaw-<agent-id>)").option("--instance-id <uuid>", "Omni instance UUID for the openclaw channel account").option("--account-name <name>", "Account name in openclaw.json (default: agent-id)").option("--plugin-path <path>", "Path to omni.ts plugin entry (auto-detected from CWD)").option("--skip-openclaw-config", "Skip openclaw.json updates entirely").option("--non-interactive", "Error on missing required flags instead of prompting").action(async (options) => {
@@ -92372,7 +92430,9 @@ function createSetupCommand() {
92372
92430
  }
92373
92431
  await runOpenClawSetup(resolved);
92374
92432
  });
92375
- setup.command("genie").description("Set up a Genie provider (Claude Code team inbox integration)").option("--agent-name <name>", 'Agent identity / "from" field').option("--target-agent <name>", "Target agent inbox to deliver messages to").option("--team-name <template>", "Team name template (supports {chat_id}, {thread_id}, etc.)").option("--agent-role <role>", "Registered genie dir agent name (default: team-lead)").option("--name <name>", "Provider name (default: genie-<agent-name>)").option("--base-url <url>", "Base URL (default: file:///home/genie/.claude/teams)").option("--instance-id <uuid>", "Omni instance UUID to auto-assign provider").option("--non-interactive", "Error on missing required flags instead of prompting").action(handleGenieSetup);
92433
+ setup.command("genie").description("[DEPRECATED] Use `omni connect <instance-id> <agent-name>` instead").allowUnknownOption().action(() => {
92434
+ error("The `providers setup genie` command has been replaced.\nUse `omni connect <instance-id> <agent-name>` for NATS-based Genie integration.");
92435
+ });
92376
92436
  return setup;
92377
92437
  }
92378
92438
 
@@ -92427,18 +92487,17 @@ function buildClaudeCodeConfig(options) {
92427
92487
  config2.systemPrompt = options.systemPrompt;
92428
92488
  return config2;
92429
92489
  }
92430
- function buildGenieConfig(options) {
92431
- return {
92432
- agentName: options.agentName,
92433
- targetAgent: options.targetAgent,
92434
- teamName: options.teamName ?? "omni-{chat_id}"
92435
- };
92490
+ function buildNatsGenieConfig(options) {
92491
+ const config2 = {};
92492
+ if (options.agentName)
92493
+ config2.agentName = options.agentName;
92494
+ return config2;
92436
92495
  }
92437
92496
  function buildSchemaConfig(options) {
92438
92497
  const builders = {
92439
92498
  openclaw: buildOpenClawConfig,
92440
92499
  "claude-code": buildClaudeCodeConfig,
92441
- genie: buildGenieConfig
92500
+ "nats-genie": buildNatsGenieConfig
92442
92501
  };
92443
92502
  const builder = builders[options.schema];
92444
92503
  if (builder) {
@@ -93649,7 +93708,7 @@ function createTtsCommand() {
93649
93708
  }
93650
93709
 
93651
93710
  // src/commands/update.ts
93652
- import { createInterface as createInterface3 } from "readline";
93711
+ import { createInterface as createInterface4 } from "readline";
93653
93712
  init_config();
93654
93713
  var PACKAGE_NAME = "@automagik/omni";
93655
93714
  var UPDATE_HEALTH_TIMEOUT_MS = 1e4;
@@ -93742,7 +93801,7 @@ async function restartServicesAndVerify(servicesToRestart, latest) {
93742
93801
  process.exit(1);
93743
93802
  }
93744
93803
  async function promptConfirm(question) {
93745
- const rl = createInterface3({
93804
+ const rl = createInterface4({
93746
93805
  input: process.stdin,
93747
93806
  output: process.stdout
93748
93807
  });
@@ -94108,6 +94167,12 @@ var COMMANDS = [
94108
94167
  helpGroup: "Core",
94109
94168
  helpDescription: "Text-to-speech operations"
94110
94169
  },
94170
+ {
94171
+ create: createChannelsCommand,
94172
+ category: "core",
94173
+ helpGroup: "Management",
94174
+ helpDescription: "Channel types, add instances, status overview"
94175
+ },
94111
94176
  {
94112
94177
  create: createInstancesCommand,
94113
94178
  category: "core",
@@ -94133,6 +94198,12 @@ var COMMANDS = [
94133
94198
  helpGroup: "Management",
94134
94199
  helpDescription: "AI/LLM providers configuration"
94135
94200
  },
94201
+ {
94202
+ create: createConnectCommand,
94203
+ category: "core",
94204
+ helpGroup: "Management",
94205
+ helpDescription: "Connect instance to genie agent via NATS"
94206
+ },
94136
94207
  {
94137
94208
  create: createRoutesCommand,
94138
94209
  category: "standard",
@@ -94245,7 +94316,7 @@ function getHiddenCount() {
94245
94316
  return COMMANDS.filter((cmd) => !cmd.helpDescription).length;
94246
94317
  }
94247
94318
  var program2 = new Command;
94248
- program2.name("omni").description("CLI for Omni v2 - Universal Omnichannel Platform").version(VERSION, "-V, --version", "output the version number").enablePositionalOptions().passThroughOptions().option("--no-color", "Disable colored output").option("--all", "Show all commands including debug commands").hook("preAction", (_thisCommand, actionCommand) => {
94319
+ program2.name("omni").description("CLI for Omni - Universal Omnichannel Platform").version(VERSION, "-V, --version", "output the version number").enablePositionalOptions().passThroughOptions().option("--no-color", "Disable colored output").option("--all", "Show all commands including debug commands").hook("preAction", (_thisCommand, actionCommand) => {
94249
94320
  const opts = actionCommand.optsWithGlobals();
94250
94321
  if (opts.color === false) {
94251
94322
  disableColors();