@sentry/node 11.0.0-alpha.2 → 11.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +19 -0
  2. package/build/cjs/index.js +4 -3
  3. package/build/cjs/index.js.map +1 -1
  4. package/build/cjs/integrations/anr/index.js +1 -1
  5. package/build/cjs/integrations/fs/vendored/instrumentation.js +2 -1
  6. package/build/cjs/integrations/fs/vendored/instrumentation.js.map +1 -1
  7. package/build/cjs/integrations/http/SentryHttpInstrumentation.js +5 -4
  8. package/build/cjs/integrations/http/SentryHttpInstrumentation.js.map +1 -1
  9. package/build/cjs/integrations/http/httpServerIntegration.js +4 -3
  10. package/build/cjs/integrations/http/httpServerIntegration.js.map +1 -1
  11. package/build/cjs/integrations/http/httpServerSpansIntegration.js +5 -33
  12. package/build/cjs/integrations/http/httpServerSpansIntegration.js.map +1 -1
  13. package/build/cjs/integrations/http/index.js +8 -4
  14. package/build/cjs/integrations/http/index.js.map +1 -1
  15. package/build/cjs/integrations/local-variables/local-variables-async.js +1 -1
  16. package/build/cjs/integrations/node-fetch/undici-instrumentation.js +13 -2
  17. package/build/cjs/integrations/node-fetch/undici-instrumentation.js.map +1 -1
  18. package/build/cjs/integrations/nodeRuntimeMetrics.js +2 -1
  19. package/build/cjs/integrations/nodeRuntimeMetrics.js.map +1 -1
  20. package/build/cjs/integrations/onunhandledrejection.js +5 -3
  21. package/build/cjs/integrations/onunhandledrejection.js.map +1 -1
  22. package/build/cjs/sdk/api.js +2 -1
  23. package/build/cjs/sdk/api.js.map +1 -1
  24. package/build/cjs/sdk/client.js +2 -1
  25. package/build/cjs/sdk/client.js.map +1 -1
  26. package/build/cjs/sdk/index.js +1 -1
  27. package/build/cjs/sdk/index.js.map +1 -1
  28. package/build/esm/index.js +3 -2
  29. package/build/esm/index.js.map +1 -1
  30. package/build/esm/integrations/anr/index.js +1 -1
  31. package/build/esm/integrations/anr/worker-script.js +2 -2
  32. package/build/esm/integrations/fs/vendored/instrumentation.js +2 -1
  33. package/build/esm/integrations/fs/vendored/instrumentation.js.map +1 -1
  34. package/build/esm/integrations/http/SentryHttpInstrumentation.js +2 -1
  35. package/build/esm/integrations/http/SentryHttpInstrumentation.js.map +1 -1
  36. package/build/esm/integrations/http/httpServerIntegration.js +3 -2
  37. package/build/esm/integrations/http/httpServerIntegration.js.map +1 -1
  38. package/build/esm/integrations/http/httpServerSpansIntegration.js +7 -35
  39. package/build/esm/integrations/http/httpServerSpansIntegration.js.map +1 -1
  40. package/build/esm/integrations/http/index.js +6 -2
  41. package/build/esm/integrations/http/index.js.map +1 -1
  42. package/build/esm/integrations/local-variables/local-variables-async.js +1 -1
  43. package/build/esm/integrations/local-variables/worker-script.js +1 -1
  44. package/build/esm/integrations/node-fetch/undici-instrumentation.js +15 -4
  45. package/build/esm/integrations/node-fetch/undici-instrumentation.js.map +1 -1
  46. package/build/esm/integrations/nodeRuntimeMetrics.js +2 -1
  47. package/build/esm/integrations/nodeRuntimeMetrics.js.map +1 -1
  48. package/build/esm/integrations/onunhandledrejection.js +5 -3
  49. package/build/esm/integrations/onunhandledrejection.js.map +1 -1
  50. package/build/esm/package.json +1 -1
  51. package/build/esm/sdk/api.js +2 -1
  52. package/build/esm/sdk/api.js.map +1 -1
  53. package/build/esm/sdk/client.js +2 -1
  54. package/build/esm/sdk/client.js.map +1 -1
  55. package/build/esm/sdk/index.js +1 -1
  56. package/build/esm/sdk/index.js.map +1 -1
  57. package/build/import-hook.mjs +1 -1
  58. package/build/types/index.d.ts +4 -3
  59. package/build/types/index.d.ts.map +1 -1
  60. package/build/types/integrations/fs/vendored/instrumentation.d.ts.map +1 -1
  61. package/build/types/integrations/http/SentryHttpInstrumentation.d.ts +2 -1
  62. package/build/types/integrations/http/SentryHttpInstrumentation.d.ts.map +1 -1
  63. package/build/types/integrations/http/httpServerIntegration.d.ts +3 -2
  64. package/build/types/integrations/http/httpServerIntegration.d.ts.map +1 -1
  65. package/build/types/integrations/http/httpServerSpansIntegration.d.ts +2 -1
  66. package/build/types/integrations/http/httpServerSpansIntegration.d.ts.map +1 -1
  67. package/build/types/integrations/http/index.d.ts.map +1 -1
  68. package/build/types/integrations/node-fetch/undici-instrumentation.d.ts.map +1 -1
  69. package/build/types/integrations/nodeRuntimeMetrics.d.ts.map +1 -1
  70. package/build/types/sdk/api.d.ts.map +1 -1
  71. package/build/types/sdk/client.d.ts +1 -1
  72. package/build/types/sdk/client.d.ts.map +1 -1
  73. package/build/types/types.d.ts +2 -1
  74. package/build/types/types.d.ts.map +1 -1
  75. package/package.json +6 -5
package/README.md CHANGED
@@ -72,6 +72,25 @@ If it is not possible for you to pass the `--import` flag to the Node.js binary,
72
72
  NODE_OPTIONS="--import ./instrument.mjs" npm run start
