@sentry/node 8.0.0-alpha.1 → 8.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/README.md +14 -93
  2. package/cjs/index.js +3665 -77
  3. package/cjs/index.js.map +1 -1
  4. package/esm/index.js +3614 -31
  5. package/esm/index.js.map +1 -1
  6. package/esm/integrations/anr/worker-script.js +2 -2
  7. package/esm/package.json +1 -0
  8. package/package.json +21 -6
  9. package/types/index.d.ts +6 -5
  10. package/types/index.d.ts.map +1 -1
  11. package/types/integrations/anr/index.d.ts.map +1 -1
  12. package/types/integrations/anr/worker-script.d.ts +1 -1
  13. package/types/integrations/anr/worker-script.d.ts.map +1 -1
  14. package/types/integrations/http.d.ts +4 -0
  15. package/types/integrations/http.d.ts.map +1 -1
  16. package/types/integrations/local-variables/common.d.ts +1 -0
  17. package/types/integrations/local-variables/common.d.ts.map +1 -1
  18. package/types/integrations/local-variables/local-variables-sync.d.ts +1 -0
  19. package/types/integrations/local-variables/local-variables-sync.d.ts.map +1 -1
  20. package/types/integrations/tracing/fastify.d.ts +9 -0
  21. package/types/integrations/tracing/fastify.d.ts.map +1 -1
  22. package/types/integrations/tracing/hapi/index.d.ts.map +1 -1
  23. package/types/integrations/tracing/prisma.d.ts.map +1 -1
  24. package/types/proxy/helpers.d.ts +2 -2
  25. package/types/proxy/helpers.d.ts.map +1 -1
  26. package/types/proxy/index.d.ts.map +1 -1
  27. package/types/sdk/hub.d.ts.map +1 -1
  28. package/types/sdk/init.d.ts.map +1 -1
  29. package/types/transports/http-module.d.ts +2 -2
  30. package/types/transports/http-module.d.ts.map +1 -1
  31. package/types/types.d.ts +12 -4
  32. package/types/types.d.ts.map +1 -1
  33. package/types-ts3.8/index.d.ts +6 -5
  34. package/types-ts3.8/integrations/anr/worker-script.d.ts +1 -1
  35. package/types-ts3.8/integrations/http.d.ts +4 -0
  36. package/types-ts3.8/integrations/local-variables/common.d.ts +1 -0
  37. package/types-ts3.8/integrations/local-variables/local-variables-sync.d.ts +1 -0
  38. package/types-ts3.8/integrations/tracing/fastify.d.ts +9 -0
  39. package/types-ts3.8/proxy/helpers.d.ts +2 -2
  40. package/types-ts3.8/transports/http-module.d.ts +2 -2
  41. package/types-ts3.8/types.d.ts +12 -4
  42. package/cjs/cron/common.js +0 -56
  43. package/cjs/cron/common.js.map +0 -1
  44. package/cjs/cron/cron.js +0 -102
  45. package/cjs/cron/cron.js.map +0 -1
  46. package/cjs/cron/index.js +0 -15
  47. package/cjs/cron/index.js.map +0 -1
  48. package/cjs/cron/node-cron.js +0 -61
  49. package/cjs/cron/node-cron.js.map +0 -1
  50. package/cjs/cron/node-schedule.js +0 -57
  51. package/cjs/cron/node-schedule.js.map +0 -1
  52. package/cjs/debug-build.js +0 -11
  53. package/cjs/debug-build.js.map +0 -1
  54. package/cjs/integrations/anr/index.js +0 -145
  55. package/cjs/integrations/anr/index.js.map +0 -1
  56. package/cjs/integrations/anr/worker-script.js +0 -2
  57. package/cjs/integrations/anr/worker-script.js.map +0 -1
  58. package/cjs/integrations/console.js +0 -40
  59. package/cjs/integrations/console.js.map +0 -1
  60. package/cjs/integrations/context.js +0 -435
  61. package/cjs/integrations/context.js.map +0 -1
  62. package/cjs/integrations/contextlines.js +0 -137
  63. package/cjs/integrations/contextlines.js.map +0 -1
  64. package/cjs/integrations/http.js +0 -137
  65. package/cjs/integrations/http.js.map +0 -1
  66. package/cjs/integrations/local-variables/common.js +0 -87
  67. package/cjs/integrations/local-variables/common.js.map +0 -1
  68. package/cjs/integrations/local-variables/index.js +0 -8
  69. package/cjs/integrations/local-variables/index.js.map +0 -1
  70. package/cjs/integrations/local-variables/local-variables-sync.js +0 -400
  71. package/cjs/integrations/local-variables/local-variables-sync.js.map +0 -1
  72. package/cjs/integrations/modules.js +0 -99
  73. package/cjs/integrations/modules.js.map +0 -1
  74. package/cjs/integrations/node-fetch.js +0 -82
  75. package/cjs/integrations/node-fetch.js.map +0 -1
  76. package/cjs/integrations/onuncaughtexception.js +0 -137
  77. package/cjs/integrations/onuncaughtexception.js.map +0 -1
  78. package/cjs/integrations/onunhandledrejection.js +0 -90
  79. package/cjs/integrations/onunhandledrejection.js.map +0 -1
  80. package/cjs/integrations/spotlight.js +0 -109
  81. package/cjs/integrations/spotlight.js.map +0 -1
  82. package/cjs/integrations/tracing/express.js +0 -103
  83. package/cjs/integrations/tracing/express.js.map +0 -1
  84. package/cjs/integrations/tracing/fastify.js +0 -33
  85. package/cjs/integrations/tracing/fastify.js.map +0 -1
  86. package/cjs/integrations/tracing/graphql.js +0 -34
  87. package/cjs/integrations/tracing/graphql.js.map +0 -1
  88. package/cjs/integrations/tracing/hapi/index.js +0 -81
  89. package/cjs/integrations/tracing/hapi/index.js.map +0 -1
  90. package/cjs/integrations/tracing/index.js +0 -37
  91. package/cjs/integrations/tracing/index.js.map +0 -1
  92. package/cjs/integrations/tracing/koa.js +0 -21
  93. package/cjs/integrations/tracing/koa.js.map +0 -1
  94. package/cjs/integrations/tracing/mongo.js +0 -33
  95. package/cjs/integrations/tracing/mongo.js.map +0 -1
  96. package/cjs/integrations/tracing/mongoose.js +0 -33
  97. package/cjs/integrations/tracing/mongoose.js.map +0 -1
  98. package/cjs/integrations/tracing/mysql.js +0 -26
  99. package/cjs/integrations/tracing/mysql.js.map +0 -1
  100. package/cjs/integrations/tracing/mysql2.js +0 -33
  101. package/cjs/integrations/tracing/mysql2.js.map +0 -1
  102. package/cjs/integrations/tracing/nest.js +0 -26
  103. package/cjs/integrations/tracing/nest.js.map +0 -1
  104. package/cjs/integrations/tracing/postgres.js +0 -34
  105. package/cjs/integrations/tracing/postgres.js.map +0 -1
  106. package/cjs/integrations/tracing/prisma.js +0 -33
  107. package/cjs/integrations/tracing/prisma.js.map +0 -1
  108. package/cjs/nodeVersion.js +0 -12
  109. package/cjs/nodeVersion.js.map +0 -1
  110. package/cjs/otel/contextManager.js +0 -16
  111. package/cjs/otel/contextManager.js.map +0 -1
  112. package/cjs/proxy/base.js +0 -126
  113. package/cjs/proxy/base.js.map +0 -1
  114. package/cjs/proxy/index.js +0 -209
  115. package/cjs/proxy/index.js.map +0 -1
  116. package/cjs/proxy/parse-proxy-response.js +0 -104
  117. package/cjs/proxy/parse-proxy-response.js.map +0 -1
  118. package/cjs/sdk/api.js +0 -74
  119. package/cjs/sdk/api.js.map +0 -1
  120. package/cjs/sdk/client.js +0 -57
  121. package/cjs/sdk/client.js.map +0 -1
  122. package/cjs/sdk/hub.js +0 -104
  123. package/cjs/sdk/hub.js.map +0 -1
  124. package/cjs/sdk/init.js +0 -224
  125. package/cjs/sdk/init.js.map +0 -1
  126. package/cjs/sdk/initOtel.js +0 -70
  127. package/cjs/sdk/initOtel.js.map +0 -1
  128. package/cjs/sdk/scope.js +0 -18
  129. package/cjs/sdk/scope.js.map +0 -1
  130. package/cjs/transports/http.js +0 -160
  131. package/cjs/transports/http.js.map +0 -1
  132. package/cjs/utils/addOriginToSpan.js +0 -11
  133. package/cjs/utils/addOriginToSpan.js.map +0 -1
  134. package/cjs/utils/errorhandling.js +0 -44
  135. package/cjs/utils/errorhandling.js.map +0 -1
  136. package/cjs/utils/getRequestUrl.js +0 -18
  137. package/cjs/utils/getRequestUrl.js.map +0 -1
  138. package/cjs/utils/module.js +0 -62
  139. package/cjs/utils/module.js.map +0 -1
  140. package/esm/cron/common.js +0 -54
  141. package/esm/cron/common.js.map +0 -1
  142. package/esm/cron/cron.js +0 -100
  143. package/esm/cron/cron.js.map +0 -1
  144. package/esm/cron/index.js +0 -13
  145. package/esm/cron/index.js.map +0 -1
  146. package/esm/cron/node-cron.js +0 -56
  147. package/esm/cron/node-cron.js.map +0 -1
  148. package/esm/cron/node-schedule.js +0 -55
  149. package/esm/cron/node-schedule.js.map +0 -1
  150. package/esm/debug-build.js +0 -9
  151. package/esm/debug-build.js.map +0 -1
  152. package/esm/integrations/anr/index.js +0 -139
  153. package/esm/integrations/anr/index.js.map +0 -1
  154. package/esm/integrations/anr/worker-script.js.map +0 -1
  155. package/esm/integrations/console.js +0 -38
  156. package/esm/integrations/console.js.map +0 -1
  157. package/esm/integrations/context.js +0 -427
  158. package/esm/integrations/context.js.map +0 -1
  159. package/esm/integrations/contextlines.js +0 -131
  160. package/esm/integrations/contextlines.js.map +0 -1
  161. package/esm/integrations/http.js +0 -132
  162. package/esm/integrations/http.js.map +0 -1
  163. package/esm/integrations/local-variables/common.js +0 -81
  164. package/esm/integrations/local-variables/common.js.map +0 -1
  165. package/esm/integrations/local-variables/index.js +0 -6
  166. package/esm/integrations/local-variables/index.js.map +0 -1
  167. package/esm/integrations/local-variables/local-variables-sync.js +0 -394
  168. package/esm/integrations/local-variables/local-variables-sync.js.map +0 -1
  169. package/esm/integrations/modules.js +0 -97
  170. package/esm/integrations/modules.js.map +0 -1
  171. package/esm/integrations/node-fetch.js +0 -80
  172. package/esm/integrations/node-fetch.js.map +0 -1
  173. package/esm/integrations/onuncaughtexception.js +0 -134
  174. package/esm/integrations/onuncaughtexception.js.map +0 -1
  175. package/esm/integrations/onunhandledrejection.js +0 -87
  176. package/esm/integrations/onunhandledrejection.js.map +0 -1
  177. package/esm/integrations/spotlight.js +0 -106
  178. package/esm/integrations/spotlight.js.map +0 -1
  179. package/esm/integrations/tracing/express.js +0 -96
  180. package/esm/integrations/tracing/express.js.map +0 -1
  181. package/esm/integrations/tracing/fastify.js +0 -31
  182. package/esm/integrations/tracing/fastify.js.map +0 -1
  183. package/esm/integrations/tracing/graphql.js +0 -32
  184. package/esm/integrations/tracing/graphql.js.map +0 -1
  185. package/esm/integrations/tracing/hapi/index.js +0 -77
  186. package/esm/integrations/tracing/hapi/index.js.map +0 -1
  187. package/esm/integrations/tracing/index.js +0 -35
  188. package/esm/integrations/tracing/index.js.map +0 -1
  189. package/esm/integrations/tracing/koa.js +0 -19
  190. package/esm/integrations/tracing/koa.js.map +0 -1
  191. package/esm/integrations/tracing/mongo.js +0 -31
  192. package/esm/integrations/tracing/mongo.js.map +0 -1
  193. package/esm/integrations/tracing/mongoose.js +0 -31
  194. package/esm/integrations/tracing/mongoose.js.map +0 -1
  195. package/esm/integrations/tracing/mysql.js +0 -24
  196. package/esm/integrations/tracing/mysql.js.map +0 -1
  197. package/esm/integrations/tracing/mysql2.js +0 -31
  198. package/esm/integrations/tracing/mysql2.js.map +0 -1
  199. package/esm/integrations/tracing/nest.js +0 -24
  200. package/esm/integrations/tracing/nest.js.map +0 -1
  201. package/esm/integrations/tracing/postgres.js +0 -32
  202. package/esm/integrations/tracing/postgres.js.map +0 -1
  203. package/esm/integrations/tracing/prisma.js +0 -31
  204. package/esm/integrations/tracing/prisma.js.map +0 -1
  205. package/esm/nodeVersion.js +0 -9
  206. package/esm/nodeVersion.js.map +0 -1
  207. package/esm/otel/contextManager.js +0 -14
  208. package/esm/otel/contextManager.js.map +0 -1
  209. package/esm/proxy/base.js +0 -121
  210. package/esm/proxy/base.js.map +0 -1
  211. package/esm/proxy/index.js +0 -203
  212. package/esm/proxy/index.js.map +0 -1
  213. package/esm/proxy/parse-proxy-response.js +0 -102
  214. package/esm/proxy/parse-proxy-response.js.map +0 -1
  215. package/esm/sdk/api.js +0 -69
  216. package/esm/sdk/api.js.map +0 -1
  217. package/esm/sdk/client.js +0 -52
  218. package/esm/sdk/client.js.map +0 -1
  219. package/esm/sdk/hub.js +0 -102
  220. package/esm/sdk/hub.js.map +0 -1
  221. package/esm/sdk/init.js +0 -221
  222. package/esm/sdk/init.js.map +0 -1
  223. package/esm/sdk/initOtel.js +0 -67
  224. package/esm/sdk/initOtel.js.map +0 -1
  225. package/esm/sdk/scope.js +0 -16
  226. package/esm/sdk/scope.js.map +0 -1
  227. package/esm/transports/http.js +0 -155
  228. package/esm/transports/http.js.map +0 -1
  229. package/esm/utils/addOriginToSpan.js +0 -9
  230. package/esm/utils/addOriginToSpan.js.map +0 -1
  231. package/esm/utils/errorhandling.js +0 -42
  232. package/esm/utils/errorhandling.js.map +0 -1
  233. package/esm/utils/getRequestUrl.js +0 -16
  234. package/esm/utils/getRequestUrl.js.map +0 -1
  235. package/esm/utils/module.js +0 -60
  236. package/esm/utils/module.js.map +0 -1
  237. package/types/integrations/local-variables/local-variables-async.d.ts +0 -14
  238. package/types/integrations/local-variables/local-variables-async.d.ts.map +0 -1
  239. package/types-ts3.8/integrations/local-variables/local-variables-async.d.ts +0 -14
package/esm/index.js CHANGED
@@ -1,33 +1,3616 @@
1
- export { httpIntegration } from './integrations/http.js';
2
- export { nativeNodeFetchIntegration } from './integrations/node-fetch.js';
3
- export { consoleIntegration } from './integrations/console.js';
4
- export { nodeContextIntegration } from './integrations/context.js';
5
- export { contextLinesIntegration } from './integrations/contextlines.js';
6
- export { localVariablesIntegration } from './integrations/local-variables/index.js';
7
- export { modulesIntegration } from './integrations/modules.js';
8
- export { onUncaughtExceptionIntegration } from './integrations/onuncaughtexception.js';
9
- export { onUnhandledRejectionIntegration } from './integrations/onunhandledrejection.js';
10
- export { anrIntegration } from './integrations/anr/index.js';
11
- export { expressErrorHandler, expressIntegration, setupExpressErrorHandler } from './integrations/tracing/express.js';
12
- export { fastifyIntegration } from './integrations/tracing/fastify.js';
13
- export { graphqlIntegration } from './integrations/tracing/graphql.js';
14
- export { mongoIntegration } from './integrations/tracing/mongo.js';
15
- export { mongooseIntegration } from './integrations/tracing/mongoose.js';
16
- export { mysqlIntegration } from './integrations/tracing/mysql.js';
17
- export { mysql2Integration } from './integrations/tracing/mysql2.js';
18
- export { nestIntegration } from './integrations/tracing/nest.js';
19
- export { postgresIntegration } from './integrations/tracing/postgres.js';
20
- export { prismaIntegration } from './integrations/tracing/prisma.js';
21
- export { hapiIntegration, setupHapiErrorHandler } from './integrations/tracing/hapi/index.js';
22
- export { getDefaultIntegrations, init } from './sdk/init.js';
23
- export { getAutoPerformanceIntegrations } from './integrations/tracing/index.js';
24
- export { defaultStackParser, getClient, getSentryRelease, makeMain } from './sdk/api.js';
25
- export { createGetModuleFromFilename } from './utils/module.js';
26
- export { makeNodeTransport } from './transports/http.js';
27
- export { NodeClient } from './sdk/client.js';
28
- export { getCurrentHub } from './sdk/hub.js';
29
- export { cron } from './cron/index.js';
30
- export { getActiveSpan, startInactiveSpan, startSpan, startSpanManual, withActiveSpan } from '@sentry/opentelemetry';
1
+ import { _optionalChainDelete, _nullishCoalesce, _optionalChain } from '@sentry/utils';
2
+ import { context, SpanKind, trace, diag, DiagLogLevel } from '@opentelemetry/api';
3
+ import { registerInstrumentations } from '@opentelemetry/instrumentation';
4
+ import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
5
+ import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, isSentryRequestUrl, getIsolationScope, addBreadcrumb, getClient as getClient$2, convertIntegrationFnToClass, captureException, getCurrentScope, SDK_VERSION, getActiveSpan, getRootSpan, SPAN_STATUS_ERROR, createTransport, ServerRuntimeClient, applySdkMetadata, inboundFiltersIntegration, functionToStringIntegration, linkedErrorsIntegration, requestDataIntegration, hasTracingEnabled, getIntegrationsToSetup, startSession, endSession, withScope, captureEvent, setUser, setTags, setTag, setExtra, setExtras, setContext, withMonitor } from '@sentry/core';
6
+ export { Hub, SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, Scope, addBreadcrumb, addEventProcessor, addIntegration, captureCheckIn, captureConsoleIntegration, captureEvent, captureException, captureMessage, captureSession, close, createTransport, debugIntegration, dedupeIntegration, endSession, extraErrorDataIntegration, flush, functionToStringIntegration, getActiveSpan, getCurrentScope, getGlobalScope, getIsolationScope, getRootSpan, getSpanDescendants, getSpanStatusFromHttpCode, inboundFiltersIntegration, isInitialized, linkedErrorsIntegration, metricsDefault as metrics, parameterize, requestDataIntegration, rewriteFramesIntegration, sessionTimingIntegration, setContext, setCurrentClient, setExtra, setExtras, setHttpStatus, setMeasurement, setTag, setTags, setUser, startInactiveSpan, startSession, startSpan, startSpanManual, withActiveSpan, withIsolationScope, withMonitor, withScope } from '@sentry/core';
7
+ import { getScopesFromContext, getClient as getClient$1, getSpanKind, _INTERNAL, wrapContextManagerClass, setupEventContextTrace, SentrySampler, SentrySpanProcessor, SentryPropagator, setOpenTelemetryContextAsyncContextStrategy, openTelemetrySetupCheck } from '@sentry/opentelemetry';
8
+ export { continueTrace } from '@sentry/opentelemetry';
9
+ import { parseSemver, addConsoleInstrumentationHandler, severityLevelFromString, LRUMap, addContextToFrame, logger, consoleSandbox, serializeEnvelope, dirname as dirname$1, createStackParser, nodeStackLineParser, GLOBAL_OBJ, dropUndefinedKeys, stackParserFromStackParserOptions, propagationContextFromHeaders } from '@sentry/utils';
31
10
  export { DEFAULT_USER_INCLUDES, addRequestDataToEvent, extractRequestData } from '@sentry/utils';
32
- export { Hub, SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, Scope, addBreadcrumb, addEventProcessor, captureCheckIn, captureConsoleIntegration, captureEvent, captureException, captureMessage, close, continueTrace, createTransport, debugIntegration, dedupeIntegration, extraErrorDataIntegration, flush, functionToStringIntegration, getCurrentScope, getGlobalScope, getIsolationScope, getSpanStatusFromHttpCode, inboundFiltersIntegration, isInitialized, linkedErrorsIntegration, parameterize, requestDataIntegration, rewriteFramesIntegration, sessionTimingIntegration, setContext, setCurrentClient, setExtra, setExtras, setHttpStatus, setMeasurement, setTag, setTags, setUser, withIsolationScope, withMonitor, withScope } from '@sentry/core';
11
+ import * as util from 'util';
12
+ import { promisify } from 'util';
13
+ import { execFile } from 'child_process';
14
+ import { readFile, readdir, promises, existsSync, readFileSync } from 'fs';
15
+ import * as os from 'os';
16
+ import { join, dirname, posix, sep } from 'path';
17
+ import * as inspector from 'inspector';
18
+ import { Session } from 'inspector';
19
+ import { Worker } from 'worker_threads';
20
+ import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
21
+ import { FastifyInstrumentation } from '@opentelemetry/instrumentation-fastify';
22
+ import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql';
23
+ import { MongoDBInstrumentation } from '@opentelemetry/instrumentation-mongodb';
24
+ import { MongooseInstrumentation } from '@opentelemetry/instrumentation-mongoose';
25
+ import { MySQLInstrumentation } from '@opentelemetry/instrumentation-mysql';
26
+ import { MySQL2Instrumentation } from '@opentelemetry/instrumentation-mysql2';
27
+ import { NestInstrumentation } from '@opentelemetry/instrumentation-nestjs-core';
28
+ import { PgInstrumentation } from '@opentelemetry/instrumentation-pg';
29
+ import * as prismaInstrumentation from '@prisma/instrumentation';
30
+ import { HapiInstrumentation } from '@opentelemetry/instrumentation-hapi';
31
+ import * as http from 'http';
32
+ import { KoaInstrumentation } from '@opentelemetry/instrumentation-koa';
33
+ import * as http$1 from 'node:http';
34
+ import * as https from 'node:https';
35
+ import { Readable } from 'stream';
36
+ import { createGzip } from 'zlib';
37
+ import * as net from 'net';
38
+ import * as tls from 'tls';
39
+ import { Resource } from '@opentelemetry/resources';
40
+ import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
41
+ import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
42
+ import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
43
+
44
+ /**
45
+ * Update the active isolation scope.
46
+ * Should be used with caution!
47
+ */
48
+ function setIsolationScope(isolationScope) {
49
+ const scopes = getScopesFromContext(context.active());
50
+ if (scopes) {
51
+ scopes.isolationScope = isolationScope;
52
+ }
53
+ }
54
+
55
+ /** Adds an origin to an OTEL Span. */
56
+ function addOriginToSpan(span, origin) {
57
+ span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, origin);
58
+ }
59
+
60
+ /** Build a full URL from request options. */
61
+ function getRequestUrl(requestOptions) {
62
+ const protocol = requestOptions.protocol || '';
63
+ const hostname = requestOptions.hostname || requestOptions.host || '';
64
+ // Don't log standard :80 (http) and :443 (https) ports to reduce the noise
65
+ // Also don't add port if the hostname already includes a port
66
+ const port =
67
+ !requestOptions.port || requestOptions.port === 80 || requestOptions.port === 443 || /^(.*):(\d+)$/.test(hostname)
68
+ ? ''
69
+ : `:${requestOptions.port}`;
70
+ const path = requestOptions.path ? requestOptions.path : '/';
71
+ return `${protocol}//${hostname}${port}${path}`;
72
+ }
73
+
74
+ function _optionalChain$8(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
75
+
76
+ const _httpIntegration = ((options = {}) => {
77
+ const _breadcrumbs = typeof options.breadcrumbs === 'undefined' ? true : options.breadcrumbs;
78
+ const _ignoreOutgoingRequests = options.ignoreOutgoingRequests;
79
+ const _ignoreIncomingRequests = options.ignoreIncomingRequests;
80
+
81
+ return {
82
+ name: 'Http',
83
+ setupOnce() {
84
+ const instrumentations = [
85
+ new HttpInstrumentation({
86
+ ignoreOutgoingRequestHook: request => {
87
+ const url = getRequestUrl(request);
88
+
89
+ if (!url) {
90
+ return false;
91
+ }
92
+
93
+ if (isSentryRequestUrl(url, getClient$1())) {
94
+ return true;
95
+ }
96
+
97
+ if (_ignoreOutgoingRequests && _ignoreOutgoingRequests(url)) {
98
+ return true;
99
+ }
100
+
101
+ return false;
102
+ },
103
+
104
+ ignoreIncomingRequestHook: request => {
105
+ const url = getRequestUrl(request);
106
+
107
+ const method = _optionalChain$8([request, 'access', _ => _.method, 'optionalAccess', _2 => _2.toUpperCase, 'call', _3 => _3()]);
108
+ // We do not capture OPTIONS/HEAD requests as transactions
109
+ if (method === 'OPTIONS' || method === 'HEAD') {
110
+ return true;
111
+ }
112
+
113
+ if (_ignoreIncomingRequests && _ignoreIncomingRequests(url)) {
114
+ return true;
115
+ }
116
+
117
+ return false;
118
+ },
119
+
120
+ requireParentforOutgoingSpans: true,
121
+ requireParentforIncomingSpans: false,
122
+ requestHook: (span, req) => {
123
+ _updateSpan$1(span);
124
+
125
+ // Update the isolation scope, isolate this request
126
+ if (getSpanKind(span) === SpanKind.SERVER) {
127
+ const isolationScope = getIsolationScope().clone();
128
+ isolationScope.setSDKProcessingMetadata({ request: req });
129
+
130
+ const client = getClient$1();
131
+ if (client && client.getOptions().autoSessionTracking) {
132
+ isolationScope.setRequestSession({ status: 'ok' });
133
+ }
134
+ setIsolationScope(isolationScope);
135
+ }
136
+ },
137
+ responseHook: (span, res) => {
138
+ if (_breadcrumbs) {
139
+ _addRequestBreadcrumb$1(span, res);
140
+ }
141
+
142
+ const client = getClient$1();
143
+ if (client && client.getOptions().autoSessionTracking) {
144
+ setImmediate(() => {
145
+ client['_captureRequestSession']();
146
+ });
147
+ }
148
+ },
149
+ }),
150
+ ];
151
+
152
+ registerInstrumentations({
153
+ instrumentations,
154
+ });
155
+ },
156
+ };
157
+ }) ;
158
+
159
+ /**
160
+ * The http integration instruments Node's internal http and https modules.
161
+ * It creates breadcrumbs and spans for outgoing HTTP requests which will be attached to the currently active span.
162
+ */
163
+ const httpIntegration = defineIntegration(_httpIntegration);
164
+
165
+ /** Update the span with data we need. */
166
+ function _updateSpan$1(span) {
167
+ addOriginToSpan(span, 'auto.http.otel.http');
168
+ }
169
+
170
+ /** Add a breadcrumb for outgoing requests. */
171
+ function _addRequestBreadcrumb$1(span, response) {
172
+ if (getSpanKind(span) !== SpanKind.CLIENT) {
173
+ return;
174
+ }
175
+
176
+ const data = _INTERNAL.getRequestSpanData(span);
177
+ addBreadcrumb(
178
+ {
179
+ category: 'http',
180
+ data: {
181
+ status_code: response.statusCode,
182
+ ...data,
183
+ },
184
+ type: 'http',
185
+ },
186
+ {
187
+ event: 'response',
188
+ // TODO FN: Do we need access to `request` here?
189
+ // If we do, we'll have to use the `applyCustomAttributesOnSpan` hook instead,
190
+ // but this has worse context semantics than request/responseHook.
191
+ response,
192
+ },
193
+ );
194
+ }
195
+
196
+ const NODE_VERSION = parseSemver(process.versions.node)
197
+
198
+ ;
199
+ const NODE_MAJOR = NODE_VERSION.major || 0;
200
+
201
+ const _nativeNodeFetchIntegration = ((options = {}) => {
202
+ const _breadcrumbs = typeof options.breadcrumbs === 'undefined' ? true : options.breadcrumbs;
203
+ const _ignoreOutgoingRequests = options.ignoreOutgoingRequests;
204
+
205
+ async function getInstrumentation() {
206
+ // Only add NodeFetch if Node >= 16, as previous versions do not support it
207
+ if (NODE_MAJOR < 16) {
208
+ return;
209
+ }
210
+
211
+ try {
212
+ const pkg = await import('opentelemetry-instrumentation-fetch-node');
213
+ return [
214
+ new pkg.FetchInstrumentation({
215
+ ignoreRequestHook: (request) => {
216
+ const url = request.origin;
217
+ return _ignoreOutgoingRequests && url && _ignoreOutgoingRequests(url);
218
+ },
219
+ onRequest: ({ span }) => {
220
+ _updateSpan(span);
221
+
222
+ if (_breadcrumbs) {
223
+ _addRequestBreadcrumb(span);
224
+ }
225
+ },
226
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
227
+ } ),
228
+ ];
229
+ } catch (error) {
230
+ // Could not load instrumentation
231
+ }
232
+ }
233
+
234
+ return {
235
+ name: 'NodeFetch',
236
+ setupOnce() {
237
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
238
+ getInstrumentation().then(instrumentations => {
239
+ if (instrumentations) {
240
+ registerInstrumentations({
241
+ instrumentations,
242
+ });
243
+ }
244
+ });
245
+ },
246
+ };
247
+ }) ;
248
+
249
+ const nativeNodeFetchIntegration = defineIntegration(_nativeNodeFetchIntegration);
250
+
251
+ /** Update the span with data we need. */
252
+ function _updateSpan(span) {
253
+ addOriginToSpan(span, 'auto.http.otel.node_fetch');
254
+ }
255
+
256
+ /** Add a breadcrumb for outgoing requests. */
257
+ function _addRequestBreadcrumb(span) {
258
+ if (getSpanKind(span) !== SpanKind.CLIENT) {
259
+ return;
260
+ }
261
+
262
+ const data = _INTERNAL.getRequestSpanData(span);
263
+ addBreadcrumb({
264
+ category: 'http',
265
+ data: {
266
+ ...data,
267
+ },
268
+ type: 'http',
269
+ });
270
+ }
271
+
272
+ const INTEGRATION_NAME$8 = 'Console';
273
+
274
+ const _consoleIntegration = (() => {
275
+ return {
276
+ name: INTEGRATION_NAME$8,
277
+ setup(client) {
278
+ addConsoleInstrumentationHandler(({ args, level }) => {
279
+ if (getClient$2() !== client) {
280
+ return;
281
+ }
282
+
283
+ addBreadcrumb(
284
+ {
285
+ category: 'console',
286
+ level: severityLevelFromString(level),
287
+ message: util.format.apply(undefined, args),
288
+ },
289
+ {
290
+ input: [...args],
291
+ level,
292
+ },
293
+ );
294
+ });
295
+ },
296
+ };
297
+ }) ;
298
+
299
+ /**
300
+ * Capture console logs as breadcrumbs.
301
+ */
302
+ const consoleIntegration = defineIntegration(_consoleIntegration);
303
+
304
+ function _optionalChain$7(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
305
+ const readFileAsync$1 = promisify(readFile);
306
+ const readDirAsync = promisify(readdir);
307
+
308
+ const INTEGRATION_NAME$7 = 'Context';
309
+
310
+ const _nodeContextIntegration = ((options = {}) => {
311
+ let cachedContext;
312
+
313
+ const _options = {
314
+ app: true,
315
+ os: true,
316
+ device: true,
317
+ culture: true,
318
+ cloudResource: true,
319
+ ...options,
320
+ };
321
+
322
+ /** Add contexts to the event. Caches the context so we only look it up once. */
323
+ async function addContext(event) {
324
+ if (cachedContext === undefined) {
325
+ cachedContext = _getContexts();
326
+ }
327
+
328
+ const updatedContext = _updateContext(await cachedContext);
329
+
330
+ event.contexts = {
331
+ ...event.contexts,
332
+ app: { ...updatedContext.app, ..._optionalChain$7([event, 'access', _ => _.contexts, 'optionalAccess', _2 => _2.app]) },
333
+ os: { ...updatedContext.os, ..._optionalChain$7([event, 'access', _3 => _3.contexts, 'optionalAccess', _4 => _4.os]) },
334
+ device: { ...updatedContext.device, ..._optionalChain$7([event, 'access', _5 => _5.contexts, 'optionalAccess', _6 => _6.device]) },
335
+ culture: { ...updatedContext.culture, ..._optionalChain$7([event, 'access', _7 => _7.contexts, 'optionalAccess', _8 => _8.culture]) },
336
+ cloud_resource: { ...updatedContext.cloud_resource, ..._optionalChain$7([event, 'access', _9 => _9.contexts, 'optionalAccess', _10 => _10.cloud_resource]) },
337
+ };
338
+
339
+ return event;
340
+ }
341
+
342
+ /** Get the contexts from node. */
343
+ async function _getContexts() {
344
+ const contexts = {};
345
+
346
+ if (_options.os) {
347
+ contexts.os = await getOsContext();
348
+ }
349
+
350
+ if (_options.app) {
351
+ contexts.app = getAppContext();
352
+ }
353
+
354
+ if (_options.device) {
355
+ contexts.device = getDeviceContext(_options.device);
356
+ }
357
+
358
+ if (_options.culture) {
359
+ const culture = getCultureContext();
360
+
361
+ if (culture) {
362
+ contexts.culture = culture;
363
+ }
364
+ }
365
+
366
+ if (_options.cloudResource) {
367
+ contexts.cloud_resource = getCloudResourceContext();
368
+ }
369
+
370
+ return contexts;
371
+ }
372
+
373
+ return {
374
+ name: INTEGRATION_NAME$7,
375
+ processEvent(event) {
376
+ return addContext(event);
377
+ },
378
+ };
379
+ }) ;
380
+
381
+ /**
382
+ * Capture context about the environment and the device that the client is running on, to events.
383
+ */
384
+ const nodeContextIntegration = defineIntegration(_nodeContextIntegration);
385
+
386
+ /**
387
+ * Updates the context with dynamic values that can change
388
+ */
389
+ function _updateContext(contexts) {
390
+ // Only update properties if they exist
391
+ if (_optionalChain$7([contexts, 'optionalAccess', _11 => _11.app, 'optionalAccess', _12 => _12.app_memory])) {
392
+ contexts.app.app_memory = process.memoryUsage().rss;
393
+ }
394
+
395
+ if (_optionalChain$7([contexts, 'optionalAccess', _13 => _13.device, 'optionalAccess', _14 => _14.free_memory])) {
396
+ contexts.device.free_memory = os.freemem();
397
+ }
398
+
399
+ return contexts;
400
+ }
401
+
402
+ /**
403
+ * Returns the operating system context.
404
+ *
405
+ * Based on the current platform, this uses a different strategy to provide the
406
+ * most accurate OS information. Since this might involve spawning subprocesses
407
+ * or accessing the file system, this should only be executed lazily and cached.
408
+ *
409
+ * - On macOS (Darwin), this will execute the `sw_vers` utility. The context
410
+ * has a `name`, `version`, `build` and `kernel_version` set.
411
+ * - On Linux, this will try to load a distribution release from `/etc` and set
412
+ * the `name`, `version` and `kernel_version` fields.
413
+ * - On all other platforms, only a `name` and `version` will be returned. Note
414
+ * that `version` might actually be the kernel version.
415
+ */
416
+ async function getOsContext() {
417
+ const platformId = os.platform();
418
+ switch (platformId) {
419
+ case 'darwin':
420
+ return getDarwinInfo();
421
+ case 'linux':
422
+ return getLinuxInfo();
423
+ default:
424
+ return {
425
+ name: PLATFORM_NAMES[platformId] || platformId,
426
+ version: os.release(),
427
+ };
428
+ }
429
+ }
430
+
431
+ function getCultureContext() {
432
+ try {
433
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
434
+ if (typeof (process.versions ).icu !== 'string') {
435
+ // Node was built without ICU support
436
+ return;
437
+ }
438
+
439
+ // Check that node was built with full Intl support. Its possible it was built without support for non-English
440
+ // locales which will make resolvedOptions inaccurate
441
+ //
442
+ // https://nodejs.org/api/intl.html#detecting-internationalization-support
443
+ const january = new Date(9e8);
444
+ const spanish = new Intl.DateTimeFormat('es', { month: 'long' });
445
+ if (spanish.format(january) === 'enero') {
446
+ const options = Intl.DateTimeFormat().resolvedOptions();
447
+
448
+ return {
449
+ locale: options.locale,
450
+ timezone: options.timeZone,
451
+ };
452
+ }
453
+ } catch (err) {
454
+ //
455
+ }
456
+
457
+ return;
458
+ }
459
+
460
+ function getAppContext() {
461
+ const app_memory = process.memoryUsage().rss;
462
+ const app_start_time = new Date(Date.now() - process.uptime() * 1000).toISOString();
463
+
464
+ return { app_start_time, app_memory };
465
+ }
466
+
467
+ /**
468
+ * Gets device information from os
469
+ */
470
+ function getDeviceContext(deviceOpt) {
471
+ const device = {};
472
+
473
+ // Sometimes os.uptime() throws due to lacking permissions: https://github.com/getsentry/sentry-javascript/issues/8202
474
+ let uptime;
475
+ try {
476
+ uptime = os.uptime && os.uptime();
477
+ } catch (e) {
478
+ // noop
479
+ }
480
+
481
+ // os.uptime or its return value seem to be undefined in certain environments (e.g. Azure functions).
482
+ // Hence, we only set boot time, if we get a valid uptime value.
483
+ // @see https://github.com/getsentry/sentry-javascript/issues/5856
484
+ if (typeof uptime === 'number') {
485
+ device.boot_time = new Date(Date.now() - uptime * 1000).toISOString();
486
+ }
487
+
488
+ device.arch = os.arch();
489
+
490
+ if (deviceOpt === true || deviceOpt.memory) {
491
+ device.memory_size = os.totalmem();
492
+ device.free_memory = os.freemem();
493
+ }
494
+
495
+ if (deviceOpt === true || deviceOpt.cpu) {
496
+ const cpuInfo = os.cpus();
497
+ if (cpuInfo && cpuInfo.length) {
498
+ const firstCpu = cpuInfo[0];
499
+
500
+ device.processor_count = cpuInfo.length;
501
+ device.cpu_description = firstCpu.model;
502
+ device.processor_frequency = firstCpu.speed;
503
+ }
504
+ }
505
+
506
+ return device;
507
+ }
508
+
509
+ /** Mapping of Node's platform names to actual OS names. */
510
+ const PLATFORM_NAMES = {
511
+ aix: 'IBM AIX',
512
+ freebsd: 'FreeBSD',
513
+ openbsd: 'OpenBSD',
514
+ sunos: 'SunOS',
515
+ win32: 'Windows',
516
+ };
517
+
518
+ /** Linux version file to check for a distribution. */
519
+
520
+ /** Mapping of linux release files located in /etc to distributions. */
521
+ const LINUX_DISTROS = [
522
+ { name: 'fedora-release', distros: ['Fedora'] },
523
+ { name: 'redhat-release', distros: ['Red Hat Linux', 'Centos'] },
524
+ { name: 'redhat_version', distros: ['Red Hat Linux'] },
525
+ { name: 'SuSE-release', distros: ['SUSE Linux'] },
526
+ { name: 'lsb-release', distros: ['Ubuntu Linux', 'Arch Linux'] },
527
+ { name: 'debian_version', distros: ['Debian'] },
528
+ { name: 'debian_release', distros: ['Debian'] },
529
+ { name: 'arch-release', distros: ['Arch Linux'] },
530
+ { name: 'gentoo-release', distros: ['Gentoo Linux'] },
531
+ { name: 'novell-release', distros: ['SUSE Linux'] },
532
+ { name: 'alpine-release', distros: ['Alpine Linux'] },
533
+ ];
534
+
535
+ /** Functions to extract the OS version from Linux release files. */
536
+ const LINUX_VERSIONS
537
+
538
+ = {
539
+ alpine: content => content,
540
+ arch: content => matchFirst(/distrib_release=(.*)/, content),
541
+ centos: content => matchFirst(/release ([^ ]+)/, content),
542
+ debian: content => content,
543
+ fedora: content => matchFirst(/release (..)/, content),
544
+ mint: content => matchFirst(/distrib_release=(.*)/, content),
545
+ red: content => matchFirst(/release ([^ ]+)/, content),
546
+ suse: content => matchFirst(/VERSION = (.*)\n/, content),
547
+ ubuntu: content => matchFirst(/distrib_release=(.*)/, content),
548
+ };
549
+
550
+ /**
551
+ * Executes a regular expression with one capture group.
552
+ *
553
+ * @param regex A regular expression to execute.
554
+ * @param text Content to execute the RegEx on.
555
+ * @returns The captured string if matched; otherwise undefined.
556
+ */
557
+ function matchFirst(regex, text) {
558
+ const match = regex.exec(text);
559
+ return match ? match[1] : undefined;
560
+ }
561
+
562
+ /** Loads the macOS operating system context. */
563
+ async function getDarwinInfo() {
564
+ // Default values that will be used in case no operating system information
565
+ // can be loaded. The default version is computed via heuristics from the
566
+ // kernel version, but the build ID is missing.
567
+ const darwinInfo = {
568
+ kernel_version: os.release(),
569
+ name: 'Mac OS X',
570
+ version: `10.${Number(os.release().split('.')[0]) - 4}`,
571
+ };
572
+
573
+ try {
574
+ // We try to load the actual macOS version by executing the `sw_vers` tool.
575
+ // This tool should be available on every standard macOS installation. In
576
+ // case this fails, we stick with the values computed above.
577
+
578
+ const output = await new Promise((resolve, reject) => {
579
+ execFile('/usr/bin/sw_vers', (error, stdout) => {
580
+ if (error) {
581
+ reject(error);
582
+ return;
583
+ }
584
+ resolve(stdout);
585
+ });
586
+ });
587
+
588
+ darwinInfo.name = matchFirst(/^ProductName:\s+(.*)$/m, output);
589
+ darwinInfo.version = matchFirst(/^ProductVersion:\s+(.*)$/m, output);
590
+ darwinInfo.build = matchFirst(/^BuildVersion:\s+(.*)$/m, output);
591
+ } catch (e) {
592
+ // ignore
593
+ }
594
+
595
+ return darwinInfo;
596
+ }
597
+
598
+ /** Returns a distribution identifier to look up version callbacks. */
599
+ function getLinuxDistroId(name) {
600
+ return name.split(' ')[0].toLowerCase();
601
+ }
602
+
603
+ /** Loads the Linux operating system context. */
604
+ async function getLinuxInfo() {
605
+ // By default, we cannot assume anything about the distribution or Linux
606
+ // version. `os.release()` returns the kernel version and we assume a generic
607
+ // "Linux" name, which will be replaced down below.
608
+ const linuxInfo = {
609
+ kernel_version: os.release(),
610
+ name: 'Linux',
611
+ };
612
+
613
+ try {
614
+ // We start guessing the distribution by listing files in the /etc
615
+ // directory. This is were most Linux distributions (except Knoppix) store
616
+ // release files with certain distribution-dependent meta data. We search
617
+ // for exactly one known file defined in `LINUX_DISTROS` and exit if none
618
+ // are found. In case there are more than one file, we just stick with the
619
+ // first one.
620
+ const etcFiles = await readDirAsync('/etc');
621
+ const distroFile = LINUX_DISTROS.find(file => etcFiles.includes(file.name));
622
+ if (!distroFile) {
623
+ return linuxInfo;
624
+ }
625
+
626
+ // Once that file is known, load its contents. To make searching in those
627
+ // files easier, we lowercase the file contents. Since these files are
628
+ // usually quite small, this should not allocate too much memory and we only
629
+ // hold on to it for a very short amount of time.
630
+ const distroPath = join('/etc', distroFile.name);
631
+ const contents = ((await readFileAsync$1(distroPath, { encoding: 'utf-8' })) ).toLowerCase();
632
+
633
+ // Some Linux distributions store their release information in the same file
634
+ // (e.g. RHEL and Centos). In those cases, we scan the file for an
635
+ // identifier, that basically consists of the first word of the linux
636
+ // distribution name (e.g. "red" for Red Hat). In case there is no match, we
637
+ // just assume the first distribution in our list.
638
+ const { distros } = distroFile;
639
+ linuxInfo.name = distros.find(d => contents.indexOf(getLinuxDistroId(d)) >= 0) || distros[0];
640
+
641
+ // Based on the found distribution, we can now compute the actual version
642
+ // number. This is different for every distribution, so several strategies
643
+ // are computed in `LINUX_VERSIONS`.
644
+ const id = getLinuxDistroId(linuxInfo.name);
645
+ linuxInfo.version = LINUX_VERSIONS[id](contents);
646
+ } catch (e) {
647
+ // ignore
648
+ }
649
+
650
+ return linuxInfo;
651
+ }
652
+
653
+ /**
654
+ * Grabs some information about hosting provider based on best effort.
655
+ */
656
+ function getCloudResourceContext() {
657
+ if (process.env.VERCEL) {
658
+ // https://vercel.com/docs/concepts/projects/environment-variables/system-environment-variables#system-environment-variables
659
+ return {
660
+ 'cloud.provider': 'vercel',
661
+ 'cloud.region': process.env.VERCEL_REGION,
662
+ };
663
+ } else if (process.env.AWS_REGION) {
664
+ // https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html
665
+ return {
666
+ 'cloud.provider': 'aws',
667
+ 'cloud.region': process.env.AWS_REGION,
668
+ 'cloud.platform': process.env.AWS_EXECUTION_ENV,
669
+ };
670
+ } else if (process.env.GCP_PROJECT) {
671
+ // https://cloud.google.com/composer/docs/how-to/managing/environment-variables#reserved_variables
672
+ return {
673
+ 'cloud.provider': 'gcp',
674
+ };
675
+ } else if (process.env.ALIYUN_REGION_ID) {
676
+ // TODO: find where I found these environment variables - at least gc.github.com returns something
677
+ return {
678
+ 'cloud.provider': 'alibaba_cloud',
679
+ 'cloud.region': process.env.ALIYUN_REGION_ID,
680
+ };
681
+ } else if (process.env.WEBSITE_SITE_NAME && process.env.REGION_NAME) {
682
+ // https://learn.microsoft.com/en-us/azure/app-service/reference-app-settings?tabs=kudu%2Cdotnet#app-environment
683
+ return {
684
+ 'cloud.provider': 'azure',
685
+ 'cloud.region': process.env.REGION_NAME,
686
+ };
687
+ } else if (process.env.IBM_CLOUD_REGION) {
688
+ // TODO: find where I found these environment variables - at least gc.github.com returns something
689
+ return {
690
+ 'cloud.provider': 'ibm_cloud',
691
+ 'cloud.region': process.env.IBM_CLOUD_REGION,
692
+ };
693
+ } else if (process.env.TENCENTCLOUD_REGION) {
694
+ // https://www.tencentcloud.com/document/product/583/32748
695
+ return {
696
+ 'cloud.provider': 'tencent_cloud',
697
+ 'cloud.region': process.env.TENCENTCLOUD_REGION,
698
+ 'cloud.account.id': process.env.TENCENTCLOUD_APPID,
699
+ 'cloud.availability_zone': process.env.TENCENTCLOUD_ZONE,
700
+ };
701
+ } else if (process.env.NETLIFY) {
702
+ // https://docs.netlify.com/configure-builds/environment-variables/#read-only-variables
703
+ return {
704
+ 'cloud.provider': 'netlify',
705
+ };
706
+ } else if (process.env.FLY_REGION) {
707
+ // https://fly.io/docs/reference/runtime-environment/
708
+ return {
709
+ 'cloud.provider': 'fly.io',
710
+ 'cloud.region': process.env.FLY_REGION,
711
+ };
712
+ } else if (process.env.DYNO) {
713
+ // https://devcenter.heroku.com/articles/dynos#local-environment-variables
714
+ return {
715
+ 'cloud.provider': 'heroku',
716
+ };
717
+ } else {
718
+ return undefined;
719
+ }
720
+ }
721
+
722
+ function _optionalChain$6(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
723
+ const FILE_CONTENT_CACHE = new LRUMap(100);
724
+ const DEFAULT_LINES_OF_CONTEXT = 7;
725
+ const INTEGRATION_NAME$6 = 'ContextLines';
726
+
727
+ const readFileAsync = promises.readFile;
728
+
729
+ /** Exported only for tests, as a type-safe variant. */
730
+ const _contextLinesIntegration = ((options = {}) => {
731
+ const contextLines = options.frameContextLines !== undefined ? options.frameContextLines : DEFAULT_LINES_OF_CONTEXT;
732
+
733
+ return {
734
+ name: INTEGRATION_NAME$6,
735
+ processEvent(event) {
736
+ return addSourceContext(event, contextLines);
737
+ },
738
+ };
739
+ }) ;
740
+
741
+ /**
742
+ * Capture the lines before and after the frame's context.
743
+ */
744
+ const contextLinesIntegration = defineIntegration(_contextLinesIntegration);
745
+
746
+ async function addSourceContext(event, contextLines) {
747
+ // keep a lookup map of which files we've already enqueued to read,
748
+ // so we don't enqueue the same file multiple times which would cause multiple i/o reads
749
+ const enqueuedReadSourceFileTasks = {};
750
+ const readSourceFileTasks = [];
751
+
752
+ if (contextLines > 0 && _optionalChain$6([event, 'access', _2 => _2.exception, 'optionalAccess', _3 => _3.values])) {
753
+ for (const exception of event.exception.values) {
754
+ if (!_optionalChain$6([exception, 'access', _4 => _4.stacktrace, 'optionalAccess', _5 => _5.frames])) {
755
+ continue;
756
+ }
757
+
758
+ // We want to iterate in reverse order as calling cache.get will bump the file in our LRU cache.
759
+ // This ends up prioritizes source context for frames at the top of the stack instead of the bottom.
760
+ for (let i = exception.stacktrace.frames.length - 1; i >= 0; i--) {
761
+ const frame = exception.stacktrace.frames[i];
762
+ // Call cache.get to bump the file to the top of the cache and ensure we have not already
763
+ // enqueued a read operation for this filename
764
+ if (frame.filename && !enqueuedReadSourceFileTasks[frame.filename] && !FILE_CONTENT_CACHE.get(frame.filename)) {
765
+ readSourceFileTasks.push(_readSourceFile(frame.filename));
766
+ enqueuedReadSourceFileTasks[frame.filename] = 1;
767
+ }
768
+ }
769
+ }
770
+ }
771
+
772
+ // check if files to read > 0, if so, await all of them to be read before adding source contexts.
773
+ // Normally, Promise.all here could be short circuited if one of the promises rejects, but we
774
+ // are guarding from that by wrapping the i/o read operation in a try/catch.
775
+ if (readSourceFileTasks.length > 0) {
776
+ await Promise.all(readSourceFileTasks);
777
+ }
778
+
779
+ // Perform the same loop as above, but this time we can assume all files are in the cache
780
+ // and attempt to add source context to frames.
781
+ if (contextLines > 0 && _optionalChain$6([event, 'access', _6 => _6.exception, 'optionalAccess', _7 => _7.values])) {
782
+ for (const exception of event.exception.values) {
783
+ if (exception.stacktrace && exception.stacktrace.frames) {
784
+ await addSourceContextToFrames(exception.stacktrace.frames, contextLines);
785
+ }
786
+ }
787
+ }
788
+
789
+ return event;
790
+ }
791
+
792
+ /** Adds context lines to frames */
793
+ function addSourceContextToFrames(frames, contextLines) {
794
+ for (const frame of frames) {
795
+ // Only add context if we have a filename and it hasn't already been added
796
+ if (frame.filename && frame.context_line === undefined) {
797
+ const sourceFileLines = FILE_CONTENT_CACHE.get(frame.filename);
798
+
799
+ if (sourceFileLines) {
800
+ try {
801
+ addContextToFrame(sourceFileLines, frame, contextLines);
802
+ } catch (e) {
803
+ // anomaly, being defensive in case
804
+ // unlikely to ever happen in practice but can definitely happen in theory
805
+ }
806
+ }
807
+ }
808
+ }
809
+ }
810
+
811
+ /**
812
+ * Reads file contents and caches them in a global LRU cache.
813
+ * If reading fails, mark the file as null in the cache so we don't try again.
814
+ *
815
+ * @param filename filepath to read content from.
816
+ */
817
+ async function _readSourceFile(filename) {
818
+ const cachedFile = FILE_CONTENT_CACHE.get(filename);
819
+
820
+ // We have already attempted to read this file and failed, do not try again
821
+ if (cachedFile === null) {
822
+ return null;
823
+ }
824
+
825
+ // We have a cache hit, return it
826
+ if (cachedFile !== undefined) {
827
+ return cachedFile;
828
+ }
829
+
830
+ // Guard from throwing if readFile fails, this enables us to use Promise.all and
831
+ // not have it short circuiting if one of the promises rejects + since context lines are added
832
+ // on a best effort basis, we want to throw here anyways.
833
+
834
+ // If we made it to here, it means that our file is not cache nor marked as failed, so attempt to read it
835
+ let content = null;
836
+ try {
837
+ const rawFileContents = await readFileAsync(filename, 'utf-8');
838
+ content = rawFileContents.split('\n');
839
+ } catch (_) {
840
+ // if we fail, we will mark the file as null in the cache and short circuit next time we try to read it
841
+ }
842
+
843
+ FILE_CONTENT_CACHE.set(filename, content);
844
+ return content;
845
+ }
846
+
847
+ /**
848
+ * Creates a rate limiter that will call the disable callback when the rate limit is reached and the enable callback
849
+ * when a timeout has occurred.
850
+ * @param maxPerSecond Maximum number of calls per second
851
+ * @param enable Callback to enable capture
852
+ * @param disable Callback to disable capture
853
+ * @returns A function to call to increment the rate limiter count
854
+ */
855
+ function createRateLimiter(
856
+ maxPerSecond,
857
+ enable,
858
+ disable,
859
+ ) {
860
+ let count = 0;
861
+ let retrySeconds = 5;
862
+ let disabledTimeout = 0;
863
+
864
+ setInterval(() => {
865
+ if (disabledTimeout === 0) {
866
+ if (count > maxPerSecond) {
867
+ retrySeconds *= 2;
868
+ disable(retrySeconds);
869
+
870
+ // Cap at one day
871
+ if (retrySeconds > 86400) {
872
+ retrySeconds = 86400;
873
+ }
874
+ disabledTimeout = retrySeconds;
875
+ }
876
+ } else {
877
+ disabledTimeout -= 1;
878
+
879
+ if (disabledTimeout === 0) {
880
+ enable();
881
+ }
882
+ }
883
+
884
+ count = 0;
885
+ }, 1000).unref();
886
+
887
+ return () => {
888
+ count += 1;
889
+ };
890
+ }
891
+
892
+ // Add types for the exception event data
893
+
894
+ /** Could this be an anonymous function? */
895
+ function isAnonymous(name) {
896
+ return name !== undefined && (name.length === 0 || name === '?' || name === '<anonymous>');
897
+ }
898
+
899
+ /** Do the function names appear to match? */
900
+ function functionNamesMatch(a, b) {
901
+ return a === b || (isAnonymous(a) && isAnonymous(b));
902
+ }
903
+
904
+ /** Creates a unique hash from stack frames */
905
+ function hashFrames(frames) {
906
+ if (frames === undefined) {
907
+ return;
908
+ }
909
+
910
+ // Only hash the 10 most recent frames (ie. the last 10)
911
+ return frames.slice(-10).reduce((acc, frame) => `${acc},${frame.function},${frame.lineno},${frame.colno}`, '');
912
+ }
913
+
914
+ /**
915
+ * We use the stack parser to create a unique hash from the exception stack trace
916
+ * This is used to lookup vars when the exception passes through the event processor
917
+ */
918
+ function hashFromStack(stackParser, stack) {
919
+ if (stack === undefined) {
920
+ return undefined;
921
+ }
922
+
923
+ return hashFrames(stackParser(stack, 1));
924
+ }
925
+
926
+ function _optionalChain$5(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
927
+ /** Creates a container for callbacks to be called sequentially */
928
+ function createCallbackList(complete) {
929
+ // A collection of callbacks to be executed last to first
930
+ let callbacks = [];
931
+
932
+ let completedCalled = false;
933
+ function checkedComplete(result) {
934
+ callbacks = [];
935
+ if (completedCalled) {
936
+ return;
937
+ }
938
+ completedCalled = true;
939
+ complete(result);
940
+ }
941
+
942
+ // complete should be called last
943
+ callbacks.push(checkedComplete);
944
+
945
+ function add(fn) {
946
+ callbacks.push(fn);
947
+ }
948
+
949
+ function next(result) {
950
+ const popped = callbacks.pop() || checkedComplete;
951
+
952
+ try {
953
+ popped(result);
954
+ } catch (_) {
955
+ // If there is an error, we still want to call the complete callback
956
+ checkedComplete(result);
957
+ }
958
+ }
959
+
960
+ return { add, next };
961
+ }
962
+
963
+ /**
964
+ * Promise API is available as `Experimental` and in Node 19 only.
965
+ *
966
+ * Callback-based API is `Stable` since v14 and `Experimental` since v8.
967
+ * Because of that, we are creating our own `AsyncSession` class.
968
+ *
969
+ * https://nodejs.org/docs/latest-v19.x/api/inspector.html#promises-api
970
+ * https://nodejs.org/docs/latest-v14.x/api/inspector.html
971
+ */
972
+ class AsyncSession {
973
+
974
+ /** Throws if inspector API is not available */
975
+ constructor() {
976
+ this._session = new Session();
977
+ }
978
+
979
+ /** @inheritdoc */
980
+ configureAndConnect(onPause, captureAll) {
981
+ this._session.connect();
982
+
983
+ this._session.on('Debugger.paused', event => {
984
+ onPause(event, () => {
985
+ // After the pause work is complete, resume execution or the exception context memory is leaked
986
+ this._session.post('Debugger.resume');
987
+ });
988
+ });
989
+
990
+ this._session.post('Debugger.enable');
991
+ this._session.post('Debugger.setPauseOnExceptions', { state: captureAll ? 'all' : 'uncaught' });
992
+ }
993
+
994
+ setPauseOnExceptions(captureAll) {
995
+ this._session.post('Debugger.setPauseOnExceptions', { state: captureAll ? 'all' : 'uncaught' });
996
+ }
997
+
998
+ /** @inheritdoc */
999
+ getLocalVariables(objectId, complete) {
1000
+ this._getProperties(objectId, props => {
1001
+ const { add, next } = createCallbackList(complete);
1002
+
1003
+ for (const prop of props) {
1004
+ if (_optionalChain$5([prop, 'optionalAccess', _2 => _2.value, 'optionalAccess', _3 => _3.objectId]) && _optionalChain$5([prop, 'optionalAccess', _4 => _4.value, 'access', _5 => _5.className]) === 'Array') {
1005
+ const id = prop.value.objectId;
1006
+ add(vars => this._unrollArray(id, prop.name, vars, next));
1007
+ } else if (_optionalChain$5([prop, 'optionalAccess', _6 => _6.value, 'optionalAccess', _7 => _7.objectId]) && _optionalChain$5([prop, 'optionalAccess', _8 => _8.value, 'optionalAccess', _9 => _9.className]) === 'Object') {
1008
+ const id = prop.value.objectId;
1009
+ add(vars => this._unrollObject(id, prop.name, vars, next));
1010
+ } else if (_optionalChain$5([prop, 'optionalAccess', _10 => _10.value])) {
1011
+ add(vars => this._unrollOther(prop, vars, next));
1012
+ }
1013
+ }
1014
+
1015
+ next({});
1016
+ });
1017
+ }
1018
+
1019
+ /**
1020
+ * Gets all the PropertyDescriptors of an object
1021
+ */
1022
+ _getProperties(objectId, next) {
1023
+ this._session.post(
1024
+ 'Runtime.getProperties',
1025
+ {
1026
+ objectId,
1027
+ ownProperties: true,
1028
+ },
1029
+ (err, params) => {
1030
+ if (err) {
1031
+ next([]);
1032
+ } else {
1033
+ next(params.result);
1034
+ }
1035
+ },
1036
+ );
1037
+ }
1038
+
1039
+ /**
1040
+ * Unrolls an array property
1041
+ */
1042
+ _unrollArray(objectId, name, vars, next) {
1043
+ this._getProperties(objectId, props => {
1044
+ vars[name] = props
1045
+ .filter(v => v.name !== 'length' && !isNaN(parseInt(v.name, 10)))
1046
+ .sort((a, b) => parseInt(a.name, 10) - parseInt(b.name, 10))
1047
+ .map(v => _optionalChain$5([v, 'optionalAccess', _11 => _11.value, 'optionalAccess', _12 => _12.value]));
1048
+
1049
+ next(vars);
1050
+ });
1051
+ }
1052
+
1053
+ /**
1054
+ * Unrolls an object property
1055
+ */
1056
+ _unrollObject(objectId, name, vars, next) {
1057
+ this._getProperties(objectId, props => {
1058
+ vars[name] = props
1059
+ .map(v => [v.name, _optionalChain$5([v, 'optionalAccess', _13 => _13.value, 'optionalAccess', _14 => _14.value])])
1060
+ .reduce((obj, [key, val]) => {
1061
+ obj[key] = val;
1062
+ return obj;
1063
+ }, {} );
1064
+
1065
+ next(vars);
1066
+ });
1067
+ }
1068
+
1069
+ /**
1070
+ * Unrolls other properties
1071
+ */
1072
+ _unrollOther(prop, vars, next) {
1073
+ if (prop.value) {
1074
+ if ('value' in prop.value) {
1075
+ if (prop.value.value === undefined || prop.value.value === null) {
1076
+ vars[prop.name] = `<${prop.value.value}>`;
1077
+ } else {
1078
+ vars[prop.name] = prop.value.value;
1079
+ }
1080
+ } else if ('description' in prop.value && prop.value.type !== 'function') {
1081
+ vars[prop.name] = `<${prop.value.description}>`;
1082
+ } else if (prop.value.type === 'undefined') {
1083
+ vars[prop.name] = '<undefined>';
1084
+ }
1085
+ }
1086
+
1087
+ next(vars);
1088
+ }
1089
+ }
1090
+
1091
+ /**
1092
+ * When using Vercel pkg, the inspector module is not available.
1093
+ * https://github.com/getsentry/sentry-javascript/issues/6769
1094
+ */
1095
+ function tryNewAsyncSession() {
1096
+ try {
1097
+ return new AsyncSession();
1098
+ } catch (e) {
1099
+ return undefined;
1100
+ }
1101
+ }
1102
+
1103
+ const INTEGRATION_NAME$5 = 'LocalVariables';
1104
+
1105
+ /**
1106
+ * Adds local variables to exception frames
1107
+ */
1108
+ const _localVariablesSyncIntegration = ((
1109
+ options = {},
1110
+ session = tryNewAsyncSession(),
1111
+ ) => {
1112
+ const cachedFrames = new LRUMap(20);
1113
+ let rateLimiter;
1114
+ let shouldProcessEvent = false;
1115
+
1116
+ function handlePaused(
1117
+ stackParser,
1118
+ { params: { reason, data, callFrames } },
1119
+ complete,
1120
+ ) {
1121
+ if (reason !== 'exception' && reason !== 'promiseRejection') {
1122
+ complete();
1123
+ return;
1124
+ }
1125
+
1126
+ _optionalChain$5([rateLimiter, 'optionalCall', _15 => _15()]);
1127
+
1128
+ // data.description contains the original error.stack
1129
+ const exceptionHash = hashFromStack(stackParser, _optionalChain$5([data, 'optionalAccess', _16 => _16.description]));
1130
+
1131
+ if (exceptionHash == undefined) {
1132
+ complete();
1133
+ return;
1134
+ }
1135
+
1136
+ const { add, next } = createCallbackList(frames => {
1137
+ cachedFrames.set(exceptionHash, frames);
1138
+ complete();
1139
+ });
1140
+
1141
+ // Because we're queuing up and making all these calls synchronously, we can potentially overflow the stack
1142
+ // For this reason we only attempt to get local variables for the first 5 frames
1143
+ for (let i = 0; i < Math.min(callFrames.length, 5); i++) {
1144
+ const { scopeChain, functionName, this: obj } = callFrames[i];
1145
+
1146
+ const localScope = scopeChain.find(scope => scope.type === 'local');
1147
+
1148
+ // obj.className is undefined in ESM modules
1149
+ const fn = obj.className === 'global' || !obj.className ? functionName : `${obj.className}.${functionName}`;
1150
+
1151
+ if (_optionalChain$5([localScope, 'optionalAccess', _17 => _17.object, 'access', _18 => _18.objectId]) === undefined) {
1152
+ add(frames => {
1153
+ frames[i] = { function: fn };
1154
+ next(frames);
1155
+ });
1156
+ } else {
1157
+ const id = localScope.object.objectId;
1158
+ add(frames =>
1159
+ _optionalChain$5([session, 'optionalAccess', _19 => _19.getLocalVariables, 'call', _20 => _20(id, vars => {
1160
+ frames[i] = { function: fn, vars };
1161
+ next(frames);
1162
+ })]),
1163
+ );
1164
+ }
1165
+ }
1166
+
1167
+ next([]);
1168
+ }
1169
+
1170
+ function addLocalVariablesToException(exception) {
1171
+ const hash = hashFrames(_optionalChain$5([exception, 'optionalAccess', _21 => _21.stacktrace, 'optionalAccess', _22 => _22.frames]));
1172
+
1173
+ if (hash === undefined) {
1174
+ return;
1175
+ }
1176
+
1177
+ // Check if we have local variables for an exception that matches the hash
1178
+ // remove is identical to get but also removes the entry from the cache
1179
+ const cachedFrame = cachedFrames.remove(hash);
1180
+
1181
+ if (cachedFrame === undefined) {
1182
+ return;
1183
+ }
1184
+
1185
+ const frameCount = _optionalChain$5([exception, 'access', _23 => _23.stacktrace, 'optionalAccess', _24 => _24.frames, 'optionalAccess', _25 => _25.length]) || 0;
1186
+
1187
+ for (let i = 0; i < frameCount; i++) {
1188
+ // Sentry frames are in reverse order
1189
+ const frameIndex = frameCount - i - 1;
1190
+
1191
+ // Drop out if we run out of frames to match up
1192
+ if (!_optionalChain$5([exception, 'optionalAccess', _26 => _26.stacktrace, 'optionalAccess', _27 => _27.frames, 'optionalAccess', _28 => _28[frameIndex]]) || !cachedFrame[i]) {
1193
+ break;
1194
+ }
1195
+
1196
+ if (
1197
+ // We need to have vars to add
1198
+ cachedFrame[i].vars === undefined ||
1199
+ // We're not interested in frames that are not in_app because the vars are not relevant
1200
+ exception.stacktrace.frames[frameIndex].in_app === false ||
1201
+ // The function names need to match
1202
+ !functionNamesMatch(exception.stacktrace.frames[frameIndex].function, cachedFrame[i].function)
1203
+ ) {
1204
+ continue;
1205
+ }
1206
+
1207
+ exception.stacktrace.frames[frameIndex].vars = cachedFrame[i].vars;
1208
+ }
1209
+ }
1210
+
1211
+ function addLocalVariablesToEvent(event) {
1212
+ for (const exception of _optionalChain$5([event, 'optionalAccess', _29 => _29.exception, 'optionalAccess', _30 => _30.values]) || []) {
1213
+ addLocalVariablesToException(exception);
1214
+ }
1215
+
1216
+ return event;
1217
+ }
1218
+
1219
+ return {
1220
+ name: INTEGRATION_NAME$5,
1221
+ setupOnce() {
1222
+ const client = getClient$2();
1223
+ const clientOptions = _optionalChain$5([client, 'optionalAccess', _31 => _31.getOptions, 'call', _32 => _32()]);
1224
+
1225
+ if (session && _optionalChain$5([clientOptions, 'optionalAccess', _33 => _33.includeLocalVariables])) {
1226
+ // Only setup this integration if the Node version is >= v18
1227
+ // https://github.com/getsentry/sentry-javascript/issues/7697
1228
+ const unsupportedNodeVersion = NODE_MAJOR < 18;
1229
+
1230
+ if (unsupportedNodeVersion) {
1231
+ logger.log('The `LocalVariables` integration is only supported on Node >= v18.');
1232
+ return;
1233
+ }
1234
+
1235
+ const captureAll = options.captureAllExceptions !== false;
1236
+
1237
+ session.configureAndConnect(
1238
+ (ev, complete) =>
1239
+ handlePaused(clientOptions.stackParser, ev , complete),
1240
+ captureAll,
1241
+ );
1242
+
1243
+ if (captureAll) {
1244
+ const max = options.maxExceptionsPerSecond || 50;
1245
+
1246
+ rateLimiter = createRateLimiter(
1247
+ max,
1248
+ () => {
1249
+ logger.log('Local variables rate-limit lifted.');
1250
+ _optionalChain$5([session, 'optionalAccess', _34 => _34.setPauseOnExceptions, 'call', _35 => _35(true)]);
1251
+ },
1252
+ seconds => {
1253
+ logger.log(
1254
+ `Local variables rate-limit exceeded. Disabling capturing of caught exceptions for ${seconds} seconds.`,
1255
+ );
1256
+ _optionalChain$5([session, 'optionalAccess', _36 => _36.setPauseOnExceptions, 'call', _37 => _37(false)]);
1257
+ },
1258
+ );
1259
+ }
1260
+
1261
+ shouldProcessEvent = true;
1262
+ }
1263
+ },
1264
+ processEvent(event) {
1265
+ if (shouldProcessEvent) {
1266
+ return addLocalVariablesToEvent(event);
1267
+ }
1268
+
1269
+ return event;
1270
+ },
1271
+ // These are entirely for testing
1272
+ _getCachedFramesCount() {
1273
+ return cachedFrames.size;
1274
+ },
1275
+ _getFirstCachedFrame() {
1276
+ return cachedFrames.values()[0];
1277
+ },
1278
+ };
1279
+ }) ;
1280
+
1281
+ const localVariablesSyncIntegration = defineIntegration(_localVariablesSyncIntegration);
1282
+
1283
+ /**
1284
+ * Adds local variables to exception frames.
1285
+ * @deprecated Use `localVariablesSyncIntegration()` instead.
1286
+ */
1287
+ // eslint-disable-next-line deprecation/deprecation
1288
+ convertIntegrationFnToClass(
1289
+ INTEGRATION_NAME$5,
1290
+ localVariablesSyncIntegration,
1291
+ )
1292
+
1293
+ ;
1294
+
1295
+ // eslint-disable-next-line deprecation/deprecation
1296
+
1297
+ const localVariablesIntegration = localVariablesSyncIntegration;
1298
+
1299
+ let moduleCache;
1300
+
1301
+ const INTEGRATION_NAME$4 = 'Modules';
1302
+
1303
+ const _modulesIntegration = (() => {
1304
+ return {
1305
+ name: INTEGRATION_NAME$4,
1306
+ processEvent(event) {
1307
+ event.modules = {
1308
+ ...event.modules,
1309
+ ..._getModules(),
1310
+ };
1311
+
1312
+ return event;
1313
+ },
1314
+ };
1315
+ }) ;
1316
+
1317
+ /**
1318
+ * Add node modules / packages to the event.
1319
+ */
1320
+ const modulesIntegration = defineIntegration(_modulesIntegration);
1321
+
1322
+ /** Extract information about paths */
1323
+ function getPaths() {
1324
+ try {
1325
+ return require.cache ? Object.keys(require.cache ) : [];
1326
+ } catch (e) {
1327
+ return [];
1328
+ }
1329
+ }
1330
+
1331
+ /** Extract information about package.json modules */
1332
+ function collectModules()
1333
+
1334
+ {
1335
+ const mainPaths = (require.main && require.main.paths) || [];
1336
+ const paths = getPaths();
1337
+ const infos
1338
+
1339
+ = {};
1340
+ const seen
1341
+
1342
+ = {};
1343
+
1344
+ paths.forEach(path => {
1345
+ let dir = path;
1346
+
1347
+ /** Traverse directories upward in the search of package.json file */
1348
+ const updir = () => {
1349
+ const orig = dir;
1350
+ dir = dirname(orig);
1351
+
1352
+ if (!dir || orig === dir || seen[orig]) {
1353
+ return undefined;
1354
+ }
1355
+ if (mainPaths.indexOf(dir) < 0) {
1356
+ return updir();
1357
+ }
1358
+
1359
+ const pkgfile = join(orig, 'package.json');
1360
+ seen[orig] = true;
1361
+
1362
+ if (!existsSync(pkgfile)) {
1363
+ return updir();
1364
+ }
1365
+
1366
+ try {
1367
+ const info = JSON.parse(readFileSync(pkgfile, 'utf8'))
1368
+
1369
+ ;
1370
+ infos[info.name] = info.version;
1371
+ } catch (_oO) {
1372
+ // no-empty
1373
+ }
1374
+ };
1375
+
1376
+ updir();
1377
+ });
1378
+
1379
+ return infos;
1380
+ }
1381
+
1382
+ /** Fetches the list of modules and the versions loaded by the entry file for your node.js app. */
1383
+ function _getModules() {
1384
+ if (!moduleCache) {
1385
+ moduleCache = collectModules();
1386
+ }
1387
+ return moduleCache;
1388
+ }
1389
+
1390
+ /**
1391
+ * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.
1392
+ *
1393
+ * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.
1394
+ */
1395
+ const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__);
1396
+
1397
+ const DEFAULT_SHUTDOWN_TIMEOUT = 2000;
1398
+
1399
+ /**
1400
+ * @hidden
1401
+ */
1402
+ function logAndExitProcess(error) {
1403
+ consoleSandbox(() => {
1404
+ // eslint-disable-next-line no-console
1405
+ console.error(error);
1406
+ });
1407
+
1408
+ const client = getClient$2();
1409
+
1410
+ if (client === undefined) {
1411
+ DEBUG_BUILD && logger.warn('No NodeClient was defined, we are exiting the process now.');
1412
+ global.process.exit(1);
1413
+ return;
1414
+ }
1415
+
1416
+ const options = client.getOptions();
1417
+ const timeout =
1418
+ (options && options.shutdownTimeout && options.shutdownTimeout > 0 && options.shutdownTimeout) ||
1419
+ DEFAULT_SHUTDOWN_TIMEOUT;
1420
+ client.close(timeout).then(
1421
+ (result) => {
1422
+ if (!result) {
1423
+ DEBUG_BUILD && logger.warn('We reached the timeout for emptying the request buffer, still exiting now!');
1424
+ }
1425
+ global.process.exit(1);
1426
+ },
1427
+ error => {
1428
+ DEBUG_BUILD && logger.error(error);
1429
+ },
1430
+ );
1431
+ }
1432
+
1433
+ const INTEGRATION_NAME$3 = 'OnUncaughtException';
1434
+
1435
+ const _onUncaughtExceptionIntegration = ((options = {}) => {
1436
+ const _options = {
1437
+ exitEvenIfOtherHandlersAreRegistered: true,
1438
+ ...options,
1439
+ };
1440
+
1441
+ return {
1442
+ name: INTEGRATION_NAME$3,
1443
+ setup(client) {
1444
+ global.process.on('uncaughtException', makeErrorHandler(client, _options));
1445
+ },
1446
+ };
1447
+ }) ;
1448
+
1449
+ /**
1450
+ * Add a global exception handler.
1451
+ */
1452
+ const onUncaughtExceptionIntegration = defineIntegration(_onUncaughtExceptionIntegration);
1453
+
1454
+ /** Exported only for tests */
1455
+ function makeErrorHandler(client, options) {
1456
+ const timeout = 2000;
1457
+ let caughtFirstError = false;
1458
+ let caughtSecondError = false;
1459
+ let calledFatalError = false;
1460
+ let firstError;
1461
+
1462
+ const clientOptions = client.getOptions();
1463
+
1464
+ return Object.assign(
1465
+ (error) => {
1466
+ let onFatalError = logAndExitProcess;
1467
+
1468
+ if (options.onFatalError) {
1469
+ onFatalError = options.onFatalError;
1470
+ } else if (clientOptions.onFatalError) {
1471
+ onFatalError = clientOptions.onFatalError ;
1472
+ }
1473
+
1474
+ // Attaching a listener to `uncaughtException` will prevent the node process from exiting. We generally do not
1475
+ // want to alter this behaviour so we check for other listeners that users may have attached themselves and adjust
1476
+ // exit behaviour of the SDK accordingly:
1477
+ // - If other listeners are attached, do not exit.
1478
+ // - If the only listener attached is ours, exit.
1479
+ const userProvidedListenersCount = (global.process.listeners('uncaughtException') ).filter(
1480
+ listener => {
1481
+ // There are 3 listeners we ignore:
1482
+ return (
1483
+ // as soon as we're using domains this listener is attached by node itself
1484
+ listener.name !== 'domainUncaughtExceptionClear' &&
1485
+ // the handler we register for tracing
1486
+ listener.tag !== 'sentry_tracingErrorCallback' &&
1487
+ // the handler we register in this integration
1488
+ (listener )._errorHandler !== true
1489
+ );
1490
+ },
1491
+ ).length;
1492
+
1493
+ const processWouldExit = userProvidedListenersCount === 0;
1494
+ const shouldApplyFatalHandlingLogic = options.exitEvenIfOtherHandlersAreRegistered || processWouldExit;
1495
+
1496
+ if (!caughtFirstError) {
1497
+ // this is the first uncaught error and the ultimate reason for shutting down
1498
+ // we want to do absolutely everything possible to ensure it gets captured
1499
+ // also we want to make sure we don't go recursion crazy if more errors happen after this one
1500
+ firstError = error;
1501
+ caughtFirstError = true;
1502
+
1503
+ if (getClient$2() === client) {
1504
+ captureException(error, {
1505
+ originalException: error,
1506
+ captureContext: {
1507
+ level: 'fatal',
1508
+ },
1509
+ mechanism: {
1510
+ handled: false,
1511
+ type: 'onuncaughtexception',
1512
+ },
1513
+ });
1514
+ }
1515
+
1516
+ if (!calledFatalError && shouldApplyFatalHandlingLogic) {
1517
+ calledFatalError = true;
1518
+ onFatalError(error);
1519
+ }
1520
+ } else {
1521
+ if (shouldApplyFatalHandlingLogic) {
1522
+ if (calledFatalError) {
1523
+ // we hit an error *after* calling onFatalError - pretty boned at this point, just shut it down
1524
+ DEBUG_BUILD &&
1525
+ logger.warn(
1526
+ 'uncaught exception after calling fatal error shutdown callback - this is bad! forcing shutdown',
1527
+ );
1528
+ logAndExitProcess(error);
1529
+ } else if (!caughtSecondError) {
1530
+ // two cases for how we can hit this branch:
1531
+ // - capturing of first error blew up and we just caught the exception from that
1532
+ // - quit trying to capture, proceed with shutdown
1533
+ // - a second independent error happened while waiting for first error to capture
1534
+ // - want to avoid causing premature shutdown before first error capture finishes
1535
+ // it's hard to immediately tell case 1 from case 2 without doing some fancy/questionable domain stuff
1536
+ // so let's instead just delay a bit before we proceed with our action here
1537
+ // in case 1, we just wait a bit unnecessarily but ultimately do the same thing
1538
+ // in case 2, the delay hopefully made us wait long enough for the capture to finish
1539
+ // two potential nonideal outcomes:
1540
+ // nonideal case 1: capturing fails fast, we sit around for a few seconds unnecessarily before proceeding correctly by calling onFatalError
1541
+ // nonideal case 2: case 2 happens, 1st error is captured but slowly, timeout completes before capture and we treat second error as the sendErr of (nonexistent) failure from trying to capture first error
1542
+ // note that after hitting this branch, we might catch more errors where (caughtSecondError && !calledFatalError)
1543
+ // we ignore them - they don't matter to us, we're just waiting for the second error timeout to finish
1544
+ caughtSecondError = true;
1545
+ setTimeout(() => {
1546
+ if (!calledFatalError) {
1547
+ // it was probably case 1, let's treat err as the sendErr and call onFatalError
1548
+ calledFatalError = true;
1549
+ onFatalError(firstError, error);
1550
+ }
1551
+ }, timeout); // capturing could take at least sendTimeout to fail, plus an arbitrary second for how long it takes to collect surrounding source etc
1552
+ }
1553
+ }
1554
+ }
1555
+ },
1556
+ { _errorHandler: true },
1557
+ );
1558
+ }
1559
+
1560
+ const INTEGRATION_NAME$2 = 'OnUnhandledRejection';
1561
+
1562
+ const _onUnhandledRejectionIntegration = ((options = {}) => {
1563
+ const mode = options.mode || 'warn';
1564
+
1565
+ return {
1566
+ name: INTEGRATION_NAME$2,
1567
+ setup(client) {
1568
+ global.process.on('unhandledRejection', makeUnhandledPromiseHandler(client, { mode }));
1569
+ },
1570
+ };
1571
+ }) ;
1572
+
1573
+ /**
1574
+ * Add a global promise rejection handler.
1575
+ */
1576
+ const onUnhandledRejectionIntegration = defineIntegration(_onUnhandledRejectionIntegration);
1577
+
1578
+ /**
1579
+ * Send an exception with reason
1580
+ * @param reason string
1581
+ * @param promise promise
1582
+ *
1583
+ * Exported only for tests.
1584
+ */
1585
+ function makeUnhandledPromiseHandler(
1586
+ client,
1587
+ options,
1588
+ ) {
1589
+ return function sendUnhandledPromise(reason, promise) {
1590
+ if (getClient$2() !== client) {
1591
+ return;
1592
+ }
1593
+
1594
+ captureException(reason, {
1595
+ originalException: promise,
1596
+ captureContext: {
1597
+ extra: { unhandledPromiseRejection: true },
1598
+ },
1599
+ mechanism: {
1600
+ handled: false,
1601
+ type: 'onunhandledrejection',
1602
+ },
1603
+ });
1604
+
1605
+ handleRejection(reason, options);
1606
+ };
1607
+ }
1608
+
1609
+ /**
1610
+ * Handler for `mode` option
1611
+
1612
+ */
1613
+ function handleRejection(
1614
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1615
+ reason,
1616
+ options,
1617
+ ) {
1618
+ // https://github.com/nodejs/node/blob/7cf6f9e964aa00772965391c23acda6d71972a9a/lib/internal/process/promises.js#L234-L240
1619
+ const rejectionWarning =
1620
+ 'This error originated either by ' +
1621
+ 'throwing inside of an async function without a catch block, ' +
1622
+ 'or by rejecting a promise which was not handled with .catch().' +
1623
+ ' The promise rejected with the reason:';
1624
+
1625
+ /* eslint-disable no-console */
1626
+ if (options.mode === 'warn') {
1627
+ consoleSandbox(() => {
1628
+ console.warn(rejectionWarning);
1629
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1630
+ console.error(reason && reason.stack ? reason.stack : reason);
1631
+ });
1632
+ } else if (options.mode === 'strict') {
1633
+ consoleSandbox(() => {
1634
+ console.warn(rejectionWarning);
1635
+ });
1636
+ logAndExitProcess(reason);
1637
+ }
1638
+ /* eslint-enable no-console */
1639
+ }
1640
+
1641
+ // This string is a placeholder that gets overwritten with the worker code.
1642
+ const base64WorkerScript = 'aW1wb3J0IHsgU2Vzc2lvbiB9IGZyb20gJ2luc3BlY3Rvcic7CmltcG9ydCB7IHdvcmtlckRhdGEsIHBhcmVudFBvcnQgfSBmcm9tICd3b3JrZXJfdGhyZWFkcyc7CmltcG9ydCB7IHBvc2l4LCBzZXAgfSBmcm9tICdwYXRoJzsKaW1wb3J0ICogYXMgaHR0cCQxIGZyb20gJ25vZGU6aHR0cCc7CmltcG9ydCAqIGFzIGh0dHBzIGZyb20gJ25vZGU6aHR0cHMnOwppbXBvcnQgeyBSZWFkYWJsZSB9IGZyb20gJ3N0cmVhbSc7CmltcG9ydCB7IGNyZWF0ZUd6aXAgfSBmcm9tICd6bGliJzsKaW1wb3J0ICogYXMgbmV0IGZyb20gJ25ldCc7CmltcG9ydCAqIGFzIHRscyBmcm9tICd0bHMnOwppbXBvcnQgKiBhcyBodHRwIGZyb20gJ2h0dHAnOwoKLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC91bmJvdW5kLW1ldGhvZApjb25zdCBvYmplY3RUb1N0cmluZyA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmc7CgovKioKICogQ2hlY2tzIHdoZXRoZXIgZ2l2ZW4gdmFsdWUncyB0eXBlIGlzIG9uZSBvZiBhIGZldyBFcnJvciBvciBFcnJvci1saWtlCiAqIHtAbGluayBpc0Vycm9yfS4KICoKICogQHBhcmFtIHdhdCBBIHZhbHVlIHRvIGJlIGNoZWNrZWQuCiAqIEByZXR1cm5zIEEgYm9vbGVhbiByZXByZXNlbnRpbmcgdGhlIHJlc3VsdC4KICovCmZ1bmN0aW9uIGlzRXJyb3Iod2F0KSB7CiAgc3dpdGNoIChvYmplY3RUb1N0cmluZy5jYWxsKHdhdCkpIHsKICAgIGNhc2UgJ1tvYmplY3QgRXJyb3JdJzoKICAgIGNhc2UgJ1tvYmplY3QgRXhjZXB0aW9uXSc6CiAgICBjYXNlICdbb2JqZWN0IERPTUV4Y2VwdGlvbl0nOgogICAgICByZXR1cm4gdHJ1ZTsKICAgIGRlZmF1bHQ6CiAgICAgIHJldHVybiBpc0luc3RhbmNlT2Yod2F0LCBFcnJvcik7CiAgfQp9Ci8qKgogKiBDaGVja3Mgd2hldGhlciBnaXZlbiB2YWx1ZSBpcyBhbiBpbnN0YW5jZSBvZiB0aGUgZ2l2ZW4gYnVpbHQtaW4gY2xhc3MuCiAqCiAqIEBwYXJhbSB3YXQgVGhlIHZhbHVlIHRvIGJlIGNoZWNrZWQKICogQHBhcmFtIGNsYXNzTmFtZQogKiBAcmV0dXJucyBBIGJvb2xlYW4gcmVwcmVzZW50aW5nIHRoZSByZXN1bHQuCiAqLwpmdW5jdGlvbiBpc0J1aWx0aW4od2F0LCBjbGFzc05hbWUpIHsKICByZXR1cm4gb2JqZWN0VG9TdHJpbmcuY2FsbCh3YXQpID09PSBgW29iamVjdCAke2NsYXNzTmFtZX1dYDsKfQoKLyoqCiAqIENoZWNrcyB3aGV0aGVyIGdpdmVuIHZhbHVlJ3MgdHlwZSBpcyBhIHN0cmluZwogKiB7QGxpbmsgaXNTdHJpbmd9LgogKgogKiBAcGFyYW0gd2F0IEEgdmFsdWUgdG8gYmUgY2hlY2tlZC4KICogQHJldHVybnMgQSBib29sZWFuIHJlcHJlc2VudGluZyB0aGUgcmVzdWx0LgogKi8KZnVuY3Rpb24gaXNTdHJpbmcod2F0KSB7CiAgcmV0dXJuIGlzQnVpbHRpbih3YXQsICdTdHJpbmcnKTsKfQoKLyoqCiAqIENoZWNrcyB3aGV0aGVyIGdpdmVuIHZhbHVlJ3MgdHlwZSBpcyBhbiBvYmplY3QgbGl0ZXJhbCwgb3IgYSBjbGFzcyBpbnN0YW5jZS4KICoge0BsaW5rIGlzUGxhaW5PYmplY3R9LgogKgogKiBAcGFyYW0gd2F0IEEgdmFsdWUgdG8gYmUgY2hlY2tlZC4KICogQHJldHVybnMgQSBib29sZWFuIHJlcHJlc2VudGluZyB0aGUgcmVzdWx0LgogKi8KZnVuY3Rpb24gaXNQbGFpbk9iamVjdCh3YXQpIHsKICByZXR1cm4gaXNCdWlsdGluKHdhdCwgJ09iamVjdCcpOwp9CgovKioKICogQ2hlY2tzIHdoZXRoZXIgZ2l2ZW4gdmFsdWUncyB0eXBlIGlzIGFuIEV2ZW50IGluc3RhbmNlCiAqIHtAbGluayBpc0V2ZW50fS4KICoKICogQHBhcmFtIHdhdCBBIHZhbHVlIHRvIGJlIGNoZWNrZWQuCiAqIEByZXR1cm5zIEEgYm9vbGVhbiByZXByZXNlbnRpbmcgdGhlIHJlc3VsdC4KICovCmZ1bmN0aW9uIGlzRXZlbnQod2F0KSB7CiAgcmV0dXJuIHR5cGVvZiBFdmVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgaXNJbnN0YW5jZU9mKHdhdCwgRXZlbnQpOwp9CgovKioKICogQ2hlY2tzIHdoZXRoZXIgZ2l2ZW4gdmFsdWUncyB0eXBlIGlzIGFuIEVsZW1lbnQgaW5zdGFuY2UKICoge0BsaW5rIGlzRWxlbWVudH0uCiAqCiAqIEBwYXJhbSB3YXQgQSB2YWx1ZSB0byBiZSBjaGVja2VkLgogKiBAcmV0dXJucyBBIGJvb2xlYW4gcmVwcmVzZW50aW5nIHRoZSByZXN1bHQuCiAqLwpmdW5jdGlvbiBpc0VsZW1lbnQod2F0KSB7CiAgcmV0dXJuIHR5cGVvZiBFbGVtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpc0luc3RhbmNlT2Yod2F0LCBFbGVtZW50KTsKfQoKLyoqCiAqIENoZWNrcyB3aGV0aGVyIGdpdmVuIHZhbHVlIGhhcyBhIHRoZW4gZnVuY3Rpb24uCiAqIEBwYXJhbSB3YXQgQSB2YWx1ZSB0byBiZSBjaGVja2VkLgogKi8KZnVuY3Rpb24gaXNUaGVuYWJsZSh3YXQpIHsKICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1tZW1iZXItYWNjZXNzCiAgcmV0dXJuIEJvb2xlYW4od2F0ICYmIHdhdC50aGVuICYmIHR5cGVvZiB3YXQudGhlbiA9PT0gJ2Z1bmN0aW9uJyk7Cn0KCi8qKgogKiBDaGVja3Mgd2hldGhlciBnaXZlbiB2YWx1ZSdzIHR5cGUgaXMgYSBTeW50aGV0aWNFdmVudAogKiB7QGxpbmsgaXNTeW50aGV0aWNFdmVudH0uCiAqCiAqIEBwYXJhbSB3YXQgQSB2YWx1ZSB0byBiZSBjaGVja2VkLgogKiBAcmV0dXJucyBBIGJvb2xlYW4gcmVwcmVzZW50aW5nIHRoZSByZXN1bHQuCiAqLwpmdW5jdGlvbiBpc1N5bnRoZXRpY0V2ZW50KHdhdCkgewogIHJldHVybiBpc1BsYWluT2JqZWN0KHdhdCkgJiYgJ25hdGl2ZUV2ZW50JyBpbiB3YXQgJiYgJ3ByZXZlbnREZWZhdWx0JyBpbiB3YXQgJiYgJ3N0b3BQcm9wYWdhdGlvbicgaW4gd2F0Owp9CgovKioKICogQ2hlY2tzIHdoZXRoZXIgZ2l2ZW4gdmFsdWUgaXMgTmFOCiAqIHtAbGluayBpc05hTn0uCiAqCiAqIEBwYXJhbSB3YXQgQSB2YWx1ZSB0byBiZSBjaGVja2VkLgogKiBAcmV0dXJucyBBIGJvb2xlYW4gcmVwcmVzZW50aW5nIHRoZSByZXN1bHQuCiAqLwpmdW5jdGlvbiBpc05hTiQxKHdhdCkgewogIHJldHVybiB0eXBlb2Ygd2F0ID09PSAnbnVtYmVyJyAmJiB3YXQgIT09IHdhdDsKfQoKLyoqCiAqIENoZWNrcyB3aGV0aGVyIGdpdmVuIHZhbHVlJ3MgdHlwZSBpcyBhbiBpbnN0YW5jZSBvZiBwcm92aWRlZCBjb25zdHJ1Y3Rvci4KICoge0BsaW5rIGlzSW5zdGFuY2VPZn0uCiAqCiAqIEBwYXJhbSB3YXQgQSB2YWx1ZSB0byBiZSBjaGVja2VkLgogKiBAcGFyYW0gYmFzZSBBIGNvbnN0cnVjdG9yIHRvIGJlIHVzZWQgaW4gYSBjaGVjay4KICogQHJldHVybnMgQSBib29sZWFuIHJlcHJlc2VudGluZyB0aGUgcmVzdWx0LgogKi8KZnVuY3Rpb24gaXNJbnN0YW5jZU9mKHdhdCwgYmFzZSkgewogIHRyeSB7CiAgICByZXR1cm4gd2F0IGluc3RhbmNlb2YgYmFzZTsKICB9IGNhdGNoIChfZSkgewogICAgcmV0dXJuIGZhbHNlOwogIH0KfQoKLyoqCiAqIENoZWNrcyB3aGV0aGVyIGdpdmVuIHZhbHVlJ3MgdHlwZSBpcyBhIFZ1ZSBWaWV3TW9kZWwuCiAqCiAqIEBwYXJhbSB3YXQgQSB2YWx1ZSB0byBiZSBjaGVja2VkLgogKiBAcmV0dXJucyBBIGJvb2xlYW4gcmVwcmVzZW50aW5nIHRoZSByZXN1bHQuCiAqLwpmdW5jdGlvbiBpc1Z1ZVZpZXdNb2RlbCh3YXQpIHsKICAvLyBOb3QgdXNpbmcgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZyBiZWNhdXNlIGluIFZ1ZSAzIGl0IHdvdWxkIHJlYWQgdGhlIGluc3RhbmNlJ3MgU3ltYm9sKFN5bWJvbC50b1N0cmluZ1RhZykgcHJvcGVydHkuCiAgcmV0dXJuICEhKHR5cGVvZiB3YXQgPT09ICdvYmplY3QnICYmIHdhdCAhPT0gbnVsbCAmJiAoKHdhdCApLl9faXNWdWUgfHwgKHdhdCApLl9pc1Z1ZSkpOwp9CgovKiogSW50ZXJuYWwgZ2xvYmFsIHdpdGggY29tbW9uIHByb3BlcnRpZXMgYW5kIFNlbnRyeSBleHRlbnNpb25zICAqLwoKLy8gVGhlIGNvZGUgYmVsb3cgZm9yICdpc0dsb2JhbE9iaicgYW5kICdHTE9CQUxfT0JKJyB3YXMgY29waWVkIGZyb20gY29yZS1qcyBiZWZvcmUgbW9kaWZpY2F0aW9uCi8vIGh0dHBzOi8vZ2l0aHViLmNvbS96bG9pcm9jay9jb3JlLWpzL2Jsb2IvMWI5NDRkZjU1MjgyY2RjOTljOTBkYjVmNDllYjBiNmVkYTJjYzBhMy9wYWNrYWdlcy9jb3JlLWpzL2ludGVybmFscy9nbG9iYWwuanMKLy8gY29yZS1qcyBoYXMgdGhlIGZvbGxvd2luZyBsaWNlbmNlOgovLwovLyBDb3B5cmlnaHQgKGMpIDIwMTQtMjAyMiBEZW5pcyBQdXNoa2FyZXYKLy8KLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weQovLyBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbAovLyBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzCi8vIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwKLy8gY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzCi8vIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6Ci8vCi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluCi8vIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLgovLwovLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgovLyBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKLy8gRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCi8vIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKLy8gTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwKLy8gT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTgovLyBUSEUgU09GVFdBUkUuCgovKiogUmV0dXJucyAnb2JqJyBpZiBpdCdzIHRoZSBnbG9iYWwgb2JqZWN0LCBvdGhlcndpc2UgcmV0dXJucyB1bmRlZmluZWQgKi8KZnVuY3Rpb24gaXNHbG9iYWxPYmoob2JqKSB7CiAgcmV0dXJuIG9iaiAmJiBvYmouTWF0aCA9PSBNYXRoID8gb2JqIDogdW5kZWZpbmVkOwp9CgovKiogR2V0J3MgdGhlIGdsb2JhbCBvYmplY3QgZm9yIHRoZSBjdXJyZW50IEphdmFTY3JpcHQgcnVudGltZSAqLwpjb25zdCBHTE9CQUxfT0JKID0KICAodHlwZW9mIGdsb2JhbFRoaXMgPT0gJ29iamVjdCcgJiYgaXNHbG9iYWxPYmooZ2xvYmFsVGhpcykpIHx8CiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXJlc3RyaWN0ZWQtZ2xvYmFscwogICh0eXBlb2Ygd2luZG93ID09ICdvYmplY3QnICYmIGlzR2xvYmFsT2JqKHdpbmRvdykpIHx8CiAgKHR5cGVvZiBzZWxmID09ICdvYmplY3QnICYmIGlzR2xvYmFsT2JqKHNlbGYpKSB8fAogICh0eXBlb2YgZ2xvYmFsID09ICdvYmplY3QnICYmIGlzR2xvYmFsT2JqKGdsb2JhbCkpIHx8CiAgKGZ1bmN0aW9uICgpIHsKICAgIHJldHVybiB0aGlzOwogIH0pKCkgfHwKICB7fTsKCi8qKgogKiBAZGVwcmVjYXRlZCBVc2UgR0xPQkFMX09CSiBpbnN0ZWFkIG9yIFdJTkRPVyBmcm9tIEBzZW50cnkvYnJvd3Nlci4gVGhpcyB3aWxsIGJlIHJlbW92ZWQgaW4gdjgKICovCmZ1bmN0aW9uIGdldEdsb2JhbE9iamVjdCgpIHsKICByZXR1cm4gR0xPQkFMX09CSiA7Cn0KCi8qKgogKiBSZXR1cm5zIGEgZ2xvYmFsIHNpbmdsZXRvbiBjb250YWluZWQgaW4gdGhlIGdsb2JhbCBgX19TRU5UUllfX2Agb2JqZWN0LgogKgogKiBJZiB0aGUgc2luZ2xldG9uIGRvZXNuJ3QgYWxyZWFkeSBleGlzdCBpbiBgX19TRU5UUllfX2AsIGl0IHdpbGwgYmUgY3JlYXRlZCB1c2luZyB0aGUgZ2l2ZW4gZmFjdG9yeQogKiBmdW5jdGlvbiBhbmQgYWRkZWQgdG8gdGhlIGBfX1NFTlRSWV9fYCBvYmplY3QuCiAqCiAqIEBwYXJhbSBuYW1lIG5hbWUgb2YgdGhlIGdsb2JhbCBzaW5nbGV0b24gb24gX19TRU5UUllfXwogKiBAcGFyYW0gY3JlYXRvciBjcmVhdG9yIEZhY3RvcnkgZnVuY3Rpb24gdG8gY3JlYXRlIHRoZSBzaW5nbGV0b24gaWYgaXQgZG9lc24ndCBhbHJlYWR5IGV4aXN0IG9uIGBfX1NFTlRSWV9fYAogKiBAcGFyYW0gb2JqIChPcHRpb25hbCkgVGhlIGdsb2JhbCBvYmplY3Qgb24gd2hpY2ggdG8gbG9vayBmb3IgYF9fU0VOVFJZX19gLCBpZiBub3QgYEdMT0JBTF9PQkpgJ3MgcmV0dXJuIHZhbHVlCiAqIEByZXR1cm5zIHRoZSBzaW5nbGV0b24KICovCmZ1bmN0aW9uIGdldEdsb2JhbFNpbmdsZXRvbihuYW1lLCBjcmVhdG9yLCBvYmopIHsKICBjb25zdCBnYmwgPSAob2JqIHx8IEdMT0JBTF9PQkopIDsKICBjb25zdCBfX1NFTlRSWV9fID0gKGdibC5fX1NFTlRSWV9fID0gZ2JsLl9fU0VOVFJZX18gfHwge30pOwogIGNvbnN0IHNpbmdsZXRvbiA9IF9fU0VOVFJZX19bbmFtZV0gfHwgKF9fU0VOVFJZX19bbmFtZV0gPSBjcmVhdG9yKCkpOwogIHJldHVybiBzaW5nbGV0b247Cn0KCi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgpjb25zdCBXSU5ET1ckNSA9IGdldEdsb2JhbE9iamVjdCgpOwoKY29uc3QgREVGQVVMVF9NQVhfU1RSSU5HX0xFTkdUSCA9IDgwOwoKLyoqCiAqIEdpdmVuIGEgY2hpbGQgRE9NIGVsZW1lbnQsIHJldHVybnMgYSBxdWVyeS1zZWxlY3RvciBzdGF0ZW1lbnQgZGVzY3JpYmluZyB0aGF0CiAqIGFuZCBpdHMgYW5jZXN0b3JzCiAqIGUuZy4gW0hUTUxFbGVtZW50XSA9PiBib2R5ID4gZGl2ID4gaW5wdXQjZm9vLmJ0bltuYW1lPWJhel0KICogQHJldHVybnMgZ2VuZXJhdGVkIERPTSBwYXRoCiAqLwpmdW5jdGlvbiBodG1sVHJlZUFzU3RyaW5nKAogIGVsZW0sCiAgb3B0aW9ucyA9IHt9LAopIHsKICBpZiAoIWVsZW0pIHsKICAgIHJldHVybiAnPHVua25vd24+JzsKICB9CgogIC8vIHRyeS9jYXRjaCBib3RoOgogIC8vIC0gYWNjZXNzaW5nIGV2ZW50LnRhcmdldCAoc2VlIGdldHNlbnRyeS9yYXZlbi1qcyM4MzgsICM3NjgpCiAgLy8gLSBgaHRtbFRyZWVBc1N0cmluZ2AgYmVjYXVzZSBpdCdzIGNvbXBsZXgsIGFuZCBqdXN0IGFjY2Vzc2luZyB0aGUgRE9NIGluY29ycmVjdGx5CiAgLy8gLSBjYW4gdGhyb3cgYW4gZXhjZXB0aW9uIGluIHNvbWUgY2lyY3Vtc3RhbmNlcy4KICB0cnkgewogICAgbGV0IGN1cnJlbnRFbGVtID0gZWxlbSA7CiAgICBjb25zdCBNQVhfVFJBVkVSU0VfSEVJR0hUID0gNTsKICAgIGNvbnN0IG91dCA9IFtdOwogICAgbGV0IGhlaWdodCA9IDA7CiAgICBsZXQgbGVuID0gMDsKICAgIGNvbnN0IHNlcGFyYXRvciA9ICcgPiAnOwogICAgY29uc3Qgc2VwTGVuZ3RoID0gc2VwYXJhdG9yLmxlbmd0aDsKICAgIGxldCBuZXh0U3RyOwogICAgY29uc3Qga2V5QXR0cnMgPSBBcnJheS5pc0FycmF5KG9wdGlvbnMpID8gb3B0aW9ucyA6IG9wdGlvbnMua2V5QXR0cnM7CiAgICBjb25zdCBtYXhTdHJpbmdMZW5ndGggPSAoIUFycmF5LmlzQXJyYXkob3B0aW9ucykgJiYgb3B0aW9ucy5tYXhTdHJpbmdMZW5ndGgpIHx8IERFRkFVTFRfTUFYX1NUUklOR19MRU5HVEg7CgogICAgd2hpbGUgKGN1cnJlbnRFbGVtICYmIGhlaWdodCsrIDwgTUFYX1RSQVZFUlNFX0hFSUdIVCkgewogICAgICBuZXh0U3RyID0gX2h0bWxFbGVtZW50QXNTdHJpbmcoY3VycmVudEVsZW0sIGtleUF0dHJzKTsKICAgICAgLy8gYmFpbCBvdXQgaWYKICAgICAgLy8gLSBuZXh0U3RyIGlzIHRoZSAnaHRtbCcgZWxlbWVudAogICAgICAvLyAtIHRoZSBsZW5ndGggb2YgdGhlIHN0cmluZyB0aGF0IHdvdWxkIGJlIGNyZWF0ZWQgZXhjZWVkcyBtYXhTdHJpbmdMZW5ndGgKICAgICAgLy8gICAoaWdub3JlIHRoaXMgbGltaXQgaWYgd2UgYXJlIG9uIHRoZSBmaXJzdCBpdGVyYXRpb24pCiAgICAgIGlmIChuZXh0U3RyID09PSAnaHRtbCcgfHwgKGhlaWdodCA+IDEgJiYgbGVuICsgb3V0Lmxlbmd0aCAqIHNlcExlbmd0aCArIG5leHRTdHIubGVuZ3RoID49IG1heFN0cmluZ0xlbmd0aCkpIHsKICAgICAgICBicmVhazsKICAgICAgfQoKICAgICAgb3V0LnB1c2gobmV4dFN0cik7CgogICAgICBsZW4gKz0gbmV4dFN0ci5sZW5ndGg7CiAgICAgIGN1cnJlbnRFbGVtID0gY3VycmVudEVsZW0ucGFyZW50Tm9kZTsKICAgIH0KCiAgICByZXR1cm4gb3V0LnJldmVyc2UoKS5qb2luKHNlcGFyYXRvcik7CiAgfSBjYXRjaCAoX29PKSB7CiAgICByZXR1cm4gJzx1bmtub3duPic7CiAgfQp9CgovKioKICogUmV0dXJucyBhIHNpbXBsZSwgcXVlcnktc2VsZWN0b3IgcmVwcmVzZW50YXRpb24gb2YgYSBET00gZWxlbWVudAogKiBlLmcuIFtIVE1MRWxlbWVudF0gPT4gaW5wdXQjZm9vLmJ0bltuYW1lPWJhel0KICogQHJldHVybnMgZ2VuZXJhdGVkIERPTSBwYXRoCiAqLwpmdW5jdGlvbiBfaHRtbEVsZW1lbnRBc1N0cmluZyhlbCwga2V5QXR0cnMpIHsKICBjb25zdCBlbGVtID0gZWwKCjsKCiAgY29uc3Qgb3V0ID0gW107CiAgbGV0IGNsYXNzTmFtZTsKICBsZXQgY2xhc3NlczsKICBsZXQga2V5OwogIGxldCBhdHRyOwogIGxldCBpOwoKICBpZiAoIWVsZW0gfHwgIWVsZW0udGFnTmFtZSkgewogICAgcmV0dXJuICcnOwogIH0KCiAgLy8gQHRzLWV4cGVjdC1lcnJvciBXSU5ET1cgaGFzIEhUTUxFbGVtZW50CiAgaWYgKFdJTkRPVyQ1LkhUTUxFbGVtZW50KSB7CiAgICAvLyBJZiB1c2luZyB0aGUgY29tcG9uZW50IG5hbWUgYW5ub3RhdGlvbiBwbHVnaW4sIHRoaXMgdmFsdWUgbWF5IGJlIGF2YWlsYWJsZSBvbiB0aGUgRE9NIG5vZGUKICAgIGlmIChlbGVtIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQgJiYgZWxlbS5kYXRhc2V0ICYmIGVsZW0uZGF0YXNldFsnc2VudHJ5Q29tcG9uZW50J10pIHsKICAgICAgcmV0dXJuIGVsZW0uZGF0YXNldFsnc2VudHJ5Q29tcG9uZW50J107CiAgICB9CiAgfQoKICBvdXQucHVzaChlbGVtLnRhZ05hbWUudG9Mb3dlckNhc2UoKSk7CgogIC8vIFBhaXJzIG9mIGF0dHJpYnV0ZSBrZXlzIGRlZmluZWQgaW4gYHNlcmlhbGl6ZUF0dHJpYnV0ZWAgYW5kIHRoZWlyIHZhbHVlcyBvbiBlbGVtZW50LgogIGNvbnN0IGtleUF0dHJQYWlycyA9CiAgICBrZXlBdHRycyAmJiBrZXlBdHRycy5sZW5ndGgKICAgICAgPyBrZXlBdHRycy5maWx0ZXIoa2V5QXR0ciA9PiBlbGVtLmdldEF0dHJpYnV0ZShrZXlBdHRyKSkubWFwKGtleUF0dHIgPT4gW2tleUF0dHIsIGVsZW0uZ2V0QXR0cmlidXRlKGtleUF0dHIpXSkKICAgICAgOiBudWxsOwoKICBpZiAoa2V5QXR0clBhaXJzICYmIGtleUF0dHJQYWlycy5sZW5ndGgpIHsKICAgIGtleUF0dHJQYWlycy5mb3JFYWNoKGtleUF0dHJQYWlyID0+IHsKICAgICAgb3V0LnB1c2goYFske2tleUF0dHJQYWlyWzBdfT0iJHtrZXlBdHRyUGFpclsxXX0iXWApOwogICAgfSk7CiAgfSBlbHNlIHsKICAgIGlmIChlbGVtLmlkKSB7CiAgICAgIG91dC5wdXNoKGAjJHtlbGVtLmlkfWApOwogICAgfQoKICAgIGNsYXNzTmFtZSA9IGVsZW0uY2xhc3NOYW1lOwogICAgaWYgKGNsYXNzTmFtZSAmJiBpc1N0cmluZyhjbGFzc05hbWUpKSB7CiAgICAgIGNsYXNzZXMgPSBjbGFzc05hbWUuc3BsaXQoL1xzKy8pOwogICAgICBmb3IgKGkgPSAwOyBpIDwgY2xhc3Nlcy5sZW5ndGg7IGkrKykgewogICAgICAgIG91dC5wdXNoKGAuJHtjbGFzc2VzW2ldfWApOwogICAgICB9CiAgICB9CiAgfQogIGNvbnN0IGFsbG93ZWRBdHRycyA9IFsnYXJpYS1sYWJlbCcsICd0eXBlJywgJ25hbWUnLCAndGl0bGUnLCAnYWx0J107CiAgZm9yIChpID0gMDsgaSA8IGFsbG93ZWRBdHRycy5sZW5ndGg7IGkrKykgewogICAga2V5ID0gYWxsb3dlZEF0dHJzW2ldOwogICAgYXR0ciA9IGVsZW0uZ2V0QXR0cmlidXRlKGtleSk7CiAgICBpZiAoYXR0cikgewogICAgICBvdXQucHVzaChgWyR7a2V5fT0iJHthdHRyfSJdYCk7CiAgICB9CiAgfQogIHJldHVybiBvdXQuam9pbignJyk7Cn0KCi8qKgogKiBUaGlzIHNlcnZlcyBhcyBhIGJ1aWxkIHRpbWUgZmxhZyB0aGF0IHdpbGwgYmUgdHJ1ZSBieSBkZWZhdWx0LCBidXQgZmFsc2UgaW4gbm9uLWRlYnVnIGJ1aWxkcyBvciBpZiB1c2VycyByZXBsYWNlIGBfX1NFTlRSWV9ERUJVR19fYCBpbiB0aGVpciBnZW5lcmF0ZWQgY29kZS4KICoKICogQVRURU5USU9OOiBUaGlzIGNvbnN0YW50IG11c3QgbmV2ZXIgY3Jvc3MgcGFja2FnZSBib3VuZGFyaWVzIChpLmUuIGJlIGV4cG9ydGVkKSB0byBndWFyYW50ZWUgdGhhdCBpdCBjYW4gYmUgdXNlZCBmb3IgdHJlZSBzaGFraW5nLgogKi8KY29uc3QgREVCVUdfQlVJTEQkMSA9ICh0eXBlb2YgX19TRU5UUllfREVCVUdfXyA9PT0gJ3VuZGVmaW5lZCcgfHwgX19TRU5UUllfREVCVUdfXyk7CgovKiogUHJlZml4IGZvciBsb2dnaW5nIHN0cmluZ3MgKi8KY29uc3QgUFJFRklYID0gJ1NlbnRyeSBMb2dnZXIgJzsKCmNvbnN0IENPTlNPTEVfTEVWRUxTID0gWwogICdkZWJ1ZycsCiAgJ2luZm8nLAogICd3YXJuJywKICAnZXJyb3InLAogICdsb2cnLAogICdhc3NlcnQnLAogICd0cmFjZScsCl0gOwoKLyoqIFRoaXMgbWF5IGJlIG11dGF0ZWQgYnkgdGhlIGNvbnNvbGUgaW5zdHJ1bWVudGF0aW9uLiAqLwpjb25zdCBvcmlnaW5hbENvbnNvbGVNZXRob2RzCgogPSB7fTsKCi8qKiBKU0RvYyAqLwoKLyoqCiAqIFRlbXBvcmFyaWx5IGRpc2FibGUgc2VudHJ5IGNvbnNvbGUgaW5zdHJ1bWVudGF0aW9ucy4KICoKICogQHBhcmFtIGNhbGxiYWNrIFRoZSBmdW5jdGlvbiB0byBydW4gYWdhaW5zdCB0aGUgb3JpZ2luYWwgYGNvbnNvbGVgIG1lc3NhZ2VzCiAqIEByZXR1cm5zIFRoZSByZXN1bHRzIG9mIHRoZSBjYWxsYmFjawogKi8KZnVuY3Rpb24gY29uc29sZVNhbmRib3goY2FsbGJhY2spIHsKICBpZiAoISgnY29uc29sZScgaW4gR0xPQkFMX09CSikpIHsKICAgIHJldHVybiBjYWxsYmFjaygpOwogIH0KCiAgY29uc3QgY29uc29sZSA9IEdMT0JBTF9PQkouY29uc29sZSA7CiAgY29uc3Qgd3JhcHBlZEZ1bmNzID0ge307CgogIGNvbnN0IHdyYXBwZWRMZXZlbHMgPSBPYmplY3Qua2V5cyhvcmlnaW5hbENvbnNvbGVNZXRob2RzKSA7CgogIC8vIFJlc3RvcmUgYWxsIHdyYXBwZWQgY29uc29sZSBtZXRob2RzCiAgd3JhcHBlZExldmVscy5mb3JFYWNoKGxldmVsID0+IHsKICAgIGNvbnN0IG9yaWdpbmFsQ29uc29sZU1ldGhvZCA9IG9yaWdpbmFsQ29uc29sZU1ldGhvZHNbbGV2ZWxdIDsKICAgIHdyYXBwZWRGdW5jc1tsZXZlbF0gPSBjb25zb2xlW2xldmVsXSA7CiAgICBjb25zb2xlW2xldmVsXSA9IG9yaWdpbmFsQ29uc29sZU1ldGhvZDsKICB9KTsKCiAgdHJ5IHsKICAgIHJldHVybiBjYWxsYmFjaygpOwogIH0gZmluYWxseSB7CiAgICAvLyBSZXZlcnQgcmVzdG9yYXRpb24gdG8gd3JhcHBlZCBzdGF0ZQogICAgd3JhcHBlZExldmVscy5mb3JFYWNoKGxldmVsID0+IHsKICAgICAgY29uc29sZVtsZXZlbF0gPSB3cmFwcGVkRnVuY3NbbGV2ZWxdIDsKICAgIH0pOwogIH0KfQoKZnVuY3Rpb24gbWFrZUxvZ2dlcigpIHsKICBsZXQgZW5hYmxlZCA9IGZhbHNlOwogIGNvbnN0IGxvZ2dlciA9IHsKICAgIGVuYWJsZTogKCkgPT4gewogICAgICBlbmFibGVkID0gdHJ1ZTsKICAgIH0sCiAgICBkaXNhYmxlOiAoKSA9PiB7CiAgICAgIGVuYWJsZWQgPSBmYWxzZTsKICAgIH0sCiAgICBpc0VuYWJsZWQ6ICgpID0+IGVuYWJsZWQsCiAgfTsKCiAgaWYgKERFQlVHX0JVSUxEJDEpIHsKICAgIENPTlNPTEVfTEVWRUxTLmZvckVhY2gobmFtZSA9PiB7CiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55CiAgICAgIGxvZ2dlcltuYW1lXSA9ICguLi5hcmdzKSA9PiB7CiAgICAgICAgaWYgKGVuYWJsZWQpIHsKICAgICAgICAgIGNvbnNvbGVTYW5kYm94KCgpID0+IHsKICAgICAgICAgICAgR0xPQkFMX09CSi5jb25zb2xlW25hbWVdKGAke1BSRUZJWH1bJHtuYW1lfV06YCwgLi4uYXJncyk7CiAgICAgICAgICB9KTsKICAgICAgICB9CiAgICAgIH07CiAgICB9KTsKICB9IGVsc2UgewogICAgQ09OU09MRV9MRVZFTFMuZm9yRWFjaChuYW1lID0+IHsKICAgICAgbG9nZ2VyW25hbWVdID0gKCkgPT4gdW5kZWZpbmVkOwogICAgfSk7CiAgfQoKICByZXR1cm4gbG9nZ2VyIDsKfQoKY29uc3QgbG9nZ2VyID0gbWFrZUxvZ2dlcigpOwoKLyoqCiAqIFJlbmRlcnMgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGlzIERzbi4KICoKICogQnkgZGVmYXVsdCwgdGhpcyB3aWxsIHJlbmRlciB0aGUgcHVibGljIHJlcHJlc2VudGF0aW9uIHdpdGhvdXQgdGhlIHBhc3N3b3JkCiAqIGNvbXBvbmVudC4gVG8gZ2V0IHRoZSBkZXByZWNhdGVkIHByaXZhdGUgcmVwcmVzZW50YXRpb24sIHNldCBgd2l0aFBhc3N3b3JkYAogKiB0byB0cnVlLgogKgogKiBAcGFyYW0gd2l0aFBhc3N3b3JkIFdoZW4gc2V0IHRvIHRydWUsIHRoZSBwYXNzd29yZCB3aWxsIGJlIGluY2x1ZGVkLgogKi8KZnVuY3Rpb24gZHNuVG9TdHJpbmcoZHNuLCB3aXRoUGFzc3dvcmQgPSBmYWxzZSkgewogIGNvbnN0IHsgaG9zdCwgcGF0aCwgcGFzcywgcG9ydCwgcHJvamVjdElkLCBwcm90b2NvbCwgcHVibGljS2V5IH0gPSBkc247CiAgcmV0dXJuICgKICAgIGAke3Byb3RvY29sfTovLyR7cHVibGljS2V5fSR7d2l0aFBhc3N3b3JkICYmIHBhc3MgPyBgOiR7cGFzc31gIDogJyd9YCArCiAgICBgQCR7aG9zdH0ke3BvcnQgPyBgOiR7cG9ydH1gIDogJyd9LyR7cGF0aCA/IGAke3BhdGh9L2AgOiBwYXRofSR7cHJvamVjdElkfWAKICApOwp9CgovKiogQW4gZXJyb3IgZW1pdHRlZCBieSBTZW50cnkgU0RLcyBhbmQgcmVsYXRlZCB1dGlsaXRpZXMuICovCmNsYXNzIFNlbnRyeUVycm9yIGV4dGVuZHMgRXJyb3IgewogIC8qKiBEaXNwbGF5IG5hbWUgb2YgdGhpcyBlcnJvciBpbnN0YW5jZS4gKi8KCiAgIGNvbnN0cnVjdG9yKCBtZXNzYWdlLCBsb2dMZXZlbCA9ICd3YXJuJykgewogICAgc3VwZXIobWVzc2FnZSk7dGhpcy5tZXNzYWdlID0gbWVzc2FnZTsKICAgIHRoaXMubmFtZSA9IG5ldy50YXJnZXQucHJvdG90eXBlLmNvbnN0cnVjdG9yLm5hbWU7CiAgICAvLyBUaGlzIHNldHMgdGhlIHByb3RvdHlwZSB0byBiZSBgRXJyb3JgLCBub3QgYFNlbnRyeUVycm9yYC4gSXQncyB1bmNsZWFyIHdoeSB3ZSBkbyB0aGlzLCBidXQgY29tbWVudGluZyB0aGlzIGxpbmUKICAgIC8vIG91dCBjYXVzZXMgdmFyaW91cyAoc2VlbWluZ2x5IHRvdGFsbHkgdW5yZWxhdGVkKSBwbGF5d3JpZ2h0IHRlc3RzIGNvbnNpc3RlbnRseSB0aW1lIG91dC4gRllJLCB0aGlzIG1ha2VzCiAgICAvLyBpbnN0YW5jZXMgb2YgYFNlbnRyeUVycm9yYCBmYWlsIGBvYmogaW5zdGFuY2VvZiBTZW50cnlFcnJvcmAgY2hlY2tzLgogICAgT2JqZWN0LnNldFByb3RvdHlwZU9mKHRoaXMsIG5ldy50YXJnZXQucHJvdG90eXBlKTsKICAgIHRoaXMubG9nTGV2ZWwgPSBsb2dMZXZlbDsKICB9Cn0KCmNvbnN0IFNUQUNLVFJBQ0VfRlJBTUVfTElNSVQgPSA1MDsKY29uc3QgVU5LTk9XTl9GVU5DVElPTiA9ICc/JzsKY29uc3QgU1RSSVBfRlJBTUVfUkVHRVhQID0gL2NhcHR1cmVNZXNzYWdlfGNhcHR1cmVFeGNlcHRpb24vOwoKLyoqCiAqIFJlbW92ZXMgU2VudHJ5IGZyYW1lcyBmcm9tIHRoZSB0b3AgYW5kIGJvdHRvbSBvZiB0aGUgc3RhY2sgaWYgcHJlc2VudCBhbmQgZW5mb3JjZXMgYSBsaW1pdCBvZiBtYXggbnVtYmVyIG9mIGZyYW1lcy4KICogQXNzdW1lcyBzdGFjayBpbnB1dCBpcyBvcmRlcmVkIGZyb20gdG9wIHRvIGJvdHRvbSBhbmQgcmV0dXJucyB0aGUgcmV2ZXJzZSByZXByZXNlbnRhdGlvbiBzbyBjYWxsIHNpdGUgb2YgdGhlCiAqIGZ1bmN0aW9uIHRoYXQgY2F1c2VkIHRoZSBjcmFzaCBpcyB0aGUgbGFzdCBmcmFtZSBpbiB0aGUgYXJyYXkuCiAqIEBoaWRkZW4KICovCmZ1bmN0aW9uIHN0cmlwU2VudHJ5RnJhbWVzQW5kUmV2ZXJzZShzdGFjaykgewogIGlmICghc3RhY2subGVuZ3RoKSB7CiAgICByZXR1cm4gW107CiAgfQoKICBjb25zdCBsb2NhbFN0YWNrID0gQXJyYXkuZnJvbShzdGFjayk7CgogIC8vIElmIHN0YWNrIHN0YXJ0cyB3aXRoIG9uZSBvZiBvdXIgQVBJIGNhbGxzLCByZW1vdmUgaXQgKHN0YXJ0cywgbWVhbmluZyBpdCdzIHRoZSB0b3Agb2YgdGhlIHN0YWNrIC0gYWthIGxhc3QgY2FsbCkKICBpZiAoL3NlbnRyeVdyYXBwZWQvLnRlc3QobG9jYWxTdGFja1tsb2NhbFN0YWNrLmxlbmd0aCAtIDFdLmZ1bmN0aW9uIHx8ICcnKSkgewogICAgbG9jYWxTdGFjay5wb3AoKTsKICB9CgogIC8vIFJldmVyc2luZyBpbiB0aGUgbWlkZGxlIG9mIHRoZSBwcm9jZWR1cmUgYWxsb3dzIHVzIHRvIGp1c3QgcG9wIHRoZSB2YWx1ZXMgb2ZmIHRoZSBzdGFjawogIGxvY2FsU3RhY2sucmV2ZXJzZSgpOwoKICAvLyBJZiBzdGFjayBlbmRzIHdpdGggb25lIG9mIG91ciBpbnRlcm5hbCBBUEkgY2FsbHMsIHJlbW92ZSBpdCAoZW5kcywgbWVhbmluZyBpdCdzIHRoZSBib3R0b20gb2YgdGhlIHN0YWNrIC0gYWthIHRvcC1tb3N0IGNhbGwpCiAgaWYgKFNUUklQX0ZSQU1FX1JFR0VYUC50ZXN0KGxvY2FsU3RhY2tbbG9jYWxTdGFjay5sZW5ndGggLSAxXS5mdW5jdGlvbiB8fCAnJykpIHsKICAgIGxvY2FsU3RhY2sucG9wKCk7CgogICAgLy8gV2hlbiB1c2luZyBzeW50aGV0aWMgZXZlbnRzLCB3ZSB3aWxsIGhhdmUgYSAyIGxldmVscyBkZWVwIHN0YWNrLCBhcyBgbmV3IEVycm9yKCdTZW50cnkgc3ludGhldGljRXhjZXB0aW9uJylgCiAgICAvLyBpcyBwcm9kdWNlZCB3aXRoaW4gdGhlIGh1YiBpdHNlbGYsIG1ha2luZyBpdDoKICAgIC8vCiAgICAvLyAgIFNlbnRyeS5jYXB0dXJlRXhjZXB0aW9uKCkKICAgIC8vICAgZ2V0Q3VycmVudEh1YigpLmNhcHR1cmVFeGNlcHRpb24oKQogICAgLy8KICAgIC8vIGluc3RlYWQgb2YganVzdCB0aGUgdG9wIGBTZW50cnlgIGNhbGwgaXRzZWxmLgogICAgLy8gVGhpcyBmb3JjZXMgdXMgdG8gcG9zc2libHkgc3RyaXAgYW4gYWRkaXRpb25hbCBmcmFtZSBpbiB0aGUgZXhhY3Qgc2FtZSB3YXMgYXMgYWJvdmUuCiAgICBpZiAoU1RSSVBfRlJBTUVfUkVHRVhQLnRlc3QobG9jYWxTdGFja1tsb2NhbFN0YWNrLmxlbmd0aCAtIDFdLmZ1bmN0aW9uIHx8ICcnKSkgewogICAgICBsb2NhbFN0YWNrLnBvcCgpOwogICAgfQogIH0KCiAgcmV0dXJuIGxvY2FsU3RhY2suc2xpY2UoMCwgU1RBQ0tUUkFDRV9GUkFNRV9MSU1JVCkubWFwKGZyYW1lID0+ICh7CiAgICAuLi5mcmFtZSwKICAgIGZpbGVuYW1lOiBmcmFtZS5maWxlbmFtZSB8fCBsb2NhbFN0YWNrW2xvY2FsU3RhY2subGVuZ3RoIC0gMV0uZmlsZW5hbWUsCiAgICBmdW5jdGlvbjogZnJhbWUuZnVuY3Rpb24gfHwgVU5LTk9XTl9GVU5DVElPTiwKICB9KSk7Cn0KCmNvbnN0IGRlZmF1bHRGdW5jdGlvbk5hbWUgPSAnPGFub255bW91cz4nOwoKLyoqCiAqIFNhZmVseSBleHRyYWN0IGZ1bmN0aW9uIG5hbWUgZnJvbSBpdHNlbGYKICovCmZ1bmN0aW9uIGdldEZ1bmN0aW9uTmFtZShmbikgewogIHRyeSB7CiAgICBpZiAoIWZuIHx8IHR5cGVvZiBmbiAhPT0gJ2Z1bmN0aW9uJykgewogICAgICByZXR1cm4gZGVmYXVsdEZ1bmN0aW9uTmFtZTsKICAgIH0KICAgIHJldHVybiBmbi5uYW1lIHx8IGRlZmF1bHRGdW5jdGlvbk5hbWU7CiAgfSBjYXRjaCAoZSkgewogICAgLy8gSnVzdCBhY2Nlc3NpbmcgY3VzdG9tIHByb3BzIGluIHNvbWUgU2VsZW5pdW0gZW52aXJvbm1lbnRzCiAgICAvLyBjYW4gY2F1c2UgYSAiUGVybWlzc2lvbiBkZW5pZWQiIGV4Y2VwdGlvbiAoc2VlIHJhdmVuLWpzIzQ5NSkuCiAgICByZXR1cm4gZGVmYXVsdEZ1bmN0aW9uTmFtZTsKICB9Cn0KCi8qKgogKiBUaGlzIGV4dHJhY3RzIHRoZSBvcmlnaW5hbCBmdW5jdGlvbiBpZiBhdmFpbGFibGUuICBTZWUKICogYG1hcmtGdW5jdGlvbldyYXBwZWRgIGZvciBtb3JlIGluZm9ybWF0aW9uLgogKgogKiBAcGFyYW0gZnVuYyB0aGUgZnVuY3Rpb24gdG8gdW53cmFwCiAqIEByZXR1cm5zIHRoZSB1bndyYXBwZWQgdmVyc2lvbiBvZiB0aGUgZnVuY3Rpb24gaWYgYXZhaWxhYmxlLgogKi8KZnVuY3Rpb24gZ2V0T3JpZ2luYWxGdW5jdGlvbihmdW5jKSB7CiAgcmV0dXJuIGZ1bmMuX19zZW50cnlfb3JpZ2luYWxfXzsKfQoKLyoqCiAqIEVuY29kZXMgZ2l2ZW4gb2JqZWN0IGludG8gdXJsLWZyaWVuZGx5IGZvcm1hdAogKgogKiBAcGFyYW0gb2JqZWN0IEFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIHNlcmlhbGl6YWJsZSB2YWx1ZXMKICogQHJldHVybnMgc3RyaW5nIEVuY29kZWQKICovCmZ1bmN0aW9uIHVybEVuY29kZShvYmplY3QpIHsKICByZXR1cm4gT2JqZWN0LmtleXMob2JqZWN0KQogICAgLm1hcChrZXkgPT4gYCR7ZW5jb2RlVVJJQ29tcG9uZW50KGtleSl9PSR7ZW5jb2RlVVJJQ29tcG9uZW50KG9iamVjdFtrZXldKX1gKQogICAgLmpvaW4oJyYnKTsKfQoKLyoqCiAqIFRyYW5zZm9ybXMgYW55IGBFcnJvcmAgb3IgYEV2ZW50YCBpbnRvIGEgcGxhaW4gb2JqZWN0IHdpdGggYWxsIG9mIHRoZWlyIGVudW1lcmFibGUgcHJvcGVydGllcywgYW5kIHNvbWUgb2YgdGhlaXIKICogbm9uLWVudW1lcmFibGUgcHJvcGVydGllcyBhdHRhY2hlZC4KICoKICogQHBhcmFtIHZhbHVlIEluaXRpYWwgc291cmNlIHRoYXQgd2UgaGF2ZSB0byB0cmFuc2Zvcm0gaW4gb3JkZXIgZm9yIGl0IHRvIGJlIHVzYWJsZSBieSB0aGUgc2VyaWFsaXplcgogKiBAcmV0dXJucyBBbiBFdmVudCBvciBFcnJvciB0dXJuZWQgaW50byBhbiBvYmplY3QgLSBvciB0aGUgdmFsdWUgYXJndXJtZW50IGl0c2VsZiwgd2hlbiB2YWx1ZSBpcyBuZWl0aGVyIGFuIEV2ZW50IG5vcgogKiAgYW4gRXJyb3IuCiAqLwpmdW5jdGlvbiBjb252ZXJ0VG9QbGFpbk9iamVjdCgKICB2YWx1ZSwKKQoKIHsKICBpZiAoaXNFcnJvcih2YWx1ZSkpIHsKICAgIHJldHVybiB7CiAgICAgIG1lc3NhZ2U6IHZhbHVlLm1lc3NhZ2UsCiAgICAgIG5hbWU6IHZhbHVlLm5hbWUsCiAgICAgIHN0YWNrOiB2YWx1ZS5zdGFjaywKICAgICAgLi4uZ2V0T3duUHJvcGVydGllcyh2YWx1ZSksCiAgICB9OwogIH0gZWxzZSBpZiAoaXNFdmVudCh2YWx1ZSkpIHsKICAgIGNvbnN0IG5ld09iagoKID0gewogICAgICB0eXBlOiB2YWx1ZS50eXBlLAogICAgICB0YXJnZXQ6IHNlcmlhbGl6ZUV2ZW50VGFyZ2V0KHZhbHVlLnRhcmdldCksCiAgICAgIGN1cnJlbnRUYXJnZXQ6IHNlcmlhbGl6ZUV2ZW50VGFyZ2V0KHZhbHVlLmN1cnJlbnRUYXJnZXQpLAogICAgICAuLi5nZXRPd25Qcm9wZXJ0aWVzKHZhbHVlKSwKICAgIH07CgogICAgaWYgKHR5cGVvZiBDdXN0b21FdmVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgaXNJbnN0YW5jZU9mKHZhbHVlLCBDdXN0b21FdmVudCkpIHsKICAgICAgbmV3T2JqLmRldGFpbCA9IHZhbHVlLmRldGFpbDsKICAgIH0KCiAgICByZXR1cm4gbmV3T2JqOwogIH0gZWxzZSB7CiAgICByZXR1cm4gdmFsdWU7CiAgfQp9CgovKiogQ3JlYXRlcyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgdGFyZ2V0IG9mIGFuIGBFdmVudGAgb2JqZWN0ICovCmZ1bmN0aW9uIHNlcmlhbGl6ZUV2ZW50VGFyZ2V0KHRhcmdldCkgewogIHRyeSB7CiAgICByZXR1cm4gaXNFbGVtZW50KHRhcmdldCkgPyBodG1sVHJlZUFzU3RyaW5nKHRhcmdldCkgOiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodGFyZ2V0KTsKICB9IGNhdGNoIChfb08pIHsKICAgIHJldHVybiAnPHVua25vd24+JzsKICB9Cn0KCi8qKiBGaWx0ZXJzIG91dCBhbGwgYnV0IGFuIG9iamVjdCdzIG93biBwcm9wZXJ0aWVzICovCmZ1bmN0aW9uIGdldE93blByb3BlcnRpZXMob2JqKSB7CiAgaWYgKHR5cGVvZiBvYmogPT09ICdvYmplY3QnICYmIG9iaiAhPT0gbnVsbCkgewogICAgY29uc3QgZXh0cmFjdGVkUHJvcHMgPSB7fTsKICAgIGZvciAoY29uc3QgcHJvcGVydHkgaW4gb2JqKSB7CiAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBwcm9wZXJ0eSkpIHsKICAgICAgICBleHRyYWN0ZWRQcm9wc1twcm9wZXJ0eV0gPSAob2JqIClbcHJvcGVydHldOwogICAgICB9CiAgICB9CiAgICByZXR1cm4gZXh0cmFjdGVkUHJvcHM7CiAgfSBlbHNlIHsKICAgIHJldHVybiB7fTsKICB9Cn0KCi8qKgogKiBHaXZlbiBhbnkgb2JqZWN0LCByZXR1cm4gYSBuZXcgb2JqZWN0IGhhdmluZyByZW1vdmVkIGFsbCBmaWVsZHMgd2hvc2UgdmFsdWUgd2FzIGB1bmRlZmluZWRgLgogKiBXb3JrcyByZWN1cnNpdmVseSBvbiBvYmplY3RzIGFuZCBhcnJheXMuCiAqCiAqIEF0dGVudGlvbjogVGhpcyBmdW5jdGlvbiBrZWVwcyBjaXJjdWxhciByZWZlcmVuY2VzIGluIHRoZSByZXR1cm5lZCBvYmplY3QuCiAqLwpmdW5jdGlvbiBkcm9wVW5kZWZpbmVkS2V5cyhpbnB1dFZhbHVlKSB7CiAgLy8gVGhpcyBtYXAga2VlcHMgdHJhY2sgb2Ygd2hhdCBhbHJlYWR5IHZpc2l0ZWQgbm9kZXMgbWFwIHRvLgogIC8vIE91ciBTZXQgLSBiYXNlZCBtZW1vQnVpbGRlciBkb2Vzbid0IHdvcmsgaGVyZSBiZWNhdXNlIHdlIHdhbnQgdG8gdGhlIG91dHB1dCBvYmplY3QgdG8gaGF2ZSB0aGUgc2FtZSBjaXJjdWxhcgogIC8vIHJlZmVyZW5jZXMgYXMgdGhlIGlucHV0IG9iamVjdC4KICBjb25zdCBtZW1vaXphdGlvbk1hcCA9IG5ldyBNYXAoKTsKCiAgLy8gVGhpcyBmdW5jdGlvbiBqdXN0IHByb3hpZXMgYF9kcm9wVW5kZWZpbmVkS2V5c2AgdG8ga2VlcCB0aGUgYG1lbW9CdWlsZGVyYCBvdXQgb2YgdGhpcyBmdW5jdGlvbidzIEFQSQogIHJldHVybiBfZHJvcFVuZGVmaW5lZEtleXMoaW5wdXRWYWx1ZSwgbWVtb2l6YXRpb25NYXApOwp9CgpmdW5jdGlvbiBfZHJvcFVuZGVmaW5lZEtleXMoaW5wdXRWYWx1ZSwgbWVtb2l6YXRpb25NYXApIHsKICBpZiAoaXNQb2pvKGlucHV0VmFsdWUpKSB7CiAgICAvLyBJZiB0aGlzIG5vZGUgaGFzIGFscmVhZHkgYmVlbiB2aXNpdGVkIGR1ZSB0byBhIGNpcmN1bGFyIHJlZmVyZW5jZSwgcmV0dXJuIHRoZSBvYmplY3QgaXQgd2FzIG1hcHBlZCB0byBpbiB0aGUgbmV3IG9iamVjdAogICAgY29uc3QgbWVtb1ZhbCA9IG1lbW9pemF0aW9uTWFwLmdldChpbnB1dFZhbHVlKTsKICAgIGlmIChtZW1vVmFsICE9PSB1bmRlZmluZWQpIHsKICAgICAgcmV0dXJuIG1lbW9WYWwgOwogICAgfQoKICAgIGNvbnN0IHJldHVyblZhbHVlID0ge307CiAgICAvLyBTdG9yZSB0aGUgbWFwcGluZyBvZiB0aGlzIHZhbHVlIGluIGNhc2Ugd2UgdmlzaXQgaXQgYWdhaW4sIGluIGNhc2Ugb2YgY2lyY3VsYXIgZGF0YQogICAgbWVtb2l6YXRpb25NYXAuc2V0KGlucHV0VmFsdWUsIHJldHVyblZhbHVlKTsKCiAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhpbnB1dFZhbHVlKSkgewogICAgICBpZiAodHlwZW9mIGlucHV0VmFsdWVba2V5XSAhPT0gJ3VuZGVmaW5lZCcpIHsKICAgICAgICByZXR1cm5WYWx1ZVtrZXldID0gX2Ryb3BVbmRlZmluZWRLZXlzKGlucHV0VmFsdWVba2V5XSwgbWVtb2l6YXRpb25NYXApOwogICAgICB9CiAgICB9CgogICAgcmV0dXJuIHJldHVyblZhbHVlIDsKICB9CgogIGlmIChBcnJheS5pc0FycmF5KGlucHV0VmFsdWUpKSB7CiAgICAvLyBJZiB0aGlzIG5vZGUgaGFzIGFscmVhZHkgYmVlbiB2aXNpdGVkIGR1ZSB0byBhIGNpcmN1bGFyIHJlZmVyZW5jZSwgcmV0dXJuIHRoZSBhcnJheSBpdCB3YXMgbWFwcGVkIHRvIGluIHRoZSBuZXcgb2JqZWN0CiAgICBjb25zdCBtZW1vVmFsID0gbWVtb2l6YXRpb25NYXAuZ2V0KGlucHV0VmFsdWUpOwogICAgaWYgKG1lbW9WYWwgIT09IHVuZGVmaW5lZCkgewogICAgICByZXR1cm4gbWVtb1ZhbCA7CiAgICB9CgogICAgY29uc3QgcmV0dXJuVmFsdWUgPSBbXTsKICAgIC8vIFN0b3JlIHRoZSBtYXBwaW5nIG9mIHRoaXMgdmFsdWUgaW4gY2FzZSB3ZSB2aXNpdCBpdCBhZ2FpbiwgaW4gY2FzZSBvZiBjaXJjdWxhciBkYXRhCiAgICBtZW1vaXphdGlvbk1hcC5zZXQoaW5wdXRWYWx1ZSwgcmV0dXJuVmFsdWUpOwoKICAgIGlucHV0VmFsdWUuZm9yRWFjaCgoaXRlbSkgPT4gewogICAgICByZXR1cm5WYWx1ZS5wdXNoKF9kcm9wVW5kZWZpbmVkS2V5cyhpdGVtLCBtZW1vaXphdGlvbk1hcCkpOwogICAgfSk7CgogICAgcmV0dXJuIHJldHVyblZhbHVlIDsKICB9CgogIHJldHVybiBpbnB1dFZhbHVlOwp9CgpmdW5jdGlvbiBpc1Bvam8oaW5wdXQpIHsKICBpZiAoIWlzUGxhaW5PYmplY3QoaW5wdXQpKSB7CiAgICByZXR1cm4gZmFsc2U7CiAgfQoKICB0cnkgewogICAgY29uc3QgbmFtZSA9IChPYmplY3QuZ2V0UHJvdG90eXBlT2YoaW5wdXQpICkuY29uc3RydWN0b3IubmFtZTsKICAgIHJldHVybiAhbmFtZSB8fCBuYW1lID09PSAnT2JqZWN0JzsKICB9IGNhdGNoIChlKSB7CiAgICByZXR1cm4gdHJ1ZTsKICB9Cn0KCi8qKgogKiBVVUlENCBnZW5lcmF0b3IKICoKICogQHJldHVybnMgc3RyaW5nIEdlbmVyYXRlZCBVVUlENC4KICovCmZ1bmN0aW9uIHV1aWQ0KCkgewogIGNvbnN0IGdibCA9IEdMT0JBTF9PQkogOwogIGNvbnN0IGNyeXB0byA9IGdibC5jcnlwdG8gfHwgZ2JsLm1zQ3J5cHRvOwoKICBsZXQgZ2V0UmFuZG9tQnl0ZSA9ICgpID0+IE1hdGgucmFuZG9tKCkgKiAxNjsKICB0cnkgewogICAgaWYgKGNyeXB0byAmJiBjcnlwdG8ucmFuZG9tVVVJRCkgewogICAgICByZXR1cm4gY3J5cHRvLnJhbmRvbVVVSUQoKS5yZXBsYWNlKC8tL2csICcnKTsKICAgIH0KICAgIGlmIChjcnlwdG8gJiYgY3J5cHRvLmdldFJhbmRvbVZhbHVlcykgewogICAgICBnZXRSYW5kb21CeXRlID0gKCkgPT4gewogICAgICAgIC8vIGNyeXB0by5nZXRSYW5kb21WYWx1ZXMgbWlnaHQgcmV0dXJuIHVuZGVmaW5lZCBpbnN0ZWFkIG9mIHRoZSB0eXBlZCBhcnJheQogICAgICAgIC8vIGluIG9sZCBDaHJvbWl1bSB2ZXJzaW9ucyAoZS5nLiAyMy4wLjEyMzUuMCAoMTUxNDIyKSkKICAgICAgICAvLyBIb3dldmVyLCBgdHlwZWRBcnJheWAgaXMgc3RpbGwgZmlsbGVkIGluLXBsYWNlLgogICAgICAgIC8vIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0NyeXB0by9nZXRSYW5kb21WYWx1ZXMjdHlwZWRhcnJheQogICAgICAgIGNvbnN0IHR5cGVkQXJyYXkgPSBuZXcgVWludDhBcnJheSgxKTsKICAgICAgICBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKHR5cGVkQXJyYXkpOwogICAgICAgIHJldHVybiB0eXBlZEFycmF5WzBdOwogICAgICB9OwogICAgfQogIH0gY2F0Y2ggKF8pIHsKICAgIC8vIHNvbWUgcnVudGltZXMgY2FuIGNyYXNoIGludm9raW5nIGNyeXB0bwogICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdC9pc3N1ZXMvODkzNQogIH0KCiAgLy8gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xMDUwMzQvaG93LXRvLWNyZWF0ZS1hLWd1aWQtdXVpZC1pbi1qYXZhc2NyaXB0LzIxMTc1MjMjMjExNzUyMwogIC8vIENvbmNhdGVuYXRpbmcgdGhlIGZvbGxvd2luZyBudW1iZXJzIGFzIHN0cmluZ3MgcmVzdWx0cyBpbiAnMTAwMDAwMDAxMDAwNDAwMDgwMDAxMDAwMDAwMDAwMDAnCiAgcmV0dXJuICgoWzFlN10gKSArIDFlMyArIDRlMyArIDhlMyArIDFlMTEpLnJlcGxhY2UoL1swMThdL2csIGMgPT4KICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1iaXR3aXNlCiAgICAoKGMgKSBeICgoZ2V0UmFuZG9tQnl0ZSgpICYgMTUpID4+ICgoYyApIC8gNCkpKS50b1N0cmluZygxNiksCiAgKTsKfQoKLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1tZW1iZXItYWNjZXNzICovCi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkgKi8KCi8qKgogKiBIZWxwZXIgdG8gZGVjeWNsZSBqc29uIG9iamVjdHMKICovCmZ1bmN0aW9uIG1lbW9CdWlsZGVyKCkgewogIGNvbnN0IGhhc1dlYWtTZXQgPSB0eXBlb2YgV2Vha1NldCA9PT0gJ2Z1bmN0aW9uJzsKICBjb25zdCBpbm5lciA9IGhhc1dlYWtTZXQgPyBuZXcgV2Vha1NldCgpIDogW107CiAgZnVuY3Rpb24gbWVtb2l6ZShvYmopIHsKICAgIGlmIChoYXNXZWFrU2V0KSB7CiAgICAgIGlmIChpbm5lci5oYXMob2JqKSkgewogICAgICAgIHJldHVybiB0cnVlOwogICAgICB9CiAgICAgIGlubmVyLmFkZChvYmopOwogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L3ByZWZlci1mb3Itb2YKICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaW5uZXIubGVuZ3RoOyBpKyspIHsKICAgICAgY29uc3QgdmFsdWUgPSBpbm5lcltpXTsKICAgICAgaWYgKHZhbHVlID09PSBvYmopIHsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgfQogICAgfQogICAgaW5uZXIucHVzaChvYmopOwogICAgcmV0dXJuIGZhbHNlOwogIH0KCiAgZnVuY3Rpb24gdW5tZW1vaXplKG9iaikgewogICAgaWYgKGhhc1dlYWtTZXQpIHsKICAgICAgaW5uZXIuZGVsZXRlKG9iaik7CiAgICB9IGVsc2UgewogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGlubmVyLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgaWYgKGlubmVyW2ldID09PSBvYmopIHsKICAgICAgICAgIGlubmVyLnNwbGljZShpLCAxKTsKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgfQogICAgfQogIH0KICByZXR1cm4gW21lbW9pemUsIHVubWVtb2l6ZV07Cn0KCi8qKgogKiBSZWN1cnNpdmVseSBub3JtYWxpemVzIHRoZSBnaXZlbiBvYmplY3QuCiAqCiAqIC0gQ3JlYXRlcyBhIGNvcHkgdG8gcHJldmVudCBvcmlnaW5hbCBpbnB1dCBtdXRhdGlvbgogKiAtIFNraXBzIG5vbi1lbnVtZXJhYmxlIHByb3BlcnRpZXMKICogLSBXaGVuIHN0cmluZ2lmeWluZywgY2FsbHMgYHRvSlNPTmAgaWYgaW1wbGVtZW50ZWQKICogLSBSZW1vdmVzIGNpcmN1bGFyIHJlZmVyZW5jZXMKICogLSBUcmFuc2xhdGVzIG5vbi1zZXJpYWxpemFibGUgdmFsdWVzIChgdW5kZWZpbmVkYC9gTmFOYC9mdW5jdGlvbnMpIHRvIHNlcmlhbGl6YWJsZSBmb3JtYXQKICogLSBUcmFuc2xhdGVzIGtub3duIGdsb2JhbCBvYmplY3RzL2NsYXNzZXMgdG8gYSBzdHJpbmcgcmVwcmVzZW50YXRpb25zCiAqIC0gVGFrZXMgY2FyZSBvZiBgRXJyb3JgIG9iamVjdCBzZXJpYWxpemF0aW9uCiAqIC0gT3B0aW9uYWxseSBsaW1pdHMgZGVwdGggb2YgZmluYWwgb3V0cHV0CiAqIC0gT3B0aW9uYWxseSBsaW1pdHMgbnVtYmVyIG9mIHByb3BlcnRpZXMvZWxlbWVudHMgaW5jbHVkZWQgaW4gYW55IHNpbmdsZSBvYmplY3QvYXJyYXkKICoKICogQHBhcmFtIGlucHV0IFRoZSBvYmplY3QgdG8gYmUgbm9ybWFsaXplZC4KICogQHBhcmFtIGRlcHRoIFRoZSBtYXggZGVwdGggdG8gd2hpY2ggdG8gbm9ybWFsaXplIHRoZSBvYmplY3QuIChBbnl0aGluZyBkZWVwZXIgc3RyaW5naWZpZWQgd2hvbGUuKQogKiBAcGFyYW0gbWF4UHJvcGVydGllcyBUaGUgbWF4IG51bWJlciBvZiBlbGVtZW50cyBvciBwcm9wZXJ0aWVzIHRvIGJlIGluY2x1ZGVkIGluIGFueSBzaW5nbGUgYXJyYXkgb3IKICogb2JqZWN0IGluIHRoZSBub3JtYWxsaXplZCBvdXRwdXQuCiAqIEByZXR1cm5zIEEgbm9ybWFsaXplZCB2ZXJzaW9uIG9mIHRoZSBvYmplY3QsIG9yIGAiKipub24tc2VyaWFsaXphYmxlKioiYCBpZiBhbnkgZXJyb3JzIGFyZSB0aHJvd24gZHVyaW5nIG5vcm1hbGl6YXRpb24uCiAqLwovLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueQpmdW5jdGlvbiBub3JtYWxpemUoaW5wdXQsIGRlcHRoID0gMTAwLCBtYXhQcm9wZXJ0aWVzID0gK0luZmluaXR5KSB7CiAgdHJ5IHsKICAgIC8vIHNpbmNlIHdlJ3JlIGF0IHRoZSBvdXRlcm1vc3QgbGV2ZWwsIHdlIGRvbid0IHByb3ZpZGUgYSBrZXkKICAgIHJldHVybiB2aXNpdCgnJywgaW5wdXQsIGRlcHRoLCBtYXhQcm9wZXJ0aWVzKTsKICB9IGNhdGNoIChlcnIpIHsKICAgIHJldHVybiB7IEVSUk9SOiBgKipub24tc2VyaWFsaXphYmxlKiogKCR7ZXJyfSlgIH07CiAgfQp9CgovKioKICogVmlzaXRzIGEgbm9kZSB0byBwZXJmb3JtIG5vcm1hbGl6YXRpb24gb24gaXQKICoKICogQHBhcmFtIGtleSBUaGUga2V5IGNvcnJlc3BvbmRpbmcgdG8gdGhlIGdpdmVuIG5vZGUKICogQHBhcmFtIHZhbHVlIFRoZSBub2RlIHRvIGJlIHZpc2l0ZWQKICogQHBhcmFtIGRlcHRoIE9wdGlvbmFsIG51bWJlciBpbmRpY2F0aW5nIHRoZSBtYXhpbXVtIHJlY3Vyc2lvbiBkZXB0aAogKiBAcGFyYW0gbWF4UHJvcGVydGllcyBPcHRpb25hbCBtYXhpbXVtIG51bWJlciBvZiBwcm9wZXJ0aWVzL2VsZW1lbnRzIGluY2x1ZGVkIGluIGFueSBzaW5nbGUgb2JqZWN0L2FycmF5CiAqIEBwYXJhbSBtZW1vIE9wdGlvbmFsIE1lbW8gY2xhc3MgaGFuZGxpbmcgZGVjeWNsaW5nCiAqLwpmdW5jdGlvbiB2aXNpdCgKICBrZXksCiAgdmFsdWUsCiAgZGVwdGggPSArSW5maW5pdHksCiAgbWF4UHJvcGVydGllcyA9ICtJbmZpbml0eSwKICBtZW1vID0gbWVtb0J1aWxkZXIoKSwKKSB7CiAgY29uc3QgW21lbW9pemUsIHVubWVtb2l6ZV0gPSBtZW1vOwoKICAvLyBHZXQgdGhlIHNpbXBsZSBjYXNlcyBvdXQgb2YgdGhlIHdheSBmaXJzdAogIGlmICgKICAgIHZhbHVlID09IG51bGwgfHwgLy8gdGhpcyBtYXRjaGVzIG51bGwgYW5kIHVuZGVmaW5lZCAtPiBlcWVxIG5vdCBlcWVxZXEKICAgIChbJ251bWJlcicsICdib29sZWFuJywgJ3N0cmluZyddLmluY2x1ZGVzKHR5cGVvZiB2YWx1ZSkgJiYgIWlzTmFOJDEodmFsdWUpKQogICkgewogICAgcmV0dXJuIHZhbHVlIDsKICB9CgogIGNvbnN0IHN0cmluZ2lmaWVkID0gc3RyaW5naWZ5VmFsdWUoa2V5LCB2YWx1ZSk7CgogIC8vIEFueXRoaW5nIHdlIGNvdWxkIHBvdGVudGlhbGx5IGRpZyBpbnRvIG1vcmUgKG9iamVjdHMgb3IgYXJyYXlzKSB3aWxsIGhhdmUgY29tZSBiYWNrIGFzIGAiW29iamVjdCBYWFhYXSJgLgogIC8vIEV2ZXJ5dGhpbmcgZWxzZSB3aWxsIGhhdmUgYWxyZWFkeSBiZWVuIHNlcmlhbGl6ZWQsIHNvIGlmIHdlIGRvbid0IHNlZSB0aGF0IHBhdHRlcm4sIHdlJ3JlIGRvbmUuCiAgaWYgKCFzdHJpbmdpZmllZC5zdGFydHNXaXRoKCdbb2JqZWN0ICcpKSB7CiAgICByZXR1cm4gc3RyaW5naWZpZWQ7CiAgfQoKICAvLyBGcm9tIGhlcmUgb24sIHdlIGNhbiBhc3NlcnQgdGhhdCBgdmFsdWVgIGlzIGVpdGhlciBhbiBvYmplY3Qgb3IgYW4gYXJyYXkuCgogIC8vIERvIG5vdCBub3JtYWxpemUgb2JqZWN0cyB0aGF0IHdlIGtub3cgaGF2ZSBhbHJlYWR5IGJlZW4gbm9ybWFsaXplZC4gQXMgYSBnZW5lcmFsIHJ1bGUsIHRoZQogIC8vICJfX3NlbnRyeV9za2lwX25vcm1hbGl6YXRpb25fXyIgcHJvcGVydHkgc2hvdWxkIG9ubHkgYmUgdXNlZCBzcGFyaW5nbHkgYW5kIG9ubHkgc2hvdWxkIG9ubHkgYmUgc2V0IG9uIG9iamVjdHMgdGhhdAogIC8vIGhhdmUgYWxyZWFkeSBiZWVuIG5vcm1hbGl6ZWQuCiAgaWYgKCh2YWx1ZSApWydfX3NlbnRyeV9za2lwX25vcm1hbGl6YXRpb25fXyddKSB7CiAgICByZXR1cm4gdmFsdWUgOwogIH0KCiAgLy8gV2UgY2FuIHNldCBgX19zZW50cnlfb3ZlcnJpZGVfbm9ybWFsaXphdGlvbl9kZXB0aF9fYCBvbiBhbiBvYmplY3QgdG8gZW5zdXJlIHRoYXQgZnJvbSB0aGVyZQogIC8vIFdlIGtlZXAgYSBjZXJ0YWluIGFtb3VudCBvZiBkZXB0aC4KICAvLyBUaGlzIHNob3VsZCBiZSB1c2VkIHNwYXJpbmdseSwgZS5nLiB3ZSB1c2UgaXQgZm9yIHRoZSByZWR1eCBpbnRlZ3JhdGlvbiB0byBlbnN1cmUgd2UgZ2V0IGEgY2VydGFpbiBhbW91bnQgb2Ygc3RhdGUuCiAgY29uc3QgcmVtYWluaW5nRGVwdGggPQogICAgdHlwZW9mICh2YWx1ZSApWydfX3NlbnRyeV9vdmVycmlkZV9ub3JtYWxpemF0aW9uX2RlcHRoX18nXSA9PT0gJ251bWJlcicKICAgICAgPyAoKHZhbHVlIClbJ19fc2VudHJ5X292ZXJyaWRlX25vcm1hbGl6YXRpb25fZGVwdGhfXyddICkKICAgICAgOiBkZXB0aDsKCiAgLy8gV2UncmUgYWxzbyBkb25lIGlmIHdlJ3ZlIHJlYWNoZWQgdGhlIG1heCBkZXB0aAogIGlmIChyZW1haW5pbmdEZXB0aCA9PT0gMCkgewogICAgLy8gQXQgdGhpcyBwb2ludCB3ZSBrbm93IGBzZXJpYWxpemVkYCBpcyBhIHN0cmluZyBvZiB0aGUgZm9ybSBgIltvYmplY3QgWFhYWF0iYC4gQ2xlYW4gaXQgdXAgc28gaXQncyBqdXN0IGAiW1hYWFhdImAuCiAgICByZXR1cm4gc3RyaW5naWZpZWQucmVwbGFjZSgnb2JqZWN0ICcsICcnKTsKICB9CgogIC8vIElmIHdlJ3ZlIGFscmVhZHkgdmlzaXRlZCB0aGlzIGJyYW5jaCwgYmFpbCBvdXQsIGFzIGl0J3MgY2lyY3VsYXIgcmVmZXJlbmNlLiBJZiBub3QsIG5vdGUgdGhhdCB3ZSdyZSBzZWVpbmcgaXQgbm93LgogIGlmIChtZW1vaXplKHZhbHVlKSkgewogICAgcmV0dXJuICdbQ2lyY3VsYXIgfl0nOwogIH0KCiAgLy8gSWYgdGhlIHZhbHVlIGhhcyBhIGB0b0pTT05gIG1ldGhvZCwgd2UgY2FsbCBpdCB0byBleHRyYWN0IG1vcmUgaW5mb3JtYXRpb24KICBjb25zdCB2YWx1ZVdpdGhUb0pTT04gPSB2YWx1ZSA7CiAgaWYgKHZhbHVlV2l0aFRvSlNPTiAmJiB0eXBlb2YgdmFsdWVXaXRoVG9KU09OLnRvSlNPTiA9PT0gJ2Z1bmN0aW9uJykgewogICAgdHJ5IHsKICAgICAgY29uc3QganNvblZhbHVlID0gdmFsdWVXaXRoVG9KU09OLnRvSlNPTigpOwogICAgICAvLyBXZSBuZWVkIHRvIG5vcm1hbGl6ZSB0aGUgcmV0dXJuIHZhbHVlIG9mIGAudG9KU09OKClgIGluIGNhc2UgaXQgaGFzIGNpcmN1bGFyIHJlZmVyZW5jZXMKICAgICAgcmV0dXJuIHZpc2l0KCcnLCBqc29uVmFsdWUsIHJlbWFpbmluZ0RlcHRoIC0gMSwgbWF4UHJvcGVydGllcywgbWVtbyk7CiAgICB9IGNhdGNoIChlcnIpIHsKICAgICAgLy8gcGFzcyAoVGhlIGJ1aWx0LWluIGB0b0pTT05gIGZhaWxlZCwgYnV0IHdlIGNhbiBzdGlsbCB0cnkgdG8gZG8gaXQgb3Vyc2VsdmVzKQogICAgfQogIH0KCiAgLy8gQXQgdGhpcyBwb2ludCB3ZSBrbm93IHdlIGVpdGhlciBoYXZlIGFuIG9iamVjdCBvciBhbiBhcnJheSwgd2UgaGF2ZW4ndCBzZWVuIGl0IGJlZm9yZSwgYW5kIHdlJ3JlIGdvaW5nIHRvIHJlY3Vyc2UKICAvLyBiZWNhdXNlIHdlIGhhdmVuJ3QgeWV0IHJlYWNoZWQgdGhlIG1heCBkZXB0aC4gQ3JlYXRlIGFuIGFjY3VtdWxhdG9yIHRvIGhvbGQgdGhlIHJlc3VsdHMgb2YgdmlzaXRpbmcgZWFjaAogIC8vIHByb3BlcnR5L2VudHJ5LCBhbmQga2VlcCB0cmFjayBvZiB0aGUgbnVtYmVyIG9mIGl0ZW1zIHdlIGFkZCB0byBpdC4KICBjb25zdCBub3JtYWxpemVkID0gKEFycmF5LmlzQXJyYXkodmFsdWUpID8gW10gOiB7fSkgOwogIGxldCBudW1BZGRlZCA9IDA7CgogIC8vIEJlZm9yZSB3ZSBiZWdpbiwgY29udmVydGBFcnJvcmAgYW5kYEV2ZW50YCBpbnN0YW5jZXMgaW50byBwbGFpbiBvYmplY3RzLCBzaW5jZSBzb21lIG9mIGVhY2ggb2YgdGhlaXIgcmVsZXZhbnQKICAvLyBwcm9wZXJ0aWVzIGFyZSBub24tZW51bWVyYWJsZSBhbmQgb3RoZXJ3aXNlIHdvdWxkIGdldCBtaXNzZWQuCiAgY29uc3QgdmlzaXRhYmxlID0gY29udmVydFRvUGxhaW5PYmplY3QodmFsdWUgKTsKCiAgZm9yIChjb25zdCB2aXNpdEtleSBpbiB2aXNpdGFibGUpIHsKICAgIC8vIEF2b2lkIGl0ZXJhdGluZyBvdmVyIGZpZWxkcyBpbiB0aGUgcHJvdG90eXBlIGlmIHRoZXkndmUgc29tZWhvdyBiZWVuIGV4cG9zZWQgdG8gZW51bWVyYXRpb24uCiAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh2aXNpdGFibGUsIHZpc2l0S2V5KSkgewogICAgICBjb250aW51ZTsKICAgIH0KCiAgICBpZiAobnVtQWRkZWQgPj0gbWF4UHJvcGVydGllcykgewogICAgICBub3JtYWxpemVkW3Zpc2l0S2V5XSA9ICdbTWF4UHJvcGVydGllcyB+XSc7CiAgICAgIGJyZWFrOwogICAgfQoKICAgIC8vIFJlY3Vyc2l2ZWx5IHZpc2l0IGFsbCB0aGUgY2hpbGQgbm9kZXMKICAgIGNvbnN0IHZpc2l0VmFsdWUgPSB2aXNpdGFibGVbdmlzaXRLZXldOwogICAgbm9ybWFsaXplZFt2aXNpdEtleV0gPSB2aXNpdCh2aXNpdEtleSwgdmlzaXRWYWx1ZSwgcmVtYWluaW5nRGVwdGggLSAxLCBtYXhQcm9wZXJ0aWVzLCBtZW1vKTsKCiAgICBudW1BZGRlZCsrOwogIH0KCiAgLy8gT25jZSB3ZSd2ZSB2aXNpdGVkIGFsbCB0aGUgYnJhbmNoZXMsIHJlbW92ZSB0aGUgcGFyZW50IGZyb20gbWVtbyBzdG9yYWdlCiAgdW5tZW1vaXplKHZhbHVlKTsKCiAgLy8gUmV0dXJuIGFjY3VtdWxhdGVkIHZhbHVlcwogIHJldHVybiBub3JtYWxpemVkOwp9CgovKiBlc2xpbnQtZGlzYWJsZSBjb21wbGV4aXR5ICovCi8qKgogKiBTdHJpbmdpZnkgdGhlIGdpdmVuIHZhbHVlLiBIYW5kbGVzIHZhcmlvdXMga25vd24gc3BlY2lhbCB2YWx1ZXMgYW5kIHR5cGVzLgogKgogKiBOb3QgbWVhbnQgdG8gYmUgdXNlZCBvbiBzaW1wbGUgcHJpbWl0aXZlcyB3aGljaCBhbHJlYWR5IGhhdmUgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24sIGFzIGl0IHdpbGwsIGZvciBleGFtcGxlLCB0dXJuCiAqIHRoZSBudW1iZXIgMTIzMSBpbnRvICJbT2JqZWN0IE51bWJlcl0iLCBub3Igb24gYG51bGxgLCBhcyBpdCB3aWxsIHRocm93LgogKgogKiBAcGFyYW0gdmFsdWUgVGhlIHZhbHVlIHRvIHN0cmluZ2lmeQogKiBAcmV0dXJucyBBIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBnaXZlbiB2YWx1ZQogKi8KZnVuY3Rpb24gc3RyaW5naWZ5VmFsdWUoCiAga2V5LAogIC8vIHRoaXMgdHlwZSBpcyBhIHRpbnkgYml0IG9mIGEgY2hlYXQsIHNpbmNlIHRoaXMgZnVuY3Rpb24gZG9lcyBoYW5kbGUgTmFOICh3aGljaCBpcyB0ZWNobmljYWxseSBhIG51bWJlciksIGJ1dCBmb3IKICAvLyBvdXIgaW50ZXJuYWwgdXNlLCBpdCdsbCBkbwogIHZhbHVlLAopIHsKICB0cnkgewogICAgaWYgKGtleSA9PT0gJ2RvbWFpbicgJiYgdmFsdWUgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiAodmFsdWUgKS5fZXZlbnRzKSB7CiAgICAgIHJldHVybiAnW0RvbWFpbl0nOwogICAgfQoKICAgIGlmIChrZXkgPT09ICdkb21haW5FbWl0dGVyJykgewogICAgICByZXR1cm4gJ1tEb21haW5FbWl0dGVyXSc7CiAgICB9CgogICAgLy8gSXQncyBzYWZlIHRvIHVzZSBgZ2xvYmFsYCwgYHdpbmRvd2AsIGFuZCBgZG9jdW1lbnRgIGhlcmUgaW4gdGhpcyBtYW5uZXIsIGFzIHdlIGFyZSBhc3NlcnRpbmcgdXNpbmcgYHR5cGVvZmAgZmlyc3QKICAgIC8vIHdoaWNoIHdvbid0IHRocm93IGlmIHRoZXkgYXJlIG5vdCBwcmVzZW50LgoKICAgIGlmICh0eXBlb2YgZ2xvYmFsICE9PSAndW5kZWZpbmVkJyAmJiB2YWx1ZSA9PT0gZ2xvYmFsKSB7CiAgICAgIHJldHVybiAnW0dsb2JhbF0nOwogICAgfQoKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1yZXN0cmljdGVkLWdsb2JhbHMKICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiB2YWx1ZSA9PT0gd2luZG93KSB7CiAgICAgIHJldHVybiAnW1dpbmRvd10nOwogICAgfQoKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1yZXN0cmljdGVkLWdsb2JhbHMKICAgIGlmICh0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnICYmIHZhbHVlID09PSBkb2N1bWVudCkgewogICAgICByZXR1cm4gJ1tEb2N1bWVudF0nOwogICAgfQoKICAgIGlmIChpc1Z1ZVZpZXdNb2RlbCh2YWx1ZSkpIHsKICAgICAgcmV0dXJuICdbVnVlVmlld01vZGVsXSc7CiAgICB9CgogICAgLy8gUmVhY3QncyBTeW50aGV0aWNFdmVudCB0aGluZ3kKICAgIGlmIChpc1N5bnRoZXRpY0V2ZW50KHZhbHVlKSkgewogICAgICByZXR1cm4gJ1tTeW50aGV0aWNFdmVudF0nOwogICAgfQoKICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInICYmIHZhbHVlICE9PSB2YWx1ZSkgewogICAgICByZXR1cm4gJ1tOYU5dJzsKICAgIH0KCiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7CiAgICAgIHJldHVybiBgW0Z1bmN0aW9uOiAke2dldEZ1bmN0aW9uTmFtZSh2YWx1ZSl9XWA7CiAgICB9CgogICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N5bWJvbCcpIHsKICAgICAgcmV0dXJuIGBbJHtTdHJpbmcodmFsdWUpfV1gOwogICAgfQoKICAgIC8vIHN0cmluZ2lmaWVkIEJpZ0ludHMgYXJlIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gcmVndWxhciBudW1iZXJzLCBzbyB3ZSBuZWVkIHRvIGxhYmVsIHRoZW0gdG8gYXZvaWQgY29uZnVzaW9uCiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnYmlnaW50JykgewogICAgICByZXR1cm4gYFtCaWdJbnQ6ICR7U3RyaW5nKHZhbHVlKX1dYDsKICAgIH0KCiAgICAvLyBOb3cgdGhhdCB3ZSd2ZSBrbm9ja2VkIG91dCBhbGwgdGhlIHNwZWNpYWwgY2FzZXMgYW5kIHRoZSBwcmltaXRpdmVzLCBhbGwgd2UgaGF2ZSBsZWZ0IGFyZSBvYmplY3RzLiBTaW1wbHkgY2FzdGluZwogICAgLy8gdGhlbSB0byBzdHJpbmdzIG1lYW5zIHRoYXQgaW5zdGFuY2VzIG9mIGNsYXNzZXMgd2hpY2ggaGF2ZW4ndCBkZWZpbmVkIHRoZWlyIGB0b1N0cmluZ1RhZ2Agd2lsbCBqdXN0IGNvbWUgb3V0IGFzCiAgICAvLyBgIltvYmplY3QgT2JqZWN0XSJgLiBJZiB3ZSBpbnN0ZWFkIGxvb2sgYXQgdGhlIGNvbnN0cnVjdG9yJ3MgbmFtZSAod2hpY2ggaXMgdGhlIHNhbWUgYXMgdGhlIG5hbWUgb2YgdGhlIGNsYXNzKSwKICAgIC8vIHdlIGNhbiBtYWtlIHN1cmUgdGhhdCBvbmx5IHBsYWluIG9iamVjdHMgY29tZSBvdXQgdGhhdCB3YXkuCiAgICBjb25zdCBvYmpOYW1lID0gZ2V0Q29uc3RydWN0b3JOYW1lKHZhbHVlKTsKCiAgICAvLyBIYW5kbGUgSFRNTCBFbGVtZW50cwogICAgaWYgKC9eSFRNTChcdyopRWxlbWVudCQvLnRlc3Qob2JqTmFtZSkpIHsKICAgICAgcmV0dXJuIGBbSFRNTEVsZW1lbnQ6ICR7b2JqTmFtZX1dYDsKICAgIH0KCiAgICByZXR1cm4gYFtvYmplY3QgJHtvYmpOYW1lfV1gOwogIH0gY2F0Y2ggKGVycikgewogICAgcmV0dXJuIGAqKm5vbi1zZXJpYWxpemFibGUqKiAoJHtlcnJ9KWA7CiAgfQp9Ci8qIGVzbGludC1lbmFibGUgY29tcGxleGl0eSAqLwoKZnVuY3Rpb24gZ2V0Q29uc3RydWN0b3JOYW1lKHZhbHVlKSB7CiAgY29uc3QgcHJvdG90eXBlID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKHZhbHVlKTsKCiAgcmV0dXJuIHByb3RvdHlwZSA/IHByb3RvdHlwZS5jb25zdHJ1Y3Rvci5uYW1lIDogJ251bGwgcHJvdG90eXBlJzsKfQoKLyoqCiAqIE5vcm1hbGl6ZXMgVVJMcyBpbiBleGNlcHRpb25zIGFuZCBzdGFja3RyYWNlcyB0byBhIGJhc2UgcGF0aCBzbyBTZW50cnkgY2FuIGZpbmdlcnByaW50CiAqIGFjcm9zcyBwbGF0Zm9ybXMgYW5kIHdvcmtpbmcgZGlyZWN0b3J5LgogKgogKiBAcGFyYW0gdXJsIFRoZSBVUkwgdG8gYmUgbm9ybWFsaXplZC4KICogQHBhcmFtIGJhc2VQYXRoIFRoZSBhcHBsaWNhdGlvbiBiYXNlIHBhdGguCiAqIEByZXR1cm5zIFRoZSBub3JtYWxpemVkIFVSTC4KICovCmZ1bmN0aW9uIG5vcm1hbGl6ZVVybFRvQmFzZSh1cmwsIGJhc2VQYXRoKSB7CiAgY29uc3QgZXNjYXBlZEJhc2UgPSBiYXNlUGF0aAogICAgLy8gQmFja3NsYXNoIHRvIGZvcndhcmQKICAgIC5yZXBsYWNlKC9cXC9nLCAnLycpCiAgICAvLyBFc2NhcGUgUmVnRXhwIHNwZWNpYWwgY2hhcmFjdGVycwogICAgLnJlcGxhY2UoL1t8XFx7fSgpW1xdXiQrKj8uXS9nLCAnXFwkJicpOwoKICBsZXQgbmV3VXJsID0gdXJsOwogIHRyeSB7CiAgICBuZXdVcmwgPSBkZWNvZGVVUkkodXJsKTsKICB9IGNhdGNoIChfT28pIHsKICAgIC8vIFNvbWV0aW1lIHRoaXMgYnJlYWtzCiAgfQogIHJldHVybiAoCiAgICBuZXdVcmwKICAgICAgLnJlcGxhY2UoL1xcL2csICcvJykKICAgICAgLnJlcGxhY2UoL3dlYnBhY2s6XC8/L2csICcnKSAvLyBSZW1vdmUgaW50ZXJtZWRpYXRlIGJhc2UgcGF0aAogICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHNlbnRyeS1pbnRlcm5hbC9zZGsvbm8tcmVnZXhwLWNvbnN0cnVjdG9yCiAgICAgIC5yZXBsYWNlKG5ldyBSZWdFeHAoYChmaWxlOi8vKT8vKiR7ZXNjYXBlZEJhc2V9LypgLCAnaWcnKSwgJ2FwcDovLy8nKQogICk7Cn0KCi8vIFNwbGl0IGEgZmlsZW5hbWUgaW50byBbcm9vdCwgZGlyLCBiYXNlbmFtZSwgZXh0XSwgdW5peCB2ZXJzaW9uCi8vICdyb290JyBpcyBqdXN0IGEgc2xhc2gsIG9yIG5vdGhpbmcuCmNvbnN0IHNwbGl0UGF0aFJlID0gL14oXFMrOlxcfFwvPykoW1xzXFNdKj8pKCg/OlwuezEsMn18W14vXFxdKz98KShcLlteLi9cXF0qfCkpKD86Wy9cXF0qKSQvOwovKiogSlNEb2MgKi8KZnVuY3Rpb24gc3BsaXRQYXRoKGZpbGVuYW1lKSB7CiAgLy8gVHJ1bmNhdGUgZmlsZXMgbmFtZXMgZ3JlYXRlciB0aGFuIDEwMjQgY2hhcmFjdGVycyB0byBhdm9pZCByZWdleCBkb3MKICAvLyBodHRwczovL2dpdGh1Yi5jb20vZ2V0c2VudHJ5L3NlbnRyeS1qYXZhc2NyaXB0L3B1bGwvODczNyNkaXNjdXNzaW9uX3IxMjg1NzE5MTcyCiAgY29uc3QgdHJ1bmNhdGVkID0gZmlsZW5hbWUubGVuZ3RoID4gMTAyNCA/IGA8dHJ1bmNhdGVkPiR7ZmlsZW5hbWUuc2xpY2UoLTEwMjQpfWAgOiBmaWxlbmFtZTsKICBjb25zdCBwYXJ0cyA9IHNwbGl0UGF0aFJlLmV4ZWModHJ1bmNhdGVkKTsKICByZXR1cm4gcGFydHMgPyBwYXJ0cy5zbGljZSgxKSA6IFtdOwp9CgovKiogSlNEb2MgKi8KZnVuY3Rpb24gZGlybmFtZShwYXRoKSB7CiAgY29uc3QgcmVzdWx0ID0gc3BsaXRQYXRoKHBhdGgpOwogIGNvbnN0IHJvb3QgPSByZXN1bHRbMF07CiAgbGV0IGRpciA9IHJlc3VsdFsxXTsKCiAgaWYgKCFyb290ICYmICFkaXIpIHsKICAgIC8vIE5vIGRpcm5hbWUgd2hhdHNvZXZlcgogICAgcmV0dXJuICcuJzsKICB9CgogIGlmIChkaXIpIHsKICAgIC8vIEl0IGhhcyBhIGRpcm5hbWUsIHN0cmlwIHRyYWlsaW5nIHNsYXNoCiAgICBkaXIgPSBkaXIuc2xpY2UoMCwgZGlyLmxlbmd0aCAtIDEpOwogIH0KCiAgcmV0dXJuIHJvb3QgKyBkaXI7Cn0KCi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9leHBsaWNpdC1mdW5jdGlvbi1yZXR1cm4tdHlwZSAqLwovKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55ICovCgovKiogU3luY1Byb21pc2UgaW50ZXJuYWwgc3RhdGVzICovCnZhciBTdGF0ZXM7IChmdW5jdGlvbiAoU3RhdGVzKSB7CiAgLyoqIFBlbmRpbmcgKi8KICBjb25zdCBQRU5ESU5HID0gMDsgU3RhdGVzW1N0YXRlc1siUEVORElORyJdID0gUEVORElOR10gPSAiUEVORElORyI7CiAgLyoqIFJlc29sdmVkIC8gT0sgKi8KICBjb25zdCBSRVNPTFZFRCA9IDE7IFN0YXRlc1tTdGF0ZXNbIlJFU09MVkVEIl0gPSBSRVNPTFZFRF0gPSAiUkVTT0xWRUQiOwogIC8qKiBSZWplY3RlZCAvIEVycm9yICovCiAgY29uc3QgUkVKRUNURUQgPSAyOyBTdGF0ZXNbU3RhdGVzWyJSRUpFQ1RFRCJdID0gUkVKRUNURURdID0gIlJFSkVDVEVEIjsKfSkoU3RhdGVzIHx8IChTdGF0ZXMgPSB7fSkpOwoKLy8gT3ZlcmxvYWRzIHNvIHdlIGNhbiBjYWxsIHJlc29sdmVkU3luY1Byb21pc2Ugd2l0aG91dCBhcmd1bWVudHMgYW5kIGdlbmVyaWMgYXJndW1lbnQKCi8qKgogKiBDcmVhdGVzIGEgcmVzb2x2ZWQgc3luYyBwcm9taXNlLgogKgogKiBAcGFyYW0gdmFsdWUgdGhlIHZhbHVlIHRvIHJlc29sdmUgdGhlIHByb21pc2Ugd2l0aAogKiBAcmV0dXJucyB0aGUgcmVzb2x2ZWQgc3luYyBwcm9taXNlCiAqLwpmdW5jdGlvbiByZXNvbHZlZFN5bmNQcm9taXNlKHZhbHVlKSB7CiAgcmV0dXJuIG5ldyBTeW5jUHJvbWlzZShyZXNvbHZlID0+IHsKICAgIHJlc29sdmUodmFsdWUpOwogIH0pOwp9CgovKioKICogQ3JlYXRlcyBhIHJlamVjdGVkIHN5bmMgcHJvbWlzZS4KICoKICogQHBhcmFtIHZhbHVlIHRoZSB2YWx1ZSB0byByZWplY3QgdGhlIHByb21pc2Ugd2l0aAogKiBAcmV0dXJucyB0aGUgcmVqZWN0ZWQgc3luYyBwcm9taXNlCiAqLwpmdW5jdGlvbiByZWplY3RlZFN5bmNQcm9taXNlKHJlYXNvbikgewogIHJldHVybiBuZXcgU3luY1Byb21pc2UoKF8sIHJlamVjdCkgPT4gewogICAgcmVqZWN0KHJlYXNvbik7CiAgfSk7Cn0KCi8qKgogKiBUaGVuYWJsZSBjbGFzcyB0aGF0IGJlaGF2ZXMgbGlrZSBhIFByb21pc2UgYW5kIGZvbGxvd3MgaXQncyBpbnRlcmZhY2UKICogYnV0IGlzIG5vdCBhc3luYyBpbnRlcm5hbGx5CiAqLwpjbGFzcyBTeW5jUHJvbWlzZSB7CgogICBjb25zdHJ1Y3RvcigKICAgIGV4ZWN1dG9yLAogICkge1N5bmNQcm9taXNlLnByb3RvdHlwZS5fX2luaXQuY2FsbCh0aGlzKTtTeW5jUHJvbWlzZS5wcm90b3R5cGUuX19pbml0Mi5jYWxsKHRoaXMpO1N5bmNQcm9taXNlLnByb3RvdHlwZS5fX2luaXQzLmNhbGwodGhpcyk7U3luY1Byb21pc2UucHJvdG90eXBlLl9faW5pdDQuY2FsbCh0aGlzKTsKICAgIHRoaXMuX3N0YXRlID0gU3RhdGVzLlBFTkRJTkc7CiAgICB0aGlzLl9oYW5kbGVycyA9IFtdOwoKICAgIHRyeSB7CiAgICAgIGV4ZWN1dG9yKHRoaXMuX3Jlc29sdmUsIHRoaXMuX3JlamVjdCk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIHRoaXMuX3JlamVjdChlKTsKICAgIH0KICB9CgogIC8qKiBKU0RvYyAqLwogICB0aGVuKAogICAgb25mdWxmaWxsZWQsCiAgICBvbnJlamVjdGVkLAogICkgewogICAgcmV0dXJuIG5ldyBTeW5jUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7CiAgICAgIHRoaXMuX2hhbmRsZXJzLnB1c2goWwogICAgICAgIGZhbHNlLAogICAgICAgIHJlc3VsdCA9PiB7CiAgICAgICAgICBpZiAoIW9uZnVsZmlsbGVkKSB7CiAgICAgICAgICAgIC8vIFRPRE86IMKvXF8o44OEKV8vwq8KICAgICAgICAgICAgLy8gVE9ETzogRklYTUUKICAgICAgICAgICAgcmVzb2x2ZShyZXN1bHQgKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgcmVzb2x2ZShvbmZ1bGZpbGxlZChyZXN1bHQpKTsKICAgICAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgICAgIHJlamVjdChlKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgcmVhc29uID0+IHsKICAgICAgICAgIGlmICghb25yZWplY3RlZCkgewogICAgICAgICAgICByZWplY3QocmVhc29uKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgcmVzb2x2ZShvbnJlamVjdGVkKHJlYXNvbikpOwogICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgcmVqZWN0KGUpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgXSk7CiAgICAgIHRoaXMuX2V4ZWN1dGVIYW5kbGVycygpOwogICAgfSk7CiAgfQoKICAvKiogSlNEb2MgKi8KICAgY2F0Y2goCiAgICBvbnJlamVjdGVkLAogICkgewogICAgcmV0dXJuIHRoaXMudGhlbih2YWwgPT4gdmFsLCBvbnJlamVjdGVkKTsKICB9CgogIC8qKiBKU0RvYyAqLwogICBmaW5hbGx5KG9uZmluYWxseSkgewogICAgcmV0dXJuIG5ldyBTeW5jUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7CiAgICAgIGxldCB2YWw7CiAgICAgIGxldCBpc1JlamVjdGVkOwoKICAgICAgcmV0dXJuIHRoaXMudGhlbigKICAgICAgICB2YWx1ZSA9PiB7CiAgICAgICAgICBpc1JlamVjdGVkID0gZmFsc2U7CiAgICAgICAgICB2YWwgPSB2YWx1ZTsKICAgICAgICAgIGlmIChvbmZpbmFsbHkpIHsKICAgICAgICAgICAgb25maW5hbGx5KCk7CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICByZWFzb24gPT4gewogICAgICAgICAgaXNSZWplY3RlZCA9IHRydWU7CiAgICAgICAgICB2YWwgPSByZWFzb247CiAgICAgICAgICBpZiAob25maW5hbGx5KSB7CiAgICAgICAgICAgIG9uZmluYWxseSgpOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICkudGhlbigoKSA9PiB7CiAgICAgICAgaWYgKGlzUmVqZWN0ZWQpIHsKICAgICAgICAgIHJlamVjdCh2YWwpOwogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KCiAgICAgICAgcmVzb2x2ZSh2YWwgKTsKICAgICAgfSk7CiAgICB9KTsKICB9CgogIC8qKiBKU0RvYyAqLwogICAgX19pbml0KCkge3RoaXMuX3Jlc29sdmUgPSAodmFsdWUpID0+IHsKICAgIHRoaXMuX3NldFJlc3VsdChTdGF0ZXMuUkVTT0xWRUQsIHZhbHVlKTsKICB9O30KCiAgLyoqIEpTRG9jICovCiAgICBfX2luaXQyKCkge3RoaXMuX3JlamVjdCA9IChyZWFzb24pID0+IHsKICAgIHRoaXMuX3NldFJlc3VsdChTdGF0ZXMuUkVKRUNURUQsIHJlYXNvbik7CiAgfTt9CgogIC8qKiBKU0RvYyAqLwogICAgX19pbml0MygpIHt0aGlzLl9zZXRSZXN1bHQgPSAoc3RhdGUsIHZhbHVlKSA9PiB7CiAgICBpZiAodGhpcy5fc3RhdGUgIT09IFN0YXRlcy5QRU5ESU5HKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICBpZiAoaXNUaGVuYWJsZSh2YWx1ZSkpIHsKICAgICAgdm9pZCAodmFsdWUgKS50aGVuKHRoaXMuX3Jlc29sdmUsIHRoaXMuX3JlamVjdCk7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICB0aGlzLl9zdGF0ZSA9IHN0YXRlOwogICAgdGhpcy5fdmFsdWUgPSB2YWx1ZTsKCiAgICB0aGlzLl9leGVjdXRlSGFuZGxlcnMoKTsKICB9O30KCiAgLyoqIEpTRG9jICovCiAgICBfX2luaXQ0KCkge3RoaXMuX2V4ZWN1dGVIYW5kbGVycyA9ICgpID0+IHsKICAgIGlmICh0aGlzLl9zdGF0ZSA9PT0gU3RhdGVzLlBFTkRJTkcpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIGNvbnN0IGNhY2hlZEhhbmRsZXJzID0gdGhpcy5faGFuZGxlcnMuc2xpY2UoKTsKICAgIHRoaXMuX2hhbmRsZXJzID0gW107CgogICAgY2FjaGVkSGFuZGxlcnMuZm9yRWFjaChoYW5kbGVyID0+IHsKICAgICAgaWYgKGhhbmRsZXJbMF0pIHsKICAgICAgICByZXR1cm47CiAgICAgIH0KCiAgICAgIGlmICh0aGlzLl9zdGF0ZSA9PT0gU3RhdGVzLlJFU09MVkVEKSB7CiAgICAgICAgaGFuZGxlclsxXSh0aGlzLl92YWx1ZSApOwogICAgICB9CgogICAgICBpZiAodGhpcy5fc3RhdGUgPT09IFN0YXRlcy5SRUpFQ1RFRCkgewogICAgICAgIGhhbmRsZXJbMl0odGhpcy5fdmFsdWUpOwogICAgICB9CgogICAgICBoYW5kbGVyWzBdID0gdHJ1ZTsKICAgIH0pOwogIH07fQp9CgovKioKICogQ3JlYXRlcyBhbiBuZXcgUHJvbWlzZUJ1ZmZlciBvYmplY3Qgd2l0aCB0aGUgc3BlY2lmaWVkIGxpbWl0CiAqIEBwYXJhbSBsaW1pdCBtYXggbnVtYmVyIG9mIHByb21pc2VzIHRoYXQgY2FuIGJlIHN0b3JlZCBpbiB0aGUgYnVmZmVyCiAqLwpmdW5jdGlvbiBtYWtlUHJvbWlzZUJ1ZmZlcihsaW1pdCkgewogIGNvbnN0IGJ1ZmZlciA9IFtdOwoKICBmdW5jdGlvbiBpc1JlYWR5KCkgewogICAgcmV0dXJuIGxpbWl0ID09PSB1bmRlZmluZWQgfHwgYnVmZmVyLmxlbmd0aCA8IGxpbWl0OwogIH0KCiAgLyoqCiAgICogUmVtb3ZlIGEgcHJvbWlzZSBmcm9tIHRoZSBxdWV1ZS4KICAgKgogICAqIEBwYXJhbSB0YXNrIENhbiBiZSBhbnkgUHJvbWlzZUxpa2U8VD4KICAgKiBAcmV0dXJucyBSZW1vdmVkIHByb21pc2UuCiAgICovCiAgZnVuY3Rpb24gcmVtb3ZlKHRhc2spIHsKICAgIHJldHVybiBidWZmZXIuc3BsaWNlKGJ1ZmZlci5pbmRleE9mKHRhc2spLCAxKVswXTsKICB9CgogIC8qKgogICAqIEFkZCBhIHByb21pc2UgKHJlcHJlc2VudGluZyBhbiBpbi1mbGlnaHQgYWN0aW9uKSB0byB0aGUgcXVldWUsIGFuZCBzZXQgaXQgdG8gcmVtb3ZlIGl0c2VsZiBvbiBmdWxmaWxsbWVudC4KICAgKgogICAqIEBwYXJhbSB0YXNrUHJvZHVjZXIgQSBmdW5jdGlvbiBwcm9kdWNpbmcgYW55IFByb21pc2VMaWtlPFQ+OyBJbiBwcmV2aW91cyB2ZXJzaW9ucyB0aGlzIHVzZWQgdG8gYmUgYHRhc2s6CiAgICogICAgICAgIFByb21pc2VMaWtlPFQ+YCwgYnV0IHVuZGVyIHRoYXQgbW9kZWwsIFByb21pc2VzIHdlcmUgaW5zdGFudGx5IGNyZWF0ZWQgb24gdGhlIGNhbGwtc2l0ZSBhbmQgdGhlaXIgZXhlY3V0b3IKICAgKiAgICAgICAgZnVuY3Rpb25zIHRoZXJlZm9yZSByYW4gaW1tZWRpYXRlbHkuIFRodXMsIGV2ZW4gaWYgdGhlIGJ1ZmZlciB3YXMgZnVsbCwgdGhlIGFjdGlvbiBzdGlsbCBoYXBwZW5lZC4gQnkKICAgKiAgICAgICAgcmVxdWlyaW5nIHRoZSBwcm9taXNlIHRvIGJlIHdyYXBwZWQgaW4gYSBmdW5jdGlvbiwgd2UgY2FuIGRlZmVyIHByb21pc2UgY3JlYXRpb24gdW50aWwgYWZ0ZXIgdGhlIGJ1ZmZlcgogICAqICAgICAgICBsaW1pdCBjaGVjay4KICAgKiBAcmV0dXJucyBUaGUgb3JpZ2luYWwgcHJvbWlzZS4KICAgKi8KICBmdW5jdGlvbiBhZGQodGFza1Byb2R1Y2VyKSB7CiAgICBpZiAoIWlzUmVhZHkoKSkgewogICAgICByZXR1cm4gcmVqZWN0ZWRTeW5jUHJvbWlzZShuZXcgU2VudHJ5RXJyb3IoJ05vdCBhZGRpbmcgUHJvbWlzZSBiZWNhdXNlIGJ1ZmZlciBsaW1pdCB3YXMgcmVhY2hlZC4nKSk7CiAgICB9CgogICAgLy8gc3RhcnQgdGhlIHRhc2sgYW5kIGFkZCBpdHMgcHJvbWlzZSB0byB0aGUgcXVldWUKICAgIGNvbnN0IHRhc2sgPSB0YXNrUHJvZHVjZXIoKTsKICAgIGlmIChidWZmZXIuaW5kZXhPZih0YXNrKSA9PT0gLTEpIHsKICAgICAgYnVmZmVyLnB1c2godGFzayk7CiAgICB9CiAgICB2b2lkIHRhc2sKICAgICAgLnRoZW4oKCkgPT4gcmVtb3ZlKHRhc2spKQogICAgICAvLyBVc2UgYHRoZW4obnVsbCwgcmVqZWN0aW9uSGFuZGxlcilgIHJhdGhlciB0aGFuIGBjYXRjaChyZWplY3Rpb25IYW5kbGVyKWAgc28gdGhhdCB3ZSBjYW4gdXNlIGBQcm9taXNlTGlrZWAKICAgICAgLy8gcmF0aGVyIHRoYW4gYFByb21pc2VgLiBgUHJvbWlzZUxpa2VgIGRvZXNuJ3QgaGF2ZSBhIGAuY2F0Y2hgIG1ldGhvZCwgbWFraW5nIGl0cyBwb2x5ZmlsbCBzbWFsbGVyLiAoRVM1IGRpZG4ndAogICAgICAvLyBoYXZlIHByb21pc2VzLCBzbyBUUyBoYXMgdG8gcG9seWZpbGwgd2hlbiBkb3duLWNvbXBpbGluZy4pCiAgICAgIC50aGVuKG51bGwsICgpID0+CiAgICAgICAgcmVtb3ZlKHRhc2spLnRoZW4obnVsbCwgKCkgPT4gewogICAgICAgICAgLy8gV2UgaGF2ZSB0byBhZGQgYW5vdGhlciBjYXRjaCBoZXJlIGJlY2F1c2UgYHJlbW92ZSgpYCBzdGFydHMgYSBuZXcgcHJvbWlzZSBjaGFpbi4KICAgICAgICB9KSwKICAgICAgKTsKICAgIHJldHVybiB0YXNrOwogIH0KCiAgLyoqCiAgICogV2FpdCBmb3IgYWxsIHByb21pc2VzIGluIHRoZSBxdWV1ZSB0byByZXNvbHZlIG9yIGZvciB0aW1lb3V0IHRvIGV4cGlyZSwgd2hpY2hldmVyIGNvbWVzIGZpcnN0LgogICAqCiAgICogQHBhcmFtIHRpbWVvdXQgVGhlIHRpbWUsIGluIG1zLCBhZnRlciB3aGljaCB0byByZXNvbHZlIHRvIGBmYWxzZWAgaWYgdGhlIHF1ZXVlIGlzIHN0aWxsIG5vbi1lbXB0eS4gUGFzc2luZyBgMGAgKG9yCiAgICogbm90IHBhc3NpbmcgYW55dGhpbmcpIHdpbGwgbWFrZSB0aGUgcHJvbWlzZSB3YWl0IGFzIGxvbmcgYXMgaXQgdGFrZXMgZm9yIHRoZSBxdWV1ZSB0byBkcmFpbiBiZWZvcmUgcmVzb2x2aW5nIHRvCiAgICogYHRydWVgLgogICAqIEByZXR1cm5zIEEgcHJvbWlzZSB3aGljaCB3aWxsIHJlc29sdmUgdG8gYHRydWVgIGlmIHRoZSBxdWV1ZSBpcyBhbHJlYWR5IGVtcHR5IG9yIGRyYWlucyBiZWZvcmUgdGhlIHRpbWVvdXQsIGFuZAogICAqIGBmYWxzZWAgb3RoZXJ3aXNlCiAgICovCiAgZnVuY3Rpb24gZHJhaW4odGltZW91dCkgewogICAgcmV0dXJuIG5ldyBTeW5jUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7CiAgICAgIGxldCBjb3VudGVyID0gYnVmZmVyLmxlbmd0aDsKCiAgICAgIGlmICghY291bnRlcikgewogICAgICAgIHJldHVybiByZXNvbHZlKHRydWUpOwogICAgICB9CgogICAgICAvLyB3YWl0IGZvciBgdGltZW91dGAgbXMgYW5kIHRoZW4gcmVzb2x2ZSB0byBgZmFsc2VgIChpZiBub3QgY2FuY2VsbGVkIGZpcnN0KQogICAgICBjb25zdCBjYXB0dXJlZFNldFRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHsKICAgICAgICBpZiAodGltZW91dCAmJiB0aW1lb3V0ID4gMCkgewogICAgICAgICAgcmVzb2x2ZShmYWxzZSk7CiAgICAgICAgfQogICAgICB9LCB0aW1lb3V0KTsKCiAgICAgIC8vIGlmIGFsbCBwcm9taXNlcyByZXNvbHZlIGluIHRpbWUsIGNhbmNlbCB0aGUgdGltZXIgYW5kIHJlc29sdmUgdG8gYHRydWVgCiAgICAgIGJ1ZmZlci5mb3JFYWNoKGl0ZW0gPT4gewogICAgICAgIHZvaWQgcmVzb2x2ZWRTeW5jUHJvbWlzZShpdGVtKS50aGVuKCgpID0+IHsKICAgICAgICAgIGlmICghLS1jb3VudGVyKSB7CiAgICAgICAgICAgIGNsZWFyVGltZW91dChjYXB0dXJlZFNldFRpbWVvdXQpOwogICAgICAgICAgICByZXNvbHZlKHRydWUpOwogICAgICAgICAgfQogICAgICAgIH0sIHJlamVjdCk7CiAgICAgIH0pOwogICAgfSk7CiAgfQoKICByZXR1cm4gewogICAgJDogYnVmZmVyLAogICAgYWRkLAogICAgZHJhaW4sCiAgfTsKfQoKLyoqCiAqIFRoaXMgY29kZSB3YXMgb3JpZ2luYWxseSBjb3BpZWQgZnJvbSB0aGUgJ2Nvb2tpZWAgbW9kdWxlIGF0IHYwLjUuMCBhbmQgd2FzIHNpbXBsaWZpZWQgZm9yIG91ciB1c2UgY2FzZS4KICogaHR0cHM6Ly9naXRodWIuY29tL2pzaHR0cC9jb29raWUvYmxvYi9hMGM4NDE0N2FhYjYyNjZiZGIzOTk2Y2Y0MDYyZTkzOTA3YzBiMGZjL2luZGV4LmpzCiAqIEl0IGhhZCB0aGUgZm9sbG93aW5nIGxpY2Vuc2U6CiAqCiAqIChUaGUgTUlUIExpY2Vuc2UpCiAqCiAqIENvcHlyaWdodCAoYykgMjAxMi0yMDE0IFJvbWFuIFNodHlsbWFuIDxzaHR5bG1hbkBnbWFpbC5jb20+CiAqIENvcHlyaWdodCAoYykgMjAxNSBEb3VnbGFzIENocmlzdG9waGVyIFdpbHNvbiA8ZG91Z0Bzb21ldGhpbmdkb3VnLmNvbT4KICoKICogUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nCiAqIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZQogKiAnU29mdHdhcmUnKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nCiAqIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwKICogZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvCiAqIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0bwogKiB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CiAqCiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlCiAqIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLgogKgogKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgJ0FTIElTJywgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwKICogRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GCiAqIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4KICogSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkKICogQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwKICogVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUKICogU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCiAqLwoKLyoqCiAqIFBhcnNlcyBhIGNvb2tpZSBzdHJpbmcKICovCmZ1bmN0aW9uIHBhcnNlQ29va2llKHN0cikgewogIGNvbnN0IG9iaiA9IHt9OwogIGxldCBpbmRleCA9IDA7CgogIHdoaWxlIChpbmRleCA8IHN0ci5sZW5ndGgpIHsKICAgIGNvbnN0IGVxSWR4ID0gc3RyLmluZGV4T2YoJz0nLCBpbmRleCk7CgogICAgLy8gbm8gbW9yZSBjb29raWUgcGFpcnMKICAgIGlmIChlcUlkeCA9PT0gLTEpIHsKICAgICAgYnJlYWs7CiAgICB9CgogICAgbGV0IGVuZElkeCA9IHN0ci5pbmRleE9mKCc7JywgaW5kZXgpOwoKICAgIGlmIChlbmRJZHggPT09IC0xKSB7CiAgICAgIGVuZElkeCA9IHN0ci5sZW5ndGg7CiAgICB9IGVsc2UgaWYgKGVuZElkeCA8IGVxSWR4KSB7CiAgICAgIC8vIGJhY2t0cmFjayBvbiBwcmlvciBzZW1pY29sb24KICAgICAgaW5kZXggPSBzdHIubGFzdEluZGV4T2YoJzsnLCBlcUlkeCAtIDEpICsgMTsKICAgICAgY29udGludWU7CiAgICB9CgogICAgY29uc3Qga2V5ID0gc3RyLnNsaWNlKGluZGV4LCBlcUlkeCkudHJpbSgpOwoKICAgIC8vIG9ubHkgYXNzaWduIG9uY2UKICAgIGlmICh1bmRlZmluZWQgPT09IG9ialtrZXldKSB7CiAgICAgIGxldCB2YWwgPSBzdHIuc2xpY2UoZXFJZHggKyAxLCBlbmRJZHgpLnRyaW0oKTsKCiAgICAgIC8vIHF1b3RlZCB2YWx1ZXMKICAgICAgaWYgKHZhbC5jaGFyQ29kZUF0KDApID09PSAweDIyKSB7CiAgICAgICAgdmFsID0gdmFsLnNsaWNlKDEsIC0xKTsKICAgICAgfQoKICAgICAgdHJ5IHsKICAgICAgICBvYmpba2V5XSA9IHZhbC5pbmRleE9mKCclJykgIT09IC0xID8gZGVjb2RlVVJJQ29tcG9uZW50KHZhbCkgOiB2YWw7CiAgICAgIH0gY2F0Y2ggKGUpIHsKICAgICAgICBvYmpba2V5XSA9IHZhbDsKICAgICAgfQogICAgfQoKICAgIGluZGV4ID0gZW5kSWR4ICsgMTsKICB9CgogIHJldHVybiBvYmo7Cn0KCi8qKgogKiBTdHJpcCB0aGUgcXVlcnkgc3RyaW5nIGFuZCBmcmFnbWVudCBvZmYgb2YgYSBnaXZlbiBVUkwgb3IgcGF0aCAoaWYgcHJlc2VudCkKICoKICogQHBhcmFtIHVybFBhdGggRnVsbCBVUkwgb3IgcGF0aCwgaW5jbHVkaW5nIHBvc3NpYmxlIHF1ZXJ5IHN0cmluZyBhbmQvb3IgZnJhZ21lbnQKICogQHJldHVybnMgVVJMIG9yIHBhdGggd2l0aG91dCBxdWVyeSBzdHJpbmcgb3IgZnJhZ21lbnQKICovCmZ1bmN0aW9uIHN0cmlwVXJsUXVlcnlBbmRGcmFnbWVudCh1cmxQYXRoKSB7CiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVzZWxlc3MtZXNjYXBlCiAgcmV0dXJuIHVybFBhdGguc3BsaXQoL1tcPyNdLywgMSlbMF07Cn0KCmNvbnN0IERFRkFVTFRfSU5DTFVERVMgPSB7CiAgaXA6IGZhbHNlLAogIHJlcXVlc3Q6IHRydWUsCiAgdHJhbnNhY3Rpb246IHRydWUsCiAgdXNlcjogdHJ1ZSwKfTsKY29uc3QgREVGQVVMVF9SRVFVRVNUX0lOQ0xVREVTID0gWydjb29raWVzJywgJ2RhdGEnLCAnaGVhZGVycycsICdtZXRob2QnLCAncXVlcnlfc3RyaW5nJywgJ3VybCddOwpjb25zdCBERUZBVUxUX1VTRVJfSU5DTFVERVMgPSBbJ2lkJywgJ3VzZXJuYW1lJywgJ2VtYWlsJ107CgovKioKICogRXh0cmFjdHMgYSBjb21wbGV0ZSBhbmQgcGFyYW1ldGVyaXplZCBwYXRoIGZyb20gdGhlIHJlcXVlc3Qgb2JqZWN0IGFuZCB1c2VzIGl0IHRvIGNvbnN0cnVjdCB0cmFuc2FjdGlvbiBuYW1lLgogKiBJZiB0aGUgcGFyYW1ldGVyaXplZCB0cmFuc2FjdGlvbiBuYW1lIGNhbm5vdCBiZSBleHRyYWN0ZWQsIHdlIGZhbGwgYmFjayB0byB0aGUgcmF3IFVSTC4KICoKICogQWRkaXRpb25hbGx5LCB0aGlzIGZ1bmN0aW9uIGRldGVybWluZXMgYW5kIHJldHVybnMgdGhlIHRyYW5zYWN0aW9uIG5hbWUgc291cmNlCiAqCiAqIGVnLiBHRVQgL21vdW50cG9pbnQvdXNlci86aWQKICoKICogQHBhcmFtIHJlcSBBIHJlcXVlc3Qgb2JqZWN0CiAqIEBwYXJhbSBvcHRpb25zIFdoYXQgdG8gaW5jbHVkZSBpbiB0aGUgdHJhbnNhY3Rpb24gbmFtZSAobWV0aG9kLCBwYXRoLCBvciBhIGN1c3RvbSByb3V0ZSBuYW1lIHRvIGJlCiAqICAgICAgICAgICAgICAgIHVzZWQgaW5zdGVhZCBvZiB0aGUgcmVxdWVzdCdzIHJvdXRlKQogKgogKiBAcmV0dXJucyBBIHR1cGxlIG9mIHRoZSBmdWxseSBjb25zdHJ1Y3RlZCB0cmFuc2FjdGlvbiBuYW1lIFswXSBhbmQgaXRzIHNvdXJjZSBbMV0gKGNhbiBiZSBlaXRoZXIgJ3JvdXRlJyBvciAndXJsJykKICovCmZ1bmN0aW9uIGV4dHJhY3RQYXRoRm9yVHJhbnNhY3Rpb24oCiAgcmVxLAogIG9wdGlvbnMgPSB7fSwKKSB7CiAgY29uc3QgbWV0aG9kID0gcmVxLm1ldGhvZCAmJiByZXEubWV0aG9kLnRvVXBwZXJDYXNlKCk7CgogIGxldCBwYXRoID0gJyc7CiAgbGV0IHNvdXJjZSA9ICd1cmwnOwoKICAvLyBDaGVjayB0byBzZWUgaWYgdGhlcmUncyBhIHBhcmFtZXRlcml6ZWQgcm91dGUgd2UgY2FuIHVzZSAoYXMgdGhlcmUgaXMgaW4gRXhwcmVzcykKICBpZiAob3B0aW9ucy5jdXN0b21Sb3V0ZSB8fCByZXEucm91dGUpIHsKICAgIHBhdGggPSBvcHRpb25zLmN1c3RvbVJvdXRlIHx8IGAke3JlcS5iYXNlVXJsIHx8ICcnfSR7cmVxLnJvdXRlICYmIHJlcS5yb3V0ZS5wYXRofWA7CiAgICBzb3VyY2UgPSAncm91dGUnOwogIH0KCiAgLy8gT3RoZXJ3aXNlLCBqdXN0IHRha2UgdGhlIG9yaWdpbmFsIFVSTAogIGVsc2UgaWYgKHJlcS5vcmlnaW5hbFVybCB8fCByZXEudXJsKSB7CiAgICBwYXRoID0gc3RyaXBVcmxRdWVyeUFuZEZyYWdtZW50KHJlcS5vcmlnaW5hbFVybCB8fCByZXEudXJsIHx8ICcnKTsKICB9CgogIGxldCBuYW1lID0gJyc7CiAgaWYgKG9wdGlvbnMubWV0aG9kICYmIG1ldGhvZCkgewogICAgbmFtZSArPSBtZXRob2Q7CiAgfQogIGlmIChvcHRpb25zLm1ldGhvZCAmJiBvcHRpb25zLnBhdGgpIHsKICAgIG5hbWUgKz0gJyAnOwogIH0KICBpZiAob3B0aW9ucy5wYXRoICYmIHBhdGgpIHsKICAgIG5hbWUgKz0gcGF0aDsKICB9CgogIHJldHVybiBbbmFtZSwgc291cmNlXTsKfQoKLyoqIEpTRG9jICovCmZ1bmN0aW9uIGV4dHJhY3RUcmFuc2FjdGlvbihyZXEsIHR5cGUpIHsKICBzd2l0Y2ggKHR5cGUpIHsKICAgIGNhc2UgJ3BhdGgnOiB7CiAgICAgIHJldHVybiBleHRyYWN0UGF0aEZvclRyYW5zYWN0aW9uKHJlcSwgeyBwYXRoOiB0cnVlIH0pWzBdOwogICAgfQogICAgY2FzZSAnaGFuZGxlcic6IHsKICAgICAgcmV0dXJuIChyZXEucm91dGUgJiYgcmVxLnJvdXRlLnN0YWNrICYmIHJlcS5yb3V0ZS5zdGFja1swXSAmJiByZXEucm91dGUuc3RhY2tbMF0ubmFtZSkgfHwgJzxhbm9ueW1vdXM+JzsKICAgIH0KICAgIGNhc2UgJ21ldGhvZFBhdGgnOgogICAgZGVmYXVsdDogewogICAgICAvLyBpZiBleGlzdCBfcmVjb25zdHJ1Y3RlZFJvdXRlIHJldHVybiB0aGF0IHBhdGggaW5zdGVhZCBvZiByb3V0ZS5wYXRoCiAgICAgIGNvbnN0IGN1c3RvbVJvdXRlID0gcmVxLl9yZWNvbnN0cnVjdGVkUm91dGUgPyByZXEuX3JlY29uc3RydWN0ZWRSb3V0ZSA6IHVuZGVmaW5lZDsKICAgICAgcmV0dXJuIGV4dHJhY3RQYXRoRm9yVHJhbnNhY3Rpb24ocmVxLCB7IHBhdGg6IHRydWUsIG1ldGhvZDogdHJ1ZSwgY3VzdG9tUm91dGUgfSlbMF07CiAgICB9CiAgfQp9CgovKiogSlNEb2MgKi8KZnVuY3Rpb24gZXh0cmFjdFVzZXJEYXRhKAogIHVzZXIKCiwKICBrZXlzLAopIHsKICBjb25zdCBleHRyYWN0ZWRVc2VyID0ge307CiAgY29uc3QgYXR0cmlidXRlcyA9IEFycmF5LmlzQXJyYXkoa2V5cykgPyBrZXlzIDogREVGQVVMVF9VU0VSX0lOQ0xVREVTOwoKICBhdHRyaWJ1dGVzLmZvckVhY2goa2V5ID0+IHsKICAgIGlmICh1c2VyICYmIGtleSBpbiB1c2VyKSB7CiAgICAgIGV4dHJhY3RlZFVzZXJba2V5XSA9IHVzZXJba2V5XTsKICAgIH0KICB9KTsKCiAgcmV0dXJuIGV4dHJhY3RlZFVzZXI7Cn0KCi8qKgogKiBOb3JtYWxpemUgZGF0YSBmcm9tIHRoZSByZXF1ZXN0IG9iamVjdCwgYWNjb3VudGluZyBmb3IgZnJhbWV3b3JrIGRpZmZlcmVuY2VzLgogKgogKiBAcGFyYW0gcmVxIFRoZSByZXF1ZXN0IG9iamVjdCBmcm9tIHdoaWNoIHRvIGV4dHJhY3QgZGF0YQogKiBAcGFyYW0gb3B0aW9ucy5pbmNsdWRlIEFuIG9wdGlvbmFsIGFycmF5IG9mIGtleXMgdG8gaW5jbHVkZSBpbiB0aGUgbm9ybWFsaXplZCBkYXRhLiBEZWZhdWx0cyB0bwogKiBERUZBVUxUX1JFUVVFU1RfSU5DTFVERVMgaWYgbm90IHByb3ZpZGVkLgogKiBAcGFyYW0gb3B0aW9ucy5kZXBzIEluamVjdGVkLCBwbGF0Zm9ybS1zcGVjaWZpYyBkZXBlbmRlbmNpZXMKICogQHJldHVybnMgQW4gb2JqZWN0IGNvbnRhaW5pbmcgbm9ybWFsaXplZCByZXF1ZXN0IGRhdGEKICovCmZ1bmN0aW9uIGV4dHJhY3RSZXF1ZXN0RGF0YSgKICByZXEsCiAgb3B0aW9ucwoKLAopIHsKICBjb25zdCB7IGluY2x1ZGUgPSBERUZBVUxUX1JFUVVFU1RfSU5DTFVERVMgfSA9IG9wdGlvbnMgfHwge307CiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkKICBjb25zdCByZXF1ZXN0RGF0YSA9IHt9OwoKICAvLyBoZWFkZXJzOgogIC8vICAgbm9kZSwgZXhwcmVzcywga29hLCBuZXh0anM6IHJlcS5oZWFkZXJzCiAgY29uc3QgaGVhZGVycyA9IChyZXEuaGVhZGVycyB8fCB7fSkKCjsKICAvLyBtZXRob2Q6CiAgLy8gICBub2RlLCBleHByZXNzLCBrb2EsIG5leHRqczogcmVxLm1ldGhvZAogIGNvbnN0IG1ldGhvZCA9IHJlcS5tZXRob2Q7CiAgLy8gaG9zdDoKICAvLyAgIGV4cHJlc3M6IHJlcS5ob3N0bmFtZSBpbiA+IDQgYW5kIHJlcS5ob3N0IGluIDwgNAogIC8vICAga29hOiByZXEuaG9zdAogIC8vICAgbm9kZSwgbmV4dGpzOiByZXEuaGVhZGVycy5ob3N0CiAgLy8gRXhwcmVzcyA0IG1pc3Rha2VubHkgc3RyaXBzIG9mZiBwb3J0IG51bWJlciBmcm9tIHJlcS5ob3N0IC8gcmVxLmhvc3RuYW1lIHNvIHdlIGNhbid0IHJlbHkgb24gdGhlbQogIC8vIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL2V4cHJlc3Nqcy9leHByZXNzL2lzc3Vlcy8zMDQ3I2lzc3VlY29tbWVudC0yMzY2NTMyMjMKICAvLyBBbHNvOiBodHRwczovL2dpdGh1Yi5jb20vZ2V0c2VudHJ5L3NlbnRyeS1qYXZhc2NyaXB0L2lzc3Vlcy8xOTE3CiAgY29uc3QgaG9zdCA9IGhlYWRlcnMuaG9zdCB8fCByZXEuaG9zdG5hbWUgfHwgcmVxLmhvc3QgfHwgJzxubyBob3N0Pic7CiAgLy8gcHJvdG9jb2w6CiAgLy8gICBub2RlLCBuZXh0anM6IDxuL2E+CiAgLy8gICBleHByZXNzLCBrb2E6IHJlcS5wcm90b2NvbAogIGNvbnN0IHByb3RvY29sID0gcmVxLnByb3RvY29sID09PSAnaHR0cHMnIHx8IChyZXEuc29ja2V0ICYmIHJlcS5zb2NrZXQuZW5jcnlwdGVkKSA/ICdodHRwcycgOiAnaHR0cCc7CiAgLy8gdXJsIChpbmNsdWRpbmcgcGF0aCBhbmQgcXVlcnkgc3RyaW5nKToKICAvLyAgIG5vZGUsIGV4cHJlc3M6IHJlcS5vcmlnaW5hbFVybAogIC8vICAga29hLCBuZXh0anM6IHJlcS51cmwKICBjb25zdCBvcmlnaW5hbFVybCA9IHJlcS5vcmlnaW5hbFVybCB8fCByZXEudXJsIHx8ICcnOwogIC8vIGFic29sdXRlIHVybAogIGNvbnN0IGFic29sdXRlVXJsID0gb3JpZ2luYWxVcmwuc3RhcnRzV2l0aChwcm90b2NvbCkgPyBvcmlnaW5hbFVybCA6IGAke3Byb3RvY29sfTovLyR7aG9zdH0ke29yaWdpbmFsVXJsfWA7CiAgaW5jbHVkZS5mb3JFYWNoKGtleSA9PiB7CiAgICBzd2l0Y2ggKGtleSkgewogICAgICBjYXNlICdoZWFkZXJzJzogewogICAgICAgIHJlcXVlc3REYXRhLmhlYWRlcnMgPSBoZWFkZXJzOwoKICAgICAgICAvLyBSZW1vdmUgdGhlIENvb2tpZSBoZWFkZXIgaW4gY2FzZSBjb29raWUgZGF0YSBzaG91bGQgbm90IGJlIGluY2x1ZGVkIGluIHRoZSBldmVudAogICAgICAgIGlmICghaW5jbHVkZS5pbmNsdWRlcygnY29va2llcycpKSB7CiAgICAgICAgICBkZWxldGUgKHJlcXVlc3REYXRhLmhlYWRlcnMgKS5jb29raWU7CiAgICAgICAgfQoKICAgICAgICBicmVhazsKICAgICAgfQogICAgICBjYXNlICdtZXRob2QnOiB7CiAgICAgICAgcmVxdWVzdERhdGEubWV0aG9kID0gbWV0aG9kOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICAgIGNhc2UgJ3VybCc6IHsKICAgICAgICByZXF1ZXN0RGF0YS51cmwgPSBhYnNvbHV0ZVVybDsKICAgICAgICBicmVhazsKICAgICAgfQogICAgICBjYXNlICdjb29raWVzJzogewogICAgICAgIC8vIGNvb2tpZXM6CiAgICAgICAgLy8gICBub2RlLCBleHByZXNzLCBrb2E6IHJlcS5oZWFkZXJzLmNvb2tpZQogICAgICAgIC8vICAgdmVyY2VsLCBzYWlscy5qcywgZXhwcmVzcyAody8gY29va2llIG1pZGRsZXdhcmUpLCBuZXh0anM6IHJlcS5jb29raWVzCiAgICAgICAgcmVxdWVzdERhdGEuY29va2llcyA9CiAgICAgICAgICAvLyBUT0RPICh2OCAvICM1MjU3KTogV2UncmUgb25seSBzZW5kaW5nIHRoZSBlbXB0eSBvYmplY3QgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5LCBzbyB0aGUgbGFzdCBiaXQgY2FuCiAgICAgICAgICAvLyBjb21lIG9mZiBpbiB2OAogICAgICAgICAgcmVxLmNvb2tpZXMgfHwgKGhlYWRlcnMuY29va2llICYmIHBhcnNlQ29va2llKGhlYWRlcnMuY29va2llKSkgfHwge307CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgICAgY2FzZSAncXVlcnlfc3RyaW5nJzogewogICAgICAgIC8vIHF1ZXJ5IHN0cmluZzoKICAgICAgICAvLyAgIG5vZGU6IHJlcS51cmwgKHJhdykKICAgICAgICAvLyAgIGV4cHJlc3MsIGtvYSwgbmV4dGpzOiByZXEucXVlcnkKICAgICAgICByZXF1ZXN0RGF0YS5xdWVyeV9zdHJpbmcgPSBleHRyYWN0UXVlcnlQYXJhbXMocmVxKTsKICAgICAgICBicmVhazsKICAgICAgfQogICAgICBjYXNlICdkYXRhJzogewogICAgICAgIGlmIChtZXRob2QgPT09ICdHRVQnIHx8IG1ldGhvZCA9PT0gJ0hFQUQnKSB7CiAgICAgICAgICBicmVhazsKICAgICAgICB9CiAgICAgICAgLy8gYm9keSBkYXRhOgogICAgICAgIC8vICAgZXhwcmVzcywga29hLCBuZXh0anM6IHJlcS5ib2R5CiAgICAgICAgLy8KICAgICAgICAvLyAgIHdoZW4gdXNpbmcgbm9kZSBieSBpdHNlbGYsIHlvdSBoYXZlIHRvIHJlYWQgdGhlIGluY29taW5nIHN0cmVhbShzZWUKICAgICAgICAvLyAgIGh0dHBzOi8vbm9kZWpzLmRldi9sZWFybi9nZXQtaHR0cC1yZXF1ZXN0LWJvZHktZGF0YS11c2luZy1ub2RlanMpOyBpZiBhIHVzZXIgaXMgZG9pbmcgdGhhdCwgd2UgY2FuJ3Qga25vdwogICAgICAgIC8vICAgd2hlcmUgdGhleSdyZSBnb2luZyB0byBzdG9yZSB0aGUgZmluYWwgcmVzdWx0LCBzbyB0aGV5J2xsIGhhdmUgdG8gY2FwdHVyZSB0aGlzIGRhdGEgdGhlbXNlbHZlcwogICAgICAgIGlmIChyZXEuYm9keSAhPT0gdW5kZWZpbmVkKSB7CiAgICAgICAgICByZXF1ZXN0RGF0YS5kYXRhID0gaXNTdHJpbmcocmVxLmJvZHkpID8gcmVxLmJvZHkgOiBKU09OLnN0cmluZ2lmeShub3JtYWxpemUocmVxLmJvZHkpKTsKICAgICAgICB9CiAgICAgICAgYnJlYWs7CiAgICAgIH0KICAgICAgZGVmYXVsdDogewogICAgICAgIGlmICh7fS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHJlcSwga2V5KSkgewogICAgICAgICAgcmVxdWVzdERhdGFba2V5XSA9IChyZXEgKVtrZXldOwogICAgICAgIH0KICAgICAgfQogICAgfQogIH0pOwoKICByZXR1cm4gcmVxdWVzdERhdGE7Cn0KCi8qKgogKiBBZGQgZGF0YSBmcm9tIHRoZSBnaXZlbiByZXF1ZXN0IHRvIHRoZSBnaXZlbiBldmVudAogKgogKiBAcGFyYW0gZXZlbnQgVGhlIGV2ZW50IHRvIHdoaWNoIHRoZSByZXF1ZXN0IGRhdGEgd2lsbCBiZSBhZGRlZAogKiBAcGFyYW0gcmVxIFJlcXVlc3Qgb2JqZWN0CiAqIEBwYXJhbSBvcHRpb25zLmluY2x1ZGUgRmxhZ3MgdG8gY29udHJvbCB3aGF0IGRhdGEgaXMgaW5jbHVkZWQKICogQHBhcmFtIG9wdGlvbnMuZGVwcyBJbmplY3RlZCBwbGF0Zm9ybS1zcGVjaWZpYyBkZXBlbmRlbmNpZXMKICogQHJldHVybnMgVGhlIG11dGF0ZWQgYEV2ZW50YCBvYmplY3QKICovCmZ1bmN0aW9uIGFkZFJlcXVlc3REYXRhVG9FdmVudCgKICBldmVudCwKICByZXEsCiAgb3B0aW9ucywKKSB7CiAgY29uc3QgaW5jbHVkZSA9IHsKICAgIC4uLkRFRkFVTFRfSU5DTFVERVMsCiAgICAuLi4ob3B0aW9ucyAmJiBvcHRpb25zLmluY2x1ZGUpLAogIH07CgogIGlmIChpbmNsdWRlLnJlcXVlc3QpIHsKICAgIGNvbnN0IGV4dHJhY3RlZFJlcXVlc3REYXRhID0gQXJyYXkuaXNBcnJheShpbmNsdWRlLnJlcXVlc3QpCiAgICAgID8gZXh0cmFjdFJlcXVlc3REYXRhKHJlcSwgeyBpbmNsdWRlOiBpbmNsdWRlLnJlcXVlc3QgfSkKICAgICAgOiBleHRyYWN0UmVxdWVzdERhdGEocmVxKTsKCiAgICBldmVudC5yZXF1ZXN0ID0gewogICAgICAuLi5ldmVudC5yZXF1ZXN0LAogICAgICAuLi5leHRyYWN0ZWRSZXF1ZXN0RGF0YSwKICAgIH07CiAgfQoKICBpZiAoaW5jbHVkZS51c2VyKSB7CiAgICBjb25zdCBleHRyYWN0ZWRVc2VyID0gcmVxLnVzZXIgJiYgaXNQbGFpbk9iamVjdChyZXEudXNlcikgPyBleHRyYWN0VXNlckRhdGEocmVxLnVzZXIsIGluY2x1ZGUudXNlcikgOiB7fTsKCiAgICBpZiAoT2JqZWN0LmtleXMoZXh0cmFjdGVkVXNlcikubGVuZ3RoKSB7CiAgICAgIGV2ZW50LnVzZXIgPSB7CiAgICAgICAgLi4uZXZlbnQudXNlciwKICAgICAgICAuLi5leHRyYWN0ZWRVc2VyLAogICAgICB9OwogICAgfQogIH0KCiAgLy8gY2xpZW50IGlwOgogIC8vICAgbm9kZSwgbmV4dGpzOiByZXEuc29ja2V0LnJlbW90ZUFkZHJlc3MKICAvLyAgIGV4cHJlc3MsIGtvYTogcmVxLmlwCiAgaWYgKGluY2x1ZGUuaXApIHsKICAgIGNvbnN0IGlwID0gcmVxLmlwIHx8IChyZXEuc29ja2V0ICYmIHJlcS5zb2NrZXQucmVtb3RlQWRkcmVzcyk7CiAgICBpZiAoaXApIHsKICAgICAgZXZlbnQudXNlciA9IHsKICAgICAgICAuLi5ldmVudC51c2VyLAogICAgICAgIGlwX2FkZHJlc3M6IGlwLAogICAgICB9OwogICAgfQogIH0KCiAgaWYgKGluY2x1ZGUudHJhbnNhY3Rpb24gJiYgIWV2ZW50LnRyYW5zYWN0aW9uKSB7CiAgICAvLyBUT0RPIGRvIHdlIGV2ZW4gbmVlZCB0aGlzIGFueW1vcmU/CiAgICAvLyBUT0RPIG1ha2UgdGhpcyB3b3JrIGZvciBuZXh0anMKICAgIGV2ZW50LnRyYW5zYWN0aW9uID0gZXh0cmFjdFRyYW5zYWN0aW9uKHJlcSwgaW5jbHVkZS50cmFuc2FjdGlvbik7CiAgfQoKICByZXR1cm4gZXZlbnQ7Cn0KCmZ1bmN0aW9uIGV4dHJhY3RRdWVyeVBhcmFtcyhyZXEpIHsKICAvLyB1cmwgKGluY2x1ZGluZyBwYXRoIGFuZCBxdWVyeSBzdHJpbmcpOgogIC8vICAgbm9kZSwgZXhwcmVzczogcmVxLm9yaWdpbmFsVXJsCiAgLy8gICBrb2EsIG5leHRqczogcmVxLnVybAogIGxldCBvcmlnaW5hbFVybCA9IHJlcS5vcmlnaW5hbFVybCB8fCByZXEudXJsIHx8ICcnOwoKICBpZiAoIW9yaWdpbmFsVXJsKSB7CiAgICByZXR1cm47CiAgfQoKICAvLyBUaGUgYFVSTGAgY29uc3RydWN0b3IgY2FuJ3QgaGFuZGxlIGludGVybmFsIFVSTHMgb2YgdGhlIGZvcm0gYC9zb21lL3BhdGgvaGVyZWAsIHNvIHN0aWNrIGEgZHVtbXkgcHJvdG9jb2wgYW5kCiAgLy8gaG9zdG5hbWUgb24gdGhlIGJlZ2lubmluZy4gU2luY2UgdGhlIHBvaW50IGhlcmUgaXMganVzdCB0byBncmFiIHRoZSBxdWVyeSBzdHJpbmcsIGl0IGRvZXNuJ3QgbWF0dGVyIHdoYXQgd2UgdXNlLgogIGlmIChvcmlnaW5hbFVybC5zdGFydHNXaXRoKCcvJykpIHsKICAgIG9yaWdpbmFsVXJsID0gYGh0dHA6Ly9kb2dzLmFyZS5ncmVhdCR7b3JpZ2luYWxVcmx9YDsKICB9CgogIHRyeSB7CiAgICBjb25zdCBxdWVyeVBhcmFtcyA9IHJlcS5xdWVyeSB8fCBuZXcgVVJMKG9yaWdpbmFsVXJsKS5zZWFyY2guc2xpY2UoMSk7CiAgICByZXR1cm4gcXVlcnlQYXJhbXMubGVuZ3RoID8gcXVlcnlQYXJhbXMgOiB1bmRlZmluZWQ7CiAgfSBjYXRjaCAoZTIpIHsKICAgIHJldHVybiB1bmRlZmluZWQ7CiAgfQp9CgovKioKICogRG9lcyB0aGlzIGZpbGVuYW1lIGxvb2sgbGlrZSBpdCdzIHBhcnQgb2YgdGhlIGFwcCBjb2RlPwogKi8KZnVuY3Rpb24gZmlsZW5hbWVJc0luQXBwKGZpbGVuYW1lLCBpc05hdGl2ZSA9IGZhbHNlKSB7CiAgY29uc3QgaXNJbnRlcm5hbCA9CiAgICBpc05hdGl2ZSB8fAogICAgKGZpbGVuYW1lICYmCiAgICAgIC8vIEl0J3Mgbm90IGludGVybmFsIGlmIGl0J3MgYW4gYWJzb2x1dGUgbGludXggcGF0aAogICAgICAhZmlsZW5hbWUuc3RhcnRzV2l0aCgnLycpICYmCiAgICAgIC8vIEl0J3Mgbm90IGludGVybmFsIGlmIGl0J3MgYW4gYWJzb2x1dGUgd2luZG93cyBwYXRoCiAgICAgICFmaWxlbmFtZS5tYXRjaCgvXltBLVpdOi8pICYmCiAgICAgIC8vIEl0J3Mgbm90IGludGVybmFsIGlmIHRoZSBwYXRoIGlzIHN0YXJ0aW5nIHdpdGggYSBkb3QKICAgICAgIWZpbGVuYW1lLnN0YXJ0c1dpdGgoJy4nKSAmJgogICAgICAvLyBJdCdzIG5vdCBpbnRlcm5hbCBpZiB0aGUgZnJhbWUgaGFzIGEgcHJvdG9jb2wuIEluIG5vZGUsIHRoaXMgaXMgdXN1YWxseSB0aGUgY2FzZSBpZiB0aGUgZmlsZSBnb3QgcHJlLXByb2Nlc3NlZCB3aXRoIGEgYnVuZGxlciBsaWtlIHdlYnBhY2sKICAgICAgIWZpbGVuYW1lLm1hdGNoKC9eW2EtekEtWl0oW2EtekEtWjAtOS5cLStdKSo6XC9cLy8pKTsgLy8gU2NoZW1hIGZyb206IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zNjQxNzgyCgogIC8vIGluX2FwcCBpcyBhbGwgdGhhdCdzIG5vdCBhbiBpbnRlcm5hbCBOb2RlIGZ1bmN0aW9uIG9yIGEgbW9kdWxlIHdpdGhpbiBub2RlX21vZHVsZXMKICAvLyBub3RlIHRoYXQgaXNOYXRpdmUgYXBwZWFycyB0byByZXR1cm4gdHJ1ZSBldmVuIGZvciBub2RlIGNvcmUgbGlicmFyaWVzCiAgLy8gc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9nZXRzZW50cnkvcmF2ZW4tbm9kZS9pc3N1ZXMvMTc2CgogIHJldHVybiAhaXNJbnRlcm5hbCAmJiBmaWxlbmFtZSAhPT0gdW5kZWZpbmVkICYmICFmaWxlbmFtZS5pbmNsdWRlcygnbm9kZV9tb2R1bGVzLycpOwp9Cgpjb25zdCBPTkVfU0VDT05EX0lOX01TID0gMTAwMDsKCi8qKgogKiBBIHBhcnRpYWwgZGVmaW5pdGlvbiBvZiB0aGUgW1BlcmZvcm1hbmNlIFdlYiBBUElde0BsaW5rIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9QZXJmb3JtYW5jZX0KICogZm9yIGFjY2Vzc2luZyBhIGhpZ2gtcmVzb2x1dGlvbiBtb25vdG9uaWMgY2xvY2suCiAqLwoKLyoqCiAqIFJldHVybnMgYSB0aW1lc3RhbXAgaW4gc2Vjb25kcyBzaW5jZSB0aGUgVU5JWCBlcG9jaCB1c2luZyB0aGUgRGF0ZSBBUEkuCiAqCiAqIFRPRE8odjgpOiBSZXR1cm4gdHlwZSBzaG91bGQgYmUgcm91bmRlZC4KICovCmZ1bmN0aW9uIGRhdGVUaW1lc3RhbXBJblNlY29uZHMoKSB7CiAgcmV0dXJuIERhdGUubm93KCkgLyBPTkVfU0VDT05EX0lOX01TOwp9CgovKioKICogUmV0dXJucyBhIHdyYXBwZXIgYXJvdW5kIHRoZSBuYXRpdmUgUGVyZm9ybWFuY2UgQVBJIGJyb3dzZXIgaW1wbGVtZW50YXRpb24sIG9yIHVuZGVmaW5lZCBmb3IgYnJvd3NlcnMgdGhhdCBkbyBub3QKICogc3VwcG9ydCB0aGUgQVBJLgogKgogKiBXcmFwcGluZyB0aGUgbmF0aXZlIEFQSSB3b3JrcyBhcm91bmQgZGlmZmVyZW5jZXMgaW4gYmVoYXZpb3IgZnJvbSBkaWZmZXJlbnQgYnJvd3NlcnMuCiAqLwpmdW5jdGlvbiBjcmVhdGVVbml4VGltZXN0YW1wSW5TZWNvbmRzRnVuYygpIHsKICBjb25zdCB7IHBlcmZvcm1hbmNlIH0gPSBHTE9CQUxfT0JKIDsKICBpZiAoIXBlcmZvcm1hbmNlIHx8ICFwZXJmb3JtYW5jZS5ub3cpIHsKICAgIHJldHVybiBkYXRlVGltZXN0YW1wSW5TZWNvbmRzOwogIH0KCiAgLy8gU29tZSBicm93c2VyIGFuZCBlbnZpcm9ubWVudHMgZG9uJ3QgaGF2ZSBhIHRpbWVPcmlnaW4sIHNvIHdlIGZhbGxiYWNrIHRvCiAgLy8gdXNpbmcgRGF0ZS5ub3coKSB0byBjb21wdXRlIHRoZSBzdGFydGluZyB0aW1lLgogIGNvbnN0IGFwcHJveFN0YXJ0aW5nVGltZU9yaWdpbiA9IERhdGUubm93KCkgLSBwZXJmb3JtYW5jZS5ub3coKTsKICBjb25zdCB0aW1lT3JpZ2luID0gcGVyZm9ybWFuY2UudGltZU9yaWdpbiA9PSB1bmRlZmluZWQgPyBhcHByb3hTdGFydGluZ1RpbWVPcmlnaW4gOiBwZXJmb3JtYW5jZS50aW1lT3JpZ2luOwoKICAvLyBwZXJmb3JtYW5jZS5ub3coKSBpcyBhIG1vbm90b25pYyBjbG9jaywgd2hpY2ggbWVhbnMgaXQgc3RhcnRzIGF0IDAgd2hlbiB0aGUgcHJvY2VzcyBiZWdpbnMuIFRvIGdldCB0aGUgY3VycmVudAogIC8vIHdhbGwgY2xvY2sgdGltZSAoYWN0dWFsIFVOSVggdGltZXN0YW1wKSwgd2UgbmVlZCB0byBhZGQgdGhlIHN0YXJ0aW5nIHRpbWUgb3JpZ2luIGFuZCB0aGUgY3VycmVudCB0aW1lIGVsYXBzZWQuCiAgLy8KICAvLyBUT0RPOiBUaGlzIGRvZXMgbm90IGFjY291bnQgZm9yIHRoZSBjYXNlIHdoZXJlIHRoZSBtb25vdG9uaWMgY2xvY2sgdGhhdCBwb3dlcnMgcGVyZm9ybWFuY2Uubm93KCkgZHJpZnRzIGZyb20gdGhlCiAgLy8gd2FsbCBjbG9jayB0aW1lLCB3aGljaCBjYXVzZXMgdGhlIHJldHVybmVkIHRpbWVzdGFtcCB0byBiZSBpbmFjY3VyYXRlLiBXZSBzaG91bGQgaW52ZXN0aWdhdGUgaG93IHRvIGRldGVjdCBhbmQKICAvLyBjb3JyZWN0IGZvciB0aGlzLgogIC8vIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdC9pc3N1ZXMvMjU5MAogIC8vIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL21kbi9jb250ZW50L2lzc3Vlcy80NzEzCiAgLy8gU2VlOiBodHRwczovL2Rldi50by9ub2Ftci93aGVuLWEtbWlsbGlzZWNvbmQtaXMtbm90LWEtbWlsbGlzZWNvbmQtM2g2CiAgcmV0dXJuICgpID0+IHsKICAgIHJldHVybiAodGltZU9yaWdpbiArIHBlcmZvcm1hbmNlLm5vdygpKSAvIE9ORV9TRUNPTkRfSU5fTVM7CiAgfTsKfQoKLyoqCiAqIFJldHVybnMgYSB0aW1lc3RhbXAgaW4gc2Vjb25kcyBzaW5jZSB0aGUgVU5JWCBlcG9jaCB1c2luZyBlaXRoZXIgdGhlIFBlcmZvcm1hbmNlIG9yIERhdGUgQVBJcywgZGVwZW5kaW5nIG9uIHRoZQogKiBhdmFpbGFiaWxpdHkgb2YgdGhlIFBlcmZvcm1hbmNlIEFQSS4KICoKICogQlVHOiBOb3RlIHRoYXQgYmVjYXVzZSBvZiBob3cgYnJvd3NlcnMgaW1wbGVtZW50IHRoZSBQZXJmb3JtYW5jZSBBUEksIHRoZSBjbG9jayBtaWdodCBzdG9wIHdoZW4gdGhlIGNvbXB1dGVyIGlzCiAqIGFzbGVlcC4gVGhpcyBjcmVhdGVzIGEgc2tldyBiZXR3ZWVuIGBkYXRlVGltZXN0YW1wSW5TZWNvbmRzYCBhbmQgYHRpbWVzdGFtcEluU2Vjb25kc2AuIFRoZQogKiBza2V3IGNhbiBncm93IHRvIGFyYml0cmFyeSBhbW91bnRzIGxpa2UgZGF5cywgd2Vla3Mgb3IgbW9udGhzLgogKiBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdC9pc3N1ZXMvMjU5MC4KICovCmNvbnN0IHRpbWVzdGFtcEluU2Vjb25kcyA9IGNyZWF0ZVVuaXhUaW1lc3RhbXBJblNlY29uZHNGdW5jKCk7CgovKioKICogVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgc2luY2UgdGhlIFVOSVggZXBvY2guIFRoaXMgdmFsdWUgaXMgb25seSB1c2FibGUgaW4gYSBicm93c2VyLCBhbmQgb25seSB3aGVuIHRoZQogKiBwZXJmb3JtYW5jZSBBUEkgaXMgYXZhaWxhYmxlLgogKi8KKCgpID0+IHsKICAvLyBVbmZvcnR1bmF0ZWx5IGJyb3dzZXJzIG1heSByZXBvcnQgYW4gaW5hY2N1cmF0ZSB0aW1lIG9yaWdpbiBkYXRhLCB0aHJvdWdoIGVpdGhlciBwZXJmb3JtYW5jZS50aW1lT3JpZ2luIG9yCiAgLy8gcGVyZm9ybWFuY2UudGltaW5nLm5hdmlnYXRpb25TdGFydCwgd2hpY2ggcmVzdWx0cyBpbiBwb29yIHJlc3VsdHMgaW4gcGVyZm9ybWFuY2UgZGF0YS4gV2Ugb25seSB0cmVhdCB0aW1lIG9yaWdpbgogIC8vIGRhdGEgYXMgcmVsaWFibGUgaWYgdGhleSBhcmUgd2l0aGluIGEgcmVhc29uYWJsZSB0aHJlc2hvbGQgb2YgdGhlIGN1cnJlbnQgdGltZS4KCiAgY29uc3QgeyBwZXJmb3JtYW5jZSB9ID0gR0xPQkFMX09CSiA7CiAgaWYgKCFwZXJmb3JtYW5jZSB8fCAhcGVyZm9ybWFuY2Uubm93KSB7CiAgICByZXR1cm4gdW5kZWZpbmVkOwogIH0KCiAgY29uc3QgdGhyZXNob2xkID0gMzYwMCAqIDEwMDA7CiAgY29uc3QgcGVyZm9ybWFuY2VOb3cgPSBwZXJmb3JtYW5jZS5ub3coKTsKICBjb25zdCBkYXRlTm93ID0gRGF0ZS5ub3coKTsKCiAgLy8gaWYgdGltZU9yaWdpbiBpc24ndCBhdmFpbGFibGUgc2V0IGRlbHRhIHRvIHRocmVzaG9sZCBzbyBpdCBpc24ndCB1c2VkCiAgY29uc3QgdGltZU9yaWdpbkRlbHRhID0gcGVyZm9ybWFuY2UudGltZU9yaWdpbgogICAgPyBNYXRoLmFicyhwZXJmb3JtYW5jZS50aW1lT3JpZ2luICsgcGVyZm9ybWFuY2VOb3cgLSBkYXRlTm93KQogICAgOiB0aHJlc2hvbGQ7CiAgY29uc3QgdGltZU9yaWdpbklzUmVsaWFibGUgPSB0aW1lT3JpZ2luRGVsdGEgPCB0aHJlc2hvbGQ7CgogIC8vIFdoaWxlIHBlcmZvcm1hbmNlLnRpbWluZy5uYXZpZ2F0aW9uU3RhcnQgaXMgZGVwcmVjYXRlZCBpbiBmYXZvciBvZiBwZXJmb3JtYW5jZS50aW1lT3JpZ2luLCBwZXJmb3JtYW5jZS50aW1lT3JpZ2luCiAgLy8gaXMgbm90IGFzIHdpZGVseSBzdXBwb3J0ZWQuIE5hbWVseSwgcGVyZm9ybWFuY2UudGltZU9yaWdpbiBpcyB1bmRlZmluZWQgaW4gU2FmYXJpIGFzIG9mIHdyaXRpbmcuCiAgLy8gQWxzbyBhcyBvZiB3cml0aW5nLCBwZXJmb3JtYW5jZS50aW1pbmcgaXMgbm90IGF2YWlsYWJsZSBpbiBXZWIgV29ya2VycyBpbiBtYWluc3RyZWFtIGJyb3dzZXJzLCBzbyBpdCBpcyBub3QgYWx3YXlzCiAgLy8gYSB2YWxpZCBmYWxsYmFjay4gSW4gdGhlIGFic2VuY2Ugb2YgYW4gaW5pdGlhbCB0aW1lIHByb3ZpZGVkIGJ5IHRoZSBicm93c2VyLCBmYWxsYmFjayB0byB0aGUgY3VycmVudCB0aW1lIGZyb20gdGhlCiAgLy8gRGF0ZSBBUEkuCiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgY29uc3QgbmF2aWdhdGlvblN0YXJ0ID0gcGVyZm9ybWFuY2UudGltaW5nICYmIHBlcmZvcm1hbmNlLnRpbWluZy5uYXZpZ2F0aW9uU3RhcnQ7CiAgY29uc3QgaGFzTmF2aWdhdGlvblN0YXJ0ID0gdHlwZW9mIG5hdmlnYXRpb25TdGFydCA9PT0gJ251bWJlcic7CiAgLy8gaWYgbmF2aWdhdGlvblN0YXJ0IGlzbid0IGF2YWlsYWJsZSBzZXQgZGVsdGEgdG8gdGhyZXNob2xkIHNvIGl0IGlzbid0IHVzZWQKICBjb25zdCBuYXZpZ2F0aW9uU3RhcnREZWx0YSA9IGhhc05hdmlnYXRpb25TdGFydCA/IE1hdGguYWJzKG5hdmlnYXRpb25TdGFydCArIHBlcmZvcm1hbmNlTm93IC0gZGF0ZU5vdykgOiB0aHJlc2hvbGQ7CiAgY29uc3QgbmF2aWdhdGlvblN0YXJ0SXNSZWxpYWJsZSA9IG5hdmlnYXRpb25TdGFydERlbHRhIDwgdGhyZXNob2xkOwoKICBpZiAodGltZU9yaWdpbklzUmVsaWFibGUgfHwgbmF2aWdhdGlvblN0YXJ0SXNSZWxpYWJsZSkgewogICAgLy8gVXNlIHRoZSBtb3JlIHJlbGlhYmxlIHRpbWUgb3JpZ2luCiAgICBpZiAodGltZU9yaWdpbkRlbHRhIDw9IG5hdmlnYXRpb25TdGFydERlbHRhKSB7CiAgICAgIHJldHVybiBwZXJmb3JtYW5jZS50aW1lT3JpZ2luOwogICAgfSBlbHNlIHsKICAgICAgcmV0dXJuIG5hdmlnYXRpb25TdGFydDsKICAgIH0KICB9CiAgcmV0dXJuIGRhdGVOb3c7Cn0pKCk7CgovKioKICogQ3JlYXRlcyBhbiBlbnZlbG9wZS4KICogTWFrZSBzdXJlIHRvIGFsd2F5cyBleHBsaWNpdGx5IHByb3ZpZGUgdGhlIGdlbmVyaWMgdG8gdGhpcyBmdW5jdGlvbgogKiBzbyB0aGF0IHRoZSBlbnZlbG9wZSB0eXBlcyByZXNvbHZlIGNvcnJlY3RseS4KICovCmZ1bmN0aW9uIGNyZWF0ZUVudmVsb3BlKGhlYWRlcnMsIGl0ZW1zID0gW10pIHsKICByZXR1cm4gW2hlYWRlcnMsIGl0ZW1zXSA7Cn0KCi8qKgogKiBDb252ZW5pZW5jZSBmdW5jdGlvbiB0byBsb29wIHRocm91Z2ggdGhlIGl0ZW1zIGFuZCBpdGVtIHR5cGVzIG9mIGFuIGVudmVsb3BlLgogKiAoVGhpcyBmdW5jdGlvbiB3YXMgbW9zdGx5IGNyZWF0ZWQgYmVjYXVzZSB3b3JraW5nIHdpdGggZW52ZWxvcGUgdHlwZXMgaXMgcGFpbmZ1bCBhdCB0aGUgbW9tZW50KQogKgogKiBJZiB0aGUgY2FsbGJhY2sgcmV0dXJucyB0cnVlLCB0aGUgcmVzdCBvZiB0aGUgaXRlbXMgd2lsbCBiZSBza2lwcGVkLgogKi8KZnVuY3Rpb24gZm9yRWFjaEVudmVsb3BlSXRlbSgKICBlbnZlbG9wZSwKICBjYWxsYmFjaywKKSB7CiAgY29uc3QgZW52ZWxvcGVJdGVtcyA9IGVudmVsb3BlWzFdOwoKICBmb3IgKGNvbnN0IGVudmVsb3BlSXRlbSBvZiBlbnZlbG9wZUl0ZW1zKSB7CiAgICBjb25zdCBlbnZlbG9wZUl0ZW1UeXBlID0gZW52ZWxvcGVJdGVtWzBdLnR5cGU7CiAgICBjb25zdCByZXN1bHQgPSBjYWxsYmFjayhlbnZlbG9wZUl0ZW0sIGVudmVsb3BlSXRlbVR5cGUpOwoKICAgIGlmIChyZXN1bHQpIHsKICAgICAgcmV0dXJuIHRydWU7CiAgICB9CiAgfQoKICByZXR1cm4gZmFsc2U7Cn0KCi8qKgogKiBFbmNvZGUgYSBzdHJpbmcgdG8gVVRGOCBhcnJheS4KICovCmZ1bmN0aW9uIGVuY29kZVVURjgoaW5wdXQpIHsKICByZXR1cm4gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKGlucHV0KTsKfQoKLyoqCiAqIFNlcmlhbGl6ZXMgYW4gZW52ZWxvcGUuCiAqLwpmdW5jdGlvbiBzZXJpYWxpemVFbnZlbG9wZShlbnZlbG9wZSkgewogIGNvbnN0IFtlbnZIZWFkZXJzLCBpdGVtc10gPSBlbnZlbG9wZTsKCiAgLy8gSW5pdGlhbGx5IHdlIGNvbnN0cnVjdCBvdXIgZW52ZWxvcGUgYXMgYSBzdHJpbmcgYW5kIG9ubHkgY29udmVydCB0byBiaW5hcnkgY2h1bmtzIGlmIHdlIGVuY291bnRlciBiaW5hcnkgZGF0YQogIGxldCBwYXJ0cyA9IEpTT04uc3RyaW5naWZ5KGVudkhlYWRlcnMpOwoKICBmdW5jdGlvbiBhcHBlbmQobmV4dCkgewogICAgaWYgKHR5cGVvZiBwYXJ0cyA9PT0gJ3N0cmluZycpIHsKICAgICAgcGFydHMgPSB0eXBlb2YgbmV4dCA9PT0gJ3N0cmluZycgPyBwYXJ0cyArIG5leHQgOiBbZW5jb2RlVVRGOChwYXJ0cyksIG5leHRdOwogICAgfSBlbHNlIHsKICAgICAgcGFydHMucHVzaCh0eXBlb2YgbmV4dCA9PT0gJ3N0cmluZycgPyBlbmNvZGVVVEY4KG5leHQpIDogbmV4dCk7CiAgICB9CiAgfQoKICBmb3IgKGNvbnN0IGl0ZW0gb2YgaXRlbXMpIHsKICAgIGNvbnN0IFtpdGVtSGVhZGVycywgcGF5bG9hZF0gPSBpdGVtOwoKICAgIGFwcGVuZChgXG4ke0pTT04uc3RyaW5naWZ5KGl0ZW1IZWFkZXJzKX1cbmApOwoKICAgIGlmICh0eXBlb2YgcGF5bG9hZCA9PT0gJ3N0cmluZycgfHwgcGF5bG9hZCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpIHsKICAgICAgYXBwZW5kKHBheWxvYWQpOwogICAgfSBlbHNlIHsKICAgICAgbGV0IHN0cmluZ2lmaWVkUGF5bG9hZDsKICAgICAgdHJ5IHsKICAgICAgICBzdHJpbmdpZmllZFBheWxvYWQgPSBKU09OLnN0cmluZ2lmeShwYXlsb2FkKTsKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIC8vIEluIGNhc2UsIGRlc3BpdGUgYWxsIG91ciBlZmZvcnRzIHRvIGtlZXAgYHBheWxvYWRgIGNpcmN1bGFyLWRlcGVuZGVuY3ktZnJlZSwgYEpTT04uc3RyaW5pZnkoKWAgc3RpbGwKICAgICAgICAvLyBmYWlscywgd2UgdHJ5IGFnYWluIGFmdGVyIG5vcm1hbGl6aW5nIGl0IGFnYWluIHdpdGggaW5maW5pdGUgbm9ybWFsaXphdGlvbiBkZXB0aC4gVGhpcyBvZiBjb3Vyc2UgaGFzIGEKICAgICAgICAvLyBwZXJmb3JtYW5jZSBpbXBhY3QgYnV0IGluIHRoaXMgY2FzZSBhIHBlcmZvcm1hbmNlIGhpdCBpcyBiZXR0ZXIgdGhhbiB0aHJvd2luZy4KICAgICAgICBzdHJpbmdpZmllZFBheWxvYWQgPSBKU09OLnN0cmluZ2lmeShub3JtYWxpemUocGF5bG9hZCkpOwogICAgICB9CiAgICAgIGFwcGVuZChzdHJpbmdpZmllZFBheWxvYWQpOwogICAgfQogIH0KCiAgcmV0dXJuIHR5cGVvZiBwYXJ0cyA9PT0gJ3N0cmluZycgPyBwYXJ0cyA6IGNvbmNhdEJ1ZmZlcnMocGFydHMpOwp9CgpmdW5jdGlvbiBjb25jYXRCdWZmZXJzKGJ1ZmZlcnMpIHsKICBjb25zdCB0b3RhbExlbmd0aCA9IGJ1ZmZlcnMucmVkdWNlKChhY2MsIGJ1ZikgPT4gYWNjICsgYnVmLmxlbmd0aCwgMCk7CgogIGNvbnN0IG1lcmdlZCA9IG5ldyBVaW50OEFycmF5KHRvdGFsTGVuZ3RoKTsKICBsZXQgb2Zmc2V0ID0gMDsKICBmb3IgKGNvbnN0IGJ1ZmZlciBvZiBidWZmZXJzKSB7CiAgICBtZXJnZWQuc2V0KGJ1ZmZlciwgb2Zmc2V0KTsKICAgIG9mZnNldCArPSBidWZmZXIubGVuZ3RoOwogIH0KCiAgcmV0dXJuIG1lcmdlZDsKfQoKY29uc3QgSVRFTV9UWVBFX1RPX0RBVEFfQ0FURUdPUllfTUFQID0gewogIHNlc3Npb246ICdzZXNzaW9uJywKICBzZXNzaW9uczogJ3Nlc3Npb24nLAogIGF0dGFjaG1lbnQ6ICdhdHRhY2htZW50JywKICB0cmFuc2FjdGlvbjogJ3RyYW5zYWN0aW9uJywKICBldmVudDogJ2Vycm9yJywKICBjbGllbnRfcmVwb3J0OiAnaW50ZXJuYWwnLAogIHVzZXJfcmVwb3J0OiAnZGVmYXVsdCcsCiAgcHJvZmlsZTogJ3Byb2ZpbGUnLAogIHJlcGxheV9ldmVudDogJ3JlcGxheScsCiAgcmVwbGF5X3JlY29yZGluZzogJ3JlcGxheScsCiAgY2hlY2tfaW46ICdtb25pdG9yJywKICBmZWVkYmFjazogJ2ZlZWRiYWNrJywKICAvLyBUT0RPOiBUaGlzIGlzIGEgdGVtcG9yYXJ5IHdvcmthcm91bmQgdW50aWwgd2UgaGF2ZSBhIHByb3BlciBkYXRhIGNhdGVnb3J5IGZvciBtZXRyaWNzCiAgc3RhdHNkOiAndW5rbm93bicsCn07CgovKioKICogTWFwcyB0aGUgdHlwZSBvZiBhbiBlbnZlbG9wZSBpdGVtIHRvIGEgZGF0YSBjYXRlZ29yeS4KICovCmZ1bmN0aW9uIGVudmVsb3BlSXRlbVR5cGVUb0RhdGFDYXRlZ29yeSh0eXBlKSB7CiAgcmV0dXJuIElURU1fVFlQRV9UT19EQVRBX0NBVEVHT1JZX01BUFt0eXBlXTsKfQoKLyoqIEV4dHJhY3RzIHRoZSBtaW5pbWFsIFNESyBpbmZvIGZyb20gZnJvbSB0aGUgbWV0YWRhdGEgb3IgYW4gZXZlbnRzICovCmZ1bmN0aW9uIGdldFNka01ldGFkYXRhRm9yRW52ZWxvcGVIZWFkZXIobWV0YWRhdGFPckV2ZW50KSB7CiAgaWYgKCFtZXRhZGF0YU9yRXZlbnQgfHwgIW1ldGFkYXRhT3JFdmVudC5zZGspIHsKICAgIHJldHVybjsKICB9CiAgY29uc3QgeyBuYW1lLCB2ZXJzaW9uIH0gPSBtZXRhZGF0YU9yRXZlbnQuc2RrOwogIHJldHVybiB7IG5hbWUsIHZlcnNpb24gfTsKfQoKLyoqCiAqIENyZWF0ZXMgZXZlbnQgZW52ZWxvcGUgaGVhZGVycywgYmFzZWQgb24gZXZlbnQsIHNkayBpbmZvIGFuZCB0dW5uZWwKICogTm90ZTogVGhpcyBmdW5jdGlvbiB3YXMgZXh0cmFjdGVkIGZyb20gdGhlIGNvcmUgcGFja2FnZSB0byBtYWtlIGl0IGF2YWlsYWJsZSBpbiBSZXBsYXkKICovCmZ1bmN0aW9uIGNyZWF0ZUV2ZW50RW52ZWxvcGVIZWFkZXJzKAogIGV2ZW50LAogIHNka0luZm8sCiAgdHVubmVsLAogIGRzbiwKKSB7CiAgY29uc3QgZHluYW1pY1NhbXBsaW5nQ29udGV4dCA9IGV2ZW50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YSAmJiBldmVudC5zZGtQcm9jZXNzaW5nTWV0YWRhdGEuZHluYW1pY1NhbXBsaW5nQ29udGV4dDsKICByZXR1cm4gewogICAgZXZlbnRfaWQ6IGV2ZW50LmV2ZW50X2lkICwKICAgIHNlbnRfYXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSwKICAgIC4uLihzZGtJbmZvICYmIHsgc2RrOiBzZGtJbmZvIH0pLAogICAgLi4uKCEhdHVubmVsICYmIGRzbiAmJiB7IGRzbjogZHNuVG9TdHJpbmcoZHNuKSB9KSwKICAgIC4uLihkeW5hbWljU2FtcGxpbmdDb250ZXh0ICYmIHsKICAgICAgdHJhY2U6IGRyb3BVbmRlZmluZWRLZXlzKHsgLi4uZHluYW1pY1NhbXBsaW5nQ29udGV4dCB9KSwKICAgIH0pLAogIH07Cn0KCi8vIEludGVudGlvbmFsbHkga2VlcGluZyB0aGUga2V5IGJyb2FkLCBhcyB3ZSBkb24ndCBrbm93IGZvciBzdXJlIHdoYXQgcmF0ZSBsaW1pdCBoZWFkZXJzIGdldCByZXR1cm5lZCBmcm9tIGJhY2tlbmQKCmNvbnN0IERFRkFVTFRfUkVUUllfQUZURVIgPSA2MCAqIDEwMDA7IC8vIDYwIHNlY29uZHMKCi8qKgogKiBFeHRyYWN0cyBSZXRyeS1BZnRlciB2YWx1ZSBmcm9tIHRoZSByZXF1ZXN0IGhlYWRlciBvciByZXR1cm5zIGRlZmF1bHQgdmFsdWUKICogQHBhcmFtIGhlYWRlciBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgJ1JldHJ5LUFmdGVyJyBoZWFkZXIKICogQHBhcmFtIG5vdyBjdXJyZW50IHVuaXggdGltZXN0YW1wCiAqCiAqLwpmdW5jdGlvbiBwYXJzZVJldHJ5QWZ0ZXJIZWFkZXIoaGVhZGVyLCBub3cgPSBEYXRlLm5vdygpKSB7CiAgY29uc3QgaGVhZGVyRGVsYXkgPSBwYXJzZUludChgJHtoZWFkZXJ9YCwgMTApOwogIGlmICghaXNOYU4oaGVhZGVyRGVsYXkpKSB7CiAgICByZXR1cm4gaGVhZGVyRGVsYXkgKiAxMDAwOwogIH0KCiAgY29uc3QgaGVhZGVyRGF0ZSA9IERhdGUucGFyc2UoYCR7aGVhZGVyfWApOwogIGlmICghaXNOYU4oaGVhZGVyRGF0ZSkpIHsKICAgIHJldHVybiBoZWFkZXJEYXRlIC0gbm93OwogIH0KCiAgcmV0dXJuIERFRkFVTFRfUkVUUllfQUZURVI7Cn0KCi8qKgogKiBHZXRzIHRoZSB0aW1lIHRoYXQgdGhlIGdpdmVuIGNhdGVnb3J5IGlzIGRpc2FibGVkIHVudGlsIGZvciByYXRlIGxpbWl0aW5nLgogKiBJbiBjYXNlIG5vIGNhdGVnb3J5LXNwZWNpZmljIGxpbWl0IGlzIHNldCBidXQgYSBnZW5lcmFsIHJhdGUgbGltaXQgYWNyb3NzIGFsbCBjYXRlZ29yaWVzIGlzIGFjdGl2ZSwKICogdGhhdCB0aW1lIGlzIHJldHVybmVkLgogKgogKiBAcmV0dXJuIHRoZSB0aW1lIGluIG1zIHRoYXQgdGhlIGNhdGVnb3J5IGlzIGRpc2FibGVkIHVudGlsIG9yIDAgaWYgdGhlcmUncyBubyBhY3RpdmUgcmF0ZSBsaW1pdC4KICovCmZ1bmN0aW9uIGRpc2FibGVkVW50aWwobGltaXRzLCBjYXRlZ29yeSkgewogIHJldHVybiBsaW1pdHNbY2F0ZWdvcnldIHx8IGxpbWl0cy5hbGwgfHwgMDsKfQoKLyoqCiAqIENoZWNrcyBpZiBhIGNhdGVnb3J5IGlzIHJhdGUgbGltaXRlZAogKi8KZnVuY3Rpb24gaXNSYXRlTGltaXRlZChsaW1pdHMsIGNhdGVnb3J5LCBub3cgPSBEYXRlLm5vdygpKSB7CiAgcmV0dXJuIGRpc2FibGVkVW50aWwobGltaXRzLCBjYXRlZ29yeSkgPiBub3c7Cn0KCi8qKgogKiBVcGRhdGUgcmF0ZWxpbWl0cyBmcm9tIGluY29taW5nIGhlYWRlcnMuCiAqCiAqIEByZXR1cm4gdGhlIHVwZGF0ZWQgUmF0ZUxpbWl0cyBvYmplY3QuCiAqLwpmdW5jdGlvbiB1cGRhdGVSYXRlTGltaXRzKAogIGxpbWl0cywKICB7IHN0YXR1c0NvZGUsIGhlYWRlcnMgfSwKICBub3cgPSBEYXRlLm5vdygpLAopIHsKICBjb25zdCB1cGRhdGVkUmF0ZUxpbWl0cyA9IHsKICAgIC4uLmxpbWl0cywKICB9OwoKICAvLyAiVGhlIG5hbWUgaXMgY2FzZS1pbnNlbnNpdGl2ZS4iCiAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0hlYWRlcnMvZ2V0CiAgY29uc3QgcmF0ZUxpbWl0SGVhZGVyID0gaGVhZGVycyAmJiBoZWFkZXJzWyd4LXNlbnRyeS1yYXRlLWxpbWl0cyddOwogIGNvbnN0IHJldHJ5QWZ0ZXJIZWFkZXIgPSBoZWFkZXJzICYmIGhlYWRlcnNbJ3JldHJ5LWFmdGVyJ107CgogIGlmIChyYXRlTGltaXRIZWFkZXIpIHsKICAgIC8qKgogICAgICogcmF0ZSBsaW1pdCBoZWFkZXJzIGFyZSBvZiB0aGUgZm9ybQogICAgICogICAgIDxoZWFkZXI+LDxoZWFkZXI+LC4uCiAgICAgKiB3aGVyZSBlYWNoIDxoZWFkZXI+IGlzIG9mIHRoZSBmb3JtCiAgICAgKiAgICAgPHJldHJ5X2FmdGVyPjogPGNhdGVnb3JpZXM+OiA8c2NvcGU+OiA8cmVhc29uX2NvZGU+CiAgICAgKiB3aGVyZQogICAgICogICAgIDxyZXRyeV9hZnRlcj4gaXMgYSBkZWxheSBpbiBzZWNvbmRzCiAgICAgKiAgICAgPGNhdGVnb3JpZXM+IGlzIHRoZSBldmVudCB0eXBlKHMpIChlcnJvciwgdHJhbnNhY3Rpb24sIGV0YykgYmVpbmcgcmF0ZSBsaW1pdGVkIGFuZCBpcyBvZiB0aGUgZm9ybQogICAgICogICAgICAgICA8Y2F0ZWdvcnk+OzxjYXRlZ29yeT47Li4uCiAgICAgKiAgICAgPHNjb3BlPiBpcyB3aGF0J3MgYmVpbmcgbGltaXRlZCAob3JnLCBwcm9qZWN0LCBvciBrZXkpIC0gaWdub3JlZCBieSBTREsKICAgICAqICAgICA8cmVhc29uX2NvZGU+IGlzIGFuIGFyYml0cmFyeSBzdHJpbmcgbGlrZSAib3JnX3F1b3RhIiAtIGlnbm9yZWQgYnkgU0RLCiAgICAgKi8KICAgIGZvciAoY29uc3QgbGltaXQgb2YgcmF0ZUxpbWl0SGVhZGVyLnRyaW0oKS5zcGxpdCgnLCcpKSB7CiAgICAgIGNvbnN0IFtyZXRyeUFmdGVyLCBjYXRlZ29yaWVzXSA9IGxpbWl0LnNwbGl0KCc6JywgMik7CiAgICAgIGNvbnN0IGhlYWRlckRlbGF5ID0gcGFyc2VJbnQocmV0cnlBZnRlciwgMTApOwogICAgICBjb25zdCBkZWxheSA9ICghaXNOYU4oaGVhZGVyRGVsYXkpID8gaGVhZGVyRGVsYXkgOiA2MCkgKiAxMDAwOyAvLyA2MHNlYyBkZWZhdWx0CiAgICAgIGlmICghY2F0ZWdvcmllcykgewogICAgICAgIHVwZGF0ZWRSYXRlTGltaXRzLmFsbCA9IG5vdyArIGRlbGF5OwogICAgICB9IGVsc2UgewogICAgICAgIGZvciAoY29uc3QgY2F0ZWdvcnkgb2YgY2F0ZWdvcmllcy5zcGxpdCgnOycpKSB7CiAgICAgICAgICB1cGRhdGVkUmF0ZUxpbWl0c1tjYXRlZ29yeV0gPSBub3cgKyBkZWxheTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9IGVsc2UgaWYgKHJldHJ5QWZ0ZXJIZWFkZXIpIHsKICAgIHVwZGF0ZWRSYXRlTGltaXRzLmFsbCA9IG5vdyArIHBhcnNlUmV0cnlBZnRlckhlYWRlcihyZXRyeUFmdGVySGVhZGVyLCBub3cpOwogIH0gZWxzZSBpZiAoc3RhdHVzQ29kZSA9PT0gNDI5KSB7CiAgICB1cGRhdGVkUmF0ZUxpbWl0cy5hbGwgPSBub3cgKyA2MCAqIDEwMDA7CiAgfQoKICByZXR1cm4gdXBkYXRlZFJhdGVMaW1pdHM7Cn0KCi8qKgogKiBBIG5vZGUuanMgd2F0Y2hkb2cgdGltZXIKICogQHBhcmFtIHBvbGxJbnRlcnZhbCBUaGUgaW50ZXJ2YWwgdGhhdCB3ZSBleHBlY3QgdG8gZ2V0IHBvbGxlZCBhdAogKiBAcGFyYW0gYW5yVGhyZXNob2xkIFRoZSB0aHJlc2hvbGQgZm9yIHdoZW4gd2UgY29uc2lkZXIgQU5SCiAqIEBwYXJhbSBjYWxsYmFjayBUaGUgY2FsbGJhY2sgdG8gY2FsbCBmb3IgQU5SCiAqIEByZXR1cm5zIEFuIG9iamVjdCB3aXRoIGBwb2xsYCBhbmQgYGVuYWJsZWRgIGZ1bmN0aW9ucyB7QGxpbmsgV2F0Y2hkb2dSZXR1cm59CiAqLwpmdW5jdGlvbiB3YXRjaGRvZ1RpbWVyKAogIGNyZWF0ZVRpbWVyLAogIHBvbGxJbnRlcnZhbCwKICBhbnJUaHJlc2hvbGQsCiAgY2FsbGJhY2ssCikgewogIGNvbnN0IHRpbWVyID0gY3JlYXRlVGltZXIoKTsKICBsZXQgdHJpZ2dlcmVkID0gZmFsc2U7CiAgbGV0IGVuYWJsZWQgPSB0cnVlOwoKICBzZXRJbnRlcnZhbCgoKSA9PiB7CiAgICBjb25zdCBkaWZmTXMgPSB0aW1lci5nZXRUaW1lTXMoKTsKCiAgICBpZiAodHJpZ2dlcmVkID09PSBmYWxzZSAmJiBkaWZmTXMgPiBwb2xsSW50ZXJ2YWwgKyBhbnJUaHJlc2hvbGQpIHsKICAgICAgdHJpZ2dlcmVkID0gdHJ1ZTsKICAgICAgaWYgKGVuYWJsZWQpIHsKICAgICAgICBjYWxsYmFjaygpOwogICAgICB9CiAgICB9CgogICAgaWYgKGRpZmZNcyA8IHBvbGxJbnRlcnZhbCArIGFuclRocmVzaG9sZCkgewogICAgICB0cmlnZ2VyZWQgPSBmYWxzZTsKICAgIH0KICB9LCAyMCk7CgogIHJldHVybiB7CiAgICBwb2xsOiAoKSA9PiB7CiAgICAgIHRpbWVyLnJlc2V0KCk7CiAgICB9LAogICAgZW5hYmxlZDogKHN0YXRlKSA9PiB7CiAgICAgIGVuYWJsZWQgPSBzdGF0ZTsKICAgIH0sCiAgfTsKfQoKLy8gdHlwZXMgY29waWVkIGZyb20gaW5zcGVjdG9yLmQudHMKCi8qKgogKiBDb252ZXJ0cyBEZWJ1Z2dlci5DYWxsRnJhbWUgdG8gU2VudHJ5IFN0YWNrRnJhbWUKICovCmZ1bmN0aW9uIGNhbGxGcmFtZVRvU3RhY2tGcmFtZSgKICBmcmFtZSwKICB1cmwsCiAgZ2V0TW9kdWxlRnJvbUZpbGVuYW1lLAopIHsKICBjb25zdCBmaWxlbmFtZSA9IHVybCA/IHVybC5yZXBsYWNlKC9eZmlsZTpcL1wvLywgJycpIDogdW5kZWZpbmVkOwoKICAvLyBDYWxsRnJhbWUgcm93L2NvbCBhcmUgMCBiYXNlZCwgd2hlcmVhcyBTdGFja0ZyYW1lIGFyZSAxIGJhc2VkCiAgY29uc3QgY29sbm8gPSBmcmFtZS5sb2NhdGlvbi5jb2x1bW5OdW1iZXIgPyBmcmFtZS5sb2NhdGlvbi5jb2x1bW5OdW1iZXIgKyAxIDogdW5kZWZpbmVkOwogIGNvbnN0IGxpbmVubyA9IGZyYW1lLmxvY2F0aW9uLmxpbmVOdW1iZXIgPyBmcmFtZS5sb2NhdGlvbi5saW5lTnVtYmVyICsgMSA6IHVuZGVmaW5lZDsKCiAgcmV0dXJuIGRyb3BVbmRlZmluZWRLZXlzKHsKICAgIGZpbGVuYW1lLAogICAgbW9kdWxlOiBnZXRNb2R1bGVGcm9tRmlsZW5hbWUoZmlsZW5hbWUpLAogICAgZnVuY3Rpb246IGZyYW1lLmZ1bmN0aW9uTmFtZSB8fCBVTktOT1dOX0ZVTkNUSU9OLAogICAgY29sbm8sCiAgICBsaW5lbm8sCiAgICBpbl9hcHA6IGZpbGVuYW1lID8gZmlsZW5hbWVJc0luQXBwKGZpbGVuYW1lKSA6IHVuZGVmaW5lZCwKICB9KTsKfQoKLyoqCiAqIFRoaXMgc2VydmVzIGFzIGEgYnVpbGQgdGltZSBmbGFnIHRoYXQgd2lsbCBiZSB0cnVlIGJ5IGRlZmF1bHQsIGJ1dCBmYWxzZSBpbiBub24tZGVidWcgYnVpbGRzIG9yIGlmIHVzZXJzIHJlcGxhY2UgYF9fU0VOVFJZX0RFQlVHX19gIGluIHRoZWlyIGdlbmVyYXRlZCBjb2RlLgogKgogKiBBVFRFTlRJT046IFRoaXMgY29uc3RhbnQgbXVzdCBuZXZlciBjcm9zcyBwYWNrYWdlIGJvdW5kYXJpZXMgKGkuZS4gYmUgZXhwb3J0ZWQpIHRvIGd1YXJhbnRlZSB0aGF0IGl0IGNhbiBiZSB1c2VkIGZvciB0cmVlIHNoYWtpbmcuCiAqLwpjb25zdCBERUJVR19CVUlMRCA9ICh0eXBlb2YgX19TRU5UUllfREVCVUdfXyA9PT0gJ3VuZGVmaW5lZCcgfHwgX19TRU5UUllfREVCVUdfXyk7CgovKioKICogQHByaXZhdGUgUHJpdmF0ZSBBUEkgd2l0aCBubyBzZW12ZXIgZ3VhcmFudGVlcyEKICoKICogU3RyYXRlZ3kgdXNlZCB0byB0cmFjayBhc3luYyBjb250ZXh0LgogKi8KCi8qKgogKiBSZXR1cm5zIHRoZSBnbG9iYWwgc2hpbSByZWdpc3RyeS4KICoKICogRklYTUU6IFRoaXMgZnVuY3Rpb24gaXMgcHJvYmxlbWF0aWMsIGJlY2F1c2UgZGVzcGl0ZSBhbHdheXMgcmV0dXJuaW5nIGEgdmFsaWQgQ2FycmllciwKICogaXQgaGFzIGFuIG9wdGlvbmFsIGBfX1NFTlRSWV9fYCBwcm9wZXJ0eSwgd2hpY2ggdGhlbiBpbiB0dXJuIHJlcXVpcmVzIHVzIHRvIGFsd2F5cyBwZXJmb3JtIGFuIHVubmVjZXNzYXJ5IGNoZWNrCiAqIGF0IHRoZSBjYWxsLXNpdGUuIFdlIGFsd2F5cyBhY2Nlc3MgdGhlIGNhcnJpZXIgdGhyb3VnaCB0aGlzIGZ1bmN0aW9uLCBzbyB3ZSBjYW4gZ3VhcmFudGVlIHRoYXQgYF9fU0VOVFJZX19gIGlzIHRoZXJlLgogKiovCmZ1bmN0aW9uIGdldE1haW5DYXJyaWVyKCkgewogIC8vIFRoaXMgZW5zdXJlcyBhIFNlbnRyeSBjYXJyaWVyIGV4aXN0cwogIGdldFNlbnRyeUNhcnJpZXIoR0xPQkFMX09CSik7CiAgcmV0dXJuIEdMT0JBTF9PQko7Cn0KCi8qKiBXaWxsIGVpdGhlciBnZXQgdGhlIGV4aXN0aW5nIHNlbnRyeSBjYXJyaWVyLCBvciBjcmVhdGUgYSBuZXcgb25lLiAqLwpmdW5jdGlvbiBnZXRTZW50cnlDYXJyaWVyKGNhcnJpZXIpIHsKICBpZiAoIWNhcnJpZXIuX19TRU5UUllfXykgewogICAgY2Fycmllci5fX1NFTlRSWV9fID0gewogICAgICBleHRlbnNpb25zOiB7fSwKICAgIH07CiAgfQogIHJldHVybiBjYXJyaWVyLl9fU0VOVFJZX187Cn0KCmNvbnN0IERFRkFVTFRfRU5WSVJPTk1FTlQgPSAncHJvZHVjdGlvbic7CgovKioKICogQ3JlYXRlcyBhIG5ldyBgU2Vzc2lvbmAgb2JqZWN0IGJ5IHNldHRpbmcgY2VydGFpbiBkZWZhdWx0IHBhcmFtZXRlcnMuIElmIG9wdGlvbmFsIEBwYXJhbSBjb250ZXh0CiAqIGlzIHBhc3NlZCwgdGhlIHBhc3NlZCBwcm9wZXJ0aWVzIGFyZSBhcHBsaWVkIHRvIHRoZSBzZXNzaW9uIG9iamVjdC4KICoKICogQHBhcmFtIGNvbnRleHQgKG9wdGlvbmFsKSBhZGRpdGlvbmFsIHByb3BlcnRpZXMgdG8gYmUgYXBwbGllZCB0byB0aGUgcmV0dXJuZWQgc2Vzc2lvbiBvYmplY3QKICoKICogQHJldHVybnMgYSBuZXcgYFNlc3Npb25gIG9iamVjdAogKi8KZnVuY3Rpb24gbWFrZVNlc3Npb24oY29udGV4dCkgewogIC8vIEJvdGggdGltZXN0YW1wIGFuZCBzdGFydGVkIGFyZSBpbiBzZWNvbmRzIHNpbmNlIHRoZSBVTklYIGVwb2NoLgogIGNvbnN0IHN0YXJ0aW5nVGltZSA9IHRpbWVzdGFtcEluU2Vjb25kcygpOwoKICBjb25zdCBzZXNzaW9uID0gewogICAgc2lkOiB1dWlkNCgpLAogICAgaW5pdDogdHJ1ZSwKICAgIHRpbWVzdGFtcDogc3RhcnRpbmdUaW1lLAogICAgc3RhcnRlZDogc3RhcnRpbmdUaW1lLAogICAgZHVyYXRpb246IDAsCiAgICBzdGF0dXM6ICdvaycsCiAgICBlcnJvcnM6IDAsCiAgICBpZ25vcmVEdXJhdGlvbjogZmFsc2UsCiAgICB0b0pTT046ICgpID0+IHNlc3Npb25Ub0pTT04oc2Vzc2lvbiksCiAgfTsKCiAgaWYgKGNvbnRleHQpIHsKICAgIHVwZGF0ZVNlc3Npb24oc2Vzc2lvbiwgY29udGV4dCk7CiAgfQoKICByZXR1cm4gc2Vzc2lvbjsKfQoKLyoqCiAqIFVwZGF0ZXMgYSBzZXNzaW9uIG9iamVjdCB3aXRoIHRoZSBwcm9wZXJ0aWVzIHBhc3NlZCBpbiB0aGUgY29udGV4dC4KICoKICogTm90ZSB0aGF0IHRoaXMgZnVuY3Rpb24gbXV0YXRlcyB0aGUgcGFzc2VkIG9iamVjdCBhbmQgcmV0dXJucyB2b2lkLgogKiAoSGFkIHRvIGRvIHRoaXMgaW5zdGVhZCBvZiByZXR1cm5pbmcgYSBuZXcgYW5kIHVwZGF0ZWQgc2Vzc2lvbiBiZWNhdXNlIGNsb3NpbmcgYW5kIHNlbmRpbmcgYSBzZXNzaW9uCiAqIG1ha2VzIGFuIHVwZGF0ZSB0byB0aGUgc2Vzc2lvbiBhZnRlciBpdCB3YXMgcGFzc2VkIHRvIHRoZSBzZW5kaW5nIGxvZ2ljLgogKiBAc2VlIEJhc2VDbGllbnQuY2FwdHVyZVNlc3Npb24gKQogKgogKiBAcGFyYW0gc2Vzc2lvbiB0aGUgYFNlc3Npb25gIHRvIHVwZGF0ZQogKiBAcGFyYW0gY29udGV4dCB0aGUgYFNlc3Npb25Db250ZXh0YCBob2xkaW5nIHRoZSBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkIGJlIHVwZGF0ZWQgaW4gQHBhcmFtIHNlc3Npb24KICovCi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5CmZ1bmN0aW9uIHVwZGF0ZVNlc3Npb24oc2Vzc2lvbiwgY29udGV4dCA9IHt9KSB7CiAgaWYgKGNvbnRleHQudXNlcikgewogICAgaWYgKCFzZXNzaW9uLmlwQWRkcmVzcyAmJiBjb250ZXh0LnVzZXIuaXBfYWRkcmVzcykgewogICAgICBzZXNzaW9uLmlwQWRkcmVzcyA9IGNvbnRleHQudXNlci5pcF9hZGRyZXNzOwogICAgfQoKICAgIGlmICghc2Vzc2lvbi5kaWQgJiYgIWNvbnRleHQuZGlkKSB7CiAgICAgIHNlc3Npb24uZGlkID0gY29udGV4dC51c2VyLmlkIHx8IGNvbnRleHQudXNlci5lbWFpbCB8fCBjb250ZXh0LnVzZXIudXNlcm5hbWU7CiAgICB9CiAgfQoKICBzZXNzaW9uLnRpbWVzdGFtcCA9IGNvbnRleHQudGltZXN0YW1wIHx8IHRpbWVzdGFtcEluU2Vjb25kcygpOwoKICBpZiAoY29udGV4dC5hYm5vcm1hbF9tZWNoYW5pc20pIHsKICAgIHNlc3Npb24uYWJub3JtYWxfbWVjaGFuaXNtID0gY29udGV4dC5hYm5vcm1hbF9tZWNoYW5pc207CiAgfQoKICBpZiAoY29udGV4dC5pZ25vcmVEdXJhdGlvbikgewogICAgc2Vzc2lvbi5pZ25vcmVEdXJhdGlvbiA9IGNvbnRleHQuaWdub3JlRHVyYXRpb247CiAgfQogIGlmIChjb250ZXh0LnNpZCkgewogICAgLy8gR29vZCBlbm91Z2ggdXVpZCB2YWxpZGF0aW9uLiDigJQgS2FtaWwKICAgIHNlc3Npb24uc2lkID0gY29udGV4dC5zaWQubGVuZ3RoID09PSAzMiA/IGNvbnRleHQuc2lkIDogdXVpZDQoKTsKICB9CiAgaWYgKGNvbnRleHQuaW5pdCAhPT0gdW5kZWZpbmVkKSB7CiAgICBzZXNzaW9uLmluaXQgPSBjb250ZXh0LmluaXQ7CiAgfQogIGlmICghc2Vzc2lvbi5kaWQgJiYgY29udGV4dC5kaWQpIHsKICAgIHNlc3Npb24uZGlkID0gYCR7Y29udGV4dC5kaWR9YDsKICB9CiAgaWYgKHR5cGVvZiBjb250ZXh0LnN0YXJ0ZWQgPT09ICdudW1iZXInKSB7CiAgICBzZXNzaW9uLnN0YXJ0ZWQgPSBjb250ZXh0LnN0YXJ0ZWQ7CiAgfQogIGlmIChzZXNzaW9uLmlnbm9yZUR1cmF0aW9uKSB7CiAgICBzZXNzaW9uLmR1cmF0aW9uID0gdW5kZWZpbmVkOwogIH0gZWxzZSBpZiAodHlwZW9mIGNvbnRleHQuZHVyYXRpb24gPT09ICdudW1iZXInKSB7CiAgICBzZXNzaW9uLmR1cmF0aW9uID0gY29udGV4dC5kdXJhdGlvbjsKICB9IGVsc2UgewogICAgY29uc3QgZHVyYXRpb24gPSBzZXNzaW9uLnRpbWVzdGFtcCAtIHNlc3Npb24uc3RhcnRlZDsKICAgIHNlc3Npb24uZHVyYXRpb24gPSBkdXJhdGlvbiA+PSAwID8gZHVyYXRpb24gOiAwOwogIH0KICBpZiAoY29udGV4dC5yZWxlYXNlKSB7CiAgICBzZXNzaW9uLnJlbGVhc2UgPSBjb250ZXh0LnJlbGVhc2U7CiAgfQogIGlmIChjb250ZXh0LmVudmlyb25tZW50KSB7CiAgICBzZXNzaW9uLmVudmlyb25tZW50ID0gY29udGV4dC5lbnZpcm9ubWVudDsKICB9CiAgaWYgKCFzZXNzaW9uLmlwQWRkcmVzcyAmJiBjb250ZXh0LmlwQWRkcmVzcykgewogICAgc2Vzc2lvbi5pcEFkZHJlc3MgPSBjb250ZXh0LmlwQWRkcmVzczsKICB9CiAgaWYgKCFzZXNzaW9uLnVzZXJBZ2VudCAmJiBjb250ZXh0LnVzZXJBZ2VudCkgewogICAgc2Vzc2lvbi51c2VyQWdlbnQgPSBjb250ZXh0LnVzZXJBZ2VudDsKICB9CiAgaWYgKHR5cGVvZiBjb250ZXh0LmVycm9ycyA9PT0gJ251bWJlcicpIHsKICAgIHNlc3Npb24uZXJyb3JzID0gY29udGV4dC5lcnJvcnM7CiAgfQogIGlmIChjb250ZXh0LnN0YXR1cykgewogICAgc2Vzc2lvbi5zdGF0dXMgPSBjb250ZXh0LnN0YXR1czsKICB9Cn0KCi8qKgogKiBDbG9zZXMgYSBzZXNzaW9uIGJ5IHNldHRpbmcgaXRzIHN0YXR1cyBhbmQgdXBkYXRpbmcgdGhlIHNlc3Npb24gb2JqZWN0IHdpdGggaXQuCiAqIEludGVybmFsbHkgY2FsbHMgYHVwZGF0ZVNlc3Npb25gIHRvIHVwZGF0ZSB0aGUgcGFzc2VkIHNlc3Npb24gb2JqZWN0LgogKgogKiBOb3RlIHRoYXQgdGhpcyBmdW5jdGlvbiBtdXRhdGVzIHRoZSBwYXNzZWQgc2Vzc2lvbiAoQHNlZSB1cGRhdGVTZXNzaW9uIGZvciBleHBsYW5hdGlvbikuCiAqCiAqIEBwYXJhbSBzZXNzaW9uIHRoZSBgU2Vzc2lvbmAgb2JqZWN0IHRvIGJlIGNsb3NlZAogKiBAcGFyYW0gc3RhdHVzIHRoZSBgU2Vzc2lvblN0YXR1c2Agd2l0aCB3aGljaCB0aGUgc2Vzc2lvbiB3YXMgY2xvc2VkLiBJZiB5b3UgZG9uJ3QgcGFzcyBhIHN0YXR1cywKICogICAgICAgICAgICAgICB0aGlzIGZ1bmN0aW9uIHdpbGwga2VlcCB0aGUgcHJldmlvdXNseSBzZXQgc3RhdHVzLCB1bmxlc3MgaXQgd2FzIGAnb2snYCBpbiB3aGljaCBjYXNlCiAqICAgICAgICAgICAgICAgaXQgaXMgY2hhbmdlZCB0byBgJ2V4aXRlZCdgLgogKi8KZnVuY3Rpb24gY2xvc2VTZXNzaW9uKHNlc3Npb24sIHN0YXR1cykgewogIGxldCBjb250ZXh0ID0ge307CiAgaWYgKHN0YXR1cykgewogICAgY29udGV4dCA9IHsgc3RhdHVzIH07CiAgfSBlbHNlIGlmIChzZXNzaW9uLnN0YXR1cyA9PT0gJ29rJykgewogICAgY29udGV4dCA9IHsgc3RhdHVzOiAnZXhpdGVkJyB9OwogIH0KCiAgdXBkYXRlU2Vzc2lvbihzZXNzaW9uLCBjb250ZXh0KTsKfQoKLyoqCiAqIFNlcmlhbGl6ZXMgYSBwYXNzZWQgc2Vzc2lvbiBvYmplY3QgdG8gYSBKU09OIG9iamVjdCB3aXRoIGEgc2xpZ2h0bHkgZGlmZmVyZW50IHN0cnVjdHVyZS4KICogVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSB0aGUgU2VudHJ5IGJhY2tlbmQgcmVxdWlyZXMgYSBzbGlnaHRseSBkaWZmZXJlbnQgc2NoZW1hIG9mIGEgc2Vzc2lvbgogKiB0aGFuIHRoZSBvbmUgdGhlIEpTIFNES3MgdXNlIGludGVybmFsbHkuCiAqCiAqIEBwYXJhbSBzZXNzaW9uIHRoZSBzZXNzaW9uIHRvIGJlIGNvbnZlcnRlZAogKgogKiBAcmV0dXJucyBhIEpTT04gb2JqZWN0IG9mIHRoZSBwYXNzZWQgc2Vzc2lvbgogKi8KZnVuY3Rpb24gc2Vzc2lvblRvSlNPTihzZXNzaW9uKSB7CiAgcmV0dXJuIGRyb3BVbmRlZmluZWRLZXlzKHsKICAgIHNpZDogYCR7c2Vzc2lvbi5zaWR9YCwKICAgIGluaXQ6IHNlc3Npb24uaW5pdCwKICAgIC8vIE1ha2Ugc3VyZSB0aGF0IHNlYyBpcyBjb252ZXJ0ZWQgdG8gbXMgZm9yIGRhdGUgY29uc3RydWN0b3IKICAgIHN0YXJ0ZWQ6IG5ldyBEYXRlKHNlc3Npb24uc3RhcnRlZCAqIDEwMDApLnRvSVNPU3RyaW5nKCksCiAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKHNlc3Npb24udGltZXN0YW1wICogMTAwMCkudG9JU09TdHJpbmcoKSwKICAgIHN0YXR1czogc2Vzc2lvbi5zdGF0dXMsCiAgICBlcnJvcnM6IHNlc3Npb24uZXJyb3JzLAogICAgZGlkOiB0eXBlb2Ygc2Vzc2lvbi5kaWQgPT09ICdudW1iZXInIHx8IHR5cGVvZiBzZXNzaW9uLmRpZCA9PT0gJ3N0cmluZycgPyBgJHtzZXNzaW9uLmRpZH1gIDogdW5kZWZpbmVkLAogICAgZHVyYXRpb246IHNlc3Npb24uZHVyYXRpb24sCiAgICBhYm5vcm1hbF9tZWNoYW5pc206IHNlc3Npb24uYWJub3JtYWxfbWVjaGFuaXNtLAogICAgYXR0cnM6IHsKICAgICAgcmVsZWFzZTogc2Vzc2lvbi5yZWxlYXNlLAogICAgICBlbnZpcm9ubWVudDogc2Vzc2lvbi5lbnZpcm9ubWVudCwKICAgICAgaXBfYWRkcmVzczogc2Vzc2lvbi5pcEFkZHJlc3MsCiAgICAgIHVzZXJfYWdlbnQ6IHNlc3Npb24udXNlckFnZW50LAogICAgfSwKICB9KTsKfQoKLyoqCiAqIERlZmF1bHQgdmFsdWUgZm9yIG1heGltdW0gbnVtYmVyIG9mIGJyZWFkY3J1bWJzIGFkZGVkIHRvIGFuIGV2ZW50LgogKi8KY29uc3QgREVGQVVMVF9NQVhfQlJFQURDUlVNQlMgPSAxMDA7CgovKioKICogSG9sZHMgYWRkaXRpb25hbCBldmVudCBpbmZvcm1hdGlvbi4KICovCmNsYXNzIFNjb3BlICB7CiAgLyoqIEZsYWcgaWYgbm90aWZ5aW5nIGlzIGhhcHBlbmluZy4gKi8KCiAgLyoqIENhbGxiYWNrIGZvciBjbGllbnQgdG8gcmVjZWl2ZSBzY29wZSBjaGFuZ2VzLiAqLwoKICAvKiogQ2FsbGJhY2sgbGlzdCB0aGF0IHdpbGwgYmUgY2FsbGVkIGR1cmluZyBldmVudCBwcm9jZXNzaW5nLiAqLwoKICAvKiogQXJyYXkgb2YgYnJlYWRjcnVtYnMuICovCgogIC8qKiBVc2VyICovCgogIC8qKiBUYWdzICovCgogIC8qKiBFeHRyYSAqLwoKICAvKiogQ29udGV4dHMgKi8KCiAgLyoqIEF0dGFjaG1lbnRzICovCgogIC8qKiBQcm9wYWdhdGlvbiBDb250ZXh0IGZvciBkaXN0cmlidXRlZCB0cmFjaW5nICovCgogIC8qKgogICAqIEEgcGxhY2UgdG8gc3Rhc2ggZGF0YSB3aGljaCBpcyBuZWVkZWQgYXQgc29tZSBwb2ludCBpbiB0aGUgU0RLJ3MgZXZlbnQgcHJvY2Vzc2luZyBwaXBlbGluZSBidXQgd2hpY2ggc2hvdWxkbid0IGdldAogICAqIHNlbnQgdG8gU2VudHJ5CiAgICovCgogIC8qKiBGaW5nZXJwcmludCAqLwoKICAvKiogU2V2ZXJpdHkgKi8KCiAgLyoqCiAgICogVHJhbnNhY3Rpb24gTmFtZQogICAqCiAgICogSU1QT1JUQU5UOiBUaGUgdHJhbnNhY3Rpb24gbmFtZSBvbiB0aGUgc2NvcGUgaGFzIG5vdGhpbmcgdG8gZG8gd2l0aCByb290IHNwYW5zL3RyYW5zYWN0aW9uIG9iamVjdHMuCiAgICogSXQncyBwdXJwb3NlIGlzIHRvIGFzc2lnbiBhIHRyYW5zYWN0aW9uIHRvIHRoZSBzY29wZSB0aGF0J3MgYWRkZWQgdG8gbm9uLXRyYW5zYWN0aW9uIGV2ZW50cy4KICAgKi8KCiAgLyoqIFNwYW4gKi8KCiAgLyoqIFNlc3Npb24gKi8KCiAgLyoqIFJlcXVlc3QgTW9kZSBTZXNzaW9uIFN0YXR1cyAqLwoKICAvKiogVGhlIGNsaWVudCBvbiB0aGlzIHNjb3BlICovCgogIC8vIE5PVEU6IEFueSBmaWVsZCB3aGljaCBnZXRzIGFkZGVkIGhlcmUgc2hvdWxkIGdldCBhZGRlZCBub3Qgb25seSB0byB0aGUgY29uc3RydWN0b3IgYnV0IGFsc28gdG8gdGhlIGBjbG9uZWAgbWV0aG9kLgoKICAgY29uc3RydWN0b3IoKSB7CiAgICB0aGlzLl9ub3RpZnlpbmdMaXN0ZW5lcnMgPSBmYWxzZTsKICAgIHRoaXMuX3Njb3BlTGlzdGVuZXJzID0gW107CiAgICB0aGlzLl9ldmVudFByb2Nlc3NvcnMgPSBbXTsKICAgIHRoaXMuX2JyZWFkY3J1bWJzID0gW107CiAgICB0aGlzLl9hdHRhY2htZW50cyA9IFtdOwogICAgdGhpcy5fdXNlciA9IHt9OwogICAgdGhpcy5fdGFncyA9IHt9OwogICAgdGhpcy5fZXh0cmEgPSB7fTsKICAgIHRoaXMuX2NvbnRleHRzID0ge307CiAgICB0aGlzLl9zZGtQcm9jZXNzaW5nTWV0YWRhdGEgPSB7fTsKICAgIHRoaXMuX3Byb3BhZ2F0aW9uQ29udGV4dCA9IGdlbmVyYXRlUHJvcGFnYXRpb25Db250ZXh0KCk7CiAgfQoKICAvKioKICAgKiBJbmhlcml0IHZhbHVlcyBmcm9tIHRoZSBwYXJlbnQgc2NvcGUuCiAgICogQGRlcHJlY2F0ZWQgVXNlIGBzY29wZS5jbG9uZSgpYCBhbmQgYG5ldyBTY29wZSgpYCBpbnN0ZWFkLgogICAqLwogICBzdGF0aWMgY2xvbmUoc2NvcGUpIHsKICAgIHJldHVybiBzY29wZSA/IHNjb3BlLmNsb25lKCkgOiBuZXcgU2NvcGUoKTsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGNsb25lKCkgewogICAgY29uc3QgbmV3U2NvcGUgPSBuZXcgU2NvcGUoKTsKICAgIG5ld1Njb3BlLl9icmVhZGNydW1icyA9IFsuLi50aGlzLl9icmVhZGNydW1ic107CiAgICBuZXdTY29wZS5fdGFncyA9IHsgLi4udGhpcy5fdGFncyB9OwogICAgbmV3U2NvcGUuX2V4dHJhID0geyAuLi50aGlzLl9leHRyYSB9OwogICAgbmV3U2NvcGUuX2NvbnRleHRzID0geyAuLi50aGlzLl9jb250ZXh0cyB9OwogICAgbmV3U2NvcGUuX3VzZXIgPSB0aGlzLl91c2VyOwogICAgbmV3U2NvcGUuX2xldmVsID0gdGhpcy5fbGV2ZWw7CiAgICBuZXdTY29wZS5fc3BhbiA9IHRoaXMuX3NwYW47CiAgICBuZXdTY29wZS5fc2Vzc2lvbiA9IHRoaXMuX3Nlc3Npb247CiAgICBuZXdTY29wZS5fdHJhbnNhY3Rpb25OYW1lID0gdGhpcy5fdHJhbnNhY3Rpb25OYW1lOwogICAgbmV3U2NvcGUuX2ZpbmdlcnByaW50ID0gdGhpcy5fZmluZ2VycHJpbnQ7CiAgICBuZXdTY29wZS5fZXZlbnRQcm9jZXNzb3JzID0gWy4uLnRoaXMuX2V2ZW50UHJvY2Vzc29yc107CiAgICBuZXdTY29wZS5fcmVxdWVzdFNlc3Npb24gPSB0aGlzLl9yZXF1ZXN0U2Vzc2lvbjsKICAgIG5ld1Njb3BlLl9hdHRhY2htZW50cyA9IFsuLi50aGlzLl9hdHRhY2htZW50c107CiAgICBuZXdTY29wZS5fc2RrUHJvY2Vzc2luZ01ldGFkYXRhID0geyAuLi50aGlzLl9zZGtQcm9jZXNzaW5nTWV0YWRhdGEgfTsKICAgIG5ld1Njb3BlLl9wcm9wYWdhdGlvbkNvbnRleHQgPSB7IC4uLnRoaXMuX3Byb3BhZ2F0aW9uQ29udGV4dCB9OwogICAgbmV3U2NvcGUuX2NsaWVudCA9IHRoaXMuX2NsaWVudDsKCiAgICByZXR1cm4gbmV3U2NvcGU7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBzZXRDbGllbnQoY2xpZW50KSB7CiAgICB0aGlzLl9jbGllbnQgPSBjbGllbnQ7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBnZXRDbGllbnQoKSB7CiAgICByZXR1cm4gdGhpcy5fY2xpZW50IDsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGFkZFNjb3BlTGlzdGVuZXIoY2FsbGJhY2spIHsKICAgIHRoaXMuX3Njb3BlTGlzdGVuZXJzLnB1c2goY2FsbGJhY2spOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgYWRkRXZlbnRQcm9jZXNzb3IoY2FsbGJhY2spIHsKICAgIHRoaXMuX2V2ZW50UHJvY2Vzc29ycy5wdXNoKGNhbGxiYWNrKTsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgc2V0VXNlcih1c2VyKSB7CiAgICAvLyBJZiBudWxsIGlzIHBhc3NlZCB3ZSB3YW50IHRvIHVuc2V0IGV2ZXJ5dGhpbmcsIGJ1dCBzdGlsbCBkZWZpbmUga2V5cywKICAgIC8vIHNvIHRoYXQgbGF0ZXIgZG93biBpbiB0aGUgcGlwZWxpbmUgYW55IGV4aXN0aW5nIHZhbHVlcyBhcmUgY2xlYXJlZC4KICAgIHRoaXMuX3VzZXIgPSB1c2VyIHx8IHsKICAgICAgZW1haWw6IHVuZGVmaW5lZCwKICAgICAgaWQ6IHVuZGVmaW5lZCwKICAgICAgaXBfYWRkcmVzczogdW5kZWZpbmVkLAogICAgICB1c2VybmFtZTogdW5kZWZpbmVkLAogICAgfTsKCiAgICBpZiAodGhpcy5fc2Vzc2lvbikgewogICAgICB1cGRhdGVTZXNzaW9uKHRoaXMuX3Nlc3Npb24sIHsgdXNlciB9KTsKICAgIH0KCiAgICB0aGlzLl9ub3RpZnlTY29wZUxpc3RlbmVycygpOwogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBnZXRVc2VyKCkgewogICAgcmV0dXJuIHRoaXMuX3VzZXI7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBnZXRSZXF1ZXN0U2Vzc2lvbigpIHsKICAgIHJldHVybiB0aGlzLl9yZXF1ZXN0U2Vzc2lvbjsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIHNldFJlcXVlc3RTZXNzaW9uKHJlcXVlc3RTZXNzaW9uKSB7CiAgICB0aGlzLl9yZXF1ZXN0U2Vzc2lvbiA9IHJlcXVlc3RTZXNzaW9uOwogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBzZXRUYWdzKHRhZ3MpIHsKICAgIHRoaXMuX3RhZ3MgPSB7CiAgICAgIC4uLnRoaXMuX3RhZ3MsCiAgICAgIC4uLnRhZ3MsCiAgICB9OwogICAgdGhpcy5fbm90aWZ5U2NvcGVMaXN0ZW5lcnMoKTsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgc2V0VGFnKGtleSwgdmFsdWUpIHsKICAgIHRoaXMuX3RhZ3MgPSB7IC4uLnRoaXMuX3RhZ3MsIFtrZXldOiB2YWx1ZSB9OwogICAgdGhpcy5fbm90aWZ5U2NvcGVMaXN0ZW5lcnMoKTsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgc2V0RXh0cmFzKGV4dHJhcykgewogICAgdGhpcy5fZXh0cmEgPSB7CiAgICAgIC4uLnRoaXMuX2V4dHJhLAogICAgICAuLi5leHRyYXMsCiAgICB9OwogICAgdGhpcy5fbm90aWZ5U2NvcGVMaXN0ZW5lcnMoKTsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgc2V0RXh0cmEoa2V5LCBleHRyYSkgewogICAgdGhpcy5fZXh0cmEgPSB7IC4uLnRoaXMuX2V4dHJhLCBba2V5XTogZXh0cmEgfTsKICAgIHRoaXMuX25vdGlmeVNjb3BlTGlzdGVuZXJzKCk7CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIHNldEZpbmdlcnByaW50KGZpbmdlcnByaW50KSB7CiAgICB0aGlzLl9maW5nZXJwcmludCA9IGZpbmdlcnByaW50OwogICAgdGhpcy5fbm90aWZ5U2NvcGVMaXN0ZW5lcnMoKTsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgc2V0TGV2ZWwobGV2ZWwpIHsKICAgIHRoaXMuX2xldmVsID0gbGV2ZWw7CiAgICB0aGlzLl9ub3RpZnlTY29wZUxpc3RlbmVycygpOwogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBzZXRUcmFuc2FjdGlvbk5hbWUobmFtZSkgewogICAgdGhpcy5fdHJhbnNhY3Rpb25OYW1lID0gbmFtZTsKICAgIHRoaXMuX25vdGlmeVNjb3BlTGlzdGVuZXJzKCk7CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIHNldENvbnRleHQoa2V5LCBjb250ZXh0KSB7CiAgICBpZiAoY29udGV4dCA9PT0gbnVsbCkgewogICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWR5bmFtaWMtZGVsZXRlCiAgICAgIGRlbGV0ZSB0aGlzLl9jb250ZXh0c1trZXldOwogICAgfSBlbHNlIHsKICAgICAgdGhpcy5fY29udGV4dHNba2V5XSA9IGNvbnRleHQ7CiAgICB9CgogICAgdGhpcy5fbm90aWZ5U2NvcGVMaXN0ZW5lcnMoKTsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogU2V0cyB0aGUgU3BhbiBvbiB0aGUgc2NvcGUuCiAgICogQHBhcmFtIHNwYW4gU3BhbgogICAqIEBkZXByZWNhdGVkIEluc3RlYWQgb2Ygc2V0dGluZyBhIHNwYW4gb24gYSBzY29wZSwgdXNlIGBzdGFydFNwYW4oKWAvYHN0YXJ0U3Bhbk1hbnVhbCgpYCBpbnN0ZWFkLgogICAqLwogICBzZXRTcGFuKHNwYW4pIHsKICAgIHRoaXMuX3NwYW4gPSBzcGFuOwogICAgdGhpcy5fbm90aWZ5U2NvcGVMaXN0ZW5lcnMoKTsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogUmV0dXJucyB0aGUgYFNwYW5gIGlmIHRoZXJlIGlzIG9uZS4KICAgKiBAZGVwcmVjYXRlZCBVc2UgYGdldEFjdGl2ZVNwYW4oKWAgaW5zdGVhZC4KICAgKi8KICAgZ2V0U3BhbigpIHsKICAgIHJldHVybiB0aGlzLl9zcGFuOwogIH0KCiAgLyoqCiAgICogUmV0dXJucyB0aGUgYFRyYW5zYWN0aW9uYCBhdHRhY2hlZCB0byB0aGUgc2NvcGUgKGlmIHRoZXJlIGlzIG9uZSkuCiAgICogQGRlcHJlY2F0ZWQgWW91IHNob3VsZCBub3QgcmVseSBvbiB0aGUgdHJhbnNhY3Rpb24sIGJ1dCBqdXN0IHVzZSBgc3RhcnRTcGFuKClgIEFQSXMgaW5zdGVhZC4KICAgKi8KICAgZ2V0VHJhbnNhY3Rpb24oKSB7CiAgICAvLyBPZnRlbiwgdGhpcyBzcGFuIChpZiBpdCBleGlzdHMgYXQgYWxsKSB3aWxsIGJlIGEgdHJhbnNhY3Rpb24sIGJ1dCBpdCdzIG5vdCBndWFyYW50ZWVkIHRvIGJlLiBSZWdhcmRsZXNzLCBpdCB3aWxsCiAgICAvLyBoYXZlIGEgcG9pbnRlciB0byB0aGUgY3VycmVudGx5LWFjdGl2ZSB0cmFuc2FjdGlvbi4KICAgIGNvbnN0IHNwYW4gPSB0aGlzLl9zcGFuOwoKICAgIC8vIENhbm5vdCByZXBsYWNlIHdpdGggZ2V0Um9vdFNwYW4gYmVjYXVzZSBnZXRSb290U3BhbiByZXR1cm5zIGEgc3Bhbiwgbm90IGEgdHJhbnNhY3Rpb24KICAgIC8vIEFsc28sIHRoaXMgbWV0aG9kIHdpbGwgYmUgcmVtb3ZlZCBhbnl3YXkuCiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGlmIChzcGFuICYmIChzcGFuICkudHJhbnNhY3Rpb24pIHsKICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICAgIHJldHVybiAoc3BhbiApLnRyYW5zYWN0aW9uOwogICAgfQogICAgcmV0dXJuIHVuZGVmaW5lZDsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIHNldFNlc3Npb24oc2Vzc2lvbikgewogICAgaWYgKCFzZXNzaW9uKSB7CiAgICAgIGRlbGV0ZSB0aGlzLl9zZXNzaW9uOwogICAgfSBlbHNlIHsKICAgICAgdGhpcy5fc2Vzc2lvbiA9IHNlc3Npb247CiAgICB9CiAgICB0aGlzLl9ub3RpZnlTY29wZUxpc3RlbmVycygpOwogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBnZXRTZXNzaW9uKCkgewogICAgcmV0dXJuIHRoaXMuX3Nlc3Npb247CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICB1cGRhdGUoY2FwdHVyZUNvbnRleHQpIHsKICAgIGlmICghY2FwdHVyZUNvbnRleHQpIHsKICAgICAgcmV0dXJuIHRoaXM7CiAgICB9CgogICAgY29uc3Qgc2NvcGVUb01lcmdlID0gdHlwZW9mIGNhcHR1cmVDb250ZXh0ID09PSAnZnVuY3Rpb24nID8gY2FwdHVyZUNvbnRleHQodGhpcykgOiBjYXB0dXJlQ29udGV4dDsKCiAgICBpZiAoc2NvcGVUb01lcmdlIGluc3RhbmNlb2YgU2NvcGUpIHsKICAgICAgY29uc3Qgc2NvcGVEYXRhID0gc2NvcGVUb01lcmdlLmdldFNjb3BlRGF0YSgpOwoKICAgICAgdGhpcy5fdGFncyA9IHsgLi4udGhpcy5fdGFncywgLi4uc2NvcGVEYXRhLnRhZ3MgfTsKICAgICAgdGhpcy5fZXh0cmEgPSB7IC4uLnRoaXMuX2V4dHJhLCAuLi5zY29wZURhdGEuZXh0cmEgfTsKICAgICAgdGhpcy5fY29udGV4dHMgPSB7IC4uLnRoaXMuX2NvbnRleHRzLCAuLi5zY29wZURhdGEuY29udGV4dHMgfTsKICAgICAgaWYgKHNjb3BlRGF0YS51c2VyICYmIE9iamVjdC5rZXlzKHNjb3BlRGF0YS51c2VyKS5sZW5ndGgpIHsKICAgICAgICB0aGlzLl91c2VyID0gc2NvcGVEYXRhLnVzZXI7CiAgICAgIH0KICAgICAgaWYgKHNjb3BlRGF0YS5sZXZlbCkgewogICAgICAgIHRoaXMuX2xldmVsID0gc2NvcGVEYXRhLmxldmVsOwogICAgICB9CiAgICAgIGlmIChzY29wZURhdGEuZmluZ2VycHJpbnQubGVuZ3RoKSB7CiAgICAgICAgdGhpcy5fZmluZ2VycHJpbnQgPSBzY29wZURhdGEuZmluZ2VycHJpbnQ7CiAgICAgIH0KICAgICAgaWYgKHNjb3BlVG9NZXJnZS5nZXRSZXF1ZXN0U2Vzc2lvbigpKSB7CiAgICAgICAgdGhpcy5fcmVxdWVzdFNlc3Npb24gPSBzY29wZVRvTWVyZ2UuZ2V0UmVxdWVzdFNlc3Npb24oKTsKICAgICAgfQogICAgICBpZiAoc2NvcGVEYXRhLnByb3BhZ2F0aW9uQ29udGV4dCkgewogICAgICAgIHRoaXMuX3Byb3BhZ2F0aW9uQ29udGV4dCA9IHNjb3BlRGF0YS5wcm9wYWdhdGlvbkNvbnRleHQ7CiAgICAgIH0KICAgIH0gZWxzZSBpZiAoaXNQbGFpbk9iamVjdChzY29wZVRvTWVyZ2UpKSB7CiAgICAgIGNvbnN0IHNjb3BlQ29udGV4dCA9IGNhcHR1cmVDb250ZXh0IDsKICAgICAgdGhpcy5fdGFncyA9IHsgLi4udGhpcy5fdGFncywgLi4uc2NvcGVDb250ZXh0LnRhZ3MgfTsKICAgICAgdGhpcy5fZXh0cmEgPSB7IC4uLnRoaXMuX2V4dHJhLCAuLi5zY29wZUNvbnRleHQuZXh0cmEgfTsKICAgICAgdGhpcy5fY29udGV4dHMgPSB7IC4uLnRoaXMuX2NvbnRleHRzLCAuLi5zY29wZUNvbnRleHQuY29udGV4dHMgfTsKICAgICAgaWYgKHNjb3BlQ29udGV4dC51c2VyKSB7CiAgICAgICAgdGhpcy5fdXNlciA9IHNjb3BlQ29udGV4dC51c2VyOwogICAgICB9CiAgICAgIGlmIChzY29wZUNvbnRleHQubGV2ZWwpIHsKICAgICAgICB0aGlzLl9sZXZlbCA9IHNjb3BlQ29udGV4dC5sZXZlbDsKICAgICAgfQogICAgICBpZiAoc2NvcGVDb250ZXh0LmZpbmdlcnByaW50KSB7CiAgICAgICAgdGhpcy5fZmluZ2VycHJpbnQgPSBzY29wZUNvbnRleHQuZmluZ2VycHJpbnQ7CiAgICAgIH0KICAgICAgaWYgKHNjb3BlQ29udGV4dC5yZXF1ZXN0U2Vzc2lvbikgewogICAgICAgIHRoaXMuX3JlcXVlc3RTZXNzaW9uID0gc2NvcGVDb250ZXh0LnJlcXVlc3RTZXNzaW9uOwogICAgICB9CiAgICAgIGlmIChzY29wZUNvbnRleHQucHJvcGFnYXRpb25Db250ZXh0KSB7CiAgICAgICAgdGhpcy5fcHJvcGFnYXRpb25Db250ZXh0ID0gc2NvcGVDb250ZXh0LnByb3BhZ2F0aW9uQ29udGV4dDsKICAgICAgfQogICAgfQoKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgY2xlYXIoKSB7CiAgICAvLyBjbGllbnQgaXMgbm90IGNsZWFyZWQgaGVyZSBvbiBwdXJwb3NlIQogICAgdGhpcy5fYnJlYWRjcnVtYnMgPSBbXTsKICAgIHRoaXMuX3RhZ3MgPSB7fTsKICAgIHRoaXMuX2V4dHJhID0ge307CiAgICB0aGlzLl91c2VyID0ge307CiAgICB0aGlzLl9jb250ZXh0cyA9IHt9OwogICAgdGhpcy5fbGV2ZWwgPSB1bmRlZmluZWQ7CiAgICB0aGlzLl90cmFuc2FjdGlvbk5hbWUgPSB1bmRlZmluZWQ7CiAgICB0aGlzLl9maW5nZXJwcmludCA9IHVuZGVmaW5lZDsKICAgIHRoaXMuX3JlcXVlc3RTZXNzaW9uID0gdW5kZWZpbmVkOwogICAgdGhpcy5fc3BhbiA9IHVuZGVmaW5lZDsKICAgIHRoaXMuX3Nlc3Npb24gPSB1bmRlZmluZWQ7CiAgICB0aGlzLl9ub3RpZnlTY29wZUxpc3RlbmVycygpOwogICAgdGhpcy5fYXR0YWNobWVudHMgPSBbXTsKICAgIHRoaXMuX3Byb3BhZ2F0aW9uQ29udGV4dCA9IGdlbmVyYXRlUHJvcGFnYXRpb25Db250ZXh0KCk7CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGFkZEJyZWFkY3J1bWIoYnJlYWRjcnVtYiwgbWF4QnJlYWRjcnVtYnMpIHsKICAgIGNvbnN0IG1heENydW1icyA9IHR5cGVvZiBtYXhCcmVhZGNydW1icyA9PT0gJ251bWJlcicgPyBtYXhCcmVhZGNydW1icyA6IERFRkFVTFRfTUFYX0JSRUFEQ1JVTUJTOwoKICAgIC8vIE5vIGRhdGEgaGFzIGJlZW4gY2hhbmdlZCwgc28gZG9uJ3Qgbm90aWZ5IHNjb3BlIGxpc3RlbmVycwogICAgaWYgKG1heENydW1icyA8PSAwKSB7CiAgICAgIHJldHVybiB0aGlzOwogICAgfQoKICAgIGNvbnN0IG1lcmdlZEJyZWFkY3J1bWIgPSB7CiAgICAgIHRpbWVzdGFtcDogZGF0ZVRpbWVzdGFtcEluU2Vjb25kcygpLAogICAgICAuLi5icmVhZGNydW1iLAogICAgfTsKCiAgICBjb25zdCBicmVhZGNydW1icyA9IHRoaXMuX2JyZWFkY3J1bWJzOwogICAgYnJlYWRjcnVtYnMucHVzaChtZXJnZWRCcmVhZGNydW1iKTsKICAgIHRoaXMuX2JyZWFkY3J1bWJzID0gYnJlYWRjcnVtYnMubGVuZ3RoID4gbWF4Q3J1bWJzID8gYnJlYWRjcnVtYnMuc2xpY2UoLW1heENydW1icykgOiBicmVhZGNydW1iczsKCiAgICB0aGlzLl9ub3RpZnlTY29wZUxpc3RlbmVycygpOwoKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgZ2V0TGFzdEJyZWFkY3J1bWIoKSB7CiAgICByZXR1cm4gdGhpcy5fYnJlYWRjcnVtYnNbdGhpcy5fYnJlYWRjcnVtYnMubGVuZ3RoIC0gMV07CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBjbGVhckJyZWFkY3J1bWJzKCkgewogICAgdGhpcy5fYnJlYWRjcnVtYnMgPSBbXTsKICAgIHRoaXMuX25vdGlmeVNjb3BlTGlzdGVuZXJzKCk7CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGFkZEF0dGFjaG1lbnQoYXR0YWNobWVudCkgewogICAgdGhpcy5fYXR0YWNobWVudHMucHVzaChhdHRhY2htZW50KTsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKiBAZGVwcmVjYXRlZCBVc2UgYGdldFNjb3BlRGF0YSgpYCBpbnN0ZWFkLgogICAqLwogICBnZXRBdHRhY2htZW50cygpIHsKICAgIGNvbnN0IGRhdGEgPSB0aGlzLmdldFNjb3BlRGF0YSgpOwoKICAgIHJldHVybiBkYXRhLmF0dGFjaG1lbnRzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgY2xlYXJBdHRhY2htZW50cygpIHsKICAgIHRoaXMuX2F0dGFjaG1lbnRzID0gW107CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKiBAaW5oZXJpdERvYyAqLwogICBnZXRTY29wZURhdGEoKSB7CiAgICBjb25zdCB7CiAgICAgIF9icmVhZGNydW1icywKICAgICAgX2F0dGFjaG1lbnRzLAogICAgICBfY29udGV4dHMsCiAgICAgIF90YWdzLAogICAgICBfZXh0cmEsCiAgICAgIF91c2VyLAogICAgICBfbGV2ZWwsCiAgICAgIF9maW5nZXJwcmludCwKICAgICAgX2V2ZW50UHJvY2Vzc29ycywKICAgICAgX3Byb3BhZ2F0aW9uQ29udGV4dCwKICAgICAgX3Nka1Byb2Nlc3NpbmdNZXRhZGF0YSwKICAgICAgX3RyYW5zYWN0aW9uTmFtZSwKICAgICAgX3NwYW4sCiAgICB9ID0gdGhpczsKCiAgICByZXR1cm4gewogICAgICBicmVhZGNydW1iczogX2JyZWFkY3J1bWJzLAogICAgICBhdHRhY2htZW50czogX2F0dGFjaG1lbnRzLAogICAgICBjb250ZXh0czogX2NvbnRleHRzLAogICAgICB0YWdzOiBfdGFncywKICAgICAgZXh0cmE6IF9leHRyYSwKICAgICAgdXNlcjogX3VzZXIsCiAgICAgIGxldmVsOiBfbGV2ZWwsCiAgICAgIGZpbmdlcnByaW50OiBfZmluZ2VycHJpbnQgfHwgW10sCiAgICAgIGV2ZW50UHJvY2Vzc29yczogX2V2ZW50UHJvY2Vzc29ycywKICAgICAgcHJvcGFnYXRpb25Db250ZXh0OiBfcHJvcGFnYXRpb25Db250ZXh0LAogICAgICBzZGtQcm9jZXNzaW5nTWV0YWRhdGE6IF9zZGtQcm9jZXNzaW5nTWV0YWRhdGEsCiAgICAgIHRyYW5zYWN0aW9uTmFtZTogX3RyYW5zYWN0aW9uTmFtZSwKICAgICAgc3BhbjogX3NwYW4sCiAgICB9OwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgc2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKG5ld0RhdGEpIHsKICAgIHRoaXMuX3Nka1Byb2Nlc3NpbmdNZXRhZGF0YSA9IHsgLi4udGhpcy5fc2RrUHJvY2Vzc2luZ01ldGFkYXRhLCAuLi5uZXdEYXRhIH07CgogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBzZXRQcm9wYWdhdGlvbkNvbnRleHQoY29udGV4dCkgewogICAgdGhpcy5fcHJvcGFnYXRpb25Db250ZXh0ID0gY29udGV4dDsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgZ2V0UHJvcGFnYXRpb25Db250ZXh0KCkgewogICAgcmV0dXJuIHRoaXMuX3Byb3BhZ2F0aW9uQ29udGV4dDsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGNhcHR1cmVFeGNlcHRpb24oZXhjZXB0aW9uLCBoaW50KSB7CiAgICBjb25zdCBldmVudElkID0gaGludCAmJiBoaW50LmV2ZW50X2lkID8gaGludC5ldmVudF9pZCA6IHV1aWQ0KCk7CgogICAgaWYgKCF0aGlzLl9jbGllbnQpIHsKICAgICAgbG9nZ2VyLndhcm4oJ05vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBleGNlcHRpb24hJyk7CiAgICAgIHJldHVybiBldmVudElkOwogICAgfQoKICAgIGNvbnN0IHN5bnRoZXRpY0V4Y2VwdGlvbiA9IG5ldyBFcnJvcignU2VudHJ5IHN5bnRoZXRpY0V4Y2VwdGlvbicpOwoKICAgIHRoaXMuX2NsaWVudC5jYXB0dXJlRXhjZXB0aW9uKAogICAgICBleGNlcHRpb24sCiAgICAgIHsKICAgICAgICBvcmlnaW5hbEV4Y2VwdGlvbjogZXhjZXB0aW9uLAogICAgICAgIHN5bnRoZXRpY0V4Y2VwdGlvbiwKICAgICAgICAuLi5oaW50LAogICAgICAgIGV2ZW50X2lkOiBldmVudElkLAogICAgICB9LAogICAgICB0aGlzLAogICAgKTsKCiAgICByZXR1cm4gZXZlbnRJZDsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGNhcHR1cmVNZXNzYWdlKG1lc3NhZ2UsIGxldmVsLCBoaW50KSB7CiAgICBjb25zdCBldmVudElkID0gaGludCAmJiBoaW50LmV2ZW50X2lkID8gaGludC5ldmVudF9pZCA6IHV1aWQ0KCk7CgogICAgaWYgKCF0aGlzLl9jbGllbnQpIHsKICAgICAgbG9nZ2VyLndhcm4oJ05vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBtZXNzYWdlIScpOwogICAgICByZXR1cm4gZXZlbnRJZDsKICAgIH0KCiAgICBjb25zdCBzeW50aGV0aWNFeGNlcHRpb24gPSBuZXcgRXJyb3IobWVzc2FnZSk7CgogICAgdGhpcy5fY2xpZW50LmNhcHR1cmVNZXNzYWdlKAogICAgICBtZXNzYWdlLAogICAgICBsZXZlbCwKICAgICAgewogICAgICAgIG9yaWdpbmFsRXhjZXB0aW9uOiBtZXNzYWdlLAogICAgICAgIHN5bnRoZXRpY0V4Y2VwdGlvbiwKICAgICAgICAuLi5oaW50LAogICAgICAgIGV2ZW50X2lkOiBldmVudElkLAogICAgICB9LAogICAgICB0aGlzLAogICAgKTsKCiAgICByZXR1cm4gZXZlbnRJZDsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGNhcHR1cmVFdmVudChldmVudCwgaGludCkgewogICAgY29uc3QgZXZlbnRJZCA9IGhpbnQgJiYgaGludC5ldmVudF9pZCA/IGhpbnQuZXZlbnRfaWQgOiB1dWlkNCgpOwoKICAgIGlmICghdGhpcy5fY2xpZW50KSB7CiAgICAgIGxvZ2dlci53YXJuKCdObyBjbGllbnQgY29uZmlndXJlZCBvbiBzY29wZSAtIHdpbGwgbm90IGNhcHR1cmUgZXZlbnQhJyk7CiAgICAgIHJldHVybiBldmVudElkOwogICAgfQoKICAgIHRoaXMuX2NsaWVudC5jYXB0dXJlRXZlbnQoZXZlbnQsIHsgLi4uaGludCwgZXZlbnRfaWQ6IGV2ZW50SWQgfSwgdGhpcyk7CgogICAgcmV0dXJuIGV2ZW50SWQ7CiAgfQoKICAvKioKICAgKiBUaGlzIHdpbGwgYmUgY2FsbGVkIG9uIGV2ZXJ5IHNldCBjYWxsLgogICAqLwogICBfbm90aWZ5U2NvcGVMaXN0ZW5lcnMoKSB7CiAgICAvLyBXZSBuZWVkIHRoaXMgY2hlY2sgZm9yIHRoaXMuX25vdGlmeWluZ0xpc3RlbmVycyB0byBiZSBhYmxlIHRvIHdvcmsgb24gc2NvcGUgZHVyaW5nIHVwZGF0ZXMKICAgIC8vIElmIHRoaXMgY2hlY2sgaXMgbm90IGhlcmUgd2UnbGwgcHJvZHVjZSBlbmRsZXNzIHJlY3Vyc2lvbiB3aGVuIHNvbWV0aGluZyBpcyBkb25lIHdpdGggdGhlIHNjb3BlCiAgICAvLyBkdXJpbmcgdGhlIGNhbGxiYWNrLgogICAgaWYgKCF0aGlzLl9ub3RpZnlpbmdMaXN0ZW5lcnMpIHsKICAgICAgdGhpcy5fbm90aWZ5aW5nTGlzdGVuZXJzID0gdHJ1ZTsKICAgICAgdGhpcy5fc2NvcGVMaXN0ZW5lcnMuZm9yRWFjaChjYWxsYmFjayA9PiB7CiAgICAgICAgY2FsbGJhY2sodGhpcyk7CiAgICAgIH0pOwogICAgICB0aGlzLl9ub3RpZnlpbmdMaXN0ZW5lcnMgPSBmYWxzZTsKICAgIH0KICB9Cn0KCmZ1bmN0aW9uIGdlbmVyYXRlUHJvcGFnYXRpb25Db250ZXh0KCkgewogIHJldHVybiB7CiAgICB0cmFjZUlkOiB1dWlkNCgpLAogICAgc3BhbklkOiB1dWlkNCgpLnN1YnN0cmluZygxNiksCiAgfTsKfQoKY29uc3QgU0RLX1ZFUlNJT04gPSAnOC4wLjAtYWxwaGEuMyc7CgovKioKICogQVBJIGNvbXBhdGliaWxpdHkgdmVyc2lvbiBvZiB0aGlzIGh1Yi4KICoKICogV0FSTklORzogVGhpcyBudW1iZXIgc2hvdWxkIG9ubHkgYmUgaW5jcmVhc2VkIHdoZW4gdGhlIGdsb2JhbCBpbnRlcmZhY2UKICogY2hhbmdlcyBhbmQgbmV3IG1ldGhvZHMgYXJlIGludHJvZHVjZWQuCiAqCiAqIEBoaWRkZW4KICovCmNvbnN0IEFQSV9WRVJTSU9OID0gcGFyc2VGbG9hdChTREtfVkVSU0lPTik7CgovKioKICogRGVmYXVsdCBtYXhpbXVtIG51bWJlciBvZiBicmVhZGNydW1icyBhZGRlZCB0byBhbiBldmVudC4gQ2FuIGJlIG92ZXJ3cml0dGVuCiAqIHdpdGgge0BsaW5rIE9wdGlvbnMubWF4QnJlYWRjcnVtYnN9LgogKi8KY29uc3QgREVGQVVMVF9CUkVBRENSVU1CUyQxID0gMTAwOwoKLyoqCiAqIEEgbGF5ZXIgaW4gdGhlIHByb2Nlc3Mgc3RhY2suCiAqIEBoaWRkZW4KICovCgovKioKICogQGluaGVyaXREb2MKICovCmNsYXNzIEh1YiAgewogIC8qKiBJcyBhIHtAbGluayBMYXllcn1bXSBjb250YWluaW5nIHRoZSBjbGllbnQgYW5kIHNjb3BlICovCgogIC8qKgogICAqIENyZWF0ZXMgYSBuZXcgaW5zdGFuY2Ugb2YgdGhlIGh1Yiwgd2lsbCBwdXNoIG9uZSB7QGxpbmsgTGF5ZXJ9IGludG8gdGhlCiAgICogaW50ZXJuYWwgc3RhY2sgb24gY3JlYXRpb24uCiAgICoKICAgKiBAcGFyYW0gY2xpZW50IGJvdW5kIHRvIHRoZSBodWIuCiAgICogQHBhcmFtIHNjb3BlIGJvdW5kIHRvIHRoZSBodWIuCiAgICogQHBhcmFtIHZlcnNpb24gbnVtYmVyLCBoaWdoZXIgbnVtYmVyIG1lYW5zIGhpZ2hlciBwcmlvcml0eS4KICAgKgogICAqIEBkZXByZWNhdGVkIEluc3RhbnRpYXRpb24gb2YgSHViIG9iamVjdHMgaXMgZGVwcmVjYXRlZCBhbmQgdGhlIGNvbnN0cnVjdG9yIHdpbGwgYmUgcmVtb3ZlZCBpbiB2ZXJzaW9uIDggb2YgdGhlIFNESy4KICAgKgogICAqIElmIHlvdSBhcmUgY3VycmVudGx5IHVzaW5nIHRoZSBIdWIgZm9yIG11bHRpLWNsaWVudCB1c2UgbGlrZSBzbzoKICAgKgogICAqIGBgYAogICAqIC8vIE9MRAogICAqIGNvbnN0IGh1YiA9IG5ldyBIdWIoKTsKICAgKiBodWIuYmluZENsaWVudChjbGllbnQpOwogICAqIG1ha2VNYWluKGh1YikKICAgKiBgYGAKICAgKgogICAqIGluc3RlYWQgaW5pdGlhbGl6ZSB0aGUgY2xpZW50IGFzIGZvbGxvd3M6CiAgICoKICAgKiBgYGAKICAgKiAvLyBORVcKICAgKiBTZW50cnkud2l0aElzb2xhdGlvblNjb3BlKCgpID0+IHsKICAgKiAgICBTZW50cnkuc2V0Q3VycmVudENsaWVudChjbGllbnQpOwogICAqICAgIGNsaWVudC5pbml0KCk7CiAgICogfSk7CiAgICogYGBgCiAgICoKICAgKiBJZiB5b3UgYXJlIHVzaW5nIHRoZSBIdWIgdG8gY2FwdHVyZSBldmVudHMgbGlrZSBzbzoKICAgKgogICAqIGBgYAogICAqIC8vIE9MRAogICAqIGNvbnN0IGNsaWVudCA9IG5ldyBDbGllbnQoKTsKICAgKiBjb25zdCBodWIgPSBuZXcgSHViKGNsaWVudCk7CiAgICogaHViLmNhcHR1cmVFeGNlcHRpb24oKQogICAqIGBgYAogICAqCiAgICogaW5zdGVhZCBjYXB0dXJlIGlzb2xhdGVkIGV2ZW50cyBhcyBmb2xsb3dzOgogICAqCiAgICogYGBgCiAgICogLy8gTkVXCiAgICogY29uc3QgY2xpZW50ID0gbmV3IENsaWVudCgpOwogICAqIGNvbnN0IHNjb3BlID0gbmV3IFNjb3BlKCk7CiAgICogc2NvcGUuc2V0Q2xpZW50KGNsaWVudCk7CiAgICogc2NvcGUuY2FwdHVyZUV4Y2VwdGlvbigpOwogICAqIGBgYAogICAqLwogICBjb25zdHJ1Y3RvcigKICAgIGNsaWVudCwKICAgIHNjb3BlLAogICAgaXNvbGF0aW9uU2NvcGUsCiAgICAgIF92ZXJzaW9uID0gQVBJX1ZFUlNJT04sCiAgKSB7dGhpcy5fdmVyc2lvbiA9IF92ZXJzaW9uOwogICAgbGV0IGFzc2lnbmVkU2NvcGU7CiAgICBpZiAoIXNjb3BlKSB7CiAgICAgIGFzc2lnbmVkU2NvcGUgPSBuZXcgU2NvcGUoKTsKICAgICAgYXNzaWduZWRTY29wZS5zZXRDbGllbnQoY2xpZW50KTsKICAgIH0gZWxzZSB7CiAgICAgIGFzc2lnbmVkU2NvcGUgPSBzY29wZTsKICAgIH0KCiAgICBsZXQgYXNzaWduZWRJc29sYXRpb25TY29wZTsKICAgIGlmICghaXNvbGF0aW9uU2NvcGUpIHsKICAgICAgYXNzaWduZWRJc29sYXRpb25TY29wZSA9IG5ldyBTY29wZSgpOwogICAgICBhc3NpZ25lZElzb2xhdGlvblNjb3BlLnNldENsaWVudChjbGllbnQpOwogICAgfSBlbHNlIHsKICAgICAgYXNzaWduZWRJc29sYXRpb25TY29wZSA9IGlzb2xhdGlvblNjb3BlOwogICAgfQoKICAgIHRoaXMuX3N0YWNrID0gW3sgc2NvcGU6IGFzc2lnbmVkU2NvcGUgfV07CgogICAgaWYgKGNsaWVudCkgewogICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgICAgdGhpcy5iaW5kQ2xpZW50KGNsaWVudCk7CiAgICB9CgogICAgdGhpcy5faXNvbGF0aW9uU2NvcGUgPSBhc3NpZ25lZElzb2xhdGlvblNjb3BlOwogIH0KCiAgLyoqCiAgICogQ2hlY2tzIGlmIHRoaXMgaHViJ3MgdmVyc2lvbiBpcyBvbGRlciB0aGFuIHRoZSBnaXZlbiB2ZXJzaW9uLgogICAqCiAgICogQHBhcmFtIHZlcnNpb24gQSB2ZXJzaW9uIG51bWJlciB0byBjb21wYXJlIHRvLgogICAqIEByZXR1cm4gVHJ1ZSBpZiB0aGUgZ2l2ZW4gdmVyc2lvbiBpcyBuZXdlcjsgb3RoZXJ3aXNlIGZhbHNlLgogICAqCiAgICogQGRlcHJlY2F0ZWQgVGhpcyB3aWxsIGJlIHJlbW92ZWQgaW4gdjguCiAgICovCiAgIGlzT2xkZXJUaGFuKHZlcnNpb24pIHsKICAgIHJldHVybiB0aGlzLl92ZXJzaW9uIDwgdmVyc2lvbjsKICB9CgogIC8qKgogICAqIFRoaXMgYmluZHMgdGhlIGdpdmVuIGNsaWVudCB0byB0aGUgY3VycmVudCBzY29wZS4KICAgKiBAcGFyYW0gY2xpZW50IEFuIFNESyBjbGllbnQgKGNsaWVudCkgaW5zdGFuY2UuCiAgICoKICAgKiBAZGVwcmVjYXRlZCBVc2UgYGluaXRBbmRCaW5kKClgIGRpcmVjdGx5LCBvciBgc2V0Q3VycmVudENsaWVudCgpYCBhbmQvb3IgYGNsaWVudC5pbml0KClgIGluc3RlYWQuCiAgICovCiAgIGJpbmRDbGllbnQoY2xpZW50KSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGNvbnN0IHRvcCA9IHRoaXMuZ2V0U3RhY2tUb3AoKTsKICAgIHRvcC5jbGllbnQgPSBjbGllbnQ7CiAgICB0b3Auc2NvcGUuc2V0Q2xpZW50KGNsaWVudCk7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGlmIChjbGllbnQgJiYgY2xpZW50LnNldHVwSW50ZWdyYXRpb25zKSB7CiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgICBjbGllbnQuc2V0dXBJbnRlZ3JhdGlvbnMoKTsKICAgIH0KICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICoKICAgKiBAZGVwcmVjYXRlZCBVc2UgYHdpdGhTY29wZWAgaW5zdGVhZC4KICAgKi8KICAgcHVzaFNjb3BlKCkgewogICAgLy8gV2Ugd2FudCB0byBjbG9uZSB0aGUgY29udGVudCBvZiBwcmV2IHNjb3BlCiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGNvbnN0IHNjb3BlID0gdGhpcy5nZXRTY29wZSgpLmNsb25lKCk7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHRoaXMuZ2V0U3RhY2soKS5wdXNoKHsKICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICAgIGNsaWVudDogdGhpcy5nZXRDbGllbnQoKSwKICAgICAgc2NvcGUsCiAgICB9KTsKICAgIHJldHVybiBzY29wZTsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICoKICAgKiBAZGVwcmVjYXRlZCBVc2UgYHdpdGhTY29wZWAgaW5zdGVhZC4KICAgKi8KICAgcG9wU2NvcGUoKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGlmICh0aGlzLmdldFN0YWNrKCkubGVuZ3RoIDw9IDEpIHJldHVybiBmYWxzZTsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgcmV0dXJuICEhdGhpcy5nZXRTdGFjaygpLnBvcCgpOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKgogICAqIEBkZXByZWNhdGVkIFVzZSBgU2VudHJ5LndpdGhTY29wZSgpYCBpbnN0ZWFkLgogICAqLwogICB3aXRoU2NvcGUoY2FsbGJhY2spIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgY29uc3Qgc2NvcGUgPSB0aGlzLnB1c2hTY29wZSgpOwoKICAgIGxldCBtYXliZVByb21pc2VSZXN1bHQ7CiAgICB0cnkgewogICAgICBtYXliZVByb21pc2VSZXN1bHQgPSBjYWxsYmFjayhzY29wZSk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgICB0aGlzLnBvcFNjb3BlKCk7CiAgICAgIHRocm93IGU7CiAgICB9CgogICAgaWYgKGlzVGhlbmFibGUobWF5YmVQcm9taXNlUmVzdWx0KSkgewogICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIC0gaXNUaGVuYWJsZSByZXR1cm5zIHRoZSB3cm9uZyB0eXBlCiAgICAgIHJldHVybiBtYXliZVByb21pc2VSZXN1bHQudGhlbigKICAgICAgICByZXMgPT4gewogICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICAgICAgICB0aGlzLnBvcFNjb3BlKCk7CiAgICAgICAgICByZXR1cm4gcmVzOwogICAgICAgIH0sCiAgICAgICAgZSA9PiB7CiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgICAgICAgIHRoaXMucG9wU2NvcGUoKTsKICAgICAgICAgIHRocm93IGU7CiAgICAgICAgfSwKICAgICAgKTsKICAgIH0KCiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHRoaXMucG9wU2NvcGUoKTsKICAgIHJldHVybiBtYXliZVByb21pc2VSZXN1bHQ7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqCiAgICogQGRlcHJlY2F0ZWQgVXNlIGBTZW50cnkuZ2V0Q2xpZW50KClgIGluc3RlYWQuCiAgICovCiAgIGdldENsaWVudCgpIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgcmV0dXJuIHRoaXMuZ2V0U3RhY2tUb3AoKS5jbGllbnQgOwogIH0KCiAgLyoqCiAgICogUmV0dXJucyB0aGUgc2NvcGUgb2YgdGhlIHRvcCBzdGFjay4KICAgKgogICAqIEBkZXByZWNhdGVkIFVzZSBgU2VudHJ5LmdldEN1cnJlbnRTY29wZSgpYCBpbnN0ZWFkLgogICAqLwogICBnZXRTY29wZSgpIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgcmV0dXJuIHRoaXMuZ2V0U3RhY2tUb3AoKS5zY29wZTsKICB9CgogIC8qKgogICAqIEBkZXByZWNhdGVkIFVzZSBgU2VudHJ5LmdldElzb2xhdGlvblNjb3BlKClgIGluc3RlYWQuCiAgICovCiAgIGdldElzb2xhdGlvblNjb3BlKCkgewogICAgcmV0dXJuIHRoaXMuX2lzb2xhdGlvblNjb3BlOwogIH0KCiAgLyoqCiAgICogUmV0dXJucyB0aGUgc2NvcGUgc3RhY2sgZm9yIGRvbWFpbnMgb3IgdGhlIHByb2Nlc3MuCiAgICogQGRlcHJlY2F0ZWQgVGhpcyB3aWxsIGJlIHJlbW92ZWQgaW4gdjguCiAgICovCiAgIGdldFN0YWNrKCkgewogICAgcmV0dXJuIHRoaXMuX3N0YWNrOwogIH0KCiAgLyoqCiAgICogUmV0dXJucyB0aGUgdG9wbW9zdCBzY29wZSBsYXllciBpbiB0aGUgb3JkZXIgZG9tYWluID4gbG9jYWwgPiBwcm9jZXNzLgogICAqIEBkZXByZWNhdGVkIFRoaXMgd2lsbCBiZSByZW1vdmVkIGluIHY4LgogICAqLwogICBnZXRTdGFja1RvcCgpIHsKICAgIHJldHVybiB0aGlzLl9zdGFja1t0aGlzLl9zdGFjay5sZW5ndGggLSAxXTsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICoKICAgKiBAZGVwcmVjYXRlZCBVc2UgYFNlbnRyeS5jYXB0dXJlRXhjZXB0aW9uKClgIGluc3RlYWQuCiAgICovCiAgIGNhcHR1cmVFeGNlcHRpb24oZXhjZXB0aW9uLCBoaW50KSB7CiAgICBjb25zdCBldmVudElkID0gaGludCAmJiBoaW50LmV2ZW50X2lkID8gaGludC5ldmVudF9pZCA6IHV1aWQ0KCk7CiAgICBjb25zdCBzeW50aGV0aWNFeGNlcHRpb24gPSBuZXcgRXJyb3IoJ1NlbnRyeSBzeW50aGV0aWNFeGNlcHRpb24nKTsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgdGhpcy5nZXRTY29wZSgpLmNhcHR1cmVFeGNlcHRpb24oZXhjZXB0aW9uLCB7CiAgICAgIG9yaWdpbmFsRXhjZXB0aW9uOiBleGNlcHRpb24sCiAgICAgIHN5bnRoZXRpY0V4Y2VwdGlvbiwKICAgICAgLi4uaGludCwKICAgICAgZXZlbnRfaWQ6IGV2ZW50SWQsCiAgICB9KTsKCiAgICByZXR1cm4gZXZlbnRJZDsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICoKICAgKiBAZGVwcmVjYXRlZCBVc2UgIGBTZW50cnkuY2FwdHVyZU1lc3NhZ2UoKWAgaW5zdGVhZC4KICAgKi8KICAgY2FwdHVyZU1lc3NhZ2UobWVzc2FnZSwgbGV2ZWwsIGhpbnQpIHsKICAgIGNvbnN0IGV2ZW50SWQgPSBoaW50ICYmIGhpbnQuZXZlbnRfaWQgPyBoaW50LmV2ZW50X2lkIDogdXVpZDQoKTsKICAgIGNvbnN0IHN5bnRoZXRpY0V4Y2VwdGlvbiA9IG5ldyBFcnJvcihtZXNzYWdlKTsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgdGhpcy5nZXRTY29wZSgpLmNhcHR1cmVNZXNzYWdlKG1lc3NhZ2UsIGxldmVsLCB7CiAgICAgIG9yaWdpbmFsRXhjZXB0aW9uOiBtZXNzYWdlLAogICAgICBzeW50aGV0aWNFeGNlcHRpb24sCiAgICAgIC4uLmhpbnQsCiAgICAgIGV2ZW50X2lkOiBldmVudElkLAogICAgfSk7CgogICAgcmV0dXJuIGV2ZW50SWQ7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqCiAgICogQGRlcHJlY2F0ZWQgVXNlIGBTZW50cnkuY2FwdHVyZUV2ZW50KClgIGluc3RlYWQuCiAgICovCiAgIGNhcHR1cmVFdmVudChldmVudCwgaGludCkgewogICAgY29uc3QgZXZlbnRJZCA9IGhpbnQgJiYgaGludC5ldmVudF9pZCA/IGhpbnQuZXZlbnRfaWQgOiB1dWlkNCgpOwogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICB0aGlzLmdldFNjb3BlKCkuY2FwdHVyZUV2ZW50KGV2ZW50LCB7IC4uLmhpbnQsIGV2ZW50X2lkOiBldmVudElkIH0pOwogICAgcmV0dXJuIGV2ZW50SWQ7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqCiAgICogQGRlcHJlY2F0ZWQgVXNlIGBTZW50cnkuYWRkQnJlYWRjcnVtYigpYCBpbnN0ZWFkLgogICAqLwogICBhZGRCcmVhZGNydW1iKGJyZWFkY3J1bWIsIGhpbnQpIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgY29uc3QgeyBjbGllbnQgfSA9IHRoaXMuZ2V0U3RhY2tUb3AoKTsKCiAgICBpZiAoIWNsaWVudCkgcmV0dXJuOwoKICAgIGNvbnN0IHsgYmVmb3JlQnJlYWRjcnVtYiA9IG51bGwsIG1heEJyZWFkY3J1bWJzID0gREVGQVVMVF9CUkVBRENSVU1CUyQxIH0gPQogICAgICAoY2xpZW50LmdldE9wdGlvbnMgJiYgY2xpZW50LmdldE9wdGlvbnMoKSkgfHwge307CgogICAgaWYgKG1heEJyZWFkY3J1bWJzIDw9IDApIHJldHVybjsKCiAgICBjb25zdCB0aW1lc3RhbXAgPSBkYXRlVGltZXN0YW1wSW5TZWNvbmRzKCk7CiAgICBjb25zdCBtZXJnZWRCcmVhZGNydW1iID0geyB0aW1lc3RhbXAsIC4uLmJyZWFkY3J1bWIgfTsKICAgIGNvbnN0IGZpbmFsQnJlYWRjcnVtYiA9IGJlZm9yZUJyZWFkY3J1bWIKICAgICAgPyAoY29uc29sZVNhbmRib3goKCkgPT4gYmVmb3JlQnJlYWRjcnVtYihtZXJnZWRCcmVhZGNydW1iLCBoaW50KSkgKQogICAgICA6IG1lcmdlZEJyZWFkY3J1bWI7CgogICAgaWYgKGZpbmFsQnJlYWRjcnVtYiA9PT0gbnVsbCkgcmV0dXJuOwoKICAgIGNsaWVudC5lbWl0KCdiZWZvcmVBZGRCcmVhZGNydW1iJywgZmluYWxCcmVhZGNydW1iLCBoaW50KTsKCiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHRoaXMuZ2V0SXNvbGF0aW9uU2NvcGUoKS5hZGRCcmVhZGNydW1iKGZpbmFsQnJlYWRjcnVtYiwgbWF4QnJlYWRjcnVtYnMpOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKiBAZGVwcmVjYXRlZCBVc2UgYFNlbnRyeS5zZXRVc2VyKClgIGluc3RlYWQuCiAgICovCiAgIHNldFVzZXIodXNlcikgewogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICB0aGlzLmdldElzb2xhdGlvblNjb3BlKCkuc2V0VXNlcih1c2VyKTsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICogQGRlcHJlY2F0ZWQgVXNlIGBTZW50cnkuc2V0VGFncygpYCBpbnN0ZWFkLgogICAqLwogICBzZXRUYWdzKHRhZ3MpIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgdGhpcy5nZXRJc29sYXRpb25TY29wZSgpLnNldFRhZ3ModGFncyk7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqIEBkZXByZWNhdGVkIFVzZSBgU2VudHJ5LnNldEV4dHJhcygpYCBpbnN0ZWFkLgogICAqLwogICBzZXRFeHRyYXMoZXh0cmFzKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHRoaXMuZ2V0SXNvbGF0aW9uU2NvcGUoKS5zZXRFeHRyYXMoZXh0cmFzKTsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICogQGRlcHJlY2F0ZWQgVXNlIGBTZW50cnkuc2V0VGFnKClgIGluc3RlYWQuCiAgICovCiAgIHNldFRhZyhrZXksIHZhbHVlKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHRoaXMuZ2V0SXNvbGF0aW9uU2NvcGUoKS5zZXRUYWcoa2V5LCB2YWx1ZSk7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqIEBkZXByZWNhdGVkIFVzZSBgU2VudHJ5LnNldEV4dHJhKClgIGluc3RlYWQuCiAgICovCiAgIHNldEV4dHJhKGtleSwgZXh0cmEpIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgdGhpcy5nZXRJc29sYXRpb25TY29wZSgpLnNldEV4dHJhKGtleSwgZXh0cmEpOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKiBAZGVwcmVjYXRlZCBVc2UgYFNlbnRyeS5zZXRDb250ZXh0KClgIGluc3RlYWQuCiAgICovCiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkKICAgc2V0Q29udGV4dChuYW1lLCBjb250ZXh0KSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHRoaXMuZ2V0SXNvbGF0aW9uU2NvcGUoKS5zZXRDb250ZXh0KG5hbWUsIGNvbnRleHQpOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKiBAZGVwcmVjYXRlZCBVc2UgYFNlbnRyeS5nZXRDbGllbnQoKS5nZXRJbnRlZ3JhdGlvbkJ5TmFtZSgpYCBpbnN0ZWFkLgogICAqLwogICBnZXRJbnRlZ3JhdGlvbihpbnRlZ3JhdGlvbikgewogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICBjb25zdCBjbGllbnQgPSB0aGlzLmdldENsaWVudCgpOwogICAgaWYgKCFjbGllbnQpIHJldHVybiBudWxsOwogICAgdHJ5IHsKICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICAgIHJldHVybiBjbGllbnQuZ2V0SW50ZWdyYXRpb24oaW50ZWdyYXRpb24pOwogICAgfSBjYXRjaCAoX29PKSB7CiAgICAgIERFQlVHX0JVSUxEICYmIGxvZ2dlci53YXJuKGBDYW5ub3QgcmV0cmlldmUgaW50ZWdyYXRpb24gJHtpbnRlZ3JhdGlvbi5pZH0gZnJvbSB0aGUgY3VycmVudCBIdWJgKTsKICAgICAgcmV0dXJuIG51bGw7CiAgICB9CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqCiAgICogQGRlcHJlY2F0ZWQgVXNlIHRvcCBsZXZlbCBgY2FwdHVyZVNlc3Npb25gIGluc3RlYWQuCiAgICovCiAgIGNhcHR1cmVTZXNzaW9uKGVuZFNlc3Npb24gPSBmYWxzZSkgewogICAgLy8gYm90aCBzZW5kIHRoZSB1cGRhdGUgYW5kIHB1bGwgdGhlIHNlc3Npb24gZnJvbSB0aGUgc2NvcGUKICAgIGlmIChlbmRTZXNzaW9uKSB7CiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgICByZXR1cm4gdGhpcy5lbmRTZXNzaW9uKCk7CiAgICB9CgogICAgLy8gb25seSBzZW5kIHRoZSB1cGRhdGUKICAgIHRoaXMuX3NlbmRTZXNzaW9uVXBkYXRlKCk7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqIEBkZXByZWNhdGVkIFVzZSB0b3AgbGV2ZWwgYGVuZFNlc3Npb25gIGluc3RlYWQuCiAgICovCiAgIGVuZFNlc3Npb24oKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGNvbnN0IGxheWVyID0gdGhpcy5nZXRTdGFja1RvcCgpOwogICAgY29uc3Qgc2NvcGUgPSBsYXllci5zY29wZTsKICAgIGNvbnN0IHNlc3Npb24gPSBzY29wZS5nZXRTZXNzaW9uKCk7CiAgICBpZiAoc2Vzc2lvbikgewogICAgICBjbG9zZVNlc3Npb24oc2Vzc2lvbik7CiAgICB9CiAgICB0aGlzLl9zZW5kU2Vzc2lvblVwZGF0ZSgpOwoKICAgIC8vIHRoZSBzZXNzaW9uIGlzIG92ZXI7IHRha2UgaXQgb2ZmIG9mIHRoZSBzY29wZQogICAgc2NvcGUuc2V0U2Vzc2lvbigpOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKiBAZGVwcmVjYXRlZCBVc2UgdG9wIGxldmVsIGBzdGFydFNlc3Npb25gIGluc3RlYWQuCiAgICovCiAgIHN0YXJ0U2Vzc2lvbihjb250ZXh0KSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGNvbnN0IHsgc2NvcGUsIGNsaWVudCB9ID0gdGhpcy5nZXRTdGFja1RvcCgpOwogICAgY29uc3QgeyByZWxlYXNlLCBlbnZpcm9ubWVudCA9IERFRkFVTFRfRU5WSVJPTk1FTlQgfSA9IChjbGllbnQgJiYgY2xpZW50LmdldE9wdGlvbnMoKSkgfHwge307CgogICAgLy8gV2lsbCBmZXRjaCB1c2VyQWdlbnQgaWYgY2FsbGVkIGZyb20gYnJvd3NlciBzZGsKICAgIGNvbnN0IHsgdXNlckFnZW50IH0gPSBHTE9CQUxfT0JKLm5hdmlnYXRvciB8fCB7fTsKCiAgICBjb25zdCBzZXNzaW9uID0gbWFrZVNlc3Npb24oewogICAgICByZWxlYXNlLAogICAgICBlbnZpcm9ubWVudCwKICAgICAgdXNlcjogc2NvcGUuZ2V0VXNlcigpLAogICAgICAuLi4odXNlckFnZW50ICYmIHsgdXNlckFnZW50IH0pLAogICAgICAuLi5jb250ZXh0LAogICAgfSk7CgogICAgLy8gRW5kIGV4aXN0aW5nIHNlc3Npb24gaWYgdGhlcmUncyBvbmUKICAgIGNvbnN0IGN1cnJlbnRTZXNzaW9uID0gc2NvcGUuZ2V0U2Vzc2lvbiAmJiBzY29wZS5nZXRTZXNzaW9uKCk7CiAgICBpZiAoY3VycmVudFNlc3Npb24gJiYgY3VycmVudFNlc3Npb24uc3RhdHVzID09PSAnb2snKSB7CiAgICAgIHVwZGF0ZVNlc3Npb24oY3VycmVudFNlc3Npb24sIHsgc3RhdHVzOiAnZXhpdGVkJyB9KTsKICAgIH0KICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgdGhpcy5lbmRTZXNzaW9uKCk7CgogICAgLy8gQWZ0ZXJ3YXJkcyB3ZSBzZXQgdGhlIG5ldyBzZXNzaW9uIG9uIHRoZSBzY29wZQogICAgc2NvcGUuc2V0U2Vzc2lvbihzZXNzaW9uKTsKCiAgICByZXR1cm4gc2Vzc2lvbjsKICB9CgogIC8qKgogICAqIFJldHVybnMgaWYgZGVmYXVsdCBQSUkgc2hvdWxkIGJlIHNlbnQgdG8gU2VudHJ5IGFuZCBwcm9wYWdhdGVkIGluIG91cmdvaW5nIHJlcXVlc3RzCiAgICogd2hlbiBUcmFjaW5nIGlzIHVzZWQuCiAgICoKICAgKiBAZGVwcmVjYXRlZCBVc2UgdG9wLWxldmVsIGBnZXRDbGllbnQoKS5nZXRPcHRpb25zKCkuc2VuZERlZmF1bHRQaWlgIGluc3RlYWQuIFRoaXMgZnVuY3Rpb24KICAgKiBvbmx5IHVubmVjZXNzYXJpbHkgaW5jcmVhc2VkIEFQSSBzdXJmYWNlIGJ1dCBvbmx5IHdyYXBwZWQgYWNjZXNzaW5nIHRoZSBvcHRpb24uCiAgICovCiAgIHNob3VsZFNlbmREZWZhdWx0UGlpKCkgewogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICBjb25zdCBjbGllbnQgPSB0aGlzLmdldENsaWVudCgpOwogICAgY29uc3Qgb3B0aW9ucyA9IGNsaWVudCAmJiBjbGllbnQuZ2V0T3B0aW9ucygpOwogICAgcmV0dXJuIEJvb2xlYW4ob3B0aW9ucyAmJiBvcHRpb25zLnNlbmREZWZhdWx0UGlpKTsKICB9CgogIC8qKgogICAqIFNlbmRzIHRoZSBjdXJyZW50IFNlc3Npb24gb24gdGhlIHNjb3BlCiAgICovCiAgIF9zZW5kU2Vzc2lvblVwZGF0ZSgpIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgY29uc3QgeyBzY29wZSwgY2xpZW50IH0gPSB0aGlzLmdldFN0YWNrVG9wKCk7CgogICAgY29uc3Qgc2Vzc2lvbiA9IHNjb3BlLmdldFNlc3Npb24oKTsKICAgIGlmIChzZXNzaW9uICYmIGNsaWVudCAmJiBjbGllbnQuY2FwdHVyZVNlc3Npb24pIHsKICAgICAgY2xpZW50LmNhcHR1cmVTZXNzaW9uKHNlc3Npb24pOwogICAgfQogIH0KCiAgLyoqCiAgICogQ2FsbHMgZ2xvYmFsIGV4dGVuc2lvbiBtZXRob2QgYW5kIGJpbmRpbmcgY3VycmVudCBpbnN0YW5jZSB0byB0aGUgZnVuY3Rpb24gY2FsbAogICAqLwogIC8vIEB0cy1leHBlY3QtZXJyb3IgRnVuY3Rpb24gbGFja3MgZW5kaW5nIHJldHVybiBzdGF0ZW1lbnQgYW5kIHJldHVybiB0eXBlIGRvZXMgbm90IGluY2x1ZGUgJ3VuZGVmaW5lZCcuIHRzKDIzNjYpCiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkKICAgX2NhbGxFeHRlbnNpb25NZXRob2QobWV0aG9kLCAuLi5hcmdzKSB7CiAgICBjb25zdCBjYXJyaWVyID0gZ2V0TWFpbkNhcnJpZXIoKTsKICAgIGNvbnN0IHNlbnRyeSA9IGdldFNlbnRyeUNhcnJpZXIoY2Fycmllcik7CiAgICBpZiAoc2VudHJ5LmV4dGVuc2lvbnMgJiYgdHlwZW9mIHNlbnRyeS5leHRlbnNpb25zW21ldGhvZF0gPT09ICdmdW5jdGlvbicpIHsKICAgICAgcmV0dXJuIHNlbnRyeS5leHRlbnNpb25zW21ldGhvZF0uYXBwbHkodGhpcywgYXJncyk7CiAgICB9CiAgICBERUJVR19CVUlMRCAmJiBsb2dnZXIud2FybihgRXh0ZW5zaW9uIG1ldGhvZCAke21ldGhvZH0gY291bGRuJ3QgYmUgZm91bmQsIGRvaW5nIG5vdGhpbmcuYCk7CiAgfQp9CgovKiogR2V0IHRoZSBkZWZhdWx0IGN1cnJlbnQgc2NvcGUuICovCmZ1bmN0aW9uIGdldERlZmF1bHRDdXJyZW50U2NvcGUoKSB7CiAgcmV0dXJuIGdldEdsb2JhbFNpbmdsZXRvbignZGVmYXVsdEN1cnJlbnRTY29wZScsICgpID0+IG5ldyBTY29wZSgpKTsKfQoKLyoqIEdldCB0aGUgZGVmYXVsdCBpc29sYXRpb24gc2NvcGUuICovCmZ1bmN0aW9uIGdldERlZmF1bHRJc29sYXRpb25TY29wZSgpIHsKICByZXR1cm4gZ2V0R2xvYmFsU2luZ2xldG9uKCdkZWZhdWx0SXNvbGF0aW9uU2NvcGUnLCAoKSA9PiBuZXcgU2NvcGUoKSk7Cn0KCi8qKgogKiBHZXQgdGhlIGdsb2JhbCBodWIuCiAqIFRoaXMgd2lsbCBiZSByZW1vdmVkIGR1cmluZyB0aGUgdjggY3ljbGUgYW5kIGlzIG9ubHkgaGVyZSB0byBtYWtlIG1pZ3JhdGlvbiBlYXNpZXIuCiAqLwpmdW5jdGlvbiBnZXRHbG9iYWxIdWIoKSB7CiAgY29uc3QgcmVnaXN0cnkgPSBnZXRNYWluQ2FycmllcigpOwogIGNvbnN0IHNlbnRyeSA9IGdldFNlbnRyeUNhcnJpZXIocmVnaXN0cnkpIDsKCiAgLy8gSWYgdGhlcmUncyBubyBodWIsIG9yIGl0cyBhbiBvbGQgQVBJLCBhc3NpZ24gYSBuZXcgb25lCiAgaWYgKHNlbnRyeS5odWIpIHsKICAgIHJldHVybiBzZW50cnkuaHViOwogIH0KCiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgc2VudHJ5Lmh1YiA9IG5ldyBIdWIodW5kZWZpbmVkLCBnZXREZWZhdWx0Q3VycmVudFNjb3BlKCksIGdldERlZmF1bHRJc29sYXRpb25TY29wZSgpKTsKICByZXR1cm4gc2VudHJ5Lmh1YjsKfQoKLyoqCiAqIEdldCB0aGUgY3VycmVudCBhc3luYyBjb250ZXh0IHN0cmF0ZWd5LgogKiBJZiBub25lIGhhcyBiZWVuIHNldHVwLCB0aGUgZGVmYXVsdCB3aWxsIGJlIHVzZWQuCiAqLwpmdW5jdGlvbiBnZXRBc3luY0NvbnRleHRTdHJhdGVneShjYXJyaWVyKSB7CiAgY29uc3Qgc2VudHJ5ID0gZ2V0U2VudHJ5Q2FycmllcihjYXJyaWVyKTsKCiAgaWYgKHNlbnRyeS5hY3MpIHsKICAgIHJldHVybiBzZW50cnkuYWNzOwogIH0KCiAgLy8gT3RoZXJ3aXNlLCB1c2UgdGhlIGRlZmF1bHQgb25lCiAgcmV0dXJuIGdldEh1YlN0YWNrQXN5bmNDb250ZXh0U3RyYXRlZ3koKTsKfQoKZnVuY3Rpb24gd2l0aFNjb3BlJDEoY2FsbGJhY2spIHsKICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICByZXR1cm4gZ2V0R2xvYmFsSHViKCkud2l0aFNjb3BlKGNhbGxiYWNrKTsKfQoKZnVuY3Rpb24gd2l0aFNldFNjb3BlKHNjb3BlLCBjYWxsYmFjaykgewogIGNvbnN0IGh1YiA9IGdldEdsb2JhbEh1YigpIDsKICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICByZXR1cm4gaHViLndpdGhTY29wZSgoKSA9PiB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGh1Yi5nZXRTdGFja1RvcCgpLnNjb3BlID0gc2NvcGUgOwogICAgcmV0dXJuIGNhbGxiYWNrKHNjb3BlKTsKICB9KTsKfQoKZnVuY3Rpb24gd2l0aElzb2xhdGlvblNjb3BlJDEoY2FsbGJhY2spIHsKICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICByZXR1cm4gZ2V0R2xvYmFsSHViKCkud2l0aFNjb3BlKCgpID0+IHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgcmV0dXJuIGNhbGxiYWNrKGdldEdsb2JhbEh1YigpLmdldElzb2xhdGlvblNjb3BlKCkpOwogIH0pOwp9CgovKiBlc2xpbnQtZGlzYWJsZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbiAqLwpmdW5jdGlvbiBnZXRIdWJTdGFja0FzeW5jQ29udGV4dFN0cmF0ZWd5KCkgewogIHJldHVybiB7CiAgICBnZXRDdXJyZW50SHViOiBnZXRHbG9iYWxIdWIsCiAgICB3aXRoSXNvbGF0aW9uU2NvcGU6IHdpdGhJc29sYXRpb25TY29wZSQxLAogICAgd2l0aFNjb3BlOiB3aXRoU2NvcGUkMSwKICAgIHdpdGhTZXRTY29wZSwKICAgIHdpdGhTZXRJc29sYXRpb25TY29wZTogKF9pc29sYXRpb25TY29wZSwgY2FsbGJhY2spID0+IHsKICAgICAgcmV0dXJuIHdpdGhJc29sYXRpb25TY29wZSQxKGNhbGxiYWNrKTsKICAgIH0sCiAgICBnZXRDdXJyZW50U2NvcGU6ICgpID0+IGdldEdsb2JhbEh1YigpLmdldFNjb3BlKCksCiAgICBnZXRJc29sYXRpb25TY29wZTogKCkgPT4gZ2V0R2xvYmFsSHViKCkuZ2V0SXNvbGF0aW9uU2NvcGUoKSwKICB9Owp9Ci8qIGVzbGludC1lbmFibGUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24gKi8KCi8qKgogKiBHZXQgdGhlIGN1cnJlbnRseSBhY3RpdmUgc2NvcGUuCiAqLwpmdW5jdGlvbiBnZXRDdXJyZW50U2NvcGUoKSB7CiAgY29uc3QgY2FycmllciA9IGdldE1haW5DYXJyaWVyKCk7CiAgY29uc3QgYWNzID0gZ2V0QXN5bmNDb250ZXh0U3RyYXRlZ3koY2Fycmllcik7CiAgcmV0dXJuIGFjcy5nZXRDdXJyZW50U2NvcGUoKTsKfQoKLyoqCiAqIEdldCB0aGUgY3VycmVudGx5IGFjdGl2ZSBjbGllbnQuCiAqLwpmdW5jdGlvbiBnZXRDbGllbnQoKSB7CiAgcmV0dXJuIGdldEN1cnJlbnRTY29wZSgpLmdldENsaWVudCgpOwp9CgovKioKICogRmV0Y2hlcyB0aGUgbWV0cmljIHN1bW1hcnkgaWYgaXQgZXhpc3RzIGZvciB0aGUgcGFzc2VkIHNwYW4KICovCmZ1bmN0aW9uIGdldE1ldHJpY1N1bW1hcnlKc29uRm9yU3BhbihzcGFuKSB7CgogIHsKICAgIHJldHVybiB1bmRlZmluZWQ7CiAgfQp9CgovKioKICogVXNlIHRoaXMgYXR0cmlidXRlIHRvIHJlcHJlc2VudCB0aGUgb3BlcmF0aW9uIG9mIGEgc3Bhbi4KICovCmNvbnN0IFNFTUFOVElDX0FUVFJJQlVURV9TRU5UUllfT1AgPSAnc2VudHJ5Lm9wJzsKCi8qKgogKiBVc2UgdGhpcyBhdHRyaWJ1dGUgdG8gcmVwcmVzZW50IHRoZSBvcmlnaW4gb2YgYSBzcGFuLgogKi8KY29uc3QgU0VNQU5USUNfQVRUUklCVVRFX1NFTlRSWV9PUklHSU4gPSAnc2VudHJ5Lm9yaWdpbic7Cgpjb25zdCBTUEFOX1NUQVRVU19VTlNFVCA9IDA7CmNvbnN0IFNQQU5fU1RBVFVTX09LID0gMTsKCi8qKgogKiBDb252ZXJ0IGEgc3BhbiB0aW1lIGlucHV0IGludHAgYSB0aW1lc3RhbXAgaW4gc2Vjb25kcy4KICovCmZ1bmN0aW9uIHNwYW5UaW1lSW5wdXRUb1NlY29uZHMoaW5wdXQpIHsKICBpZiAodHlwZW9mIGlucHV0ID09PSAnbnVtYmVyJykgewogICAgcmV0dXJuIGVuc3VyZVRpbWVzdGFtcEluU2Vjb25kcyhpbnB1dCk7CiAgfQoKICBpZiAoQXJyYXkuaXNBcnJheShpbnB1dCkpIHsKICAgIC8vIFNlZSB7QGxpbmsgSHJUaW1lfSBmb3IgdGhlIGFycmF5LWJhc2VkIHRpbWUgZm9ybWF0CiAgICByZXR1cm4gaW5wdXRbMF0gKyBpbnB1dFsxXSAvIDFlOTsKICB9CgogIGlmIChpbnB1dCBpbnN0YW5jZW9mIERhdGUpIHsKICAgIHJldHVybiBlbnN1cmVUaW1lc3RhbXBJblNlY29uZHMoaW5wdXQuZ2V0VGltZSgpKTsKICB9CgogIHJldHVybiB0aW1lc3RhbXBJblNlY29uZHMoKTsKfQoKLyoqCiAqIENvbnZlcnRzIGEgdGltZXN0YW1wIHRvIHNlY29uZCwgaWYgaXQgd2FzIGluIG1pbGxpc2Vjb25kcywgb3Iga2VlcHMgaXQgYXMgc2Vjb25kLgogKi8KZnVuY3Rpb24gZW5zdXJlVGltZXN0YW1wSW5TZWNvbmRzKHRpbWVzdGFtcCkgewogIGNvbnN0IGlzTXMgPSB0aW1lc3RhbXAgPiA5OTk5OTk5OTk5OwogIHJldHVybiBpc01zID8gdGltZXN0YW1wIC8gMTAwMCA6IHRpbWVzdGFtcDsKfQoKLyoqCiAqIENvbnZlcnQgYSBzcGFuIHRvIGEgSlNPTiByZXByZXNlbnRhdGlvbi4KICogTm90ZSB0aGF0IGFsbCBmaWVsZHMgcmV0dXJuZWQgaGVyZSBhcmUgb3B0aW9uYWwgYW5kIG5lZWQgdG8gYmUgZ3VhcmRlZCBhZ2FpbnN0LgogKgogKiBOb3RlOiBCZWNhdXNlIG9mIHRoaXMsIHdlIGN1cnJlbnRseSBoYXZlIGEgY2lyY3VsYXIgdHlwZSBkZXBlbmRlbmN5ICh3aGljaCB3ZSBvcHRlZCBvdXQgb2YgaW4gcGFja2FnZS5qc29uKS4KICogVGhpcyBpcyBub3QgYXZvaWRhYmxlIGFzIHdlIG5lZWQgYHNwYW5Ub0pTT05gIGluIGBzcGFuVXRpbHMudHNgLCB3aGljaCBpbiB0dXJuIGlzIG5lZWRlZCBieSBgc3Bhbi50c2AgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5LgogKiBBbmQgYHNwYW5Ub0pTT05gIG5lZWRzIHRoZSBTcGFuIGNsYXNzIGZyb20gYHNwYW4udHNgIHRvIGNoZWNrIGhlcmUuCiAqLwpmdW5jdGlvbiBzcGFuVG9KU09OKHNwYW4pIHsKICBpZiAoc3BhbklzU2VudHJ5U3BhbihzcGFuKSkgewogICAgcmV0dXJuIHNwYW4uZ2V0U3BhbkpTT04oKTsKICB9CgogIHRyeSB7CiAgICBjb25zdCB7IHNwYW5JZDogc3Bhbl9pZCwgdHJhY2VJZDogdHJhY2VfaWQgfSA9IHNwYW4uc3BhbkNvbnRleHQoKTsKCiAgICAvLyBIYW5kbGUgYSBzcGFuIGZyb20gQG9wZW50ZWxlbWV0cnkvc2RrLWJhc2UtdHJhY2UncyBgU3BhbmAgY2xhc3MKICAgIGlmIChzcGFuSXNPcGVuVGVsZW1ldHJ5U2RrVHJhY2VCYXNlU3BhbihzcGFuKSkgewogICAgICBjb25zdCB7IGF0dHJpYnV0ZXMsIHN0YXJ0VGltZSwgbmFtZSwgZW5kVGltZSwgcGFyZW50U3BhbklkLCBzdGF0dXMgfSA9IHNwYW47CgogICAgICByZXR1cm4gZHJvcFVuZGVmaW5lZEtleXMoewogICAgICAgIHNwYW5faWQsCiAgICAgICAgdHJhY2VfaWQsCiAgICAgICAgZGF0YTogYXR0cmlidXRlcywKICAgICAgICBkZXNjcmlwdGlvbjogbmFtZSwKICAgICAgICBwYXJlbnRfc3Bhbl9pZDogcGFyZW50U3BhbklkLAogICAgICAgIHN0YXJ0X3RpbWVzdGFtcDogc3BhblRpbWVJbnB1dFRvU2Vjb25kcyhzdGFydFRpbWUpLAogICAgICAgIC8vIFRoaXMgaXMgWzAsMF0gYnkgZGVmYXVsdCBpbiBPVEVMLCBpbiB3aGljaCBjYXNlIHdlIHdhbnQgdG8gaW50ZXJwcmV0IHRoaXMgYXMgbm8gZW5kIHRpbWUKICAgICAgICB0aW1lc3RhbXA6IHNwYW5UaW1lSW5wdXRUb1NlY29uZHMoZW5kVGltZSkgfHwgdW5kZWZpbmVkLAogICAgICAgIHN0YXR1czogZ2V0U3RhdHVzTWVzc2FnZShzdGF0dXMpLAogICAgICAgIG9wOiBhdHRyaWJ1dGVzW1NFTUFOVElDX0FUVFJJQlVURV9TRU5UUllfT1BdLAogICAgICAgIG9yaWdpbjogYXR0cmlidXRlc1tTRU1BTlRJQ19BVFRSSUJVVEVfU0VOVFJZX09SSUdJTl0gLAogICAgICAgIF9tZXRyaWNzX3N1bW1hcnk6IGdldE1ldHJpY1N1bW1hcnlKc29uRm9yU3BhbigpLAogICAgICB9KTsKICAgIH0KCiAgICAvLyBGaW5hbGx5LCBhdCBsZWFzdCB3ZSBoYXZlIGBzcGFuQ29udGV4dCgpYC4uLi4KICAgIHJldHVybiB7CiAgICAgIHNwYW5faWQsCiAgICAgIHRyYWNlX2lkLAogICAgfTsKICB9IGNhdGNoIChlKSB7CiAgICByZXR1cm4ge307CiAgfQp9CgpmdW5jdGlvbiBzcGFuSXNPcGVuVGVsZW1ldHJ5U2RrVHJhY2VCYXNlU3BhbihzcGFuKSB7CiAgY29uc3QgY2FzdFNwYW4gPSBzcGFuIDsKICByZXR1cm4gISFjYXN0U3Bhbi5hdHRyaWJ1dGVzICYmICEhY2FzdFNwYW4uc3RhcnRUaW1lICYmICEhY2FzdFNwYW4ubmFtZSAmJiAhIWNhc3RTcGFuLmVuZFRpbWUgJiYgISFjYXN0U3Bhbi5zdGF0dXM7Cn0KCi8qKiBFeHBvcnRlZCBvbmx5IGZvciB0ZXN0cy4gKi8KCi8qKgogKiBTYWRseSwgZHVlIHRvIGNpcmN1bGFyIGRlcGVuZGVuY3kgY2hlY2tzIHdlIGNhbm5vdCBhY3R1YWxseSBpbXBvcnQgdGhlIFNwYW4gY2xhc3MgaGVyZSBhbmQgY2hlY2sgZm9yIGluc3RhbmNlb2YuCiAqIDooIFNvIGluc3RlYWQgd2UgYXBwcm94aW1hdGUgdGhpcyBieSBjaGVja2luZyBpZiBpdCBoYXMgdGhlIGBnZXRTcGFuSlNPTmAgbWV0aG9kLgogKi8KZnVuY3Rpb24gc3BhbklzU2VudHJ5U3BhbihzcGFuKSB7CiAgcmV0dXJuIHR5cGVvZiAoc3BhbiApLmdldFNwYW5KU09OID09PSAnZnVuY3Rpb24nOwp9CgovKiogR2V0IHRoZSBzdGF0dXMgbWVzc2FnZSB0byB1c2UgZm9yIGEgSlNPTiByZXByZXNlbnRhdGlvbiBvZiBhIHNwYW4uICovCmZ1bmN0aW9uIGdldFN0YXR1c01lc3NhZ2Uoc3RhdHVzKSB7CiAgaWYgKCFzdGF0dXMgfHwgc3RhdHVzLmNvZGUgPT09IFNQQU5fU1RBVFVTX1VOU0VUKSB7CiAgICByZXR1cm4gdW5kZWZpbmVkOwogIH0KCiAgaWYgKHN0YXR1cy5jb2RlID09PSBTUEFOX1NUQVRVU19PSykgewogICAgcmV0dXJuICdvayc7CiAgfQoKICByZXR1cm4gc3RhdHVzLm1lc3NhZ2UgfHwgJ3Vua25vd25fZXJyb3InOwp9CgovKioKICogQXBwbHkgU2RrSW5mbyAobmFtZSwgdmVyc2lvbiwgcGFja2FnZXMsIGludGVncmF0aW9ucykgdG8gdGhlIGNvcnJlc3BvbmRpbmcgZXZlbnQga2V5LgogKiBNZXJnZSB3aXRoIGV4aXN0aW5nIGRhdGEgaWYgYW55LgogKiovCmZ1bmN0aW9uIGVuaGFuY2VFdmVudFdpdGhTZGtJbmZvKGV2ZW50LCBzZGtJbmZvKSB7CiAgaWYgKCFzZGtJbmZvKSB7CiAgICByZXR1cm4gZXZlbnQ7CiAgfQogIGV2ZW50LnNkayA9IGV2ZW50LnNkayB8fCB7fTsKICBldmVudC5zZGsubmFtZSA9IGV2ZW50LnNkay5uYW1lIHx8IHNka0luZm8ubmFtZTsKICBldmVudC5zZGsudmVyc2lvbiA9IGV2ZW50LnNkay52ZXJzaW9uIHx8IHNka0luZm8udmVyc2lvbjsKICBldmVudC5zZGsuaW50ZWdyYXRpb25zID0gWy4uLihldmVudC5zZGsuaW50ZWdyYXRpb25zIHx8IFtdKSwgLi4uKHNka0luZm8uaW50ZWdyYXRpb25zIHx8IFtdKV07CiAgZXZlbnQuc2RrLnBhY2thZ2VzID0gWy4uLihldmVudC5zZGsucGFja2FnZXMgfHwgW10pLCAuLi4oc2RrSW5mby5wYWNrYWdlcyB8fCBbXSldOwogIHJldHVybiBldmVudDsKfQoKLyoqIENyZWF0ZXMgYW4gZW52ZWxvcGUgZnJvbSBhIFNlc3Npb24gKi8KZnVuY3Rpb24gY3JlYXRlU2Vzc2lvbkVudmVsb3BlKAogIHNlc3Npb24sCiAgZHNuLAogIG1ldGFkYXRhLAogIHR1bm5lbCwKKSB7CiAgY29uc3Qgc2RrSW5mbyA9IGdldFNka01ldGFkYXRhRm9yRW52ZWxvcGVIZWFkZXIobWV0YWRhdGEpOwogIGNvbnN0IGVudmVsb3BlSGVhZGVycyA9IHsKICAgIHNlbnRfYXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSwKICAgIC4uLihzZGtJbmZvICYmIHsgc2RrOiBzZGtJbmZvIH0pLAogICAgLi4uKCEhdHVubmVsICYmIGRzbiAmJiB7IGRzbjogZHNuVG9TdHJpbmcoZHNuKSB9KSwKICB9OwoKICBjb25zdCBlbnZlbG9wZUl0ZW0gPQogICAgJ2FnZ3JlZ2F0ZXMnIGluIHNlc3Npb24gPyBbeyB0eXBlOiAnc2Vzc2lvbnMnIH0sIHNlc3Npb25dIDogW3sgdHlwZTogJ3Nlc3Npb24nIH0sIHNlc3Npb24udG9KU09OKCldOwoKICByZXR1cm4gY3JlYXRlRW52ZWxvcGUoZW52ZWxvcGVIZWFkZXJzLCBbZW52ZWxvcGVJdGVtXSk7Cn0KCi8qKgogKiBDcmVhdGUgYW4gRW52ZWxvcGUgZnJvbSBhbiBldmVudC4KICovCmZ1bmN0aW9uIGNyZWF0ZUV2ZW50RW52ZWxvcGUoCiAgZXZlbnQsCiAgZHNuLAogIG1ldGFkYXRhLAogIHR1bm5lbCwKKSB7CiAgY29uc3Qgc2RrSW5mbyA9IGdldFNka01ldGFkYXRhRm9yRW52ZWxvcGVIZWFkZXIobWV0YWRhdGEpOwoKICAvKgogICAgTm90ZTogRHVlIHRvIFRTLCBldmVudC50eXBlIG1heSBiZSBgcmVwbGF5X2V2ZW50YCwgdGhlb3JldGljYWxseS4KICAgIEluIHByYWN0aWNlLCB3ZSBuZXZlciBjYWxsIGBjcmVhdGVFdmVudEVudmVsb3BlYCB3aXRoIGByZXBsYXlfZXZlbnRgIHR5cGUsCiAgICBhbmQgd2UnZCBoYXZlIHRvIGFkanV0IGEgbG9vb3Qgb2YgdHlwZXMgdG8gbWFrZSB0aGlzIHdvcmsgcHJvcGVybHkuCiAgICBXZSB3YW50IHRvIGF2b2lkIGNhc3RpbmcgdGhpcyBhcm91bmQsIGFzIHRoYXQgY291bGQgbGVhZCB0byBidWdzIChlLmcuIHdoZW4gd2UgYWRkIGFub3RoZXIgdHlwZSkKICAgIFNvIHRoZSBzYWZlIGNob2ljZSBpcyB0byByZWFsbHkgZ3VhcmQgYWdhaW5zdCB0aGUgcmVwbGF5X2V2ZW50IHR5cGUgaGVyZS4KICAqLwogIGNvbnN0IGV2ZW50VHlwZSA9IGV2ZW50LnR5cGUgJiYgZXZlbnQudHlwZSAhPT0gJ3JlcGxheV9ldmVudCcgPyBldmVudC50eXBlIDogJ2V2ZW50JzsKCiAgZW5oYW5jZUV2ZW50V2l0aFNka0luZm8oZXZlbnQsIG1ldGFkYXRhICYmIG1ldGFkYXRhLnNkayk7CgogIGNvbnN0IGVudmVsb3BlSGVhZGVycyA9IGNyZWF0ZUV2ZW50RW52ZWxvcGVIZWFkZXJzKGV2ZW50LCBzZGtJbmZvLCB0dW5uZWwsIGRzbik7CgogIC8vIFByZXZlbnQgdGhpcyBkYXRhICh3aGljaCwgaWYgaXQgZXhpc3RzLCB3YXMgdXNlZCBpbiBlYXJsaWVyIHN0ZXBzIGluIHRoZSBwcm9jZXNzaW5nIHBpcGVsaW5lKSBmcm9tIGJlaW5nIHNlbnQgdG8KICAvLyBzZW50cnkuIChOb3RlOiBPdXIgdXNlIG9mIHRoaXMgcHJvcGVydHkgY29tZXMgYW5kIGdvZXMgd2l0aCB3aGF0ZXZlciB3ZSBtaWdodCBiZSBkZWJ1Z2dpbmcsIHdoYXRldmVyIGhhY2tzIHdlIG1heQogIC8vIGhhdmUgdGVtcG9yYXJpbHkgYWRkZWQsIGV0Yy4gRXZlbiBpZiB3ZSBkb24ndCBoYXBwZW4gdG8gYmUgdXNpbmcgaXQgYXQgc29tZSBwb2ludCBpbiB0aGUgZnV0dXJlLCBsZXQncyBub3QgZ2V0IHJpZAogIC8vIG9mIHRoaXMgYGRlbGV0ZWAsIGxlc3Qgd2UgbWlzcyBwdXR0aW5nIGl0IGJhY2sgaW4gdGhlIG5leHQgdGltZSB0aGUgcHJvcGVydHkgaXMgaW4gdXNlLikKICBkZWxldGUgZXZlbnQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhOwoKICBjb25zdCBldmVudEl0ZW0gPSBbeyB0eXBlOiBldmVudFR5cGUgfSwgZXZlbnRdOwogIHJldHVybiBjcmVhdGVFbnZlbG9wZShlbnZlbG9wZUhlYWRlcnMsIFtldmVudEl0ZW1dKTsKfQoKY29uc3QgU0VOVFJZX0FQSV9WRVJTSU9OID0gJzcnOwoKLyoqIFJldHVybnMgdGhlIHByZWZpeCB0byBjb25zdHJ1Y3QgU2VudHJ5IGluZ2VzdGlvbiBBUEkgZW5kcG9pbnRzLiAqLwpmdW5jdGlvbiBnZXRCYXNlQXBpRW5kcG9pbnQoZHNuKSB7CiAgY29uc3QgcHJvdG9jb2wgPSBkc24ucHJvdG9jb2wgPyBgJHtkc24ucHJvdG9jb2x9OmAgOiAnJzsKICBjb25zdCBwb3J0ID0gZHNuLnBvcnQgPyBgOiR7ZHNuLnBvcnR9YCA6ICcnOwogIHJldHVybiBgJHtwcm90b2NvbH0vLyR7ZHNuLmhvc3R9JHtwb3J0fSR7ZHNuLnBhdGggPyBgLyR7ZHNuLnBhdGh9YCA6ICcnfS9hcGkvYDsKfQoKLyoqIFJldHVybnMgdGhlIGluZ2VzdCBBUEkgZW5kcG9pbnQgZm9yIHRhcmdldC4gKi8KZnVuY3Rpb24gX2dldEluZ2VzdEVuZHBvaW50KGRzbikgewogIHJldHVybiBgJHtnZXRCYXNlQXBpRW5kcG9pbnQoZHNuKX0ke2Rzbi5wcm9qZWN0SWR9L2VudmVsb3BlL2A7Cn0KCi8qKiBSZXR1cm5zIGEgVVJMLWVuY29kZWQgc3RyaW5nIHdpdGggYXV0aCBjb25maWcgc3VpdGFibGUgZm9yIGEgcXVlcnkgc3RyaW5nLiAqLwpmdW5jdGlvbiBfZW5jb2RlZEF1dGgoZHNuLCBzZGtJbmZvKSB7CiAgcmV0dXJuIHVybEVuY29kZSh7CiAgICAvLyBXZSBzZW5kIG9ubHkgdGhlIG1pbmltdW0gc2V0IG9mIHJlcXVpcmVkIGluZm9ybWF0aW9uLiBTZWUKICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9nZXRzZW50cnkvc2VudHJ5LWphdmFzY3JpcHQvaXNzdWVzLzI1NzIuCiAgICBzZW50cnlfa2V5OiBkc24ucHVibGljS2V5LAogICAgc2VudHJ5X3ZlcnNpb246IFNFTlRSWV9BUElfVkVSU0lPTiwKICAgIC4uLihzZGtJbmZvICYmIHsgc2VudHJ5X2NsaWVudDogYCR7c2RrSW5mby5uYW1lfS8ke3Nka0luZm8udmVyc2lvbn1gIH0pLAogIH0pOwp9CgovKioKICogUmV0dXJucyB0aGUgZW52ZWxvcGUgZW5kcG9pbnQgVVJMIHdpdGggYXV0aCBpbiB0aGUgcXVlcnkgc3RyaW5nLgogKgogKiBTZW5kaW5nIGF1dGggYXMgcGFydCBvZiB0aGUgcXVlcnkgc3RyaW5nIGFuZCBub3QgYXMgY3VzdG9tIEhUVFAgaGVhZGVycyBhdm9pZHMgQ09SUyBwcmVmbGlnaHQgcmVxdWVzdHMuCiAqLwpmdW5jdGlvbiBnZXRFbnZlbG9wZUVuZHBvaW50V2l0aFVybEVuY29kZWRBdXRoKAogIGRzbiwKICAvLyBUT0RPICh2OCk6IFJlbW92ZSBgdHVubmVsT3JPcHRpb25zYCBpbiBmYXZvciBvZiBgb3B0aW9uc2AsIGFuZCB1c2UgdGhlIHN1YnN0aXR1dGUgY29kZSBiZWxvdwogIC8vIG9wdGlvbnM6IENsaWVudE9wdGlvbnMgPSB7fSBhcyBDbGllbnRPcHRpb25zLAogIHR1bm5lbE9yT3B0aW9ucyA9IHt9ICwKKSB7CiAgLy8gVE9ETyAodjgpOiBVc2UgdGhpcyBjb2RlIGluc3RlYWQKICAvLyBjb25zdCB7IHR1bm5lbCwgX21ldGFkYXRhID0ge30gfSA9IG9wdGlvbnM7CiAgLy8gcmV0dXJuIHR1bm5lbCA/IHR1bm5lbCA6IGAke19nZXRJbmdlc3RFbmRwb2ludChkc24pfT8ke19lbmNvZGVkQXV0aChkc24sIF9tZXRhZGF0YS5zZGspfWA7CgogIGNvbnN0IHR1bm5lbCA9IHR5cGVvZiB0dW5uZWxPck9wdGlvbnMgPT09ICdzdHJpbmcnID8gdHVubmVsT3JPcHRpb25zIDogdHVubmVsT3JPcHRpb25zLnR1bm5lbDsKICBjb25zdCBzZGtJbmZvID0KICAgIHR5cGVvZiB0dW5uZWxPck9wdGlvbnMgPT09ICdzdHJpbmcnIHx8ICF0dW5uZWxPck9wdGlvbnMuX21ldGFkYXRhID8gdW5kZWZpbmVkIDogdHVubmVsT3JPcHRpb25zLl9tZXRhZGF0YS5zZGs7CgogIHJldHVybiB0dW5uZWwgPyB0dW5uZWwgOiBgJHtfZ2V0SW5nZXN0RW5kcG9pbnQoZHNuKX0/JHtfZW5jb2RlZEF1dGgoZHNuLCBzZGtJbmZvKX1gOwp9CgovKioKICogQ29udmVydCBhIG5ldyBpbnRlZ3JhdGlvbiBmdW5jdGlvbiB0byB0aGUgbGVnYWN5IGNsYXNzIHN5bnRheC4KICogSW4gdjgsIHdlIGNhbiByZW1vdmUgdGhpcyBhbmQgaW5zdGVhZCBleHBvcnQgdGhlIGludGVncmF0aW9uIGZ1bmN0aW9ucyBkaXJlY3RseS4KICoKICogQGRlcHJlY2F0ZWQgVGhpcyB3aWxsIGJlIHJlbW92ZWQgaW4gdjghCiAqLwpmdW5jdGlvbiBjb252ZXJ0SW50ZWdyYXRpb25GblRvQ2xhc3MoCiAgbmFtZSwKICBmbiwKKSB7CiAgcmV0dXJuIE9iamVjdC5hc3NpZ24oCiAgICBmdW5jdGlvbiBDb252ZXJ0ZWRJbnRlZ3JhdGlvbiguLi5hcmdzKSB7CiAgICAgIHJldHVybiBmbiguLi5hcmdzKTsKICAgIH0sCiAgICB7IGlkOiBuYW1lIH0sCiAgKSA7Cn0KCi8qKgogKiBEZWZpbmUgYW4gaW50ZWdyYXRpb24gZnVuY3Rpb24gdGhhdCBjYW4gYmUgdXNlZCB0byBjcmVhdGUgYW4gaW50ZWdyYXRpb24gaW5zdGFuY2UuCiAqIE5vdGUgdGhhdCB0aGlzIGJ5IGRlc2lnbiBoaWRlcyB0aGUgaW1wbGVtZW50YXRpb24gZGV0YWlscyBvZiB0aGUgaW50ZWdyYXRpb24sIGFzIHRoZXkgYXJlIGNvbnNpZGVyZWQgaW50ZXJuYWwuCiAqLwpmdW5jdGlvbiBkZWZpbmVJbnRlZ3JhdGlvbihmbikgewogIHJldHVybiBmbjsKfQoKY29uc3QgREVGQVVMVF9UUkFOU1BPUlRfQlVGRkVSX1NJWkUgPSAzMDsKCi8qKgogKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIGEgU2VudHJ5IGBUcmFuc3BvcnRgCiAqCiAqIEBwYXJhbSBvcHRpb25zCiAqIEBwYXJhbSBtYWtlUmVxdWVzdAogKi8KZnVuY3Rpb24gY3JlYXRlVHJhbnNwb3J0KAogIG9wdGlvbnMsCiAgbWFrZVJlcXVlc3QsCiAgYnVmZmVyID0gbWFrZVByb21pc2VCdWZmZXIoCiAgICBvcHRpb25zLmJ1ZmZlclNpemUgfHwgREVGQVVMVF9UUkFOU1BPUlRfQlVGRkVSX1NJWkUsCiAgKSwKKSB7CiAgbGV0IHJhdGVMaW1pdHMgPSB7fTsKICBjb25zdCBmbHVzaCA9ICh0aW1lb3V0KSA9PiBidWZmZXIuZHJhaW4odGltZW91dCk7CgogIGZ1bmN0aW9uIHNlbmQoZW52ZWxvcGUpIHsKICAgIGNvbnN0IGZpbHRlcmVkRW52ZWxvcGVJdGVtcyA9IFtdOwoKICAgIC8vIERyb3AgcmF0ZSBsaW1pdGVkIGl0ZW1zIGZyb20gZW52ZWxvcGUKICAgIGZvckVhY2hFbnZlbG9wZUl0ZW0oZW52ZWxvcGUsIChpdGVtLCB0eXBlKSA9PiB7CiAgICAgIGNvbnN0IGVudmVsb3BlSXRlbURhdGFDYXRlZ29yeSA9IGVudmVsb3BlSXRlbVR5cGVUb0RhdGFDYXRlZ29yeSh0eXBlKTsKICAgICAgaWYgKGlzUmF0ZUxpbWl0ZWQocmF0ZUxpbWl0cywgZW52ZWxvcGVJdGVtRGF0YUNhdGVnb3J5KSkgewogICAgICAgIGNvbnN0IGV2ZW50ID0gZ2V0RXZlbnRGb3JFbnZlbG9wZUl0ZW0oaXRlbSwgdHlwZSk7CiAgICAgICAgb3B0aW9ucy5yZWNvcmREcm9wcGVkRXZlbnQoJ3JhdGVsaW1pdF9iYWNrb2ZmJywgZW52ZWxvcGVJdGVtRGF0YUNhdGVnb3J5LCBldmVudCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgZmlsdGVyZWRFbnZlbG9wZUl0ZW1zLnB1c2goaXRlbSk7CiAgICAgIH0KICAgIH0pOwoKICAgIC8vIFNraXAgc2VuZGluZyBpZiBlbnZlbG9wZSBpcyBlbXB0eSBhZnRlciBmaWx0ZXJpbmcgb3V0IHJhdGUgbGltaXRlZCBldmVudHMKICAgIGlmIChmaWx0ZXJlZEVudmVsb3BlSXRlbXMubGVuZ3RoID09PSAwKSB7CiAgICAgIHJldHVybiByZXNvbHZlZFN5bmNQcm9taXNlKHt9KTsKICAgIH0KCiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueQogICAgY29uc3QgZmlsdGVyZWRFbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlKGVudmVsb3BlWzBdLCBmaWx0ZXJlZEVudmVsb3BlSXRlbXMgKTsKCiAgICAvLyBDcmVhdGVzIGNsaWVudCByZXBvcnQgZm9yIGVhY2ggaXRlbSBpbiBhbiBlbnZlbG9wZQogICAgY29uc3QgcmVjb3JkRW52ZWxvcGVMb3NzID0gKHJlYXNvbikgPT4gewogICAgICBmb3JFYWNoRW52ZWxvcGVJdGVtKGZpbHRlcmVkRW52ZWxvcGUsIChpdGVtLCB0eXBlKSA9PiB7CiAgICAgICAgY29uc3QgZXZlbnQgPSBnZXRFdmVudEZvckVudmVsb3BlSXRlbShpdGVtLCB0eXBlKTsKICAgICAgICBvcHRpb25zLnJlY29yZERyb3BwZWRFdmVudChyZWFzb24sIGVudmVsb3BlSXRlbVR5cGVUb0RhdGFDYXRlZ29yeSh0eXBlKSwgZXZlbnQpOwogICAgICB9KTsKICAgIH07CgogICAgY29uc3QgcmVxdWVzdFRhc2sgPSAoKSA9PgogICAgICBtYWtlUmVxdWVzdCh7IGJvZHk6IHNlcmlhbGl6ZUVudmVsb3BlKGZpbHRlcmVkRW52ZWxvcGUpIH0pLnRoZW4oCiAgICAgICAgcmVzcG9uc2UgPT4gewogICAgICAgICAgLy8gV2UgZG9uJ3Qgd2FudCB0byB0aHJvdyBvbiBOT0sgcmVzcG9uc2VzLCBidXQgd2Ugd2FudCB0byBhdCBsZWFzdCBsb2cgdGhlbQogICAgICAgICAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgIT09IHVuZGVmaW5lZCAmJiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA8IDIwMCB8fCByZXNwb25zZS5zdGF0dXNDb2RlID49IDMwMCkpIHsKICAgICAgICAgICAgREVCVUdfQlVJTEQgJiYgbG9nZ2VyLndhcm4oYFNlbnRyeSByZXNwb25kZWQgd2l0aCBzdGF0dXMgY29kZSAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9IHRvIHNlbnQgZXZlbnQuYCk7CiAgICAgICAgICB9CgogICAgICAgICAgcmF0ZUxpbWl0cyA9IHVwZGF0ZVJhdGVMaW1pdHMocmF0ZUxpbWl0cywgcmVzcG9uc2UpOwogICAgICAgICAgcmV0dXJuIHJlc3BvbnNlOwogICAgICAgIH0sCiAgICAgICAgZXJyb3IgPT4gewogICAgICAgICAgcmVjb3JkRW52ZWxvcGVMb3NzKCduZXR3b3JrX2Vycm9yJyk7CiAgICAgICAgICB0aHJvdyBlcnJvcjsKICAgICAgICB9LAogICAgICApOwoKICAgIHJldHVybiBidWZmZXIuYWRkKHJlcXVlc3RUYXNrKS50aGVuKAogICAgICByZXN1bHQgPT4gcmVzdWx0LAogICAgICBlcnJvciA9PiB7CiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgU2VudHJ5RXJyb3IpIHsKICAgICAgICAgIERFQlVHX0JVSUxEICYmIGxvZ2dlci5lcnJvcignU2tpcHBlZCBzZW5kaW5nIGV2ZW50IGJlY2F1c2UgYnVmZmVyIGlzIGZ1bGwuJyk7CiAgICAgICAgICByZWNvcmRFbnZlbG9wZUxvc3MoJ3F1ZXVlX292ZXJmbG93Jyk7CiAgICAgICAgICByZXR1cm4gcmVzb2x2ZWRTeW5jUHJvbWlzZSh7fSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHRocm93IGVycm9yOwogICAgICAgIH0KICAgICAgfSwKICAgICk7CiAgfQoKICByZXR1cm4gewogICAgc2VuZCwKICAgIGZsdXNoLAogIH07Cn0KCmZ1bmN0aW9uIGdldEV2ZW50Rm9yRW52ZWxvcGVJdGVtKGl0ZW0sIHR5cGUpIHsKICBpZiAodHlwZSAhPT0gJ2V2ZW50JyAmJiB0eXBlICE9PSAndHJhbnNhY3Rpb24nKSB7CiAgICByZXR1cm4gdW5kZWZpbmVkOwogIH0KCiAgcmV0dXJuIEFycmF5LmlzQXJyYXkoaXRlbSkgPyAoaXRlbSApWzFdIDogdW5kZWZpbmVkOwp9CgovKiogS2V5cyBhcmUgc291cmNlIGZpbGVuYW1lL3VybCwgdmFsdWVzIGFyZSBtZXRhZGF0YSBvYmplY3RzLiAqLwovLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueQpjb25zdCBmaWxlbmFtZU1ldGFkYXRhTWFwID0gbmV3IE1hcCgpOwovKiogU2V0IG9mIHN0YWNrIHN0cmluZ3MgdGhhdCBoYXZlIGFscmVhZHkgYmVlbiBwYXJzZWQuICovCmNvbnN0IHBhcnNlZFN0YWNrcyA9IG5ldyBTZXQoKTsKCmZ1bmN0aW9uIGVuc3VyZU1ldGFkYXRhU3RhY2tzQXJlUGFyc2VkKHBhcnNlcikgewogIGlmICghR0xPQkFMX09CSi5fc2VudHJ5TW9kdWxlTWV0YWRhdGEpIHsKICAgIHJldHVybjsKICB9CgogIGZvciAoY29uc3Qgc3RhY2sgb2YgT2JqZWN0LmtleXMoR0xPQkFMX09CSi5fc2VudHJ5TW9kdWxlTWV0YWRhdGEpKSB7CiAgICBjb25zdCBtZXRhZGF0YSA9IEdMT0JBTF9PQkouX3NlbnRyeU1vZHVsZU1ldGFkYXRhW3N0YWNrXTsKCiAgICBpZiAocGFyc2VkU3RhY2tzLmhhcyhzdGFjaykpIHsKICAgICAgY29udGludWU7CiAgICB9CgogICAgLy8gRW5zdXJlIHRoaXMgc3RhY2sgZG9lc24ndCBnZXQgcGFyc2VkIGFnYWluCiAgICBwYXJzZWRTdGFja3MuYWRkKHN0YWNrKTsKCiAgICBjb25zdCBmcmFtZXMgPSBwYXJzZXIoc3RhY2spOwoKICAgIC8vIEdvIHRocm91Z2ggdGhlIGZyYW1lcyBzdGFydGluZyBmcm9tIHRoZSB0b3Agb2YgdGhlIHN0YWNrIGFuZCBmaW5kIHRoZSBmaXJzdCBvbmUgd2l0aCBhIGZpbGVuYW1lCiAgICBmb3IgKGNvbnN0IGZyYW1lIG9mIGZyYW1lcy5yZXZlcnNlKCkpIHsKICAgICAgaWYgKGZyYW1lLmZpbGVuYW1lKSB7CiAgICAgICAgLy8gU2F2ZSB0aGUgbWV0YWRhdGEgZm9yIHRoaXMgZmlsZW5hbWUKICAgICAgICBmaWxlbmFtZU1ldGFkYXRhTWFwLnNldChmcmFtZS5maWxlbmFtZSwgbWV0YWRhdGEpOwogICAgICAgIGJyZWFrOwogICAgICB9CiAgICB9CiAgfQp9CgovKioKICogUmV0cmlldmUgbWV0YWRhdGEgZm9yIGEgc3BlY2lmaWMgSmF2YVNjcmlwdCBmaWxlIFVSTC4KICoKICogTWV0YWRhdGEgaXMgaW5qZWN0ZWQgYnkgdGhlIFNlbnRyeSBidW5kbGVyIHBsdWdpbnMgdXNpbmcgdGhlIGBfZXhwZXJpbWVudHMubW9kdWxlTWV0YWRhdGFgIGNvbmZpZyBvcHRpb24uCiAqLwovLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueQpmdW5jdGlvbiBnZXRNZXRhZGF0YUZvclVybChwYXJzZXIsIGZpbGVuYW1lKSB7CiAgZW5zdXJlTWV0YWRhdGFTdGFja3NBcmVQYXJzZWQocGFyc2VyKTsKICByZXR1cm4gZmlsZW5hbWVNZXRhZGF0YU1hcC5nZXQoZmlsZW5hbWUpOwp9CgovKioKICogQWRkcyBtZXRhZGF0YSB0byBzdGFjayBmcmFtZXMuCiAqCiAqIE1ldGFkYXRhIGlzIGluamVjdGVkIGJ5IHRoZSBTZW50cnkgYnVuZGxlciBwbHVnaW5zIHVzaW5nIHRoZSBgX2V4cGVyaW1lbnRzLm1vZHVsZU1ldGFkYXRhYCBjb25maWcgb3B0aW9uLgogKi8KZnVuY3Rpb24gYWRkTWV0YWRhdGFUb1N0YWNrRnJhbWVzKHBhcnNlciwgZXZlbnQpIHsKICB0cnkgewogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1ub24tbnVsbC1hc3NlcnRpb24KICAgIGV2ZW50LmV4Y2VwdGlvbi52YWx1ZXMuZm9yRWFjaChleGNlcHRpb24gPT4gewogICAgICBpZiAoIWV4Y2VwdGlvbi5zdGFja3RyYWNlKSB7CiAgICAgICAgcmV0dXJuOwogICAgICB9CgogICAgICBmb3IgKGNvbnN0IGZyYW1lIG9mIGV4Y2VwdGlvbi5zdGFja3RyYWNlLmZyYW1lcyB8fCBbXSkgewogICAgICAgIGlmICghZnJhbWUuZmlsZW5hbWUpIHsKICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgIH0KCiAgICAgICAgY29uc3QgbWV0YWRhdGEgPSBnZXRNZXRhZGF0YUZvclVybChwYXJzZXIsIGZyYW1lLmZpbGVuYW1lKTsKCiAgICAgICAgaWYgKG1ldGFkYXRhKSB7CiAgICAgICAgICBmcmFtZS5tb2R1bGVfbWV0YWRhdGEgPSBtZXRhZGF0YTsKICAgICAgICB9CiAgICAgIH0KICAgIH0pOwogIH0gY2F0Y2ggKF8pIHsKICAgIC8vIFRvIHNhdmUgYnVuZGxlIHNpemUgd2UncmUganVzdCB0cnkgY2F0Y2hpbmcgaGVyZSBpbnN0ZWFkIG9mIGNoZWNraW5nIGZvciB0aGUgZXhpc3RlbmNlIG9mIGFsbCB0aGUgZGlmZmVyZW50IG9iamVjdHMuCiAgfQp9CgovKioKICogU3RyaXBzIG1ldGFkYXRhIGZyb20gc3RhY2sgZnJhbWVzLgogKi8KZnVuY3Rpb24gc3RyaXBNZXRhZGF0YUZyb21TdGFja0ZyYW1lcyhldmVudCkgewogIHRyeSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLW5vbi1udWxsLWFzc2VydGlvbgogICAgZXZlbnQuZXhjZXB0aW9uLnZhbHVlcy5mb3JFYWNoKGV4Y2VwdGlvbiA9PiB7CiAgICAgIGlmICghZXhjZXB0aW9uLnN0YWNrdHJhY2UpIHsKICAgICAgICByZXR1cm47CiAgICAgIH0KCiAgICAgIGZvciAoY29uc3QgZnJhbWUgb2YgZXhjZXB0aW9uLnN0YWNrdHJhY2UuZnJhbWVzIHx8IFtdKSB7CiAgICAgICAgZGVsZXRlIGZyYW1lLm1vZHVsZV9tZXRhZGF0YTsKICAgICAgfQogICAgfSk7CiAgfSBjYXRjaCAoXykgewogICAgLy8gVG8gc2F2ZSBidW5kbGUgc2l6ZSB3ZSdyZSBqdXN0IHRyeSBjYXRjaGluZyBoZXJlIGluc3RlYWQgb2YgY2hlY2tpbmcgZm9yIHRoZSBleGlzdGVuY2Ugb2YgYWxsIHRoZSBkaWZmZXJlbnQgb2JqZWN0cy4KICB9Cn0KCmNvbnN0IElOVEVHUkFUSU9OX05BTUUkYSA9ICdNb2R1bGVNZXRhZGF0YSc7Cgpjb25zdCBfbW9kdWxlTWV0YWRhdGFJbnRlZ3JhdGlvbiA9ICgoKSA9PiB7CiAgcmV0dXJuIHsKICAgIG5hbWU6IElOVEVHUkFUSU9OX05BTUUkYSwKICAgIHNldHVwKGNsaWVudCkgewogICAgICAvLyBXZSBuZWVkIHRvIHN0cmlwIG1ldGFkYXRhIGZyb20gc3RhY2sgZnJhbWVzIGJlZm9yZSBzZW5kaW5nIHRoZW0gdG8gU2VudHJ5IHNpbmNlIHRoZXNlIGFyZSBjbGllbnQgc2lkZSBvbmx5LgogICAgICBjbGllbnQub24oJ2JlZm9yZUVudmVsb3BlJywgZW52ZWxvcGUgPT4gewogICAgICAgIGZvckVhY2hFbnZlbG9wZUl0ZW0oZW52ZWxvcGUsIChpdGVtLCB0eXBlKSA9PiB7CiAgICAgICAgICBpZiAodHlwZSA9PT0gJ2V2ZW50JykgewogICAgICAgICAgICBjb25zdCBldmVudCA9IEFycmF5LmlzQXJyYXkoaXRlbSkgPyAoaXRlbSApWzFdIDogdW5kZWZpbmVkOwoKICAgICAgICAgICAgaWYgKGV2ZW50KSB7CiAgICAgICAgICAgICAgc3RyaXBNZXRhZGF0YUZyb21TdGFja0ZyYW1lcyhldmVudCk7CiAgICAgICAgICAgICAgaXRlbVsxXSA9IGV2ZW50OwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfSk7CiAgICAgIH0pOwogICAgfSwKCiAgICBwcm9jZXNzRXZlbnQoZXZlbnQsIF9oaW50LCBjbGllbnQpIHsKICAgICAgY29uc3Qgc3RhY2tQYXJzZXIgPSBjbGllbnQuZ2V0T3B0aW9ucygpLnN0YWNrUGFyc2VyOwogICAgICBhZGRNZXRhZGF0YVRvU3RhY2tGcmFtZXMoc3RhY2tQYXJzZXIsIGV2ZW50KTsKICAgICAgcmV0dXJuIGV2ZW50OwogICAgfSwKICB9Owp9KSA7Cgpjb25zdCBtb2R1bGVNZXRhZGF0YUludGVncmF0aW9uID0gZGVmaW5lSW50ZWdyYXRpb24oX21vZHVsZU1ldGFkYXRhSW50ZWdyYXRpb24pOwoKLyoqCiAqIEFkZHMgbW9kdWxlIG1ldGFkYXRhIHRvIHN0YWNrIGZyYW1lcy4KICoKICogTWV0YWRhdGEgY2FuIGJlIGluamVjdGVkIGJ5IHRoZSBTZW50cnkgYnVuZGxlciBwbHVnaW5zIHVzaW5nIHRoZSBgX2V4cGVyaW1lbnRzLm1vZHVsZU1ldGFkYXRhYCBjb25maWcgb3B0aW9uLgogKgogKiBXaGVuIHRoaXMgaW50ZWdyYXRpb24gaXMgYWRkZWQsIHRoZSBtZXRhZGF0YSBwYXNzZWQgdG8gdGhlIGJ1bmRsZXIgcGx1Z2luIGlzIGFkZGVkIHRvIHRoZSBzdGFjayBmcmFtZXMgb2YgYWxsIGV2ZW50cwogKiB1bmRlciB0aGUgYG1vZHVsZV9tZXRhZGF0YWAgcHJvcGVydHkuIFRoaXMgY2FuIGJlIHVzZWQgdG8gaGVscCBpbiB0YWdnaW5nIG9yIHJvdXRpbmcgb2YgZXZlbnRzIGZyb20gZGlmZmVyZW50IHRlYW1zCiAqIG91ciBzb3VyY2VzCiAqCiAqIEBkZXByZWNhdGVkIFVzZSBgbW9kdWxlTWV0YWRhdGFJbnRlZ3JhdGlvbigpYCBpbnN0ZWFkLgogKi8KLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCmNvbnZlcnRJbnRlZ3JhdGlvbkZuVG9DbGFzcygKICBJTlRFR1JBVElPTl9OQU1FJGEsCiAgbW9kdWxlTWV0YWRhdGFJbnRlZ3JhdGlvbiwKKQoKOwoKY29uc3QgREVGQVVMVF9PUFRJT05TID0gewogIGluY2x1ZGU6IHsKICAgIGNvb2tpZXM6IHRydWUsCiAgICBkYXRhOiB0cnVlLAogICAgaGVhZGVyczogdHJ1ZSwKICAgIGlwOiBmYWxzZSwKICAgIHF1ZXJ5X3N0cmluZzogdHJ1ZSwKICAgIHVybDogdHJ1ZSwKICAgIHVzZXI6IHsKICAgICAgaWQ6IHRydWUsCiAgICAgIHVzZXJuYW1lOiB0cnVlLAogICAgICBlbWFpbDogdHJ1ZSwKICAgIH0sCiAgfSwKICB0cmFuc2FjdGlvbk5hbWluZ1NjaGVtZTogJ21ldGhvZFBhdGgnICwKfTsKCmNvbnN0IElOVEVHUkFUSU9OX05BTUUkOSA9ICdSZXF1ZXN0RGF0YSc7Cgpjb25zdCBfcmVxdWVzdERhdGFJbnRlZ3JhdGlvbiA9ICgob3B0aW9ucyA9IHt9KSA9PiB7CiAgY29uc3QgX29wdGlvbnMgPSB7CiAgICAuLi5ERUZBVUxUX09QVElPTlMsCiAgICAuLi5vcHRpb25zLAogICAgaW5jbHVkZTogewogICAgICAuLi5ERUZBVUxUX09QVElPTlMuaW5jbHVkZSwKICAgICAgLi4ub3B0aW9ucy5pbmNsdWRlLAogICAgICB1c2VyOgogICAgICAgIG9wdGlvbnMuaW5jbHVkZSAmJiB0eXBlb2Ygb3B0aW9ucy5pbmNsdWRlLnVzZXIgPT09ICdib29sZWFuJwogICAgICAgICAgPyBvcHRpb25zLmluY2x1ZGUudXNlcgogICAgICAgICAgOiB7CiAgICAgICAgICAgICAgLi4uREVGQVVMVF9PUFRJT05TLmluY2x1ZGUudXNlciwKICAgICAgICAgICAgICAvLyBVbmNsZWFyIHdoeSBUUyBzdGlsbCB0aGlua3MgYG9wdGlvbnMuaW5jbHVkZS51c2VyYCBjb3VsZCBiZSBhIGJvb2xlYW4gYXQgdGhpcyBwb2ludAogICAgICAgICAgICAgIC4uLigob3B0aW9ucy5pbmNsdWRlIHx8IHt9KS51c2VyICksCiAgICAgICAgICAgIH0sCiAgICB9LAogIH07CgogIHJldHVybiB7CiAgICBuYW1lOiBJTlRFR1JBVElPTl9OQU1FJDksCiAgICBwcm9jZXNzRXZlbnQoZXZlbnQsIF9oaW50LCBjbGllbnQpIHsKICAgICAgLy8gTm90ZTogSW4gdGhlIGxvbmcgcnVuLCBtb3N0IG9mIHRoZSBsb2dpYyBoZXJlIHNob3VsZCBwcm9iYWJseSBtb3ZlIGludG8gdGhlIHJlcXVlc3QgZGF0YSB1dGlsaXR5IGZ1bmN0aW9ucy4gRm9yCiAgICAgIC8vIHRoZSBtb21lbnQgaXQgbGl2ZXMgaGVyZSwgdGhvdWdoLCB1bnRpbCBodHRwczovL2dpdGh1Yi5jb20vZ2V0c2VudHJ5L3NlbnRyeS1qYXZhc2NyaXB0L2lzc3Vlcy81NzE4IGlzIGFkZHJlc3NlZC4KICAgICAgLy8gKFRMO0RSOiBUaG9zZSBmdW5jdGlvbnMgdG91Y2ggbWFueSBwYXJ0cyBvZiB0aGUgcmVwbyBpbiBtYW55IGRpZmZlcmVudCB3YXlzLCBhbmQgbmVlZCB0byBiZSBjbGVuZWQgdXAuIE9uY2UKICAgICAgLy8gdGhhdCdzIGhhcHBlbmVkLCBpdCB3aWxsIGJlIGVhc2llciB0byBhZGQgdGhpcyBsb2dpYyBpbiB3aXRob3V0IHdvcnJ5aW5nIGFib3V0IHVuZXhwZWN0ZWQgc2lkZSBlZmZlY3RzLikKICAgICAgY29uc3QgeyB0cmFuc2FjdGlvbk5hbWluZ1NjaGVtZSB9ID0gX29wdGlvbnM7CgogICAgICBjb25zdCB7IHNka1Byb2Nlc3NpbmdNZXRhZGF0YSA9IHt9IH0gPSBldmVudDsKICAgICAgY29uc3QgcmVxID0gc2RrUHJvY2Vzc2luZ01ldGFkYXRhLnJlcXVlc3Q7CgogICAgICBpZiAoIXJlcSkgewogICAgICAgIHJldHVybiBldmVudDsKICAgICAgfQoKICAgICAgY29uc3QgYWRkUmVxdWVzdERhdGFPcHRpb25zID0gY29udmVydFJlcURhdGFJbnRlZ3JhdGlvbk9wdHNUb0FkZFJlcURhdGFPcHRzKF9vcHRpb25zKTsKCiAgICAgIGNvbnN0IHByb2Nlc3NlZEV2ZW50ID0gYWRkUmVxdWVzdERhdGFUb0V2ZW50KGV2ZW50LCByZXEsIGFkZFJlcXVlc3REYXRhT3B0aW9ucyk7CgogICAgICAvLyBUcmFuc2FjdGlvbiBldmVudHMgYWxyZWFkeSBoYXZlIHRoZSByaWdodCBgdHJhbnNhY3Rpb25gIHZhbHVlCiAgICAgIGlmIChldmVudC50eXBlID09PSAndHJhbnNhY3Rpb24nIHx8IHRyYW5zYWN0aW9uTmFtaW5nU2NoZW1lID09PSAnaGFuZGxlcicpIHsKICAgICAgICByZXR1cm4gcHJvY2Vzc2VkRXZlbnQ7CiAgICAgIH0KCiAgICAgIC8vIEluIGFsbCBvdGhlciBjYXNlcywgdXNlIHRoZSByZXF1ZXN0J3MgYXNzb2NpYXRlZCB0cmFuc2FjdGlvbiAoaWYgYW55KSB0byBvdmVyd3JpdGUgdGhlIGV2ZW50J3MgYHRyYW5zYWN0aW9uYAogICAgICAvLyB2YWx1ZSB3aXRoIGEgaGlnaC1xdWFsaXR5IG9uZQogICAgICBjb25zdCByZXFXaXRoVHJhbnNhY3Rpb24gPSByZXEgOwogICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IHJlcVdpdGhUcmFuc2FjdGlvbi5fc2VudHJ5VHJhbnNhY3Rpb247CiAgICAgIGlmICh0cmFuc2FjdGlvbikgewogICAgICAgIGNvbnN0IG5hbWUgPSBzcGFuVG9KU09OKHRyYW5zYWN0aW9uKS5kZXNjcmlwdGlvbiB8fCAnJzsKCiAgICAgICAgLy8gVE9ETyAodjgpOiBSZW1vdmUgdGhlIG5leHRqcyBjaGVjayBhbmQganVzdCBiYXNlIGl0IG9uIGB0cmFuc2FjdGlvbk5hbWluZ1NjaGVtZWAgZm9yIGFsbCBTREtzLiAoV2UgaGF2ZSB0bwogICAgICAgIC8vIGtlZXAgaXQgdGhlIHdheSBpdCBpcyBmb3IgdGhlIG1vbWVudCwgYmVjYXVzZSBjaGFuZ2luZyB0aGUgbmFtZXMgb2YgdHJhbnNhY3Rpb25zIGluIFNlbnRyeSBoYXMgdGhlIHBvdGVudGlhbAogICAgICAgIC8vIHRvIGJyZWFrIHRoaW5ncyBsaWtlIGFsZXJ0IHJ1bGVzLikKICAgICAgICBjb25zdCBzaG91bGRJbmNsdWRlTWV0aG9kSW5UcmFuc2FjdGlvbk5hbWUgPQogICAgICAgICAgZ2V0U0RLTmFtZShjbGllbnQpID09PSAnc2VudHJ5LmphdmFzY3JpcHQubmV4dGpzJwogICAgICAgICAgICA/IG5hbWUuc3RhcnRzV2l0aCgnL2FwaScpCiAgICAgICAgICAgIDogdHJhbnNhY3Rpb25OYW1pbmdTY2hlbWUgIT09ICdwYXRoJzsKCiAgICAgICAgY29uc3QgW3RyYW5zYWN0aW9uVmFsdWVdID0gZXh0cmFjdFBhdGhGb3JUcmFuc2FjdGlvbihyZXEsIHsKICAgICAgICAgIHBhdGg6IHRydWUsCiAgICAgICAgICBtZXRob2Q6IHNob3VsZEluY2x1ZGVNZXRob2RJblRyYW5zYWN0aW9uTmFtZSwKICAgICAgICAgIGN1c3RvbVJvdXRlOiBuYW1lLAogICAgICAgIH0pOwoKICAgICAgICBwcm9jZXNzZWRFdmVudC50cmFuc2FjdGlvbiA9IHRyYW5zYWN0aW9uVmFsdWU7CiAgICAgIH0KCiAgICAgIHJldHVybiBwcm9jZXNzZWRFdmVudDsKICAgIH0sCiAgfTsKfSkgOwoKY29uc3QgcmVxdWVzdERhdGFJbnRlZ3JhdGlvbiA9IGRlZmluZUludGVncmF0aW9uKF9yZXF1ZXN0RGF0YUludGVncmF0aW9uKTsKCi8qKgogKiBBZGQgZGF0YSBhYm91dCBhIHJlcXVlc3QgdG8gYW4gZXZlbnQuIFByaW1hcmlseSBmb3IgdXNlIGluIE5vZGUtYmFzZWQgU0RLcywgYnV0IGluY2x1ZGVkIGluIGBAc2VudHJ5L2NvcmVgCiAqIHNvIGl0IGNhbiBiZSB1c2VkIGluIGNyb3NzLXBsYXRmb3JtIFNES3MgbGlrZSBgQHNlbnRyeS9uZXh0anNgLgogKiBAZGVwcmVjYXRlZCBVc2UgYHJlcXVlc3REYXRhSW50ZWdyYXRpb24oKWAgaW5zdGVhZC4KICovCi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgpjb252ZXJ0SW50ZWdyYXRpb25GblRvQ2xhc3MoSU5URUdSQVRJT05fTkFNRSQ5LCByZXF1ZXN0RGF0YUludGVncmF0aW9uKQoKOwoKLyoqIENvbnZlcnQgdGhpcyBpbnRlZ3JhdGlvbidzIG9wdGlvbnMgdG8gbWF0Y2ggd2hhdCBgYWRkUmVxdWVzdERhdGFUb0V2ZW50YCBleHBlY3RzICovCi8qKiBUT0RPOiBDYW4gcG9zc2libHkgYmUgZGVsZXRlZCBvbmNlIGh0dHBzOi8vZ2l0aHViLmNvbS9nZXRzZW50cnkvc2VudHJ5LWphdmFzY3JpcHQvaXNzdWVzLzU3MTggaXMgZml4ZWQgKi8KZnVuY3Rpb24gY29udmVydFJlcURhdGFJbnRlZ3JhdGlvbk9wdHNUb0FkZFJlcURhdGFPcHRzKAogIGludGVncmF0aW9uT3B0aW9ucywKKSB7CiAgY29uc3QgewogICAgdHJhbnNhY3Rpb25OYW1pbmdTY2hlbWUsCiAgICBpbmNsdWRlOiB7IGlwLCB1c2VyLCAuLi5yZXF1ZXN0T3B0aW9ucyB9LAogIH0gPSBpbnRlZ3JhdGlvbk9wdGlvbnM7CgogIGNvbnN0IHJlcXVlc3RJbmNsdWRlS2V5cyA9IFsnbWV0aG9kJ107CiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMocmVxdWVzdE9wdGlvbnMpKSB7CiAgICBpZiAodmFsdWUpIHsKICAgICAgcmVxdWVzdEluY2x1ZGVLZXlzLnB1c2goa2V5KTsKICAgIH0KICB9CgogIGxldCBhZGRSZXFEYXRhVXNlck9wdDsKICBpZiAodXNlciA9PT0gdW5kZWZpbmVkKSB7CiAgICBhZGRSZXFEYXRhVXNlck9wdCA9IHRydWU7CiAgfSBlbHNlIGlmICh0eXBlb2YgdXNlciA9PT0gJ2Jvb2xlYW4nKSB7CiAgICBhZGRSZXFEYXRhVXNlck9wdCA9IHVzZXI7CiAgfSBlbHNlIHsKICAgIGNvbnN0IHVzZXJJbmNsdWRlS2V5cyA9IFtdOwogICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXModXNlcikpIHsKICAgICAgaWYgKHZhbHVlKSB7CiAgICAgICAgdXNlckluY2x1ZGVLZXlzLnB1c2goa2V5KTsKICAgICAgfQogICAgfQogICAgYWRkUmVxRGF0YVVzZXJPcHQgPSB1c2VySW5jbHVkZUtleXM7CiAgfQoKICByZXR1cm4gewogICAgaW5jbHVkZTogewogICAgICBpcCwKICAgICAgdXNlcjogYWRkUmVxRGF0YVVzZXJPcHQsCiAgICAgIHJlcXVlc3Q6IHJlcXVlc3RJbmNsdWRlS2V5cy5sZW5ndGggIT09IDAgPyByZXF1ZXN0SW5jbHVkZUtleXMgOiB1bmRlZmluZWQsCiAgICAgIHRyYW5zYWN0aW9uOiB0cmFuc2FjdGlvbk5hbWluZ1NjaGVtZSwKICAgIH0sCiAgfTsKfQoKZnVuY3Rpb24gZ2V0U0RLTmFtZShjbGllbnQpIHsKICB0cnkgewogICAgLy8gRm9yIGEgbG9uZyBjaGFpbiBsaWtlIHRoaXMsIGl0J3MgZmV3ZXIgYnl0ZXMgdG8gY29tYmluZSBhIHRyeS1jYXRjaCB3aXRoIGFzc3VtaW5nIGV2ZXJ5dGhpbmcgaXMgdGhlcmUgdGhhbiB0bwogICAgLy8gd3JpdGUgb3V0IGEgbG9uZyBjaGFpbiBvZiBgYSAmJiBhLmIgJiYgYS5iLmMgJiYgLi4uYAogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1ub24tbnVsbC1hc3NlcnRpb24KICAgIHJldHVybiBjbGllbnQuZ2V0T3B0aW9ucygpLl9tZXRhZGF0YS5zZGsubmFtZTsKICB9IGNhdGNoIChlcnIpIHsKICAgIC8vIEluIHRoZW9yeSB3ZSBzaG91bGQgbmV2ZXIgZ2V0IGhlcmUKICAgIHJldHVybiB1bmRlZmluZWQ7CiAgfQp9CgpsZXQgb3JpZ2luYWxGdW5jdGlvblRvU3RyaW5nOwoKY29uc3QgSU5URUdSQVRJT05fTkFNRSQ4ID0gJ0Z1bmN0aW9uVG9TdHJpbmcnOwoKY29uc3QgU0VUVVBfQ0xJRU5UUyA9IG5ldyBXZWFrTWFwKCk7Cgpjb25zdCBfZnVuY3Rpb25Ub1N0cmluZ0ludGVncmF0aW9uID0gKCgpID0+IHsKICByZXR1cm4gewogICAgbmFtZTogSU5URUdSQVRJT05fTkFNRSQ4LAogICAgc2V0dXBPbmNlKCkgewogICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L3VuYm91bmQtbWV0aG9kCiAgICAgIG9yaWdpbmFsRnVuY3Rpb25Ub1N0cmluZyA9IEZ1bmN0aW9uLnByb3RvdHlwZS50b1N0cmluZzsKCiAgICAgIC8vIGludHJpbnNpY3MgKGxpa2UgRnVuY3Rpb24ucHJvdG90eXBlKSBtaWdodCBiZSBpbW11dGFibGUgaW4gc29tZSBlbnZpcm9ubWVudHMKICAgICAgLy8gZS5nLiBOb2RlIHdpdGggLS1mcm96ZW4taW50cmluc2ljcywgWFMgKGFuIGVtYmVkZGVkIEphdmFTY3JpcHQgZW5naW5lKSBvciBTRVMgKGEgSmF2YVNjcmlwdCBwcm9wb3NhbCkKICAgICAgdHJ5IHsKICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueQogICAgICAgIEZ1bmN0aW9uLnByb3RvdHlwZS50b1N0cmluZyA9IGZ1bmN0aW9uICggLi4uYXJncykgewogICAgICAgICAgY29uc3Qgb3JpZ2luYWxGdW5jdGlvbiA9IGdldE9yaWdpbmFsRnVuY3Rpb24odGhpcyk7CiAgICAgICAgICBjb25zdCBjb250ZXh0ID0KICAgICAgICAgICAgU0VUVVBfQ0xJRU5UUy5oYXMoZ2V0Q2xpZW50KCkgKSAmJiBvcmlnaW5hbEZ1bmN0aW9uICE9PSB1bmRlZmluZWQgPyBvcmlnaW5hbEZ1bmN0aW9uIDogdGhpczsKICAgICAgICAgIHJldHVybiBvcmlnaW5hbEZ1bmN0aW9uVG9TdHJpbmcuYXBwbHkoY29udGV4dCwgYXJncyk7CiAgICAgICAgfTsKICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgIC8vIGlnbm9yZSBlcnJvcnMgaGVyZSwganVzdCBkb24ndCBwYXRjaCB0aGlzCiAgICAgIH0KICAgIH0sCiAgICBzZXR1cChjbGllbnQpIHsKICAgICAgU0VUVVBfQ0xJRU5UUy5zZXQoY2xpZW50LCB0cnVlKTsKICAgIH0sCiAgfTsKfSkgOwoKLyoqCiAqIFBhdGNoIHRvU3RyaW5nIGNhbGxzIHRvIHJldHVybiBwcm9wZXIgbmFtZSBmb3Igd3JhcHBlZCBmdW5jdGlvbnMuCiAqCiAqIGBgYGpzCiAqIFNlbnRyeS5pbml0KHsKICogICBpbnRlZ3JhdGlvbnM6IFsKICogICAgIGZ1bmN0aW9uVG9TdHJpbmdJbnRlZ3JhdGlvbigpLAogKiAgIF0sCiAqIH0pOwogKiBgYGAKICovCmNvbnN0IGZ1bmN0aW9uVG9TdHJpbmdJbnRlZ3JhdGlvbiA9IGRlZmluZUludGVncmF0aW9uKF9mdW5jdGlvblRvU3RyaW5nSW50ZWdyYXRpb24pOwoKLyoqCiAqIFBhdGNoIHRvU3RyaW5nIGNhbGxzIHRvIHJldHVybiBwcm9wZXIgbmFtZSBmb3Igd3JhcHBlZCBmdW5jdGlvbnMuCiAqCiAqIEBkZXByZWNhdGVkIFVzZSBgZnVuY3Rpb25Ub1N0cmluZ0ludGVncmF0aW9uKClgIGluc3RlYWQuCiAqLwovLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KY29udmVydEludGVncmF0aW9uRm5Ub0NsYXNzKAogIElOVEVHUkFUSU9OX05BTUUkOCwKICBmdW5jdGlvblRvU3RyaW5nSW50ZWdyYXRpb24sCikgOwoKZnVuY3Rpb24gX251bGxpc2hDb2FsZXNjZSQyKGxocywgcmhzRm4pIHsgaWYgKGxocyAhPSBudWxsKSB7IHJldHVybiBsaHM7IH0gZWxzZSB7IHJldHVybiByaHNGbigpOyB9IH0vKioKICogVGhpcyBjb2RlIHdhcyBvcmlnaW5hbGx5IGZvcmtlZCBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9Ub29UYWxsTmF0ZS9wcm94eS1hZ2VudHMvdHJlZS9iMTMzMjk1ZmQxNmY2NDc1NTc4YjZiMTViZDliNGUzM2VjYjBkMGI3CiAqIFdpdGggdGhlIGZvbGxvd2luZyBsaWNlbmNlOgogKgogKiAoVGhlIE1JVCBMaWNlbnNlKQogKgogKiBDb3B5cmlnaHQgKGMpIDIwMTMgTmF0aGFuIFJhamxpY2ggPG5hdGhhbkB0b290YWxsbmF0ZS5uZXQ+KgogKgogKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcKICogYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlCiAqICdTb2Z0d2FyZScpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcKICogd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLAogKiBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8KICogcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvCiAqIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoqCiAqCiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlCiAqIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLioKICoKICogVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICdBUyBJUycsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsCiAqIEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRgogKiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuCiAqIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCiAqIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsCiAqIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFCiAqIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgogKi8KCmNvbnN0IElOVEVSTkFMID0gU3ltYm9sKCdBZ2VudEJhc2VJbnRlcm5hbFN0YXRlJyk7CgpjbGFzcyBBZ2VudCBleHRlbmRzIGh0dHAuQWdlbnQgewoKICAvLyBTZXQgYnkgYGh0dHAuQWdlbnRgIC0gbWlzc2luZyBmcm9tIGBAdHlwZXMvbm9kZWAKCiAgY29uc3RydWN0b3Iob3B0cykgewogICAgc3VwZXIob3B0cyk7CiAgICB0aGlzW0lOVEVSTkFMXSA9IHt9OwogIH0KCiAgLyoqCiAgICogRGV0ZXJtaW5lIHdoZXRoZXIgdGhpcyBpcyBhbiBgaHR0cGAgb3IgYGh0dHBzYCByZXF1ZXN0LgogICAqLwogIGlzU2VjdXJlRW5kcG9pbnQob3B0aW9ucykgewogICAgaWYgKG9wdGlvbnMpIHsKICAgICAgLy8gRmlyc3QgY2hlY2sgdGhlIGBzZWN1cmVFbmRwb2ludGAgcHJvcGVydHkgZXhwbGljaXRseSwgc2luY2UgdGhpcwogICAgICAvLyBtZWFucyB0aGF0IGEgcGFyZW50IGBBZ2VudGAgaXMgInBhc3NpbmcgdGhyb3VnaCIgdG8gdGhpcyBpbnN0YW5jZS4KICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnksIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtbWVtYmVyLWFjY2VzcwogICAgICBpZiAodHlwZW9mIChvcHRpb25zICkuc2VjdXJlRW5kcG9pbnQgPT09ICdib29sZWFuJykgewogICAgICAgIHJldHVybiBvcHRpb25zLnNlY3VyZUVuZHBvaW50OwogICAgICB9CgogICAgICAvLyBJZiBubyBleHBsaWNpdCBgc2VjdXJlYCBlbmRwb2ludCwgY2hlY2sgaWYgYHByb3RvY29sYCBwcm9wZXJ0eSBpcwogICAgICAvLyBzZXQuIFRoaXMgd2lsbCB1c3VhbGx5IGJlIHRoZSBjYXNlIHNpbmNlIHVzaW5nIGEgZnVsbCBzdHJpbmcgVVJMCiAgICAgIC8vIG9yIGBVUkxgIGluc3RhbmNlIHNob3VsZCBiZSB0aGUgbW9zdCBjb21tb24gdXNhZ2UuCiAgICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5wcm90b2NvbCA9PT0gJ3N0cmluZycpIHsKICAgICAgICByZXR1cm4gb3B0aW9ucy5wcm90b2NvbCA9PT0gJ2h0dHBzOic7CiAgICAgIH0KICAgIH0KCiAgICAvLyBGaW5hbGx5LCBpZiBubyBgcHJvdG9jb2xgIHByb3BlcnR5IHdhcyBzZXQsIHRoZW4gZmFsbCBiYWNrIHRvCiAgICAvLyBjaGVja2luZyB0aGUgc3RhY2sgdHJhY2Ugb2YgdGhlIGN1cnJlbnQgY2FsbCBzdGFjaywgYW5kIHRyeSB0bwogICAgLy8gZGV0ZWN0IHRoZSAiaHR0cHMiIG1vZHVsZS4KICAgIGNvbnN0IHsgc3RhY2sgfSA9IG5ldyBFcnJvcigpOwogICAgaWYgKHR5cGVvZiBzdGFjayAhPT0gJ3N0cmluZycpIHJldHVybiBmYWxzZTsKICAgIHJldHVybiBzdGFjay5zcGxpdCgnXG4nKS5zb21lKGwgPT4gbC5pbmRleE9mKCcoaHR0cHMuanM6JykgIT09IC0xIHx8IGwuaW5kZXhPZignbm9kZTpodHRwczonKSAhPT0gLTEpOwogIH0KCiAgY3JlYXRlU29ja2V0KHJlcSwgb3B0aW9ucywgY2IpIHsKICAgIGNvbnN0IGNvbm5lY3RPcHRzID0gewogICAgICAuLi5vcHRpb25zLAogICAgICBzZWN1cmVFbmRwb2ludDogdGhpcy5pc1NlY3VyZUVuZHBvaW50KG9wdGlvbnMpLAogICAgfTsKICAgIFByb21pc2UucmVzb2x2ZSgpCiAgICAgIC50aGVuKCgpID0+IHRoaXMuY29ubmVjdChyZXEsIGNvbm5lY3RPcHRzKSkKICAgICAgLnRoZW4oc29ja2V0ID0+IHsKICAgICAgICBpZiAoc29ja2V0IGluc3RhbmNlb2YgaHR0cC5BZ2VudCkgewogICAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciBgYWRkUmVxdWVzdCgpYCBpc24ndCBkZWZpbmVkIGluIGBAdHlwZXMvbm9kZWAKICAgICAgICAgIHJldHVybiBzb2NrZXQuYWRkUmVxdWVzdChyZXEsIGNvbm5lY3RPcHRzKTsKICAgICAgICB9CiAgICAgICAgdGhpc1tJTlRFUk5BTF0uY3VycmVudFNvY2tldCA9IHNvY2tldDsKICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIGBjcmVhdGVTb2NrZXQoKWAgaXNuJ3QgZGVmaW5lZCBpbiBgQHR5cGVzL25vZGVgCiAgICAgICAgc3VwZXIuY3JlYXRlU29ja2V0KHJlcSwgb3B0aW9ucywgY2IpOwogICAgICB9LCBjYik7CiAgfQoKICBjcmVhdGVDb25uZWN0aW9uKCkgewogICAgY29uc3Qgc29ja2V0ID0gdGhpc1tJTlRFUk5BTF0uY3VycmVudFNvY2tldDsKICAgIHRoaXNbSU5URVJOQUxdLmN1cnJlbnRTb2NrZXQgPSB1bmRlZmluZWQ7CiAgICBpZiAoIXNvY2tldCkgewogICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHNvY2tldCB3YXMgcmV0dXJuZWQgaW4gdGhlIGBjb25uZWN0KClgIGZ1bmN0aW9uJyk7CiAgICB9CiAgICByZXR1cm4gc29ja2V0OwogIH0KCiAgZ2V0IGRlZmF1bHRQb3J0KCkgewogICAgcmV0dXJuIF9udWxsaXNoQ29hbGVzY2UkMih0aGlzW0lOVEVSTkFMXS5kZWZhdWx0UG9ydCwgKCkgPT4gKCAodGhpcy5wcm90b2NvbCA9PT0gJ2h0dHBzOicgPyA0NDMgOiA4MCkpKTsKICB9CgogIHNldCBkZWZhdWx0UG9ydCh2KSB7CiAgICBpZiAodGhpc1tJTlRFUk5BTF0pIHsKICAgICAgdGhpc1tJTlRFUk5BTF0uZGVmYXVsdFBvcnQgPSB2OwogICAgfQogIH0KCiAgZ2V0IHByb3RvY29sKCkgewogICAgcmV0dXJuIF9udWxsaXNoQ29hbGVzY2UkMih0aGlzW0lOVEVSTkFMXS5wcm90b2NvbCwgKCkgPT4gKCAodGhpcy5pc1NlY3VyZUVuZHBvaW50KCkgPyAnaHR0cHM6JyA6ICdodHRwOicpKSk7CiAgfQoKICBzZXQgcHJvdG9jb2wodikgewogICAgaWYgKHRoaXNbSU5URVJOQUxdKSB7CiAgICAgIHRoaXNbSU5URVJOQUxdLnByb3RvY29sID0gdjsKICAgIH0KICB9Cn0KCmZ1bmN0aW9uIGRlYnVnJDEoLi4uYXJncykgewogIGxvZ2dlci5sb2coJ1todHRwcy1wcm94eS1hZ2VudDpwYXJzZS1wcm94eS1yZXNwb25zZV0nLCAuLi5hcmdzKTsKfQoKZnVuY3Rpb24gcGFyc2VQcm94eVJlc3BvbnNlKHNvY2tldCkgewogIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7CiAgICAvLyB3ZSBuZWVkIHRvIGJ1ZmZlciBhbnkgSFRUUCB0cmFmZmljIHRoYXQgaGFwcGVucyB3aXRoIHRoZSBwcm94eSBiZWZvcmUgd2UgZ2V0CiAgICAvLyB0aGUgQ09OTkVDVCByZXNwb25zZSwgc28gdGhhdCBpZiB0aGUgcmVzcG9uc2UgaXMgYW55dGhpbmcgb3RoZXIgdGhhbiBhbiAiMjAwIgogICAgLy8gcmVzcG9uc2UgY29kZSwgdGhlbiB3ZSBjYW4gcmUtcGxheSB0aGUgImRhdGEiIGV2ZW50cyBvbiB0aGUgc29ja2V0IG9uY2UgdGhlCiAgICAvLyBIVFRQIHBhcnNlciBpcyBob29rZWQgdXAuLi4KICAgIGxldCBidWZmZXJzTGVuZ3RoID0gMDsKICAgIGNvbnN0IGJ1ZmZlcnMgPSBbXTsKCiAgICBmdW5jdGlvbiByZWFkKCkgewogICAgICBjb25zdCBiID0gc29ja2V0LnJlYWQoKTsKICAgICAgaWYgKGIpIG9uZGF0YShiKTsKICAgICAgZWxzZSBzb2NrZXQub25jZSgncmVhZGFibGUnLCByZWFkKTsKICAgIH0KCiAgICBmdW5jdGlvbiBjbGVhbnVwKCkgewogICAgICBzb2NrZXQucmVtb3ZlTGlzdGVuZXIoJ2VuZCcsIG9uZW5kKTsKICAgICAgc29ja2V0LnJlbW92ZUxpc3RlbmVyKCdlcnJvcicsIG9uZXJyb3IpOwogICAgICBzb2NrZXQucmVtb3ZlTGlzdGVuZXIoJ3JlYWRhYmxlJywgcmVhZCk7CiAgICB9CgogICAgZnVuY3Rpb24gb25lbmQoKSB7CiAgICAgIGNsZWFudXAoKTsKICAgICAgZGVidWckMSgnb25lbmQnKTsKICAgICAgcmVqZWN0KG5ldyBFcnJvcignUHJveHkgY29ubmVjdGlvbiBlbmRlZCBiZWZvcmUgcmVjZWl2aW5nIENPTk5FQ1QgcmVzcG9uc2UnKSk7CiAgICB9CgogICAgZnVuY3Rpb24gb25lcnJvcihlcnIpIHsKICAgICAgY2xlYW51cCgpOwogICAgICBkZWJ1ZyQxKCdvbmVycm9yICVvJywgZXJyKTsKICAgICAgcmVqZWN0KGVycik7CiAgICB9CgogICAgZnVuY3Rpb24gb25kYXRhKGIpIHsKICAgICAgYnVmZmVycy5wdXNoKGIpOwogICAgICBidWZmZXJzTGVuZ3RoICs9IGIubGVuZ3RoOwoKICAgICAgY29uc3QgYnVmZmVyZWQgPSBCdWZmZXIuY29uY2F0KGJ1ZmZlcnMsIGJ1ZmZlcnNMZW5ndGgpOwogICAgICBjb25zdCBlbmRPZkhlYWRlcnMgPSBidWZmZXJlZC5pbmRleE9mKCdcclxuXHJcbicpOwoKICAgICAgaWYgKGVuZE9mSGVhZGVycyA9PT0gLTEpIHsKICAgICAgICAvLyBrZWVwIGJ1ZmZlcmluZwogICAgICAgIGRlYnVnJDEoJ2hhdmUgbm90IHJlY2VpdmVkIGVuZCBvZiBIVFRQIGhlYWRlcnMgeWV0Li4uJyk7CiAgICAgICAgcmVhZCgpOwogICAgICAgIHJldHVybjsKICAgICAgfQoKICAgICAgY29uc3QgaGVhZGVyUGFydHMgPSBidWZmZXJlZC5zbGljZSgwLCBlbmRPZkhlYWRlcnMpLnRvU3RyaW5nKCdhc2NpaScpLnNwbGl0KCdcclxuJyk7CiAgICAgIGNvbnN0IGZpcnN0TGluZSA9IGhlYWRlclBhcnRzLnNoaWZ0KCk7CiAgICAgIGlmICghZmlyc3RMaW5lKSB7CiAgICAgICAgc29ja2V0LmRlc3Ryb3koKTsKICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBFcnJvcignTm8gaGVhZGVyIHJlY2VpdmVkIGZyb20gcHJveHkgQ09OTkVDVCByZXNwb25zZScpKTsKICAgICAgfQogICAgICBjb25zdCBmaXJzdExpbmVQYXJ0cyA9IGZpcnN0TGluZS5zcGxpdCgnICcpOwogICAgICBjb25zdCBzdGF0dXNDb2RlID0gK2ZpcnN0TGluZVBhcnRzWzFdOwogICAgICBjb25zdCBzdGF0dXNUZXh0ID0gZmlyc3RMaW5lUGFydHMuc2xpY2UoMikuam9pbignICcpOwogICAgICBjb25zdCBoZWFkZXJzID0ge307CiAgICAgIGZvciAoY29uc3QgaGVhZGVyIG9mIGhlYWRlclBhcnRzKSB7CiAgICAgICAgaWYgKCFoZWFkZXIpIGNvbnRpbnVlOwogICAgICAgIGNvbnN0IGZpcnN0Q29sb24gPSBoZWFkZXIuaW5kZXhPZignOicpOwogICAgICAgIGlmIChmaXJzdENvbG9uID09PSAtMSkgewogICAgICAgICAgc29ja2V0LmRlc3Ryb3koKTsKICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEVycm9yKGBJbnZhbGlkIGhlYWRlciBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2U6ICIke2hlYWRlcn0iYCkpOwogICAgICAgIH0KICAgICAgICBjb25zdCBrZXkgPSBoZWFkZXIuc2xpY2UoMCwgZmlyc3RDb2xvbikudG9Mb3dlckNhc2UoKTsKICAgICAgICBjb25zdCB2YWx1ZSA9IGhlYWRlci5zbGljZShmaXJzdENvbG9uICsgMSkudHJpbVN0YXJ0KCk7CiAgICAgICAgY29uc3QgY3VycmVudCA9IGhlYWRlcnNba2V5XTsKICAgICAgICBpZiAodHlwZW9mIGN1cnJlbnQgPT09ICdzdHJpbmcnKSB7CiAgICAgICAgICBoZWFkZXJzW2tleV0gPSBbY3VycmVudCwgdmFsdWVdOwogICAgICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShjdXJyZW50KSkgewogICAgICAgICAgY3VycmVudC5wdXNoKHZhbHVlKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgaGVhZGVyc1trZXldID0gdmFsdWU7CiAgICAgICAgfQogICAgICB9CiAgICAgIGRlYnVnJDEoJ2dvdCBwcm94eSBzZXJ2ZXIgcmVzcG9uc2U6ICVvICVvJywgZmlyc3RMaW5lLCBoZWFkZXJzKTsKICAgICAgY2xlYW51cCgpOwogICAgICByZXNvbHZlKHsKICAgICAgICBjb25uZWN0OiB7CiAgICAgICAgICBzdGF0dXNDb2RlLAogICAgICAgICAgc3RhdHVzVGV4dCwKICAgICAgICAgIGhlYWRlcnMsCiAgICAgICAgfSwKICAgICAgICBidWZmZXJlZCwKICAgICAgfSk7CiAgICB9CgogICAgc29ja2V0Lm9uKCdlcnJvcicsIG9uZXJyb3IpOwogICAgc29ja2V0Lm9uKCdlbmQnLCBvbmVuZCk7CgogICAgcmVhZCgpOwogIH0pOwp9CgpmdW5jdGlvbiBfbnVsbGlzaENvYWxlc2NlJDEobGhzLCByaHNGbikgeyBpZiAobGhzICE9IG51bGwpIHsgcmV0dXJuIGxoczsgfSBlbHNlIHsgcmV0dXJuIHJoc0ZuKCk7IH0gfSBmdW5jdGlvbiBfb3B0aW9uYWxDaGFpbiQxKG9wcykgeyBsZXQgbGFzdEFjY2Vzc0xIUyA9IHVuZGVmaW5lZDsgbGV0IHZhbHVlID0gb3BzWzBdOyBsZXQgaSA9IDE7IHdoaWxlIChpIDwgb3BzLmxlbmd0aCkgeyBjb25zdCBvcCA9IG9wc1tpXTsgY29uc3QgZm4gPSBvcHNbaSArIDFdOyBpICs9IDI7IGlmICgob3AgPT09ICdvcHRpb25hbEFjY2VzcycgfHwgb3AgPT09ICdvcHRpb25hbENhbGwnKSAmJiB2YWx1ZSA9PSBudWxsKSB7IHJldHVybiB1bmRlZmluZWQ7IH0gaWYgKG9wID09PSAnYWNjZXNzJyB8fCBvcCA9PT0gJ29wdGlvbmFsQWNjZXNzJykgeyBsYXN0QWNjZXNzTEhTID0gdmFsdWU7IHZhbHVlID0gZm4odmFsdWUpOyB9IGVsc2UgaWYgKG9wID09PSAnY2FsbCcgfHwgb3AgPT09ICdvcHRpb25hbENhbGwnKSB7IHZhbHVlID0gZm4oKC4uLmFyZ3MpID0+IHZhbHVlLmNhbGwobGFzdEFjY2Vzc0xIUywgLi4uYXJncykpOyBsYXN0QWNjZXNzTEhTID0gdW5kZWZpbmVkOyB9IH0gcmV0dXJuIHZhbHVlOyB9CgpmdW5jdGlvbiBkZWJ1ZyguLi5hcmdzKSB7CiAgbG9nZ2VyLmxvZygnW2h0dHBzLXByb3h5LWFnZW50XScsIC4uLmFyZ3MpOwp9CgovKioKICogVGhlIGBIdHRwc1Byb3h5QWdlbnRgIGltcGxlbWVudHMgYW4gSFRUUCBBZ2VudCBzdWJjbGFzcyB0aGF0IGNvbm5lY3RzIHRvCiAqIHRoZSBzcGVjaWZpZWQgIkhUVFAocykgcHJveHkgc2VydmVyIiBpbiBvcmRlciB0byBwcm94eSBIVFRQUyByZXF1ZXN0cy4KICoKICogT3V0Z29pbmcgSFRUUCByZXF1ZXN0cyBhcmUgZmlyc3QgdHVubmVsZWQgdGhyb3VnaCB0aGUgcHJveHkgc2VydmVyIHVzaW5nIHRoZQogKiBgQ09OTkVDVGAgSFRUUCByZXF1ZXN0IG1ldGhvZCB0byBlc3RhYmxpc2ggYSBjb25uZWN0aW9uIHRvIHRoZSBwcm94eSBzZXJ2ZXIsCiAqIGFuZCB0aGVuIHRoZSBwcm94eSBzZXJ2ZXIgY29ubmVjdHMgdG8gdGhlIGRlc3RpbmF0aW9uIHRhcmdldCBhbmQgaXNzdWVzIHRoZQogKiBIVFRQIHJlcXVlc3QgZnJvbSB0aGUgcHJveHkgc2VydmVyLgogKgogKiBgaHR0cHM6YCByZXF1ZXN0cyBoYXZlIHRoZWlyIHNvY2tldCBjb25uZWN0aW9uIHVwZ3JhZGVkIHRvIFRMUyBvbmNlCiAqIHRoZSBjb25uZWN0aW9uIHRvIHRoZSBwcm94eSBzZXJ2ZXIgaGFzIGJlZW4gZXN0YWJsaXNoZWQuCiAqLwpjbGFzcyBIdHRwc1Byb3h5QWdlbnQgZXh0ZW5kcyBBZ2VudCB7CiAgc3RhdGljIF9faW5pdFN0YXRpYygpIHt0aGlzLnByb3RvY29scyA9IFsnaHR0cCcsICdodHRwcyddOyB9CgogIGNvbnN0cnVjdG9yKHByb3h5LCBvcHRzKSB7CiAgICBzdXBlcihvcHRzKTsKICAgIHRoaXMub3B0aW9ucyA9IHt9OwogICAgdGhpcy5wcm94eSA9IHR5cGVvZiBwcm94eSA9PT0gJ3N0cmluZycgPyBuZXcgVVJMKHByb3h5KSA6IHByb3h5OwogICAgdGhpcy5wcm94eUhlYWRlcnMgPSBfbnVsbGlzaENvYWxlc2NlJDEoX29wdGlvbmFsQ2hhaW4kMShbb3B0cywgJ29wdGlvbmFsQWNjZXNzJywgXzIgPT4gXzIuaGVhZGVyc10pLCAoKSA9PiAoIHt9KSk7CiAgICBkZWJ1ZygnQ3JlYXRpbmcgbmV3IEh0dHBzUHJveHlBZ2VudCBpbnN0YW5jZTogJW8nLCB0aGlzLnByb3h5LmhyZWYpOwoKICAgIC8vIFRyaW0gb2ZmIHRoZSBicmFja2V0cyBmcm9tIElQdjYgYWRkcmVzc2VzCiAgICBjb25zdCBob3N0ID0gKHRoaXMucHJveHkuaG9zdG5hbWUgfHwgdGhpcy5wcm94eS5ob3N0KS5yZXBsYWNlKC9eXFt8XF0kL2csICcnKTsKICAgIGNvbnN0IHBvcnQgPSB0aGlzLnByb3h5LnBvcnQgPyBwYXJzZUludCh0aGlzLnByb3h5LnBvcnQsIDEwKSA6IHRoaXMucHJveHkucHJvdG9jb2wgPT09ICdodHRwczonID8gNDQzIDogODA7CiAgICB0aGlzLmNvbm5lY3RPcHRzID0gewogICAgICAvLyBBdHRlbXB0IHRvIG5lZ290aWF0ZSBodHRwLzEuMSBmb3IgcHJveHkgc2VydmVycyB0aGF0IHN1cHBvcnQgaHR0cC8yCiAgICAgIEFMUE5Qcm90b2NvbHM6IFsnaHR0cC8xLjEnXSwKICAgICAgLi4uKG9wdHMgPyBvbWl0KG9wdHMsICdoZWFkZXJzJykgOiBudWxsKSwKICAgICAgaG9zdCwKICAgICAgcG9ydCwKICAgIH07CiAgfQoKICAvKioKICAgKiBDYWxsZWQgd2hlbiB0aGUgbm9kZS1jb3JlIEhUVFAgY2xpZW50IGxpYnJhcnkgaXMgY3JlYXRpbmcgYQogICAqIG5ldyBIVFRQIHJlcXVlc3QuCiAgICovCiAgYXN5bmMgY29ubmVjdChyZXEsIG9wdHMpIHsKICAgIGNvbnN0IHsgcHJveHkgfSA9IHRoaXM7CgogICAgaWYgKCFvcHRzLmhvc3QpIHsKICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignTm8gImhvc3QiIHByb3ZpZGVkJyk7CiAgICB9CgogICAgLy8gQ3JlYXRlIGEgc29ja2V0IGNvbm5lY3Rpb24gdG8gdGhlIHByb3h5IHNlcnZlci4KICAgIGxldCBzb2NrZXQ7CiAgICBpZiAocHJveHkucHJvdG9jb2wgPT09ICdodHRwczonKSB7CiAgICAgIGRlYnVnKCdDcmVhdGluZyBgdGxzLlNvY2tldGA6ICVvJywgdGhpcy5jb25uZWN0T3B0cyk7CiAgICAgIGNvbnN0IHNlcnZlcm5hbWUgPSB0aGlzLmNvbm5lY3RPcHRzLnNlcnZlcm5hbWUgfHwgdGhpcy5jb25uZWN0T3B0cy5ob3N0OwogICAgICBzb2NrZXQgPSB0bHMuY29ubmVjdCh7CiAgICAgICAgLi4udGhpcy5jb25uZWN0T3B0cywKICAgICAgICBzZXJ2ZXJuYW1lOiBzZXJ2ZXJuYW1lICYmIG5ldC5pc0lQKHNlcnZlcm5hbWUpID8gdW5kZWZpbmVkIDogc2VydmVybmFtZSwKICAgICAgfSk7CiAgICB9IGVsc2UgewogICAgICBkZWJ1ZygnQ3JlYXRpbmcgYG5ldC5Tb2NrZXRgOiAlbycsIHRoaXMuY29ubmVjdE9wdHMpOwogICAgICBzb2NrZXQgPSBuZXQuY29ubmVjdCh0aGlzLmNvbm5lY3RPcHRzKTsKICAgIH0KCiAgICBjb25zdCBoZWFkZXJzID0KICAgICAgdHlwZW9mIHRoaXMucHJveHlIZWFkZXJzID09PSAnZnVuY3Rpb24nID8gdGhpcy5wcm94eUhlYWRlcnMoKSA6IHsgLi4udGhpcy5wcm94eUhlYWRlcnMgfTsKICAgIGNvbnN0IGhvc3QgPSBuZXQuaXNJUHY2KG9wdHMuaG9zdCkgPyBgWyR7b3B0cy5ob3N0fV1gIDogb3B0cy5ob3N0OwogICAgbGV0IHBheWxvYWQgPSBgQ09OTkVDVCAke2hvc3R9OiR7b3B0cy5wb3J0fSBIVFRQLzEuMVxyXG5gOwoKICAgIC8vIEluamVjdCB0aGUgYFByb3h5LUF1dGhvcml6YXRpb25gIGhlYWRlciBpZiBuZWNlc3NhcnkuCiAgICBpZiAocHJveHkudXNlcm5hbWUgfHwgcHJveHkucGFzc3dvcmQpIHsKICAgICAgY29uc3QgYXV0aCA9IGAke2RlY29kZVVSSUNvbXBvbmVudChwcm94eS51c2VybmFtZSl9OiR7ZGVjb2RlVVJJQ29tcG9uZW50KHByb3h5LnBhc3N3b3JkKX1gOwogICAgICBoZWFkZXJzWydQcm94eS1BdXRob3JpemF0aW9uJ10gPSBgQmFzaWMgJHtCdWZmZXIuZnJvbShhdXRoKS50b1N0cmluZygnYmFzZTY0Jyl9YDsKICAgIH0KCiAgICBoZWFkZXJzLkhvc3QgPSBgJHtob3N0fToke29wdHMucG9ydH1gOwoKICAgIGlmICghaGVhZGVyc1snUHJveHktQ29ubmVjdGlvbiddKSB7CiAgICAgIGhlYWRlcnNbJ1Byb3h5LUNvbm5lY3Rpb24nXSA9IHRoaXMua2VlcEFsaXZlID8gJ0tlZXAtQWxpdmUnIDogJ2Nsb3NlJzsKICAgIH0KICAgIGZvciAoY29uc3QgbmFtZSBvZiBPYmplY3Qua2V5cyhoZWFkZXJzKSkgewogICAgICBwYXlsb2FkICs9IGAke25hbWV9OiAke2hlYWRlcnNbbmFtZV19XHJcbmA7CiAgICB9CgogICAgY29uc3QgcHJveHlSZXNwb25zZVByb21pc2UgPSBwYXJzZVByb3h5UmVzcG9uc2Uoc29ja2V0KTsKCiAgICBzb2NrZXQud3JpdGUoYCR7cGF5bG9hZH1cclxuYCk7CgogICAgY29uc3QgeyBjb25uZWN0LCBidWZmZXJlZCB9ID0gYXdhaXQgcHJveHlSZXNwb25zZVByb21pc2U7CiAgICByZXEuZW1pdCgncHJveHlDb25uZWN0JywgY29ubmVjdCk7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10cy1jb21tZW50CiAgICAvLyBAdHMtaWdub3JlIE5vdCBFdmVudEVtaXR0ZXIgaW4gTm9kZSB0eXBlcwogICAgdGhpcy5lbWl0KCdwcm94eUNvbm5lY3QnLCBjb25uZWN0LCByZXEpOwoKICAgIGlmIChjb25uZWN0LnN0YXR1c0NvZGUgPT09IDIwMCkgewogICAgICByZXEub25jZSgnc29ja2V0JywgcmVzdW1lKTsKCiAgICAgIGlmIChvcHRzLnNlY3VyZUVuZHBvaW50KSB7CiAgICAgICAgLy8gVGhlIHByb3h5IGlzIGNvbm5lY3RpbmcgdG8gYSBUTFMgc2VydmVyLCBzbyB1cGdyYWRlCiAgICAgICAgLy8gdGhpcyBzb2NrZXQgY29ubmVjdGlvbiB0byBhIFRMUyBjb25uZWN0aW9uLgogICAgICAgIGRlYnVnKCdVcGdyYWRpbmcgc29ja2V0IGNvbm5lY3Rpb24gdG8gVExTJyk7CiAgICAgICAgY29uc3Qgc2VydmVybmFtZSA9IG9wdHMuc2VydmVybmFtZSB8fCBvcHRzLmhvc3Q7CiAgICAgICAgcmV0dXJuIHRscy5jb25uZWN0KHsKICAgICAgICAgIC4uLm9taXQob3B0cywgJ2hvc3QnLCAncGF0aCcsICdwb3J0JyksCiAgICAgICAgICBzb2NrZXQsCiAgICAgICAgICBzZXJ2ZXJuYW1lOiBuZXQuaXNJUChzZXJ2ZXJuYW1lKSA/IHVuZGVmaW5lZCA6IHNlcnZlcm5hbWUsCiAgICAgICAgfSk7CiAgICAgIH0KCiAgICAgIHJldHVybiBzb2NrZXQ7CiAgICB9CgogICAgLy8gU29tZSBvdGhlciBzdGF0dXMgY29kZSB0aGF0J3Mgbm90IDIwMC4uLiBuZWVkIHRvIHJlLXBsYXkgdGhlIEhUVFAKICAgIC8vIGhlYWRlciAiZGF0YSIgZXZlbnRzIG9udG8gdGhlIHNvY2tldCBvbmNlIHRoZSBIVFRQIG1hY2hpbmVyeSBpcwogICAgLy8gYXR0YWNoZWQgc28gdGhhdCB0aGUgbm9kZSBjb3JlIGBodHRwYCBjYW4gcGFyc2UgYW5kIGhhbmRsZSB0aGUKICAgIC8vIGVycm9yIHN0YXR1cyBjb2RlLgoKICAgIC8vIENsb3NlIHRoZSBvcmlnaW5hbCBzb2NrZXQsIGFuZCBhIG5ldyAiZmFrZSIgc29ja2V0IGlzIHJldHVybmVkCiAgICAvLyBpbnN0ZWFkLCBzbyB0aGF0IHRoZSBwcm94eSBkb2Vzbid0IGdldCB0aGUgSFRUUCByZXF1ZXN0CiAgICAvLyB3cml0dGVuIHRvIGl0ICh3aGljaCBtYXkgY29udGFpbiBgQXV0aG9yaXphdGlvbmAgaGVhZGVycyBvciBvdGhlcgogICAgLy8gc2Vuc2l0aXZlIGRhdGEpLgogICAgLy8KICAgIC8vIFNlZTogaHR0cHM6Ly9oYWNrZXJvbmUuY29tL3JlcG9ydHMvNTQxNTAyCiAgICBzb2NrZXQuZGVzdHJveSgpOwoKICAgIGNvbnN0IGZha2VTb2NrZXQgPSBuZXcgbmV0LlNvY2tldCh7IHdyaXRhYmxlOiBmYWxzZSB9KTsKICAgIGZha2VTb2NrZXQucmVhZGFibGUgPSB0cnVlOwoKICAgIC8vIE5lZWQgdG8gd2FpdCBmb3IgdGhlICJzb2NrZXQiIGV2ZW50IHRvIHJlLXBsYXkgdGhlICJkYXRhIiBldmVudHMuCiAgICByZXEub25jZSgnc29ja2V0JywgKHMpID0+IHsKICAgICAgZGVidWcoJ1JlcGxheWluZyBwcm94eSBidWZmZXIgZm9yIGZhaWxlZCByZXF1ZXN0Jyk7CiAgICAgIC8vIFJlcGxheSB0aGUgImJ1ZmZlcmVkIiBCdWZmZXIgb250byB0aGUgZmFrZSBgc29ja2V0YCwgc2luY2UgYXQKICAgICAgLy8gdGhpcyBwb2ludCB0aGUgSFRUUCBtb2R1bGUgbWFjaGluZXJ5IGhhcyBiZWVuIGhvb2tlZCB1cCBmb3IKICAgICAgLy8gdGhlIHVzZXIuCiAgICAgIHMucHVzaChidWZmZXJlZCk7CiAgICAgIHMucHVzaChudWxsKTsKICAgIH0pOwoKICAgIHJldHVybiBmYWtlU29ja2V0OwogIH0KfSBIdHRwc1Byb3h5QWdlbnQuX19pbml0U3RhdGljKCk7CgpmdW5jdGlvbiByZXN1bWUoc29ja2V0KSB7CiAgc29ja2V0LnJlc3VtZSgpOwp9CgpmdW5jdGlvbiBvbWl0KAogIG9iaiwKICAuLi5rZXlzCikKCiB7CiAgY29uc3QgcmV0ID0ge30KCjsKICBsZXQga2V5OwogIGZvciAoa2V5IGluIG9iaikgewogICAgaWYgKCFrZXlzLmluY2x1ZGVzKGtleSkpIHsKICAgICAgcmV0W2tleV0gPSBvYmpba2V5XTsKICAgIH0KICB9CiAgcmV0dXJuIHJldDsKfQoKZnVuY3Rpb24gX251bGxpc2hDb2FsZXNjZShsaHMsIHJoc0ZuKSB7IGlmIChsaHMgIT0gbnVsbCkgeyByZXR1cm4gbGhzOyB9IGVsc2UgeyByZXR1cm4gcmhzRm4oKTsgfSB9Ci8vIEVzdGltYXRlZCBtYXhpbXVtIHNpemUgZm9yIHJlYXNvbmFibGUgc3RhbmRhbG9uZSBldmVudApjb25zdCBHWklQX1RIUkVTSE9MRCA9IDEwMjQgKiAzMjsKCi8qKgogKiBHZXRzIGEgc3RyZWFtIGZyb20gYSBVaW50OEFycmF5IG9yIHN0cmluZwogKiBSZWFkYWJsZS5mcm9tIGlzIGlkZWFsIGJ1dCB3YXMgYWRkZWQgaW4gbm9kZS5qcyB2MTIuMy4wIGFuZCB2MTAuMTcuMAogKi8KZnVuY3Rpb24gc3RyZWFtRnJvbUJvZHkoYm9keSkgewogIHJldHVybiBuZXcgUmVhZGFibGUoewogICAgcmVhZCgpIHsKICAgICAgdGhpcy5wdXNoKGJvZHkpOwogICAgICB0aGlzLnB1c2gobnVsbCk7CiAgICB9LAogIH0pOwp9CgovKioKICogQ3JlYXRlcyBhIFRyYW5zcG9ydCB0aGF0IHVzZXMgbmF0aXZlIHRoZSBuYXRpdmUgJ2h0dHAnIGFuZCAnaHR0cHMnIG1vZHVsZXMgdG8gc2VuZCBldmVudHMgdG8gU2VudHJ5LgogKi8KZnVuY3Rpb24gbWFrZU5vZGVUcmFuc3BvcnQob3B0aW9ucykgewogIGxldCB1cmxTZWdtZW50czsKCiAgdHJ5IHsKICAgIHVybFNlZ21lbnRzID0gbmV3IFVSTChvcHRpb25zLnVybCk7CiAgfSBjYXRjaCAoZSkgewogICAgY29uc29sZVNhbmRib3goKCkgPT4gewogICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZQogICAgICBjb25zb2xlLndhcm4oCiAgICAgICAgJ1tAc2VudHJ5L25vZGVdOiBJbnZhbGlkIGRzbiBvciB0dW5uZWwgb3B0aW9uLCB3aWxsIG5vdCBzZW5kIGFueSBldmVudHMuIFRoZSB0dW5uZWwgb3B0aW9uIG11c3QgYmUgYSBmdWxsIFVSTCB3aGVuIHVzZWQuJywKICAgICAgKTsKICAgIH0pOwogICAgcmV0dXJuIGNyZWF0ZVRyYW5zcG9ydChvcHRpb25zLCAoKSA9PiBQcm9taXNlLnJlc29sdmUoe30pKTsKICB9CgogIGNvbnN0IGlzSHR0cHMgPSB1cmxTZWdtZW50cy5wcm90b2NvbCA9PT0gJ2h0dHBzOic7CgogIC8vIFByb3h5IHByaW9yaXRpemF0aW9uOiBodHRwID0+IGBvcHRpb25zLnByb3h5YCB8IGBwcm9jZXNzLmVudi5odHRwX3Byb3h5YAogIC8vIFByb3h5IHByaW9yaXRpemF0aW9uOiBodHRwcyA9PiBgb3B0aW9ucy5wcm94eWAgfCBgcHJvY2Vzcy5lbnYuaHR0cHNfcHJveHlgIHwgYHByb2Nlc3MuZW52Lmh0dHBfcHJveHlgCiAgY29uc3QgcHJveHkgPSBhcHBseU5vUHJveHlPcHRpb24oCiAgICB1cmxTZWdtZW50cywKICAgIG9wdGlvbnMucHJveHkgfHwgKGlzSHR0cHMgPyBwcm9jZXNzLmVudi5odHRwc19wcm94eSA6IHVuZGVmaW5lZCkgfHwgcHJvY2Vzcy5lbnYuaHR0cF9wcm94eSwKICApOwoKICBjb25zdCBuYXRpdmVIdHRwTW9kdWxlID0gaXNIdHRwcyA/IGh0dHBzIDogaHR0cCQxOwogIGNvbnN0IGtlZXBBbGl2ZSA9IG9wdGlvbnMua2VlcEFsaXZlID09PSB1bmRlZmluZWQgPyBmYWxzZSA6IG9wdGlvbnMua2VlcEFsaXZlOwoKICAvLyBUT0RPKHY3KTogRXZhbHVhdGUgaWYgd2UgY2FuIHNldCBrZWVwQWxpdmUgdG8gdHJ1ZS4gVGhpcyB3b3VsZCBpbnZvbHZlIHRlc3RpbmcgZm9yIG1lbW9yeSBsZWFrcyBpbiBvbGRlciBub2RlCiAgLy8gdmVyc2lvbnMoPj0gOCkgYXMgdGhleSBoYWQgbWVtb3J5IGxlYWtzIHdoZW4gdXNpbmcgaXQ6ICMyNTU1CiAgY29uc3QgYWdlbnQgPSBwcm94eQogICAgPyAobmV3IEh0dHBzUHJveHlBZ2VudChwcm94eSkgKQogICAgOiBuZXcgbmF0aXZlSHR0cE1vZHVsZS5BZ2VudCh7IGtlZXBBbGl2ZSwgbWF4U29ja2V0czogMzAsIHRpbWVvdXQ6IDIwMDAgfSk7CgogIGNvbnN0IHJlcXVlc3RFeGVjdXRvciA9IGNyZWF0ZVJlcXVlc3RFeGVjdXRvcihvcHRpb25zLCBfbnVsbGlzaENvYWxlc2NlKG9wdGlvbnMuaHR0cE1vZHVsZSwgKCkgPT4gKCBuYXRpdmVIdHRwTW9kdWxlKSksIGFnZW50KTsKICByZXR1cm4gY3JlYXRlVHJhbnNwb3J0KG9wdGlvbnMsIHJlcXVlc3RFeGVjdXRvcik7Cn0KCi8qKgogKiBIb25vcnMgdGhlIGBub19wcm94eWAgZW52IHZhcmlhYmxlIHdpdGggdGhlIGhpZ2hlc3QgcHJpb3JpdHkgdG8gYWxsb3cgZm9yIGhvc3RzIGV4Y2x1c2lvbi4KICoKICogQHBhcmFtIHRyYW5zcG9ydFVybCBUaGUgVVJMIHRoZSB0cmFuc3BvcnQgaW50ZW5kcyB0byBzZW5kIGV2ZW50cyB0by4KICogQHBhcmFtIHByb3h5IFRoZSBjbGllbnQgY29uZmlndXJlZCBwcm94eS4KICogQHJldHVybnMgQSBwcm94eSB0aGUgdHJhbnNwb3J0IHNob3VsZCB1c2UuCiAqLwpmdW5jdGlvbiBhcHBseU5vUHJveHlPcHRpb24odHJhbnNwb3J0VXJsU2VnbWVudHMsIHByb3h5KSB7CiAgY29uc3QgeyBub19wcm94eSB9ID0gcHJvY2Vzcy5lbnY7CgogIGNvbnN0IHVybElzRXhlbXB0RnJvbVByb3h5ID0KICAgIG5vX3Byb3h5ICYmCiAgICBub19wcm94eQogICAgICAuc3BsaXQoJywnKQogICAgICAuc29tZSgKICAgICAgICBleGVtcHRpb24gPT4gdHJhbnNwb3J0VXJsU2VnbWVudHMuaG9zdC5lbmRzV2l0aChleGVtcHRpb24pIHx8IHRyYW5zcG9ydFVybFNlZ21lbnRzLmhvc3RuYW1lLmVuZHNXaXRoKGV4ZW1wdGlvbiksCiAgICAgICk7CgogIGlmICh1cmxJc0V4ZW1wdEZyb21Qcm94eSkgewogICAgcmV0dXJuIHVuZGVmaW5lZDsKICB9IGVsc2UgewogICAgcmV0dXJuIHByb3h5OwogIH0KfQoKLyoqCiAqIENyZWF0ZXMgYSBSZXF1ZXN0RXhlY3V0b3IgdG8gYmUgdXNlZCB3aXRoIGBjcmVhdGVUcmFuc3BvcnRgLgogKi8KZnVuY3Rpb24gY3JlYXRlUmVxdWVzdEV4ZWN1dG9yKAogIG9wdGlvbnMsCiAgaHR0cE1vZHVsZSwKICBhZ2VudCwKKSB7CiAgY29uc3QgeyBob3N0bmFtZSwgcGF0aG5hbWUsIHBvcnQsIHByb3RvY29sLCBzZWFyY2ggfSA9IG5ldyBVUkwob3B0aW9ucy51cmwpOwogIHJldHVybiBmdW5jdGlvbiBtYWtlUmVxdWVzdChyZXF1ZXN0KSB7CiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4gewogICAgICBsZXQgYm9keSA9IHN0cmVhbUZyb21Cb2R5KHJlcXVlc3QuYm9keSk7CgogICAgICBjb25zdCBoZWFkZXJzID0geyAuLi5vcHRpb25zLmhlYWRlcnMgfTsKCiAgICAgIGlmIChyZXF1ZXN0LmJvZHkubGVuZ3RoID4gR1pJUF9USFJFU0hPTEQpIHsKICAgICAgICBoZWFkZXJzWydjb250ZW50LWVuY29kaW5nJ10gPSAnZ3ppcCc7CiAgICAgICAgYm9keSA9IGJvZHkucGlwZShjcmVhdGVHemlwKCkpOwogICAgICB9CgogICAgICBjb25zdCByZXEgPSBodHRwTW9kdWxlLnJlcXVlc3QoCiAgICAgICAgewogICAgICAgICAgbWV0aG9kOiAnUE9TVCcsCiAgICAgICAgICBhZ2VudCwKICAgICAgICAgIGhlYWRlcnMsCiAgICAgICAgICBob3N0bmFtZSwKICAgICAgICAgIHBhdGg6IGAke3BhdGhuYW1lfSR7c2VhcmNofWAsCiAgICAgICAgICBwb3J0LAogICAgICAgICAgcHJvdG9jb2wsCiAgICAgICAgICBjYTogb3B0aW9ucy5jYUNlcnRzLAogICAgICAgIH0sCiAgICAgICAgcmVzID0+IHsKICAgICAgICAgIHJlcy5vbignZGF0YScsICgpID0+IHsKICAgICAgICAgICAgLy8gRHJhaW4gc29ja2V0CiAgICAgICAgICB9KTsKCiAgICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHsKICAgICAgICAgICAgLy8gRHJhaW4gc29ja2V0CiAgICAgICAgICB9KTsKCiAgICAgICAgICByZXMuc2V0RW5jb2RpbmcoJ3V0ZjgnKTsKCiAgICAgICAgICAvLyAiS2V5LXZhbHVlIHBhaXJzIG9mIGhlYWRlciBuYW1lcyBhbmQgdmFsdWVzLiBIZWFkZXIgbmFtZXMgYXJlIGxvd2VyLWNhc2VkLiIKICAgICAgICAgIC8vIGh0dHBzOi8vbm9kZWpzLm9yZy9hcGkvaHR0cC5odG1sI2h0dHBfbWVzc2FnZV9oZWFkZXJzCiAgICAgICAgICBjb25zdCByZXRyeUFmdGVySGVhZGVyID0gX251bGxpc2hDb2FsZXNjZShyZXMuaGVhZGVyc1sncmV0cnktYWZ0ZXInXSwgKCkgPT4gKCBudWxsKSk7CiAgICAgICAgICBjb25zdCByYXRlTGltaXRzSGVhZGVyID0gX251bGxpc2hDb2FsZXNjZShyZXMuaGVhZGVyc1sneC1zZW50cnktcmF0ZS1saW1pdHMnXSwgKCkgPT4gKCBudWxsKSk7CgogICAgICAgICAgcmVzb2x2ZSh7CiAgICAgICAgICAgIHN0YXR1c0NvZGU6IHJlcy5zdGF0dXNDb2RlLAogICAgICAgICAgICBoZWFkZXJzOiB7CiAgICAgICAgICAgICAgJ3JldHJ5LWFmdGVyJzogcmV0cnlBZnRlckhlYWRlciwKICAgICAgICAgICAgICAneC1zZW50cnktcmF0ZS1saW1pdHMnOiBBcnJheS5pc0FycmF5KHJhdGVMaW1pdHNIZWFkZXIpID8gcmF0ZUxpbWl0c0hlYWRlclswXSA6IHJhdGVMaW1pdHNIZWFkZXIsCiAgICAgICAgICAgIH0sCiAgICAgICAgICB9KTsKICAgICAgICB9LAogICAgICApOwoKICAgICAgcmVxLm9uKCdlcnJvcicsIHJlamVjdCk7CiAgICAgIGJvZHkucGlwZShyZXEpOwogICAgfSk7CiAgfTsKfQoKLyoqIG5vcm1hbGl6ZXMgV2luZG93cyBwYXRocyAqLwpmdW5jdGlvbiBub3JtYWxpemVXaW5kb3dzUGF0aChwYXRoKSB7CiAgcmV0dXJuIHBhdGgKICAgIC5yZXBsYWNlKC9eW0EtWl06LywgJycpIC8vIHJlbW92ZSBXaW5kb3dzLXN0eWxlIHByZWZpeAogICAgLnJlcGxhY2UoL1xcL2csICcvJyk7IC8vIHJlcGxhY2UgYWxsIGBcYCBpbnN0YW5jZXMgd2l0aCBgL2AKfQoKLyoqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0IGdldHMgdGhlIG1vZHVsZSBuYW1lIGZyb20gYSBmaWxlbmFtZSAqLwpmdW5jdGlvbiBjcmVhdGVHZXRNb2R1bGVGcm9tRmlsZW5hbWUoCiAgYmFzZVBhdGggPSBwcm9jZXNzLmFyZ3ZbMV0gPyBkaXJuYW1lKHByb2Nlc3MuYXJndlsxXSkgOiBwcm9jZXNzLmN3ZCgpLAogIGlzV2luZG93cyA9IHNlcCA9PT0gJ1xcJywKKSB7CiAgY29uc3Qgbm9ybWFsaXplZEJhc2UgPSBpc1dpbmRvd3MgPyBub3JtYWxpemVXaW5kb3dzUGF0aChiYXNlUGF0aCkgOiBiYXNlUGF0aDsKCiAgcmV0dXJuIChmaWxlbmFtZSkgPT4gewogICAgaWYgKCFmaWxlbmFtZSkgewogICAgICByZXR1cm47CiAgICB9CgogICAgY29uc3Qgbm9ybWFsaXplZEZpbGVuYW1lID0gaXNXaW5kb3dzID8gbm9ybWFsaXplV2luZG93c1BhdGgoZmlsZW5hbWUpIDogZmlsZW5hbWU7CgogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIHByZWZlci1jb25zdAogICAgbGV0IHsgZGlyLCBiYXNlOiBmaWxlLCBleHQgfSA9IHBvc2l4LnBhcnNlKG5vcm1hbGl6ZWRGaWxlbmFtZSk7CgogICAgaWYgKGV4dCA9PT0gJy5qcycgfHwgZXh0ID09PSAnLm1qcycgfHwgZXh0ID09PSAnLmNqcycpIHsKICAgICAgZmlsZSA9IGZpbGUuc2xpY2UoMCwgZXh0Lmxlbmd0aCAqIC0xKTsKICAgIH0KCiAgICBpZiAoIWRpcikgewogICAgICAvLyBObyBkaXJuYW1lIHdoYXRzb2V2ZXIKICAgICAgZGlyID0gJy4nOwogICAgfQoKICAgIGNvbnN0IG4gPSBkaXIubGFzdEluZGV4T2YoJy9ub2RlX21vZHVsZXMnKTsKICAgIGlmIChuID4gLTEpIHsKICAgICAgcmV0dXJuIGAke2Rpci5zbGljZShuICsgMTQpLnJlcGxhY2UoL1wvL2csICcuJyl9OiR7ZmlsZX1gOwogICAgfQoKICAgIC8vIExldCdzIHNlZSBpZiBpdCdzIGEgcGFydCBvZiB0aGUgbWFpbiBtb2R1bGUKICAgIC8vIFRvIGJlIGEgcGFydCBvZiBtYWluIG1vZHVsZSwgaXQgaGFzIHRvIHNoYXJlIHRoZSBzYW1lIGJhc2UKICAgIGlmIChkaXIuc3RhcnRzV2l0aChub3JtYWxpemVkQmFzZSkpIHsKICAgICAgbGV0IG1vZHVsZU5hbWUgPSBkaXIuc2xpY2Uobm9ybWFsaXplZEJhc2UubGVuZ3RoICsgMSkucmVwbGFjZSgvXC8vZywgJy4nKTsKCiAgICAgIGlmIChtb2R1bGVOYW1lKSB7CiAgICAgICAgbW9kdWxlTmFtZSArPSAnOic7CiAgICAgIH0KICAgICAgbW9kdWxlTmFtZSArPSBmaWxlOwoKICAgICAgcmV0dXJuIG1vZHVsZU5hbWU7CiAgICB9CgogICAgcmV0dXJuIGZpbGU7CiAgfTsKfQoKZnVuY3Rpb24gX29wdGlvbmFsQ2hhaW4ob3BzKSB7IGxldCBsYXN0QWNjZXNzTEhTID0gdW5kZWZpbmVkOyBsZXQgdmFsdWUgPSBvcHNbMF07IGxldCBpID0gMTsgd2hpbGUgKGkgPCBvcHMubGVuZ3RoKSB7IGNvbnN0IG9wID0gb3BzW2ldOyBjb25zdCBmbiA9IG9wc1tpICsgMV07IGkgKz0gMjsgaWYgKChvcCA9PT0gJ29wdGlvbmFsQWNjZXNzJyB8fCBvcCA9PT0gJ29wdGlvbmFsQ2FsbCcpICYmIHZhbHVlID09IG51bGwpIHsgcmV0dXJuIHVuZGVmaW5lZDsgfSBpZiAob3AgPT09ICdhY2Nlc3MnIHx8IG9wID09PSAnb3B0aW9uYWxBY2Nlc3MnKSB7IGxhc3RBY2Nlc3NMSFMgPSB2YWx1ZTsgdmFsdWUgPSBmbih2YWx1ZSk7IH0gZWxzZSBpZiAob3AgPT09ICdjYWxsJyB8fCBvcCA9PT0gJ29wdGlvbmFsQ2FsbCcpIHsgdmFsdWUgPSBmbigoLi4uYXJncykgPT4gdmFsdWUuY2FsbChsYXN0QWNjZXNzTEhTLCAuLi5hcmdzKSk7IGxhc3RBY2Nlc3NMSFMgPSB1bmRlZmluZWQ7IH0gfSByZXR1cm4gdmFsdWU7IH0KY29uc3Qgb3B0aW9ucyA9IHdvcmtlckRhdGE7CmxldCBzZXNzaW9uOwpsZXQgaGFzU2VudEFuckV2ZW50ID0gZmFsc2U7CgpmdW5jdGlvbiBsb2cobXNnKSB7CiAgaWYgKG9wdGlvbnMuZGVidWcpIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlCiAgICBjb25zb2xlLmxvZyhgW0FOUiBXb3JrZXJdICR7bXNnfWApOwogIH0KfQoKY29uc3QgdXJsID0gZ2V0RW52ZWxvcGVFbmRwb2ludFdpdGhVcmxFbmNvZGVkQXV0aChvcHRpb25zLmRzbik7CmNvbnN0IHRyYW5zcG9ydCA9IG1ha2VOb2RlVHJhbnNwb3J0KHsKICB1cmwsCiAgcmVjb3JkRHJvcHBlZEV2ZW50OiAoKSA9PiB7CiAgICAvLwogIH0sCn0pOwoKYXN5bmMgZnVuY3Rpb24gc2VuZEFibm9ybWFsU2Vzc2lvbigpIHsKICAvLyBvZiB3ZSBoYXZlIGFuIGV4aXN0aW5nIHNlc3Npb24gcGFzc2VkIGZyb20gdGhlIG1haW4gdGhyZWFkLCBzZW5kIGl0IGFzIGFibm9ybWFsCiAgaWYgKHNlc3Npb24pIHsKICAgIGxvZygnU2VuZGluZyBhYm5vcm1hbCBzZXNzaW9uJyk7CiAgICB1cGRhdGVTZXNzaW9uKHNlc3Npb24sIHsgc3RhdHVzOiAnYWJub3JtYWwnLCBhYm5vcm1hbF9tZWNoYW5pc206ICdhbnJfZm9yZWdyb3VuZCcgfSk7CgogICAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVTZXNzaW9uRW52ZWxvcGUoc2Vzc2lvbiwgb3B0aW9ucy5kc24sIG9wdGlvbnMuc2RrTWV0YWRhdGEpOwogICAgLy8gTG9nIHRoZSBlbnZlbG9wZSBzbyB0byBhaWQgaW4gdGVzdGluZwogICAgbG9nKEpTT04uc3RyaW5naWZ5KGVudmVsb3BlKSk7CgogICAgYXdhaXQgdHJhbnNwb3J0LnNlbmQoZW52ZWxvcGUpOwoKICAgIHRyeSB7CiAgICAgIC8vIE5vdGlmeSB0aGUgbWFpbiBwcm9jZXNzIHRoYXQgdGhlIHNlc3Npb24gaGFzIGVuZGVkIHNvIHRoZSBzZXNzaW9uIGNhbiBiZSBjbGVhcmVkIGZyb20gdGhlIHNjb3BlCiAgICAgIF9vcHRpb25hbENoYWluKFtwYXJlbnRQb3J0LCAnb3B0aW9uYWxBY2Nlc3MnLCBfMiA9PiBfMi5wb3N0TWVzc2FnZSwgJ2NhbGwnLCBfMyA9PiBfMygnc2Vzc2lvbi1lbmRlZCcpXSk7CiAgICB9IGNhdGNoIChfKSB7CiAgICAgIC8vIGlnbm9yZQogICAgfQogIH0KfQoKbG9nKCdTdGFydGVkJyk7CgpmdW5jdGlvbiBwcmVwYXJlU3RhY2tGcmFtZXMoc3RhY2tGcmFtZXMpIHsKICBpZiAoIXN0YWNrRnJhbWVzKSB7CiAgICByZXR1cm4gdW5kZWZpbmVkOwogIH0KCiAgLy8gU3RyaXAgU2VudHJ5IGZyYW1lcyBhbmQgcmV2ZXJzZSB0aGUgc3RhY2sgZnJhbWVzIHNvIHRoZXkgYXJlIGluIHRoZSBjb3JyZWN0IG9yZGVyCiAgY29uc3Qgc3RyaXBwZWRGcmFtZXMgPSBzdHJpcFNlbnRyeUZyYW1lc0FuZFJldmVyc2Uoc3RhY2tGcmFtZXMpOwoKICAvLyBJZiB3ZSBoYXZlIGFuIGFwcCByb290IHBhdGgsIHJld3JpdGUgdGhlIGZpbGVuYW1lcyB0byBiZSByZWxhdGl2ZSB0byB0aGUgYXBwIHJvb3QKICBpZiAob3B0aW9ucy5hcHBSb290UGF0aCkgewogICAgZm9yIChjb25zdCBmcmFtZSBvZiBzdHJpcHBlZEZyYW1lcykgewogICAgICBpZiAoIWZyYW1lLmZpbGVuYW1lKSB7CiAgICAgICAgY29udGludWU7CiAgICAgIH0KCiAgICAgIGZyYW1lLmZpbGVuYW1lID0gbm9ybWFsaXplVXJsVG9CYXNlKGZyYW1lLmZpbGVuYW1lLCBvcHRpb25zLmFwcFJvb3RQYXRoKTsKICAgIH0KICB9CgogIHJldHVybiBzdHJpcHBlZEZyYW1lczsKfQoKYXN5bmMgZnVuY3Rpb24gc2VuZEFuckV2ZW50KGZyYW1lcywgdHJhY2VDb250ZXh0KSB7CiAgaWYgKGhhc1NlbnRBbnJFdmVudCkgewogICAgcmV0dXJuOwogIH0KCiAgaGFzU2VudEFuckV2ZW50ID0gdHJ1ZTsKCiAgYXdhaXQgc2VuZEFibm9ybWFsU2Vzc2lvbigpOwoKICBsb2coJ1NlbmRpbmcgZXZlbnQnKTsKCiAgY29uc3QgZXZlbnQgPSB7CiAgICBldmVudF9pZDogdXVpZDQoKSwKICAgIGNvbnRleHRzOiB7IC4uLm9wdGlvbnMuY29udGV4dHMsIHRyYWNlOiB0cmFjZUNvbnRleHQgfSwKICAgIHJlbGVhc2U6IG9wdGlvbnMucmVsZWFzZSwKICAgIGVudmlyb25tZW50OiBvcHRpb25zLmVudmlyb25tZW50LAogICAgZGlzdDogb3B0aW9ucy5kaXN0LAogICAgcGxhdGZvcm06ICdub2RlJywKICAgIGxldmVsOiAnZXJyb3InLAogICAgZXhjZXB0aW9uOiB7CiAgICAgIHZhbHVlczogWwogICAgICAgIHsKICAgICAgICAgIHR5cGU6ICdBcHBsaWNhdGlvbk5vdFJlc3BvbmRpbmcnLAogICAgICAgICAgdmFsdWU6IGBBcHBsaWNhdGlvbiBOb3QgUmVzcG9uZGluZyBmb3IgYXQgbGVhc3QgJHtvcHRpb25zLmFuclRocmVzaG9sZH0gbXNgLAogICAgICAgICAgc3RhY2t0cmFjZTogeyBmcmFtZXM6IHByZXBhcmVTdGFja0ZyYW1lcyhmcmFtZXMpIH0sCiAgICAgICAgICAvLyBUaGlzIGVuc3VyZXMgdGhlIFVJIGRvZXNuJ3Qgc2F5ICdDcmFzaGVkIGluJyBmb3IgdGhlIHN0YWNrIHRyYWNlCiAgICAgICAgICBtZWNoYW5pc206IHsgdHlwZTogJ0FOUicgfSwKICAgICAgICB9LAogICAgICBdLAogICAgfSwKICAgIHRhZ3M6IG9wdGlvbnMuc3RhdGljVGFncywKICB9OwoKICBjb25zdCBlbnZlbG9wZSA9IGNyZWF0ZUV2ZW50RW52ZWxvcGUoZXZlbnQsIG9wdGlvbnMuZHNuLCBvcHRpb25zLnNka01ldGFkYXRhKTsKICAvLyBMb2cgdGhlIGVudmVsb3BlIHNvIHRvIGFpZCBpbiB0ZXN0aW5nCiAgbG9nKEpTT04uc3RyaW5naWZ5KGVudmVsb3BlKSk7CgogIGF3YWl0IHRyYW5zcG9ydC5zZW5kKGVudmVsb3BlKTsKICBhd2FpdCB0cmFuc3BvcnQuZmx1c2goMjAwMCk7CgogIC8vIERlbGF5IGZvciA1IHNlY29uZHMgc28gdGhhdCBzdGRpbyBjYW4gZmx1c2ggaW4gdGhlIG1haW4gZXZlbnQgbG9vcCBldmVyIHJlc3RhcnRzLgogIC8vIFRoaXMgaXMgbWFpbmx5IGZvciB0aGUgYmVuZWZpdCBvZiBsb2dnaW5nL2RlYnVnZ2luZyBpc3N1ZXMuCiAgc2V0VGltZW91dCgoKSA9PiB7CiAgICBwcm9jZXNzLmV4aXQoMCk7CiAgfSwgNTAwMCk7Cn0KCmxldCBkZWJ1Z2dlclBhdXNlOwoKaWYgKG9wdGlvbnMuY2FwdHVyZVN0YWNrVHJhY2UpIHsKICBsb2coJ0Nvbm5lY3RpbmcgdG8gZGVidWdnZXInKTsKCiAgY29uc3Qgc2Vzc2lvbiA9IG5ldyBTZXNzaW9uKCk7CiAgc2Vzc2lvbi5jb25uZWN0VG9NYWluVGhyZWFkKCk7CgogIGxvZygnQ29ubmVjdGVkIHRvIGRlYnVnZ2VyJyk7CgogIC8vIENvbGxlY3Qgc2NyaXB0SWQgLT4gdXJsIG1hcCBzbyB3ZSBjYW4gbG9vayB1cCB0aGUgZmlsZW5hbWVzIGxhdGVyCiAgY29uc3Qgc2NyaXB0cyA9IG5ldyBNYXAoKTsKCiAgc2Vzc2lvbi5vbignRGVidWdnZXIuc2NyaXB0UGFyc2VkJywgZXZlbnQgPT4gewogICAgc2NyaXB0cy5zZXQoZXZlbnQucGFyYW1zLnNjcmlwdElkLCBldmVudC5wYXJhbXMudXJsKTsKICB9KTsKCiAgc2Vzc2lvbi5vbignRGVidWdnZXIucGF1c2VkJywgZXZlbnQgPT4gewogICAgaWYgKGV2ZW50LnBhcmFtcy5yZWFzb24gIT09ICdvdGhlcicpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIHRyeSB7CiAgICAgIGxvZygnRGVidWdnZXIgcGF1c2VkJyk7CgogICAgICAvLyBjb3B5IHRoZSBmcmFtZXMKICAgICAgY29uc3QgY2FsbEZyYW1lcyA9IFsuLi5ldmVudC5wYXJhbXMuY2FsbEZyYW1lc107CgogICAgICBjb25zdCBnZXRNb2R1bGVOYW1lID0gb3B0aW9ucy5hcHBSb290UGF0aCA/IGNyZWF0ZUdldE1vZHVsZUZyb21GaWxlbmFtZShvcHRpb25zLmFwcFJvb3RQYXRoKSA6ICgpID0+IHVuZGVmaW5lZDsKICAgICAgY29uc3Qgc3RhY2tGcmFtZXMgPSBjYWxsRnJhbWVzLm1hcChmcmFtZSA9PgogICAgICAgIGNhbGxGcmFtZVRvU3RhY2tGcmFtZShmcmFtZSwgc2NyaXB0cy5nZXQoZnJhbWUubG9jYXRpb24uc2NyaXB0SWQpLCBnZXRNb2R1bGVOYW1lKSwKICAgICAgKTsKCiAgICAgIC8vIEV2YWx1YXRlIGEgc2NyaXB0IGluIHRoZSBjdXJyZW50bHkgcGF1c2VkIGNvbnRleHQKICAgICAgc2Vzc2lvbi5wb3N0KAogICAgICAgICdSdW50aW1lLmV2YWx1YXRlJywKICAgICAgICB7CiAgICAgICAgICAvLyBHcmFiIHRoZSB0cmFjZSBjb250ZXh0IGZyb20gdGhlIGN1cnJlbnQgc2NvcGUKICAgICAgICAgIGV4cHJlc3Npb246CiAgICAgICAgICAgICdjb25zdCBjdHggPSBfX1NFTlRSWV9fLmFjcz8uZ2V0Q3VycmVudFNjb3BlKCkuZ2V0UHJvcGFnYXRpb25Db250ZXh0KCkgfHwge307IGN0eC50cmFjZUlkICsgIi0iICsgY3R4LnNwYW5JZCArICItIiArIGN0eC5wYXJlbnRTcGFuSWQnLAogICAgICAgICAgLy8gRG9uJ3QgcmUtdHJpZ2dlciB0aGUgZGVidWdnZXIgaWYgdGhpcyBjYXVzZXMgYW4gZXJyb3IKICAgICAgICAgIHNpbGVudDogdHJ1ZSwKICAgICAgICB9LAogICAgICAgIChfLCBwYXJhbSkgPT4gewogICAgICAgICAgY29uc3QgdHJhY2VJZCA9IHBhcmFtICYmIHBhcmFtLnJlc3VsdCA/IChwYXJhbS5yZXN1bHQudmFsdWUgKSA6ICctLSc7CiAgICAgICAgICBjb25zdCBbdHJhY2VfaWQsIHNwYW5faWQsIHBhcmVudF9zcGFuX2lkXSA9IHRyYWNlSWQuc3BsaXQoJy0nKSA7CgogICAgICAgICAgc2Vzc2lvbi5wb3N0KCdEZWJ1Z2dlci5yZXN1bWUnKTsKICAgICAgICAgIHNlc3Npb24ucG9zdCgnRGVidWdnZXIuZGlzYWJsZScpOwoKICAgICAgICAgIGNvbnN0IGNvbnRleHQgPSBfb3B0aW9uYWxDaGFpbihbdHJhY2VfaWQsICdvcHRpb25hbEFjY2VzcycsIF80ID0+IF80Lmxlbmd0aF0pICYmIF9vcHRpb25hbENoYWluKFtzcGFuX2lkLCAnb3B0aW9uYWxBY2Nlc3MnLCBfNSA9PiBfNS5sZW5ndGhdKSA/IHsgdHJhY2VfaWQsIHNwYW5faWQsIHBhcmVudF9zcGFuX2lkIH0gOiB1bmRlZmluZWQ7CiAgICAgICAgICBzZW5kQW5yRXZlbnQoc3RhY2tGcmFtZXMsIGNvbnRleHQpLnRoZW4obnVsbCwgKCkgPT4gewogICAgICAgICAgICBsb2coJ1NlbmRpbmcgQU5SIGV2ZW50IGZhaWxlZC4nKTsKICAgICAgICAgIH0pOwogICAgICAgIH0sCiAgICAgICk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIHNlc3Npb24ucG9zdCgnRGVidWdnZXIucmVzdW1lJyk7CiAgICAgIHNlc3Npb24ucG9zdCgnRGVidWdnZXIuZGlzYWJsZScpOwogICAgICB0aHJvdyBlOwogICAgfQogIH0pOwoKICBkZWJ1Z2dlclBhdXNlID0gKCkgPT4gewogICAgdHJ5IHsKICAgICAgc2Vzc2lvbi5wb3N0KCdEZWJ1Z2dlci5lbmFibGUnLCAoKSA9PiB7CiAgICAgICAgc2Vzc2lvbi5wb3N0KCdEZWJ1Z2dlci5wYXVzZScpOwogICAgICB9KTsKICAgIH0gY2F0Y2ggKF8pIHsKICAgICAgLy8KICAgIH0KICB9Owp9CgpmdW5jdGlvbiBjcmVhdGVIclRpbWVyKCkgewogIC8vIFRPRE8gKHY4KTogV2UgY2FuIHVzZSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKSBhZnRlciB3ZSBkcm9wIG5vZGUgdjgKICBsZXQgbGFzdFBvbGwgPSBwcm9jZXNzLmhydGltZSgpOwoKICByZXR1cm4gewogICAgZ2V0VGltZU1zOiAoKSA9PiB7CiAgICAgIGNvbnN0IFtzZWNvbmRzLCBuYW5vU2Vjb25kc10gPSBwcm9jZXNzLmhydGltZShsYXN0UG9sbCk7CiAgICAgIHJldHVybiBNYXRoLmZsb29yKHNlY29uZHMgKiAxZTMgKyBuYW5vU2Vjb25kcyAvIDFlNik7CiAgICB9LAogICAgcmVzZXQ6ICgpID0+IHsKICAgICAgbGFzdFBvbGwgPSBwcm9jZXNzLmhydGltZSgpOwogICAgfSwKICB9Owp9CgpmdW5jdGlvbiB3YXRjaGRvZ1RpbWVvdXQoKSB7CiAgbG9nKCdXYXRjaGRvZyB0aW1lb3V0Jyk7CgogIGlmIChkZWJ1Z2dlclBhdXNlKSB7CiAgICBsb2coJ1BhdXNpbmcgZGVidWdnZXIgdG8gY2FwdHVyZSBzdGFjayB0cmFjZScpOwogICAgZGVidWdnZXJQYXVzZSgpOwogIH0gZWxzZSB7CiAgICBsb2coJ0NhcHR1cmluZyBldmVudCB3aXRob3V0IGEgc3RhY2sgdHJhY2UnKTsKICAgIHNlbmRBbnJFdmVudCgpLnRoZW4obnVsbCwgKCkgPT4gewogICAgICBsb2coJ1NlbmRpbmcgQU5SIGV2ZW50IGZhaWxlZCBvbiB3YXRjaGRvZyB0aW1lb3V0LicpOwogICAgfSk7CiAgfQp9Cgpjb25zdCB7IHBvbGwgfSA9IHdhdGNoZG9nVGltZXIoY3JlYXRlSHJUaW1lciwgb3B0aW9ucy5wb2xsSW50ZXJ2YWwsIG9wdGlvbnMuYW5yVGhyZXNob2xkLCB3YXRjaGRvZ1RpbWVvdXQpOwoKX29wdGlvbmFsQ2hhaW4oW3BhcmVudFBvcnQsICdvcHRpb25hbEFjY2VzcycsIF82ID0+IF82Lm9uLCAnY2FsbCcsIF83ID0+IF83KCdtZXNzYWdlJywgKG1zZykgPT4gewogIGlmIChtc2cuc2Vzc2lvbikgewogICAgc2Vzc2lvbiA9IG1ha2VTZXNzaW9uKG1zZy5zZXNzaW9uKTsKICB9CgogIHBvbGwoKTsKfSldKTs=';
1643
+
1644
+ function _optionalChain$4(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
1645
+ const DEFAULT_INTERVAL = 50;
1646
+ const DEFAULT_HANG_THRESHOLD = 5000;
1647
+
1648
+ function log(message, ...args) {
1649
+ logger.log(`[ANR] ${message}`, ...args);
1650
+ }
1651
+
1652
+ /**
1653
+ * Gets contexts by calling all event processors. This relies on being called after all integrations are setup
1654
+ */
1655
+ async function getContexts(client) {
1656
+ let event = { message: 'ANR' };
1657
+ const eventHint = {};
1658
+
1659
+ for (const processor of client.getEventProcessors()) {
1660
+ if (event === null) break;
1661
+ event = await processor(event, eventHint);
1662
+ }
1663
+
1664
+ return _optionalChain$4([event, 'optionalAccess', _2 => _2.contexts]) || {};
1665
+ }
1666
+
1667
+ const INTEGRATION_NAME$1 = 'Anr';
1668
+
1669
+ const _anrIntegration = ((options = {}) => {
1670
+ return {
1671
+ name: INTEGRATION_NAME$1,
1672
+ setup(client) {
1673
+ if (NODE_MAJOR < 16 || (NODE_MAJOR === 16 && (NODE_VERSION.minor || 0) < 17)) {
1674
+ throw new Error('ANR detection requires Node 16.17.0 or later');
1675
+ }
1676
+
1677
+ // setImmediate is used to ensure that all other integrations have been setup
1678
+ setImmediate(() => _startWorker(client, options));
1679
+ },
1680
+ };
1681
+ }) ;
1682
+
1683
+ const anrIntegration = defineIntegration(_anrIntegration);
1684
+
1685
+ /**
1686
+ * Starts the ANR worker thread
1687
+ */
1688
+ async function _startWorker(client, _options) {
1689
+ const contexts = await getContexts(client);
1690
+ const dsn = client.getDsn();
1691
+
1692
+ if (!dsn) {
1693
+ return;
1694
+ }
1695
+
1696
+ // These will not be accurate if sent later from the worker thread
1697
+ _optionalChainDelete([contexts, 'access', _3 => _3.app, 'optionalAccess', _4 => delete _4.app_memory]);
1698
+ _optionalChainDelete([contexts, 'access', _5 => _5.device, 'optionalAccess', _6 => delete _6.free_memory]);
1699
+
1700
+ const initOptions = client.getOptions();
1701
+
1702
+ const sdkMetadata = client.getSdkMetadata() || {};
1703
+ if (sdkMetadata.sdk) {
1704
+ sdkMetadata.sdk.integrations = initOptions.integrations.map(i => i.name);
1705
+ }
1706
+
1707
+ const options = {
1708
+ debug: logger.isEnabled(),
1709
+ dsn,
1710
+ environment: initOptions.environment || 'production',
1711
+ release: initOptions.release,
1712
+ dist: initOptions.dist,
1713
+ sdkMetadata,
1714
+ appRootPath: _options.appRootPath,
1715
+ pollInterval: _options.pollInterval || DEFAULT_INTERVAL,
1716
+ anrThreshold: _options.anrThreshold || DEFAULT_HANG_THRESHOLD,
1717
+ captureStackTrace: !!_options.captureStackTrace,
1718
+ staticTags: _options.staticTags || {},
1719
+ contexts,
1720
+ };
1721
+
1722
+ if (options.captureStackTrace) {
1723
+ if (!inspector.url()) {
1724
+ inspector.open(0);
1725
+ }
1726
+ }
1727
+
1728
+ const worker = new Worker(new URL(`data:application/javascript;base64,${base64WorkerScript}`), {
1729
+ workerData: options,
1730
+ });
1731
+
1732
+ process.on('exit', () => {
1733
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
1734
+ worker.terminate();
1735
+ });
1736
+
1737
+ const timer = setInterval(() => {
1738
+ try {
1739
+ const currentSession = getCurrentScope().getSession();
1740
+ // We need to copy the session object and remove the toJSON method so it can be sent to the worker
1741
+ // serialized without making it a SerializedSession
1742
+ const session = currentSession ? { ...currentSession, toJSON: undefined } : undefined;
1743
+ // message the worker to tell it the main event loop is still running
1744
+ worker.postMessage({ session });
1745
+ } catch (_) {
1746
+ //
1747
+ }
1748
+ }, options.pollInterval);
1749
+ // Timer should not block exit
1750
+ timer.unref();
1751
+
1752
+ worker.on('message', (msg) => {
1753
+ if (msg === 'session-ended') {
1754
+ log('ANR event sent from ANR worker. Clearing session in this thread.');
1755
+ getCurrentScope().setSession(undefined);
1756
+ }
1757
+ });
1758
+
1759
+ worker.once('error', (err) => {
1760
+ clearInterval(timer);
1761
+ log('ANR worker error', err);
1762
+ });
1763
+
1764
+ worker.once('exit', (code) => {
1765
+ clearInterval(timer);
1766
+ log('ANR worker exit', code);
1767
+ });
1768
+
1769
+ // Ensure this thread can't block app exit
1770
+ worker.unref();
1771
+ }
1772
+
1773
+ function _optionalChain$3(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
1774
+
1775
+ const _expressIntegration = (() => {
1776
+ return {
1777
+ name: 'Express',
1778
+ setupOnce() {
1779
+ registerInstrumentations({
1780
+ instrumentations: [
1781
+ new ExpressInstrumentation({
1782
+ requestHook(span) {
1783
+ addOriginToSpan(span, 'auto.http.otel.express');
1784
+ },
1785
+ }),
1786
+ ],
1787
+ });
1788
+ },
1789
+ };
1790
+ }) ;
1791
+
1792
+ /**
1793
+ * Express integration
1794
+ *
1795
+ * Capture tracing data for express.
1796
+ * In order to capture exceptions, you have to call `setupExpressErrorHandler(app)` before any other middleware and after all controllers.
1797
+ */
1798
+ const expressIntegration = defineIntegration(_expressIntegration);
1799
+
1800
+ /**
1801
+ * An Express-compatible error handler.
1802
+ */
1803
+ function expressErrorHandler(options
1804
+
1805
+ ) {
1806
+ return function sentryErrorMiddleware(
1807
+ error,
1808
+ _req,
1809
+ res,
1810
+ next,
1811
+ ) {
1812
+ const shouldHandleError = _optionalChain$3([options, 'optionalAccess', _ => _.shouldHandleError]) || defaultShouldHandleError;
1813
+
1814
+ if (shouldHandleError(error)) {
1815
+ const client = getClient$2();
1816
+ if (client && client.getOptions().autoSessionTracking) {
1817
+ // Check if the `SessionFlusher` is instantiated on the client to go into this branch that marks the
1818
+ // `requestSession.status` as `Crashed`, and this check is necessary because the `SessionFlusher` is only
1819
+ // instantiated when the the`requestHandler` middleware is initialised, which indicates that we should be
1820
+ // running in SessionAggregates mode
1821
+ const isSessionAggregatesMode = client['_sessionFlusher'] !== undefined;
1822
+ if (isSessionAggregatesMode) {
1823
+ const requestSession = getIsolationScope().getRequestSession();
1824
+ // If an error bubbles to the `errorHandler`, then this is an unhandled error, and should be reported as a
1825
+ // Crashed session. The `_requestSession.status` is checked to ensure that this error is happening within
1826
+ // the bounds of a request, and if so the status is updated
1827
+ if (requestSession && requestSession.status !== undefined) {
1828
+ requestSession.status = 'crashed';
1829
+ }
1830
+ }
1831
+ }
1832
+
1833
+ const eventId = captureException(error, { mechanism: { type: 'middleware', handled: false } });
1834
+ (res ).sentry = eventId;
1835
+ next(error);
1836
+
1837
+ return;
1838
+ }
1839
+
1840
+ next(error);
1841
+ };
1842
+ }
1843
+
1844
+ /**
1845
+ * Setup an error handler for Express.
1846
+ * The error handler must be before any other middleware and after all controllers.
1847
+ */
1848
+ function setupExpressErrorHandler(app) {
1849
+ app.use(expressErrorHandler());
1850
+ }
1851
+
1852
+ function getStatusCodeFromResponse(error) {
1853
+ const statusCode = error.status || error.statusCode || error.status_code || (error.output && error.output.statusCode);
1854
+ return statusCode ? parseInt(statusCode , 10) : 500;
1855
+ }
1856
+
1857
+ /** Returns true if response code is internal server error */
1858
+ function defaultShouldHandleError(error) {
1859
+ const status = getStatusCodeFromResponse(error);
1860
+ return status >= 500;
1861
+ }
1862
+
1863
+ const _fastifyIntegration = (() => {
1864
+ return {
1865
+ name: 'Fastify',
1866
+ setupOnce() {
1867
+ registerInstrumentations({
1868
+ instrumentations: [
1869
+ new FastifyInstrumentation({
1870
+ requestHook(span) {
1871
+ addOriginToSpan(span, 'auto.http.otel.fastify');
1872
+ },
1873
+ }),
1874
+ ],
1875
+ });
1876
+ },
1877
+ };
1878
+ }) ;
1879
+
1880
+ /**
1881
+ * Express integration
1882
+ *
1883
+ * Capture tracing data for fastify.
1884
+ */
1885
+ const fastifyIntegration = defineIntegration(_fastifyIntegration);
1886
+
1887
+ // We inline the types we care about here
1888
+
1889
+ /**
1890
+ * Setup an error handler for Fastify.
1891
+ */
1892
+ function setupFastifyErrorHandler(fastify) {
1893
+ const plugin = Object.assign(
1894
+ function (fastify, options, done) {
1895
+ fastify.addHook('onError', async (_request, _reply, error) => {
1896
+ captureException(error);
1897
+ });
1898
+
1899
+ done();
1900
+ },
1901
+ {
1902
+ [Symbol.for('skip-override')]: true,
1903
+ [Symbol.for('fastify.display-name')]: 'sentry-fastify-error-handler',
1904
+ },
1905
+ );
1906
+
1907
+ fastify.register(plugin);
1908
+ }
1909
+
1910
+ const _graphqlIntegration = (() => {
1911
+ return {
1912
+ name: 'Graphql',
1913
+ setupOnce() {
1914
+ registerInstrumentations({
1915
+ instrumentations: [
1916
+ new GraphQLInstrumentation({
1917
+ ignoreTrivialResolveSpans: true,
1918
+ responseHook(span) {
1919
+ addOriginToSpan(span, 'auto.graphql.otel.graphql');
1920
+ },
1921
+ }),
1922
+ ],
1923
+ });
1924
+ },
1925
+ };
1926
+ }) ;
1927
+
1928
+ /**
1929
+ * GraphQL integration
1930
+ *
1931
+ * Capture tracing data for GraphQL.
1932
+ */
1933
+ const graphqlIntegration = defineIntegration(_graphqlIntegration);
1934
+
1935
+ const _mongoIntegration = (() => {
1936
+ return {
1937
+ name: 'Mongo',
1938
+ setupOnce() {
1939
+ registerInstrumentations({
1940
+ instrumentations: [
1941
+ new MongoDBInstrumentation({
1942
+ responseHook(span) {
1943
+ addOriginToSpan(span, 'auto.db.otel.mongo');
1944
+ },
1945
+ }),
1946
+ ],
1947
+ });
1948
+ },
1949
+ };
1950
+ }) ;
1951
+
1952
+ /**
1953
+ * MongoDB integration
1954
+ *
1955
+ * Capture tracing data for MongoDB.
1956
+ */
1957
+ const mongoIntegration = defineIntegration(_mongoIntegration);
1958
+
1959
+ const _mongooseIntegration = (() => {
1960
+ return {
1961
+ name: 'Mongoose',
1962
+ setupOnce() {
1963
+ registerInstrumentations({
1964
+ instrumentations: [
1965
+ new MongooseInstrumentation({
1966
+ responseHook(span) {
1967
+ addOriginToSpan(span, 'auto.db.otel.mongoose');
1968
+ },
1969
+ }),
1970
+ ],
1971
+ });
1972
+ },
1973
+ };
1974
+ }) ;
1975
+
1976
+ /**
1977
+ * Mongoose integration
1978
+ *
1979
+ * Capture tracing data for Mongoose.
1980
+ */
1981
+ const mongooseIntegration = defineIntegration(_mongooseIntegration);
1982
+
1983
+ const _mysqlIntegration = (() => {
1984
+ return {
1985
+ name: 'Mysql',
1986
+ setupOnce() {
1987
+ registerInstrumentations({
1988
+ instrumentations: [new MySQLInstrumentation({})],
1989
+ });
1990
+ },
1991
+ };
1992
+ }) ;
1993
+
1994
+ /**
1995
+ * MySQL integration
1996
+ *
1997
+ * Capture tracing data for mysql.
1998
+ */
1999
+ const mysqlIntegration = defineIntegration(_mysqlIntegration);
2000
+
2001
+ const _mysql2Integration = (() => {
2002
+ return {
2003
+ name: 'Mysql2',
2004
+ setupOnce() {
2005
+ registerInstrumentations({
2006
+ instrumentations: [
2007
+ new MySQL2Instrumentation({
2008
+ responseHook(span) {
2009
+ addOriginToSpan(span, 'auto.db.otel.mysql2');
2010
+ },
2011
+ }),
2012
+ ],
2013
+ });
2014
+ },
2015
+ };
2016
+ }) ;
2017
+
2018
+ /**
2019
+ * MySQL2 integration
2020
+ *
2021
+ * Capture tracing data for mysql2
2022
+ */
2023
+ const mysql2Integration = defineIntegration(_mysql2Integration);
2024
+
2025
+ const _nestIntegration = (() => {
2026
+ return {
2027
+ name: 'Nest',
2028
+ setupOnce() {
2029
+ registerInstrumentations({
2030
+ instrumentations: [new NestInstrumentation({})],
2031
+ });
2032
+ },
2033
+ };
2034
+ }) ;
2035
+
2036
+ /**
2037
+ * Nest framework integration
2038
+ *
2039
+ * Capture tracing data for nest.
2040
+ */
2041
+ const nestIntegration = defineIntegration(_nestIntegration);
2042
+
2043
+ const _postgresIntegration = (() => {
2044
+ return {
2045
+ name: 'Postgres',
2046
+ setupOnce() {
2047
+ registerInstrumentations({
2048
+ instrumentations: [
2049
+ new PgInstrumentation({
2050
+ requireParentSpan: true,
2051
+ requestHook(span) {
2052
+ addOriginToSpan(span, 'auto.db.otel.postgres');
2053
+ },
2054
+ }),
2055
+ ],
2056
+ });
2057
+ },
2058
+ };
2059
+ }) ;
2060
+
2061
+ /**
2062
+ * Postgres integration
2063
+ *
2064
+ * Capture tracing data for pg.
2065
+ */
2066
+ const postgresIntegration = defineIntegration(_postgresIntegration);
2067
+
2068
+ const _prismaIntegration = (() => {
2069
+ return {
2070
+ name: 'Prisma',
2071
+ setupOnce() {
2072
+ registerInstrumentations({
2073
+ instrumentations: [
2074
+ // does not have a hook to adjust spans & add origin
2075
+ new prismaInstrumentation.PrismaInstrumentation({}),
2076
+ ],
2077
+ });
2078
+ },
2079
+ };
2080
+ }) ;
2081
+
2082
+ /**
2083
+ * Prisma integration
2084
+ *
2085
+ * Capture tracing data for prisma.
2086
+ * Note: This requieres to set:
2087
+ * previewFeatures = ["tracing"]
2088
+ * For the prisma client.
2089
+ * See https://www.prisma.io/docs/concepts/components/prisma-client/opentelemetry-tracing for more details.
2090
+ */
2091
+ const prismaIntegration = defineIntegration(_prismaIntegration);
2092
+
2093
+ const _hapiIntegration = (() => {
2094
+ return {
2095
+ name: 'Hapi',
2096
+ setupOnce() {
2097
+ registerInstrumentations({
2098
+ instrumentations: [new HapiInstrumentation()],
2099
+ });
2100
+ },
2101
+ };
2102
+ }) ;
2103
+
2104
+ /**
2105
+ * Hapi integration
2106
+ *
2107
+ * Capture tracing data for Hapi.
2108
+ * If you also want to capture errors, you need to call `setupHapiErrorHandler(server)` after you set up your server.
2109
+ */
2110
+ const hapiIntegration = defineIntegration(_hapiIntegration);
2111
+
2112
+ function isBoomObject(response) {
2113
+ return response && (response ).isBoom !== undefined;
2114
+ }
2115
+
2116
+ function isErrorEvent(event) {
2117
+ return event && (event ).error !== undefined;
2118
+ }
2119
+
2120
+ function sendErrorToSentry(errorData) {
2121
+ captureException(errorData, {
2122
+ mechanism: {
2123
+ type: 'hapi',
2124
+ handled: false,
2125
+ data: {
2126
+ function: 'hapiErrorPlugin',
2127
+ },
2128
+ },
2129
+ });
2130
+ }
2131
+
2132
+ const hapiErrorPlugin = {
2133
+ name: 'SentryHapiErrorPlugin',
2134
+ version: SDK_VERSION,
2135
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2136
+ register: async function (serverArg) {
2137
+ const server = serverArg ;
2138
+
2139
+ server.events.on('request', (request, event) => {
2140
+ const activeSpan = getActiveSpan();
2141
+ const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;
2142
+
2143
+ if (request.response && isBoomObject(request.response)) {
2144
+ sendErrorToSentry(request.response);
2145
+ } else if (isErrorEvent(event)) {
2146
+ sendErrorToSentry(event.error);
2147
+ }
2148
+
2149
+ if (rootSpan) {
2150
+ rootSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
2151
+ rootSpan.end();
2152
+ }
2153
+ });
2154
+ },
2155
+ };
2156
+
2157
+ /**
2158
+ * Add a Hapi plugin to capture errors to Sentry.
2159
+ */
2160
+ async function setupHapiErrorHandler(server) {
2161
+ await server.register(hapiErrorPlugin);
2162
+ }
2163
+
2164
+ const INTEGRATION_NAME = 'Spotlight';
2165
+
2166
+ const _spotlightIntegration = ((options = {}) => {
2167
+ const _options = {
2168
+ sidecarUrl: options.sidecarUrl || 'http://localhost:8969/stream',
2169
+ };
2170
+
2171
+ return {
2172
+ name: INTEGRATION_NAME,
2173
+ setup(client) {
2174
+ if (typeof process === 'object' && process.env && process.env.NODE_ENV !== 'development') {
2175
+ logger.warn("[Spotlight] It seems you're not in dev mode. Do you really want to have Spotlight enabled?");
2176
+ }
2177
+ connectToSpotlight(client, _options);
2178
+ },
2179
+ };
2180
+ }) ;
2181
+
2182
+ /**
2183
+ * Use this integration to send errors and transactions to Spotlight.
2184
+ *
2185
+ * Learn more about spotlight at https://spotlightjs.com
2186
+ *
2187
+ * Important: This integration only works with Node 18 or newer.
2188
+ */
2189
+ const spotlightIntegration = defineIntegration(_spotlightIntegration);
2190
+
2191
+ function connectToSpotlight(client, options) {
2192
+ const spotlightUrl = parseSidecarUrl(options.sidecarUrl);
2193
+ if (!spotlightUrl) {
2194
+ return;
2195
+ }
2196
+
2197
+ let failedRequests = 0;
2198
+
2199
+ client.on('beforeEnvelope', (envelope) => {
2200
+ if (failedRequests > 3) {
2201
+ logger.warn('[Spotlight] Disabled Sentry -> Spotlight integration due to too many failed requests');
2202
+ return;
2203
+ }
2204
+
2205
+ const serializedEnvelope = serializeEnvelope(envelope);
2206
+
2207
+ const request = getNativeHttpRequest();
2208
+ const req = request(
2209
+ {
2210
+ method: 'POST',
2211
+ path: spotlightUrl.pathname,
2212
+ hostname: spotlightUrl.hostname,
2213
+ port: spotlightUrl.port,
2214
+ headers: {
2215
+ 'Content-Type': 'application/x-sentry-envelope',
2216
+ },
2217
+ },
2218
+ res => {
2219
+ res.on('data', () => {
2220
+ // Drain socket
2221
+ });
2222
+
2223
+ res.on('end', () => {
2224
+ // Drain socket
2225
+ });
2226
+ res.setEncoding('utf8');
2227
+ },
2228
+ );
2229
+
2230
+ req.on('error', () => {
2231
+ failedRequests++;
2232
+ logger.warn('[Spotlight] Failed to send envelope to Spotlight Sidecar');
2233
+ });
2234
+ req.write(serializedEnvelope);
2235
+ req.end();
2236
+ });
2237
+ }
2238
+
2239
+ function parseSidecarUrl(url) {
2240
+ try {
2241
+ return new URL(`${url}`);
2242
+ } catch (e) {
2243
+ logger.warn(`[Spotlight] Invalid sidecar URL: ${url}`);
2244
+ return undefined;
2245
+ }
2246
+ }
2247
+
2248
+ /**
2249
+ * We want to get an unpatched http request implementation to avoid capturing our own calls.
2250
+ */
2251
+ function getNativeHttpRequest() {
2252
+ const { request } = http;
2253
+ if (isWrapped(request)) {
2254
+ return request.__sentry_original__;
2255
+ }
2256
+
2257
+ return request;
2258
+ }
2259
+
2260
+ function isWrapped(impl) {
2261
+ return '__sentry_original__' in impl;
2262
+ }
2263
+
2264
+ const _koaIntegration = (() => {
2265
+ return {
2266
+ name: 'Koa',
2267
+ setupOnce() {
2268
+ registerInstrumentations({
2269
+ instrumentations: [new KoaInstrumentation()],
2270
+ });
2271
+ },
2272
+ };
2273
+ }) ;
2274
+
2275
+ const koaIntegration = defineIntegration(_koaIntegration);
2276
+
2277
+ /**
2278
+ * With OTEL, all performance integrations will be added, as OTEL only initializes them when the patched package is actually required.
2279
+ */
2280
+ function getAutoPerformanceIntegrations() {
2281
+ return [
2282
+ expressIntegration(),
2283
+ fastifyIntegration(),
2284
+ graphqlIntegration(),
2285
+ mongoIntegration(),
2286
+ mongooseIntegration(),
2287
+ mysqlIntegration(),
2288
+ mysql2Integration(),
2289
+ postgresIntegration(),
2290
+ prismaIntegration(),
2291
+ nestIntegration(),
2292
+ hapiIntegration(),
2293
+ koaIntegration(),
2294
+ ];
2295
+ }
2296
+
2297
+ function _nullishCoalesce$2(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }/**
2298
+ * This code was originally forked from https://github.com/TooTallNate/proxy-agents/tree/b133295fd16f6475578b6b15bd9b4e33ecb0d0b7
2299
+ * With the following licence:
2300
+ *
2301
+ * (The MIT License)
2302
+ *
2303
+ * Copyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>*
2304
+ *
2305
+ * Permission is hereby granted, free of charge, to any person obtaining
2306
+ * a copy of this software and associated documentation files (the
2307
+ * 'Software'), to deal in the Software without restriction, including
2308
+ * without limitation the rights to use, copy, modify, merge, publish,
2309
+ * distribute, sublicense, and/or sell copies of the Software, and to
2310
+ * permit persons to whom the Software is furnished to do so, subject to
2311
+ * the following conditions:*
2312
+ *
2313
+ * The above copyright notice and this permission notice shall be
2314
+ * included in all copies or substantial portions of the Software.*
2315
+ *
2316
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
2317
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2318
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2319
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
2320
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2321
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2322
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2323
+ */
2324
+
2325
+ const INTERNAL = Symbol('AgentBaseInternalState');
2326
+
2327
+ class Agent extends http.Agent {
2328
+
2329
+ // Set by `http.Agent` - missing from `@types/node`
2330
+
2331
+ constructor(opts) {
2332
+ super(opts);
2333
+ this[INTERNAL] = {};
2334
+ }
2335
+
2336
+ /**
2337
+ * Determine whether this is an `http` or `https` request.
2338
+ */
2339
+ isSecureEndpoint(options) {
2340
+ if (options) {
2341
+ // First check the `secureEndpoint` property explicitly, since this
2342
+ // means that a parent `Agent` is "passing through" to this instance.
2343
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
2344
+ if (typeof (options ).secureEndpoint === 'boolean') {
2345
+ return options.secureEndpoint;
2346
+ }
2347
+
2348
+ // If no explicit `secure` endpoint, check if `protocol` property is
2349
+ // set. This will usually be the case since using a full string URL
2350
+ // or `URL` instance should be the most common usage.
2351
+ if (typeof options.protocol === 'string') {
2352
+ return options.protocol === 'https:';
2353
+ }
2354
+ }
2355
+
2356
+ // Finally, if no `protocol` property was set, then fall back to
2357
+ // checking the stack trace of the current call stack, and try to
2358
+ // detect the "https" module.
2359
+ const { stack } = new Error();
2360
+ if (typeof stack !== 'string') return false;
2361
+ return stack.split('\n').some(l => l.indexOf('(https.js:') !== -1 || l.indexOf('node:https:') !== -1);
2362
+ }
2363
+
2364
+ createSocket(req, options, cb) {
2365
+ const connectOpts = {
2366
+ ...options,
2367
+ secureEndpoint: this.isSecureEndpoint(options),
2368
+ };
2369
+ Promise.resolve()
2370
+ .then(() => this.connect(req, connectOpts))
2371
+ .then(socket => {
2372
+ if (socket instanceof http.Agent) {
2373
+ // @ts-expect-error `addRequest()` isn't defined in `@types/node`
2374
+ return socket.addRequest(req, connectOpts);
2375
+ }
2376
+ this[INTERNAL].currentSocket = socket;
2377
+ // @ts-expect-error `createSocket()` isn't defined in `@types/node`
2378
+ super.createSocket(req, options, cb);
2379
+ }, cb);
2380
+ }
2381
+
2382
+ createConnection() {
2383
+ const socket = this[INTERNAL].currentSocket;
2384
+ this[INTERNAL].currentSocket = undefined;
2385
+ if (!socket) {
2386
+ throw new Error('No socket was returned in the `connect()` function');
2387
+ }
2388
+ return socket;
2389
+ }
2390
+
2391
+ get defaultPort() {
2392
+ return _nullishCoalesce$2(this[INTERNAL].defaultPort, () => ( (this.protocol === 'https:' ? 443 : 80)));
2393
+ }
2394
+
2395
+ set defaultPort(v) {
2396
+ if (this[INTERNAL]) {
2397
+ this[INTERNAL].defaultPort = v;
2398
+ }
2399
+ }
2400
+
2401
+ get protocol() {
2402
+ return _nullishCoalesce$2(this[INTERNAL].protocol, () => ( (this.isSecureEndpoint() ? 'https:' : 'http:')));
2403
+ }
2404
+
2405
+ set protocol(v) {
2406
+ if (this[INTERNAL]) {
2407
+ this[INTERNAL].protocol = v;
2408
+ }
2409
+ }
2410
+ }
2411
+
2412
+ function debug$1(...args) {
2413
+ logger.log('[https-proxy-agent:parse-proxy-response]', ...args);
2414
+ }
2415
+
2416
+ function parseProxyResponse(socket) {
2417
+ return new Promise((resolve, reject) => {
2418
+ // we need to buffer any HTTP traffic that happens with the proxy before we get
2419
+ // the CONNECT response, so that if the response is anything other than an "200"
2420
+ // response code, then we can re-play the "data" events on the socket once the
2421
+ // HTTP parser is hooked up...
2422
+ let buffersLength = 0;
2423
+ const buffers = [];
2424
+
2425
+ function read() {
2426
+ const b = socket.read();
2427
+ if (b) ondata(b);
2428
+ else socket.once('readable', read);
2429
+ }
2430
+
2431
+ function cleanup() {
2432
+ socket.removeListener('end', onend);
2433
+ socket.removeListener('error', onerror);
2434
+ socket.removeListener('readable', read);
2435
+ }
2436
+
2437
+ function onend() {
2438
+ cleanup();
2439
+ debug$1('onend');
2440
+ reject(new Error('Proxy connection ended before receiving CONNECT response'));
2441
+ }
2442
+
2443
+ function onerror(err) {
2444
+ cleanup();
2445
+ debug$1('onerror %o', err);
2446
+ reject(err);
2447
+ }
2448
+
2449
+ function ondata(b) {
2450
+ buffers.push(b);
2451
+ buffersLength += b.length;
2452
+
2453
+ const buffered = Buffer.concat(buffers, buffersLength);
2454
+ const endOfHeaders = buffered.indexOf('\r\n\r\n');
2455
+
2456
+ if (endOfHeaders === -1) {
2457
+ // keep buffering
2458
+ debug$1('have not received end of HTTP headers yet...');
2459
+ read();
2460
+ return;
2461
+ }
2462
+
2463
+ const headerParts = buffered.slice(0, endOfHeaders).toString('ascii').split('\r\n');
2464
+ const firstLine = headerParts.shift();
2465
+ if (!firstLine) {
2466
+ socket.destroy();
2467
+ return reject(new Error('No header received from proxy CONNECT response'));
2468
+ }
2469
+ const firstLineParts = firstLine.split(' ');
2470
+ const statusCode = +firstLineParts[1];
2471
+ const statusText = firstLineParts.slice(2).join(' ');
2472
+ const headers = {};
2473
+ for (const header of headerParts) {
2474
+ if (!header) continue;
2475
+ const firstColon = header.indexOf(':');
2476
+ if (firstColon === -1) {
2477
+ socket.destroy();
2478
+ return reject(new Error(`Invalid header from proxy CONNECT response: "${header}"`));
2479
+ }
2480
+ const key = header.slice(0, firstColon).toLowerCase();
2481
+ const value = header.slice(firstColon + 1).trimStart();
2482
+ const current = headers[key];
2483
+ if (typeof current === 'string') {
2484
+ headers[key] = [current, value];
2485
+ } else if (Array.isArray(current)) {
2486
+ current.push(value);
2487
+ } else {
2488
+ headers[key] = value;
2489
+ }
2490
+ }
2491
+ debug$1('got proxy server response: %o %o', firstLine, headers);
2492
+ cleanup();
2493
+ resolve({
2494
+ connect: {
2495
+ statusCode,
2496
+ statusText,
2497
+ headers,
2498
+ },
2499
+ buffered,
2500
+ });
2501
+ }
2502
+
2503
+ socket.on('error', onerror);
2504
+ socket.on('end', onend);
2505
+
2506
+ read();
2507
+ });
2508
+ }
2509
+
2510
+ function _nullishCoalesce$1(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }function _optionalChain$2(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2511
+
2512
+ function debug(...args) {
2513
+ logger.log('[https-proxy-agent]', ...args);
2514
+ }
2515
+
2516
+ /**
2517
+ * The `HttpsProxyAgent` implements an HTTP Agent subclass that connects to
2518
+ * the specified "HTTP(s) proxy server" in order to proxy HTTPS requests.
2519
+ *
2520
+ * Outgoing HTTP requests are first tunneled through the proxy server using the
2521
+ * `CONNECT` HTTP request method to establish a connection to the proxy server,
2522
+ * and then the proxy server connects to the destination target and issues the
2523
+ * HTTP request from the proxy server.
2524
+ *
2525
+ * `https:` requests have their socket connection upgraded to TLS once
2526
+ * the connection to the proxy server has been established.
2527
+ */
2528
+ class HttpsProxyAgent extends Agent {
2529
+ static __initStatic() {this.protocols = ['http', 'https']; }
2530
+
2531
+ constructor(proxy, opts) {
2532
+ super(opts);
2533
+ this.options = {};
2534
+ this.proxy = typeof proxy === 'string' ? new URL(proxy) : proxy;
2535
+ this.proxyHeaders = _nullishCoalesce$1(_optionalChain$2([opts, 'optionalAccess', _2 => _2.headers]), () => ( {}));
2536
+ debug('Creating new HttpsProxyAgent instance: %o', this.proxy.href);
2537
+
2538
+ // Trim off the brackets from IPv6 addresses
2539
+ const host = (this.proxy.hostname || this.proxy.host).replace(/^\[|\]$/g, '');
2540
+ const port = this.proxy.port ? parseInt(this.proxy.port, 10) : this.proxy.protocol === 'https:' ? 443 : 80;
2541
+ this.connectOpts = {
2542
+ // Attempt to negotiate http/1.1 for proxy servers that support http/2
2543
+ ALPNProtocols: ['http/1.1'],
2544
+ ...(opts ? omit(opts, 'headers') : null),
2545
+ host,
2546
+ port,
2547
+ };
2548
+ }
2549
+
2550
+ /**
2551
+ * Called when the node-core HTTP client library is creating a
2552
+ * new HTTP request.
2553
+ */
2554
+ async connect(req, opts) {
2555
+ const { proxy } = this;
2556
+
2557
+ if (!opts.host) {
2558
+ throw new TypeError('No "host" provided');
2559
+ }
2560
+
2561
+ // Create a socket connection to the proxy server.
2562
+ let socket;
2563
+ if (proxy.protocol === 'https:') {
2564
+ debug('Creating `tls.Socket`: %o', this.connectOpts);
2565
+ const servername = this.connectOpts.servername || this.connectOpts.host;
2566
+ socket = tls.connect({
2567
+ ...this.connectOpts,
2568
+ servername: servername && net.isIP(servername) ? undefined : servername,
2569
+ });
2570
+ } else {
2571
+ debug('Creating `net.Socket`: %o', this.connectOpts);
2572
+ socket = net.connect(this.connectOpts);
2573
+ }
2574
+
2575
+ const headers =
2576
+ typeof this.proxyHeaders === 'function' ? this.proxyHeaders() : { ...this.proxyHeaders };
2577
+ const host = net.isIPv6(opts.host) ? `[${opts.host}]` : opts.host;
2578
+ let payload = `CONNECT ${host}:${opts.port} HTTP/1.1\r\n`;
2579
+
2580
+ // Inject the `Proxy-Authorization` header if necessary.
2581
+ if (proxy.username || proxy.password) {
2582
+ const auth = `${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password)}`;
2583
+ headers['Proxy-Authorization'] = `Basic ${Buffer.from(auth).toString('base64')}`;
2584
+ }
2585
+
2586
+ headers.Host = `${host}:${opts.port}`;
2587
+
2588
+ if (!headers['Proxy-Connection']) {
2589
+ headers['Proxy-Connection'] = this.keepAlive ? 'Keep-Alive' : 'close';
2590
+ }
2591
+ for (const name of Object.keys(headers)) {
2592
+ payload += `${name}: ${headers[name]}\r\n`;
2593
+ }
2594
+
2595
+ const proxyResponsePromise = parseProxyResponse(socket);
2596
+
2597
+ socket.write(`${payload}\r\n`);
2598
+
2599
+ const { connect, buffered } = await proxyResponsePromise;
2600
+ req.emit('proxyConnect', connect);
2601
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2602
+ // @ts-ignore Not EventEmitter in Node types
2603
+ this.emit('proxyConnect', connect, req);
2604
+
2605
+ if (connect.statusCode === 200) {
2606
+ req.once('socket', resume);
2607
+
2608
+ if (opts.secureEndpoint) {
2609
+ // The proxy is connecting to a TLS server, so upgrade
2610
+ // this socket connection to a TLS connection.
2611
+ debug('Upgrading socket connection to TLS');
2612
+ const servername = opts.servername || opts.host;
2613
+ return tls.connect({
2614
+ ...omit(opts, 'host', 'path', 'port'),
2615
+ socket,
2616
+ servername: net.isIP(servername) ? undefined : servername,
2617
+ });
2618
+ }
2619
+
2620
+ return socket;
2621
+ }
2622
+
2623
+ // Some other status code that's not 200... need to re-play the HTTP
2624
+ // header "data" events onto the socket once the HTTP machinery is
2625
+ // attached so that the node core `http` can parse and handle the
2626
+ // error status code.
2627
+
2628
+ // Close the original socket, and a new "fake" socket is returned
2629
+ // instead, so that the proxy doesn't get the HTTP request
2630
+ // written to it (which may contain `Authorization` headers or other
2631
+ // sensitive data).
2632
+ //
2633
+ // See: https://hackerone.com/reports/541502
2634
+ socket.destroy();
2635
+
2636
+ const fakeSocket = new net.Socket({ writable: false });
2637
+ fakeSocket.readable = true;
2638
+
2639
+ // Need to wait for the "socket" event to re-play the "data" events.
2640
+ req.once('socket', (s) => {
2641
+ debug('Replaying proxy buffer for failed request');
2642
+ // Replay the "buffered" Buffer onto the fake `socket`, since at
2643
+ // this point the HTTP module machinery has been hooked up for
2644
+ // the user.
2645
+ s.push(buffered);
2646
+ s.push(null);
2647
+ });
2648
+
2649
+ return fakeSocket;
2650
+ }
2651
+ }HttpsProxyAgent.__initStatic();
2652
+
2653
+ function resume(socket) {
2654
+ socket.resume();
2655
+ }
2656
+
2657
+ function omit(
2658
+ obj,
2659
+ ...keys
2660
+ )
2661
+
2662
+ {
2663
+ const ret = {}
2664
+
2665
+ ;
2666
+ let key;
2667
+ for (key in obj) {
2668
+ if (!keys.includes(key)) {
2669
+ ret[key] = obj[key];
2670
+ }
2671
+ }
2672
+ return ret;
2673
+ }
2674
+
2675
+ // Estimated maximum size for reasonable standalone event
2676
+ const GZIP_THRESHOLD = 1024 * 32;
2677
+
2678
+ /**
2679
+ * Gets a stream from a Uint8Array or string
2680
+ * Readable.from is ideal but was added in node.js v12.3.0 and v10.17.0
2681
+ */
2682
+ function streamFromBody(body) {
2683
+ return new Readable({
2684
+ read() {
2685
+ this.push(body);
2686
+ this.push(null);
2687
+ },
2688
+ });
2689
+ }
2690
+
2691
+ /**
2692
+ * Creates a Transport that uses native the native 'http' and 'https' modules to send events to Sentry.
2693
+ */
2694
+ function makeNodeTransport(options) {
2695
+ let urlSegments;
2696
+
2697
+ try {
2698
+ urlSegments = new URL(options.url);
2699
+ } catch (e) {
2700
+ consoleSandbox(() => {
2701
+ // eslint-disable-next-line no-console
2702
+ console.warn(
2703
+ '[@sentry/node]: Invalid dsn or tunnel option, will not send any events. The tunnel option must be a full URL when used.',
2704
+ );
2705
+ });
2706
+ return createTransport(options, () => Promise.resolve({}));
2707
+ }
2708
+
2709
+ const isHttps = urlSegments.protocol === 'https:';
2710
+
2711
+ // Proxy prioritization: http => `options.proxy` | `process.env.http_proxy`
2712
+ // Proxy prioritization: https => `options.proxy` | `process.env.https_proxy` | `process.env.http_proxy`
2713
+ const proxy = applyNoProxyOption(
2714
+ urlSegments,
2715
+ options.proxy || (isHttps ? process.env.https_proxy : undefined) || process.env.http_proxy,
2716
+ );
2717
+
2718
+ const nativeHttpModule = isHttps ? https : http$1;
2719
+ const keepAlive = options.keepAlive === undefined ? false : options.keepAlive;
2720
+
2721
+ // TODO(v7): Evaluate if we can set keepAlive to true. This would involve testing for memory leaks in older node
2722
+ // versions(>= 8) as they had memory leaks when using it: #2555
2723
+ const agent = proxy
2724
+ ? (new HttpsProxyAgent(proxy) )
2725
+ : new nativeHttpModule.Agent({ keepAlive, maxSockets: 30, timeout: 2000 });
2726
+
2727
+ const requestExecutor = createRequestExecutor(options, _nullishCoalesce(options.httpModule, () => ( nativeHttpModule)), agent);
2728
+ return createTransport(options, requestExecutor);
2729
+ }
2730
+
2731
+ /**
2732
+ * Honors the `no_proxy` env variable with the highest priority to allow for hosts exclusion.
2733
+ *
2734
+ * @param transportUrl The URL the transport intends to send events to.
2735
+ * @param proxy The client configured proxy.
2736
+ * @returns A proxy the transport should use.
2737
+ */
2738
+ function applyNoProxyOption(transportUrlSegments, proxy) {
2739
+ const { no_proxy } = process.env;
2740
+
2741
+ const urlIsExemptFromProxy =
2742
+ no_proxy &&
2743
+ no_proxy
2744
+ .split(',')
2745
+ .some(
2746
+ exemption => transportUrlSegments.host.endsWith(exemption) || transportUrlSegments.hostname.endsWith(exemption),
2747
+ );
2748
+
2749
+ if (urlIsExemptFromProxy) {
2750
+ return undefined;
2751
+ } else {
2752
+ return proxy;
2753
+ }
2754
+ }
2755
+
2756
+ /**
2757
+ * Creates a RequestExecutor to be used with `createTransport`.
2758
+ */
2759
+ function createRequestExecutor(
2760
+ options,
2761
+ httpModule,
2762
+ agent,
2763
+ ) {
2764
+ const { hostname, pathname, port, protocol, search } = new URL(options.url);
2765
+ return function makeRequest(request) {
2766
+ return new Promise((resolve, reject) => {
2767
+ let body = streamFromBody(request.body);
2768
+
2769
+ const headers = { ...options.headers };
2770
+
2771
+ if (request.body.length > GZIP_THRESHOLD) {
2772
+ headers['content-encoding'] = 'gzip';
2773
+ body = body.pipe(createGzip());
2774
+ }
2775
+
2776
+ const req = httpModule.request(
2777
+ {
2778
+ method: 'POST',
2779
+ agent,
2780
+ headers,
2781
+ hostname,
2782
+ path: `${pathname}${search}`,
2783
+ port,
2784
+ protocol,
2785
+ ca: options.caCerts,
2786
+ },
2787
+ res => {
2788
+ res.on('data', () => {
2789
+ // Drain socket
2790
+ });
2791
+
2792
+ res.on('end', () => {
2793
+ // Drain socket
2794
+ });
2795
+
2796
+ res.setEncoding('utf8');
2797
+
2798
+ // "Key-value pairs of header names and values. Header names are lower-cased."
2799
+ // https://nodejs.org/api/http.html#http_message_headers
2800
+ const retryAfterHeader = _nullishCoalesce(res.headers['retry-after'], () => ( null));
2801
+ const rateLimitsHeader = _nullishCoalesce(res.headers['x-sentry-rate-limits'], () => ( null));
2802
+
2803
+ resolve({
2804
+ statusCode: res.statusCode,
2805
+ headers: {
2806
+ 'retry-after': retryAfterHeader,
2807
+ 'x-sentry-rate-limits': Array.isArray(rateLimitsHeader) ? rateLimitsHeader[0] : rateLimitsHeader,
2808
+ },
2809
+ });
2810
+ },
2811
+ );
2812
+
2813
+ req.on('error', reject);
2814
+ body.pipe(req);
2815
+ });
2816
+ };
2817
+ }
2818
+
2819
+ /** normalizes Windows paths */
2820
+ function normalizeWindowsPath(path) {
2821
+ return path
2822
+ .replace(/^[A-Z]:/, '') // remove Windows-style prefix
2823
+ .replace(/\\/g, '/'); // replace all `\` instances with `/`
2824
+ }
2825
+
2826
+ /** Creates a function that gets the module name from a filename */
2827
+ function createGetModuleFromFilename(
2828
+ basePath = process.argv[1] ? dirname$1(process.argv[1]) : process.cwd(),
2829
+ isWindows = sep === '\\',
2830
+ ) {
2831
+ const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
2832
+
2833
+ return (filename) => {
2834
+ if (!filename) {
2835
+ return;
2836
+ }
2837
+
2838
+ const normalizedFilename = isWindows ? normalizeWindowsPath(filename) : filename;
2839
+
2840
+ // eslint-disable-next-line prefer-const
2841
+ let { dir, base: file, ext } = posix.parse(normalizedFilename);
2842
+
2843
+ if (ext === '.js' || ext === '.mjs' || ext === '.cjs') {
2844
+ file = file.slice(0, ext.length * -1);
2845
+ }
2846
+
2847
+ if (!dir) {
2848
+ // No dirname whatsoever
2849
+ dir = '.';
2850
+ }
2851
+
2852
+ const n = dir.lastIndexOf('/node_modules');
2853
+ if (n > -1) {
2854
+ return `${dir.slice(n + 14).replace(/\//g, '.')}:${file}`;
2855
+ }
2856
+
2857
+ // Let's see if it's a part of the main module
2858
+ // To be a part of main module, it has to share the same base
2859
+ if (dir.startsWith(normalizedBase)) {
2860
+ let moduleName = dir.slice(normalizedBase.length + 1).replace(/\//g, '.');
2861
+
2862
+ if (moduleName) {
2863
+ moduleName += ':';
2864
+ }
2865
+ moduleName += file;
2866
+
2867
+ return moduleName;
2868
+ }
2869
+
2870
+ return file;
2871
+ };
2872
+ }
2873
+
2874
+ // PUBLIC APIS
2875
+
2876
+
2877
+ /** Get the currently active client. */
2878
+ function getClient() {
2879
+ const currentScope = getCurrentScope();
2880
+
2881
+ const client = currentScope.getClient();
2882
+ if (client) {
2883
+ return client ;
2884
+ }
2885
+
2886
+ // TODO otherwise ensure we use a noop client
2887
+ return {} ;
2888
+ }
2889
+
2890
+ /**
2891
+ * Returns a release dynamically from environment variables.
2892
+ */
2893
+ function getSentryRelease(fallback) {
2894
+ // Always read first as Sentry takes this as precedence
2895
+ if (process.env.SENTRY_RELEASE) {
2896
+ return process.env.SENTRY_RELEASE;
2897
+ }
2898
+
2899
+ // This supports the variable that sentry-webpack-plugin injects
2900
+ if (GLOBAL_OBJ.SENTRY_RELEASE && GLOBAL_OBJ.SENTRY_RELEASE.id) {
2901
+ return GLOBAL_OBJ.SENTRY_RELEASE.id;
2902
+ }
2903
+
2904
+ return (
2905
+ // GitHub Actions - https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables#default-environment-variables
2906
+ process.env.GITHUB_SHA ||
2907
+ // Netlify - https://docs.netlify.com/configure-builds/environment-variables/#build-metadata
2908
+ process.env.COMMIT_REF ||
2909
+ // Vercel - https://vercel.com/docs/v2/build-step#system-environment-variables
2910
+ process.env.VERCEL_GIT_COMMIT_SHA ||
2911
+ process.env.VERCEL_GITHUB_COMMIT_SHA ||
2912
+ process.env.VERCEL_GITLAB_COMMIT_SHA ||
2913
+ process.env.VERCEL_BITBUCKET_COMMIT_SHA ||
2914
+ // Zeit (now known as Vercel)
2915
+ process.env.ZEIT_GITHUB_COMMIT_SHA ||
2916
+ process.env.ZEIT_GITLAB_COMMIT_SHA ||
2917
+ process.env.ZEIT_BITBUCKET_COMMIT_SHA ||
2918
+ // Cloudflare Pages - https://developers.cloudflare.com/pages/platform/build-configuration/#environment-variables
2919
+ process.env.CF_PAGES_COMMIT_SHA ||
2920
+ fallback
2921
+ );
2922
+ }
2923
+
2924
+ /** Node.js stack parser */
2925
+ const defaultStackParser = createStackParser(nodeStackLineParser(createGetModuleFromFilename()));
2926
+
2927
+ /**
2928
+ * This method is a noop and only here to ensure vite-plugin v0.6.0 (which is used by Sveltekit) still works,
2929
+ * as that uses this.
2930
+ *
2931
+ * @deprecated This will be removed before v8 is finalized.
2932
+ */
2933
+ function makeMain(hub) {
2934
+ // noop
2935
+ return hub;
2936
+ }
2937
+
2938
+ function _optionalChain$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2939
+ /** A client for using Sentry with Node & OpenTelemetry. */
2940
+ class NodeClient extends ServerRuntimeClient {
2941
+
2942
+ constructor(options) {
2943
+ const clientOptions = {
2944
+ ...options,
2945
+ platform: 'node',
2946
+ runtime: { name: 'node', version: global.process.version },
2947
+ serverName: options.serverName || global.process.env.SENTRY_NAME || os.hostname(),
2948
+ };
2949
+
2950
+ applySdkMetadata(clientOptions, 'node');
2951
+
2952
+ super(clientOptions);
2953
+ }
2954
+
2955
+ /** Get the OTEL tracer. */
2956
+ get tracer() {
2957
+ if (this._tracer) {
2958
+ return this._tracer;
2959
+ }
2960
+
2961
+ const name = '@sentry/node';
2962
+ const version = SDK_VERSION;
2963
+ const tracer = trace.getTracer(name, version);
2964
+ this._tracer = tracer;
2965
+
2966
+ return tracer;
2967
+ }
2968
+
2969
+ /**
2970
+ * @inheritDoc
2971
+ */
2972
+ async flush(timeout) {
2973
+ const provider = this.traceProvider;
2974
+ const spanProcessor = _optionalChain$1([provider, 'optionalAccess', _ => _.activeSpanProcessor]);
2975
+
2976
+ if (spanProcessor) {
2977
+ await spanProcessor.forceFlush();
2978
+ }
2979
+
2980
+ return super.flush(timeout);
2981
+ }
2982
+ }
2983
+
2984
+ /**
2985
+ * This is a custom ContextManager for OpenTelemetry, which extends the default AsyncLocalStorageContextManager.
2986
+ * It ensures that we create a new hub per context, so that the OTEL Context & the Sentry Hub are always in sync.
2987
+ *
2988
+ * Note that we currently only support AsyncHooks with this,
2989
+ * but since this should work for Node 14+ anyhow that should be good enough.
2990
+ */
2991
+ const SentryContextManager = wrapContextManagerClass(AsyncLocalStorageContextManager);
2992
+
2993
+ /**
2994
+ * Initialize OpenTelemetry for Node.
2995
+ */
2996
+ function initOtel() {
2997
+ const client = getClient();
2998
+
2999
+ if (!client) {
3000
+ DEBUG_BUILD &&
3001
+ logger.warn(
3002
+ 'No client available, skipping OpenTelemetry setup. This probably means that `Sentry.init()` was not called before `initOtel()`.',
3003
+ );
3004
+ return;
3005
+ }
3006
+
3007
+ if (client.getOptions().debug) {
3008
+ const otelLogger = new Proxy(logger , {
3009
+ get(target, prop, receiver) {
3010
+ const actualProp = prop === 'verbose' ? 'debug' : prop;
3011
+ return Reflect.get(target, actualProp, receiver);
3012
+ },
3013
+ });
3014
+
3015
+ diag.setLogger(otelLogger, DiagLogLevel.DEBUG);
3016
+ }
3017
+
3018
+ setupEventContextTrace(client);
3019
+
3020
+ const provider = setupOtel(client);
3021
+ client.traceProvider = provider;
3022
+ }
3023
+
3024
+ /** Just exported for tests. */
3025
+ function setupOtel(client) {
3026
+ // Create and configure NodeTracerProvider
3027
+ const provider = new BasicTracerProvider({
3028
+ sampler: new SentrySampler(client),
3029
+ resource: new Resource({
3030
+ [SemanticResourceAttributes.SERVICE_NAME]: 'node',
3031
+ [SemanticResourceAttributes.SERVICE_NAMESPACE]: 'sentry',
3032
+ [SemanticResourceAttributes.SERVICE_VERSION]: SDK_VERSION,
3033
+ }),
3034
+ forceFlushTimeoutMillis: 500,
3035
+ });
3036
+ provider.addSpanProcessor(new SentrySpanProcessor());
3037
+
3038
+ // Initialize the provider
3039
+ provider.register({
3040
+ propagator: new SentryPropagator(),
3041
+ contextManager: new SentryContextManager(),
3042
+ });
3043
+
3044
+ return provider;
3045
+ }
3046
+
3047
+ function getCjsOnlyIntegrations(isCjs = typeof require !== 'undefined') {
3048
+ return isCjs ? [modulesIntegration()] : [];
3049
+ }
3050
+
3051
+ /** Get the default integrations for the Node Experimental SDK. */
3052
+ function getDefaultIntegrations(options) {
3053
+ return [
3054
+ // Common
3055
+ inboundFiltersIntegration(),
3056
+ functionToStringIntegration(),
3057
+ linkedErrorsIntegration(),
3058
+ requestDataIntegration(),
3059
+ // Native Wrappers
3060
+ consoleIntegration(),
3061
+ httpIntegration(),
3062
+ nativeNodeFetchIntegration(),
3063
+ // Global Handlers
3064
+ onUncaughtExceptionIntegration(),
3065
+ onUnhandledRejectionIntegration(),
3066
+ // Event Info
3067
+ contextLinesIntegration(),
3068
+ localVariablesIntegration(),
3069
+ nodeContextIntegration(),
3070
+ httpIntegration(),
3071
+ ...getCjsOnlyIntegrations(),
3072
+ ...(hasTracingEnabled(options) ? getAutoPerformanceIntegrations() : []),
3073
+ ];
3074
+ }
3075
+
3076
+ /**
3077
+ * Initialize Sentry for Node.
3078
+ */
3079
+ function init(options = {}) {
3080
+ const clientOptions = getClientOptions(options);
3081
+
3082
+ if (clientOptions.debug === true) {
3083
+ if (DEBUG_BUILD) {
3084
+ logger.enable();
3085
+ } else {
3086
+ // use `console.warn` rather than `logger.warn` since by non-debug bundles have all `logger.x` statements stripped
3087
+ consoleSandbox(() => {
3088
+ // eslint-disable-next-line no-console
3089
+ console.warn('[Sentry] Cannot initialize SDK with `debug` option using a non-debug bundle.');
3090
+ });
3091
+ }
3092
+ }
3093
+
3094
+ setOpenTelemetryContextAsyncContextStrategy();
3095
+
3096
+ const scope = getCurrentScope();
3097
+ scope.update(options.initialScope);
3098
+
3099
+ const client = new NodeClient(clientOptions);
3100
+ // The client is on the current scope, from where it generally is inherited
3101
+ getCurrentScope().setClient(client);
3102
+
3103
+ if (isEnabled(client)) {
3104
+ client.init();
3105
+ }
3106
+
3107
+ if (options.autoSessionTracking) {
3108
+ startSessionTracking();
3109
+ }
3110
+
3111
+ updateScopeFromEnvVariables();
3112
+
3113
+ if (options.spotlight) {
3114
+ // force integrations to be setup even if no DSN was set
3115
+ // If they have already been added before, they will be ignored anyhow
3116
+ const integrations = client.getOptions().integrations;
3117
+ for (const integration of integrations) {
3118
+ client.addIntegration(integration);
3119
+ }
3120
+ client.addIntegration(
3121
+ spotlightIntegration({
3122
+ sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,
3123
+ }),
3124
+ );
3125
+ }
3126
+
3127
+ // If users opt-out of this, they _have_ to set up OpenTelemetry themselves
3128
+ // There is no way to use this SDK without OpenTelemetry!
3129
+ if (!options.skipOpenTelemetrySetup) {
3130
+ initOtel();
3131
+ }
3132
+
3133
+ validateOpenTelemetrySetup();
3134
+ }
3135
+
3136
+ function validateOpenTelemetrySetup() {
3137
+ if (!DEBUG_BUILD) {
3138
+ return;
3139
+ }
3140
+
3141
+ const setup = openTelemetrySetupCheck();
3142
+
3143
+ const required = ['SentrySpanProcessor', 'SentryContextManager', 'SentryPropagator'] ;
3144
+ for (const k of required) {
3145
+ if (!setup.includes(k)) {
3146
+ logger.error(
3147
+ `You have to set up the ${k}. Without this, the OpenTelemetry & Sentry integration will not work properly.`,
3148
+ );
3149
+ }
3150
+ }
3151
+
3152
+ if (!setup.includes('SentrySampler')) {
3153
+ logger.warn(
3154
+ 'You have to set up the SentrySampler. Without this, the OpenTelemetry & Sentry integration may still work, but sample rates set for the Sentry SDK will not be respected.',
3155
+ );
3156
+ }
3157
+ }
3158
+
3159
+ function getClientOptions(options) {
3160
+ if (options.defaultIntegrations === undefined) {
3161
+ options.defaultIntegrations = getDefaultIntegrations(options);
3162
+ }
3163
+
3164
+ const release = getRelease(options.release);
3165
+
3166
+ const autoSessionTracking =
3167
+ typeof release !== 'string'
3168
+ ? false
3169
+ : options.autoSessionTracking === undefined
3170
+ ? true
3171
+ : options.autoSessionTracking;
3172
+
3173
+ const tracesSampleRate = getTracesSampleRate(options.tracesSampleRate);
3174
+
3175
+ const baseOptions = dropUndefinedKeys({
3176
+ transport: makeNodeTransport,
3177
+ dsn: process.env.SENTRY_DSN,
3178
+ environment: process.env.SENTRY_ENVIRONMENT,
3179
+ });
3180
+
3181
+ const overwriteOptions = dropUndefinedKeys({
3182
+ release,
3183
+ autoSessionTracking,
3184
+ tracesSampleRate,
3185
+ });
3186
+
3187
+ const clientOptions = {
3188
+ ...baseOptions,
3189
+ ...options,
3190
+ ...overwriteOptions,
3191
+ stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),
3192
+ integrations: getIntegrationsToSetup({
3193
+ defaultIntegrations: options.defaultIntegrations,
3194
+ integrations: options.integrations,
3195
+ }),
3196
+ };
3197
+
3198
+ return clientOptions;
3199
+ }
3200
+
3201
+ function getRelease(release) {
3202
+ if (release !== undefined) {
3203
+ return release;
3204
+ }
3205
+
3206
+ const detectedRelease = getSentryRelease();
3207
+ if (detectedRelease !== undefined) {
3208
+ return detectedRelease;
3209
+ }
3210
+
3211
+ return undefined;
3212
+ }
3213
+
3214
+ function getTracesSampleRate(tracesSampleRate) {
3215
+ if (tracesSampleRate !== undefined) {
3216
+ return tracesSampleRate;
3217
+ }
3218
+
3219
+ const sampleRateFromEnv = process.env.SENTRY_TRACES_SAMPLE_RATE;
3220
+ if (!sampleRateFromEnv) {
3221
+ return undefined;
3222
+ }
3223
+
3224
+ const parsed = parseFloat(sampleRateFromEnv);
3225
+ return isFinite(parsed) ? parsed : undefined;
3226
+ }
3227
+
3228
+ /**
3229
+ * Update scope and propagation context based on environmental variables.
3230
+ *
3231
+ * See https://github.com/getsentry/rfcs/blob/main/text/0071-continue-trace-over-process-boundaries.md
3232
+ * for more details.
3233
+ */
3234
+ function updateScopeFromEnvVariables() {
3235
+ const sentryUseEnvironment = (process.env.SENTRY_USE_ENVIRONMENT || '').toLowerCase();
3236
+ if (!['false', 'n', 'no', 'off', '0'].includes(sentryUseEnvironment)) {
3237
+ const sentryTraceEnv = process.env.SENTRY_TRACE;
3238
+ const baggageEnv = process.env.SENTRY_BAGGAGE;
3239
+ const propagationContext = propagationContextFromHeaders(sentryTraceEnv, baggageEnv);
3240
+ getCurrentScope().setPropagationContext(propagationContext);
3241
+ }
3242
+ }
3243
+
3244
+ /**
3245
+ * Enable automatic Session Tracking for the node process.
3246
+ */
3247
+ function startSessionTracking() {
3248
+ const client = getClient$2();
3249
+ if (client && client.getOptions().autoSessionTracking) {
3250
+ client.initSessionFlusher();
3251
+ }
3252
+
3253
+ startSession();
3254
+
3255
+ // Emitted in the case of healthy sessions, error of `mechanism.handled: true` and unhandledrejections because
3256
+ // The 'beforeExit' event is not emitted for conditions causing explicit termination,
3257
+ // such as calling process.exit() or uncaught exceptions.
3258
+ // Ref: https://nodejs.org/api/process.html#process_event_beforeexit
3259
+ process.on('beforeExit', () => {
3260
+ const session = getIsolationScope().getSession();
3261
+
3262
+ // Only call endSession, if the Session exists on Scope and SessionStatus is not a
3263
+ // Terminal Status i.e. Exited or Crashed because
3264
+ // "When a session is moved away from ok it must not be updated anymore."
3265
+ // Ref: https://develop.sentry.dev/sdk/sessions/
3266
+ if (session && session.status !== 'ok') {
3267
+ endSession();
3268
+ }
3269
+ });
3270
+ }
3271
+
3272
+ function isEnabled(client) {
3273
+ return client.getOptions().enabled !== false && client.getTransport() !== undefined;
3274
+ }
3275
+
3276
+ /**
3277
+ * This is for legacy reasons, and returns a proxy object instead of a hub to be used.
3278
+ * @deprecated Use the methods directly.
3279
+ */
3280
+ function getCurrentHub() {
3281
+ return {
3282
+ isOlderThan(_version) {
3283
+ return false;
3284
+ },
3285
+
3286
+ bindClient(client) {
3287
+ const scope = getCurrentScope();
3288
+ scope.setClient(client);
3289
+ },
3290
+
3291
+ pushScope() {
3292
+ // TODO: This does not work and is actually deprecated
3293
+ return getCurrentScope();
3294
+ },
3295
+
3296
+ popScope() {
3297
+ // TODO: This does not work and is actually deprecated
3298
+ return false;
3299
+ },
3300
+
3301
+ withScope,
3302
+ getClient: () => getClient() ,
3303
+ getScope: getCurrentScope,
3304
+ getIsolationScope,
3305
+ captureException: (exception, hint) => {
3306
+ return getCurrentScope().captureException(exception, hint);
3307
+ },
3308
+ captureMessage: (message, level, hint) => {
3309
+ return getCurrentScope().captureMessage(message, level, hint);
3310
+ },
3311
+ captureEvent,
3312
+ addBreadcrumb,
3313
+ setUser,
3314
+ setTags,
3315
+ setTag,
3316
+ setExtra,
3317
+ setExtras,
3318
+ setContext,
3319
+
3320
+ getIntegration(integration) {
3321
+ // eslint-disable-next-line deprecation/deprecation
3322
+ return getClient().getIntegration(integration);
3323
+ },
3324
+
3325
+ startSession,
3326
+
3327
+ endSession,
3328
+
3329
+ captureSession(endSession) {
3330
+ // both send the update and pull the session from the scope
3331
+ if (endSession) {
3332
+ // eslint-disable-next-line deprecation/deprecation
3333
+ return this.endSession();
3334
+ }
3335
+
3336
+ // only send the update
3337
+ _sendSessionUpdate();
3338
+ },
3339
+
3340
+ shouldSendDefaultPii() {
3341
+ const client = getClient();
3342
+ const options = client.getOptions();
3343
+ return Boolean(options.sendDefaultPii);
3344
+ },
3345
+ };
3346
+ }
3347
+
3348
+ /**
3349
+ * Sends the current Session on the scope
3350
+ */
3351
+ function _sendSessionUpdate() {
3352
+ const scope = getCurrentScope();
3353
+ const client = getClient();
3354
+
3355
+ const session = scope.getSession();
3356
+ if (session) {
3357
+ client.captureSession(session);
3358
+ }
3359
+ }
3360
+
3361
+ const replacements = [
3362
+ ['january', '1'],
3363
+ ['february', '2'],
3364
+ ['march', '3'],
3365
+ ['april', '4'],
3366
+ ['may', '5'],
3367
+ ['june', '6'],
3368
+ ['july', '7'],
3369
+ ['august', '8'],
3370
+ ['september', '9'],
3371
+ ['october', '10'],
3372
+ ['november', '11'],
3373
+ ['december', '12'],
3374
+ ['jan', '1'],
3375
+ ['feb', '2'],
3376
+ ['mar', '3'],
3377
+ ['apr', '4'],
3378
+ ['may', '5'],
3379
+ ['jun', '6'],
3380
+ ['jul', '7'],
3381
+ ['aug', '8'],
3382
+ ['sep', '9'],
3383
+ ['oct', '10'],
3384
+ ['nov', '11'],
3385
+ ['dec', '12'],
3386
+ ['sunday', '0'],
3387
+ ['monday', '1'],
3388
+ ['tuesday', '2'],
3389
+ ['wednesday', '3'],
3390
+ ['thursday', '4'],
3391
+ ['friday', '5'],
3392
+ ['saturday', '6'],
3393
+ ['sun', '0'],
3394
+ ['mon', '1'],
3395
+ ['tue', '2'],
3396
+ ['wed', '3'],
3397
+ ['thu', '4'],
3398
+ ['fri', '5'],
3399
+ ['sat', '6'],
3400
+ ];
3401
+
3402
+ /**
3403
+ * Replaces names in cron expressions
3404
+ */
3405
+ function replaceCronNames(cronExpression) {
3406
+ return replacements.reduce(
3407
+ // eslint-disable-next-line @sentry-internal/sdk/no-regexp-constructor
3408
+ (acc, [name, replacement]) => acc.replace(new RegExp(name, 'gi'), replacement),
3409
+ cronExpression,
3410
+ );
3411
+ }
3412
+
3413
+ const ERROR_TEXT = 'Automatic instrumentation of CronJob only supports crontab string';
3414
+
3415
+ /**
3416
+ * Instruments the `cron` library to send a check-in event to Sentry for each job execution.
3417
+ *
3418
+ * ```ts
3419
+ * import * as Sentry from '@sentry/node';
3420
+ * import { CronJob } from 'cron';
3421
+ *
3422
+ * const CronJobWithCheckIn = Sentry.cron.instrumentCron(CronJob, 'my-cron-job');
3423
+ *
3424
+ * // use the constructor
3425
+ * const job = new CronJobWithCheckIn('* * * * *', () => {
3426
+ * console.log('You will see this message every minute');
3427
+ * });
3428
+ *
3429
+ * // or from
3430
+ * const job = CronJobWithCheckIn.from({ cronTime: '* * * * *', onTick: () => {
3431
+ * console.log('You will see this message every minute');
3432
+ * });
3433
+ * ```
3434
+ */
3435
+ function instrumentCron(lib, monitorSlug) {
3436
+ let jobScheduled = false;
3437
+
3438
+ return new Proxy(lib, {
3439
+ construct(target, args) {
3440
+ const [cronTime, onTick, onComplete, start, timeZone, ...rest] = args;
3441
+
3442
+ if (typeof cronTime !== 'string') {
3443
+ throw new Error(ERROR_TEXT);
3444
+ }
3445
+
3446
+ if (jobScheduled) {
3447
+ throw new Error(`A job named '${monitorSlug}' has already been scheduled`);
3448
+ }
3449
+
3450
+ jobScheduled = true;
3451
+
3452
+ const cronString = replaceCronNames(cronTime);
3453
+
3454
+ function monitoredTick(context, onComplete) {
3455
+ return withMonitor(
3456
+ monitorSlug,
3457
+ () => {
3458
+ return onTick(context, onComplete);
3459
+ },
3460
+ {
3461
+ schedule: { type: 'crontab', value: cronString },
3462
+ ...(timeZone ? { timeZone } : {}),
3463
+ },
3464
+ );
3465
+ }
3466
+
3467
+ return new target(cronTime, monitoredTick, onComplete, start, timeZone, ...rest);
3468
+ },
3469
+ get(target, prop) {
3470
+ if (prop === 'from') {
3471
+ return (param) => {
3472
+ const { cronTime, onTick, timeZone } = param;
3473
+
3474
+ if (typeof cronTime !== 'string') {
3475
+ throw new Error(ERROR_TEXT);
3476
+ }
3477
+
3478
+ if (jobScheduled) {
3479
+ throw new Error(`A job named '${monitorSlug}' has already been scheduled`);
3480
+ }
3481
+
3482
+ jobScheduled = true;
3483
+
3484
+ const cronString = replaceCronNames(cronTime);
3485
+
3486
+ param.onTick = (context, onComplete) => {
3487
+ return withMonitor(
3488
+ monitorSlug,
3489
+ () => {
3490
+ return onTick(context, onComplete);
3491
+ },
3492
+ {
3493
+ schedule: { type: 'crontab', value: cronString },
3494
+ ...(timeZone ? { timeZone } : {}),
3495
+ },
3496
+ );
3497
+ };
3498
+
3499
+ return target.from(param);
3500
+ };
3501
+ } else {
3502
+ return target[prop];
3503
+ }
3504
+ },
3505
+ });
3506
+ }
3507
+
3508
+ /**
3509
+ * Wraps the `node-cron` library with check-in monitoring.
3510
+ *
3511
+ * ```ts
3512
+ * import * as Sentry from "@sentry/node";
3513
+ * import cron from "node-cron";
3514
+ *
3515
+ * const cronWithCheckIn = Sentry.cron.instrumentNodeCron(cron);
3516
+ *
3517
+ * cronWithCheckIn.schedule(
3518
+ * "* * * * *",
3519
+ * () => {
3520
+ * console.log("running a task every minute");
3521
+ * },
3522
+ * { name: "my-cron-job" },
3523
+ * );
3524
+ * ```
3525
+ */
3526
+ function instrumentNodeCron(lib) {
3527
+ return new Proxy(lib, {
3528
+ get(target, prop) {
3529
+ if (prop === 'schedule' && target.schedule) {
3530
+ // When 'get' is called for schedule, return a proxied version of the schedule function
3531
+ return new Proxy(target.schedule, {
3532
+ apply(target, thisArg, argArray) {
3533
+ const [expression, , options] = argArray;
3534
+
3535
+ if (!_optionalChain([options, 'optionalAccess', _ => _.name])) {
3536
+ throw new Error('Missing "name" for scheduled job. A name is required for Sentry check-in monitoring.');
3537
+ }
3538
+
3539
+ return withMonitor(
3540
+ options.name,
3541
+ () => {
3542
+ return target.apply(thisArg, argArray);
3543
+ },
3544
+ {
3545
+ schedule: { type: 'crontab', value: replaceCronNames(expression) },
3546
+ timezone: _optionalChain([options, 'optionalAccess', _2 => _2.timezone]),
3547
+ },
3548
+ );
3549
+ },
3550
+ });
3551
+ } else {
3552
+ return target[prop];
3553
+ }
3554
+ },
3555
+ });
3556
+ }
3557
+
3558
+ /**
3559
+ * Instruments the `node-schedule` library to send a check-in event to Sentry for each job execution.
3560
+ *
3561
+ * ```ts
3562
+ * import * as Sentry from '@sentry/node';
3563
+ * import * as schedule from 'node-schedule';
3564
+ *
3565
+ * const scheduleWithCheckIn = Sentry.cron.instrumentNodeSchedule(schedule);
3566
+ *
3567
+ * const job = scheduleWithCheckIn.scheduleJob('my-cron-job', '* * * * *', () => {
3568
+ * console.log('You will see this message every minute');
3569
+ * });
3570
+ * ```
3571
+ */
3572
+ function instrumentNodeSchedule(lib) {
3573
+ return new Proxy(lib, {
3574
+ get(target, prop) {
3575
+ if (prop === 'scheduleJob') {
3576
+ // eslint-disable-next-line @typescript-eslint/unbound-method
3577
+ return new Proxy(target.scheduleJob, {
3578
+ apply(target, thisArg, argArray) {
3579
+ const [nameOrExpression, expressionOrCallback] = argArray;
3580
+
3581
+ if (typeof nameOrExpression !== 'string' || typeof expressionOrCallback !== 'string') {
3582
+ throw new Error(
3583
+ "Automatic instrumentation of 'node-schedule' requires the first parameter of 'scheduleJob' to be a job name string and the second parameter to be a crontab string",
3584
+ );
3585
+ }
3586
+
3587
+ const monitorSlug = nameOrExpression;
3588
+ const expression = expressionOrCallback;
3589
+
3590
+ return withMonitor(
3591
+ monitorSlug,
3592
+ () => {
3593
+ return target.apply(thisArg, argArray);
3594
+ },
3595
+ {
3596
+ schedule: { type: 'crontab', value: replaceCronNames(expression) },
3597
+ },
3598
+ );
3599
+ },
3600
+ });
3601
+ }
3602
+
3603
+ return target[prop];
3604
+ },
3605
+ });
3606
+ }
3607
+
3608
+ /** Methods to instrument cron libraries for Sentry check-ins */
3609
+ const cron = {
3610
+ instrumentCron,
3611
+ instrumentNodeCron,
3612
+ instrumentNodeSchedule,
3613
+ };
3614
+
3615
+ export { NodeClient, anrIntegration, consoleIntegration, contextLinesIntegration, createGetModuleFromFilename, cron, defaultStackParser, expressErrorHandler, expressIntegration, fastifyIntegration, getAutoPerformanceIntegrations, getClient, getCurrentHub, getDefaultIntegrations, getSentryRelease, graphqlIntegration, hapiIntegration, httpIntegration, init, localVariablesIntegration, makeMain, makeNodeTransport, modulesIntegration, mongoIntegration, mongooseIntegration, mysql2Integration, mysqlIntegration, nativeNodeFetchIntegration, nestIntegration, nodeContextIntegration, onUncaughtExceptionIntegration, onUnhandledRejectionIntegration, postgresIntegration, prismaIntegration, setupExpressErrorHandler, setupFastifyErrorHandler, setupHapiErrorHandler, spotlightIntegration };
33
3616
  //# sourceMappingURL=index.js.map