@sentry/node 9.9.0 → 9.10.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 +2 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/integrations/anr/index.js +1 -1
- package/build/cjs/integrations/console.js +1 -1
- package/build/cjs/integrations/console.js.map +1 -1
- package/build/cjs/integrations/local-variables/local-variables-async.js +1 -1
- package/build/cjs/integrations/tracing/connect.js +1 -1
- package/build/cjs/integrations/tracing/connect.js.map +1 -1
- package/build/cjs/integrations/tracing/dataloader.js +24 -18
- package/build/cjs/integrations/tracing/dataloader.js.map +1 -1
- package/build/cjs/integrations/tracing/genericPool.js +16 -11
- package/build/cjs/integrations/tracing/genericPool.js.map +1 -1
- package/build/cjs/integrations/tracing/knex.js +14 -9
- package/build/cjs/integrations/tracing/knex.js.map +1 -1
- package/build/cjs/integrations/tracing/prisma.js +19 -7
- package/build/cjs/integrations/tracing/prisma.js.map +1 -1
- package/build/cjs/integrations/tracing/tedious.js +18 -13
- package/build/cjs/integrations/tracing/tedious.js.map +1 -1
- package/build/cjs/integrations/tracing/vercelai/index.js +135 -134
- package/build/cjs/integrations/tracing/vercelai/index.js.map +1 -1
- package/build/cjs/integrations/tracing/vercelai/instrumentation.js +20 -5
- package/build/cjs/integrations/tracing/vercelai/instrumentation.js.map +1 -1
- package/build/cjs/log.js +200 -0
- package/build/cjs/log.js.map +1 -0
- package/build/cjs/otel/instrument.js +54 -3
- package/build/cjs/otel/instrument.js.map +1 -1
- package/build/cjs/sdk/index.js +15 -33
- package/build/cjs/sdk/index.js.map +1 -1
- package/build/esm/index.js +2 -0
- package/build/esm/index.js.map +1 -1
- package/build/esm/integrations/anr/index.js +1 -1
- package/build/esm/integrations/anr/worker-script.js +2 -2
- package/build/esm/integrations/console.js +2 -2
- package/build/esm/integrations/console.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/tracing/connect.js +1 -1
- package/build/esm/integrations/tracing/connect.js.map +1 -1
- package/build/esm/integrations/tracing/dataloader.js +26 -20
- package/build/esm/integrations/tracing/dataloader.js.map +1 -1
- package/build/esm/integrations/tracing/genericPool.js +17 -12
- package/build/esm/integrations/tracing/genericPool.js.map +1 -1
- package/build/esm/integrations/tracing/knex.js +15 -10
- package/build/esm/integrations/tracing/knex.js.map +1 -1
- package/build/esm/integrations/tracing/prisma.js +19 -7
- package/build/esm/integrations/tracing/prisma.js.map +1 -1
- package/build/esm/integrations/tracing/tedious.js +19 -14
- package/build/esm/integrations/tracing/tedious.js.map +1 -1
- package/build/esm/integrations/tracing/vercelai/index.js +136 -135
- package/build/esm/integrations/tracing/vercelai/index.js.map +1 -1
- package/build/esm/integrations/tracing/vercelai/instrumentation.js +21 -6
- package/build/esm/integrations/tracing/vercelai/instrumentation.js.map +1 -1
- package/build/esm/log.js +193 -0
- package/build/esm/log.js.map +1 -0
- package/build/esm/otel/instrument.js +54 -4
- package/build/esm/otel/instrument.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/sdk/index.js +16 -34
- package/build/esm/sdk/index.js.map +1 -1
- package/build/types/index.d.ts +2 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/types/integrations/console.d.ts.map +1 -1
- package/build/types/integrations/http/index.d.ts +1 -1
- package/build/types/integrations/tracing/amqplib.d.ts +2 -1
- package/build/types/integrations/tracing/amqplib.d.ts.map +1 -1
- package/build/types/integrations/tracing/connect.d.ts +2 -1
- package/build/types/integrations/tracing/connect.d.ts.map +1 -1
- package/build/types/integrations/tracing/dataloader.d.ts +2 -1
- package/build/types/integrations/tracing/dataloader.d.ts.map +1 -1
- package/build/types/integrations/tracing/express.d.ts +4 -2
- package/build/types/integrations/tracing/express.d.ts.map +1 -1
- package/build/types/integrations/tracing/fastify.d.ts +2 -1
- package/build/types/integrations/tracing/fastify.d.ts.map +1 -1
- package/build/types/integrations/tracing/genericPool.d.ts +2 -1
- package/build/types/integrations/tracing/genericPool.d.ts.map +1 -1
- package/build/types/integrations/tracing/graphql.d.ts +1 -1
- package/build/types/integrations/tracing/hapi/index.d.ts +2 -1
- package/build/types/integrations/tracing/hapi/index.d.ts.map +1 -1
- package/build/types/integrations/tracing/kafka.d.ts +2 -1
- package/build/types/integrations/tracing/kafka.d.ts.map +1 -1
- package/build/types/integrations/tracing/knex.d.ts +2 -1
- package/build/types/integrations/tracing/knex.d.ts.map +1 -1
- package/build/types/integrations/tracing/koa.d.ts +2 -1
- package/build/types/integrations/tracing/koa.d.ts.map +1 -1
- package/build/types/integrations/tracing/lrumemoizer.d.ts +2 -1
- package/build/types/integrations/tracing/lrumemoizer.d.ts.map +1 -1
- package/build/types/integrations/tracing/mongo.d.ts +2 -1
- package/build/types/integrations/tracing/mongo.d.ts.map +1 -1
- package/build/types/integrations/tracing/mongoose.d.ts +2 -1
- package/build/types/integrations/tracing/mongoose.d.ts.map +1 -1
- package/build/types/integrations/tracing/mysql.d.ts +2 -1
- package/build/types/integrations/tracing/mysql.d.ts.map +1 -1
- package/build/types/integrations/tracing/mysql2.d.ts +2 -1
- package/build/types/integrations/tracing/mysql2.d.ts.map +1 -1
- package/build/types/integrations/tracing/postgres.d.ts +2 -1
- package/build/types/integrations/tracing/postgres.d.ts.map +1 -1
- package/build/types/integrations/tracing/prisma.d.ts +1 -1
- package/build/types/integrations/tracing/prisma.d.ts.map +1 -1
- package/build/types/integrations/tracing/tedious.d.ts +2 -1
- package/build/types/integrations/tracing/tedious.d.ts.map +1 -1
- package/build/types/integrations/tracing/vercelai/index.d.ts +2 -1
- package/build/types/integrations/tracing/vercelai/index.d.ts.map +1 -1
- package/build/types/integrations/tracing/vercelai/instrumentation.d.ts +7 -1
- package/build/types/integrations/tracing/vercelai/instrumentation.d.ts.map +1 -1
- package/build/types/log.d.ts +151 -0
- package/build/types/log.d.ts.map +1 -0
- package/build/types/otel/instrument.d.ts +14 -1
- package/build/types/otel/instrument.d.ts.map +1 -1
- package/build/types/sdk/index.d.ts.map +1 -1
- package/build/types-ts3.8/index.d.ts +2 -0
- package/build/types-ts3.8/integrations/http/index.d.ts +1 -1
- package/build/types-ts3.8/integrations/tracing/amqplib.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/connect.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/dataloader.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/express.d.ts +4 -2
- package/build/types-ts3.8/integrations/tracing/fastify.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/genericPool.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/graphql.d.ts +1 -1
- package/build/types-ts3.8/integrations/tracing/hapi/index.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/kafka.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/knex.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/koa.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/lrumemoizer.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/mongo.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/mongoose.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/mysql.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/mysql2.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/postgres.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/prisma.d.ts +1 -1
- package/build/types-ts3.8/integrations/tracing/tedious.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/vercelai/index.d.ts +2 -1
- package/build/types-ts3.8/integrations/tracing/vercelai/instrumentation.d.ts +7 -1
- package/build/types-ts3.8/log.d.ts +158 -0
- package/build/types-ts3.8/otel/instrument.d.ts +14 -1
- package/package.json +3 -3
package/build/cjs/index.js
CHANGED
|
@@ -46,6 +46,7 @@ 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 log = require('./log.js');
|
|
49
50
|
|
|
50
51
|
|
|
51
52
|
|
|
@@ -175,4 +176,5 @@ exports.withIsolationScope = core.withIsolationScope;
|
|
|
175
176
|
exports.withMonitor = core.withMonitor;
|
|
176
177
|
exports.withScope = core.withScope;
|
|
177
178
|
exports.zodErrorsIntegration = core.zodErrorsIntegration;
|
|
179
|
+
exports.logger = log;
|
|
178
180
|
//# 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -9,7 +9,7 @@ const debug = require('../../utils/debug.js');
|
|
|
9
9
|
const { isPromise } = util.types;
|
|
10
10
|
|
|
11
11
|
// This string is a placeholder that gets overwritten with the worker code.
|
|
12
|
-
const base64WorkerScript = 'LyohIEBzZW50cnkvbm9kZSA5LjkuMCAoNDNjNGM4MykgfCBodHRwczovL2dpdGh1Yi5jb20vZ2V0c2VudHJ5L3NlbnRyeS1qYXZhc2NyaXB0ICovCmltcG9ydHtTZXNzaW9uIGFzIHR9ZnJvbSJub2RlOmluc3BlY3RvciI7aW1wb3J0e3dvcmtlckRhdGEgYXMgbixwYXJlbnRQb3J0IGFzIGV9ZnJvbSJub2RlOndvcmtlcl90aHJlYWRzIjtpbXBvcnR7cG9zaXggYXMgcixzZXAgYXMgb31mcm9tIm5vZGU6cGF0aCI7aW1wb3J0KmFzIHMgZnJvbSJub2RlOmh0dHAiO2ltcG9ydCphcyBpIGZyb20ibm9kZTpodHRwcyI7aW1wb3J0e1JlYWRhYmxlIGFzIGN9ZnJvbSJub2RlOnN0cmVhbSI7aW1wb3J0e2NyZWF0ZUd6aXAgYXMgdX1mcm9tIm5vZGU6emxpYiI7aW1wb3J0KmFzIGEgZnJvbSJub2RlOm5ldCI7aW1wb3J0KmFzIGYgZnJvbSJub2RlOnRscyI7Y29uc3QgaD0idW5kZWZpbmVkIj09dHlwZW9mIF9fU0VOVFJZX0RFQlVHX198fF9fU0VOVFJZX0RFQlVHX18scD1nbG9iYWxUaGlzLGw9InVuZGVmaW5lZCI9PXR5cGVvZiBfX1NFTlRSWV9ERUJVR19ffHxfX1NFTlRSWV9ERUJVR19fLGQ9IjkuOS4wIjtmdW5jdGlvbiBtKCl7cmV0dXJuIGcocCkscH1mdW5jdGlvbiBnKHQpe2NvbnN0IG49dC5fX1NFTlRSWV9fPXQuX19TRU5UUllfX3x8e307cmV0dXJuIG4udmVyc2lvbj1uLnZlcnNpb258fGQsbltkXT1uW2RdfHx7fX1mdW5jdGlvbiB5KHQsbixlPXApe2NvbnN0IHI9ZS5fX1NFTlRSWV9fPWUuX19TRU5UUllfX3x8e30sbz1yW2RdPXJbZF18fHt9O3JldHVybiBvW3RdfHwob1t0XT1uKCkpfWNvbnN0IGI9WyJkZWJ1ZyIsImluZm8iLCJ3YXJuIiwiZXJyb3IiLCJsb2ciLCJhc3NlcnQiLCJ0cmFjZSJdLF89e307ZnVuY3Rpb24gdih0KXtpZighKCJjb25zb2xlImluIHApKXJldHVybiB0KCk7Y29uc3Qgbj1wLmNvbnNvbGUsZT17fSxyPU9iamVjdC5rZXlzKF8pO3IuZm9yRWFjaCgodD0+e2NvbnN0IHI9X1t0XTtlW3RdPW5bdF0sblt0XT1yfSkpO3RyeXtyZXR1cm4gdCgpfWZpbmFsbHl7ci5mb3JFYWNoKCh0PT57blt0XT1lW3RdfSkpfX1jb25zdCB3PXkoImxvZ2dlciIsKGZ1bmN0aW9uKCl7bGV0IHQ9ITE7Y29uc3Qgbj17ZW5hYmxlOigpPT57dD0hMH0sZGlzYWJsZTooKT0+e3Q9ITF9LGlzRW5hYmxlZDooKT0+dH07cmV0dXJuIGw/Yi5mb3JFYWNoKChlPT57bltlXT0oLi4ubik9Pnt0JiZ2KCgoKT0+e3AuY29uc29sZVtlXShgU2VudHJ5IExvZ2dlciBbJHtlfV06YCwuLi5uKX0pKX19KSk6Yi5mb3JFYWNoKCh0PT57blt0XT0oKT0+e319KSksbn0pKSxTPTUwLCQ9Ij8iLEU9L2NhcHR1cmVNZXNzYWdlfGNhcHR1cmVFeGNlcHRpb24vO2Z1bmN0aW9uIHgodCl7cmV0dXJuIHRbdC5sZW5ndGgtMV18fHt9fWNvbnN0IE49Ijxhbm9ueW1vdXM+Ijtjb25zdCBUPTFlMztmdW5jdGlvbiBDKCl7cmV0dXJuIERhdGUubm93KCkvVH1jb25zdCBqPWZ1bmN0aW9uKCl7Y29uc3R7cGVyZm9ybWFuY2U6dH09cDtpZighdD8ubm93KXJldHVybiBDO2NvbnN0IG49RGF0ZS5ub3coKS10Lm5vdygpLGU9bnVsbD09dC50aW1lT3JpZ2luP246dC50aW1lT3JpZ2luO3JldHVybigpPT4oZSt0Lm5vdygpKS9UfSgpLFI9T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztmdW5jdGlvbiBrKHQsbil7cmV0dXJuIFIuY2FsbCh0KT09PWBbb2JqZWN0ICR7bn1dYH1mdW5jdGlvbiBPKHQpe3JldHVybiBrKHQsIlN0cmluZyIpfWZ1bmN0aW9uIEQodCl7cmV0dXJuIGsodCwiT2JqZWN0Iil9ZnVuY3Rpb24gSSh0KXtyZXR1cm4gQm9vbGVhbih0Py50aGVuJiYiZnVuY3Rpb24iPT10eXBlb2YgdC50aGVuKX1mdW5jdGlvbiBBKHQsbil7dHJ5e3JldHVybiB0IGluc3RhbmNlb2Ygbn1jYXRjaCh0KXtyZXR1cm4hMX19Y29uc3QgUD1wLFU9ODA7ZnVuY3Rpb24gTSh0LG4pe2NvbnN0IGU9dCxyPVtdO2lmKCFlPy50YWdOYW1lKXJldHVybiIiO2lmKFAuSFRNTEVsZW1lbnQmJmUgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCYmZS5kYXRhc2V0KXtpZihlLmRhdGFzZXQuc2VudHJ5Q29tcG9uZW50KXJldHVybiBlLmRhdGFzZXQuc2VudHJ5Q29tcG9uZW50O2lmKGUuZGF0YXNldC5zZW50cnlFbGVtZW50KXJldHVybiBlLmRhdGFzZXQuc2VudHJ5RWxlbWVudH1yLnB1c2goZS50YWdOYW1lLnRvTG93ZXJDYXNlKCkpO2NvbnN0IG89bj8ubGVuZ3RoP24uZmlsdGVyKCh0PT5lLmdldEF0dHJpYnV0ZSh0KSkpLm1hcCgodD0+W3QsZS5nZXRBdHRyaWJ1dGUodCldKSk6bnVsbDtpZihvPy5sZW5ndGgpby5mb3JFYWNoKCh0PT57ci5wdXNoKGBbJHt0WzBdfT0iJHt0WzFdfSJdYCl9KSk7ZWxzZXtlLmlkJiZyLnB1c2goYCMke2UuaWR9YCk7Y29uc3QgdD1lLmNsYXNzTmFtZTtpZih0JiZPKHQpKXtjb25zdCBuPXQuc3BsaXQoL1xzKy8pO2Zvcihjb25zdCB0IG9mIG4pci5wdXNoKGAuJHt0fWApfX1jb25zdCBzPVsiYXJpYS1sYWJlbCIsInR5cGUiLCJuYW1lIiwidGl0bGUiLCJhbHQiXTtmb3IoY29uc3QgdCBvZiBzKXtjb25zdCBuPWUuZ2V0QXR0cmlidXRlKHQpO24mJnIucHVzaChgWyR7dH09IiR7bn0iXWApfXJldHVybiByLmpvaW4oIiIpfWZ1bmN0aW9uIEwodCl7aWYoZnVuY3Rpb24odCl7c3dpdGNoKFIuY2FsbCh0KSl7Y2FzZSJbb2JqZWN0IEVycm9yXSI6Y2FzZSJbb2JqZWN0IEV4Y2VwdGlvbl0iOmNhc2UiW29iamVjdCBET01FeGNlcHRpb25dIjpjYXNlIltvYmplY3QgV2ViQXNzZW1ibHkuRXhjZXB0aW9uXSI6cmV0dXJuITA7ZGVmYXVsdDpyZXR1cm4gQSh0LEVycm9yKX19KHQpKXJldHVybnttZXNzYWdlOnQubWVzc2FnZSxuYW1lOnQubmFtZSxzdGFjazp0LnN0YWNrLC4uLkcodCl9O2lmKG49dCwidW5kZWZpbmVkIiE9dHlwZW9mIEV2ZW50JiZBKG4sRXZlbnQpKXtjb25zdCBuPXt0eXBlOnQudHlwZSx0YXJnZXQ6Qih0LnRhcmdldCksY3VycmVudFRhcmdldDpCKHQuY3VycmVudFRhcmdldCksLi4uRyh0KX07cmV0dXJuInVuZGVmaW5lZCIhPXR5cGVvZiBDdXN0b21FdmVudCYmQSh0LEN1c3RvbUV2ZW50KSYmKG4uZGV0YWlsPXQuZGV0YWlsKSxufXJldHVybiB0O3ZhciBufWZ1bmN0aW9uIEIodCl7dHJ5e3JldHVybiBuPXQsInVuZGVmaW5lZCIhPXR5cGVvZiBFbGVtZW50JiZBKG4sRWxlbWVudCk/ZnVuY3Rpb24odCxuPXt9KXtpZighdClyZXR1cm4iPHVua25vd24+Ijt0cnl7bGV0IGU9dDtjb25zdCByPTUsbz1bXTtsZXQgcz0wLGk9MDtjb25zdCBjPSIgPiAiLHU9Yy5sZW5ndGg7bGV0IGE7Y29uc3QgZj1BcnJheS5pc0FycmF5KG4pP246bi5rZXlBdHRycyxoPSFBcnJheS5pc0FycmF5KG4pJiZuLm1heFN0cmluZ0xlbmd0aHx8VTtmb3IoO2UmJnMrKzxyJiYoYT1NKGUsZiksISgiaHRtbCI9PT1hfHxzPjEmJmkrby5sZW5ndGgqdSthLmxlbmd0aD49aCkpOylvLnB1c2goYSksaSs9YS5sZW5ndGgsZT1lLnBhcmVudE5vZGU7cmV0dXJuIG8ucmV2ZXJzZSgpLmpvaW4oYyl9Y2F0Y2godCl7cmV0dXJuIjx1bmtub3duPiJ9fSh0KTpPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodCl9Y2F0Y2godCl7cmV0dXJuIjx1bmtub3duPiJ9dmFyIG59ZnVuY3Rpb24gRyh0KXtpZigib2JqZWN0Ij09dHlwZW9mIHQmJm51bGwhPT10KXtjb25zdCBuPXt9O2Zvcihjb25zdCBlIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQsZSkmJihuW2VdPXRbZV0pO3JldHVybiBufXJldHVybnt9fWZ1bmN0aW9uIEoodCl7cmV0dXJuIFkodCxuZXcgTWFwKX1mdW5jdGlvbiBZKHQsbil7aWYobnVsbD09PXR8fCJvYmplY3QiIT10eXBlb2YgdClyZXR1cm4gdDtjb25zdCBlPW4uZ2V0KHQpO2lmKHZvaWQgMCE9PWUpcmV0dXJuIGU7aWYoQXJyYXkuaXNBcnJheSh0KSl7Y29uc3QgZT1bXTtyZXR1cm4gbi5zZXQodCxlKSx0LmZvckVhY2goKHQ9PntlLnB1c2goWSh0LG4pKX0pKSxlfWlmKGZ1bmN0aW9uKHQpe2NvbnN0IG49dC5jb25zdHJ1Y3RvcjtyZXR1cm4gbj09PU9iamVjdHx8dm9pZCAwPT09bn0odCkpe2NvbnN0IGU9e307bi5zZXQodCxlKTtyZXR1cm4gT2JqZWN0LmtleXModCkuZm9yRWFjaCgocj0+e2NvbnN0IG89dFtyXTt2b2lkIDAhPT1vJiYoZVtyXT1ZKG8sbikpfSkpLGV9cmV0dXJuIHR9ZnVuY3Rpb24geih0PWZ1bmN0aW9uKCl7Y29uc3QgdD1wO3JldHVybiB0LmNyeXB0b3x8dC5tc0NyeXB0b30oKSl7bGV0IG49KCk9PjE2Kk1hdGgucmFuZG9tKCk7dHJ5e2lmKHQ/LnJhbmRvbVVVSUQpcmV0dXJuIHQucmFuZG9tVVVJRCgpLnJlcGxhY2UoLy0vZywiIik7dD8uZ2V0UmFuZG9tVmFsdWVzJiYobj0oKT0+e2NvbnN0IG49bmV3IFVpbnQ4QXJyYXkoMSk7cmV0dXJuIHQuZ2V0UmFuZG9tVmFsdWVzKG4pLG5bMF19KX1jYXRjaCh0KXt9cmV0dXJuKFsxZTddKzFlMys0ZTMrOGUzKzFlMTEpLnJlcGxhY2UoL1swMThdL2csKHQ9Pih0XigxNSZuKCkpPj50LzQpLnRvU3RyaW5nKDE2KSkpfXZhciBIO2Z1bmN0aW9uIFcodCl7cmV0dXJuIG5ldyBGKChuPT57bih0KX0pKX0hZnVuY3Rpb24odCl7dFt0LlBFTkRJTkc9MF09IlBFTkRJTkciO3RbdC5SRVNPTFZFRD0xXT0iUkVTT0xWRUQiO3RbdC5SRUpFQ1RFRD0yXT0iUkVKRUNURUQifShIfHwoSD17fSkpO2NsYXNzIEZ7Y29uc3RydWN0b3IodCl7dGhpcy50PUguUEVORElORyx0aGlzLm89W10sdGhpcy5pKHQpfXRoZW4odCxuKXtyZXR1cm4gbmV3IEYoKChlLHIpPT57dGhpcy5vLnB1c2goWyExLG49PntpZih0KXRyeXtlKHQobikpfWNhdGNoKHQpe3IodCl9ZWxzZSBlKG4pfSx0PT57aWYobil0cnl7ZShuKHQpKX1jYXRjaCh0KXtyKHQpfWVsc2Ugcih0KX1dKSx0aGlzLnUoKX0pKX1jYXRjaCh0KXtyZXR1cm4gdGhpcy50aGVuKCh0PT50KSx0KX1maW5hbGx5KHQpe3JldHVybiBuZXcgRigoKG4sZSk9PntsZXQgcixvO3JldHVybiB0aGlzLnRoZW4oKG49PntvPSExLHI9bix0JiZ0KCl9KSwobj0+e289ITAscj1uLHQmJnQoKX0pKS50aGVuKCgoKT0+e28/ZShyKTpuKHIpfSkpfSkpfXUoKXtpZih0aGlzLnQ9PT1ILlBFTkRJTkcpcmV0dXJuO2NvbnN0IHQ9dGhpcy5vLnNsaWNlKCk7dGhpcy5vPVtdLHQuZm9yRWFjaCgodD0+e3RbMF18fCh0aGlzLnQ9PT1ILlJFU09MVkVEJiZ0WzFdKHRoaXMuaCksdGhpcy50PT09SC5SRUpFQ1RFRCYmdFsyXSh0aGlzLmgpLHRbMF09ITApfSkpfWkodCl7Y29uc3Qgbj0odCxuKT0+e3RoaXMudD09PUguUEVORElORyYmKEkobik/bi50aGVuKGUscik6KHRoaXMudD10LHRoaXMuaD1uLHRoaXMudSgpKSl9LGU9dD0+e24oSC5SRVNPTFZFRCx0KX0scj10PT57bihILlJFSkVDVEVELHQpfTt0cnl7dChlLHIpfWNhdGNoKHQpe3IodCl9fX1mdW5jdGlvbiBLKHQpe2NvbnN0IG49aigpLGU9e3NpZDp6KCksaW5pdDohMCx0aW1lc3RhbXA6bixzdGFydGVkOm4sZHVyYXRpb246MCxzdGF0dXM6Im9rIixlcnJvcnM6MCxpZ25vcmVEdXJhdGlvbjohMSx0b0pTT046KCk9PmZ1bmN0aW9uKHQpe3JldHVybntzaWQ6YCR7dC5zaWR9YCxpbml0OnQuaW5pdCxzdGFydGVkOm5ldyBEYXRlKDFlMyp0LnN0YXJ0ZWQpLnRvSVNPU3RyaW5nKCksdGltZXN0YW1wOm5ldyBEYXRlKDFlMyp0LnRpbWVzdGFtcCkudG9JU09TdHJpbmcoKSxzdGF0dXM6dC5zdGF0dXMsZXJyb3JzOnQuZXJyb3JzLGRpZDoibnVtYmVyIj09dHlwZW9mIHQuZGlkfHwic3RyaW5nIj09dHlwZW9mIHQuZGlkP2Ake3QuZGlkfWA6dm9pZCAwLGR1cmF0aW9uOnQuZHVyYXRpb24sYWJub3JtYWxfbWVjaGFuaXNtOnQuYWJub3JtYWxfbWVjaGFuaXNtLGF0dHJzOntyZWxlYXNlOnQucmVsZWFzZSxlbnZpcm9ubWVudDp0LmVudmlyb25tZW50LGlwX2FkZHJlc3M6dC5pcEFkZHJlc3MsdXNlcl9hZ2VudDp0LnVzZXJBZ2VudH19fShlKX07cmV0dXJuIHQmJlYoZSx0KSxlfWZ1bmN0aW9uIFYodCxuPXt9KXtpZihuLnVzZXImJighdC5pcEFkZHJlc3MmJm4udXNlci5pcF9hZGRyZXNzJiYodC5pcEFkZHJlc3M9bi51c2VyLmlwX2FkZHJlc3MpLHQuZGlkfHxuLmRpZHx8KHQuZGlkPW4udXNlci5pZHx8bi51c2VyLmVtYWlsfHxuLnVzZXIudXNlcm5hbWUpKSx0LnRpbWVzdGFtcD1uLnRpbWVzdGFtcHx8aigpLG4uYWJub3JtYWxfbWVjaGFuaXNtJiYodC5hYm5vcm1hbF9tZWNoYW5pc209bi5hYm5vcm1hbF9tZWNoYW5pc20pLG4uaWdub3JlRHVyYXRpb24mJih0Lmlnbm9yZUR1cmF0aW9uPW4uaWdub3JlRHVyYXRpb24pLG4uc2lkJiYodC5zaWQ9MzI9PT1uLnNpZC5sZW5ndGg/bi5zaWQ6eigpKSx2b2lkIDAhPT1uLmluaXQmJih0LmluaXQ9bi5pbml0KSwhdC5kaWQmJm4uZGlkJiYodC5kaWQ9YCR7bi5kaWR9YCksIm51bWJlciI9PXR5cGVvZiBuLnN0YXJ0ZWQmJih0LnN0YXJ0ZWQ9bi5zdGFydGVkKSx0Lmlnbm9yZUR1cmF0aW9uKXQuZHVyYXRpb249dm9pZCAwO2Vsc2UgaWYoIm51bWJlciI9PXR5cGVvZiBuLmR1cmF0aW9uKXQuZHVyYXRpb249bi5kdXJhdGlvbjtlbHNle2NvbnN0IG49dC50aW1lc3RhbXAtdC5zdGFydGVkO3QuZHVyYXRpb249bj49MD9uOjB9bi5yZWxlYXNlJiYodC5yZWxlYXNlPW4ucmVsZWFzZSksbi5lbnZpcm9ubWVudCYmKHQuZW52aXJvbm1lbnQ9bi5lbnZpcm9ubWVudCksIXQuaXBBZGRyZXNzJiZuLmlwQWRkcmVzcyYmKHQuaXBBZGRyZXNzPW4uaXBBZGRyZXNzKSwhdC51c2VyQWdlbnQmJm4udXNlckFnZW50JiYodC51c2VyQWdlbnQ9bi51c2VyQWdlbnQpLCJudW1iZXIiPT10eXBlb2Ygbi5lcnJvcnMmJih0LmVycm9ycz1uLmVycm9ycyksbi5zdGF0dXMmJih0LnN0YXR1cz1uLnN0YXR1cyl9ZnVuY3Rpb24gWigpe3JldHVybiB6KCl9ZnVuY3Rpb24gcSgpe3JldHVybiB6KCkuc3Vic3RyaW5nKDE2KX1mdW5jdGlvbiBRKHQsbixlPTIpe2lmKCFufHwib2JqZWN0IiE9dHlwZW9mIG58fGU8PTApcmV0dXJuIG47aWYodCYmMD09PU9iamVjdC5rZXlzKG4pLmxlbmd0aClyZXR1cm4gdDtjb25zdCByPXsuLi50fTtmb3IoY29uc3QgdCBpbiBuKU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChuLHQpJiYoclt0XT1RKHJbdF0sblt0XSxlLTEpKTtyZXR1cm4gcn1jb25zdCBYPSJfc2VudHJ5U3BhbiI7ZnVuY3Rpb24gdHQodCxuKXtuP2Z1bmN0aW9uKHQsbixlKXt0cnl7T2JqZWN0LmRlZmluZVByb3BlcnR5KHQsbix7dmFsdWU6ZSx3cml0YWJsZTohMCxjb25maWd1cmFibGU6ITB9KX1jYXRjaChlKXtsJiZ3LmxvZyhgRmFpbGVkIHRvIGFkZCBub24tZW51bWVyYWJsZSBwcm9wZXJ0eSAiJHtufSIgdG8gb2JqZWN0YCx0KX19KHQsWCxuKTpkZWxldGUgdFtYXX1mdW5jdGlvbiBudCh0KXtyZXR1cm4gdFtYXX1jbGFzcyBldHtjb25zdHJ1Y3Rvcigpe3RoaXMucD0hMSx0aGlzLmw9W10sdGhpcy5tPVtdLHRoaXMuXz1bXSx0aGlzLnY9W10sdGhpcy5TPXt9LHRoaXMuTj17fSx0aGlzLlQ9e30sdGhpcy5DPXt9LHRoaXMuaj17fSx0aGlzLlI9e3RyYWNlSWQ6WigpLHNhbXBsZVJhbmQ6TWF0aC5yYW5kb20oKX19Y2xvbmUoKXtjb25zdCB0PW5ldyBldDtyZXR1cm4gdC5fPVsuLi50aGlzLl9dLHQuTj17Li4udGhpcy5OfSx0LlQ9ey4uLnRoaXMuVH0sdC5DPXsuLi50aGlzLkN9LHRoaXMuQy5mbGFncyYmKHQuQy5mbGFncz17dmFsdWVzOlsuLi50aGlzLkMuZmxhZ3MudmFsdWVzXX0pLHQuUz10aGlzLlMsdC5rPXRoaXMuayx0Lk89dGhpcy5PLHQuRD10aGlzLkQsdC5JPXRoaXMuSSx0Lm09Wy4uLnRoaXMubV0sdC52PVsuLi50aGlzLnZdLHQuaj17Li4udGhpcy5qfSx0LlI9ey4uLnRoaXMuUn0sdC5BPXRoaXMuQSx0LlA9dGhpcy5QLHR0KHQsbnQodGhpcykpLHR9c2V0Q2xpZW50KHQpe3RoaXMuQT10fXNldExhc3RFdmVudElkKHQpe3RoaXMuUD10fWdldENsaWVudCgpe3JldHVybiB0aGlzLkF9bGFzdEV2ZW50SWQoKXtyZXR1cm4gdGhpcy5QfWFkZFNjb3BlTGlzdGVuZXIodCl7dGhpcy5sLnB1c2godCl9YWRkRXZlbnRQcm9jZXNzb3IodCl7cmV0dXJuIHRoaXMubS5wdXNoKHQpLHRoaXN9c2V0VXNlcih0KXtyZXR1cm4gdGhpcy5TPXR8fHtlbWFpbDp2b2lkIDAsaWQ6dm9pZCAwLGlwX2FkZHJlc3M6dm9pZCAwLHVzZXJuYW1lOnZvaWQgMH0sdGhpcy5PJiZWKHRoaXMuTyx7dXNlcjp0fSksdGhpcy5VKCksdGhpc31nZXRVc2VyKCl7cmV0dXJuIHRoaXMuU31zZXRUYWdzKHQpe3JldHVybiB0aGlzLk49ey4uLnRoaXMuTiwuLi50fSx0aGlzLlUoKSx0aGlzfXNldFRhZyh0LG4pe3JldHVybiB0aGlzLk49ey4uLnRoaXMuTixbdF06bn0sdGhpcy5VKCksdGhpc31zZXRFeHRyYXModCl7cmV0dXJuIHRoaXMuVD17Li4udGhpcy5ULC4uLnR9LHRoaXMuVSgpLHRoaXN9c2V0RXh0cmEodCxuKXtyZXR1cm4gdGhpcy5UPXsuLi50aGlzLlQsW3RdOm59LHRoaXMuVSgpLHRoaXN9c2V0RmluZ2VycHJpbnQodCl7cmV0dXJuIHRoaXMuST10LHRoaXMuVSgpLHRoaXN9c2V0TGV2ZWwodCl7cmV0dXJuIHRoaXMuaz10LHRoaXMuVSgpLHRoaXN9c2V0VHJhbnNhY3Rpb25OYW1lKHQpe3JldHVybiB0aGlzLkQ9dCx0aGlzLlUoKSx0aGlzfXNldENvbnRleHQodCxuKXtyZXR1cm4gbnVsbD09PW4/ZGVsZXRlIHRoaXMuQ1t0XTp0aGlzLkNbdF09bix0aGlzLlUoKSx0aGlzfXNldFNlc3Npb24odCl7cmV0dXJuIHQ/dGhpcy5PPXQ6ZGVsZXRlIHRoaXMuTyx0aGlzLlUoKSx0aGlzfWdldFNlc3Npb24oKXtyZXR1cm4gdGhpcy5PfXVwZGF0ZSh0KXtpZighdClyZXR1cm4gdGhpcztjb25zdCBuPSJmdW5jdGlvbiI9PXR5cGVvZiB0P3QodGhpcyk6dCxlPW4gaW5zdGFuY2VvZiBldD9uLmdldFNjb3BlRGF0YSgpOkQobik/dDp2b2lkIDAse3RhZ3M6cixleHRyYTpvLHVzZXI6cyxjb250ZXh0czppLGxldmVsOmMsZmluZ2VycHJpbnQ6dT1bXSxwcm9wYWdhdGlvbkNvbnRleHQ6YX09ZXx8e307cmV0dXJuIHRoaXMuTj17Li4udGhpcy5OLC4uLnJ9LHRoaXMuVD17Li4udGhpcy5ULC4uLm99LHRoaXMuQz17Li4udGhpcy5DLC4uLml9LHMmJk9iamVjdC5rZXlzKHMpLmxlbmd0aCYmKHRoaXMuUz1zKSxjJiYodGhpcy5rPWMpLHUubGVuZ3RoJiYodGhpcy5JPXUpLGEmJih0aGlzLlI9YSksdGhpc31jbGVhcigpe3JldHVybiB0aGlzLl89W10sdGhpcy5OPXt9LHRoaXMuVD17fSx0aGlzLlM9e30sdGhpcy5DPXt9LHRoaXMuaz12b2lkIDAsdGhpcy5EPXZvaWQgMCx0aGlzLkk9dm9pZCAwLHRoaXMuTz12b2lkIDAsdHQodGhpcyx2b2lkIDApLHRoaXMudj1bXSx0aGlzLnNldFByb3BhZ2F0aW9uQ29udGV4dCh7dHJhY2VJZDpaKCksc2FtcGxlUmFuZDpNYXRoLnJhbmRvbSgpfSksdGhpcy5VKCksdGhpc31hZGRCcmVhZGNydW1iKHQsbil7Y29uc3QgZT0ibnVtYmVyIj09dHlwZW9mIG4/bjoxMDA7aWYoZTw9MClyZXR1cm4gdGhpcztjb25zdCByPXt0aW1lc3RhbXA6QygpLC4uLnR9O3JldHVybiB0aGlzLl8ucHVzaChyKSx0aGlzLl8ubGVuZ3RoPmUmJih0aGlzLl89dGhpcy5fLnNsaWNlKC1lKSx0aGlzLkE/LnJlY29yZERyb3BwZWRFdmVudCgiYnVmZmVyX292ZXJmbG93IiwibG9nX2l0ZW0iKSksdGhpcy5VKCksdGhpc31nZXRMYXN0QnJlYWRjcnVtYigpe3JldHVybiB0aGlzLl9bdGhpcy5fLmxlbmd0aC0xXX1jbGVhckJyZWFkY3J1bWJzKCl7cmV0dXJuIHRoaXMuXz1bXSx0aGlzLlUoKSx0aGlzfWFkZEF0dGFjaG1lbnQodCl7cmV0dXJuIHRoaXMudi5wdXNoKHQpLHRoaXN9Y2xlYXJBdHRhY2htZW50cygpe3JldHVybiB0aGlzLnY9W10sdGhpc31nZXRTY29wZURhdGEoKXtyZXR1cm57YnJlYWRjcnVtYnM6dGhpcy5fLGF0dGFjaG1lbnRzOnRoaXMudixjb250ZXh0czp0aGlzLkMsdGFnczp0aGlzLk4sZXh0cmE6dGhpcy5ULHVzZXI6dGhpcy5TLGxldmVsOnRoaXMuayxmaW5nZXJwcmludDp0aGlzLkl8fFtdLGV2ZW50UHJvY2Vzc29yczp0aGlzLm0scHJvcGFnYXRpb25Db250ZXh0OnRoaXMuUixzZGtQcm9jZXNzaW5nTWV0YWRhdGE6dGhpcy5qLHRyYW5zYWN0aW9uTmFtZTp0aGlzLkQsc3BhbjpudCh0aGlzKX19c2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKHQpe3JldHVybiB0aGlzLmo9USh0aGlzLmosdCwyKSx0aGlzfXNldFByb3BhZ2F0aW9uQ29udGV4dCh0KXtyZXR1cm4gdGhpcy5SPXQsdGhpc31nZXRQcm9wYWdhdGlvbkNvbnRleHQoKXtyZXR1cm4gdGhpcy5SfWNhcHR1cmVFeGNlcHRpb24odCxuKXtjb25zdCBlPW4/LmV2ZW50X2lkfHx6KCk7aWYoIXRoaXMuQSlyZXR1cm4gdy53YXJuKCJObyBjbGllbnQgY29uZmlndXJlZCBvbiBzY29wZSAtIHdpbGwgbm90IGNhcHR1cmUgZXhjZXB0aW9uISIpLGU7Y29uc3Qgcj1uZXcgRXJyb3IoIlNlbnRyeSBzeW50aGV0aWNFeGNlcHRpb24iKTtyZXR1cm4gdGhpcy5BLmNhcHR1cmVFeGNlcHRpb24odCx7b3JpZ2luYWxFeGNlcHRpb246dCxzeW50aGV0aWNFeGNlcHRpb246ciwuLi5uLGV2ZW50X2lkOmV9LHRoaXMpLGV9Y2FwdHVyZU1lc3NhZ2UodCxuLGUpe2NvbnN0IHI9ZT8uZXZlbnRfaWR8fHooKTtpZighdGhpcy5BKXJldHVybiB3Lndhcm4oIk5vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBtZXNzYWdlISIpLHI7Y29uc3Qgbz1uZXcgRXJyb3IodCk7cmV0dXJuIHRoaXMuQS5jYXB0dXJlTWVzc2FnZSh0LG4se29yaWdpbmFsRXhjZXB0aW9uOnQsc3ludGhldGljRXhjZXB0aW9uOm8sLi4uZSxldmVudF9pZDpyfSx0aGlzKSxyfWNhcHR1cmVFdmVudCh0LG4pe2NvbnN0IGU9bj8uZXZlbnRfaWR8fHooKTtyZXR1cm4gdGhpcy5BPyh0aGlzLkEuY2FwdHVyZUV2ZW50KHQsey4uLm4sZXZlbnRfaWQ6ZX0sdGhpcyksZSk6KHcud2FybigiTm8gY2xpZW50IGNvbmZpZ3VyZWQgb24gc2NvcGUgLSB3aWxsIG5vdCBjYXB0dXJlIGV2ZW50ISIpLGUpfVUoKXt0aGlzLnB8fCh0aGlzLnA9ITAsdGhpcy5sLmZvckVhY2goKHQ9Pnt0KHRoaXMpfSkpLHRoaXMucD0hMSl9fWNsYXNzIHJ0e2NvbnN0cnVjdG9yKHQsbil7bGV0IGUscjtlPXR8fG5ldyBldCxyPW58fG5ldyBldCx0aGlzLk09W3tzY29wZTplfV0sdGhpcy5MPXJ9d2l0aFNjb3BlKHQpe2NvbnN0IG49dGhpcy5CKCk7bGV0IGU7dHJ5e2U9dChuKX1jYXRjaCh0KXt0aHJvdyB0aGlzLkcoKSx0fXJldHVybiBJKGUpP2UudGhlbigodD0+KHRoaXMuRygpLHQpKSwodD0+e3Rocm93IHRoaXMuRygpLHR9KSk6KHRoaXMuRygpLGUpfWdldENsaWVudCgpe3JldHVybiB0aGlzLmdldFN0YWNrVG9wKCkuY2xpZW50fWdldFNjb3BlKCl7cmV0dXJuIHRoaXMuZ2V0U3RhY2tUb3AoKS5zY29wZX1nZXRJc29sYXRpb25TY29wZSgpe3JldHVybiB0aGlzLkx9Z2V0U3RhY2tUb3AoKXtyZXR1cm4gdGhpcy5NW3RoaXMuTS5sZW5ndGgtMV19Qigpe2NvbnN0IHQ9dGhpcy5nZXRTY29wZSgpLmNsb25lKCk7cmV0dXJuIHRoaXMuTS5wdXNoKHtjbGllbnQ6dGhpcy5nZXRDbGllbnQoKSxzY29wZTp0fSksdH1HKCl7cmV0dXJuISh0aGlzLk0ubGVuZ3RoPD0xKSYmISF0aGlzLk0ucG9wKCl9fWZ1bmN0aW9uIG90KCl7Y29uc3QgdD1nKG0oKSk7cmV0dXJuIHQuc3RhY2s9dC5zdGFja3x8bmV3IHJ0KHkoImRlZmF1bHRDdXJyZW50U2NvcGUiLCgoKT0+bmV3IGV0KSkseSgiZGVmYXVsdElzb2xhdGlvblNjb3BlIiwoKCk9Pm5ldyBldCkpKX1mdW5jdGlvbiBzdCh0KXtyZXR1cm4gb3QoKS53aXRoU2NvcGUodCl9ZnVuY3Rpb24gaXQodCxuKXtjb25zdCBlPW90KCk7cmV0dXJuIGUud2l0aFNjb3BlKCgoKT0+KGUuZ2V0U3RhY2tUb3AoKS5zY29wZT10LG4odCkpKSl9ZnVuY3Rpb24gY3QodCl7cmV0dXJuIG90KCkud2l0aFNjb3BlKCgoKT0+dChvdCgpLmdldElzb2xhdGlvblNjb3BlKCkpKSl9ZnVuY3Rpb24gdXQodCl7Y29uc3Qgbj1nKHQpO3JldHVybiBuLmFjcz9uLmFjczp7d2l0aElzb2xhdGlvblNjb3BlOmN0LHdpdGhTY29wZTpzdCx3aXRoU2V0U2NvcGU6aXQsd2l0aFNldElzb2xhdGlvblNjb3BlOih0LG4pPT5jdChuKSxnZXRDdXJyZW50U2NvcGU6KCk9Pm90KCkuZ2V0U2NvcGUoKSxnZXRJc29sYXRpb25TY29wZTooKT0+b3QoKS5nZXRJc29sYXRpb25TY29wZSgpfX1mdW5jdGlvbiBhdCgpe3JldHVybiB1dChtKCkpLmdldEN1cnJlbnRTY29wZSgpLmdldENsaWVudCgpfWNvbnN0IGZ0PSJzZW50cnkuc291cmNlIixodD0ic2VudHJ5LnNhbXBsZV9yYXRlIixwdD0ic2VudHJ5Lm9wIixsdD0ic2VudHJ5Lm9yaWdpbiIsZHQ9MCxtdD0xLGd0PSJfc2VudHJ5U2NvcGUiLHl0PSJfc2VudHJ5SXNvbGF0aW9uU2NvcGUiO2Z1bmN0aW9uIGJ0KHQpe3JldHVybntzY29wZTp0W2d0XSxpc29sYXRpb25TY29wZTp0W3l0XX19Y29uc3QgX3Q9InNlbnRyeS0iLHZ0PS9ec2VudHJ5LS87ZnVuY3Rpb24gd3QodCl7Y29uc3Qgbj1mdW5jdGlvbih0KXtpZighdHx8IU8odCkmJiFBcnJheS5pc0FycmF5KHQpKXJldHVybjtpZihBcnJheS5pc0FycmF5KHQpKXJldHVybiB0LnJlZHVjZSgoKHQsbik9Pntjb25zdCBlPVN0KG4pO3JldHVybiBPYmplY3QuZW50cmllcyhlKS5mb3JFYWNoKCgoW24sZV0pPT57dFtuXT1lfSkpLHR9KSx7fSk7cmV0dXJuIFN0KHQpfSh0KTtpZighbilyZXR1cm47Y29uc3QgZT1PYmplY3QuZW50cmllcyhuKS5yZWR1Y2UoKCh0LFtuLGVdKT0+e2lmKG4ubWF0Y2godnQpKXt0W24uc2xpY2UoX3QubGVuZ3RoKV09ZX1yZXR1cm4gdH0pLHt9KTtyZXR1cm4gT2JqZWN0LmtleXMoZSkubGVuZ3RoPjA/ZTp2b2lkIDB9ZnVuY3Rpb24gU3QodCl7cmV0dXJuIHQuc3BsaXQoIiwiKS5tYXAoKHQ9PnQuc3BsaXQoIj0iKS5tYXAoKHQ9PmRlY29kZVVSSUNvbXBvbmVudCh0LnRyaW0oKSkpKSkpLnJlZHVjZSgoKHQsW24sZV0pPT4obiYmZSYmKHRbbl09ZSksdCkpLHt9KX1jb25zdCAkdD0xO2Z1bmN0aW9uIEV0KHQpe2NvbnN0e3NwYW5JZDpuLHRyYWNlSWQ6ZSxpc1JlbW90ZTpyfT10LnNwYW5Db250ZXh0KCksbz1yP246Q3QodCkucGFyZW50X3NwYW5faWQscz1idCh0KS5zY29wZTtyZXR1cm4gSih7cGFyZW50X3NwYW5faWQ6byxzcGFuX2lkOnI/cz8uZ2V0UHJvcGFnYXRpb25Db250ZXh0KCkucHJvcGFnYXRpb25TcGFuSWR8fHEoKTpuLHRyYWNlX2lkOmV9KX1mdW5jdGlvbiB4dCh0KXtyZXR1cm4gdCYmdC5sZW5ndGg+MD90Lm1hcCgoKHtjb250ZXh0OntzcGFuSWQ6dCx0cmFjZUlkOm4sdHJhY2VGbGFnczplLC4uLnJ9LGF0dHJpYnV0ZXM6b30pPT4oe3NwYW5faWQ6dCx0cmFjZV9pZDpuLHNhbXBsZWQ6ZT09PSR0LGF0dHJpYnV0ZXM6bywuLi5yfSkpKTp2b2lkIDB9ZnVuY3Rpb24gTnQodCl7cmV0dXJuIm51bWJlciI9PXR5cGVvZiB0P1R0KHQpOkFycmF5LmlzQXJyYXkodCk/dFswXSt0WzFdLzFlOTp0IGluc3RhbmNlb2YgRGF0ZT9UdCh0LmdldFRpbWUoKSk6aigpfWZ1bmN0aW9uIFR0KHQpe3JldHVybiB0Pjk5OTk5OTk5OTk/dC8xZTM6dH1mdW5jdGlvbiBDdCh0KXtpZihmdW5jdGlvbih0KXtyZXR1cm4iZnVuY3Rpb24iPT10eXBlb2YgdC5nZXRTcGFuSlNPTn0odCkpcmV0dXJuIHQuZ2V0U3BhbkpTT04oKTtjb25zdHtzcGFuSWQ6bix0cmFjZUlkOmV9PXQuc3BhbkNvbnRleHQoKTtpZihmdW5jdGlvbih0KXtjb25zdCBuPXQ7cmV0dXJuISEobi5hdHRyaWJ1dGVzJiZuLnN0YXJ0VGltZSYmbi5uYW1lJiZuLmVuZFRpbWUmJm4uc3RhdHVzKX0odCkpe2NvbnN0e2F0dHJpYnV0ZXM6cixzdGFydFRpbWU6byxuYW1lOnMsZW5kVGltZTppLHBhcmVudFNwYW5JZDpjLHN0YXR1czp1LGxpbmtzOmF9PXQ7cmV0dXJuIEooe3NwYW5faWQ6bix0cmFjZV9pZDplLGRhdGE6cixkZXNjcmlwdGlvbjpzLHBhcmVudF9zcGFuX2lkOmMsc3RhcnRfdGltZXN0YW1wOk50KG8pLHRpbWVzdGFtcDpOdChpKXx8dm9pZCAwLHN0YXR1czpqdCh1KSxvcDpyW3B0XSxvcmlnaW46cltsdF0sbGlua3M6eHQoYSl9KX1yZXR1cm57c3Bhbl9pZDpuLHRyYWNlX2lkOmUsc3RhcnRfdGltZXN0YW1wOjAsZGF0YTp7fX19ZnVuY3Rpb24ganQodCl7aWYodCYmdC5jb2RlIT09ZHQpcmV0dXJuIHQuY29kZT09PW10PyJvayI6dC5tZXNzYWdlfHwidW5rbm93bl9lcnJvciJ9Y29uc3QgUnQ9Il9zZW50cnlSb290U3BhbiI7ZnVuY3Rpb24ga3QodCl7cmV0dXJuIHRbUnRdfHx0fWNvbnN0IE90PSJwcm9kdWN0aW9uIixEdD0iX2Zyb3plbkRzYyI7ZnVuY3Rpb24gSXQodCl7Y29uc3Qgbj1hdCgpO2lmKCFuKXJldHVybnt9O2NvbnN0IGU9a3QodCkscj1DdChlKSxvPXIuZGF0YSxzPWUuc3BhbkNvbnRleHQoKS50cmFjZVN0YXRlLGk9cz8uZ2V0KCJzZW50cnkuc2FtcGxlX3JhdGUiKT8/b1todF07ZnVuY3Rpb24gYyh0KXtyZXR1cm4ibnVtYmVyIiE9dHlwZW9mIGkmJiJzdHJpbmciIT10eXBlb2YgaXx8KHQuc2FtcGxlX3JhdGU9YCR7aX1gKSx0fWNvbnN0IHU9ZVtEdF07aWYodSlyZXR1cm4gYyh1KTtjb25zdCBhPXM/LmdldCgic2VudHJ5LmRzYyIpLGY9YSYmd3QoYSk7aWYoZilyZXR1cm4gYyhmKTtjb25zdCBoPWZ1bmN0aW9uKHQsbil7Y29uc3QgZT1uLmdldE9wdGlvbnMoKSx7cHVibGljS2V5OnJ9PW4uZ2V0RHNuKCl8fHt9LG89Sih7ZW52aXJvbm1lbnQ6ZS5lbnZpcm9ubWVudHx8T3QscmVsZWFzZTplLnJlbGVhc2UscHVibGljX2tleTpyLHRyYWNlX2lkOnR9KTtyZXR1cm4gbi5lbWl0KCJjcmVhdGVEc2MiLG8pLG99KHQuc3BhbkNvbnRleHQoKS50cmFjZUlkLG4pLHA9b1tmdF0sbD1yLmRlc2NyaXB0aW9uO3JldHVybiJ1cmwiIT09cCYmbCYmKGgudHJhbnNhY3Rpb249bCksZnVuY3Rpb24odCl7aWYoImJvb2xlYW4iPT10eXBlb2YgX19TRU5UUllfVFJBQ0lOR19fJiYhX19TRU5UUllfVFJBQ0lOR19fKXJldHVybiExO2NvbnN0IG49dHx8YXQoKT8uZ2V0T3B0aW9ucygpO3JldHVybiEoIW58fG51bGw9PW4udHJhY2VzU2FtcGxlUmF0ZSYmIW4udHJhY2VzU2FtcGxlcil9KCkmJihoLnNhbXBsZWQ9U3RyaW5nKGZ1bmN0aW9uKHQpe2NvbnN0e3RyYWNlRmxhZ3M6bn09dC5zcGFuQ29udGV4dCgpO3JldHVybiBuPT09JHR9KGUpKSxoLnNhbXBsZV9yYW5kPXM/LmdldCgic2VudHJ5LnNhbXBsZV9yYW5kIik/P2J0KGUpLnNjb3BlPy5nZXRQcm9wYWdhdGlvbkNvbnRleHQoKS5zYW1wbGVSYW5kLnRvU3RyaW5nKCkpLGMoaCksbi5lbWl0KCJjcmVhdGVEc2MiLGgsZSksaH1mdW5jdGlvbiBBdCh0LG49ITEpe2NvbnN0e2hvc3Q6ZSxwYXRoOnIscGFzczpvLHBvcnQ6cyxwcm9qZWN0SWQ6aSxwcm90b2NvbDpjLHB1YmxpY0tleTp1fT10O3JldHVybmAke2N9Oi8vJHt1fSR7biYmbz9gOiR7b31gOiIifUAke2V9JHtzP2A6JHtzfWA6IiJ9LyR7cj9gJHtyfS9gOnJ9JHtpfWB9ZnVuY3Rpb24gUHQodCxuPTEwMCxlPTEvMCl7dHJ5e3JldHVybiBVdCgiIix0LG4sZSl9Y2F0Y2godCl7cmV0dXJue0VSUk9SOmAqKm5vbi1zZXJpYWxpemFibGUqKiAoJHt0fSlgfX19ZnVuY3Rpb24gVXQodCxuLGU9MS8wLHI9MS8wLG89ZnVuY3Rpb24oKXtjb25zdCB0PW5ldyBXZWFrU2V0O2Z1bmN0aW9uIG4obil7cmV0dXJuISF0LmhhcyhuKXx8KHQuYWRkKG4pLCExKX1mdW5jdGlvbiBlKG4pe3QuZGVsZXRlKG4pfXJldHVybltuLGVdfSgpKXtjb25zdFtzLGldPW87aWYobnVsbD09bnx8WyJib29sZWFuIiwic3RyaW5nIl0uaW5jbHVkZXModHlwZW9mIG4pfHwibnVtYmVyIj09dHlwZW9mIG4mJk51bWJlci5pc0Zpbml0ZShuKSlyZXR1cm4gbjtjb25zdCBjPWZ1bmN0aW9uKHQsbil7dHJ5e2lmKCJkb21haW4iPT09dCYmbiYmIm9iamVjdCI9PXR5cGVvZiBuJiZuLkopcmV0dXJuIltEb21haW5dIjtpZigiZG9tYWluRW1pdHRlciI9PT10KXJldHVybiJbRG9tYWluRW1pdHRlcl0iO2lmKCJ1bmRlZmluZWQiIT10eXBlb2YgZ2xvYmFsJiZuPT09Z2xvYmFsKXJldHVybiJbR2xvYmFsXSI7aWYoInVuZGVmaW5lZCIhPXR5cGVvZiB3aW5kb3cmJm49PT13aW5kb3cpcmV0dXJuIltXaW5kb3ddIjtpZigidW5kZWZpbmVkIiE9dHlwZW9mIGRvY3VtZW50JiZuPT09ZG9jdW1lbnQpcmV0dXJuIltEb2N1bWVudF0iO2lmKCJvYmplY3QiPT10eXBlb2YoZT1uKSYmbnVsbCE9PWUmJihlLl9faXNWdWV8fGUuWSkpcmV0dXJuIltWdWVWaWV3TW9kZWxdIjtpZihmdW5jdGlvbih0KXtyZXR1cm4gRCh0KSYmIm5hdGl2ZUV2ZW50ImluIHQmJiJwcmV2ZW50RGVmYXVsdCJpbiB0JiYic3RvcFByb3BhZ2F0aW9uImluIHR9KG4pKXJldHVybiJbU3ludGhldGljRXZlbnRdIjtpZigibnVtYmVyIj09dHlwZW9mIG4mJiFOdW1iZXIuaXNGaW5pdGUobikpcmV0dXJuYFske259XWA7aWYoImZ1bmN0aW9uIj09dHlwZW9mIG4pcmV0dXJuYFtGdW5jdGlvbjogJHtmdW5jdGlvbih0KXt0cnl7cmV0dXJuIHQmJiJmdW5jdGlvbiI9PXR5cGVvZiB0JiZ0Lm5hbWV8fE59Y2F0Y2godCl7cmV0dXJuIE59fShuKX1dYDtpZigic3ltYm9sIj09dHlwZW9mIG4pcmV0dXJuYFske1N0cmluZyhuKX1dYDtpZigiYmlnaW50Ij09dHlwZW9mIG4pcmV0dXJuYFtCaWdJbnQ6ICR7U3RyaW5nKG4pfV1gO2NvbnN0IHI9ZnVuY3Rpb24odCl7Y29uc3Qgbj1PYmplY3QuZ2V0UHJvdG90eXBlT2YodCk7cmV0dXJuIG4/LmNvbnN0cnVjdG9yP24uY29uc3RydWN0b3IubmFtZToibnVsbCBwcm90b3R5cGUifShuKTtyZXR1cm4vXkhUTUwoXHcqKUVsZW1lbnQkLy50ZXN0KHIpP2BbSFRNTEVsZW1lbnQ6ICR7cn1dYDpgW29iamVjdCAke3J9XWB9Y2F0Y2godCl7cmV0dXJuYCoqbm9uLXNlcmlhbGl6YWJsZSoqICgke3R9KWB9dmFyIGV9KHQsbik7aWYoIWMuc3RhcnRzV2l0aCgiW29iamVjdCAiKSlyZXR1cm4gYztpZihuLl9fc2VudHJ5X3NraXBfbm9ybWFsaXphdGlvbl9fKXJldHVybiBuO2NvbnN0IHU9Im51bWJlciI9PXR5cGVvZiBuLl9fc2VudHJ5X292ZXJyaWRlX25vcm1hbGl6YXRpb25fZGVwdGhfXz9uLl9fc2VudHJ5X292ZXJyaWRlX25vcm1hbGl6YXRpb25fZGVwdGhfXzplO2lmKDA9PT11KXJldHVybiBjLnJlcGxhY2UoIm9iamVjdCAiLCIiKTtpZihzKG4pKXJldHVybiJbQ2lyY3VsYXIgfl0iO2NvbnN0IGE9bjtpZihhJiYiZnVuY3Rpb24iPT10eXBlb2YgYS50b0pTT04pdHJ5e3JldHVybiBVdCgiIixhLnRvSlNPTigpLHUtMSxyLG8pfWNhdGNoKHQpe31jb25zdCBmPUFycmF5LmlzQXJyYXkobik/W106e307bGV0IGg9MDtjb25zdCBwPUwobik7Zm9yKGNvbnN0IHQgaW4gcCl7aWYoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChwLHQpKWNvbnRpbnVlO2lmKGg+PXIpe2ZbdF09IltNYXhQcm9wZXJ0aWVzIH5dIjticmVha31jb25zdCBuPXBbdF07Zlt0XT1VdCh0LG4sdS0xLHIsbyksaCsrfXJldHVybiBpKG4pLGZ9ZnVuY3Rpb24gTXQodCxuKXtjb25zdCBlPW4ucmVwbGFjZSgvXFwvZywiLyIpLnJlcGxhY2UoL1t8XFx7fSgpW1xdXiQrKj8uXS9nLCJcXCQmIik7bGV0IHI9dDt0cnl7cj1kZWNvZGVVUkkodCl9Y2F0Y2godCl7fXJldHVybiByLnJlcGxhY2UoL1xcL2csIi8iKS5yZXBsYWNlKC93ZWJwYWNrOlwvPy9nLCIiKS5yZXBsYWNlKG5ldyBSZWdFeHAoYChmaWxlOi8vKT8vKiR7ZX0vKmAsImlnIiksImFwcDovLy8iKX1mdW5jdGlvbiBMdCh0LG49W10pe3JldHVyblt0LG5dfWZ1bmN0aW9uIEJ0KHQsbil7Y29uc3QgZT10WzFdO2Zvcihjb25zdCB0IG9mIGUpe2lmKG4odCx0WzBdLnR5cGUpKXJldHVybiEwfXJldHVybiExfWZ1bmN0aW9uIEd0KHQpe2NvbnN0IG49ZyhwKTtyZXR1cm4gbi5lbmNvZGVQb2x5ZmlsbD9uLmVuY29kZVBvbHlmaWxsKHQpOihuZXcgVGV4dEVuY29kZXIpLmVuY29kZSh0KX1mdW5jdGlvbiBKdCh0KXtjb25zdFtuLGVdPXQ7bGV0IHI9SlNPTi5zdHJpbmdpZnkobik7ZnVuY3Rpb24gbyh0KXsic3RyaW5nIj09dHlwZW9mIHI/cj0ic3RyaW5nIj09dHlwZW9mIHQ/cit0OltHdChyKSx0XTpyLnB1c2goInN0cmluZyI9PXR5cGVvZiB0P0d0KHQpOnQpfWZvcihjb25zdCB0IG9mIGUpe2NvbnN0W24sZV09dDtpZihvKGBcbiR7SlNPTi5zdHJpbmdpZnkobil9XG5gKSwic3RyaW5nIj09dHlwZW9mIGV8fGUgaW5zdGFuY2VvZiBVaW50OEFycmF5KW8oZSk7ZWxzZXtsZXQgdDt0cnl7dD1KU09OLnN0cmluZ2lmeShlKX1jYXRjaChuKXt0PUpTT04uc3RyaW5naWZ5KFB0KGUpKX1vKHQpfX1yZXR1cm4ic3RyaW5nIj09dHlwZW9mIHI/cjpmdW5jdGlvbih0KXtjb25zdCBuPXQucmVkdWNlKCgodCxuKT0+dCtuLmxlbmd0aCksMCksZT1uZXcgVWludDhBcnJheShuKTtsZXQgcj0wO2Zvcihjb25zdCBuIG9mIHQpZS5zZXQobixyKSxyKz1uLmxlbmd0aDtyZXR1cm4gZX0ocil9Y29uc3QgWXQ9e3Nlc3Npb246InNlc3Npb24iLHNlc3Npb25zOiJzZXNzaW9uIixhdHRhY2htZW50OiJhdHRhY2htZW50Iix0cmFuc2FjdGlvbjoidHJhbnNhY3Rpb24iLGV2ZW50OiJlcnJvciIsY2xpZW50X3JlcG9ydDoiaW50ZXJuYWwiLHVzZXJfcmVwb3J0OiJkZWZhdWx0Iixwcm9maWxlOiJwcm9maWxlIixwcm9maWxlX2NodW5rOiJwcm9maWxlIixyZXBsYXlfZXZlbnQ6InJlcGxheSIscmVwbGF5X3JlY29yZGluZzoicmVwbGF5IixjaGVja19pbjoibW9uaXRvciIsZmVlZGJhY2s6ImZlZWRiYWNrIixzcGFuOiJzcGFuIixyYXdfc2VjdXJpdHk6InNlY3VyaXR5IixvdGVsX2xvZzoibG9nX2l0ZW0ifTtmdW5jdGlvbiB6dCh0KXtpZighdD8uc2RrKXJldHVybjtjb25zdHtuYW1lOm4sdmVyc2lvbjplfT10LnNkaztyZXR1cm57bmFtZTpuLHZlcnNpb246ZX19ZnVuY3Rpb24gSHQodCxuLGUscil7Y29uc3Qgbz16dChlKSxzPXQudHlwZSYmInJlcGxheV9ldmVudCIhPT10LnR5cGU/dC50eXBlOiJldmVudCI7IWZ1bmN0aW9uKHQsbil7biYmKHQuc2RrPXQuc2RrfHx7fSx0LnNkay5uYW1lPXQuc2RrLm5hbWV8fG4ubmFtZSx0LnNkay52ZXJzaW9uPXQuc2RrLnZlcnNpb258fG4udmVyc2lvbix0LnNkay5pbnRlZ3JhdGlvbnM9Wy4uLnQuc2RrLmludGVncmF0aW9uc3x8W10sLi4ubi5pbnRlZ3JhdGlvbnN8fFtdXSx0LnNkay5wYWNrYWdlcz1bLi4udC5zZGsucGFja2FnZXN8fFtdLC4uLm4ucGFja2FnZXN8fFtdXSl9KHQsZT8uc2RrKTtjb25zdCBpPWZ1bmN0aW9uKHQsbixlLHIpe2NvbnN0IG89dC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE/LmR5bmFtaWNTYW1wbGluZ0NvbnRleHQ7cmV0dXJue2V2ZW50X2lkOnQuZXZlbnRfaWQsc2VudF9hdDoobmV3IERhdGUpLnRvSVNPU3RyaW5nKCksLi4ubiYme3NkazpufSwuLi4hIWUmJnImJntkc246QXQocil9LC4uLm8mJnt0cmFjZTpvfX19KHQsbyxyLG4pO2RlbGV0ZSB0LnNka1Byb2Nlc3NpbmdNZXRhZGF0YTtyZXR1cm4gTHQoaSxbW3t0eXBlOnN9LHRdXSl9Y29uc3QgV3Q9Il9fU0VOVFJZX1NVUFBSRVNTX1RSQUNJTkdfXyI7ZnVuY3Rpb24gRnQodCl7Y29uc3Qgbj11dChtKCkpO3JldHVybiBuLnN1cHByZXNzVHJhY2luZz9uLnN1cHByZXNzVHJhY2luZyh0KTpmdW5jdGlvbiguLi50KXtjb25zdCBuPXV0KG0oKSk7aWYoMj09PXQubGVuZ3RoKXtjb25zdFtlLHJdPXQ7cmV0dXJuIGU/bi53aXRoU2V0U2NvcGUoZSxyKTpuLndpdGhTY29wZShyKX1yZXR1cm4gbi53aXRoU2NvcGUodFswXSl9KChuPT4obi5zZXRTREtQcm9jZXNzaW5nTWV0YWRhdGEoe1tXdF06ITB9KSx0KCkpKSl9ZnVuY3Rpb24gS3QodCxuKXtjb25zdHtmaW5nZXJwcmludDplLHNwYW46cixicmVhZGNydW1iczpvLHNka1Byb2Nlc3NpbmdNZXRhZGF0YTpzfT1uOyFmdW5jdGlvbih0LG4pe2NvbnN0e2V4dHJhOmUsdGFnczpyLHVzZXI6byxjb250ZXh0czpzLGxldmVsOmksdHJhbnNhY3Rpb25OYW1lOmN9PW47T2JqZWN0LmtleXMoZSkubGVuZ3RoJiYodC5leHRyYT17Li4uZSwuLi50LmV4dHJhfSk7T2JqZWN0LmtleXMocikubGVuZ3RoJiYodC50YWdzPXsuLi5yLC4uLnQudGFnc30pO09iamVjdC5rZXlzKG8pLmxlbmd0aCYmKHQudXNlcj17Li4ubywuLi50LnVzZXJ9KTtPYmplY3Qua2V5cyhzKS5sZW5ndGgmJih0LmNvbnRleHRzPXsuLi5zLC4uLnQuY29udGV4dHN9KTtpJiYodC5sZXZlbD1pKTtjJiYidHJhbnNhY3Rpb24iIT09dC50eXBlJiYodC50cmFuc2FjdGlvbj1jKX0odCxuKSxyJiZmdW5jdGlvbih0LG4pe3QuY29udGV4dHM9e3RyYWNlOkV0KG4pLC4uLnQuY29udGV4dHN9LHQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhPXtkeW5hbWljU2FtcGxpbmdDb250ZXh0Okl0KG4pLC4uLnQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhfTtjb25zdCBlPWt0KG4pLHI9Q3QoZSkuZGVzY3JpcHRpb247ciYmIXQudHJhbnNhY3Rpb24mJiJ0cmFuc2FjdGlvbiI9PT10LnR5cGUmJih0LnRyYW5zYWN0aW9uPXIpfSh0LHIpLGZ1bmN0aW9uKHQsbil7dC5maW5nZXJwcmludD10LmZpbmdlcnByaW50P0FycmF5LmlzQXJyYXkodC5maW5nZXJwcmludCk/dC5maW5nZXJwcmludDpbdC5maW5nZXJwcmludF06W10sbiYmKHQuZmluZ2VycHJpbnQ9dC5maW5nZXJwcmludC5jb25jYXQobikpO3QuZmluZ2VycHJpbnQubGVuZ3RofHxkZWxldGUgdC5maW5nZXJwcmludH0odCxlKSxmdW5jdGlvbih0LG4pe2NvbnN0IGU9Wy4uLnQuYnJlYWRjcnVtYnN8fFtdLC4uLm5dO3QuYnJlYWRjcnVtYnM9ZS5sZW5ndGg/ZTp2b2lkIDB9KHQsbyksZnVuY3Rpb24odCxuKXt0LnNka1Byb2Nlc3NpbmdNZXRhZGF0YT17Li4udC5zZGtQcm9jZXNzaW5nTWV0YWRhdGEsLi4ubn19KHQscyl9Y29uc3QgVnQ9IjciO2NsYXNzIFp0IGV4dGVuZHMgRXJyb3J7Y29uc3RydWN0b3IodCxuPSJ3YXJuIil7c3VwZXIodCksdGhpcy5tZXNzYWdlPXQsdGhpcy5sb2dMZXZlbD1ufX1mdW5jdGlvbiBxdCh0KXtjb25zdCBuPVtdO2Z1bmN0aW9uIGUodCl7cmV0dXJuIG4uc3BsaWNlKG4uaW5kZXhPZih0KSwxKVswXXx8UHJvbWlzZS5yZXNvbHZlKHZvaWQgMCl9cmV0dXJueyQ6bixhZGQ6ZnVuY3Rpb24ocil7aWYoISh2b2lkIDA9PT10fHxuLmxlbmd0aDx0KSlyZXR1cm4gbz1uZXcgWnQoIk5vdCBhZGRpbmcgUHJvbWlzZSBiZWNhdXNlIGJ1ZmZlciBsaW1pdCB3YXMgcmVhY2hlZC4iKSxuZXcgRigoKHQsbik9PntuKG8pfSkpO3ZhciBvO2NvbnN0IHM9cigpO3JldHVybi0xPT09bi5pbmRleE9mKHMpJiZuLnB1c2gocykscy50aGVuKCgoKT0+ZShzKSkpLnRoZW4obnVsbCwoKCk9PmUocykudGhlbihudWxsLCgoKT0+e30pKSkpLHN9LGRyYWluOmZ1bmN0aW9uKHQpe3JldHVybiBuZXcgRigoKGUscik9PntsZXQgbz1uLmxlbmd0aDtpZighbylyZXR1cm4gZSghMCk7Y29uc3Qgcz1zZXRUaW1lb3V0KCgoKT0+e3QmJnQ+MCYmZSghMSl9KSx0KTtuLmZvckVhY2goKHQ9PntXKHQpLnRoZW4oKCgpPT57LS1vfHwoY2xlYXJUaW1lb3V0KHMpLGUoITApKX0pLHIpfSkpfSkpfX19Y29uc3QgUXQ9NmU0O2Z1bmN0aW9uIFh0KHQse3N0YXR1c0NvZGU6bixoZWFkZXJzOmV9LHI9RGF0ZS5ub3coKSl7Y29uc3Qgbz17Li4udH0scz1lPy5bIngtc2VudHJ5LXJhdGUtbGltaXRzIl0saT1lPy5bInJldHJ5LWFmdGVyIl07aWYocylmb3IoY29uc3QgdCBvZiBzLnRyaW0oKS5zcGxpdCgiLCIpKXtjb25zdFtuLGUsLCxzXT10LnNwbGl0KCI6Iiw1KSxpPXBhcnNlSW50KG4sMTApLGM9MWUzKihpc05hTihpKT82MDppKTtpZihlKWZvcihjb25zdCB0IG9mIGUuc3BsaXQoIjsiKSkibWV0cmljX2J1Y2tldCI9PT10JiZzJiYhcy5zcGxpdCgiOyIpLmluY2x1ZGVzKCJjdXN0b20iKXx8KG9bdF09citjKTtlbHNlIG8uYWxsPXIrY31lbHNlIGk/by5hbGw9citmdW5jdGlvbih0LG49RGF0ZS5ub3coKSl7Y29uc3QgZT1wYXJzZUludChgJHt0fWAsMTApO2lmKCFpc05hTihlKSlyZXR1cm4gMWUzKmU7Y29uc3Qgcj1EYXRlLnBhcnNlKGAke3R9YCk7cmV0dXJuIGlzTmFOKHIpP1F0OnItbn0oaSxyKTo0Mjk9PT1uJiYoby5hbGw9cis2ZTQpO3JldHVybiBvfWNvbnN0IHRuPTY0O2Z1bmN0aW9uIG5uKHQsbixlPXF0KHQuYnVmZmVyU2l6ZXx8dG4pKXtsZXQgcj17fTtyZXR1cm57c2VuZDpmdW5jdGlvbih0KXtjb25zdCBvPVtdO2lmKEJ0KHQsKCh0LG4pPT57Y29uc3QgZT1mdW5jdGlvbih0KXtyZXR1cm4gWXRbdF19KG4pOyhmdW5jdGlvbih0LG4sZT1EYXRlLm5vdygpKXtyZXR1cm4gZnVuY3Rpb24odCxuKXtyZXR1cm4gdFtuXXx8dC5hbGx8fDB9KHQsbik+ZX0pKHIsZSl8fG8ucHVzaCh0KX0pKSwwPT09by5sZW5ndGgpcmV0dXJuIFcoe30pO2NvbnN0IHM9THQodFswXSxvKSxpPXQ9PntCdChzLCgodCxuKT0+e30pKX07cmV0dXJuIGUuYWRkKCgoKT0+bih7Ym9keTpKdChzKX0pLnRoZW4oKHQ9Pih2b2lkIDAhPT10LnN0YXR1c0NvZGUmJih0LnN0YXR1c0NvZGU8MjAwfHx0LnN0YXR1c0NvZGU+PTMwMCkmJmgmJncud2FybihgU2VudHJ5IHJlc3BvbmRlZCB3aXRoIHN0YXR1cyBjb2RlICR7dC5zdGF0dXNDb2RlfSB0byBzZW50IGV2ZW50LmApLHI9WHQocix0KSx0KSksKHQ9Pnt0aHJvdyBpKCksdH0pKSkpLnRoZW4oKHQ9PnQpLCh0PT57aWYodCBpbnN0YW5jZW9mIFp0KXJldHVybiBoJiZ3LmVycm9yKCJTa2lwcGVkIHNlbmRpbmcgZXZlbnQgYmVjYXVzZSBidWZmZXIgaXMgZnVsbC4iKSxpKCksVyh7fSk7dGhyb3cgdH0pKX0sZmx1c2g6dD0+ZS5kcmFpbih0KX19Y29uc3QgZW49L14oXFMrOlxcfFwvPykoW1xzXFNdKj8pKCg/OlwuezEsMn18W14vXFxdKz98KShcLlteLi9cXF0qfCkpKD86Wy9cXF0qKSQvO2Z1bmN0aW9uIHJuKHQpe2NvbnN0IG49ZnVuY3Rpb24odCl7Y29uc3Qgbj10Lmxlbmd0aD4xMDI0P2A8dHJ1bmNhdGVkPiR7dC5zbGljZSgtMTAyNCl9YDp0LGU9ZW4uZXhlYyhuKTtyZXR1cm4gZT9lLnNsaWNlKDEpOltdfSh0KSxlPW5bMF18fCIiO2xldCByPW5bMV07cmV0dXJuIGV8fHI/KHImJihyPXIuc2xpY2UoMCxyLmxlbmd0aC0xKSksZStyKToiLiJ9ZnVuY3Rpb24gb24odCxuPSExKXtyZXR1cm4hKG58fHQmJiF0LnN0YXJ0c1dpdGgoIi8iKSYmIXQubWF0Y2goL15bQS1aXTovKSYmIXQuc3RhcnRzV2l0aCgiLiIpJiYhdC5tYXRjaCgvXlthLXpBLVpdKFthLXpBLVowLTkuXC0rXSkqOlwvXC8vKSkmJnZvaWQgMCE9PXQmJiF0LmluY2x1ZGVzKCJub2RlX21vZHVsZXMvIil9Y29uc3Qgc249U3ltYm9sKCJBZ2VudEJhc2VJbnRlcm5hbFN0YXRlIik7Y2xhc3MgY24gZXh0ZW5kcyBzLkFnZW50e2NvbnN0cnVjdG9yKHQpe3N1cGVyKHQpLHRoaXNbc25dPXt9fWlzU2VjdXJlRW5kcG9pbnQodCl7aWYodCl7aWYoImJvb2xlYW4iPT10eXBlb2YgdC5zZWN1cmVFbmRwb2ludClyZXR1cm4gdC5zZWN1cmVFbmRwb2ludDtpZigic3RyaW5nIj09dHlwZW9mIHQucHJvdG9jb2wpcmV0dXJuImh0dHBzOiI9PT10LnByb3RvY29sfWNvbnN0e3N0YWNrOm59PW5ldyBFcnJvcjtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIG4mJm4uc3BsaXQoIlxuIikuc29tZSgodD0+LTEhPT10LmluZGV4T2YoIihodHRwcy5qczoiKXx8LTEhPT10LmluZGV4T2YoIm5vZGU6aHR0cHM6IikpKX1jcmVhdGVTb2NrZXQodCxuLGUpe2NvbnN0IHI9ey4uLm4sc2VjdXJlRW5kcG9pbnQ6dGhpcy5pc1NlY3VyZUVuZHBvaW50KG4pfTtQcm9taXNlLnJlc29sdmUoKS50aGVuKCgoKT0+dGhpcy5jb25uZWN0KHQscikpKS50aGVuKChvPT57aWYobyBpbnN0YW5jZW9mIHMuQWdlbnQpcmV0dXJuIG8uYWRkUmVxdWVzdCh0LHIpO3RoaXNbc25dLmN1cnJlbnRTb2NrZXQ9byxzdXBlci5jcmVhdGVTb2NrZXQodCxuLGUpfSksZSl9Y3JlYXRlQ29ubmVjdGlvbigpe2NvbnN0IHQ9dGhpc1tzbl0uY3VycmVudFNvY2tldDtpZih0aGlzW3NuXS5jdXJyZW50U29ja2V0PXZvaWQgMCwhdCl0aHJvdyBuZXcgRXJyb3IoIk5vIHNvY2tldCB3YXMgcmV0dXJuZWQgaW4gdGhlIGBjb25uZWN0KClgIGZ1bmN0aW9uIik7cmV0dXJuIHR9Z2V0IGRlZmF1bHRQb3J0KCl7cmV0dXJuIHRoaXNbc25dLmRlZmF1bHRQb3J0Pz8oImh0dHBzOiI9PT10aGlzLnByb3RvY29sPzQ0Mzo4MCl9c2V0IGRlZmF1bHRQb3J0KHQpe3RoaXNbc25dJiYodGhpc1tzbl0uZGVmYXVsdFBvcnQ9dCl9Z2V0IHByb3RvY29sKCl7cmV0dXJuIHRoaXNbc25dLnByb3RvY29sPz8odGhpcy5pc1NlY3VyZUVuZHBvaW50KCk/Imh0dHBzOiI6Imh0dHA6Iil9c2V0IHByb3RvY29sKHQpe3RoaXNbc25dJiYodGhpc1tzbl0ucHJvdG9jb2w9dCl9fWZ1bmN0aW9uIHVuKC4uLnQpe3cubG9nKCJbaHR0cHMtcHJveHktYWdlbnQ6cGFyc2UtcHJveHktcmVzcG9uc2VdIiwuLi50KX1mdW5jdGlvbiBhbih0KXtyZXR1cm4gbmV3IFByb21pc2UoKChuLGUpPT57bGV0IHI9MDtjb25zdCBvPVtdO2Z1bmN0aW9uIHMoKXtjb25zdCBjPXQucmVhZCgpO2M/ZnVuY3Rpb24oYyl7by5wdXNoKGMpLHIrPWMubGVuZ3RoO2NvbnN0IHU9QnVmZmVyLmNvbmNhdChvLHIpLGE9dS5pbmRleE9mKCJcclxuXHJcbiIpO2lmKC0xPT09YSlyZXR1cm4gdW4oImhhdmUgbm90IHJlY2VpdmVkIGVuZCBvZiBIVFRQIGhlYWRlcnMgeWV0Li4uIiksdm9pZCBzKCk7Y29uc3QgZj11LnN1YmFycmF5KDAsYSkudG9TdHJpbmcoImFzY2lpIikuc3BsaXQoIlxyXG4iKSxoPWYuc2hpZnQoKTtpZighaClyZXR1cm4gdC5kZXN0cm95KCksZShuZXcgRXJyb3IoIk5vIGhlYWRlciByZWNlaXZlZCBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2UiKSk7Y29uc3QgcD1oLnNwbGl0KCIgIiksbD0rKHBbMV18fDApLGQ9cC5zbGljZSgyKS5qb2luKCIgIiksbT17fTtmb3IoY29uc3QgbiBvZiBmKXtpZighbiljb250aW51ZTtjb25zdCByPW4uaW5kZXhPZigiOiIpO2lmKC0xPT09cilyZXR1cm4gdC5kZXN0cm95KCksZShuZXcgRXJyb3IoYEludmFsaWQgaGVhZGVyIGZyb20gcHJveHkgQ09OTkVDVCByZXNwb25zZTogIiR7bn0iYCkpO2NvbnN0IG89bi5zbGljZSgwLHIpLnRvTG93ZXJDYXNlKCkscz1uLnNsaWNlKHIrMSkudHJpbVN0YXJ0KCksaT1tW29dOyJzdHJpbmciPT10eXBlb2YgaT9tW29dPVtpLHNdOkFycmF5LmlzQXJyYXkoaSk/aS5wdXNoKHMpOm1bb109c311bigiZ290IHByb3h5IHNlcnZlciByZXNwb25zZTogJW8gJW8iLGgsbSksaSgpLG4oe2Nvbm5lY3Q6e3N0YXR1c0NvZGU6bCxzdGF0dXNUZXh0OmQsaGVhZGVyczptfSxidWZmZXJlZDp1fSl9KGMpOnQub25jZSgicmVhZGFibGUiLHMpfWZ1bmN0aW9uIGkoKXt0LnJlbW92ZUxpc3RlbmVyKCJlbmQiLGMpLHQucmVtb3ZlTGlzdGVuZXIoImVycm9yIix1KSx0LnJlbW92ZUxpc3RlbmVyKCJyZWFkYWJsZSIscyl9ZnVuY3Rpb24gYygpe2koKSx1bigib25lbmQiKSxlKG5ldyBFcnJvcigiUHJveHkgY29ubmVjdGlvbiBlbmRlZCBiZWZvcmUgcmVjZWl2aW5nIENPTk5FQ1QgcmVzcG9uc2UiKSl9ZnVuY3Rpb24gdSh0KXtpKCksdW4oIm9uZXJyb3IgJW8iLHQpLGUodCl9dC5vbigiZXJyb3IiLHUpLHQub24oImVuZCIsYykscygpfSkpfWZ1bmN0aW9uIGZuKC4uLnQpe3cubG9nKCJbaHR0cHMtcHJveHktYWdlbnRdIiwuLi50KX1jbGFzcyBobiBleHRlbmRzIGNue3N0YXRpYyBfX2luaXRTdGF0aWMoKXt0aGlzLnByb3RvY29scz1bImh0dHAiLCJodHRwcyJdfWNvbnN0cnVjdG9yKHQsbil7c3VwZXIobiksdGhpcy5vcHRpb25zPXt9LHRoaXMucHJveHk9InN0cmluZyI9PXR5cGVvZiB0P25ldyBVUkwodCk6dCx0aGlzLnByb3h5SGVhZGVycz1uPy5oZWFkZXJzPz97fSxmbigiQ3JlYXRpbmcgbmV3IEh0dHBzUHJveHlBZ2VudCBpbnN0YW5jZTogJW8iLHRoaXMucHJveHkuaHJlZik7Y29uc3QgZT0odGhpcy5wcm94eS5ob3N0bmFtZXx8dGhpcy5wcm94eS5ob3N0KS5yZXBsYWNlKC9eXFt8XF0kL2csIiIpLHI9dGhpcy5wcm94eS5wb3J0P3BhcnNlSW50KHRoaXMucHJveHkucG9ydCwxMCk6Imh0dHBzOiI9PT10aGlzLnByb3h5LnByb3RvY29sPzQ0Mzo4MDt0aGlzLmNvbm5lY3RPcHRzPXtBTFBOUHJvdG9jb2xzOlsiaHR0cC8xLjEiXSwuLi5uP2xuKG4sImhlYWRlcnMiKTpudWxsLGhvc3Q6ZSxwb3J0OnJ9fWFzeW5jIGNvbm5lY3QodCxuKXtjb25zdHtwcm94eTplfT10aGlzO2lmKCFuLmhvc3QpdGhyb3cgbmV3IFR5cGVFcnJvcignTm8gImhvc3QiIHByb3ZpZGVkJyk7bGV0IHI7aWYoImh0dHBzOiI9PT1lLnByb3RvY29sKXtmbigiQ3JlYXRpbmcgYHRscy5Tb2NrZXRgOiAlbyIsdGhpcy5jb25uZWN0T3B0cyk7Y29uc3QgdD10aGlzLmNvbm5lY3RPcHRzLnNlcnZlcm5hbWV8fHRoaXMuY29ubmVjdE9wdHMuaG9zdDtyPWYuY29ubmVjdCh7Li4udGhpcy5jb25uZWN0T3B0cyxzZXJ2ZXJuYW1lOnQmJmEuaXNJUCh0KT92b2lkIDA6dH0pfWVsc2UgZm4oIkNyZWF0aW5nIGBuZXQuU29ja2V0YDogJW8iLHRoaXMuY29ubmVjdE9wdHMpLHI9YS5jb25uZWN0KHRoaXMuY29ubmVjdE9wdHMpO2NvbnN0IG89ImZ1bmN0aW9uIj09dHlwZW9mIHRoaXMucHJveHlIZWFkZXJzP3RoaXMucHJveHlIZWFkZXJzKCk6ey4uLnRoaXMucHJveHlIZWFkZXJzfSxzPWEuaXNJUHY2KG4uaG9zdCk/YFske24uaG9zdH1dYDpuLmhvc3Q7bGV0IGk9YENPTk5FQ1QgJHtzfToke24ucG9ydH0gSFRUUC8xLjFcclxuYDtpZihlLnVzZXJuYW1lfHxlLnBhc3N3b3JkKXtjb25zdCB0PWAke2RlY29kZVVSSUNvbXBvbmVudChlLnVzZXJuYW1lKX06JHtkZWNvZGVVUklDb21wb25lbnQoZS5wYXNzd29yZCl9YDtvWyJQcm94eS1BdXRob3JpemF0aW9uIl09YEJhc2ljICR7QnVmZmVyLmZyb20odCkudG9TdHJpbmcoImJhc2U2NCIpfWB9by5Ib3N0PWAke3N9OiR7bi5wb3J0fWAsb1siUHJveHktQ29ubmVjdGlvbiJdfHwob1siUHJveHktQ29ubmVjdGlvbiJdPXRoaXMua2VlcEFsaXZlPyJLZWVwLUFsaXZlIjoiY2xvc2UiKTtmb3IoY29uc3QgdCBvZiBPYmplY3Qua2V5cyhvKSlpKz1gJHt0fTogJHtvW3RdfVxyXG5gO2NvbnN0IGM9YW4ocik7ci53cml0ZShgJHtpfVxyXG5gKTtjb25zdHtjb25uZWN0OnUsYnVmZmVyZWQ6aH09YXdhaXQgYztpZih0LmVtaXQoInByb3h5Q29ubmVjdCIsdSksdGhpcy5lbWl0KCJwcm94eUNvbm5lY3QiLHUsdCksMjAwPT09dS5zdGF0dXNDb2RlKXtpZih0Lm9uY2UoInNvY2tldCIscG4pLG4uc2VjdXJlRW5kcG9pbnQpe2ZuKCJVcGdyYWRpbmcgc29ja2V0IGNvbm5lY3Rpb24gdG8gVExTIik7Y29uc3QgdD1uLnNlcnZlcm5hbWV8fG4uaG9zdDtyZXR1cm4gZi5jb25uZWN0KHsuLi5sbihuLCJob3N0IiwicGF0aCIsInBvcnQiKSxzb2NrZXQ6cixzZXJ2ZXJuYW1lOmEuaXNJUCh0KT92b2lkIDA6dH0pfXJldHVybiByfXIuZGVzdHJveSgpO2NvbnN0IHA9bmV3IGEuU29ja2V0KHt3cml0YWJsZTohMX0pO3JldHVybiBwLnJlYWRhYmxlPSEwLHQub25jZSgic29ja2V0IiwodD0+e2ZuKCJSZXBsYXlpbmcgcHJveHkgYnVmZmVyIGZvciBmYWlsZWQgcmVxdWVzdCIpLHQucHVzaChoKSx0LnB1c2gobnVsbCl9KSkscH19ZnVuY3Rpb24gcG4odCl7dC5yZXN1bWUoKX1mdW5jdGlvbiBsbih0LC4uLm4pe2NvbnN0IGU9e307bGV0IHI7Zm9yKHIgaW4gdCluLmluY2x1ZGVzKHIpfHwoZVtyXT10W3JdKTtyZXR1cm4gZX1obi5fX2luaXRTdGF0aWMoKTtjb25zdCBkbj0zMjc2ODtmdW5jdGlvbiBtbih0KXtyZXR1cm4gdC5yZXBsYWNlKC9eW0EtWl06LywiIikucmVwbGFjZSgvXFwvZywiLyIpfWNvbnN0IGduPW47bGV0IHluLGJuPTAsX249e307ZnVuY3Rpb24gdm4odCl7Z24uZGVidWcmJmNvbnNvbGUubG9nKGBbQU5SIFdvcmtlcl0gJHt0fWApfXZhciB3bixTbiwkbjtjb25zdCBFbj1mdW5jdGlvbih0KXtsZXQgbjt0cnl7bj1uZXcgVVJMKHQudXJsKX1jYXRjaChuKXtyZXR1cm4gdigoKCk9Pntjb25zb2xlLndhcm4oIltAc2VudHJ5L25vZGVdOiBJbnZhbGlkIGRzbiBvciB0dW5uZWwgb3B0aW9uLCB3aWxsIG5vdCBzZW5kIGFueSBldmVudHMuIFRoZSB0dW5uZWwgb3B0aW9uIG11c3QgYmUgYSBmdWxsIFVSTCB3aGVuIHVzZWQuIil9KSksbm4odCwoKCk9PlByb21pc2UucmVzb2x2ZSh7fSkpKX1jb25zdCBlPSJodHRwczoiPT09bi5wcm90b2NvbCxyPWZ1bmN0aW9uKHQsbil7Y29uc3R7bm9fcHJveHk6ZX09cHJvY2Vzcy5lbnYscj1lPy5zcGxpdCgiLCIpLnNvbWUoKG49PnQuaG9zdC5lbmRzV2l0aChuKXx8dC5ob3N0bmFtZS5lbmRzV2l0aChuKSkpO3JldHVybiByP3ZvaWQgMDpufShuLHQucHJveHl8fChlP3Byb2Nlc3MuZW52Lmh0dHBzX3Byb3h5OnZvaWQgMCl8fHByb2Nlc3MuZW52Lmh0dHBfcHJveHkpLG89ZT9pOnMsYT12b2lkIDAhPT10LmtlZXBBbGl2ZSYmdC5rZWVwQWxpdmUsZj1yP25ldyBobihyKTpuZXcgby5BZ2VudCh7a2VlcEFsaXZlOmEsbWF4U29ja2V0czozMCx0aW1lb3V0OjJlM30pLGg9ZnVuY3Rpb24odCxuLGUpe2NvbnN0e2hvc3RuYW1lOnIscGF0aG5hbWU6byxwb3J0OnMscHJvdG9jb2w6aSxzZWFyY2g6YX09bmV3IFVSTCh0LnVybCk7cmV0dXJuIGZ1bmN0aW9uKGYpe3JldHVybiBuZXcgUHJvbWlzZSgoKGgscCk9PntGdCgoKCk9PntsZXQgbD1mdW5jdGlvbih0KXtyZXR1cm4gbmV3IGMoe3JlYWQoKXt0aGlzLnB1c2godCksdGhpcy5wdXNoKG51bGwpfX0pfShmLmJvZHkpO2NvbnN0IGQ9ey4uLnQuaGVhZGVyc307Zi5ib2R5Lmxlbmd0aD5kbiYmKGRbImNvbnRlbnQtZW5jb2RpbmciXT0iZ3ppcCIsbD1sLnBpcGUodSgpKSk7Y29uc3QgbT1uLnJlcXVlc3Qoe21ldGhvZDoiUE9TVCIsYWdlbnQ6ZSxoZWFkZXJzOmQsaG9zdG5hbWU6cixwYXRoOmAke299JHthfWAscG9ydDpzLHByb3RvY29sOmksY2E6dC5jYUNlcnRzfSwodD0+e3Qub24oImRhdGEiLCgoKT0+e30pKSx0Lm9uKCJlbmQiLCgoKT0+e30pKSx0LnNldEVuY29kaW5nKCJ1dGY4Iik7Y29uc3Qgbj10LmhlYWRlcnNbInJldHJ5LWFmdGVyIl0/P251bGwsZT10LmhlYWRlcnNbIngtc2VudHJ5LXJhdGUtbGltaXRzIl0/P251bGw7aCh7c3RhdHVzQ29kZTp0LnN0YXR1c0NvZGUsaGVhZGVyczp7InJldHJ5LWFmdGVyIjpuLCJ4LXNlbnRyeS1yYXRlLWxpbWl0cyI6QXJyYXkuaXNBcnJheShlKT9lWzBdfHxudWxsOmV9fSl9KSk7bS5vbigiZXJyb3IiLHApLGwucGlwZShtKX0pKX0pKX19KHQsdC5odHRwTW9kdWxlPz9vLGYpO3JldHVybiBubih0LGgpfSh7dXJsOih3bj1nbi5kc24sU249Z24udHVubmVsLCRuPWduLnNka01ldGFkYXRhLnNkayxTbnx8YCR7ZnVuY3Rpb24odCl7cmV0dXJuYCR7ZnVuY3Rpb24odCl7Y29uc3Qgbj10LnByb3RvY29sP2Ake3QucHJvdG9jb2x9OmA6IiIsZT10LnBvcnQ/YDoke3QucG9ydH1gOiIiO3JldHVybmAke259Ly8ke3QuaG9zdH0ke2V9JHt0LnBhdGg/YC8ke3QucGF0aH1gOiIifS9hcGkvYH0odCl9JHt0LnByb2plY3RJZH0vZW52ZWxvcGUvYH0od24pfT8ke2Z1bmN0aW9uKHQsbil7Y29uc3QgZT17c2VudHJ5X3ZlcnNpb246VnR9O3JldHVybiB0LnB1YmxpY0tleSYmKGUuc2VudHJ5X2tleT10LnB1YmxpY0tleSksbiYmKGUuc2VudHJ5X2NsaWVudD1gJHtuLm5hbWV9LyR7bi52ZXJzaW9ufWApLG5ldyBVUkxTZWFyY2hQYXJhbXMoZSkudG9TdHJpbmcoKX0od24sJG4pfWApfSk7YXN5bmMgZnVuY3Rpb24geG4oKXtpZih5bil7dm4oIlNlbmRpbmcgYWJub3JtYWwgc2Vzc2lvbiIpLFYoeW4se3N0YXR1czoiYWJub3JtYWwiLGFibm9ybWFsX21lY2hhbmlzbToiYW5yX2ZvcmVncm91bmQiLHJlbGVhc2U6Z24ucmVsZWFzZSxlbnZpcm9ubWVudDpnbi5lbnZpcm9ubWVudH0pO2NvbnN0IHQ9ZnVuY3Rpb24odCxuLGUscil7Y29uc3Qgbz16dChlKTtyZXR1cm4gTHQoe3NlbnRfYXQ6KG5ldyBEYXRlKS50b0lTT1N0cmluZygpLC4uLm8mJntzZGs6b30sLi4uISFyJiZuJiZ7ZHNuOkF0KG4pfX0sWyJhZ2dyZWdhdGVzImluIHQ/W3t0eXBlOiJzZXNzaW9ucyJ9LHRdOlt7dHlwZToic2Vzc2lvbiJ9LHQudG9KU09OKCldXSl9KHluLGduLmRzbixnbi5zZGtNZXRhZGF0YSxnbi50dW5uZWwpO3ZuKEpTT04uc3RyaW5naWZ5KHQpKSxhd2FpdCBFbi5zZW5kKHQpO3RyeXtlPy5wb3N0TWVzc2FnZSgic2Vzc2lvbi1lbmRlZCIpfWNhdGNoKHQpe319fWZ1bmN0aW9uIE5uKHQpe2lmKCF0KXJldHVybjtjb25zdCBuPWZ1bmN0aW9uKHQpe2lmKCF0Lmxlbmd0aClyZXR1cm5bXTtjb25zdCBuPUFycmF5LmZyb20odCk7cmV0dXJuL3NlbnRyeVdyYXBwZWQvLnRlc3QoeChuKS5mdW5jdGlvbnx8IiIpJiZuLnBvcCgpLG4ucmV2ZXJzZSgpLEUudGVzdCh4KG4pLmZ1bmN0aW9ufHwiIikmJihuLnBvcCgpLEUudGVzdCh4KG4pLmZ1bmN0aW9ufHwiIikmJm4ucG9wKCkpLG4uc2xpY2UoMCxTKS5tYXAoKHQ9Pih7Li4udCxmaWxlbmFtZTp0LmZpbGVuYW1lfHx4KG4pLmZpbGVuYW1lLGZ1bmN0aW9uOnQuZnVuY3Rpb258fCR9KSkpfSh0KTtpZihnbi5hcHBSb290UGF0aClmb3IoY29uc3QgdCBvZiBuKXQuZmlsZW5hbWUmJih0LmZpbGVuYW1lPU10KHQuZmlsZW5hbWUsZ24uYXBwUm9vdFBhdGgpKTtyZXR1cm4gbn1hc3luYyBmdW5jdGlvbiBUbih0LG4pe2lmKGJuPj1nbi5tYXhBbnJFdmVudHMpcmV0dXJuO2JuKz0xLGF3YWl0IHhuKCksdm4oIlNlbmRpbmcgZXZlbnQiKTtjb25zdCBlPXtldmVudF9pZDp6KCksY29udGV4dHM6Z24uY29udGV4dHMscmVsZWFzZTpnbi5yZWxlYXNlLGVudmlyb25tZW50OmduLmVudmlyb25tZW50LGRpc3Q6Z24uZGlzdCxwbGF0Zm9ybToibm9kZSIsbGV2ZWw6ImVycm9yIixleGNlcHRpb246e3ZhbHVlczpbe3R5cGU6IkFwcGxpY2F0aW9uTm90UmVzcG9uZGluZyIsdmFsdWU6YEFwcGxpY2F0aW9uIE5vdCBSZXNwb25kaW5nIGZvciBhdCBsZWFzdCAke2duLmFuclRocmVzaG9sZH0gbXNgLHN0YWNrdHJhY2U6e2ZyYW1lczpObih0KX0sbWVjaGFuaXNtOnt0eXBlOiJBTlIifX1dfSx0YWdzOmduLnN0YXRpY1RhZ3N9O24mJmZ1bmN0aW9uKHQsbil7aWYoS3QodCxuKSwhdC5jb250ZXh0cz8udHJhY2Upe2NvbnN0e3RyYWNlSWQ6ZSxwYXJlbnRTcGFuSWQ6cixwcm9wYWdhdGlvblNwYW5JZDpvfT1uLnByb3BhZ2F0aW9uQ29udGV4dDt0LmNvbnRleHRzPXt0cmFjZTp7dHJhY2VfaWQ6ZSxzcGFuX2lkOm98fHEoKSxwYXJlbnRfc3Bhbl9pZDpyfSwuLi50LmNvbnRleHRzfX19KGUsbiksZnVuY3Rpb24odCl7aWYoMD09PU9iamVjdC5rZXlzKF9uKS5sZW5ndGgpcmV0dXJuO2NvbnN0IG49Z24uYXBwUm9vdFBhdGg/e306X247aWYoZ24uYXBwUm9vdFBhdGgpZm9yKGNvbnN0W3QsZV1vZiBPYmplY3QuZW50cmllcyhfbikpbltNdCh0LGduLmFwcFJvb3RQYXRoKV09ZTtjb25zdCBlPW5ldyBNYXA7Zm9yKGNvbnN0IHIgb2YgdC5leGNlcHRpb24/LnZhbHVlc3x8W10pZm9yKGNvbnN0IHQgb2Ygci5zdGFja3RyYWNlPy5mcmFtZXN8fFtdKXtjb25zdCByPXQuYWJzX3BhdGh8fHQuZmlsZW5hbWU7ciYmbltyXSYmZS5zZXQocixuW3JdKX1pZihlLnNpemU+MCl7Y29uc3Qgbj1bXTtmb3IoY29uc3RbdCxyXW9mIGUuZW50cmllcygpKW4ucHVzaCh7dHlwZToic291cmNlbWFwIixjb2RlX2ZpbGU6dCxkZWJ1Z19pZDpyfSk7dC5kZWJ1Z19tZXRhPXtpbWFnZXM6bn19fShlKTtjb25zdCByPUh0KGUsZ24uZHNuLGduLnNka01ldGFkYXRhLGduLnR1bm5lbCk7dm4oSlNPTi5zdHJpbmdpZnkocikpLGF3YWl0IEVuLnNlbmQociksYXdhaXQgRW4uZmx1c2goMmUzKSxibj49Z24ubWF4QW5yRXZlbnRzJiZzZXRUaW1lb3V0KCgoKT0+e3Byb2Nlc3MuZXhpdCgwKX0pLDVlMyl9bGV0IENuO2lmKHZuKCJTdGFydGVkIiksZ24uY2FwdHVyZVN0YWNrVHJhY2Upe3ZuKCJDb25uZWN0aW5nIHRvIGRlYnVnZ2VyIik7Y29uc3Qgbj1uZXcgdDtuLmNvbm5lY3RUb01haW5UaHJlYWQoKSx2bigiQ29ubmVjdGVkIHRvIGRlYnVnZ2VyIik7Y29uc3QgZT1uZXcgTWFwO24ub24oIkRlYnVnZ2VyLnNjcmlwdFBhcnNlZCIsKHQ9PntlLnNldCh0LnBhcmFtcy5zY3JpcHRJZCx0LnBhcmFtcy51cmwpfSkpLG4ub24oIkRlYnVnZ2VyLnBhdXNlZCIsKHQ9PntpZigib3RoZXIiPT09dC5wYXJhbXMucmVhc29uKXRyeXt2bigiRGVidWdnZXIgcGF1c2VkIik7Y29uc3Qgcz1bLi4udC5wYXJhbXMuY2FsbEZyYW1lc10saT1nbi5hcHBSb290UGF0aD9mdW5jdGlvbih0PShwcm9jZXNzLmFyZ3ZbMV0/cm4ocHJvY2Vzcy5hcmd2WzFdKTpwcm9jZXNzLmN3ZCgpKSxuPSJcXCI9PT1vKXtjb25zdCBlPW4/bW4odCk6dDtyZXR1cm4gdD0+e2lmKCF0KXJldHVybjtjb25zdCBvPW4/bW4odCk6dDtsZXR7ZGlyOnMsYmFzZTppLGV4dDpjfT1yLnBhcnNlKG8pOyIuanMiIT09YyYmIi5tanMiIT09YyYmIi5janMiIT09Y3x8KGk9aS5zbGljZSgwLC0xKmMubGVuZ3RoKSk7Y29uc3QgdT1kZWNvZGVVUklDb21wb25lbnQoaSk7c3x8KHM9Ii4iKTtjb25zdCBhPXMubGFzdEluZGV4T2YoIi9ub2RlX21vZHVsZXMiKTtpZihhPi0xKXJldHVybmAke3Muc2xpY2UoYSsxNCkucmVwbGFjZSgvXC8vZywiLiIpfToke3V9YDtpZihzLnN0YXJ0c1dpdGgoZSkpe2NvbnN0IHQ9cy5zbGljZShlLmxlbmd0aCsxKS5yZXBsYWNlKC9cLy9nLCIuIik7cmV0dXJuIHQ/YCR7dH06JHt1fWA6dX1yZXR1cm4gdX19KGduLmFwcFJvb3RQYXRoKTooKT0+e30sYz1zLm1hcCgodD0+ZnVuY3Rpb24odCxuLGUpe2NvbnN0IHI9bj9uLnJlcGxhY2UoL15maWxlOlwvXC8vLCIiKTp2b2lkIDAsbz10LmxvY2F0aW9uLmNvbHVtbk51bWJlcj90LmxvY2F0aW9uLmNvbHVtbk51bWJlcisxOnZvaWQgMCxzPXQubG9jYXRpb24ubGluZU51bWJlcj90LmxvY2F0aW9uLmxpbmVOdW1iZXIrMTp2b2lkIDA7cmV0dXJuIEooe2ZpbGVuYW1lOnIsbW9kdWxlOmUociksZnVuY3Rpb246dC5mdW5jdGlvbk5hbWV8fCQsY29sbm86byxsaW5lbm86cyxpbl9hcHA6cj9vbihyKTp2b2lkIDB9KX0odCxlLmdldCh0LmxvY2F0aW9uLnNjcmlwdElkKSxpKSkpLHU9c2V0VGltZW91dCgoKCk9PntUbihjKS50aGVuKG51bGwsKCgpPT57dm4oIlNlbmRpbmcgQU5SIGV2ZW50IGZhaWxlZC4iKX0pKX0pLDVlMyk7bi5wb3N0KCJSdW50aW1lLmV2YWx1YXRlIix7ZXhwcmVzc2lvbjoiZ2xvYmFsLl9fU0VOVFJZX0dFVF9TQ09QRVNfXygpOyIsc2lsZW50OiEwLHJldHVybkJ5VmFsdWU6ITB9LCgodCxlKT0+e3QmJnZuKGBFcnJvciBleGVjdXRpbmcgc2NyaXB0OiAnJHt0Lm1lc3NhZ2V9J2ApLGNsZWFyVGltZW91dCh1KTtjb25zdCByPWU/LnJlc3VsdD9lLnJlc3VsdC52YWx1ZTp2b2lkIDA7bi5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKSxuLnBvc3QoIkRlYnVnZ2VyLmRpc2FibGUiKSxUbihjLHIpLnRoZW4obnVsbCwoKCk9Pnt2bigiU2VuZGluZyBBTlIgZXZlbnQgZmFpbGVkLiIpfSkpfSkpfWNhdGNoKHQpe3Rocm93IG4ucG9zdCgiRGVidWdnZXIucmVzdW1lIiksbi5wb3N0KCJEZWJ1Z2dlci5kaXNhYmxlIiksdH19KSksQ249KCk9Pnt0cnl7bi5wb3N0KCJEZWJ1Z2dlci5lbmFibGUiLCgoKT0+e24ucG9zdCgiRGVidWdnZXIucGF1c2UiKX0pKX1jYXRjaCh0KXt9fX1jb25zdHtwb2xsOmpufT1mdW5jdGlvbih0LG4sZSxyKXtjb25zdCBvPXQoKTtsZXQgcz0hMSxpPSEwO3JldHVybiBzZXRJbnRlcnZhbCgoKCk9Pntjb25zdCB0PW8uZ2V0VGltZU1zKCk7ITE9PT1zJiZ0Pm4rZSYmKHM9ITAsaSYmcigpKSx0PG4rZSYmKHM9ITEpfSksMjApLHtwb2xsOigpPT57by5yZXNldCgpfSxlbmFibGVkOnQ9PntpPXR9fX0oKGZ1bmN0aW9uKCl7bGV0IHQ9cHJvY2Vzcy5ocnRpbWUoKTtyZXR1cm57Z2V0VGltZU1zOigpPT57Y29uc3RbbixlXT1wcm9jZXNzLmhydGltZSh0KTtyZXR1cm4gTWF0aC5mbG9vcigxZTMqbitlLzFlNil9LHJlc2V0OigpPT57dD1wcm9jZXNzLmhydGltZSgpfX19KSxnbi5wb2xsSW50ZXJ2YWwsZ24uYW5yVGhyZXNob2xkLChmdW5jdGlvbigpe3ZuKCJXYXRjaGRvZyB0aW1lb3V0IiksQ24/KHZuKCJQYXVzaW5nIGRlYnVnZ2VyIHRvIGNhcHR1cmUgc3RhY2sgdHJhY2UiKSxDbigpKToodm4oIkNhcHR1cmluZyBldmVudCB3aXRob3V0IGEgc3RhY2sgdHJhY2UiKSxUbigpLnRoZW4obnVsbCwoKCk9Pnt2bigiU2VuZGluZyBBTlIgZXZlbnQgZmFpbGVkIG9uIHdhdGNoZG9nIHRpbWVvdXQuIil9KSkpfSkpO2U/Lm9uKCJtZXNzYWdlIiwodD0+e3Quc2Vzc2lvbiYmKHluPUsodC5zZXNzaW9uKSksdC5kZWJ1Z0ltYWdlcyYmKF9uPXQuZGVidWdJbWFnZXMpLGpuKCl9KSk7';
|
|
12
|
+
const base64WorkerScript = 'LyohIEBzZW50cnkvbm9kZSA5LjEwLjAgKGUzODNmZmYpIHwgaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdCAqLwppbXBvcnR7U2Vzc2lvbiBhcyB0fWZyb20ibm9kZTppbnNwZWN0b3IiO2ltcG9ydHt3b3JrZXJEYXRhIGFzIG4scGFyZW50UG9ydCBhcyBlfWZyb20ibm9kZTp3b3JrZXJfdGhyZWFkcyI7aW1wb3J0e3Bvc2l4IGFzIHIsc2VwIGFzIG99ZnJvbSJub2RlOnBhdGgiO2ltcG9ydCphcyBzIGZyb20ibm9kZTpodHRwIjtpbXBvcnQqYXMgaSBmcm9tIm5vZGU6aHR0cHMiO2ltcG9ydHtSZWFkYWJsZSBhcyBjfWZyb20ibm9kZTpzdHJlYW0iO2ltcG9ydHtjcmVhdGVHemlwIGFzIHV9ZnJvbSJub2RlOnpsaWIiO2ltcG9ydCphcyBhIGZyb20ibm9kZTpuZXQiO2ltcG9ydCphcyBmIGZyb20ibm9kZTp0bHMiO2NvbnN0IGg9InVuZGVmaW5lZCI9PXR5cGVvZiBfX1NFTlRSWV9ERUJVR19ffHxfX1NFTlRSWV9ERUJVR19fLHA9Z2xvYmFsVGhpcyxsPSJ1bmRlZmluZWQiPT10eXBlb2YgX19TRU5UUllfREVCVUdfX3x8X19TRU5UUllfREVCVUdfXyxkPSI5LjEwLjAiO2Z1bmN0aW9uIG0oKXtyZXR1cm4gZyhwKSxwfWZ1bmN0aW9uIGcodCl7Y29uc3Qgbj10Ll9fU0VOVFJZX189dC5fX1NFTlRSWV9ffHx7fTtyZXR1cm4gbi52ZXJzaW9uPW4udmVyc2lvbnx8ZCxuW2RdPW5bZF18fHt9fWZ1bmN0aW9uIHkodCxuLGU9cCl7Y29uc3Qgcj1lLl9fU0VOVFJZX189ZS5fX1NFTlRSWV9ffHx7fSxvPXJbZF09cltkXXx8e307cmV0dXJuIG9bdF18fChvW3RdPW4oKSl9Y29uc3QgYj1bImRlYnVnIiwiaW5mbyIsIndhcm4iLCJlcnJvciIsImxvZyIsImFzc2VydCIsInRyYWNlIl0sXz17fTtmdW5jdGlvbiB2KHQpe2lmKCEoImNvbnNvbGUiaW4gcCkpcmV0dXJuIHQoKTtjb25zdCBuPXAuY29uc29sZSxlPXt9LHI9T2JqZWN0LmtleXMoXyk7ci5mb3JFYWNoKCh0PT57Y29uc3Qgcj1fW3RdO2VbdF09blt0XSxuW3RdPXJ9KSk7dHJ5e3JldHVybiB0KCl9ZmluYWxseXtyLmZvckVhY2goKHQ9PntuW3RdPWVbdF19KSl9fWNvbnN0IHc9eSgibG9nZ2VyIiwoZnVuY3Rpb24oKXtsZXQgdD0hMTtjb25zdCBuPXtlbmFibGU6KCk9Pnt0PSEwfSxkaXNhYmxlOigpPT57dD0hMX0saXNFbmFibGVkOigpPT50fTtyZXR1cm4gbD9iLmZvckVhY2goKGU9PntuW2VdPSguLi5uKT0+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+PTMwMCkmJmgmJncud2FybihgU2VudHJ5IHJlc3BvbmRlZCB3aXRoIHN0YXR1cyBjb2RlICR7dC5zdGF0dXNDb2RlfSB0byBzZW50IGV2ZW50LmApLHI9UXQocix0KSx0KSksKHQ9Pnt0aHJvdyBpKCksdH0pKSkpLnRoZW4oKHQ9PnQpLCh0PT57aWYodD09PVZ0KXJldHVybiBoJiZ3LmVycm9yKCJTa2lwcGVkIHNlbmRpbmcgZXZlbnQgYmVjYXVzZSBidWZmZXIgaXMgZnVsbC4iKSxpKCksSCh7fSk7dGhyb3cgdH0pKX0sZmx1c2g6dD0+ZS5kcmFpbih0KX19Y29uc3Qgbm49L14oXFMrOlxcfFwvPykoW1xzXFNdKj8pKCg/OlwuezEsMn18W14vXFxdKz98KShcLlteLi9cXF0qfCkpKD86Wy9cXF0qKSQvO2Z1bmN0aW9uIGVuKHQpe2NvbnN0IG49ZnVuY3Rpb24odCl7Y29uc3Qgbj10Lmxlbmd0aD4xMDI0P2A8dHJ1bmNhdGVkPiR7dC5zbGljZSgtMTAyNCl9YDp0LGU9bm4uZXhlYyhuKTtyZXR1cm4gZT9lLnNsaWNlKDEpOltdfSh0KSxlPW5bMF18fCIiO2xldCByPW5bMV07cmV0dXJuIGV8fHI/KHImJihyPXIuc2xpY2UoMCxyLmxlbmd0aC0xKSksZStyKToiLiJ9ZnVuY3Rpb24gcm4odCxuPSExKXtyZXR1cm4hKG58fHQmJiF0LnN0YXJ0c1dpdGgoIi8iKSYmIXQubWF0Y2goL15bQS1aXTovKSYmIXQuc3RhcnRzV2l0aCgiLiIpJiYhdC5tYXRjaCgvXlthLXpBLVpdKFthLXpBLVowLTkuXC0rXSkqOlwvXC8vKSkmJnZvaWQgMCE9PXQmJiF0LmluY2x1ZGVzKCJub2RlX21vZHVsZXMvIil9Y29uc3Qgb249U3ltYm9sKCJBZ2VudEJhc2VJbnRlcm5hbFN0YXRlIik7Y2xhc3Mgc24gZXh0ZW5kcyBzLkFnZW50e2NvbnN0cnVjdG9yKHQpe3N1cGVyKHQpLHRoaXNbb25dPXt9fWlzU2VjdXJlRW5kcG9pbnQodCl7aWYodCl7aWYoImJvb2xlYW4iPT10eXBlb2YgdC5zZWN1cmVFbmRwb2ludClyZXR1cm4gdC5zZWN1cmVFbmRwb2ludDtpZigic3RyaW5nIj09dHlwZW9mIHQucHJvdG9jb2wpcmV0dXJuImh0dHBzOiI9PT10LnByb3RvY29sfWNvbnN0e3N0YWNrOm59PW5ldyBFcnJvcjtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIG4mJm4uc3BsaXQoIlxuIikuc29tZSgodD0+LTEhPT10LmluZGV4T2YoIihodHRwcy5qczoiKXx8LTEhPT10LmluZGV4T2YoIm5vZGU6aHR0cHM6IikpKX1jcmVhdGVTb2NrZXQodCxuLGUpe2NvbnN0IHI9ey4uLm4sc2VjdXJlRW5kcG9pbnQ6dGhpcy5pc1NlY3VyZUVuZHBvaW50KG4pfTtQcm9taXNlLnJlc29sdmUoKS50aGVuKCgoKT0+dGhpcy5jb25uZWN0KHQscikpKS50aGVuKChvPT57aWYobyBpbnN0YW5jZW9mIHMuQWdlbnQpcmV0dXJuIG8uYWRkUmVxdWVzdCh0LHIpO3RoaXNbb25dLmN1cnJlbnRTb2NrZXQ9byxzdXBlci5jcmVhdGVTb2NrZXQodCxuLGUpfSksZSl9Y3JlYXRlQ29ubmVjdGlvbigpe2NvbnN0IHQ9dGhpc1tvbl0uY3VycmVudFNvY2tldDtpZih0aGlzW29uXS5jdXJyZW50U29ja2V0PXZvaWQgMCwhdCl0aHJvdyBuZXcgRXJyb3IoIk5vIHNvY2tldCB3YXMgcmV0dXJuZWQgaW4gdGhlIGBjb25uZWN0KClgIGZ1bmN0aW9uIik7cmV0dXJuIHR9Z2V0IGRlZmF1bHRQb3J0KCl7cmV0dXJuIHRoaXNbb25dLmRlZmF1bHRQb3J0Pz8oImh0dHBzOiI9PT10aGlzLnByb3RvY29sPzQ0Mzo4MCl9c2V0IGRlZmF1bHRQb3J0KHQpe3RoaXNbb25dJiYodGhpc1tvbl0uZGVmYXVsdFBvcnQ9dCl9Z2V0IHByb3RvY29sKCl7cmV0dXJuIHRoaXNbb25dLnByb3RvY29sPz8odGhpcy5pc1NlY3VyZUVuZHBvaW50KCk/Imh0dHBzOiI6Imh0dHA6Iil9c2V0IHByb3RvY29sKHQpe3RoaXNbb25dJiYodGhpc1tvbl0ucHJvdG9jb2w9dCl9fWZ1bmN0aW9uIGNuKC4uLnQpe3cubG9nKCJbaHR0cHMtcHJveHktYWdlbnQ6cGFyc2UtcHJveHktcmVzcG9uc2VdIiwuLi50KX1mdW5jdGlvbiB1bih0KXtyZXR1cm4gbmV3IFByb21pc2UoKChuLGUpPT57bGV0IHI9MDtjb25zdCBvPVtdO2Z1bmN0aW9uIHMoKXtjb25zdCBjPXQucmVhZCgpO2M/ZnVuY3Rpb24oYyl7by5wdXNoKGMpLHIrPWMubGVuZ3RoO2NvbnN0IHU9QnVmZmVyLmNvbmNhdChvLHIpLGE9dS5pbmRleE9mKCJcclxuXHJcbiIpO2lmKC0xPT09YSlyZXR1cm4gY24oImhhdmUgbm90IHJlY2VpdmVkIGVuZCBvZiBIVFRQIGhlYWRlcnMgeWV0Li4uIiksdm9pZCBzKCk7Y29uc3QgZj11LnN1YmFycmF5KDAsYSkudG9TdHJpbmcoImFzY2lpIikuc3BsaXQoIlxyXG4iKSxoPWYuc2hpZnQoKTtpZighaClyZXR1cm4gdC5kZXN0cm95KCksZShuZXcgRXJyb3IoIk5vIGhlYWRlciByZWNlaXZlZCBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2UiKSk7Y29uc3QgcD1oLnNwbGl0KCIgIiksbD0rKHBbMV18fDApLGQ9cC5zbGljZSgyKS5qb2luKCIgIiksbT17fTtmb3IoY29uc3QgbiBvZiBmKXtpZighbiljb250aW51ZTtjb25zdCByPW4uaW5kZXhPZigiOiIpO2lmKC0xPT09cilyZXR1cm4gdC5kZXN0cm95KCksZShuZXcgRXJyb3IoYEludmFsaWQgaGVhZGVyIGZyb20gcHJveHkgQ09OTkVDVCByZXNwb25zZTogIiR7bn0iYCkpO2NvbnN0IG89bi5zbGljZSgwLHIpLnRvTG93ZXJDYXNlKCkscz1uLnNsaWNlKHIrMSkudHJpbVN0YXJ0KCksaT1tW29dOyJzdHJpbmciPT10eXBlb2YgaT9tW29dPVtpLHNdOkFycmF5LmlzQXJyYXkoaSk/aS5wdXNoKHMpOm1bb109c31jbigiZ290IHByb3h5IHNlcnZlciByZXNwb25zZTogJW8gJW8iLGgsbSksaSgpLG4oe2Nvbm5lY3Q6e3N0YXR1c0NvZGU6bCxzdGF0dXNUZXh0OmQsaGVhZGVyczptfSxidWZmZXJlZDp1fSl9KGMpOnQub25jZSgicmVhZGFibGUiLHMpfWZ1bmN0aW9uIGkoKXt0LnJlbW92ZUxpc3RlbmVyKCJlbmQiLGMpLHQucmVtb3ZlTGlzdGVuZXIoImVycm9yIix1KSx0LnJlbW92ZUxpc3RlbmVyKCJyZWFkYWJsZSIscyl9ZnVuY3Rpb24gYygpe2koKSxjbigib25lbmQiKSxlKG5ldyBFcnJvcigiUHJveHkgY29ubmVjdGlvbiBlbmRlZCBiZWZvcmUgcmVjZWl2aW5nIENPTk5FQ1QgcmVzcG9uc2UiKSl9ZnVuY3Rpb24gdSh0KXtpKCksY24oIm9uZXJyb3IgJW8iLHQpLGUodCl9dC5vbigiZXJyb3IiLHUpLHQub24oImVuZCIsYykscygpfSkpfWZ1bmN0aW9uIGFuKC4uLnQpe3cubG9nKCJbaHR0cHMtcHJveHktYWdlbnRdIiwuLi50KX1jbGFzcyBmbiBleHRlbmRzIHNue3N0YXRpYyBfX2luaXRTdGF0aWMoKXt0aGlzLnByb3RvY29scz1bImh0dHAiLCJodHRwcyJdfWNvbnN0cnVjdG9yKHQsbil7c3VwZXIobiksdGhpcy5vcHRpb25zPXt9LHRoaXMucHJveHk9InN0cmluZyI9PXR5cGVvZiB0P25ldyBVUkwodCk6dCx0aGlzLnByb3h5SGVhZGVycz1uPy5oZWFkZXJzPz97fSxhbigiQ3JlYXRpbmcgbmV3IEh0dHBzUHJveHlBZ2VudCBpbnN0YW5jZTogJW8iLHRoaXMucHJveHkuaHJlZik7Y29uc3QgZT0odGhpcy5wcm94eS5ob3N0bmFtZXx8dGhpcy5wcm94eS5ob3N0KS5yZXBsYWNlKC9eXFt8XF0kL2csIiIpLHI9dGhpcy5wcm94eS5wb3J0P3BhcnNlSW50KHRoaXMucHJveHkucG9ydCwxMCk6Imh0dHBzOiI9PT10aGlzLnByb3h5LnByb3RvY29sPzQ0Mzo4MDt0aGlzLmNvbm5lY3RPcHRzPXtBTFBOUHJvdG9jb2xzOlsiaHR0cC8xLjEiXSwuLi5uP3BuKG4sImhlYWRlcnMiKTpudWxsLGhvc3Q6ZSxwb3J0OnJ9fWFzeW5jIGNvbm5lY3QodCxuKXtjb25zdHtwcm94eTplfT10aGlzO2lmKCFuLmhvc3QpdGhyb3cgbmV3IFR5cGVFcnJvcignTm8gImhvc3QiIHByb3ZpZGVkJyk7bGV0IHI7aWYoImh0dHBzOiI9PT1lLnByb3RvY29sKXthbigiQ3JlYXRpbmcgYHRscy5Tb2NrZXRgOiAlbyIsdGhpcy5jb25uZWN0T3B0cyk7Y29uc3QgdD10aGlzLmNvbm5lY3RPcHRzLnNlcnZlcm5hbWV8fHRoaXMuY29ubmVjdE9wdHMuaG9zdDtyPWYuY29ubmVjdCh7Li4udGhpcy5jb25uZWN0T3B0cyxzZXJ2ZXJuYW1lOnQmJmEuaXNJUCh0KT92b2lkIDA6dH0pfWVsc2UgYW4oIkNyZWF0aW5nIGBuZXQuU29ja2V0YDogJW8iLHRoaXMuY29ubmVjdE9wdHMpLHI9YS5jb25uZWN0KHRoaXMuY29ubmVjdE9wdHMpO2NvbnN0IG89ImZ1bmN0aW9uIj09dHlwZW9mIHRoaXMucHJveHlIZWFkZXJzP3RoaXMucHJveHlIZWFkZXJzKCk6ey4uLnRoaXMucHJveHlIZWFkZXJzfSxzPWEuaXNJUHY2KG4uaG9zdCk/YFske24uaG9zdH1dYDpuLmhvc3Q7bGV0IGk9YENPTk5FQ1QgJHtzfToke24ucG9ydH0gSFRUUC8xLjFcclxuYDtpZihlLnVzZXJuYW1lfHxlLnBhc3N3b3JkKXtjb25zdCB0PWAke2RlY29kZVVSSUNvbXBvbmVudChlLnVzZXJuYW1lKX06JHtkZWNvZGVVUklDb21wb25lbnQoZS5wYXNzd29yZCl9YDtvWyJQcm94eS1BdXRob3JpemF0aW9uIl09YEJhc2ljICR7QnVmZmVyLmZyb20odCkudG9TdHJpbmcoImJhc2U2NCIpfWB9by5Ib3N0PWAke3N9OiR7bi5wb3J0fWAsb1siUHJveHktQ29ubmVjdGlvbiJdfHwob1siUHJveHktQ29ubmVjdGlvbiJdPXRoaXMua2VlcEFsaXZlPyJLZWVwLUFsaXZlIjoiY2xvc2UiKTtmb3IoY29uc3QgdCBvZiBPYmplY3Qua2V5cyhvKSlpKz1gJHt0fTogJHtvW3RdfVxyXG5gO2NvbnN0IGM9dW4ocik7ci53cml0ZShgJHtpfVxyXG5gKTtjb25zdHtjb25uZWN0OnUsYnVmZmVyZWQ6aH09YXdhaXQgYztpZih0LmVtaXQoInByb3h5Q29ubmVjdCIsdSksdGhpcy5lbWl0KCJwcm94eUNvbm5lY3QiLHUsdCksMjAwPT09dS5zdGF0dXNDb2RlKXtpZih0Lm9uY2UoInNvY2tldCIsaG4pLG4uc2VjdXJlRW5kcG9pbnQpe2FuKCJVcGdyYWRpbmcgc29ja2V0IGNvbm5lY3Rpb24gdG8gVExTIik7Y29uc3QgdD1uLnNlcnZlcm5hbWV8fG4uaG9zdDtyZXR1cm4gZi5jb25uZWN0KHsuLi5wbihuLCJob3N0IiwicGF0aCIsInBvcnQiKSxzb2NrZXQ6cixzZXJ2ZXJuYW1lOmEuaXNJUCh0KT92b2lkIDA6dH0pfXJldHVybiByfXIuZGVzdHJveSgpO2NvbnN0IHA9bmV3IGEuU29ja2V0KHt3cml0YWJsZTohMX0pO3JldHVybiBwLnJlYWRhYmxlPSEwLHQub25jZSgic29ja2V0IiwodD0+e2FuKCJSZXBsYXlpbmcgcHJveHkgYnVmZmVyIGZvciBmYWlsZWQgcmVxdWVzdCIpLHQucHVzaChoKSx0LnB1c2gobnVsbCl9KSkscH19ZnVuY3Rpb24gaG4odCl7dC5yZXN1bWUoKX1mdW5jdGlvbiBwbih0LC4uLm4pe2NvbnN0IGU9e307bGV0IHI7Zm9yKHIgaW4gdCluLmluY2x1ZGVzKHIpfHwoZVtyXT10W3JdKTtyZXR1cm4gZX1mbi5fX2luaXRTdGF0aWMoKTtjb25zdCBsbj0zMjc2ODtmdW5jdGlvbiBkbih0KXtyZXR1cm4gdC5yZXBsYWNlKC9eW0EtWl06LywiIikucmVwbGFjZSgvXFwvZywiLyIpfWNvbnN0IG1uPW47bGV0IGduLHluPTAsYm49e307ZnVuY3Rpb24gX24odCl7bW4uZGVidWcmJmNvbnNvbGUubG9nKGBbQU5SIFdvcmtlcl0gJHt0fWApfXZhciB2bix3bixTbjtjb25zdCAkbj1mdW5jdGlvbih0KXtsZXQgbjt0cnl7bj1uZXcgVVJMKHQudXJsKX1jYXRjaChuKXtyZXR1cm4gdigoKCk9Pntjb25zb2xlLndhcm4oIltAc2VudHJ5L25vZGVdOiBJbnZhbGlkIGRzbiBvciB0dW5uZWwgb3B0aW9uLCB3aWxsIG5vdCBzZW5kIGFueSBldmVudHMuIFRoZSB0dW5uZWwgb3B0aW9uIG11c3QgYmUgYSBmdWxsIFVSTCB3aGVuIHVzZWQuIil9KSksdG4odCwoKCk9PlByb21pc2UucmVzb2x2ZSh7fSkpKX1jb25zdCBlPSJodHRwczoiPT09bi5wcm90b2NvbCxyPWZ1bmN0aW9uKHQsbil7Y29uc3R7bm9fcHJveHk6ZX09cHJvY2Vzcy5lbnYscj1lPy5zcGxpdCgiLCIpLnNvbWUoKG49PnQuaG9zdC5lbmRzV2l0aChuKXx8dC5ob3N0bmFtZS5lbmRzV2l0aChuKSkpO3JldHVybiByP3ZvaWQgMDpufShuLHQucHJveHl8fChlP3Byb2Nlc3MuZW52Lmh0dHBzX3Byb3h5OnZvaWQgMCl8fHByb2Nlc3MuZW52Lmh0dHBfcHJveHkpLG89ZT9pOnMsYT12b2lkIDAhPT10LmtlZXBBbGl2ZSYmdC5rZWVwQWxpdmUsZj1yP25ldyBmbihyKTpuZXcgby5BZ2VudCh7a2VlcEFsaXZlOmEsbWF4U29ja2V0czozMCx0aW1lb3V0OjJlM30pLGg9ZnVuY3Rpb24odCxuLGUpe2NvbnN0e2hvc3RuYW1lOnIscGF0aG5hbWU6byxwb3J0OnMscHJvdG9jb2w6aSxzZWFyY2g6YX09bmV3IFVSTCh0LnVybCk7cmV0dXJuIGZ1bmN0aW9uKGYpe3JldHVybiBuZXcgUHJvbWlzZSgoKGgscCk9PntGdCgoKCk9PntsZXQgbD1mdW5jdGlvbih0KXtyZXR1cm4gbmV3IGMoe3JlYWQoKXt0aGlzLnB1c2godCksdGhpcy5wdXNoKG51bGwpfX0pfShmLmJvZHkpO2NvbnN0IGQ9ey4uLnQuaGVhZGVyc307Zi5ib2R5Lmxlbmd0aD5sbiYmKGRbImNvbnRlbnQtZW5jb2RpbmciXT0iZ3ppcCIsbD1sLnBpcGUodSgpKSk7Y29uc3QgbT1uLnJlcXVlc3Qoe21ldGhvZDoiUE9TVCIsYWdlbnQ6ZSxoZWFkZXJzOmQsaG9zdG5hbWU6cixwYXRoOmAke299JHthfWAscG9ydDpzLHByb3RvY29sOmksY2E6dC5jYUNlcnRzfSwodD0+e3Qub24oImRhdGEiLCgoKT0+e30pKSx0Lm9uKCJlbmQiLCgoKT0+e30pKSx0LnNldEVuY29kaW5nKCJ1dGY4Iik7Y29uc3Qgbj10LmhlYWRlcnNbInJldHJ5LWFmdGVyIl0/P251bGwsZT10LmhlYWRlcnNbIngtc2VudHJ5LXJhdGUtbGltaXRzIl0/P251bGw7aCh7c3RhdHVzQ29kZTp0LnN0YXR1c0NvZGUsaGVhZGVyczp7InJldHJ5LWFmdGVyIjpuLCJ4LXNlbnRyeS1yYXRlLWxpbWl0cyI6QXJyYXkuaXNBcnJheShlKT9lWzBdfHxudWxsOmV9fSl9KSk7bS5vbigiZXJyb3IiLHApLGwucGlwZShtKX0pKX0pKX19KHQsdC5odHRwTW9kdWxlPz9vLGYpO3JldHVybiB0bih0LGgpfSh7dXJsOih2bj1tbi5kc24sd249bW4udHVubmVsLFNuPW1uLnNka01ldGFkYXRhLnNkayx3bnx8YCR7ZnVuY3Rpb24odCl7cmV0dXJuYCR7ZnVuY3Rpb24odCl7Y29uc3Qgbj10LnByb3RvY29sP2Ake3QucHJvdG9jb2x9OmA6IiIsZT10LnBvcnQ/YDoke3QucG9ydH1gOiIiO3JldHVybmAke259Ly8ke3QuaG9zdH0ke2V9JHt0LnBhdGg/YC8ke3QucGF0aH1gOiIifS9hcGkvYH0odCl9JHt0LnByb2plY3RJZH0vZW52ZWxvcGUvYH0odm4pfT8ke2Z1bmN0aW9uKHQsbil7Y29uc3QgZT17c2VudHJ5X3ZlcnNpb246S3R9O3JldHVybiB0LnB1YmxpY0tleSYmKGUuc2VudHJ5X2tleT10LnB1YmxpY0tleSksbiYmKGUuc2VudHJ5X2NsaWVudD1gJHtuLm5hbWV9LyR7bi52ZXJzaW9ufWApLG5ldyBVUkxTZWFyY2hQYXJhbXMoZSkudG9TdHJpbmcoKX0odm4sU24pfWApfSk7YXN5bmMgZnVuY3Rpb24gRW4oKXtpZihnbil7X24oIlNlbmRpbmcgYWJub3JtYWwgc2Vzc2lvbiIpLEsoZ24se3N0YXR1czoiYWJub3JtYWwiLGFibm9ybWFsX21lY2hhbmlzbToiYW5yX2ZvcmVncm91bmQiLHJlbGVhc2U6bW4ucmVsZWFzZSxlbnZpcm9ubWVudDptbi5lbnZpcm9ubWVudH0pO2NvbnN0IHQ9ZnVuY3Rpb24odCxuLGUscil7Y29uc3Qgbz1ZdChlKTtyZXR1cm4gTXQoe3NlbnRfYXQ6KG5ldyBEYXRlKS50b0lTT1N0cmluZygpLC4uLm8mJntzZGs6b30sLi4uISFyJiZuJiZ7ZHNuOk90KG4pfX0sWyJhZ2dyZWdhdGVzImluIHQ/W3t0eXBlOiJzZXNzaW9ucyJ9LHRdOlt7dHlwZToic2Vzc2lvbiJ9LHQudG9KU09OKCldXSl9KGduLG1uLmRzbixtbi5zZGtNZXRhZGF0YSxtbi50dW5uZWwpO19uKEpTT04uc3RyaW5naWZ5KHQpKSxhd2FpdCAkbi5zZW5kKHQpO3RyeXtlPy5wb3N0TWVzc2FnZSgic2Vzc2lvbi1lbmRlZCIpfWNhdGNoKHQpe319fWZ1bmN0aW9uIHhuKHQpe2lmKCF0KXJldHVybjtjb25zdCBuPWZ1bmN0aW9uKHQpe2lmKCF0Lmxlbmd0aClyZXR1cm5bXTtjb25zdCBuPUFycmF5LmZyb20odCk7cmV0dXJuL3NlbnRyeVdyYXBwZWQvLnRlc3QoeChuKS5mdW5jdGlvbnx8IiIpJiZuLnBvcCgpLG4ucmV2ZXJzZSgpLEUudGVzdCh4KG4pLmZ1bmN0aW9ufHwiIikmJihuLnBvcCgpLEUudGVzdCh4KG4pLmZ1bmN0aW9ufHwiIikmJm4ucG9wKCkpLG4uc2xpY2UoMCxTKS5tYXAoKHQ9Pih7Li4udCxmaWxlbmFtZTp0LmZpbGVuYW1lfHx4KG4pLmZpbGVuYW1lLGZ1bmN0aW9uOnQuZnVuY3Rpb258fCR9KSkpfSh0KTtpZihtbi5hcHBSb290UGF0aClmb3IoY29uc3QgdCBvZiBuKXQuZmlsZW5hbWUmJih0LmZpbGVuYW1lPVV0KHQuZmlsZW5hbWUsbW4uYXBwUm9vdFBhdGgpKTtyZXR1cm4gbn1hc3luYyBmdW5jdGlvbiBObih0LG4pe2lmKHluPj1tbi5tYXhBbnJFdmVudHMpcmV0dXJuO3luKz0xLGF3YWl0IEVuKCksX24oIlNlbmRpbmcgZXZlbnQiKTtjb25zdCBlPXtldmVudF9pZDpZKCksY29udGV4dHM6bW4uY29udGV4dHMscmVsZWFzZTptbi5yZWxlYXNlLGVudmlyb25tZW50Om1uLmVudmlyb25tZW50LGRpc3Q6bW4uZGlzdCxwbGF0Zm9ybToibm9kZSIsbGV2ZWw6ImVycm9yIixleGNlcHRpb246e3ZhbHVlczpbe3R5cGU6IkFwcGxpY2F0aW9uTm90UmVzcG9uZGluZyIsdmFsdWU6YEFwcGxpY2F0aW9uIE5vdCBSZXNwb25kaW5nIGZvciBhdCBsZWFzdCAke21uLmFuclRocmVzaG9sZH0gbXNgLHN0YWNrdHJhY2U6e2ZyYW1lczp4bih0KX0sbWVjaGFuaXNtOnt0eXBlOiJBTlIifX1dfSx0YWdzOm1uLnN0YXRpY1RhZ3N9O24mJmZ1bmN0aW9uKHQsbil7aWYoV3QodCxuKSwhdC5jb250ZXh0cz8udHJhY2Upe2NvbnN0e3RyYWNlSWQ6ZSxwYXJlbnRTcGFuSWQ6cixwcm9wYWdhdGlvblNwYW5JZDpvfT1uLnByb3BhZ2F0aW9uQ29udGV4dDt0LmNvbnRleHRzPXt0cmFjZTp7dHJhY2VfaWQ6ZSxzcGFuX2lkOm98fFooKSxwYXJlbnRfc3Bhbl9pZDpyfSwuLi50LmNvbnRleHRzfX19KGUsbiksZnVuY3Rpb24odCl7aWYoMD09PU9iamVjdC5rZXlzKGJuKS5sZW5ndGgpcmV0dXJuO2NvbnN0IG49bW4uYXBwUm9vdFBhdGg/e306Ym47aWYobW4uYXBwUm9vdFBhdGgpZm9yKGNvbnN0W3QsZV1vZiBPYmplY3QuZW50cmllcyhibikpbltVdCh0LG1uLmFwcFJvb3RQYXRoKV09ZTtjb25zdCBlPW5ldyBNYXA7Zm9yKGNvbnN0IHIgb2YgdC5leGNlcHRpb24/LnZhbHVlc3x8W10pZm9yKGNvbnN0IHQgb2Ygci5zdGFja3RyYWNlPy5mcmFtZXN8fFtdKXtjb25zdCByPXQuYWJzX3BhdGh8fHQuZmlsZW5hbWU7ciYmbltyXSYmZS5zZXQocixuW3JdKX1pZihlLnNpemU+MCl7Y29uc3Qgbj1bXTtmb3IoY29uc3RbdCxyXW9mIGUuZW50cmllcygpKW4ucHVzaCh7dHlwZToic291cmNlbWFwIixjb2RlX2ZpbGU6dCxkZWJ1Z19pZDpyfSk7dC5kZWJ1Z19tZXRhPXtpbWFnZXM6bn19fShlKTtjb25zdCByPXp0KGUsbW4uZHNuLG1uLnNka01ldGFkYXRhLG1uLnR1bm5lbCk7X24oSlNPTi5zdHJpbmdpZnkocikpLGF3YWl0ICRuLnNlbmQociksYXdhaXQgJG4uZmx1c2goMmUzKSx5bj49bW4ubWF4QW5yRXZlbnRzJiZzZXRUaW1lb3V0KCgoKT0+e3Byb2Nlc3MuZXhpdCgwKX0pLDVlMyl9bGV0IFRuO2lmKF9uKCJTdGFydGVkIiksbW4uY2FwdHVyZVN0YWNrVHJhY2Upe19uKCJDb25uZWN0aW5nIHRvIGRlYnVnZ2VyIik7Y29uc3Qgbj1uZXcgdDtuLmNvbm5lY3RUb01haW5UaHJlYWQoKSxfbigiQ29ubmVjdGVkIHRvIGRlYnVnZ2VyIik7Y29uc3QgZT1uZXcgTWFwO24ub24oIkRlYnVnZ2VyLnNjcmlwdFBhcnNlZCIsKHQ9PntlLnNldCh0LnBhcmFtcy5zY3JpcHRJZCx0LnBhcmFtcy51cmwpfSkpLG4ub24oIkRlYnVnZ2VyLnBhdXNlZCIsKHQ9PntpZigib3RoZXIiPT09dC5wYXJhbXMucmVhc29uKXRyeXtfbigiRGVidWdnZXIgcGF1c2VkIik7Y29uc3Qgcz1bLi4udC5wYXJhbXMuY2FsbEZyYW1lc10saT1tbi5hcHBSb290UGF0aD9mdW5jdGlvbih0PShwcm9jZXNzLmFyZ3ZbMV0/ZW4ocHJvY2Vzcy5hcmd2WzFdKTpwcm9jZXNzLmN3ZCgpKSxuPSJcXCI9PT1vKXtjb25zdCBlPW4/ZG4odCk6dDtyZXR1cm4gdD0+e2lmKCF0KXJldHVybjtjb25zdCBvPW4/ZG4odCk6dDtsZXR7ZGlyOnMsYmFzZTppLGV4dDpjfT1yLnBhcnNlKG8pOyIuanMiIT09YyYmIi5tanMiIT09YyYmIi5janMiIT09Y3x8KGk9aS5zbGljZSgwLC0xKmMubGVuZ3RoKSk7Y29uc3QgdT1kZWNvZGVVUklDb21wb25lbnQoaSk7c3x8KHM9Ii4iKTtjb25zdCBhPXMubGFzdEluZGV4T2YoIi9ub2RlX21vZHVsZXMiKTtpZihhPi0xKXJldHVybmAke3Muc2xpY2UoYSsxNCkucmVwbGFjZSgvXC8vZywiLiIpfToke3V9YDtpZihzLnN0YXJ0c1dpdGgoZSkpe2NvbnN0IHQ9cy5zbGljZShlLmxlbmd0aCsxKS5yZXBsYWNlKC9cLy9nLCIuIik7cmV0dXJuIHQ/YCR7dH06JHt1fWA6dX1yZXR1cm4gdX19KG1uLmFwcFJvb3RQYXRoKTooKT0+e30sYz1zLm1hcCgodD0+ZnVuY3Rpb24odCxuLGUpe2NvbnN0IHI9bj9uLnJlcGxhY2UoL15maWxlOlwvXC8vLCIiKTp2b2lkIDAsbz10LmxvY2F0aW9uLmNvbHVtbk51bWJlcj90LmxvY2F0aW9uLmNvbHVtbk51bWJlcisxOnZvaWQgMCxzPXQubG9jYXRpb24ubGluZU51bWJlcj90LmxvY2F0aW9uLmxpbmVOdW1iZXIrMTp2b2lkIDA7cmV0dXJue2ZpbGVuYW1lOnIsbW9kdWxlOmUociksZnVuY3Rpb246dC5mdW5jdGlvbk5hbWV8fCQsY29sbm86byxsaW5lbm86cyxpbl9hcHA6cj9ybihyKTp2b2lkIDB9fSh0LGUuZ2V0KHQubG9jYXRpb24uc2NyaXB0SWQpLGkpKSksdT1zZXRUaW1lb3V0KCgoKT0+e05uKGMpLnRoZW4obnVsbCwoKCk9PntfbigiU2VuZGluZyBBTlIgZXZlbnQgZmFpbGVkLiIpfSkpfSksNWUzKTtuLnBvc3QoIlJ1bnRpbWUuZXZhbHVhdGUiLHtleHByZXNzaW9uOiJnbG9iYWwuX19TRU5UUllfR0VUX1NDT1BFU19fKCk7IixzaWxlbnQ6ITAscmV0dXJuQnlWYWx1ZTohMH0sKCh0LGUpPT57dCYmX24oYEVycm9yIGV4ZWN1dGluZyBzY3JpcHQ6ICcke3QubWVzc2FnZX0nYCksY2xlYXJUaW1lb3V0KHUpO2NvbnN0IHI9ZT8ucmVzdWx0P2UucmVzdWx0LnZhbHVlOnZvaWQgMDtuLnBvc3QoIkRlYnVnZ2VyLnJlc3VtZSIpLG4ucG9zdCgiRGVidWdnZXIuZGlzYWJsZSIpLE5uKGMscikudGhlbihudWxsLCgoKT0+e19uKCJTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQuIil9KSl9KSl9Y2F0Y2godCl7dGhyb3cgbi5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKSxuLnBvc3QoIkRlYnVnZ2VyLmRpc2FibGUiKSx0fX0pKSxUbj0oKT0+e3RyeXtuLnBvc3QoIkRlYnVnZ2VyLmVuYWJsZSIsKCgpPT57bi5wb3N0KCJEZWJ1Z2dlci5wYXVzZSIpfSkpfWNhdGNoKHQpe319fWNvbnN0e3BvbGw6Q259PWZ1bmN0aW9uKHQsbixlLHIpe2NvbnN0IG89dCgpO2xldCBzPSExLGk9ITA7cmV0dXJuIHNldEludGVydmFsKCgoKT0+e2NvbnN0IHQ9by5nZXRUaW1lTXMoKTshMT09PXMmJnQ+bitlJiYocz0hMCxpJiZyKCkpLHQ8bitlJiYocz0hMSl9KSwyMCkse3BvbGw6KCk9PntvLnJlc2V0KCl9LGVuYWJsZWQ6dD0+e2k9dH19fSgoZnVuY3Rpb24oKXtsZXQgdD1wcm9jZXNzLmhydGltZSgpO3JldHVybntnZXRUaW1lTXM6KCk9Pntjb25zdFtuLGVdPXByb2Nlc3MuaHJ0aW1lKHQpO3JldHVybiBNYXRoLmZsb29yKDFlMypuK2UvMWU2KX0scmVzZXQ6KCk9Pnt0PXByb2Nlc3MuaHJ0aW1lKCl9fX0pLG1uLnBvbGxJbnRlcnZhbCxtbi5hbnJUaHJlc2hvbGQsKGZ1bmN0aW9uKCl7X24oIldhdGNoZG9nIHRpbWVvdXQiKSxUbj8oX24oIlBhdXNpbmcgZGVidWdnZXIgdG8gY2FwdHVyZSBzdGFjayB0cmFjZSIpLFRuKCkpOihfbigiQ2FwdHVyaW5nIGV2ZW50IHdpdGhvdXQgYSBzdGFjayB0cmFjZSIpLE5uKCkudGhlbihudWxsLCgoKT0+e19uKCJTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQgb24gd2F0Y2hkb2cgdGltZW91dC4iKX0pKSl9KSk7ZT8ub24oIm1lc3NhZ2UiLCh0PT57dC5zZXNzaW9uJiYoZ249Vyh0LnNlc3Npb24pKSx0LmRlYnVnSW1hZ2VzJiYoYm49dC5kZWJ1Z0ltYWdlcyksQ24oKX0pKTs=';
|
|
13
13
|
|
|
14
14
|
const DEFAULT_INTERVAL = 50;
|
|
15
15
|
const DEFAULT_HANG_THRESHOLD = 5000;
|
|
@@ -21,7 +21,7 @@ const consoleIntegration = core.defineIntegration(() => {
|
|
|
21
21
|
{
|
|
22
22
|
category: 'console',
|
|
23
23
|
level: core.severityLevelFromString(level),
|
|
24
|
-
message:
|
|
24
|
+
message: util.format.apply(undefined, args),
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
input: [...args],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console.js","sources":["../../../src/integrations/console.ts"],"sourcesContent":["import * as util from 'node:util';\nimport {\n addBreadcrumb,\n addConsoleInstrumentationHandler,\n defineIntegration,\n getClient,\n severityLevelFromString,\n
|
|
1
|
+
{"version":3,"file":"console.js","sources":["../../../src/integrations/console.ts"],"sourcesContent":["import * as util from 'node:util';\nimport {\n addBreadcrumb,\n addConsoleInstrumentationHandler,\n defineIntegration,\n getClient,\n severityLevelFromString,\n} from '@sentry/core';\n\nconst INTEGRATION_NAME = 'Console';\n\n/**\n * Capture console logs as breadcrumbs.\n */\nexport const consoleIntegration = defineIntegration(() => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n addConsoleInstrumentationHandler(({ args, level }) => {\n if (getClient() !== client) {\n return;\n }\n\n addBreadcrumb(\n {\n category: 'console',\n level: severityLevelFromString(level),\n message: util.format.apply(undefined, args),\n },\n {\n input: [...args],\n level,\n },\n );\n });\n },\n };\n});\n"],"names":["defineIntegration","addConsoleInstrumentationHandler","getClient","addBreadcrumb","severityLevelFromString"],"mappings":";;;;;AASA,MAAM,gBAAA,GAAmB,SAAS;;AAElC;AACA;AACA;MACa,kBAAmB,GAAEA,sBAAiB,CAAC,MAAM;AAC1D,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,KAAK,CAAC,MAAM,EAAE;AAClB,MAAMC,qCAAgC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAA,EAAO,KAAK;AAC5D,QAAQ,IAAIC,cAAS,EAAG,KAAI,MAAM,EAAE;AACpC,UAAU;AACV;;AAEA,QAAQC,kBAAa;AACrB,UAAU;AACV,YAAY,QAAQ,EAAE,SAAS;AAC/B,YAAY,KAAK,EAAEC,4BAAuB,CAAC,KAAK,CAAC;AACjD,YAAY,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC;AACvD,WAAW;AACX,UAAU;AACV,YAAY,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;AAC5B,YAAY,KAAK;AACjB,WAAW;AACX,SAAS;AACT,OAAO,CAAC;AACR,KAAK;AACL,GAAG;AACH,CAAC;;;;"}
|
|
@@ -6,7 +6,7 @@ const debug = require('../../utils/debug.js');
|
|
|
6
6
|
const common = require('./common.js');
|
|
7
7
|
|
|
8
8
|
// This string is a placeholder that gets overwritten with the worker code.
|
|
9
|
-
const base64WorkerScript = '
|
|
9
|
+
const base64WorkerScript = 'LyohIEBzZW50cnkvbm9kZSA5LjEwLjAgKGUzODNmZmYpIHwgaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdCAqLwppbXBvcnR7U2Vzc2lvbiBhcyBlfWZyb20ibm9kZTppbnNwZWN0b3IvcHJvbWlzZXMiO2ltcG9ydHt3b3JrZXJEYXRhIGFzIHR9ZnJvbSJub2RlOndvcmtlcl90aHJlYWRzIjtjb25zdCBuPWdsb2JhbFRoaXMsbz0idW5kZWZpbmVkIj09dHlwZW9mIF9fU0VOVFJZX0RFQlVHX198fF9fU0VOVFJZX0RFQlVHX18saT0iOS4xMC4wIjtjb25zdCBhPVsiZGVidWciLCJpbmZvIiwid2FybiIsImVycm9yIiwibG9nIiwiYXNzZXJ0IiwidHJhY2UiXSxzPXt9O2Z1bmN0aW9uIGMoZSl7aWYoISgiY29uc29sZSJpbiBuKSlyZXR1cm4gZSgpO2NvbnN0IHQ9bi5jb25zb2xlLG89e30saT1PYmplY3Qua2V5cyhzKTtpLmZvckVhY2goKGU9Pntjb25zdCBuPXNbZV07b1tlXT10W2VdLHRbZV09bn0pKTt0cnl7cmV0dXJuIGUoKX1maW5hbGx5e2kuZm9yRWFjaCgoZT0+e3RbZV09b1tlXX0pKX19IWZ1bmN0aW9uKGUsdCxvPW4pe2NvbnN0IGE9by5fX1NFTlRSWV9fPW8uX19TRU5UUllfX3x8e30scz1hW2ldPWFbaV18fHt9O3NbZV18fChzW2VdPXQoKSl9KCJsb2dnZXIiLChmdW5jdGlvbigpe2xldCBlPSExO2NvbnN0IHQ9e2VuYWJsZTooKT0+e2U9ITB9LGRpc2FibGU6KCk9PntlPSExfSxpc0VuYWJsZWQ6KCk9PmV9O3JldHVybiBvP2EuZm9yRWFjaCgobz0+e3Rbb109KC4uLnQpPT57ZSYmYygoKCk9PntuLmNvbnNvbGVbb10oYFNlbnRyeSBMb2dnZXIgWyR7b31dOmAsLi4udCl9KSl9fSkpOmEuZm9yRWFjaCgoZT0+e3RbZV09KCk9Pnt9fSkpLHR9KSk7Y29uc3Qgcj0iX19TRU5UUllfRVJST1JfTE9DQUxfVkFSSUFCTEVTX18iO2NvbnN0IHU9dDtmdW5jdGlvbiBsKC4uLmUpe3UuZGVidWcmJmMoKCgpPT5jb25zb2xlLmxvZygiW0xvY2FsVmFyaWFibGVzIFdvcmtlcl0iLC4uLmUpKSl9YXN5bmMgZnVuY3Rpb24gZihlLHQsbixvKXtjb25zdCBpPWF3YWl0IGUucG9zdCgiUnVudGltZS5nZXRQcm9wZXJ0aWVzIix7b2JqZWN0SWQ6dCxvd25Qcm9wZXJ0aWVzOiEwfSk7b1tuXT1pLnJlc3VsdC5maWx0ZXIoKGU9PiJsZW5ndGgiIT09ZS5uYW1lJiYhaXNOYU4ocGFyc2VJbnQoZS5uYW1lLDEwKSkpKS5zb3J0KCgoZSx0KT0+cGFyc2VJbnQoZS5uYW1lLDEwKS1wYXJzZUludCh0Lm5hbWUsMTApKSkubWFwKChlPT5lLnZhbHVlPy52YWx1ZSkpfWFzeW5jIGZ1bmN0aW9uIGcoZSx0LG4sbyl7Y29uc3QgaT1hd2FpdCBlLnBvc3QoIlJ1bnRpbWUuZ2V0UHJvcGVydGllcyIse29iamVjdElkOnQsb3duUHJvcGVydGllczohMH0pO29bbl09aS5yZXN1bHQubWFwKChlPT5bZS5uYW1lLGUudmFsdWU/LnZhbHVlXSkpLnJlZHVjZSgoKGUsW3Qsbl0pPT4oZVt0XT1uLGUpKSx7fSl9ZnVuY3Rpb24gZChlLHQpe2UudmFsdWUmJigidmFsdWUiaW4gZS52YWx1ZT92b2lkIDA9PT1lLnZhbHVlLnZhbHVlfHxudWxsPT09ZS52YWx1ZS52YWx1ZT90W2UubmFtZV09YDwke2UudmFsdWUudmFsdWV9PmA6dFtlLm5hbWVdPWUudmFsdWUudmFsdWU6ImRlc2NyaXB0aW9uImluIGUudmFsdWUmJiJmdW5jdGlvbiIhPT1lLnZhbHVlLnR5cGU/dFtlLm5hbWVdPWA8JHtlLnZhbHVlLmRlc2NyaXB0aW9ufT5gOiJ1bmRlZmluZWQiPT09ZS52YWx1ZS50eXBlJiYodFtlLm5hbWVdPSI8dW5kZWZpbmVkPiIpKX1hc3luYyBmdW5jdGlvbiBiKGUsdCl7Y29uc3Qgbj1hd2FpdCBlLnBvc3QoIlJ1bnRpbWUuZ2V0UHJvcGVydGllcyIse29iamVjdElkOnQsb3duUHJvcGVydGllczohMH0pLG89e307Zm9yKGNvbnN0IHQgb2Ygbi5yZXN1bHQpaWYodC52YWx1ZT8ub2JqZWN0SWQmJiJBcnJheSI9PT10LnZhbHVlLmNsYXNzTmFtZSl7Y29uc3Qgbj10LnZhbHVlLm9iamVjdElkO2F3YWl0IGYoZSxuLHQubmFtZSxvKX1lbHNlIGlmKHQudmFsdWU/Lm9iamVjdElkJiYiT2JqZWN0Ij09PXQudmFsdWUuY2xhc3NOYW1lKXtjb25zdCBuPXQudmFsdWUub2JqZWN0SWQ7YXdhaXQgZyhlLG4sdC5uYW1lLG8pfWVsc2UgdC52YWx1ZSYmZCh0LG8pO3JldHVybiBvfWxldCBwOyhhc3luYyBmdW5jdGlvbigpe2NvbnN0IHQ9bmV3IGU7dC5jb25uZWN0VG9NYWluVGhyZWFkKCksbCgiQ29ubmVjdGVkIHRvIG1haW4gdGhyZWFkIik7bGV0IG49ITE7dC5vbigiRGVidWdnZXIucmVzdW1lZCIsKCgpPT57bj0hMX0pKSx0Lm9uKCJEZWJ1Z2dlci5wYXVzZWQiLChlPT57bj0hMCxhc3luYyBmdW5jdGlvbihlLHtyZWFzb246dCxkYXRhOntvYmplY3RJZDpufSxjYWxsRnJhbWVzOm99KXtpZigiZXhjZXB0aW9uIiE9PXQmJiJwcm9taXNlUmVqZWN0aW9uIiE9PXQpcmV0dXJuO2lmKHA/LigpLG51bGw9PW4pcmV0dXJuO2NvbnN0IGk9W107Zm9yKGxldCB0PTA7dDxvLmxlbmd0aDt0Kyspe2NvbnN0e3Njb3BlQ2hhaW46bixmdW5jdGlvbk5hbWU6YSx0aGlzOnN9PW9bdF0sYz1uLmZpbmQoKGU9PiJsb2NhbCI9PT1lLnR5cGUpKSxyPSJnbG9iYWwiIT09cy5jbGFzc05hbWUmJnMuY2xhc3NOYW1lP2Ake3MuY2xhc3NOYW1lfS4ke2F9YDphO2lmKHZvaWQgMD09PWM/Lm9iamVjdC5vYmplY3RJZClpW3RdPXtmdW5jdGlvbjpyfTtlbHNle2NvbnN0IG49YXdhaXQgYihlLGMub2JqZWN0Lm9iamVjdElkKTtpW3RdPXtmdW5jdGlvbjpyLHZhcnM6bn19fWF3YWl0IGUucG9zdCgiUnVudGltZS5jYWxsRnVuY3Rpb25PbiIse2Z1bmN0aW9uRGVjbGFyYXRpb246YGZ1bmN0aW9uKCkgeyB0aGlzLiR7cn0gPSB0aGlzLiR7cn0gfHwgJHtKU09OLnN0cmluZ2lmeShpKX07IH1gLHNpbGVudDohMCxvYmplY3RJZDpufSksYXdhaXQgZS5wb3N0KCJSdW50aW1lLnJlbGVhc2VPYmplY3QiLHtvYmplY3RJZDpufSl9KHQsZS5wYXJhbXMpLnRoZW4oKGFzeW5jKCk9PntuJiZhd2FpdCB0LnBvc3QoIkRlYnVnZ2VyLnJlc3VtZSIpfSksKGFzeW5jIGU9PntuJiZhd2FpdCB0LnBvc3QoIkRlYnVnZ2VyLnJlc3VtZSIpfSkpfSkpLGF3YWl0IHQucG9zdCgiRGVidWdnZXIuZW5hYmxlIik7Y29uc3Qgbz0hMSE9PXUuY2FwdHVyZUFsbEV4Y2VwdGlvbnM7aWYoYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5zZXRQYXVzZU9uRXhjZXB0aW9ucyIse3N0YXRlOm8/ImFsbCI6InVuY2F1Z2h0In0pLG8pe2NvbnN0IGU9dS5tYXhFeGNlcHRpb25zUGVyU2Vjb25kfHw1MDtwPWZ1bmN0aW9uKGUsdCxuKXtsZXQgbz0wLGk9NSxhPTA7cmV0dXJuIHNldEludGVydmFsKCgoKT0+ezA9PT1hP28+ZSYmKGkqPTIsbihpKSxpPjg2NDAwJiYoaT04NjQwMCksYT1pKTooYS09MSwwPT09YSYmdCgpKSxvPTB9KSwxZTMpLnVucmVmKCksKCk9PntvKz0xfX0oZSwoYXN5bmMoKT0+e2woIlJhdGUtbGltaXQgbGlmdGVkLiIpLGF3YWl0IHQucG9zdCgiRGVidWdnZXIuc2V0UGF1c2VPbkV4Y2VwdGlvbnMiLHtzdGF0ZToiYWxsIn0pfSksKGFzeW5jIGU9PntsKGBSYXRlLWxpbWl0IGV4Y2VlZGVkLiBEaXNhYmxpbmcgY2FwdHVyaW5nIG9mIGNhdWdodCBleGNlcHRpb25zIGZvciAke2V9IHNlY29uZHMuYCksYXdhaXQgdC5wb3N0KCJEZWJ1Z2dlci5zZXRQYXVzZU9uRXhjZXB0aW9ucyIse3N0YXRlOiJ1bmNhdWdodCJ9KX0pKX19KSgpLmNhdGNoKChlPT57bCgiRmFpbGVkIHRvIHN0YXJ0IGRlYnVnZ2VyIixlKX0pKSxzZXRJbnRlcnZhbCgoKCk9Pnt9KSwxZTQpOw==';
|
|
10
10
|
|
|
11
11
|
function log(...args) {
|
|
12
12
|
core.logger.log('[LocalVariables]', ...args);
|
|
@@ -93,7 +93,7 @@ function addConnectSpanAttributes(span) {
|
|
|
93
93
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: `${type}.connect`,
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
// Also update the name, we don't need
|
|
96
|
+
// Also update the name, we don't need the "middleware - " prefix
|
|
97
97
|
const name = attributes['connect.name'];
|
|
98
98
|
if (typeof name === 'string') {
|
|
99
99
|
span.updateName(name);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect.js","sources":["../../../../src/integrations/tracing/connect.ts"],"sourcesContent":["import { ConnectInstrumentation } from '@opentelemetry/instrumentation-connect';\nimport type { IntegrationFn, Span } from '@sentry/core';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n captureException,\n defineIntegration,\n getClient,\n spanToJSON,\n} from '@sentry/core';\nimport { generateInstrumentOnce } from '../../otel/instrument';\nimport { ensureIsWrapped } from '../../utils/ensureIsWrapped';\n\ntype ConnectApp = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n use: (middleware: any) => void;\n};\n\nconst INTEGRATION_NAME = 'Connect';\n\nexport const instrumentConnect = generateInstrumentOnce(INTEGRATION_NAME, () => new ConnectInstrumentation());\n\nconst _connectIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n instrumentConnect();\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for [Connect](https://github.com/senchalabs/connect/).\n *\n * If you also want to capture errors, you need to call `setupConnectErrorHandler(app)` after you initialize your connect app.\n *\n * For more information, see the [connect documentation](https://docs.sentry.io/platforms/javascript/guides/connect/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.connectIntegration()],\n * })\n * ```\n */\nexport const connectIntegration = defineIntegration(_connectIntegration);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction connectErrorMiddleware(err: any, req: any, res: any, next: any): void {\n captureException(err);\n next(err);\n}\n\n/**\n * Add a Connect middleware to capture errors to Sentry.\n *\n * @param app The Connect app to attach the error handler to\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n * const connect = require(\"connect\");\n *\n * const app = connect();\n *\n * Sentry.setupConnectErrorHandler(app);\n *\n * // Add you connect routes here\n *\n * app.listen(3000);\n * ```\n */\nexport const setupConnectErrorHandler = (app: ConnectApp): void => {\n app.use(connectErrorMiddleware);\n\n // Sadly, ConnectInstrumentation has no requestHook, so we need to add the attributes here\n // We register this hook in this method, because if we register it in the integration `setup`,\n // it would always run even for users that are not even using connect\n const client = getClient();\n if (client) {\n client.on('spanStart', span => {\n addConnectSpanAttributes(span);\n });\n }\n\n ensureIsWrapped(app.use, 'connect');\n};\n\nfunction addConnectSpanAttributes(span: Span): void {\n const attributes = spanToJSON(span).data;\n\n // this is one of: middleware, request_handler\n const type = attributes['connect.type'];\n\n // If this is already set, or we have no connect span, no need to process again...\n if (attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] || !type) {\n return;\n }\n\n span.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.connect',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `${type}.connect`,\n });\n\n // Also update the name, we don't need
|
|
1
|
+
{"version":3,"file":"connect.js","sources":["../../../../src/integrations/tracing/connect.ts"],"sourcesContent":["import { ConnectInstrumentation } from '@opentelemetry/instrumentation-connect';\nimport type { IntegrationFn, Span } from '@sentry/core';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n captureException,\n defineIntegration,\n getClient,\n spanToJSON,\n} from '@sentry/core';\nimport { generateInstrumentOnce } from '../../otel/instrument';\nimport { ensureIsWrapped } from '../../utils/ensureIsWrapped';\n\ntype ConnectApp = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n use: (middleware: any) => void;\n};\n\nconst INTEGRATION_NAME = 'Connect';\n\nexport const instrumentConnect = generateInstrumentOnce(INTEGRATION_NAME, () => new ConnectInstrumentation());\n\nconst _connectIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n instrumentConnect();\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for [Connect](https://github.com/senchalabs/connect/).\n *\n * If you also want to capture errors, you need to call `setupConnectErrorHandler(app)` after you initialize your connect app.\n *\n * For more information, see the [connect documentation](https://docs.sentry.io/platforms/javascript/guides/connect/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.connectIntegration()],\n * })\n * ```\n */\nexport const connectIntegration = defineIntegration(_connectIntegration);\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction connectErrorMiddleware(err: any, req: any, res: any, next: any): void {\n captureException(err);\n next(err);\n}\n\n/**\n * Add a Connect middleware to capture errors to Sentry.\n *\n * @param app The Connect app to attach the error handler to\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n * const connect = require(\"connect\");\n *\n * const app = connect();\n *\n * Sentry.setupConnectErrorHandler(app);\n *\n * // Add you connect routes here\n *\n * app.listen(3000);\n * ```\n */\nexport const setupConnectErrorHandler = (app: ConnectApp): void => {\n app.use(connectErrorMiddleware);\n\n // Sadly, ConnectInstrumentation has no requestHook, so we need to add the attributes here\n // We register this hook in this method, because if we register it in the integration `setup`,\n // it would always run even for users that are not even using connect\n const client = getClient();\n if (client) {\n client.on('spanStart', span => {\n addConnectSpanAttributes(span);\n });\n }\n\n ensureIsWrapped(app.use, 'connect');\n};\n\nfunction addConnectSpanAttributes(span: Span): void {\n const attributes = spanToJSON(span).data;\n\n // this is one of: middleware, request_handler\n const type = attributes['connect.type'];\n\n // If this is already set, or we have no connect span, no need to process again...\n if (attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] || !type) {\n return;\n }\n\n span.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.connect',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `${type}.connect`,\n });\n\n // Also update the name, we don't need the \"middleware - \" prefix\n const name = attributes['connect.name'];\n if (typeof name === 'string') {\n span.updateName(name);\n }\n}\n"],"names":["generateInstrumentOnce","ConnectInstrumentation","defineIntegration","captureException","getClient","ensureIsWrapped","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN"],"mappings":";;;;;;;AAkBA,MAAM,gBAAA,GAAmB,SAAS;;AAErB,MAAA,iBAAA,GAAoBA,iCAAsB,CAAC,gBAAgB,EAAE,MAAM,IAAIC,6CAAsB,EAAE;;AAE5G,MAAM,mBAAoB,IAAG,MAAM;AACnC,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,SAAS,GAAG;AAChB,MAAM,iBAAiB,EAAE;AACzB,KAAK;AACL,GAAG;AACH,CAAC,CAAE;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;MACa,kBAAmB,GAAEC,sBAAiB,CAAC,mBAAmB;;AAEvE;AACA,SAAS,sBAAsB,CAAC,GAAG,EAAO,GAAG,EAAO,GAAG,EAAO,IAAI,EAAa;AAC/E,EAAEC,qBAAgB,CAAC,GAAG,CAAC;AACvB,EAAE,IAAI,CAAC,GAAG,CAAC;AACX;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACa,MAAA,wBAAA,GAA2B,CAAC,GAAG,KAAuB;AACnE,EAAE,GAAG,CAAC,GAAG,CAAC,sBAAsB,CAAC;;AAEjC;AACA;AACA;AACA,EAAE,MAAM,MAAA,GAASC,cAAS,EAAE;AAC5B,EAAE,IAAI,MAAM,EAAE;AACd,IAAI,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ;AACnC,MAAM,wBAAwB,CAAC,IAAI,CAAC;AACpC,KAAK,CAAC;AACN;;AAEA,EAAEC,+BAAe,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC;AACrC;;AAEA,SAAS,wBAAwB,CAAC,IAAI,EAAc;AACpD,EAAE,MAAM,aAAaC,eAAU,CAAC,IAAI,CAAC,CAAC,IAAI;;AAE1C;AACA,EAAE,MAAM,IAAK,GAAE,UAAU,CAAC,cAAc,CAAC;;AAEzC;AACA,EAAE,IAAI,UAAU,CAACC,iCAA4B,CAAE,IAAG,CAAC,IAAI,EAAE;AACzD,IAAI;AACJ;;AAEA,EAAE,IAAI,CAAC,aAAa,CAAC;AACrB,IAAI,CAACC,qCAAgC,GAAG,wBAAwB;AAChE,IAAI,CAACD,iCAA4B,GAAG,CAAC,EAAA,IAAA,CAAA,QAAA,CAAA;AACA,GAAA,CAAA;;AAEA;AACA,EAAA,MAAA,IAAA,GAAA,UAAA,CAAA,cAAA,CAAA;AACA,EAAA,IAAA,OAAA,IAAA,KAAA,QAAA,EAAA;AACA,IAAA,IAAA,CAAA,UAAA,CAAA,IAAA,CAAA;AACA;AACA;;;;;;"}
|
|
@@ -15,31 +15,37 @@ const instrumentDataloader = instrument.generateInstrumentOnce(
|
|
|
15
15
|
);
|
|
16
16
|
|
|
17
17
|
const _dataloaderIntegration = (() => {
|
|
18
|
+
let instrumentationWrappedCallback;
|
|
19
|
+
|
|
18
20
|
return {
|
|
19
21
|
name: INTEGRATION_NAME,
|
|
20
22
|
setupOnce() {
|
|
21
|
-
instrumentDataloader();
|
|
23
|
+
const instrumentation = instrumentDataloader();
|
|
24
|
+
instrumentationWrappedCallback = instrument.instrumentWhenWrapped(instrumentation);
|
|
22
25
|
},
|
|
23
26
|
|
|
24
27
|
setup(client) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
// This is called either immediately or when the instrumentation is wrapped
|
|
29
|
+
instrumentationWrappedCallback?.(() => {
|
|
30
|
+
client.on('spanStart', span => {
|
|
31
|
+
const spanJSON = core.spanToJSON(span);
|
|
32
|
+
if (spanJSON.description?.startsWith('dataloader')) {
|
|
33
|
+
span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.dataloader');
|
|
34
|
+
}
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
// These are all possible dataloader span descriptions
|
|
37
|
+
// Still checking for the future versions
|
|
38
|
+
// in case they add support for `clear` and `prime`
|
|
39
|
+
if (
|
|
40
|
+
spanJSON.description === 'dataloader.load' ||
|
|
41
|
+
spanJSON.description === 'dataloader.loadMany' ||
|
|
42
|
+
spanJSON.description === 'dataloader.batch'
|
|
43
|
+
) {
|
|
44
|
+
span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'cache.get');
|
|
45
|
+
// TODO: We can try adding `key` to the `data` attribute upstream.
|
|
46
|
+
// Or alternatively, we can add `requestHook` to the dataloader instrumentation.
|
|
47
|
+
}
|
|
48
|
+
});
|
|
43
49
|
});
|
|
44
50
|
},
|
|
45
51
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataloader.js","sources":["../../../../src/integrations/tracing/dataloader.ts"],"sourcesContent":["import { DataloaderInstrumentation } from '@opentelemetry/instrumentation-dataloader';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n defineIntegration,\n spanToJSON,\n} from '@sentry/core';\nimport type { IntegrationFn } from '@sentry/core';\nimport { generateInstrumentOnce } from '../../otel/instrument';\n\nconst INTEGRATION_NAME = 'Dataloader';\n\nexport const instrumentDataloader = generateInstrumentOnce(\n INTEGRATION_NAME,\n () =>\n new DataloaderInstrumentation({\n requireParentSpan: true,\n }),\n);\n\nconst _dataloaderIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n instrumentDataloader();\n },\n\n setup(client) {\n client.on('spanStart', span => {\n
|
|
1
|
+
{"version":3,"file":"dataloader.js","sources":["../../../../src/integrations/tracing/dataloader.ts"],"sourcesContent":["import { DataloaderInstrumentation } from '@opentelemetry/instrumentation-dataloader';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n defineIntegration,\n spanToJSON,\n} from '@sentry/core';\nimport type { IntegrationFn } from '@sentry/core';\nimport { instrumentWhenWrapped, generateInstrumentOnce } from '../../otel/instrument';\n\nconst INTEGRATION_NAME = 'Dataloader';\n\nexport const instrumentDataloader = generateInstrumentOnce(\n INTEGRATION_NAME,\n () =>\n new DataloaderInstrumentation({\n requireParentSpan: true,\n }),\n);\n\nconst _dataloaderIntegration = (() => {\n let instrumentationWrappedCallback: undefined | ((callback: () => void) => void);\n\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n const instrumentation = instrumentDataloader();\n instrumentationWrappedCallback = instrumentWhenWrapped(instrumentation);\n },\n\n setup(client) {\n // This is called either immediately or when the instrumentation is wrapped\n instrumentationWrappedCallback?.(() => {\n client.on('spanStart', span => {\n const spanJSON = spanToJSON(span);\n if (spanJSON.description?.startsWith('dataloader')) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.dataloader');\n }\n\n // These are all possible dataloader span descriptions\n // Still checking for the future versions\n // in case they add support for `clear` and `prime`\n if (\n spanJSON.description === 'dataloader.load' ||\n spanJSON.description === 'dataloader.loadMany' ||\n spanJSON.description === 'dataloader.batch'\n ) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'cache.get');\n // TODO: We can try adding `key` to the `data` attribute upstream.\n // Or alternatively, we can add `requestHook` to the dataloader instrumentation.\n }\n });\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for the [dataloader](https://www.npmjs.com/package/dataloader) library.\n *\n * For more information, see the [`dataloaderIntegration` documentation](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/dataloader/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.dataloaderIntegration()],\n * });\n * ```\n */\nexport const dataloaderIntegration = defineIntegration(_dataloaderIntegration);\n"],"names":["generateInstrumentOnce","DataloaderInstrumentation","instrumentWhenWrapped","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","defineIntegration"],"mappings":";;;;;;AAUA,MAAM,gBAAA,GAAmB,YAAY;;AAE9B,MAAM,oBAAqB,GAAEA,iCAAsB;AAC1D,EAAE,gBAAgB;AAClB,EAAE;AACF,IAAI,IAAIC,mDAAyB,CAAC;AAClC,MAAM,iBAAiB,EAAE,IAAI;AAC7B,KAAK,CAAC;AACN;;AAEA,MAAM,sBAAuB,IAAG,MAAM;AACtC,EAAE,IAAI,8BAA8B;;AAEpC,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,SAAS,GAAG;AAChB,MAAM,MAAM,eAAA,GAAkB,oBAAoB,EAAE;AACpD,MAAM,8BAA+B,GAAEC,gCAAqB,CAAC,eAAe,CAAC;AAC7E,KAAK;;AAEL,IAAI,KAAK,CAAC,MAAM,EAAE;AAClB;AACA,MAAM,8BAA8B,GAAG,MAAM;AAC7C,QAAQ,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ;AACvC,UAAU,MAAM,QAAS,GAAEC,eAAU,CAAC,IAAI,CAAC;AAC3C,UAAU,IAAI,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC,YAAY,CAAC,EAAE;AAC9D,YAAY,IAAI,CAAC,YAAY,CAACC,qCAAgC,EAAE,yBAAyB,CAAC;AAC1F;;AAEA;AACA;AACA;AACA,UAAU;AACV,YAAY,QAAQ,CAAC,WAAY,KAAI,iBAAkB;AACvD,YAAY,QAAQ,CAAC,WAAY,KAAI,qBAAsB;AAC3D,YAAY,QAAQ,CAAC,WAAA,KAAgB;AACrC,YAAY;AACZ,YAAY,IAAI,CAAC,YAAY,CAACC,iCAA4B,EAAE,WAAW,CAAC;AACxE;AACA;AACA;AACA,SAAS,CAAC;AACV,OAAO,CAAC;AACR,KAAK;AACL,GAAG;AACH,CAAC,CAAE;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;MACa,qBAAsB,GAAEC,sBAAiB,CAAC,sBAAsB;;;;;"}
|
|
@@ -9,26 +9,31 @@ const INTEGRATION_NAME = 'GenericPool';
|
|
|
9
9
|
const instrumentGenericPool = instrument.generateInstrumentOnce(INTEGRATION_NAME, () => new instrumentationGenericPool.GenericPoolInstrumentation({}));
|
|
10
10
|
|
|
11
11
|
const _genericPoolIntegration = (() => {
|
|
12
|
+
let instrumentationWrappedCallback;
|
|
13
|
+
|
|
12
14
|
return {
|
|
13
15
|
name: INTEGRATION_NAME,
|
|
14
16
|
setupOnce() {
|
|
15
|
-
instrumentGenericPool();
|
|
17
|
+
const instrumentation = instrumentGenericPool();
|
|
18
|
+
instrumentationWrappedCallback = instrument.instrumentWhenWrapped(instrumentation);
|
|
16
19
|
},
|
|
17
20
|
|
|
18
21
|
setup(client) {
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
instrumentationWrappedCallback?.(() =>
|
|
23
|
+
client.on('spanStart', span => {
|
|
24
|
+
const spanJSON = core.spanToJSON(span);
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
const spanDescription = spanJSON.description;
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
// typo in emitted span for version <= 0.38.0 of @opentelemetry/instrumentation-generic-pool
|
|
29
|
+
const isGenericPoolSpan =
|
|
30
|
+
spanDescription === 'generic-pool.aquire' || spanDescription === 'generic-pool.acquire';
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
if (isGenericPoolSpan) {
|
|
33
|
+
span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.generic_pool');
|
|
34
|
+
}
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
32
37
|
},
|
|
33
38
|
};
|
|
34
39
|
}) ;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"genericPool.js","sources":["../../../../src/integrations/tracing/genericPool.ts"],"sourcesContent":["import { GenericPoolInstrumentation } from '@opentelemetry/instrumentation-generic-pool';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, spanToJSON } from '@sentry/core';\nimport type { IntegrationFn } from '@sentry/core';\nimport { generateInstrumentOnce } from '../../otel/instrument';\n\nconst INTEGRATION_NAME = 'GenericPool';\n\nexport const instrumentGenericPool = generateInstrumentOnce(INTEGRATION_NAME, () => new GenericPoolInstrumentation({}));\n\nconst _genericPoolIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n instrumentGenericPool();\n },\n\n setup(client) {\n client.on('spanStart', span => {\n
|
|
1
|
+
{"version":3,"file":"genericPool.js","sources":["../../../../src/integrations/tracing/genericPool.ts"],"sourcesContent":["import { GenericPoolInstrumentation } from '@opentelemetry/instrumentation-generic-pool';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, spanToJSON } from '@sentry/core';\nimport type { IntegrationFn } from '@sentry/core';\nimport { generateInstrumentOnce, instrumentWhenWrapped } from '../../otel/instrument';\n\nconst INTEGRATION_NAME = 'GenericPool';\n\nexport const instrumentGenericPool = generateInstrumentOnce(INTEGRATION_NAME, () => new GenericPoolInstrumentation({}));\n\nconst _genericPoolIntegration = (() => {\n let instrumentationWrappedCallback: undefined | ((callback: () => void) => void);\n\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n const instrumentation = instrumentGenericPool();\n instrumentationWrappedCallback = instrumentWhenWrapped(instrumentation);\n },\n\n setup(client) {\n instrumentationWrappedCallback?.(() =>\n client.on('spanStart', span => {\n const spanJSON = spanToJSON(span);\n\n const spanDescription = spanJSON.description;\n\n // typo in emitted span for version <= 0.38.0 of @opentelemetry/instrumentation-generic-pool\n const isGenericPoolSpan =\n spanDescription === 'generic-pool.aquire' || spanDescription === 'generic-pool.acquire';\n\n if (isGenericPoolSpan) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.generic_pool');\n }\n }),\n );\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for the [generic-pool](https://www.npmjs.com/package/generic-pool) library.\n *\n * For more information, see the [`genericPoolIntegration` documentation](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/genericpool/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.genericPoolIntegration()],\n * });\n * ```\n */\nexport const genericPoolIntegration = defineIntegration(_genericPoolIntegration);\n"],"names":["generateInstrumentOnce","GenericPoolInstrumentation","instrumentWhenWrapped","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","defineIntegration"],"mappings":";;;;;;AAKA,MAAM,gBAAA,GAAmB,aAAa;;MAEzB,qBAAsB,GAAEA,iCAAsB,CAAC,gBAAgB,EAAE,MAAM,IAAIC,qDAA0B,CAAC,EAAE,CAAC;;AAEtH,MAAM,uBAAwB,IAAG,MAAM;AACvC,EAAE,IAAI,8BAA8B;;AAEpC,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,SAAS,GAAG;AAChB,MAAM,MAAM,eAAA,GAAkB,qBAAqB,EAAE;AACrD,MAAM,8BAA+B,GAAEC,gCAAqB,CAAC,eAAe,CAAC;AAC7E,KAAK;;AAEL,IAAI,KAAK,CAAC,MAAM,EAAE;AAClB,MAAM,8BAA8B,GAAG;AACvC,QAAQ,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ;AACvC,UAAU,MAAM,QAAS,GAAEC,eAAU,CAAC,IAAI,CAAC;;AAE3C,UAAU,MAAM,eAAA,GAAkB,QAAQ,CAAC,WAAW;;AAEtD;AACA,UAAU,MAAM,iBAAkB;AAClC,YAAY,oBAAoB,qBAAA,IAAyB,eAAA,KAAoB,sBAAsB;;AAEnG,UAAU,IAAI,iBAAiB,EAAE;AACjC,YAAY,IAAI,CAAC,YAAY,CAACC,qCAAgC,EAAE,2BAA2B,CAAC;AAC5F;AACA,SAAS,CAAC;AACV,OAAO;AACP,KAAK;AACL,GAAG;AACH,CAAC,CAAE;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;MACa,sBAAuB,GAAEC,sBAAiB,CAAC,uBAAuB;;;;;"}
|
|
@@ -12,21 +12,26 @@ const instrumentKnex = instrument.generateInstrumentOnce(
|
|
|
12
12
|
);
|
|
13
13
|
|
|
14
14
|
const _knexIntegration = (() => {
|
|
15
|
+
let instrumentationWrappedCallback;
|
|
16
|
+
|
|
15
17
|
return {
|
|
16
18
|
name: INTEGRATION_NAME,
|
|
17
19
|
setupOnce() {
|
|
18
|
-
instrumentKnex();
|
|
20
|
+
const instrumentation = instrumentKnex();
|
|
21
|
+
instrumentationWrappedCallback = instrument.instrumentWhenWrapped(instrumentation);
|
|
19
22
|
},
|
|
20
23
|
|
|
21
24
|
setup(client) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
instrumentationWrappedCallback?.(() =>
|
|
26
|
+
client.on('spanStart', span => {
|
|
27
|
+
const { data } = core.spanToJSON(span);
|
|
28
|
+
// knex.version is always set in the span data
|
|
29
|
+
// https://github.com/open-telemetry/opentelemetry-js-contrib/blob/0309caeafc44ac9cb13a3345b790b01b76d0497d/plugins/node/opentelemetry-instrumentation-knex/src/instrumentation.ts#L138
|
|
30
|
+
if ('knex.version' in data) {
|
|
31
|
+
span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.knex');
|
|
32
|
+
}
|
|
33
|
+
}),
|
|
34
|
+
);
|
|
30
35
|
},
|
|
31
36
|
};
|
|
32
37
|
}) ;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knex.js","sources":["../../../../src/integrations/tracing/knex.ts"],"sourcesContent":["import { KnexInstrumentation } from '@opentelemetry/instrumentation-knex';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, spanToJSON } from '@sentry/core';\nimport type { IntegrationFn } from '@sentry/core';\nimport { generateInstrumentOnce } from '../../otel/instrument';\n\nconst INTEGRATION_NAME = 'Knex';\n\nexport const instrumentKnex = generateInstrumentOnce(\n INTEGRATION_NAME,\n () => new KnexInstrumentation({ requireParentSpan: true }),\n);\n\nconst _knexIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n instrumentKnex();\n },\n\n setup(client) {\n client.on('spanStart', span => {\n
|
|
1
|
+
{"version":3,"file":"knex.js","sources":["../../../../src/integrations/tracing/knex.ts"],"sourcesContent":["import { KnexInstrumentation } from '@opentelemetry/instrumentation-knex';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, spanToJSON } from '@sentry/core';\nimport type { IntegrationFn } from '@sentry/core';\nimport { generateInstrumentOnce, instrumentWhenWrapped } from '../../otel/instrument';\n\nconst INTEGRATION_NAME = 'Knex';\n\nexport const instrumentKnex = generateInstrumentOnce(\n INTEGRATION_NAME,\n () => new KnexInstrumentation({ requireParentSpan: true }),\n);\n\nconst _knexIntegration = (() => {\n let instrumentationWrappedCallback: undefined | ((callback: () => void) => void);\n\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n const instrumentation = instrumentKnex();\n instrumentationWrappedCallback = instrumentWhenWrapped(instrumentation);\n },\n\n setup(client) {\n instrumentationWrappedCallback?.(() =>\n client.on('spanStart', span => {\n const { data } = spanToJSON(span);\n // knex.version is always set in the span data\n // https://github.com/open-telemetry/opentelemetry-js-contrib/blob/0309caeafc44ac9cb13a3345b790b01b76d0497d/plugins/node/opentelemetry-instrumentation-knex/src/instrumentation.ts#L138\n if ('knex.version' in data) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.knex');\n }\n }),\n );\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Knex integration\n *\n * Capture tracing data for [Knex](https://knexjs.org/).\n *\n * @example\n * ```javascript\n * import * as Sentry from '@sentry/node';\n *\n * Sentry.init({\n * integrations: [Sentry.knexIntegration()],\n * });\n * ```\n */\nexport const knexIntegration = defineIntegration(_knexIntegration);\n"],"names":["generateInstrumentOnce","KnexInstrumentation","instrumentWhenWrapped","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","defineIntegration"],"mappings":";;;;;;AAKA,MAAM,gBAAA,GAAmB,MAAM;;AAExB,MAAM,cAAe,GAAEA,iCAAsB;AACpD,EAAE,gBAAgB;AAClB,EAAE,MAAM,IAAIC,uCAAmB,CAAC,EAAE,iBAAiB,EAAE,IAAK,EAAC,CAAC;AAC5D;;AAEA,MAAM,gBAAiB,IAAG,MAAM;AAChC,EAAE,IAAI,8BAA8B;;AAEpC,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,SAAS,GAAG;AAChB,MAAM,MAAM,eAAA,GAAkB,cAAc,EAAE;AAC9C,MAAM,8BAA+B,GAAEC,gCAAqB,CAAC,eAAe,CAAC;AAC7E,KAAK;;AAEL,IAAI,KAAK,CAAC,MAAM,EAAE;AAClB,MAAM,8BAA8B,GAAG;AACvC,QAAQ,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,QAAQ;AACvC,UAAU,MAAM,EAAE,IAAK,EAAA,GAAIC,eAAU,CAAC,IAAI,CAAC;AAC3C;AACA;AACA,UAAU,IAAI,cAAe,IAAG,IAAI,EAAE;AACtC,YAAY,IAAI,CAAC,YAAY,CAACC,qCAAgC,EAAE,mBAAmB,CAAC;AACpF;AACA,SAAS,CAAC;AACV,OAAO;AACP,KAAK;AACL,GAAG;AACH,CAAC,CAAE;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;MACa,eAAgB,GAAEC,sBAAiB,CAAC,gBAAgB;;;;;"}
|
|
@@ -15,6 +15,18 @@ function isPrismaV6TracingHelper(helper) {
|
|
|
15
15
|
return !!helper && typeof helper === 'object' && 'dispatchEngineSpans' in helper;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
function getPrismaTracingHelper() {
|
|
19
|
+
const prismaInstrumentationObject = (globalThis ).PRISMA_INSTRUMENTATION;
|
|
20
|
+
const prismaTracingHelper =
|
|
21
|
+
prismaInstrumentationObject &&
|
|
22
|
+
typeof prismaInstrumentationObject === 'object' &&
|
|
23
|
+
'helper' in prismaInstrumentationObject
|
|
24
|
+
? prismaInstrumentationObject.helper
|
|
25
|
+
: undefined;
|
|
26
|
+
|
|
27
|
+
return prismaTracingHelper;
|
|
28
|
+
}
|
|
29
|
+
|
|
18
30
|
class SentryPrismaInteropInstrumentation extends EsmInteropPrismaInstrumentation {
|
|
19
31
|
constructor() {
|
|
20
32
|
super();
|
|
@@ -26,13 +38,7 @@ class SentryPrismaInteropInstrumentation extends EsmInteropPrismaInstrumentation
|
|
|
26
38
|
// The PrismaIntegration (super class) defines a global variable `global["PRISMA_INSTRUMENTATION"]` when `enable()` is called. This global variable holds a "TracingHelper" which Prisma uses internally to create tracing data. It's their way of not depending on OTEL with their main package. The sucky thing is, prisma broke the interface of the tracing helper with the v6 major update. This means that if you use Prisma 5 with the v6 instrumentation (or vice versa) Prisma just blows up, because tries to call methods on the helper that no longer exist.
|
|
27
39
|
// Because we actually want to use the v6 instrumentation and not blow up in Prisma 5 user's faces, what we're doing here is backfilling the v5 method (`createEngineSpan`) with a noop so that no longer crashes when it attempts to call that function.
|
|
28
40
|
// We still won't fully emit all the spans, but this could potentially be implemented in the future.
|
|
29
|
-
const
|
|
30
|
-
const prismaTracingHelper =
|
|
31
|
-
prismaInstrumentationObject &&
|
|
32
|
-
typeof prismaInstrumentationObject === 'object' &&
|
|
33
|
-
'helper' in prismaInstrumentationObject
|
|
34
|
-
? prismaInstrumentationObject.helper
|
|
35
|
-
: undefined;
|
|
41
|
+
const prismaTracingHelper = getPrismaTracingHelper();
|
|
36
42
|
|
|
37
43
|
let emittedWarning = false;
|
|
38
44
|
|
|
@@ -108,6 +114,12 @@ const prismaIntegration = core.defineIntegration(
|
|
|
108
114
|
instrumentPrisma({ prismaInstrumentation });
|
|
109
115
|
},
|
|
110
116
|
setup(client) {
|
|
117
|
+
// If no tracing helper exists, we skip any work here
|
|
118
|
+
// this means that prisma is not being used
|
|
119
|
+
if (!getPrismaTracingHelper()) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
111
123
|
client.on('spanStart', span => {
|
|
112
124
|
const spanJSON = core.spanToJSON(span);
|
|
113
125
|
if (spanJSON.description?.startsWith('prisma:')) {
|