@sentry/node 9.12.0 → 9.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/index.js +7 -4
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/integrations/anr/index.js +3 -3
- package/build/cjs/integrations/anr/index.js.map +1 -1
- package/build/cjs/integrations/context.js +3 -3
- package/build/cjs/integrations/context.js.map +1 -1
- package/build/cjs/integrations/http/SentryHttpInstrumentation.js +37 -36
- package/build/cjs/integrations/http/SentryHttpInstrumentation.js.map +1 -1
- package/build/cjs/integrations/local-variables/local-variables-async.js +1 -1
- package/build/cjs/integrations/node-fetch/index.js +11 -7
- package/build/cjs/integrations/node-fetch/index.js.map +1 -1
- package/build/cjs/integrations/tracing/graphql.js +31 -3
- package/build/cjs/integrations/tracing/graphql.js.map +1 -1
- package/build/cjs/integrations/winston.js +151 -0
- package/build/cjs/integrations/winston.js.map +1 -0
- package/build/cjs/logs/capture.js +29 -0
- package/build/cjs/logs/capture.js.map +1 -0
- package/build/cjs/{log.js → logs/exports.js} +8 -30
- package/build/cjs/logs/exports.js.map +1 -0
- package/build/cjs/otel/instrument.js +50 -2
- package/build/cjs/otel/instrument.js.map +1 -1
- package/build/cjs/sdk/index.js +1 -2
- package/build/cjs/sdk/index.js.map +1 -1
- package/build/esm/index.js +4 -4
- package/build/esm/integrations/anr/index.js +1 -1
- package/build/esm/integrations/anr/worker-script.js +2 -2
- package/build/esm/integrations/http/SentryHttpInstrumentation.js +37 -36
- package/build/esm/integrations/http/SentryHttpInstrumentation.js.map +1 -1
- package/build/esm/integrations/local-variables/local-variables-async.js +1 -1
- package/build/esm/integrations/local-variables/worker-script.js +2 -2
- package/build/esm/integrations/node-fetch/index.js +11 -7
- package/build/esm/integrations/node-fetch/index.js.map +1 -1
- package/build/esm/integrations/tracing/express.js +1 -1
- package/build/esm/integrations/tracing/fastify.js +1 -1
- package/build/esm/integrations/tracing/graphql.js +32 -4
- package/build/esm/integrations/tracing/graphql.js.map +1 -1
- package/build/esm/integrations/tracing/koa.js +1 -1
- package/build/esm/integrations/winston.js +149 -0
- package/build/esm/integrations/winston.js.map +1 -0
- package/build/esm/logs/capture.js +27 -0
- package/build/esm/logs/capture.js.map +1 -0
- package/build/esm/{log.js → logs/exports.js} +2 -25
- package/build/esm/logs/exports.js.map +1 -0
- package/build/esm/otel/instrument.js +50 -2
- package/build/esm/otel/instrument.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/sdk/index.js +1 -2
- package/build/esm/sdk/index.js.map +1 -1
- package/build/types/index.d.ts +3 -3
- package/build/types/index.d.ts.map +1 -1
- package/build/types/integrations/http/SentryHttpInstrumentation.d.ts.map +1 -1
- package/build/types/integrations/node-fetch/index.d.ts.map +1 -1
- package/build/types/integrations/tracing/graphql.d.ts +2 -1
- package/build/types/integrations/tracing/graphql.d.ts.map +1 -1
- package/build/types/integrations/winston.d.ts +44 -0
- package/build/types/integrations/winston.d.ts.map +1 -0
- package/build/types/logs/capture.d.ts +11 -0
- package/build/types/logs/capture.d.ts.map +1 -0
- package/build/{types-ts3.8/log.d.ts → types/logs/exports.d.ts} +150 -158
- package/build/types/logs/exports.d.ts.map +1 -0
- package/build/types/otel/instrument.d.ts +3 -4
- package/build/types/otel/instrument.d.ts.map +1 -1
- package/build/types-ts3.8/index.d.ts +3 -3
- package/build/types-ts3.8/integrations/tracing/graphql.d.ts +2 -1
- package/build/types-ts3.8/integrations/winston.d.ts +44 -0
- package/build/types-ts3.8/logs/capture.d.ts +18 -0
- package/build/{types/log.d.ts → types-ts3.8/logs/exports.d.ts} +150 -151
- package/build/types-ts3.8/otel/instrument.d.ts +3 -4
- package/package.json +4 -4
- package/build/cjs/integrations/console.js +0 -37
- package/build/cjs/integrations/console.js.map +0 -1
- package/build/cjs/log.js.map +0 -1
- package/build/esm/integrations/console.js +0 -35
- package/build/esm/integrations/console.js.map +0 -1
- package/build/esm/log.js.map +0 -1
- package/build/types/integrations/console.d.ts +0 -5
- package/build/types/integrations/console.d.ts.map +0 -1
- package/build/types/log.d.ts.map +0 -1
- package/build/types-ts3.8/integrations/console.d.ts +0 -5
package/build/cjs/index.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const index = require('./integrations/http/index.js');
|
|
4
4
|
const index$1 = require('./integrations/node-fetch/index.js');
|
|
5
5
|
const fs = require('./integrations/fs.js');
|
|
6
|
-
const console = require('./integrations/console.js');
|
|
7
6
|
const context = require('./integrations/context.js');
|
|
8
7
|
const contextlines = require('./integrations/contextlines.js');
|
|
9
8
|
const index$2 = require('./integrations/local-variables/index.js');
|
|
@@ -34,6 +33,7 @@ const dataloader = require('./integrations/tracing/dataloader.js');
|
|
|
34
33
|
const amqplib = require('./integrations/tracing/amqplib.js');
|
|
35
34
|
const index$5 = require('./integrations/tracing/vercelai/index.js');
|
|
36
35
|
const childProcess = require('./integrations/childProcess.js');
|
|
36
|
+
const winston = require('./integrations/winston.js');
|
|
37
37
|
const contextManager = require('./otel/contextManager.js');
|
|
38
38
|
const instrument = require('./otel/instrument.js');
|
|
39
39
|
const index$6 = require('./sdk/index.js');
|
|
@@ -46,14 +46,13 @@ const client = require('./sdk/client.js');
|
|
|
46
46
|
const index$8 = require('./cron/index.js');
|
|
47
47
|
const opentelemetry = require('@sentry/opentelemetry');
|
|
48
48
|
const core = require('@sentry/core');
|
|
49
|
-
const
|
|
49
|
+
const exports$1 = require('./logs/exports.js');
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
exports.httpIntegration = index.httpIntegration;
|
|
54
54
|
exports.nativeNodeFetchIntegration = index$1.nativeNodeFetchIntegration;
|
|
55
55
|
exports.fsIntegration = fs.fsIntegration;
|
|
56
|
-
exports.consoleIntegration = console.consoleIntegration;
|
|
57
56
|
exports.nodeContextIntegration = context.nodeContextIntegration;
|
|
58
57
|
exports.contextLinesIntegration = contextlines.contextLinesIntegration;
|
|
59
58
|
exports.localVariablesIntegration = index$2.localVariablesIntegration;
|
|
@@ -91,6 +90,7 @@ exports.dataloaderIntegration = dataloader.dataloaderIntegration;
|
|
|
91
90
|
exports.amqplibIntegration = amqplib.amqplibIntegration;
|
|
92
91
|
exports.vercelAIIntegration = index$5.vercelAIIntegration;
|
|
93
92
|
exports.childProcessIntegration = childProcess.childProcessIntegration;
|
|
93
|
+
exports.createSentryWinstonTransport = winston.createSentryWinstonTransport;
|
|
94
94
|
exports.SentryContextManager = contextManager.SentryContextManager;
|
|
95
95
|
exports.generateInstrumentOnce = instrument.generateInstrumentOnce;
|
|
96
96
|
exports.getDefaultIntegrations = index$6.getDefaultIntegrations;
|
|
@@ -125,6 +125,7 @@ exports.captureFeedback = core.captureFeedback;
|
|
|
125
125
|
exports.captureMessage = core.captureMessage;
|
|
126
126
|
exports.captureSession = core.captureSession;
|
|
127
127
|
exports.close = core.close;
|
|
128
|
+
exports.consoleIntegration = core.consoleIntegration;
|
|
128
129
|
exports.consoleLoggingIntegration = core.consoleLoggingIntegration;
|
|
129
130
|
exports.continueTrace = core.continueTrace;
|
|
130
131
|
exports.createTransport = core.createTransport;
|
|
@@ -145,6 +146,7 @@ exports.getSpanStatusFromHttpCode = core.getSpanStatusFromHttpCode;
|
|
|
145
146
|
exports.getTraceData = core.getTraceData;
|
|
146
147
|
exports.getTraceMetaTags = core.getTraceMetaTags;
|
|
147
148
|
exports.inboundFiltersIntegration = core.inboundFiltersIntegration;
|
|
149
|
+
exports.instrumentSupabaseClient = core.instrumentSupabaseClient;
|
|
148
150
|
exports.isInitialized = core.isInitialized;
|
|
149
151
|
exports.lastEventId = core.lastEventId;
|
|
150
152
|
exports.linkedErrorsIntegration = core.linkedErrorsIntegration;
|
|
@@ -169,6 +171,7 @@ exports.startNewTrace = core.startNewTrace;
|
|
|
169
171
|
exports.startSession = core.startSession;
|
|
170
172
|
exports.startSpan = core.startSpan;
|
|
171
173
|
exports.startSpanManual = core.startSpanManual;
|
|
174
|
+
exports.supabaseIntegration = core.supabaseIntegration;
|
|
172
175
|
exports.suppressTracing = core.suppressTracing;
|
|
173
176
|
exports.trpcMiddleware = core.trpcMiddleware;
|
|
174
177
|
exports.updateSpanName = core.updateSpanName;
|
|
@@ -177,5 +180,5 @@ exports.withIsolationScope = core.withIsolationScope;
|
|
|
177
180
|
exports.withMonitor = core.withMonitor;
|
|
178
181
|
exports.withScope = core.withScope;
|
|
179
182
|
exports.zodErrorsIntegration = core.zodErrorsIntegration;
|
|
180
|
-
exports.logger =
|
|
183
|
+
exports.logger = exports$1;
|
|
181
184
|
//# sourceMappingURL=index.js.map
|
package/build/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const node_util = require('node:util');
|
|
4
4
|
const node_worker_threads = require('node:worker_threads');
|
|
5
5
|
const core = require('@sentry/core');
|
|
6
6
|
const nodeVersion = require('../../nodeVersion.js');
|
|
7
7
|
const debug = require('../../utils/debug.js');
|
|
8
8
|
|
|
9
|
-
const { isPromise } =
|
|
9
|
+
const { isPromise } = node_util.types;
|
|
10
10
|
|
|
11
11
|
// This string is a placeholder that gets overwritten with the worker code.
|
|
12
|
-
const base64WorkerScript = 'LyohIEBzZW50cnkvbm9kZSA5LjEyLjAgKDRlYjc4ZTUpIHwgaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdCAqLwppbXBvcnR7U2Vzc2lvbiBhcyB0fWZyb20ibm9kZTppbnNwZWN0b3IiO2ltcG9ydHt3b3JrZXJEYXRhIGFzIG4scGFyZW50UG9ydCBhcyBlfWZyb20ibm9kZTp3b3JrZXJfdGhyZWFkcyI7aW1wb3J0e3Bvc2l4IGFzIHIsc2VwIGFzIG99ZnJvbSJub2RlOnBhdGgiO2ltcG9ydCphcyBzIGZyb20ibm9kZTpodHRwIjtpbXBvcnQqYXMgaSBmcm9tIm5vZGU6aHR0cHMiO2ltcG9ydHtSZWFkYWJsZSBhcyBjfWZyb20ibm9kZTpzdHJlYW0iO2ltcG9ydHtjcmVhdGVHemlwIGFzIHV9ZnJvbSJub2RlOnpsaWIiO2ltcG9ydCphcyBhIGZyb20ibm9kZTpuZXQiO2ltcG9ydCphcyBmIGZyb20ibm9kZTp0bHMiO2NvbnN0IGg9InVuZGVmaW5lZCI9PXR5cGVvZiBfX1NFTlRSWV9ERUJVR19ffHxfX1NFTlRSWV9ERUJVR19fLHA9Z2xvYmFsVGhpcyxsPSJ1bmRlZmluZWQiPT10eXBlb2YgX19TRU5UUllfREVCVUdfX3x8X19TRU5UUllfREVCVUdfXyxkPSI5LjEyLjAiO2Z1bmN0aW9uIG0oKXtyZXR1cm4gZyhwKSxwfWZ1bmN0aW9uIGcodCl7Y29uc3Qgbj10Ll9fU0VOVFJZX189dC5fX1NFTlRSWV9ffHx7fTtyZXR1cm4gbi52ZXJzaW9uPW4udmVyc2lvbnx8ZCxuW2RdPW5bZF18fHt9fWZ1bmN0aW9uIHkodCxuLGU9cCl7Y29uc3Qgcj1lLl9fU0VOVFJZX189ZS5fX1NFTlRSWV9ffHx7fSxvPXJbZF09cltkXXx8e307cmV0dXJuIG9bdF18fChvW3RdPW4oKSl9Y29uc3QgYj1bImRlYnVnIiwiaW5mbyIsIndhcm4iLCJlcnJvciIsImxvZyIsImFzc2VydCIsInRyYWNlIl0sXz17fTtmdW5jdGlvbiB2KHQpe2lmKCEoImNvbnNvbGUiaW4gcCkpcmV0dXJuIHQoKTtjb25zdCBuPXAuY29uc29sZSxlPXt9LHI9T2JqZWN0LmtleXMoXyk7ci5mb3JFYWNoKCh0PT57Y29uc3Qgcj1fW3RdO2VbdF09blt0XSxuW3RdPXJ9KSk7dHJ5e3JldHVybiB0KCl9ZmluYWxseXtyLmZvckVhY2goKHQ9PntuW3RdPWVbdF19KSl9fWNvbnN0IHc9eSgibG9nZ2VyIiwoZnVuY3Rpb24oKXtsZXQgdD0hMTtjb25zdCBuPXtlbmFibGU6KCk9Pnt0PSEwfSxkaXNhYmxlOigpPT57dD0hMX0saXNFbmFibGVkOigpPT50fTtyZXR1cm4gbD9iLmZvckVhY2goKGU9PntuW2VdPSguLi5uKT0+e3QmJnYoKCgpPT57cC5jb25zb2xlW2VdKGBTZW50cnkgTG9nZ2VyIFske2V9XTpgLC4uLm4pfSkpfX0pKTpiLmZvckVhY2goKHQ9PntuW3RdPSgpPT57fX0pKSxufSkpLFM9NTAsJD0iPyIsRT0vY2FwdHVyZU1lc3NhZ2V8Y2FwdHVyZUV4Y2VwdGlvbi87ZnVuY3Rpb24geCh0KXtyZXR1cm4gdFt0Lmxlbmd0aC0xXXx8e319Y29uc3QgTj0iPGFub255bW91cz4iO2NvbnN0IFQ9MWUzO2Z1bmN0aW9uIEMoKXtyZXR1cm4gRGF0ZS5ub3coKS9UfWNvbnN0IFI9ZnVuY3Rpb24oKXtjb25zdHtwZXJmb3JtYW5jZTp0fT1wO2lmKCF0Py5ub3cpcmV0dXJuIEM7Y29uc3Qgbj1EYXRlLm5vdygpLXQubm93KCksZT1udWxsPT10LnRpbWVPcmlnaW4/bjp0LnRpbWVPcmlnaW47cmV0dXJuKCk9PihlK3Qubm93KCkpL1R9KCksaz1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nO2Z1bmN0aW9uIGoodCxuKXtyZXR1cm4gay5jYWxsKHQpPT09YFtvYmplY3QgJHtufV1gfWZ1bmN0aW9uIEQodCl7cmV0dXJuIGoodCwiU3RyaW5nIil9ZnVuY3Rpb24gSSh0KXtyZXR1cm4gaih0LCJPYmplY3QiKX1mdW5jdGlvbiBPKHQpe3JldHVybiBCb29sZWFuKHQ/LnRoZW4mJiJmdW5jdGlvbiI9PXR5cGVvZiB0LnRoZW4pfWZ1bmN0aW9uIEEodCxuKXt0cnl7cmV0dXJuIHQgaW5zdGFuY2VvZiBufWNhdGNoKHQpe3JldHVybiExfX1jb25zdCBQPXAsVT04MDtmdW5jdGlvbiBNKHQsbil7Y29uc3QgZT10LHI9W107aWYoIWU/LnRhZ05hbWUpcmV0dXJuIiI7aWYoUC5IVE1MRWxlbWVudCYmZSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50JiZlLmRhdGFzZXQpe2lmKGUuZGF0YXNldC5zZW50cnlDb21wb25lbnQpcmV0dXJuIGUuZGF0YXNldC5zZW50cnlDb21wb25lbnQ7aWYoZS5kYXRhc2V0LnNlbnRyeUVsZW1lbnQpcmV0dXJuIGUuZGF0YXNldC5zZW50cnlFbGVtZW50fXIucHVzaChlLnRhZ05hbWUudG9Mb3dlckNhc2UoKSk7Y29uc3Qgbz1uPy5sZW5ndGg/bi5maWx0ZXIoKHQ9PmUuZ2V0QXR0cmlidXRlKHQpKSkubWFwKCh0PT5bdCxlLmdldEF0dHJpYnV0ZSh0KV0pKTpudWxsO2lmKG8/Lmxlbmd0aClvLmZvckVhY2goKHQ9PntyLnB1c2goYFske3RbMF19PSIke3RbMV19Il1gKX0pKTtlbHNle2UuaWQmJnIucHVzaChgIyR7ZS5pZH1gKTtjb25zdCB0PWUuY2xhc3NOYW1lO2lmKHQmJkQodCkpe2NvbnN0IG49dC5zcGxpdCgvXHMrLyk7Zm9yKGNvbnN0IHQgb2YgbilyLnB1c2goYC4ke3R9YCl9fWNvbnN0IHM9WyJhcmlhLWxhYmVsIiwidHlwZSIsIm5hbWUiLCJ0aXRsZSIsImFsdCJdO2Zvcihjb25zdCB0IG9mIHMpe2NvbnN0IG49ZS5nZXRBdHRyaWJ1dGUodCk7biYmci5wdXNoKGBbJHt0fT0iJHtufSJdYCl9cmV0dXJuIHIuam9pbigiIil9ZnVuY3Rpb24gTCh0LG49MCl7cmV0dXJuInN0cmluZyIhPXR5cGVvZiB0fHwwPT09bnx8dC5sZW5ndGg8PW4/dDpgJHt0LnNsaWNlKDAsbil9Li4uYH1mdW5jdGlvbiBCKHQpe2lmKGZ1bmN0aW9uKHQpe3N3aXRjaChrLmNhbGwodCkpe2Nhc2UiW29iamVjdCBFcnJvcl0iOmNhc2UiW29iamVjdCBFeGNlcHRpb25dIjpjYXNlIltvYmplY3QgRE9NRXhjZXB0aW9uXSI6Y2FzZSJbb2JqZWN0IFdlYkFzc2VtYmx5LkV4Y2VwdGlvbl0iOnJldHVybiEwO2RlZmF1bHQ6cmV0dXJuIEEodCxFcnJvcil9fSh0KSlyZXR1cm57bWVzc2FnZTp0Lm1lc3NhZ2UsbmFtZTp0Lm5hbWUsc3RhY2s6dC5zdGFjaywuLi5KKHQpfTtpZihuPXQsInVuZGVmaW5lZCIhPXR5cGVvZiBFdmVudCYmQShuLEV2ZW50KSl7Y29uc3Qgbj17dHlwZTp0LnR5cGUsdGFyZ2V0OkcodC50YXJnZXQpLGN1cnJlbnRUYXJnZXQ6Ryh0LmN1cnJlbnRUYXJnZXQpLC4uLkoodCl9O3JldHVybiJ1bmRlZmluZWQiIT10eXBlb2YgQ3VzdG9tRXZlbnQmJkEodCxDdXN0b21FdmVudCkmJihuLmRldGFpbD10LmRldGFpbCksbn1yZXR1cm4gdDt2YXIgbn1mdW5jdGlvbiBHKHQpe3RyeXtyZXR1cm4gbj10LCJ1bmRlZmluZWQiIT10eXBlb2YgRWxlbWVudCYmQShuLEVsZW1lbnQpP2Z1bmN0aW9uKHQsbj17fSl7aWYoIXQpcmV0dXJuIjx1bmtub3duPiI7dHJ5e2xldCBlPXQ7Y29uc3Qgcj01LG89W107bGV0IHM9MCxpPTA7Y29uc3QgYz0iID4gIix1PWMubGVuZ3RoO2xldCBhO2NvbnN0IGY9QXJyYXkuaXNBcnJheShuKT9uOm4ua2V5QXR0cnMsaD0hQXJyYXkuaXNBcnJheShuKSYmbi5tYXhTdHJpbmdMZW5ndGh8fFU7Zm9yKDtlJiZzKys8ciYmKGE9TShlLGYpLCEoImh0bWwiPT09YXx8cz4xJiZpK28ubGVuZ3RoKnUrYS5sZW5ndGg+PWgpKTspby5wdXNoKGEpLGkrPWEubGVuZ3RoLGU9ZS5wYXJlbnROb2RlO3JldHVybiBvLnJldmVyc2UoKS5qb2luKGMpfWNhdGNoKHQpe3JldHVybiI8dW5rbm93bj4ifX0odCk6T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHQpfWNhdGNoKHQpe3JldHVybiI8dW5rbm93bj4ifXZhciBufWZ1bmN0aW9uIEoodCl7aWYoIm9iamVjdCI9PXR5cGVvZiB0JiZudWxsIT09dCl7Y29uc3Qgbj17fTtmb3IoY29uc3QgZSBpbiB0KU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0LGUpJiYobltlXT10W2VdKTtyZXR1cm4gbn1yZXR1cm57fX1mdW5jdGlvbiBZKHQ9ZnVuY3Rpb24oKXtjb25zdCB0PXA7cmV0dXJuIHQuY3J5cHRvfHx0Lm1zQ3J5cHRvfSgpKXtsZXQgbj0oKT0+MTYqTWF0aC5yYW5kb20oKTt0cnl7aWYodD8ucmFuZG9tVVVJRClyZXR1cm4gdC5yYW5kb21VVUlEKCkucmVwbGFjZSgvLS9nLCIiKTt0Py5nZXRSYW5kb21WYWx1ZXMmJihuPSgpPT57Y29uc3Qgbj1uZXcgVWludDhBcnJheSgxKTtyZXR1cm4gdC5nZXRSYW5kb21WYWx1ZXMobiksblswXX0pfWNhdGNoKHQpe31yZXR1cm4oWzFlN10rMWUzKzRlMys4ZTMrMWUxMSkucmVwbGFjZSgvWzAxOF0vZywodD0+KHReKDE1Jm4oKSk+PnQvNCkudG9TdHJpbmcoMTYpKSl9dmFyIHo7ZnVuY3Rpb24gSCh0KXtyZXR1cm4gbmV3IEYoKG49PntuKHQpfSkpfSFmdW5jdGlvbih0KXt0W3QuUEVORElORz0wXT0iUEVORElORyI7dFt0LlJFU09MVkVEPTFdPSJSRVNPTFZFRCI7dFt0LlJFSkVDVEVEPTJdPSJSRUpFQ1RFRCJ9KHp8fCh6PXt9KSk7Y2xhc3MgRntjb25zdHJ1Y3Rvcih0KXt0aGlzLnQ9ei5QRU5ESU5HLHRoaXMubz1bXSx0aGlzLmkodCl9dGhlbih0LG4pe3JldHVybiBuZXcgRigoKGUscik9Pnt0aGlzLm8ucHVzaChbITEsbj0+e2lmKHQpdHJ5e2UodChuKSl9Y2F0Y2godCl7cih0KX1lbHNlIGUobil9LHQ9PntpZihuKXRyeXtlKG4odCkpfWNhdGNoKHQpe3IodCl9ZWxzZSByKHQpfV0pLHRoaXMudSgpfSkpfWNhdGNoKHQpe3JldHVybiB0aGlzLnRoZW4oKHQ9PnQpLHQpfWZpbmFsbHkodCl7cmV0dXJuIG5ldyBGKCgobixlKT0+e2xldCByLG87cmV0dXJuIHRoaXMudGhlbigobj0+e289ITEscj1uLHQmJnQoKX0pLChuPT57bz0hMCxyPW4sdCYmdCgpfSkpLnRoZW4oKCgpPT57bz9lKHIpOm4ocil9KSl9KSl9dSgpe2lmKHRoaXMudD09PXouUEVORElORylyZXR1cm47Y29uc3QgdD10aGlzLm8uc2xpY2UoKTt0aGlzLm89W10sdC5mb3JFYWNoKCh0PT57dFswXXx8KHRoaXMudD09PXouUkVTT0xWRUQmJnRbMV0odGhpcy5oKSx0aGlzLnQ9PT16LlJFSkVDVEVEJiZ0WzJdKHRoaXMuaCksdFswXT0hMCl9KSl9aSh0KXtjb25zdCBuPSh0LG4pPT57dGhpcy50PT09ei5QRU5ESU5HJiYoTyhuKT9uLnRoZW4oZSxyKToodGhpcy50PXQsdGhpcy5oPW4sdGhpcy51KCkpKX0sZT10PT57bih6LlJFU09MVkVELHQpfSxyPXQ9PntuKHouUkVKRUNURUQsdCl9O3RyeXt0KGUscil9Y2F0Y2godCl7cih0KX19fWZ1bmN0aW9uIFcodCl7Y29uc3Qgbj1SKCksZT17c2lkOlkoKSxpbml0OiEwLHRpbWVzdGFtcDpuLHN0YXJ0ZWQ6bixkdXJhdGlvbjowLHN0YXR1czoib2siLGVycm9yczowLGlnbm9yZUR1cmF0aW9uOiExLHRvSlNPTjooKT0+ZnVuY3Rpb24odCl7cmV0dXJue3NpZDpgJHt0LnNpZH1gLGluaXQ6dC5pbml0LHN0YXJ0ZWQ6bmV3IERhdGUoMWUzKnQuc3RhcnRlZCkudG9JU09TdHJpbmcoKSx0aW1lc3RhbXA6bmV3IERhdGUoMWUzKnQudGltZXN0YW1wKS50b0lTT1N0cmluZygpLHN0YXR1czp0LnN0YXR1cyxlcnJvcnM6dC5lcnJvcnMsZGlkOiJudW1iZXIiPT10eXBlb2YgdC5kaWR8fCJzdHJpbmciPT10eXBlb2YgdC5kaWQ/YCR7dC5kaWR9YDp2b2lkIDAsZHVyYXRpb246dC5kdXJhdGlvbixhYm5vcm1hbF9tZWNoYW5pc206dC5hYm5vcm1hbF9tZWNoYW5pc20sYXR0cnM6e3JlbGVhc2U6dC5yZWxlYXNlLGVudmlyb25tZW50OnQuZW52aXJvbm1lbnQsaXBfYWRkcmVzczp0LmlwQWRkcmVzcyx1c2VyX2FnZW50OnQudXNlckFnZW50fX19KGUpfTtyZXR1cm4gdCYmSyhlLHQpLGV9ZnVuY3Rpb24gSyh0LG49e30pe2lmKG4udXNlciYmKCF0LmlwQWRkcmVzcyYmbi51c2VyLmlwX2FkZHJlc3MmJih0LmlwQWRkcmVzcz1uLnVzZXIuaXBfYWRkcmVzcyksdC5kaWR8fG4uZGlkfHwodC5kaWQ9bi51c2VyLmlkfHxuLnVzZXIuZW1haWx8fG4udXNlci51c2VybmFtZSkpLHQudGltZXN0YW1wPW4udGltZXN0YW1wfHxSKCksbi5hYm5vcm1hbF9tZWNoYW5pc20mJih0LmFibm9ybWFsX21lY2hhbmlzbT1uLmFibm9ybWFsX21lY2hhbmlzbSksbi5pZ25vcmVEdXJhdGlvbiYmKHQuaWdub3JlRHVyYXRpb249bi5pZ25vcmVEdXJhdGlvbiksbi5zaWQmJih0LnNpZD0zMj09PW4uc2lkLmxlbmd0aD9uLnNpZDpZKCkpLHZvaWQgMCE9PW4uaW5pdCYmKHQuaW5pdD1uLmluaXQpLCF0LmRpZCYmbi5kaWQmJih0LmRpZD1gJHtuLmRpZH1gKSwibnVtYmVyIj09dHlwZW9mIG4uc3RhcnRlZCYmKHQuc3RhcnRlZD1uLnN0YXJ0ZWQpLHQuaWdub3JlRHVyYXRpb24pdC5kdXJhdGlvbj12b2lkIDA7ZWxzZSBpZigibnVtYmVyIj09dHlwZW9mIG4uZHVyYXRpb24pdC5kdXJhdGlvbj1uLmR1cmF0aW9uO2Vsc2V7Y29uc3Qgbj10LnRpbWVzdGFtcC10LnN0YXJ0ZWQ7dC5kdXJhdGlvbj1uPj0wP246MH1uLnJlbGVhc2UmJih0LnJlbGVhc2U9bi5yZWxlYXNlKSxuLmVudmlyb25tZW50JiYodC5lbnZpcm9ubWVudD1uLmVudmlyb25tZW50KSwhdC5pcEFkZHJlc3MmJm4uaXBBZGRyZXNzJiYodC5pcEFkZHJlc3M9bi5pcEFkZHJlc3MpLCF0LnVzZXJBZ2VudCYmbi51c2VyQWdlbnQmJih0LnVzZXJBZ2VudD1uLnVzZXJBZ2VudCksIm51bWJlciI9PXR5cGVvZiBuLmVycm9ycyYmKHQuZXJyb3JzPW4uZXJyb3JzKSxuLnN0YXR1cyYmKHQuc3RhdHVzPW4uc3RhdHVzKX1mdW5jdGlvbiBWKCl7cmV0dXJuIFkoKX1mdW5jdGlvbiBaKCl7cmV0dXJuIFkoKS5zdWJzdHJpbmcoMTYpfWZ1bmN0aW9uIHEodCxuLGU9Mil7aWYoIW58fCJvYmplY3QiIT10eXBlb2Ygbnx8ZTw9MClyZXR1cm4gbjtpZih0JiYwPT09T2JqZWN0LmtleXMobikubGVuZ3RoKXJldHVybiB0O2NvbnN0IHI9ey4uLnR9O2Zvcihjb25zdCB0IGluIG4pT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG4sdCkmJihyW3RdPXEoclt0XSxuW3RdLGUtMSkpO3JldHVybiByfWNvbnN0IFE9Il9zZW50cnlTcGFuIjtmdW5jdGlvbiBYKHQsbil7bj9mdW5jdGlvbih0LG4sZSl7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eSh0LG4se3ZhbHVlOmUsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfSl9Y2F0Y2goZSl7bCYmdy5sb2coYEZhaWxlZCB0byBhZGQgbm9uLWVudW1lcmFibGUgcHJvcGVydHkgIiR7bn0iIHRvIG9iamVjdGAsdCl9fSh0LFEsbik6ZGVsZXRlIHRbUV19ZnVuY3Rpb24gdHQodCl7cmV0dXJuIHRbUV19Y2xhc3MgbnR7Y29uc3RydWN0b3IoKXt0aGlzLnA9ITEsdGhpcy5sPVtdLHRoaXMubT1bXSx0aGlzLl89W10sdGhpcy52PVtdLHRoaXMuUz17fSx0aGlzLk49e30sdGhpcy5UPXt9LHRoaXMuQz17fSx0aGlzLlI9e30sdGhpcy5rPXt0cmFjZUlkOlYoKSxzYW1wbGVSYW5kOk1hdGgucmFuZG9tKCl9fWNsb25lKCl7Y29uc3QgdD1uZXcgbnQ7cmV0dXJuIHQuXz1bLi4udGhpcy5fXSx0Lk49ey4uLnRoaXMuTn0sdC5UPXsuLi50aGlzLlR9LHQuQz17Li4udGhpcy5DfSx0aGlzLkMuZmxhZ3MmJih0LkMuZmxhZ3M9e3ZhbHVlczpbLi4udGhpcy5DLmZsYWdzLnZhbHVlc119KSx0LlM9dGhpcy5TLHQuaj10aGlzLmosdC5EPXRoaXMuRCx0Lkk9dGhpcy5JLHQuTz10aGlzLk8sdC5tPVsuLi50aGlzLm1dLHQudj1bLi4udGhpcy52XSx0LlI9ey4uLnRoaXMuUn0sdC5rPXsuLi50aGlzLmt9LHQuQT10aGlzLkEsdC5QPXRoaXMuUCxYKHQsdHQodGhpcykpLHR9c2V0Q2xpZW50KHQpe3RoaXMuQT10fXNldExhc3RFdmVudElkKHQpe3RoaXMuUD10fWdldENsaWVudCgpe3JldHVybiB0aGlzLkF9bGFzdEV2ZW50SWQoKXtyZXR1cm4gdGhpcy5QfWFkZFNjb3BlTGlzdGVuZXIodCl7dGhpcy5sLnB1c2godCl9YWRkRXZlbnRQcm9jZXNzb3IodCl7cmV0dXJuIHRoaXMubS5wdXNoKHQpLHRoaXN9c2V0VXNlcih0KXtyZXR1cm4gdGhpcy5TPXR8fHtlbWFpbDp2b2lkIDAsaWQ6dm9pZCAwLGlwX2FkZHJlc3M6dm9pZCAwLHVzZXJuYW1lOnZvaWQgMH0sdGhpcy5EJiZLKHRoaXMuRCx7dXNlcjp0fSksdGhpcy5VKCksdGhpc31nZXRVc2VyKCl7cmV0dXJuIHRoaXMuU31zZXRUYWdzKHQpe3JldHVybiB0aGlzLk49ey4uLnRoaXMuTiwuLi50fSx0aGlzLlUoKSx0aGlzfXNldFRhZyh0LG4pe3JldHVybiB0aGlzLk49ey4uLnRoaXMuTixbdF06bn0sdGhpcy5VKCksdGhpc31zZXRFeHRyYXModCl7cmV0dXJuIHRoaXMuVD17Li4udGhpcy5ULC4uLnR9LHRoaXMuVSgpLHRoaXN9c2V0RXh0cmEodCxuKXtyZXR1cm4gdGhpcy5UPXsuLi50aGlzLlQsW3RdOm59LHRoaXMuVSgpLHRoaXN9c2V0RmluZ2VycHJpbnQodCl7cmV0dXJuIHRoaXMuTz10LHRoaXMuVSgpLHRoaXN9c2V0TGV2ZWwodCl7cmV0dXJuIHRoaXMuaj10LHRoaXMuVSgpLHRoaXN9c2V0VHJhbnNhY3Rpb25OYW1lKHQpe3JldHVybiB0aGlzLkk9dCx0aGlzLlUoKSx0aGlzfXNldENvbnRleHQodCxuKXtyZXR1cm4gbnVsbD09PW4/ZGVsZXRlIHRoaXMuQ1t0XTp0aGlzLkNbdF09bix0aGlzLlUoKSx0aGlzfXNldFNlc3Npb24odCl7cmV0dXJuIHQ/dGhpcy5EPXQ6ZGVsZXRlIHRoaXMuRCx0aGlzLlUoKSx0aGlzfWdldFNlc3Npb24oKXtyZXR1cm4gdGhpcy5EfXVwZGF0ZSh0KXtpZighdClyZXR1cm4gdGhpcztjb25zdCBuPSJmdW5jdGlvbiI9PXR5cGVvZiB0P3QodGhpcyk6dCxlPW4gaW5zdGFuY2VvZiBudD9uLmdldFNjb3BlRGF0YSgpOkkobik/dDp2b2lkIDAse3RhZ3M6cixleHRyYTpvLHVzZXI6cyxjb250ZXh0czppLGxldmVsOmMsZmluZ2VycHJpbnQ6dT1bXSxwcm9wYWdhdGlvbkNvbnRleHQ6YX09ZXx8e307cmV0dXJuIHRoaXMuTj17Li4udGhpcy5OLC4uLnJ9LHRoaXMuVD17Li4udGhpcy5ULC4uLm99LHRoaXMuQz17Li4udGhpcy5DLC4uLml9LHMmJk9iamVjdC5rZXlzKHMpLmxlbmd0aCYmKHRoaXMuUz1zKSxjJiYodGhpcy5qPWMpLHUubGVuZ3RoJiYodGhpcy5PPXUpLGEmJih0aGlzLms9YSksdGhpc31jbGVhcigpe3JldHVybiB0aGlzLl89W10sdGhpcy5OPXt9LHRoaXMuVD17fSx0aGlzLlM9e30sdGhpcy5DPXt9LHRoaXMuaj12b2lkIDAsdGhpcy5JPXZvaWQgMCx0aGlzLk89dm9pZCAwLHRoaXMuRD12b2lkIDAsWCh0aGlzLHZvaWQgMCksdGhpcy52PVtdLHRoaXMuc2V0UHJvcGFnYXRpb25Db250ZXh0KHt0cmFjZUlkOlYoKSxzYW1wbGVSYW5kOk1hdGgucmFuZG9tKCl9KSx0aGlzLlUoKSx0aGlzfWFkZEJyZWFkY3J1bWIodCxuKXtjb25zdCBlPSJudW1iZXIiPT10eXBlb2Ygbj9uOjEwMDtpZihlPD0wKXJldHVybiB0aGlzO2NvbnN0IHI9e3RpbWVzdGFtcDpDKCksLi4udCxtZXNzYWdlOnQubWVzc2FnZT9MKHQubWVzc2FnZSwyMDQ4KTp0Lm1lc3NhZ2V9O3JldHVybiB0aGlzLl8ucHVzaChyKSx0aGlzLl8ubGVuZ3RoPmUmJih0aGlzLl89dGhpcy5fLnNsaWNlKC1lKSx0aGlzLkE/LnJlY29yZERyb3BwZWRFdmVudCgiYnVmZmVyX292ZXJmbG93IiwibG9nX2l0ZW0iKSksdGhpcy5VKCksdGhpc31nZXRMYXN0QnJlYWRjcnVtYigpe3JldHVybiB0aGlzLl9bdGhpcy5fLmxlbmd0aC0xXX1jbGVhckJyZWFkY3J1bWJzKCl7cmV0dXJuIHRoaXMuXz1bXSx0aGlzLlUoKSx0aGlzfWFkZEF0dGFjaG1lbnQodCl7cmV0dXJuIHRoaXMudi5wdXNoKHQpLHRoaXN9Y2xlYXJBdHRhY2htZW50cygpe3JldHVybiB0aGlzLnY9W10sdGhpc31nZXRTY29wZURhdGEoKXtyZXR1cm57YnJlYWRjcnVtYnM6dGhpcy5fLGF0dGFjaG1lbnRzOnRoaXMudixjb250ZXh0czp0aGlzLkMsdGFnczp0aGlzLk4sZXh0cmE6dGhpcy5ULHVzZXI6dGhpcy5TLGxldmVsOnRoaXMuaixmaW5nZXJwcmludDp0aGlzLk98fFtdLGV2ZW50UHJvY2Vzc29yczp0aGlzLm0scHJvcGFnYXRpb25Db250ZXh0OnRoaXMuayxzZGtQcm9jZXNzaW5nTWV0YWRhdGE6dGhpcy5SLHRyYW5zYWN0aW9uTmFtZTp0aGlzLkksc3Bhbjp0dCh0aGlzKX19c2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKHQpe3JldHVybiB0aGlzLlI9cSh0aGlzLlIsdCwyKSx0aGlzfXNldFByb3BhZ2F0aW9uQ29udGV4dCh0KXtyZXR1cm4gdGhpcy5rPXQsdGhpc31nZXRQcm9wYWdhdGlvbkNvbnRleHQoKXtyZXR1cm4gdGhpcy5rfWNhcHR1cmVFeGNlcHRpb24odCxuKXtjb25zdCBlPW4/LmV2ZW50X2lkfHxZKCk7aWYoIXRoaXMuQSlyZXR1cm4gdy53YXJuKCJObyBjbGllbnQgY29uZmlndXJlZCBvbiBzY29wZSAtIHdpbGwgbm90IGNhcHR1cmUgZXhjZXB0aW9uISIpLGU7Y29uc3Qgcj1uZXcgRXJyb3IoIlNlbnRyeSBzeW50aGV0aWNFeGNlcHRpb24iKTtyZXR1cm4gdGhpcy5BLmNhcHR1cmVFeGNlcHRpb24odCx7b3JpZ2luYWxFeGNlcHRpb246dCxzeW50aGV0aWNFeGNlcHRpb246ciwuLi5uLGV2ZW50X2lkOmV9LHRoaXMpLGV9Y2FwdHVyZU1lc3NhZ2UodCxuLGUpe2NvbnN0IHI9ZT8uZXZlbnRfaWR8fFkoKTtpZighdGhpcy5BKXJldHVybiB3Lndhcm4oIk5vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBtZXNzYWdlISIpLHI7Y29uc3Qgbz1uZXcgRXJyb3IodCk7cmV0dXJuIHRoaXMuQS5jYXB0dXJlTWVzc2FnZSh0LG4se29yaWdpbmFsRXhjZXB0aW9uOnQsc3ludGhldGljRXhjZXB0aW9uOm8sLi4uZSxldmVudF9pZDpyfSx0aGlzKSxyfWNhcHR1cmVFdmVudCh0LG4pe2NvbnN0IGU9bj8uZXZlbnRfaWR8fFkoKTtyZXR1cm4gdGhpcy5BPyh0aGlzLkEuY2FwdHVyZUV2ZW50KHQsey4uLm4sZXZlbnRfaWQ6ZX0sdGhpcyksZSk6KHcud2FybigiTm8gY2xpZW50IGNvbmZpZ3VyZWQgb24gc2NvcGUgLSB3aWxsIG5vdCBjYXB0dXJlIGV2ZW50ISIpLGUpfVUoKXt0aGlzLnB8fCh0aGlzLnA9ITAsdGhpcy5sLmZvckVhY2goKHQ9Pnt0KHRoaXMpfSkpLHRoaXMucD0hMSl9fWNsYXNzIGV0e2NvbnN0cnVjdG9yKHQsbil7bGV0IGUscjtlPXR8fG5ldyBudCxyPW58fG5ldyBudCx0aGlzLk09W3tzY29wZTplfV0sdGhpcy5MPXJ9d2l0aFNjb3BlKHQpe2NvbnN0IG49dGhpcy5CKCk7bGV0IGU7dHJ5e2U9dChuKX1jYXRjaCh0KXt0aHJvdyB0aGlzLkcoKSx0fXJldHVybiBPKGUpP2UudGhlbigodD0+KHRoaXMuRygpLHQpKSwodD0+e3Rocm93IHRoaXMuRygpLHR9KSk6KHRoaXMuRygpLGUpfWdldENsaWVudCgpe3JldHVybiB0aGlzLmdldFN0YWNrVG9wKCkuY2xpZW50fWdldFNjb3BlKCl7cmV0dXJuIHRoaXMuZ2V0U3RhY2tUb3AoKS5zY29wZX1nZXRJc29sYXRpb25TY29wZSgpe3JldHVybiB0aGlzLkx9Z2V0U3RhY2tUb3AoKXtyZXR1cm4gdGhpcy5NW3RoaXMuTS5sZW5ndGgtMV19Qigpe2NvbnN0IHQ9dGhpcy5nZXRTY29wZSgpLmNsb25lKCk7cmV0dXJuIHRoaXMuTS5wdXNoKHtjbGllbnQ6dGhpcy5nZXRDbGllbnQoKSxzY29wZTp0fSksdH1HKCl7cmV0dXJuISh0aGlzLk0ubGVuZ3RoPD0xKSYmISF0aGlzLk0ucG9wKCl9fWZ1bmN0aW9uIHJ0KCl7Y29uc3QgdD1nKG0oKSk7cmV0dXJuIHQuc3RhY2s9dC5zdGFja3x8bmV3IGV0KHkoImRlZmF1bHRDdXJyZW50U2NvcGUiLCgoKT0+bmV3IG50KSkseSgiZGVmYXVsdElzb2xhdGlvblNjb3BlIiwoKCk9Pm5ldyBudCkpKX1mdW5jdGlvbiBvdCh0KXtyZXR1cm4gcnQoKS53aXRoU2NvcGUodCl9ZnVuY3Rpb24gc3QodCxuKXtjb25zdCBlPXJ0KCk7cmV0dXJuIGUud2l0aFNjb3BlKCgoKT0+KGUuZ2V0U3RhY2tUb3AoKS5zY29wZT10LG4odCkpKSl9ZnVuY3Rpb24gaXQodCl7cmV0dXJuIHJ0KCkud2l0aFNjb3BlKCgoKT0+dChydCgpLmdldElzb2xhdGlvblNjb3BlKCkpKSl9ZnVuY3Rpb24gY3QodCl7Y29uc3Qgbj1nKHQpO3JldHVybiBuLmFjcz9uLmFjczp7d2l0aElzb2xhdGlvblNjb3BlOml0LHdpdGhTY29wZTpvdCx3aXRoU2V0U2NvcGU6c3Qsd2l0aFNldElzb2xhdGlvblNjb3BlOih0LG4pPT5pdChuKSxnZXRDdXJyZW50U2NvcGU6KCk9PnJ0KCkuZ2V0U2NvcGUoKSxnZXRJc29sYXRpb25TY29wZTooKT0+cnQoKS5nZXRJc29sYXRpb25TY29wZSgpfX1mdW5jdGlvbiB1dCgpe3JldHVybiBjdChtKCkpLmdldEN1cnJlbnRTY29wZSgpLmdldENsaWVudCgpfWNvbnN0IGF0PSJzZW50cnkuc291cmNlIixmdD0ic2VudHJ5LnNhbXBsZV9yYXRlIixodD0ic2VudHJ5Lm9wIixwdD0ic2VudHJ5Lm9yaWdpbiIsbHQ9MCxkdD0xLG10PSJfc2VudHJ5U2NvcGUiLGd0PSJfc2VudHJ5SXNvbGF0aW9uU2NvcGUiO2Z1bmN0aW9uIHl0KHQpe3JldHVybntzY29wZTp0W210XSxpc29sYXRpb25TY29wZTp0W2d0XX19Y29uc3QgYnQ9InNlbnRyeS0iLF90PS9ec2VudHJ5LS87ZnVuY3Rpb24gdnQodCl7Y29uc3Qgbj1mdW5jdGlvbih0KXtpZighdHx8IUQodCkmJiFBcnJheS5pc0FycmF5KHQpKXJldHVybjtpZihBcnJheS5pc0FycmF5KHQpKXJldHVybiB0LnJlZHVjZSgoKHQsbik9Pntjb25zdCBlPXd0KG4pO3JldHVybiBPYmplY3QuZW50cmllcyhlKS5mb3JFYWNoKCgoW24sZV0pPT57dFtuXT1lfSkpLHR9KSx7fSk7cmV0dXJuIHd0KHQpfSh0KTtpZighbilyZXR1cm47Y29uc3QgZT1PYmplY3QuZW50cmllcyhuKS5yZWR1Y2UoKCh0LFtuLGVdKT0+e2lmKG4ubWF0Y2goX3QpKXt0W24uc2xpY2UoYnQubGVuZ3RoKV09ZX1yZXR1cm4gdH0pLHt9KTtyZXR1cm4gT2JqZWN0LmtleXMoZSkubGVuZ3RoPjA/ZTp2b2lkIDB9ZnVuY3Rpb24gd3QodCl7cmV0dXJuIHQuc3BsaXQoIiwiKS5tYXAoKHQ9PnQuc3BsaXQoIj0iKS5tYXAoKHQ9PmRlY29kZVVSSUNvbXBvbmVudCh0LnRyaW0oKSkpKSkpLnJlZHVjZSgoKHQsW24sZV0pPT4obiYmZSYmKHRbbl09ZSksdCkpLHt9KX1jb25zdCBTdD0xO2Z1bmN0aW9uICR0KHQpe2NvbnN0e3NwYW5JZDpuLHRyYWNlSWQ6ZSxpc1JlbW90ZTpyfT10LnNwYW5Db250ZXh0KCksbz1yP246VHQodCkucGFyZW50X3NwYW5faWQscz15dCh0KS5zY29wZTtyZXR1cm57cGFyZW50X3NwYW5faWQ6byxzcGFuX2lkOnI/cz8uZ2V0UHJvcGFnYXRpb25Db250ZXh0KCkucHJvcGFnYXRpb25TcGFuSWR8fFooKTpuLHRyYWNlX2lkOmV9fWZ1bmN0aW9uIEV0KHQpe3JldHVybiB0JiZ0Lmxlbmd0aD4wP3QubWFwKCgoe2NvbnRleHQ6e3NwYW5JZDp0LHRyYWNlSWQ6bix0cmFjZUZsYWdzOmUsLi4ucn0sYXR0cmlidXRlczpvfSk9Pih7c3Bhbl9pZDp0LHRyYWNlX2lkOm4sc2FtcGxlZDplPT09U3QsYXR0cmlidXRlczpvLC4uLnJ9KSkpOnZvaWQgMH1mdW5jdGlvbiB4dCh0KXtyZXR1cm4ibnVtYmVyIj09dHlwZW9mIHQ/TnQodCk6QXJyYXkuaXNBcnJheSh0KT90WzBdK3RbMV0vMWU5OnQgaW5zdGFuY2VvZiBEYXRlP050KHQuZ2V0VGltZSgpKTpSKCl9ZnVuY3Rpb24gTnQodCl7cmV0dXJuIHQ+OTk5OTk5OTk5OT90LzFlMzp0fWZ1bmN0aW9uIFR0KHQpe2lmKGZ1bmN0aW9uKHQpe3JldHVybiJmdW5jdGlvbiI9PXR5cGVvZiB0LmdldFNwYW5KU09OfSh0KSlyZXR1cm4gdC5nZXRTcGFuSlNPTigpO2NvbnN0e3NwYW5JZDpuLHRyYWNlSWQ6ZX09dC5zcGFuQ29udGV4dCgpO2lmKGZ1bmN0aW9uKHQpe2NvbnN0IG49dDtyZXR1cm4hIShuLmF0dHJpYnV0ZXMmJm4uc3RhcnRUaW1lJiZuLm5hbWUmJm4uZW5kVGltZSYmbi5zdGF0dXMpfSh0KSl7Y29uc3R7YXR0cmlidXRlczpyLHN0YXJ0VGltZTpvLG5hbWU6cyxlbmRUaW1lOmkscGFyZW50U3BhbklkOmMsc3RhdHVzOnUsbGlua3M6YX09dDtyZXR1cm57c3Bhbl9pZDpuLHRyYWNlX2lkOmUsZGF0YTpyLGRlc2NyaXB0aW9uOnMscGFyZW50X3NwYW5faWQ6YyxzdGFydF90aW1lc3RhbXA6eHQobyksdGltZXN0YW1wOnh0KGkpfHx2b2lkIDAsc3RhdHVzOkN0KHUpLG9wOnJbaHRdLG9yaWdpbjpyW3B0XSxsaW5rczpFdChhKX19cmV0dXJue3NwYW5faWQ6bix0cmFjZV9pZDplLHN0YXJ0X3RpbWVzdGFtcDowLGRhdGE6e319fWZ1bmN0aW9uIEN0KHQpe2lmKHQmJnQuY29kZSE9PWx0KXJldHVybiB0LmNvZGU9PT1kdD8ib2siOnQubWVzc2FnZXx8InVua25vd25fZXJyb3IifWNvbnN0IFJ0PSJfc2VudHJ5Um9vdFNwYW4iO2Z1bmN0aW9uIGt0KHQpe3JldHVybiB0W1J0XXx8dH1jb25zdCBqdD0icHJvZHVjdGlvbiIsRHQ9Il9mcm96ZW5Ec2MiO2Z1bmN0aW9uIEl0KHQpe2NvbnN0IG49dXQoKTtpZighbilyZXR1cm57fTtjb25zdCBlPWt0KHQpLHI9VHQoZSksbz1yLmRhdGEscz1lLnNwYW5Db250ZXh0KCkudHJhY2VTdGF0ZSxpPXM/LmdldCgic2VudHJ5LnNhbXBsZV9yYXRlIik/P29bZnRdO2Z1bmN0aW9uIGModCl7cmV0dXJuIm51bWJlciIhPXR5cGVvZiBpJiYic3RyaW5nIiE9dHlwZW9mIGl8fCh0LnNhbXBsZV9yYXRlPWAke2l9YCksdH1jb25zdCB1PWVbRHRdO2lmKHUpcmV0dXJuIGModSk7Y29uc3QgYT1zPy5nZXQoInNlbnRyeS5kc2MiKSxmPWEmJnZ0KGEpO2lmKGYpcmV0dXJuIGMoZik7Y29uc3QgaD1mdW5jdGlvbih0LG4pe2NvbnN0IGU9bi5nZXRPcHRpb25zKCkse3B1YmxpY0tleTpyfT1uLmdldERzbigpfHx7fSxvPXtlbnZpcm9ubWVudDplLmVudmlyb25tZW50fHxqdCxyZWxlYXNlOmUucmVsZWFzZSxwdWJsaWNfa2V5OnIsdHJhY2VfaWQ6dH07cmV0dXJuIG4uZW1pdCgiY3JlYXRlRHNjIixvKSxvfSh0LnNwYW5Db250ZXh0KCkudHJhY2VJZCxuKSxwPW9bYXRdLGw9ci5kZXNjcmlwdGlvbjtyZXR1cm4idXJsIiE9PXAmJmwmJihoLnRyYW5zYWN0aW9uPWwpLGZ1bmN0aW9uKHQpe2lmKCJib29sZWFuIj09dHlwZW9mIF9fU0VOVFJZX1RSQUNJTkdfXyYmIV9fU0VOVFJZX1RSQUNJTkdfXylyZXR1cm4hMTtjb25zdCBuPXR8fHV0KCk/LmdldE9wdGlvbnMoKTtyZXR1cm4hKCFufHxudWxsPT1uLnRyYWNlc1NhbXBsZVJhdGUmJiFuLnRyYWNlc1NhbXBsZXIpfSgpJiYoaC5zYW1wbGVkPVN0cmluZyhmdW5jdGlvbih0KXtjb25zdHt0cmFjZUZsYWdzOm59PXQuc3BhbkNvbnRleHQoKTtyZXR1cm4gbj09PVN0fShlKSksaC5zYW1wbGVfcmFuZD1zPy5nZXQoInNlbnRyeS5zYW1wbGVfcmFuZCIpPz95dChlKS5zY29wZT8uZ2V0UHJvcGFnYXRpb25Db250ZXh0KCkuc2FtcGxlUmFuZC50b1N0cmluZygpKSxjKGgpLG4uZW1pdCgiY3JlYXRlRHNjIixoLGUpLGh9ZnVuY3Rpb24gT3QodCxuPSExKXtjb25zdHtob3N0OmUscGF0aDpyLHBhc3M6byxwb3J0OnMscHJvamVjdElkOmkscHJvdG9jb2w6YyxwdWJsaWNLZXk6dX09dDtyZXR1cm5gJHtjfTovLyR7dX0ke24mJm8/YDoke299YDoiIn1AJHtlfSR7cz9gOiR7c31gOiIifS8ke3I/YCR7cn0vYDpyfSR7aX1gfWZ1bmN0aW9uIEF0KHQsbj0xMDAsZT0xLzApe3RyeXtyZXR1cm4gUHQoIiIsdCxuLGUpfWNhdGNoKHQpe3JldHVybntFUlJPUjpgKipub24tc2VyaWFsaXphYmxlKiogKCR7dH0pYH19fWZ1bmN0aW9uIFB0KHQsbixlPTEvMCxyPTEvMCxvPWZ1bmN0aW9uKCl7Y29uc3QgdD1uZXcgV2Vha1NldDtmdW5jdGlvbiBuKG4pe3JldHVybiEhdC5oYXMobil8fCh0LmFkZChuKSwhMSl9ZnVuY3Rpb24gZShuKXt0LmRlbGV0ZShuKX1yZXR1cm5bbixlXX0oKSl7Y29uc3RbcyxpXT1vO2lmKG51bGw9PW58fFsiYm9vbGVhbiIsInN0cmluZyJdLmluY2x1ZGVzKHR5cGVvZiBuKXx8Im51bWJlciI9PXR5cGVvZiBuJiZOdW1iZXIuaXNGaW5pdGUobikpcmV0dXJuIG47Y29uc3QgYz1mdW5jdGlvbih0LG4pe3RyeXtpZigiZG9tYWluIj09PXQmJm4mJiJvYmplY3QiPT10eXBlb2YgbiYmbi5KKXJldHVybiJbRG9tYWluXSI7aWYoImRvbWFpbkVtaXR0ZXIiPT09dClyZXR1cm4iW0RvbWFpbkVtaXR0ZXJdIjtpZigidW5kZWZpbmVkIiE9dHlwZW9mIGdsb2JhbCYmbj09PWdsb2JhbClyZXR1cm4iW0dsb2JhbF0iO2lmKCJ1bmRlZmluZWQiIT10eXBlb2Ygd2luZG93JiZuPT09d2luZG93KXJldHVybiJbV2luZG93XSI7aWYoInVuZGVmaW5lZCIhPXR5cGVvZiBkb2N1bWVudCYmbj09PWRvY3VtZW50KXJldHVybiJbRG9jdW1lbnRdIjtpZigib2JqZWN0Ij09dHlwZW9mKGU9bikmJm51bGwhPT1lJiYoZS5fX2lzVnVlfHxlLlkpKXJldHVybiJbVnVlVmlld01vZGVsXSI7aWYoZnVuY3Rpb24odCl7cmV0dXJuIEkodCkmJiJuYXRpdmVFdmVudCJpbiB0JiYicHJldmVudERlZmF1bHQiaW4gdCYmInN0b3BQcm9wYWdhdGlvbiJpbiB0fShuKSlyZXR1cm4iW1N5bnRoZXRpY0V2ZW50XSI7aWYoIm51bWJlciI9PXR5cGVvZiBuJiYhTnVtYmVyLmlzRmluaXRlKG4pKXJldHVybmBbJHtufV1gO2lmKCJmdW5jdGlvbiI9PXR5cGVvZiBuKXJldHVybmBbRnVuY3Rpb246ICR7ZnVuY3Rpb24odCl7dHJ5e3JldHVybiB0JiYiZnVuY3Rpb24iPT10eXBlb2YgdCYmdC5uYW1lfHxOfWNhdGNoKHQpe3JldHVybiBOfX0obil9XWA7aWYoInN5bWJvbCI9PXR5cGVvZiBuKXJldHVybmBbJHtTdHJpbmcobil9XWA7aWYoImJpZ2ludCI9PXR5cGVvZiBuKXJldHVybmBbQmlnSW50OiAke1N0cmluZyhuKX1dYDtjb25zdCByPWZ1bmN0aW9uKHQpe2NvbnN0IG49T2JqZWN0LmdldFByb3RvdHlwZU9mKHQpO3JldHVybiBuPy5jb25zdHJ1Y3Rvcj9uLmNvbnN0cnVjdG9yLm5hbWU6Im51bGwgcHJvdG90eXBlIn0obik7cmV0dXJuL15IVE1MKFx3KilFbGVtZW50JC8udGVzdChyKT9gW0hUTUxFbGVtZW50OiAke3J9XWA6YFtvYmplY3QgJHtyfV1gfWNhdGNoKHQpe3JldHVybmAqKm5vbi1zZXJpYWxpemFibGUqKiAoJHt0fSlgfXZhciBlfSh0LG4pO2lmKCFjLnN0YXJ0c1dpdGgoIltvYmplY3QgIikpcmV0dXJuIGM7aWYobi5fX3NlbnRyeV9za2lwX25vcm1hbGl6YXRpb25fXylyZXR1cm4gbjtjb25zdCB1PSJudW1iZXIiPT10eXBlb2Ygbi5fX3NlbnRyeV9vdmVycmlkZV9ub3JtYWxpemF0aW9uX2RlcHRoX18/bi5fX3NlbnRyeV9vdmVycmlkZV9ub3JtYWxpemF0aW9uX2RlcHRoX186ZTtpZigwPT09dSlyZXR1cm4gYy5yZXBsYWNlKCJvYmplY3QgIiwiIik7aWYocyhuKSlyZXR1cm4iW0NpcmN1bGFyIH5dIjtjb25zdCBhPW47aWYoYSYmImZ1bmN0aW9uIj09dHlwZW9mIGEudG9KU09OKXRyeXtyZXR1cm4gUHQoIiIsYS50b0pTT04oKSx1LTEscixvKX1jYXRjaCh0KXt9Y29uc3QgZj1BcnJheS5pc0FycmF5KG4pP1tdOnt9O2xldCBoPTA7Y29uc3QgcD1CKG4pO2Zvcihjb25zdCB0IGluIHApe2lmKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocCx0KSljb250aW51ZTtpZihoPj1yKXtmW3RdPSJbTWF4UHJvcGVydGllcyB+XSI7YnJlYWt9Y29uc3Qgbj1wW3RdO2ZbdF09UHQodCxuLHUtMSxyLG8pLGgrK31yZXR1cm4gaShuKSxmfWZ1bmN0aW9uIFV0KHQsbil7Y29uc3QgZT1uLnJlcGxhY2UoL1xcL2csIi8iKS5yZXBsYWNlKC9bfFxce30oKVtcXV4kKyo/Ll0vZywiXFwkJiIpO2xldCByPXQ7dHJ5e3I9ZGVjb2RlVVJJKHQpfWNhdGNoKHQpe31yZXR1cm4gci5yZXBsYWNlKC9cXC9nLCIvIikucmVwbGFjZSgvd2VicGFjazpcLz8vZywiIikucmVwbGFjZShuZXcgUmVnRXhwKGAoZmlsZTovLyk/Lyoke2V9LypgLCJpZyIpLCJhcHA6Ly8vIil9ZnVuY3Rpb24gTXQodCxuPVtdKXtyZXR1cm5bdCxuXX1mdW5jdGlvbiBMdCh0LG4pe2NvbnN0IGU9dFsxXTtmb3IoY29uc3QgdCBvZiBlKXtpZihuKHQsdFswXS50eXBlKSlyZXR1cm4hMH1yZXR1cm4hMX1mdW5jdGlvbiBCdCh0KXtjb25zdCBuPWcocCk7cmV0dXJuIG4uZW5jb2RlUG9seWZpbGw/bi5lbmNvZGVQb2x5ZmlsbCh0KToobmV3IFRleHRFbmNvZGVyKS5lbmNvZGUodCl9ZnVuY3Rpb24gR3QodCl7Y29uc3RbbixlXT10O2xldCByPUpTT04uc3RyaW5naWZ5KG4pO2Z1bmN0aW9uIG8odCl7InN0cmluZyI9PXR5cGVvZiByP3I9InN0cmluZyI9PXR5cGVvZiB0P3IrdDpbQnQociksdF06ci5wdXNoKCJzdHJpbmciPT10eXBlb2YgdD9CdCh0KTp0KX1mb3IoY29uc3QgdCBvZiBlKXtjb25zdFtuLGVdPXQ7aWYobyhgXG4ke0pTT04uc3RyaW5naWZ5KG4pfVxuYCksInN0cmluZyI9PXR5cGVvZiBlfHxlIGluc3RhbmNlb2YgVWludDhBcnJheSlvKGUpO2Vsc2V7bGV0IHQ7dHJ5e3Q9SlNPTi5zdHJpbmdpZnkoZSl9Y2F0Y2gobil7dD1KU09OLnN0cmluZ2lmeShBdChlKSl9byh0KX19cmV0dXJuInN0cmluZyI9PXR5cGVvZiByP3I6ZnVuY3Rpb24odCl7Y29uc3Qgbj10LnJlZHVjZSgoKHQsbik9PnQrbi5sZW5ndGgpLDApLGU9bmV3IFVpbnQ4QXJyYXkobik7bGV0IHI9MDtmb3IoY29uc3QgbiBvZiB0KWUuc2V0KG4scikscis9bi5sZW5ndGg7cmV0dXJuIGV9KHIpfWNvbnN0IEp0PXtzZXNzaW9uOiJzZXNzaW9uIixzZXNzaW9uczoic2Vzc2lvbiIsYXR0YWNobWVudDoiYXR0YWNobWVudCIsdHJhbnNhY3Rpb246InRyYW5zYWN0aW9uIixldmVudDoiZXJyb3IiLGNsaWVudF9yZXBvcnQ6ImludGVybmFsIix1c2VyX3JlcG9ydDoiZGVmYXVsdCIscHJvZmlsZToicHJvZmlsZSIscHJvZmlsZV9jaHVuazoicHJvZmlsZSIscmVwbGF5X2V2ZW50OiJyZXBsYXkiLHJlcGxheV9yZWNvcmRpbmc6InJlcGxheSIsY2hlY2tfaW46Im1vbml0b3IiLGZlZWRiYWNrOiJmZWVkYmFjayIsc3Bhbjoic3BhbiIscmF3X3NlY3VyaXR5OiJzZWN1cml0eSIsb3RlbF9sb2c6ImxvZ19pdGVtIn07ZnVuY3Rpb24gWXQodCl7aWYoIXQ/LnNkaylyZXR1cm47Y29uc3R7bmFtZTpuLHZlcnNpb246ZX09dC5zZGs7cmV0dXJue25hbWU6bix2ZXJzaW9uOmV9fWZ1bmN0aW9uIHp0KHQsbixlLHIpe2NvbnN0IG89WXQoZSkscz10LnR5cGUmJiJyZXBsYXlfZXZlbnQiIT09dC50eXBlP3QudHlwZToiZXZlbnQiOyFmdW5jdGlvbih0LG4pe24mJih0LnNkaz10LnNka3x8e30sdC5zZGsubmFtZT10LnNkay5uYW1lfHxuLm5hbWUsdC5zZGsudmVyc2lvbj10LnNkay52ZXJzaW9ufHxuLnZlcnNpb24sdC5zZGsuaW50ZWdyYXRpb25zPVsuLi50LnNkay5pbnRlZ3JhdGlvbnN8fFtdLC4uLm4uaW50ZWdyYXRpb25zfHxbXV0sdC5zZGsucGFja2FnZXM9Wy4uLnQuc2RrLnBhY2thZ2VzfHxbXSwuLi5uLnBhY2thZ2VzfHxbXV0pfSh0LGU/LnNkayk7Y29uc3QgaT1mdW5jdGlvbih0LG4sZSxyKXtjb25zdCBvPXQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhPy5keW5hbWljU2FtcGxpbmdDb250ZXh0O3JldHVybntldmVudF9pZDp0LmV2ZW50X2lkLHNlbnRfYXQ6KG5ldyBEYXRlKS50b0lTT1N0cmluZygpLC4uLm4mJntzZGs6bn0sLi4uISFlJiZyJiZ7ZHNuOk90KHIpfSwuLi5vJiZ7dHJhY2U6b319fSh0LG8scixuKTtkZWxldGUgdC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE7cmV0dXJuIE10KGksW1t7dHlwZTpzfSx0XV0pfWNvbnN0IEh0PSJfX1NFTlRSWV9TVVBQUkVTU19UUkFDSU5HX18iO2Z1bmN0aW9uIEZ0KHQpe2NvbnN0IG49Y3QobSgpKTtyZXR1cm4gbi5zdXBwcmVzc1RyYWNpbmc/bi5zdXBwcmVzc1RyYWNpbmcodCk6ZnVuY3Rpb24oLi4udCl7Y29uc3Qgbj1jdChtKCkpO2lmKDI9PT10Lmxlbmd0aCl7Y29uc3RbZSxyXT10O3JldHVybiBlP24ud2l0aFNldFNjb3BlKGUscik6bi53aXRoU2NvcGUocil9cmV0dXJuIG4ud2l0aFNjb3BlKHRbMF0pfSgobj0+KG4uc2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKHtbSHRdOiEwfSksdCgpKSkpfWZ1bmN0aW9uIFd0KHQsbil7Y29uc3R7ZmluZ2VycHJpbnQ6ZSxzcGFuOnIsYnJlYWRjcnVtYnM6byxzZGtQcm9jZXNzaW5nTWV0YWRhdGE6c309bjshZnVuY3Rpb24odCxuKXtjb25zdHtleHRyYTplLHRhZ3M6cix1c2VyOm8sY29udGV4dHM6cyxsZXZlbDppLHRyYW5zYWN0aW9uTmFtZTpjfT1uO09iamVjdC5rZXlzKGUpLmxlbmd0aCYmKHQuZXh0cmE9ey4uLmUsLi4udC5leHRyYX0pO09iamVjdC5rZXlzKHIpLmxlbmd0aCYmKHQudGFncz17Li4uciwuLi50LnRhZ3N9KTtPYmplY3Qua2V5cyhvKS5sZW5ndGgmJih0LnVzZXI9ey4uLm8sLi4udC51c2VyfSk7T2JqZWN0LmtleXMocykubGVuZ3RoJiYodC5jb250ZXh0cz17Li4ucywuLi50LmNvbnRleHRzfSk7aSYmKHQubGV2ZWw9aSk7YyYmInRyYW5zYWN0aW9uIiE9PXQudHlwZSYmKHQudHJhbnNhY3Rpb249Yyl9KHQsbiksciYmZnVuY3Rpb24odCxuKXt0LmNvbnRleHRzPXt0cmFjZTokdChuKSwuLi50LmNvbnRleHRzfSx0LnNka1Byb2Nlc3NpbmdNZXRhZGF0YT17ZHluYW1pY1NhbXBsaW5nQ29udGV4dDpJdChuKSwuLi50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YX07Y29uc3QgZT1rdChuKSxyPVR0KGUpLmRlc2NyaXB0aW9uO3ImJiF0LnRyYW5zYWN0aW9uJiYidHJhbnNhY3Rpb24iPT09dC50eXBlJiYodC50cmFuc2FjdGlvbj1yKX0odCxyKSxmdW5jdGlvbih0LG4pe3QuZmluZ2VycHJpbnQ9dC5maW5nZXJwcmludD9BcnJheS5pc0FycmF5KHQuZmluZ2VycHJpbnQpP3QuZmluZ2VycHJpbnQ6W3QuZmluZ2VycHJpbnRdOltdLG4mJih0LmZpbmdlcnByaW50PXQuZmluZ2VycHJpbnQuY29uY2F0KG4pKTt0LmZpbmdlcnByaW50Lmxlbmd0aHx8ZGVsZXRlIHQuZmluZ2VycHJpbnR9KHQsZSksZnVuY3Rpb24odCxuKXtjb25zdCBlPVsuLi50LmJyZWFkY3J1bWJzfHxbXSwuLi5uXTt0LmJyZWFkY3J1bWJzPWUubGVuZ3RoP2U6dm9pZCAwfSh0LG8pLGZ1bmN0aW9uKHQsbil7dC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE9ey4uLnQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhLC4uLm59fSh0LHMpfWNvbnN0IEt0PSI3Ijtjb25zdCBWdD1TeW1ib2wuZm9yKCJTZW50cnlCdWZmZXJGdWxsRXJyb3IiKTtmdW5jdGlvbiBadCh0KXtjb25zdCBuPVtdO2Z1bmN0aW9uIGUodCl7cmV0dXJuIG4uc3BsaWNlKG4uaW5kZXhPZih0KSwxKVswXXx8UHJvbWlzZS5yZXNvbHZlKHZvaWQgMCl9cmV0dXJueyQ6bixhZGQ6ZnVuY3Rpb24ocil7aWYoISh2b2lkIDA9PT10fHxuLmxlbmd0aDx0KSlyZXR1cm4gbz1WdCxuZXcgRigoKHQsbik9PntuKG8pfSkpO3ZhciBvO2NvbnN0IHM9cigpO3JldHVybi0xPT09bi5pbmRleE9mKHMpJiZuLnB1c2gocykscy50aGVuKCgoKT0+ZShzKSkpLnRoZW4obnVsbCwoKCk9PmUocykudGhlbihudWxsLCgoKT0+e30pKSkpLHN9LGRyYWluOmZ1bmN0aW9uKHQpe3JldHVybiBuZXcgRigoKGUscik9PntsZXQgbz1uLmxlbmd0aDtpZighbylyZXR1cm4gZSghMCk7Y29uc3Qgcz1zZXRUaW1lb3V0KCgoKT0+e3QmJnQ+MCYmZSghMSl9KSx0KTtuLmZvckVhY2goKHQ9PntIKHQpLnRoZW4oKCgpPT57LS1vfHwoY2xlYXJUaW1lb3V0KHMpLGUoITApKX0pLHIpfSkpfSkpfX19Y29uc3QgcXQ9NmU0O2Z1bmN0aW9uIFF0KHQse3N0YXR1c0NvZGU6bixoZWFkZXJzOmV9LHI9RGF0ZS5ub3coKSl7Y29uc3Qgbz17Li4udH0scz1lPy5bIngtc2VudHJ5LXJhdGUtbGltaXRzIl0saT1lPy5bInJldHJ5LWFmdGVyIl07aWYocylmb3IoY29uc3QgdCBvZiBzLnRyaW0oKS5zcGxpdCgiLCIpKXtjb25zdFtuLGUsLCxzXT10LnNwbGl0KCI6Iiw1KSxpPXBhcnNlSW50KG4sMTApLGM9MWUzKihpc05hTihpKT82MDppKTtpZihlKWZvcihjb25zdCB0IG9mIGUuc3BsaXQoIjsiKSkibWV0cmljX2J1Y2tldCI9PT10JiZzJiYhcy5zcGxpdCgiOyIpLmluY2x1ZGVzKCJjdXN0b20iKXx8KG9bdF09citjKTtlbHNlIG8uYWxsPXIrY31lbHNlIGk/by5hbGw9citmdW5jdGlvbih0LG49RGF0ZS5ub3coKSl7Y29uc3QgZT1wYXJzZUludChgJHt0fWAsMTApO2lmKCFpc05hTihlKSlyZXR1cm4gMWUzKmU7Y29uc3Qgcj1EYXRlLnBhcnNlKGAke3R9YCk7cmV0dXJuIGlzTmFOKHIpP3F0OnItbn0oaSxyKTo0Mjk9PT1uJiYoby5hbGw9cis2ZTQpO3JldHVybiBvfWNvbnN0IFh0PTY0O2Z1bmN0aW9uIHRuKHQsbixlPVp0KHQuYnVmZmVyU2l6ZXx8WHQpKXtsZXQgcj17fTtyZXR1cm57c2VuZDpmdW5jdGlvbih0KXtjb25zdCBvPVtdO2lmKEx0KHQsKCh0LG4pPT57Y29uc3QgZT1mdW5jdGlvbih0KXtyZXR1cm4gSnRbdF19KG4pOyhmdW5jdGlvbih0LG4sZT1EYXRlLm5vdygpKXtyZXR1cm4gZnVuY3Rpb24odCxuKXtyZXR1cm4gdFtuXXx8dC5hbGx8fDB9KHQsbik+ZX0pKHIsZSl8fG8ucHVzaCh0KX0pKSwwPT09by5sZW5ndGgpcmV0dXJuIEgoe30pO2NvbnN0IHM9TXQodFswXSxvKSxpPXQ9PntMdChzLCgodCxuKT0+e30pKX07cmV0dXJuIGUuYWRkKCgoKT0+bih7Ym9keTpHdChzKX0pLnRoZW4oKHQ9Pih2b2lkIDAhPT10LnN0YXR1c0NvZGUmJih0LnN0YXR1c0NvZGU8MjAwfHx0LnN0YXR1c0NvZGU+PTMwMCkmJmgmJncud2FybihgU2VudHJ5IHJlc3BvbmRlZCB3aXRoIHN0YXR1cyBjb2RlICR7dC5zdGF0dXNDb2RlfSB0byBzZW50IGV2ZW50LmApLHI9UXQocix0KSx0KSksKHQ9Pnt0aHJvdyBpKCksaCYmdy5lcnJvcigiRW5jb3VudGVyZWQgZXJyb3IgcnVubmluZyB0cmFuc3BvcnQgcmVxdWVzdDoiLHQpLHR9KSkpKS50aGVuKCh0PT50KSwodD0+e2lmKHQ9PT1WdClyZXR1cm4gaCYmdy5lcnJvcigiU2tpcHBlZCBzZW5kaW5nIGV2ZW50IGJlY2F1c2UgYnVmZmVyIGlzIGZ1bGwuIiksaSgpLEgoe30pO3Rocm93IHR9KSl9LGZsdXNoOnQ9PmUuZHJhaW4odCl9fWNvbnN0IG5uPS9eKFxTKzpcXHxcLz8pKFtcc1xTXSo/KSgoPzpcLnsxLDJ9fFteL1xcXSs/fCkoXC5bXi4vXFxdKnwpKSg/OlsvXFxdKikkLztmdW5jdGlvbiBlbih0KXtjb25zdCBuPWZ1bmN0aW9uKHQpe2NvbnN0IG49dC5sZW5ndGg+MTAyND9gPHRydW5jYXRlZD4ke3Quc2xpY2UoLTEwMjQpfWA6dCxlPW5uLmV4ZWMobik7cmV0dXJuIGU/ZS5zbGljZSgxKTpbXX0odCksZT1uWzBdfHwiIjtsZXQgcj1uWzFdO3JldHVybiBlfHxyPyhyJiYocj1yLnNsaWNlKDAsci5sZW5ndGgtMSkpLGUrcik6Ii4ifWZ1bmN0aW9uIHJuKHQsbj0hMSl7cmV0dXJuIShufHx0JiYhdC5zdGFydHNXaXRoKCIvIikmJiF0Lm1hdGNoKC9eW0EtWl06LykmJiF0LnN0YXJ0c1dpdGgoIi4iKSYmIXQubWF0Y2goL15bYS16QS1aXShbYS16QS1aMC05LlwtK10pKjpcL1wvLykpJiZ2b2lkIDAhPT10JiYhdC5pbmNsdWRlcygibm9kZV9tb2R1bGVzLyIpfWNvbnN0IG9uPVN5bWJvbCgiQWdlbnRCYXNlSW50ZXJuYWxTdGF0ZSIpO2NsYXNzIHNuIGV4dGVuZHMgcy5BZ2VudHtjb25zdHJ1Y3Rvcih0KXtzdXBlcih0KSx0aGlzW29uXT17fX1pc1NlY3VyZUVuZHBvaW50KHQpe2lmKHQpe2lmKCJib29sZWFuIj09dHlwZW9mIHQuc2VjdXJlRW5kcG9pbnQpcmV0dXJuIHQuc2VjdXJlRW5kcG9pbnQ7aWYoInN0cmluZyI9PXR5cGVvZiB0LnByb3RvY29sKXJldHVybiJodHRwczoiPT09dC5wcm90b2NvbH1jb25zdHtzdGFjazpufT1uZXcgRXJyb3I7cmV0dXJuInN0cmluZyI9PXR5cGVvZiBuJiZuLnNwbGl0KCJcbiIpLnNvbWUoKHQ9Pi0xIT09dC5pbmRleE9mKCIoaHR0cHMuanM6Iil8fC0xIT09dC5pbmRleE9mKCJub2RlOmh0dHBzOiIpKSl9Y3JlYXRlU29ja2V0KHQsbixlKXtjb25zdCByPXsuLi5uLHNlY3VyZUVuZHBvaW50OnRoaXMuaXNTZWN1cmVFbmRwb2ludChuKX07UHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKCk9PnRoaXMuY29ubmVjdCh0LHIpKSkudGhlbigobz0+e2lmKG8gaW5zdGFuY2VvZiBzLkFnZW50KXJldHVybiBvLmFkZFJlcXVlc3QodCxyKTt0aGlzW29uXS5jdXJyZW50U29ja2V0PW8sc3VwZXIuY3JlYXRlU29ja2V0KHQsbixlKX0pLGUpfWNyZWF0ZUNvbm5lY3Rpb24oKXtjb25zdCB0PXRoaXNbb25dLmN1cnJlbnRTb2NrZXQ7aWYodGhpc1tvbl0uY3VycmVudFNvY2tldD12b2lkIDAsIXQpdGhyb3cgbmV3IEVycm9yKCJObyBzb2NrZXQgd2FzIHJldHVybmVkIGluIHRoZSBgY29ubmVjdCgpYCBmdW5jdGlvbiIpO3JldHVybiB0fWdldCBkZWZhdWx0UG9ydCgpe3JldHVybiB0aGlzW29uXS5kZWZhdWx0UG9ydD8/KCJodHRwczoiPT09dGhpcy5wcm90b2NvbD80NDM6ODApfXNldCBkZWZhdWx0UG9ydCh0KXt0aGlzW29uXSYmKHRoaXNbb25dLmRlZmF1bHRQb3J0PXQpfWdldCBwcm90b2NvbCgpe3JldHVybiB0aGlzW29uXS5wcm90b2NvbD8/KHRoaXMuaXNTZWN1cmVFbmRwb2ludCgpPyJodHRwczoiOiJodHRwOiIpfXNldCBwcm90b2NvbCh0KXt0aGlzW29uXSYmKHRoaXNbb25dLnByb3RvY29sPXQpfX1mdW5jdGlvbiBjbiguLi50KXt3LmxvZygiW2h0dHBzLXByb3h5LWFnZW50OnBhcnNlLXByb3h5LXJlc3BvbnNlXSIsLi4udCl9ZnVuY3Rpb24gdW4odCl7cmV0dXJuIG5ldyBQcm9taXNlKCgobixlKT0+e2xldCByPTA7Y29uc3Qgbz1bXTtmdW5jdGlvbiBzKCl7Y29uc3QgYz10LnJlYWQoKTtjP2Z1bmN0aW9uKGMpe28ucHVzaChjKSxyKz1jLmxlbmd0aDtjb25zdCB1PUJ1ZmZlci5jb25jYXQobyxyKSxhPXUuaW5kZXhPZigiXHJcblxyXG4iKTtpZigtMT09PWEpcmV0dXJuIGNuKCJoYXZlIG5vdCByZWNlaXZlZCBlbmQgb2YgSFRUUCBoZWFkZXJzIHlldC4uLiIpLHZvaWQgcygpO2NvbnN0IGY9dS5zdWJhcnJheSgwLGEpLnRvU3RyaW5nKCJhc2NpaSIpLnNwbGl0KCJcclxuIiksaD1mLnNoaWZ0KCk7aWYoIWgpcmV0dXJuIHQuZGVzdHJveSgpLGUobmV3IEVycm9yKCJObyBoZWFkZXIgcmVjZWl2ZWQgZnJvbSBwcm94eSBDT05ORUNUIHJlc3BvbnNlIikpO2NvbnN0IHA9aC5zcGxpdCgiICIpLGw9KyhwWzFdfHwwKSxkPXAuc2xpY2UoMikuam9pbigiICIpLG09e307Zm9yKGNvbnN0IG4gb2YgZil7aWYoIW4pY29udGludWU7Y29uc3Qgcj1uLmluZGV4T2YoIjoiKTtpZigtMT09PXIpcmV0dXJuIHQuZGVzdHJveSgpLGUobmV3IEVycm9yKGBJbnZhbGlkIGhlYWRlciBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2U6ICIke259ImApKTtjb25zdCBvPW4uc2xpY2UoMCxyKS50b0xvd2VyQ2FzZSgpLHM9bi5zbGljZShyKzEpLnRyaW1TdGFydCgpLGk9bVtvXTsic3RyaW5nIj09dHlwZW9mIGk/bVtvXT1baSxzXTpBcnJheS5pc0FycmF5KGkpP2kucHVzaChzKTptW29dPXN9Y24oImdvdCBwcm94eSBzZXJ2ZXIgcmVzcG9uc2U6ICVvICVvIixoLG0pLGkoKSxuKHtjb25uZWN0OntzdGF0dXNDb2RlOmwsc3RhdHVzVGV4dDpkLGhlYWRlcnM6bX0sYnVmZmVyZWQ6dX0pfShjKTp0Lm9uY2UoInJlYWRhYmxlIixzKX1mdW5jdGlvbiBpKCl7dC5yZW1vdmVMaXN0ZW5lcigiZW5kIixjKSx0LnJlbW92ZUxpc3RlbmVyKCJlcnJvciIsdSksdC5yZW1vdmVMaXN0ZW5lcigicmVhZGFibGUiLHMpfWZ1bmN0aW9uIGMoKXtpKCksY24oIm9uZW5kIiksZShuZXcgRXJyb3IoIlByb3h5IGNvbm5lY3Rpb24gZW5kZWQgYmVmb3JlIHJlY2VpdmluZyBDT05ORUNUIHJlc3BvbnNlIikpfWZ1bmN0aW9uIHUodCl7aSgpLGNuKCJvbmVycm9yICVvIix0KSxlKHQpfXQub24oImVycm9yIix1KSx0Lm9uKCJlbmQiLGMpLHMoKX0pKX1mdW5jdGlvbiBhbiguLi50KXt3LmxvZygiW2h0dHBzLXByb3h5LWFnZW50XSIsLi4udCl9Y2xhc3MgZm4gZXh0ZW5kcyBzbntzdGF0aWMgX19pbml0U3RhdGljKCl7dGhpcy5wcm90b2NvbHM9WyJodHRwIiwiaHR0cHMiXX1jb25zdHJ1Y3Rvcih0LG4pe3N1cGVyKG4pLHRoaXMub3B0aW9ucz17fSx0aGlzLnByb3h5PSJzdHJpbmciPT10eXBlb2YgdD9uZXcgVVJMKHQpOnQsdGhpcy5wcm94eUhlYWRlcnM9bj8uaGVhZGVycz8/e30sYW4oIkNyZWF0aW5nIG5ldyBIdHRwc1Byb3h5QWdlbnQgaW5zdGFuY2U6ICVvIix0aGlzLnByb3h5LmhyZWYpO2NvbnN0IGU9KHRoaXMucHJveHkuaG9zdG5hbWV8fHRoaXMucHJveHkuaG9zdCkucmVwbGFjZSgvXlxbfFxdJC9nLCIiKSxyPXRoaXMucHJveHkucG9ydD9wYXJzZUludCh0aGlzLnByb3h5LnBvcnQsMTApOiJodHRwczoiPT09dGhpcy5wcm94eS5wcm90b2NvbD80NDM6ODA7dGhpcy5jb25uZWN0T3B0cz17QUxQTlByb3RvY29sczpbImh0dHAvMS4xIl0sLi4ubj9wbihuLCJoZWFkZXJzIik6bnVsbCxob3N0OmUscG9ydDpyfX1hc3luYyBjb25uZWN0KHQsbil7Y29uc3R7cHJveHk6ZX09dGhpcztpZighbi5ob3N0KXRocm93IG5ldyBUeXBlRXJyb3IoJ05vICJob3N0IiBwcm92aWRlZCcpO2xldCByO2lmKCJodHRwczoiPT09ZS5wcm90b2NvbCl7YW4oIkNyZWF0aW5nIGB0bHMuU29ja2V0YDogJW8iLHRoaXMuY29ubmVjdE9wdHMpO2NvbnN0IHQ9dGhpcy5jb25uZWN0T3B0cy5zZXJ2ZXJuYW1lfHx0aGlzLmNvbm5lY3RPcHRzLmhvc3Q7cj1mLmNvbm5lY3Qoey4uLnRoaXMuY29ubmVjdE9wdHMsc2VydmVybmFtZTp0JiZhLmlzSVAodCk/dm9pZCAwOnR9KX1lbHNlIGFuKCJDcmVhdGluZyBgbmV0LlNvY2tldGA6ICVvIix0aGlzLmNvbm5lY3RPcHRzKSxyPWEuY29ubmVjdCh0aGlzLmNvbm5lY3RPcHRzKTtjb25zdCBvPSJmdW5jdGlvbiI9PXR5cGVvZiB0aGlzLnByb3h5SGVhZGVycz90aGlzLnByb3h5SGVhZGVycygpOnsuLi50aGlzLnByb3h5SGVhZGVyc30scz1hLmlzSVB2NihuLmhvc3QpP2BbJHtuLmhvc3R9XWA6bi5ob3N0O2xldCBpPWBDT05ORUNUICR7c306JHtuLnBvcnR9IEhUVFAvMS4xXHJcbmA7aWYoZS51c2VybmFtZXx8ZS5wYXNzd29yZCl7Y29uc3QgdD1gJHtkZWNvZGVVUklDb21wb25lbnQoZS51c2VybmFtZSl9OiR7ZGVjb2RlVVJJQ29tcG9uZW50KGUucGFzc3dvcmQpfWA7b1siUHJveHktQXV0aG9yaXphdGlvbiJdPWBCYXNpYyAke0J1ZmZlci5mcm9tKHQpLnRvU3RyaW5nKCJiYXNlNjQiKX1gfW8uSG9zdD1gJHtzfToke24ucG9ydH1gLG9bIlByb3h5LUNvbm5lY3Rpb24iXXx8KG9bIlByb3h5LUNvbm5lY3Rpb24iXT10aGlzLmtlZXBBbGl2ZT8iS2VlcC1BbGl2ZSI6ImNsb3NlIik7Zm9yKGNvbnN0IHQgb2YgT2JqZWN0LmtleXMobykpaSs9YCR7dH06ICR7b1t0XX1cclxuYDtjb25zdCBjPXVuKHIpO3Iud3JpdGUoYCR7aX1cclxuYCk7Y29uc3R7Y29ubmVjdDp1LGJ1ZmZlcmVkOmh9PWF3YWl0IGM7aWYodC5lbWl0KCJwcm94eUNvbm5lY3QiLHUpLHRoaXMuZW1pdCgicHJveHlDb25uZWN0Iix1LHQpLDIwMD09PXUuc3RhdHVzQ29kZSl7aWYodC5vbmNlKCJzb2NrZXQiLGhuKSxuLnNlY3VyZUVuZHBvaW50KXthbigiVXBncmFkaW5nIHNvY2tldCBjb25uZWN0aW9uIHRvIFRMUyIpO2NvbnN0IHQ9bi5zZXJ2ZXJuYW1lfHxuLmhvc3Q7cmV0dXJuIGYuY29ubmVjdCh7Li4ucG4obiwiaG9zdCIsInBhdGgiLCJwb3J0Iiksc29ja2V0OnIsc2VydmVybmFtZTphLmlzSVAodCk/dm9pZCAwOnR9KX1yZXR1cm4gcn1yLmRlc3Ryb3koKTtjb25zdCBwPW5ldyBhLlNvY2tldCh7d3JpdGFibGU6ITF9KTtyZXR1cm4gcC5yZWFkYWJsZT0hMCx0Lm9uY2UoInNvY2tldCIsKHQ9PnthbigiUmVwbGF5aW5nIHByb3h5IGJ1ZmZlciBmb3IgZmFpbGVkIHJlcXVlc3QiKSx0LnB1c2goaCksdC5wdXNoKG51bGwpfSkpLHB9fWZ1bmN0aW9uIGhuKHQpe3QucmVzdW1lKCl9ZnVuY3Rpb24gcG4odCwuLi5uKXtjb25zdCBlPXt9O2xldCByO2ZvcihyIGluIHQpbi5pbmNsdWRlcyhyKXx8KGVbcl09dFtyXSk7cmV0dXJuIGV9Zm4uX19pbml0U3RhdGljKCk7Y29uc3QgbG49MzI3Njg7ZnVuY3Rpb24gZG4odCl7cmV0dXJuIHQucmVwbGFjZSgvXltBLVpdOi8sIiIpLnJlcGxhY2UoL1xcL2csIi8iKX1jb25zdCBtbj1uO2xldCBnbix5bj0wLGJuPXt9O2Z1bmN0aW9uIF9uKHQpe21uLmRlYnVnJiZjb25zb2xlLmxvZyhgW0FOUiBXb3JrZXJdICR7dH1gKX12YXIgdm4sd24sU247Y29uc3QgJG49ZnVuY3Rpb24odCl7bGV0IG47dHJ5e249bmV3IFVSTCh0LnVybCl9Y2F0Y2gobil7cmV0dXJuIHYoKCgpPT57Y29uc29sZS53YXJuKCJbQHNlbnRyeS9ub2RlXTogSW52YWxpZCBkc24gb3IgdHVubmVsIG9wdGlvbiwgd2lsbCBub3Qgc2VuZCBhbnkgZXZlbnRzLiBUaGUgdHVubmVsIG9wdGlvbiBtdXN0IGJlIGEgZnVsbCBVUkwgd2hlbiB1c2VkLiIpfSkpLHRuKHQsKCgpPT5Qcm9taXNlLnJlc29sdmUoe30pKSl9Y29uc3QgZT0iaHR0cHM6Ij09PW4ucHJvdG9jb2wscj1mdW5jdGlvbih0LG4pe2NvbnN0e25vX3Byb3h5OmV9PXByb2Nlc3MuZW52LHI9ZT8uc3BsaXQoIiwiKS5zb21lKChuPT50Lmhvc3QuZW5kc1dpdGgobil8fHQuaG9zdG5hbWUuZW5kc1dpdGgobikpKTtyZXR1cm4gcj92b2lkIDA6bn0obix0LnByb3h5fHwoZT9wcm9jZXNzLmVudi5odHRwc19wcm94eTp2b2lkIDApfHxwcm9jZXNzLmVudi5odHRwX3Byb3h5KSxvPWU/aTpzLGE9dm9pZCAwIT09dC5rZWVwQWxpdmUmJnQua2VlcEFsaXZlLGY9cj9uZXcgZm4ocik6bmV3IG8uQWdlbnQoe2tlZXBBbGl2ZTphLG1heFNvY2tldHM6MzAsdGltZW91dDoyZTN9KSxoPWZ1bmN0aW9uKHQsbixlKXtjb25zdHtob3N0bmFtZTpyLHBhdGhuYW1lOm8scG9ydDpzLHByb3RvY29sOmksc2VhcmNoOmF9PW5ldyBVUkwodC51cmwpO3JldHVybiBmdW5jdGlvbihmKXtyZXR1cm4gbmV3IFByb21pc2UoKChoLHApPT57RnQoKCgpPT57bGV0IGw9ZnVuY3Rpb24odCl7cmV0dXJuIG5ldyBjKHtyZWFkKCl7dGhpcy5wdXNoKHQpLHRoaXMucHVzaChudWxsKX19KX0oZi5ib2R5KTtjb25zdCBkPXsuLi50LmhlYWRlcnN9O2YuYm9keS5sZW5ndGg+bG4mJihkWyJjb250ZW50LWVuY29kaW5nIl09Imd6aXAiLGw9bC5waXBlKHUoKSkpO2NvbnN0IG09bi5yZXF1ZXN0KHttZXRob2Q6IlBPU1QiLGFnZW50OmUsaGVhZGVyczpkLGhvc3RuYW1lOnIscGF0aDpgJHtvfSR7YX1gLHBvcnQ6cyxwcm90b2NvbDppLGNhOnQuY2FDZXJ0c30sKHQ9Pnt0Lm9uKCJkYXRhIiwoKCk9Pnt9KSksdC5vbigiZW5kIiwoKCk9Pnt9KSksdC5zZXRFbmNvZGluZygidXRmOCIpO2NvbnN0IG49dC5oZWFkZXJzWyJyZXRyeS1hZnRlciJdPz9udWxsLGU9dC5oZWFkZXJzWyJ4LXNlbnRyeS1yYXRlLWxpbWl0cyJdPz9udWxsO2goe3N0YXR1c0NvZGU6dC5zdGF0dXNDb2RlLGhlYWRlcnM6eyJyZXRyeS1hZnRlciI6biwieC1zZW50cnktcmF0ZS1saW1pdHMiOkFycmF5LmlzQXJyYXkoZSk/ZVswXXx8bnVsbDplfX0pfSkpO20ub24oImVycm9yIixwKSxsLnBpcGUobSl9KSl9KSl9fSh0LHQuaHR0cE1vZHVsZT8/byxmKTtyZXR1cm4gdG4odCxoKX0oe3VybDoodm49bW4uZHNuLHduPW1uLnR1bm5lbCxTbj1tbi5zZGtNZXRhZGF0YS5zZGssd258fGAke2Z1bmN0aW9uKHQpe3JldHVybmAke2Z1bmN0aW9uKHQpe2NvbnN0IG49dC5wcm90b2NvbD9gJHt0LnByb3RvY29sfTpgOiIiLGU9dC5wb3J0P2A6JHt0LnBvcnR9YDoiIjtyZXR1cm5gJHtufS8vJHt0Lmhvc3R9JHtlfSR7dC5wYXRoP2AvJHt0LnBhdGh9YDoiIn0vYXBpL2B9KHQpfSR7dC5wcm9qZWN0SWR9L2VudmVsb3BlL2B9KHZuKX0/JHtmdW5jdGlvbih0LG4pe2NvbnN0IGU9e3NlbnRyeV92ZXJzaW9uOkt0fTtyZXR1cm4gdC5wdWJsaWNLZXkmJihlLnNlbnRyeV9rZXk9dC5wdWJsaWNLZXkpLG4mJihlLnNlbnRyeV9jbGllbnQ9YCR7bi5uYW1lfS8ke24udmVyc2lvbn1gKSxuZXcgVVJMU2VhcmNoUGFyYW1zKGUpLnRvU3RyaW5nKCl9KHZuLFNuKX1gKX0pO2FzeW5jIGZ1bmN0aW9uIEVuKCl7aWYoZ24pe19uKCJTZW5kaW5nIGFibm9ybWFsIHNlc3Npb24iKSxLKGduLHtzdGF0dXM6ImFibm9ybWFsIixhYm5vcm1hbF9tZWNoYW5pc206ImFucl9mb3JlZ3JvdW5kIixyZWxlYXNlOm1uLnJlbGVhc2UsZW52aXJvbm1lbnQ6bW4uZW52aXJvbm1lbnR9KTtjb25zdCB0PWZ1bmN0aW9uKHQsbixlLHIpe2NvbnN0IG89WXQoZSk7cmV0dXJuIE10KHtzZW50X2F0OihuZXcgRGF0ZSkudG9JU09TdHJpbmcoKSwuLi5vJiZ7c2RrOm99LC4uLiEhciYmbiYme2RzbjpPdChuKX19LFsiYWdncmVnYXRlcyJpbiB0P1t7dHlwZToic2Vzc2lvbnMifSx0XTpbe3R5cGU6InNlc3Npb24ifSx0LnRvSlNPTigpXV0pfShnbixtbi5kc24sbW4uc2RrTWV0YWRhdGEsbW4udHVubmVsKTtfbihKU09OLnN0cmluZ2lmeSh0KSksYXdhaXQgJG4uc2VuZCh0KTt0cnl7ZT8ucG9zdE1lc3NhZ2UoInNlc3Npb24tZW5kZWQiKX1jYXRjaCh0KXt9fX1mdW5jdGlvbiB4bih0KXtpZighdClyZXR1cm47Y29uc3Qgbj1mdW5jdGlvbih0KXtpZighdC5sZW5ndGgpcmV0dXJuW107Y29uc3Qgbj1BcnJheS5mcm9tKHQpO3JldHVybi9zZW50cnlXcmFwcGVkLy50ZXN0KHgobikuZnVuY3Rpb258fCIiKSYmbi5wb3AoKSxuLnJldmVyc2UoKSxFLnRlc3QoeChuKS5mdW5jdGlvbnx8IiIpJiYobi5wb3AoKSxFLnRlc3QoeChuKS5mdW5jdGlvbnx8IiIpJiZuLnBvcCgpKSxuLnNsaWNlKDAsUykubWFwKCh0PT4oey4uLnQsZmlsZW5hbWU6dC5maWxlbmFtZXx8eChuKS5maWxlbmFtZSxmdW5jdGlvbjp0LmZ1bmN0aW9ufHwkfSkpKX0odCk7aWYobW4uYXBwUm9vdFBhdGgpZm9yKGNvbnN0IHQgb2Ygbil0LmZpbGVuYW1lJiYodC5maWxlbmFtZT1VdCh0LmZpbGVuYW1lLG1uLmFwcFJvb3RQYXRoKSk7cmV0dXJuIG59YXN5bmMgZnVuY3Rpb24gTm4odCxuKXtpZih5bj49bW4ubWF4QW5yRXZlbnRzKXJldHVybjt5bis9MSxhd2FpdCBFbigpLF9uKCJTZW5kaW5nIGV2ZW50Iik7Y29uc3QgZT17ZXZlbnRfaWQ6WSgpLGNvbnRleHRzOm1uLmNvbnRleHRzLHJlbGVhc2U6bW4ucmVsZWFzZSxlbnZpcm9ubWVudDptbi5lbnZpcm9ubWVudCxkaXN0Om1uLmRpc3QscGxhdGZvcm06Im5vZGUiLGxldmVsOiJlcnJvciIsZXhjZXB0aW9uOnt2YWx1ZXM6W3t0eXBlOiJBcHBsaWNhdGlvbk5vdFJlc3BvbmRpbmciLHZhbHVlOmBBcHBsaWNhdGlvbiBOb3QgUmVzcG9uZGluZyBmb3IgYXQgbGVhc3QgJHttbi5hbnJUaHJlc2hvbGR9IG1zYCxzdGFja3RyYWNlOntmcmFtZXM6eG4odCl9LG1lY2hhbmlzbTp7dHlwZToiQU5SIn19XX0sdGFnczptbi5zdGF0aWNUYWdzfTtuJiZmdW5jdGlvbih0LG4pe2lmKFd0KHQsbiksIXQuY29udGV4dHM/LnRyYWNlKXtjb25zdHt0cmFjZUlkOmUscGFyZW50U3BhbklkOnIscHJvcGFnYXRpb25TcGFuSWQ6b309bi5wcm9wYWdhdGlvbkNvbnRleHQ7dC5jb250ZXh0cz17dHJhY2U6e3RyYWNlX2lkOmUsc3Bhbl9pZDpvfHxaKCkscGFyZW50X3NwYW5faWQ6cn0sLi4udC5jb250ZXh0c319fShlLG4pLGZ1bmN0aW9uKHQpe2lmKDA9PT1PYmplY3Qua2V5cyhibikubGVuZ3RoKXJldHVybjtjb25zdCBuPW1uLmFwcFJvb3RQYXRoP3t9OmJuO2lmKG1uLmFwcFJvb3RQYXRoKWZvcihjb25zdFt0LGVdb2YgT2JqZWN0LmVudHJpZXMoYm4pKW5bVXQodCxtbi5hcHBSb290UGF0aCldPWU7Y29uc3QgZT1uZXcgTWFwO2Zvcihjb25zdCByIG9mIHQuZXhjZXB0aW9uPy52YWx1ZXN8fFtdKWZvcihjb25zdCB0IG9mIHIuc3RhY2t0cmFjZT8uZnJhbWVzfHxbXSl7Y29uc3Qgcj10LmFic19wYXRofHx0LmZpbGVuYW1lO3ImJm5bcl0mJmUuc2V0KHIsbltyXSl9aWYoZS5zaXplPjApe2NvbnN0IG49W107Zm9yKGNvbnN0W3Qscl1vZiBlLmVudHJpZXMoKSluLnB1c2goe3R5cGU6InNvdXJjZW1hcCIsY29kZV9maWxlOnQsZGVidWdfaWQ6cn0pO3QuZGVidWdfbWV0YT17aW1hZ2VzOm59fX0oZSk7Y29uc3Qgcj16dChlLG1uLmRzbixtbi5zZGtNZXRhZGF0YSxtbi50dW5uZWwpO19uKEpTT04uc3RyaW5naWZ5KHIpKSxhd2FpdCAkbi5zZW5kKHIpLGF3YWl0ICRuLmZsdXNoKDJlMykseW4+PW1uLm1heEFuckV2ZW50cyYmc2V0VGltZW91dCgoKCk9Pntwcm9jZXNzLmV4aXQoMCl9KSw1ZTMpfWxldCBUbjtpZihfbigiU3RhcnRlZCIpLG1uLmNhcHR1cmVTdGFja1RyYWNlKXtfbigiQ29ubmVjdGluZyB0byBkZWJ1Z2dlciIpO2NvbnN0IG49bmV3IHQ7bi5jb25uZWN0VG9NYWluVGhyZWFkKCksX24oIkNvbm5lY3RlZCB0byBkZWJ1Z2dlciIpO2NvbnN0IGU9bmV3IE1hcDtuLm9uKCJEZWJ1Z2dlci5zY3JpcHRQYXJzZWQiLCh0PT57ZS5zZXQodC5wYXJhbXMuc2NyaXB0SWQsdC5wYXJhbXMudXJsKX0pKSxuLm9uKCJEZWJ1Z2dlci5wYXVzZWQiLCh0PT57aWYoIm90aGVyIj09PXQucGFyYW1zLnJlYXNvbil0cnl7X24oIkRlYnVnZ2VyIHBhdXNlZCIpO2NvbnN0IHM9Wy4uLnQucGFyYW1zLmNhbGxGcmFtZXNdLGk9bW4uYXBwUm9vdFBhdGg/ZnVuY3Rpb24odD0ocHJvY2Vzcy5hcmd2WzFdP2VuKHByb2Nlc3MuYXJndlsxXSk6cHJvY2Vzcy5jd2QoKSksbj0iXFwiPT09byl7Y29uc3QgZT1uP2RuKHQpOnQ7cmV0dXJuIHQ9PntpZighdClyZXR1cm47Y29uc3Qgbz1uP2RuKHQpOnQ7bGV0e2RpcjpzLGJhc2U6aSxleHQ6Y309ci5wYXJzZShvKTsiLmpzIiE9PWMmJiIubWpzIiE9PWMmJiIuY2pzIiE9PWN8fChpPWkuc2xpY2UoMCwtMSpjLmxlbmd0aCkpO2NvbnN0IHU9ZGVjb2RlVVJJQ29tcG9uZW50KGkpO3N8fChzPSIuIik7Y29uc3QgYT1zLmxhc3RJbmRleE9mKCIvbm9kZV9tb2R1bGVzIik7aWYoYT4tMSlyZXR1cm5gJHtzLnNsaWNlKGErMTQpLnJlcGxhY2UoL1wvL2csIi4iKX06JHt1fWA7aWYocy5zdGFydHNXaXRoKGUpKXtjb25zdCB0PXMuc2xpY2UoZS5sZW5ndGgrMSkucmVwbGFjZSgvXC8vZywiLiIpO3JldHVybiB0P2Ake3R9OiR7dX1gOnV9cmV0dXJuIHV9fShtbi5hcHBSb290UGF0aCk6KCk9Pnt9LGM9cy5tYXAoKHQ9PmZ1bmN0aW9uKHQsbixlKXtjb25zdCByPW4/bi5yZXBsYWNlKC9eZmlsZTpcL1wvLywiIik6dm9pZCAwLG89dC5sb2NhdGlvbi5jb2x1bW5OdW1iZXI/dC5sb2NhdGlvbi5jb2x1bW5OdW1iZXIrMTp2b2lkIDAscz10LmxvY2F0aW9uLmxpbmVOdW1iZXI/dC5sb2NhdGlvbi5saW5lTnVtYmVyKzE6dm9pZCAwO3JldHVybntmaWxlbmFtZTpyLG1vZHVsZTplKHIpLGZ1bmN0aW9uOnQuZnVuY3Rpb25OYW1lfHwkLGNvbG5vOm8sbGluZW5vOnMsaW5fYXBwOnI/cm4ocik6dm9pZCAwfX0odCxlLmdldCh0LmxvY2F0aW9uLnNjcmlwdElkKSxpKSkpLHU9c2V0VGltZW91dCgoKCk9PntObihjKS50aGVuKG51bGwsKCgpPT57X24oIlNlbmRpbmcgQU5SIGV2ZW50IGZhaWxlZC4iKX0pKX0pLDVlMyk7bi5wb3N0KCJSdW50aW1lLmV2YWx1YXRlIix7ZXhwcmVzc2lvbjoiZ2xvYmFsLl9fU0VOVFJZX0dFVF9TQ09QRVNfXygpOyIsc2lsZW50OiEwLHJldHVybkJ5VmFsdWU6ITB9LCgodCxlKT0+e3QmJl9uKGBFcnJvciBleGVjdXRpbmcgc2NyaXB0OiAnJHt0Lm1lc3NhZ2V9J2ApLGNsZWFyVGltZW91dCh1KTtjb25zdCByPWU/LnJlc3VsdD9lLnJlc3VsdC52YWx1ZTp2b2lkIDA7bi5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKSxuLnBvc3QoIkRlYnVnZ2VyLmRpc2FibGUiKSxObihjLHIpLnRoZW4obnVsbCwoKCk9PntfbigiU2VuZGluZyBBTlIgZXZlbnQgZmFpbGVkLiIpfSkpfSkpfWNhdGNoKHQpe3Rocm93IG4ucG9zdCgiRGVidWdnZXIucmVzdW1lIiksbi5wb3N0KCJEZWJ1Z2dlci5kaXNhYmxlIiksdH19KSksVG49KCk9Pnt0cnl7bi5wb3N0KCJEZWJ1Z2dlci5lbmFibGUiLCgoKT0+e24ucG9zdCgiRGVidWdnZXIucGF1c2UiKX0pKX1jYXRjaCh0KXt9fX1jb25zdHtwb2xsOkNufT1mdW5jdGlvbih0LG4sZSxyKXtjb25zdCBvPXQoKTtsZXQgcz0hMSxpPSEwO3JldHVybiBzZXRJbnRlcnZhbCgoKCk9Pntjb25zdCB0PW8uZ2V0VGltZU1zKCk7ITE9PT1zJiZ0Pm4rZSYmKHM9ITAsaSYmcigpKSx0PG4rZSYmKHM9ITEpfSksMjApLHtwb2xsOigpPT57by5yZXNldCgpfSxlbmFibGVkOnQ9PntpPXR9fX0oKGZ1bmN0aW9uKCl7bGV0IHQ9cHJvY2Vzcy5ocnRpbWUoKTtyZXR1cm57Z2V0VGltZU1zOigpPT57Y29uc3RbbixlXT1wcm9jZXNzLmhydGltZSh0KTtyZXR1cm4gTWF0aC5mbG9vcigxZTMqbitlLzFlNil9LHJlc2V0OigpPT57dD1wcm9jZXNzLmhydGltZSgpfX19KSxtbi5wb2xsSW50ZXJ2YWwsbW4uYW5yVGhyZXNob2xkLChmdW5jdGlvbigpe19uKCJXYXRjaGRvZyB0aW1lb3V0IiksVG4/KF9uKCJQYXVzaW5nIGRlYnVnZ2VyIHRvIGNhcHR1cmUgc3RhY2sgdHJhY2UiKSxUbigpKTooX24oIkNhcHR1cmluZyBldmVudCB3aXRob3V0IGEgc3RhY2sgdHJhY2UiKSxObigpLnRoZW4obnVsbCwoKCk9PntfbigiU2VuZGluZyBBTlIgZXZlbnQgZmFpbGVkIG9uIHdhdGNoZG9nIHRpbWVvdXQuIil9KSkpfSkpO2U/Lm9uKCJtZXNzYWdlIiwodD0+e3Quc2Vzc2lvbiYmKGduPVcodC5zZXNzaW9uKSksdC5kZWJ1Z0ltYWdlcyYmKGJuPXQuZGVidWdJbWFnZXMpLENuKCl9KSk7';
|
|
12
|
+
const base64WorkerScript = 'LyohIEBzZW50cnkvbm9kZSA5LjE0LjAgKDBiNjM3MTApIHwgaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdCAqLwppbXBvcnR7U2Vzc2lvbiBhcyB0fWZyb20ibm9kZTppbnNwZWN0b3IiO2ltcG9ydHt3b3JrZXJEYXRhIGFzIG4scGFyZW50UG9ydCBhcyBlfWZyb20ibm9kZTp3b3JrZXJfdGhyZWFkcyI7aW1wb3J0e3Bvc2l4IGFzIHIsc2VwIGFzIG99ZnJvbSJub2RlOnBhdGgiO2ltcG9ydCphcyBzIGZyb20ibm9kZTpodHRwIjtpbXBvcnQqYXMgaSBmcm9tIm5vZGU6aHR0cHMiO2ltcG9ydHtSZWFkYWJsZSBhcyBjfWZyb20ibm9kZTpzdHJlYW0iO2ltcG9ydHtjcmVhdGVHemlwIGFzIHV9ZnJvbSJub2RlOnpsaWIiO2ltcG9ydCphcyBhIGZyb20ibm9kZTpuZXQiO2ltcG9ydCphcyBmIGZyb20ibm9kZTp0bHMiO2NvbnN0IGg9InVuZGVmaW5lZCI9PXR5cGVvZiBfX1NFTlRSWV9ERUJVR19ffHxfX1NFTlRSWV9ERUJVR19fLHA9Z2xvYmFsVGhpcyxsPSJ1bmRlZmluZWQiPT10eXBlb2YgX19TRU5UUllfREVCVUdfX3x8X19TRU5UUllfREVCVUdfXyxkPSI5LjE0LjAiO2Z1bmN0aW9uIG0oKXtyZXR1cm4gZyhwKSxwfWZ1bmN0aW9uIGcodCl7Y29uc3Qgbj10Ll9fU0VOVFJZX189dC5fX1NFTlRSWV9ffHx7fTtyZXR1cm4gbi52ZXJzaW9uPW4udmVyc2lvbnx8ZCxuW2RdPW5bZF18fHt9fWZ1bmN0aW9uIHkodCxuLGU9cCl7Y29uc3Qgcj1lLl9fU0VOVFJZX189ZS5fX1NFTlRSWV9ffHx7fSxvPXJbZF09cltkXXx8e307cmV0dXJuIG9bdF18fChvW3RdPW4oKSl9Y29uc3QgYj1bImRlYnVnIiwiaW5mbyIsIndhcm4iLCJlcnJvciIsImxvZyIsImFzc2VydCIsInRyYWNlIl0sXz17fTtmdW5jdGlvbiB2KHQpe2lmKCEoImNvbnNvbGUiaW4gcCkpcmV0dXJuIHQoKTtjb25zdCBuPXAuY29uc29sZSxlPXt9LHI9T2JqZWN0LmtleXMoXyk7ci5mb3JFYWNoKCh0PT57Y29uc3Qgcj1fW3RdO2VbdF09blt0XSxuW3RdPXJ9KSk7dHJ5e3JldHVybiB0KCl9ZmluYWxseXtyLmZvckVhY2goKHQ9PntuW3RdPWVbdF19KSl9fWNvbnN0IHc9eSgibG9nZ2VyIiwoZnVuY3Rpb24oKXtsZXQgdD0hMTtjb25zdCBuPXtlbmFibGU6KCk9Pnt0PSEwfSxkaXNhYmxlOigpPT57dD0hMX0saXNFbmFibGVkOigpPT50fTtyZXR1cm4gbD9iLmZvckVhY2goKGU9PntuW2VdPSguLi5uKT0+e3QmJnYoKCgpPT57cC5jb25zb2xlW2VdKGBTZW50cnkgTG9nZ2VyIFske2V9XTpgLC4uLm4pfSkpfX0pKTpiLmZvckVhY2goKHQ9PntuW3RdPSgpPT57fX0pKSxufSkpLFM9NTAsJD0iPyIsRT0vY2FwdHVyZU1lc3NhZ2V8Y2FwdHVyZUV4Y2VwdGlvbi87ZnVuY3Rpb24geCh0KXtyZXR1cm4gdFt0Lmxlbmd0aC0xXXx8e319Y29uc3QgTj0iPGFub255bW91cz4iO2NvbnN0IFQ9T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztmdW5jdGlvbiBDKHQsbil7cmV0dXJuIFQuY2FsbCh0KT09PWBbb2JqZWN0ICR7bn1dYH1mdW5jdGlvbiBSKHQpe3JldHVybiBDKHQsIlN0cmluZyIpfWZ1bmN0aW9uIGsodCl7cmV0dXJuIEModCwiT2JqZWN0Iil9ZnVuY3Rpb24gaih0KXtyZXR1cm4gQm9vbGVhbih0Py50aGVuJiYiZnVuY3Rpb24iPT10eXBlb2YgdC50aGVuKX1mdW5jdGlvbiBEKHQsbil7dHJ5e3JldHVybiB0IGluc3RhbmNlb2Ygbn1jYXRjaCh0KXtyZXR1cm4hMX19Y29uc3QgST1wLE89ODA7ZnVuY3Rpb24gQSh0LG4pe2NvbnN0IGU9dCxyPVtdO2lmKCFlPy50YWdOYW1lKXJldHVybiIiO2lmKEkuSFRNTEVsZW1lbnQmJmUgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCYmZS5kYXRhc2V0KXtpZihlLmRhdGFzZXQuc2VudHJ5Q29tcG9uZW50KXJldHVybiBlLmRhdGFzZXQuc2VudHJ5Q29tcG9uZW50O2lmKGUuZGF0YXNldC5zZW50cnlFbGVtZW50KXJldHVybiBlLmRhdGFzZXQuc2VudHJ5RWxlbWVudH1yLnB1c2goZS50YWdOYW1lLnRvTG93ZXJDYXNlKCkpO2NvbnN0IG89bj8ubGVuZ3RoP24uZmlsdGVyKCh0PT5lLmdldEF0dHJpYnV0ZSh0KSkpLm1hcCgodD0+W3QsZS5nZXRBdHRyaWJ1dGUodCldKSk6bnVsbDtpZihvPy5sZW5ndGgpby5mb3JFYWNoKCh0PT57ci5wdXNoKGBbJHt0WzBdfT0iJHt0WzFdfSJdYCl9KSk7ZWxzZXtlLmlkJiZyLnB1c2goYCMke2UuaWR9YCk7Y29uc3QgdD1lLmNsYXNzTmFtZTtpZih0JiZSKHQpKXtjb25zdCBuPXQuc3BsaXQoL1xzKy8pO2Zvcihjb25zdCB0IG9mIG4pci5wdXNoKGAuJHt0fWApfX1jb25zdCBzPVsiYXJpYS1sYWJlbCIsInR5cGUiLCJuYW1lIiwidGl0bGUiLCJhbHQiXTtmb3IoY29uc3QgdCBvZiBzKXtjb25zdCBuPWUuZ2V0QXR0cmlidXRlKHQpO24mJnIucHVzaChgWyR7dH09IiR7bn0iXWApfXJldHVybiByLmpvaW4oIiIpfWZ1bmN0aW9uIFAodCxuPTApe3JldHVybiJzdHJpbmciIT10eXBlb2YgdHx8MD09PW58fHQubGVuZ3RoPD1uP3Q6YCR7dC5zbGljZSgwLG4pfS4uLmB9ZnVuY3Rpb24gVSh0KXtpZihmdW5jdGlvbih0KXtzd2l0Y2goVC5jYWxsKHQpKXtjYXNlIltvYmplY3QgRXJyb3JdIjpjYXNlIltvYmplY3QgRXhjZXB0aW9uXSI6Y2FzZSJbb2JqZWN0IERPTUV4Y2VwdGlvbl0iOmNhc2UiW29iamVjdCBXZWJBc3NlbWJseS5FeGNlcHRpb25dIjpyZXR1cm4hMDtkZWZhdWx0OnJldHVybiBEKHQsRXJyb3IpfX0odCkpcmV0dXJue21lc3NhZ2U6dC5tZXNzYWdlLG5hbWU6dC5uYW1lLHN0YWNrOnQuc3RhY2ssLi4uTCh0KX07aWYobj10LCJ1bmRlZmluZWQiIT10eXBlb2YgRXZlbnQmJkQobixFdmVudCkpe2NvbnN0IG49e3R5cGU6dC50eXBlLHRhcmdldDpNKHQudGFyZ2V0KSxjdXJyZW50VGFyZ2V0Ok0odC5jdXJyZW50VGFyZ2V0KSwuLi5MKHQpfTtyZXR1cm4idW5kZWZpbmVkIiE9dHlwZW9mIEN1c3RvbUV2ZW50JiZEKHQsQ3VzdG9tRXZlbnQpJiYobi5kZXRhaWw9dC5kZXRhaWwpLG59cmV0dXJuIHQ7dmFyIG59ZnVuY3Rpb24gTSh0KXt0cnl7cmV0dXJuIG49dCwidW5kZWZpbmVkIiE9dHlwZW9mIEVsZW1lbnQmJkQobixFbGVtZW50KT9mdW5jdGlvbih0LG49e30pe2lmKCF0KXJldHVybiI8dW5rbm93bj4iO3RyeXtsZXQgZT10O2NvbnN0IHI9NSxvPVtdO2xldCBzPTAsaT0wO2NvbnN0IGM9IiA+ICIsdT1jLmxlbmd0aDtsZXQgYTtjb25zdCBmPUFycmF5LmlzQXJyYXkobik/bjpuLmtleUF0dHJzLGg9IUFycmF5LmlzQXJyYXkobikmJm4ubWF4U3RyaW5nTGVuZ3RofHxPO2Zvcig7ZSYmcysrPHImJihhPUEoZSxmKSwhKCJodG1sIj09PWF8fHM+MSYmaStvLmxlbmd0aCp1K2EubGVuZ3RoPj1oKSk7KW8ucHVzaChhKSxpKz1hLmxlbmd0aCxlPWUucGFyZW50Tm9kZTtyZXR1cm4gby5yZXZlcnNlKCkuam9pbihjKX1jYXRjaCh0KXtyZXR1cm4iPHVua25vd24+In19KHQpOk9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh0KX1jYXRjaCh0KXtyZXR1cm4iPHVua25vd24+In12YXIgbn1mdW5jdGlvbiBMKHQpe2lmKCJvYmplY3QiPT10eXBlb2YgdCYmbnVsbCE9PXQpe2NvbnN0IG49e307Zm9yKGNvbnN0IGUgaW4gdClPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodCxlKSYmKG5bZV09dFtlXSk7cmV0dXJuIG59cmV0dXJue319ZnVuY3Rpb24gQih0PWZ1bmN0aW9uKCl7Y29uc3QgdD1wO3JldHVybiB0LmNyeXB0b3x8dC5tc0NyeXB0b30oKSl7bGV0IG49KCk9PjE2Kk1hdGgucmFuZG9tKCk7dHJ5e2lmKHQ/LnJhbmRvbVVVSUQpcmV0dXJuIHQucmFuZG9tVVVJRCgpLnJlcGxhY2UoLy0vZywiIik7dD8uZ2V0UmFuZG9tVmFsdWVzJiYobj0oKT0+e2NvbnN0IG49bmV3IFVpbnQ4QXJyYXkoMSk7cmV0dXJuIHQuZ2V0UmFuZG9tVmFsdWVzKG4pLG5bMF19KX1jYXRjaCh0KXt9cmV0dXJuKFsxZTddKzFlMys0ZTMrOGUzKzFlMTEpLnJlcGxhY2UoL1swMThdL2csKHQ9Pih0XigxNSZuKCkpPj50LzQpLnRvU3RyaW5nKDE2KSkpfWNvbnN0IEc9MWUzO2Z1bmN0aW9uIEooKXtyZXR1cm4gRGF0ZS5ub3coKS9HfWNvbnN0IFk9ZnVuY3Rpb24oKXtjb25zdHtwZXJmb3JtYW5jZTp0fT1wO2lmKCF0Py5ub3cpcmV0dXJuIEo7Y29uc3Qgbj1EYXRlLm5vdygpLXQubm93KCksZT1udWxsPT10LnRpbWVPcmlnaW4/bjp0LnRpbWVPcmlnaW47cmV0dXJuKCk9PihlK3Qubm93KCkpL0d9KCk7ZnVuY3Rpb24geih0KXtjb25zdCBuPVkoKSxlPXtzaWQ6QigpLGluaXQ6ITAsdGltZXN0YW1wOm4sc3RhcnRlZDpuLGR1cmF0aW9uOjAsc3RhdHVzOiJvayIsZXJyb3JzOjAsaWdub3JlRHVyYXRpb246ITEsdG9KU09OOigpPT5mdW5jdGlvbih0KXtyZXR1cm57c2lkOmAke3Quc2lkfWAsaW5pdDp0LmluaXQsc3RhcnRlZDpuZXcgRGF0ZSgxZTMqdC5zdGFydGVkKS50b0lTT1N0cmluZygpLHRpbWVzdGFtcDpuZXcgRGF0ZSgxZTMqdC50aW1lc3RhbXApLnRvSVNPU3RyaW5nKCksc3RhdHVzOnQuc3RhdHVzLGVycm9yczp0LmVycm9ycyxkaWQ6Im51bWJlciI9PXR5cGVvZiB0LmRpZHx8InN0cmluZyI9PXR5cGVvZiB0LmRpZD9gJHt0LmRpZH1gOnZvaWQgMCxkdXJhdGlvbjp0LmR1cmF0aW9uLGFibm9ybWFsX21lY2hhbmlzbTp0LmFibm9ybWFsX21lY2hhbmlzbSxhdHRyczp7cmVsZWFzZTp0LnJlbGVhc2UsZW52aXJvbm1lbnQ6dC5lbnZpcm9ubWVudCxpcF9hZGRyZXNzOnQuaXBBZGRyZXNzLHVzZXJfYWdlbnQ6dC51c2VyQWdlbnR9fX0oZSl9O3JldHVybiB0JiZIKGUsdCksZX1mdW5jdGlvbiBIKHQsbj17fSl7aWYobi51c2VyJiYoIXQuaXBBZGRyZXNzJiZuLnVzZXIuaXBfYWRkcmVzcyYmKHQuaXBBZGRyZXNzPW4udXNlci5pcF9hZGRyZXNzKSx0LmRpZHx8bi5kaWR8fCh0LmRpZD1uLnVzZXIuaWR8fG4udXNlci5lbWFpbHx8bi51c2VyLnVzZXJuYW1lKSksdC50aW1lc3RhbXA9bi50aW1lc3RhbXB8fFkoKSxuLmFibm9ybWFsX21lY2hhbmlzbSYmKHQuYWJub3JtYWxfbWVjaGFuaXNtPW4uYWJub3JtYWxfbWVjaGFuaXNtKSxuLmlnbm9yZUR1cmF0aW9uJiYodC5pZ25vcmVEdXJhdGlvbj1uLmlnbm9yZUR1cmF0aW9uKSxuLnNpZCYmKHQuc2lkPTMyPT09bi5zaWQubGVuZ3RoP24uc2lkOkIoKSksdm9pZCAwIT09bi5pbml0JiYodC5pbml0PW4uaW5pdCksIXQuZGlkJiZuLmRpZCYmKHQuZGlkPWAke24uZGlkfWApLCJudW1iZXIiPT10eXBlb2Ygbi5zdGFydGVkJiYodC5zdGFydGVkPW4uc3RhcnRlZCksdC5pZ25vcmVEdXJhdGlvbil0LmR1cmF0aW9uPXZvaWQgMDtlbHNlIGlmKCJudW1iZXIiPT10eXBlb2Ygbi5kdXJhdGlvbil0LmR1cmF0aW9uPW4uZHVyYXRpb247ZWxzZXtjb25zdCBuPXQudGltZXN0YW1wLXQuc3RhcnRlZDt0LmR1cmF0aW9uPW4+PTA/bjowfW4ucmVsZWFzZSYmKHQucmVsZWFzZT1uLnJlbGVhc2UpLG4uZW52aXJvbm1lbnQmJih0LmVudmlyb25tZW50PW4uZW52aXJvbm1lbnQpLCF0LmlwQWRkcmVzcyYmbi5pcEFkZHJlc3MmJih0LmlwQWRkcmVzcz1uLmlwQWRkcmVzcyksIXQudXNlckFnZW50JiZuLnVzZXJBZ2VudCYmKHQudXNlckFnZW50PW4udXNlckFnZW50KSwibnVtYmVyIj09dHlwZW9mIG4uZXJyb3JzJiYodC5lcnJvcnM9bi5lcnJvcnMpLG4uc3RhdHVzJiYodC5zdGF0dXM9bi5zdGF0dXMpfWZ1bmN0aW9uIEYoKXtyZXR1cm4gQigpfWZ1bmN0aW9uIFcoKXtyZXR1cm4gQigpLnN1YnN0cmluZygxNil9ZnVuY3Rpb24gSyh0LG4sZT0yKXtpZighbnx8Im9iamVjdCIhPXR5cGVvZiBufHxlPD0wKXJldHVybiBuO2lmKHQmJjA9PT1PYmplY3Qua2V5cyhuKS5sZW5ndGgpcmV0dXJuIHQ7Y29uc3Qgcj17Li4udH07Zm9yKGNvbnN0IHQgaW4gbilPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobix0KSYmKHJbdF09SyhyW3RdLG5bdF0sZS0xKSk7cmV0dXJuIHJ9Y29uc3QgVj0iX3NlbnRyeVNwYW4iO2Z1bmN0aW9uIFoodCxuKXtuP2Z1bmN0aW9uKHQsbixlKXt0cnl7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsbix7dmFsdWU6ZSx3cml0YWJsZTohMCxjb25maWd1cmFibGU6ITB9KX1jYXRjaChlKXtsJiZ3LmxvZyhgRmFpbGVkIHRvIGFkZCBub24tZW51bWVyYWJsZSBwcm9wZXJ0eSAiJHtufSIgdG8gb2JqZWN0YCx0KX19KHQsVixuKTpkZWxldGUgdFtWXX1mdW5jdGlvbiBxKHQpe3JldHVybiB0W1ZdfWNsYXNzIFF7Y29uc3RydWN0b3IoKXt0aGlzLnQ9ITEsdGhpcy5vPVtdLHRoaXMuaT1bXSx0aGlzLnU9W10sdGhpcy5oPVtdLHRoaXMucD17fSx0aGlzLmw9e30sdGhpcy5tPXt9LHRoaXMuXz17fSx0aGlzLnY9e30sdGhpcy5TPXt0cmFjZUlkOkYoKSxzYW1wbGVSYW5kOk1hdGgucmFuZG9tKCl9fWNsb25lKCl7Y29uc3QgdD1uZXcgUTtyZXR1cm4gdC51PVsuLi50aGlzLnVdLHQubD17Li4udGhpcy5sfSx0Lm09ey4uLnRoaXMubX0sdC5fPXsuLi50aGlzLl99LHRoaXMuXy5mbGFncyYmKHQuXy5mbGFncz17dmFsdWVzOlsuLi50aGlzLl8uZmxhZ3MudmFsdWVzXX0pLHQucD10aGlzLnAsdC5OPXRoaXMuTix0LlQ9dGhpcy5ULHQuQz10aGlzLkMsdC5SPXRoaXMuUix0Lmk9Wy4uLnRoaXMuaV0sdC5oPVsuLi50aGlzLmhdLHQudj17Li4udGhpcy52fSx0LlM9ey4uLnRoaXMuU30sdC5rPXRoaXMuayx0Lmo9dGhpcy5qLFoodCxxKHRoaXMpKSx0fXNldENsaWVudCh0KXt0aGlzLms9dH1zZXRMYXN0RXZlbnRJZCh0KXt0aGlzLmo9dH1nZXRDbGllbnQoKXtyZXR1cm4gdGhpcy5rfWxhc3RFdmVudElkKCl7cmV0dXJuIHRoaXMuan1hZGRTY29wZUxpc3RlbmVyKHQpe3RoaXMuby5wdXNoKHQpfWFkZEV2ZW50UHJvY2Vzc29yKHQpe3JldHVybiB0aGlzLmkucHVzaCh0KSx0aGlzfXNldFVzZXIodCl7cmV0dXJuIHRoaXMucD10fHx7ZW1haWw6dm9pZCAwLGlkOnZvaWQgMCxpcF9hZGRyZXNzOnZvaWQgMCx1c2VybmFtZTp2b2lkIDB9LHRoaXMuVCYmSCh0aGlzLlQse3VzZXI6dH0pLHRoaXMuRCgpLHRoaXN9Z2V0VXNlcigpe3JldHVybiB0aGlzLnB9c2V0VGFncyh0KXtyZXR1cm4gdGhpcy5sPXsuLi50aGlzLmwsLi4udH0sdGhpcy5EKCksdGhpc31zZXRUYWcodCxuKXtyZXR1cm4gdGhpcy5sPXsuLi50aGlzLmwsW3RdOm59LHRoaXMuRCgpLHRoaXN9c2V0RXh0cmFzKHQpe3JldHVybiB0aGlzLm09ey4uLnRoaXMubSwuLi50fSx0aGlzLkQoKSx0aGlzfXNldEV4dHJhKHQsbil7cmV0dXJuIHRoaXMubT17Li4udGhpcy5tLFt0XTpufSx0aGlzLkQoKSx0aGlzfXNldEZpbmdlcnByaW50KHQpe3JldHVybiB0aGlzLlI9dCx0aGlzLkQoKSx0aGlzfXNldExldmVsKHQpe3JldHVybiB0aGlzLk49dCx0aGlzLkQoKSx0aGlzfXNldFRyYW5zYWN0aW9uTmFtZSh0KXtyZXR1cm4gdGhpcy5DPXQsdGhpcy5EKCksdGhpc31zZXRDb250ZXh0KHQsbil7cmV0dXJuIG51bGw9PT1uP2RlbGV0ZSB0aGlzLl9bdF06dGhpcy5fW3RdPW4sdGhpcy5EKCksdGhpc31zZXRTZXNzaW9uKHQpe3JldHVybiB0P3RoaXMuVD10OmRlbGV0ZSB0aGlzLlQsdGhpcy5EKCksdGhpc31nZXRTZXNzaW9uKCl7cmV0dXJuIHRoaXMuVH11cGRhdGUodCl7aWYoIXQpcmV0dXJuIHRoaXM7Y29uc3Qgbj0iZnVuY3Rpb24iPT10eXBlb2YgdD90KHRoaXMpOnQsZT1uIGluc3RhbmNlb2YgUT9uLmdldFNjb3BlRGF0YSgpOmsobik/dDp2b2lkIDAse3RhZ3M6cixleHRyYTpvLHVzZXI6cyxjb250ZXh0czppLGxldmVsOmMsZmluZ2VycHJpbnQ6dT1bXSxwcm9wYWdhdGlvbkNvbnRleHQ6YX09ZXx8e307cmV0dXJuIHRoaXMubD17Li4udGhpcy5sLC4uLnJ9LHRoaXMubT17Li4udGhpcy5tLC4uLm99LHRoaXMuXz17Li4udGhpcy5fLC4uLml9LHMmJk9iamVjdC5rZXlzKHMpLmxlbmd0aCYmKHRoaXMucD1zKSxjJiYodGhpcy5OPWMpLHUubGVuZ3RoJiYodGhpcy5SPXUpLGEmJih0aGlzLlM9YSksdGhpc31jbGVhcigpe3JldHVybiB0aGlzLnU9W10sdGhpcy5sPXt9LHRoaXMubT17fSx0aGlzLnA9e30sdGhpcy5fPXt9LHRoaXMuTj12b2lkIDAsdGhpcy5DPXZvaWQgMCx0aGlzLlI9dm9pZCAwLHRoaXMuVD12b2lkIDAsWih0aGlzLHZvaWQgMCksdGhpcy5oPVtdLHRoaXMuc2V0UHJvcGFnYXRpb25Db250ZXh0KHt0cmFjZUlkOkYoKSxzYW1wbGVSYW5kOk1hdGgucmFuZG9tKCl9KSx0aGlzLkQoKSx0aGlzfWFkZEJyZWFkY3J1bWIodCxuKXtjb25zdCBlPSJudW1iZXIiPT10eXBlb2Ygbj9uOjEwMDtpZihlPD0wKXJldHVybiB0aGlzO2NvbnN0IHI9e3RpbWVzdGFtcDpKKCksLi4udCxtZXNzYWdlOnQubWVzc2FnZT9QKHQubWVzc2FnZSwyMDQ4KTp0Lm1lc3NhZ2V9O3JldHVybiB0aGlzLnUucHVzaChyKSx0aGlzLnUubGVuZ3RoPmUmJih0aGlzLnU9dGhpcy51LnNsaWNlKC1lKSx0aGlzLms/LnJlY29yZERyb3BwZWRFdmVudCgiYnVmZmVyX292ZXJmbG93IiwibG9nX2l0ZW0iKSksdGhpcy5EKCksdGhpc31nZXRMYXN0QnJlYWRjcnVtYigpe3JldHVybiB0aGlzLnVbdGhpcy51Lmxlbmd0aC0xXX1jbGVhckJyZWFkY3J1bWJzKCl7cmV0dXJuIHRoaXMudT1bXSx0aGlzLkQoKSx0aGlzfWFkZEF0dGFjaG1lbnQodCl7cmV0dXJuIHRoaXMuaC5wdXNoKHQpLHRoaXN9Y2xlYXJBdHRhY2htZW50cygpe3JldHVybiB0aGlzLmg9W10sdGhpc31nZXRTY29wZURhdGEoKXtyZXR1cm57YnJlYWRjcnVtYnM6dGhpcy51LGF0dGFjaG1lbnRzOnRoaXMuaCxjb250ZXh0czp0aGlzLl8sdGFnczp0aGlzLmwsZXh0cmE6dGhpcy5tLHVzZXI6dGhpcy5wLGxldmVsOnRoaXMuTixmaW5nZXJwcmludDp0aGlzLlJ8fFtdLGV2ZW50UHJvY2Vzc29yczp0aGlzLmkscHJvcGFnYXRpb25Db250ZXh0OnRoaXMuUyxzZGtQcm9jZXNzaW5nTWV0YWRhdGE6dGhpcy52LHRyYW5zYWN0aW9uTmFtZTp0aGlzLkMsc3BhbjpxKHRoaXMpfX1zZXRTREtQcm9jZXNzaW5nTWV0YWRhdGEodCl7cmV0dXJuIHRoaXMudj1LKHRoaXMudix0LDIpLHRoaXN9c2V0UHJvcGFnYXRpb25Db250ZXh0KHQpe3JldHVybiB0aGlzLlM9dCx0aGlzfWdldFByb3BhZ2F0aW9uQ29udGV4dCgpe3JldHVybiB0aGlzLlN9Y2FwdHVyZUV4Y2VwdGlvbih0LG4pe2NvbnN0IGU9bj8uZXZlbnRfaWR8fEIoKTtpZighdGhpcy5rKXJldHVybiB3Lndhcm4oIk5vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBleGNlcHRpb24hIiksZTtjb25zdCByPW5ldyBFcnJvcigiU2VudHJ5IHN5bnRoZXRpY0V4Y2VwdGlvbiIpO3JldHVybiB0aGlzLmsuY2FwdHVyZUV4Y2VwdGlvbih0LHtvcmlnaW5hbEV4Y2VwdGlvbjp0LHN5bnRoZXRpY0V4Y2VwdGlvbjpyLC4uLm4sZXZlbnRfaWQ6ZX0sdGhpcyksZX1jYXB0dXJlTWVzc2FnZSh0LG4sZSl7Y29uc3Qgcj1lPy5ldmVudF9pZHx8QigpO2lmKCF0aGlzLmspcmV0dXJuIHcud2FybigiTm8gY2xpZW50IGNvbmZpZ3VyZWQgb24gc2NvcGUgLSB3aWxsIG5vdCBjYXB0dXJlIG1lc3NhZ2UhIikscjtjb25zdCBvPW5ldyBFcnJvcih0KTtyZXR1cm4gdGhpcy5rLmNhcHR1cmVNZXNzYWdlKHQsbix7b3JpZ2luYWxFeGNlcHRpb246dCxzeW50aGV0aWNFeGNlcHRpb246bywuLi5lLGV2ZW50X2lkOnJ9LHRoaXMpLHJ9Y2FwdHVyZUV2ZW50KHQsbil7Y29uc3QgZT1uPy5ldmVudF9pZHx8QigpO3JldHVybiB0aGlzLms/KHRoaXMuay5jYXB0dXJlRXZlbnQodCx7Li4ubixldmVudF9pZDplfSx0aGlzKSxlKToody53YXJuKCJObyBjbGllbnQgY29uZmlndXJlZCBvbiBzY29wZSAtIHdpbGwgbm90IGNhcHR1cmUgZXZlbnQhIiksZSl9RCgpe3RoaXMudHx8KHRoaXMudD0hMCx0aGlzLm8uZm9yRWFjaCgodD0+e3QodGhpcyl9KSksdGhpcy50PSExKX19Y2xhc3MgWHtjb25zdHJ1Y3Rvcih0LG4pe2xldCBlLHI7ZT10fHxuZXcgUSxyPW58fG5ldyBRLHRoaXMuST1be3Njb3BlOmV9XSx0aGlzLk89cn13aXRoU2NvcGUodCl7Y29uc3Qgbj10aGlzLkEoKTtsZXQgZTt0cnl7ZT10KG4pfWNhdGNoKHQpe3Rocm93IHRoaXMuUCgpLHR9cmV0dXJuIGooZSk/ZS50aGVuKCh0PT4odGhpcy5QKCksdCkpLCh0PT57dGhyb3cgdGhpcy5QKCksdH0pKToodGhpcy5QKCksZSl9Z2V0Q2xpZW50KCl7cmV0dXJuIHRoaXMuZ2V0U3RhY2tUb3AoKS5jbGllbnR9Z2V0U2NvcGUoKXtyZXR1cm4gdGhpcy5nZXRTdGFja1RvcCgpLnNjb3BlfWdldElzb2xhdGlvblNjb3BlKCl7cmV0dXJuIHRoaXMuT31nZXRTdGFja1RvcCgpe3JldHVybiB0aGlzLklbdGhpcy5JLmxlbmd0aC0xXX1BKCl7Y29uc3QgdD10aGlzLmdldFNjb3BlKCkuY2xvbmUoKTtyZXR1cm4gdGhpcy5JLnB1c2goe2NsaWVudDp0aGlzLmdldENsaWVudCgpLHNjb3BlOnR9KSx0fVAoKXtyZXR1cm4hKHRoaXMuSS5sZW5ndGg8PTEpJiYhIXRoaXMuSS5wb3AoKX19ZnVuY3Rpb24gdHQoKXtjb25zdCB0PWcobSgpKTtyZXR1cm4gdC5zdGFjaz10LnN0YWNrfHxuZXcgWCh5KCJkZWZhdWx0Q3VycmVudFNjb3BlIiwoKCk9Pm5ldyBRKSkseSgiZGVmYXVsdElzb2xhdGlvblNjb3BlIiwoKCk9Pm5ldyBRKSkpfWZ1bmN0aW9uIG50KHQpe3JldHVybiB0dCgpLndpdGhTY29wZSh0KX1mdW5jdGlvbiBldCh0LG4pe2NvbnN0IGU9dHQoKTtyZXR1cm4gZS53aXRoU2NvcGUoKCgpPT4oZS5nZXRTdGFja1RvcCgpLnNjb3BlPXQsbih0KSkpKX1mdW5jdGlvbiBydCh0KXtyZXR1cm4gdHQoKS53aXRoU2NvcGUoKCgpPT50KHR0KCkuZ2V0SXNvbGF0aW9uU2NvcGUoKSkpKX1mdW5jdGlvbiBvdCh0KXtjb25zdCBuPWcodCk7cmV0dXJuIG4uYWNzP24uYWNzOnt3aXRoSXNvbGF0aW9uU2NvcGU6cnQsd2l0aFNjb3BlOm50LHdpdGhTZXRTY29wZTpldCx3aXRoU2V0SXNvbGF0aW9uU2NvcGU6KHQsbik9PnJ0KG4pLGdldEN1cnJlbnRTY29wZTooKT0+dHQoKS5nZXRTY29wZSgpLGdldElzb2xhdGlvblNjb3BlOigpPT50dCgpLmdldElzb2xhdGlvblNjb3BlKCl9fWZ1bmN0aW9uIHN0KCl7cmV0dXJuIG90KG0oKSkuZ2V0Q3VycmVudFNjb3BlKCkuZ2V0Q2xpZW50KCl9Y29uc3QgaXQ9InNlbnRyeS5zb3VyY2UiLGN0PSJzZW50cnkuc2FtcGxlX3JhdGUiLHV0PSJzZW50cnkub3AiLGF0PSJzZW50cnkub3JpZ2luIixmdD0wLGh0PTEscHQ9Il9zZW50cnlTY29wZSIsbHQ9Il9zZW50cnlJc29sYXRpb25TY29wZSI7ZnVuY3Rpb24gZHQodCl7cmV0dXJue3Njb3BlOnRbcHRdLGlzb2xhdGlvblNjb3BlOnRbbHRdfX1jb25zdCBtdD0ic2VudHJ5LSIsZ3Q9L15zZW50cnktLztmdW5jdGlvbiB5dCh0KXtjb25zdCBuPWZ1bmN0aW9uKHQpe2lmKCF0fHwhUih0KSYmIUFycmF5LmlzQXJyYXkodCkpcmV0dXJuO2lmKEFycmF5LmlzQXJyYXkodCkpcmV0dXJuIHQucmVkdWNlKCgodCxuKT0+e2NvbnN0IGU9YnQobik7cmV0dXJuIE9iamVjdC5lbnRyaWVzKGUpLmZvckVhY2goKChbbixlXSk9Pnt0W25dPWV9KSksdH0pLHt9KTtyZXR1cm4gYnQodCl9KHQpO2lmKCFuKXJldHVybjtjb25zdCBlPU9iamVjdC5lbnRyaWVzKG4pLnJlZHVjZSgoKHQsW24sZV0pPT57aWYobi5tYXRjaChndCkpe3Rbbi5zbGljZShtdC5sZW5ndGgpXT1lfXJldHVybiB0fSkse30pO3JldHVybiBPYmplY3Qua2V5cyhlKS5sZW5ndGg+MD9lOnZvaWQgMH1mdW5jdGlvbiBidCh0KXtyZXR1cm4gdC5zcGxpdCgiLCIpLm1hcCgodD0+dC5zcGxpdCgiPSIpLm1hcCgodD0+ZGVjb2RlVVJJQ29tcG9uZW50KHQudHJpbSgpKSkpKSkucmVkdWNlKCgodCxbbixlXSk9PihuJiZlJiYodFtuXT1lKSx0KSkse30pfWNvbnN0IF90PTE7ZnVuY3Rpb24gdnQodCl7Y29uc3R7c3BhbklkOm4sdHJhY2VJZDplLGlzUmVtb3RlOnJ9PXQuc3BhbkNvbnRleHQoKSxvPXI/bjpFdCh0KS5wYXJlbnRfc3Bhbl9pZCxzPWR0KHQpLnNjb3BlO3JldHVybntwYXJlbnRfc3Bhbl9pZDpvLHNwYW5faWQ6cj9zPy5nZXRQcm9wYWdhdGlvbkNvbnRleHQoKS5wcm9wYWdhdGlvblNwYW5JZHx8VygpOm4sdHJhY2VfaWQ6ZX19ZnVuY3Rpb24gd3QodCl7cmV0dXJuIHQmJnQubGVuZ3RoPjA/dC5tYXAoKCh7Y29udGV4dDp7c3BhbklkOnQsdHJhY2VJZDpuLHRyYWNlRmxhZ3M6ZSwuLi5yfSxhdHRyaWJ1dGVzOm99KT0+KHtzcGFuX2lkOnQsdHJhY2VfaWQ6bixzYW1wbGVkOmU9PT1fdCxhdHRyaWJ1dGVzOm8sLi4ucn0pKSk6dm9pZCAwfWZ1bmN0aW9uIFN0KHQpe3JldHVybiJudW1iZXIiPT10eXBlb2YgdD8kdCh0KTpBcnJheS5pc0FycmF5KHQpP3RbMF0rdFsxXS8xZTk6dCBpbnN0YW5jZW9mIERhdGU/JHQodC5nZXRUaW1lKCkpOlkoKX1mdW5jdGlvbiAkdCh0KXtyZXR1cm4gdD45OTk5OTk5OTk5P3QvMWUzOnR9ZnVuY3Rpb24gRXQodCl7aWYoZnVuY3Rpb24odCl7cmV0dXJuImZ1bmN0aW9uIj09dHlwZW9mIHQuZ2V0U3BhbkpTT059KHQpKXJldHVybiB0LmdldFNwYW5KU09OKCk7Y29uc3R7c3BhbklkOm4sdHJhY2VJZDplfT10LnNwYW5Db250ZXh0KCk7aWYoZnVuY3Rpb24odCl7Y29uc3Qgbj10O3JldHVybiEhKG4uYXR0cmlidXRlcyYmbi5zdGFydFRpbWUmJm4ubmFtZSYmbi5lbmRUaW1lJiZuLnN0YXR1cyl9KHQpKXtjb25zdHthdHRyaWJ1dGVzOnIsc3RhcnRUaW1lOm8sbmFtZTpzLGVuZFRpbWU6aSxwYXJlbnRTcGFuSWQ6YyxzdGF0dXM6dSxsaW5rczphfT10O3JldHVybntzcGFuX2lkOm4sdHJhY2VfaWQ6ZSxkYXRhOnIsZGVzY3JpcHRpb246cyxwYXJlbnRfc3Bhbl9pZDpjLHN0YXJ0X3RpbWVzdGFtcDpTdChvKSx0aW1lc3RhbXA6U3QoaSl8fHZvaWQgMCxzdGF0dXM6eHQodSksb3A6clt1dF0sb3JpZ2luOnJbYXRdLGxpbmtzOnd0KGEpfX1yZXR1cm57c3Bhbl9pZDpuLHRyYWNlX2lkOmUsc3RhcnRfdGltZXN0YW1wOjAsZGF0YTp7fX19ZnVuY3Rpb24geHQodCl7aWYodCYmdC5jb2RlIT09ZnQpcmV0dXJuIHQuY29kZT09PWh0PyJvayI6dC5tZXNzYWdlfHwidW5rbm93bl9lcnJvciJ9Y29uc3QgTnQ9Il9zZW50cnlSb290U3BhbiI7ZnVuY3Rpb24gVHQodCl7cmV0dXJuIHRbTnRdfHx0fWNvbnN0IEN0PSJwcm9kdWN0aW9uIixSdD0iX2Zyb3plbkRzYyI7ZnVuY3Rpb24ga3QodCl7Y29uc3Qgbj1zdCgpO2lmKCFuKXJldHVybnt9O2NvbnN0IGU9VHQodCkscj1FdChlKSxvPXIuZGF0YSxzPWUuc3BhbkNvbnRleHQoKS50cmFjZVN0YXRlLGk9cz8uZ2V0KCJzZW50cnkuc2FtcGxlX3JhdGUiKT8/b1tjdF07ZnVuY3Rpb24gYyh0KXtyZXR1cm4ibnVtYmVyIiE9dHlwZW9mIGkmJiJzdHJpbmciIT10eXBlb2YgaXx8KHQuc2FtcGxlX3JhdGU9YCR7aX1gKSx0fWNvbnN0IHU9ZVtSdF07aWYodSlyZXR1cm4gYyh1KTtjb25zdCBhPXM/LmdldCgic2VudHJ5LmRzYyIpLGY9YSYmeXQoYSk7aWYoZilyZXR1cm4gYyhmKTtjb25zdCBoPWZ1bmN0aW9uKHQsbil7Y29uc3QgZT1uLmdldE9wdGlvbnMoKSx7cHVibGljS2V5OnJ9PW4uZ2V0RHNuKCl8fHt9LG89e2Vudmlyb25tZW50OmUuZW52aXJvbm1lbnR8fEN0LHJlbGVhc2U6ZS5yZWxlYXNlLHB1YmxpY19rZXk6cix0cmFjZV9pZDp0fTtyZXR1cm4gbi5lbWl0KCJjcmVhdGVEc2MiLG8pLG99KHQuc3BhbkNvbnRleHQoKS50cmFjZUlkLG4pLHA9b1tpdF0sbD1yLmRlc2NyaXB0aW9uO3JldHVybiJ1cmwiIT09cCYmbCYmKGgudHJhbnNhY3Rpb249bCksZnVuY3Rpb24odCl7aWYoImJvb2xlYW4iPT10eXBlb2YgX19TRU5UUllfVFJBQ0lOR19fJiYhX19TRU5UUllfVFJBQ0lOR19fKXJldHVybiExO2NvbnN0IG49dHx8c3QoKT8uZ2V0T3B0aW9ucygpO3JldHVybiEoIW58fG51bGw9PW4udHJhY2VzU2FtcGxlUmF0ZSYmIW4udHJhY2VzU2FtcGxlcil9KCkmJihoLnNhbXBsZWQ9U3RyaW5nKGZ1bmN0aW9uKHQpe2NvbnN0e3RyYWNlRmxhZ3M6bn09dC5zcGFuQ29udGV4dCgpO3JldHVybiBuPT09X3R9KGUpKSxoLnNhbXBsZV9yYW5kPXM/LmdldCgic2VudHJ5LnNhbXBsZV9yYW5kIik/P2R0KGUpLnNjb3BlPy5nZXRQcm9wYWdhdGlvbkNvbnRleHQoKS5zYW1wbGVSYW5kLnRvU3RyaW5nKCkpLGMoaCksbi5lbWl0KCJjcmVhdGVEc2MiLGgsZSksaH1mdW5jdGlvbiBqdCh0LG49ITEpe2NvbnN0e2hvc3Q6ZSxwYXRoOnIscGFzczpvLHBvcnQ6cyxwcm9qZWN0SWQ6aSxwcm90b2NvbDpjLHB1YmxpY0tleTp1fT10O3JldHVybmAke2N9Oi8vJHt1fSR7biYmbz9gOiR7b31gOiIifUAke2V9JHtzP2A6JHtzfWA6IiJ9LyR7cj9gJHtyfS9gOnJ9JHtpfWB9ZnVuY3Rpb24gRHQodCxuPTEwMCxlPTEvMCl7dHJ5e3JldHVybiBJdCgiIix0LG4sZSl9Y2F0Y2godCl7cmV0dXJue0VSUk9SOmAqKm5vbi1zZXJpYWxpemFibGUqKiAoJHt0fSlgfX19ZnVuY3Rpb24gSXQodCxuLGU9MS8wLHI9MS8wLG89ZnVuY3Rpb24oKXtjb25zdCB0PW5ldyBXZWFrU2V0O2Z1bmN0aW9uIG4obil7cmV0dXJuISF0LmhhcyhuKXx8KHQuYWRkKG4pLCExKX1mdW5jdGlvbiBlKG4pe3QuZGVsZXRlKG4pfXJldHVybltuLGVdfSgpKXtjb25zdFtzLGldPW87aWYobnVsbD09bnx8WyJib29sZWFuIiwic3RyaW5nIl0uaW5jbHVkZXModHlwZW9mIG4pfHwibnVtYmVyIj09dHlwZW9mIG4mJk51bWJlci5pc0Zpbml0ZShuKSlyZXR1cm4gbjtjb25zdCBjPWZ1bmN0aW9uKHQsbil7dHJ5e2lmKCJkb21haW4iPT09dCYmbiYmIm9iamVjdCI9PXR5cGVvZiBuJiZuLlUpcmV0dXJuIltEb21haW5dIjtpZigiZG9tYWluRW1pdHRlciI9PT10KXJldHVybiJbRG9tYWluRW1pdHRlcl0iO2lmKCJ1bmRlZmluZWQiIT10eXBlb2YgZ2xvYmFsJiZuPT09Z2xvYmFsKXJldHVybiJbR2xvYmFsXSI7aWYoInVuZGVmaW5lZCIhPXR5cGVvZiB3aW5kb3cmJm49PT13aW5kb3cpcmV0dXJuIltXaW5kb3ddIjtpZigidW5kZWZpbmVkIiE9dHlwZW9mIGRvY3VtZW50JiZuPT09ZG9jdW1lbnQpcmV0dXJuIltEb2N1bWVudF0iO2lmKCJvYmplY3QiPT10eXBlb2YoZT1uKSYmbnVsbCE9PWUmJihlLl9faXNWdWV8fGUuTSkpcmV0dXJuIltWdWVWaWV3TW9kZWxdIjtpZihmdW5jdGlvbih0KXtyZXR1cm4gayh0KSYmIm5hdGl2ZUV2ZW50ImluIHQmJiJwcmV2ZW50RGVmYXVsdCJpbiB0JiYic3RvcFByb3BhZ2F0aW9uImluIHR9KG4pKXJldHVybiJbU3ludGhldGljRXZlbnRdIjtpZigibnVtYmVyIj09dHlwZW9mIG4mJiFOdW1iZXIuaXNGaW5pdGUobikpcmV0dXJuYFske259XWA7aWYoImZ1bmN0aW9uIj09dHlwZW9mIG4pcmV0dXJuYFtGdW5jdGlvbjogJHtmdW5jdGlvbih0KXt0cnl7cmV0dXJuIHQmJiJmdW5jdGlvbiI9PXR5cGVvZiB0JiZ0Lm5hbWV8fE59Y2F0Y2godCl7cmV0dXJuIE59fShuKX1dYDtpZigic3ltYm9sIj09dHlwZW9mIG4pcmV0dXJuYFske1N0cmluZyhuKX1dYDtpZigiYmlnaW50Ij09dHlwZW9mIG4pcmV0dXJuYFtCaWdJbnQ6ICR7U3RyaW5nKG4pfV1gO2NvbnN0IHI9ZnVuY3Rpb24odCl7Y29uc3Qgbj1PYmplY3QuZ2V0UHJvdG90eXBlT2YodCk7cmV0dXJuIG4/LmNvbnN0cnVjdG9yP24uY29uc3RydWN0b3IubmFtZToibnVsbCBwcm90b3R5cGUifShuKTtyZXR1cm4vXkhUTUwoXHcqKUVsZW1lbnQkLy50ZXN0KHIpP2BbSFRNTEVsZW1lbnQ6ICR7cn1dYDpgW29iamVjdCAke3J9XWB9Y2F0Y2godCl7cmV0dXJuYCoqbm9uLXNlcmlhbGl6YWJsZSoqICgke3R9KWB9dmFyIGV9KHQsbik7aWYoIWMuc3RhcnRzV2l0aCgiW29iamVjdCAiKSlyZXR1cm4gYztpZihuLl9fc2VudHJ5X3NraXBfbm9ybWFsaXphdGlvbl9fKXJldHVybiBuO2NvbnN0IHU9Im51bWJlciI9PXR5cGVvZiBuLl9fc2VudHJ5X292ZXJyaWRlX25vcm1hbGl6YXRpb25fZGVwdGhfXz9uLl9fc2VudHJ5X292ZXJyaWRlX25vcm1hbGl6YXRpb25fZGVwdGhfXzplO2lmKDA9PT11KXJldHVybiBjLnJlcGxhY2UoIm9iamVjdCAiLCIiKTtpZihzKG4pKXJldHVybiJbQ2lyY3VsYXIgfl0iO2NvbnN0IGE9bjtpZihhJiYiZnVuY3Rpb24iPT10eXBlb2YgYS50b0pTT04pdHJ5e3JldHVybiBJdCgiIixhLnRvSlNPTigpLHUtMSxyLG8pfWNhdGNoKHQpe31jb25zdCBmPUFycmF5LmlzQXJyYXkobik/W106e307bGV0IGg9MDtjb25zdCBwPVUobik7Zm9yKGNvbnN0IHQgaW4gcCl7aWYoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChwLHQpKWNvbnRpbnVlO2lmKGg+PXIpe2ZbdF09IltNYXhQcm9wZXJ0aWVzIH5dIjticmVha31jb25zdCBuPXBbdF07Zlt0XT1JdCh0LG4sdS0xLHIsbyksaCsrfXJldHVybiBpKG4pLGZ9ZnVuY3Rpb24gT3QodCxuKXtjb25zdCBlPW4ucmVwbGFjZSgvXFwvZywiLyIpLnJlcGxhY2UoL1t8XFx7fSgpW1xdXiQrKj8uXS9nLCJcXCQmIik7bGV0IHI9dDt0cnl7cj1kZWNvZGVVUkkodCl9Y2F0Y2godCl7fXJldHVybiByLnJlcGxhY2UoL1xcL2csIi8iKS5yZXBsYWNlKC93ZWJwYWNrOlwvPy9nLCIiKS5yZXBsYWNlKG5ldyBSZWdFeHAoYChmaWxlOi8vKT8vKiR7ZX0vKmAsImlnIiksImFwcDovLy8iKX1mdW5jdGlvbiBBdCh0LG49W10pe3JldHVyblt0LG5dfWZ1bmN0aW9uIFB0KHQsbil7Y29uc3QgZT10WzFdO2Zvcihjb25zdCB0IG9mIGUpe2lmKG4odCx0WzBdLnR5cGUpKXJldHVybiEwfXJldHVybiExfWZ1bmN0aW9uIFV0KHQpe2NvbnN0IG49ZyhwKTtyZXR1cm4gbi5lbmNvZGVQb2x5ZmlsbD9uLmVuY29kZVBvbHlmaWxsKHQpOihuZXcgVGV4dEVuY29kZXIpLmVuY29kZSh0KX1mdW5jdGlvbiBNdCh0KXtjb25zdFtuLGVdPXQ7bGV0IHI9SlNPTi5zdHJpbmdpZnkobik7ZnVuY3Rpb24gbyh0KXsic3RyaW5nIj09dHlwZW9mIHI/cj0ic3RyaW5nIj09dHlwZW9mIHQ/cit0OltVdChyKSx0XTpyLnB1c2goInN0cmluZyI9PXR5cGVvZiB0P1V0KHQpOnQpfWZvcihjb25zdCB0IG9mIGUpe2NvbnN0W24sZV09dDtpZihvKGBcbiR7SlNPTi5zdHJpbmdpZnkobil9XG5gKSwic3RyaW5nIj09dHlwZW9mIGV8fGUgaW5zdGFuY2VvZiBVaW50OEFycmF5KW8oZSk7ZWxzZXtsZXQgdDt0cnl7dD1KU09OLnN0cmluZ2lmeShlKX1jYXRjaChuKXt0PUpTT04uc3RyaW5naWZ5KER0KGUpKX1vKHQpfX1yZXR1cm4ic3RyaW5nIj09dHlwZW9mIHI/cjpmdW5jdGlvbih0KXtjb25zdCBuPXQucmVkdWNlKCgodCxuKT0+dCtuLmxlbmd0aCksMCksZT1uZXcgVWludDhBcnJheShuKTtsZXQgcj0wO2Zvcihjb25zdCBuIG9mIHQpZS5zZXQobixyKSxyKz1uLmxlbmd0aDtyZXR1cm4gZX0ocil9Y29uc3QgTHQ9e3Nlc3Npb246InNlc3Npb24iLHNlc3Npb25zOiJzZXNzaW9uIixhdHRhY2htZW50OiJhdHRhY2htZW50Iix0cmFuc2FjdGlvbjoidHJhbnNhY3Rpb24iLGV2ZW50OiJlcnJvciIsY2xpZW50X3JlcG9ydDoiaW50ZXJuYWwiLHVzZXJfcmVwb3J0OiJkZWZhdWx0Iixwcm9maWxlOiJwcm9maWxlIixwcm9maWxlX2NodW5rOiJwcm9maWxlIixyZXBsYXlfZXZlbnQ6InJlcGxheSIscmVwbGF5X3JlY29yZGluZzoicmVwbGF5IixjaGVja19pbjoibW9uaXRvciIsZmVlZGJhY2s6ImZlZWRiYWNrIixzcGFuOiJzcGFuIixyYXdfc2VjdXJpdHk6InNlY3VyaXR5IixvdGVsX2xvZzoibG9nX2l0ZW0ifTtmdW5jdGlvbiBCdCh0KXtpZighdD8uc2RrKXJldHVybjtjb25zdHtuYW1lOm4sdmVyc2lvbjplfT10LnNkaztyZXR1cm57bmFtZTpuLHZlcnNpb246ZX19ZnVuY3Rpb24gR3QodCxuLGUscil7Y29uc3Qgbz1CdChlKSxzPXQudHlwZSYmInJlcGxheV9ldmVudCIhPT10LnR5cGU/dC50eXBlOiJldmVudCI7IWZ1bmN0aW9uKHQsbil7biYmKHQuc2RrPXQuc2RrfHx7fSx0LnNkay5uYW1lPXQuc2RrLm5hbWV8fG4ubmFtZSx0LnNkay52ZXJzaW9uPXQuc2RrLnZlcnNpb258fG4udmVyc2lvbix0LnNkay5pbnRlZ3JhdGlvbnM9Wy4uLnQuc2RrLmludGVncmF0aW9uc3x8W10sLi4ubi5pbnRlZ3JhdGlvbnN8fFtdXSx0LnNkay5wYWNrYWdlcz1bLi4udC5zZGsucGFja2FnZXN8fFtdLC4uLm4ucGFja2FnZXN8fFtdXSl9KHQsZT8uc2RrKTtjb25zdCBpPWZ1bmN0aW9uKHQsbixlLHIpe2NvbnN0IG89dC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE/LmR5bmFtaWNTYW1wbGluZ0NvbnRleHQ7cmV0dXJue2V2ZW50X2lkOnQuZXZlbnRfaWQsc2VudF9hdDoobmV3IERhdGUpLnRvSVNPU3RyaW5nKCksLi4ubiYme3NkazpufSwuLi4hIWUmJnImJntkc246anQocil9LC4uLm8mJnt0cmFjZTpvfX19KHQsbyxyLG4pO2RlbGV0ZSB0LnNka1Byb2Nlc3NpbmdNZXRhZGF0YTtyZXR1cm4gQXQoaSxbW3t0eXBlOnN9LHRdXSl9Y29uc3QgSnQ9Il9fU0VOVFJZX1NVUFBSRVNTX1RSQUNJTkdfXyI7ZnVuY3Rpb24gWXQodCl7Y29uc3Qgbj1vdChtKCkpO3JldHVybiBuLnN1cHByZXNzVHJhY2luZz9uLnN1cHByZXNzVHJhY2luZyh0KTpmdW5jdGlvbiguLi50KXtjb25zdCBuPW90KG0oKSk7aWYoMj09PXQubGVuZ3RoKXtjb25zdFtlLHJdPXQ7cmV0dXJuIGU/bi53aXRoU2V0U2NvcGUoZSxyKTpuLndpdGhTY29wZShyKX1yZXR1cm4gbi53aXRoU2NvcGUodFswXSl9KChuPT4obi5zZXRTREtQcm9jZXNzaW5nTWV0YWRhdGEoe1tKdF06ITB9KSx0KCkpKSl9dmFyIHp0O2Z1bmN0aW9uIEh0KHQpe3JldHVybiBuZXcgRnQoKG49PntuKHQpfSkpfSFmdW5jdGlvbih0KXt0W3QuUEVORElORz0wXT0iUEVORElORyI7dFt0LlJFU09MVkVEPTFdPSJSRVNPTFZFRCI7dFt0LlJFSkVDVEVEPTJdPSJSRUpFQ1RFRCJ9KHp0fHwoenQ9e30pKTtjbGFzcyBGdHtjb25zdHJ1Y3Rvcih0KXt0aGlzLkw9enQuUEVORElORyx0aGlzLkI9W10sdGhpcy5HKHQpfXRoZW4odCxuKXtyZXR1cm4gbmV3IEZ0KCgoZSxyKT0+e3RoaXMuQi5wdXNoKFshMSxuPT57aWYodCl0cnl7ZSh0KG4pKX1jYXRjaCh0KXtyKHQpfWVsc2UgZShuKX0sdD0+e2lmKG4pdHJ5e2Uobih0KSl9Y2F0Y2godCl7cih0KX1lbHNlIHIodCl9XSksdGhpcy5KKCl9KSl9Y2F0Y2godCl7cmV0dXJuIHRoaXMudGhlbigodD0+dCksdCl9ZmluYWxseSh0KXtyZXR1cm4gbmV3IEZ0KCgobixlKT0+e2xldCByLG87cmV0dXJuIHRoaXMudGhlbigobj0+e289ITEscj1uLHQmJnQoKX0pLChuPT57bz0hMCxyPW4sdCYmdCgpfSkpLnRoZW4oKCgpPT57bz9lKHIpOm4ocil9KSl9KSl9Sigpe2lmKHRoaXMuTD09PXp0LlBFTkRJTkcpcmV0dXJuO2NvbnN0IHQ9dGhpcy5CLnNsaWNlKCk7dGhpcy5CPVtdLHQuZm9yRWFjaCgodD0+e3RbMF18fCh0aGlzLkw9PT16dC5SRVNPTFZFRCYmdFsxXSh0aGlzLlkpLHRoaXMuTD09PXp0LlJFSkVDVEVEJiZ0WzJdKHRoaXMuWSksdFswXT0hMCl9KSl9Ryh0KXtjb25zdCBuPSh0LG4pPT57dGhpcy5MPT09enQuUEVORElORyYmKGoobik/bi50aGVuKGUscik6KHRoaXMuTD10LHRoaXMuWT1uLHRoaXMuSigpKSl9LGU9dD0+e24oenQuUkVTT0xWRUQsdCl9LHI9dD0+e24oenQuUkVKRUNURUQsdCl9O3RyeXt0KGUscil9Y2F0Y2godCl7cih0KX19fWZ1bmN0aW9uIFd0KHQsbil7Y29uc3R7ZmluZ2VycHJpbnQ6ZSxzcGFuOnIsYnJlYWRjcnVtYnM6byxzZGtQcm9jZXNzaW5nTWV0YWRhdGE6c309bjshZnVuY3Rpb24odCxuKXtjb25zdHtleHRyYTplLHRhZ3M6cix1c2VyOm8sY29udGV4dHM6cyxsZXZlbDppLHRyYW5zYWN0aW9uTmFtZTpjfT1uO09iamVjdC5rZXlzKGUpLmxlbmd0aCYmKHQuZXh0cmE9ey4uLmUsLi4udC5leHRyYX0pO09iamVjdC5rZXlzKHIpLmxlbmd0aCYmKHQudGFncz17Li4uciwuLi50LnRhZ3N9KTtPYmplY3Qua2V5cyhvKS5sZW5ndGgmJih0LnVzZXI9ey4uLm8sLi4udC51c2VyfSk7T2JqZWN0LmtleXMocykubGVuZ3RoJiYodC5jb250ZXh0cz17Li4ucywuLi50LmNvbnRleHRzfSk7aSYmKHQubGV2ZWw9aSk7YyYmInRyYW5zYWN0aW9uIiE9PXQudHlwZSYmKHQudHJhbnNhY3Rpb249Yyl9KHQsbiksciYmZnVuY3Rpb24odCxuKXt0LmNvbnRleHRzPXt0cmFjZTp2dChuKSwuLi50LmNvbnRleHRzfSx0LnNka1Byb2Nlc3NpbmdNZXRhZGF0YT17ZHluYW1pY1NhbXBsaW5nQ29udGV4dDprdChuKSwuLi50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YX07Y29uc3QgZT1UdChuKSxyPUV0KGUpLmRlc2NyaXB0aW9uO3ImJiF0LnRyYW5zYWN0aW9uJiYidHJhbnNhY3Rpb24iPT09dC50eXBlJiYodC50cmFuc2FjdGlvbj1yKX0odCxyKSxmdW5jdGlvbih0LG4pe3QuZmluZ2VycHJpbnQ9dC5maW5nZXJwcmludD9BcnJheS5pc0FycmF5KHQuZmluZ2VycHJpbnQpP3QuZmluZ2VycHJpbnQ6W3QuZmluZ2VycHJpbnRdOltdLG4mJih0LmZpbmdlcnByaW50PXQuZmluZ2VycHJpbnQuY29uY2F0KG4pKTt0LmZpbmdlcnByaW50Lmxlbmd0aHx8ZGVsZXRlIHQuZmluZ2VycHJpbnR9KHQsZSksZnVuY3Rpb24odCxuKXtjb25zdCBlPVsuLi50LmJyZWFkY3J1bWJzfHxbXSwuLi5uXTt0LmJyZWFkY3J1bWJzPWUubGVuZ3RoP2U6dm9pZCAwfSh0LG8pLGZ1bmN0aW9uKHQsbil7dC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE9ey4uLnQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhLC4uLm59fSh0LHMpfWNvbnN0IEt0PSI3Ijtjb25zdCBWdD1TeW1ib2wuZm9yKCJTZW50cnlCdWZmZXJGdWxsRXJyb3IiKTtmdW5jdGlvbiBadCh0KXtjb25zdCBuPVtdO2Z1bmN0aW9uIGUodCl7cmV0dXJuIG4uc3BsaWNlKG4uaW5kZXhPZih0KSwxKVswXXx8UHJvbWlzZS5yZXNvbHZlKHZvaWQgMCl9cmV0dXJueyQ6bixhZGQ6ZnVuY3Rpb24ocil7aWYoISh2b2lkIDA9PT10fHxuLmxlbmd0aDx0KSlyZXR1cm4gbz1WdCxuZXcgRnQoKCh0LG4pPT57bihvKX0pKTt2YXIgbztjb25zdCBzPXIoKTtyZXR1cm4tMT09PW4uaW5kZXhPZihzKSYmbi5wdXNoKHMpLHMudGhlbigoKCk9PmUocykpKS50aGVuKG51bGwsKCgpPT5lKHMpLnRoZW4obnVsbCwoKCk9Pnt9KSkpKSxzfSxkcmFpbjpmdW5jdGlvbih0KXtyZXR1cm4gbmV3IEZ0KCgoZSxyKT0+e2xldCBvPW4ubGVuZ3RoO2lmKCFvKXJldHVybiBlKCEwKTtjb25zdCBzPXNldFRpbWVvdXQoKCgpPT57dCYmdD4wJiZlKCExKX0pLHQpO24uZm9yRWFjaCgodD0+e0h0KHQpLnRoZW4oKCgpPT57LS1vfHwoY2xlYXJUaW1lb3V0KHMpLGUoITApKX0pLHIpfSkpfSkpfX19Y29uc3QgcXQ9NmU0O2Z1bmN0aW9uIFF0KHQse3N0YXR1c0NvZGU6bixoZWFkZXJzOmV9LHI9RGF0ZS5ub3coKSl7Y29uc3Qgbz17Li4udH0scz1lPy5bIngtc2VudHJ5LXJhdGUtbGltaXRzIl0saT1lPy5bInJldHJ5LWFmdGVyIl07aWYocylmb3IoY29uc3QgdCBvZiBzLnRyaW0oKS5zcGxpdCgiLCIpKXtjb25zdFtuLGUsLCxzXT10LnNwbGl0KCI6Iiw1KSxpPXBhcnNlSW50KG4sMTApLGM9MWUzKihpc05hTihpKT82MDppKTtpZihlKWZvcihjb25zdCB0IG9mIGUuc3BsaXQoIjsiKSkibWV0cmljX2J1Y2tldCI9PT10JiZzJiYhcy5zcGxpdCgiOyIpLmluY2x1ZGVzKCJjdXN0b20iKXx8KG9bdF09citjKTtlbHNlIG8uYWxsPXIrY31lbHNlIGk/by5hbGw9citmdW5jdGlvbih0LG49RGF0ZS5ub3coKSl7Y29uc3QgZT1wYXJzZUludChgJHt0fWAsMTApO2lmKCFpc05hTihlKSlyZXR1cm4gMWUzKmU7Y29uc3Qgcj1EYXRlLnBhcnNlKGAke3R9YCk7cmV0dXJuIGlzTmFOKHIpP3F0OnItbn0oaSxyKTo0Mjk9PT1uJiYoby5hbGw9cis2ZTQpO3JldHVybiBvfWNvbnN0IFh0PTY0O2Z1bmN0aW9uIHRuKHQsbixlPVp0KHQuYnVmZmVyU2l6ZXx8WHQpKXtsZXQgcj17fTtyZXR1cm57c2VuZDpmdW5jdGlvbih0KXtjb25zdCBvPVtdO2lmKFB0KHQsKCh0LG4pPT57Y29uc3QgZT1mdW5jdGlvbih0KXtyZXR1cm4gTHRbdF19KG4pOyhmdW5jdGlvbih0LG4sZT1EYXRlLm5vdygpKXtyZXR1cm4gZnVuY3Rpb24odCxuKXtyZXR1cm4gdFtuXXx8dC5hbGx8fDB9KHQsbik+ZX0pKHIsZSl8fG8ucHVzaCh0KX0pKSwwPT09by5sZW5ndGgpcmV0dXJuIEh0KHt9KTtjb25zdCBzPUF0KHRbMF0sbyksaT10PT57UHQocywoKHQsbik9Pnt9KSl9O3JldHVybiBlLmFkZCgoKCk9Pm4oe2JvZHk6TXQocyl9KS50aGVuKCh0PT4odm9pZCAwIT09dC5zdGF0dXNDb2RlJiYodC5zdGF0dXNDb2RlPDIwMHx8dC5zdGF0dXNDb2RlPj0zMDApJiZoJiZ3Lndhcm4oYFNlbnRyeSByZXNwb25kZWQgd2l0aCBzdGF0dXMgY29kZSAke3Quc3RhdHVzQ29kZX0gdG8gc2VudCBldmVudC5gKSxyPVF0KHIsdCksdCkpLCh0PT57dGhyb3cgaSgpLGgmJncuZXJyb3IoIkVuY291bnRlcmVkIGVycm9yIHJ1bm5pbmcgdHJhbnNwb3J0IHJlcXVlc3Q6Iix0KSx0fSkpKSkudGhlbigodD0+dCksKHQ9PntpZih0PT09VnQpcmV0dXJuIGgmJncuZXJyb3IoIlNraXBwZWQgc2VuZGluZyBldmVudCBiZWNhdXNlIGJ1ZmZlciBpcyBmdWxsLiIpLGkoKSxIdCh7fSk7dGhyb3cgdH0pKX0sZmx1c2g6dD0+ZS5kcmFpbih0KX19Y29uc3Qgbm49L14oXFMrOlxcfFwvPykoW1xzXFNdKj8pKCg/OlwuezEsMn18W14vXFxdKz98KShcLlteLi9cXF0qfCkpKD86Wy9cXF0qKSQvO2Z1bmN0aW9uIGVuKHQpe2NvbnN0IG49ZnVuY3Rpb24odCl7Y29uc3Qgbj10Lmxlbmd0aD4xMDI0P2A8dHJ1bmNhdGVkPiR7dC5zbGljZSgtMTAyNCl9YDp0LGU9bm4uZXhlYyhuKTtyZXR1cm4gZT9lLnNsaWNlKDEpOltdfSh0KSxlPW5bMF18fCIiO2xldCByPW5bMV07cmV0dXJuIGV8fHI/KHImJihyPXIuc2xpY2UoMCxyLmxlbmd0aC0xKSksZStyKToiLiJ9ZnVuY3Rpb24gcm4odCxuPSExKXtyZXR1cm4hKG58fHQmJiF0LnN0YXJ0c1dpdGgoIi8iKSYmIXQubWF0Y2goL15bQS1aXTovKSYmIXQuc3RhcnRzV2l0aCgiLiIpJiYhdC5tYXRjaCgvXlthLXpBLVpdKFthLXpBLVowLTkuXC0rXSkqOlwvXC8vKSkmJnZvaWQgMCE9PXQmJiF0LmluY2x1ZGVzKCJub2RlX21vZHVsZXMvIil9Y29uc3Qgb249U3ltYm9sKCJBZ2VudEJhc2VJbnRlcm5hbFN0YXRlIik7Y2xhc3Mgc24gZXh0ZW5kcyBzLkFnZW50e2NvbnN0cnVjdG9yKHQpe3N1cGVyKHQpLHRoaXNbb25dPXt9fWlzU2VjdXJlRW5kcG9pbnQodCl7aWYodCl7aWYoImJvb2xlYW4iPT10eXBlb2YgdC5zZWN1cmVFbmRwb2ludClyZXR1cm4gdC5zZWN1cmVFbmRwb2ludDtpZigic3RyaW5nIj09dHlwZW9mIHQucHJvdG9jb2wpcmV0dXJuImh0dHBzOiI9PT10LnByb3RvY29sfWNvbnN0e3N0YWNrOm59PW5ldyBFcnJvcjtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIG4mJm4uc3BsaXQoIlxuIikuc29tZSgodD0+LTEhPT10LmluZGV4T2YoIihodHRwcy5qczoiKXx8LTEhPT10LmluZGV4T2YoIm5vZGU6aHR0cHM6IikpKX1jcmVhdGVTb2NrZXQodCxuLGUpe2NvbnN0IHI9ey4uLm4sc2VjdXJlRW5kcG9pbnQ6dGhpcy5pc1NlY3VyZUVuZHBvaW50KG4pfTtQcm9taXNlLnJlc29sdmUoKS50aGVuKCgoKT0+dGhpcy5jb25uZWN0KHQscikpKS50aGVuKChvPT57aWYobyBpbnN0YW5jZW9mIHMuQWdlbnQpcmV0dXJuIG8uYWRkUmVxdWVzdCh0LHIpO3RoaXNbb25dLmN1cnJlbnRTb2NrZXQ9byxzdXBlci5jcmVhdGVTb2NrZXQodCxuLGUpfSksZSl9Y3JlYXRlQ29ubmVjdGlvbigpe2NvbnN0IHQ9dGhpc1tvbl0uY3VycmVudFNvY2tldDtpZih0aGlzW29uXS5jdXJyZW50U29ja2V0PXZvaWQgMCwhdCl0aHJvdyBuZXcgRXJyb3IoIk5vIHNvY2tldCB3YXMgcmV0dXJuZWQgaW4gdGhlIGBjb25uZWN0KClgIGZ1bmN0aW9uIik7cmV0dXJuIHR9Z2V0IGRlZmF1bHRQb3J0KCl7cmV0dXJuIHRoaXNbb25dLmRlZmF1bHRQb3J0Pz8oImh0dHBzOiI9PT10aGlzLnByb3RvY29sPzQ0Mzo4MCl9c2V0IGRlZmF1bHRQb3J0KHQpe3RoaXNbb25dJiYodGhpc1tvbl0uZGVmYXVsdFBvcnQ9dCl9Z2V0IHByb3RvY29sKCl7cmV0dXJuIHRoaXNbb25dLnByb3RvY29sPz8odGhpcy5pc1NlY3VyZUVuZHBvaW50KCk/Imh0dHBzOiI6Imh0dHA6Iil9c2V0IHByb3RvY29sKHQpe3RoaXNbb25dJiYodGhpc1tvbl0ucHJvdG9jb2w9dCl9fWZ1bmN0aW9uIGNuKC4uLnQpe3cubG9nKCJbaHR0cHMtcHJveHktYWdlbnQ6cGFyc2UtcHJveHktcmVzcG9uc2VdIiwuLi50KX1mdW5jdGlvbiB1bih0KXtyZXR1cm4gbmV3IFByb21pc2UoKChuLGUpPT57bGV0IHI9MDtjb25zdCBvPVtdO2Z1bmN0aW9uIHMoKXtjb25zdCBjPXQucmVhZCgpO2M/ZnVuY3Rpb24oYyl7by5wdXNoKGMpLHIrPWMubGVuZ3RoO2NvbnN0IHU9QnVmZmVyLmNvbmNhdChvLHIpLGE9dS5pbmRleE9mKCJcclxuXHJcbiIpO2lmKC0xPT09YSlyZXR1cm4gY24oImhhdmUgbm90IHJlY2VpdmVkIGVuZCBvZiBIVFRQIGhlYWRlcnMgeWV0Li4uIiksdm9pZCBzKCk7Y29uc3QgZj11LnN1YmFycmF5KDAsYSkudG9TdHJpbmcoImFzY2lpIikuc3BsaXQoIlxyXG4iKSxoPWYuc2hpZnQoKTtpZighaClyZXR1cm4gdC5kZXN0cm95KCksZShuZXcgRXJyb3IoIk5vIGhlYWRlciByZWNlaXZlZCBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2UiKSk7Y29uc3QgcD1oLnNwbGl0KCIgIiksbD0rKHBbMV18fDApLGQ9cC5zbGljZSgyKS5qb2luKCIgIiksbT17fTtmb3IoY29uc3QgbiBvZiBmKXtpZighbiljb250aW51ZTtjb25zdCByPW4uaW5kZXhPZigiOiIpO2lmKC0xPT09cilyZXR1cm4gdC5kZXN0cm95KCksZShuZXcgRXJyb3IoYEludmFsaWQgaGVhZGVyIGZyb20gcHJveHkgQ09OTkVDVCByZXNwb25zZTogIiR7bn0iYCkpO2NvbnN0IG89bi5zbGljZSgwLHIpLnRvTG93ZXJDYXNlKCkscz1uLnNsaWNlKHIrMSkudHJpbVN0YXJ0KCksaT1tW29dOyJzdHJpbmciPT10eXBlb2YgaT9tW29dPVtpLHNdOkFycmF5LmlzQXJyYXkoaSk/aS5wdXNoKHMpOm1bb109c31jbigiZ290IHByb3h5IHNlcnZlciByZXNwb25zZTogJW8gJW8iLGgsbSksaSgpLG4oe2Nvbm5lY3Q6e3N0YXR1c0NvZGU6bCxzdGF0dXNUZXh0OmQsaGVhZGVyczptfSxidWZmZXJlZDp1fSl9KGMpOnQub25jZSgicmVhZGFibGUiLHMpfWZ1bmN0aW9uIGkoKXt0LnJlbW92ZUxpc3RlbmVyKCJlbmQiLGMpLHQucmVtb3ZlTGlzdGVuZXIoImVycm9yIix1KSx0LnJlbW92ZUxpc3RlbmVyKCJyZWFkYWJsZSIscyl9ZnVuY3Rpb24gYygpe2koKSxjbigib25lbmQiKSxlKG5ldyBFcnJvcigiUHJveHkgY29ubmVjdGlvbiBlbmRlZCBiZWZvcmUgcmVjZWl2aW5nIENPTk5FQ1QgcmVzcG9uc2UiKSl9ZnVuY3Rpb24gdSh0KXtpKCksY24oIm9uZXJyb3IgJW8iLHQpLGUodCl9dC5vbigiZXJyb3IiLHUpLHQub24oImVuZCIsYykscygpfSkpfWZ1bmN0aW9uIGFuKC4uLnQpe3cubG9nKCJbaHR0cHMtcHJveHktYWdlbnRdIiwuLi50KX1jbGFzcyBmbiBleHRlbmRzIHNue3N0YXRpYyBfX2luaXRTdGF0aWMoKXt0aGlzLnByb3RvY29scz1bImh0dHAiLCJodHRwcyJdfWNvbnN0cnVjdG9yKHQsbil7c3VwZXIobiksdGhpcy5vcHRpb25zPXt9LHRoaXMucHJveHk9InN0cmluZyI9PXR5cGVvZiB0P25ldyBVUkwodCk6dCx0aGlzLnByb3h5SGVhZGVycz1uPy5oZWFkZXJzPz97fSxhbigiQ3JlYXRpbmcgbmV3IEh0dHBzUHJveHlBZ2VudCBpbnN0YW5jZTogJW8iLHRoaXMucHJveHkuaHJlZik7Y29uc3QgZT0odGhpcy5wcm94eS5ob3N0bmFtZXx8dGhpcy5wcm94eS5ob3N0KS5yZXBsYWNlKC9eXFt8XF0kL2csIiIpLHI9dGhpcy5wcm94eS5wb3J0P3BhcnNlSW50KHRoaXMucHJveHkucG9ydCwxMCk6Imh0dHBzOiI9PT10aGlzLnByb3h5LnByb3RvY29sPzQ0Mzo4MDt0aGlzLmNvbm5lY3RPcHRzPXtBTFBOUHJvdG9jb2xzOlsiaHR0cC8xLjEiXSwuLi5uP3BuKG4sImhlYWRlcnMiKTpudWxsLGhvc3Q6ZSxwb3J0OnJ9fWFzeW5jIGNvbm5lY3QodCxuKXtjb25zdHtwcm94eTplfT10aGlzO2lmKCFuLmhvc3QpdGhyb3cgbmV3IFR5cGVFcnJvcignTm8gImhvc3QiIHByb3ZpZGVkJyk7bGV0IHI7aWYoImh0dHBzOiI9PT1lLnByb3RvY29sKXthbigiQ3JlYXRpbmcgYHRscy5Tb2NrZXRgOiAlbyIsdGhpcy5jb25uZWN0T3B0cyk7Y29uc3QgdD10aGlzLmNvbm5lY3RPcHRzLnNlcnZlcm5hbWV8fHRoaXMuY29ubmVjdE9wdHMuaG9zdDtyPWYuY29ubmVjdCh7Li4udGhpcy5jb25uZWN0T3B0cyxzZXJ2ZXJuYW1lOnQmJmEuaXNJUCh0KT92b2lkIDA6dH0pfWVsc2UgYW4oIkNyZWF0aW5nIGBuZXQuU29ja2V0YDogJW8iLHRoaXMuY29ubmVjdE9wdHMpLHI9YS5jb25uZWN0KHRoaXMuY29ubmVjdE9wdHMpO2NvbnN0IG89ImZ1bmN0aW9uIj09dHlwZW9mIHRoaXMucHJveHlIZWFkZXJzP3RoaXMucHJveHlIZWFkZXJzKCk6ey4uLnRoaXMucHJveHlIZWFkZXJzfSxzPWEuaXNJUHY2KG4uaG9zdCk/YFske24uaG9zdH1dYDpuLmhvc3Q7bGV0IGk9YENPTk5FQ1QgJHtzfToke24ucG9ydH0gSFRUUC8xLjFcclxuYDtpZihlLnVzZXJuYW1lfHxlLnBhc3N3b3JkKXtjb25zdCB0PWAke2RlY29kZVVSSUNvbXBvbmVudChlLnVzZXJuYW1lKX06JHtkZWNvZGVVUklDb21wb25lbnQoZS5wYXNzd29yZCl9YDtvWyJQcm94eS1BdXRob3JpemF0aW9uIl09YEJhc2ljICR7QnVmZmVyLmZyb20odCkudG9TdHJpbmcoImJhc2U2NCIpfWB9by5Ib3N0PWAke3N9OiR7bi5wb3J0fWAsb1siUHJveHktQ29ubmVjdGlvbiJdfHwob1siUHJveHktQ29ubmVjdGlvbiJdPXRoaXMua2VlcEFsaXZlPyJLZWVwLUFsaXZlIjoiY2xvc2UiKTtmb3IoY29uc3QgdCBvZiBPYmplY3Qua2V5cyhvKSlpKz1gJHt0fTogJHtvW3RdfVxyXG5gO2NvbnN0IGM9dW4ocik7ci53cml0ZShgJHtpfVxyXG5gKTtjb25zdHtjb25uZWN0OnUsYnVmZmVyZWQ6aH09YXdhaXQgYztpZih0LmVtaXQoInByb3h5Q29ubmVjdCIsdSksdGhpcy5lbWl0KCJwcm94eUNvbm5lY3QiLHUsdCksMjAwPT09dS5zdGF0dXNDb2RlKXtpZih0Lm9uY2UoInNvY2tldCIsaG4pLG4uc2VjdXJlRW5kcG9pbnQpe2FuKCJVcGdyYWRpbmcgc29ja2V0IGNvbm5lY3Rpb24gdG8gVExTIik7Y29uc3QgdD1uLnNlcnZlcm5hbWV8fG4uaG9zdDtyZXR1cm4gZi5jb25uZWN0KHsuLi5wbihuLCJob3N0IiwicGF0aCIsInBvcnQiKSxzb2NrZXQ6cixzZXJ2ZXJuYW1lOmEuaXNJUCh0KT92b2lkIDA6dH0pfXJldHVybiByfXIuZGVzdHJveSgpO2NvbnN0IHA9bmV3IGEuU29ja2V0KHt3cml0YWJsZTohMX0pO3JldHVybiBwLnJlYWRhYmxlPSEwLHQub25jZSgic29ja2V0IiwodD0+e2FuKCJSZXBsYXlpbmcgcHJveHkgYnVmZmVyIGZvciBmYWlsZWQgcmVxdWVzdCIpLHQucHVzaChoKSx0LnB1c2gobnVsbCl9KSkscH19ZnVuY3Rpb24gaG4odCl7dC5yZXN1bWUoKX1mdW5jdGlvbiBwbih0LC4uLm4pe2NvbnN0IGU9e307bGV0IHI7Zm9yKHIgaW4gdCluLmluY2x1ZGVzKHIpfHwoZVtyXT10W3JdKTtyZXR1cm4gZX1mbi5fX2luaXRTdGF0aWMoKTtjb25zdCBsbj0zMjc2ODtmdW5jdGlvbiBkbih0KXtyZXR1cm4gdC5yZXBsYWNlKC9eW0EtWl06LywiIikucmVwbGFjZSgvXFwvZywiLyIpfWNvbnN0IG1uPW47bGV0IGduLHluPTAsYm49e307ZnVuY3Rpb24gX24odCl7bW4uZGVidWcmJmNvbnNvbGUubG9nKGBbQU5SIFdvcmtlcl0gJHt0fWApfXZhciB2bix3bixTbjtjb25zdCAkbj1mdW5jdGlvbih0KXtsZXQgbjt0cnl7bj1uZXcgVVJMKHQudXJsKX1jYXRjaChuKXtyZXR1cm4gdigoKCk9Pntjb25zb2xlLndhcm4oIltAc2VudHJ5L25vZGVdOiBJbnZhbGlkIGRzbiBvciB0dW5uZWwgb3B0aW9uLCB3aWxsIG5vdCBzZW5kIGFueSBldmVudHMuIFRoZSB0dW5uZWwgb3B0aW9uIG11c3QgYmUgYSBmdWxsIFVSTCB3aGVuIHVzZWQuIil9KSksdG4odCwoKCk9PlByb21pc2UucmVzb2x2ZSh7fSkpKX1jb25zdCBlPSJodHRwczoiPT09bi5wcm90b2NvbCxyPWZ1bmN0aW9uKHQsbil7Y29uc3R7bm9fcHJveHk6ZX09cHJvY2Vzcy5lbnYscj1lPy5zcGxpdCgiLCIpLnNvbWUoKG49PnQuaG9zdC5lbmRzV2l0aChuKXx8dC5ob3N0bmFtZS5lbmRzV2l0aChuKSkpO3JldHVybiByP3ZvaWQgMDpufShuLHQucHJveHl8fChlP3Byb2Nlc3MuZW52Lmh0dHBzX3Byb3h5OnZvaWQgMCl8fHByb2Nlc3MuZW52Lmh0dHBfcHJveHkpLG89ZT9pOnMsYT12b2lkIDAhPT10LmtlZXBBbGl2ZSYmdC5rZWVwQWxpdmUsZj1yP25ldyBmbihyKTpuZXcgby5BZ2VudCh7a2VlcEFsaXZlOmEsbWF4U29ja2V0czozMCx0aW1lb3V0OjJlM30pLGg9ZnVuY3Rpb24odCxuLGUpe2NvbnN0e2hvc3RuYW1lOnIscGF0aG5hbWU6byxwb3J0OnMscHJvdG9jb2w6aSxzZWFyY2g6YX09bmV3IFVSTCh0LnVybCk7cmV0dXJuIGZ1bmN0aW9uKGYpe3JldHVybiBuZXcgUHJvbWlzZSgoKGgscCk9PntZdCgoKCk9PntsZXQgbD1mdW5jdGlvbih0KXtyZXR1cm4gbmV3IGMoe3JlYWQoKXt0aGlzLnB1c2godCksdGhpcy5wdXNoKG51bGwpfX0pfShmLmJvZHkpO2NvbnN0IGQ9ey4uLnQuaGVhZGVyc307Zi5ib2R5Lmxlbmd0aD5sbiYmKGRbImNvbnRlbnQtZW5jb2RpbmciXT0iZ3ppcCIsbD1sLnBpcGUodSgpKSk7Y29uc3QgbT1uLnJlcXVlc3Qoe21ldGhvZDoiUE9TVCIsYWdlbnQ6ZSxoZWFkZXJzOmQsaG9zdG5hbWU6cixwYXRoOmAke299JHthfWAscG9ydDpzLHByb3RvY29sOmksY2E6dC5jYUNlcnRzfSwodD0+e3Qub24oImRhdGEiLCgoKT0+e30pKSx0Lm9uKCJlbmQiLCgoKT0+e30pKSx0LnNldEVuY29kaW5nKCJ1dGY4Iik7Y29uc3Qgbj10LmhlYWRlcnNbInJldHJ5LWFmdGVyIl0/P251bGwsZT10LmhlYWRlcnNbIngtc2VudHJ5LXJhdGUtbGltaXRzIl0/P251bGw7aCh7c3RhdHVzQ29kZTp0LnN0YXR1c0NvZGUsaGVhZGVyczp7InJldHJ5LWFmdGVyIjpuLCJ4LXNlbnRyeS1yYXRlLWxpbWl0cyI6QXJyYXkuaXNBcnJheShlKT9lWzBdfHxudWxsOmV9fSl9KSk7bS5vbigiZXJyb3IiLHApLGwucGlwZShtKX0pKX0pKX19KHQsdC5odHRwTW9kdWxlPz9vLGYpO3JldHVybiB0bih0LGgpfSh7dXJsOih2bj1tbi5kc24sd249bW4udHVubmVsLFNuPW1uLnNka01ldGFkYXRhLnNkayx3bnx8YCR7ZnVuY3Rpb24odCl7cmV0dXJuYCR7ZnVuY3Rpb24odCl7Y29uc3Qgbj10LnByb3RvY29sP2Ake3QucHJvdG9jb2x9OmA6IiIsZT10LnBvcnQ/YDoke3QucG9ydH1gOiIiO3JldHVybmAke259Ly8ke3QuaG9zdH0ke2V9JHt0LnBhdGg/YC8ke3QucGF0aH1gOiIifS9hcGkvYH0odCl9JHt0LnByb2plY3RJZH0vZW52ZWxvcGUvYH0odm4pfT8ke2Z1bmN0aW9uKHQsbil7Y29uc3QgZT17c2VudHJ5X3ZlcnNpb246S3R9O3JldHVybiB0LnB1YmxpY0tleSYmKGUuc2VudHJ5X2tleT10LnB1YmxpY0tleSksbiYmKGUuc2VudHJ5X2NsaWVudD1gJHtuLm5hbWV9LyR7bi52ZXJzaW9ufWApLG5ldyBVUkxTZWFyY2hQYXJhbXMoZSkudG9TdHJpbmcoKX0odm4sU24pfWApfSk7YXN5bmMgZnVuY3Rpb24gRW4oKXtpZihnbil7X24oIlNlbmRpbmcgYWJub3JtYWwgc2Vzc2lvbiIpLEgoZ24se3N0YXR1czoiYWJub3JtYWwiLGFibm9ybWFsX21lY2hhbmlzbToiYW5yX2ZvcmVncm91bmQiLHJlbGVhc2U6bW4ucmVsZWFzZSxlbnZpcm9ubWVudDptbi5lbnZpcm9ubWVudH0pO2NvbnN0IHQ9ZnVuY3Rpb24odCxuLGUscil7Y29uc3Qgbz1CdChlKTtyZXR1cm4gQXQoe3NlbnRfYXQ6KG5ldyBEYXRlKS50b0lTT1N0cmluZygpLC4uLm8mJntzZGs6b30sLi4uISFyJiZuJiZ7ZHNuOmp0KG4pfX0sWyJhZ2dyZWdhdGVzImluIHQ/W3t0eXBlOiJzZXNzaW9ucyJ9LHRdOlt7dHlwZToic2Vzc2lvbiJ9LHQudG9KU09OKCldXSl9KGduLG1uLmRzbixtbi5zZGtNZXRhZGF0YSxtbi50dW5uZWwpO19uKEpTT04uc3RyaW5naWZ5KHQpKSxhd2FpdCAkbi5zZW5kKHQpO3RyeXtlPy5wb3N0TWVzc2FnZSgic2Vzc2lvbi1lbmRlZCIpfWNhdGNoKHQpe319fWZ1bmN0aW9uIHhuKHQpe2lmKCF0KXJldHVybjtjb25zdCBuPWZ1bmN0aW9uKHQpe2lmKCF0Lmxlbmd0aClyZXR1cm5bXTtjb25zdCBuPUFycmF5LmZyb20odCk7cmV0dXJuL3NlbnRyeVdyYXBwZWQvLnRlc3QoeChuKS5mdW5jdGlvbnx8IiIpJiZuLnBvcCgpLG4ucmV2ZXJzZSgpLEUudGVzdCh4KG4pLmZ1bmN0aW9ufHwiIikmJihuLnBvcCgpLEUudGVzdCh4KG4pLmZ1bmN0aW9ufHwiIikmJm4ucG9wKCkpLG4uc2xpY2UoMCxTKS5tYXAoKHQ9Pih7Li4udCxmaWxlbmFtZTp0LmZpbGVuYW1lfHx4KG4pLmZpbGVuYW1lLGZ1bmN0aW9uOnQuZnVuY3Rpb258fCR9KSkpfSh0KTtpZihtbi5hcHBSb290UGF0aClmb3IoY29uc3QgdCBvZiBuKXQuZmlsZW5hbWUmJih0LmZpbGVuYW1lPU90KHQuZmlsZW5hbWUsbW4uYXBwUm9vdFBhdGgpKTtyZXR1cm4gbn1hc3luYyBmdW5jdGlvbiBObih0LG4pe2lmKHluPj1tbi5tYXhBbnJFdmVudHMpcmV0dXJuO3luKz0xLGF3YWl0IEVuKCksX24oIlNlbmRpbmcgZXZlbnQiKTtjb25zdCBlPXtldmVudF9pZDpCKCksY29udGV4dHM6bW4uY29udGV4dHMscmVsZWFzZTptbi5yZWxlYXNlLGVudmlyb25tZW50Om1uLmVudmlyb25tZW50LGRpc3Q6bW4uZGlzdCxwbGF0Zm9ybToibm9kZSIsbGV2ZWw6ImVycm9yIixleGNlcHRpb246e3ZhbHVlczpbe3R5cGU6IkFwcGxpY2F0aW9uTm90UmVzcG9uZGluZyIsdmFsdWU6YEFwcGxpY2F0aW9uIE5vdCBSZXNwb25kaW5nIGZvciBhdCBsZWFzdCAke21uLmFuclRocmVzaG9sZH0gbXNgLHN0YWNrdHJhY2U6e2ZyYW1lczp4bih0KX0sbWVjaGFuaXNtOnt0eXBlOiJBTlIifX1dfSx0YWdzOm1uLnN0YXRpY1RhZ3N9O24mJmZ1bmN0aW9uKHQsbil7aWYoV3QodCxuKSwhdC5jb250ZXh0cz8udHJhY2Upe2NvbnN0e3RyYWNlSWQ6ZSxwYXJlbnRTcGFuSWQ6cixwcm9wYWdhdGlvblNwYW5JZDpvfT1uLnByb3BhZ2F0aW9uQ29udGV4dDt0LmNvbnRleHRzPXt0cmFjZTp7dHJhY2VfaWQ6ZSxzcGFuX2lkOm98fFcoKSxwYXJlbnRfc3Bhbl9pZDpyfSwuLi50LmNvbnRleHRzfX19KGUsbiksZnVuY3Rpb24odCl7aWYoMD09PU9iamVjdC5rZXlzKGJuKS5sZW5ndGgpcmV0dXJuO2NvbnN0IG49bW4uYXBwUm9vdFBhdGg/e306Ym47aWYobW4uYXBwUm9vdFBhdGgpZm9yKGNvbnN0W3QsZV1vZiBPYmplY3QuZW50cmllcyhibikpbltPdCh0LG1uLmFwcFJvb3RQYXRoKV09ZTtjb25zdCBlPW5ldyBNYXA7Zm9yKGNvbnN0IHIgb2YgdC5leGNlcHRpb24/LnZhbHVlc3x8W10pZm9yKGNvbnN0IHQgb2Ygci5zdGFja3RyYWNlPy5mcmFtZXN8fFtdKXtjb25zdCByPXQuYWJzX3BhdGh8fHQuZmlsZW5hbWU7ciYmbltyXSYmZS5zZXQocixuW3JdKX1pZihlLnNpemU+MCl7Y29uc3Qgbj1bXTtmb3IoY29uc3RbdCxyXW9mIGUuZW50cmllcygpKW4ucHVzaCh7dHlwZToic291cmNlbWFwIixjb2RlX2ZpbGU6dCxkZWJ1Z19pZDpyfSk7dC5kZWJ1Z19tZXRhPXtpbWFnZXM6bn19fShlKTtjb25zdCByPUd0KGUsbW4uZHNuLG1uLnNka01ldGFkYXRhLG1uLnR1bm5lbCk7X24oSlNPTi5zdHJpbmdpZnkocikpLGF3YWl0ICRuLnNlbmQociksYXdhaXQgJG4uZmx1c2goMmUzKSx5bj49bW4ubWF4QW5yRXZlbnRzJiZzZXRUaW1lb3V0KCgoKT0+e3Byb2Nlc3MuZXhpdCgwKX0pLDVlMyl9bGV0IFRuO2lmKF9uKCJTdGFydGVkIiksbW4uY2FwdHVyZVN0YWNrVHJhY2Upe19uKCJDb25uZWN0aW5nIHRvIGRlYnVnZ2VyIik7Y29uc3Qgbj1uZXcgdDtuLmNvbm5lY3RUb01haW5UaHJlYWQoKSxfbigiQ29ubmVjdGVkIHRvIGRlYnVnZ2VyIik7Y29uc3QgZT1uZXcgTWFwO24ub24oIkRlYnVnZ2VyLnNjcmlwdFBhcnNlZCIsKHQ9PntlLnNldCh0LnBhcmFtcy5zY3JpcHRJZCx0LnBhcmFtcy51cmwpfSkpLG4ub24oIkRlYnVnZ2VyLnBhdXNlZCIsKHQ9PntpZigib3RoZXIiPT09dC5wYXJhbXMucmVhc29uKXRyeXtfbigiRGVidWdnZXIgcGF1c2VkIik7Y29uc3Qgcz1bLi4udC5wYXJhbXMuY2FsbEZyYW1lc10saT1tbi5hcHBSb290UGF0aD9mdW5jdGlvbih0PShwcm9jZXNzLmFyZ3ZbMV0/ZW4ocHJvY2Vzcy5hcmd2WzFdKTpwcm9jZXNzLmN3ZCgpKSxuPSJcXCI9PT1vKXtjb25zdCBlPW4/ZG4odCk6dDtyZXR1cm4gdD0+e2lmKCF0KXJldHVybjtjb25zdCBvPW4/ZG4odCk6dDtsZXR7ZGlyOnMsYmFzZTppLGV4dDpjfT1yLnBhcnNlKG8pOyIuanMiIT09YyYmIi5tanMiIT09YyYmIi5janMiIT09Y3x8KGk9aS5zbGljZSgwLC0xKmMubGVuZ3RoKSk7Y29uc3QgdT1kZWNvZGVVUklDb21wb25lbnQoaSk7c3x8KHM9Ii4iKTtjb25zdCBhPXMubGFzdEluZGV4T2YoIi9ub2RlX21vZHVsZXMiKTtpZihhPi0xKXJldHVybmAke3Muc2xpY2UoYSsxNCkucmVwbGFjZSgvXC8vZywiLiIpfToke3V9YDtpZihzLnN0YXJ0c1dpdGgoZSkpe2NvbnN0IHQ9cy5zbGljZShlLmxlbmd0aCsxKS5yZXBsYWNlKC9cLy9nLCIuIik7cmV0dXJuIHQ/YCR7dH06JHt1fWA6dX1yZXR1cm4gdX19KG1uLmFwcFJvb3RQYXRoKTooKT0+e30sYz1zLm1hcCgodD0+ZnVuY3Rpb24odCxuLGUpe2NvbnN0IHI9bj9uLnJlcGxhY2UoL15maWxlOlwvXC8vLCIiKTp2b2lkIDAsbz10LmxvY2F0aW9uLmNvbHVtbk51bWJlcj90LmxvY2F0aW9uLmNvbHVtbk51bWJlcisxOnZvaWQgMCxzPXQubG9jYXRpb24ubGluZU51bWJlcj90LmxvY2F0aW9uLmxpbmVOdW1iZXIrMTp2b2lkIDA7cmV0dXJue2ZpbGVuYW1lOnIsbW9kdWxlOmUociksZnVuY3Rpb246dC5mdW5jdGlvbk5hbWV8fCQsY29sbm86byxsaW5lbm86cyxpbl9hcHA6cj9ybihyKTp2b2lkIDB9fSh0LGUuZ2V0KHQubG9jYXRpb24uc2NyaXB0SWQpLGkpKSksdT1zZXRUaW1lb3V0KCgoKT0+e05uKGMpLnRoZW4obnVsbCwoKCk9PntfbigiU2VuZGluZyBBTlIgZXZlbnQgZmFpbGVkLiIpfSkpfSksNWUzKTtuLnBvc3QoIlJ1bnRpbWUuZXZhbHVhdGUiLHtleHByZXNzaW9uOiJnbG9iYWwuX19TRU5UUllfR0VUX1NDT1BFU19fKCk7IixzaWxlbnQ6ITAscmV0dXJuQnlWYWx1ZTohMH0sKCh0LGUpPT57dCYmX24oYEVycm9yIGV4ZWN1dGluZyBzY3JpcHQ6ICcke3QubWVzc2FnZX0nYCksY2xlYXJUaW1lb3V0KHUpO2NvbnN0IHI9ZT8ucmVzdWx0P2UucmVzdWx0LnZhbHVlOnZvaWQgMDtuLnBvc3QoIkRlYnVnZ2VyLnJlc3VtZSIpLG4ucG9zdCgiRGVidWdnZXIuZGlzYWJsZSIpLE5uKGMscikudGhlbihudWxsLCgoKT0+e19uKCJTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQuIil9KSl9KSl9Y2F0Y2godCl7dGhyb3cgbi5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKSxuLnBvc3QoIkRlYnVnZ2VyLmRpc2FibGUiKSx0fX0pKSxUbj0oKT0+e3RyeXtuLnBvc3QoIkRlYnVnZ2VyLmVuYWJsZSIsKCgpPT57bi5wb3N0KCJEZWJ1Z2dlci5wYXVzZSIpfSkpfWNhdGNoKHQpe319fWNvbnN0e3BvbGw6Q259PWZ1bmN0aW9uKHQsbixlLHIpe2NvbnN0IG89dCgpO2xldCBzPSExLGk9ITA7cmV0dXJuIHNldEludGVydmFsKCgoKT0+e2NvbnN0IHQ9by5nZXRUaW1lTXMoKTshMT09PXMmJnQ+bitlJiYocz0hMCxpJiZyKCkpLHQ8bitlJiYocz0hMSl9KSwyMCkse3BvbGw6KCk9PntvLnJlc2V0KCl9LGVuYWJsZWQ6dD0+e2k9dH19fSgoZnVuY3Rpb24oKXtsZXQgdD1wcm9jZXNzLmhydGltZSgpO3JldHVybntnZXRUaW1lTXM6KCk9Pntjb25zdFtuLGVdPXByb2Nlc3MuaHJ0aW1lKHQpO3JldHVybiBNYXRoLmZsb29yKDFlMypuK2UvMWU2KX0scmVzZXQ6KCk9Pnt0PXByb2Nlc3MuaHJ0aW1lKCl9fX0pLG1uLnBvbGxJbnRlcnZhbCxtbi5hbnJUaHJlc2hvbGQsKGZ1bmN0aW9uKCl7X24oIldhdGNoZG9nIHRpbWVvdXQiKSxUbj8oX24oIlBhdXNpbmcgZGVidWdnZXIgdG8gY2FwdHVyZSBzdGFjayB0cmFjZSIpLFRuKCkpOihfbigiQ2FwdHVyaW5nIGV2ZW50IHdpdGhvdXQgYSBzdGFjayB0cmFjZSIpLE5uKCkudGhlbihudWxsLCgoKT0+e19uKCJTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQgb24gd2F0Y2hkb2cgdGltZW91dC4iKX0pKSl9KSk7ZT8ub24oIm1lc3NhZ2UiLCh0PT57dC5zZXNzaW9uJiYoZ249eih0LnNlc3Npb24pKSx0LmRlYnVnSW1hZ2VzJiYoYm49dC5kZWJ1Z0ltYWdlcyksQ24oKX0pKTs=';
|
|
13
13
|
|
|
14
14
|
const DEFAULT_INTERVAL = 50;
|
|
15
15
|
const DEFAULT_HANG_THRESHOLD = 5000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/integrations/anr/index.ts"],"sourcesContent":["import { types } from 'node:util';\nimport { Worker } from 'node:worker_threads';\nimport type { Contexts, Event, EventHint, Integration, IntegrationFn, ScopeData } from '@sentry/core';\nimport {\n GLOBAL_OBJ,\n defineIntegration,\n getClient,\n getCurrentScope,\n getFilenameToDebugIdMap,\n getGlobalScope,\n getIsolationScope,\n logger,\n mergeScopeData,\n} from '@sentry/core';\nimport { NODE_VERSION } from '../../nodeVersion';\nimport type { NodeClient } from '../../sdk/client';\nimport { isDebuggerEnabled } from '../../utils/debug';\nimport type { AnrIntegrationOptions, WorkerStartData } from './common';\n\nconst { isPromise } = types;\n\n// This string is a placeholder that gets overwritten with the worker code.\nexport const base64WorkerScript = '###AnrWorkerScript###';\n\nconst DEFAULT_INTERVAL = 50;\nconst DEFAULT_HANG_THRESHOLD = 5000;\n\nfunction log(message: string, ...args: unknown[]): void {\n logger.log(`[ANR] ${message}`, ...args);\n}\n\nfunction globalWithScopeFetchFn(): typeof GLOBAL_OBJ & { __SENTRY_GET_SCOPES__?: () => ScopeData } {\n return GLOBAL_OBJ;\n}\n\n/** Fetches merged scope data */\nfunction getScopeData(): ScopeData {\n const scope = getGlobalScope().getScopeData();\n mergeScopeData(scope, getIsolationScope().getScopeData());\n mergeScopeData(scope, getCurrentScope().getScopeData());\n\n // We remove attachments because they likely won't serialize well as json\n scope.attachments = [];\n // We can't serialize event processor functions\n scope.eventProcessors = [];\n\n return scope;\n}\n\n/**\n * Gets contexts by calling all event processors. This shouldn't be called until all integrations are setup\n */\nasync function getContexts(client: NodeClient): Promise<Contexts> {\n let event: Event | null = { message: 'ANR' };\n const eventHint: EventHint = {};\n\n for (const processor of client.getEventProcessors()) {\n if (event === null) break;\n event = await processor(event, eventHint);\n }\n\n return event?.contexts || {};\n}\n\nconst INTEGRATION_NAME = 'Anr';\n\ntype AnrInternal = { startWorker: () => void; stopWorker: () => void };\n\nconst _anrIntegration = ((options: Partial<AnrIntegrationOptions> = {}) => {\n if (NODE_VERSION.major < 16 || (NODE_VERSION.major === 16 && NODE_VERSION.minor < 17)) {\n throw new Error('ANR detection requires Node 16.17.0 or later');\n }\n\n let worker: Promise<() => void> | undefined;\n let client: NodeClient | undefined;\n\n // Hookup the scope fetch function to the global object so that it can be called from the worker thread via the\n // debugger when it pauses\n const gbl = globalWithScopeFetchFn();\n gbl.__SENTRY_GET_SCOPES__ = getScopeData;\n\n return {\n name: INTEGRATION_NAME,\n startWorker: () => {\n if (worker) {\n return;\n }\n\n if (client) {\n worker = _startWorker(client, options);\n }\n },\n stopWorker: () => {\n if (worker) {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.then(stop => {\n stop();\n worker = undefined;\n });\n }\n },\n async setup(initClient: NodeClient) {\n client = initClient;\n\n if (options.captureStackTrace && (await isDebuggerEnabled())) {\n logger.warn('ANR captureStackTrace has been disabled because the debugger was already enabled');\n options.captureStackTrace = false;\n }\n\n // setImmediate is used to ensure that all other integrations have had their setup called first.\n // This allows us to call into all integrations to fetch the full context\n setImmediate(() => this.startWorker());\n },\n } as Integration & AnrInternal;\n}) satisfies IntegrationFn;\n\ntype AnrReturn = (options?: Partial<AnrIntegrationOptions>) => Integration & AnrInternal;\n\nexport const anrIntegration = defineIntegration(_anrIntegration) as AnrReturn;\n\n/**\n * Starts the ANR worker thread\n *\n * @returns A function to stop the worker\n */\nasync function _startWorker(\n client: NodeClient,\n integrationOptions: Partial<AnrIntegrationOptions>,\n): Promise<() => void> {\n const dsn = client.getDsn();\n\n if (!dsn) {\n return () => {\n //\n };\n }\n\n const contexts = await getContexts(client);\n\n // These will not be accurate if sent later from the worker thread\n delete contexts.app?.app_memory;\n delete contexts.device?.free_memory;\n\n const initOptions = client.getOptions();\n\n const sdkMetadata = client.getSdkMetadata() || {};\n if (sdkMetadata.sdk) {\n sdkMetadata.sdk.integrations = initOptions.integrations.map(i => i.name);\n }\n\n const options: WorkerStartData = {\n debug: logger.isEnabled(),\n dsn,\n tunnel: initOptions.tunnel,\n environment: initOptions.environment || 'production',\n release: initOptions.release,\n dist: initOptions.dist,\n sdkMetadata,\n appRootPath: integrationOptions.appRootPath,\n pollInterval: integrationOptions.pollInterval || DEFAULT_INTERVAL,\n anrThreshold: integrationOptions.anrThreshold || DEFAULT_HANG_THRESHOLD,\n captureStackTrace: !!integrationOptions.captureStackTrace,\n maxAnrEvents: integrationOptions.maxAnrEvents || 1,\n staticTags: integrationOptions.staticTags || {},\n contexts,\n };\n\n if (options.captureStackTrace) {\n const inspector = await import('node:inspector');\n if (!inspector.url()) {\n inspector.open(0);\n }\n }\n\n const worker = new Worker(new URL(`data:application/javascript;base64,${base64WorkerScript}`), {\n workerData: options,\n // We don't want any Node args to be passed to the worker\n execArgv: [],\n env: { ...process.env, NODE_OPTIONS: undefined },\n });\n\n process.on('exit', () => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n });\n\n const timer = setInterval(() => {\n try {\n const currentSession = getIsolationScope().getSession();\n // We need to copy the session object and remove the toJSON method so it can be sent to the worker\n // serialized without making it a SerializedSession\n const session = currentSession ? { ...currentSession, toJSON: undefined } : undefined;\n // message the worker to tell it the main event loop is still running\n worker.postMessage({ session, debugImages: getFilenameToDebugIdMap(initOptions.stackParser) });\n } catch (_) {\n //\n }\n }, options.pollInterval);\n // Timer should not block exit\n timer.unref();\n\n worker.on('message', (msg: string) => {\n if (msg === 'session-ended') {\n log('ANR event sent from ANR worker. Clearing session in this thread.');\n getIsolationScope().setSession(undefined);\n }\n });\n\n worker.once('error', (err: Error) => {\n clearInterval(timer);\n log('ANR worker error', err);\n });\n\n worker.once('exit', (code: number) => {\n clearInterval(timer);\n log('ANR worker exit', code);\n });\n\n // Ensure this thread can't block app exit\n worker.unref();\n\n return () => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n clearInterval(timer);\n };\n}\n\nexport function disableAnrDetectionForCallback<T>(callback: () => T): T;\nexport function disableAnrDetectionForCallback<T>(callback: () => Promise<T>): Promise<T>;\n/**\n * Disables ANR detection for the duration of the callback\n */\nexport function disableAnrDetectionForCallback<T>(callback: () => T | Promise<T>): T | Promise<T> {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as AnrInternal | undefined;\n\n if (!integration) {\n return callback();\n }\n\n integration.stopWorker();\n\n const result = callback();\n if (isPromise(result)) {\n return result.finally(() => integration.startWorker());\n }\n\n integration.startWorker();\n return result;\n}\n"],"names":["types","logger","GLOBAL_OBJ","getGlobalScope","mergeScopeData","getIsolationScope","getCurrentScope","NODE_VERSION","isDebuggerEnabled","defineIntegration","Worker","getFilenameToDebugIdMap","getClient"],"mappings":";;;;;;;;AAmBA,MAAM,EAAE,SAAA,EAAY,GAAEA,UAAK;;AAE3B;AACO,MAAM,kBAAmB,GAAE;;AAElC,MAAM,gBAAA,GAAmB,EAAE;AAC3B,MAAM,sBAAA,GAAyB,IAAI;;AAEnC,SAAS,GAAG,CAAC,OAAO,EAAU,GAAG,IAAI,EAAmB;AACxD,EAAEC,WAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA,EAAA,GAAA,IAAA,CAAA;AACA;;AAEA,SAAA,sBAAA,GAAA;AACA,EAAA,OAAAC,eAAA;AACA;;AAEA;AACA,SAAA,YAAA,GAAA;AACA,EAAA,MAAA,KAAA,GAAAC,mBAAA,EAAA,CAAA,YAAA,EAAA;AACA,EAAAC,mBAAA,CAAA,KAAA,EAAAC,sBAAA,EAAA,CAAA,YAAA,EAAA,CAAA;AACA,EAAAD,mBAAA,CAAA,KAAA,EAAAE,oBAAA,EAAA,CAAA,YAAA,EAAA,CAAA;;AAEA;AACA,EAAA,KAAA,CAAA,WAAA,GAAA,EAAA;AACA;AACA,EAAA,KAAA,CAAA,eAAA,GAAA,EAAA;;AAEA,EAAA,OAAA,KAAA;AACA;;AAEA;AACA;AACA;AACA,eAAA,WAAA,CAAA,MAAA,EAAA;AACA,EAAA,IAAA,KAAA,GAAA,EAAA,OAAA,EAAA,KAAA,EAAA;AACA,EAAA,MAAA,SAAA,GAAA,EAAA;;AAEA,EAAA,KAAA,MAAA,SAAA,IAAA,MAAA,CAAA,kBAAA,EAAA,EAAA;AACA,IAAA,IAAA,KAAA,KAAA,IAAA,EAAA;AACA,IAAA,KAAA,GAAA,MAAA,SAAA,CAAA,KAAA,EAAA,SAAA,CAAA;AACA;;AAEA,EAAA,OAAA,KAAA,EAAA,QAAA,IAAA,EAAA;AACA;;AAEA,MAAA,gBAAA,GAAA,KAAA;;AAIA,MAAA,eAAA,IAAA,CAAA,OAAA,GAAA,EAAA,KAAA;AACA,EAAA,IAAAC,wBAAA,CAAA,KAAA,GAAA,EAAA,KAAAA,wBAAA,CAAA,KAAA,KAAA,EAAA,IAAAA,wBAAA,CAAA,KAAA,GAAA,EAAA,CAAA,EAAA;AACA,IAAA,MAAA,IAAA,KAAA,CAAA,8CAAA,CAAA;AACA;;AAEA,EAAA,IAAA,MAAA;AACA,EAAA,IAAA,MAAA;;AAEA;AACA;AACA,EAAA,MAAA,GAAA,GAAA,sBAAA,EAAA;AACA,EAAA,GAAA,CAAA,qBAAA,GAAA,YAAA;;AAEA,EAAA,OAAA;AACA,IAAA,IAAA,EAAA,gBAAA;AACA,IAAA,WAAA,EAAA,MAAA;AACA,MAAA,IAAA,MAAA,EAAA;AACA,QAAA;AACA;;AAEA,MAAA,IAAA,MAAA,EAAA;AACA,QAAA,MAAA,GAAA,YAAA,CAAA,MAAA,EAAA,OAAA,CAAA;AACA;AACA,KAAA;AACA,IAAA,UAAA,EAAA,MAAA;AACA,MAAA,IAAA,MAAA,EAAA;AACA;AACA,QAAA,MAAA,CAAA,IAAA,CAAA,IAAA,IAAA;AACA,UAAA,IAAA,EAAA;AACA,UAAA,MAAA,GAAA,SAAA;AACA,SAAA,CAAA;AACA;AACA,KAAA;AACA,IAAA,MAAA,KAAA,CAAA,UAAA,EAAA;AACA,MAAA,MAAA,GAAA,UAAA;;AAEA,MAAA,IAAA,OAAA,CAAA,iBAAA,KAAA,MAAAC,uBAAA,EAAA,CAAA,EAAA;AACA,QAAAP,WAAA,CAAA,IAAA,CAAA,kFAAA,CAAA;AACA,QAAA,OAAA,CAAA,iBAAA,GAAA,KAAA;AACA;;AAEA;AACA;AACA,MAAA,YAAA,CAAA,MAAA,IAAA,CAAA,WAAA,EAAA,CAAA;AACA,KAAA;AACA,GAAA;AACA,CAAA,CAAA;;AAIA,MAAA,cAAA,GAAAQ,sBAAA,CAAA,eAAA,CAAA;;AAEA;AACA;AACA;AACA;AACA;AACA,eAAA,YAAA;AACA,EAAA,MAAA;AACA,EAAA,kBAAA;AACA,EAAA;AACA,EAAA,MAAA,GAAA,GAAA,MAAA,CAAA,MAAA,EAAA;;AAEA,EAAA,IAAA,CAAA,GAAA,EAAA;AACA,IAAA,OAAA,MAAA;AACA;AACA,KAAA;AACA;;AAEA,EAAA,MAAA,QAAA,GAAA,MAAA,WAAA,CAAA,MAAA,CAAA;;AAEA;AACA,EAAA,OAAA,QAAA,CAAA,GAAA,EAAA,UAAA;AACA,EAAA,OAAA,QAAA,CAAA,MAAA,EAAA,WAAA;;AAEA,EAAA,MAAA,WAAA,GAAA,MAAA,CAAA,UAAA,EAAA;;AAEA,EAAA,MAAA,WAAA,GAAA,MAAA,CAAA,cAAA,EAAA,IAAA,EAAA;AACA,EAAA,IAAA,WAAA,CAAA,GAAA,EAAA;AACA,IAAA,WAAA,CAAA,GAAA,CAAA,YAAA,GAAA,WAAA,CAAA,YAAA,CAAA,GAAA,CAAA,CAAA,IAAA,CAAA,CAAA,IAAA,CAAA;AACA;;AAEA,EAAA,MAAA,OAAA,GAAA;AACA,IAAA,KAAA,EAAAR,WAAA,CAAA,SAAA,EAAA;AACA,IAAA,GAAA;AACA,IAAA,MAAA,EAAA,WAAA,CAAA,MAAA;AACA,IAAA,WAAA,EAAA,WAAA,CAAA,WAAA,IAAA,YAAA;AACA,IAAA,OAAA,EAAA,WAAA,CAAA,OAAA;AACA,IAAA,IAAA,EAAA,WAAA,CAAA,IAAA;AACA,IAAA,WAAA;AACA,IAAA,WAAA,EAAA,kBAAA,CAAA,WAAA;AACA,IAAA,YAAA,EAAA,kBAAA,CAAA,YAAA,IAAA,gBAAA;AACA,IAAA,YAAA,EAAA,kBAAA,CAAA,YAAA,IAAA,sBAAA;AACA,IAAA,iBAAA,EAAA,CAAA,CAAA,kBAAA,CAAA,iBAAA;AACA,IAAA,YAAA,EAAA,kBAAA,CAAA,YAAA,IAAA,CAAA;AACA,IAAA,UAAA,EAAA,kBAAA,CAAA,UAAA,IAAA,EAAA;AACA,IAAA,QAAA;AACA,GAAA;;AAEA,EAAA,IAAA,OAAA,CAAA,iBAAA,EAAA;AACA,IAAA,MAAA,SAAA,GAAA,MAAA,OAAA,gBAAA,CAAA;AACA,IAAA,IAAA,CAAA,SAAA,CAAA,GAAA,EAAA,EAAA;AACA,MAAA,SAAA,CAAA,IAAA,CAAA,CAAA,CAAA;AACA;AACA;;AAEA,EAAA,MAAA,MAAA,GAAA,IAAAS,0BAAA,CAAA,IAAA,GAAA,CAAA,CAAA,mCAAA,EAAA,kBAAA,CAAA,CAAA,CAAA,EAAA;AACA,IAAA,UAAA,EAAA,OAAA;AACA;AACA,IAAA,QAAA,EAAA,EAAA;AACA,IAAA,GAAA,EAAA,EAAA,GAAA,OAAA,CAAA,GAAA,EAAA,YAAA,EAAA,SAAA,EAAA;AACA,GAAA,CAAA;;AAEA,EAAA,OAAA,CAAA,EAAA,CAAA,MAAA,EAAA,MAAA;AACA;AACA,IAAA,MAAA,CAAA,SAAA,EAAA;AACA,GAAA,CAAA;;AAEA,EAAA,MAAA,KAAA,GAAA,WAAA,CAAA,MAAA;AACA,IAAA,IAAA;AACA,MAAA,MAAA,cAAA,GAAAL,sBAAA,EAAA,CAAA,UAAA,EAAA;AACA;AACA;AACA,MAAA,MAAA,OAAA,GAAA,cAAA,GAAA,EAAA,GAAA,cAAA,EAAA,MAAA,EAAA,SAAA,EAAA,GAAA,SAAA;AACA;AACA,MAAA,MAAA,CAAA,WAAA,CAAA,EAAA,OAAA,EAAA,WAAA,EAAAM,4BAAA,CAAA,WAAA,CAAA,WAAA,CAAA,EAAA,CAAA;AACA,KAAA,CAAA,OAAA,CAAA,EAAA;AACA;AACA;AACA,GAAA,EAAA,OAAA,CAAA,YAAA,CAAA;AACA;AACA,EAAA,KAAA,CAAA,KAAA,EAAA;;AAEA,EAAA,MAAA,CAAA,EAAA,CAAA,SAAA,EAAA,CAAA,GAAA,KAAA;AACA,IAAA,IAAA,GAAA,KAAA,eAAA,EAAA;AACA,MAAA,GAAA,CAAA,kEAAA,CAAA;AACA,MAAAN,sBAAA,EAAA,CAAA,UAAA,CAAA,SAAA,CAAA;AACA;AACA,GAAA,CAAA;;AAEA,EAAA,MAAA,CAAA,IAAA,CAAA,OAAA,EAAA,CAAA,GAAA,KAAA;AACA,IAAA,aAAA,CAAA,KAAA,CAAA;AACA,IAAA,GAAA,CAAA,kBAAA,EAAA,GAAA,CAAA;AACA,GAAA,CAAA;;AAEA,EAAA,MAAA,CAAA,IAAA,CAAA,MAAA,EAAA,CAAA,IAAA,KAAA;AACA,IAAA,aAAA,CAAA,KAAA,CAAA;AACA,IAAA,GAAA,CAAA,iBAAA,EAAA,IAAA,CAAA;AACA,GAAA,CAAA;;AAEA;AACA,EAAA,MAAA,CAAA,KAAA,EAAA;;AAEA,EAAA,OAAA,MAAA;AACA;AACA,IAAA,MAAA,CAAA,SAAA,EAAA;AACA,IAAA,aAAA,CAAA,KAAA,CAAA;AACA,GAAA;AACA;;AAIA;AACA;AACA;AACA,SAAA,8BAAA,CAAA,QAAA,EAAA;AACA,EAAA,MAAA,WAAA,GAAAO,cAAA,EAAA,EAAA,oBAAA,CAAA,gBAAA,CAAA;;AAEA,EAAA,IAAA,CAAA,WAAA,EAAA;AACA,IAAA,OAAA,QAAA,EAAA;AACA;;AAEA,EAAA,WAAA,CAAA,UAAA,EAAA;;AAEA,EAAA,MAAA,MAAA,GAAA,QAAA,EAAA;AACA,EAAA,IAAA,SAAA,CAAA,MAAA,CAAA,EAAA;AACA,IAAA,OAAA,MAAA,CAAA,OAAA,CAAA,MAAA,WAAA,CAAA,WAAA,EAAA,CAAA;AACA;;AAEA,EAAA,WAAA,CAAA,WAAA,EAAA;AACA,EAAA,OAAA,MAAA;AACA;;;;;;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/integrations/anr/index.ts"],"sourcesContent":["import { types } from 'node:util';\nimport { Worker } from 'node:worker_threads';\nimport type { Contexts, Event, EventHint, Integration, IntegrationFn, ScopeData } from '@sentry/core';\nimport {\n GLOBAL_OBJ,\n defineIntegration,\n getClient,\n getCurrentScope,\n getFilenameToDebugIdMap,\n getGlobalScope,\n getIsolationScope,\n logger,\n mergeScopeData,\n} from '@sentry/core';\nimport { NODE_VERSION } from '../../nodeVersion';\nimport type { NodeClient } from '../../sdk/client';\nimport { isDebuggerEnabled } from '../../utils/debug';\nimport type { AnrIntegrationOptions, WorkerStartData } from './common';\n\nconst { isPromise } = types;\n\n// This string is a placeholder that gets overwritten with the worker code.\nexport const base64WorkerScript = '###AnrWorkerScript###';\n\nconst DEFAULT_INTERVAL = 50;\nconst DEFAULT_HANG_THRESHOLD = 5000;\n\nfunction log(message: string, ...args: unknown[]): void {\n logger.log(`[ANR] ${message}`, ...args);\n}\n\nfunction globalWithScopeFetchFn(): typeof GLOBAL_OBJ & { __SENTRY_GET_SCOPES__?: () => ScopeData } {\n return GLOBAL_OBJ;\n}\n\n/** Fetches merged scope data */\nfunction getScopeData(): ScopeData {\n const scope = getGlobalScope().getScopeData();\n mergeScopeData(scope, getIsolationScope().getScopeData());\n mergeScopeData(scope, getCurrentScope().getScopeData());\n\n // We remove attachments because they likely won't serialize well as json\n scope.attachments = [];\n // We can't serialize event processor functions\n scope.eventProcessors = [];\n\n return scope;\n}\n\n/**\n * Gets contexts by calling all event processors. This shouldn't be called until all integrations are setup\n */\nasync function getContexts(client: NodeClient): Promise<Contexts> {\n let event: Event | null = { message: 'ANR' };\n const eventHint: EventHint = {};\n\n for (const processor of client.getEventProcessors()) {\n if (event === null) break;\n event = await processor(event, eventHint);\n }\n\n return event?.contexts || {};\n}\n\nconst INTEGRATION_NAME = 'Anr';\n\ntype AnrInternal = { startWorker: () => void; stopWorker: () => void };\n\nconst _anrIntegration = ((options: Partial<AnrIntegrationOptions> = {}) => {\n if (NODE_VERSION.major < 16 || (NODE_VERSION.major === 16 && NODE_VERSION.minor < 17)) {\n throw new Error('ANR detection requires Node 16.17.0 or later');\n }\n\n let worker: Promise<() => void> | undefined;\n let client: NodeClient | undefined;\n\n // Hookup the scope fetch function to the global object so that it can be called from the worker thread via the\n // debugger when it pauses\n const gbl = globalWithScopeFetchFn();\n gbl.__SENTRY_GET_SCOPES__ = getScopeData;\n\n return {\n name: INTEGRATION_NAME,\n startWorker: () => {\n if (worker) {\n return;\n }\n\n if (client) {\n worker = _startWorker(client, options);\n }\n },\n stopWorker: () => {\n if (worker) {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.then(stop => {\n stop();\n worker = undefined;\n });\n }\n },\n async setup(initClient: NodeClient) {\n client = initClient;\n\n if (options.captureStackTrace && (await isDebuggerEnabled())) {\n logger.warn('ANR captureStackTrace has been disabled because the debugger was already enabled');\n options.captureStackTrace = false;\n }\n\n // setImmediate is used to ensure that all other integrations have had their setup called first.\n // This allows us to call into all integrations to fetch the full context\n setImmediate(() => this.startWorker());\n },\n } as Integration & AnrInternal;\n}) satisfies IntegrationFn;\n\ntype AnrReturn = (options?: Partial<AnrIntegrationOptions>) => Integration & AnrInternal;\n\nexport const anrIntegration = defineIntegration(_anrIntegration) as AnrReturn;\n\n/**\n * Starts the ANR worker thread\n *\n * @returns A function to stop the worker\n */\nasync function _startWorker(\n client: NodeClient,\n integrationOptions: Partial<AnrIntegrationOptions>,\n): Promise<() => void> {\n const dsn = client.getDsn();\n\n if (!dsn) {\n return () => {\n //\n };\n }\n\n const contexts = await getContexts(client);\n\n // These will not be accurate if sent later from the worker thread\n delete contexts.app?.app_memory;\n delete contexts.device?.free_memory;\n\n const initOptions = client.getOptions();\n\n const sdkMetadata = client.getSdkMetadata() || {};\n if (sdkMetadata.sdk) {\n sdkMetadata.sdk.integrations = initOptions.integrations.map(i => i.name);\n }\n\n const options: WorkerStartData = {\n debug: logger.isEnabled(),\n dsn,\n tunnel: initOptions.tunnel,\n environment: initOptions.environment || 'production',\n release: initOptions.release,\n dist: initOptions.dist,\n sdkMetadata,\n appRootPath: integrationOptions.appRootPath,\n pollInterval: integrationOptions.pollInterval || DEFAULT_INTERVAL,\n anrThreshold: integrationOptions.anrThreshold || DEFAULT_HANG_THRESHOLD,\n captureStackTrace: !!integrationOptions.captureStackTrace,\n maxAnrEvents: integrationOptions.maxAnrEvents || 1,\n staticTags: integrationOptions.staticTags || {},\n contexts,\n };\n\n if (options.captureStackTrace) {\n const inspector = await import('node:inspector');\n if (!inspector.url()) {\n inspector.open(0);\n }\n }\n\n const worker = new Worker(new URL(`data:application/javascript;base64,${base64WorkerScript}`), {\n workerData: options,\n // We don't want any Node args to be passed to the worker\n execArgv: [],\n env: { ...process.env, NODE_OPTIONS: undefined },\n });\n\n process.on('exit', () => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n });\n\n const timer = setInterval(() => {\n try {\n const currentSession = getIsolationScope().getSession();\n // We need to copy the session object and remove the toJSON method so it can be sent to the worker\n // serialized without making it a SerializedSession\n const session = currentSession ? { ...currentSession, toJSON: undefined } : undefined;\n // message the worker to tell it the main event loop is still running\n worker.postMessage({ session, debugImages: getFilenameToDebugIdMap(initOptions.stackParser) });\n } catch (_) {\n //\n }\n }, options.pollInterval);\n // Timer should not block exit\n timer.unref();\n\n worker.on('message', (msg: string) => {\n if (msg === 'session-ended') {\n log('ANR event sent from ANR worker. Clearing session in this thread.');\n getIsolationScope().setSession(undefined);\n }\n });\n\n worker.once('error', (err: Error) => {\n clearInterval(timer);\n log('ANR worker error', err);\n });\n\n worker.once('exit', (code: number) => {\n clearInterval(timer);\n log('ANR worker exit', code);\n });\n\n // Ensure this thread can't block app exit\n worker.unref();\n\n return () => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n clearInterval(timer);\n };\n}\n\nexport function disableAnrDetectionForCallback<T>(callback: () => T): T;\nexport function disableAnrDetectionForCallback<T>(callback: () => Promise<T>): Promise<T>;\n/**\n * Disables ANR detection for the duration of the callback\n */\nexport function disableAnrDetectionForCallback<T>(callback: () => T | Promise<T>): T | Promise<T> {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as AnrInternal | undefined;\n\n if (!integration) {\n return callback();\n }\n\n integration.stopWorker();\n\n const result = callback();\n if (isPromise(result)) {\n return result.finally(() => integration.startWorker());\n }\n\n integration.startWorker();\n return result;\n}\n"],"names":["types","logger","GLOBAL_OBJ","getGlobalScope","mergeScopeData","getIsolationScope","getCurrentScope","NODE_VERSION","isDebuggerEnabled","defineIntegration","Worker","getFilenameToDebugIdMap","getClient"],"mappings":"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"}
|
|
@@ -4,14 +4,14 @@ const node_child_process = require('node:child_process');
|
|
|
4
4
|
const node_fs = require('node:fs');
|
|
5
5
|
const os = require('node:os');
|
|
6
6
|
const node_path = require('node:path');
|
|
7
|
-
const
|
|
7
|
+
const node_util = require('node:util');
|
|
8
8
|
const core = require('@sentry/core');
|
|
9
9
|
|
|
10
10
|
/* eslint-disable max-lines */
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
const readFileAsync =
|
|
14
|
-
const readDirAsync =
|
|
13
|
+
const readFileAsync = node_util.promisify(node_fs.readFile);
|
|
14
|
+
const readDirAsync = node_util.promisify(node_fs.readdir);
|
|
15
15
|
|
|
16
16
|
// Process enhanced with methods from Node 18, 20, 22 as @types/node
|
|
17
17
|
// is on `14.18.0` to match minimum version requirements of the SDK
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sources":["../../../src/integrations/context.ts"],"sourcesContent":["/* eslint-disable max-lines */\n\nimport { execFile } from 'node:child_process';\nimport { readFile, readdir } from 'node:fs';\nimport * as os from 'node:os';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\nimport type {\n AppContext,\n CloudResourceContext,\n Contexts,\n CultureContext,\n DeviceContext,\n Event,\n IntegrationFn,\n OsContext,\n} from '@sentry/core';\nimport { defineIntegration } from '@sentry/core';\n\nexport const readFileAsync = promisify(readFile);\nexport const readDirAsync = promisify(readdir);\n\n// Process enhanced with methods from Node 18, 20, 22 as @types/node\n// is on `14.18.0` to match minimum version requirements of the SDK\ninterface ProcessWithCurrentValues extends NodeJS.Process {\n availableMemory?(): number;\n}\n\nconst INTEGRATION_NAME = 'Context';\n\ninterface DeviceContextOptions {\n cpu?: boolean;\n memory?: boolean;\n}\n\ninterface ContextOptions {\n app?: boolean;\n os?: boolean;\n device?: DeviceContextOptions | boolean;\n culture?: boolean;\n cloudResource?: boolean;\n}\n\nconst _nodeContextIntegration = ((options: ContextOptions = {}) => {\n let cachedContext: Promise<Contexts> | undefined;\n\n const _options = {\n app: true,\n os: true,\n device: true,\n culture: true,\n cloudResource: true,\n ...options,\n };\n\n /** Add contexts to the event. Caches the context so we only look it up once. */\n async function addContext(event: Event): Promise<Event> {\n if (cachedContext === undefined) {\n cachedContext = _getContexts();\n }\n\n const updatedContext = _updateContext(await cachedContext);\n\n event.contexts = {\n ...event.contexts,\n app: { ...updatedContext.app, ...event.contexts?.app },\n os: { ...updatedContext.os, ...event.contexts?.os },\n device: { ...updatedContext.device, ...event.contexts?.device },\n culture: { ...updatedContext.culture, ...event.contexts?.culture },\n cloud_resource: { ...updatedContext.cloud_resource, ...event.contexts?.cloud_resource },\n };\n\n return event;\n }\n\n /** Get the contexts from node. */\n async function _getContexts(): Promise<Contexts> {\n const contexts: Contexts = {};\n\n if (_options.os) {\n contexts.os = await getOsContext();\n }\n\n if (_options.app) {\n contexts.app = getAppContext();\n }\n\n if (_options.device) {\n contexts.device = getDeviceContext(_options.device);\n }\n\n if (_options.culture) {\n const culture = getCultureContext();\n\n if (culture) {\n contexts.culture = culture;\n }\n }\n\n if (_options.cloudResource) {\n contexts.cloud_resource = getCloudResourceContext();\n }\n\n return contexts;\n }\n\n return {\n name: INTEGRATION_NAME,\n processEvent(event) {\n return addContext(event);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Capture context about the environment and the device that the client is running on, to events.\n */\nexport const nodeContextIntegration = defineIntegration(_nodeContextIntegration);\n\n/**\n * Updates the context with dynamic values that can change\n */\nfunction _updateContext(contexts: Contexts): Contexts {\n // Only update properties if they exist\n\n if (contexts.app?.app_memory) {\n contexts.app.app_memory = process.memoryUsage().rss;\n }\n\n if (contexts.app?.free_memory && typeof (process as ProcessWithCurrentValues).availableMemory === 'function') {\n const freeMemory = (process as ProcessWithCurrentValues).availableMemory?.();\n if (freeMemory != null) {\n contexts.app.free_memory = freeMemory;\n }\n }\n\n if (contexts.device?.free_memory) {\n contexts.device.free_memory = os.freemem();\n }\n\n return contexts;\n}\n\n/**\n * Returns the operating system context.\n *\n * Based on the current platform, this uses a different strategy to provide the\n * most accurate OS information. Since this might involve spawning subprocesses\n * or accessing the file system, this should only be executed lazily and cached.\n *\n * - On macOS (Darwin), this will execute the `sw_vers` utility. The context\n * has a `name`, `version`, `build` and `kernel_version` set.\n * - On Linux, this will try to load a distribution release from `/etc` and set\n * the `name`, `version` and `kernel_version` fields.\n * - On all other platforms, only a `name` and `version` will be returned. Note\n * that `version` might actually be the kernel version.\n */\nasync function getOsContext(): Promise<OsContext> {\n const platformId = os.platform();\n switch (platformId) {\n case 'darwin':\n return getDarwinInfo();\n case 'linux':\n return getLinuxInfo();\n default:\n return {\n name: PLATFORM_NAMES[platformId] || platformId,\n version: os.release(),\n };\n }\n}\n\nfunction getCultureContext(): CultureContext | undefined {\n try {\n if (typeof process.versions.icu !== 'string') {\n // Node was built without ICU support\n return;\n }\n\n // Check that node was built with full Intl support. Its possible it was built without support for non-English\n // locales which will make resolvedOptions inaccurate\n //\n // https://nodejs.org/api/intl.html#detecting-internationalization-support\n const january = new Date(9e8);\n const spanish = new Intl.DateTimeFormat('es', { month: 'long' });\n if (spanish.format(january) === 'enero') {\n const options = Intl.DateTimeFormat().resolvedOptions();\n\n return {\n locale: options.locale,\n timezone: options.timeZone,\n };\n }\n } catch (err) {\n //\n }\n\n return;\n}\n\n/**\n * Get app context information from process\n */\nexport function getAppContext(): AppContext {\n const app_memory = process.memoryUsage().rss;\n const app_start_time = new Date(Date.now() - process.uptime() * 1000).toISOString();\n // https://nodejs.org/api/process.html#processavailablememory\n const appContext: AppContext = { app_start_time, app_memory };\n\n if (typeof (process as ProcessWithCurrentValues).availableMemory === 'function') {\n const freeMemory = (process as ProcessWithCurrentValues).availableMemory?.();\n if (freeMemory != null) {\n appContext.free_memory = freeMemory;\n }\n }\n\n return appContext;\n}\n\n/**\n * Gets device information from os\n */\nexport function getDeviceContext(deviceOpt: DeviceContextOptions | true): DeviceContext {\n const device: DeviceContext = {};\n\n // Sometimes os.uptime() throws due to lacking permissions: https://github.com/getsentry/sentry-javascript/issues/8202\n let uptime;\n try {\n uptime = os.uptime();\n } catch (e) {\n // noop\n }\n\n // os.uptime or its return value seem to be undefined in certain environments (e.g. Azure functions).\n // Hence, we only set boot time, if we get a valid uptime value.\n // @see https://github.com/getsentry/sentry-javascript/issues/5856\n if (typeof uptime === 'number') {\n device.boot_time = new Date(Date.now() - uptime * 1000).toISOString();\n }\n\n device.arch = os.arch();\n\n if (deviceOpt === true || deviceOpt.memory) {\n device.memory_size = os.totalmem();\n device.free_memory = os.freemem();\n }\n\n if (deviceOpt === true || deviceOpt.cpu) {\n const cpuInfo = os.cpus() as os.CpuInfo[] | undefined;\n const firstCpu = cpuInfo?.[0];\n if (firstCpu) {\n device.processor_count = cpuInfo.length;\n device.cpu_description = firstCpu.model;\n device.processor_frequency = firstCpu.speed;\n }\n }\n\n return device;\n}\n\n/** Mapping of Node's platform names to actual OS names. */\nconst PLATFORM_NAMES: { [platform: string]: string } = {\n aix: 'IBM AIX',\n freebsd: 'FreeBSD',\n openbsd: 'OpenBSD',\n sunos: 'SunOS',\n win32: 'Windows',\n};\n\n/** Linux version file to check for a distribution. */\ninterface DistroFile {\n /** The file name, located in `/etc`. */\n name: string;\n /** Potential distributions to check. */\n distros: [string, ...string[]];\n}\n\n/** Mapping of linux release files located in /etc to distributions. */\nconst LINUX_DISTROS: DistroFile[] = [\n { name: 'fedora-release', distros: ['Fedora'] },\n { name: 'redhat-release', distros: ['Red Hat Linux', 'Centos'] },\n { name: 'redhat_version', distros: ['Red Hat Linux'] },\n { name: 'SuSE-release', distros: ['SUSE Linux'] },\n { name: 'lsb-release', distros: ['Ubuntu Linux', 'Arch Linux'] },\n { name: 'debian_version', distros: ['Debian'] },\n { name: 'debian_release', distros: ['Debian'] },\n { name: 'arch-release', distros: ['Arch Linux'] },\n { name: 'gentoo-release', distros: ['Gentoo Linux'] },\n { name: 'novell-release', distros: ['SUSE Linux'] },\n { name: 'alpine-release', distros: ['Alpine Linux'] },\n];\n\n/** Functions to extract the OS version from Linux release files. */\nconst LINUX_VERSIONS: {\n [identifier: string]: (content: string) => string | undefined;\n} = {\n alpine: content => content,\n arch: content => matchFirst(/distrib_release=(.*)/, content),\n centos: content => matchFirst(/release ([^ ]+)/, content),\n debian: content => content,\n fedora: content => matchFirst(/release (..)/, content),\n mint: content => matchFirst(/distrib_release=(.*)/, content),\n red: content => matchFirst(/release ([^ ]+)/, content),\n suse: content => matchFirst(/VERSION = (.*)\\n/, content),\n ubuntu: content => matchFirst(/distrib_release=(.*)/, content),\n};\n\n/**\n * Executes a regular expression with one capture group.\n *\n * @param regex A regular expression to execute.\n * @param text Content to execute the RegEx on.\n * @returns The captured string if matched; otherwise undefined.\n */\nfunction matchFirst(regex: RegExp, text: string): string | undefined {\n const match = regex.exec(text);\n return match ? match[1] : undefined;\n}\n\n/** Loads the macOS operating system context. */\nasync function getDarwinInfo(): Promise<OsContext> {\n // Default values that will be used in case no operating system information\n // can be loaded. The default version is computed via heuristics from the\n // kernel version, but the build ID is missing.\n const darwinInfo: OsContext = {\n kernel_version: os.release(),\n name: 'Mac OS X',\n version: `10.${Number(os.release().split('.')[0]) - 4}`,\n };\n\n try {\n // We try to load the actual macOS version by executing the `sw_vers` tool.\n // This tool should be available on every standard macOS installation. In\n // case this fails, we stick with the values computed above.\n\n const output = await new Promise<string>((resolve, reject) => {\n execFile('/usr/bin/sw_vers', (error: Error | null, stdout: string) => {\n if (error) {\n reject(error);\n return;\n }\n resolve(stdout);\n });\n });\n\n darwinInfo.name = matchFirst(/^ProductName:\\s+(.*)$/m, output);\n darwinInfo.version = matchFirst(/^ProductVersion:\\s+(.*)$/m, output);\n darwinInfo.build = matchFirst(/^BuildVersion:\\s+(.*)$/m, output);\n } catch (e) {\n // ignore\n }\n\n return darwinInfo;\n}\n\n/** Returns a distribution identifier to look up version callbacks. */\nfunction getLinuxDistroId(name: string): string {\n return (name.split(' ') as [string])[0].toLowerCase();\n}\n\n/** Loads the Linux operating system context. */\nasync function getLinuxInfo(): Promise<OsContext> {\n // By default, we cannot assume anything about the distribution or Linux\n // version. `os.release()` returns the kernel version and we assume a generic\n // \"Linux\" name, which will be replaced down below.\n const linuxInfo: OsContext = {\n kernel_version: os.release(),\n name: 'Linux',\n };\n\n try {\n // We start guessing the distribution by listing files in the /etc\n // directory. This is were most Linux distributions (except Knoppix) store\n // release files with certain distribution-dependent meta data. We search\n // for exactly one known file defined in `LINUX_DISTROS` and exit if none\n // are found. In case there are more than one file, we just stick with the\n // first one.\n const etcFiles = await readDirAsync('/etc');\n const distroFile = LINUX_DISTROS.find(file => etcFiles.includes(file.name));\n if (!distroFile) {\n return linuxInfo;\n }\n\n // Once that file is known, load its contents. To make searching in those\n // files easier, we lowercase the file contents. Since these files are\n // usually quite small, this should not allocate too much memory and we only\n // hold on to it for a very short amount of time.\n const distroPath = join('/etc', distroFile.name);\n const contents = ((await readFileAsync(distroPath, { encoding: 'utf-8' })) as string).toLowerCase();\n\n // Some Linux distributions store their release information in the same file\n // (e.g. RHEL and Centos). In those cases, we scan the file for an\n // identifier, that basically consists of the first word of the linux\n // distribution name (e.g. \"red\" for Red Hat). In case there is no match, we\n // just assume the first distribution in our list.\n const { distros } = distroFile;\n linuxInfo.name = distros.find(d => contents.indexOf(getLinuxDistroId(d)) >= 0) || distros[0];\n\n // Based on the found distribution, we can now compute the actual version\n // number. This is different for every distribution, so several strategies\n // are computed in `LINUX_VERSIONS`.\n const id = getLinuxDistroId(linuxInfo.name);\n linuxInfo.version = LINUX_VERSIONS[id]?.(contents);\n } catch (e) {\n // ignore\n }\n\n return linuxInfo;\n}\n\n/**\n * Grabs some information about hosting provider based on best effort.\n */\nfunction getCloudResourceContext(): CloudResourceContext | undefined {\n if (process.env.VERCEL) {\n // https://vercel.com/docs/concepts/projects/environment-variables/system-environment-variables#system-environment-variables\n return {\n 'cloud.provider': 'vercel',\n 'cloud.region': process.env.VERCEL_REGION,\n };\n } else if (process.env.AWS_REGION) {\n // https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html\n return {\n 'cloud.provider': 'aws',\n 'cloud.region': process.env.AWS_REGION,\n 'cloud.platform': process.env.AWS_EXECUTION_ENV,\n };\n } else if (process.env.GCP_PROJECT) {\n // https://cloud.google.com/composer/docs/how-to/managing/environment-variables#reserved_variables\n return {\n 'cloud.provider': 'gcp',\n };\n } else if (process.env.ALIYUN_REGION_ID) {\n // TODO: find where I found these environment variables - at least gc.github.com returns something\n return {\n 'cloud.provider': 'alibaba_cloud',\n 'cloud.region': process.env.ALIYUN_REGION_ID,\n };\n } else if (process.env.WEBSITE_SITE_NAME && process.env.REGION_NAME) {\n // https://learn.microsoft.com/en-us/azure/app-service/reference-app-settings?tabs=kudu%2Cdotnet#app-environment\n return {\n 'cloud.provider': 'azure',\n 'cloud.region': process.env.REGION_NAME,\n };\n } else if (process.env.IBM_CLOUD_REGION) {\n // TODO: find where I found these environment variables - at least gc.github.com returns something\n return {\n 'cloud.provider': 'ibm_cloud',\n 'cloud.region': process.env.IBM_CLOUD_REGION,\n };\n } else if (process.env.TENCENTCLOUD_REGION) {\n // https://www.tencentcloud.com/document/product/583/32748\n return {\n 'cloud.provider': 'tencent_cloud',\n 'cloud.region': process.env.TENCENTCLOUD_REGION,\n 'cloud.account.id': process.env.TENCENTCLOUD_APPID,\n 'cloud.availability_zone': process.env.TENCENTCLOUD_ZONE,\n };\n } else if (process.env.NETLIFY) {\n // https://docs.netlify.com/configure-builds/environment-variables/#read-only-variables\n return {\n 'cloud.provider': 'netlify',\n };\n } else if (process.env.FLY_REGION) {\n // https://fly.io/docs/reference/runtime-environment/\n return {\n 'cloud.provider': 'fly.io',\n 'cloud.region': process.env.FLY_REGION,\n };\n } else if (process.env.DYNO) {\n // https://devcenter.heroku.com/articles/dynos#local-environment-variables\n return {\n 'cloud.provider': 'heroku',\n };\n } else {\n return undefined;\n }\n}\n"],"names":["promisify","readFile","readdir","defineIntegration","execFile","join"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"context.js","sources":["../../../src/integrations/context.ts"],"sourcesContent":["/* eslint-disable max-lines */\n\nimport { execFile } from 'node:child_process';\nimport { readFile, readdir } from 'node:fs';\nimport * as os from 'node:os';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\nimport type {\n AppContext,\n CloudResourceContext,\n Contexts,\n CultureContext,\n DeviceContext,\n Event,\n IntegrationFn,\n OsContext,\n} from '@sentry/core';\nimport { defineIntegration } from '@sentry/core';\n\nexport const readFileAsync = promisify(readFile);\nexport const readDirAsync = promisify(readdir);\n\n// Process enhanced with methods from Node 18, 20, 22 as @types/node\n// is on `14.18.0` to match minimum version requirements of the SDK\ninterface ProcessWithCurrentValues extends NodeJS.Process {\n availableMemory?(): number;\n}\n\nconst INTEGRATION_NAME = 'Context';\n\ninterface DeviceContextOptions {\n cpu?: boolean;\n memory?: boolean;\n}\n\ninterface ContextOptions {\n app?: boolean;\n os?: boolean;\n device?: DeviceContextOptions | boolean;\n culture?: boolean;\n cloudResource?: boolean;\n}\n\nconst _nodeContextIntegration = ((options: ContextOptions = {}) => {\n let cachedContext: Promise<Contexts> | undefined;\n\n const _options = {\n app: true,\n os: true,\n device: true,\n culture: true,\n cloudResource: true,\n ...options,\n };\n\n /** Add contexts to the event. Caches the context so we only look it up once. */\n async function addContext(event: Event): Promise<Event> {\n if (cachedContext === undefined) {\n cachedContext = _getContexts();\n }\n\n const updatedContext = _updateContext(await cachedContext);\n\n event.contexts = {\n ...event.contexts,\n app: { ...updatedContext.app, ...event.contexts?.app },\n os: { ...updatedContext.os, ...event.contexts?.os },\n device: { ...updatedContext.device, ...event.contexts?.device },\n culture: { ...updatedContext.culture, ...event.contexts?.culture },\n cloud_resource: { ...updatedContext.cloud_resource, ...event.contexts?.cloud_resource },\n };\n\n return event;\n }\n\n /** Get the contexts from node. */\n async function _getContexts(): Promise<Contexts> {\n const contexts: Contexts = {};\n\n if (_options.os) {\n contexts.os = await getOsContext();\n }\n\n if (_options.app) {\n contexts.app = getAppContext();\n }\n\n if (_options.device) {\n contexts.device = getDeviceContext(_options.device);\n }\n\n if (_options.culture) {\n const culture = getCultureContext();\n\n if (culture) {\n contexts.culture = culture;\n }\n }\n\n if (_options.cloudResource) {\n contexts.cloud_resource = getCloudResourceContext();\n }\n\n return contexts;\n }\n\n return {\n name: INTEGRATION_NAME,\n processEvent(event) {\n return addContext(event);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Capture context about the environment and the device that the client is running on, to events.\n */\nexport const nodeContextIntegration = defineIntegration(_nodeContextIntegration);\n\n/**\n * Updates the context with dynamic values that can change\n */\nfunction _updateContext(contexts: Contexts): Contexts {\n // Only update properties if they exist\n\n if (contexts.app?.app_memory) {\n contexts.app.app_memory = process.memoryUsage().rss;\n }\n\n if (contexts.app?.free_memory && typeof (process as ProcessWithCurrentValues).availableMemory === 'function') {\n const freeMemory = (process as ProcessWithCurrentValues).availableMemory?.();\n if (freeMemory != null) {\n contexts.app.free_memory = freeMemory;\n }\n }\n\n if (contexts.device?.free_memory) {\n contexts.device.free_memory = os.freemem();\n }\n\n return contexts;\n}\n\n/**\n * Returns the operating system context.\n *\n * Based on the current platform, this uses a different strategy to provide the\n * most accurate OS information. Since this might involve spawning subprocesses\n * or accessing the file system, this should only be executed lazily and cached.\n *\n * - On macOS (Darwin), this will execute the `sw_vers` utility. The context\n * has a `name`, `version`, `build` and `kernel_version` set.\n * - On Linux, this will try to load a distribution release from `/etc` and set\n * the `name`, `version` and `kernel_version` fields.\n * - On all other platforms, only a `name` and `version` will be returned. Note\n * that `version` might actually be the kernel version.\n */\nasync function getOsContext(): Promise<OsContext> {\n const platformId = os.platform();\n switch (platformId) {\n case 'darwin':\n return getDarwinInfo();\n case 'linux':\n return getLinuxInfo();\n default:\n return {\n name: PLATFORM_NAMES[platformId] || platformId,\n version: os.release(),\n };\n }\n}\n\nfunction getCultureContext(): CultureContext | undefined {\n try {\n if (typeof process.versions.icu !== 'string') {\n // Node was built without ICU support\n return;\n }\n\n // Check that node was built with full Intl support. Its possible it was built without support for non-English\n // locales which will make resolvedOptions inaccurate\n //\n // https://nodejs.org/api/intl.html#detecting-internationalization-support\n const january = new Date(9e8);\n const spanish = new Intl.DateTimeFormat('es', { month: 'long' });\n if (spanish.format(january) === 'enero') {\n const options = Intl.DateTimeFormat().resolvedOptions();\n\n return {\n locale: options.locale,\n timezone: options.timeZone,\n };\n }\n } catch (err) {\n //\n }\n\n return;\n}\n\n/**\n * Get app context information from process\n */\nexport function getAppContext(): AppContext {\n const app_memory = process.memoryUsage().rss;\n const app_start_time = new Date(Date.now() - process.uptime() * 1000).toISOString();\n // https://nodejs.org/api/process.html#processavailablememory\n const appContext: AppContext = { app_start_time, app_memory };\n\n if (typeof (process as ProcessWithCurrentValues).availableMemory === 'function') {\n const freeMemory = (process as ProcessWithCurrentValues).availableMemory?.();\n if (freeMemory != null) {\n appContext.free_memory = freeMemory;\n }\n }\n\n return appContext;\n}\n\n/**\n * Gets device information from os\n */\nexport function getDeviceContext(deviceOpt: DeviceContextOptions | true): DeviceContext {\n const device: DeviceContext = {};\n\n // Sometimes os.uptime() throws due to lacking permissions: https://github.com/getsentry/sentry-javascript/issues/8202\n let uptime;\n try {\n uptime = os.uptime();\n } catch (e) {\n // noop\n }\n\n // os.uptime or its return value seem to be undefined in certain environments (e.g. Azure functions).\n // Hence, we only set boot time, if we get a valid uptime value.\n // @see https://github.com/getsentry/sentry-javascript/issues/5856\n if (typeof uptime === 'number') {\n device.boot_time = new Date(Date.now() - uptime * 1000).toISOString();\n }\n\n device.arch = os.arch();\n\n if (deviceOpt === true || deviceOpt.memory) {\n device.memory_size = os.totalmem();\n device.free_memory = os.freemem();\n }\n\n if (deviceOpt === true || deviceOpt.cpu) {\n const cpuInfo = os.cpus() as os.CpuInfo[] | undefined;\n const firstCpu = cpuInfo?.[0];\n if (firstCpu) {\n device.processor_count = cpuInfo.length;\n device.cpu_description = firstCpu.model;\n device.processor_frequency = firstCpu.speed;\n }\n }\n\n return device;\n}\n\n/** Mapping of Node's platform names to actual OS names. */\nconst PLATFORM_NAMES: { [platform: string]: string } = {\n aix: 'IBM AIX',\n freebsd: 'FreeBSD',\n openbsd: 'OpenBSD',\n sunos: 'SunOS',\n win32: 'Windows',\n};\n\n/** Linux version file to check for a distribution. */\ninterface DistroFile {\n /** The file name, located in `/etc`. */\n name: string;\n /** Potential distributions to check. */\n distros: [string, ...string[]];\n}\n\n/** Mapping of linux release files located in /etc to distributions. */\nconst LINUX_DISTROS: DistroFile[] = [\n { name: 'fedora-release', distros: ['Fedora'] },\n { name: 'redhat-release', distros: ['Red Hat Linux', 'Centos'] },\n { name: 'redhat_version', distros: ['Red Hat Linux'] },\n { name: 'SuSE-release', distros: ['SUSE Linux'] },\n { name: 'lsb-release', distros: ['Ubuntu Linux', 'Arch Linux'] },\n { name: 'debian_version', distros: ['Debian'] },\n { name: 'debian_release', distros: ['Debian'] },\n { name: 'arch-release', distros: ['Arch Linux'] },\n { name: 'gentoo-release', distros: ['Gentoo Linux'] },\n { name: 'novell-release', distros: ['SUSE Linux'] },\n { name: 'alpine-release', distros: ['Alpine Linux'] },\n];\n\n/** Functions to extract the OS version from Linux release files. */\nconst LINUX_VERSIONS: {\n [identifier: string]: (content: string) => string | undefined;\n} = {\n alpine: content => content,\n arch: content => matchFirst(/distrib_release=(.*)/, content),\n centos: content => matchFirst(/release ([^ ]+)/, content),\n debian: content => content,\n fedora: content => matchFirst(/release (..)/, content),\n mint: content => matchFirst(/distrib_release=(.*)/, content),\n red: content => matchFirst(/release ([^ ]+)/, content),\n suse: content => matchFirst(/VERSION = (.*)\\n/, content),\n ubuntu: content => matchFirst(/distrib_release=(.*)/, content),\n};\n\n/**\n * Executes a regular expression with one capture group.\n *\n * @param regex A regular expression to execute.\n * @param text Content to execute the RegEx on.\n * @returns The captured string if matched; otherwise undefined.\n */\nfunction matchFirst(regex: RegExp, text: string): string | undefined {\n const match = regex.exec(text);\n return match ? match[1] : undefined;\n}\n\n/** Loads the macOS operating system context. */\nasync function getDarwinInfo(): Promise<OsContext> {\n // Default values that will be used in case no operating system information\n // can be loaded. The default version is computed via heuristics from the\n // kernel version, but the build ID is missing.\n const darwinInfo: OsContext = {\n kernel_version: os.release(),\n name: 'Mac OS X',\n version: `10.${Number(os.release().split('.')[0]) - 4}`,\n };\n\n try {\n // We try to load the actual macOS version by executing the `sw_vers` tool.\n // This tool should be available on every standard macOS installation. In\n // case this fails, we stick with the values computed above.\n\n const output = await new Promise<string>((resolve, reject) => {\n execFile('/usr/bin/sw_vers', (error: Error | null, stdout: string) => {\n if (error) {\n reject(error);\n return;\n }\n resolve(stdout);\n });\n });\n\n darwinInfo.name = matchFirst(/^ProductName:\\s+(.*)$/m, output);\n darwinInfo.version = matchFirst(/^ProductVersion:\\s+(.*)$/m, output);\n darwinInfo.build = matchFirst(/^BuildVersion:\\s+(.*)$/m, output);\n } catch (e) {\n // ignore\n }\n\n return darwinInfo;\n}\n\n/** Returns a distribution identifier to look up version callbacks. */\nfunction getLinuxDistroId(name: string): string {\n return (name.split(' ') as [string])[0].toLowerCase();\n}\n\n/** Loads the Linux operating system context. */\nasync function getLinuxInfo(): Promise<OsContext> {\n // By default, we cannot assume anything about the distribution or Linux\n // version. `os.release()` returns the kernel version and we assume a generic\n // \"Linux\" name, which will be replaced down below.\n const linuxInfo: OsContext = {\n kernel_version: os.release(),\n name: 'Linux',\n };\n\n try {\n // We start guessing the distribution by listing files in the /etc\n // directory. This is were most Linux distributions (except Knoppix) store\n // release files with certain distribution-dependent meta data. We search\n // for exactly one known file defined in `LINUX_DISTROS` and exit if none\n // are found. In case there are more than one file, we just stick with the\n // first one.\n const etcFiles = await readDirAsync('/etc');\n const distroFile = LINUX_DISTROS.find(file => etcFiles.includes(file.name));\n if (!distroFile) {\n return linuxInfo;\n }\n\n // Once that file is known, load its contents. To make searching in those\n // files easier, we lowercase the file contents. Since these files are\n // usually quite small, this should not allocate too much memory and we only\n // hold on to it for a very short amount of time.\n const distroPath = join('/etc', distroFile.name);\n const contents = ((await readFileAsync(distroPath, { encoding: 'utf-8' })) as string).toLowerCase();\n\n // Some Linux distributions store their release information in the same file\n // (e.g. RHEL and Centos). In those cases, we scan the file for an\n // identifier, that basically consists of the first word of the linux\n // distribution name (e.g. \"red\" for Red Hat). In case there is no match, we\n // just assume the first distribution in our list.\n const { distros } = distroFile;\n linuxInfo.name = distros.find(d => contents.indexOf(getLinuxDistroId(d)) >= 0) || distros[0];\n\n // Based on the found distribution, we can now compute the actual version\n // number. This is different for every distribution, so several strategies\n // are computed in `LINUX_VERSIONS`.\n const id = getLinuxDistroId(linuxInfo.name);\n linuxInfo.version = LINUX_VERSIONS[id]?.(contents);\n } catch (e) {\n // ignore\n }\n\n return linuxInfo;\n}\n\n/**\n * Grabs some information about hosting provider based on best effort.\n */\nfunction getCloudResourceContext(): CloudResourceContext | undefined {\n if (process.env.VERCEL) {\n // https://vercel.com/docs/concepts/projects/environment-variables/system-environment-variables#system-environment-variables\n return {\n 'cloud.provider': 'vercel',\n 'cloud.region': process.env.VERCEL_REGION,\n };\n } else if (process.env.AWS_REGION) {\n // https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html\n return {\n 'cloud.provider': 'aws',\n 'cloud.region': process.env.AWS_REGION,\n 'cloud.platform': process.env.AWS_EXECUTION_ENV,\n };\n } else if (process.env.GCP_PROJECT) {\n // https://cloud.google.com/composer/docs/how-to/managing/environment-variables#reserved_variables\n return {\n 'cloud.provider': 'gcp',\n };\n } else if (process.env.ALIYUN_REGION_ID) {\n // TODO: find where I found these environment variables - at least gc.github.com returns something\n return {\n 'cloud.provider': 'alibaba_cloud',\n 'cloud.region': process.env.ALIYUN_REGION_ID,\n };\n } else if (process.env.WEBSITE_SITE_NAME && process.env.REGION_NAME) {\n // https://learn.microsoft.com/en-us/azure/app-service/reference-app-settings?tabs=kudu%2Cdotnet#app-environment\n return {\n 'cloud.provider': 'azure',\n 'cloud.region': process.env.REGION_NAME,\n };\n } else if (process.env.IBM_CLOUD_REGION) {\n // TODO: find where I found these environment variables - at least gc.github.com returns something\n return {\n 'cloud.provider': 'ibm_cloud',\n 'cloud.region': process.env.IBM_CLOUD_REGION,\n };\n } else if (process.env.TENCENTCLOUD_REGION) {\n // https://www.tencentcloud.com/document/product/583/32748\n return {\n 'cloud.provider': 'tencent_cloud',\n 'cloud.region': process.env.TENCENTCLOUD_REGION,\n 'cloud.account.id': process.env.TENCENTCLOUD_APPID,\n 'cloud.availability_zone': process.env.TENCENTCLOUD_ZONE,\n };\n } else if (process.env.NETLIFY) {\n // https://docs.netlify.com/configure-builds/environment-variables/#read-only-variables\n return {\n 'cloud.provider': 'netlify',\n };\n } else if (process.env.FLY_REGION) {\n // https://fly.io/docs/reference/runtime-environment/\n return {\n 'cloud.provider': 'fly.io',\n 'cloud.region': process.env.FLY_REGION,\n };\n } else if (process.env.DYNO) {\n // https://devcenter.heroku.com/articles/dynos#local-environment-variables\n return {\n 'cloud.provider': 'heroku',\n };\n } else {\n return undefined;\n }\n}\n"],"names":["promisify","readFile","readdir","defineIntegration","execFile","join"],"mappings":"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"}
|