73
73
  ```
74
74
 
75
+ ### Bundling your server
76
+
77
+ `@sentry/node` installs its automatic (diagnostics-channel) instrumentation through a runtime module
78
+ hook that ships in `@sentry/server-runtime-injection` and is designed to run from `node_modules`. There are two
79
+ supported ways to keep auto-instrumentation working when you bundle your server:
80
+
81
+ 1. **Keep `@sentry/server-runtime-injection` external** (do not inline it into the bundle) so the runtime hook
82
+ loads from `node_modules`. Most bundlers externalize `node_modules` for a Node target by default;
83
+ if yours inlines everything, mark `@sentry/server-runtime-injection` as external explicitly.
84
+ 2. **Instrument at build time** with the Sentry bundler plugins (`@sentry/node/esbuild`,
85
+ `@sentry/node/webpack`, `@sentry/node/vite`, `@sentry/node/rollup`), which inject the
86
+ instrumentation into your bundled dependencies during the build. In this mode the runtime hook is
87
+ not needed.
88
+
89
+ If you bundle `@sentry/server-runtime-injection` **and** don't use the build-time plugin, its internal code
90
+ transformer is stripped and runtime auto-instrumentation is disabled. `@sentry/node` warns the
91
+ first time an instrumented dependency loads uninstrumented, so a build-time-instrumented app never
92
+ sees the warning.
93
+
75
94
  ## Links
76
95
 
77
96
  - [Official SDK Docs](https://docs.sentry.io/quickstart/)
@@ -16,6 +16,7 @@ const initOtel = require('./sdk/initOtel.js');
16
16
  const index$3 = require('./integrations/tracing/index.js');
17
17
  const opentelemetry = require('@sentry/opentelemetry');
18
18
  const core = require('@sentry/core');
19
+ const server = require('@sentry/core/server');
19
20
  const exports$1 = require('./logs/exports.js');
20
21
  const childProcess = require('./integrations/childProcess.js');
21
22
  const console = require('./integrations/console.js');
@@ -78,7 +79,7 @@ exports.mongooseIntegration = serverUtils.mongooseIntegration;
78
79
  exports.mysql2Integration = serverUtils.mysql2Integration;
79
80
  exports.mysqlIntegration = serverUtils.mysqlIntegration;
80
81
  exports.openAIIntegration = serverUtils.openAIIntegration;
81
- exports.otlpIntegration = serverUtils.otlpIntegration;
82
+ exports.openTelemetryIntegration = serverUtils.openTelemetryIntegration;
82
83
  exports.postgresIntegration = serverUtils.postgresIntegration;
83
84
  exports.postgresJsIntegration = serverUtils.postgresJsIntegration;
84
85
  exports.prismaIntegration = serverUtils.prismaIntegration;
@@ -176,7 +177,6 @@ exports.startSpan = core.startSpan;
176
177
  exports.startSpanManual = core.startSpanManual;
177
178
  exports.supabaseIntegration = core.supabaseIntegration;
178
179
  exports.suppressTracing = core.suppressTracing;
179
- exports.trpcMiddleware = core.trpcMiddleware;
180
180
  exports.updateSpanName = core.updateSpanName;
181
181
  exports.winterCGHeadersToDict = core.winterCGHeadersToDict;
182
182
  exports.withActiveSpan = core.withActiveSpan;
@@ -185,8 +185,9 @@ exports.withMonitor = core.withMonitor;
185
185
  exports.withScope = core.withScope;
186
186
  exports.withStaticSpan = core.withStaticSpan;
187
187
  exports.withStreamedSpan = core.withStreamedSpan;
188
- exports.wrapMcpServerWithSentry = core.wrapMcpServerWithSentry;
189
188
  exports.zodErrorsIntegration = core.zodErrorsIntegration;
189
+ exports.trpcMiddleware = server.trpcMiddleware;
190
+ exports.wrapMcpServerWithSentry = server.wrapMcpServerWithSentry;
190
191
  exports.logger = exports$1;
191
192
  exports.childProcessIntegration = childProcess.childProcessIntegration;
192
193
  exports.consoleIntegration = console.consoleIntegration;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -6,7 +6,7 @@ const core = require('@sentry/core');
6
6
  const debug = require('../../utils/debug.js');
7
7
 
8
8
  const { isPromise } = util.types;
9
- const base64WorkerScript = "LyohIEBzZW50cnkvbm9kZSAxMS4wLjAtYWxwaGEuMiAoYTcxYTk0MykgfCBodHRwczovL2dpdGh1Yi5jb20vZ2V0c2VudHJ5L3NlbnRyeS1qYXZhc2NyaXB0ICovCmltcG9ydHtTZXNzaW9uIGFzIHR9ZnJvbSJub2RlOmluc3BlY3RvciI7aW1wb3J0e3dvcmtlckRhdGEgYXMgZSxwYXJlbnRQb3J0IGFzIG59ZnJvbSJub2RlOndvcmtlcl90aHJlYWRzIjtpbXBvcnR7cG9zaXggYXMgcixzZXAgYXMgb31mcm9tIm5vZGU6cGF0aCI7aW1wb3J0KmFzIHMgZnJvbSJub2RlOmh0dHAiO2ltcG9ydCphcyBpIGZyb20ibm9kZTpodHRwcyI7aW1wb3J0e1JlYWRhYmxlIGFzIGN9ZnJvbSJub2RlOnN0cmVhbSI7aW1wb3J0e2NyZWF0ZUd6aXAgYXMgdX1mcm9tIm5vZGU6emxpYiI7aW1wb3J0KmFzIGEgZnJvbSJub2RlOm5ldCI7aW1wb3J0KmFzIGYgZnJvbSJub2RlOnRscyI7Y29uc3QgaD0idW5kZWZpbmVkIj09dHlwZW9mIF9fU0VOVFJZX0RFQlVHX198fF9fU0VOVFJZX0RFQlVHX18scD1nbG9iYWxUaGlzLGw9IjExLjAuMC1hbHBoYS4yIjtmdW5jdGlvbiBkKCl7cmV0dXJuIGcocCkscH1mdW5jdGlvbiBnKHQpe2NvbnN0IGU9dC5fX1NFTlRSWV9fPXQuX19TRU5UUllfX3x8e307cmV0dXJuIGUudmVyc2lvbj1lLnZlcnNpb258fGwsZVtsXT1lW2xdfHx7fX1mdW5jdGlvbiBtKHQsZSxuPXApe2NvbnN0IHI9bi5fX1NFTlRSWV9fPW4uX19TRU5UUllfX3x8e30sbz1yW2xdPXJbbF18fHt9O3JldHVybiBvW3RdfHwob1t0XT1lKCkpfWNvbnN0IHk9e307ZnVuY3Rpb24gYih0KXtpZighKCJjb25zb2xlImluIHApKXJldHVybiB0KCk7Y29uc3QgZT1wLmNvbnNvbGUsbj17fSxyPU9iamVjdC5rZXlzKHkpO3IuZm9yRWFjaCh0PT57Y29uc3Qgcj15W3RdO25bdF09ZVt0XSxlW3RdPXJ9KTt0cnl7cmV0dXJuIHQoKX1maW5hbGx5e3IuZm9yRWFjaCh0PT57ZVt0XT1uW3RdfSl9fWZ1bmN0aW9uIHYoKXtyZXR1cm4gUygpLmVuYWJsZWR9ZnVuY3Rpb24gdyh0LC4uLmUpe2gmJnYoKSYmYigoKT0+e3AuY29uc29sZVt0XShgU2VudHJ5IExvZ2dlciBbJHt0fV06YCwuLi5lKX0pfWZ1bmN0aW9uIFMoKXtyZXR1cm4gaD9tKCJsb2dnZXJTZXR0aW5ncyIsKCk9Pih7ZW5hYmxlZDohMX0pKTp7ZW5hYmxlZDohMX19Y29uc3QgXz17ZW5hYmxlOmZ1bmN0aW9uKCl7UygpLmVuYWJsZWQ9ITB9LGRpc2FibGU6ZnVuY3Rpb24oKXtTKCkuZW5hYmxlZD0hMX0saXNFbmFibGVkOnYsbG9nOmZ1bmN0aW9uKC4uLnQpe3coImxvZyIsLi4udCl9LHdhcm46ZnVuY3Rpb24oLi4udCl7dygid2FybiIsLi4udCl9LGVycm9yOmZ1bmN0aW9uKC4uLnQpe3coImVycm9yIiwuLi50KX19LCQ9L2NhcHR1cmVNZXNzYWdlfGNhcHR1cmVFeGNlcHRpb24vO2Z1bmN0aW9uIEUodCl7cmV0dXJuIHRbdC5sZW5ndGgtMV18fHt9fWNvbnN0IHg9Ijxhbm9ueW1vdXM+Ijtjb25zdCBOPU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmc7ZnVuY3Rpb24gQyh0KXtyZXR1cm4gZnVuY3Rpb24odCxlKXtyZXR1cm4gTi5jYWxsKHQpPT09YFtvYmplY3QgJHtlfV1gfSh0LCJPYmplY3QiKX1mdW5jdGlvbiBqKHQpe3JldHVybiBCb29sZWFuKHQ/LnRoZW4mJiJmdW5jdGlvbiI9PXR5cGVvZiB0LnRoZW4pfWZ1bmN0aW9uIE8odCxlKXt0cnl7cmV0dXJuIHQgaW5zdGFuY2VvZiBlfWNhdGNoe3JldHVybiExfX1mdW5jdGlvbiBQKHQpe2lmKGZ1bmN0aW9uKHQpe3N3aXRjaChOLmNhbGwodCkpe2Nhc2UiW29iamVjdCBFcnJvcl0iOmNhc2UiW29iamVjdCBFeGNlcHRpb25dIjpjYXNlIltvYmplY3QgRE9NRXhjZXB0aW9uXSI6Y2FzZSJbb2JqZWN0IFdlYkFzc2VtYmx5LkV4Y2VwdGlvbl0iOnJldHVybiEwO2RlZmF1bHQ6cmV0dXJuIE8odCxFcnJvcil9fSh0KSlyZXR1cm57bWVzc2FnZTp0Lm1lc3NhZ2UsbmFtZTp0Lm5hbWUsc3RhY2s6dC5zdGFjaywuLi5BKHQpfTtpZihlPXQsInVuZGVmaW5lZCIhPXR5cGVvZiBFdmVudCYmTyhlLEV2ZW50KSl7Y29uc3R7dHlwZTplLHRhcmdldDpuLGN1cnJlbnRUYXJnZXQ6cixkZXRhaWw6b309dDtyZXR1cm57dHlwZTplLHRhcmdldDpuLGN1cnJlbnRUYXJnZXQ6ciwuLi5vP3tkZXRhaWw6b306e30sLi4uQSh0KX19dmFyIGU7cmV0dXJuIHR9ZnVuY3Rpb24gQSh0KXtyZXR1cm4ib2JqZWN0Ij09dHlwZW9mKGU9dCkmJm51bGwhPT1lP09iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyh0KSk6e307dmFyIGV9bGV0IFQ7ZnVuY3Rpb24gayh0KXtpZih2b2lkIDAhPT1UKXJldHVybiBUP1QodCk6dCgpO2NvbnN0IGU9U3ltYm9sLmZvcigiX19TRU5UUllfU0FGRV9SQU5ET01fSURfV1JBUFBFUl9fIiksbj1wO3JldHVybiBlIGluIG4mJiJmdW5jdGlvbiI9PXR5cGVvZiBuW2VdPyhUPW5bZV0sVCh0KSk6KFQ9bnVsbCx0KCkpfWZ1bmN0aW9uIFIoKXtyZXR1cm4gaygoKT0+TWF0aC5yYW5kb20oKSl9ZnVuY3Rpb24gSSgpe3JldHVybiBrKCgpPT5EYXRlLm5vdygpKX1jb25zdCBEPVN5bWJvbC5mb3IoInNlbnRyeS5za2lwTm9ybWFsaXphdGlvbiIpLFU9U3ltYm9sLmZvcigic2VudHJ5Lm92ZXJyaWRlTm9ybWFsaXphdGlvbkRlcHRoIik7ZnVuY3Rpb24gQih0LGU9MTAwLG49MS8wKXt0cnl7cmV0dXJuIEwoIiIsdCxlLG4pfWNhdGNoKHQpe3JldHVybntFUlJPUjpgKipub24tc2VyaWFsaXphYmxlKiogKCR7dH0pYH19fWZ1bmN0aW9uIEwodCxlLG49MS8wLHI9MS8wLG89ZnVuY3Rpb24oKXtjb25zdCB0PW5ldyBXZWFrU2V0O2Z1bmN0aW9uIGUoZSl7cmV0dXJuISF0LmhhcyhlKXx8KHQuYWRkKGUpLCExKX1mdW5jdGlvbiBuKGUpe3QuZGVsZXRlKGUpfXJldHVybltlLG5dfSgpKXtjb25zdFtzLGldPW87aWYobnVsbD09ZXx8WyJib29sZWFuIiwic3RyaW5nIl0uaW5jbHVkZXModHlwZW9mIGUpfHwibnVtYmVyIj09dHlwZW9mIGUmJk51bWJlci5pc0Zpbml0ZShlKSlyZXR1cm4gZTtjb25zdCBjPWZ1bmN0aW9uKHQsZSl7dHJ5e2lmKCJ1bmRlZmluZWQiIT10eXBlb2YgZ2xvYmFsJiZlPT09Z2xvYmFsKXJldHVybiJbR2xvYmFsXSI7aWYoIm51bWJlciI9PXR5cGVvZiBlJiYhTnVtYmVyLmlzRmluaXRlKGUpKXJldHVybmBbJHtlfV1gO2lmKCJmdW5jdGlvbiI9PXR5cGVvZiBlKXJldHVybmBbRnVuY3Rpb246ICR7ZnVuY3Rpb24odCl7dHJ5e3JldHVybiB0JiYiZnVuY3Rpb24iPT10eXBlb2YgdCYmdC5uYW1lfHx4fWNhdGNoe3JldHVybiB4fX0oZSl9XWA7aWYoInN5bWJvbCI9PXR5cGVvZiBlKXJldHVybmBbJHtTdHJpbmcoZSl9XWA7aWYoImJpZ2ludCI9PXR5cGVvZiBlKXJldHVybmBbQmlnSW50OiAke1N0cmluZyhlKX1dYDtjb25zdCB0PWZ1bmN0aW9uKHQpe2NvbnN0IGU9T2JqZWN0LmdldFByb3RvdHlwZU9mKHQpO3JldHVybiBlPy5jb25zdHJ1Y3Rvcj9lLmNvbnN0cnVjdG9yLm5hbWU6Im51bGwgcHJvdG90eXBlIn0oZSk7cmV0dXJuYFtvYmplY3QgJHt0fV1gfWNhdGNoKHQpe3JldHVybmAqKm5vbi1zZXJpYWxpemFibGUqKiAoJHt0fSlgfX0oMCxlKTtpZighYy5zdGFydHNXaXRoKCJbb2JqZWN0ICIpKXJldHVybiBjO2lmKGZ1bmN0aW9uKHQpe3JldHVybiBCb29sZWFuKHRbRF0pfShlKSlyZXR1cm4gZTtjb25zdCB1PWZ1bmN0aW9uKHQpe2NvbnN0IGU9dFtVXTtyZXR1cm4ibnVtYmVyIj09dHlwZW9mIGU/ZTp2b2lkIDB9KGUpLGE9dm9pZCAwIT09dT91Om47aWYoMD09PWEpcmV0dXJuIGMucmVwbGFjZSgib2JqZWN0ICIsIiIpO2lmKHMoZSkpcmV0dXJuIltDaXJjdWxhciB+XSI7Y29uc3QgZj1lO2lmKGYmJiJmdW5jdGlvbiI9PXR5cGVvZiBmLnRvSlNPTil0cnl7cmV0dXJuIEwoIiIsZi50b0pTT04oKSxhLTEscixvKX1jYXRjaHt9Y29uc3QgaD1BcnJheS5pc0FycmF5KGUpP1tdOnt9O2xldCBwPTA7Y29uc3QgbD1QKGUpO2Zvcihjb25zdCB0IGluIGwpe2lmKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobCx0KSljb250aW51ZTtpZihwPj1yKXtoW3RdPSJbTWF4UHJvcGVydGllcyB+XSI7YnJlYWt9Y29uc3QgZT1sW3RdO2hbdF09TCh0LGUsYS0xLHIsbykscCsrfXJldHVybiBpKGUpLGh9ZnVuY3Rpb24gTSh0LGUpe2NvbnN0IG49ZS5yZXBsYWNlKC9cXC9nLCIvIikucmVwbGFjZSgvW3xcXHt9KClbXF1eJCsqPy5dL2csIlxcJCYiKTtsZXQgcj10O3RyeXtyPWRlY29kZVVSSSh0KX1jYXRjaHt9cmV0dXJuIHIucmVwbGFjZSgvXFwvZywiLyIpLnJlcGxhY2UoL3dlYnBhY2s6XC8/L2csIiIpLnJlcGxhY2UobmV3IFJlZ0V4cChgKGZpbGU6Ly8pPy8qJHtufS8qYCwiaWciKSwiYXBwOi8vLyIpfWZ1bmN0aW9uIHoodCxlPTApe3JldHVybiJzdHJpbmciIT10eXBlb2YgdHx8MD09PWV8fHQubGVuZ3RoPD1lP3Q6YCR7dC5zbGljZSgwLGUpfS4uLmB9bGV0IEo7ZnVuY3Rpb24gVyh0PWZ1bmN0aW9uKCl7Y29uc3QgdD1wO3JldHVybiB0LmNyeXB0b3x8dC5tc0NyeXB0b30oKSl7dHJ5e2lmKHQ/LnJhbmRvbVVVSUQpcmV0dXJuIGsoKCk9PnQucmFuZG9tVVVJRCgpKS5yZXBsYWNlKC8tL2csIiIpfWNhdGNoe31yZXR1cm4gSnx8KEo9IjEwMDAwMDAwMTAwMDQwMDA4MDAwMTAwMDAwMDAwMDAwIiksSi5yZXBsYWNlKC9bMDE4XS9nLHQ9Pih0XigxNipSKCkmMTUpPj50LzQpLnRvU3RyaW5nKDE2KSl9ZnVuY3Rpb24gRigpe3JldHVybiBJKCkvMWUzfWxldCBHO2Z1bmN0aW9uIFkoKXtyZXR1cm4oRz8/KEc9ZnVuY3Rpb24oKXtjb25zdHtwZXJmb3JtYW5jZTp0fT1wO2lmKCF0Py5ub3d8fCF0LnRpbWVPcmlnaW4pcmV0dXJuIEY7Y29uc3QgZT10LnRpbWVPcmlnaW47cmV0dXJuKCk9PihlK2soKCk9PnQubm93KCkpKS8xZTN9KCkpKSgpfWZ1bmN0aW9uIEgodCl7Y29uc3QgZT1ZKCksbj17c2lkOlcoKSxpbml0OiEwLHRpbWVzdGFtcDplLHN0YXJ0ZWQ6ZSxkdXJhdGlvbjowLHN0YXR1czoib2siLGVycm9yczowLGlnbm9yZUR1cmF0aW9uOiExLHRvSlNPTjooKT0+ZnVuY3Rpb24odCl7cmV0dXJue3NpZDpgJHt0LnNpZH1gLGluaXQ6dC5pbml0LHN0YXJ0ZWQ6bmV3IERhdGUoMWUzKnQuc3RhcnRlZCkudG9JU09TdHJpbmcoKSx0aW1lc3RhbXA6bmV3IERhdGUoMWUzKnQudGltZXN0YW1wKS50b0lTT1N0cmluZygpLHN0YXR1czp0LnN0YXR1cyxlcnJvcnM6dC5lcnJvcnMsZGlkOiJudW1iZXIiPT10eXBlb2YgdC5kaWR8fCJzdHJpbmciPT10eXBlb2YgdC5kaWQ/YCR7dC5kaWR9YDp2b2lkIDAsZHVyYXRpb246dC5kdXJhdGlvbixhYm5vcm1hbF9tZWNoYW5pc206dC5hYm5vcm1hbF9tZWNoYW5pc20sYXR0cnM6e3JlbGVhc2U6dC5yZWxlYXNlLGVudmlyb25tZW50OnQuZW52aXJvbm1lbnQsaXBfYWRkcmVzczp0LmlwQWRkcmVzcyx1c2VyX2FnZW50OnQudXNlckFnZW50fX19KG4pfTtyZXR1cm4gdCYmWihuLHQpLG59ZnVuY3Rpb24gWih0LGU9e30pe2lmKGUudXNlciYmKCF0LmlwQWRkcmVzcyYmZS51c2VyLmlwX2FkZHJlc3MmJih0LmlwQWRkcmVzcz1lLnVzZXIuaXBfYWRkcmVzcyksdC5kaWR8fGUuZGlkfHwodC5kaWQ9ZS51c2VyLmlkfHxlLnVzZXIuZW1haWx8fGUudXNlci51c2VybmFtZSkpLHQudGltZXN0YW1wPWUudGltZXN0YW1wfHxZKCksZS5hYm5vcm1hbF9tZWNoYW5pc20mJih0LmFibm9ybWFsX21lY2hhbmlzbT1lLmFibm9ybWFsX21lY2hhbmlzbSksZS5pZ25vcmVEdXJhdGlvbiYmKHQuaWdub3JlRHVyYXRpb249ZS5pZ25vcmVEdXJhdGlvbiksZS5zaWQmJih0LnNpZD0zMj09PWUuc2lkLmxlbmd0aD9lLnNpZDpXKCkpLHZvaWQgMCE9PWUuaW5pdCYmKHQuaW5pdD1lLmluaXQpLCF0LmRpZCYmZS5kaWQmJih0LmRpZD1gJHtlLmRpZH1gKSwibnVtYmVyIj09dHlwZW9mIGUuc3RhcnRlZCYmKHQuc3RhcnRlZD1lLnN0YXJ0ZWQpLHQuaWdub3JlRHVyYXRpb24pdC5kdXJhdGlvbj12b2lkIDA7ZWxzZSBpZigibnVtYmVyIj09dHlwZW9mIGUuZHVyYXRpb24pdC5kdXJhdGlvbj1lLmR1cmF0aW9uO2Vsc2V7Y29uc3QgZT10LnRpbWVzdGFtcC10LnN0YXJ0ZWQ7dC5kdXJhdGlvbj1lPj0wP2U6MH1lLnJlbGVhc2UmJih0LnJlbGVhc2U9ZS5yZWxlYXNlKSxlLmVudmlyb25tZW50JiYodC5lbnZpcm9ubWVudD1lLmVudmlyb25tZW50KSwhdC5pcEFkZHJlc3MmJmUuaXBBZGRyZXNzJiYodC5pcEFkZHJlc3M9ZS5pcEFkZHJlc3MpLCF0LnVzZXJBZ2VudCYmZS51c2VyQWdlbnQmJih0LnVzZXJBZ2VudD1lLnVzZXJBZ2VudCksIm51bWJlciI9PXR5cGVvZiBlLmVycm9ycyYmKHQuZXJyb3JzPWUuZXJyb3JzKSxlLnN0YXR1cyYmKHQuc3RhdHVzPWUuc3RhdHVzKX1mdW5jdGlvbiBxKHQsZSxuPTIpe2lmKCFlfHwib2JqZWN0IiE9dHlwZW9mIGV8fG48PTApcmV0dXJuIGU7aWYodCYmMD09PU9iamVjdC5rZXlzKGUpLmxlbmd0aClyZXR1cm4gdDtjb25zdCByPXsuLi50fTtmb3IoY29uc3QgdCBpbiBlKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChlLHQpJiYoclt0XT1xKHJbdF0sZVt0XSxuLTEpKTtyZXR1cm4gcn1jbGFzcyBLe2NvbnN0cnVjdG9yKCl7dGhpcy50PSExLHRoaXMubz1bXSx0aGlzLmk9W10sdGhpcy51PVtdLHRoaXMuaD1bXSx0aGlzLnA9e30sdGhpcy5sPXt9LHRoaXMubT17fSx0aGlzLnY9e30sdGhpcy5TPXt9LHRoaXMuXz17fSxmdW5jdGlvbih0LGUsbil7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LGUse3ZhbHVlOm4sd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfSl9Y2F0Y2h7aCYmXy5sb2coYEZhaWxlZCB0byBhZGQgbm9uLWVudW1lcmFibGUgcHJvcGVydHkgIiR7U3RyaW5nKGUpfSIgdG8gb2JqZWN0YCx0KX19KHRoaXMsInJlZnMiLHt9KSx0aGlzLk49e3RyYWNlSWQ6VygpLHNhbXBsZVJhbmQ6UigpfX1jbG9uZSgpe2NvbnN0IHQ9bmV3IEs7cmV0dXJuIHQudT1bLi4udGhpcy51XSx0Lmw9ey4uLnRoaXMubH0sdC5tPXsuLi50aGlzLm19LHQudj17Li4udGhpcy52fSx0LlM9ey4uLnRoaXMuU30sdGhpcy5TLmZsYWdzJiYodC5TLmZsYWdzPXt2YWx1ZXM6Wy4uLnRoaXMuUy5mbGFncy52YWx1ZXNdfSksdC5wPXRoaXMucCx0LkM9dGhpcy5DLHQuaj10aGlzLmosdC5PPXRoaXMuTyx0LlA9dGhpcy5QLHQuaT1bLi4udGhpcy5pXSx0Lmg9Wy4uLnRoaXMuaF0sdC5fPXsuLi50aGlzLl99LHQuTj17Li4udGhpcy5OfSx0LkE9dGhpcy5BLHQuVD10aGlzLlQsdC5rPXRoaXMuayx0LnJlZnM9ey4uLnRoaXMucmVmc30sdH1zZXRDbGllbnQodCl7dGhpcy5BPXR9c2V0TGFzdEV2ZW50SWQodCl7dGhpcy5UPXR9Z2V0Q2xpZW50KCl7cmV0dXJuIHRoaXMuQX1sYXN0RXZlbnRJZCgpe3JldHVybiB0aGlzLlR9YWRkU2NvcGVMaXN0ZW5lcih0KXt0aGlzLm8ucHVzaCh0KX1hZGRFdmVudFByb2Nlc3Nvcih0KXtyZXR1cm4gdGhpcy5pLnB1c2godCksdGhpc31zZXRVc2VyKHQpe3JldHVybiB0aGlzLnA9dHx8e2VtYWlsOnZvaWQgMCxpZDp2b2lkIDAsaXBfYWRkcmVzczp2b2lkIDAsdXNlcm5hbWU6dm9pZCAwfSx0aGlzLmomJloodGhpcy5qLHt1c2VyOnR9KSx0aGlzLlIoKSx0aGlzfWdldFVzZXIoKXtyZXR1cm4gdGhpcy5wfXNldENvbnZlcnNhdGlvbklkKHQpe3JldHVybiB0aGlzLms9dHx8dm9pZCAwLHRoaXMuUigpLHRoaXN9c2V0VGFncyh0KXtyZXR1cm4gdGhpcy5sPXsuLi50aGlzLmwsLi4udH0sdGhpcy5SKCksdGhpc31zZXRUYWcodCxlKXtyZXR1cm4gdGhpcy5zZXRUYWdzKHtbdF06ZX0pfXNldEF0dHJpYnV0ZXModCl7cmV0dXJuIHRoaXMubT17Li4udGhpcy5tLC4uLnR9LHRoaXMuUigpLHRoaXN9c2V0QXR0cmlidXRlKHQsZSl7cmV0dXJuIHRoaXMuc2V0QXR0cmlidXRlcyh7W3RdOmV9KX1yZW1vdmVBdHRyaWJ1dGUodCl7cmV0dXJuIHQgaW4gdGhpcy5tJiYoZGVsZXRlIHRoaXMubVt0XSx0aGlzLlIoKSksdGhpc31zZXRFeHRyYXModCl7cmV0dXJuIHRoaXMudj17Li4udGhpcy52LC4uLnR9LHRoaXMuUigpLHRoaXN9c2V0RXh0cmEodCxlKXtyZXR1cm4gdGhpcy52PXsuLi50aGlzLnYsW3RdOmV9LHRoaXMuUigpLHRoaXN9c2V0RmluZ2VycHJpbnQodCl7cmV0dXJuIHRoaXMuUD10LHRoaXMuUigpLHRoaXN9c2V0TGV2ZWwodCl7cmV0dXJuIHRoaXMuQz10LHRoaXMuUigpLHRoaXN9c2V0VHJhbnNhY3Rpb25OYW1lKHQpe3JldHVybiB0aGlzLk89dCx0aGlzLlIoKSx0aGlzfXNldENvbnRleHQodCxlKXtyZXR1cm4gbnVsbD09PWU/ZGVsZXRlIHRoaXMuU1t0XTp0aGlzLlNbdF09ZSx0aGlzLlIoKSx0aGlzfXNldFNlc3Npb24odCl7cmV0dXJuIHQ/dGhpcy5qPXQ6ZGVsZXRlIHRoaXMuaix0aGlzLlIoKSx0aGlzfWdldFNlc3Npb24oKXtyZXR1cm4gdGhpcy5qfXVwZGF0ZSh0KXtpZighdClyZXR1cm4gdGhpcztjb25zdCBlPSJmdW5jdGlvbiI9PXR5cGVvZiB0P3QodGhpcyk6dCxuPWUgaW5zdGFuY2VvZiBLP2UuZ2V0U2NvcGVEYXRhKCk6QyhlKT90OnZvaWQgMCx7dGFnczpyLGF0dHJpYnV0ZXM6byxleHRyYTpzLHVzZXI6aSxjb250ZXh0czpjLGxldmVsOnUsZmluZ2VycHJpbnQ6YT1bXSxwcm9wYWdhdGlvbkNvbnRleHQ6Zixjb252ZXJzYXRpb25JZDpofT1ufHx7fTtyZXR1cm4gdGhpcy5sPXsuLi50aGlzLmwsLi4ucn0sdGhpcy5tPXsuLi50aGlzLm0sLi4ub30sdGhpcy52PXsuLi50aGlzLnYsLi4uc30sdGhpcy5TPXsuLi50aGlzLlMsLi4uY30saSYmT2JqZWN0LmtleXMoaSkubGVuZ3RoJiYodGhpcy5wPWkpLHUmJih0aGlzLkM9dSksYS5sZW5ndGgmJih0aGlzLlA9YSksZiYmKHRoaXMuTj1mKSxoJiYodGhpcy5rPWgpLHRoaXN9YWRkQnJlYWRjcnVtYih0LGUpe2NvbnN0IG49Im51bWJlciI9PXR5cGVvZiBlP2U6MTAwO2lmKG48PTApcmV0dXJuIHRoaXM7Y29uc3Qgcj17dGltZXN0YW1wOkYoKSwuLi50LG1lc3NhZ2U6dC5tZXNzYWdlP3oodC5tZXNzYWdlLDIwNDgpOnQubWVzc2FnZX07cmV0dXJuIHRoaXMudS5wdXNoKHIpLHRoaXMudS5sZW5ndGg+biYmKHRoaXMudT10aGlzLnUuc2xpY2UoLW4pLHRoaXMuQT8ucmVjb3JkRHJvcHBlZEV2ZW50KCJidWZmZXJfb3ZlcmZsb3ciLCJsb2dfaXRlbSIpKSx0aGlzLlIoKSx0aGlzfWdldExhc3RCcmVhZGNydW1iKCl7cmV0dXJuIHRoaXMudVt0aGlzLnUubGVuZ3RoLTFdfWNsZWFyQnJlYWRjcnVtYnMoKXtyZXR1cm4gdGhpcy51PVtdLHRoaXMuUigpLHRoaXN9YWRkQXR0YWNobWVudCh0KXtyZXR1cm4gdGhpcy5oLnB1c2godCksdGhpc31jbGVhckF0dGFjaG1lbnRzKCl7cmV0dXJuIHRoaXMuaD1bXSx0aGlzfWdldFNjb3BlRGF0YSgpe3JldHVybnticmVhZGNydW1iczp0aGlzLnUsYXR0YWNobWVudHM6dGhpcy5oLGNvbnRleHRzOnRoaXMuUyx0YWdzOnRoaXMubCxhdHRyaWJ1dGVzOnRoaXMubSxleHRyYTp0aGlzLnYsdXNlcjp0aGlzLnAsbGV2ZWw6dGhpcy5DLGZpbmdlcnByaW50OnRoaXMuUHx8W10sZXZlbnRQcm9jZXNzb3JzOnRoaXMuaSxwcm9wYWdhdGlvbkNvbnRleHQ6dGhpcy5OLHNka1Byb2Nlc3NpbmdNZXRhZGF0YTp0aGlzLl8sdHJhbnNhY3Rpb25OYW1lOnRoaXMuTyxjb252ZXJzYXRpb25JZDp0aGlzLmt9fXNldFNES1Byb2Nlc3NpbmdNZXRhZGF0YSh0KXtyZXR1cm4gdGhpcy5fPXEodGhpcy5fLHQsMiksdGhpc31zZXRQcm9wYWdhdGlvbkNvbnRleHQodCl7cmV0dXJuIHRoaXMuTj10LHRoaXN9Z2V0UHJvcGFnYXRpb25Db250ZXh0KCl7cmV0dXJuIHRoaXMuTn1jYXB0dXJlRXhjZXB0aW9uKHQsZSl7Y29uc3Qgbj1lPy5ldmVudF9pZHx8VygpO2lmKCF0aGlzLkEpcmV0dXJuIGgmJl8ud2FybigiTm8gY2xpZW50IGNvbmZpZ3VyZWQgb24gc2NvcGUgLSB3aWxsIG5vdCBjYXB0dXJlIGV4Y2VwdGlvbiEiKSxuO2NvbnN0IHI9bmV3IEVycm9yKCJTZW50cnkgc3ludGhldGljRXhjZXB0aW9uIik7cmV0dXJuIHRoaXMuQS5jYXB0dXJlRXhjZXB0aW9uKHQse29yaWdpbmFsRXhjZXB0aW9uOnQsc3ludGhldGljRXhjZXB0aW9uOnIsLi4uZSxldmVudF9pZDpufSx0aGlzKSxufWNhcHR1cmVNZXNzYWdlKHQsZSxuKXtjb25zdCByPW4/LmV2ZW50X2lkfHxXKCk7aWYoIXRoaXMuQSlyZXR1cm4gaCYmXy53YXJuKCJObyBjbGllbnQgY29uZmlndXJlZCBvbiBzY29wZSAtIHdpbGwgbm90IGNhcHR1cmUgbWVzc2FnZSEiKSxyO2NvbnN0IG89bj8uc3ludGhldGljRXhjZXB0aW9uPz9uZXcgRXJyb3IodCk7cmV0dXJuIHRoaXMuQS5jYXB0dXJlTWVzc2FnZSh0LGUse29yaWdpbmFsRXhjZXB0aW9uOnQsc3ludGhldGljRXhjZXB0aW9uOm8sLi4ubixldmVudF9pZDpyfSx0aGlzKSxyfWNhcHR1cmVFdmVudCh0LGUpe2NvbnN0IG49dC5ldmVudF9pZHx8ZT8uZXZlbnRfaWR8fFcoKTtyZXR1cm4gdGhpcy5BPyh0aGlzLkEuY2FwdHVyZUV2ZW50KHQsey4uLmUsZXZlbnRfaWQ6bn0sdGhpcyksbik6KGgmJl8ud2FybigiTm8gY2xpZW50IGNvbmZpZ3VyZWQgb24gc2NvcGUgLSB3aWxsIG5vdCBjYXB0dXJlIGV2ZW50ISIpLG4pfVIoKXt0aGlzLnR8fCh0aGlzLnQ9ITAsdGhpcy5vLmZvckVhY2godD0+e3QodGhpcyl9KSx0aGlzLnQ9ITEpfX1jb25zdCBWPSJfX1NFTlRSWV9TVVBQUkVTU19UUkFDSU5HX18iLFE9dD0+dCBpbnN0YW5jZW9mIFByb21pc2UmJiF0W1hdLFg9U3ltYm9sKCJjaGFpbmVkIFByb21pc2VMaWtlIiksdHQ9KHQsZSk9PntpZighZSlyZXR1cm4gdDtsZXQgbj0hMTtmb3IoY29uc3QgciBpbiB0KXtpZihyIGluIGUpY29udGludWU7bj0hMDtjb25zdCBvPXRbcl07ImZ1bmN0aW9uIj09dHlwZW9mIG8/T2JqZWN0LmRlZmluZVByb3BlcnR5KGUscix7dmFsdWU6KC4uLmUpPT5vLmFwcGx5KHQsZSksZW51bWVyYWJsZTohMCxjb25maWd1cmFibGU6ITAsd3JpdGFibGU6ITB9KTplW3JdPW99cmV0dXJuIG4mJk9iamVjdC5hc3NpZ24oZSx7W1hdOiEwfSksZX07Y2xhc3MgZXR7Y29uc3RydWN0b3IodCxlKXtsZXQgbixyO249dHx8bmV3IEsscj1lfHxuZXcgSyx0aGlzLkk9W3tzY29wZTpufV0sdGhpcy5EPXJ9d2l0aFNjb3BlKHQpe2NvbnN0IGU9dGhpcy5VKCk7bGV0IG47dHJ5e249dChlKX1jYXRjaCh0KXt0aHJvdyB0aGlzLkIoKSx0fXJldHVybiBqKG4pPygodCxlLG4pPT57Y29uc3Qgcj10LnRoZW4odD0+KGUodCksdCksdD0+e3Rocm93IG4odCksdH0pO3JldHVybiBRKHIpJiZRKHQpP3I6dHQodCxyKX0pKG4sKCk9PnRoaXMuQigpLCgpPT50aGlzLkIoKSk6KHRoaXMuQigpLG4pfWdldENsaWVudCgpe3JldHVybiB0aGlzLmdldFN0YWNrVG9wKCkuY2xpZW50fWdldFNjb3BlKCl7cmV0dXJuIHRoaXMuZ2V0U3RhY2tUb3AoKS5zY29wZX1nZXRJc29sYXRpb25TY29wZSgpe3JldHVybiB0aGlzLkR9Z2V0U3RhY2tUb3AoKXtyZXR1cm4gdGhpcy5JW3RoaXMuSS5sZW5ndGgtMV19VSgpe2NvbnN0IHQ9dGhpcy5nZXRTY29wZSgpLmNsb25lKCk7cmV0dXJuIHRoaXMuSS5wdXNoKHtjbGllbnQ6dGhpcy5nZXRDbGllbnQoKSxzY29wZTp0fSksdH1CKCl7cmV0dXJuISh0aGlzLkkubGVuZ3RoPD0xKSYmISF0aGlzLkkucG9wKCl9fWZ1bmN0aW9uIG50KCl7Y29uc3QgdD1nKGQoKSk7cmV0dXJuIHQuc3RhY2s9dC5zdGFja3x8bmV3IGV0KG0oImRlZmF1bHRDdXJyZW50U2NvcGUiLCgpPT5uZXcgSyksbSgiZGVmYXVsdElzb2xhdGlvblNjb3BlIiwoKT0+bmV3IEspKX1mdW5jdGlvbiBydCh0KXtyZXR1cm4gbnQoKS53aXRoU2NvcGUodCl9ZnVuY3Rpb24gb3QodCxlKXtjb25zdCBuPW50KCk7cmV0dXJuIG4ud2l0aFNjb3BlKCgpPT4obi5nZXRTdGFja1RvcCgpLnNjb3BlPXQsZSh0KSkpfWZ1bmN0aW9uIHN0KHQpe3JldHVybiBudCgpLndpdGhTY29wZSgoKT0+dChudCgpLmdldElzb2xhdGlvblNjb3BlKCkpKX1mdW5jdGlvbiBpdCh0KXtyZXR1cm4gcnQoZT0+e2Uuc2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKHtbVl06ITB9KTtjb25zdCBuPXQoKTtyZXR1cm4gZS5zZXRTREtQcm9jZXNzaW5nTWV0YWRhdGEoe1tWXTp2b2lkIDB9KSxufSl9ZnVuY3Rpb24gY3QodCl7Y29uc3QgZT1nKHQpO3JldHVybiBlLmFjcz9lLmFjczp7c3VwcHJlc3NUcmFjaW5nOml0LHdpdGhJc29sYXRpb25TY29wZTpzdCx3aXRoU2NvcGU6cnQsd2l0aFNldFNjb3BlOm90LHdpdGhTZXRJc29sYXRpb25TY29wZToodCxlKT0+c3QoZSksZ2V0Q3VycmVudFNjb3BlOigpPT5udCgpLmdldFNjb3BlKCksZ2V0SXNvbGF0aW9uU2NvcGU6KCk9Pm50KCkuZ2V0SXNvbGF0aW9uU2NvcGUoKX19ZnVuY3Rpb24gdXQodCxlPSExKXtjb25zdHtob3N0Om4scGF0aDpyLHBhc3M6byxwb3J0OnMscHJvamVjdElkOmkscHJvdG9jb2w6YyxwdWJsaWNLZXk6dX09dDtyZXR1cm5gJHtjfTovLyR7dX0ke2UmJm8/YDoke299YDoiIn1AJHtufSR7cz9gOiR7c31gOiIifS8ke3I/YCR7cn0vYDpyfSR7aX1gfWZ1bmN0aW9uIGF0KHQsZSl7Y29uc3R7ZmluZ2VycHJpbnQ6bixicmVhZGNydW1iczpyLHNka1Byb2Nlc3NpbmdNZXRhZGF0YTpvfT1lOyFmdW5jdGlvbih0LGUpe2NvbnN0e2V4dHJhOm4sdGFnczpyLHVzZXI6byxjb250ZXh0czpzLGxldmVsOmksdHJhbnNhY3Rpb25OYW1lOmN9PWU7T2JqZWN0LmtleXMobikubGVuZ3RoJiYodC5leHRyYT17Li4ubiwuLi50LmV4dHJhfSk7T2JqZWN0LmtleXMocikubGVuZ3RoJiYodC50YWdzPXsuLi5yLC4uLnQudGFnc30pO09iamVjdC5rZXlzKG8pLmxlbmd0aCYmKHQudXNlcj17Li4ubywuLi50LnVzZXJ9KTtPYmplY3Qua2V5cyhzKS5sZW5ndGgmJih0LmNvbnRleHRzPXsuLi5zLC4uLnQuY29udGV4dHN9KTtpJiYodC5sZXZlbD1pKTtjJiYidHJhbnNhY3Rpb24iIT09dC50eXBlJiYodC50cmFuc2FjdGlvbj1jKX0odCxlKSxmdW5jdGlvbih0LGUpe3QuZmluZ2VycHJpbnQ9dC5maW5nZXJwcmludD9BcnJheS5pc0FycmF5KHQuZmluZ2VycHJpbnQpP3QuZmluZ2VycHJpbnQ6W3QuZmluZ2VycHJpbnRdOltdLGUmJih0LmZpbmdlcnByaW50PXQuZmluZ2VycHJpbnQuY29uY2F0KGUpKTt0LmZpbmdlcnByaW50Lmxlbmd0aHx8ZGVsZXRlIHQuZmluZ2VycHJpbnR9KHQsbiksZnVuY3Rpb24odCxlKXtjb25zdCBuPVsuLi50LmJyZWFkY3J1bWJzfHxbXSwuLi5lXTt0LmJyZWFkY3J1bWJzPW4ubGVuZ3RoP246dm9pZCAwfSh0LHIpLGZ1bmN0aW9uKHQsZSl7dC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE9ey4uLnQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhLC4uLmV9fSh0LG8pfWZ1bmN0aW9uIGZ0KHQsZT1bXSl7cmV0dXJuW3QsZV19ZnVuY3Rpb24gaHQodCxlKXtjb25zdCBuPXRbMV07Zm9yKGNvbnN0IHQgb2Ygbil7aWYoZSh0LHRbMF0udHlwZSkpcmV0dXJuITB9cmV0dXJuITF9ZnVuY3Rpb24gcHQodCl7Y29uc3QgZT1nKHApO3JldHVybiBlLmVuY29kZVBvbHlmaWxsP2UuZW5jb2RlUG9seWZpbGwodCk6KG5ldyBUZXh0RW5jb2RlcikuZW5jb2RlKHQpfWZ1bmN0aW9uIGx0KHQpe2NvbnN0W2Usbl09dDtsZXQgcj1KU09OLnN0cmluZ2lmeShlKTtmdW5jdGlvbiBvKHQpeyJzdHJpbmciPT10eXBlb2Ygcj9yPSJzdHJpbmciPT10eXBlb2YgdD9yK3Q6W3B0KHIpLHRdOnIucHVzaCgic3RyaW5nIj09dHlwZW9mIHQ/cHQodCk6dCl9Zm9yKGNvbnN0IHQgb2Ygbil7Y29uc3RbZSxuXT10O2lmKG8oYFxuJHtKU09OLnN0cmluZ2lmeShlKX1cbmApLCJzdHJpbmciPT10eXBlb2Ygbnx8biBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpbyhuKTtlbHNle2xldCB0O3RyeXt0PUpTT04uc3RyaW5naWZ5KG4pfWNhdGNoe3Q9SlNPTi5zdHJpbmdpZnkoQihuKSl9byh0KX19cmV0dXJuInN0cmluZyI9PXR5cGVvZiByP3I6ZnVuY3Rpb24odCl7Y29uc3QgZT10LnJlZHVjZSgodCxlKT0+dCtlLmxlbmd0aCwwKSxuPW5ldyBVaW50OEFycmF5KGUpO2xldCByPTA7Zm9yKGNvbnN0IGUgb2YgdCluLnNldChlLHIpLHIrPWUubGVuZ3RoO3JldHVybiBufShyKX1jb25zdCBkdD17c2Vzc2lvbnM6InNlc3Npb24iLGV2ZW50OiJlcnJvciIsY2xpZW50X3JlcG9ydDoiaW50ZXJuYWwiLHVzZXJfcmVwb3J0OiJkZWZhdWx0Iixwcm9maWxlX2NodW5rOiJwcm9maWxlIixyZXBsYXlfZXZlbnQ6InJlcGxheSIscmVwbGF5X3JlY29yZGluZzoicmVwbGF5IixjaGVja19pbjoibW9uaXRvciIscmF3X3NlY3VyaXR5OiJzZWN1cml0eSIsbG9nOiJsb2dfaXRlbSIsdHJhY2VfbWV0cmljOiJtZXRyaWMifTtmdW5jdGlvbiBndCh0KXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIHQgaW4gZHR9KHQpP2R0W3RdOnR9ZnVuY3Rpb24gbXQodCl7aWYoIXQ/LnNkaylyZXR1cm47Y29uc3R7bmFtZTplLHZlcnNpb246bn09dC5zZGs7cmV0dXJue25hbWU6ZSx2ZXJzaW9uOm59fWZ1bmN0aW9uIHl0KHQpe2NvbnN0IGU9Y3QoZCgpKTtyZXR1cm4gZS5zdXBwcmVzc1RyYWNpbmc/ZS5zdXBwcmVzc1RyYWNpbmcodCk6ZnVuY3Rpb24oLi4udCl7Y29uc3QgZT1jdChkKCkpO2lmKDI9PT10Lmxlbmd0aCl7Y29uc3RbbixyXT10O3JldHVybiBuP2Uud2l0aFNldFNjb3BlKG4scik6ZS53aXRoU2NvcGUocil9cmV0dXJuIGUud2l0aFNjb3BlKHRbMF0pfShlPT4oZS5zZXRTREtQcm9jZXNzaW5nTWV0YWRhdGEoe1tWXTohMH0pLHQoKSkpfWZ1bmN0aW9uIGJ0KHQsZSxuLHIpe2NvbnN0IG89bXQobikscz10LnR5cGUmJiJyZXBsYXlfZXZlbnQiIT09dC50eXBlP3QudHlwZToiZXZlbnQiOyFmdW5jdGlvbih0LGUpe2lmKCFlKXJldHVybiB0O2NvbnN0IG49dC5zZGt8fHt9O3Quc2RrPXsuLi5uLG5hbWU6bi5uYW1lfHxlLm5hbWUsdmVyc2lvbjpuLnZlcnNpb258fGUudmVyc2lvbixpbnRlZ3JhdGlvbnM6Wy4uLnQuc2RrPy5pbnRlZ3JhdGlvbnN8fFtdLC4uLmUuaW50ZWdyYXRpb25zfHxbXV0scGFja2FnZXM6Wy4uLnQuc2RrPy5wYWNrYWdlc3x8W10sLi4uZS5wYWNrYWdlc3x8W11dLHNldHRpbmdzOnQuc2RrPy5zZXR0aW5nc3x8ZS5zZXR0aW5ncz97Li4udC5zZGs/LnNldHRpbmdzLC4uLmUuc2V0dGluZ3N9OnZvaWQgMH19KHQsbj8uc2RrKTtjb25zdCBpPWZ1bmN0aW9uKHQsZSxuLHIpe2NvbnN0IG89dC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE/LmR5bmFtaWNTYW1wbGluZ0NvbnRleHQ7cmV0dXJue2V2ZW50X2lkOnQuZXZlbnRfaWQsc2VudF9hdDpuZXcgRGF0ZShJKCkpLnRvSVNPU3RyaW5nKCksLi4uZSYme3NkazplfSwuLi4hIW4mJnImJntkc246dXQocil9LC4uLm8mJnt0cmFjZTpvfX19KHQsbyxyLGUpO2RlbGV0ZSB0LnNka1Byb2Nlc3NpbmdNZXRhZGF0YTtyZXR1cm4gZnQoaSxbW3t0eXBlOnN9LHRdXSl9Y2xhc3MgdnR7Y29uc3RydWN0b3IodCl7dGhpcy5MPTAsdGhpcy5NPVtdLHRoaXMuSih0KX10aGVuKHQsZSl7cmV0dXJuIG5ldyB2dCgobixyKT0+e3RoaXMuTS5wdXNoKFshMSxlPT57aWYodCl0cnl7bih0KGUpKX1jYXRjaCh0KXtyKHQpfWVsc2UgbihlKX0sdD0+e2lmKGUpdHJ5e24oZSh0KSl9Y2F0Y2godCl7cih0KX1lbHNlIHIodCl9XSksdGhpcy5XKCl9KX1jYXRjaCh0KXtyZXR1cm4gdGhpcy50aGVuKHQ9PnQsdCl9ZmluYWxseSh0KXtyZXR1cm4gbmV3IHZ0KChlLG4pPT57bGV0IHIsbztyZXR1cm4gdGhpcy50aGVuKGU9PntvPSExLHI9ZSx0JiZ0KCl9LGU9PntvPSEwLHI9ZSx0JiZ0KCl9KS50aGVuKCgpPT57bz9uKHIpOmUocil9KX0pfVcoKXtpZigwPT09dGhpcy5MKXJldHVybjtjb25zdCB0PXRoaXMuTS5zbGljZSgpO3RoaXMuTT1bXSx0LmZvckVhY2godD0+e3RbMF18fCgxPT09dGhpcy5MJiZ0WzFdKHRoaXMuRiksMj09PXRoaXMuTCYmdFsyXSh0aGlzLkYpLHRbMF09ITApfSl9Sih0KXtjb25zdCBlPSh0LGUpPT57MD09PXRoaXMuTCYmKGooZSk/ZS50aGVuKG4scik6KHRoaXMuTD10LHRoaXMuRj1lLHRoaXMuVygpKSl9LG49dD0+e2UoMSx0KX0scj10PT57ZSgyLHQpfTt0cnl7dChuLHIpfWNhdGNoKHQpe3IodCl9fX1jb25zdCB3dD1TeW1ib2wuZm9yKCJTZW50cnlCdWZmZXJGdWxsRXJyb3IiKTtmdW5jdGlvbiBTdCh0PTEwMCl7Y29uc3QgZT1uZXcgU2V0O2Z1bmN0aW9uIG4odCl7ZS5kZWxldGUodCl9cmV0dXJue2dldCAkKCl7cmV0dXJuIEFycmF5LmZyb20oZSl9LGFkZDpmdW5jdGlvbihyKXtpZighKGUuc2l6ZTx0KSlyZXR1cm4gbz13dCxuZXcgdnQoKHQsZSk9PntlKG8pfSk7dmFyIG87Y29uc3Qgcz1yKCk7cmV0dXJuIGUuYWRkKHMpLHMudGhlbigoKT0+bihzKSwoKT0+bihzKSksc30sZHJhaW46ZnVuY3Rpb24odCl7aWYoIWUuc2l6ZSlyZXR1cm4gbj0hMCxuZXcgdnQodD0+e3Qobil9KTt2YXIgbjtjb25zdCByPVByb21pc2UuYWxsU2V0dGxlZChBcnJheS5mcm9tKGUpKS50aGVuKCgpPT4hMCk7aWYoIXQpcmV0dXJuIHI7Y29uc3Qgbz1bcixuZXcgUHJvbWlzZShlPT57cmV0dXJuIm9iamVjdCI9PXR5cGVvZihuPXNldFRpbWVvdXQoKCk9PmUoITEpLHQpKSYmImZ1bmN0aW9uIj09dHlwZW9mIG4udW5yZWYmJm4udW5yZWYoKSxuO3ZhciBufSldO3JldHVybiBQcm9taXNlLnJhY2Uobyl9fX1mdW5jdGlvbiBfdCh0LHtzdGF0dXNDb2RlOmUsaGVhZGVyczpufSxyPUkoKSl7Y29uc3Qgbz17Li4udH0scz1uPy5bIngtc2VudHJ5LXJhdGUtbGltaXRzIl0saT1uPy5bInJldHJ5LWFmdGVyIl07aWYocylmb3IoY29uc3QgdCBvZiBzLnRyaW0oKS5zcGxpdCgiLCIpKXtjb25zdFtlLG4sLCxzXT10LnNwbGl0KCI6Iiw1KSxpPXBhcnNlSW50KGUsMTApLGM9MWUzKihpc05hTihpKT82MDppKTtpZihuKWZvcihjb25zdCB0IG9mIG4uc3BsaXQoIjsiKSkibWV0cmljX2J1Y2tldCI9PT10JiZzJiYhcy5zcGxpdCgiOyIpLmluY2x1ZGVzKCJjdXN0b20iKXx8KG9bdF09citjKTtlbHNlIG8uYWxsPXIrY31lbHNlIGk/by5hbGw9citmdW5jdGlvbih0LGU9SSgpKXtjb25zdCBuPXBhcnNlSW50KGAke3R9YCwxMCk7aWYoIWlzTmFOKG4pKXJldHVybiAxZTMqbjtjb25zdCByPURhdGUucGFyc2UoYCR7dH1gKTtyZXR1cm4gaXNOYU4ocik/NmU0OnItZX0oaSxyKTo0Mjk9PT1lJiYoby5hbGw9cis2ZTQpO3JldHVybiBvfWZ1bmN0aW9uICR0KHQsZSxuPVN0KHQuYnVmZmVyU2l6ZXx8NjQpKXtsZXQgcj17fTtyZXR1cm57c2VuZDpmdW5jdGlvbih0KXtjb25zdCBvPVtdO2lmKGh0KHQsKHQsZSk9Pntjb25zdCBuPWd0KGUpOyhmdW5jdGlvbih0LGUsbj1JKCkpe3JldHVybiBmdW5jdGlvbih0LGUpe3JldHVybiB0W2VdfHx0LmFsbHx8MH0odCxlKT5ufSkocixuKXx8by5wdXNoKHQpfSksMD09PW8ubGVuZ3RoKXJldHVybiBQcm9taXNlLnJlc29sdmUoe30pO2NvbnN0IHM9ZnQodFswXSxvKSxpPXQ9PnshZnVuY3Rpb24odCxlKXtyZXR1cm4gaHQodCwodCxuKT0+ZS5pbmNsdWRlcyhuKSl9KHMsWyJjbGllbnRfcmVwb3J0Il0pP2h0KHMsKHQsZSk9Pnt9KTpoJiZfLndhcm4oYERyb3BwaW5nIGNsaWVudCByZXBvcnQuIFdpbGwgbm90IHNlbmQgb3V0Y29tZXMgKHJlYXNvbjogJHt0fSkuYCl9O3JldHVybiBuLmFkZCgoKT0+ZSh7Ym9keTpsdChzKX0pLnRoZW4odD0+NDEzPT09dC5zdGF0dXNDb2RlPyhoJiZfLmVycm9yKCJTZW50cnkgcmVzcG9uZGVkIHdpdGggc3RhdHVzIGNvZGUgNDEzLiBFbnZlbG9wZSB3YXMgZGlzY2FyZGVkIGR1ZSB0byBleGNlZWRpbmcgc2l6ZSBsaW1pdHMuIiksaSgic2VuZF9lcnJvciIpLHQpOihoJiZ2b2lkIDAhPT10LnN0YXR1c0NvZGUmJih0LnN0YXR1c0NvZGU8MjAwfHx0LnN0YXR1c0NvZGU+PTMwMCkmJl8ud2FybihgU2VudHJ5IHJlc3BvbmRlZCB3aXRoIHN0YXR1cyBjb2RlICR7dC5zdGF0dXNDb2RlfSB0byBzZW50IGV2ZW50LmApLHI9X3Qocix0KSx0KSx0PT57dGhyb3cgaSgibmV0d29ya19lcnJvciIpLGgmJl8uZXJyb3IoIkVuY291bnRlcmVkIGVycm9yIHJ1bm5pbmcgdHJhbnNwb3J0IHJlcXVlc3Q6Iix0KSx0fSkpLnRoZW4odD0+dCx0PT57aWYodD09PXd0KXJldHVybiBoJiZfLmVycm9yKCJTa2lwcGVkIHNlbmRpbmcgZXZlbnQgYmVjYXVzZSBidWZmZXIgaXMgZnVsbC4iKSxpKCJxdWV1ZV9vdmVyZmxvdyIpLFByb21pc2UucmVzb2x2ZSh7fSk7dGhyb3cgdH0pfSxmbHVzaDp0PT5uLmRyYWluKHQpfX1jb25zdCBFdD0vXihcUys6XFx8XC8/KShbXHNcU10qPykoKD86XC57MSwyfXxbXi9cXF0rP3wpKFwuW14uL1xcXSp8KSkoPzpbL1xcXSopJC87ZnVuY3Rpb24geHQodCl7Y29uc3QgZT1mdW5jdGlvbih0KXtjb25zdCBlPXQubGVuZ3RoPjEwMjQ/YDx0cnVuY2F0ZWQ+JHt0LnNsaWNlKC0xMDI0KX1gOnQsbj1FdC5leGVjKGUpO3JldHVybiBuP24uc2xpY2UoMSk6W119KHQpLG49ZVswXXx8IiI7bGV0IHI9ZVsxXTtyZXR1cm4gbnx8cj8ociYmKHI9ci5zbGljZSgwLHIubGVuZ3RoLTEpKSxuK3IpOiIuIn1mdW5jdGlvbiBOdCh0LGU9ITEpe3JldHVybiEoZXx8dCYmIXQuc3RhcnRzV2l0aCgiLyIpJiYhdC5tYXRjaCgvXltBLVpdOi8pJiYhdC5zdGFydHNXaXRoKCIuIikmJiF0Lm1hdGNoKC9eW2EtekEtWl0oW2EtekEtWjAtOS5cLStdKSo6XC9cLy8pKSYmdm9pZCAwIT09dCYmIXQuaW5jbHVkZXMoIm5vZGVfbW9kdWxlcy8iKX12YXIgQ3Q7Y29uc3QganQ9U3ltYm9sKCJBZ2VudEJhc2VJbnRlcm5hbFN0YXRlIik7Y2xhc3MgT3QgZXh0ZW5kcyhDdD1zLkFnZW50LEN0KXtjb25zdHJ1Y3Rvcih0KXtzdXBlcih0KSx0aGlzW2p0XT17fX1pc1NlY3VyZUVuZHBvaW50KHQpe2lmKHQpe2lmKCJib29sZWFuIj09dHlwZW9mIHQuc2VjdXJlRW5kcG9pbnQpcmV0dXJuIHQuc2VjdXJlRW5kcG9pbnQ7aWYoInN0cmluZyI9PXR5cGVvZiB0LnByb3RvY29sKXJldHVybiJodHRwczoiPT09dC5wcm90b2NvbH1jb25zdHtzdGFjazplfT1uZXcgRXJyb3I7cmV0dXJuInN0cmluZyI9PXR5cGVvZiBlJiZlLnNwbGl0KCJcbiIpLnNvbWUodD0+LTEhPT10LmluZGV4T2YoIihodHRwcy5qczoiKXx8LTEhPT10LmluZGV4T2YoIm5vZGU6aHR0cHM6IikpfWNyZWF0ZVNvY2tldCh0LGUsbil7Y29uc3Qgcj17Li4uZSxzZWN1cmVFbmRwb2ludDp0aGlzLmlzU2VjdXJlRW5kcG9pbnQoZSl9O1Byb21pc2UucmVzb2x2ZSgpLnRoZW4oKCk9PnRoaXMuY29ubmVjdCh0LHIpKS50aGVuKG89PntpZihvIGluc3RhbmNlb2Ygcy5BZ2VudClyZXR1cm4gby5hZGRSZXF1ZXN0KHQscik7dGhpc1tqdF0uY3VycmVudFNvY2tldD1vLHN1cGVyLmNyZWF0ZVNvY2tldCh0LGUsbil9LG4pfWNyZWF0ZUNvbm5lY3Rpb24oKXtjb25zdCB0PXRoaXNbanRdLmN1cnJlbnRTb2NrZXQ7aWYodGhpc1tqdF0uY3VycmVudFNvY2tldD12b2lkIDAsIXQpdGhyb3cgbmV3IEVycm9yKCJObyBzb2NrZXQgd2FzIHJldHVybmVkIGluIHRoZSBgY29ubmVjdCgpYCBmdW5jdGlvbiIpO3JldHVybiB0fWdldCBkZWZhdWx0UG9ydCgpe3JldHVybiB0aGlzW2p0XS5kZWZhdWx0UG9ydD8/KCJodHRwczoiPT09dGhpcy5wcm90b2NvbD80NDM6ODApfXNldCBkZWZhdWx0UG9ydCh0KXt0aGlzW2p0XSYmKHRoaXNbanRdLmRlZmF1bHRQb3J0PXQpfWdldCBwcm90b2NvbCgpe3JldHVybiB0aGlzW2p0XS5wcm90b2NvbD8/KHRoaXMuaXNTZWN1cmVFbmRwb2ludCgpPyJodHRwczoiOiJodHRwOiIpfXNldCBwcm90b2NvbCh0KXt0aGlzW2p0XSYmKHRoaXNbanRdLnByb3RvY29sPXQpfX1mdW5jdGlvbiBQdCguLi50KXtfLmxvZygiW2h0dHBzLXByb3h5LWFnZW50OnBhcnNlLXByb3h5LXJlc3BvbnNlXSIsLi4udCl9ZnVuY3Rpb24gQXQodCl7cmV0dXJuIG5ldyBQcm9taXNlKChlLG4pPT57bGV0IHI9MDtjb25zdCBvPVtdO2Z1bmN0aW9uIHMoKXtjb25zdCBjPXQucmVhZCgpO2M/ZnVuY3Rpb24oYyl7by5wdXNoKGMpLHIrPWMubGVuZ3RoO2NvbnN0IHU9QnVmZmVyLmNvbmNhdChvLHIpLGE9dS5pbmRleE9mKCJcclxuXHJcbiIpO2lmKC0xPT09YSlyZXR1cm4gUHQoImhhdmUgbm90IHJlY2VpdmVkIGVuZCBvZiBIVFRQIGhlYWRlcnMgeWV0Li4uIiksdm9pZCBzKCk7Y29uc3QgZj11LnN1YmFycmF5KDAsYSkudG9TdHJpbmcoImFzY2lpIikuc3BsaXQoIlxyXG4iKSxoPWYuc2hpZnQoKTtpZighaClyZXR1cm4gdC5kZXN0cm95KCksbihuZXcgRXJyb3IoIk5vIGhlYWRlciByZWNlaXZlZCBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2UiKSk7Y29uc3QgcD1oLnNwbGl0KCIgIiksbD0rKHBbMV18fDApLGQ9cC5zbGljZSgyKS5qb2luKCIgIiksZz17fTtmb3IoY29uc3QgZSBvZiBmKXtpZighZSljb250aW51ZTtjb25zdCByPWUuaW5kZXhPZigiOiIpO2lmKC0xPT09cilyZXR1cm4gdC5kZXN0cm95KCksbihuZXcgRXJyb3IoYEludmFsaWQgaGVhZGVyIGZyb20gcHJveHkgQ09OTkVDVCByZXNwb25zZTogIiR7ZX0iYCkpO2NvbnN0IG89ZS5zbGljZSgwLHIpLnRvTG93ZXJDYXNlKCkscz1lLnNsaWNlKHIrMSkudHJpbVN0YXJ0KCksaT1nW29dOyJzdHJpbmciPT10eXBlb2YgaT9nW29dPVtpLHNdOkFycmF5LmlzQXJyYXkoaSk/aS5wdXNoKHMpOmdbb109c31QdCgiZ290IHByb3h5IHNlcnZlciByZXNwb25zZTogJW8gJW8iLGgsZyksaSgpLGUoe2Nvbm5lY3Q6e3N0YXR1c0NvZGU6bCxzdGF0dXNUZXh0OmQsaGVhZGVyczpnfSxidWZmZXJlZDp1fSl9KGMpOnQub25jZSgicmVhZGFibGUiLHMpfWZ1bmN0aW9uIGkoKXt0LnJlbW92ZUxpc3RlbmVyKCJlbmQiLGMpLHQucmVtb3ZlTGlzdGVuZXIoImVycm9yIix1KSx0LnJlbW92ZUxpc3RlbmVyKCJyZWFkYWJsZSIscyl9ZnVuY3Rpb24gYygpe2koKSxQdCgib25lbmQiKSxuKG5ldyBFcnJvcigiUHJveHkgY29ubmVjdGlvbiBlbmRlZCBiZWZvcmUgcmVjZWl2aW5nIENPTk5FQ1QgcmVzcG9uc2UiKSl9ZnVuY3Rpb24gdSh0KXtpKCksUHQoIm9uZXJyb3IgJW8iLHQpLG4odCl9dC5vbigiZXJyb3IiLHUpLHQub24oImVuZCIsYykscygpfSl9ZnVuY3Rpb24gVHQoLi4udCl7Xy5sb2coIltodHRwcy1wcm94eS1hZ2VudF0iLC4uLnQpfWNsYXNzIGt0IGV4dGVuZHMgT3R7Y29uc3RydWN0b3IodCxlKXtzdXBlcihlKSx0aGlzLm9wdGlvbnM9e30sdGhpcy5wcm94eT0ic3RyaW5nIj09dHlwZW9mIHQ/bmV3IFVSTCh0KTp0LHRoaXMucHJveHlIZWFkZXJzPWU/LmhlYWRlcnM/P3t9LFR0KCJDcmVhdGluZyBuZXcgSHR0cHNQcm94eUFnZW50IGluc3RhbmNlOiAlbyIsdGhpcy5wcm94eS5ocmVmKTtjb25zdCBuPSh0aGlzLnByb3h5Lmhvc3RuYW1lfHx0aGlzLnByb3h5Lmhvc3QpLnJlcGxhY2UoL15cW3xcXSQvZywiIikscj10aGlzLnByb3h5LnBvcnQ/cGFyc2VJbnQodGhpcy5wcm94eS5wb3J0LDEwKToiaHR0cHM6Ij09PXRoaXMucHJveHkucHJvdG9jb2w/NDQzOjgwO3RoaXMuY29ubmVjdE9wdHM9e0FMUE5Qcm90b2NvbHM6WyJodHRwLzEuMSJdLC4uLmU/SXQoZSwiaGVhZGVycyIpOm51bGwsaG9zdDpuLHBvcnQ6cn19YXN5bmMgY29ubmVjdCh0LGUpe2NvbnN0e3Byb3h5Om59PXRoaXM7aWYoIWUuaG9zdCl0aHJvdyBuZXcgVHlwZUVycm9yKCdObyAiaG9zdCIgcHJvdmlkZWQnKTtsZXQgcjtpZigiaHR0cHM6Ij09PW4ucHJvdG9jb2wpe1R0KCJDcmVhdGluZyBgdGxzLlNvY2tldGA6ICVvIix0aGlzLmNvbm5lY3RPcHRzKTtjb25zdCB0PXRoaXMuY29ubmVjdE9wdHMuc2VydmVybmFtZXx8dGhpcy5jb25uZWN0T3B0cy5ob3N0O3I9Zi5jb25uZWN0KHsuLi50aGlzLmNvbm5lY3RPcHRzLHNlcnZlcm5hbWU6dCYmYS5pc0lQKHQpP3ZvaWQgMDp0fSl9ZWxzZSBUdCgiQ3JlYXRpbmcgYG5ldC5Tb2NrZXRgOiAlbyIsdGhpcy5jb25uZWN0T3B0cykscj1hLmNvbm5lY3QodGhpcy5jb25uZWN0T3B0cyk7Y29uc3Qgbz0iZnVuY3Rpb24iPT10eXBlb2YgdGhpcy5wcm94eUhlYWRlcnM/dGhpcy5wcm94eUhlYWRlcnMoKTp7Li4udGhpcy5wcm94eUhlYWRlcnN9LHM9YS5pc0lQdjYoZS5ob3N0KT9gWyR7ZS5ob3N0fV1gOmUuaG9zdDtsZXQgaT1gQ09OTkVDVCAke3N9OiR7ZS5wb3J0fSBIVFRQLzEuMVxyXG5gO2lmKG4udXNlcm5hbWV8fG4ucGFzc3dvcmQpe2NvbnN0IHQ9YCR7ZGVjb2RlVVJJQ29tcG9uZW50KG4udXNlcm5hbWUpfToke2RlY29kZVVSSUNvbXBvbmVudChuLnBhc3N3b3JkKX1gO29bIlByb3h5LUF1dGhvcml6YXRpb24iXT1gQmFzaWMgJHtCdWZmZXIuZnJvbSh0KS50b1N0cmluZygiYmFzZTY0Iil9YH1vLkhvc3Q9YCR7c306JHtlLnBvcnR9YCxvWyJQcm94eS1Db25uZWN0aW9uIl18fChvWyJQcm94eS1Db25uZWN0aW9uIl09dGhpcy5rZWVwQWxpdmU/IktlZXAtQWxpdmUiOiJjbG9zZSIpO2Zvcihjb25zdCB0IG9mIE9iamVjdC5rZXlzKG8pKWkrPWAke3R9OiAke29bdF19XHJcbmA7Y29uc3QgYz1BdChyKTtyLndyaXRlKGAke2l9XHJcbmApO2NvbnN0e2Nvbm5lY3Q6dSxidWZmZXJlZDpofT1hd2FpdCBjO2lmKHQuZW1pdCgicHJveHlDb25uZWN0Iix1KSx0aGlzLmVtaXQoInByb3h5Q29ubmVjdCIsdSx0KSwyMDA9PT11LnN0YXR1c0NvZGUpe2lmKHQub25jZSgic29ja2V0IixSdCksZS5zZWN1cmVFbmRwb2ludCl7VHQoIlVwZ3JhZGluZyBzb2NrZXQgY29ubmVjdGlvbiB0byBUTFMiKTtjb25zdCB0PWUuc2VydmVybmFtZXx8ZS5ob3N0O3JldHVybiBmLmNvbm5lY3Qoey4uLkl0KGUsImhvc3QiLCJwYXRoIiwicG9ydCIpLHNvY2tldDpyLHNlcnZlcm5hbWU6YS5pc0lQKHQpP3ZvaWQgMDp0fSl9cmV0dXJuIHJ9ci5kZXN0cm95KCk7Y29uc3QgcD1uZXcgYS5Tb2NrZXQoe3dyaXRhYmxlOiExfSk7cmV0dXJuIHAucmVhZGFibGU9ITAsdC5vbmNlKCJzb2NrZXQiLHQ9PntUdCgiUmVwbGF5aW5nIHByb3h5IGJ1ZmZlciBmb3IgZmFpbGVkIHJlcXVlc3QiKSx0LnB1c2goaCksdC5wdXNoKG51bGwpfSkscH19ZnVuY3Rpb24gUnQodCl7dC5yZXN1bWUoKX1mdW5jdGlvbiBJdCh0LC4uLmUpe2NvbnN0IG49e307bGV0IHI7Zm9yKHIgaW4gdCllLmluY2x1ZGVzKHIpfHwobltyXT10W3JdKTtyZXR1cm4gbn1rdC5wcm90b2NvbHM9WyJodHRwIiwiaHR0cHMiXTtmdW5jdGlvbiBEdCh0KXtyZXR1cm4gdC5yZXBsYWNlKC9eW0EtWl06LywiIikucmVwbGFjZSgvXFwvZywiLyIpfWNvbnN0IFV0PWU7bGV0IEJ0LEx0PTAsTXQ9e307ZnVuY3Rpb24genQodCl7VXQuZGVidWcmJmNvbnNvbGUubG9nKGBbQU5SIFdvcmtlcl0gJHt0fWApfXZhciBKdCxXdCxGdDtjb25zdCBHdD1mdW5jdGlvbih0KXtsZXQgZTt0cnl7ZT1uZXcgVVJMKHQudXJsKX1jYXRjaHtyZXR1cm4gYigoKT0+e2NvbnNvbGUud2FybigiW0BzZW50cnkvbm9kZV06IEludmFsaWQgZHNuIG9yIHR1bm5lbCBvcHRpb24sIHdpbGwgbm90IHNlbmQgYW55IGV2ZW50cy4gVGhlIHR1bm5lbCBvcHRpb24gbXVzdCBiZSBhIGZ1bGwgVVJMIHdoZW4gdXNlZC4iKX0pLCR0KHQsKCk9PlByb21pc2UucmVzb2x2ZSh7fSkpfWNvbnN0IG49Imh0dHBzOiI9PT1lLnByb3RvY29sLHI9ZnVuY3Rpb24odCxlKXtjb25zdHtub19wcm94eTpufT1wcm9jZXNzLmVudixyPW4/LnNwbGl0KCIsIikuc29tZShlPT50Lmhvc3QuZW5kc1dpdGgoZSl8fHQuaG9zdG5hbWUuZW5kc1dpdGgoZSkpO3JldHVybiByP3ZvaWQgMDplfShlLHQucHJveHl8fChuP3Byb2Nlc3MuZW52Lmh0dHBzX3Byb3h5OnZvaWQgMCl8fHByb2Nlc3MuZW52Lmh0dHBfcHJveHkpLG89bj9pOnMsYT10LmtlZXBBbGl2ZT8/ITAsZj1yP25ldyBrdChyKTpuZXcgby5BZ2VudCh7a2VlcEFsaXZlOmEsbWF4U29ja2V0czozMCx0aW1lb3V0OjJlM30pLGg9ZnVuY3Rpb24odCxlLG4pe2NvbnN0e2hvc3RuYW1lOnIscGF0aG5hbWU6byxwb3J0OnMscHJvdG9jb2w6aSxzZWFyY2g6YX09bmV3IFVSTCh0LnVybCk7cmV0dXJuIGZ1bmN0aW9uKGYpe2NvbnN0IGg9cD0+bmV3IFByb21pc2UoKGwsZCk9Pnt5dCgoKT0+e2xldCBnPWZ1bmN0aW9uKHQpe3JldHVybiBuZXcgYyh7cmVhZCgpe3RoaXMucHVzaCh0KSx0aGlzLnB1c2gobnVsbCl9fSl9KGYuYm9keSk7Y29uc3QgbT17Li4udC5oZWFkZXJzfTtmLmJvZHkubGVuZ3RoPjMyNzY4JiYobVsiY29udGVudC1lbmNvZGluZyJdPSJnemlwIixnPWcucGlwZSh1KCkpKTtjb25zdCB5PXIuc3RhcnRzV2l0aCgiWyIpLGI9ZS5yZXF1ZXN0KHttZXRob2Q6IlBPU1QiLGFnZW50Om4saGVhZGVyczptLGhvc3RuYW1lOnk/ci5zbGljZSgxLC0xKTpyLHBhdGg6YCR7b30ke2F9YCxwb3J0OnMscHJvdG9jb2w6aSxjYTp0LmNhQ2VydHN9LHQ9Pnt0Lm9uKCJkYXRhIiwoKT0+e30pLHQub24oImVuZCIsKCk9Pnt9KSx0LnNldEVuY29kaW5nKCJ1dGY4Iik7Y29uc3QgZT10LmhlYWRlcnNbInJldHJ5LWFmdGVyIl0/P251bGwsbj10LmhlYWRlcnNbIngtc2VudHJ5LXJhdGUtbGltaXRzIl0/P251bGw7bCh7c3RhdHVzQ29kZTp0LnN0YXR1c0NvZGUsaGVhZGVyczp7InJldHJ5LWFmdGVyIjplLCJ4LXNlbnRyeS1yYXRlLWxpbWl0cyI6QXJyYXkuaXNBcnJheShuKT9uWzBdfHxudWxsOm59fSl9KTtiLm9uKCJlcnJvciIsdD0+e3AmJmIucmV1c2VkU29ja2V0JiYiRUNPTk5SRVNFVCI9PT10LmNvZGU/bChoKCExKSk6ZCh0KX0pLGcucGlwZShiKX0pfSk7cmV0dXJuIGgoITApfX0odCx0Lmh0dHBNb2R1bGU/P28sZik7cmV0dXJuICR0KHQsaCl9KHt1cmw6KEp0PVV0LmRzbixXdD1VdC50dW5uZWwsRnQ9VXQuc2RrTWV0YWRhdGEuc2RrLFd0fHxgJHtmdW5jdGlvbih0KXtyZXR1cm5gJHtmdW5jdGlvbih0KXtjb25zdCBlPXQucHJvdG9jb2w/YCR7dC5wcm90b2NvbH06YDoiIixuPXQucG9ydD9gOiR7dC5wb3J0fWA6IiI7cmV0dXJuYCR7ZX0vLyR7dC5ob3N0fSR7bn0ke3QucGF0aD9gLyR7dC5wYXRofWA6IiJ9L2FwaS9gfSh0KX0ke3QucHJvamVjdElkfS9lbnZlbG9wZS9gfShKdCl9PyR7ZnVuY3Rpb24odCxlKXtjb25zdCBuPXtzZW50cnlfdmVyc2lvbjoiNyJ9O3JldHVybiB0LnB1YmxpY0tleSYmKG4uc2VudHJ5X2tleT10LnB1YmxpY0tleSksZSYmKG4uc2VudHJ5X2NsaWVudD1gJHtlLm5hbWV9LyR7ZS52ZXJzaW9ufWApLG5ldyBVUkxTZWFyY2hQYXJhbXMobikudG9TdHJpbmcoKX0oSnQsRnQpfWApfSk7YXN5bmMgZnVuY3Rpb24gWXQoKXtpZihCdCl7enQoIlNlbmRpbmcgYWJub3JtYWwgc2Vzc2lvbiIpLFooQnQse3N0YXR1czoiYWJub3JtYWwiLGFibm9ybWFsX21lY2hhbmlzbToiYW5yX2ZvcmVncm91bmQiLHJlbGVhc2U6VXQucmVsZWFzZSxlbnZpcm9ubWVudDpVdC5lbnZpcm9ubWVudH0pO2NvbnN0IHQ9ZnVuY3Rpb24odCxlLG4scil7Y29uc3Qgbz1tdChuKTtyZXR1cm4gZnQoe3NlbnRfYXQ6bmV3IERhdGUoSSgpKS50b0lTT1N0cmluZygpLC4uLm8mJntzZGs6b30sLi4uISFyJiZlJiZ7ZHNuOnV0KGUpfX0sWyJhZ2dyZWdhdGVzImluIHQ/W3t0eXBlOiJzZXNzaW9ucyJ9LHRdOlt7dHlwZToic2Vzc2lvbiJ9LHQudG9KU09OKCldXSl9KEJ0LFV0LmRzbixVdC5zZGtNZXRhZGF0YSxVdC50dW5uZWwpO3p0KEpTT04uc3RyaW5naWZ5KHQpKSxhd2FpdCBHdC5zZW5kKHQpO3RyeXtuPy5wb3N0TWVzc2FnZSgic2Vzc2lvbi1lbmRlZCIpfWNhdGNoe319fWZ1bmN0aW9uIEh0KHQpe2lmKCF0KXJldHVybjtjb25zdCBlPWZ1bmN0aW9uKHQpe2lmKCF0Lmxlbmd0aClyZXR1cm5bXTtjb25zdCBlPUFycmF5LmZyb20odCk7cmV0dXJuL3NlbnRyeVdyYXBwZWQvLnRlc3QoRShlKS5mdW5jdGlvbnx8IiIpJiZlLnBvcCgpLGUucmV2ZXJzZSgpLCQudGVzdChFKGUpLmZ1bmN0aW9ufHwiIikmJihlLnBvcCgpLCQudGVzdChFKGUpLmZ1bmN0aW9ufHwiIikmJmUucG9wKCkpLGUuc2xpY2UoMCw1MCkubWFwKHQ9Pih7Li4udCxmaWxlbmFtZTp0LmZpbGVuYW1lfHxFKGUpLmZpbGVuYW1lLGZ1bmN0aW9uOnQuZnVuY3Rpb258fCI/In0pKX0odCk7aWYoVXQuYXBwUm9vdFBhdGgpZm9yKGNvbnN0IHQgb2YgZSl0LmZpbGVuYW1lJiYodC5maWxlbmFtZT1NKHQuZmlsZW5hbWUsVXQuYXBwUm9vdFBhdGgpKTtyZXR1cm4gZX1hc3luYyBmdW5jdGlvbiBadCh0LGUpe2lmKEx0Pj1VdC5tYXhBbnJFdmVudHMpcmV0dXJuO0x0Kz0xLGF3YWl0IFl0KCksenQoIlNlbmRpbmcgZXZlbnQiKTtjb25zdCBuPXtldmVudF9pZDpXKCksY29udGV4dHM6VXQuY29udGV4dHMscmVsZWFzZTpVdC5yZWxlYXNlLGVudmlyb25tZW50OlV0LmVudmlyb25tZW50LGRpc3Q6VXQuZGlzdCxwbGF0Zm9ybToibm9kZSIsbGV2ZWw6ImVycm9yIixleGNlcHRpb246e3ZhbHVlczpbe3R5cGU6IkFwcGxpY2F0aW9uTm90UmVzcG9uZGluZyIsdmFsdWU6YEFwcGxpY2F0aW9uIE5vdCBSZXNwb25kaW5nIGZvciBhdCBsZWFzdCAke1V0LmFuclRocmVzaG9sZH0gbXNgLHN0YWNrdHJhY2U6e2ZyYW1lczpIdCh0KX0sbWVjaGFuaXNtOnt0eXBlOiJBTlIifX1dfSx0YWdzOlV0LnN0YXRpY1RhZ3N9O2UmJmZ1bmN0aW9uKHQsZSl7aWYoYXQodCxlKSwhdC5jb250ZXh0cz8udHJhY2Upe2NvbnN0e3RyYWNlSWQ6bixwYXJlbnRTcGFuSWQ6cixwcm9wYWdhdGlvblNwYW5JZDpvfT1lLnByb3BhZ2F0aW9uQ29udGV4dDt0LmNvbnRleHRzPXt0cmFjZTp7dHJhY2VfaWQ6bixzcGFuX2lkOm98fFcoKS5zdWJzdHJpbmcoMTYpLHBhcmVudF9zcGFuX2lkOnJ9LC4uLnQuY29udGV4dHN9fX0obixlKSxmdW5jdGlvbih0KXtpZigwPT09T2JqZWN0LmtleXMoTXQpLmxlbmd0aClyZXR1cm47Y29uc3QgZT1VdC5hcHBSb290UGF0aD97fTpNdDtpZihVdC5hcHBSb290UGF0aClmb3IoY29uc3RbdCxuXW9mIE9iamVjdC5lbnRyaWVzKE10KSllW00odCxVdC5hcHBSb290UGF0aCldPW47Y29uc3Qgbj1uZXcgTWFwO2Zvcihjb25zdCByIG9mIHQuZXhjZXB0aW9uPy52YWx1ZXN8fFtdKWZvcihjb25zdCB0IG9mIHIuc3RhY2t0cmFjZT8uZnJhbWVzfHxbXSl7Y29uc3Qgcj10LmFic19wYXRofHx0LmZpbGVuYW1lO3ImJmVbcl0mJm4uc2V0KHIsZVtyXSl9aWYobi5zaXplPjApe2NvbnN0IGU9W107Zm9yKGNvbnN0W3Qscl1vZiBuLmVudHJpZXMoKSllLnB1c2goe3R5cGU6InNvdXJjZW1hcCIsY29kZV9maWxlOnQsZGVidWdfaWQ6cn0pO3QuZGVidWdfbWV0YT17aW1hZ2VzOmV9fX0obik7Y29uc3Qgcj1idChuLFV0LmRzbixVdC5zZGtNZXRhZGF0YSxVdC50dW5uZWwpO3p0KEpTT04uc3RyaW5naWZ5KHIpKSxhd2FpdCBHdC5zZW5kKHIpLGF3YWl0IEd0LmZsdXNoKDJlMyksTHQ+PVV0Lm1heEFuckV2ZW50cyYmc2V0VGltZW91dCgoKT0+e3Byb2Nlc3MuZXhpdCgwKX0sNWUzKX1sZXQgcXQ7aWYoenQoIlN0YXJ0ZWQiKSxVdC5jYXB0dXJlU3RhY2tUcmFjZSl7enQoIkNvbm5lY3RpbmcgdG8gZGVidWdnZXIiKTtjb25zdCBlPW5ldyB0O2UuY29ubmVjdFRvTWFpblRocmVhZCgpLHp0KCJDb25uZWN0ZWQgdG8gZGVidWdnZXIiKTtjb25zdCBuPW5ldyBNYXA7ZS5vbigiRGVidWdnZXIuc2NyaXB0UGFyc2VkIix0PT57bi5zZXQodC5wYXJhbXMuc2NyaXB0SWQsdC5wYXJhbXMudXJsKX0pLGUub24oIkRlYnVnZ2VyLnBhdXNlZCIsdD0+e2lmKCJvdGhlciI9PT10LnBhcmFtcy5yZWFzb24pdHJ5e3p0KCJEZWJ1Z2dlciBwYXVzZWQiKTtjb25zdCBzPVsuLi50LnBhcmFtcy5jYWxsRnJhbWVzXSxpPVV0LmFwcFJvb3RQYXRoP2Z1bmN0aW9uKHQ9KHByb2Nlc3MuYXJndlsxXT94dChwcm9jZXNzLmFyZ3ZbMV0pOnByb2Nlc3MuY3dkKCkpLGU9IlxcIj09PW8pe2NvbnN0IG49ZT9EdCh0KTp0O3JldHVybiB0PT57aWYoIXQpcmV0dXJuO2NvbnN0IG89ZT9EdCh0KTp0O2xldHtkaXI6cyxiYXNlOmksZXh0OmN9PXIucGFyc2Uobyk7Ii5qcyIhPT1jJiYiLm1qcyIhPT1jJiYiLmNqcyIhPT1jfHwoaT1pLnNsaWNlKDAsLTEqYy5sZW5ndGgpKTtjb25zdCB1PWRlY29kZVVSSUNvbXBvbmVudChpKTtzfHwocz0iLiIpO2NvbnN0IGE9cy5sYXN0SW5kZXhPZigiL25vZGVfbW9kdWxlcyIpO2lmKGE+LTEpcmV0dXJuYCR7cy5zbGljZShhKzE0KS5yZXBsYWNlKC9cLy9nLCIuIil9OiR7dX1gO2lmKHMuc3RhcnRzV2l0aChuKSl7Y29uc3QgdD1zLnNsaWNlKG4ubGVuZ3RoKzEpLnJlcGxhY2UoL1wvL2csIi4iKTtyZXR1cm4gdD9gJHt0fToke3V9YDp1fXJldHVybiB1fX0oVXQuYXBwUm9vdFBhdGgpOigpPT57fSxjPXMubWFwKHQ9PmZ1bmN0aW9uKHQsZSxuKXtjb25zdCByPWU/ZS5yZXBsYWNlKC9eZmlsZTpcL1wvLywiIik6dm9pZCAwLG89dC5sb2NhdGlvbi5jb2x1bW5OdW1iZXI/dC5sb2NhdGlvbi5jb2x1bW5OdW1iZXIrMTp2b2lkIDAscz10LmxvY2F0aW9uLmxpbmVOdW1iZXI/dC5sb2NhdGlvbi5saW5lTnVtYmVyKzE6dm9pZCAwO3JldHVybntmaWxlbmFtZTpyLG1vZHVsZTpuKHIpLGZ1bmN0aW9uOnQuZnVuY3Rpb25OYW1lfHwiPyIsY29sbm86byxsaW5lbm86cyxpbl9hcHA6cj9OdChyKTp2b2lkIDB9fSh0LG4uZ2V0KHQubG9jYXRpb24uc2NyaXB0SWQpLGkpKSx1PXNldFRpbWVvdXQoKCk9PntadChjKS50aGVuKG51bGwsKCk9Pnt6dCgiU2VuZGluZyBBTlIgZXZlbnQgZmFpbGVkLiIpfSl9LDVlMyk7ZS5wb3N0KCJSdW50aW1lLmV2YWx1YXRlIix7ZXhwcmVzc2lvbjoiZ2xvYmFsLl9fU0VOVFJZX0dFVF9TQ09QRVNfXygpOyIsc2lsZW50OiEwLHJldHVybkJ5VmFsdWU6ITB9LCh0LG4pPT57dCYmenQoYEVycm9yIGV4ZWN1dGluZyBzY3JpcHQ6ICcke3QubWVzc2FnZX0nYCksY2xlYXJUaW1lb3V0KHUpO2NvbnN0IHI9bj8ucmVzdWx0P24ucmVzdWx0LnZhbHVlOnZvaWQgMDtlLnBvc3QoIkRlYnVnZ2VyLnJlc3VtZSIpLGUucG9zdCgiRGVidWdnZXIuZGlzYWJsZSIpLFp0KGMscikudGhlbihudWxsLCgpPT57enQoIlNlbmRpbmcgQU5SIGV2ZW50IGZhaWxlZC4iKX0pfSl9Y2F0Y2godCl7dGhyb3cgZS5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKSxlLnBvc3QoIkRlYnVnZ2VyLmRpc2FibGUiKSx0fX0pLHF0PSgpPT57dHJ5e2UucG9zdCgiRGVidWdnZXIuZW5hYmxlIiwoKT0+e2UucG9zdCgiRGVidWdnZXIucGF1c2UiKX0pfWNhdGNoe319fWNvbnN0e3BvbGw6S3R9PWZ1bmN0aW9uKHQsZSxuLHIpe2NvbnN0IG89dCgpO2xldCBzPSExLGk9ITA7cmV0dXJuIHNldEludGVydmFsKCgpPT57Y29uc3QgdD1vLmdldFRpbWVNcygpOyExPT09cyYmdD5lK24mJihzPSEwLGkmJnIoKSksdDxlK24mJihzPSExKX0sMjApLHtwb2xsOigpPT57by5yZXNldCgpfSxlbmFibGVkOnQ9PntpPXR9fX0oZnVuY3Rpb24oKXtsZXQgdD1wcm9jZXNzLmhydGltZSgpO3JldHVybntnZXRUaW1lTXM6KCk9Pntjb25zdFtlLG5dPXByb2Nlc3MuaHJ0aW1lKHQpO3JldHVybiBNYXRoLmZsb29yKDFlMyplK24vMWU2KX0scmVzZXQ6KCk9Pnt0PXByb2Nlc3MuaHJ0aW1lKCl9fX0sVXQucG9sbEludGVydmFsLFV0LmFuclRocmVzaG9sZCxmdW5jdGlvbigpe3p0KCJXYXRjaGRvZyB0aW1lb3V0IikscXQ/KHp0KCJQYXVzaW5nIGRlYnVnZ2VyIHRvIGNhcHR1cmUgc3RhY2sgdHJhY2UiKSxxdCgpKTooenQoIkNhcHR1cmluZyBldmVudCB3aXRob3V0IGEgc3RhY2sgdHJhY2UiKSxadCgpLnRoZW4obnVsbCwoKT0+e3p0KCJTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQgb24gd2F0Y2hkb2cgdGltZW91dC4iKX0pKX0pO24/Lm9uKCJtZXNzYWdlIix0PT57dC5zZXNzaW9uJiYoQnQ9SCh0LnNlc3Npb24pKSx0LmRlYnVnSW1hZ2VzJiYoTXQ9dC5kZWJ1Z0ltYWdlcyksS3QoKX0pOw==";
9
+ const base64WorkerScript = "LyohIEBzZW50cnkvbm9kZSAxMS4wLjAtYmV0YS4wICg1NGJiYWU5KSB8IGh0dHBzOi8vZ2l0aHViLmNvbS9nZXRzZW50cnkvc2VudHJ5LWphdmFzY3JpcHQgKi8KaW1wb3J0e1Nlc3Npb24gYXMgdH1mcm9tIm5vZGU6aW5zcGVjdG9yIjtpbXBvcnR7d29ya2VyRGF0YSBhcyBlLHBhcmVudFBvcnQgYXMgbn1mcm9tIm5vZGU6d29ya2VyX3RocmVhZHMiO2ltcG9ydHtwb3NpeCBhcyByLHNlcCBhcyBvfWZyb20ibm9kZTpwYXRoIjtpbXBvcnQqYXMgcyBmcm9tIm5vZGU6aHR0cCI7aW1wb3J0KmFzIGkgZnJvbSJub2RlOmh0dHBzIjtpbXBvcnR7UmVhZGFibGUgYXMgY31mcm9tIm5vZGU6c3RyZWFtIjtpbXBvcnR7Y3JlYXRlR3ppcCBhcyB1fWZyb20ibm9kZTp6bGliIjtpbXBvcnQqYXMgYSBmcm9tIm5vZGU6bmV0IjtpbXBvcnQqYXMgZiBmcm9tIm5vZGU6dGxzIjtjb25zdCBoPSJ1bmRlZmluZWQiPT10eXBlb2YgX19TRU5UUllfREVCVUdfX3x8X19TRU5UUllfREVCVUdfXyxwPWdsb2JhbFRoaXMsbD0iMTEuMC4wLWJldGEuMCI7ZnVuY3Rpb24gZCgpe3JldHVybiBnKHApLHB9ZnVuY3Rpb24gZyh0KXtjb25zdCBlPXQuX19TRU5UUllfXz10Ll9fU0VOVFJZX198fHt9O3JldHVybiBlLnZlcnNpb249ZS52ZXJzaW9ufHxsLGVbbF09ZVtsXXx8e319ZnVuY3Rpb24gbSh0LGUsbj1wKXtjb25zdCByPW4uX19TRU5UUllfXz1uLl9fU0VOVFJZX198fHt9LG89cltsXT1yW2xdfHx7fTtyZXR1cm4gb1t0XXx8KG9bdF09ZSgpKX1jb25zdCB5PXt9O2Z1bmN0aW9uIGIodCl7aWYoISgiY29uc29sZSJpbiBwKSlyZXR1cm4gdCgpO2NvbnN0IGU9cC5jb25zb2xlLG49e30scj1PYmplY3Qua2V5cyh5KTtyLmZvckVhY2godD0+e2NvbnN0IHI9eVt0XTtuW3RdPWVbdF0sZVt0XT1yfSk7dHJ5e3JldHVybiB0KCl9ZmluYWxseXtyLmZvckVhY2godD0+e2VbdF09blt0XX0pfX1mdW5jdGlvbiB2KCl7cmV0dXJuIFMoKS5lbmFibGVkfWZ1bmN0aW9uIHcodCwuLi5lKXtoJiZ2KCkmJmIoKCk9PntwLmNvbnNvbGVbdF0oYFNlbnRyeSBMb2dnZXIgWyR7dH1dOmAsLi4uZSl9KX1mdW5jdGlvbiBTKCl7cmV0dXJuIGg/bSgibG9nZ2VyU2V0dGluZ3MiLCgpPT4oe2VuYWJsZWQ6ITF9KSk6e2VuYWJsZWQ6ITF9fWNvbnN0IF89e2VuYWJsZTpmdW5jdGlvbigpe1MoKS5lbmFibGVkPSEwfSxkaXNhYmxlOmZ1bmN0aW9uKCl7UygpLmVuYWJsZWQ9ITF9LGlzRW5hYmxlZDp2LGxvZzpmdW5jdGlvbiguLi50KXt3KCJsb2ciLC4uLnQpfSx3YXJuOmZ1bmN0aW9uKC4uLnQpe3coIndhcm4iLC4uLnQpfSxlcnJvcjpmdW5jdGlvbiguLi50KXt3KCJlcnJvciIsLi4udCl9fSwkPS9jYXB0dXJlTWVzc2FnZXxjYXB0dXJlRXhjZXB0aW9uLztmdW5jdGlvbiBFKHQpe3JldHVybiB0W3QubGVuZ3RoLTFdfHx7fX1jb25zdCB4PSI8YW5vbnltb3VzPiI7Y29uc3QgTj1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nO2Z1bmN0aW9uIEModCl7cmV0dXJuIGZ1bmN0aW9uKHQsZSl7cmV0dXJuIE4uY2FsbCh0KT09PWBbb2JqZWN0ICR7ZX1dYH0odCwiT2JqZWN0Iil9ZnVuY3Rpb24gaih0KXtyZXR1cm4gQm9vbGVhbih0Py50aGVuJiYiZnVuY3Rpb24iPT10eXBlb2YgdC50aGVuKX1mdW5jdGlvbiBPKHQsZSl7dHJ5e3JldHVybiB0IGluc3RhbmNlb2YgZX1jYXRjaHtyZXR1cm4hMX19ZnVuY3Rpb24gUCh0KXtpZihmdW5jdGlvbih0KXtzd2l0Y2goTi5jYWxsKHQpKXtjYXNlIltvYmplY3QgRXJyb3JdIjpjYXNlIltvYmplY3QgRXhjZXB0aW9uXSI6Y2FzZSJbb2JqZWN0IERPTUV4Y2VwdGlvbl0iOmNhc2UiW29iamVjdCBXZWJBc3NlbWJseS5FeGNlcHRpb25dIjpyZXR1cm4hMDtkZWZhdWx0OnJldHVybiBPKHQsRXJyb3IpfX0odCkpcmV0dXJue21lc3NhZ2U6dC5tZXNzYWdlLG5hbWU6dC5uYW1lLHN0YWNrOnQuc3RhY2ssLi4uQSh0KX07aWYoZT10LCJ1bmRlZmluZWQiIT10eXBlb2YgRXZlbnQmJk8oZSxFdmVudCkpe2NvbnN0e3R5cGU6ZSx0YXJnZXQ6bixjdXJyZW50VGFyZ2V0OnIsZGV0YWlsOm99PXQ7cmV0dXJue3R5cGU6ZSx0YXJnZXQ6bixjdXJyZW50VGFyZ2V0OnIsLi4ubz97ZGV0YWlsOm99Ont9LC4uLkEodCl9fXZhciBlO3JldHVybiB0fWZ1bmN0aW9uIEEodCl7cmV0dXJuIm9iamVjdCI9PXR5cGVvZihlPXQpJiZudWxsIT09ZT9PYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXModCkpOnt9O3ZhciBlfWxldCBUO2Z1bmN0aW9uIGsodCl7aWYodm9pZCAwIT09VClyZXR1cm4gVD9UKHQpOnQoKTtjb25zdCBlPVN5bWJvbC5mb3IoIl9fU0VOVFJZX1NBRkVfUkFORE9NX0lEX1dSQVBQRVJfXyIpLG49cDtyZXR1cm4gZSBpbiBuJiYiZnVuY3Rpb24iPT10eXBlb2YgbltlXT8oVD1uW2VdLFQodCkpOihUPW51bGwsdCgpKX1mdW5jdGlvbiBSKCl7cmV0dXJuIGsoKCk9Pk1hdGgucmFuZG9tKCkpfWZ1bmN0aW9uIEkoKXtyZXR1cm4gaygoKT0+RGF0ZS5ub3coKSl9Y29uc3QgRD1TeW1ib2wuZm9yKCJzZW50cnkuc2tpcE5vcm1hbGl6YXRpb24iKSxVPVN5bWJvbC5mb3IoInNlbnRyeS5vdmVycmlkZU5vcm1hbGl6YXRpb25EZXB0aCIpO2Z1bmN0aW9uIEIodCxlPTEwMCxuPTEvMCl7dHJ5e3JldHVybiBMKCIiLHQsZSxuKX1jYXRjaCh0KXtyZXR1cm57RVJST1I6YCoqbm9uLXNlcmlhbGl6YWJsZSoqICgke3R9KWB9fX1mdW5jdGlvbiBMKHQsZSxuPTEvMCxyPTEvMCxvPWZ1bmN0aW9uKCl7Y29uc3QgdD1uZXcgV2Vha1NldDtmdW5jdGlvbiBlKGUpe3JldHVybiEhdC5oYXMoZSl8fCh0LmFkZChlKSwhMSl9ZnVuY3Rpb24gbihlKXt0LmRlbGV0ZShlKX1yZXR1cm5bZSxuXX0oKSl7Y29uc3RbcyxpXT1vO2lmKG51bGw9PWV8fFsiYm9vbGVhbiIsInN0cmluZyJdLmluY2x1ZGVzKHR5cGVvZiBlKXx8Im51bWJlciI9PXR5cGVvZiBlJiZOdW1iZXIuaXNGaW5pdGUoZSkpcmV0dXJuIGU7Y29uc3QgYz1mdW5jdGlvbih0LGUpe3RyeXtpZigidW5kZWZpbmVkIiE9dHlwZW9mIGdsb2JhbCYmZT09PWdsb2JhbClyZXR1cm4iW0dsb2JhbF0iO2lmKCJudW1iZXIiPT10eXBlb2YgZSYmIU51bWJlci5pc0Zpbml0ZShlKSlyZXR1cm5gWyR7ZX1dYDtpZigiZnVuY3Rpb24iPT10eXBlb2YgZSlyZXR1cm5gW0Z1bmN0aW9uOiAke2Z1bmN0aW9uKHQpe3RyeXtyZXR1cm4gdCYmImZ1bmN0aW9uIj09dHlwZW9mIHQmJnQubmFtZXx8eH1jYXRjaHtyZXR1cm4geH19KGUpfV1gO2lmKCJzeW1ib2wiPT10eXBlb2YgZSlyZXR1cm5gWyR7U3RyaW5nKGUpfV1gO2lmKCJiaWdpbnQiPT10eXBlb2YgZSlyZXR1cm5gW0JpZ0ludDogJHtTdHJpbmcoZSl9XWA7Y29uc3QgdD1mdW5jdGlvbih0KXtjb25zdCBlPU9iamVjdC5nZXRQcm90b3R5cGVPZih0KTtyZXR1cm4gZT8uY29uc3RydWN0b3I/ZS5jb25zdHJ1Y3Rvci5uYW1lOiJudWxsIHByb3RvdHlwZSJ9KGUpO3JldHVybmBbb2JqZWN0ICR7dH1dYH1jYXRjaCh0KXtyZXR1cm5gKipub24tc2VyaWFsaXphYmxlKiogKCR7dH0pYH19KDAsZSk7aWYoIWMuc3RhcnRzV2l0aCgiW29iamVjdCAiKSlyZXR1cm4gYztpZihmdW5jdGlvbih0KXtyZXR1cm4gQm9vbGVhbih0W0RdKX0oZSkpcmV0dXJuIGU7Y29uc3QgdT1mdW5jdGlvbih0KXtjb25zdCBlPXRbVV07cmV0dXJuIm51bWJlciI9PXR5cGVvZiBlP2U6dm9pZCAwfShlKSxhPXZvaWQgMCE9PXU/dTpuO2lmKDA9PT1hKXJldHVybiBjLnJlcGxhY2UoIm9iamVjdCAiLCIiKTtpZihzKGUpKXJldHVybiJbQ2lyY3VsYXIgfl0iO2NvbnN0IGY9ZTtpZihmJiYiZnVuY3Rpb24iPT10eXBlb2YgZi50b0pTT04pdHJ5e3JldHVybiBMKCIiLGYudG9KU09OKCksYS0xLHIsbyl9Y2F0Y2h7fWNvbnN0IGg9QXJyYXkuaXNBcnJheShlKT9bXTp7fTtsZXQgcD0wO2NvbnN0IGw9UChlKTtmb3IoY29uc3QgdCBpbiBsKXtpZighT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGwsdCkpY29udGludWU7aWYocD49cil7aFt0XT0iW01heFByb3BlcnRpZXMgfl0iO2JyZWFrfWNvbnN0IGU9bFt0XTtoW3RdPUwodCxlLGEtMSxyLG8pLHArK31yZXR1cm4gaShlKSxofWZ1bmN0aW9uIE0odCxlKXtjb25zdCBuPWUucmVwbGFjZSgvXFwvZywiLyIpLnJlcGxhY2UoL1t8XFx7fSgpW1xdXiQrKj8uXS9nLCJcXCQmIik7bGV0IHI9dDt0cnl7cj1kZWNvZGVVUkkodCl9Y2F0Y2h7fXJldHVybiByLnJlcGxhY2UoL1xcL2csIi8iKS5yZXBsYWNlKC93ZWJwYWNrOlwvPy9nLCIiKS5yZXBsYWNlKG5ldyBSZWdFeHAoYChmaWxlOi8vKT8vKiR7bn0vKmAsImlnIiksImFwcDovLy8iKX1mdW5jdGlvbiB6KHQsZT0wKXtyZXR1cm4ic3RyaW5nIiE9dHlwZW9mIHR8fDA9PT1lfHx0Lmxlbmd0aDw9ZT90OmAke3Quc2xpY2UoMCxlKX0uLi5gfWxldCBKO2Z1bmN0aW9uIFcodD1mdW5jdGlvbigpe2NvbnN0IHQ9cDtyZXR1cm4gdC5jcnlwdG98fHQubXNDcnlwdG99KCkpe3RyeXtpZih0Py5yYW5kb21VVUlEKXJldHVybiBrKCgpPT50LnJhbmRvbVVVSUQoKSkucmVwbGFjZSgvLS9nLCIiKX1jYXRjaHt9cmV0dXJuIEp8fChKPSIxMDAwMDAwMDEwMDA0MDAwODAwMDEwMDAwMDAwMDAwMCIpLEoucmVwbGFjZSgvWzAxOF0vZyx0PT4odF4oMTYqUigpJjE1KT4+dC80KS50b1N0cmluZygxNikpfWZ1bmN0aW9uIEYoKXtyZXR1cm4gSSgpLzFlM31sZXQgRztmdW5jdGlvbiBZKCl7cmV0dXJuKEc/PyhHPWZ1bmN0aW9uKCl7Y29uc3R7cGVyZm9ybWFuY2U6dH09cDtpZighdD8ubm93fHwhdC50aW1lT3JpZ2luKXJldHVybiBGO2NvbnN0IGU9dC50aW1lT3JpZ2luO3JldHVybigpPT4oZStrKCgpPT50Lm5vdygpKSkvMWUzfSgpKSkoKX1mdW5jdGlvbiBIKHQpe2NvbnN0IGU9WSgpLG49e3NpZDpXKCksaW5pdDohMCx0aW1lc3RhbXA6ZSxzdGFydGVkOmUsZHVyYXRpb246MCxzdGF0dXM6Im9rIixlcnJvcnM6MCxpZ25vcmVEdXJhdGlvbjohMSx0b0pTT046KCk9PmZ1bmN0aW9uKHQpe3JldHVybntzaWQ6YCR7dC5zaWR9YCxpbml0OnQuaW5pdCxzdGFydGVkOm5ldyBEYXRlKDFlMyp0LnN0YXJ0ZWQpLnRvSVNPU3RyaW5nKCksdGltZXN0YW1wOm5ldyBEYXRlKDFlMyp0LnRpbWVzdGFtcCkudG9JU09TdHJpbmcoKSxzdGF0dXM6dC5zdGF0dXMsZXJyb3JzOnQuZXJyb3JzLGRpZDoibnVtYmVyIj09dHlwZW9mIHQuZGlkfHwic3RyaW5nIj09dHlwZW9mIHQuZGlkP2Ake3QuZGlkfWA6dm9pZCAwLGR1cmF0aW9uOnQuZHVyYXRpb24sYWJub3JtYWxfbWVjaGFuaXNtOnQuYWJub3JtYWxfbWVjaGFuaXNtLGF0dHJzOntyZWxlYXNlOnQucmVsZWFzZSxlbnZpcm9ubWVudDp0LmVudmlyb25tZW50LGlwX2FkZHJlc3M6dC5pcEFkZHJlc3MsdXNlcl9hZ2VudDp0LnVzZXJBZ2VudH19fShuKX07cmV0dXJuIHQmJloobix0KSxufWZ1bmN0aW9uIFoodCxlPXt9KXtpZihlLnVzZXImJighdC5pcEFkZHJlc3MmJmUudXNlci5pcF9hZGRyZXNzJiYodC5pcEFkZHJlc3M9ZS51c2VyLmlwX2FkZHJlc3MpLHQuZGlkfHxlLmRpZHx8KHQuZGlkPWUudXNlci5pZHx8ZS51c2VyLmVtYWlsfHxlLnVzZXIudXNlcm5hbWUpKSx0LnRpbWVzdGFtcD1lLnRpbWVzdGFtcHx8WSgpLGUuYWJub3JtYWxfbWVjaGFuaXNtJiYodC5hYm5vcm1hbF9tZWNoYW5pc209ZS5hYm5vcm1hbF9tZWNoYW5pc20pLGUuaWdub3JlRHVyYXRpb24mJih0Lmlnbm9yZUR1cmF0aW9uPWUuaWdub3JlRHVyYXRpb24pLGUuc2lkJiYodC5zaWQ9MzI9PT1lLnNpZC5sZW5ndGg/ZS5zaWQ6VygpKSx2b2lkIDAhPT1lLmluaXQmJih0LmluaXQ9ZS5pbml0KSwhdC5kaWQmJmUuZGlkJiYodC5kaWQ9YCR7ZS5kaWR9YCksIm51bWJlciI9PXR5cGVvZiBlLnN0YXJ0ZWQmJih0LnN0YXJ0ZWQ9ZS5zdGFydGVkKSx0Lmlnbm9yZUR1cmF0aW9uKXQuZHVyYXRpb249dm9pZCAwO2Vsc2UgaWYoIm51bWJlciI9PXR5cGVvZiBlLmR1cmF0aW9uKXQuZHVyYXRpb249ZS5kdXJhdGlvbjtlbHNle2NvbnN0IGU9dC50aW1lc3RhbXAtdC5zdGFydGVkO3QuZHVyYXRpb249ZT49MD9lOjB9ZS5yZWxlYXNlJiYodC5yZWxlYXNlPWUucmVsZWFzZSksZS5lbnZpcm9ubWVudCYmKHQuZW52aXJvbm1lbnQ9ZS5lbnZpcm9ubWVudCksIXQuaXBBZGRyZXNzJiZlLmlwQWRkcmVzcyYmKHQuaXBBZGRyZXNzPWUuaXBBZGRyZXNzKSwhdC51c2VyQWdlbnQmJmUudXNlckFnZW50JiYodC51c2VyQWdlbnQ9ZS51c2VyQWdlbnQpLCJudW1iZXIiPT10eXBlb2YgZS5lcnJvcnMmJih0LmVycm9ycz1lLmVycm9ycyksZS5zdGF0dXMmJih0LnN0YXR1cz1lLnN0YXR1cyl9ZnVuY3Rpb24gcSh0LGUsbj0yKXtpZighZXx8Im9iamVjdCIhPXR5cGVvZiBlfHxuPD0wKXJldHVybiBlO2lmKHQmJjA9PT1PYmplY3Qua2V5cyhlKS5sZW5ndGgpcmV0dXJuIHQ7Y29uc3Qgcj17Li4udH07Zm9yKGNvbnN0IHQgaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSx0KSYmKHJbdF09cShyW3RdLGVbdF0sbi0xKSk7cmV0dXJuIHJ9Y2xhc3MgS3tjb25zdHJ1Y3Rvcigpe3RoaXMudD0hMSx0aGlzLm89W10sdGhpcy5pPVtdLHRoaXMudT1bXSx0aGlzLmg9W10sdGhpcy5wPXt9LHRoaXMubD17fSx0aGlzLm09e30sdGhpcy52PXt9LHRoaXMuUz17fSx0aGlzLl89e30sZnVuY3Rpb24odCxlLG4pe3RyeXtPYmplY3QuZGVmaW5lUHJvcGVydHkodCxlLHt2YWx1ZTpuLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pfWNhdGNoe2gmJl8ubG9nKGBGYWlsZWQgdG8gYWRkIG5vbi1lbnVtZXJhYmxlIHByb3BlcnR5ICIke1N0cmluZyhlKX0iIHRvIG9iamVjdGAsdCl9fSh0aGlzLCJyZWZzIix7fSksdGhpcy5OPXt0cmFjZUlkOlcoKSxzYW1wbGVSYW5kOlIoKX19Y2xvbmUoKXtjb25zdCB0PW5ldyBLO3JldHVybiB0LnU9Wy4uLnRoaXMudV0sdC5sPXsuLi50aGlzLmx9LHQubT17Li4udGhpcy5tfSx0LnY9ey4uLnRoaXMudn0sdC5TPXsuLi50aGlzLlN9LHRoaXMuUy5mbGFncyYmKHQuUy5mbGFncz17dmFsdWVzOlsuLi50aGlzLlMuZmxhZ3MudmFsdWVzXX0pLHQucD10aGlzLnAsdC5DPXRoaXMuQyx0Lmo9dGhpcy5qLHQuTz10aGlzLk8sdC5QPXRoaXMuUCx0Lmk9Wy4uLnRoaXMuaV0sdC5oPVsuLi50aGlzLmhdLHQuXz17Li4udGhpcy5ffSx0Lk49ey4uLnRoaXMuTn0sdC5BPXRoaXMuQSx0LlQ9dGhpcy5ULHQuaz10aGlzLmssdC5yZWZzPXsuLi50aGlzLnJlZnN9LHR9c2V0Q2xpZW50KHQpe3RoaXMuQT10fXNldExhc3RFdmVudElkKHQpe3RoaXMuVD10fWdldENsaWVudCgpe3JldHVybiB0aGlzLkF9bGFzdEV2ZW50SWQoKXtyZXR1cm4gdGhpcy5UfWFkZFNjb3BlTGlzdGVuZXIodCl7dGhpcy5vLnB1c2godCl9YWRkRXZlbnRQcm9jZXNzb3IodCl7cmV0dXJuIHRoaXMuaS5wdXNoKHQpLHRoaXN9c2V0VXNlcih0KXtyZXR1cm4gdGhpcy5wPXR8fHtlbWFpbDp2b2lkIDAsaWQ6dm9pZCAwLGlwX2FkZHJlc3M6dm9pZCAwLHVzZXJuYW1lOnZvaWQgMH0sdGhpcy5qJiZaKHRoaXMuaix7dXNlcjp0fSksdGhpcy5SKCksdGhpc31nZXRVc2VyKCl7cmV0dXJuIHRoaXMucH1zZXRDb252ZXJzYXRpb25JZCh0KXtyZXR1cm4gdGhpcy5rPXR8fHZvaWQgMCx0aGlzLlIoKSx0aGlzfXNldFRhZ3ModCl7cmV0dXJuIHRoaXMubD17Li4udGhpcy5sLC4uLnR9LHRoaXMuUigpLHRoaXN9c2V0VGFnKHQsZSl7cmV0dXJuIHRoaXMuc2V0VGFncyh7W3RdOmV9KX1zZXRBdHRyaWJ1dGVzKHQpe3JldHVybiB0aGlzLm09ey4uLnRoaXMubSwuLi50fSx0aGlzLlIoKSx0aGlzfXNldEF0dHJpYnV0ZSh0LGUpe3JldHVybiB0aGlzLnNldEF0dHJpYnV0ZXMoe1t0XTplfSl9cmVtb3ZlQXR0cmlidXRlKHQpe3JldHVybiB0IGluIHRoaXMubSYmKGRlbGV0ZSB0aGlzLm1bdF0sdGhpcy5SKCkpLHRoaXN9c2V0RXh0cmFzKHQpe3JldHVybiB0aGlzLnY9ey4uLnRoaXMudiwuLi50fSx0aGlzLlIoKSx0aGlzfXNldEV4dHJhKHQsZSl7cmV0dXJuIHRoaXMudj17Li4udGhpcy52LFt0XTplfSx0aGlzLlIoKSx0aGlzfXNldEZpbmdlcnByaW50KHQpe3JldHVybiB0aGlzLlA9dCx0aGlzLlIoKSx0aGlzfXNldExldmVsKHQpe3JldHVybiB0aGlzLkM9dCx0aGlzLlIoKSx0aGlzfXNldFRyYW5zYWN0aW9uTmFtZSh0KXtyZXR1cm4gdGhpcy5PPXQsdGhpcy5SKCksdGhpc31zZXRDb250ZXh0KHQsZSl7cmV0dXJuIG51bGw9PT1lP2RlbGV0ZSB0aGlzLlNbdF06dGhpcy5TW3RdPWUsdGhpcy5SKCksdGhpc31zZXRTZXNzaW9uKHQpe3JldHVybiB0P3RoaXMuaj10OmRlbGV0ZSB0aGlzLmosdGhpcy5SKCksdGhpc31nZXRTZXNzaW9uKCl7cmV0dXJuIHRoaXMuan11cGRhdGUodCl7aWYoIXQpcmV0dXJuIHRoaXM7Y29uc3QgZT0iZnVuY3Rpb24iPT10eXBlb2YgdD90KHRoaXMpOnQsbj1lIGluc3RhbmNlb2YgSz9lLmdldFNjb3BlRGF0YSgpOkMoZSk/dDp2b2lkIDAse3RhZ3M6cixhdHRyaWJ1dGVzOm8sZXh0cmE6cyx1c2VyOmksY29udGV4dHM6YyxsZXZlbDp1LGZpbmdlcnByaW50OmE9W10scHJvcGFnYXRpb25Db250ZXh0OmYsY29udmVyc2F0aW9uSWQ6aH09bnx8e307cmV0dXJuIHRoaXMubD17Li4udGhpcy5sLC4uLnJ9LHRoaXMubT17Li4udGhpcy5tLC4uLm99LHRoaXMudj17Li4udGhpcy52LC4uLnN9LHRoaXMuUz17Li4udGhpcy5TLC4uLmN9LGkmJk9iamVjdC5rZXlzKGkpLmxlbmd0aCYmKHRoaXMucD1pKSx1JiYodGhpcy5DPXUpLGEubGVuZ3RoJiYodGhpcy5QPWEpLGYmJih0aGlzLk49ZiksaCYmKHRoaXMuaz1oKSx0aGlzfWFkZEJyZWFkY3J1bWIodCxlKXtjb25zdCBuPSJudW1iZXIiPT10eXBlb2YgZT9lOjEwMDtpZihuPD0wKXJldHVybiB0aGlzO2NvbnN0IHI9e3RpbWVzdGFtcDpGKCksLi4udCxtZXNzYWdlOnQubWVzc2FnZT96KHQubWVzc2FnZSwyMDQ4KTp0Lm1lc3NhZ2V9O3JldHVybiB0aGlzLnUucHVzaChyKSx0aGlzLnUubGVuZ3RoPm4mJih0aGlzLnU9dGhpcy51LnNsaWNlKC1uKSx0aGlzLkE/LnJlY29yZERyb3BwZWRFdmVudCgiYnVmZmVyX292ZXJmbG93IiwibG9nX2l0ZW0iKSksdGhpcy5SKCksdGhpc31nZXRMYXN0QnJlYWRjcnVtYigpe3JldHVybiB0aGlzLnVbdGhpcy51Lmxlbmd0aC0xXX1jbGVhckJyZWFkY3J1bWJzKCl7cmV0dXJuIHRoaXMudT1bXSx0aGlzLlIoKSx0aGlzfWFkZEF0dGFjaG1lbnQodCl7cmV0dXJuIHRoaXMuaC5wdXNoKHQpLHRoaXN9Y2xlYXJBdHRhY2htZW50cygpe3JldHVybiB0aGlzLmg9W10sdGhpc31nZXRTY29wZURhdGEoKXtyZXR1cm57YnJlYWRjcnVtYnM6dGhpcy51LGF0dGFjaG1lbnRzOnRoaXMuaCxjb250ZXh0czp0aGlzLlMsdGFnczp0aGlzLmwsYXR0cmlidXRlczp0aGlzLm0sZXh0cmE6dGhpcy52LHVzZXI6dGhpcy5wLGxldmVsOnRoaXMuQyxmaW5nZXJwcmludDp0aGlzLlB8fFtdLGV2ZW50UHJvY2Vzc29yczp0aGlzLmkscHJvcGFnYXRpb25Db250ZXh0OnRoaXMuTixzZGtQcm9jZXNzaW5nTWV0YWRhdGE6dGhpcy5fLHRyYW5zYWN0aW9uTmFtZTp0aGlzLk8sY29udmVyc2F0aW9uSWQ6dGhpcy5rfX1zZXRTREtQcm9jZXNzaW5nTWV0YWRhdGEodCl7cmV0dXJuIHRoaXMuXz1xKHRoaXMuXyx0LDIpLHRoaXN9c2V0UHJvcGFnYXRpb25Db250ZXh0KHQpe3JldHVybiB0aGlzLk49dCx0aGlzfWdldFByb3BhZ2F0aW9uQ29udGV4dCgpe3JldHVybiB0aGlzLk59Y2FwdHVyZUV4Y2VwdGlvbih0LGUpe2NvbnN0IG49ZT8uZXZlbnRfaWR8fFcoKTtpZighdGhpcy5BKXJldHVybiBoJiZfLndhcm4oIk5vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBleGNlcHRpb24hIiksbjtjb25zdCByPW5ldyBFcnJvcigiU2VudHJ5IHN5bnRoZXRpY0V4Y2VwdGlvbiIpO3JldHVybiB0aGlzLkEuY2FwdHVyZUV4Y2VwdGlvbih0LHtvcmlnaW5hbEV4Y2VwdGlvbjp0LHN5bnRoZXRpY0V4Y2VwdGlvbjpyLC4uLmUsZXZlbnRfaWQ6bn0sdGhpcyksbn1jYXB0dXJlTWVzc2FnZSh0LGUsbil7Y29uc3Qgcj1uPy5ldmVudF9pZHx8VygpO2lmKCF0aGlzLkEpcmV0dXJuIGgmJl8ud2FybigiTm8gY2xpZW50IGNvbmZpZ3VyZWQgb24gc2NvcGUgLSB3aWxsIG5vdCBjYXB0dXJlIG1lc3NhZ2UhIikscjtjb25zdCBvPW4/LnN5bnRoZXRpY0V4Y2VwdGlvbj8/bmV3IEVycm9yKHQpO3JldHVybiB0aGlzLkEuY2FwdHVyZU1lc3NhZ2UodCxlLHtvcmlnaW5hbEV4Y2VwdGlvbjp0LHN5bnRoZXRpY0V4Y2VwdGlvbjpvLC4uLm4sZXZlbnRfaWQ6cn0sdGhpcykscn1jYXB0dXJlRXZlbnQodCxlKXtjb25zdCBuPXQuZXZlbnRfaWR8fGU/LmV2ZW50X2lkfHxXKCk7cmV0dXJuIHRoaXMuQT8odGhpcy5BLmNhcHR1cmVFdmVudCh0LHsuLi5lLGV2ZW50X2lkOm59LHRoaXMpLG4pOihoJiZfLndhcm4oIk5vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBldmVudCEiKSxuKX1SKCl7dGhpcy50fHwodGhpcy50PSEwLHRoaXMuby5mb3JFYWNoKHQ9Pnt0KHRoaXMpfSksdGhpcy50PSExKX19Y29uc3QgVj0iX19TRU5UUllfU1VQUFJFU1NfVFJBQ0lOR19fIixRPXQ9PnQgaW5zdGFuY2VvZiBQcm9taXNlJiYhdFtYXSxYPVN5bWJvbCgiY2hhaW5lZCBQcm9taXNlTGlrZSIpLHR0PSh0LGUpPT57aWYoIWUpcmV0dXJuIHQ7bGV0IG49ITE7Zm9yKGNvbnN0IHIgaW4gdCl7aWYociBpbiBlKWNvbnRpbnVlO249ITA7Y29uc3Qgbz10W3JdOyJmdW5jdGlvbiI9PXR5cGVvZiBvP09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHIse3ZhbHVlOiguLi5lKT0+by5hcHBseSh0LGUpLGVudW1lcmFibGU6ITAsY29uZmlndXJhYmxlOiEwLHdyaXRhYmxlOiEwfSk6ZVtyXT1vfXJldHVybiBuJiZPYmplY3QuYXNzaWduKGUse1tYXTohMH0pLGV9O2NsYXNzIGV0e2NvbnN0cnVjdG9yKHQsZSl7bGV0IG4scjtuPXR8fG5ldyBLLHI9ZXx8bmV3IEssdGhpcy5JPVt7c2NvcGU6bn1dLHRoaXMuRD1yfXdpdGhTY29wZSh0KXtjb25zdCBlPXRoaXMuVSgpO2xldCBuO3RyeXtuPXQoZSl9Y2F0Y2godCl7dGhyb3cgdGhpcy5CKCksdH1yZXR1cm4gaihuKT8oKHQsZSxuKT0+e2NvbnN0IHI9dC50aGVuKHQ9PihlKHQpLHQpLHQ9Pnt0aHJvdyBuKHQpLHR9KTtyZXR1cm4gUShyKSYmUSh0KT9yOnR0KHQscil9KShuLCgpPT50aGlzLkIoKSwoKT0+dGhpcy5CKCkpOih0aGlzLkIoKSxuKX1nZXRDbGllbnQoKXtyZXR1cm4gdGhpcy5nZXRTdGFja1RvcCgpLmNsaWVudH1nZXRTY29wZSgpe3JldHVybiB0aGlzLmdldFN0YWNrVG9wKCkuc2NvcGV9Z2V0SXNvbGF0aW9uU2NvcGUoKXtyZXR1cm4gdGhpcy5EfWdldFN0YWNrVG9wKCl7cmV0dXJuIHRoaXMuSVt0aGlzLkkubGVuZ3RoLTFdfVUoKXtjb25zdCB0PXRoaXMuZ2V0U2NvcGUoKS5jbG9uZSgpO3JldHVybiB0aGlzLkkucHVzaCh7Y2xpZW50OnRoaXMuZ2V0Q2xpZW50KCksc2NvcGU6dH0pLHR9Qigpe3JldHVybiEodGhpcy5JLmxlbmd0aDw9MSkmJiEhdGhpcy5JLnBvcCgpfX1mdW5jdGlvbiBudCgpe2NvbnN0IHQ9ZyhkKCkpO3JldHVybiB0LnN0YWNrPXQuc3RhY2t8fG5ldyBldChtKCJkZWZhdWx0Q3VycmVudFNjb3BlIiwoKT0+bmV3IEspLG0oImRlZmF1bHRJc29sYXRpb25TY29wZSIsKCk9Pm5ldyBLKSl9ZnVuY3Rpb24gcnQodCl7cmV0dXJuIG50KCkud2l0aFNjb3BlKHQpfWZ1bmN0aW9uIG90KHQsZSl7Y29uc3Qgbj1udCgpO3JldHVybiBuLndpdGhTY29wZSgoKT0+KG4uZ2V0U3RhY2tUb3AoKS5zY29wZT10LGUodCkpKX1mdW5jdGlvbiBzdCh0KXtyZXR1cm4gbnQoKS53aXRoU2NvcGUoKCk9PnQobnQoKS5nZXRJc29sYXRpb25TY29wZSgpKSl9ZnVuY3Rpb24gaXQodCl7cmV0dXJuIHJ0KGU9PntlLnNldFNES1Byb2Nlc3NpbmdNZXRhZGF0YSh7W1ZdOiEwfSk7Y29uc3Qgbj10KCk7cmV0dXJuIGUuc2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKHtbVl06dm9pZCAwfSksbn0pfWZ1bmN0aW9uIGN0KHQpe2NvbnN0IGU9Zyh0KTtyZXR1cm4gZS5hY3M/ZS5hY3M6e3N1cHByZXNzVHJhY2luZzppdCx3aXRoSXNvbGF0aW9uU2NvcGU6c3Qsd2l0aFNjb3BlOnJ0LHdpdGhTZXRTY29wZTpvdCx3aXRoU2V0SXNvbGF0aW9uU2NvcGU6KHQsZSk9PnN0KGUpLGdldEN1cnJlbnRTY29wZTooKT0+bnQoKS5nZXRTY29wZSgpLGdldElzb2xhdGlvblNjb3BlOigpPT5udCgpLmdldElzb2xhdGlvblNjb3BlKCl9fWZ1bmN0aW9uIHV0KHQsZT0hMSl7Y29uc3R7aG9zdDpuLHBhdGg6cixwYXNzOm8scG9ydDpzLHByb2plY3RJZDppLHByb3RvY29sOmMscHVibGljS2V5OnV9PXQ7cmV0dXJuYCR7Y306Ly8ke3V9JHtlJiZvP2A6JHtvfWA6IiJ9QCR7bn0ke3M/YDoke3N9YDoiIn0vJHtyP2Ake3J9L2A6cn0ke2l9YH1mdW5jdGlvbiBhdCh0LGUpe2NvbnN0e2ZpbmdlcnByaW50Om4sYnJlYWRjcnVtYnM6cixzZGtQcm9jZXNzaW5nTWV0YWRhdGE6b309ZTshZnVuY3Rpb24odCxlKXtjb25zdHtleHRyYTpuLHRhZ3M6cix1c2VyOm8sY29udGV4dHM6cyxsZXZlbDppLHRyYW5zYWN0aW9uTmFtZTpjfT1lO09iamVjdC5rZXlzKG4pLmxlbmd0aCYmKHQuZXh0cmE9ey4uLm4sLi4udC5leHRyYX0pO09iamVjdC5rZXlzKHIpLmxlbmd0aCYmKHQudGFncz17Li4uciwuLi50LnRhZ3N9KTtPYmplY3Qua2V5cyhvKS5sZW5ndGgmJih0LnVzZXI9ey4uLm8sLi4udC51c2VyfSk7T2JqZWN0LmtleXMocykubGVuZ3RoJiYodC5jb250ZXh0cz17Li4ucywuLi50LmNvbnRleHRzfSk7aSYmKHQubGV2ZWw9aSk7YyYmInRyYW5zYWN0aW9uIiE9PXQudHlwZSYmKHQudHJhbnNhY3Rpb249Yyl9KHQsZSksZnVuY3Rpb24odCxlKXt0LmZpbmdlcnByaW50PXQuZmluZ2VycHJpbnQ/QXJyYXkuaXNBcnJheSh0LmZpbmdlcnByaW50KT90LmZpbmdlcnByaW50Olt0LmZpbmdlcnByaW50XTpbXSxlJiYodC5maW5nZXJwcmludD10LmZpbmdlcnByaW50LmNvbmNhdChlKSk7dC5maW5nZXJwcmludC5sZW5ndGh8fGRlbGV0ZSB0LmZpbmdlcnByaW50fSh0LG4pLGZ1bmN0aW9uKHQsZSl7Y29uc3Qgbj1bLi4udC5icmVhZGNydW1ic3x8W10sLi4uZV07dC5icmVhZGNydW1icz1uLmxlbmd0aD9uOnZvaWQgMH0odCxyKSxmdW5jdGlvbih0LGUpe3Quc2RrUHJvY2Vzc2luZ01ldGFkYXRhPXsuLi50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YSwuLi5lfX0odCxvKX1mdW5jdGlvbiBmdCh0LGU9W10pe3JldHVyblt0LGVdfWZ1bmN0aW9uIGh0KHQsZSl7Y29uc3Qgbj10WzFdO2Zvcihjb25zdCB0IG9mIG4pe2lmKGUodCx0WzBdLnR5cGUpKXJldHVybiEwfXJldHVybiExfWZ1bmN0aW9uIHB0KHQpe2NvbnN0IGU9ZyhwKTtyZXR1cm4gZS5lbmNvZGVQb2x5ZmlsbD9lLmVuY29kZVBvbHlmaWxsKHQpOihuZXcgVGV4dEVuY29kZXIpLmVuY29kZSh0KX1mdW5jdGlvbiBsdCh0KXtjb25zdFtlLG5dPXQ7bGV0IHI9SlNPTi5zdHJpbmdpZnkoZSk7ZnVuY3Rpb24gbyh0KXsic3RyaW5nIj09dHlwZW9mIHI/cj0ic3RyaW5nIj09dHlwZW9mIHQ/cit0OltwdChyKSx0XTpyLnB1c2goInN0cmluZyI9PXR5cGVvZiB0P3B0KHQpOnQpfWZvcihjb25zdCB0IG9mIG4pe2NvbnN0W2Usbl09dDtpZihvKGBcbiR7SlNPTi5zdHJpbmdpZnkoZSl9XG5gKSwic3RyaW5nIj09dHlwZW9mIG58fG4gaW5zdGFuY2VvZiBVaW50OEFycmF5KW8obik7ZWxzZXtsZXQgdDt0cnl7dD1KU09OLnN0cmluZ2lmeShuKX1jYXRjaHt0PUpTT04uc3RyaW5naWZ5KEIobikpfW8odCl9fXJldHVybiJzdHJpbmciPT10eXBlb2Ygcj9yOmZ1bmN0aW9uKHQpe2NvbnN0IGU9dC5yZWR1Y2UoKHQsZSk9PnQrZS5sZW5ndGgsMCksbj1uZXcgVWludDhBcnJheShlKTtsZXQgcj0wO2Zvcihjb25zdCBlIG9mIHQpbi5zZXQoZSxyKSxyKz1lLmxlbmd0aDtyZXR1cm4gbn0ocil9Y29uc3QgZHQ9e3Nlc3Npb25zOiJzZXNzaW9uIixldmVudDoiZXJyb3IiLGNsaWVudF9yZXBvcnQ6ImludGVybmFsIix1c2VyX3JlcG9ydDoiZGVmYXVsdCIscHJvZmlsZV9jaHVuazoicHJvZmlsZSIscmVwbGF5X2V2ZW50OiJyZXBsYXkiLHJlcGxheV9yZWNvcmRpbmc6InJlcGxheSIsY2hlY2tfaW46Im1vbml0b3IiLHJhd19zZWN1cml0eToic2VjdXJpdHkiLGxvZzoibG9nX2l0ZW0iLHRyYWNlX21ldHJpYzoibWV0cmljIn07ZnVuY3Rpb24gZ3QodCl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiB0IGluIGR0fSh0KT9kdFt0XTp0fWZ1bmN0aW9uIG10KHQpe2lmKCF0Py5zZGspcmV0dXJuO2NvbnN0e25hbWU6ZSx2ZXJzaW9uOm59PXQuc2RrO3JldHVybntuYW1lOmUsdmVyc2lvbjpufX1mdW5jdGlvbiB5dCh0KXtjb25zdCBlPWN0KGQoKSk7cmV0dXJuIGUuc3VwcHJlc3NUcmFjaW5nP2Uuc3VwcHJlc3NUcmFjaW5nKHQpOmZ1bmN0aW9uKC4uLnQpe2NvbnN0IGU9Y3QoZCgpKTtpZigyPT09dC5sZW5ndGgpe2NvbnN0W24scl09dDtyZXR1cm4gbj9lLndpdGhTZXRTY29wZShuLHIpOmUud2l0aFNjb3BlKHIpfXJldHVybiBlLndpdGhTY29wZSh0WzBdKX0oZT0+KGUuc2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKHtbVl06ITB9KSx0KCkpKX1mdW5jdGlvbiBidCh0LGUsbixyKXtjb25zdCBvPW10KG4pLHM9dC50eXBlJiYicmVwbGF5X2V2ZW50IiE9PXQudHlwZT90LnR5cGU6ImV2ZW50IjshZnVuY3Rpb24odCxlKXtpZighZSlyZXR1cm4gdDtjb25zdCBuPXQuc2RrfHx7fTt0LnNkaz17Li4ubixuYW1lOm4ubmFtZXx8ZS5uYW1lLHZlcnNpb246bi52ZXJzaW9ufHxlLnZlcnNpb24saW50ZWdyYXRpb25zOlsuLi50LnNkaz8uaW50ZWdyYXRpb25zfHxbXSwuLi5lLmludGVncmF0aW9uc3x8W11dLHBhY2thZ2VzOlsuLi50LnNkaz8ucGFja2FnZXN8fFtdLC4uLmUucGFja2FnZXN8fFtdXSxzZXR0aW5nczp0LnNkaz8uc2V0dGluZ3N8fGUuc2V0dGluZ3M/ey4uLnQuc2RrPy5zZXR0aW5ncywuLi5lLnNldHRpbmdzfTp2b2lkIDB9fSh0LG4/LnNkayk7Y29uc3QgaT1mdW5jdGlvbih0LGUsbixyKXtjb25zdCBvPXQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhPy5keW5hbWljU2FtcGxpbmdDb250ZXh0O3JldHVybntldmVudF9pZDp0LmV2ZW50X2lkLHNlbnRfYXQ6bmV3IERhdGUoSSgpKS50b0lTT1N0cmluZygpLC4uLmUmJntzZGs6ZX0sLi4uISFuJiZyJiZ7ZHNuOnV0KHIpfSwuLi5vJiZ7dHJhY2U6b319fSh0LG8scixlKTtkZWxldGUgdC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE7cmV0dXJuIGZ0KGksW1t7dHlwZTpzfSx0XV0pfWNsYXNzIHZ0e2NvbnN0cnVjdG9yKHQpe3RoaXMuTD0wLHRoaXMuTT1bXSx0aGlzLkoodCl9dGhlbih0LGUpe3JldHVybiBuZXcgdnQoKG4scik9Pnt0aGlzLk0ucHVzaChbITEsZT0+e2lmKHQpdHJ5e24odChlKSl9Y2F0Y2godCl7cih0KX1lbHNlIG4oZSl9LHQ9PntpZihlKXRyeXtuKGUodCkpfWNhdGNoKHQpe3IodCl9ZWxzZSByKHQpfV0pLHRoaXMuVygpfSl9Y2F0Y2godCl7cmV0dXJuIHRoaXMudGhlbih0PT50LHQpfWZpbmFsbHkodCl7cmV0dXJuIG5ldyB2dCgoZSxuKT0+e2xldCByLG87cmV0dXJuIHRoaXMudGhlbihlPT57bz0hMSxyPWUsdCYmdCgpfSxlPT57bz0hMCxyPWUsdCYmdCgpfSkudGhlbigoKT0+e28/bihyKTplKHIpfSl9KX1XKCl7aWYoMD09PXRoaXMuTClyZXR1cm47Y29uc3QgdD10aGlzLk0uc2xpY2UoKTt0aGlzLk09W10sdC5mb3JFYWNoKHQ9Pnt0WzBdfHwoMT09PXRoaXMuTCYmdFsxXSh0aGlzLkYpLDI9PT10aGlzLkwmJnRbMl0odGhpcy5GKSx0WzBdPSEwKX0pfUoodCl7Y29uc3QgZT0odCxlKT0+ezA9PT10aGlzLkwmJihqKGUpP2UudGhlbihuLHIpOih0aGlzLkw9dCx0aGlzLkY9ZSx0aGlzLlcoKSkpfSxuPXQ9PntlKDEsdCl9LHI9dD0+e2UoMix0KX07dHJ5e3QobixyKX1jYXRjaCh0KXtyKHQpfX19Y29uc3Qgd3Q9U3ltYm9sLmZvcigiU2VudHJ5QnVmZmVyRnVsbEVycm9yIik7ZnVuY3Rpb24gU3QodD0xMDApe2NvbnN0IGU9bmV3IFNldDtmdW5jdGlvbiBuKHQpe2UuZGVsZXRlKHQpfXJldHVybntnZXQgJCgpe3JldHVybiBBcnJheS5mcm9tKGUpfSxhZGQ6ZnVuY3Rpb24ocil7aWYoIShlLnNpemU8dCkpcmV0dXJuIG89d3QsbmV3IHZ0KCh0LGUpPT57ZShvKX0pO3ZhciBvO2NvbnN0IHM9cigpO3JldHVybiBlLmFkZChzKSxzLnRoZW4oKCk9Pm4ocyksKCk9Pm4ocykpLHN9LGRyYWluOmZ1bmN0aW9uKHQpe2lmKCFlLnNpemUpcmV0dXJuIG49ITAsbmV3IHZ0KHQ9Pnt0KG4pfSk7dmFyIG47Y29uc3Qgcj1Qcm9taXNlLmFsbFNldHRsZWQoQXJyYXkuZnJvbShlKSkudGhlbigoKT0+ITApO2lmKCF0KXJldHVybiByO2NvbnN0IG89W3IsbmV3IFByb21pc2UoZT0+e3JldHVybiJvYmplY3QiPT10eXBlb2Yobj1zZXRUaW1lb3V0KCgpPT5lKCExKSx0KSkmJiJmdW5jdGlvbiI9PXR5cGVvZiBuLnVucmVmJiZuLnVucmVmKCksbjt2YXIgbn0pXTtyZXR1cm4gUHJvbWlzZS5yYWNlKG8pfX19ZnVuY3Rpb24gX3QodCx7c3RhdHVzQ29kZTplLGhlYWRlcnM6bn0scj1JKCkpe2NvbnN0IG89ey4uLnR9LHM9bj8uWyJ4LXNlbnRyeS1yYXRlLWxpbWl0cyJdLGk9bj8uWyJyZXRyeS1hZnRlciJdO2lmKHMpZm9yKGNvbnN0IHQgb2Ygcy50cmltKCkuc3BsaXQoIiwiKSl7Y29uc3RbZSxuLCwsc109dC5zcGxpdCgiOiIsNSksaT1wYXJzZUludChlLDEwKSxjPTFlMyooaXNOYU4oaSk/NjA6aSk7aWYobilmb3IoY29uc3QgdCBvZiBuLnNwbGl0KCI7IikpIm1ldHJpY19idWNrZXQiPT09dCYmcyYmIXMuc3BsaXQoIjsiKS5pbmNsdWRlcygiY3VzdG9tIil8fChvW3RdPXIrYyk7ZWxzZSBvLmFsbD1yK2N9ZWxzZSBpP28uYWxsPXIrZnVuY3Rpb24odCxlPUkoKSl7Y29uc3Qgbj1wYXJzZUludChgJHt0fWAsMTApO2lmKCFpc05hTihuKSlyZXR1cm4gMWUzKm47Y29uc3Qgcj1EYXRlLnBhcnNlKGAke3R9YCk7cmV0dXJuIGlzTmFOKHIpPzZlNDpyLWV9KGkscik6NDI5PT09ZSYmKG8uYWxsPXIrNmU0KTtyZXR1cm4gb31mdW5jdGlvbiAkdCh0LGUsbj1TdCh0LmJ1ZmZlclNpemV8fDY0KSl7bGV0IHI9e307cmV0dXJue3NlbmQ6ZnVuY3Rpb24odCl7Y29uc3Qgbz1bXTtpZihodCh0LCh0LGUpPT57Y29uc3Qgbj1ndChlKTsoZnVuY3Rpb24odCxlLG49SSgpKXtyZXR1cm4gZnVuY3Rpb24odCxlKXtyZXR1cm4gdFtlXXx8dC5hbGx8fDB9KHQsZSk+bn0pKHIsbil8fG8ucHVzaCh0KX0pLDA9PT1vLmxlbmd0aClyZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHt9KTtjb25zdCBzPWZ0KHRbMF0sbyksaT10PT57IWZ1bmN0aW9uKHQsZSl7cmV0dXJuIGh0KHQsKHQsbik9PmUuaW5jbHVkZXMobikpfShzLFsiY2xpZW50X3JlcG9ydCJdKT9odChzLCh0LGUpPT57fSk6aCYmXy53YXJuKGBEcm9wcGluZyBjbGllbnQgcmVwb3J0LiBXaWxsIG5vdCBzZW5kIG91dGNvbWVzIChyZWFzb246ICR7dH0pLmApfTtyZXR1cm4gbi5hZGQoKCk9PmUoe2JvZHk6bHQocyl9KS50aGVuKHQ9PjQxMz09PXQuc3RhdHVzQ29kZT8oaCYmXy5lcnJvcigiU2VudHJ5IHJlc3BvbmRlZCB3aXRoIHN0YXR1cyBjb2RlIDQxMy4gRW52ZWxvcGUgd2FzIGRpc2NhcmRlZCBkdWUgdG8gZXhjZWVkaW5nIHNpemUgbGltaXRzLiIpLGkoInNlbmRfZXJyb3IiKSx0KTooaCYmdm9pZCAwIT09dC5zdGF0dXNDb2RlJiYodC5zdGF0dXNDb2RlPDIwMHx8dC5zdGF0dXNDb2RlPj0zMDApJiZfLndhcm4oYFNlbnRyeSByZXNwb25kZWQgd2l0aCBzdGF0dXMgY29kZSAke3Quc3RhdHVzQ29kZX0gdG8gc2VudCBldmVudC5gKSxyPV90KHIsdCksdCksdD0+e3Rocm93IGkoIm5ldHdvcmtfZXJyb3IiKSxoJiZfLmVycm9yKCJFbmNvdW50ZXJlZCBlcnJvciBydW5uaW5nIHRyYW5zcG9ydCByZXF1ZXN0OiIsdCksdH0pKS50aGVuKHQ9PnQsdD0+e2lmKHQ9PT13dClyZXR1cm4gaCYmXy5lcnJvcigiU2tpcHBlZCBzZW5kaW5nIGV2ZW50IGJlY2F1c2UgYnVmZmVyIGlzIGZ1bGwuIiksaSgicXVldWVfb3ZlcmZsb3ciKSxQcm9taXNlLnJlc29sdmUoe30pO3Rocm93IHR9KX0sZmx1c2g6dD0+bi5kcmFpbih0KX19Y29uc3QgRXQ9L14oXFMrOlxcfFwvPykoW1xzXFNdKj8pKCg/OlwuezEsMn18W14vXFxdKz98KShcLlteLi9cXF0qfCkpKD86Wy9cXF0qKSQvO2Z1bmN0aW9uIHh0KHQpe2NvbnN0IGU9ZnVuY3Rpb24odCl7Y29uc3QgZT10Lmxlbmd0aD4xMDI0P2A8dHJ1bmNhdGVkPiR7dC5zbGljZSgtMTAyNCl9YDp0LG49RXQuZXhlYyhlKTtyZXR1cm4gbj9uLnNsaWNlKDEpOltdfSh0KSxuPWVbMF18fCIiO2xldCByPWVbMV07cmV0dXJuIG58fHI/KHImJihyPXIuc2xpY2UoMCxyLmxlbmd0aC0xKSksbityKToiLiJ9ZnVuY3Rpb24gTnQodCxlPSExKXtyZXR1cm4hKGV8fHQmJiF0LnN0YXJ0c1dpdGgoIi8iKSYmIXQubWF0Y2goL15bQS1aXTovKSYmIXQuc3RhcnRzV2l0aCgiLiIpJiYhdC5tYXRjaCgvXlthLXpBLVpdKFthLXpBLVowLTkuXC0rXSkqOlwvXC8vKSkmJnZvaWQgMCE9PXQmJiF0LmluY2x1ZGVzKCJub2RlX21vZHVsZXMvIil9dmFyIEN0O2NvbnN0IGp0PVN5bWJvbCgiQWdlbnRCYXNlSW50ZXJuYWxTdGF0ZSIpO2NsYXNzIE90IGV4dGVuZHMoQ3Q9cy5BZ2VudCxDdCl7Y29uc3RydWN0b3IodCl7c3VwZXIodCksdGhpc1tqdF09e319aXNTZWN1cmVFbmRwb2ludCh0KXtpZih0KXtpZigiYm9vbGVhbiI9PXR5cGVvZiB0LnNlY3VyZUVuZHBvaW50KXJldHVybiB0LnNlY3VyZUVuZHBvaW50O2lmKCJzdHJpbmciPT10eXBlb2YgdC5wcm90b2NvbClyZXR1cm4iaHR0cHM6Ij09PXQucHJvdG9jb2x9Y29uc3R7c3RhY2s6ZX09bmV3IEVycm9yO3JldHVybiJzdHJpbmciPT10eXBlb2YgZSYmZS5zcGxpdCgiXG4iKS5zb21lKHQ9Pi0xIT09dC5pbmRleE9mKCIoaHR0cHMuanM6Iil8fC0xIT09dC5pbmRleE9mKCJub2RlOmh0dHBzOiIpKX1jcmVhdGVTb2NrZXQodCxlLG4pe2NvbnN0IHI9ey4uLmUsc2VjdXJlRW5kcG9pbnQ6dGhpcy5pc1NlY3VyZUVuZHBvaW50KGUpfTtQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpPT50aGlzLmNvbm5lY3QodCxyKSkudGhlbihvPT57aWYobyBpbnN0YW5jZW9mIHMuQWdlbnQpcmV0dXJuIG8uYWRkUmVxdWVzdCh0LHIpO3RoaXNbanRdLmN1cnJlbnRTb2NrZXQ9byxzdXBlci5jcmVhdGVTb2NrZXQodCxlLG4pfSxuKX1jcmVhdGVDb25uZWN0aW9uKCl7Y29uc3QgdD10aGlzW2p0XS5jdXJyZW50U29ja2V0O2lmKHRoaXNbanRdLmN1cnJlbnRTb2NrZXQ9dm9pZCAwLCF0KXRocm93IG5ldyBFcnJvcigiTm8gc29ja2V0IHdhcyByZXR1cm5lZCBpbiB0aGUgYGNvbm5lY3QoKWAgZnVuY3Rpb24iKTtyZXR1cm4gdH1nZXQgZGVmYXVsdFBvcnQoKXtyZXR1cm4gdGhpc1tqdF0uZGVmYXVsdFBvcnQ/PygiaHR0cHM6Ij09PXRoaXMucHJvdG9jb2w/NDQzOjgwKX1zZXQgZGVmYXVsdFBvcnQodCl7dGhpc1tqdF0mJih0aGlzW2p0XS5kZWZhdWx0UG9ydD10KX1nZXQgcHJvdG9jb2woKXtyZXR1cm4gdGhpc1tqdF0ucHJvdG9jb2w/Pyh0aGlzLmlzU2VjdXJlRW5kcG9pbnQoKT8iaHR0cHM6IjoiaHR0cDoiKX1zZXQgcHJvdG9jb2wodCl7dGhpc1tqdF0mJih0aGlzW2p0XS5wcm90b2NvbD10KX19ZnVuY3Rpb24gUHQoLi4udCl7Xy5sb2coIltodHRwcy1wcm94eS1hZ2VudDpwYXJzZS1wcm94eS1yZXNwb25zZV0iLC4uLnQpfWZ1bmN0aW9uIEF0KHQpe3JldHVybiBuZXcgUHJvbWlzZSgoZSxuKT0+e2xldCByPTA7Y29uc3Qgbz1bXTtmdW5jdGlvbiBzKCl7Y29uc3QgYz10LnJlYWQoKTtjP2Z1bmN0aW9uKGMpe28ucHVzaChjKSxyKz1jLmxlbmd0aDtjb25zdCB1PUJ1ZmZlci5jb25jYXQobyxyKSxhPXUuaW5kZXhPZigiXHJcblxyXG4iKTtpZigtMT09PWEpcmV0dXJuIFB0KCJoYXZlIG5vdCByZWNlaXZlZCBlbmQgb2YgSFRUUCBoZWFkZXJzIHlldC4uLiIpLHZvaWQgcygpO2NvbnN0IGY9dS5zdWJhcnJheSgwLGEpLnRvU3RyaW5nKCJhc2NpaSIpLnNwbGl0KCJcclxuIiksaD1mLnNoaWZ0KCk7aWYoIWgpcmV0dXJuIHQuZGVzdHJveSgpLG4obmV3IEVycm9yKCJObyBoZWFkZXIgcmVjZWl2ZWQgZnJvbSBwcm94eSBDT05ORUNUIHJlc3BvbnNlIikpO2NvbnN0IHA9aC5zcGxpdCgiICIpLGw9KyhwWzFdfHwwKSxkPXAuc2xpY2UoMikuam9pbigiICIpLGc9e307Zm9yKGNvbnN0IGUgb2YgZil7aWYoIWUpY29udGludWU7Y29uc3Qgcj1lLmluZGV4T2YoIjoiKTtpZigtMT09PXIpcmV0dXJuIHQuZGVzdHJveSgpLG4obmV3IEVycm9yKGBJbnZhbGlkIGhlYWRlciBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2U6ICIke2V9ImApKTtjb25zdCBvPWUuc2xpY2UoMCxyKS50b0xvd2VyQ2FzZSgpLHM9ZS5zbGljZShyKzEpLnRyaW1TdGFydCgpLGk9Z1tvXTsic3RyaW5nIj09dHlwZW9mIGk/Z1tvXT1baSxzXTpBcnJheS5pc0FycmF5KGkpP2kucHVzaChzKTpnW29dPXN9UHQoImdvdCBwcm94eSBzZXJ2ZXIgcmVzcG9uc2U6ICVvICVvIixoLGcpLGkoKSxlKHtjb25uZWN0OntzdGF0dXNDb2RlOmwsc3RhdHVzVGV4dDpkLGhlYWRlcnM6Z30sYnVmZmVyZWQ6dX0pfShjKTp0Lm9uY2UoInJlYWRhYmxlIixzKX1mdW5jdGlvbiBpKCl7dC5yZW1vdmVMaXN0ZW5lcigiZW5kIixjKSx0LnJlbW92ZUxpc3RlbmVyKCJlcnJvciIsdSksdC5yZW1vdmVMaXN0ZW5lcigicmVhZGFibGUiLHMpfWZ1bmN0aW9uIGMoKXtpKCksUHQoIm9uZW5kIiksbihuZXcgRXJyb3IoIlByb3h5IGNvbm5lY3Rpb24gZW5kZWQgYmVmb3JlIHJlY2VpdmluZyBDT05ORUNUIHJlc3BvbnNlIikpfWZ1bmN0aW9uIHUodCl7aSgpLFB0KCJvbmVycm9yICVvIix0KSxuKHQpfXQub24oImVycm9yIix1KSx0Lm9uKCJlbmQiLGMpLHMoKX0pfWZ1bmN0aW9uIFR0KC4uLnQpe18ubG9nKCJbaHR0cHMtcHJveHktYWdlbnRdIiwuLi50KX1jbGFzcyBrdCBleHRlbmRzIE90e2NvbnN0cnVjdG9yKHQsZSl7c3VwZXIoZSksdGhpcy5vcHRpb25zPXt9LHRoaXMucHJveHk9InN0cmluZyI9PXR5cGVvZiB0P25ldyBVUkwodCk6dCx0aGlzLnByb3h5SGVhZGVycz1lPy5oZWFkZXJzPz97fSxUdCgiQ3JlYXRpbmcgbmV3IEh0dHBzUHJveHlBZ2VudCBpbnN0YW5jZTogJW8iLHRoaXMucHJveHkuaHJlZik7Y29uc3Qgbj0odGhpcy5wcm94eS5ob3N0bmFtZXx8dGhpcy5wcm94eS5ob3N0KS5yZXBsYWNlKC9eXFt8XF0kL2csIiIpLHI9dGhpcy5wcm94eS5wb3J0P3BhcnNlSW50KHRoaXMucHJveHkucG9ydCwxMCk6Imh0dHBzOiI9PT10aGlzLnByb3h5LnByb3RvY29sPzQ0Mzo4MDt0aGlzLmNvbm5lY3RPcHRzPXtBTFBOUHJvdG9jb2xzOlsiaHR0cC8xLjEiXSwuLi5lP0l0KGUsImhlYWRlcnMiKTpudWxsLGhvc3Q6bixwb3J0OnJ9fWFzeW5jIGNvbm5lY3QodCxlKXtjb25zdHtwcm94eTpufT10aGlzO2lmKCFlLmhvc3QpdGhyb3cgbmV3IFR5cGVFcnJvcignTm8gImhvc3QiIHByb3ZpZGVkJyk7bGV0IHI7aWYoImh0dHBzOiI9PT1uLnByb3RvY29sKXtUdCgiQ3JlYXRpbmcgYHRscy5Tb2NrZXRgOiAlbyIsdGhpcy5jb25uZWN0T3B0cyk7Y29uc3QgdD10aGlzLmNvbm5lY3RPcHRzLnNlcnZlcm5hbWV8fHRoaXMuY29ubmVjdE9wdHMuaG9zdDtyPWYuY29ubmVjdCh7Li4udGhpcy5jb25uZWN0T3B0cyxzZXJ2ZXJuYW1lOnQmJmEuaXNJUCh0KT92b2lkIDA6dH0pfWVsc2UgVHQoIkNyZWF0aW5nIGBuZXQuU29ja2V0YDogJW8iLHRoaXMuY29ubmVjdE9wdHMpLHI9YS5jb25uZWN0KHRoaXMuY29ubmVjdE9wdHMpO2NvbnN0IG89ImZ1bmN0aW9uIj09dHlwZW9mIHRoaXMucHJveHlIZWFkZXJzP3RoaXMucHJveHlIZWFkZXJzKCk6ey4uLnRoaXMucHJveHlIZWFkZXJzfSxzPWEuaXNJUHY2KGUuaG9zdCk/YFske2UuaG9zdH1dYDplLmhvc3Q7bGV0IGk9YENPTk5FQ1QgJHtzfToke2UucG9ydH0gSFRUUC8xLjFcclxuYDtpZihuLnVzZXJuYW1lfHxuLnBhc3N3b3JkKXtjb25zdCB0PWAke2RlY29kZVVSSUNvbXBvbmVudChuLnVzZXJuYW1lKX06JHtkZWNvZGVVUklDb21wb25lbnQobi5wYXNzd29yZCl9YDtvWyJQcm94eS1BdXRob3JpemF0aW9uIl09YEJhc2ljICR7QnVmZmVyLmZyb20odCkudG9TdHJpbmcoImJhc2U2NCIpfWB9by5Ib3N0PWAke3N9OiR7ZS5wb3J0fWAsb1siUHJveHktQ29ubmVjdGlvbiJdfHwob1siUHJveHktQ29ubmVjdGlvbiJdPXRoaXMua2VlcEFsaXZlPyJLZWVwLUFsaXZlIjoiY2xvc2UiKTtmb3IoY29uc3QgdCBvZiBPYmplY3Qua2V5cyhvKSlpKz1gJHt0fTogJHtvW3RdfVxyXG5gO2NvbnN0IGM9QXQocik7ci53cml0ZShgJHtpfVxyXG5gKTtjb25zdHtjb25uZWN0OnUsYnVmZmVyZWQ6aH09YXdhaXQgYztpZih0LmVtaXQoInByb3h5Q29ubmVjdCIsdSksdGhpcy5lbWl0KCJwcm94eUNvbm5lY3QiLHUsdCksMjAwPT09dS5zdGF0dXNDb2RlKXtpZih0Lm9uY2UoInNvY2tldCIsUnQpLGUuc2VjdXJlRW5kcG9pbnQpe1R0KCJVcGdyYWRpbmcgc29ja2V0IGNvbm5lY3Rpb24gdG8gVExTIik7Y29uc3QgdD1lLnNlcnZlcm5hbWV8fGUuaG9zdDtyZXR1cm4gZi5jb25uZWN0KHsuLi5JdChlLCJob3N0IiwicGF0aCIsInBvcnQiKSxzb2NrZXQ6cixzZXJ2ZXJuYW1lOmEuaXNJUCh0KT92b2lkIDA6dH0pfXJldHVybiByfXIuZGVzdHJveSgpO2NvbnN0IHA9bmV3IGEuU29ja2V0KHt3cml0YWJsZTohMX0pO3JldHVybiBwLnJlYWRhYmxlPSEwLHQub25jZSgic29ja2V0Iix0PT57VHQoIlJlcGxheWluZyBwcm94eSBidWZmZXIgZm9yIGZhaWxlZCByZXF1ZXN0IiksdC5wdXNoKGgpLHQucHVzaChudWxsKX0pLHB9fWZ1bmN0aW9uIFJ0KHQpe3QucmVzdW1lKCl9ZnVuY3Rpb24gSXQodCwuLi5lKXtjb25zdCBuPXt9O2xldCByO2ZvcihyIGluIHQpZS5pbmNsdWRlcyhyKXx8KG5bcl09dFtyXSk7cmV0dXJuIG59a3QucHJvdG9jb2xzPVsiaHR0cCIsImh0dHBzIl07ZnVuY3Rpb24gRHQodCl7cmV0dXJuIHQucmVwbGFjZSgvXltBLVpdOi8sIiIpLnJlcGxhY2UoL1xcL2csIi8iKX1jb25zdCBVdD1lO2xldCBCdCxMdD0wLE10PXt9O2Z1bmN0aW9uIHp0KHQpe1V0LmRlYnVnJiZjb25zb2xlLmxvZyhgW0FOUiBXb3JrZXJdICR7dH1gKX12YXIgSnQsV3QsRnQ7Y29uc3QgR3Q9ZnVuY3Rpb24odCl7bGV0IGU7dHJ5e2U9bmV3IFVSTCh0LnVybCl9Y2F0Y2h7cmV0dXJuIGIoKCk9Pntjb25zb2xlLndhcm4oIltAc2VudHJ5L25vZGVdOiBJbnZhbGlkIGRzbiBvciB0dW5uZWwgb3B0aW9uLCB3aWxsIG5vdCBzZW5kIGFueSBldmVudHMuIFRoZSB0dW5uZWwgb3B0aW9uIG11c3QgYmUgYSBmdWxsIFVSTCB3aGVuIHVzZWQuIil9KSwkdCh0LCgpPT5Qcm9taXNlLnJlc29sdmUoe30pKX1jb25zdCBuPSJodHRwczoiPT09ZS5wcm90b2NvbCxyPWZ1bmN0aW9uKHQsZSl7Y29uc3R7bm9fcHJveHk6bn09cHJvY2Vzcy5lbnYscj1uPy5zcGxpdCgiLCIpLnNvbWUoZT0+dC5ob3N0LmVuZHNXaXRoKGUpfHx0Lmhvc3RuYW1lLmVuZHNXaXRoKGUpKTtyZXR1cm4gcj92b2lkIDA6ZX0oZSx0LnByb3h5fHwobj9wcm9jZXNzLmVudi5odHRwc19wcm94eTp2b2lkIDApfHxwcm9jZXNzLmVudi5odHRwX3Byb3h5KSxvPW4/aTpzLGE9dC5rZWVwQWxpdmU/PyEwLGY9cj9uZXcga3Qocik6bmV3IG8uQWdlbnQoe2tlZXBBbGl2ZTphLG1heFNvY2tldHM6MzAsdGltZW91dDoyZTN9KSxoPWZ1bmN0aW9uKHQsZSxuKXtjb25zdHtob3N0bmFtZTpyLHBhdGhuYW1lOm8scG9ydDpzLHByb3RvY29sOmksc2VhcmNoOmF9PW5ldyBVUkwodC51cmwpO3JldHVybiBmdW5jdGlvbihmKXtjb25zdCBoPXA9Pm5ldyBQcm9taXNlKChsLGQpPT57eXQoKCk9PntsZXQgZz1mdW5jdGlvbih0KXtyZXR1cm4gbmV3IGMoe3JlYWQoKXt0aGlzLnB1c2godCksdGhpcy5wdXNoKG51bGwpfX0pfShmLmJvZHkpO2NvbnN0IG09ey4uLnQuaGVhZGVyc307Zi5ib2R5Lmxlbmd0aD4zMjc2OCYmKG1bImNvbnRlbnQtZW5jb2RpbmciXT0iZ3ppcCIsZz1nLnBpcGUodSgpKSk7Y29uc3QgeT1yLnN0YXJ0c1dpdGgoIlsiKSxiPWUucmVxdWVzdCh7bWV0aG9kOiJQT1NUIixhZ2VudDpuLGhlYWRlcnM6bSxob3N0bmFtZTp5P3Iuc2xpY2UoMSwtMSk6cixwYXRoOmAke299JHthfWAscG9ydDpzLHByb3RvY29sOmksY2E6dC5jYUNlcnRzfSx0PT57dC5vbigiZGF0YSIsKCk9Pnt9KSx0Lm9uKCJlbmQiLCgpPT57fSksdC5zZXRFbmNvZGluZygidXRmOCIpO2NvbnN0IGU9dC5oZWFkZXJzWyJyZXRyeS1hZnRlciJdPz9udWxsLG49dC5oZWFkZXJzWyJ4LXNlbnRyeS1yYXRlLWxpbWl0cyJdPz9udWxsO2woe3N0YXR1c0NvZGU6dC5zdGF0dXNDb2RlLGhlYWRlcnM6eyJyZXRyeS1hZnRlciI6ZSwieC1zZW50cnktcmF0ZS1saW1pdHMiOkFycmF5LmlzQXJyYXkobik/blswXXx8bnVsbDpufX0pfSk7Yi5vbigiZXJyb3IiLHQ9PntwJiZiLnJldXNlZFNvY2tldCYmIkVDT05OUkVTRVQiPT09dC5jb2RlP2woaCghMSkpOmQodCl9KSxnLnBpcGUoYil9KX0pO3JldHVybiBoKCEwKX19KHQsdC5odHRwTW9kdWxlPz9vLGYpO3JldHVybiAkdCh0LGgpfSh7dXJsOihKdD1VdC5kc24sV3Q9VXQudHVubmVsLEZ0PVV0LnNka01ldGFkYXRhLnNkayxXdHx8YCR7ZnVuY3Rpb24odCl7cmV0dXJuYCR7ZnVuY3Rpb24odCl7Y29uc3QgZT10LnByb3RvY29sP2Ake3QucHJvdG9jb2x9OmA6IiIsbj10LnBvcnQ/YDoke3QucG9ydH1gOiIiO3JldHVybmAke2V9Ly8ke3QuaG9zdH0ke259JHt0LnBhdGg/YC8ke3QucGF0aH1gOiIifS9hcGkvYH0odCl9JHt0LnByb2plY3RJZH0vZW52ZWxvcGUvYH0oSnQpfT8ke2Z1bmN0aW9uKHQsZSl7Y29uc3Qgbj17c2VudHJ5X3ZlcnNpb246IjcifTtyZXR1cm4gdC5wdWJsaWNLZXkmJihuLnNlbnRyeV9rZXk9dC5wdWJsaWNLZXkpLGUmJihuLnNlbnRyeV9jbGllbnQ9YCR7ZS5uYW1lfS8ke2UudmVyc2lvbn1gKSxuZXcgVVJMU2VhcmNoUGFyYW1zKG4pLnRvU3RyaW5nKCl9KEp0LEZ0KX1gKX0pO2FzeW5jIGZ1bmN0aW9uIFl0KCl7aWYoQnQpe3p0KCJTZW5kaW5nIGFibm9ybWFsIHNlc3Npb24iKSxaKEJ0LHtzdGF0dXM6ImFibm9ybWFsIixhYm5vcm1hbF9tZWNoYW5pc206ImFucl9mb3JlZ3JvdW5kIixyZWxlYXNlOlV0LnJlbGVhc2UsZW52aXJvbm1lbnQ6VXQuZW52aXJvbm1lbnR9KTtjb25zdCB0PWZ1bmN0aW9uKHQsZSxuLHIpe2NvbnN0IG89bXQobik7cmV0dXJuIGZ0KHtzZW50X2F0Om5ldyBEYXRlKEkoKSkudG9JU09TdHJpbmcoKSwuLi5vJiZ7c2RrOm99LC4uLiEhciYmZSYme2Rzbjp1dChlKX19LFsiYWdncmVnYXRlcyJpbiB0P1t7dHlwZToic2Vzc2lvbnMifSx0XTpbe3R5cGU6InNlc3Npb24ifSx0LnRvSlNPTigpXV0pfShCdCxVdC5kc24sVXQuc2RrTWV0YWRhdGEsVXQudHVubmVsKTt6dChKU09OLnN0cmluZ2lmeSh0KSksYXdhaXQgR3Quc2VuZCh0KTt0cnl7bj8ucG9zdE1lc3NhZ2UoInNlc3Npb24tZW5kZWQiKX1jYXRjaHt9fX1mdW5jdGlvbiBIdCh0KXtpZighdClyZXR1cm47Y29uc3QgZT1mdW5jdGlvbih0KXtpZighdC5sZW5ndGgpcmV0dXJuW107Y29uc3QgZT1BcnJheS5mcm9tKHQpO3JldHVybi9zZW50cnlXcmFwcGVkLy50ZXN0KEUoZSkuZnVuY3Rpb258fCIiKSYmZS5wb3AoKSxlLnJldmVyc2UoKSwkLnRlc3QoRShlKS5mdW5jdGlvbnx8IiIpJiYoZS5wb3AoKSwkLnRlc3QoRShlKS5mdW5jdGlvbnx8IiIpJiZlLnBvcCgpKSxlLnNsaWNlKDAsNTApLm1hcCh0PT4oey4uLnQsZmlsZW5hbWU6dC5maWxlbmFtZXx8RShlKS5maWxlbmFtZSxmdW5jdGlvbjp0LmZ1bmN0aW9ufHwiPyJ9KSl9KHQpO2lmKFV0LmFwcFJvb3RQYXRoKWZvcihjb25zdCB0IG9mIGUpdC5maWxlbmFtZSYmKHQuZmlsZW5hbWU9TSh0LmZpbGVuYW1lLFV0LmFwcFJvb3RQYXRoKSk7cmV0dXJuIGV9YXN5bmMgZnVuY3Rpb24gWnQodCxlKXtpZihMdD49VXQubWF4QW5yRXZlbnRzKXJldHVybjtMdCs9MSxhd2FpdCBZdCgpLHp0KCJTZW5kaW5nIGV2ZW50Iik7Y29uc3Qgbj17ZXZlbnRfaWQ6VygpLGNvbnRleHRzOlV0LmNvbnRleHRzLHJlbGVhc2U6VXQucmVsZWFzZSxlbnZpcm9ubWVudDpVdC5lbnZpcm9ubWVudCxkaXN0OlV0LmRpc3QscGxhdGZvcm06Im5vZGUiLGxldmVsOiJlcnJvciIsZXhjZXB0aW9uOnt2YWx1ZXM6W3t0eXBlOiJBcHBsaWNhdGlvbk5vdFJlc3BvbmRpbmciLHZhbHVlOmBBcHBsaWNhdGlvbiBOb3QgUmVzcG9uZGluZyBmb3IgYXQgbGVhc3QgJHtVdC5hbnJUaHJlc2hvbGR9IG1zYCxzdGFja3RyYWNlOntmcmFtZXM6SHQodCl9LG1lY2hhbmlzbTp7dHlwZToiQU5SIn19XX0sdGFnczpVdC5zdGF0aWNUYWdzfTtlJiZmdW5jdGlvbih0LGUpe2lmKGF0KHQsZSksIXQuY29udGV4dHM/LnRyYWNlKXtjb25zdHt0cmFjZUlkOm4scGFyZW50U3BhbklkOnIscHJvcGFnYXRpb25TcGFuSWQ6b309ZS5wcm9wYWdhdGlvbkNvbnRleHQ7dC5jb250ZXh0cz17dHJhY2U6e3RyYWNlX2lkOm4sc3Bhbl9pZDpvfHxXKCkuc3Vic3RyaW5nKDE2KSxwYXJlbnRfc3Bhbl9pZDpyfSwuLi50LmNvbnRleHRzfX19KG4sZSksZnVuY3Rpb24odCl7aWYoMD09PU9iamVjdC5rZXlzKE10KS5sZW5ndGgpcmV0dXJuO2NvbnN0IGU9VXQuYXBwUm9vdFBhdGg/e306TXQ7aWYoVXQuYXBwUm9vdFBhdGgpZm9yKGNvbnN0W3Qsbl1vZiBPYmplY3QuZW50cmllcyhNdCkpZVtNKHQsVXQuYXBwUm9vdFBhdGgpXT1uO2NvbnN0IG49bmV3IE1hcDtmb3IoY29uc3QgciBvZiB0LmV4Y2VwdGlvbj8udmFsdWVzfHxbXSlmb3IoY29uc3QgdCBvZiByLnN0YWNrdHJhY2U/LmZyYW1lc3x8W10pe2NvbnN0IHI9dC5hYnNfcGF0aHx8dC5maWxlbmFtZTtyJiZlW3JdJiZuLnNldChyLGVbcl0pfWlmKG4uc2l6ZT4wKXtjb25zdCBlPVtdO2Zvcihjb25zdFt0LHJdb2Ygbi5lbnRyaWVzKCkpZS5wdXNoKHt0eXBlOiJzb3VyY2VtYXAiLGNvZGVfZmlsZTp0LGRlYnVnX2lkOnJ9KTt0LmRlYnVnX21ldGE9e2ltYWdlczplfX19KG4pO2NvbnN0IHI9YnQobixVdC5kc24sVXQuc2RrTWV0YWRhdGEsVXQudHVubmVsKTt6dChKU09OLnN0cmluZ2lmeShyKSksYXdhaXQgR3Quc2VuZChyKSxhd2FpdCBHdC5mbHVzaCgyZTMpLEx0Pj1VdC5tYXhBbnJFdmVudHMmJnNldFRpbWVvdXQoKCk9Pntwcm9jZXNzLmV4aXQoMCl9LDVlMyl9bGV0IHF0O2lmKHp0KCJTdGFydGVkIiksVXQuY2FwdHVyZVN0YWNrVHJhY2Upe3p0KCJDb25uZWN0aW5nIHRvIGRlYnVnZ2VyIik7Y29uc3QgZT1uZXcgdDtlLmNvbm5lY3RUb01haW5UaHJlYWQoKSx6dCgiQ29ubmVjdGVkIHRvIGRlYnVnZ2VyIik7Y29uc3Qgbj1uZXcgTWFwO2Uub24oIkRlYnVnZ2VyLnNjcmlwdFBhcnNlZCIsdD0+e24uc2V0KHQucGFyYW1zLnNjcmlwdElkLHQucGFyYW1zLnVybCl9KSxlLm9uKCJEZWJ1Z2dlci5wYXVzZWQiLHQ9PntpZigib3RoZXIiPT09dC5wYXJhbXMucmVhc29uKXRyeXt6dCgiRGVidWdnZXIgcGF1c2VkIik7Y29uc3Qgcz1bLi4udC5wYXJhbXMuY2FsbEZyYW1lc10saT1VdC5hcHBSb290UGF0aD9mdW5jdGlvbih0PShwcm9jZXNzLmFyZ3ZbMV0/eHQocHJvY2Vzcy5hcmd2WzFdKTpwcm9jZXNzLmN3ZCgpKSxlPSJcXCI9PT1vKXtjb25zdCBuPWU/RHQodCk6dDtyZXR1cm4gdD0+e2lmKCF0KXJldHVybjtjb25zdCBvPWU/RHQodCk6dDtsZXR7ZGlyOnMsYmFzZTppLGV4dDpjfT1yLnBhcnNlKG8pOyIuanMiIT09YyYmIi5tanMiIT09YyYmIi5janMiIT09Y3x8KGk9aS5zbGljZSgwLC0xKmMubGVuZ3RoKSk7Y29uc3QgdT1kZWNvZGVVUklDb21wb25lbnQoaSk7c3x8KHM9Ii4iKTtjb25zdCBhPXMubGFzdEluZGV4T2YoIi9ub2RlX21vZHVsZXMiKTtpZihhPi0xKXJldHVybmAke3Muc2xpY2UoYSsxNCkucmVwbGFjZSgvXC8vZywiLiIpfToke3V9YDtpZihzLnN0YXJ0c1dpdGgobikpe2NvbnN0IHQ9cy5zbGljZShuLmxlbmd0aCsxKS5yZXBsYWNlKC9cLy9nLCIuIik7cmV0dXJuIHQ/YCR7dH06JHt1fWA6dX1yZXR1cm4gdX19KFV0LmFwcFJvb3RQYXRoKTooKT0+e30sYz1zLm1hcCh0PT5mdW5jdGlvbih0LGUsbil7Y29uc3Qgcj1lP2UucmVwbGFjZSgvXmZpbGU6XC9cLy8sIiIpOnZvaWQgMCxvPXQubG9jYXRpb24uY29sdW1uTnVtYmVyP3QubG9jYXRpb24uY29sdW1uTnVtYmVyKzE6dm9pZCAwLHM9dC5sb2NhdGlvbi5saW5lTnVtYmVyP3QubG9jYXRpb24ubGluZU51bWJlcisxOnZvaWQgMDtyZXR1cm57ZmlsZW5hbWU6cixtb2R1bGU6bihyKSxmdW5jdGlvbjp0LmZ1bmN0aW9uTmFtZXx8Ij8iLGNvbG5vOm8sbGluZW5vOnMsaW5fYXBwOnI/TnQocik6dm9pZCAwfX0odCxuLmdldCh0LmxvY2F0aW9uLnNjcmlwdElkKSxpKSksdT1zZXRUaW1lb3V0KCgpPT57WnQoYykudGhlbihudWxsLCgpPT57enQoIlNlbmRpbmcgQU5SIGV2ZW50IGZhaWxlZC4iKX0pfSw1ZTMpO2UucG9zdCgiUnVudGltZS5ldmFsdWF0ZSIse2V4cHJlc3Npb246Imdsb2JhbC5fX1NFTlRSWV9HRVRfU0NPUEVTX18oKTsiLHNpbGVudDohMCxyZXR1cm5CeVZhbHVlOiEwfSwodCxuKT0+e3QmJnp0KGBFcnJvciBleGVjdXRpbmcgc2NyaXB0OiAnJHt0Lm1lc3NhZ2V9J2ApLGNsZWFyVGltZW91dCh1KTtjb25zdCByPW4/LnJlc3VsdD9uLnJlc3VsdC52YWx1ZTp2b2lkIDA7ZS5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKSxlLnBvc3QoIkRlYnVnZ2VyLmRpc2FibGUiKSxadChjLHIpLnRoZW4obnVsbCwoKT0+e3p0KCJTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQuIil9KX0pfWNhdGNoKHQpe3Rocm93IGUucG9zdCgiRGVidWdnZXIucmVzdW1lIiksZS5wb3N0KCJEZWJ1Z2dlci5kaXNhYmxlIiksdH19KSxxdD0oKT0+e3RyeXtlLnBvc3QoIkRlYnVnZ2VyLmVuYWJsZSIsKCk9PntlLnBvc3QoIkRlYnVnZ2VyLnBhdXNlIil9KX1jYXRjaHt9fX1jb25zdHtwb2xsOkt0fT1mdW5jdGlvbih0LGUsbixyKXtjb25zdCBvPXQoKTtsZXQgcz0hMSxpPSEwO3JldHVybiBzZXRJbnRlcnZhbCgoKT0+e2NvbnN0IHQ9by5nZXRUaW1lTXMoKTshMT09PXMmJnQ+ZStuJiYocz0hMCxpJiZyKCkpLHQ8ZStuJiYocz0hMSl9LDIwKSx7cG9sbDooKT0+e28ucmVzZXQoKX0sZW5hYmxlZDp0PT57aT10fX19KGZ1bmN0aW9uKCl7bGV0IHQ9cHJvY2Vzcy5ocnRpbWUoKTtyZXR1cm57Z2V0VGltZU1zOigpPT57Y29uc3RbZSxuXT1wcm9jZXNzLmhydGltZSh0KTtyZXR1cm4gTWF0aC5mbG9vcigxZTMqZStuLzFlNil9LHJlc2V0OigpPT57dD1wcm9jZXNzLmhydGltZSgpfX19LFV0LnBvbGxJbnRlcnZhbCxVdC5hbnJUaHJlc2hvbGQsZnVuY3Rpb24oKXt6dCgiV2F0Y2hkb2cgdGltZW91dCIpLHF0Pyh6dCgiUGF1c2luZyBkZWJ1Z2dlciB0byBjYXB0dXJlIHN0YWNrIHRyYWNlIikscXQoKSk6KHp0KCJDYXB0dXJpbmcgZXZlbnQgd2l0aG91dCBhIHN0YWNrIHRyYWNlIiksWnQoKS50aGVuKG51bGwsKCk9Pnt6dCgiU2VuZGluZyBBTlIgZXZlbnQgZmFpbGVkIG9uIHdhdGNoZG9nIHRpbWVvdXQuIil9KSl9KTtuPy5vbigibWVzc2FnZSIsdD0+e3Quc2Vzc2lvbiYmKEJ0PUgodC5zZXNzaW9uKSksdC5kZWJ1Z0ltYWdlcyYmKE10PXQuZGVidWdJbWFnZXMpLEt0KCl9KTs=";
10
10
  const DEFAULT_INTERVAL = 50;
11
11
  const DEFAULT_HANG_THRESHOLD = 5e3;
12
12
  function log(message, ...args) {
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const attributes = require('@sentry/conventions/attributes');
4
+ const op = require('@sentry/conventions/op');
4
5
  const core = require('@sentry/core');
5
6
  const fs = require('fs');
6
7
  const util = require('util');
@@ -8,7 +9,7 @@ const constants = require('./constants.js');
8
9
  const utils = require('./utils.js');
9
10
 
10
11
  const SPAN_ORIGIN = "auto.file.fs";
11
- const SPAN_OP = "file";
12
+ const SPAN_OP = op.FILE;
12
13
  const FS_OPERATIONS_WITH_OLD_PATH_NEW_PATH = ["rename", "renameSync"];
13
14
  const FS_OPERATIONS_WITH_SRC_DEST = ["copyFile", "cp", "copyFileSync", "cpSync"];
14
15
  const FS_OPERATIONS_WITH_EXISTING_PATH_NEW_PATH = ["link", "linkSync"];
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.js","sources":["../../../../../src/integrations/fs/vendored/instrumentation.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n *\n * NOTICE from the Sentry authors:\n * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/15ef7506553f631ea4181391e0c5725a56f0d082/packages/instrumentation-fs\n * - Upstream version: @opentelemetry/instrumentation-fs@0.37.0\n * - Minor TypeScript strictness adjustments for this repository's compiler settings\n * - The OpenTelemetry tracer APIs were replaced with Sentry's `startSpan`/`startInactiveSpan`/`suppressTracing`\n * and the configurable `createHook`/`endHook`/`requireParentSpan` options were removed in favor of inlined,\n * Sentry-specific span attributes.\n * - Completely reworked to no longer reference OpenTelemetry.\n * - The upstream `fs_error` span attribute (the error message) was replaced with the conventions-backed\n * `error.type` (the syscall error code, e.g. `ENOENT`).\n */\n\nimport { ERROR_TYPE } from '@sentry/conventions/attributes';\nimport type { Span, SpanAttributes } from '@sentry/core';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n getActiveSpan,\n startInactiveSpan,\n startSpan,\n suppressTracing,\n withActiveSpan,\n} from '@sentry/core';\nimport * as fs from 'fs';\nimport { promisify } from 'util';\nimport { CALLBACK_FUNCTIONS, PROMISE_FUNCTIONS, SYNC_FUNCTIONS } from './constants';\nimport type { FMember, FPMember, FsInstrumentationConfig, GenericFunction } from './types';\nimport { indexFs } from './utils';\n\nconst SPAN_ORIGIN = 'auto.file.fs';\nconst SPAN_OP = 'file';\n\n// The following lists categorize `fs` functions by the shape of their leading path arguments, so we can\n// record meaningful span attributes for them. These are Sentry-specific additions (not part of upstream).\nconst FS_OPERATIONS_WITH_OLD_PATH_NEW_PATH = ['rename', 'renameSync'];\nconst FS_OPERATIONS_WITH_SRC_DEST = ['copyFile', 'cp', 'copyFileSync', 'cpSync'];\nconst FS_OPERATIONS_WITH_EXISTING_PATH_NEW_PATH = ['link', 'linkSync'];\nconst FS_OPERATIONS_WITH_PREFIX = ['mkdtemp', 'mkdtempSync'];\nconst FS_OPERATIONS_WITH_TARGET_PATH = ['symlink', 'symlinkSync'];\nconst FS_OPERATIONS_WITH_PATH_ARG = [\n 'access',\n 'appendFile',\n 'chmod',\n 'chown',\n 'exists',\n 'mkdir',\n 'lchown',\n 'lstat',\n 'lutimes',\n 'open',\n 'opendir',\n 'readdir',\n 'readFile',\n 'readlink',\n 'realpath',\n 'realpath.native',\n 'rm',\n 'rmdir',\n 'stat',\n 'truncate',\n 'unlink',\n 'utimes',\n 'writeFile',\n 'accessSync',\n 'appendFileSync',\n 'chmodSync',\n 'chownSync',\n 'existsSync',\n 'lchownSync',\n 'lstatSync',\n 'lutimesSync',\n 'opendirSync',\n 'mkdirSync',\n 'openSync',\n 'readdirSync',\n 'readFileSync',\n 'readlinkSync',\n 'realpathSync',\n 'realpathSync.native',\n 'rmdirSync',\n 'rmSync',\n 'statSync',\n 'truncateSync',\n 'unlinkSync',\n 'utimesSync',\n 'writeFileSync',\n];\n\n/**\n * Builds the span attributes for a given `fs` operation, optionally including the file path arguments.\n */\nfunction getSpanAttributes(\n functionName: FMember | FPMember,\n args: ArrayLike<unknown>,\n config: FsInstrumentationConfig,\n): SpanAttributes {\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: SPAN_OP,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: SPAN_ORIGIN,\n };\n\n if (!config.recordFilePaths) {\n return attributes;\n }\n\n if (typeof args[0] === 'string' && FS_OPERATIONS_WITH_PATH_ARG.includes(functionName)) {\n attributes['path_argument'] = args[0];\n } else if (typeof args[0] === 'string' && typeof args[1] === 'string') {\n if (FS_OPERATIONS_WITH_TARGET_PATH.includes(functionName)) {\n attributes['target_argument'] = args[0];\n attributes['path_argument'] = args[1];\n } else if (FS_OPERATIONS_WITH_EXISTING_PATH_NEW_PATH.includes(functionName)) {\n attributes['existing_path_argument'] = args[0];\n attributes['new_path_argument'] = args[1];\n } else if (FS_OPERATIONS_WITH_SRC_DEST.includes(functionName)) {\n attributes['src_argument'] = args[0];\n attributes['dest_argument'] = args[1];\n } else if (FS_OPERATIONS_WITH_OLD_PATH_NEW_PATH.includes(functionName)) {\n attributes['old_path_argument'] = args[0];\n attributes['new_path_argument'] = args[1];\n }\n } else if (typeof args[0] === 'string' && FS_OPERATIONS_WITH_PREFIX.includes(functionName)) {\n attributes['prefix_argument'] = args[0];\n }\n\n return attributes;\n}\n\n/**\n * This is important for 2-level functions like `realpath.native` to retain the 2nd-level\n * when patching the 1st-level.\n */\nfunction patchedFunctionWithOriginalProperties<T extends GenericFunction>(patchedFunction: T, original: T): T {\n return Object.assign(patchedFunction, original);\n}\n\n// Tracks patched methods to prevent double-patching if `enableFsInstrumentation` is called more than once.\nconst _patched = new WeakMap<Record<string, GenericFunction>, Set<string>>();\n\nfunction _patchMethod(\n obj: Record<string, GenericFunction>,\n name: string,\n wrapper: (original: GenericFunction) => GenericFunction,\n): void {\n const original = obj[name];\n if (typeof original !== 'function') return;\n let patched = _patched.get(obj);\n if (!patched) {\n patched = new Set();\n _patched.set(obj, patched);\n }\n if (patched.has(name)) return;\n patched.add(name);\n obj[name] = wrapper(original);\n}\n\nfunction _patchSyncFunction<T extends GenericFunction>(\n functionName: FMember,\n original: T,\n config: FsInstrumentationConfig,\n): T {\n const patchedFunction = function (this: unknown, ...args: Parameters<T>): ReturnType<T> {\n const attributes = getSpanAttributes(functionName, args, config);\n return startSpan({ name: `fs.${functionName}`, onlyIfParent: true, attributes }, span => {\n try {\n return suppressTracing(() => original.apply(this, args)) as ReturnType<T>;\n } catch (error) {\n recordError(span, error, config);\n throw error;\n }\n });\n };\n return patchedFunctionWithOriginalProperties(patchedFunction as T, original);\n}\n\nfunction _patchCallbackFunction<T extends GenericFunction>(\n functionName: FMember,\n original: T,\n config: FsInstrumentationConfig,\n): T {\n const patchedFunction = function (this: unknown, ...args: Parameters<T>): ReturnType<T> {\n const lastIdx = args.length - 1;\n const cb: unknown = args[lastIdx];\n if (typeof cb !== 'function') {\n return original.apply(this, args) as ReturnType<T>;\n }\n\n const attributes = getSpanAttributes(functionName, args, config);\n const span = startInactiveSpan({ name: `fs.${functionName}`, onlyIfParent: true, attributes });\n const parentSpan = getActiveSpan();\n\n // Wrap the callback to end the span and restore the caller's active span context.\n // fs callbacks fire from Node's I/O event loop where the AsyncLocalStorage context\n // is lost, so any spans created inside the callback would otherwise have no parent.\n args[lastIdx] = function (this: unknown, ...cbArgs: unknown[]) {\n const error = cbArgs[0];\n if (error) {\n recordError(span, error, config);\n }\n span.end();\n if (parentSpan) {\n return withActiveSpan(parentSpan, () => (cb as GenericFunction).apply(this, cbArgs));\n }\n return (cb as GenericFunction).apply(this, cbArgs);\n };\n\n try {\n return suppressTracing(() => original.apply(this, args)) as ReturnType<T>;\n } catch (error) {\n recordError(span, error, config);\n span.end();\n throw error;\n }\n };\n return patchedFunctionWithOriginalProperties(patchedFunction as T, original);\n}\n\nfunction _patchExistsCallbackFunction<T extends GenericFunction>(original: T, config: FsInstrumentationConfig): T {\n const functionName = 'exists' as FMember;\n const patchedFunction = function (this: unknown, ...args: Parameters<T>): ReturnType<T> {\n const lastIdx = args.length - 1;\n const cb: unknown = args[lastIdx];\n if (typeof cb !== 'function') {\n return original.apply(this, args) as ReturnType<T>;\n }\n\n const attributes = getSpanAttributes(functionName, args, config);\n const span = startInactiveSpan({ name: `fs.${functionName}`, onlyIfParent: true, attributes });\n const parentSpan = getActiveSpan();\n\n // `exists` never calls the callback with an error\n args[lastIdx] = function (this: unknown, ...cbArgs: unknown[]) {\n span.end();\n if (parentSpan) {\n return withActiveSpan(parentSpan, () => (cb as GenericFunction).apply(this, cbArgs));\n }\n return (cb as GenericFunction).apply(this, cbArgs);\n };\n\n try {\n return suppressTracing(() => original.apply(this, args)) as ReturnType<T>;\n } catch (error) {\n recordError(span, error, config);\n span.end();\n throw error;\n }\n };\n const functionWithOriginalProperties = patchedFunctionWithOriginalProperties(patchedFunction as T, original);\n\n // `exists` has a custom promisify function because of the inconsistent signature\n // replicating that on the patched function\n const promisified = function (path: unknown): Promise<unknown> {\n return new Promise(resolve => (functionWithOriginalProperties as GenericFunction)(path, resolve));\n };\n Object.defineProperty(promisified, 'name', { value: functionName });\n Object.defineProperty(functionWithOriginalProperties, promisify.custom, {\n value: promisified,\n });\n\n return functionWithOriginalProperties;\n}\n\nfunction _patchPromiseFunction<T extends GenericFunction>(\n functionName: FPMember,\n original: T,\n config: FsInstrumentationConfig,\n): T {\n const patchedFunction = async function (this: unknown, ...args: Parameters<T>): Promise<unknown> {\n const attributes = getSpanAttributes(functionName, args, config);\n return startSpan({ name: `fs.${functionName}`, onlyIfParent: true, attributes }, async span => {\n try {\n return await suppressTracing(() => original.apply(this, args) as Promise<unknown>);\n } catch (error) {\n recordError(span, error, config);\n throw error;\n }\n });\n };\n return patchedFunctionWithOriginalProperties(patchedFunction as unknown as T, original);\n}\n\nexport function enableFsInstrumentation(config: FsInstrumentationConfig = {}): void {\n for (const fName of SYNC_FUNCTIONS) {\n const { objectToPatch, functionNameToPatch } = indexFs(fs, fName);\n _patchMethod(objectToPatch, functionNameToPatch, original => _patchSyncFunction(fName, original, config));\n }\n\n for (const fName of CALLBACK_FUNCTIONS) {\n const { objectToPatch, functionNameToPatch } = indexFs(fs, fName);\n if (fName === 'exists') {\n _patchMethod(objectToPatch, functionNameToPatch, original => _patchExistsCallbackFunction(original, config));\n } else {\n _patchMethod(objectToPatch, functionNameToPatch, original => _patchCallbackFunction(fName, original, config));\n }\n }\n\n // `fs.promises` and `import { readFile } from 'fs/promises'` share the same object in Node 14+,\n // so patching one covers both.\n const fsPromises = fs.promises as unknown as Record<string, GenericFunction>;\n for (const fName of PROMISE_FUNCTIONS) {\n _patchMethod(fsPromises, fName, original => _patchPromiseFunction(fName, original, config));\n }\n}\n\n/**\n * Sets the error status on the span and, if configured, records the error type as a span attribute.\n */\nfunction recordError(span: Span, error: unknown, config: FsInstrumentationConfig): void {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n if (config.recordErrorMessagesAsSpanAttributes && error instanceof Error) {\n span.setAttribute(ERROR_TYPE, (error as NodeJS.ErrnoException).code ?? error.name);\n }\n}\n"],"names":["SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","startSpan","suppressTracing","startInactiveSpan","getActiveSpan","withActiveSpan","promisify","SYNC_FUNCTIONS","indexFs","CALLBACK_FUNCTIONS","PROMISE_FUNCTIONS","SPAN_STATUS_ERROR","ERROR_TYPE"],"mappings":";;;;;;;;;AAkCA,MAAM,WAAA,GAAc,cAAA;AACpB,MAAM,OAAA,GAAU,MAAA;AAIhB,MAAM,oCAAA,GAAuC,CAAC,QAAA,EAAU,YAAY,CAAA;AACpE,MAAM,2BAAA,GAA8B,CAAC,UAAA,EAAY,IAAA,EAAM,gBAAgB,QAAQ,CAAA;AAC/E,MAAM,yCAAA,GAA4C,CAAC,MAAA,EAAQ,UAAU,CAAA;AACrE,MAAM,yBAAA,GAA4B,CAAC,SAAA,EAAW,aAAa,CAAA;AAC3D,MAAM,8BAAA,GAAiC,CAAC,SAAA,EAAW,aAAa,CAAA;AAChE,MAAM,2BAAA,GAA8B;AAAA,EAClC,QAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,UAAA;AAAA,EACA,UAAA;AAAA,EACA,iBAAA;AAAA,EACA,IAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,gBAAA;AAAA,EACA,WAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,qBAAA;AAAA,EACA,WAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAAA;AAKA,SAAS,iBAAA,CACP,YAAA,EACA,IAAA,EACA,MAAA,EACgB;AAChB,EAAA,MAAM,UAAA,GAA6B;AAAA,IACjC,CAACA,iCAA4B,GAAG,OAAA;AAAA,IAChC,CAACC,qCAAgC,GAAG;AAAA,GACtC;AAEA,EAAA,IAAI,CAAC,OAAO,eAAA,EAAiB;AAC3B,IAAA,OAAO,UAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,KAAK,CAAC,CAAA,KAAM,YAAY,2BAAA,CAA4B,QAAA,CAAS,YAAY,CAAA,EAAG;AACrF,IAAA,UAAA,CAAW,eAAe,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAAA,EACtC,CAAA,MAAA,IAAW,OAAO,IAAA,CAAK,CAAC,CAAA,KAAM,YAAY,OAAO,IAAA,CAAK,CAAC,CAAA,KAAM,QAAA,EAAU;AACrE,IAAA,IAAI,8BAAA,CAA+B,QAAA,CAAS,YAAY,CAAA,EAAG;AACzD,MAAA,UAAA,CAAW,iBAAiB,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACtC,MAAA,UAAA,CAAW,eAAe,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAAA,IACtC,CAAA,MAAA,IAAW,yCAAA,CAA0C,QAAA,CAAS,YAAY,CAAA,EAAG;AAC3E,MAAA,UAAA,CAAW,wBAAwB,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAC7C,MAAA,UAAA,CAAW,mBAAmB,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAAA,IAC1C,CAAA,MAAA,IAAW,2BAAA,CAA4B,QAAA,CAAS,YAAY,CAAA,EAAG;AAC7D,MAAA,UAAA,CAAW,cAAc,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACnC,MAAA,UAAA,CAAW,eAAe,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAAA,IACtC,CAAA,MAAA,IAAW,oCAAA,CAAqC,QAAA,CAAS,YAAY,CAAA,EAAG;AACtE,MAAA,UAAA,CAAW,mBAAmB,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACxC,MAAA,UAAA,CAAW,mBAAmB,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAAA,IAC1C;AAAA,EACF,CAAA,MAAA,IAAW,OAAO,IAAA,CAAK,CAAC,MAAM,QAAA,IAAY,yBAAA,CAA0B,QAAA,CAAS,YAAY,CAAA,EAAG;AAC1F,IAAA,UAAA,CAAW,iBAAiB,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AAAA,EACxC;AAEA,EAAA,OAAO,UAAA;AACT;AAMA,SAAS,qCAAA,CAAiE,iBAAoB,QAAA,EAAgB;AAC5G,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,eAAA,EAAiB,QAAQ,CAAA;AAChD;AAGA,MAAM,QAAA,uBAAe,OAAA,EAAsD;AAE3E,SAAS,YAAA,CACP,GAAA,EACA,IAAA,EACA,OAAA,EACM;AACN,EAAA,MAAM,QAAA,GAAW,IAAI,IAAI,CAAA;AACzB,EAAA,IAAI,OAAO,aAAa,UAAA,EAAY;AACpC,EAAA,IAAI,OAAA,GAAU,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA;AAC9B,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAA,uBAAc,GAAA,EAAI;AAClB,IAAA,QAAA,CAAS,GAAA,CAAI,KAAK,OAAO,CAAA;AAAA,EAC3B;AACA,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA,EAAG;AACvB,EAAA,OAAA,CAAQ,IAAI,IAAI,CAAA;AAChB,EAAA,GAAA,CAAI,IAAI,CAAA,GAAI,OAAA,CAAQ,QAAQ,CAAA;AAC9B;AAEA,SAAS,kBAAA,CACP,YAAA,EACA,QAAA,EACA,MAAA,EACG;AACH,EAAA,MAAM,eAAA,GAAkB,YAA4B,IAAA,EAAoC;AACtF,IAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,YAAA,EAAc,IAAA,EAAM,MAAM,CAAA;AAC/D,IAAA,OAAOC,cAAA,CAAU,EAAE,IAAA,EAAM,CAAA,GAAA,EAAM,YAAY,IAAI,YAAA,EAAc,IAAA,EAAM,UAAA,EAAW,EAAG,CAAA,IAAA,KAAQ;AACvF,MAAA,IAAI;AACF,QAAA,OAAOC,qBAAgB,MAAM,QAAA,CAAS,KAAA,CAAM,IAAA,EAAM,IAAI,CAAC,CAAA;AAAA,MACzD,SAAS,KAAA,EAAO;AACd,QAAA,WAAA,CAAY,IAAA,EAAM,OAAO,MAAM,CAAA;AAC/B,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA;AACA,EAAA,OAAO,qCAAA,CAAsC,iBAAsB,QAAQ,CAAA;AAC7E;AAEA,SAAS,sBAAA,CACP,YAAA,EACA,QAAA,EACA,MAAA,EACG;AACH,EAAA,MAAM,eAAA,GAAkB,YAA4B,IAAA,EAAoC;AACtF,IAAA,MAAM,OAAA,GAAU,KAAK,MAAA,GAAS,CAAA;AAC9B,IAAA,MAAM,EAAA,GAAc,KAAK,OAAO,CAAA;AAChC,IAAA,IAAI,OAAO,OAAO,UAAA,EAAY;AAC5B,MAAA,OAAO,QAAA,CAAS,KAAA,CAAM,IAAA,EAAM,IAAI,CAAA;AAAA,IAClC;AAEA,IAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,YAAA,EAAc,IAAA,EAAM,MAAM,CAAA;AAC/D,IAAA,MAAM,IAAA,GAAOC,sBAAA,CAAkB,EAAE,IAAA,EAAM,CAAA,GAAA,EAAM,YAAY,CAAA,CAAA,EAAI,YAAA,EAAc,IAAA,EAAM,UAAA,EAAY,CAAA;AAC7F,IAAA,MAAM,aAAaC,kBAAA,EAAc;AAKjC,IAAA,IAAA,CAAK,OAAO,CAAA,GAAI,SAAA,GAA4B,MAAA,EAAmB;AAC7D,MAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AACtB,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,WAAA,CAAY,IAAA,EAAM,OAAO,MAAM,CAAA;AAAA,MACjC;AACA,MAAA,IAAA,CAAK,GAAA,EAAI;AACT,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,OAAOC,oBAAe,UAAA,EAAY,MAAO,GAAuB,KAAA,CAAM,IAAA,EAAM,MAAM,CAAC,CAAA;AAAA,MACrF;AACA,MAAA,OAAQ,EAAA,CAAuB,KAAA,CAAM,IAAA,EAAM,MAAM,CAAA;AAAA,IACnD,CAAA;AAEA,IAAA,IAAI;AACF,MAAA,OAAOH,qBAAgB,MAAM,QAAA,CAAS,KAAA,CAAM,IAAA,EAAM,IAAI,CAAC,CAAA;AAAA,IACzD,SAAS,KAAA,EAAO;AACd,MAAA,WAAA,CAAY,IAAA,EAAM,OAAO,MAAM,CAAA;AAC/B,MAAA,IAAA,CAAK,GAAA,EAAI;AACT,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF,CAAA;AACA,EAAA,OAAO,qCAAA,CAAsC,iBAAsB,QAAQ,CAAA;AAC7E;AAEA,SAAS,4BAAA,CAAwD,UAAa,MAAA,EAAoC;AAChH,EAAA,MAAM,YAAA,GAAe,QAAA;AACrB,EAAA,MAAM,eAAA,GAAkB,YAA4B,IAAA,EAAoC;AACtF,IAAA,MAAM,OAAA,GAAU,KAAK,MAAA,GAAS,CAAA;AAC9B,IAAA,MAAM,EAAA,GAAc,KAAK,OAAO,CAAA;AAChC,IAAA,IAAI,OAAO,OAAO,UAAA,EAAY;AAC5B,MAAA,OAAO,QAAA,CAAS,KAAA,CAAM,IAAA,EAAM,IAAI,CAAA;AAAA,IAClC;AAEA,IAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,YAAA,EAAc,IAAA,EAAM,MAAM,CAAA;AAC/D,IAAA,MAAM,IAAA,GAAOC,sBAAA,CAAkB,EAAE,IAAA,EAAM,CAAA,GAAA,EAAM,YAAY,CAAA,CAAA,EAAI,YAAA,EAAc,IAAA,EAAM,UAAA,EAAY,CAAA;AAC7F,IAAA,MAAM,aAAaC,kBAAA,EAAc;AAGjC,IAAA,IAAA,CAAK,OAAO,CAAA,GAAI,SAAA,GAA4B,MAAA,EAAmB;AAC7D,MAAA,IAAA,CAAK,GAAA,EAAI;AACT,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,OAAOC,oBAAe,UAAA,EAAY,MAAO,GAAuB,KAAA,CAAM,IAAA,EAAM,MAAM,CAAC,CAAA;AAAA,MACrF;AACA,MAAA,OAAQ,EAAA,CAAuB,KAAA,CAAM,IAAA,EAAM,MAAM,CAAA;AAAA,IACnD,CAAA;AAEA,IAAA,IAAI;AACF,MAAA,OAAOH,qBAAgB,MAAM,QAAA,CAAS,KAAA,CAAM,IAAA,EAAM,IAAI,CAAC,CAAA;AAAA,IACzD,SAAS,KAAA,EAAO;AACd,MAAA,WAAA,CAAY,IAAA,EAAM,OAAO,MAAM,CAAA;AAC/B,MAAA,IAAA,CAAK,GAAA,EAAI;AACT,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF,CAAA;AACA,EAAA,MAAM,8BAAA,GAAiC,qCAAA,CAAsC,eAAA,EAAsB,QAAQ,CAAA;AAI3G,EAAA,MAAM,WAAA,GAAc,SAAU,IAAA,EAAiC;AAC7D,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAY,8BAAA,CAAmD,IAAA,EAAM,OAAO,CAAC,CAAA;AAAA,EAClG,CAAA;AACA,EAAA,MAAA,CAAO,eAAe,WAAA,EAAa,MAAA,EAAQ,EAAE,KAAA,EAAO,cAAc,CAAA;AAClE,EAAA,MAAA,CAAO,cAAA,CAAe,8BAAA,EAAgCI,cAAA,CAAU,MAAA,EAAQ;AAAA,IACtE,KAAA,EAAO;AAAA,GACR,CAAA;AAED,EAAA,OAAO,8BAAA;AACT;AAEA,SAAS,qBAAA,CACP,YAAA,EACA,QAAA,EACA,MAAA,EACG;AACH,EAAA,MAAM,eAAA,GAAkB,kBAAkC,IAAA,EAAuC;AAC/F,IAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,YAAA,EAAc,IAAA,EAAM,MAAM,CAAA;AAC/D,IAAA,OAAOL,cAAA,CAAU,EAAE,IAAA,EAAM,CAAA,GAAA,EAAM,YAAY,CAAA,CAAA,EAAI,YAAA,EAAc,IAAA,EAAM,UAAA,EAAW,EAAG,OAAM,IAAA,KAAQ;AAC7F,MAAA,IAAI;AACF,QAAA,OAAO,MAAMC,oBAAA,CAAgB,MAAM,SAAS,KAAA,CAAM,IAAA,EAAM,IAAI,CAAqB,CAAA;AAAA,MACnF,SAAS,KAAA,EAAO;AACd,QAAA,WAAA,CAAY,IAAA,EAAM,OAAO,MAAM,CAAA;AAC/B,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA;AACA,EAAA,OAAO,qCAAA,CAAsC,iBAAiC,QAAQ,CAAA;AACxF;AAEO,SAAS,uBAAA,CAAwB,MAAA,GAAkC,EAAC,EAAS;AAClF,EAAA,KAAA,MAAW,SAASK,wBAAA,EAAgB;AAClC,IAAA,MAAM,EAAE,aAAA,EAAe,mBAAA,EAAoB,GAAIC,aAAA,CAAQ,IAAI,KAAK,CAAA;AAChE,IAAA,YAAA,CAAa,eAAe,mBAAA,EAAqB,CAAA,QAAA,KAAY,mBAAmB,KAAA,EAAO,QAAA,EAAU,MAAM,CAAC,CAAA;AAAA,EAC1G;AAEA,EAAA,KAAA,MAAW,SAASC,4BAAA,EAAoB;AACtC,IAAA,MAAM,EAAE,aAAA,EAAe,mBAAA,EAAoB,GAAID,aAAA,CAAQ,IAAI,KAAK,CAAA;AAChE,IAAA,IAAI,UAAU,QAAA,EAAU;AACtB,MAAA,YAAA,CAAa,eAAe,mBAAA,EAAqB,CAAA,QAAA,KAAY,4BAAA,CAA6B,QAAA,EAAU,MAAM,CAAC,CAAA;AAAA,IAC7G,CAAA,MAAO;AACL,MAAA,YAAA,CAAa,eAAe,mBAAA,EAAqB,CAAA,QAAA,KAAY,uBAAuB,KAAA,EAAO,QAAA,EAAU,MAAM,CAAC,CAAA;AAAA,IAC9G;AAAA,EACF;AAIA,EAAA,MAAM,aAAa,EAAA,CAAG,QAAA;AACtB,EAAA,KAAA,MAAW,SAASE,2BAAA,EAAmB;AACrC,IAAA,YAAA,CAAa,YAAY,KAAA,EAAO,CAAA,QAAA,KAAY,sBAAsB,KAAA,EAAO,QAAA,EAAU,MAAM,CAAC,CAAA;AAAA,EAC5F;AACF;AAKA,SAAS,WAAA,CAAY,IAAA,EAAY,KAAA,EAAgB,MAAA,EAAuC;AACtF,EAAA,IAAA,CAAK,UAAU,EAAE,IAAA,EAAMC,sBAAA,EAAmB,OAAA,EAAS,kBAAkB,CAAA;AACrE,EAAA,IAAI,MAAA,CAAO,mCAAA,IAAuC,KAAA,YAAiB,KAAA,EAAO;AACxE,IAAA,IAAA,CAAK,YAAA,CAAaC,qBAAA,EAAa,KAAA,CAAgC,IAAA,IAAQ,MAAM,IAAI,CAAA;AAAA,EACnF;AACF;;;;"}
1
+ {"version":3,"file":"instrumentation.js","sources":["../../../../../src/integrations/fs/vendored/instrumentation.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n *\n * NOTICE from the Sentry authors:\n * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/15ef7506553f631ea4181391e0c5725a56f0d082/packages/instrumentation-fs\n * - Upstream version: @opentelemetry/instrumentation-fs@0.37.0\n * - Minor TypeScript strictness adjustments for this repository's compiler settings\n * - The OpenTelemetry tracer APIs were replaced with Sentry's `startSpan`/`startInactiveSpan`/`suppressTracing`\n * and the configurable `createHook`/`endHook`/`requireParentSpan` options were removed in favor of inlined,\n * Sentry-specific span attributes.\n * - Completely reworked to no longer reference OpenTelemetry.\n * - The upstream `fs_error` span attribute (the error message) was replaced with the conventions-backed\n * `error.type` (the syscall error code, e.g. `ENOENT`).\n */\n\nimport { ERROR_TYPE } from '@sentry/conventions/attributes';\nimport { FILE } from '@sentry/conventions/op';\nimport type { Span, SpanAttributes } from '@sentry/core';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n getActiveSpan,\n startInactiveSpan,\n startSpan,\n suppressTracing,\n withActiveSpan,\n} from '@sentry/core';\nimport * as fs from 'fs';\nimport { promisify } from 'util';\nimport { CALLBACK_FUNCTIONS, PROMISE_FUNCTIONS, SYNC_FUNCTIONS } from './constants';\nimport type { FMember, FPMember, FsInstrumentationConfig, GenericFunction } from './types';\nimport { indexFs } from './utils';\n\nconst SPAN_ORIGIN = 'auto.file.fs';\nconst SPAN_OP = FILE;\n\n// The following lists categorize `fs` functions by the shape of their leading path arguments, so we can\n// record meaningful span attributes for them. These are Sentry-specific additions (not part of upstream).\nconst FS_OPERATIONS_WITH_OLD_PATH_NEW_PATH = ['rename', 'renameSync'];\nconst FS_OPERATIONS_WITH_SRC_DEST = ['copyFile', 'cp', 'copyFileSync', 'cpSync'];\nconst FS_OPERATIONS_WITH_EXISTING_PATH_NEW_PATH = ['link', 'linkSync'];\nconst FS_OPERATIONS_WITH_PREFIX = ['mkdtemp', 'mkdtempSync'];\nconst FS_OPERATIONS_WITH_TARGET_PATH = ['symlink', 'symlinkSync'];\nconst FS_OPERATIONS_WITH_PATH_ARG = [\n 'access',\n 'appendFile',\n 'chmod',\n 'chown',\n 'exists',\n 'mkdir',\n 'lchown',\n 'lstat',\n 'lutimes',\n 'open',\n 'opendir',\n 'readdir',\n 'readFile',\n 'readlink',\n 'realpath',\n 'realpath.native',\n 'rm',\n 'rmdir',\n 'stat',\n 'truncate',\n 'unlink',\n 'utimes',\n 'writeFile',\n 'accessSync',\n 'appendFileSync',\n 'chmodSync',\n 'chownSync',\n 'existsSync',\n 'lchownSync',\n 'lstatSync',\n 'lutimesSync',\n 'opendirSync',\n 'mkdirSync',\n 'openSync',\n 'readdirSync',\n 'readFileSync',\n 'readlinkSync',\n 'realpathSync',\n 'realpathSync.native',\n 'rmdirSync',\n 'rmSync',\n 'statSync',\n 'truncateSync',\n 'unlinkSync',\n 'utimesSync',\n 'writeFileSync',\n];\n\n/**\n * Builds the span attributes for a given `fs` operation, optionally including the file path arguments.\n */\nfunction getSpanAttributes(\n functionName: FMember | FPMember,\n args: ArrayLike<unknown>,\n config: FsInstrumentationConfig,\n): SpanAttributes {\n const attributes: SpanAttributes = {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: SPAN_OP,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: SPAN_ORIGIN,\n };\n\n if (!config.recordFilePaths) {\n return attributes;\n }\n\n if (typeof args[0] === 'string' && FS_OPERATIONS_WITH_PATH_ARG.includes(functionName)) {\n attributes['path_argument'] = args[0];\n } else if (typeof args[0] === 'string' && typeof args[1] === 'string') {\n if (FS_OPERATIONS_WITH_TARGET_PATH.includes(functionName)) {\n attributes['target_argument'] = args[0];\n attributes['path_argument'] = args[1];\n } else if (FS_OPERATIONS_WITH_EXISTING_PATH_NEW_PATH.includes(functionName)) {\n attributes['existing_path_argument'] = args[0];\n attributes['new_path_argument'] = args[1];\n } else if (FS_OPERATIONS_WITH_SRC_DEST.includes(functionName)) {\n attributes['src_argument'] = args[0];\n attributes['dest_argument'] = args[1];\n } else if (FS_OPERATIONS_WITH_OLD_PATH_NEW_PATH.includes(functionName)) {\n attributes['old_path_argument'] = args[0];\n attributes['new_path_argument'] = args[1];\n }\n } else if (typeof args[0] === 'string' && FS_OPERATIONS_WITH_PREFIX.includes(functionName)) {\n attributes['prefix_argument'] = args[0];\n }\n\n return attributes;\n}\n\n/**\n * This is important for 2-level functions like `realpath.native` to retain the 2nd-level\n * when patching the 1st-level.\n */\nfunction patchedFunctionWithOriginalProperties<T extends GenericFunction>(patchedFunction: T, original: T): T {\n return Object.assign(patchedFunction, original);\n}\n\n// Tracks patched methods to prevent double-patching if `enableFsInstrumentation` is called more than once.\nconst _patched = new WeakMap<Record<string, GenericFunction>, Set<string>>();\n\nfunction _patchMethod(\n obj: Record<string, GenericFunction>,\n name: string,\n wrapper: (original: GenericFunction) => GenericFunction,\n): void {\n const original = obj[name];\n if (typeof original !== 'function') return;\n let patched = _patched.get(obj);\n if (!patched) {\n patched = new Set();\n _patched.set(obj, patched);\n }\n if (patched.has(name)) return;\n patched.add(name);\n obj[name] = wrapper(original);\n}\n\nfunction _patchSyncFunction<T extends GenericFunction>(\n functionName: FMember,\n original: T,\n config: FsInstrumentationConfig,\n): T {\n const patchedFunction = function (this: unknown, ...args: Parameters<T>): ReturnType<T> {\n const attributes = getSpanAttributes(functionName, args, config);\n return startSpan({ name: `fs.${functionName}`, onlyIfParent: true, attributes }, span => {\n try {\n return suppressTracing(() => original.apply(this, args)) as ReturnType<T>;\n } catch (error) {\n recordError(span, error, config);\n throw error;\n }\n });\n };\n return patchedFunctionWithOriginalProperties(patchedFunction as T, original);\n}\n\nfunction _patchCallbackFunction<T extends GenericFunction>(\n functionName: FMember,\n original: T,\n config: FsInstrumentationConfig,\n): T {\n const patchedFunction = function (this: unknown, ...args: Parameters<T>): ReturnType<T> {\n const lastIdx = args.length - 1;\n const cb: unknown = args[lastIdx];\n if (typeof cb !== 'function') {\n return original.apply(this, args) as ReturnType<T>;\n }\n\n const attributes = getSpanAttributes(functionName, args, config);\n const span = startInactiveSpan({ name: `fs.${functionName}`, onlyIfParent: true, attributes });\n const parentSpan = getActiveSpan();\n\n // Wrap the callback to end the span and restore the caller's active span context.\n // fs callbacks fire from Node's I/O event loop where the AsyncLocalStorage context\n // is lost, so any spans created inside the callback would otherwise have no parent.\n args[lastIdx] = function (this: unknown, ...cbArgs: unknown[]) {\n const error = cbArgs[0];\n if (error) {\n recordError(span, error, config);\n }\n span.end();\n if (parentSpan) {\n return withActiveSpan(parentSpan, () => (cb as GenericFunction).apply(this, cbArgs));\n }\n return (cb as GenericFunction).apply(this, cbArgs);\n };\n\n try {\n return suppressTracing(() => original.apply(this, args)) as ReturnType<T>;\n } catch (error) {\n recordError(span, error, config);\n span.end();\n throw error;\n }\n };\n return patchedFunctionWithOriginalProperties(patchedFunction as T, original);\n}\n\nfunction _patchExistsCallbackFunction<T extends GenericFunction>(original: T, config: FsInstrumentationConfig): T {\n const functionName = 'exists' as FMember;\n const patchedFunction = function (this: unknown, ...args: Parameters<T>): ReturnType<T> {\n const lastIdx = args.length - 1;\n const cb: unknown = args[lastIdx];\n if (typeof cb !== 'function') {\n return original.apply(this, args) as ReturnType<T>;\n }\n\n const attributes = getSpanAttributes(functionName, args, config);\n const span = startInactiveSpan({ name: `fs.${functionName}`, onlyIfParent: true, attributes });\n const parentSpan = getActiveSpan();\n\n // `exists` never calls the callback with an error\n args[lastIdx] = function (this: unknown, ...cbArgs: unknown[]) {\n span.end();\n if (parentSpan) {\n return withActiveSpan(parentSpan, () => (cb as GenericFunction).apply(this, cbArgs));\n }\n return (cb as GenericFunction).apply(this, cbArgs);\n };\n\n try {\n return suppressTracing(() => original.apply(this, args)) as ReturnType<T>;\n } catch (error) {\n recordError(span, error, config);\n span.end();\n throw error;\n }\n };\n const functionWithOriginalProperties = patchedFunctionWithOriginalProperties(patchedFunction as T, original);\n\n // `exists` has a custom promisify function because of the inconsistent signature\n // replicating that on the patched function\n const promisified = function (path: unknown): Promise<unknown> {\n return new Promise(resolve => (functionWithOriginalProperties as GenericFunction)(path, resolve));\n };\n Object.defineProperty(promisified, 'name', { value: functionName });\n Object.defineProperty(functionWithOriginalProperties, promisify.custom, {\n value: promisified,\n });\n\n return functionWithOriginalProperties;\n}\n\nfunction _patchPromiseFunction<T extends GenericFunction>(\n functionName: FPMember,\n original: T,\n config: FsInstrumentationConfig,\n): T {\n const patchedFunction = async function (this: unknown, ...args: Parameters<T>): Promise<unknown> {\n const attributes = getSpanAttributes(functionName, args, config);\n return startSpan({ name: `fs.${functionName}`, onlyIfParent: true, attributes }, async span => {\n try {\n return await suppressTracing(() => original.apply(this, args) as Promise<unknown>);\n } catch (error) {\n recordError(span, error, config);\n throw error;\n }\n });\n };\n return patchedFunctionWithOriginalProperties(patchedFunction as unknown as T, original);\n}\n\nexport function enableFsInstrumentation(config: FsInstrumentationConfig = {}): void {\n for (const fName of SYNC_FUNCTIONS) {\n const { objectToPatch, functionNameToPatch } = indexFs(fs, fName);\n _patchMethod(objectToPatch, functionNameToPatch, original => _patchSyncFunction(fName, original, config));\n }\n\n for (const fName of CALLBACK_FUNCTIONS) {\n const { objectToPatch, functionNameToPatch } = indexFs(fs, fName);\n if (fName === 'exists') {\n _patchMethod(objectToPatch, functionNameToPatch, original => _patchExistsCallbackFunction(original, config));\n } else {\n _patchMethod(objectToPatch, functionNameToPatch, original => _patchCallbackFunction(fName, original, config));\n }\n }\n\n // `fs.promises` and `import { readFile } from 'fs/promises'` share the same object in Node 14+,\n // so patching one covers both.\n const fsPromises = fs.promises as unknown as Record<string, GenericFunction>;\n for (const fName of PROMISE_FUNCTIONS) {\n _patchMethod(fsPromises, fName, original => _patchPromiseFunction(fName, original, config));\n }\n}\n\n/**\n * Sets the error status on the span and, if configured, records the error type as a span attribute.\n */\nfunction recordError(span: Span, error: unknown, config: FsInstrumentationConfig): void {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n if (config.recordErrorMessagesAsSpanAttributes && error instanceof Error) {\n span.setAttribute(ERROR_TYPE, (error as NodeJS.ErrnoException).code ?? error.name);\n }\n}\n"],"names":["FILE","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","startSpan","suppressTracing","startInactiveSpan","getActiveSpan","withActiveSpan","promisify","SYNC_FUNCTIONS","indexFs","CALLBACK_FUNCTIONS","PROMISE_FUNCTIONS","SPAN_STATUS_ERROR","ERROR_TYPE"],"mappings":"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"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3
3
  const diagnosticsChannel = require('node:diagnostics_channel');
4
4
  const api = require('@opentelemetry/api');
5
5
  const core = require('@sentry/core');
6
+ const server = require('@sentry/core/server');
6
7
  const nodeVersion = require('../../nodeVersion.js');
7
8
  const node_events = require('node:events');
8
9
  const http = require('node:http');
@@ -16,7 +17,7 @@ function instrumentHttpOutgoingRequests(instrumentationOptions = {}) {
16
17
  tracePropagation: options.tracePropagation ?? true,
17
18
  spans: options.spans ?? true,
18
19
  ignoreOutgoingRequests(url, request) {
19
- return core.isTracingSuppressed() || !!options.ignoreOutgoingRequests?.(url, core.getRequestOptions(request));
20
+ return core.isTracingSuppressed() || !!options.ignoreOutgoingRequests?.(url, server.getRequestOptions(request));
20
21
  },
21
22
  outgoingRequestHook(span, request) {
22
23
  options.outgoingRequestHook?.(span, request);
@@ -50,11 +51,11 @@ function instrumentHttpOutgoingRequests(instrumentationOptions = {}) {
50
51
  }
51
52
  }
52
53
  function instrumentHttpOutgoingRequestsViaChannel(options) {
53
- const { [core.HTTP_ON_CLIENT_REQUEST]: onHttpClientRequestCreated } = core.getHttpClientSubscriptions(options);
54
- diagnosticsChannel.subscribe(core.HTTP_ON_CLIENT_REQUEST, onHttpClientRequestCreated);
54
+ const { [server.HTTP_ON_CLIENT_REQUEST]: onHttpClientRequestCreated } = server.getHttpClientSubscriptions(options);
55
+ diagnosticsChannel.subscribe(server.HTTP_ON_CLIENT_REQUEST, onHttpClientRequestCreated);
55
56
  }
56
57
  function instrumentHttpOutgoingRequestsViaMonkeyPatching(options) {
57
- core.patchHttpModuleClient(http, options);
58
+ server.patchHttpModuleClient(http, options);
58
59
  }
59
60
 
60
61
  exports.instrumentHttpOutgoingRequests = instrumentHttpOutgoingRequests;
@@ -1 +1 @@
1
- {"version":3,"file":"SentryHttpInstrumentation.js","sources":["../../../../src/integrations/http/SentryHttpInstrumentation.ts"],"sourcesContent":["import { subscribe } from 'node:diagnostics_channel';\nimport { context, trace } from '@opentelemetry/api';\nimport type { ClientRequest, IncomingMessage } from 'node:http';\nimport type { HttpClientRequest, HttpIncomingMessage, HttpInstrumentationOptions, Span } from '@sentry/core';\nimport {\n getHttpClientSubscriptions,\n patchHttpModuleClient,\n getRequestOptions,\n isTracingSuppressed,\n} from '@sentry/core';\nimport { HTTP_ON_CLIENT_REQUEST } from '@sentry/core';\nimport { NODE_VERSION } from '../../nodeVersion';\nimport { errorMonitor } from 'node:events';\nimport * as http from 'node:http';\n\nconst FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL =\n (NODE_VERSION.major === 22 && NODE_VERSION.minor >= 12) ||\n (NODE_VERSION.major === 23 && NODE_VERSION.minor >= 2) ||\n NODE_VERSION.major >= 24;\n\nexport interface OutgoingHttpRequestInstrumentationOptions {\n /**\n * Whether breadcrumbs should be recorded for outgoing requests.\n *\n * @default `true`\n */\n breadcrumbs?: boolean;\n\n /**\n * Whether to create spans for outgoing requests.\n *\n * @default `true`\n */\n spans?: boolean;\n\n /**\n * Whether to propagate Sentry trace headers in outgoing requests.\n *\n * @default `true`\n */\n tracePropagation?: boolean;\n\n /**\n * Do not instrument outgoing HTTP requests to URLs where the given callback returns `true`.\n * When it returns `true`, the request is skipped entirely: no breadcrumb and no span are created,\n * and no trace headers are propagated for that request.\n *\n * @param url Contains the entire URL, including query string (if any), protocol, host, etc. of the outgoing request.\n * @param request Contains the {@type RequestOptions} object used to make the outgoing request.\n */\n ignoreOutgoingRequests?: (url: string, request: http.RequestOptions) => boolean;\n\n /**\n * Hooks for outgoing request spans, only called when spans are created for outgoing requests\n * (i.e. when `spans` is enabled).\n */\n outgoingRequestHook?: (span: Span, request: ClientRequest) => void;\n outgoingResponseHook?: (span: Span, response: IncomingMessage) => void;\n outgoingRequestApplyCustomAttributes?: (\n span: Span,\n request: HttpClientRequest,\n response: HttpIncomingMessage,\n ) => void;\n}\n\n/**\n * This instruments the http modules for outgoing requests.\n * It uses the diagnostics channel if available, otherwise it falls back to monkey-patching.\n *\n * The instrumentation will start spans, create breadcrumbs, and propagate trace headers in outgoing requests (depending on the settings).\n */\nexport function instrumentHttpOutgoingRequests(\n instrumentationOptions: OutgoingHttpRequestInstrumentationOptions = {},\n): void {\n const { outgoingRequestApplyCustomAttributes: applyCustomAttributesOnSpan, ...options } = instrumentationOptions;\n const patchOptions = {\n applyCustomAttributesOnSpan,\n ...options,\n tracePropagation: options.tracePropagation ?? true,\n spans: options.spans ?? true,\n ignoreOutgoingRequests(url, request) {\n return isTracingSuppressed() || !!options.ignoreOutgoingRequests?.(url, getRequestOptions(request));\n },\n outgoingRequestHook(span, request) {\n options.outgoingRequestHook?.(span, request as ClientRequest);\n // We monkey-patch `req.once('response'), which is used to trigger\n // the callback of the request, so that it runs in the active context\n // eslint-disable-next-line @typescript-eslint/unbound-method, typescript/no-deprecated\n const originalOnce = request.once;\n\n const newOnce = new Proxy(originalOnce, {\n apply(target, thisArg, args: Parameters<typeof originalOnce>) {\n const [event] = args;\n if (event !== 'response') {\n return target.apply(thisArg, args);\n }\n\n const parentContext = context.active();\n const requestContext = trace.setSpan(parentContext, span);\n\n return context.with(requestContext, () => {\n return target.apply(thisArg, args);\n });\n },\n });\n\n // eslint-disable-next-line typescript/no-deprecated\n request.once = newOnce;\n },\n outgoingResponseHook(span, response) {\n options.outgoingResponseHook?.(span, response as IncomingMessage);\n },\n errorMonitor,\n // Pass these in to detect OTel double-wrapping if we're enabling spans\n http,\n } satisfies HttpInstrumentationOptions;\n\n if (FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL) {\n instrumentHttpOutgoingRequestsViaChannel(patchOptions);\n } else {\n instrumentHttpOutgoingRequestsViaMonkeyPatching(patchOptions);\n }\n}\n\nfunction instrumentHttpOutgoingRequestsViaChannel(options: HttpInstrumentationOptions): void {\n const { [HTTP_ON_CLIENT_REQUEST]: onHttpClientRequestCreated } = getHttpClientSubscriptions(options);\n subscribe(HTTP_ON_CLIENT_REQUEST, onHttpClientRequestCreated);\n}\n\n/**\n * Instrument outgoing HTTP(S) requests by old-school monkey-patching the `http` module.\n * This is the fallback for runtimes that do not fully support the `node:http` client diagnostics channel\n * (Node < 22.12).\n */\nfunction instrumentHttpOutgoingRequestsViaMonkeyPatching(options: HttpInstrumentationOptions): void {\n // Patching http also patches https, as this uses the same underlying object\n patchHttpModuleClient(http, options);\n}\n"],"names":["NODE_VERSION","isTracingSuppressed","getRequestOptions","context","trace","errorMonitor","HTTP_ON_CLIENT_REQUEST","getHttpClientSubscriptions","subscribe","patchHttpModuleClient"],"mappings":";;;;;;;;;AAeA,MAAM,uCAAA,GACHA,wBAAA,CAAa,KAAA,KAAU,EAAA,IAAMA,yBAAa,KAAA,IAAS,EAAA,IACnDA,wBAAA,CAAa,KAAA,KAAU,EAAA,IAAMA,wBAAA,CAAa,KAAA,IAAS,CAAA,IACpDA,yBAAa,KAAA,IAAS,EAAA;AAqDjB,SAAS,8BAAA,CACd,sBAAA,GAAoE,EAAC,EAC/D;AACN,EAAA,MAAM,EAAE,oCAAA,EAAsC,2BAAA,EAA6B,GAAG,SAAQ,GAAI,sBAAA;AAC1F,EAAA,MAAM,YAAA,GAAe;AAAA,IACnB,2BAAA;AAAA,IACA,GAAG,OAAA;AAAA,IACH,gBAAA,EAAkB,QAAQ,gBAAA,IAAoB,IAAA;AAAA,IAC9C,KAAA,EAAO,QAAQ,KAAA,IAAS,IAAA;AAAA,IACxB,sBAAA,CAAuB,KAAK,OAAA,EAAS;AACnC,MAAA,OAAOC,wBAAA,MAAyB,CAAC,CAAC,QAAQ,sBAAA,GAAyB,GAAA,EAAKC,sBAAA,CAAkB,OAAO,CAAC,CAAA;AAAA,IACpG,CAAA;AAAA,IACA,mBAAA,CAAoB,MAAM,OAAA,EAAS;AACjC,MAAA,OAAA,CAAQ,mBAAA,GAAsB,MAAM,OAAwB,CAAA;AAI5D,MAAA,MAAM,eAAe,OAAA,CAAQ,IAAA;AAE7B,MAAA,MAAM,OAAA,GAAU,IAAI,KAAA,CAAM,YAAA,EAAc;AAAA,QACtC,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAuC;AAC5D,UAAA,MAAM,CAAC,KAAK,CAAA,GAAI,IAAA;AAChB,UAAA,IAAI,UAAU,UAAA,EAAY;AACxB,YAAA,OAAO,MAAA,CAAO,KAAA,CAAM,OAAA,EAAS,IAAI,CAAA;AAAA,UACnC;AAEA,UAAA,MAAM,aAAA,GAAgBC,YAAQ,MAAA,EAAO;AACrC,UAAA,MAAM,cAAA,GAAiBC,SAAA,CAAM,OAAA,CAAQ,aAAA,EAAe,IAAI,CAAA;AAExD,UAAA,OAAOD,WAAA,CAAQ,IAAA,CAAK,cAAA,EAAgB,MAAM;AACxC,YAAA,OAAO,MAAA,CAAO,KAAA,CAAM,OAAA,EAAS,IAAI,CAAA;AAAA,UACnC,CAAC,CAAA;AAAA,QACH;AAAA,OACD,CAAA;AAGD,MAAA,OAAA,CAAQ,IAAA,GAAO,OAAA;AAAA,IACjB,CAAA;AAAA,IACA,oBAAA,CAAqB,MAAM,QAAA,EAAU;AACnC,MAAA,OAAA,CAAQ,oBAAA,GAAuB,MAAM,QAA2B,CAAA;AAAA,IAClE,CAAA;AAAA,kBACAE,wBAAA;AAAA;AAAA,IAEA;AAAA,GACF;AAEA,EAAA,IAAI,uCAAA,EAAyC;AAC3C,IAAA,wCAAA,CAAyC,YAAY,CAAA;AAAA,EACvD,CAAA,MAAO;AACL,IAAA,+CAAA,CAAgD,YAAY,CAAA;AAAA,EAC9D;AACF;AAEA,SAAS,yCAAyC,OAAA,EAA2C;AAC3F,EAAA,MAAM,EAAE,CAACC,2BAAsB,GAAG,0BAAA,EAA2B,GAAIC,gCAA2B,OAAO,CAAA;AACnG,EAAAC,4BAAA,CAAUF,6BAAwB,0BAA0B,CAAA;AAC9D;AAOA,SAAS,gDAAgD,OAAA,EAA2C;AAElG,EAAAG,0BAAA,CAAsB,MAAM,OAAO,CAAA;AACrC;;;;"}
1
+ {"version":3,"file":"SentryHttpInstrumentation.js","sources":["../../../../src/integrations/http/SentryHttpInstrumentation.ts"],"sourcesContent":["import { subscribe } from 'node:diagnostics_channel';\nimport { context, trace } from '@opentelemetry/api';\nimport type { ClientRequest, IncomingMessage } from 'node:http';\nimport type { Span } from '@sentry/core';\nimport { isTracingSuppressed } from '@sentry/core';\nimport type { HttpClientRequest, HttpIncomingMessage, HttpInstrumentationOptions } from '@sentry/core/server';\nimport {\n getHttpClientSubscriptions,\n getRequestOptions,\n HTTP_ON_CLIENT_REQUEST,\n patchHttpModuleClient,\n} from '@sentry/core/server';\nimport { NODE_VERSION } from '../../nodeVersion';\nimport { errorMonitor } from 'node:events';\nimport * as http from 'node:http';\n\nconst FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL =\n (NODE_VERSION.major === 22 && NODE_VERSION.minor >= 12) ||\n (NODE_VERSION.major === 23 && NODE_VERSION.minor >= 2) ||\n NODE_VERSION.major >= 24;\n\nexport interface OutgoingHttpRequestInstrumentationOptions {\n /**\n * Whether breadcrumbs should be recorded for outgoing requests.\n *\n * @default `true`\n */\n breadcrumbs?: boolean;\n\n /**\n * Whether to create spans for outgoing requests.\n *\n * @default `true`\n */\n spans?: boolean;\n\n /**\n * Whether to propagate Sentry trace headers in outgoing requests.\n *\n * @default `true`\n */\n tracePropagation?: boolean;\n\n /**\n * Do not instrument outgoing HTTP requests to URLs where the given callback returns `true`.\n * When it returns `true`, the request is skipped entirely: no breadcrumb and no span are created,\n * and no trace headers are propagated for that request.\n *\n * @param url Contains the entire URL, including query string (if any), protocol, host, etc. of the outgoing request.\n * @param request Contains the {@type RequestOptions} object used to make the outgoing request.\n */\n ignoreOutgoingRequests?: (url: string, request: http.RequestOptions) => boolean;\n\n /**\n * Hooks for outgoing request spans, only called when spans are created for outgoing requests\n * (i.e. when `spans` is enabled).\n */\n outgoingRequestHook?: (span: Span, request: ClientRequest) => void;\n outgoingResponseHook?: (span: Span, response: IncomingMessage) => void;\n outgoingRequestApplyCustomAttributes?: (\n span: Span,\n request: HttpClientRequest,\n response: HttpIncomingMessage,\n ) => void;\n}\n\n/**\n * This instruments the http modules for outgoing requests.\n * It uses the diagnostics channel if available, otherwise it falls back to monkey-patching.\n *\n * The instrumentation will start spans, create breadcrumbs, and propagate trace headers in outgoing requests (depending on the settings).\n */\nexport function instrumentHttpOutgoingRequests(\n instrumentationOptions: OutgoingHttpRequestInstrumentationOptions = {},\n): void {\n const { outgoingRequestApplyCustomAttributes: applyCustomAttributesOnSpan, ...options } = instrumentationOptions;\n const patchOptions = {\n applyCustomAttributesOnSpan,\n ...options,\n tracePropagation: options.tracePropagation ?? true,\n spans: options.spans ?? true,\n ignoreOutgoingRequests(url, request) {\n return isTracingSuppressed() || !!options.ignoreOutgoingRequests?.(url, getRequestOptions(request));\n },\n outgoingRequestHook(span, request) {\n options.outgoingRequestHook?.(span, request as ClientRequest);\n // We monkey-patch `req.once('response'), which is used to trigger\n // the callback of the request, so that it runs in the active context\n // eslint-disable-next-line @typescript-eslint/unbound-method, typescript/no-deprecated\n const originalOnce = request.once;\n\n const newOnce = new Proxy(originalOnce, {\n apply(target, thisArg, args: Parameters<typeof originalOnce>) {\n const [event] = args;\n if (event !== 'response') {\n return target.apply(thisArg, args);\n }\n\n const parentContext = context.active();\n const requestContext = trace.setSpan(parentContext, span);\n\n return context.with(requestContext, () => {\n return target.apply(thisArg, args);\n });\n },\n });\n\n // eslint-disable-next-line typescript/no-deprecated\n request.once = newOnce;\n },\n outgoingResponseHook(span, response) {\n options.outgoingResponseHook?.(span, response as IncomingMessage);\n },\n errorMonitor,\n // Pass these in to detect OTel double-wrapping if we're enabling spans\n http,\n } satisfies HttpInstrumentationOptions;\n\n if (FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL) {\n instrumentHttpOutgoingRequestsViaChannel(patchOptions);\n } else {\n instrumentHttpOutgoingRequestsViaMonkeyPatching(patchOptions);\n }\n}\n\nfunction instrumentHttpOutgoingRequestsViaChannel(options: HttpInstrumentationOptions): void {\n const { [HTTP_ON_CLIENT_REQUEST]: onHttpClientRequestCreated } = getHttpClientSubscriptions(options);\n subscribe(HTTP_ON_CLIENT_REQUEST, onHttpClientRequestCreated);\n}\n\n/**\n * Instrument outgoing HTTP(S) requests by old-school monkey-patching the `http` module.\n * This is the fallback for runtimes that do not fully support the `node:http` client diagnostics channel\n * (Node < 22.12).\n */\nfunction instrumentHttpOutgoingRequestsViaMonkeyPatching(options: HttpInstrumentationOptions): void {\n // Patching http also patches https, as this uses the same underlying object\n patchHttpModuleClient(http, options);\n}\n"],"names":["NODE_VERSION","isTracingSuppressed","getRequestOptions","context","trace","errorMonitor","HTTP_ON_CLIENT_REQUEST","getHttpClientSubscriptions","subscribe","patchHttpModuleClient"],"mappings":";;;;;;;;;;AAgBA,MAAM,uCAAA,GACHA,wBAAA,CAAa,KAAA,KAAU,EAAA,IAAMA,yBAAa,KAAA,IAAS,EAAA,IACnDA,wBAAA,CAAa,KAAA,KAAU,EAAA,IAAMA,wBAAA,CAAa,KAAA,IAAS,CAAA,IACpDA,yBAAa,KAAA,IAAS,EAAA;AAqDjB,SAAS,8BAAA,CACd,sBAAA,GAAoE,EAAC,EAC/D;AACN,EAAA,MAAM,EAAE,oCAAA,EAAsC,2BAAA,EAA6B,GAAG,SAAQ,GAAI,sBAAA;AAC1F,EAAA,MAAM,YAAA,GAAe;AAAA,IACnB,2BAAA;AAAA,IACA,GAAG,OAAA;AAAA,IACH,gBAAA,EAAkB,QAAQ,gBAAA,IAAoB,IAAA;AAAA,IAC9C,KAAA,EAAO,QAAQ,KAAA,IAAS,IAAA;AAAA,IACxB,sBAAA,CAAuB,KAAK,OAAA,EAAS;AACnC,MAAA,OAAOC,wBAAA,MAAyB,CAAC,CAAC,QAAQ,sBAAA,GAAyB,GAAA,EAAKC,wBAAA,CAAkB,OAAO,CAAC,CAAA;AAAA,IACpG,CAAA;AAAA,IACA,mBAAA,CAAoB,MAAM,OAAA,EAAS;AACjC,MAAA,OAAA,CAAQ,mBAAA,GAAsB,MAAM,OAAwB,CAAA;AAI5D,MAAA,MAAM,eAAe,OAAA,CAAQ,IAAA;AAE7B,MAAA,MAAM,OAAA,GAAU,IAAI,KAAA,CAAM,YAAA,EAAc;AAAA,QACtC,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAuC;AAC5D,UAAA,MAAM,CAAC,KAAK,CAAA,GAAI,IAAA;AAChB,UAAA,IAAI,UAAU,UAAA,EAAY;AACxB,YAAA,OAAO,MAAA,CAAO,KAAA,CAAM,OAAA,EAAS,IAAI,CAAA;AAAA,UACnC;AAEA,UAAA,MAAM,aAAA,GAAgBC,YAAQ,MAAA,EAAO;AACrC,UAAA,MAAM,cAAA,GAAiBC,SAAA,CAAM,OAAA,CAAQ,aAAA,EAAe,IAAI,CAAA;AAExD,UAAA,OAAOD,WAAA,CAAQ,IAAA,CAAK,cAAA,EAAgB,MAAM;AACxC,YAAA,OAAO,MAAA,CAAO,KAAA,CAAM,OAAA,EAAS,IAAI,CAAA;AAAA,UACnC,CAAC,CAAA;AAAA,QACH;AAAA,OACD,CAAA;AAGD,MAAA,OAAA,CAAQ,IAAA,GAAO,OAAA;AAAA,IACjB,CAAA;AAAA,IACA,oBAAA,CAAqB,MAAM,QAAA,EAAU;AACnC,MAAA,OAAA,CAAQ,oBAAA,GAAuB,MAAM,QAA2B,CAAA;AAAA,IAClE,CAAA;AAAA,kBACAE,wBAAA;AAAA;AAAA,IAEA;AAAA,GACF;AAEA,EAAA,IAAI,uCAAA,EAAyC;AAC3C,IAAA,wCAAA,CAAyC,YAAY,CAAA;AAAA,EACvD,CAAA,MAAO;AACL,IAAA,+CAAA,CAAgD,YAAY,CAAA;AAAA,EAC9D;AACF;AAEA,SAAS,yCAAyC,OAAA,EAA2C;AAC3F,EAAA,MAAM,EAAE,CAACC,6BAAsB,GAAG,0BAAA,EAA2B,GAAIC,kCAA2B,OAAO,CAAA;AACnG,EAAAC,4BAAA,CAAUF,+BAAwB,0BAA0B,CAAA;AAC9D;AAOA,SAAS,gDAAgD,OAAA,EAA2C;AAElG,EAAAG,4BAAA,CAAsB,MAAM,OAAO,CAAA;AACrC;;;;"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3
3
  const diagnosticsChannel = require('node:diagnostics_channel');
4
4
  const api = require('@opentelemetry/api');
5
5
  const core = require('@sentry/core');
6
+ const server = require('@sentry/core/server');
6
7
  const debugBuild = require('../../debug-build.js');
7
8
 
8
9
  const HTTP_SERVER_INSTRUMENTED_KEY = api.createContextKey("sentry_http_server_instrumented");
@@ -57,8 +58,8 @@ const _httpServerIntegration = ((options = {}) => {
57
58
  return {
58
59
  name: INTEGRATION_NAME,
59
60
  setupOnce() {
60
- const { [core.HTTP_ON_SERVER_REQUEST]: onHttpServerRequestStart } = core.getHttpServerSubscriptions(_options);
61
- diagnosticsChannel.subscribe(core.HTTP_ON_SERVER_REQUEST, onHttpServerRequestStart);
61
+ const { [server.HTTP_ON_SERVER_REQUEST]: onHttpServerRequestStart } = server.getHttpServerSubscriptions(_options);
62
+ diagnosticsChannel.subscribe(server.HTTP_ON_SERVER_REQUEST, onHttpServerRequestStart);
62
63
  },
63
64
  afterAllSetup(client) {
64
65
  if (debugBuild.DEBUG_BUILD && client.getIntegrationByName("Http")) {
@@ -71,7 +72,7 @@ const _httpServerIntegration = ((options = {}) => {
71
72
  });
72
73
  const httpServerIntegration = _httpServerIntegration;
73
74
 
74
- exports.recordRequestSession = core.recordRequestSession;
75
+ exports.recordRequestSession = server.recordRequestSession;
75
76
  exports.addStartSpanCallback = addStartSpanCallback;
76
77
  exports.httpServerIntegration = httpServerIntegration;
77
78
  //# sourceMappingURL=httpServerIntegration.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"httpServerIntegration.js","sources":["../../../../src/integrations/http/httpServerIntegration.ts"],"sourcesContent":["import { subscribe } from 'node:diagnostics_channel';\nimport type { RequestOptions } from 'node:http';\nimport { context, createContextKey, propagation } from '@opentelemetry/api';\nimport type { HttpIncomingMessage, HttpServerResponse, Integration, IntegrationFn } from '@sentry/core';\nimport {\n addNonEnumerableProperty,\n debug,\n getClient,\n getHttpServerSubscriptions,\n HTTP_ON_SERVER_REQUEST,\n recordRequestSession,\n} from '@sentry/core';\nimport type { RequestEventData } from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\n\n// Re-export so existing test imports continue to work; the implementation now lives in core.\nexport { recordRequestSession };\n\nconst HTTP_SERVER_INSTRUMENTED_KEY = createContextKey('sentry_http_server_instrumented');\nconst INTEGRATION_NAME = 'Http.Server' as const;\n\n// Inlining this type to not depend on newer TS types\ninterface WeakRefImpl<T> {\n deref(): T | undefined;\n}\n\ntype StartSpanCallback = (next: () => boolean) => boolean;\ntype RequestWithOptionalStartSpanCallback = HttpIncomingMessage & {\n _startSpanCallback?: WeakRefImpl<StartSpanCallback>;\n};\n\nexport interface HttpServerIntegrationOptions {\n /**\n * Whether the integration should create [Sessions](https://docs.sentry.io/product/releases/health/#sessions) for incoming requests to track the health and crash-free rate of your releases in Sentry.\n * Read more about Release Health: https://docs.sentry.io/product/releases/health/\n *\n * Defaults to `true`.\n */\n sessions?: boolean;\n\n /**\n * Number of milliseconds until sessions tracked with `sessions` will be flushed as a session aggregate.\n *\n * Defaults to `60000` (60s).\n */\n sessionFlushingDelayMS?: number;\n\n /**\n * Do not capture the request body for incoming HTTP requests to URLs where the given callback returns `true`.\n * This can be useful for long running requests where the body is not needed and we want to avoid capturing it.\n *\n * @param url Contains the entire URL, including query string (if any), protocol, host, etc. of the incoming request.\n * @param request Contains the {@type RequestOptions} object used to make the incoming request.\n */\n ignoreRequestBody?: (url: string, request: RequestOptions) => boolean;\n\n /**\n * Controls the maximum size of incoming HTTP request bodies attached to events.\n *\n * Available options:\n * - 'none': No request bodies will be attached\n * - 'small': Request bodies up to 1,000 bytes will be attached\n * - 'medium': Request bodies up to 10,000 bytes will be attached (default)\n * - 'always': Request bodies will always be attached\n *\n * Note that even with 'always' setting, bodies exceeding 1MB will never be attached\n * for performance and security reasons.\n *\n * @default 'medium'\n */\n maxRequestBodySize?: 'none' | 'small' | 'medium' | 'always';\n}\n\n/**\n * Add a callback to the request object that will be called when the request is started.\n * The callback will receive the next function to continue processing the request.\n */\nexport function addStartSpanCallback(request: RequestWithOptionalStartSpanCallback, callback: StartSpanCallback): void {\n addNonEnumerableProperty(request, '_startSpanCallback', new WeakRef(callback));\n}\n\nconst _httpServerIntegration = ((options: HttpServerIntegrationOptions = {}) => {\n const _options = {\n sessions: options.sessions ?? true,\n sessionFlushingDelayMS: options.sessionFlushingDelayMS ?? 60_000,\n maxRequestBodySize: options.maxRequestBodySize,\n // Server spans are created by `httpServerSpansIntegration` via the\n // `httpServerRequest` client event + `_startSpanCallback`, not by the\n // core subscription helper. Explicitly opt out so the helper does not\n // double-create spans when the client has tracing enabled.\n spans: false as const,\n // Cast: core uses HttpIncomingMessage; node consumers pass\n // RequestOptions-typed callbacks.\n // The two are structurally compatible for the fields the callback reads\n // (url, method, headers).\n ignoreRequestBody: options.ignoreRequestBody as\n | ((url: string, request: HttpIncomingMessage) => boolean)\n | undefined,\n\n /**\n * Hook called by core's `instrumentServer` to wrap the upstream\n * `emit('request')` call.\n *\n * We use it to extract OTel context from request headers and re-enter\n * the OTel context before the framework sees the request, so subsequent\n * spans (eg from `httpServerSpansIntegration`) attach to the right trace.\n */\n wrapServerEmitRequest(\n request: HttpIncomingMessage,\n response: HttpServerResponse,\n normalizedRequest: RequestEventData,\n next: () => void,\n ): void {\n const client = getClient();\n if (!client) return next();\n\n // Guard against double-wrapping: if our wrapper somehow runs inside an\n // already-instrumented context, just continue without re-extracting\n // and re-emitting.\n if (context.active().getValue(HTTP_SERVER_INSTRUMENTED_KEY)) {\n return next();\n }\n\n const ctx = propagation\n .extract(context.active(), normalizedRequest.headers)\n .setValue(HTTP_SERVER_INSTRUMENTED_KEY, true);\n\n context.with(ctx, () => {\n // httpServerSpansIntegration listens for this and may attach\n // `_startSpanCallback` to the request to wrap span creation around\n // the emit.\n client.emit('httpServerRequest', request, response, normalizedRequest);\n\n const callback = (request as RequestWithOptionalStartSpanCallback)._startSpanCallback?.deref();\n if (callback) {\n callback(() => {\n next();\n return true;\n });\n } else {\n next();\n }\n });\n },\n };\n\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n const { [HTTP_ON_SERVER_REQUEST]: onHttpServerRequestStart } = getHttpServerSubscriptions(_options);\n subscribe(HTTP_ON_SERVER_REQUEST, onHttpServerRequestStart);\n },\n afterAllSetup(client) {\n if (DEBUG_BUILD && client.getIntegrationByName('Http')) {\n debug.warn(\n 'It seems that you have manually added `httpServerIntegration` while `httpIntegration` is also present. Make sure to remove `httpServerIntegration` when adding `httpIntegration`.',\n );\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * This integration handles request isolation, trace continuation and other core Sentry functionality around incoming http requests\n * handled via the node `http` module.\n *\n * This version uses OpenTelemetry for context propagation and span management.\n *\n * @see {@link ../../light/integrations/httpServerIntegration.ts} for the lightweight version without OpenTelemetry\n */\nexport const httpServerIntegration = _httpServerIntegration as (\n options?: HttpServerIntegrationOptions,\n) => Integration & {\n name: 'Http.Server';\n setupOnce: () => void;\n};\n"],"names":["createContextKey","addNonEnumerableProperty","getClient","context","propagation","HTTP_ON_SERVER_REQUEST","getHttpServerSubscriptions","subscribe","DEBUG_BUILD","debug"],"mappings":";;;;;;;AAkBA,MAAM,4BAAA,GAA+BA,qBAAiB,iCAAiC,CAAA;AACvF,MAAM,gBAAA,GAAmB,aAAA;AA0DlB,SAAS,oBAAA,CAAqB,SAA+C,QAAA,EAAmC;AACrH,EAAAC,6BAAA,CAAyB,OAAA,EAAS,oBAAA,EAAsB,IAAI,OAAA,CAAQ,QAAQ,CAAC,CAAA;AAC/E;AAEA,MAAM,sBAAA,IAA0B,CAAC,OAAA,GAAwC,EAAC,KAAM;AAC9E,EAAA,MAAM,QAAA,GAAW;AAAA,IACf,QAAA,EAAU,QAAQ,QAAA,IAAY,IAAA;AAAA,IAC9B,sBAAA,EAAwB,QAAQ,sBAAA,IAA0B,GAAA;AAAA,IAC1D,oBAAoB,OAAA,CAAQ,kBAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAK5B,KAAA,EAAO,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKP,mBAAmB,OAAA,CAAQ,iBAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAY3B,qBAAA,CACE,OAAA,EACA,QAAA,EACA,iBAAA,EACA,IAAA,EACM;AACN,MAAA,MAAM,SAASC,cAAA,EAAU;AACzB,MAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,IAAA,EAAK;AAKzB,MAAA,IAAIC,WAAA,CAAQ,MAAA,EAAO,CAAE,QAAA,CAAS,4BAA4B,CAAA,EAAG;AAC3D,QAAA,OAAO,IAAA,EAAK;AAAA,MACd;AAEA,MAAA,MAAM,GAAA,GAAMC,eAAA,CACT,OAAA,CAAQD,WAAA,CAAQ,MAAA,EAAO,EAAG,iBAAA,CAAkB,OAAO,CAAA,CACnD,QAAA,CAAS,4BAAA,EAA8B,IAAI,CAAA;AAE9C,MAAAA,WAAA,CAAQ,IAAA,CAAK,KAAK,MAAM;AAItB,QAAA,MAAA,CAAO,IAAA,CAAK,mBAAA,EAAqB,OAAA,EAAS,QAAA,EAAU,iBAAiB,CAAA;AAErE,QAAA,MAAM,QAAA,GAAY,OAAA,CAAiD,kBAAA,EAAoB,KAAA,EAAM;AAC7F,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,QAAA,CAAS,MAAM;AACb,YAAA,IAAA,EAAK;AACL,YAAA,OAAO,IAAA;AAAA,UACT,CAAC,CAAA;AAAA,QACH,CAAA,MAAO;AACL,UAAA,IAAA,EAAK;AAAA,QACP;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,SAAA,GAAY;AACV,MAAA,MAAM,EAAE,CAACE,2BAAsB,GAAG,wBAAA,EAAyB,GAAIC,gCAA2B,QAAQ,CAAA;AAClG,MAAAC,4BAAA,CAAUF,6BAAwB,wBAAwB,CAAA;AAAA,IAC5D,CAAA;AAAA,IACA,cAAc,MAAA,EAAQ;AACpB,MAAA,IAAIG,sBAAA,IAAe,MAAA,CAAO,oBAAA,CAAqB,MAAM,CAAA,EAAG;AACtD,QAAAC,UAAA,CAAM,IAAA;AAAA,UACJ;AAAA,SACF;AAAA,MACF;AAAA,IACF;AAAA,GACF;AACF,CAAA,CAAA;AAUO,MAAM,qBAAA,GAAwB;;;;;;"}
1
+ {"version":3,"file":"httpServerIntegration.js","sources":["../../../../src/integrations/http/httpServerIntegration.ts"],"sourcesContent":["import { subscribe } from 'node:diagnostics_channel';\nimport type { RequestOptions } from 'node:http';\nimport { context, createContextKey, propagation } from '@opentelemetry/api';\nimport type { Integration, IntegrationFn } from '@sentry/core';\nimport { addNonEnumerableProperty, debug, getClient } from '@sentry/core';\nimport type { HttpIncomingMessage, HttpServerResponse } from '@sentry/core/server';\nimport { getHttpServerSubscriptions, HTTP_ON_SERVER_REQUEST, recordRequestSession } from '@sentry/core/server';\nimport type { RequestEventData } from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\n\n// Re-export so existing test imports continue to work; the implementation now lives in core.\nexport { recordRequestSession };\n\nconst HTTP_SERVER_INSTRUMENTED_KEY = createContextKey('sentry_http_server_instrumented');\nconst INTEGRATION_NAME = 'Http.Server' as const;\n\n// Inlining this type to not depend on newer TS types\ninterface WeakRefImpl<T> {\n deref(): T | undefined;\n}\n\ntype StartSpanCallback = (next: () => boolean) => boolean;\ntype RequestWithOptionalStartSpanCallback = HttpIncomingMessage & {\n _startSpanCallback?: WeakRefImpl<StartSpanCallback>;\n};\n\nexport interface HttpServerIntegrationOptions {\n /**\n * Whether the integration should create [Sessions](https://docs.sentry.io/product/releases/health/#sessions) for incoming requests to track the health and crash-free rate of your releases in Sentry.\n * Read more about Release Health: https://docs.sentry.io/product/releases/health/\n *\n * Defaults to `true`.\n */\n sessions?: boolean;\n\n /**\n * Number of milliseconds until sessions tracked with `sessions` will be flushed as a session aggregate.\n *\n * Defaults to `60000` (60s).\n */\n sessionFlushingDelayMS?: number;\n\n /**\n * Do not capture the request body for incoming HTTP requests to URLs where the given callback returns `true`.\n * This can be useful for long running requests where the body is not needed and we want to avoid capturing it.\n *\n * @param url Contains the entire URL, including query string (if any), protocol, host, etc. of the incoming request.\n * @param request Contains the {@type RequestOptions} object used to make the incoming request.\n */\n ignoreRequestBody?: (url: string, request: RequestOptions) => boolean;\n\n /**\n * Controls the maximum size of incoming HTTP request bodies attached to events.\n *\n * Available options:\n * - 'none': No request bodies will be attached\n * - 'small': Request bodies up to 1,000 bytes will be attached\n * - 'medium': Request bodies up to 10,000 bytes will be attached (default)\n * - 'always': Request bodies will always be attached\n *\n * Note that even with 'always' setting, bodies exceeding 1MB will never be attached\n * for performance and security reasons.\n *\n * @default 'medium'\n */\n maxRequestBodySize?: 'none' | 'small' | 'medium' | 'always';\n}\n\n/**\n * Add a callback to the request object that will be called when the request is started.\n * The callback will receive the next function to continue processing the request.\n */\nexport function addStartSpanCallback(request: RequestWithOptionalStartSpanCallback, callback: StartSpanCallback): void {\n addNonEnumerableProperty(request, '_startSpanCallback', new WeakRef(callback));\n}\n\nconst _httpServerIntegration = ((options: HttpServerIntegrationOptions = {}) => {\n const _options = {\n sessions: options.sessions ?? true,\n sessionFlushingDelayMS: options.sessionFlushingDelayMS ?? 60_000,\n maxRequestBodySize: options.maxRequestBodySize,\n // Server spans are created by `httpServerSpansIntegration` via the\n // `httpServerRequest` client event + `_startSpanCallback`, not by the\n // core subscription helper. Explicitly opt out so the helper does not\n // double-create spans when the client has tracing enabled.\n spans: false as const,\n // Cast: core uses HttpIncomingMessage; node consumers pass\n // RequestOptions-typed callbacks.\n // The two are structurally compatible for the fields the callback reads\n // (url, method, headers).\n ignoreRequestBody: options.ignoreRequestBody as\n | ((url: string, request: HttpIncomingMessage) => boolean)\n | undefined,\n\n /**\n * Hook called by core's `instrumentServer` to wrap the upstream\n * `emit('request')` call.\n *\n * We use it to extract OTel context from request headers and re-enter\n * the OTel context before the framework sees the request, so subsequent\n * spans (eg from `httpServerSpansIntegration`) attach to the right trace.\n */\n wrapServerEmitRequest(\n request: HttpIncomingMessage,\n response: HttpServerResponse,\n normalizedRequest: RequestEventData,\n next: () => void,\n ): void {\n const client = getClient();\n if (!client) return next();\n\n // Guard against double-wrapping: if our wrapper somehow runs inside an\n // already-instrumented context, just continue without re-extracting\n // and re-emitting.\n if (context.active().getValue(HTTP_SERVER_INSTRUMENTED_KEY)) {\n return next();\n }\n\n const ctx = propagation\n .extract(context.active(), normalizedRequest.headers)\n .setValue(HTTP_SERVER_INSTRUMENTED_KEY, true);\n\n context.with(ctx, () => {\n // httpServerSpansIntegration listens for this and may attach\n // `_startSpanCallback` to the request to wrap span creation around\n // the emit.\n client.emit('httpServerRequest', request, response, normalizedRequest);\n\n const callback = (request as RequestWithOptionalStartSpanCallback)._startSpanCallback?.deref();\n if (callback) {\n callback(() => {\n next();\n return true;\n });\n } else {\n next();\n }\n });\n },\n };\n\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n const { [HTTP_ON_SERVER_REQUEST]: onHttpServerRequestStart } = getHttpServerSubscriptions(_options);\n subscribe(HTTP_ON_SERVER_REQUEST, onHttpServerRequestStart);\n },\n afterAllSetup(client) {\n if (DEBUG_BUILD && client.getIntegrationByName('Http')) {\n debug.warn(\n 'It seems that you have manually added `httpServerIntegration` while `httpIntegration` is also present. Make sure to remove `httpServerIntegration` when adding `httpIntegration`.',\n );\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * This integration handles request isolation, trace continuation and other core Sentry functionality around incoming http requests\n * handled via the node `http` module.\n *\n * This version uses OpenTelemetry for context propagation and span management.\n *\n * @see {@link ../../light/integrations/httpServerIntegration.ts} for the lightweight version without OpenTelemetry\n */\nexport const httpServerIntegration = _httpServerIntegration as (\n options?: HttpServerIntegrationOptions,\n) => Integration & {\n name: 'Http.Server';\n setupOnce: () => void;\n};\n"],"names":["createContextKey","addNonEnumerableProperty","getClient","context","propagation","HTTP_ON_SERVER_REQUEST","getHttpServerSubscriptions","subscribe","DEBUG_BUILD","debug"],"mappings":";;;;;;;;AAaA,MAAM,4BAAA,GAA+BA,qBAAiB,iCAAiC,CAAA;AACvF,MAAM,gBAAA,GAAmB,aAAA;AA0DlB,SAAS,oBAAA,CAAqB,SAA+C,QAAA,EAAmC;AACrH,EAAAC,6BAAA,CAAyB,OAAA,EAAS,oBAAA,EAAsB,IAAI,OAAA,CAAQ,QAAQ,CAAC,CAAA;AAC/E;AAEA,MAAM,sBAAA,IAA0B,CAAC,OAAA,GAAwC,EAAC,KAAM;AAC9E,EAAA,MAAM,QAAA,GAAW;AAAA,IACf,QAAA,EAAU,QAAQ,QAAA,IAAY,IAAA;AAAA,IAC9B,sBAAA,EAAwB,QAAQ,sBAAA,IAA0B,GAAA;AAAA,IAC1D,oBAAoB,OAAA,CAAQ,kBAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAK5B,KAAA,EAAO,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKP,mBAAmB,OAAA,CAAQ,iBAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAY3B,qBAAA,CACE,OAAA,EACA,QAAA,EACA,iBAAA,EACA,IAAA,EACM;AACN,MAAA,MAAM,SAASC,cAAA,EAAU;AACzB,MAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,IAAA,EAAK;AAKzB,MAAA,IAAIC,WAAA,CAAQ,MAAA,EAAO,CAAE,QAAA,CAAS,4BAA4B,CAAA,EAAG;AAC3D,QAAA,OAAO,IAAA,EAAK;AAAA,MACd;AAEA,MAAA,MAAM,GAAA,GAAMC,eAAA,CACT,OAAA,CAAQD,WAAA,CAAQ,MAAA,EAAO,EAAG,iBAAA,CAAkB,OAAO,CAAA,CACnD,QAAA,CAAS,4BAAA,EAA8B,IAAI,CAAA;AAE9C,MAAAA,WAAA,CAAQ,IAAA,CAAK,KAAK,MAAM;AAItB,QAAA,MAAA,CAAO,IAAA,CAAK,mBAAA,EAAqB,OAAA,EAAS,QAAA,EAAU,iBAAiB,CAAA;AAErE,QAAA,MAAM,QAAA,GAAY,OAAA,CAAiD,kBAAA,EAAoB,KAAA,EAAM;AAC7F,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,QAAA,CAAS,MAAM;AACb,YAAA,IAAA,EAAK;AACL,YAAA,OAAO,IAAA;AAAA,UACT,CAAC,CAAA;AAAA,QACH,CAAA,MAAO;AACL,UAAA,IAAA,EAAK;AAAA,QACP;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,SAAA,GAAY;AACV,MAAA,MAAM,EAAE,CAACE,6BAAsB,GAAG,wBAAA,EAAyB,GAAIC,kCAA2B,QAAQ,CAAA;AAClG,MAAAC,4BAAA,CAAUF,+BAAwB,wBAAwB,CAAA;AAAA,IAC5D,CAAA;AAAA,IACA,cAAc,MAAA,EAAQ;AACpB,MAAA,IAAIG,sBAAA,IAAe,MAAA,CAAO,oBAAA,CAAqB,MAAM,CAAA,EAAG;AACtD,QAAAC,UAAA,CAAM,IAAA;AAAA,UACJ;AAAA,SACF;AAAA,MACF;AAAA,IACF;AAAA,GACF;AACF,CAAA,CAAA;AAUO,MAAM,qBAAA,GAAwB;;;;;;"}
@@ -2,6 +2,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const node_events = require('node:events');
4
4
  const attributes = require('@sentry/conventions/attributes');
5
+ const op = require('@sentry/conventions/op');
6
+ const server = require('@sentry/core/server');
5
7
  const core = require('@sentry/core');
6
8
  const debugBuild = require('../../debug-build.js');
7
9
  const httpServerIntegration = require('./httpServerIntegration.js');
@@ -10,12 +12,7 @@ const INTEGRATION_NAME = "Http.ServerSpans";
10
12
  const _httpServerSpansIntegration = ((options = {}) => {
11
13
  const ignoreStaticAssets = options.ignoreStaticAssets ?? true;
12
14
  const ignoreIncomingRequests = options.ignoreIncomingRequests;
13
- const ignoreStatusCodes = options.ignoreStatusCodes ?? [
14
- [401, 404],
15
- // 300 and 304 are possibly valid status codes we do not want to filter
16
- [301, 303],
17
- [305, 399]
18
- ];
15
+ const ignoreStatusCodes = options.ignoreStatusCodes ?? server.DEFAULT_IGNORE_STATUS_CODES;
19
16
  const { onSpanCreated } = options;
20
17
  return {
21
18
  name: INTEGRATION_NAME,
@@ -55,7 +52,7 @@ const _httpServerSpansIntegration = ((options = {}) => {
55
52
  attributes: {
56
53
  // Sentry specific attributes
57
54
  [attributes.SENTRY_KIND]: "server",
58
- [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "http.server",
55
+ [attributes.SENTRY_OP]: op.HTTP_SERVER,
59
56
  [attributes.SENTRY_SEGMENT_NAME_SOURCE]: "url",
60
57
  [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.http_server",
61
58
  [attributes.SENTRY_HTTP_PREFETCH]: isKnownPrefetchRequest(request) || void 0,
@@ -107,23 +104,7 @@ const _httpServerSpansIntegration = ((options = {}) => {
107
104
  });
108
105
  },
109
106
  processEvent(event) {
110
- if (event.type === "transaction") {
111
- const statusCode = event.contexts?.trace?.data?.[attributes.HTTP_RESPONSE_STATUS_CODE];
112
- if (typeof statusCode === "number") {
113
- if (shouldFilterStatusCode(statusCode, ignoreStatusCodes)) {
114
- debugBuild.DEBUG_BUILD && core.debug.log("Dropping transaction due to status code", statusCode);
115
- return null;
116
- }
117
- event.contexts = {
118
- ...event.contexts,
119
- response: {
120
- ...event.contexts?.response,
121
- status_code: statusCode
122
- }
123
- };
124
- }
125
- }
126
- return event;
107
+ return server.processHttpServerTransactionEvent(event, ignoreStatusCodes);
127
108
  },
128
109
  afterAllSetup(client) {
129
110
  if (!debugBuild.DEBUG_BUILD) {
@@ -200,15 +181,6 @@ function getIncomingRequestAttributesOnResponse(request, response, collectClient
200
181
  }
201
182
  return newAttributes;
202
183
  }
203
- function shouldFilterStatusCode(statusCode, dropForStatusCodes) {
204
- return dropForStatusCodes.some((code) => {
205
- if (typeof code === "number") {
206
- return code === statusCode;
207
- }
208
- const [min, max] = code;
209
- return statusCode >= min && statusCode <= max;
210
- });
211
- }
212
184
 
213
185
  exports.httpServerSpansIntegration = httpServerSpansIntegration;
214
186
  exports.isStaticAssetRequest = isStaticAssetRequest;