@sentry/node 8.0.0-alpha.9 → 8.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/index.js +307 -76
- package/cjs/index.js.map +1 -1
- package/esm/index.js +310 -80
- package/esm/index.js.map +1 -1
- package/esm/integrations/anr/worker-script.js +2 -2
- package/esm/integrations/local-variables/worker-script.js +2 -0
- package/package.json +19 -19
- package/types/index.d.ts +2 -2
- package/types/index.d.ts.map +1 -1
- package/types/integrations/anr/index.d.ts +1 -0
- package/types/integrations/anr/index.d.ts.map +1 -1
- package/types/integrations/http.d.ts.map +1 -1
- package/types/integrations/local-variables/common.d.ts +12 -0
- package/types/integrations/local-variables/common.d.ts.map +1 -1
- package/types/integrations/local-variables/index.d.ts +3 -1
- package/types/integrations/local-variables/index.d.ts.map +1 -1
- package/types/integrations/local-variables/local-variables-async.d.ts +7 -0
- package/types/integrations/local-variables/local-variables-async.d.ts.map +1 -0
- package/types/integrations/local-variables/worker.d.ts +2 -0
- package/types/integrations/local-variables/worker.d.ts.map +1 -0
- package/types/integrations/onuncaughtexception.d.ts +1 -1
- package/types/integrations/onuncaughtexception.d.ts.map +1 -1
- package/types/integrations/tracing/express.d.ts.map +1 -1
- package/types/integrations/tracing/fastify.d.ts +2 -2
- package/types/integrations/tracing/fastify.d.ts.map +1 -1
- package/types/integrations/tracing/hapi/index.d.ts.map +1 -1
- package/types/integrations/tracing/koa.d.ts.map +1 -1
- package/types/integrations/tracing/nest.d.ts +22 -5
- package/types/integrations/tracing/nest.d.ts.map +1 -1
- package/types/sdk/initOtel.d.ts.map +1 -1
- package/types/transports/http.d.ts.map +1 -1
- package/types-ts3.8/index.d.ts +2 -2
- package/types-ts3.8/integrations/anr/index.d.ts +1 -0
- package/types-ts3.8/integrations/local-variables/common.d.ts +12 -0
- package/types-ts3.8/integrations/local-variables/index.d.ts +3 -1
- package/types-ts3.8/integrations/local-variables/local-variables-async.d.ts +7 -0
- package/types-ts3.8/integrations/local-variables/worker.d.ts +2 -0
- package/types-ts3.8/integrations/onuncaughtexception.d.ts +1 -1
- package/types-ts3.8/integrations/tracing/fastify.d.ts +2 -2
- package/types-ts3.8/integrations/tracing/nest.d.ts +22 -5
- package/register.mjs +0 -3
- package/types/integrations/anr/worker-script.d.ts +0 -2
- package/types/integrations/anr/worker-script.d.ts.map +0 -1
- package/types-ts3.8/integrations/anr/worker-script.d.ts +0 -2
package/esm/index.js
CHANGED
|
@@ -2,11 +2,11 @@ import { _optionalChainDelete, _nullishCoalesce, _optionalChain } from '@sentry/
|
|
|
2
2
|
import { context, SpanKind, trace, diag, DiagLogLevel } from '@opentelemetry/api';
|
|
3
3
|
import { registerInstrumentations } from '@opentelemetry/instrumentation';
|
|
4
4
|
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
|
|
5
|
-
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, isSentryRequestUrl, getIsolationScope, addBreadcrumb, getClient as getClient$1, captureException, getGlobalScope, mergeScopeData,
|
|
6
|
-
export {
|
|
7
|
-
import { getScopesFromContext, getClient, getSpanKind,
|
|
8
|
-
export { continueTrace } from '@sentry/opentelemetry';
|
|
9
|
-
import { parseSemver, logger, addConsoleInstrumentationHandler, severityLevelFromString, LRUMap, addContextToFrame, consoleSandbox, GLOBAL_OBJ, serializeEnvelope, dirname as dirname$1, createStackParser, nodeStackLineParser, dropUndefinedKeys, stackParserFromStackParserOptions, propagationContextFromHeaders } from '@sentry/utils';
|
|
5
|
+
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, isSentryRequestUrl, getCapturedScopesOnSpan, getIsolationScope, getCurrentScope, setCapturedScopesOnSpan, spanToJSON, addBreadcrumb, getClient as getClient$1, captureException, getGlobalScope, mergeScopeData, getDefaultIsolationScope, SDK_VERSION, getActiveSpan, getRootSpan, SPAN_STATUS_ERROR, createTransport, suppressTracing, ServerRuntimeClient, applySdkMetadata, inboundFiltersIntegration, functionToStringIntegration, linkedErrorsIntegration, requestDataIntegration, hasTracingEnabled, getIntegrationsToSetup, startSession, endSession, withMonitor } from '@sentry/core';
|
|
6
|
+
export { 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, getClient, getCurrentHub, 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, spanToJSON, spanToTraceHeader, startInactiveSpan, startSession, startSpan, startSpanManual, trpcMiddleware, withActiveSpan, withIsolationScope, withMonitor, withScope } from '@sentry/core';
|
|
7
|
+
import { getScopesFromContext, getClient, getSpanKind, getRequestSpanData, wrapContextManagerClass, setupEventContextTrace, SentrySampler, SentrySpanProcessor, SentryPropagator, setOpenTelemetryContextAsyncContextStrategy, openTelemetrySetupCheck } from '@sentry/opentelemetry';
|
|
8
|
+
export { continueTrace, setOpenTelemetryContextAsyncContextStrategy as setNodeAsyncContextStrategy } from '@sentry/opentelemetry';
|
|
9
|
+
import { stripUrlQueryAndFragment, parseSemver, logger, addConsoleInstrumentationHandler, severityLevelFromString, LRUMap, addContextToFrame, consoleSandbox, GLOBAL_OBJ, serializeEnvelope, dirname as dirname$1, createStackParser, nodeStackLineParser, dropUndefinedKeys, stackParserFromStackParserOptions, propagationContextFromHeaders } from '@sentry/utils';
|
|
10
10
|
export { DEFAULT_USER_INCLUDES, addRequestDataToEvent, extractRequestData } from '@sentry/utils';
|
|
11
11
|
import * as util from 'util';
|
|
12
12
|
import { promisify } from 'util';
|
|
@@ -14,9 +14,9 @@ import { execFile } from 'child_process';
|
|
|
14
14
|
import { readFile, readdir, promises, existsSync, readFileSync } from 'fs';
|
|
15
15
|
import * as os from 'os';
|
|
16
16
|
import { join, dirname, posix, sep } from 'path';
|
|
17
|
+
import { Worker } from 'worker_threads';
|
|
17
18
|
import * as inspector from 'inspector';
|
|
18
19
|
import { Session } from 'inspector';
|
|
19
|
-
import { Worker } from 'worker_threads';
|
|
20
20
|
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
|
|
21
21
|
import { FastifyInstrumentation } from '@opentelemetry/instrumentation-fastify';
|
|
22
22
|
import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql';
|
|
@@ -29,17 +29,16 @@ import { PgInstrumentation } from '@opentelemetry/instrumentation-pg';
|
|
|
29
29
|
import * as prismaInstrumentation from '@prisma/instrumentation';
|
|
30
30
|
import { HapiInstrumentation } from '@opentelemetry/instrumentation-hapi';
|
|
31
31
|
import { KoaInstrumentation } from '@opentelemetry/instrumentation-koa';
|
|
32
|
+
import { SEMATTRS_HTTP_ROUTE, SEMRESATTRS_SERVICE_NAME, SEMRESATTRS_SERVICE_NAMESPACE, SEMRESATTRS_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
|
|
32
33
|
import * as http from 'http';
|
|
33
34
|
import * as http$1 from 'node:http';
|
|
34
35
|
import * as https from 'node:https';
|
|
35
36
|
import { Readable } from 'stream';
|
|
36
37
|
import { createGzip } from 'zlib';
|
|
37
|
-
import { suppressTracing } from '@opentelemetry/core';
|
|
38
38
|
import * as net from 'net';
|
|
39
39
|
import * as tls from 'tls';
|
|
40
40
|
import { Resource } from '@opentelemetry/resources';
|
|
41
41
|
import { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';
|
|
42
|
-
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
|
|
43
42
|
import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
|
|
44
43
|
|
|
45
44
|
/**
|
|
@@ -72,7 +71,7 @@ function getRequestUrl(requestOptions) {
|
|
|
72
71
|
return `${protocol}//${hostname}${port}${path}`;
|
|
73
72
|
}
|
|
74
73
|
|
|
75
|
-
function _optionalChain$
|
|
74
|
+
function _optionalChain$c(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; }
|
|
76
75
|
|
|
77
76
|
const _httpIntegration = ((options = {}) => {
|
|
78
77
|
const _breadcrumbs = typeof options.breadcrumbs === 'undefined' ? true : options.breadcrumbs;
|
|
@@ -105,7 +104,7 @@ const _httpIntegration = ((options = {}) => {
|
|
|
105
104
|
ignoreIncomingRequestHook: request => {
|
|
106
105
|
const url = getRequestUrl(request);
|
|
107
106
|
|
|
108
|
-
const method = _optionalChain$
|
|
107
|
+
const method = _optionalChain$c([request, 'access', _ => _.method, 'optionalAccess', _2 => _2.toUpperCase, 'call', _3 => _3()]);
|
|
109
108
|
// We do not capture OPTIONS/HEAD requests as transactions
|
|
110
109
|
if (method === 'OPTIONS' || method === 'HEAD') {
|
|
111
110
|
return true;
|
|
@@ -118,22 +117,45 @@ const _httpIntegration = ((options = {}) => {
|
|
|
118
117
|
return false;
|
|
119
118
|
},
|
|
120
119
|
|
|
121
|
-
requireParentforOutgoingSpans:
|
|
120
|
+
requireParentforOutgoingSpans: false,
|
|
122
121
|
requireParentforIncomingSpans: false,
|
|
123
122
|
requestHook: (span, req) => {
|
|
124
|
-
|
|
123
|
+
addOriginToSpan(span, 'auto.http.otel.http');
|
|
124
|
+
|
|
125
|
+
// both, incoming requests and "client" requests made within the app trigger the requestHook
|
|
126
|
+
// we only want to isolate and further annotate incoming requests (IncomingMessage)
|
|
127
|
+
if (_isClientRequest(req)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const scopes = getCapturedScopesOnSpan(span);
|
|
132
|
+
|
|
133
|
+
const isolationScope = (scopes.isolationScope || getIsolationScope()).clone();
|
|
134
|
+
const scope = scopes.scope || getCurrentScope();
|
|
125
135
|
|
|
126
136
|
// Update the isolation scope, isolate this request
|
|
127
|
-
|
|
128
|
-
const isolationScope = getIsolationScope().clone();
|
|
129
|
-
isolationScope.setSDKProcessingMetadata({ request: req });
|
|
137
|
+
isolationScope.setSDKProcessingMetadata({ request: req });
|
|
130
138
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
setIsolationScope(isolationScope);
|
|
139
|
+
const client = getClient();
|
|
140
|
+
if (client && client.getOptions().autoSessionTracking) {
|
|
141
|
+
isolationScope.setRequestSession({ status: 'ok' });
|
|
136
142
|
}
|
|
143
|
+
setIsolationScope(isolationScope);
|
|
144
|
+
setCapturedScopesOnSpan(span, scope, isolationScope);
|
|
145
|
+
|
|
146
|
+
// attempt to update the scope's `transactionName` based on the request URL
|
|
147
|
+
// Ideally, framework instrumentations coming after the HttpInstrumentation
|
|
148
|
+
// update the transactionName once we get a parameterized route.
|
|
149
|
+
const attributes = spanToJSON(span).data;
|
|
150
|
+
if (!attributes) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const httpMethod = String(attributes['http.method']).toUpperCase() || 'GET';
|
|
155
|
+
const httpTarget = stripUrlQueryAndFragment(String(attributes['http.target'])) || '/';
|
|
156
|
+
const bestEffortTransactionName = `${httpMethod} ${httpTarget}`;
|
|
157
|
+
|
|
158
|
+
isolationScope.setTransactionName(bestEffortTransactionName);
|
|
137
159
|
},
|
|
138
160
|
responseHook: (span, res) => {
|
|
139
161
|
if (_breadcrumbs) {
|
|
@@ -163,18 +185,13 @@ const _httpIntegration = ((options = {}) => {
|
|
|
163
185
|
*/
|
|
164
186
|
const httpIntegration = defineIntegration(_httpIntegration);
|
|
165
187
|
|
|
166
|
-
/** Update the span with data we need. */
|
|
167
|
-
function _updateSpan$1(span) {
|
|
168
|
-
addOriginToSpan(span, 'auto.http.otel.http');
|
|
169
|
-
}
|
|
170
|
-
|
|
171
188
|
/** Add a breadcrumb for outgoing requests. */
|
|
172
189
|
function _addRequestBreadcrumb$1(span, response) {
|
|
173
190
|
if (getSpanKind(span) !== SpanKind.CLIENT) {
|
|
174
191
|
return;
|
|
175
192
|
}
|
|
176
193
|
|
|
177
|
-
const data =
|
|
194
|
+
const data = getRequestSpanData(span);
|
|
178
195
|
addBreadcrumb(
|
|
179
196
|
{
|
|
180
197
|
category: 'http',
|
|
@@ -194,6 +211,15 @@ function _addRequestBreadcrumb$1(span, response) {
|
|
|
194
211
|
);
|
|
195
212
|
}
|
|
196
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Determines if @param req is a ClientRequest, meaning the request was created within the express app
|
|
216
|
+
* and it's an outgoing request.
|
|
217
|
+
* Checking for properties instead of using `instanceOf` to avoid importing the request classes.
|
|
218
|
+
*/
|
|
219
|
+
function _isClientRequest(req) {
|
|
220
|
+
return 'outputData' in req && 'outputSize' in req && !('client' in req) && !('statusCode' in req);
|
|
221
|
+
}
|
|
222
|
+
|
|
197
223
|
/**
|
|
198
224
|
* 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.
|
|
199
225
|
*
|
|
@@ -267,7 +293,7 @@ function _addRequestBreadcrumb(span) {
|
|
|
267
293
|
return;
|
|
268
294
|
}
|
|
269
295
|
|
|
270
|
-
const data =
|
|
296
|
+
const data = getRequestSpanData(span);
|
|
271
297
|
addBreadcrumb({
|
|
272
298
|
category: 'http',
|
|
273
299
|
data: {
|
|
@@ -309,7 +335,7 @@ const _consoleIntegration = (() => {
|
|
|
309
335
|
*/
|
|
310
336
|
const consoleIntegration = defineIntegration(_consoleIntegration);
|
|
311
337
|
|
|
312
|
-
function _optionalChain$
|
|
338
|
+
function _optionalChain$b(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; }
|
|
313
339
|
const readFileAsync$1 = promisify(readFile);
|
|
314
340
|
const readDirAsync = promisify(readdir);
|
|
315
341
|
|
|
@@ -337,11 +363,11 @@ const _nodeContextIntegration = ((options = {}) => {
|
|
|
337
363
|
|
|
338
364
|
event.contexts = {
|
|
339
365
|
...event.contexts,
|
|
340
|
-
app: { ...updatedContext.app, ..._optionalChain$
|
|
341
|
-
os: { ...updatedContext.os, ..._optionalChain$
|
|
342
|
-
device: { ...updatedContext.device, ..._optionalChain$
|
|
343
|
-
culture: { ...updatedContext.culture, ..._optionalChain$
|
|
344
|
-
cloud_resource: { ...updatedContext.cloud_resource, ..._optionalChain$
|
|
366
|
+
app: { ...updatedContext.app, ..._optionalChain$b([event, 'access', _ => _.contexts, 'optionalAccess', _2 => _2.app]) },
|
|
367
|
+
os: { ...updatedContext.os, ..._optionalChain$b([event, 'access', _3 => _3.contexts, 'optionalAccess', _4 => _4.os]) },
|
|
368
|
+
device: { ...updatedContext.device, ..._optionalChain$b([event, 'access', _5 => _5.contexts, 'optionalAccess', _6 => _6.device]) },
|
|
369
|
+
culture: { ...updatedContext.culture, ..._optionalChain$b([event, 'access', _7 => _7.contexts, 'optionalAccess', _8 => _8.culture]) },
|
|
370
|
+
cloud_resource: { ...updatedContext.cloud_resource, ..._optionalChain$b([event, 'access', _9 => _9.contexts, 'optionalAccess', _10 => _10.cloud_resource]) },
|
|
345
371
|
};
|
|
346
372
|
|
|
347
373
|
return event;
|
|
@@ -396,11 +422,11 @@ const nodeContextIntegration = defineIntegration(_nodeContextIntegration);
|
|
|
396
422
|
*/
|
|
397
423
|
function _updateContext(contexts) {
|
|
398
424
|
// Only update properties if they exist
|
|
399
|
-
if (_optionalChain$
|
|
425
|
+
if (_optionalChain$b([contexts, 'optionalAccess', _11 => _11.app, 'optionalAccess', _12 => _12.app_memory])) {
|
|
400
426
|
contexts.app.app_memory = process.memoryUsage().rss;
|
|
401
427
|
}
|
|
402
428
|
|
|
403
|
-
if (_optionalChain$
|
|
429
|
+
if (_optionalChain$b([contexts, 'optionalAccess', _13 => _13.device, 'optionalAccess', _14 => _14.free_memory])) {
|
|
404
430
|
contexts.device.free_memory = os.freemem();
|
|
405
431
|
}
|
|
406
432
|
|
|
@@ -727,7 +753,7 @@ function getCloudResourceContext() {
|
|
|
727
753
|
}
|
|
728
754
|
}
|
|
729
755
|
|
|
730
|
-
function _optionalChain$
|
|
756
|
+
function _optionalChain$a(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; }
|
|
731
757
|
const FILE_CONTENT_CACHE = new LRUMap(100);
|
|
732
758
|
const DEFAULT_LINES_OF_CONTEXT = 7;
|
|
733
759
|
const INTEGRATION_NAME$6 = 'ContextLines';
|
|
@@ -757,9 +783,9 @@ async function addSourceContext(event, contextLines) {
|
|
|
757
783
|
const enqueuedReadSourceFileTasks = {};
|
|
758
784
|
const readSourceFileTasks = [];
|
|
759
785
|
|
|
760
|
-
if (contextLines > 0 && _optionalChain$
|
|
786
|
+
if (contextLines > 0 && _optionalChain$a([event, 'access', _2 => _2.exception, 'optionalAccess', _3 => _3.values])) {
|
|
761
787
|
for (const exception of event.exception.values) {
|
|
762
|
-
if (!_optionalChain$
|
|
788
|
+
if (!_optionalChain$a([exception, 'access', _4 => _4.stacktrace, 'optionalAccess', _5 => _5.frames])) {
|
|
763
789
|
continue;
|
|
764
790
|
}
|
|
765
791
|
|
|
@@ -786,7 +812,7 @@ async function addSourceContext(event, contextLines) {
|
|
|
786
812
|
|
|
787
813
|
// Perform the same loop as above, but this time we can assume all files are in the cache
|
|
788
814
|
// and attempt to add source context to frames.
|
|
789
|
-
if (contextLines > 0 && _optionalChain$
|
|
815
|
+
if (contextLines > 0 && _optionalChain$a([event, 'access', _6 => _6.exception, 'optionalAccess', _7 => _7.values])) {
|
|
790
816
|
for (const exception of event.exception.values) {
|
|
791
817
|
if (exception.stacktrace && exception.stacktrace.frames) {
|
|
792
818
|
await addSourceContextToFrames(exception.stacktrace.frames, contextLines);
|
|
@@ -931,7 +957,141 @@ function hashFromStack(stackParser, stack) {
|
|
|
931
957
|
return hashFrames(stackParser(stack, 1));
|
|
932
958
|
}
|
|
933
959
|
|
|
934
|
-
function _optionalChain$
|
|
960
|
+
function _optionalChain$9(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; }
|
|
961
|
+
// This string is a placeholder that gets overwritten with the worker code.
|
|
962
|
+
const base64WorkerScript$1 = 'LyohIEBzZW50cnkvbm9kZSA4LjAuMC1iZXRhLjIgKGYyMTViYWIpIHwgaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdCAqLwppbXBvcnR7U2Vzc2lvbiBhcyBlfWZyb20ibm9kZTppbnNwZWN0b3IvcHJvbWlzZXMiO2ltcG9ydHt3b3JrZXJEYXRhIGFzIG4scGFyZW50UG9ydCBhcyB0fWZyb20id29ya2VyX3RocmVhZHMiO2ltcG9ydHtwb3NpeCBhcyBvLHNlcCBhcyByfWZyb20icGF0aCI7Y29uc3QgaT01MCxzPSI/IixjPS9cKGVycm9yOiAoLiopXCkvLGE9L2NhcHR1cmVNZXNzYWdlfGNhcHR1cmVFeGNlcHRpb24vO2NvbnN0IHU9L14oXFMrOlxcfFwvPykoW1xzXFNdKj8pKCg/OlwuezEsMn18W14vXFxdKz98KShcLlteLi9cXF0qfCkpKD86Wy9cXF0qKSQvO2Z1bmN0aW9uIGYoZSl7Y29uc3Qgbj1mdW5jdGlvbihlKXtjb25zdCBuPWUubGVuZ3RoPjEwMjQ/YDx0cnVuY2F0ZWQ+JHtlLnNsaWNlKC0xMDI0KX1gOmUsdD11LmV4ZWMobik7cmV0dXJuIHQ/dC5zbGljZSgxKTpbXX0oZSksdD1uWzBdO2xldCBvPW5bMV07cmV0dXJuIHR8fG8/KG8mJihvPW8uc2xpY2UoMCxvLmxlbmd0aC0xKSksdCtvKToiLiJ9ZnVuY3Rpb24gbChlLG49ITEpe3JldHVybiEobnx8ZSYmIWUuc3RhcnRzV2l0aCgiLyIpJiYhZS5tYXRjaCgvXltBLVpdOi8pJiYhZS5zdGFydHNXaXRoKCIuIikmJiFlLm1hdGNoKC9eW2EtekEtWl0oW2EtekEtWjAtOS5cLStdKSo6XC9cLy8pKSYmdm9pZCAwIT09ZSYmIWUuaW5jbHVkZXMoIm5vZGVfbW9kdWxlcy8iKX1mdW5jdGlvbiBkKGUpe2NvbnN0IG49L15ccypbLV17NCx9JC8sdD0vYXQgKD86YXN5bmMgKT8oPzooLis/KVxzK1woKT8oPzooLispOihcZCspOihcZCspP3woW14pXSspKVwpPy87cmV0dXJuIG89Pntjb25zdCByPW8ubWF0Y2godCk7aWYocil7bGV0IG4sdCxvLGksYztpZihyWzFdKXtvPXJbMV07bGV0IGU9by5sYXN0SW5kZXhPZigiLiIpO2lmKCIuIj09PW9bZS0xXSYmZS0tLGU+MCl7bj1vLnNsaWNlKDAsZSksdD1vLnNsaWNlKGUrMSk7Y29uc3Qgcj1uLmluZGV4T2YoIi5Nb2R1bGUiKTtyPjAmJihvPW8uc2xpY2UocisxKSxuPW4uc2xpY2UoMCxyKSl9aT12b2lkIDB9dCYmKGk9bixjPXQpLCI8YW5vbnltb3VzPiI9PT10JiYoYz12b2lkIDAsbz12b2lkIDApLHZvaWQgMD09PW8mJihjPWN8fHMsbz1pP2Ake2l9LiR7Y31gOmMpO2xldCBhPXJbMl0mJnJbMl0uc3RhcnRzV2l0aCgiZmlsZTovLyIpP3JbMl0uc2xpY2UoNyk6clsyXTtjb25zdCB1PSJuYXRpdmUiPT09cls1XTtyZXR1cm4gYSYmYS5tYXRjaCgvXC9bQS1aXTovKSYmKGE9YS5zbGljZSgxKSksYXx8IXJbNV18fHV8fChhPXJbNV0pLHtmaWxlbmFtZTphLG1vZHVsZTplP2UoYSk6dm9pZCAwLGZ1bmN0aW9uOm8sbGluZW5vOnBhcnNlSW50KHJbM10sMTApfHx2b2lkIDAsY29sbm86cGFyc2VJbnQocls0XSwxMCl8fHZvaWQgMCxpbl9hcHA6bChhLHUpfX1pZihvLm1hdGNoKG4pKXJldHVybntmaWxlbmFtZTpvfX19ZnVuY3Rpb24gcChlKXtyZXR1cm4gZS5yZXBsYWNlKC9eW0EtWl06LywiIikucmVwbGFjZSgvXFwvZywiLyIpfWNvbnN0IGc9bixtPWZ1bmN0aW9uKC4uLmUpe2NvbnN0IG49ZS5zb3J0KCgoZSxuKT0+ZVswXS1uWzBdKSkubWFwKChlPT5lWzFdKSk7cmV0dXJuKGUsdD0wLG89MCk9Pntjb25zdCByPVtdLHU9ZS5zcGxpdCgiXG4iKTtmb3IobGV0IGU9dDtlPHUubGVuZ3RoO2UrKyl7Y29uc3QgdD11W2VdO2lmKHQubGVuZ3RoPjEwMjQpY29udGludWU7Y29uc3Qgcz1jLnRlc3QodCk/dC5yZXBsYWNlKGMsIiQxIik6dDtpZighcy5tYXRjaCgvXFMqRXJyb3I6IC8pKXtmb3IoY29uc3QgZSBvZiBuKXtjb25zdCBuPWUocyk7aWYobil7ci5wdXNoKG4pO2JyZWFrfX1pZihyLmxlbmd0aD49aStvKWJyZWFrfX1yZXR1cm4gZnVuY3Rpb24oZSl7aWYoIWUubGVuZ3RoKXJldHVybltdO2NvbnN0IG49QXJyYXkuZnJvbShlKTsvc2VudHJ5V3JhcHBlZC8udGVzdChuW24ubGVuZ3RoLTFdLmZ1bmN0aW9ufHwiIikmJm4ucG9wKCk7bi5yZXZlcnNlKCksYS50ZXN0KG5bbi5sZW5ndGgtMV0uZnVuY3Rpb258fCIiKSYmKG4ucG9wKCksYS50ZXN0KG5bbi5sZW5ndGgtMV0uZnVuY3Rpb258fCIiKSYmbi5wb3AoKSk7cmV0dXJuIG4uc2xpY2UoMCxpKS5tYXAoKGU9Pih7Li4uZSxmaWxlbmFtZTplLmZpbGVuYW1lfHxuW24ubGVuZ3RoLTFdLmZpbGVuYW1lLGZ1bmN0aW9uOmUuZnVuY3Rpb258fHN9KSkpfShyLnNsaWNlKG8pKX19KFs5MCxkKGZ1bmN0aW9uKGU9KHByb2Nlc3MuYXJndlsxXT9mKHByb2Nlc3MuYXJndlsxXSk6cHJvY2Vzcy5jd2QoKSksbj0iXFwiPT09cil7Y29uc3QgdD1uP3AoZSk6ZTtyZXR1cm4gZT0+e2lmKCFlKXJldHVybjtjb25zdCByPW4/cChlKTplO2xldHtkaXI6aSxiYXNlOnMsZXh0OmN9PW8ucGFyc2Uocik7Ii5qcyIhPT1jJiYiLm1qcyIhPT1jJiYiLmNqcyIhPT1jfHwocz1zLnNsaWNlKDAsLTEqYy5sZW5ndGgpKSxpfHwoaT0iLiIpO2NvbnN0IGE9aS5sYXN0SW5kZXhPZigiL25vZGVfbW9kdWxlcyIpO2lmKGE+LTEpcmV0dXJuYCR7aS5zbGljZShhKzE0KS5yZXBsYWNlKC9cLy9nLCIuIil9OiR7c31gO2lmKGkuc3RhcnRzV2l0aCh0KSl7bGV0IGU9aS5zbGljZSh0Lmxlbmd0aCsxKS5yZXBsYWNlKC9cLy9nLCIuIik7cmV0dXJuIGUmJihlKz0iOiIpLGUrPXMsZX1yZXR1cm4gc319KGcuYmFzZVBhdGgpKV0pO2Z1bmN0aW9uIGIoLi4uZSl7Zy5kZWJ1ZyYmY29uc29sZS5sb2coIltMb2NhbFZhcmlhYmxlcyBXb3JrZXJdIiwuLi5lKX1hc3luYyBmdW5jdGlvbiB2KGUsbix0LG8pe2NvbnN0IHI9YXdhaXQgZS5wb3N0KCJSdW50aW1lLmdldFByb3BlcnRpZXMiLHtvYmplY3RJZDpuLG93blByb3BlcnRpZXM6ITB9KTtvW3RdPXIucmVzdWx0LmZpbHRlcigoZT0+Imxlbmd0aCIhPT1lLm5hbWUmJiFpc05hTihwYXJzZUludChlLm5hbWUsMTApKSkpLnNvcnQoKChlLG4pPT5wYXJzZUludChlLm5hbWUsMTApLXBhcnNlSW50KG4ubmFtZSwxMCkpKS5tYXAoKGU9PmUudmFsdWU/LnZhbHVlKSl9YXN5bmMgZnVuY3Rpb24gJChlLG4sdCxvKXtjb25zdCByPWF3YWl0IGUucG9zdCgiUnVudGltZS5nZXRQcm9wZXJ0aWVzIix7b2JqZWN0SWQ6bixvd25Qcm9wZXJ0aWVzOiEwfSk7b1t0XT1yLnJlc3VsdC5tYXAoKGU9PltlLm5hbWUsZS52YWx1ZT8udmFsdWVdKSkucmVkdWNlKCgoZSxbbix0XSk9PihlW25dPXQsZSkpLHt9KX1mdW5jdGlvbiB3KGUsbil7ZS52YWx1ZSYmKCJ2YWx1ZSJpbiBlLnZhbHVlP3ZvaWQgMD09PWUudmFsdWUudmFsdWV8fG51bGw9PT1lLnZhbHVlLnZhbHVlP25bZS5uYW1lXT1gPCR7ZS52YWx1ZS52YWx1ZX0+YDpuW2UubmFtZV09ZS52YWx1ZS52YWx1ZToiZGVzY3JpcHRpb24iaW4gZS52YWx1ZSYmImZ1bmN0aW9uIiE9PWUudmFsdWUudHlwZT9uW2UubmFtZV09YDwke2UudmFsdWUuZGVzY3JpcHRpb259PmA6InVuZGVmaW5lZCI9PT1lLnZhbHVlLnR5cGUmJihuW2UubmFtZV09Ijx1bmRlZmluZWQ+IikpfWFzeW5jIGZ1bmN0aW9uIHkoZSxuKXtjb25zdCB0PWF3YWl0IGUucG9zdCgiUnVudGltZS5nZXRQcm9wZXJ0aWVzIix7b2JqZWN0SWQ6bixvd25Qcm9wZXJ0aWVzOiEwfSksbz17fTtmb3IoY29uc3QgbiBvZiB0LnJlc3VsdClpZihuPy52YWx1ZT8ub2JqZWN0SWQmJiJBcnJheSI9PT1uPy52YWx1ZS5jbGFzc05hbWUpe2NvbnN0IHQ9bi52YWx1ZS5vYmplY3RJZDthd2FpdCB2KGUsdCxuLm5hbWUsbyl9ZWxzZSBpZihuPy52YWx1ZT8ub2JqZWN0SWQmJiJPYmplY3QiPT09bj8udmFsdWU/LmNsYXNzTmFtZSl7Y29uc3QgdD1uLnZhbHVlLm9iamVjdElkO2F3YWl0ICQoZSx0LG4ubmFtZSxvKX1lbHNlIG4/LnZhbHVlJiZ3KG4sbyk7cmV0dXJuIG99bGV0IGg7KGFzeW5jIGZ1bmN0aW9uKCl7Y29uc3Qgbj1uZXcgZTtuLmNvbm5lY3RUb01haW5UaHJlYWQoKSxiKCJDb25uZWN0ZWQgdG8gbWFpbiB0aHJlYWQiKTtsZXQgbz0hMTtuLm9uKCJEZWJ1Z2dlci5yZXN1bWVkIiwoKCk9PntvPSExfSkpLG4ub24oIkRlYnVnZ2VyLnBhdXNlZCIsKGU9PntvPSEwLGFzeW5jIGZ1bmN0aW9uKGUsbix7cmVhc29uOm8sZGF0YTpyLGNhbGxGcmFtZXM6aX0pe2lmKCJleGNlcHRpb24iIT09byYmInByb21pc2VSZWplY3Rpb24iIT09bylyZXR1cm47aD8uKCk7Y29uc3Qgcz1mdW5jdGlvbihlLG4pe2lmKHZvaWQgMCE9PW4pcmV0dXJuIGZ1bmN0aW9uKGUpe2lmKHZvaWQgMCE9PWUpcmV0dXJuIGUuc2xpY2UoLTEwKS5yZWR1Y2UoKChlLG4pPT5gJHtlfSwke24uZnVuY3Rpb259LCR7bi5saW5lbm99LCR7bi5jb2xub31gKSwiIil9KGUobiwxKSl9KG4scj8uZGVzY3JpcHRpb24pO2lmKG51bGw9PXMpcmV0dXJuO2NvbnN0IGM9W107Zm9yKGxldCBuPTA7bjxpLmxlbmd0aDtuKyspe2NvbnN0e3Njb3BlQ2hhaW46dCxmdW5jdGlvbk5hbWU6byx0aGlzOnJ9PWlbbl0scz10LmZpbmQoKGU9PiJsb2NhbCI9PT1lLnR5cGUpKSxhPSJnbG9iYWwiIT09ci5jbGFzc05hbWUmJnIuY2xhc3NOYW1lP2Ake3IuY2xhc3NOYW1lfS4ke299YDpvO2lmKHZvaWQgMD09PXM/Lm9iamVjdC5vYmplY3RJZCljW25dPXtmdW5jdGlvbjphfTtlbHNle2NvbnN0IHQ9YXdhaXQgeShlLHMub2JqZWN0Lm9iamVjdElkKTtjW25dPXtmdW5jdGlvbjphLHZhcnM6dH19fXQ/LnBvc3RNZXNzYWdlKHtleGNlcHRpb25IYXNoOnMsZnJhbWVzOmN9KX0obixtLGUucGFyYW1zKS50aGVuKCgoKT0+bz9uLnBvc3QoIkRlYnVnZ2VyLnJlc3VtZSIpOlByb21pc2UucmVzb2x2ZSgpKSwoZT0+e30pKX0pKSxhd2FpdCBuLnBvc3QoIkRlYnVnZ2VyLmVuYWJsZSIpO2NvbnN0IHI9ITEhPT1nLmNhcHR1cmVBbGxFeGNlcHRpb25zO2lmKGF3YWl0IG4ucG9zdCgiRGVidWdnZXIuc2V0UGF1c2VPbkV4Y2VwdGlvbnMiLHtzdGF0ZTpyPyJhbGwiOiJ1bmNhdWdodCJ9KSxyKXtjb25zdCBlPWcubWF4RXhjZXB0aW9uc1BlclNlY29uZHx8NTA7aD1mdW5jdGlvbihlLG4sdCl7bGV0IG89MCxyPTUsaT0wO3JldHVybiBzZXRJbnRlcnZhbCgoKCk9PnswPT09aT9vPmUmJihyKj0yLHQocikscj44NjQwMCYmKHI9ODY0MDApLGk9cik6KGktPTEsMD09PWkmJm4oKSksbz0wfSksMWUzKS51bnJlZigpLCgpPT57bys9MX19KGUsKGFzeW5jKCk9PntiKCJSYXRlLWxpbWl0IGxpZnRlZC4iKSxhd2FpdCBuLnBvc3QoIkRlYnVnZ2VyLnNldFBhdXNlT25FeGNlcHRpb25zIix7c3RhdGU6ImFsbCJ9KX0pLChhc3luYyBlPT57YihgUmF0ZS1saW1pdCBleGNlZWRlZC4gRGlzYWJsaW5nIGNhcHR1cmluZyBvZiBjYXVnaHQgZXhjZXB0aW9ucyBmb3IgJHtlfSBzZWNvbmRzLmApLGF3YWl0IG4ucG9zdCgiRGVidWdnZXIuc2V0UGF1c2VPbkV4Y2VwdGlvbnMiLHtzdGF0ZToidW5jYXVnaHQifSl9KSl9fSkoKS5jYXRjaCgoZT0+e2IoIkZhaWxlZCB0byBzdGFydCBkZWJ1Z2dlciIsZSl9KSksc2V0SW50ZXJ2YWwoKCgpPT57fSksMWU0KTs=';
|
|
963
|
+
|
|
964
|
+
function log$1(...args) {
|
|
965
|
+
logger.log('[LocalVariables]', ...args);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* Adds local variables to exception frames
|
|
970
|
+
*/
|
|
971
|
+
const localVariablesAsyncIntegration = defineIntegration(((
|
|
972
|
+
integrationOptions = {},
|
|
973
|
+
) => {
|
|
974
|
+
const cachedFrames = new LRUMap(20);
|
|
975
|
+
|
|
976
|
+
function addLocalVariablesToException(exception) {
|
|
977
|
+
const hash = hashFrames(_optionalChain$9([exception, 'optionalAccess', _ => _.stacktrace, 'optionalAccess', _2 => _2.frames]));
|
|
978
|
+
|
|
979
|
+
if (hash === undefined) {
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// Check if we have local variables for an exception that matches the hash
|
|
984
|
+
// remove is identical to get but also removes the entry from the cache
|
|
985
|
+
const cachedFrame = cachedFrames.remove(hash);
|
|
986
|
+
|
|
987
|
+
if (cachedFrame === undefined) {
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
// Filter out frames where the function name is `new Promise` since these are in the error.stack frames
|
|
992
|
+
// but do not appear in the debugger call frames
|
|
993
|
+
const frames = (_optionalChain$9([exception, 'access', _3 => _3.stacktrace, 'optionalAccess', _4 => _4.frames]) || []).filter(frame => frame.function !== 'new Promise');
|
|
994
|
+
|
|
995
|
+
for (let i = 0; i < frames.length; i++) {
|
|
996
|
+
// Sentry frames are in reverse order
|
|
997
|
+
const frameIndex = frames.length - i - 1;
|
|
998
|
+
|
|
999
|
+
// Drop out if we run out of frames to match up
|
|
1000
|
+
if (!frames[frameIndex] || !cachedFrame[i]) {
|
|
1001
|
+
break;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
if (
|
|
1005
|
+
// We need to have vars to add
|
|
1006
|
+
cachedFrame[i].vars === undefined ||
|
|
1007
|
+
// We're not interested in frames that are not in_app because the vars are not relevant
|
|
1008
|
+
frames[frameIndex].in_app === false ||
|
|
1009
|
+
// The function names need to match
|
|
1010
|
+
!functionNamesMatch(frames[frameIndex].function, cachedFrame[i].function)
|
|
1011
|
+
) {
|
|
1012
|
+
continue;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
frames[frameIndex].vars = cachedFrame[i].vars;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
function addLocalVariablesToEvent(event) {
|
|
1020
|
+
for (const exception of _optionalChain$9([event, 'access', _5 => _5.exception, 'optionalAccess', _6 => _6.values]) || []) {
|
|
1021
|
+
addLocalVariablesToException(exception);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
return event;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
async function startInspector() {
|
|
1028
|
+
// We load inspector dynamically because on some platforms Node is built without inspector support
|
|
1029
|
+
const inspector = await import('inspector');
|
|
1030
|
+
if (!inspector.url()) {
|
|
1031
|
+
inspector.open(0);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
function startWorker(options) {
|
|
1036
|
+
const worker = new Worker(new URL(`data:application/javascript;base64,${base64WorkerScript$1}`), {
|
|
1037
|
+
workerData: options,
|
|
1038
|
+
});
|
|
1039
|
+
|
|
1040
|
+
process.on('exit', () => {
|
|
1041
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1042
|
+
worker.terminate();
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
worker.on('message', ({ exceptionHash, frames }) => {
|
|
1046
|
+
cachedFrames.set(exceptionHash, frames);
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
worker.once('error', (err) => {
|
|
1050
|
+
log$1('Worker error', err);
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
worker.once('exit', (code) => {
|
|
1054
|
+
log$1('Worker exit', code);
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
// Ensure this thread can't block app exit
|
|
1058
|
+
worker.unref();
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
return {
|
|
1062
|
+
name: 'LocalVariablesAsync',
|
|
1063
|
+
setup(client) {
|
|
1064
|
+
const clientOptions = client.getOptions();
|
|
1065
|
+
|
|
1066
|
+
if (!clientOptions.includeLocalVariables) {
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
const options = {
|
|
1071
|
+
...integrationOptions,
|
|
1072
|
+
debug: logger.isEnabled(),
|
|
1073
|
+
};
|
|
1074
|
+
|
|
1075
|
+
startInspector().then(
|
|
1076
|
+
() => {
|
|
1077
|
+
try {
|
|
1078
|
+
startWorker(options);
|
|
1079
|
+
} catch (e) {
|
|
1080
|
+
logger.error('Failed to start worker', e);
|
|
1081
|
+
}
|
|
1082
|
+
},
|
|
1083
|
+
e => {
|
|
1084
|
+
logger.error('Failed to start inspector', e);
|
|
1085
|
+
},
|
|
1086
|
+
);
|
|
1087
|
+
},
|
|
1088
|
+
processEvent(event) {
|
|
1089
|
+
return addLocalVariablesToEvent(event);
|
|
1090
|
+
},
|
|
1091
|
+
};
|
|
1092
|
+
}) );
|
|
1093
|
+
|
|
1094
|
+
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; }
|
|
935
1095
|
/** Creates a container for callbacks to be called sequentially */
|
|
936
1096
|
function createCallbackList(complete) {
|
|
937
1097
|
// A collection of callbacks to be executed last to first
|
|
@@ -1009,13 +1169,13 @@ class AsyncSession {
|
|
|
1009
1169
|
const { add, next } = createCallbackList(complete);
|
|
1010
1170
|
|
|
1011
1171
|
for (const prop of props) {
|
|
1012
|
-
if (_optionalChain$
|
|
1172
|
+
if (_optionalChain$8([prop, 'optionalAccess', _2 => _2.value, 'optionalAccess', _3 => _3.objectId]) && _optionalChain$8([prop, 'optionalAccess', _4 => _4.value, 'access', _5 => _5.className]) === 'Array') {
|
|
1013
1173
|
const id = prop.value.objectId;
|
|
1014
1174
|
add(vars => this._unrollArray(id, prop.name, vars, next));
|
|
1015
|
-
} else if (_optionalChain$
|
|
1175
|
+
} else if (_optionalChain$8([prop, 'optionalAccess', _6 => _6.value, 'optionalAccess', _7 => _7.objectId]) && _optionalChain$8([prop, 'optionalAccess', _8 => _8.value, 'optionalAccess', _9 => _9.className]) === 'Object') {
|
|
1016
1176
|
const id = prop.value.objectId;
|
|
1017
1177
|
add(vars => this._unrollObject(id, prop.name, vars, next));
|
|
1018
|
-
} else if (_optionalChain$
|
|
1178
|
+
} else if (_optionalChain$8([prop, 'optionalAccess', _10 => _10.value])) {
|
|
1019
1179
|
add(vars => this._unrollOther(prop, vars, next));
|
|
1020
1180
|
}
|
|
1021
1181
|
}
|
|
@@ -1052,7 +1212,7 @@ class AsyncSession {
|
|
|
1052
1212
|
vars[name] = props
|
|
1053
1213
|
.filter(v => v.name !== 'length' && !isNaN(parseInt(v.name, 10)))
|
|
1054
1214
|
.sort((a, b) => parseInt(a.name, 10) - parseInt(b.name, 10))
|
|
1055
|
-
.map(v => _optionalChain$
|
|
1215
|
+
.map(v => _optionalChain$8([v, 'optionalAccess', _11 => _11.value, 'optionalAccess', _12 => _12.value]));
|
|
1056
1216
|
|
|
1057
1217
|
next(vars);
|
|
1058
1218
|
});
|
|
@@ -1064,7 +1224,7 @@ class AsyncSession {
|
|
|
1064
1224
|
_unrollObject(objectId, name, vars, next) {
|
|
1065
1225
|
this._getProperties(objectId, props => {
|
|
1066
1226
|
vars[name] = props
|
|
1067
|
-
.map(v => [v.name, _optionalChain$
|
|
1227
|
+
.map(v => [v.name, _optionalChain$8([v, 'optionalAccess', _13 => _13.value, 'optionalAccess', _14 => _14.value])])
|
|
1068
1228
|
.reduce((obj, [key, val]) => {
|
|
1069
1229
|
obj[key] = val;
|
|
1070
1230
|
return obj;
|
|
@@ -1131,10 +1291,10 @@ const _localVariablesSyncIntegration = ((
|
|
|
1131
1291
|
return;
|
|
1132
1292
|
}
|
|
1133
1293
|
|
|
1134
|
-
_optionalChain$
|
|
1294
|
+
_optionalChain$8([rateLimiter, 'optionalCall', _15 => _15()]);
|
|
1135
1295
|
|
|
1136
1296
|
// data.description contains the original error.stack
|
|
1137
|
-
const exceptionHash = hashFromStack(stackParser, _optionalChain$
|
|
1297
|
+
const exceptionHash = hashFromStack(stackParser, _optionalChain$8([data, 'optionalAccess', _16 => _16.description]));
|
|
1138
1298
|
|
|
1139
1299
|
if (exceptionHash == undefined) {
|
|
1140
1300
|
complete();
|
|
@@ -1156,7 +1316,7 @@ const _localVariablesSyncIntegration = ((
|
|
|
1156
1316
|
// obj.className is undefined in ESM modules
|
|
1157
1317
|
const fn = obj.className === 'global' || !obj.className ? functionName : `${obj.className}.${functionName}`;
|
|
1158
1318
|
|
|
1159
|
-
if (_optionalChain$
|
|
1319
|
+
if (_optionalChain$8([localScope, 'optionalAccess', _17 => _17.object, 'access', _18 => _18.objectId]) === undefined) {
|
|
1160
1320
|
add(frames => {
|
|
1161
1321
|
frames[i] = { function: fn };
|
|
1162
1322
|
next(frames);
|
|
@@ -1164,7 +1324,7 @@ const _localVariablesSyncIntegration = ((
|
|
|
1164
1324
|
} else {
|
|
1165
1325
|
const id = localScope.object.objectId;
|
|
1166
1326
|
add(frames =>
|
|
1167
|
-
_optionalChain$
|
|
1327
|
+
_optionalChain$8([session, 'optionalAccess', _19 => _19.getLocalVariables, 'call', _20 => _20(id, vars => {
|
|
1168
1328
|
frames[i] = { function: fn, vars };
|
|
1169
1329
|
next(frames);
|
|
1170
1330
|
})]),
|
|
@@ -1176,7 +1336,7 @@ const _localVariablesSyncIntegration = ((
|
|
|
1176
1336
|
}
|
|
1177
1337
|
|
|
1178
1338
|
function addLocalVariablesToException(exception) {
|
|
1179
|
-
const hash = hashFrames(_optionalChain$
|
|
1339
|
+
const hash = hashFrames(_optionalChain$8([exception, 'optionalAccess', _21 => _21.stacktrace, 'optionalAccess', _22 => _22.frames]));
|
|
1180
1340
|
|
|
1181
1341
|
if (hash === undefined) {
|
|
1182
1342
|
return;
|
|
@@ -1192,7 +1352,7 @@ const _localVariablesSyncIntegration = ((
|
|
|
1192
1352
|
|
|
1193
1353
|
// Filter out frames where the function name is `new Promise` since these are in the error.stack frames
|
|
1194
1354
|
// but do not appear in the debugger call frames
|
|
1195
|
-
const frames = (_optionalChain$
|
|
1355
|
+
const frames = (_optionalChain$8([exception, 'access', _23 => _23.stacktrace, 'optionalAccess', _24 => _24.frames]) || []).filter(frame => frame.function !== 'new Promise');
|
|
1196
1356
|
|
|
1197
1357
|
for (let i = 0; i < frames.length; i++) {
|
|
1198
1358
|
// Sentry frames are in reverse order
|
|
@@ -1219,7 +1379,7 @@ const _localVariablesSyncIntegration = ((
|
|
|
1219
1379
|
}
|
|
1220
1380
|
|
|
1221
1381
|
function addLocalVariablesToEvent(event) {
|
|
1222
|
-
for (const exception of _optionalChain$
|
|
1382
|
+
for (const exception of _optionalChain$8([event, 'optionalAccess', _25 => _25.exception, 'optionalAccess', _26 => _26.values]) || []) {
|
|
1223
1383
|
addLocalVariablesToException(exception);
|
|
1224
1384
|
}
|
|
1225
1385
|
|
|
@@ -1230,9 +1390,9 @@ const _localVariablesSyncIntegration = ((
|
|
|
1230
1390
|
name: INTEGRATION_NAME$5,
|
|
1231
1391
|
setupOnce() {
|
|
1232
1392
|
const client = getClient$1();
|
|
1233
|
-
const clientOptions = _optionalChain$
|
|
1393
|
+
const clientOptions = _optionalChain$8([client, 'optionalAccess', _27 => _27.getOptions, 'call', _28 => _28()]);
|
|
1234
1394
|
|
|
1235
|
-
if (session && _optionalChain$
|
|
1395
|
+
if (session && _optionalChain$8([clientOptions, 'optionalAccess', _29 => _29.includeLocalVariables])) {
|
|
1236
1396
|
// Only setup this integration if the Node version is >= v18
|
|
1237
1397
|
// https://github.com/getsentry/sentry-javascript/issues/7697
|
|
1238
1398
|
const unsupportedNodeVersion = NODE_MAJOR < 18;
|
|
@@ -1257,13 +1417,13 @@ const _localVariablesSyncIntegration = ((
|
|
|
1257
1417
|
max,
|
|
1258
1418
|
() => {
|
|
1259
1419
|
logger.log('Local variables rate-limit lifted.');
|
|
1260
|
-
_optionalChain$
|
|
1420
|
+
_optionalChain$8([session, 'optionalAccess', _30 => _30.setPauseOnExceptions, 'call', _31 => _31(true)]);
|
|
1261
1421
|
},
|
|
1262
1422
|
seconds => {
|
|
1263
1423
|
logger.log(
|
|
1264
1424
|
`Local variables rate-limit exceeded. Disabling capturing of caught exceptions for ${seconds} seconds.`,
|
|
1265
1425
|
);
|
|
1266
|
-
_optionalChain$
|
|
1426
|
+
_optionalChain$8([session, 'optionalAccess', _32 => _32.setPauseOnExceptions, 'call', _33 => _33(false)]);
|
|
1267
1427
|
},
|
|
1268
1428
|
);
|
|
1269
1429
|
}
|
|
@@ -1293,7 +1453,9 @@ const _localVariablesSyncIntegration = ((
|
|
|
1293
1453
|
*/
|
|
1294
1454
|
const localVariablesSyncIntegration = defineIntegration(_localVariablesSyncIntegration);
|
|
1295
1455
|
|
|
1296
|
-
const localVariablesIntegration =
|
|
1456
|
+
const localVariablesIntegration = (options = {}) => {
|
|
1457
|
+
return NODE_VERSION.major < 19 ? localVariablesSyncIntegration(options) : localVariablesAsyncIntegration(options);
|
|
1458
|
+
};
|
|
1297
1459
|
|
|
1298
1460
|
let moduleCache;
|
|
1299
1461
|
|
|
@@ -1424,24 +1586,22 @@ function logAndExitProcess(error) {
|
|
|
1424
1586
|
|
|
1425
1587
|
const INTEGRATION_NAME$3 = 'OnUncaughtException';
|
|
1426
1588
|
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1589
|
+
/**
|
|
1590
|
+
* Add a global exception handler.
|
|
1591
|
+
*/
|
|
1592
|
+
const onUncaughtExceptionIntegration = defineIntegration((options = {}) => {
|
|
1593
|
+
const optionsWithDefaults = {
|
|
1594
|
+
exitEvenIfOtherHandlersAreRegistered: false,
|
|
1430
1595
|
...options,
|
|
1431
1596
|
};
|
|
1432
1597
|
|
|
1433
1598
|
return {
|
|
1434
1599
|
name: INTEGRATION_NAME$3,
|
|
1435
1600
|
setup(client) {
|
|
1436
|
-
global.process.on('uncaughtException', makeErrorHandler(client,
|
|
1601
|
+
global.process.on('uncaughtException', makeErrorHandler(client, optionsWithDefaults));
|
|
1437
1602
|
},
|
|
1438
1603
|
};
|
|
1439
|
-
})
|
|
1440
|
-
|
|
1441
|
-
/**
|
|
1442
|
-
* Add a global exception handler.
|
|
1443
|
-
*/
|
|
1444
|
-
const onUncaughtExceptionIntegration = defineIntegration(_onUncaughtExceptionIntegration);
|
|
1604
|
+
});
|
|
1445
1605
|
|
|
1446
1606
|
/** Exported only for tests */
|
|
1447
1607
|
function makeErrorHandler(client, options) {
|
|
@@ -1630,10 +1790,10 @@ function handleRejection(
|
|
|
1630
1790
|
/* eslint-enable no-console */
|
|
1631
1791
|
}
|
|
1632
1792
|
|
|
1793
|
+
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; }
|
|
1633
1794
|
// This string is a placeholder that gets overwritten with the worker code.
|
|
1634
|
-
const base64WorkerScript = 'aW1wb3J0IHsgU2Vzc2lvbiB9IGZyb20gJ2luc3BlY3Rvcic7CmltcG9ydCB7IHdvcmtlckRhdGEsIHBhcmVudFBvcnQgfSBmcm9tICd3b3JrZXJfdGhyZWFkcyc7CmltcG9ydCB7IHBvc2l4LCBzZXAgfSBmcm9tICdwYXRoJzsKaW1wb3J0ICogYXMgaHR0cCQxIGZyb20gJ25vZGU6aHR0cCc7CmltcG9ydCAqIGFzIGh0dHBzIGZyb20gJ25vZGU6aHR0cHMnOwppbXBvcnQgeyBSZWFkYWJsZSB9IGZyb20gJ3N0cmVhbSc7CmltcG9ydCB7IGNyZWF0ZUd6aXAgfSBmcm9tICd6bGliJzsKaW1wb3J0ICogYXMgbmV0IGZyb20gJ25ldCc7CmltcG9ydCAqIGFzIHRscyBmcm9tICd0bHMnOwppbXBvcnQgKiBhcyBodHRwIGZyb20gJ2h0dHAnOwoKLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC91bmJvdW5kLW1ldGhvZApjb25zdCBvYmplY3RUb1N0cmluZyA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmc7CgovKioKICogQ2hlY2tzIHdoZXRoZXIgZ2l2ZW4gdmFsdWUncyB0eXBlIGlzIG9uZSBvZiBhIGZldyBFcnJvciBvciBFcnJvci1saWtlCiAqIHtAbGluayBpc0Vycm9yfS4KICoKICogQHBhcmFtIHdhdCBBIHZhbHVlIHRvIGJlIGNoZWNrZWQuCiAqIEByZXR1cm5zIEEgYm9vbGVhbiByZXByZXNlbnRpbmcgdGhlIHJlc3VsdC4KICovCmZ1bmN0aW9uIGlzRXJyb3Iod2F0KSB7CiAgc3dpdGNoIChvYmplY3RUb1N0cmluZy5jYWxsKHdhdCkpIHsKICAgIGNhc2UgJ1tvYmplY3QgRXJyb3JdJzoKICAgIGNhc2UgJ1tvYmplY3QgRXhjZXB0aW9uXSc6CiAgICBjYXNlICdbb2JqZWN0IERPTUV4Y2VwdGlvbl0nOgogICAgICByZXR1cm4gdHJ1ZTsKICAgIGRlZmF1bHQ6CiAgICAgIHJldHVybiBpc0luc3RhbmNlT2Yod2F0LCBFcnJvcik7CiAgfQp9Ci8qKgogKiBDaGVja3Mgd2hldGhlciBnaXZlbiB2YWx1ZSBpcyBhbiBpbnN0YW5jZSBvZiB0aGUgZ2l2ZW4gYnVpbHQtaW4gY2xhc3MuCiAqCiAqIEBwYXJhbSB3YXQgVGhlIHZhbHVlIHRvIGJlIGNoZWNrZWQKICogQHBhcmFtIGNsYXNzTmFtZQogKiBAcmV0dXJucyBBIGJvb2xlYW4gcmVwcmVzZW50aW5nIHRoZSByZXN1bHQuCiAqLwpmdW5jdGlvbiBpc0J1aWx0aW4od2F0LCBjbGFzc05hbWUpIHsKICByZXR1cm4gb2JqZWN0VG9TdHJpbmcuY2FsbCh3YXQpID09PSBgW29iamVjdCAke2NsYXNzTmFtZX1dYDsKfQoKLyoqCiAqIENoZWNrcyB3aGV0aGVyIGdpdmVuIHZhbHVlJ3MgdHlwZSBpcyBhIHN0cmluZwogKiB7QGxpbmsgaXNTdHJpbmd9LgogKgogKiBAcGFyYW0gd2F0IEEgdmFsdWUgdG8gYmUgY2hlY2tlZC4KICogQHJldHVybnMgQSBib29sZWFuIHJlcHJlc2VudGluZyB0aGUgcmVzdWx0LgogKi8KZnVuY3Rpb24gaXNTdHJpbmcod2F0KSB7CiAgcmV0dXJuIGlzQnVpbHRpbih3YXQsICdTdHJpbmcnKTsKfQoKLyoqCiAqIENoZWNrcyB3aGV0aGVyIGdpdmVuIHZhbHVlJ3MgdHlwZSBpcyBhbiBvYmplY3QgbGl0ZXJhbCwgb3IgYSBjbGFzcyBpbnN0YW5jZS4KICoge0BsaW5rIGlzUGxhaW5PYmplY3R9LgogKgogKiBAcGFyYW0gd2F0IEEgdmFsdWUgdG8gYmUgY2hlY2tlZC4KICogQHJldHVybnMgQSBib29sZWFuIHJlcHJlc2VudGluZyB0aGUgcmVzdWx0LgogKi8KZnVuY3Rpb24gaXNQbGFpbk9iamVjdCh3YXQpIHsKICByZXR1cm4gaXNCdWlsdGluKHdhdCwgJ09iamVjdCcpOwp9CgovKioKICogQ2hlY2tzIHdoZXRoZXIgZ2l2ZW4gdmFsdWUncyB0eXBlIGlzIGFuIEV2ZW50IGluc3RhbmNlCiAqIHtAbGluayBpc0V2ZW50fS4KICoKICogQHBhcmFtIHdhdCBBIHZhbHVlIHRvIGJlIGNoZWNrZWQuCiAqIEByZXR1cm5zIEEgYm9vbGVhbiByZXByZXNlbnRpbmcgdGhlIHJlc3VsdC4KICovCmZ1bmN0aW9uIGlzRXZlbnQod2F0KSB7CiAgcmV0dXJuIHR5cGVvZiBFdmVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgaXNJbnN0YW5jZU9mKHdhdCwgRXZlbnQpOwp9CgovKioKICogQ2hlY2tzIHdoZXRoZXIgZ2l2ZW4gdmFsdWUncyB0eXBlIGlzIGFuIEVsZW1lbnQgaW5zdGFuY2UKICoge0BsaW5rIGlzRWxlbWVudH0uCiAqCiAqIEBwYXJhbSB3YXQgQSB2YWx1ZSB0byBiZSBjaGVja2VkLgogKiBAcmV0dXJucyBBIGJvb2xlYW4gcmVwcmVzZW50aW5nIHRoZSByZXN1bHQuCiAqLwpmdW5jdGlvbiBpc0VsZW1lbnQod2F0KSB7CiAgcmV0dXJuIHR5cGVvZiBFbGVtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpc0luc3RhbmNlT2Yod2F0LCBFbGVtZW50KTsKfQoKLyoqCiAqIENoZWNrcyB3aGV0aGVyIGdpdmVuIHZhbHVlIGhhcyBhIHRoZW4gZnVuY3Rpb24uCiAqIEBwYXJhbSB3YXQgQSB2YWx1ZSB0byBiZSBjaGVja2VkLgogKi8KZnVuY3Rpb24gaXNUaGVuYWJsZSh3YXQpIHsKICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1tZW1iZXItYWNjZXNzCiAgcmV0dXJuIEJvb2xlYW4od2F0ICYmIHdhdC50aGVuICYmIHR5cGVvZiB3YXQudGhlbiA9PT0gJ2Z1bmN0aW9uJyk7Cn0KCi8qKgogKiBDaGVja3Mgd2hldGhlciBnaXZlbiB2YWx1ZSdzIHR5cGUgaXMgYSBTeW50aGV0aWNFdmVudAogKiB7QGxpbmsgaXNTeW50aGV0aWNFdmVudH0uCiAqCiAqIEBwYXJhbSB3YXQgQSB2YWx1ZSB0byBiZSBjaGVja2VkLgogKiBAcmV0dXJucyBBIGJvb2xlYW4gcmVwcmVzZW50aW5nIHRoZSByZXN1bHQuCiAqLwpmdW5jdGlvbiBpc1N5bnRoZXRpY0V2ZW50KHdhdCkgewogIHJldHVybiBpc1BsYWluT2JqZWN0KHdhdCkgJiYgJ25hdGl2ZUV2ZW50JyBpbiB3YXQgJiYgJ3ByZXZlbnREZWZhdWx0JyBpbiB3YXQgJiYgJ3N0b3BQcm9wYWdhdGlvbicgaW4gd2F0Owp9CgovKioKICogQ2hlY2tzIHdoZXRoZXIgZ2l2ZW4gdmFsdWUncyB0eXBlIGlzIGFuIGluc3RhbmNlIG9mIHByb3ZpZGVkIGNvbnN0cnVjdG9yLgogKiB7QGxpbmsgaXNJbnN0YW5jZU9mfS4KICoKICogQHBhcmFtIHdhdCBBIHZhbHVlIHRvIGJlIGNoZWNrZWQuCiAqIEBwYXJhbSBiYXNlIEEgY29uc3RydWN0b3IgdG8gYmUgdXNlZCBpbiBhIGNoZWNrLgogKiBAcmV0dXJucyBBIGJvb2xlYW4gcmVwcmVzZW50aW5nIHRoZSByZXN1bHQuCiAqLwpmdW5jdGlvbiBpc0luc3RhbmNlT2Yod2F0LCBiYXNlKSB7CiAgdHJ5IHsKICAgIHJldHVybiB3YXQgaW5zdGFuY2VvZiBiYXNlOwogIH0gY2F0Y2ggKF9lKSB7CiAgICByZXR1cm4gZmFsc2U7CiAgfQp9CgovKioKICogQ2hlY2tzIHdoZXRoZXIgZ2l2ZW4gdmFsdWUncyB0eXBlIGlzIGEgVnVlIFZpZXdNb2RlbC4KICoKICogQHBhcmFtIHdhdCBBIHZhbHVlIHRvIGJlIGNoZWNrZWQuCiAqIEByZXR1cm5zIEEgYm9vbGVhbiByZXByZXNlbnRpbmcgdGhlIHJlc3VsdC4KICovCmZ1bmN0aW9uIGlzVnVlVmlld01vZGVsKHdhdCkgewogIC8vIE5vdCB1c2luZyBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nIGJlY2F1c2UgaW4gVnVlIDMgaXQgd291bGQgcmVhZCB0aGUgaW5zdGFuY2UncyBTeW1ib2woU3ltYm9sLnRvU3RyaW5nVGFnKSBwcm9wZXJ0eS4KICByZXR1cm4gISEodHlwZW9mIHdhdCA9PT0gJ29iamVjdCcgJiYgd2F0ICE9PSBudWxsICYmICgod2F0ICkuX19pc1Z1ZSB8fCAod2F0ICkuX2lzVnVlKSk7Cn0KCi8qKiBJbnRlcm5hbCBnbG9iYWwgd2l0aCBjb21tb24gcHJvcGVydGllcyBhbmQgU2VudHJ5IGV4dGVuc2lvbnMgICovCgovKiogR2V0J3MgdGhlIGdsb2JhbCBvYmplY3QgZm9yIHRoZSBjdXJyZW50IEphdmFTY3JpcHQgcnVudGltZSAqLwpjb25zdCBHTE9CQUxfT0JKID0gZ2xvYmFsVGhpcyA7CgovKioKICogUmV0dXJucyBhIGdsb2JhbCBzaW5nbGV0b24gY29udGFpbmVkIGluIHRoZSBnbG9iYWwgYF9fU0VOVFJZX19gIG9iamVjdC4KICoKICogSWYgdGhlIHNpbmdsZXRvbiBkb2Vzbid0IGFscmVhZHkgZXhpc3QgaW4gYF9fU0VOVFJZX19gLCBpdCB3aWxsIGJlIGNyZWF0ZWQgdXNpbmcgdGhlIGdpdmVuIGZhY3RvcnkKICogZnVuY3Rpb24gYW5kIGFkZGVkIHRvIHRoZSBgX19TRU5UUllfX2Agb2JqZWN0LgogKgogKiBAcGFyYW0gbmFtZSBuYW1lIG9mIHRoZSBnbG9iYWwgc2luZ2xldG9uIG9uIF9fU0VOVFJZX18KICogQHBhcmFtIGNyZWF0b3IgY3JlYXRvciBGYWN0b3J5IGZ1bmN0aW9uIHRvIGNyZWF0ZSB0aGUgc2luZ2xldG9uIGlmIGl0IGRvZXNuJ3QgYWxyZWFkeSBleGlzdCBvbiBgX19TRU5UUllfX2AKICogQHBhcmFtIG9iaiAoT3B0aW9uYWwpIFRoZSBnbG9iYWwgb2JqZWN0IG9uIHdoaWNoIHRvIGxvb2sgZm9yIGBfX1NFTlRSWV9fYCwgaWYgbm90IGBHTE9CQUxfT0JKYCdzIHJldHVybiB2YWx1ZQogKiBAcmV0dXJucyB0aGUgc2luZ2xldG9uCiAqLwpmdW5jdGlvbiBnZXRHbG9iYWxTaW5nbGV0b24obmFtZSwgY3JlYXRvciwgb2JqKSB7CiAgY29uc3QgZ2JsID0gKG9iaiB8fCBHTE9CQUxfT0JKKSA7CiAgY29uc3QgX19TRU5UUllfXyA9IChnYmwuX19TRU5UUllfXyA9IGdibC5fX1NFTlRSWV9fIHx8IHt9KTsKICBjb25zdCBzaW5nbGV0b24gPSBfX1NFTlRSWV9fW25hbWVdIHx8IChfX1NFTlRSWV9fW25hbWVdID0gY3JlYXRvcigpKTsKICByZXR1cm4gc2luZ2xldG9uOwp9Cgpjb25zdCBXSU5ET1cgPSBHTE9CQUxfT0JKIDsKCmNvbnN0IERFRkFVTFRfTUFYX1NUUklOR19MRU5HVEggPSA4MDsKCi8qKgogKiBHaXZlbiBhIGNoaWxkIERPTSBlbGVtZW50LCByZXR1cm5zIGEgcXVlcnktc2VsZWN0b3Igc3RhdGVtZW50IGRlc2NyaWJpbmcgdGhhdAogKiBhbmQgaXRzIGFuY2VzdG9ycwogKiBlLmcuIFtIVE1MRWxlbWVudF0gPT4gYm9keSA+IGRpdiA+IGlucHV0I2Zvby5idG5bbmFtZT1iYXpdCiAqIEByZXR1cm5zIGdlbmVyYXRlZCBET00gcGF0aAogKi8KZnVuY3Rpb24gaHRtbFRyZWVBc1N0cmluZygKICBlbGVtLAogIG9wdGlvbnMgPSB7fSwKKSB7CiAgaWYgKCFlbGVtKSB7CiAgICByZXR1cm4gJzx1bmtub3duPic7CiAgfQoKICAvLyB0cnkvY2F0Y2ggYm90aDoKICAvLyAtIGFjY2Vzc2luZyBldmVudC50YXJnZXQgKHNlZSBnZXRzZW50cnkvcmF2ZW4tanMjODM4LCAjNzY4KQogIC8vIC0gYGh0bWxUcmVlQXNTdHJpbmdgIGJlY2F1c2UgaXQncyBjb21wbGV4LCBhbmQganVzdCBhY2Nlc3NpbmcgdGhlIERPTSBpbmNvcnJlY3RseQogIC8vIC0gY2FuIHRocm93IGFuIGV4Y2VwdGlvbiBpbiBzb21lIGNpcmN1bXN0YW5jZXMuCiAgdHJ5IHsKICAgIGxldCBjdXJyZW50RWxlbSA9IGVsZW0gOwogICAgY29uc3QgTUFYX1RSQVZFUlNFX0hFSUdIVCA9IDU7CiAgICBjb25zdCBvdXQgPSBbXTsKICAgIGxldCBoZWlnaHQgPSAwOwogICAgbGV0IGxlbiA9IDA7CiAgICBjb25zdCBzZXBhcmF0b3IgPSAnID4gJzsKICAgIGNvbnN0IHNlcExlbmd0aCA9IHNlcGFyYXRvci5sZW5ndGg7CiAgICBsZXQgbmV4dFN0cjsKICAgIGNvbnN0IGtleUF0dHJzID0gQXJyYXkuaXNBcnJheShvcHRpb25zKSA/IG9wdGlvbnMgOiBvcHRpb25zLmtleUF0dHJzOwogICAgY29uc3QgbWF4U3RyaW5nTGVuZ3RoID0gKCFBcnJheS5pc0FycmF5KG9wdGlvbnMpICYmIG9wdGlvbnMubWF4U3RyaW5nTGVuZ3RoKSB8fCBERUZBVUxUX01BWF9TVFJJTkdfTEVOR1RIOwoKICAgIHdoaWxlIChjdXJyZW50RWxlbSAmJiBoZWlnaHQrKyA8IE1BWF9UUkFWRVJTRV9IRUlHSFQpIHsKICAgICAgbmV4dFN0ciA9IF9odG1sRWxlbWVudEFzU3RyaW5nKGN1cnJlbnRFbGVtLCBrZXlBdHRycyk7CiAgICAgIC8vIGJhaWwgb3V0IGlmCiAgICAgIC8vIC0gbmV4dFN0ciBpcyB0aGUgJ2h0bWwnIGVsZW1lbnQKICAgICAgLy8gLSB0aGUgbGVuZ3RoIG9mIHRoZSBzdHJpbmcgdGhhdCB3b3VsZCBiZSBjcmVhdGVkIGV4Y2VlZHMgbWF4U3RyaW5nTGVuZ3RoCiAgICAgIC8vICAgKGlnbm9yZSB0aGlzIGxpbWl0IGlmIHdlIGFyZSBvbiB0aGUgZmlyc3QgaXRlcmF0aW9uKQogICAgICBpZiAobmV4dFN0ciA9PT0gJ2h0bWwnIHx8IChoZWlnaHQgPiAxICYmIGxlbiArIG91dC5sZW5ndGggKiBzZXBMZW5ndGggKyBuZXh0U3RyLmxlbmd0aCA+PSBtYXhTdHJpbmdMZW5ndGgpKSB7CiAgICAgICAgYnJlYWs7CiAgICAgIH0KCiAgICAgIG91dC5wdXNoKG5leHRTdHIpOwoKICAgICAgbGVuICs9IG5leHRTdHIubGVuZ3RoOwogICAgICBjdXJyZW50RWxlbSA9IGN1cnJlbnRFbGVtLnBhcmVudE5vZGU7CiAgICB9CgogICAgcmV0dXJuIG91dC5yZXZlcnNlKCkuam9pbihzZXBhcmF0b3IpOwogIH0gY2F0Y2ggKF9vTykgewogICAgcmV0dXJuICc8dW5rbm93bj4nOwogIH0KfQoKLyoqCiAqIFJldHVybnMgYSBzaW1wbGUsIHF1ZXJ5LXNlbGVjdG9yIHJlcHJlc2VudGF0aW9uIG9mIGEgRE9NIGVsZW1lbnQKICogZS5nLiBbSFRNTEVsZW1lbnRdID0+IGlucHV0I2Zvby5idG5bbmFtZT1iYXpdCiAqIEByZXR1cm5zIGdlbmVyYXRlZCBET00gcGF0aAogKi8KZnVuY3Rpb24gX2h0bWxFbGVtZW50QXNTdHJpbmcoZWwsIGtleUF0dHJzKSB7CiAgY29uc3QgZWxlbSA9IGVsCgo7CgogIGNvbnN0IG91dCA9IFtdOwogIGxldCBjbGFzc05hbWU7CiAgbGV0IGNsYXNzZXM7CiAgbGV0IGtleTsKICBsZXQgYXR0cjsKICBsZXQgaTsKCiAgaWYgKCFlbGVtIHx8ICFlbGVtLnRhZ05hbWUpIHsKICAgIHJldHVybiAnJzsKICB9CgogIC8vIEB0cy1leHBlY3QtZXJyb3IgV0lORE9XIGhhcyBIVE1MRWxlbWVudAogIGlmIChXSU5ET1cuSFRNTEVsZW1lbnQpIHsKICAgIC8vIElmIHVzaW5nIHRoZSBjb21wb25lbnQgbmFtZSBhbm5vdGF0aW9uIHBsdWdpbiwgdGhpcyB2YWx1ZSBtYXkgYmUgYXZhaWxhYmxlIG9uIHRoZSBET00gbm9kZQogICAgaWYgKGVsZW0gaW5zdGFuY2VvZiBIVE1MRWxlbWVudCAmJiBlbGVtLmRhdGFzZXQpIHsKICAgICAgaWYgKGVsZW0uZGF0YXNldFsnc2VudHJ5Q29tcG9uZW50J10pIHsKICAgICAgICByZXR1cm4gZWxlbS5kYXRhc2V0WydzZW50cnlDb21wb25lbnQnXTsKICAgICAgfQogICAgICBpZiAoZWxlbS5kYXRhc2V0WydzZW50cnlFbGVtZW50J10pIHsKICAgICAgICByZXR1cm4gZWxlbS5kYXRhc2V0WydzZW50cnlFbGVtZW50J107CiAgICAgIH0KICAgIH0KICB9CgogIG91dC5wdXNoKGVsZW0udGFnTmFtZS50b0xvd2VyQ2FzZSgpKTsKCiAgLy8gUGFpcnMgb2YgYXR0cmlidXRlIGtleXMgZGVmaW5lZCBpbiBgc2VyaWFsaXplQXR0cmlidXRlYCBhbmQgdGhlaXIgdmFsdWVzIG9uIGVsZW1lbnQuCiAgY29uc3Qga2V5QXR0clBhaXJzID0KICAgIGtleUF0dHJzICYmIGtleUF0dHJzLmxlbmd0aAogICAgICA/IGtleUF0dHJzLmZpbHRlcihrZXlBdHRyID0+IGVsZW0uZ2V0QXR0cmlidXRlKGtleUF0dHIpKS5tYXAoa2V5QXR0ciA9PiBba2V5QXR0ciwgZWxlbS5nZXRBdHRyaWJ1dGUoa2V5QXR0cildKQogICAgICA6IG51bGw7CgogIGlmIChrZXlBdHRyUGFpcnMgJiYga2V5QXR0clBhaXJzLmxlbmd0aCkgewogICAga2V5QXR0clBhaXJzLmZvckVhY2goa2V5QXR0clBhaXIgPT4gewogICAgICBvdXQucHVzaChgWyR7a2V5QXR0clBhaXJbMF19PSIke2tleUF0dHJQYWlyWzFdfSJdYCk7CiAgICB9KTsKICB9IGVsc2UgewogICAgaWYgKGVsZW0uaWQpIHsKICAgICAgb3V0LnB1c2goYCMke2VsZW0uaWR9YCk7CiAgICB9CgogICAgY2xhc3NOYW1lID0gZWxlbS5jbGFzc05hbWU7CiAgICBpZiAoY2xhc3NOYW1lICYmIGlzU3RyaW5nKGNsYXNzTmFtZSkpIHsKICAgICAgY2xhc3NlcyA9IGNsYXNzTmFtZS5zcGxpdCgvXHMrLyk7CiAgICAgIGZvciAoaSA9IDA7IGkgPCBjbGFzc2VzLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgb3V0LnB1c2goYC4ke2NsYXNzZXNbaV19YCk7CiAgICAgIH0KICAgIH0KICB9CiAgY29uc3QgYWxsb3dlZEF0dHJzID0gWydhcmlhLWxhYmVsJywgJ3R5cGUnLCAnbmFtZScsICd0aXRsZScsICdhbHQnXTsKICBmb3IgKGkgPSAwOyBpIDwgYWxsb3dlZEF0dHJzLmxlbmd0aDsgaSsrKSB7CiAgICBrZXkgPSBhbGxvd2VkQXR0cnNbaV07CiAgICBhdHRyID0gZWxlbS5nZXRBdHRyaWJ1dGUoa2V5KTsKICAgIGlmIChhdHRyKSB7CiAgICAgIG91dC5wdXNoKGBbJHtrZXl9PSIke2F0dHJ9Il1gKTsKICAgIH0KICB9CiAgcmV0dXJuIG91dC5qb2luKCcnKTsKfQoKLyoqCiAqIFRoaXMgc2VydmVzIGFzIGEgYnVpbGQgdGltZSBmbGFnIHRoYXQgd2lsbCBiZSB0cnVlIGJ5IGRlZmF1bHQsIGJ1dCBmYWxzZSBpbiBub24tZGVidWcgYnVpbGRzIG9yIGlmIHVzZXJzIHJlcGxhY2UgYF9fU0VOVFJZX0RFQlVHX19gIGluIHRoZWlyIGdlbmVyYXRlZCBjb2RlLgogKgogKiBBVFRFTlRJT046IFRoaXMgY29uc3RhbnQgbXVzdCBuZXZlciBjcm9zcyBwYWNrYWdlIGJvdW5kYXJpZXMgKGkuZS4gYmUgZXhwb3J0ZWQpIHRvIGd1YXJhbnRlZSB0aGF0IGl0IGNhbiBiZSB1c2VkIGZvciB0cmVlIHNoYWtpbmcuCiAqLwpjb25zdCBERUJVR19CVUlMRCQxID0gKHR5cGVvZiBfX1NFTlRSWV9ERUJVR19fID09PSAndW5kZWZpbmVkJyB8fCBfX1NFTlRSWV9ERUJVR19fKTsKCi8qKiBQcmVmaXggZm9yIGxvZ2dpbmcgc3RyaW5ncyAqLwpjb25zdCBQUkVGSVggPSAnU2VudHJ5IExvZ2dlciAnOwoKY29uc3QgQ09OU09MRV9MRVZFTFMgPSBbCiAgJ2RlYnVnJywKICAnaW5mbycsCiAgJ3dhcm4nLAogICdlcnJvcicsCiAgJ2xvZycsCiAgJ2Fzc2VydCcsCiAgJ3RyYWNlJywKXSA7CgovKiogVGhpcyBtYXkgYmUgbXV0YXRlZCBieSB0aGUgY29uc29sZSBpbnN0cnVtZW50YXRpb24uICovCmNvbnN0IG9yaWdpbmFsQ29uc29sZU1ldGhvZHMKCiA9IHt9OwoKLyoqIEpTRG9jICovCgovKioKICogVGVtcG9yYXJpbHkgZGlzYWJsZSBzZW50cnkgY29uc29sZSBpbnN0cnVtZW50YXRpb25zLgogKgogKiBAcGFyYW0gY2FsbGJhY2sgVGhlIGZ1bmN0aW9uIHRvIHJ1biBhZ2FpbnN0IHRoZSBvcmlnaW5hbCBgY29uc29sZWAgbWVzc2FnZXMKICogQHJldHVybnMgVGhlIHJlc3VsdHMgb2YgdGhlIGNhbGxiYWNrCiAqLwpmdW5jdGlvbiBjb25zb2xlU2FuZGJveChjYWxsYmFjaykgewogIGlmICghKCdjb25zb2xlJyBpbiBHTE9CQUxfT0JKKSkgewogICAgcmV0dXJuIGNhbGxiYWNrKCk7CiAgfQoKICBjb25zdCBjb25zb2xlID0gR0xPQkFMX09CSi5jb25zb2xlIDsKICBjb25zdCB3cmFwcGVkRnVuY3MgPSB7fTsKCiAgY29uc3Qgd3JhcHBlZExldmVscyA9IE9iamVjdC5rZXlzKG9yaWdpbmFsQ29uc29sZU1ldGhvZHMpIDsKCiAgLy8gUmVzdG9yZSBhbGwgd3JhcHBlZCBjb25zb2xlIG1ldGhvZHMKICB3cmFwcGVkTGV2ZWxzLmZvckVhY2gobGV2ZWwgPT4gewogICAgY29uc3Qgb3JpZ2luYWxDb25zb2xlTWV0aG9kID0gb3JpZ2luYWxDb25zb2xlTWV0aG9kc1tsZXZlbF0gOwogICAgd3JhcHBlZEZ1bmNzW2xldmVsXSA9IGNvbnNvbGVbbGV2ZWxdIDsKICAgIGNvbnNvbGVbbGV2ZWxdID0gb3JpZ2luYWxDb25zb2xlTWV0aG9kOwogIH0pOwoKICB0cnkgewogICAgcmV0dXJuIGNhbGxiYWNrKCk7CiAgfSBmaW5hbGx5IHsKICAgIC8vIFJldmVydCByZXN0b3JhdGlvbiB0byB3cmFwcGVkIHN0YXRlCiAgICB3cmFwcGVkTGV2ZWxzLmZvckVhY2gobGV2ZWwgPT4gewogICAgICBjb25zb2xlW2xldmVsXSA9IHdyYXBwZWRGdW5jc1tsZXZlbF0gOwogICAgfSk7CiAgfQp9CgpmdW5jdGlvbiBtYWtlTG9nZ2VyKCkgewogIGxldCBlbmFibGVkID0gZmFsc2U7CiAgY29uc3QgbG9nZ2VyID0gewogICAgZW5hYmxlOiAoKSA9PiB7CiAgICAgIGVuYWJsZWQgPSB0cnVlOwogICAgfSwKICAgIGRpc2FibGU6ICgpID0+IHsKICAgICAgZW5hYmxlZCA9IGZhbHNlOwogICAgfSwKICAgIGlzRW5hYmxlZDogKCkgPT4gZW5hYmxlZCwKICB9OwoKICBpZiAoREVCVUdfQlVJTEQkMSkgewogICAgQ09OU09MRV9MRVZFTFMuZm9yRWFjaChuYW1lID0+IHsKICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkKICAgICAgbG9nZ2VyW25hbWVdID0gKC4uLmFyZ3MpID0+IHsKICAgICAgICBpZiAoZW5hYmxlZCkgewogICAgICAgICAgY29uc29sZVNhbmRib3goKCkgPT4gewogICAgICAgICAgICBHTE9CQUxfT0JKLmNvbnNvbGVbbmFtZV0oYCR7UFJFRklYfVske25hbWV9XTpgLCAuLi5hcmdzKTsKICAgICAgICAgIH0pOwogICAgICAgIH0KICAgICAgfTsKICAgIH0pOwogIH0gZWxzZSB7CiAgICBDT05TT0xFX0xFVkVMUy5mb3JFYWNoKG5hbWUgPT4gewogICAgICBsb2dnZXJbbmFtZV0gPSAoKSA9PiB1bmRlZmluZWQ7CiAgICB9KTsKICB9CgogIHJldHVybiBsb2dnZXIgOwp9Cgpjb25zdCBsb2dnZXIgPSBtYWtlTG9nZ2VyKCk7CgovKioKICogUmVuZGVycyB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoaXMgRHNuLgogKgogKiBCeSBkZWZhdWx0LCB0aGlzIHdpbGwgcmVuZGVyIHRoZSBwdWJsaWMgcmVwcmVzZW50YXRpb24gd2l0aG91dCB0aGUgcGFzc3dvcmQKICogY29tcG9uZW50LiBUbyBnZXQgdGhlIGRlcHJlY2F0ZWQgcHJpdmF0ZSByZXByZXNlbnRhdGlvbiwgc2V0IGB3aXRoUGFzc3dvcmRgCiAqIHRvIHRydWUuCiAqCiAqIEBwYXJhbSB3aXRoUGFzc3dvcmQgV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHBhc3N3b3JkIHdpbGwgYmUgaW5jbHVkZWQuCiAqLwpmdW5jdGlvbiBkc25Ub1N0cmluZyhkc24sIHdpdGhQYXNzd29yZCA9IGZhbHNlKSB7CiAgY29uc3QgeyBob3N0LCBwYXRoLCBwYXNzLCBwb3J0LCBwcm9qZWN0SWQsIHByb3RvY29sLCBwdWJsaWNLZXkgfSA9IGRzbjsKICByZXR1cm4gKAogICAgYCR7cHJvdG9jb2x9Oi8vJHtwdWJsaWNLZXl9JHt3aXRoUGFzc3dvcmQgJiYgcGFzcyA/IGA6JHtwYXNzfWAgOiAnJ31gICsKICAgIGBAJHtob3N0fSR7cG9ydCA/IGA6JHtwb3J0fWAgOiAnJ30vJHtwYXRoID8gYCR7cGF0aH0vYCA6IHBhdGh9JHtwcm9qZWN0SWR9YAogICk7Cn0KCi8qKiBBbiBlcnJvciBlbWl0dGVkIGJ5IFNlbnRyeSBTREtzIGFuZCByZWxhdGVkIHV0aWxpdGllcy4gKi8KY2xhc3MgU2VudHJ5RXJyb3IgZXh0ZW5kcyBFcnJvciB7CiAgLyoqIERpc3BsYXkgbmFtZSBvZiB0aGlzIGVycm9yIGluc3RhbmNlLiAqLwoKICAgY29uc3RydWN0b3IoIG1lc3NhZ2UsIGxvZ0xldmVsID0gJ3dhcm4nKSB7CiAgICBzdXBlcihtZXNzYWdlKTt0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlOwogICAgdGhpcy5uYW1lID0gbmV3LnRhcmdldC5wcm90b3R5cGUuY29uc3RydWN0b3IubmFtZTsKICAgIC8vIFRoaXMgc2V0cyB0aGUgcHJvdG90eXBlIHRvIGJlIGBFcnJvcmAsIG5vdCBgU2VudHJ5RXJyb3JgLiBJdCdzIHVuY2xlYXIgd2h5IHdlIGRvIHRoaXMsIGJ1dCBjb21tZW50aW5nIHRoaXMgbGluZQogICAgLy8gb3V0IGNhdXNlcyB2YXJpb3VzIChzZWVtaW5nbHkgdG90YWxseSB1bnJlbGF0ZWQpIHBsYXl3cmlnaHQgdGVzdHMgY29uc2lzdGVudGx5IHRpbWUgb3V0LiBGWUksIHRoaXMgbWFrZXMKICAgIC8vIGluc3RhbmNlcyBvZiBgU2VudHJ5RXJyb3JgIGZhaWwgYG9iaiBpbnN0YW5jZW9mIFNlbnRyeUVycm9yYCBjaGVja3MuCiAgICBPYmplY3Quc2V0UHJvdG90eXBlT2YodGhpcywgbmV3LnRhcmdldC5wcm90b3R5cGUpOwogICAgdGhpcy5sb2dMZXZlbCA9IGxvZ0xldmVsOwogIH0KfQoKY29uc3QgU1RBQ0tUUkFDRV9GUkFNRV9MSU1JVCA9IDUwOwpjb25zdCBVTktOT1dOX0ZVTkNUSU9OID0gJz8nOwpjb25zdCBTVFJJUF9GUkFNRV9SRUdFWFAgPSAvY2FwdHVyZU1lc3NhZ2V8Y2FwdHVyZUV4Y2VwdGlvbi87CgovKioKICogUmVtb3ZlcyBTZW50cnkgZnJhbWVzIGZyb20gdGhlIHRvcCBhbmQgYm90dG9tIG9mIHRoZSBzdGFjayBpZiBwcmVzZW50IGFuZCBlbmZvcmNlcyBhIGxpbWl0IG9mIG1heCBudW1iZXIgb2YgZnJhbWVzLgogKiBBc3N1bWVzIHN0YWNrIGlucHV0IGlzIG9yZGVyZWQgZnJvbSB0b3AgdG8gYm90dG9tIGFuZCByZXR1cm5zIHRoZSByZXZlcnNlIHJlcHJlc2VudGF0aW9uIHNvIGNhbGwgc2l0ZSBvZiB0aGUKICogZnVuY3Rpb24gdGhhdCBjYXVzZWQgdGhlIGNyYXNoIGlzIHRoZSBsYXN0IGZyYW1lIGluIHRoZSBhcnJheS4KICogQGhpZGRlbgogKi8KZnVuY3Rpb24gc3RyaXBTZW50cnlGcmFtZXNBbmRSZXZlcnNlKHN0YWNrKSB7CiAgaWYgKCFzdGFjay5sZW5ndGgpIHsKICAgIHJldHVybiBbXTsKICB9CgogIGNvbnN0IGxvY2FsU3RhY2sgPSBBcnJheS5mcm9tKHN0YWNrKTsKCiAgLy8gSWYgc3RhY2sgc3RhcnRzIHdpdGggb25lIG9mIG91ciBBUEkgY2FsbHMsIHJlbW92ZSBpdCAoc3RhcnRzLCBtZWFuaW5nIGl0J3MgdGhlIHRvcCBvZiB0aGUgc3RhY2sgLSBha2EgbGFzdCBjYWxsKQogIGlmICgvc2VudHJ5V3JhcHBlZC8udGVzdChsb2NhbFN0YWNrW2xvY2FsU3RhY2subGVuZ3RoIC0gMV0uZnVuY3Rpb24gfHwgJycpKSB7CiAgICBsb2NhbFN0YWNrLnBvcCgpOwogIH0KCiAgLy8gUmV2ZXJzaW5nIGluIHRoZSBtaWRkbGUgb2YgdGhlIHByb2NlZHVyZSBhbGxvd3MgdXMgdG8ganVzdCBwb3AgdGhlIHZhbHVlcyBvZmYgdGhlIHN0YWNrCiAgbG9jYWxTdGFjay5yZXZlcnNlKCk7CgogIC8vIElmIHN0YWNrIGVuZHMgd2l0aCBvbmUgb2Ygb3VyIGludGVybmFsIEFQSSBjYWxscywgcmVtb3ZlIGl0IChlbmRzLCBtZWFuaW5nIGl0J3MgdGhlIGJvdHRvbSBvZiB0aGUgc3RhY2sgLSBha2EgdG9wLW1vc3QgY2FsbCkKICBpZiAoU1RSSVBfRlJBTUVfUkVHRVhQLnRlc3QobG9jYWxTdGFja1tsb2NhbFN0YWNrLmxlbmd0aCAtIDFdLmZ1bmN0aW9uIHx8ICcnKSkgewogICAgbG9jYWxTdGFjay5wb3AoKTsKCiAgICAvLyBXaGVuIHVzaW5nIHN5bnRoZXRpYyBldmVudHMsIHdlIHdpbGwgaGF2ZSBhIDIgbGV2ZWxzIGRlZXAgc3RhY2ssIGFzIGBuZXcgRXJyb3IoJ1NlbnRyeSBzeW50aGV0aWNFeGNlcHRpb24nKWAKICAgIC8vIGlzIHByb2R1Y2VkIHdpdGhpbiB0aGUgaHViIGl0c2VsZiwgbWFraW5nIGl0OgogICAgLy8KICAgIC8vICAgU2VudHJ5LmNhcHR1cmVFeGNlcHRpb24oKQogICAgLy8gICBnZXRDdXJyZW50SHViKCkuY2FwdHVyZUV4Y2VwdGlvbigpCiAgICAvLwogICAgLy8gaW5zdGVhZCBvZiBqdXN0IHRoZSB0b3AgYFNlbnRyeWAgY2FsbCBpdHNlbGYuCiAgICAvLyBUaGlzIGZvcmNlcyB1cyB0byBwb3NzaWJseSBzdHJpcCBhbiBhZGRpdGlvbmFsIGZyYW1lIGluIHRoZSBleGFjdCBzYW1lIHdhcyBhcyBhYm92ZS4KICAgIGlmIChTVFJJUF9GUkFNRV9SRUdFWFAudGVzdChsb2NhbFN0YWNrW2xvY2FsU3RhY2subGVuZ3RoIC0gMV0uZnVuY3Rpb24gfHwgJycpKSB7CiAgICAgIGxvY2FsU3RhY2sucG9wKCk7CiAgICB9CiAgfQoKICByZXR1cm4gbG9jYWxTdGFjay5zbGljZSgwLCBTVEFDS1RSQUNFX0ZSQU1FX0xJTUlUKS5tYXAoZnJhbWUgPT4gKHsKICAgIC4uLmZyYW1lLAogICAgZmlsZW5hbWU6IGZyYW1lLmZpbGVuYW1lIHx8IGxvY2FsU3RhY2tbbG9jYWxTdGFjay5sZW5ndGggLSAxXS5maWxlbmFtZSwKICAgIGZ1bmN0aW9uOiBmcmFtZS5mdW5jdGlvbiB8fCBVTktOT1dOX0ZVTkNUSU9OLAogIH0pKTsKfQoKY29uc3QgZGVmYXVsdEZ1bmN0aW9uTmFtZSA9ICc8YW5vbnltb3VzPic7CgovKioKICogU2FmZWx5IGV4dHJhY3QgZnVuY3Rpb24gbmFtZSBmcm9tIGl0c2VsZgogKi8KZnVuY3Rpb24gZ2V0RnVuY3Rpb25OYW1lKGZuKSB7CiAgdHJ5IHsKICAgIGlmICghZm4gfHwgdHlwZW9mIGZuICE9PSAnZnVuY3Rpb24nKSB7CiAgICAgIHJldHVybiBkZWZhdWx0RnVuY3Rpb25OYW1lOwogICAgfQogICAgcmV0dXJuIGZuLm5hbWUgfHwgZGVmYXVsdEZ1bmN0aW9uTmFtZTsKICB9IGNhdGNoIChlKSB7CiAgICAvLyBKdXN0IGFjY2Vzc2luZyBjdXN0b20gcHJvcHMgaW4gc29tZSBTZWxlbml1bSBlbnZpcm9ubWVudHMKICAgIC8vIGNhbiBjYXVzZSBhICJQZXJtaXNzaW9uIGRlbmllZCIgZXhjZXB0aW9uIChzZWUgcmF2ZW4tanMjNDk1KS4KICAgIHJldHVybiBkZWZhdWx0RnVuY3Rpb25OYW1lOwogIH0KfQoKLyoqCiAqIERlZmluZXMgYSBub24tZW51bWVyYWJsZSBwcm9wZXJ0eSBvbiB0aGUgZ2l2ZW4gb2JqZWN0LgogKgogKiBAcGFyYW0gb2JqIFRoZSBvYmplY3Qgb24gd2hpY2ggdG8gc2V0IHRoZSBwcm9wZXJ0eQogKiBAcGFyYW0gbmFtZSBUaGUgbmFtZSBvZiB0aGUgcHJvcGVydHkgdG8gYmUgc2V0CiAqIEBwYXJhbSB2YWx1ZSBUaGUgdmFsdWUgdG8gd2hpY2ggdG8gc2V0IHRoZSBwcm9wZXJ0eQogKi8KZnVuY3Rpb24gYWRkTm9uRW51bWVyYWJsZVByb3BlcnR5KG9iaiwgbmFtZSwgdmFsdWUpIHsKICB0cnkgewogICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iaiwgbmFtZSwgewogICAgICAvLyBlbnVtZXJhYmxlOiBmYWxzZSwgLy8gdGhlIGRlZmF1bHQsIHNvIHdlIGNhbiBzYXZlIG9uIGJ1bmRsZSBzaXplIGJ5IG5vdCBleHBsaWNpdGx5IHNldHRpbmcgaXQKICAgICAgdmFsdWU6IHZhbHVlLAogICAgICB3cml0YWJsZTogdHJ1ZSwKICAgICAgY29uZmlndXJhYmxlOiB0cnVlLAogICAgfSk7CiAgfSBjYXRjaCAob19PKSB7CiAgICBERUJVR19CVUlMRCQxICYmIGxvZ2dlci5sb2coYEZhaWxlZCB0byBhZGQgbm9uLWVudW1lcmFibGUgcHJvcGVydHkgIiR7bmFtZX0iIHRvIG9iamVjdGAsIG9iaik7CiAgfQp9CgovKioKICogRW5jb2RlcyBnaXZlbiBvYmplY3QgaW50byB1cmwtZnJpZW5kbHkgZm9ybWF0CiAqCiAqIEBwYXJhbSBvYmplY3QgQW4gb2JqZWN0IHRoYXQgY29udGFpbnMgc2VyaWFsaXphYmxlIHZhbHVlcwogKiBAcmV0dXJucyBzdHJpbmcgRW5jb2RlZAogKi8KZnVuY3Rpb24gdXJsRW5jb2RlKG9iamVjdCkgewogIHJldHVybiBPYmplY3Qua2V5cyhvYmplY3QpCiAgICAubWFwKGtleSA9PiBgJHtlbmNvZGVVUklDb21wb25lbnQoa2V5KX09JHtlbmNvZGVVUklDb21wb25lbnQob2JqZWN0W2tleV0pfWApCiAgICAuam9pbignJicpOwp9CgovKioKICogVHJhbnNmb3JtcyBhbnkgYEVycm9yYCBvciBgRXZlbnRgIGludG8gYSBwbGFpbiBvYmplY3Qgd2l0aCBhbGwgb2YgdGhlaXIgZW51bWVyYWJsZSBwcm9wZXJ0aWVzLCBhbmQgc29tZSBvZiB0aGVpcgogKiBub24tZW51bWVyYWJsZSBwcm9wZXJ0aWVzIGF0dGFjaGVkLgogKgogKiBAcGFyYW0gdmFsdWUgSW5pdGlhbCBzb3VyY2UgdGhhdCB3ZSBoYXZlIHRvIHRyYW5zZm9ybSBpbiBvcmRlciBmb3IgaXQgdG8gYmUgdXNhYmxlIGJ5IHRoZSBzZXJpYWxpemVyCiAqIEByZXR1cm5zIEFuIEV2ZW50IG9yIEVycm9yIHR1cm5lZCBpbnRvIGFuIG9iamVjdCAtIG9yIHRoZSB2YWx1ZSBhcmd1cm1lbnQgaXRzZWxmLCB3aGVuIHZhbHVlIGlzIG5laXRoZXIgYW4gRXZlbnQgbm9yCiAqICBhbiBFcnJvci4KICovCmZ1bmN0aW9uIGNvbnZlcnRUb1BsYWluT2JqZWN0KAogIHZhbHVlLAopCgogewogIGlmIChpc0Vycm9yKHZhbHVlKSkgewogICAgcmV0dXJuIHsKICAgICAgbWVzc2FnZTogdmFsdWUubWVzc2FnZSwKICAgICAgbmFtZTogdmFsdWUubmFtZSwKICAgICAgc3RhY2s6IHZhbHVlLnN0YWNrLAogICAgICAuLi5nZXRPd25Qcm9wZXJ0aWVzKHZhbHVlKSwKICAgIH07CiAgfSBlbHNlIGlmIChpc0V2ZW50KHZhbHVlKSkgewogICAgY29uc3QgbmV3T2JqCgogPSB7CiAgICAgIHR5cGU6IHZhbHVlLnR5cGUsCiAgICAgIHRhcmdldDogc2VyaWFsaXplRXZlbnRUYXJnZXQodmFsdWUudGFyZ2V0KSwKICAgICAgY3VycmVudFRhcmdldDogc2VyaWFsaXplRXZlbnRUYXJnZXQodmFsdWUuY3VycmVudFRhcmdldCksCiAgICAgIC4uLmdldE93blByb3BlcnRpZXModmFsdWUpLAogICAgfTsKCiAgICBpZiAodHlwZW9mIEN1c3RvbUV2ZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpc0luc3RhbmNlT2YodmFsdWUsIEN1c3RvbUV2ZW50KSkgewogICAgICBuZXdPYmouZGV0YWlsID0gdmFsdWUuZGV0YWlsOwogICAgfQoKICAgIHJldHVybiBuZXdPYmo7CiAgfSBlbHNlIHsKICAgIHJldHVybiB2YWx1ZTsKICB9Cn0KCi8qKiBDcmVhdGVzIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSB0YXJnZXQgb2YgYW4gYEV2ZW50YCBvYmplY3QgKi8KZnVuY3Rpb24gc2VyaWFsaXplRXZlbnRUYXJnZXQodGFyZ2V0KSB7CiAgdHJ5IHsKICAgIHJldHVybiBpc0VsZW1lbnQodGFyZ2V0KSA/IGh0bWxUcmVlQXNTdHJpbmcodGFyZ2V0KSA6IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh0YXJnZXQpOwogIH0gY2F0Y2ggKF9vTykgewogICAgcmV0dXJuICc8dW5rbm93bj4nOwogIH0KfQoKLyoqIEZpbHRlcnMgb3V0IGFsbCBidXQgYW4gb2JqZWN0J3Mgb3duIHByb3BlcnRpZXMgKi8KZnVuY3Rpb24gZ2V0T3duUHJvcGVydGllcyhvYmopIHsKICBpZiAodHlwZW9mIG9iaiA9PT0gJ29iamVjdCcgJiYgb2JqICE9PSBudWxsKSB7CiAgICBjb25zdCBleHRyYWN0ZWRQcm9wcyA9IHt9OwogICAgZm9yIChjb25zdCBwcm9wZXJ0eSBpbiBvYmopIHsKICAgICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIHByb3BlcnR5KSkgewogICAgICAgIGV4dHJhY3RlZFByb3BzW3Byb3BlcnR5XSA9IChvYmogKVtwcm9wZXJ0eV07CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBleHRyYWN0ZWRQcm9wczsKICB9IGVsc2UgewogICAgcmV0dXJuIHt9OwogIH0KfQoKLyoqCiAqIEdpdmVuIGFueSBvYmplY3QsIHJldHVybiBhIG5ldyBvYmplY3QgaGF2aW5nIHJlbW92ZWQgYWxsIGZpZWxkcyB3aG9zZSB2YWx1ZSB3YXMgYHVuZGVmaW5lZGAuCiAqIFdvcmtzIHJlY3Vyc2l2ZWx5IG9uIG9iamVjdHMgYW5kIGFycmF5cy4KICoKICogQXR0ZW50aW9uOiBUaGlzIGZ1bmN0aW9uIGtlZXBzIGNpcmN1bGFyIHJlZmVyZW5jZXMgaW4gdGhlIHJldHVybmVkIG9iamVjdC4KICovCmZ1bmN0aW9uIGRyb3BVbmRlZmluZWRLZXlzKGlucHV0VmFsdWUpIHsKICAvLyBUaGlzIG1hcCBrZWVwcyB0cmFjayBvZiB3aGF0IGFscmVhZHkgdmlzaXRlZCBub2RlcyBtYXAgdG8uCiAgLy8gT3VyIFNldCAtIGJhc2VkIG1lbW9CdWlsZGVyIGRvZXNuJ3Qgd29yayBoZXJlIGJlY2F1c2Ugd2Ugd2FudCB0byB0aGUgb3V0cHV0IG9iamVjdCB0byBoYXZlIHRoZSBzYW1lIGNpcmN1bGFyCiAgLy8gcmVmZXJlbmNlcyBhcyB0aGUgaW5wdXQgb2JqZWN0LgogIGNvbnN0IG1lbW9pemF0aW9uTWFwID0gbmV3IE1hcCgpOwoKICAvLyBUaGlzIGZ1bmN0aW9uIGp1c3QgcHJveGllcyBgX2Ryb3BVbmRlZmluZWRLZXlzYCB0byBrZWVwIHRoZSBgbWVtb0J1aWxkZXJgIG91dCBvZiB0aGlzIGZ1bmN0aW9uJ3MgQVBJCiAgcmV0dXJuIF9kcm9wVW5kZWZpbmVkS2V5cyhpbnB1dFZhbHVlLCBtZW1vaXphdGlvbk1hcCk7Cn0KCmZ1bmN0aW9uIF9kcm9wVW5kZWZpbmVkS2V5cyhpbnB1dFZhbHVlLCBtZW1vaXphdGlvbk1hcCkgewogIGlmIChpc1Bvam8oaW5wdXRWYWx1ZSkpIHsKICAgIC8vIElmIHRoaXMgbm9kZSBoYXMgYWxyZWFkeSBiZWVuIHZpc2l0ZWQgZHVlIHRvIGEgY2lyY3VsYXIgcmVmZXJlbmNlLCByZXR1cm4gdGhlIG9iamVjdCBpdCB3YXMgbWFwcGVkIHRvIGluIHRoZSBuZXcgb2JqZWN0CiAgICBjb25zdCBtZW1vVmFsID0gbWVtb2l6YXRpb25NYXAuZ2V0KGlucHV0VmFsdWUpOwogICAgaWYgKG1lbW9WYWwgIT09IHVuZGVmaW5lZCkgewogICAgICByZXR1cm4gbWVtb1ZhbCA7CiAgICB9CgogICAgY29uc3QgcmV0dXJuVmFsdWUgPSB7fTsKICAgIC8vIFN0b3JlIHRoZSBtYXBwaW5nIG9mIHRoaXMgdmFsdWUgaW4gY2FzZSB3ZSB2aXNpdCBpdCBhZ2FpbiwgaW4gY2FzZSBvZiBjaXJjdWxhciBkYXRhCiAgICBtZW1vaXphdGlvbk1hcC5zZXQoaW5wdXRWYWx1ZSwgcmV0dXJuVmFsdWUpOwoKICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKGlucHV0VmFsdWUpKSB7CiAgICAgIGlmICh0eXBlb2YgaW5wdXRWYWx1ZVtrZXldICE9PSAndW5kZWZpbmVkJykgewogICAgICAgIHJldHVyblZhbHVlW2tleV0gPSBfZHJvcFVuZGVmaW5lZEtleXMoaW5wdXRWYWx1ZVtrZXldLCBtZW1vaXphdGlvbk1hcCk7CiAgICAgIH0KICAgIH0KCiAgICByZXR1cm4gcmV0dXJuVmFsdWUgOwogIH0KCiAgaWYgKEFycmF5LmlzQXJyYXkoaW5wdXRWYWx1ZSkpIHsKICAgIC8vIElmIHRoaXMgbm9kZSBoYXMgYWxyZWFkeSBiZWVuIHZpc2l0ZWQgZHVlIHRvIGEgY2lyY3VsYXIgcmVmZXJlbmNlLCByZXR1cm4gdGhlIGFycmF5IGl0IHdhcyBtYXBwZWQgdG8gaW4gdGhlIG5ldyBvYmplY3QKICAgIGNvbnN0IG1lbW9WYWwgPSBtZW1vaXphdGlvbk1hcC5nZXQoaW5wdXRWYWx1ZSk7CiAgICBpZiAobWVtb1ZhbCAhPT0gdW5kZWZpbmVkKSB7CiAgICAgIHJldHVybiBtZW1vVmFsIDsKICAgIH0KCiAgICBjb25zdCByZXR1cm5WYWx1ZSA9IFtdOwogICAgLy8gU3RvcmUgdGhlIG1hcHBpbmcgb2YgdGhpcyB2YWx1ZSBpbiBjYXNlIHdlIHZpc2l0IGl0IGFnYWluLCBpbiBjYXNlIG9mIGNpcmN1bGFyIGRhdGEKICAgIG1lbW9pemF0aW9uTWFwLnNldChpbnB1dFZhbHVlLCByZXR1cm5WYWx1ZSk7CgogICAgaW5wdXRWYWx1ZS5mb3JFYWNoKChpdGVtKSA9PiB7CiAgICAgIHJldHVyblZhbHVlLnB1c2goX2Ryb3BVbmRlZmluZWRLZXlzKGl0ZW0sIG1lbW9pemF0aW9uTWFwKSk7CiAgICB9KTsKCiAgICByZXR1cm4gcmV0dXJuVmFsdWUgOwogIH0KCiAgcmV0dXJuIGlucHV0VmFsdWU7Cn0KCmZ1bmN0aW9uIGlzUG9qbyhpbnB1dCkgewogIGlmICghaXNQbGFpbk9iamVjdChpbnB1dCkpIHsKICAgIHJldHVybiBmYWxzZTsKICB9CgogIHRyeSB7CiAgICBjb25zdCBuYW1lID0gKE9iamVjdC5nZXRQcm90b3R5cGVPZihpbnB1dCkgKS5jb25zdHJ1Y3Rvci5uYW1lOwogICAgcmV0dXJuICFuYW1lIHx8IG5hbWUgPT09ICdPYmplY3QnOwogIH0gY2F0Y2ggKGUpIHsKICAgIHJldHVybiB0cnVlOwogIH0KfQoKLyoqCiAqIFVVSUQ0IGdlbmVyYXRvcgogKgogKiBAcmV0dXJucyBzdHJpbmcgR2VuZXJhdGVkIFVVSUQ0LgogKi8KZnVuY3Rpb24gdXVpZDQoKSB7CiAgY29uc3QgZ2JsID0gR0xPQkFMX09CSiA7CiAgY29uc3QgY3J5cHRvID0gZ2JsLmNyeXB0byB8fCBnYmwubXNDcnlwdG87CgogIGxldCBnZXRSYW5kb21CeXRlID0gKCkgPT4gTWF0aC5yYW5kb20oKSAqIDE2OwogIHRyeSB7CiAgICBpZiAoY3J5cHRvICYmIGNyeXB0by5yYW5kb21VVUlEKSB7CiAgICAgIHJldHVybiBjcnlwdG8ucmFuZG9tVVVJRCgpLnJlcGxhY2UoLy0vZywgJycpOwogICAgfQogICAgaWYgKGNyeXB0byAmJiBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKSB7CiAgICAgIGdldFJhbmRvbUJ5dGUgPSAoKSA9PiB7CiAgICAgICAgLy8gY3J5cHRvLmdldFJhbmRvbVZhbHVlcyBtaWdodCByZXR1cm4gdW5kZWZpbmVkIGluc3RlYWQgb2YgdGhlIHR5cGVkIGFycmF5CiAgICAgICAgLy8gaW4gb2xkIENocm9taXVtIHZlcnNpb25zIChlLmcuIDIzLjAuMTIzNS4wICgxNTE0MjIpKQogICAgICAgIC8vIEhvd2V2ZXIsIGB0eXBlZEFycmF5YCBpcyBzdGlsbCBmaWxsZWQgaW4tcGxhY2UuCiAgICAgICAgLy8gQHNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvQ3J5cHRvL2dldFJhbmRvbVZhbHVlcyN0eXBlZGFycmF5CiAgICAgICAgY29uc3QgdHlwZWRBcnJheSA9IG5ldyBVaW50OEFycmF5KDEpOwogICAgICAgIGNyeXB0by5nZXRSYW5kb21WYWx1ZXModHlwZWRBcnJheSk7CiAgICAgICAgcmV0dXJuIHR5cGVkQXJyYXlbMF07CiAgICAgIH07CiAgICB9CiAgfSBjYXRjaCAoXykgewogICAgLy8gc29tZSBydW50aW1lcyBjYW4gY3Jhc2ggaW52b2tpbmcgY3J5cHRvCiAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vZ2V0c2VudHJ5L3NlbnRyeS1qYXZhc2NyaXB0L2lzc3Vlcy84OTM1CiAgfQoKICAvLyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzEwNTAzNC9ob3ctdG8tY3JlYXRlLWEtZ3VpZC11dWlkLWluLWphdmFzY3JpcHQvMjExNzUyMyMyMTE3NTIzCiAgLy8gQ29uY2F0ZW5hdGluZyB0aGUgZm9sbG93aW5nIG51bWJlcnMgYXMgc3RyaW5ncyByZXN1bHRzIGluICcxMDAwMDAwMDEwMDA0MDAwODAwMDEwMDAwMDAwMDAwMCcKICByZXR1cm4gKChbMWU3XSApICsgMWUzICsgNGUzICsgOGUzICsgMWUxMSkucmVwbGFjZSgvWzAxOF0vZywgYyA9PgogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWJpdHdpc2UKICAgICgoYyApIF4gKChnZXRSYW5kb21CeXRlKCkgJiAxNSkgPj4gKChjICkgLyA0KSkpLnRvU3RyaW5nKDE2KSwKICApOwp9CgovKioKICogQ2hlY2tzIHdoZXRoZXIgdGhlIGdpdmVuIGlucHV0IGlzIGFscmVhZHkgYW4gYXJyYXksIGFuZCBpZiBpdCBpc24ndCwgd3JhcHMgaXQgaW4gb25lLgogKgogKiBAcGFyYW0gbWF5YmVBcnJheSBJbnB1dCB0byB0dXJuIGludG8gYW4gYXJyYXksIGlmIG5lY2Vzc2FyeQogKiBAcmV0dXJucyBUaGUgaW5wdXQsIGlmIGFscmVhZHkgYW4gYXJyYXksIG9yIGFuIGFycmF5IHdpdGggdGhlIGlucHV0IGFzIHRoZSBvbmx5IGVsZW1lbnQsIGlmIG5vdAogKi8KZnVuY3Rpb24gYXJyYXlpZnkobWF5YmVBcnJheSkgewogIHJldHVybiBBcnJheS5pc0FycmF5KG1heWJlQXJyYXkpID8gbWF5YmVBcnJheSA6IFttYXliZUFycmF5XTsKfQoKLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1tZW1iZXItYWNjZXNzICovCi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnkgKi8KCi8qKgogKiBIZWxwZXIgdG8gZGVjeWNsZSBqc29uIG9iamVjdHMKICovCmZ1bmN0aW9uIG1lbW9CdWlsZGVyKCkgewogIGNvbnN0IGhhc1dlYWtTZXQgPSB0eXBlb2YgV2Vha1NldCA9PT0gJ2Z1bmN0aW9uJzsKICBjb25zdCBpbm5lciA9IGhhc1dlYWtTZXQgPyBuZXcgV2Vha1NldCgpIDogW107CiAgZnVuY3Rpb24gbWVtb2l6ZShvYmopIHsKICAgIGlmIChoYXNXZWFrU2V0KSB7CiAgICAgIGlmIChpbm5lci5oYXMob2JqKSkgewogICAgICAgIHJldHVybiB0cnVlOwogICAgICB9CiAgICAgIGlubmVyLmFkZChvYmopOwogICAgICByZXR1cm4gZmFsc2U7CiAgICB9CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L3ByZWZlci1mb3Itb2YKICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaW5uZXIubGVuZ3RoOyBpKyspIHsKICAgICAgY29uc3QgdmFsdWUgPSBpbm5lcltpXTsKICAgICAgaWYgKHZhbHVlID09PSBvYmopIHsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgfQogICAgfQogICAgaW5uZXIucHVzaChvYmopOwogICAgcmV0dXJuIGZhbHNlOwogIH0KCiAgZnVuY3Rpb24gdW5tZW1vaXplKG9iaikgewogICAgaWYgKGhhc1dlYWtTZXQpIHsKICAgICAgaW5uZXIuZGVsZXRlKG9iaik7CiAgICB9IGVsc2UgewogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGlubmVyLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgaWYgKGlubmVyW2ldID09PSBvYmopIHsKICAgICAgICAgIGlubmVyLnNwbGljZShpLCAxKTsKICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgfQogICAgfQogIH0KICByZXR1cm4gW21lbW9pemUsIHVubWVtb2l6ZV07Cn0KCi8qKgogKiBSZWN1cnNpdmVseSBub3JtYWxpemVzIHRoZSBnaXZlbiBvYmplY3QuCiAqCiAqIC0gQ3JlYXRlcyBhIGNvcHkgdG8gcHJldmVudCBvcmlnaW5hbCBpbnB1dCBtdXRhdGlvbgogKiAtIFNraXBzIG5vbi1lbnVtZXJhYmxlIHByb3BlcnRpZXMKICogLSBXaGVuIHN0cmluZ2lmeWluZywgY2FsbHMgYHRvSlNPTmAgaWYgaW1wbGVtZW50ZWQKICogLSBSZW1vdmVzIGNpcmN1bGFyIHJlZmVyZW5jZXMKICogLSBUcmFuc2xhdGVzIG5vbi1zZXJpYWxpemFibGUgdmFsdWVzIChgdW5kZWZpbmVkYC9gTmFOYC9mdW5jdGlvbnMpIHRvIHNlcmlhbGl6YWJsZSBmb3JtYXQKICogLSBUcmFuc2xhdGVzIGtub3duIGdsb2JhbCBvYmplY3RzL2NsYXNzZXMgdG8gYSBzdHJpbmcgcmVwcmVzZW50YXRpb25zCiAqIC0gVGFrZXMgY2FyZSBvZiBgRXJyb3JgIG9iamVjdCBzZXJpYWxpemF0aW9uCiAqIC0gT3B0aW9uYWxseSBsaW1pdHMgZGVwdGggb2YgZmluYWwgb3V0cHV0CiAqIC0gT3B0aW9uYWxseSBsaW1pdHMgbnVtYmVyIG9mIHByb3BlcnRpZXMvZWxlbWVudHMgaW5jbHVkZWQgaW4gYW55IHNpbmdsZSBvYmplY3QvYXJyYXkKICoKICogQHBhcmFtIGlucHV0IFRoZSBvYmplY3QgdG8gYmUgbm9ybWFsaXplZC4KICogQHBhcmFtIGRlcHRoIFRoZSBtYXggZGVwdGggdG8gd2hpY2ggdG8gbm9ybWFsaXplIHRoZSBvYmplY3QuIChBbnl0aGluZyBkZWVwZXIgc3RyaW5naWZpZWQgd2hvbGUuKQogKiBAcGFyYW0gbWF4UHJvcGVydGllcyBUaGUgbWF4IG51bWJlciBvZiBlbGVtZW50cyBvciBwcm9wZXJ0aWVzIHRvIGJlIGluY2x1ZGVkIGluIGFueSBzaW5nbGUgYXJyYXkgb3IKICogb2JqZWN0IGluIHRoZSBub3JtYWxsaXplZCBvdXRwdXQuCiAqIEByZXR1cm5zIEEgbm9ybWFsaXplZCB2ZXJzaW9uIG9mIHRoZSBvYmplY3QsIG9yIGAiKipub24tc2VyaWFsaXphYmxlKioiYCBpZiBhbnkgZXJyb3JzIGFyZSB0aHJvd24gZHVyaW5nIG5vcm1hbGl6YXRpb24uCiAqLwovLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueQpmdW5jdGlvbiBub3JtYWxpemUoaW5wdXQsIGRlcHRoID0gMTAwLCBtYXhQcm9wZXJ0aWVzID0gK0luZmluaXR5KSB7CiAgdHJ5IHsKICAgIC8vIHNpbmNlIHdlJ3JlIGF0IHRoZSBvdXRlcm1vc3QgbGV2ZWwsIHdlIGRvbid0IHByb3ZpZGUgYSBrZXkKICAgIHJldHVybiB2aXNpdCgnJywgaW5wdXQsIGRlcHRoLCBtYXhQcm9wZXJ0aWVzKTsKICB9IGNhdGNoIChlcnIpIHsKICAgIHJldHVybiB7IEVSUk9SOiBgKipub24tc2VyaWFsaXphYmxlKiogKCR7ZXJyfSlgIH07CiAgfQp9CgovKioKICogVmlzaXRzIGEgbm9kZSB0byBwZXJmb3JtIG5vcm1hbGl6YXRpb24gb24gaXQKICoKICogQHBhcmFtIGtleSBUaGUga2V5IGNvcnJlc3BvbmRpbmcgdG8gdGhlIGdpdmVuIG5vZGUKICogQHBhcmFtIHZhbHVlIFRoZSBub2RlIHRvIGJlIHZpc2l0ZWQKICogQHBhcmFtIGRlcHRoIE9wdGlvbmFsIG51bWJlciBpbmRpY2F0aW5nIHRoZSBtYXhpbXVtIHJlY3Vyc2lvbiBkZXB0aAogKiBAcGFyYW0gbWF4UHJvcGVydGllcyBPcHRpb25hbCBtYXhpbXVtIG51bWJlciBvZiBwcm9wZXJ0aWVzL2VsZW1lbnRzIGluY2x1ZGVkIGluIGFueSBzaW5nbGUgb2JqZWN0L2FycmF5CiAqIEBwYXJhbSBtZW1vIE9wdGlvbmFsIE1lbW8gY2xhc3MgaGFuZGxpbmcgZGVjeWNsaW5nCiAqLwpmdW5jdGlvbiB2aXNpdCgKICBrZXksCiAgdmFsdWUsCiAgZGVwdGggPSArSW5maW5pdHksCiAgbWF4UHJvcGVydGllcyA9ICtJbmZpbml0eSwKICBtZW1vID0gbWVtb0J1aWxkZXIoKSwKKSB7CiAgY29uc3QgW21lbW9pemUsIHVubWVtb2l6ZV0gPSBtZW1vOwoKICAvLyBHZXQgdGhlIHNpbXBsZSBjYXNlcyBvdXQgb2YgdGhlIHdheSBmaXJzdAogIGlmICgKICAgIHZhbHVlID09IG51bGwgfHwgLy8gdGhpcyBtYXRjaGVzIG51bGwgYW5kIHVuZGVmaW5lZCAtPiBlcWVxIG5vdCBlcWVxZXEKICAgIChbJ251bWJlcicsICdib29sZWFuJywgJ3N0cmluZyddLmluY2x1ZGVzKHR5cGVvZiB2YWx1ZSkgJiYgIU51bWJlci5pc05hTih2YWx1ZSkpCiAgKSB7CiAgICByZXR1cm4gdmFsdWUgOwogIH0KCiAgY29uc3Qgc3RyaW5naWZpZWQgPSBzdHJpbmdpZnlWYWx1ZShrZXksIHZhbHVlKTsKCiAgLy8gQW55dGhpbmcgd2UgY291bGQgcG90ZW50aWFsbHkgZGlnIGludG8gbW9yZSAob2JqZWN0cyBvciBhcnJheXMpIHdpbGwgaGF2ZSBjb21lIGJhY2sgYXMgYCJbb2JqZWN0IFhYWFhdImAuCiAgLy8gRXZlcnl0aGluZyBlbHNlIHdpbGwgaGF2ZSBhbHJlYWR5IGJlZW4gc2VyaWFsaXplZCwgc28gaWYgd2UgZG9uJ3Qgc2VlIHRoYXQgcGF0dGVybiwgd2UncmUgZG9uZS4KICBpZiAoIXN0cmluZ2lmaWVkLnN0YXJ0c1dpdGgoJ1tvYmplY3QgJykpIHsKICAgIHJldHVybiBzdHJpbmdpZmllZDsKICB9CgogIC8vIEZyb20gaGVyZSBvbiwgd2UgY2FuIGFzc2VydCB0aGF0IGB2YWx1ZWAgaXMgZWl0aGVyIGFuIG9iamVjdCBvciBhbiBhcnJheS4KCiAgLy8gRG8gbm90IG5vcm1hbGl6ZSBvYmplY3RzIHRoYXQgd2Uga25vdyBoYXZlIGFscmVhZHkgYmVlbiBub3JtYWxpemVkLiBBcyBhIGdlbmVyYWwgcnVsZSwgdGhlCiAgLy8gIl9fc2VudHJ5X3NraXBfbm9ybWFsaXphdGlvbl9fIiBwcm9wZXJ0eSBzaG91bGQgb25seSBiZSB1c2VkIHNwYXJpbmdseSBhbmQgb25seSBzaG91bGQgb25seSBiZSBzZXQgb24gb2JqZWN0cyB0aGF0CiAgLy8gaGF2ZSBhbHJlYWR5IGJlZW4gbm9ybWFsaXplZC4KICBpZiAoKHZhbHVlIClbJ19fc2VudHJ5X3NraXBfbm9ybWFsaXphdGlvbl9fJ10pIHsKICAgIHJldHVybiB2YWx1ZSA7CiAgfQoKICAvLyBXZSBjYW4gc2V0IGBfX3NlbnRyeV9vdmVycmlkZV9ub3JtYWxpemF0aW9uX2RlcHRoX19gIG9uIGFuIG9iamVjdCB0byBlbnN1cmUgdGhhdCBmcm9tIHRoZXJlCiAgLy8gV2Uga2VlcCBhIGNlcnRhaW4gYW1vdW50IG9mIGRlcHRoLgogIC8vIFRoaXMgc2hvdWxkIGJlIHVzZWQgc3BhcmluZ2x5LCBlLmcuIHdlIHVzZSBpdCBmb3IgdGhlIHJlZHV4IGludGVncmF0aW9uIHRvIGVuc3VyZSB3ZSBnZXQgYSBjZXJ0YWluIGFtb3VudCBvZiBzdGF0ZS4KICBjb25zdCByZW1haW5pbmdEZXB0aCA9CiAgICB0eXBlb2YgKHZhbHVlIClbJ19fc2VudHJ5X292ZXJyaWRlX25vcm1hbGl6YXRpb25fZGVwdGhfXyddID09PSAnbnVtYmVyJwogICAgICA/ICgodmFsdWUgKVsnX19zZW50cnlfb3ZlcnJpZGVfbm9ybWFsaXphdGlvbl9kZXB0aF9fJ10gKQogICAgICA6IGRlcHRoOwoKICAvLyBXZSdyZSBhbHNvIGRvbmUgaWYgd2UndmUgcmVhY2hlZCB0aGUgbWF4IGRlcHRoCiAgaWYgKHJlbWFpbmluZ0RlcHRoID09PSAwKSB7CiAgICAvLyBBdCB0aGlzIHBvaW50IHdlIGtub3cgYHNlcmlhbGl6ZWRgIGlzIGEgc3RyaW5nIG9mIHRoZSBmb3JtIGAiW29iamVjdCBYWFhYXSJgLiBDbGVhbiBpdCB1cCBzbyBpdCdzIGp1c3QgYCJbWFhYWF0iYC4KICAgIHJldHVybiBzdHJpbmdpZmllZC5yZXBsYWNlKCdvYmplY3QgJywgJycpOwogIH0KCiAgLy8gSWYgd2UndmUgYWxyZWFkeSB2aXNpdGVkIHRoaXMgYnJhbmNoLCBiYWlsIG91dCwgYXMgaXQncyBjaXJjdWxhciByZWZlcmVuY2UuIElmIG5vdCwgbm90ZSB0aGF0IHdlJ3JlIHNlZWluZyBpdCBub3cuCiAgaWYgKG1lbW9pemUodmFsdWUpKSB7CiAgICByZXR1cm4gJ1tDaXJjdWxhciB+XSc7CiAgfQoKICAvLyBJZiB0aGUgdmFsdWUgaGFzIGEgYHRvSlNPTmAgbWV0aG9kLCB3ZSBjYWxsIGl0IHRvIGV4dHJhY3QgbW9yZSBpbmZvcm1hdGlvbgogIGNvbnN0IHZhbHVlV2l0aFRvSlNPTiA9IHZhbHVlIDsKICBpZiAodmFsdWVXaXRoVG9KU09OICYmIHR5cGVvZiB2YWx1ZVdpdGhUb0pTT04udG9KU09OID09PSAnZnVuY3Rpb24nKSB7CiAgICB0cnkgewogICAgICBjb25zdCBqc29uVmFsdWUgPSB2YWx1ZVdpdGhUb0pTT04udG9KU09OKCk7CiAgICAgIC8vIFdlIG5lZWQgdG8gbm9ybWFsaXplIHRoZSByZXR1cm4gdmFsdWUgb2YgYC50b0pTT04oKWAgaW4gY2FzZSBpdCBoYXMgY2lyY3VsYXIgcmVmZXJlbmNlcwogICAgICByZXR1cm4gdmlzaXQoJycsIGpzb25WYWx1ZSwgcmVtYWluaW5nRGVwdGggLSAxLCBtYXhQcm9wZXJ0aWVzLCBtZW1vKTsKICAgIH0gY2F0Y2ggKGVycikgewogICAgICAvLyBwYXNzIChUaGUgYnVpbHQtaW4gYHRvSlNPTmAgZmFpbGVkLCBidXQgd2UgY2FuIHN0aWxsIHRyeSB0byBkbyBpdCBvdXJzZWx2ZXMpCiAgICB9CiAgfQoKICAvLyBBdCB0aGlzIHBvaW50IHdlIGtub3cgd2UgZWl0aGVyIGhhdmUgYW4gb2JqZWN0IG9yIGFuIGFycmF5LCB3ZSBoYXZlbid0IHNlZW4gaXQgYmVmb3JlLCBhbmQgd2UncmUgZ29pbmcgdG8gcmVjdXJzZQogIC8vIGJlY2F1c2Ugd2UgaGF2ZW4ndCB5ZXQgcmVhY2hlZCB0aGUgbWF4IGRlcHRoLiBDcmVhdGUgYW4gYWNjdW11bGF0b3IgdG8gaG9sZCB0aGUgcmVzdWx0cyBvZiB2aXNpdGluZyBlYWNoCiAgLy8gcHJvcGVydHkvZW50cnksIGFuZCBrZWVwIHRyYWNrIG9mIHRoZSBudW1iZXIgb2YgaXRlbXMgd2UgYWRkIHRvIGl0LgogIGNvbnN0IG5vcm1hbGl6ZWQgPSAoQXJyYXkuaXNBcnJheSh2YWx1ZSkgPyBbXSA6IHt9KSA7CiAgbGV0IG51bUFkZGVkID0gMDsKCiAgLy8gQmVmb3JlIHdlIGJlZ2luLCBjb252ZXJ0YEVycm9yYCBhbmRgRXZlbnRgIGluc3RhbmNlcyBpbnRvIHBsYWluIG9iamVjdHMsIHNpbmNlIHNvbWUgb2YgZWFjaCBvZiB0aGVpciByZWxldmFudAogIC8vIHByb3BlcnRpZXMgYXJlIG5vbi1lbnVtZXJhYmxlIGFuZCBvdGhlcndpc2Ugd291bGQgZ2V0IG1pc3NlZC4KICBjb25zdCB2aXNpdGFibGUgPSBjb252ZXJ0VG9QbGFpbk9iamVjdCh2YWx1ZSApOwoKICBmb3IgKGNvbnN0IHZpc2l0S2V5IGluIHZpc2l0YWJsZSkgewogICAgLy8gQXZvaWQgaXRlcmF0aW5nIG92ZXIgZmllbGRzIGluIHRoZSBwcm90b3R5cGUgaWYgdGhleSd2ZSBzb21laG93IGJlZW4gZXhwb3NlZCB0byBlbnVtZXJhdGlvbi4KICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHZpc2l0YWJsZSwgdmlzaXRLZXkpKSB7CiAgICAgIGNvbnRpbnVlOwogICAgfQoKICAgIGlmIChudW1BZGRlZCA+PSBtYXhQcm9wZXJ0aWVzKSB7CiAgICAgIG5vcm1hbGl6ZWRbdmlzaXRLZXldID0gJ1tNYXhQcm9wZXJ0aWVzIH5dJzsKICAgICAgYnJlYWs7CiAgICB9CgogICAgLy8gUmVjdXJzaXZlbHkgdmlzaXQgYWxsIHRoZSBjaGlsZCBub2RlcwogICAgY29uc3QgdmlzaXRWYWx1ZSA9IHZpc2l0YWJsZVt2aXNpdEtleV07CiAgICBub3JtYWxpemVkW3Zpc2l0S2V5XSA9IHZpc2l0KHZpc2l0S2V5LCB2aXNpdFZhbHVlLCByZW1haW5pbmdEZXB0aCAtIDEsIG1heFByb3BlcnRpZXMsIG1lbW8pOwoKICAgIG51bUFkZGVkKys7CiAgfQoKICAvLyBPbmNlIHdlJ3ZlIHZpc2l0ZWQgYWxsIHRoZSBicmFuY2hlcywgcmVtb3ZlIHRoZSBwYXJlbnQgZnJvbSBtZW1vIHN0b3JhZ2UKICB1bm1lbW9pemUodmFsdWUpOwoKICAvLyBSZXR1cm4gYWNjdW11bGF0ZWQgdmFsdWVzCiAgcmV0dXJuIG5vcm1hbGl6ZWQ7Cn0KCi8qIGVzbGludC1kaXNhYmxlIGNvbXBsZXhpdHkgKi8KLyoqCiAqIFN0cmluZ2lmeSB0aGUgZ2l2ZW4gdmFsdWUuIEhhbmRsZXMgdmFyaW91cyBrbm93biBzcGVjaWFsIHZhbHVlcyBhbmQgdHlwZXMuCiAqCiAqIE5vdCBtZWFudCB0byBiZSB1c2VkIG9uIHNpbXBsZSBwcmltaXRpdmVzIHdoaWNoIGFscmVhZHkgaGF2ZSBhIHN0cmluZyByZXByZXNlbnRhdGlvbiwgYXMgaXQgd2lsbCwgZm9yIGV4YW1wbGUsIHR1cm4KICogdGhlIG51bWJlciAxMjMxIGludG8gIltPYmplY3QgTnVtYmVyXSIsIG5vciBvbiBgbnVsbGAsIGFzIGl0IHdpbGwgdGhyb3cuCiAqCiAqIEBwYXJhbSB2YWx1ZSBUaGUgdmFsdWUgdG8gc3RyaW5naWZ5CiAqIEByZXR1cm5zIEEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb24gb2YgdGhlIGdpdmVuIHZhbHVlCiAqLwpmdW5jdGlvbiBzdHJpbmdpZnlWYWx1ZSgKICBrZXksCiAgLy8gdGhpcyB0eXBlIGlzIGEgdGlueSBiaXQgb2YgYSBjaGVhdCwgc2luY2UgdGhpcyBmdW5jdGlvbiBkb2VzIGhhbmRsZSBOYU4gKHdoaWNoIGlzIHRlY2huaWNhbGx5IGEgbnVtYmVyKSwgYnV0IGZvcgogIC8vIG91ciBpbnRlcm5hbCB1c2UsIGl0J2xsIGRvCiAgdmFsdWUsCikgewogIHRyeSB7CiAgICBpZiAoa2V5ID09PSAnZG9tYWluJyAmJiB2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmICh2YWx1ZSApLl9ldmVudHMpIHsKICAgICAgcmV0dXJuICdbRG9tYWluXSc7CiAgICB9CgogICAgaWYgKGtleSA9PT0gJ2RvbWFpbkVtaXR0ZXInKSB7CiAgICAgIHJldHVybiAnW0RvbWFpbkVtaXR0ZXJdJzsKICAgIH0KCiAgICAvLyBJdCdzIHNhZmUgdG8gdXNlIGBnbG9iYWxgLCBgd2luZG93YCwgYW5kIGBkb2N1bWVudGAgaGVyZSBpbiB0aGlzIG1hbm5lciwgYXMgd2UgYXJlIGFzc2VydGluZyB1c2luZyBgdHlwZW9mYCBmaXJzdAogICAgLy8gd2hpY2ggd29uJ3QgdGhyb3cgaWYgdGhleSBhcmUgbm90IHByZXNlbnQuCgogICAgaWYgKHR5cGVvZiBnbG9iYWwgIT09ICd1bmRlZmluZWQnICYmIHZhbHVlID09PSBnbG9iYWwpIHsKICAgICAgcmV0dXJuICdbR2xvYmFsXSc7CiAgICB9CgogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXJlc3RyaWN0ZWQtZ2xvYmFscwogICAgaWYgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHZhbHVlID09PSB3aW5kb3cpIHsKICAgICAgcmV0dXJuICdbV2luZG93XSc7CiAgICB9CgogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXJlc3RyaWN0ZWQtZ2xvYmFscwogICAgaWYgKHR5cGVvZiBkb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgdmFsdWUgPT09IGRvY3VtZW50KSB7CiAgICAgIHJldHVybiAnW0RvY3VtZW50XSc7CiAgICB9CgogICAgaWYgKGlzVnVlVmlld01vZGVsKHZhbHVlKSkgewogICAgICByZXR1cm4gJ1tWdWVWaWV3TW9kZWxdJzsKICAgIH0KCiAgICAvLyBSZWFjdCdzIFN5bnRoZXRpY0V2ZW50IHRoaW5neQogICAgaWYgKGlzU3ludGhldGljRXZlbnQodmFsdWUpKSB7CiAgICAgIHJldHVybiAnW1N5bnRoZXRpY0V2ZW50XSc7CiAgICB9CgogICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgJiYgdmFsdWUgIT09IHZhbHVlKSB7CiAgICAgIHJldHVybiAnW05hTl0nOwogICAgfQoKICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicpIHsKICAgICAgcmV0dXJuIGBbRnVuY3Rpb246ICR7Z2V0RnVuY3Rpb25OYW1lKHZhbHVlKX1dYDsKICAgIH0KCiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3ltYm9sJykgewogICAgICByZXR1cm4gYFske1N0cmluZyh2YWx1ZSl9XWA7CiAgICB9CgogICAgLy8gc3RyaW5naWZpZWQgQmlnSW50cyBhcmUgaW5kaXN0aW5ndWlzaGFibGUgZnJvbSByZWd1bGFyIG51bWJlcnMsIHNvIHdlIG5lZWQgdG8gbGFiZWwgdGhlbSB0byBhdm9pZCBjb25mdXNpb24KICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdiaWdpbnQnKSB7CiAgICAgIHJldHVybiBgW0JpZ0ludDogJHtTdHJpbmcodmFsdWUpfV1gOwogICAgfQoKICAgIC8vIE5vdyB0aGF0IHdlJ3ZlIGtub2NrZWQgb3V0IGFsbCB0aGUgc3BlY2lhbCBjYXNlcyBhbmQgdGhlIHByaW1pdGl2ZXMsIGFsbCB3ZSBoYXZlIGxlZnQgYXJlIG9iamVjdHMuIFNpbXBseSBjYXN0aW5nCiAgICAvLyB0aGVtIHRvIHN0cmluZ3MgbWVhbnMgdGhhdCBpbnN0YW5jZXMgb2YgY2xhc3NlcyB3aGljaCBoYXZlbid0IGRlZmluZWQgdGhlaXIgYHRvU3RyaW5nVGFnYCB3aWxsIGp1c3QgY29tZSBvdXQgYXMKICAgIC8vIGAiW29iamVjdCBPYmplY3RdImAuIElmIHdlIGluc3RlYWQgbG9vayBhdCB0aGUgY29uc3RydWN0b3IncyBuYW1lICh3aGljaCBpcyB0aGUgc2FtZSBhcyB0aGUgbmFtZSBvZiB0aGUgY2xhc3MpLAogICAgLy8gd2UgY2FuIG1ha2Ugc3VyZSB0aGF0IG9ubHkgcGxhaW4gb2JqZWN0cyBjb21lIG91dCB0aGF0IHdheS4KICAgIGNvbnN0IG9iak5hbWUgPSBnZXRDb25zdHJ1Y3Rvck5hbWUodmFsdWUpOwoKICAgIC8vIEhhbmRsZSBIVE1MIEVsZW1lbnRzCiAgICBpZiAoL15IVE1MKFx3KilFbGVtZW50JC8udGVzdChvYmpOYW1lKSkgewogICAgICByZXR1cm4gYFtIVE1MRWxlbWVudDogJHtvYmpOYW1lfV1gOwogICAgfQoKICAgIHJldHVybiBgW29iamVjdCAke29iak5hbWV9XWA7CiAgfSBjYXRjaCAoZXJyKSB7CiAgICByZXR1cm4gYCoqbm9uLXNlcmlhbGl6YWJsZSoqICgke2Vycn0pYDsKICB9Cn0KLyogZXNsaW50LWVuYWJsZSBjb21wbGV4aXR5ICovCgpmdW5jdGlvbiBnZXRDb25zdHJ1Y3Rvck5hbWUodmFsdWUpIHsKICBjb25zdCBwcm90b3R5cGUgPSBPYmplY3QuZ2V0UHJvdG90eXBlT2YodmFsdWUpOwoKICByZXR1cm4gcHJvdG90eXBlID8gcHJvdG90eXBlLmNvbnN0cnVjdG9yLm5hbWUgOiAnbnVsbCBwcm90b3R5cGUnOwp9CgovKioKICogTm9ybWFsaXplcyBVUkxzIGluIGV4Y2VwdGlvbnMgYW5kIHN0YWNrdHJhY2VzIHRvIGEgYmFzZSBwYXRoIHNvIFNlbnRyeSBjYW4gZmluZ2VycHJpbnQKICogYWNyb3NzIHBsYXRmb3JtcyBhbmQgd29ya2luZyBkaXJlY3RvcnkuCiAqCiAqIEBwYXJhbSB1cmwgVGhlIFVSTCB0byBiZSBub3JtYWxpemVkLgogKiBAcGFyYW0gYmFzZVBhdGggVGhlIGFwcGxpY2F0aW9uIGJhc2UgcGF0aC4KICogQHJldHVybnMgVGhlIG5vcm1hbGl6ZWQgVVJMLgogKi8KZnVuY3Rpb24gbm9ybWFsaXplVXJsVG9CYXNlKHVybCwgYmFzZVBhdGgpIHsKICBjb25zdCBlc2NhcGVkQmFzZSA9IGJhc2VQYXRoCiAgICAvLyBCYWNrc2xhc2ggdG8gZm9yd2FyZAogICAgLnJlcGxhY2UoL1xcL2csICcvJykKICAgIC8vIEVzY2FwZSBSZWdFeHAgc3BlY2lhbCBjaGFyYWN0ZXJzCiAgICAucmVwbGFjZSgvW3xcXHt9KClbXF1eJCsqPy5dL2csICdcXCQmJyk7CgogIGxldCBuZXdVcmwgPSB1cmw7CiAgdHJ5IHsKICAgIG5ld1VybCA9IGRlY29kZVVSSSh1cmwpOwogIH0gY2F0Y2ggKF9PbykgewogICAgLy8gU29tZXRpbWUgdGhpcyBicmVha3MKICB9CiAgcmV0dXJuICgKICAgIG5ld1VybAogICAgICAucmVwbGFjZSgvXFwvZywgJy8nKQogICAgICAucmVwbGFjZSgvd2VicGFjazpcLz8vZywgJycpIC8vIFJlbW92ZSBpbnRlcm1lZGlhdGUgYmFzZSBwYXRoCiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAc2VudHJ5LWludGVybmFsL3Nkay9uby1yZWdleHAtY29uc3RydWN0b3IKICAgICAgLnJlcGxhY2UobmV3IFJlZ0V4cChgKGZpbGU6Ly8pPy8qJHtlc2NhcGVkQmFzZX0vKmAsICdpZycpLCAnYXBwOi8vLycpCiAgKTsKfQoKLy8gU2xpZ2h0bHkgbW9kaWZpZWQgKG5vIElFOCBzdXBwb3J0LCBFUzYpIGFuZCB0cmFuc2NyaWJlZCB0byBUeXBlU2NyaXB0Ci8vIGh0dHBzOi8vZ2l0aHViLmNvbS9jYWx2aW5tZXRjYWxmL3JvbGx1cC1wbHVnaW4tbm9kZS1idWlsdGlucy9ibG9iLzYzYWI4YWFjZDAxMzc2NzQ0NWNhMjk5ZTQ2OGQ5YTYwYTk1MzI4ZDcvc3JjL2VzNi9wYXRoLmpzCi8vCi8vIENvcHlyaWdodCBKb3llbnQsIEluYy5hbmQgb3RoZXIgTm9kZSBjb250cmlidXRvcnMuCi8vCi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhCi8vIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUKLy8gIlNvZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZwovLyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsCi8vIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQKLy8gcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlCi8vIGZvbGxvd2luZyBjb25kaXRpb25zOgovLwovLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZAovLyBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KLy8KLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MKLy8gT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRgovLyBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOCi8vIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLAovLyBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IKLy8gT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRQovLyBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgoKCi8vIFNwbGl0IGEgZmlsZW5hbWUgaW50byBbcm9vdCwgZGlyLCBiYXNlbmFtZSwgZXh0XSwgdW5peCB2ZXJzaW9uCi8vICdyb290JyBpcyBqdXN0IGEgc2xhc2gsIG9yIG5vdGhpbmcuCmNvbnN0IHNwbGl0UGF0aFJlID0gL14oXFMrOlxcfFwvPykoW1xzXFNdKj8pKCg/OlwuezEsMn18W14vXFxdKz98KShcLlteLi9cXF0qfCkpKD86Wy9cXF0qKSQvOwovKiogSlNEb2MgKi8KZnVuY3Rpb24gc3BsaXRQYXRoKGZpbGVuYW1lKSB7CiAgLy8gVHJ1bmNhdGUgZmlsZXMgbmFtZXMgZ3JlYXRlciB0aGFuIDEwMjQgY2hhcmFjdGVycyB0byBhdm9pZCByZWdleCBkb3MKICAvLyBodHRwczovL2dpdGh1Yi5jb20vZ2V0c2VudHJ5L3NlbnRyeS1qYXZhc2NyaXB0L3B1bGwvODczNyNkaXNjdXNzaW9uX3IxMjg1NzE5MTcyCiAgY29uc3QgdHJ1bmNhdGVkID0gZmlsZW5hbWUubGVuZ3RoID4gMTAyNCA/IGA8dHJ1bmNhdGVkPiR7ZmlsZW5hbWUuc2xpY2UoLTEwMjQpfWAgOiBmaWxlbmFtZTsKICBjb25zdCBwYXJ0cyA9IHNwbGl0UGF0aFJlLmV4ZWModHJ1bmNhdGVkKTsKICByZXR1cm4gcGFydHMgPyBwYXJ0cy5zbGljZSgxKSA6IFtdOwp9CgovKiogSlNEb2MgKi8KZnVuY3Rpb24gZGlybmFtZShwYXRoKSB7CiAgY29uc3QgcmVzdWx0ID0gc3BsaXRQYXRoKHBhdGgpOwogIGNvbnN0IHJvb3QgPSByZXN1bHRbMF07CiAgbGV0IGRpciA9IHJlc3VsdFsxXTsKCiAgaWYgKCFyb290ICYmICFkaXIpIHsKICAgIC8vIE5vIGRpcm5hbWUgd2hhdHNvZXZlcgogICAgcmV0dXJuICcuJzsKICB9CgogIGlmIChkaXIpIHsKICAgIC8vIEl0IGhhcyBhIGRpcm5hbWUsIHN0cmlwIHRyYWlsaW5nIHNsYXNoCiAgICBkaXIgPSBkaXIuc2xpY2UoMCwgZGlyLmxlbmd0aCAtIDEpOwogIH0KCiAgcmV0dXJuIHJvb3QgKyBkaXI7Cn0KCi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9leHBsaWNpdC1mdW5jdGlvbi1yZXR1cm4tdHlwZSAqLwovKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55ICovCgovKiogU3luY1Byb21pc2UgaW50ZXJuYWwgc3RhdGVzICovCnZhciBTdGF0ZXM7IChmdW5jdGlvbiAoU3RhdGVzKSB7CiAgLyoqIFBlbmRpbmcgKi8KICBjb25zdCBQRU5ESU5HID0gMDsgU3RhdGVzW1N0YXRlc1siUEVORElORyJdID0gUEVORElOR10gPSAiUEVORElORyI7CiAgLyoqIFJlc29sdmVkIC8gT0sgKi8KICBjb25zdCBSRVNPTFZFRCA9IDE7IFN0YXRlc1tTdGF0ZXNbIlJFU09MVkVEIl0gPSBSRVNPTFZFRF0gPSAiUkVTT0xWRUQiOwogIC8qKiBSZWplY3RlZCAvIEVycm9yICovCiAgY29uc3QgUkVKRUNURUQgPSAyOyBTdGF0ZXNbU3RhdGVzWyJSRUpFQ1RFRCJdID0gUkVKRUNURURdID0gIlJFSkVDVEVEIjsKfSkoU3RhdGVzIHx8IChTdGF0ZXMgPSB7fSkpOwoKLy8gT3ZlcmxvYWRzIHNvIHdlIGNhbiBjYWxsIHJlc29sdmVkU3luY1Byb21pc2Ugd2l0aG91dCBhcmd1bWVudHMgYW5kIGdlbmVyaWMgYXJndW1lbnQKCi8qKgogKiBDcmVhdGVzIGEgcmVzb2x2ZWQgc3luYyBwcm9taXNlLgogKgogKiBAcGFyYW0gdmFsdWUgdGhlIHZhbHVlIHRvIHJlc29sdmUgdGhlIHByb21pc2Ugd2l0aAogKiBAcmV0dXJucyB0aGUgcmVzb2x2ZWQgc3luYyBwcm9taXNlCiAqLwpmdW5jdGlvbiByZXNvbHZlZFN5bmNQcm9taXNlKHZhbHVlKSB7CiAgcmV0dXJuIG5ldyBTeW5jUHJvbWlzZShyZXNvbHZlID0+IHsKICAgIHJlc29sdmUodmFsdWUpOwogIH0pOwp9CgovKioKICogQ3JlYXRlcyBhIHJlamVjdGVkIHN5bmMgcHJvbWlzZS4KICoKICogQHBhcmFtIHZhbHVlIHRoZSB2YWx1ZSB0byByZWplY3QgdGhlIHByb21pc2Ugd2l0aAogKiBAcmV0dXJucyB0aGUgcmVqZWN0ZWQgc3luYyBwcm9taXNlCiAqLwpmdW5jdGlvbiByZWplY3RlZFN5bmNQcm9taXNlKHJlYXNvbikgewogIHJldHVybiBuZXcgU3luY1Byb21pc2UoKF8sIHJlamVjdCkgPT4gewogICAgcmVqZWN0KHJlYXNvbik7CiAgfSk7Cn0KCi8qKgogKiBUaGVuYWJsZSBjbGFzcyB0aGF0IGJlaGF2ZXMgbGlrZSBhIFByb21pc2UgYW5kIGZvbGxvd3MgaXQncyBpbnRlcmZhY2UKICogYnV0IGlzIG5vdCBhc3luYyBpbnRlcm5hbGx5CiAqLwpjbGFzcyBTeW5jUHJvbWlzZSB7CgogICBjb25zdHJ1Y3RvcigKICAgIGV4ZWN1dG9yLAogICkge1N5bmNQcm9taXNlLnByb3RvdHlwZS5fX2luaXQuY2FsbCh0aGlzKTtTeW5jUHJvbWlzZS5wcm90b3R5cGUuX19pbml0Mi5jYWxsKHRoaXMpO1N5bmNQcm9taXNlLnByb3RvdHlwZS5fX2luaXQzLmNhbGwodGhpcyk7U3luY1Byb21pc2UucHJvdG90eXBlLl9faW5pdDQuY2FsbCh0aGlzKTsKICAgIHRoaXMuX3N0YXRlID0gU3RhdGVzLlBFTkRJTkc7CiAgICB0aGlzLl9oYW5kbGVycyA9IFtdOwoKICAgIHRyeSB7CiAgICAgIGV4ZWN1dG9yKHRoaXMuX3Jlc29sdmUsIHRoaXMuX3JlamVjdCk7CiAgICB9IGNhdGNoIChlKSB7CiAgICAgIHRoaXMuX3JlamVjdChlKTsKICAgIH0KICB9CgogIC8qKiBKU0RvYyAqLwogICB0aGVuKAogICAgb25mdWxmaWxsZWQsCiAgICBvbnJlamVjdGVkLAogICkgewogICAgcmV0dXJuIG5ldyBTeW5jUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7CiAgICAgIHRoaXMuX2hhbmRsZXJzLnB1c2goWwogICAgICAgIGZhbHNlLAogICAgICAgIHJlc3VsdCA9PiB7CiAgICAgICAgICBpZiAoIW9uZnVsZmlsbGVkKSB7CiAgICAgICAgICAgIC8vIFRPRE86IMKvXF8o44OEKV8vwq8KICAgICAgICAgICAgLy8gVE9ETzogRklYTUUKICAgICAgICAgICAgcmVzb2x2ZShyZXN1bHQgKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgcmVzb2x2ZShvbmZ1bGZpbGxlZChyZXN1bHQpKTsKICAgICAgICAgICAgfSBjYXRjaCAoZSkgewogICAgICAgICAgICAgIHJlamVjdChlKTsKICAgICAgICAgICAgfQogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgcmVhc29uID0+IHsKICAgICAgICAgIGlmICghb25yZWplY3RlZCkgewogICAgICAgICAgICByZWplY3QocmVhc29uKTsKICAgICAgICAgIH0gZWxzZSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgcmVzb2x2ZShvbnJlamVjdGVkKHJlYXNvbikpOwogICAgICAgICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgICAgICAgcmVqZWN0KGUpOwogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgXSk7CiAgICAgIHRoaXMuX2V4ZWN1dGVIYW5kbGVycygpOwogICAgfSk7CiAgfQoKICAvKiogSlNEb2MgKi8KICAgY2F0Y2goCiAgICBvbnJlamVjdGVkLAogICkgewogICAgcmV0dXJuIHRoaXMudGhlbih2YWwgPT4gdmFsLCBvbnJlamVjdGVkKTsKICB9CgogIC8qKiBKU0RvYyAqLwogICBmaW5hbGx5KG9uZmluYWxseSkgewogICAgcmV0dXJuIG5ldyBTeW5jUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7CiAgICAgIGxldCB2YWw7CiAgICAgIGxldCBpc1JlamVjdGVkOwoKICAgICAgcmV0dXJuIHRoaXMudGhlbigKICAgICAgICB2YWx1ZSA9PiB7CiAgICAgICAgICBpc1JlamVjdGVkID0gZmFsc2U7CiAgICAgICAgICB2YWwgPSB2YWx1ZTsKICAgICAgICAgIGlmIChvbmZpbmFsbHkpIHsKICAgICAgICAgICAgb25maW5hbGx5KCk7CiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICByZWFzb24gPT4gewogICAgICAgICAgaXNSZWplY3RlZCA9IHRydWU7CiAgICAgICAgICB2YWwgPSByZWFzb247CiAgICAgICAgICBpZiAob25maW5hbGx5KSB7CiAgICAgICAgICAgIG9uZmluYWxseSgpOwogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICkudGhlbigoKSA9PiB7CiAgICAgICAgaWYgKGlzUmVqZWN0ZWQpIHsKICAgICAgICAgIHJlamVjdCh2YWwpOwogICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KCiAgICAgICAgcmVzb2x2ZSh2YWwgKTsKICAgICAgfSk7CiAgICB9KTsKICB9CgogIC8qKiBKU0RvYyAqLwogICAgX19pbml0KCkge3RoaXMuX3Jlc29sdmUgPSAodmFsdWUpID0+IHsKICAgIHRoaXMuX3NldFJlc3VsdChTdGF0ZXMuUkVTT0xWRUQsIHZhbHVlKTsKICB9O30KCiAgLyoqIEpTRG9jICovCiAgICBfX2luaXQyKCkge3RoaXMuX3JlamVjdCA9IChyZWFzb24pID0+IHsKICAgIHRoaXMuX3NldFJlc3VsdChTdGF0ZXMuUkVKRUNURUQsIHJlYXNvbik7CiAgfTt9CgogIC8qKiBKU0RvYyAqLwogICAgX19pbml0MygpIHt0aGlzLl9zZXRSZXN1bHQgPSAoc3RhdGUsIHZhbHVlKSA9PiB7CiAgICBpZiAodGhpcy5fc3RhdGUgIT09IFN0YXRlcy5QRU5ESU5HKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICBpZiAoaXNUaGVuYWJsZSh2YWx1ZSkpIHsKICAgICAgdm9pZCAodmFsdWUgKS50aGVuKHRoaXMuX3Jlc29sdmUsIHRoaXMuX3JlamVjdCk7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICB0aGlzLl9zdGF0ZSA9IHN0YXRlOwogICAgdGhpcy5fdmFsdWUgPSB2YWx1ZTsKCiAgICB0aGlzLl9leGVjdXRlSGFuZGxlcnMoKTsKICB9O30KCiAgLyoqIEpTRG9jICovCiAgICBfX2luaXQ0KCkge3RoaXMuX2V4ZWN1dGVIYW5kbGVycyA9ICgpID0+IHsKICAgIGlmICh0aGlzLl9zdGF0ZSA9PT0gU3RhdGVzLlBFTkRJTkcpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIGNvbnN0IGNhY2hlZEhhbmRsZXJzID0gdGhpcy5faGFuZGxlcnMuc2xpY2UoKTsKICAgIHRoaXMuX2hhbmRsZXJzID0gW107CgogICAgY2FjaGVkSGFuZGxlcnMuZm9yRWFjaChoYW5kbGVyID0+IHsKICAgICAgaWYgKGhhbmRsZXJbMF0pIHsKICAgICAgICByZXR1cm47CiAgICAgIH0KCiAgICAgIGlmICh0aGlzLl9zdGF0ZSA9PT0gU3RhdGVzLlJFU09MVkVEKSB7CiAgICAgICAgaGFuZGxlclsxXSh0aGlzLl92YWx1ZSApOwogICAgICB9CgogICAgICBpZiAodGhpcy5fc3RhdGUgPT09IFN0YXRlcy5SRUpFQ1RFRCkgewogICAgICAgIGhhbmRsZXJbMl0odGhpcy5fdmFsdWUpOwogICAgICB9CgogICAgICBoYW5kbGVyWzBdID0gdHJ1ZTsKICAgIH0pOwogIH07fQp9CgovKioKICogQ3JlYXRlcyBhbiBuZXcgUHJvbWlzZUJ1ZmZlciBvYmplY3Qgd2l0aCB0aGUgc3BlY2lmaWVkIGxpbWl0CiAqIEBwYXJhbSBsaW1pdCBtYXggbnVtYmVyIG9mIHByb21pc2VzIHRoYXQgY2FuIGJlIHN0b3JlZCBpbiB0aGUgYnVmZmVyCiAqLwpmdW5jdGlvbiBtYWtlUHJvbWlzZUJ1ZmZlcihsaW1pdCkgewogIGNvbnN0IGJ1ZmZlciA9IFtdOwoKICBmdW5jdGlvbiBpc1JlYWR5KCkgewogICAgcmV0dXJuIGxpbWl0ID09PSB1bmRlZmluZWQgfHwgYnVmZmVyLmxlbmd0aCA8IGxpbWl0OwogIH0KCiAgLyoqCiAgICogUmVtb3ZlIGEgcHJvbWlzZSBmcm9tIHRoZSBxdWV1ZS4KICAgKgogICAqIEBwYXJhbSB0YXNrIENhbiBiZSBhbnkgUHJvbWlzZUxpa2U8VD4KICAgKiBAcmV0dXJucyBSZW1vdmVkIHByb21pc2UuCiAgICovCiAgZnVuY3Rpb24gcmVtb3ZlKHRhc2spIHsKICAgIHJldHVybiBidWZmZXIuc3BsaWNlKGJ1ZmZlci5pbmRleE9mKHRhc2spLCAxKVswXTsKICB9CgogIC8qKgogICAqIEFkZCBhIHByb21pc2UgKHJlcHJlc2VudGluZyBhbiBpbi1mbGlnaHQgYWN0aW9uKSB0byB0aGUgcXVldWUsIGFuZCBzZXQgaXQgdG8gcmVtb3ZlIGl0c2VsZiBvbiBmdWxmaWxsbWVudC4KICAgKgogICAqIEBwYXJhbSB0YXNrUHJvZHVjZXIgQSBmdW5jdGlvbiBwcm9kdWNpbmcgYW55IFByb21pc2VMaWtlPFQ+OyBJbiBwcmV2aW91cyB2ZXJzaW9ucyB0aGlzIHVzZWQgdG8gYmUgYHRhc2s6CiAgICogICAgICAgIFByb21pc2VMaWtlPFQ+YCwgYnV0IHVuZGVyIHRoYXQgbW9kZWwsIFByb21pc2VzIHdlcmUgaW5zdGFudGx5IGNyZWF0ZWQgb24gdGhlIGNhbGwtc2l0ZSBhbmQgdGhlaXIgZXhlY3V0b3IKICAgKiAgICAgICAgZnVuY3Rpb25zIHRoZXJlZm9yZSByYW4gaW1tZWRpYXRlbHkuIFRodXMsIGV2ZW4gaWYgdGhlIGJ1ZmZlciB3YXMgZnVsbCwgdGhlIGFjdGlvbiBzdGlsbCBoYXBwZW5lZC4gQnkKICAgKiAgICAgICAgcmVxdWlyaW5nIHRoZSBwcm9taXNlIHRvIGJlIHdyYXBwZWQgaW4gYSBmdW5jdGlvbiwgd2UgY2FuIGRlZmVyIHByb21pc2UgY3JlYXRpb24gdW50aWwgYWZ0ZXIgdGhlIGJ1ZmZlcgogICAqICAgICAgICBsaW1pdCBjaGVjay4KICAgKiBAcmV0dXJucyBUaGUgb3JpZ2luYWwgcHJvbWlzZS4KICAgKi8KICBmdW5jdGlvbiBhZGQodGFza1Byb2R1Y2VyKSB7CiAgICBpZiAoIWlzUmVhZHkoKSkgewogICAgICByZXR1cm4gcmVqZWN0ZWRTeW5jUHJvbWlzZShuZXcgU2VudHJ5RXJyb3IoJ05vdCBhZGRpbmcgUHJvbWlzZSBiZWNhdXNlIGJ1ZmZlciBsaW1pdCB3YXMgcmVhY2hlZC4nKSk7CiAgICB9CgogICAgLy8gc3RhcnQgdGhlIHRhc2sgYW5kIGFkZCBpdHMgcHJvbWlzZSB0byB0aGUgcXVldWUKICAgIGNvbnN0IHRhc2sgPSB0YXNrUHJvZHVjZXIoKTsKICAgIGlmIChidWZmZXIuaW5kZXhPZih0YXNrKSA9PT0gLTEpIHsKICAgICAgYnVmZmVyLnB1c2godGFzayk7CiAgICB9CiAgICB2b2lkIHRhc2sKICAgICAgLnRoZW4oKCkgPT4gcmVtb3ZlKHRhc2spKQogICAgICAvLyBVc2UgYHRoZW4obnVsbCwgcmVqZWN0aW9uSGFuZGxlcilgIHJhdGhlciB0aGFuIGBjYXRjaChyZWplY3Rpb25IYW5kbGVyKWAgc28gdGhhdCB3ZSBjYW4gdXNlIGBQcm9taXNlTGlrZWAKICAgICAgLy8gcmF0aGVyIHRoYW4gYFByb21pc2VgLiBgUHJvbWlzZUxpa2VgIGRvZXNuJ3QgaGF2ZSBhIGAuY2F0Y2hgIG1ldGhvZCwgbWFraW5nIGl0cyBwb2x5ZmlsbCBzbWFsbGVyLiAoRVM1IGRpZG4ndAogICAgICAvLyBoYXZlIHByb21pc2VzLCBzbyBUUyBoYXMgdG8gcG9seWZpbGwgd2hlbiBkb3duLWNvbXBpbGluZy4pCiAgICAgIC50aGVuKG51bGwsICgpID0+CiAgICAgICAgcmVtb3ZlKHRhc2spLnRoZW4obnVsbCwgKCkgPT4gewogICAgICAgICAgLy8gV2UgaGF2ZSB0byBhZGQgYW5vdGhlciBjYXRjaCBoZXJlIGJlY2F1c2UgYHJlbW92ZSgpYCBzdGFydHMgYSBuZXcgcHJvbWlzZSBjaGFpbi4KICAgICAgICB9KSwKICAgICAgKTsKICAgIHJldHVybiB0YXNrOwogIH0KCiAgLyoqCiAgICogV2FpdCBmb3IgYWxsIHByb21pc2VzIGluIHRoZSBxdWV1ZSB0byByZXNvbHZlIG9yIGZvciB0aW1lb3V0IHRvIGV4cGlyZSwgd2hpY2hldmVyIGNvbWVzIGZpcnN0LgogICAqCiAgICogQHBhcmFtIHRpbWVvdXQgVGhlIHRpbWUsIGluIG1zLCBhZnRlciB3aGljaCB0byByZXNvbHZlIHRvIGBmYWxzZWAgaWYgdGhlIHF1ZXVlIGlzIHN0aWxsIG5vbi1lbXB0eS4gUGFzc2luZyBgMGAgKG9yCiAgICogbm90IHBhc3NpbmcgYW55dGhpbmcpIHdpbGwgbWFrZSB0aGUgcHJvbWlzZSB3YWl0IGFzIGxvbmcgYXMgaXQgdGFrZXMgZm9yIHRoZSBxdWV1ZSB0byBkcmFpbiBiZWZvcmUgcmVzb2x2aW5nIHRvCiAgICogYHRydWVgLgogICAqIEByZXR1cm5zIEEgcHJvbWlzZSB3aGljaCB3aWxsIHJlc29sdmUgdG8gYHRydWVgIGlmIHRoZSBxdWV1ZSBpcyBhbHJlYWR5IGVtcHR5IG9yIGRyYWlucyBiZWZvcmUgdGhlIHRpbWVvdXQsIGFuZAogICAqIGBmYWxzZWAgb3RoZXJ3aXNlCiAgICovCiAgZnVuY3Rpb24gZHJhaW4odGltZW91dCkgewogICAgcmV0dXJuIG5ldyBTeW5jUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7CiAgICAgIGxldCBjb3VudGVyID0gYnVmZmVyLmxlbmd0aDsKCiAgICAgIGlmICghY291bnRlcikgewogICAgICAgIHJldHVybiByZXNvbHZlKHRydWUpOwogICAgICB9CgogICAgICAvLyB3YWl0IGZvciBgdGltZW91dGAgbXMgYW5kIHRoZW4gcmVzb2x2ZSB0byBgZmFsc2VgIChpZiBub3QgY2FuY2VsbGVkIGZpcnN0KQogICAgICBjb25zdCBjYXB0dXJlZFNldFRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHsKICAgICAgICBpZiAodGltZW91dCAmJiB0aW1lb3V0ID4gMCkgewogICAgICAgICAgcmVzb2x2ZShmYWxzZSk7CiAgICAgICAgfQogICAgICB9LCB0aW1lb3V0KTsKCiAgICAgIC8vIGlmIGFsbCBwcm9taXNlcyByZXNvbHZlIGluIHRpbWUsIGNhbmNlbCB0aGUgdGltZXIgYW5kIHJlc29sdmUgdG8gYHRydWVgCiAgICAgIGJ1ZmZlci5mb3JFYWNoKGl0ZW0gPT4gewogICAgICAgIHZvaWQgcmVzb2x2ZWRTeW5jUHJvbWlzZShpdGVtKS50aGVuKCgpID0+IHsKICAgICAgICAgIGlmICghLS1jb3VudGVyKSB7CiAgICAgICAgICAgIGNsZWFyVGltZW91dChjYXB0dXJlZFNldFRpbWVvdXQpOwogICAgICAgICAgICByZXNvbHZlKHRydWUpOwogICAgICAgICAgfQogICAgICAgIH0sIHJlamVjdCk7CiAgICAgIH0pOwogICAgfSk7CiAgfQoKICByZXR1cm4gewogICAgJDogYnVmZmVyLAogICAgYWRkLAogICAgZHJhaW4sCiAgfTsKfQoKLyoqCiAqIERvZXMgdGhpcyBmaWxlbmFtZSBsb29rIGxpa2UgaXQncyBwYXJ0IG9mIHRoZSBhcHAgY29kZT8KICovCmZ1bmN0aW9uIGZpbGVuYW1lSXNJbkFwcChmaWxlbmFtZSwgaXNOYXRpdmUgPSBmYWxzZSkgewogIGNvbnN0IGlzSW50ZXJuYWwgPQogICAgaXNOYXRpdmUgfHwKICAgIChmaWxlbmFtZSAmJgogICAgICAvLyBJdCdzIG5vdCBpbnRlcm5hbCBpZiBpdCdzIGFuIGFic29sdXRlIGxpbnV4IHBhdGgKICAgICAgIWZpbGVuYW1lLnN0YXJ0c1dpdGgoJy8nKSAmJgogICAgICAvLyBJdCdzIG5vdCBpbnRlcm5hbCBpZiBpdCdzIGFuIGFic29sdXRlIHdpbmRvd3MgcGF0aAogICAgICAhZmlsZW5hbWUubWF0Y2goL15bQS1aXTovKSAmJgogICAgICAvLyBJdCdzIG5vdCBpbnRlcm5hbCBpZiB0aGUgcGF0aCBpcyBzdGFydGluZyB3aXRoIGEgZG90CiAgICAgICFmaWxlbmFtZS5zdGFydHNXaXRoKCcuJykgJiYKICAgICAgLy8gSXQncyBub3QgaW50ZXJuYWwgaWYgdGhlIGZyYW1lIGhhcyBhIHByb3RvY29sLiBJbiBub2RlLCB0aGlzIGlzIHVzdWFsbHkgdGhlIGNhc2UgaWYgdGhlIGZpbGUgZ290IHByZS1wcm9jZXNzZWQgd2l0aCBhIGJ1bmRsZXIgbGlrZSB3ZWJwYWNrCiAgICAgICFmaWxlbmFtZS5tYXRjaCgvXlthLXpBLVpdKFthLXpBLVowLTkuXC0rXSkqOlwvXC8vKSk7IC8vIFNjaGVtYSBmcm9tOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzY0MTc4MgoKICAvLyBpbl9hcHAgaXMgYWxsIHRoYXQncyBub3QgYW4gaW50ZXJuYWwgTm9kZSBmdW5jdGlvbiBvciBhIG1vZHVsZSB3aXRoaW4gbm9kZV9tb2R1bGVzCiAgLy8gbm90ZSB0aGF0IGlzTmF0aXZlIGFwcGVhcnMgdG8gcmV0dXJuIHRydWUgZXZlbiBmb3Igbm9kZSBjb3JlIGxpYnJhcmllcwogIC8vIHNlZSBodHRwczovL2dpdGh1Yi5jb20vZ2V0c2VudHJ5L3JhdmVuLW5vZGUvaXNzdWVzLzE3NgoKICByZXR1cm4gIWlzSW50ZXJuYWwgJiYgZmlsZW5hbWUgIT09IHVuZGVmaW5lZCAmJiAhZmlsZW5hbWUuaW5jbHVkZXMoJ25vZGVfbW9kdWxlcy8nKTsKfQoKY29uc3QgT05FX1NFQ09ORF9JTl9NUyA9IDEwMDA7CgovKioKICogQSBwYXJ0aWFsIGRlZmluaXRpb24gb2YgdGhlIFtQZXJmb3JtYW5jZSBXZWIgQVBJXXtAbGluayBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvUGVyZm9ybWFuY2V9CiAqIGZvciBhY2Nlc3NpbmcgYSBoaWdoLXJlc29sdXRpb24gbW9ub3RvbmljIGNsb2NrLgogKi8KCi8qKgogKiBSZXR1cm5zIGEgdGltZXN0YW1wIGluIHNlY29uZHMgc2luY2UgdGhlIFVOSVggZXBvY2ggdXNpbmcgdGhlIERhdGUgQVBJLgogKgogKiBUT0RPKHY4KTogUmV0dXJuIHR5cGUgc2hvdWxkIGJlIHJvdW5kZWQuCiAqLwpmdW5jdGlvbiBkYXRlVGltZXN0YW1wSW5TZWNvbmRzKCkgewogIHJldHVybiBEYXRlLm5vdygpIC8gT05FX1NFQ09ORF9JTl9NUzsKfQoKLyoqCiAqIFJldHVybnMgYSB3cmFwcGVyIGFyb3VuZCB0aGUgbmF0aXZlIFBlcmZvcm1hbmNlIEFQSSBicm93c2VyIGltcGxlbWVudGF0aW9uLCBvciB1bmRlZmluZWQgZm9yIGJyb3dzZXJzIHRoYXQgZG8gbm90CiAqIHN1cHBvcnQgdGhlIEFQSS4KICoKICogV3JhcHBpbmcgdGhlIG5hdGl2ZSBBUEkgd29ya3MgYXJvdW5kIGRpZmZlcmVuY2VzIGluIGJlaGF2aW9yIGZyb20gZGlmZmVyZW50IGJyb3dzZXJzLgogKi8KZnVuY3Rpb24gY3JlYXRlVW5peFRpbWVzdGFtcEluU2Vjb25kc0Z1bmMoKSB7CiAgY29uc3QgeyBwZXJmb3JtYW5jZSB9ID0gR0xPQkFMX09CSiA7CiAgaWYgKCFwZXJmb3JtYW5jZSB8fCAhcGVyZm9ybWFuY2Uubm93KSB7CiAgICByZXR1cm4gZGF0ZVRpbWVzdGFtcEluU2Vjb25kczsKICB9CgogIC8vIFNvbWUgYnJvd3NlciBhbmQgZW52aXJvbm1lbnRzIGRvbid0IGhhdmUgYSB0aW1lT3JpZ2luLCBzbyB3ZSBmYWxsYmFjayB0bwogIC8vIHVzaW5nIERhdGUubm93KCkgdG8gY29tcHV0ZSB0aGUgc3RhcnRpbmcgdGltZS4KICBjb25zdCBhcHByb3hTdGFydGluZ1RpbWVPcmlnaW4gPSBEYXRlLm5vdygpIC0gcGVyZm9ybWFuY2Uubm93KCk7CiAgY29uc3QgdGltZU9yaWdpbiA9IHBlcmZvcm1hbmNlLnRpbWVPcmlnaW4gPT0gdW5kZWZpbmVkID8gYXBwcm94U3RhcnRpbmdUaW1lT3JpZ2luIDogcGVyZm9ybWFuY2UudGltZU9yaWdpbjsKCiAgLy8gcGVyZm9ybWFuY2Uubm93KCkgaXMgYSBtb25vdG9uaWMgY2xvY2ssIHdoaWNoIG1lYW5zIGl0IHN0YXJ0cyBhdCAwIHdoZW4gdGhlIHByb2Nlc3MgYmVnaW5zLiBUbyBnZXQgdGhlIGN1cnJlbnQKICAvLyB3YWxsIGNsb2NrIHRpbWUgKGFjdHVhbCBVTklYIHRpbWVzdGFtcCksIHdlIG5lZWQgdG8gYWRkIHRoZSBzdGFydGluZyB0aW1lIG9yaWdpbiBhbmQgdGhlIGN1cnJlbnQgdGltZSBlbGFwc2VkLgogIC8vCiAgLy8gVE9ETzogVGhpcyBkb2VzIG5vdCBhY2NvdW50IGZvciB0aGUgY2FzZSB3aGVyZSB0aGUgbW9ub3RvbmljIGNsb2NrIHRoYXQgcG93ZXJzIHBlcmZvcm1hbmNlLm5vdygpIGRyaWZ0cyBmcm9tIHRoZQogIC8vIHdhbGwgY2xvY2sgdGltZSwgd2hpY2ggY2F1c2VzIHRoZSByZXR1cm5lZCB0aW1lc3RhbXAgdG8gYmUgaW5hY2N1cmF0ZS4gV2Ugc2hvdWxkIGludmVzdGlnYXRlIGhvdyB0byBkZXRlY3QgYW5kCiAgLy8gY29ycmVjdCBmb3IgdGhpcy4KICAvLyBTZWU6IGh0dHBzOi8vZ2l0aHViLmNvbS9nZXRzZW50cnkvc2VudHJ5LWphdmFzY3JpcHQvaXNzdWVzLzI1OTAKICAvLyBTZWU6IGh0dHBzOi8vZ2l0aHViLmNvbS9tZG4vY29udGVudC9pc3N1ZXMvNDcxMwogIC8vIFNlZTogaHR0cHM6Ly9kZXYudG8vbm9hbXIvd2hlbi1hLW1pbGxpc2Vjb25kLWlzLW5vdC1hLW1pbGxpc2Vjb25kLTNoNgogIHJldHVybiAoKSA9PiB7CiAgICByZXR1cm4gKHRpbWVPcmlnaW4gKyBwZXJmb3JtYW5jZS5ub3coKSkgLyBPTkVfU0VDT05EX0lOX01TOwogIH07Cn0KCi8qKgogKiBSZXR1cm5zIGEgdGltZXN0YW1wIGluIHNlY29uZHMgc2luY2UgdGhlIFVOSVggZXBvY2ggdXNpbmcgZWl0aGVyIHRoZSBQZXJmb3JtYW5jZSBvciBEYXRlIEFQSXMsIGRlcGVuZGluZyBvbiB0aGUKICogYXZhaWxhYmlsaXR5IG9mIHRoZSBQZXJmb3JtYW5jZSBBUEkuCiAqCiAqIEJVRzogTm90ZSB0aGF0IGJlY2F1c2Ugb2YgaG93IGJyb3dzZXJzIGltcGxlbWVudCB0aGUgUGVyZm9ybWFuY2UgQVBJLCB0aGUgY2xvY2sgbWlnaHQgc3RvcCB3aGVuIHRoZSBjb21wdXRlciBpcwogKiBhc2xlZXAuIFRoaXMgY3JlYXRlcyBhIHNrZXcgYmV0d2VlbiBgZGF0ZVRpbWVzdGFtcEluU2Vjb25kc2AgYW5kIGB0aW1lc3RhbXBJblNlY29uZHNgLiBUaGUKICogc2tldyBjYW4gZ3JvdyB0byBhcmJpdHJhcnkgYW1vdW50cyBsaWtlIGRheXMsIHdlZWtzIG9yIG1vbnRocy4KICogU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9nZXRzZW50cnkvc2VudHJ5LWphdmFzY3JpcHQvaXNzdWVzLzI1OTAuCiAqLwpjb25zdCB0aW1lc3RhbXBJblNlY29uZHMgPSBjcmVhdGVVbml4VGltZXN0YW1wSW5TZWNvbmRzRnVuYygpOwoKLyoqCiAqIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHNpbmNlIHRoZSBVTklYIGVwb2NoLiBUaGlzIHZhbHVlIGlzIG9ubHkgdXNhYmxlIGluIGEgYnJvd3NlciwgYW5kIG9ubHkgd2hlbiB0aGUKICogcGVyZm9ybWFuY2UgQVBJIGlzIGF2YWlsYWJsZS4KICovCigoKSA9PiB7CiAgLy8gVW5mb3J0dW5hdGVseSBicm93c2VycyBtYXkgcmVwb3J0IGFuIGluYWNjdXJhdGUgdGltZSBvcmlnaW4gZGF0YSwgdGhyb3VnaCBlaXRoZXIgcGVyZm9ybWFuY2UudGltZU9yaWdpbiBvcgogIC8vIHBlcmZvcm1hbmNlLnRpbWluZy5uYXZpZ2F0aW9uU3RhcnQsIHdoaWNoIHJlc3VsdHMgaW4gcG9vciByZXN1bHRzIGluIHBlcmZvcm1hbmNlIGRhdGEuIFdlIG9ubHkgdHJlYXQgdGltZSBvcmlnaW4KICAvLyBkYXRhIGFzIHJlbGlhYmxlIGlmIHRoZXkgYXJlIHdpdGhpbiBhIHJlYXNvbmFibGUgdGhyZXNob2xkIG9mIHRoZSBjdXJyZW50IHRpbWUuCgogIGNvbnN0IHsgcGVyZm9ybWFuY2UgfSA9IEdMT0JBTF9PQkogOwogIGlmICghcGVyZm9ybWFuY2UgfHwgIXBlcmZvcm1hbmNlLm5vdykgewogICAgcmV0dXJuIHVuZGVmaW5lZDsKICB9CgogIGNvbnN0IHRocmVzaG9sZCA9IDM2MDAgKiAxMDAwOwogIGNvbnN0IHBlcmZvcm1hbmNlTm93ID0gcGVyZm9ybWFuY2Uubm93KCk7CiAgY29uc3QgZGF0ZU5vdyA9IERhdGUubm93KCk7CgogIC8vIGlmIHRpbWVPcmlnaW4gaXNuJ3QgYXZhaWxhYmxlIHNldCBkZWx0YSB0byB0aHJlc2hvbGQgc28gaXQgaXNuJ3QgdXNlZAogIGNvbnN0IHRpbWVPcmlnaW5EZWx0YSA9IHBlcmZvcm1hbmNlLnRpbWVPcmlnaW4KICAgID8gTWF0aC5hYnMocGVyZm9ybWFuY2UudGltZU9yaWdpbiArIHBlcmZvcm1hbmNlTm93IC0gZGF0ZU5vdykKICAgIDogdGhyZXNob2xkOwogIGNvbnN0IHRpbWVPcmlnaW5Jc1JlbGlhYmxlID0gdGltZU9yaWdpbkRlbHRhIDwgdGhyZXNob2xkOwoKICAvLyBXaGlsZSBwZXJmb3JtYW5jZS50aW1pbmcubmF2aWdhdGlvblN0YXJ0IGlzIGRlcHJlY2F0ZWQgaW4gZmF2b3Igb2YgcGVyZm9ybWFuY2UudGltZU9yaWdpbiwgcGVyZm9ybWFuY2UudGltZU9yaWdpbgogIC8vIGlzIG5vdCBhcyB3aWRlbHkgc3VwcG9ydGVkLiBOYW1lbHksIHBlcmZvcm1hbmNlLnRpbWVPcmlnaW4gaXMgdW5kZWZpbmVkIGluIFNhZmFyaSBhcyBvZiB3cml0aW5nLgogIC8vIEFsc28gYXMgb2Ygd3JpdGluZywgcGVyZm9ybWFuY2UudGltaW5nIGlzIG5vdCBhdmFpbGFibGUgaW4gV2ViIFdvcmtlcnMgaW4gbWFpbnN0cmVhbSBicm93c2Vycywgc28gaXQgaXMgbm90IGFsd2F5cwogIC8vIGEgdmFsaWQgZmFsbGJhY2suIEluIHRoZSBhYnNlbmNlIG9mIGFuIGluaXRpYWwgdGltZSBwcm92aWRlZCBieSB0aGUgYnJvd3NlciwgZmFsbGJhY2sgdG8gdGhlIGN1cnJlbnQgdGltZSBmcm9tIHRoZQogIC8vIERhdGUgQVBJLgogIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogIGNvbnN0IG5hdmlnYXRpb25TdGFydCA9IHBlcmZvcm1hbmNlLnRpbWluZyAmJiBwZXJmb3JtYW5jZS50aW1pbmcubmF2aWdhdGlvblN0YXJ0OwogIGNvbnN0IGhhc05hdmlnYXRpb25TdGFydCA9IHR5cGVvZiBuYXZpZ2F0aW9uU3RhcnQgPT09ICdudW1iZXInOwogIC8vIGlmIG5hdmlnYXRpb25TdGFydCBpc24ndCBhdmFpbGFibGUgc2V0IGRlbHRhIHRvIHRocmVzaG9sZCBzbyBpdCBpc24ndCB1c2VkCiAgY29uc3QgbmF2aWdhdGlvblN0YXJ0RGVsdGEgPSBoYXNOYXZpZ2F0aW9uU3RhcnQgPyBNYXRoLmFicyhuYXZpZ2F0aW9uU3RhcnQgKyBwZXJmb3JtYW5jZU5vdyAtIGRhdGVOb3cpIDogdGhyZXNob2xkOwogIGNvbnN0IG5hdmlnYXRpb25TdGFydElzUmVsaWFibGUgPSBuYXZpZ2F0aW9uU3RhcnREZWx0YSA8IHRocmVzaG9sZDsKCiAgaWYgKHRpbWVPcmlnaW5Jc1JlbGlhYmxlIHx8IG5hdmlnYXRpb25TdGFydElzUmVsaWFibGUpIHsKICAgIC8vIFVzZSB0aGUgbW9yZSByZWxpYWJsZSB0aW1lIG9yaWdpbgogICAgaWYgKHRpbWVPcmlnaW5EZWx0YSA8PSBuYXZpZ2F0aW9uU3RhcnREZWx0YSkgewogICAgICByZXR1cm4gcGVyZm9ybWFuY2UudGltZU9yaWdpbjsKICAgIH0gZWxzZSB7CiAgICAgIHJldHVybiBuYXZpZ2F0aW9uU3RhcnQ7CiAgICB9CiAgfQogIHJldHVybiBkYXRlTm93Owp9KSgpOwoKLyoqCiAqIENyZWF0ZXMgYW4gZW52ZWxvcGUuCiAqIE1ha2Ugc3VyZSB0byBhbHdheXMgZXhwbGljaXRseSBwcm92aWRlIHRoZSBnZW5lcmljIHRvIHRoaXMgZnVuY3Rpb24KICogc28gdGhhdCB0aGUgZW52ZWxvcGUgdHlwZXMgcmVzb2x2ZSBjb3JyZWN0bHkuCiAqLwpmdW5jdGlvbiBjcmVhdGVFbnZlbG9wZShoZWFkZXJzLCBpdGVtcyA9IFtdKSB7CiAgcmV0dXJuIFtoZWFkZXJzLCBpdGVtc10gOwp9CgovKioKICogQ29udmVuaWVuY2UgZnVuY3Rpb24gdG8gbG9vcCB0aHJvdWdoIHRoZSBpdGVtcyBhbmQgaXRlbSB0eXBlcyBvZiBhbiBlbnZlbG9wZS4KICogKFRoaXMgZnVuY3Rpb24gd2FzIG1vc3RseSBjcmVhdGVkIGJlY2F1c2Ugd29ya2luZyB3aXRoIGVudmVsb3BlIHR5cGVzIGlzIHBhaW5mdWwgYXQgdGhlIG1vbWVudCkKICoKICogSWYgdGhlIGNhbGxiYWNrIHJldHVybnMgdHJ1ZSwgdGhlIHJlc3Qgb2YgdGhlIGl0ZW1zIHdpbGwgYmUgc2tpcHBlZC4KICovCmZ1bmN0aW9uIGZvckVhY2hFbnZlbG9wZUl0ZW0oCiAgZW52ZWxvcGUsCiAgY2FsbGJhY2ssCikgewogIGNvbnN0IGVudmVsb3BlSXRlbXMgPSBlbnZlbG9wZVsxXTsKCiAgZm9yIChjb25zdCBlbnZlbG9wZUl0ZW0gb2YgZW52ZWxvcGVJdGVtcykgewogICAgY29uc3QgZW52ZWxvcGVJdGVtVHlwZSA9IGVudmVsb3BlSXRlbVswXS50eXBlOwogICAgY29uc3QgcmVzdWx0ID0gY2FsbGJhY2soZW52ZWxvcGVJdGVtLCBlbnZlbG9wZUl0ZW1UeXBlKTsKCiAgICBpZiAocmVzdWx0KSB7CiAgICAgIHJldHVybiB0cnVlOwogICAgfQogIH0KCiAgcmV0dXJuIGZhbHNlOwp9CgovKioKICogRW5jb2RlIGEgc3RyaW5nIHRvIFVURjggYXJyYXkuCiAqLwpmdW5jdGlvbiBlbmNvZGVVVEY4KGlucHV0KSB7CiAgcmV0dXJuIEdMT0JBTF9PQkouX19TRU5UUllfXyAmJiBHTE9CQUxfT0JKLl9fU0VOVFJZX18uZW5jb2RlUG9seWZpbGwKICAgID8gR0xPQkFMX09CSi5fX1NFTlRSWV9fLmVuY29kZVBvbHlmaWxsKGlucHV0KQogICAgOiBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoaW5wdXQpOwp9CgovKioKICogU2VyaWFsaXplcyBhbiBlbnZlbG9wZS4KICovCmZ1bmN0aW9uIHNlcmlhbGl6ZUVudmVsb3BlKGVudmVsb3BlKSB7CiAgY29uc3QgW2VudkhlYWRlcnMsIGl0ZW1zXSA9IGVudmVsb3BlOwoKICAvLyBJbml0aWFsbHkgd2UgY29uc3RydWN0IG91ciBlbnZlbG9wZSBhcyBhIHN0cmluZyBhbmQgb25seSBjb252ZXJ0IHRvIGJpbmFyeSBjaHVua3MgaWYgd2UgZW5jb3VudGVyIGJpbmFyeSBkYXRhCiAgbGV0IHBhcnRzID0gSlNPTi5zdHJpbmdpZnkoZW52SGVhZGVycyk7CgogIGZ1bmN0aW9uIGFwcGVuZChuZXh0KSB7CiAgICBpZiAodHlwZW9mIHBhcnRzID09PSAnc3RyaW5nJykgewogICAgICBwYXJ0cyA9IHR5cGVvZiBuZXh0ID09PSAnc3RyaW5nJyA/IHBhcnRzICsgbmV4dCA6IFtlbmNvZGVVVEY4KHBhcnRzKSwgbmV4dF07CiAgICB9IGVsc2UgewogICAgICBwYXJ0cy5wdXNoKHR5cGVvZiBuZXh0ID09PSAnc3RyaW5nJyA/IGVuY29kZVVURjgobmV4dCkgOiBuZXh0KTsKICAgIH0KICB9CgogIGZvciAoY29uc3QgaXRlbSBvZiBpdGVtcykgewogICAgY29uc3QgW2l0ZW1IZWFkZXJzLCBwYXlsb2FkXSA9IGl0ZW07CgogICAgYXBwZW5kKGBcbiR7SlNPTi5zdHJpbmdpZnkoaXRlbUhlYWRlcnMpfVxuYCk7CgogICAgaWYgKHR5cGVvZiBwYXlsb2FkID09PSAnc3RyaW5nJyB8fCBwYXlsb2FkIGluc3RhbmNlb2YgVWludDhBcnJheSkgewogICAgICBhcHBlbmQocGF5bG9hZCk7CiAgICB9IGVsc2UgewogICAgICBsZXQgc3RyaW5naWZpZWRQYXlsb2FkOwogICAgICB0cnkgewogICAgICAgIHN0cmluZ2lmaWVkUGF5bG9hZCA9IEpTT04uc3RyaW5naWZ5KHBheWxvYWQpOwogICAgICB9IGNhdGNoIChlKSB7CiAgICAgICAgLy8gSW4gY2FzZSwgZGVzcGl0ZSBhbGwgb3VyIGVmZm9ydHMgdG8ga2VlcCBgcGF5bG9hZGAgY2lyY3VsYXItZGVwZW5kZW5jeS1mcmVlLCBgSlNPTi5zdHJpbmlmeSgpYCBzdGlsbAogICAgICAgIC8vIGZhaWxzLCB3ZSB0cnkgYWdhaW4gYWZ0ZXIgbm9ybWFsaXppbmcgaXQgYWdhaW4gd2l0aCBpbmZpbml0ZSBub3JtYWxpemF0aW9uIGRlcHRoLiBUaGlzIG9mIGNvdXJzZSBoYXMgYQogICAgICAgIC8vIHBlcmZvcm1hbmNlIGltcGFjdCBidXQgaW4gdGhpcyBjYXNlIGEgcGVyZm9ybWFuY2UgaGl0IGlzIGJldHRlciB0aGFuIHRocm93aW5nLgogICAgICAgIHN0cmluZ2lmaWVkUGF5bG9hZCA9IEpTT04uc3RyaW5naWZ5KG5vcm1hbGl6ZShwYXlsb2FkKSk7CiAgICAgIH0KICAgICAgYXBwZW5kKHN0cmluZ2lmaWVkUGF5bG9hZCk7CiAgICB9CiAgfQoKICByZXR1cm4gdHlwZW9mIHBhcnRzID09PSAnc3RyaW5nJyA/IHBhcnRzIDogY29uY2F0QnVmZmVycyhwYXJ0cyk7Cn0KCmZ1bmN0aW9uIGNvbmNhdEJ1ZmZlcnMoYnVmZmVycykgewogIGNvbnN0IHRvdGFsTGVuZ3RoID0gYnVmZmVycy5yZWR1Y2UoKGFjYywgYnVmKSA9PiBhY2MgKyBidWYubGVuZ3RoLCAwKTsKCiAgY29uc3QgbWVyZ2VkID0gbmV3IFVpbnQ4QXJyYXkodG90YWxMZW5ndGgpOwogIGxldCBvZmZzZXQgPSAwOwogIGZvciAoY29uc3QgYnVmZmVyIG9mIGJ1ZmZlcnMpIHsKICAgIG1lcmdlZC5zZXQoYnVmZmVyLCBvZmZzZXQpOwogICAgb2Zmc2V0ICs9IGJ1ZmZlci5sZW5ndGg7CiAgfQoKICByZXR1cm4gbWVyZ2VkOwp9Cgpjb25zdCBJVEVNX1RZUEVfVE9fREFUQV9DQVRFR09SWV9NQVAgPSB7CiAgc2Vzc2lvbjogJ3Nlc3Npb24nLAogIHNlc3Npb25zOiAnc2Vzc2lvbicsCiAgYXR0YWNobWVudDogJ2F0dGFjaG1lbnQnLAogIHRyYW5zYWN0aW9uOiAndHJhbnNhY3Rpb24nLAogIGV2ZW50OiAnZXJyb3InLAogIGNsaWVudF9yZXBvcnQ6ICdpbnRlcm5hbCcsCiAgdXNlcl9yZXBvcnQ6ICdkZWZhdWx0JywKICBwcm9maWxlOiAncHJvZmlsZScsCiAgcmVwbGF5X2V2ZW50OiAncmVwbGF5JywKICByZXBsYXlfcmVjb3JkaW5nOiAncmVwbGF5JywKICBjaGVja19pbjogJ21vbml0b3InLAogIGZlZWRiYWNrOiAnZmVlZGJhY2snLAogIHN0YXRzZDogJ3N0YXRzZCcsCn07CgovKioKICogTWFwcyB0aGUgdHlwZSBvZiBhbiBlbnZlbG9wZSBpdGVtIHRvIGEgZGF0YSBjYXRlZ29yeS4KICovCmZ1bmN0aW9uIGVudmVsb3BlSXRlbVR5cGVUb0RhdGFDYXRlZ29yeSh0eXBlKSB7CiAgcmV0dXJuIElURU1fVFlQRV9UT19EQVRBX0NBVEVHT1JZX01BUFt0eXBlXTsKfQoKLyoqIEV4dHJhY3RzIHRoZSBtaW5pbWFsIFNESyBpbmZvIGZyb20gZnJvbSB0aGUgbWV0YWRhdGEgb3IgYW4gZXZlbnRzICovCmZ1bmN0aW9uIGdldFNka01ldGFkYXRhRm9yRW52ZWxvcGVIZWFkZXIobWV0YWRhdGFPckV2ZW50KSB7CiAgaWYgKCFtZXRhZGF0YU9yRXZlbnQgfHwgIW1ldGFkYXRhT3JFdmVudC5zZGspIHsKICAgIHJldHVybjsKICB9CiAgY29uc3QgeyBuYW1lLCB2ZXJzaW9uIH0gPSBtZXRhZGF0YU9yRXZlbnQuc2RrOwogIHJldHVybiB7IG5hbWUsIHZlcnNpb24gfTsKfQoKLyoqCiAqIENyZWF0ZXMgZXZlbnQgZW52ZWxvcGUgaGVhZGVycywgYmFzZWQgb24gZXZlbnQsIHNkayBpbmZvIGFuZCB0dW5uZWwKICogTm90ZTogVGhpcyBmdW5jdGlvbiB3YXMgZXh0cmFjdGVkIGZyb20gdGhlIGNvcmUgcGFja2FnZSB0byBtYWtlIGl0IGF2YWlsYWJsZSBpbiBSZXBsYXkKICovCmZ1bmN0aW9uIGNyZWF0ZUV2ZW50RW52ZWxvcGVIZWFkZXJzKAogIGV2ZW50LAogIHNka0luZm8sCiAgdHVubmVsLAogIGRzbiwKKSB7CiAgY29uc3QgZHluYW1pY1NhbXBsaW5nQ29udGV4dCA9IGV2ZW50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YSAmJiBldmVudC5zZGtQcm9jZXNzaW5nTWV0YWRhdGEuZHluYW1pY1NhbXBsaW5nQ29udGV4dDsKICByZXR1cm4gewogICAgZXZlbnRfaWQ6IGV2ZW50LmV2ZW50X2lkICwKICAgIHNlbnRfYXQ6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSwKICAgIC4uLihzZGtJbmZvICYmIHsgc2RrOiBzZGtJbmZvIH0pLAogICAgLi4uKCEhdHVubmVsICYmIGRzbiAmJiB7IGRzbjogZHNuVG9TdHJpbmcoZHNuKSB9KSwKICAgIC4uLihkeW5hbWljU2FtcGxpbmdDb250ZXh0ICYmIHsKICAgICAgdHJhY2U6IGRyb3BVbmRlZmluZWRLZXlzKHsgLi4uZHluYW1pY1NhbXBsaW5nQ29udGV4dCB9KSwKICAgIH0pLAogIH07Cn0KCi8vIEludGVudGlvbmFsbHkga2VlcGluZyB0aGUga2V5IGJyb2FkLCBhcyB3ZSBkb24ndCBrbm93IGZvciBzdXJlIHdoYXQgcmF0ZSBsaW1pdCBoZWFkZXJzIGdldCByZXR1cm5lZCBmcm9tIGJhY2tlbmQKCmNvbnN0IERFRkFVTFRfUkVUUllfQUZURVIgPSA2MCAqIDEwMDA7IC8vIDYwIHNlY29uZHMKCi8qKgogKiBFeHRyYWN0cyBSZXRyeS1BZnRlciB2YWx1ZSBmcm9tIHRoZSByZXF1ZXN0IGhlYWRlciBvciByZXR1cm5zIGRlZmF1bHQgdmFsdWUKICogQHBhcmFtIGhlYWRlciBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgJ1JldHJ5LUFmdGVyJyBoZWFkZXIKICogQHBhcmFtIG5vdyBjdXJyZW50IHVuaXggdGltZXN0YW1wCiAqCiAqLwpmdW5jdGlvbiBwYXJzZVJldHJ5QWZ0ZXJIZWFkZXIoaGVhZGVyLCBub3cgPSBEYXRlLm5vdygpKSB7CiAgY29uc3QgaGVhZGVyRGVsYXkgPSBwYXJzZUludChgJHtoZWFkZXJ9YCwgMTApOwogIGlmICghaXNOYU4oaGVhZGVyRGVsYXkpKSB7CiAgICByZXR1cm4gaGVhZGVyRGVsYXkgKiAxMDAwOwogIH0KCiAgY29uc3QgaGVhZGVyRGF0ZSA9IERhdGUucGFyc2UoYCR7aGVhZGVyfWApOwogIGlmICghaXNOYU4oaGVhZGVyRGF0ZSkpIHsKICAgIHJldHVybiBoZWFkZXJEYXRlIC0gbm93OwogIH0KCiAgcmV0dXJuIERFRkFVTFRfUkVUUllfQUZURVI7Cn0KCi8qKgogKiBHZXRzIHRoZSB0aW1lIHRoYXQgdGhlIGdpdmVuIGNhdGVnb3J5IGlzIGRpc2FibGVkIHVudGlsIGZvciByYXRlIGxpbWl0aW5nLgogKiBJbiBjYXNlIG5vIGNhdGVnb3J5LXNwZWNpZmljIGxpbWl0IGlzIHNldCBidXQgYSBnZW5lcmFsIHJhdGUgbGltaXQgYWNyb3NzIGFsbCBjYXRlZ29yaWVzIGlzIGFjdGl2ZSwKICogdGhhdCB0aW1lIGlzIHJldHVybmVkLgogKgogKiBAcmV0dXJuIHRoZSB0aW1lIGluIG1zIHRoYXQgdGhlIGNhdGVnb3J5IGlzIGRpc2FibGVkIHVudGlsIG9yIDAgaWYgdGhlcmUncyBubyBhY3RpdmUgcmF0ZSBsaW1pdC4KICovCmZ1bmN0aW9uIGRpc2FibGVkVW50aWwobGltaXRzLCBjYXRlZ29yeSkgewogIHJldHVybiBsaW1pdHNbY2F0ZWdvcnldIHx8IGxpbWl0cy5hbGwgfHwgMDsKfQoKLyoqCiAqIENoZWNrcyBpZiBhIGNhdGVnb3J5IGlzIHJhdGUgbGltaXRlZAogKi8KZnVuY3Rpb24gaXNSYXRlTGltaXRlZChsaW1pdHMsIGNhdGVnb3J5LCBub3cgPSBEYXRlLm5vdygpKSB7CiAgcmV0dXJuIGRpc2FibGVkVW50aWwobGltaXRzLCBjYXRlZ29yeSkgPiBub3c7Cn0KCi8qKgogKiBVcGRhdGUgcmF0ZWxpbWl0cyBmcm9tIGluY29taW5nIGhlYWRlcnMuCiAqCiAqIEByZXR1cm4gdGhlIHVwZGF0ZWQgUmF0ZUxpbWl0cyBvYmplY3QuCiAqLwpmdW5jdGlvbiB1cGRhdGVSYXRlTGltaXRzKAogIGxpbWl0cywKICB7IHN0YXR1c0NvZGUsIGhlYWRlcnMgfSwKICBub3cgPSBEYXRlLm5vdygpLAopIHsKICBjb25zdCB1cGRhdGVkUmF0ZUxpbWl0cyA9IHsKICAgIC4uLmxpbWl0cywKICB9OwoKICAvLyAiVGhlIG5hbWUgaXMgY2FzZS1pbnNlbnNpdGl2ZS4iCiAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0hlYWRlcnMvZ2V0CiAgY29uc3QgcmF0ZUxpbWl0SGVhZGVyID0gaGVhZGVycyAmJiBoZWFkZXJzWyd4LXNlbnRyeS1yYXRlLWxpbWl0cyddOwogIGNvbnN0IHJldHJ5QWZ0ZXJIZWFkZXIgPSBoZWFkZXJzICYmIGhlYWRlcnNbJ3JldHJ5LWFmdGVyJ107CgogIGlmIChyYXRlTGltaXRIZWFkZXIpIHsKICAgIC8qKgogICAgICogcmF0ZSBsaW1pdCBoZWFkZXJzIGFyZSBvZiB0aGUgZm9ybQogICAgICogICAgIDxoZWFkZXI+LDxoZWFkZXI+LC4uCiAgICAgKiB3aGVyZSBlYWNoIDxoZWFkZXI+IGlzIG9mIHRoZSBmb3JtCiAgICAgKiAgICAgPHJldHJ5X2FmdGVyPjogPGNhdGVnb3JpZXM+OiA8c2NvcGU+OiA8cmVhc29uX2NvZGU+CiAgICAgKiB3aGVyZQogICAgICogICAgIDxyZXRyeV9hZnRlcj4gaXMgYSBkZWxheSBpbiBzZWNvbmRzCiAgICAgKiAgICAgPGNhdGVnb3JpZXM+IGlzIHRoZSBldmVudCB0eXBlKHMpIChlcnJvciwgdHJhbnNhY3Rpb24sIGV0YykgYmVpbmcgcmF0ZSBsaW1pdGVkIGFuZCBpcyBvZiB0aGUgZm9ybQogICAgICogICAgICAgICA8Y2F0ZWdvcnk+OzxjYXRlZ29yeT47Li4uCiAgICAgKiAgICAgPHNjb3BlPiBpcyB3aGF0J3MgYmVpbmcgbGltaXRlZCAob3JnLCBwcm9qZWN0LCBvciBrZXkpIC0gaWdub3JlZCBieSBTREsKICAgICAqICAgICA8cmVhc29uX2NvZGU+IGlzIGFuIGFyYml0cmFyeSBzdHJpbmcgbGlrZSAib3JnX3F1b3RhIiAtIGlnbm9yZWQgYnkgU0RLCiAgICAgKi8KICAgIGZvciAoY29uc3QgbGltaXQgb2YgcmF0ZUxpbWl0SGVhZGVyLnRyaW0oKS5zcGxpdCgnLCcpKSB7CiAgICAgIGNvbnN0IFtyZXRyeUFmdGVyLCBjYXRlZ29yaWVzXSA9IGxpbWl0LnNwbGl0KCc6JywgMik7CiAgICAgIGNvbnN0IGhlYWRlckRlbGF5ID0gcGFyc2VJbnQocmV0cnlBZnRlciwgMTApOwogICAgICBjb25zdCBkZWxheSA9ICghaXNOYU4oaGVhZGVyRGVsYXkpID8gaGVhZGVyRGVsYXkgOiA2MCkgKiAxMDAwOyAvLyA2MHNlYyBkZWZhdWx0CiAgICAgIGlmICghY2F0ZWdvcmllcykgewogICAgICAgIHVwZGF0ZWRSYXRlTGltaXRzLmFsbCA9IG5vdyArIGRlbGF5OwogICAgICB9IGVsc2UgewogICAgICAgIGZvciAoY29uc3QgY2F0ZWdvcnkgb2YgY2F0ZWdvcmllcy5zcGxpdCgnOycpKSB7CiAgICAgICAgICB1cGRhdGVkUmF0ZUxpbWl0c1tjYXRlZ29yeV0gPSBub3cgKyBkZWxheTsKICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9IGVsc2UgaWYgKHJldHJ5QWZ0ZXJIZWFkZXIpIHsKICAgIHVwZGF0ZWRSYXRlTGltaXRzLmFsbCA9IG5vdyArIHBhcnNlUmV0cnlBZnRlckhlYWRlcihyZXRyeUFmdGVySGVhZGVyLCBub3cpOwogIH0gZWxzZSBpZiAoc3RhdHVzQ29kZSA9PT0gNDI5KSB7CiAgICB1cGRhdGVkUmF0ZUxpbWl0cy5hbGwgPSBub3cgKyA2MCAqIDEwMDA7CiAgfQoKICByZXR1cm4gdXBkYXRlZFJhdGVMaW1pdHM7Cn0KCi8qKgogKiBBIG5vZGUuanMgd2F0Y2hkb2cgdGltZXIKICogQHBhcmFtIHBvbGxJbnRlcnZhbCBUaGUgaW50ZXJ2YWwgdGhhdCB3ZSBleHBlY3QgdG8gZ2V0IHBvbGxlZCBhdAogKiBAcGFyYW0gYW5yVGhyZXNob2xkIFRoZSB0aHJlc2hvbGQgZm9yIHdoZW4gd2UgY29uc2lkZXIgQU5SCiAqIEBwYXJhbSBjYWxsYmFjayBUaGUgY2FsbGJhY2sgdG8gY2FsbCBmb3IgQU5SCiAqIEByZXR1cm5zIEFuIG9iamVjdCB3aXRoIGBwb2xsYCBhbmQgYGVuYWJsZWRgIGZ1bmN0aW9ucyB7QGxpbmsgV2F0Y2hkb2dSZXR1cm59CiAqLwpmdW5jdGlvbiB3YXRjaGRvZ1RpbWVyKAogIGNyZWF0ZVRpbWVyLAogIHBvbGxJbnRlcnZhbCwKICBhbnJUaHJlc2hvbGQsCiAgY2FsbGJhY2ssCikgewogIGNvbnN0IHRpbWVyID0gY3JlYXRlVGltZXIoKTsKICBsZXQgdHJpZ2dlcmVkID0gZmFsc2U7CiAgbGV0IGVuYWJsZWQgPSB0cnVlOwoKICBzZXRJbnRlcnZhbCgoKSA9PiB7CiAgICBjb25zdCBkaWZmTXMgPSB0aW1lci5nZXRUaW1lTXMoKTsKCiAgICBpZiAodHJpZ2dlcmVkID09PSBmYWxzZSAmJiBkaWZmTXMgPiBwb2xsSW50ZXJ2YWwgKyBhbnJUaHJlc2hvbGQpIHsKICAgICAgdHJpZ2dlcmVkID0gdHJ1ZTsKICAgICAgaWYgKGVuYWJsZWQpIHsKICAgICAgICBjYWxsYmFjaygpOwogICAgICB9CiAgICB9CgogICAgaWYgKGRpZmZNcyA8IHBvbGxJbnRlcnZhbCArIGFuclRocmVzaG9sZCkgewogICAgICB0cmlnZ2VyZWQgPSBmYWxzZTsKICAgIH0KICB9LCAyMCk7CgogIHJldHVybiB7CiAgICBwb2xsOiAoKSA9PiB7CiAgICAgIHRpbWVyLnJlc2V0KCk7CiAgICB9LAogICAgZW5hYmxlZDogKHN0YXRlKSA9PiB7CiAgICAgIGVuYWJsZWQgPSBzdGF0ZTsKICAgIH0sCiAgfTsKfQoKLy8gdHlwZXMgY29waWVkIGZyb20gaW5zcGVjdG9yLmQudHMKCi8qKgogKiBDb252ZXJ0cyBEZWJ1Z2dlci5DYWxsRnJhbWUgdG8gU2VudHJ5IFN0YWNrRnJhbWUKICovCmZ1bmN0aW9uIGNhbGxGcmFtZVRvU3RhY2tGcmFtZSgKICBmcmFtZSwKICB1cmwsCiAgZ2V0TW9kdWxlRnJvbUZpbGVuYW1lLAopIHsKICBjb25zdCBmaWxlbmFtZSA9IHVybCA/IHVybC5yZXBsYWNlKC9eZmlsZTpcL1wvLywgJycpIDogdW5kZWZpbmVkOwoKICAvLyBDYWxsRnJhbWUgcm93L2NvbCBhcmUgMCBiYXNlZCwgd2hlcmVhcyBTdGFja0ZyYW1lIGFyZSAxIGJhc2VkCiAgY29uc3QgY29sbm8gPSBmcmFtZS5sb2NhdGlvbi5jb2x1bW5OdW1iZXIgPyBmcmFtZS5sb2NhdGlvbi5jb2x1bW5OdW1iZXIgKyAxIDogdW5kZWZpbmVkOwogIGNvbnN0IGxpbmVubyA9IGZyYW1lLmxvY2F0aW9uLmxpbmVOdW1iZXIgPyBmcmFtZS5sb2NhdGlvbi5saW5lTnVtYmVyICsgMSA6IHVuZGVmaW5lZDsKCiAgcmV0dXJuIGRyb3BVbmRlZmluZWRLZXlzKHsKICAgIGZpbGVuYW1lLAogICAgbW9kdWxlOiBnZXRNb2R1bGVGcm9tRmlsZW5hbWUoZmlsZW5hbWUpLAogICAgZnVuY3Rpb246IGZyYW1lLmZ1bmN0aW9uTmFtZSB8fCBVTktOT1dOX0ZVTkNUSU9OLAogICAgY29sbm8sCiAgICBsaW5lbm8sCiAgICBpbl9hcHA6IGZpbGVuYW1lID8gZmlsZW5hbWVJc0luQXBwKGZpbGVuYW1lKSA6IHVuZGVmaW5lZCwKICB9KTsKfQoKLyoqCiAqIFRoaXMgc2VydmVzIGFzIGEgYnVpbGQgdGltZSBmbGFnIHRoYXQgd2lsbCBiZSB0cnVlIGJ5IGRlZmF1bHQsIGJ1dCBmYWxzZSBpbiBub24tZGVidWcgYnVpbGRzIG9yIGlmIHVzZXJzIHJlcGxhY2UgYF9fU0VOVFJZX0RFQlVHX19gIGluIHRoZWlyIGdlbmVyYXRlZCBjb2RlLgogKgogKiBBVFRFTlRJT046IFRoaXMgY29uc3RhbnQgbXVzdCBuZXZlciBjcm9zcyBwYWNrYWdlIGJvdW5kYXJpZXMgKGkuZS4gYmUgZXhwb3J0ZWQpIHRvIGd1YXJhbnRlZSB0aGF0IGl0IGNhbiBiZSB1c2VkIGZvciB0cmVlIHNoYWtpbmcuCiAqLwpjb25zdCBERUJVR19CVUlMRCA9ICh0eXBlb2YgX19TRU5UUllfREVCVUdfXyA9PT0gJ3VuZGVmaW5lZCcgfHwgX19TRU5UUllfREVCVUdfXyk7CgovKioKICogQHByaXZhdGUgUHJpdmF0ZSBBUEkgd2l0aCBubyBzZW12ZXIgZ3VhcmFudGVlcyEKICoKICogU3RyYXRlZ3kgdXNlZCB0byB0cmFjayBhc3luYyBjb250ZXh0LgogKi8KCi8qKgogKiBSZXR1cm5zIHRoZSBnbG9iYWwgc2hpbSByZWdpc3RyeS4KICoKICogRklYTUU6IFRoaXMgZnVuY3Rpb24gaXMgcHJvYmxlbWF0aWMsIGJlY2F1c2UgZGVzcGl0ZSBhbHdheXMgcmV0dXJuaW5nIGEgdmFsaWQgQ2FycmllciwKICogaXQgaGFzIGFuIG9wdGlvbmFsIGBfX1NFTlRSWV9fYCBwcm9wZXJ0eSwgd2hpY2ggdGhlbiBpbiB0dXJuIHJlcXVpcmVzIHVzIHRvIGFsd2F5cyBwZXJmb3JtIGFuIHVubmVjZXNzYXJ5IGNoZWNrCiAqIGF0IHRoZSBjYWxsLXNpdGUuIFdlIGFsd2F5cyBhY2Nlc3MgdGhlIGNhcnJpZXIgdGhyb3VnaCB0aGlzIGZ1bmN0aW9uLCBzbyB3ZSBjYW4gZ3VhcmFudGVlIHRoYXQgYF9fU0VOVFJZX19gIGlzIHRoZXJlLgogKiovCmZ1bmN0aW9uIGdldE1haW5DYXJyaWVyKCkgewogIC8vIFRoaXMgZW5zdXJlcyBhIFNlbnRyeSBjYXJyaWVyIGV4aXN0cwogIGdldFNlbnRyeUNhcnJpZXIoR0xPQkFMX09CSik7CiAgcmV0dXJuIEdMT0JBTF9PQko7Cn0KCi8qKiBXaWxsIGVpdGhlciBnZXQgdGhlIGV4aXN0aW5nIHNlbnRyeSBjYXJyaWVyLCBvciBjcmVhdGUgYSBuZXcgb25lLiAqLwpmdW5jdGlvbiBnZXRTZW50cnlDYXJyaWVyKGNhcnJpZXIpIHsKICBpZiAoIWNhcnJpZXIuX19TRU5UUllfXykgewogICAgY2Fycmllci5fX1NFTlRSWV9fID0gewogICAgICBleHRlbnNpb25zOiB7fSwKICAgIH07CiAgfQogIHJldHVybiBjYXJyaWVyLl9fU0VOVFJZX187Cn0KCmNvbnN0IERFRkFVTFRfRU5WSVJPTk1FTlQgPSAncHJvZHVjdGlvbic7CgovKioKICogQ3JlYXRlcyBhIG5ldyBgU2Vzc2lvbmAgb2JqZWN0IGJ5IHNldHRpbmcgY2VydGFpbiBkZWZhdWx0IHBhcmFtZXRlcnMuIElmIG9wdGlvbmFsIEBwYXJhbSBjb250ZXh0CiAqIGlzIHBhc3NlZCwgdGhlIHBhc3NlZCBwcm9wZXJ0aWVzIGFyZSBhcHBsaWVkIHRvIHRoZSBzZXNzaW9uIG9iamVjdC4KICoKICogQHBhcmFtIGNvbnRleHQgKG9wdGlvbmFsKSBhZGRpdGlvbmFsIHByb3BlcnRpZXMgdG8gYmUgYXBwbGllZCB0byB0aGUgcmV0dXJuZWQgc2Vzc2lvbiBvYmplY3QKICoKICogQHJldHVybnMgYSBuZXcgYFNlc3Npb25gIG9iamVjdAogKi8KZnVuY3Rpb24gbWFrZVNlc3Npb24oY29udGV4dCkgewogIC8vIEJvdGggdGltZXN0YW1wIGFuZCBzdGFydGVkIGFyZSBpbiBzZWNvbmRzIHNpbmNlIHRoZSBVTklYIGVwb2NoLgogIGNvbnN0IHN0YXJ0aW5nVGltZSA9IHRpbWVzdGFtcEluU2Vjb25kcygpOwoKICBjb25zdCBzZXNzaW9uID0gewogICAgc2lkOiB1dWlkNCgpLAogICAgaW5pdDogdHJ1ZSwKICAgIHRpbWVzdGFtcDogc3RhcnRpbmdUaW1lLAogICAgc3RhcnRlZDogc3RhcnRpbmdUaW1lLAogICAgZHVyYXRpb246IDAsCiAgICBzdGF0dXM6ICdvaycsCiAgICBlcnJvcnM6IDAsCiAgICBpZ25vcmVEdXJhdGlvbjogZmFsc2UsCiAgICB0b0pTT046ICgpID0+IHNlc3Npb25Ub0pTT04oc2Vzc2lvbiksCiAgfTsKCiAgaWYgKGNvbnRleHQpIHsKICAgIHVwZGF0ZVNlc3Npb24oc2Vzc2lvbiwgY29udGV4dCk7CiAgfQoKICByZXR1cm4gc2Vzc2lvbjsKfQoKLyoqCiAqIFVwZGF0ZXMgYSBzZXNzaW9uIG9iamVjdCB3aXRoIHRoZSBwcm9wZXJ0aWVzIHBhc3NlZCBpbiB0aGUgY29udGV4dC4KICoKICogTm90ZSB0aGF0IHRoaXMgZnVuY3Rpb24gbXV0YXRlcyB0aGUgcGFzc2VkIG9iamVjdCBhbmQgcmV0dXJucyB2b2lkLgogKiAoSGFkIHRvIGRvIHRoaXMgaW5zdGVhZCBvZiByZXR1cm5pbmcgYSBuZXcgYW5kIHVwZGF0ZWQgc2Vzc2lvbiBiZWNhdXNlIGNsb3NpbmcgYW5kIHNlbmRpbmcgYSBzZXNzaW9uCiAqIG1ha2VzIGFuIHVwZGF0ZSB0byB0aGUgc2Vzc2lvbiBhZnRlciBpdCB3YXMgcGFzc2VkIHRvIHRoZSBzZW5kaW5nIGxvZ2ljLgogKiBAc2VlIEJhc2VDbGllbnQuY2FwdHVyZVNlc3Npb24gKQogKgogKiBAcGFyYW0gc2Vzc2lvbiB0aGUgYFNlc3Npb25gIHRvIHVwZGF0ZQogKiBAcGFyYW0gY29udGV4dCB0aGUgYFNlc3Npb25Db250ZXh0YCBob2xkaW5nIHRoZSBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkIGJlIHVwZGF0ZWQgaW4gQHBhcmFtIHNlc3Npb24KICovCi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5CmZ1bmN0aW9uIHVwZGF0ZVNlc3Npb24oc2Vzc2lvbiwgY29udGV4dCA9IHt9KSB7CiAgaWYgKGNvbnRleHQudXNlcikgewogICAgaWYgKCFzZXNzaW9uLmlwQWRkcmVzcyAmJiBjb250ZXh0LnVzZXIuaXBfYWRkcmVzcykgewogICAgICBzZXNzaW9uLmlwQWRkcmVzcyA9IGNvbnRleHQudXNlci5pcF9hZGRyZXNzOwogICAgfQoKICAgIGlmICghc2Vzc2lvbi5kaWQgJiYgIWNvbnRleHQuZGlkKSB7CiAgICAgIHNlc3Npb24uZGlkID0gY29udGV4dC51c2VyLmlkIHx8IGNvbnRleHQudXNlci5lbWFpbCB8fCBjb250ZXh0LnVzZXIudXNlcm5hbWU7CiAgICB9CiAgfQoKICBzZXNzaW9uLnRpbWVzdGFtcCA9IGNvbnRleHQudGltZXN0YW1wIHx8IHRpbWVzdGFtcEluU2Vjb25kcygpOwoKICBpZiAoY29udGV4dC5hYm5vcm1hbF9tZWNoYW5pc20pIHsKICAgIHNlc3Npb24uYWJub3JtYWxfbWVjaGFuaXNtID0gY29udGV4dC5hYm5vcm1hbF9tZWNoYW5pc207CiAgfQoKICBpZiAoY29udGV4dC5pZ25vcmVEdXJhdGlvbikgewogICAgc2Vzc2lvbi5pZ25vcmVEdXJhdGlvbiA9IGNvbnRleHQuaWdub3JlRHVyYXRpb247CiAgfQogIGlmIChjb250ZXh0LnNpZCkgewogICAgLy8gR29vZCBlbm91Z2ggdXVpZCB2YWxpZGF0aW9uLiDigJQgS2FtaWwKICAgIHNlc3Npb24uc2lkID0gY29udGV4dC5zaWQubGVuZ3RoID09PSAzMiA/IGNvbnRleHQuc2lkIDogdXVpZDQoKTsKICB9CiAgaWYgKGNvbnRleHQuaW5pdCAhPT0gdW5kZWZpbmVkKSB7CiAgICBzZXNzaW9uLmluaXQgPSBjb250ZXh0LmluaXQ7CiAgfQogIGlmICghc2Vzc2lvbi5kaWQgJiYgY29udGV4dC5kaWQpIHsKICAgIHNlc3Npb24uZGlkID0gYCR7Y29udGV4dC5kaWR9YDsKICB9CiAgaWYgKHR5cGVvZiBjb250ZXh0LnN0YXJ0ZWQgPT09ICdudW1iZXInKSB7CiAgICBzZXNzaW9uLnN0YXJ0ZWQgPSBjb250ZXh0LnN0YXJ0ZWQ7CiAgfQogIGlmIChzZXNzaW9uLmlnbm9yZUR1cmF0aW9uKSB7CiAgICBzZXNzaW9uLmR1cmF0aW9uID0gdW5kZWZpbmVkOwogIH0gZWxzZSBpZiAodHlwZW9mIGNvbnRleHQuZHVyYXRpb24gPT09ICdudW1iZXInKSB7CiAgICBzZXNzaW9uLmR1cmF0aW9uID0gY29udGV4dC5kdXJhdGlvbjsKICB9IGVsc2UgewogICAgY29uc3QgZHVyYXRpb24gPSBzZXNzaW9uLnRpbWVzdGFtcCAtIHNlc3Npb24uc3RhcnRlZDsKICAgIHNlc3Npb24uZHVyYXRpb24gPSBkdXJhdGlvbiA+PSAwID8gZHVyYXRpb24gOiAwOwogIH0KICBpZiAoY29udGV4dC5yZWxlYXNlKSB7CiAgICBzZXNzaW9uLnJlbGVhc2UgPSBjb250ZXh0LnJlbGVhc2U7CiAgfQogIGlmIChjb250ZXh0LmVudmlyb25tZW50KSB7CiAgICBzZXNzaW9uLmVudmlyb25tZW50ID0gY29udGV4dC5lbnZpcm9ubWVudDsKICB9CiAgaWYgKCFzZXNzaW9uLmlwQWRkcmVzcyAmJiBjb250ZXh0LmlwQWRkcmVzcykgewogICAgc2Vzc2lvbi5pcEFkZHJlc3MgPSBjb250ZXh0LmlwQWRkcmVzczsKICB9CiAgaWYgKCFzZXNzaW9uLnVzZXJBZ2VudCAmJiBjb250ZXh0LnVzZXJBZ2VudCkgewogICAgc2Vzc2lvbi51c2VyQWdlbnQgPSBjb250ZXh0LnVzZXJBZ2VudDsKICB9CiAgaWYgKHR5cGVvZiBjb250ZXh0LmVycm9ycyA9PT0gJ251bWJlcicpIHsKICAgIHNlc3Npb24uZXJyb3JzID0gY29udGV4dC5lcnJvcnM7CiAgfQogIGlmIChjb250ZXh0LnN0YXR1cykgewogICAgc2Vzc2lvbi5zdGF0dXMgPSBjb250ZXh0LnN0YXR1czsKICB9Cn0KCi8qKgogKiBDbG9zZXMgYSBzZXNzaW9uIGJ5IHNldHRpbmcgaXRzIHN0YXR1cyBhbmQgdXBkYXRpbmcgdGhlIHNlc3Npb24gb2JqZWN0IHdpdGggaXQuCiAqIEludGVybmFsbHkgY2FsbHMgYHVwZGF0ZVNlc3Npb25gIHRvIHVwZGF0ZSB0aGUgcGFzc2VkIHNlc3Npb24gb2JqZWN0LgogKgogKiBOb3RlIHRoYXQgdGhpcyBmdW5jdGlvbiBtdXRhdGVzIHRoZSBwYXNzZWQgc2Vzc2lvbiAoQHNlZSB1cGRhdGVTZXNzaW9uIGZvciBleHBsYW5hdGlvbikuCiAqCiAqIEBwYXJhbSBzZXNzaW9uIHRoZSBgU2Vzc2lvbmAgb2JqZWN0IHRvIGJlIGNsb3NlZAogKiBAcGFyYW0gc3RhdHVzIHRoZSBgU2Vzc2lvblN0YXR1c2Agd2l0aCB3aGljaCB0aGUgc2Vzc2lvbiB3YXMgY2xvc2VkLiBJZiB5b3UgZG9uJ3QgcGFzcyBhIHN0YXR1cywKICogICAgICAgICAgICAgICB0aGlzIGZ1bmN0aW9uIHdpbGwga2VlcCB0aGUgcHJldmlvdXNseSBzZXQgc3RhdHVzLCB1bmxlc3MgaXQgd2FzIGAnb2snYCBpbiB3aGljaCBjYXNlCiAqICAgICAgICAgICAgICAgaXQgaXMgY2hhbmdlZCB0byBgJ2V4aXRlZCdgLgogKi8KZnVuY3Rpb24gY2xvc2VTZXNzaW9uKHNlc3Npb24sIHN0YXR1cykgewogIGxldCBjb250ZXh0ID0ge307CiAgaWYgKHN0YXR1cykgewogICAgY29udGV4dCA9IHsgc3RhdHVzIH07CiAgfSBlbHNlIGlmIChzZXNzaW9uLnN0YXR1cyA9PT0gJ29rJykgewogICAgY29udGV4dCA9IHsgc3RhdHVzOiAnZXhpdGVkJyB9OwogIH0KCiAgdXBkYXRlU2Vzc2lvbihzZXNzaW9uLCBjb250ZXh0KTsKfQoKLyoqCiAqIFNlcmlhbGl6ZXMgYSBwYXNzZWQgc2Vzc2lvbiBvYmplY3QgdG8gYSBKU09OIG9iamVjdCB3aXRoIGEgc2xpZ2h0bHkgZGlmZmVyZW50IHN0cnVjdHVyZS4KICogVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSB0aGUgU2VudHJ5IGJhY2tlbmQgcmVxdWlyZXMgYSBzbGlnaHRseSBkaWZmZXJlbnQgc2NoZW1hIG9mIGEgc2Vzc2lvbgogKiB0aGFuIHRoZSBvbmUgdGhlIEpTIFNES3MgdXNlIGludGVybmFsbHkuCiAqCiAqIEBwYXJhbSBzZXNzaW9uIHRoZSBzZXNzaW9uIHRvIGJlIGNvbnZlcnRlZAogKgogKiBAcmV0dXJucyBhIEpTT04gb2JqZWN0IG9mIHRoZSBwYXNzZWQgc2Vzc2lvbgogKi8KZnVuY3Rpb24gc2Vzc2lvblRvSlNPTihzZXNzaW9uKSB7CiAgcmV0dXJuIGRyb3BVbmRlZmluZWRLZXlzKHsKICAgIHNpZDogYCR7c2Vzc2lvbi5zaWR9YCwKICAgIGluaXQ6IHNlc3Npb24uaW5pdCwKICAgIC8vIE1ha2Ugc3VyZSB0aGF0IHNlYyBpcyBjb252ZXJ0ZWQgdG8gbXMgZm9yIGRhdGUgY29uc3RydWN0b3IKICAgIHN0YXJ0ZWQ6IG5ldyBEYXRlKHNlc3Npb24uc3RhcnRlZCAqIDEwMDApLnRvSVNPU3RyaW5nKCksCiAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKHNlc3Npb24udGltZXN0YW1wICogMTAwMCkudG9JU09TdHJpbmcoKSwKICAgIHN0YXR1czogc2Vzc2lvbi5zdGF0dXMsCiAgICBlcnJvcnM6IHNlc3Npb24uZXJyb3JzLAogICAgZGlkOiB0eXBlb2Ygc2Vzc2lvbi5kaWQgPT09ICdudW1iZXInIHx8IHR5cGVvZiBzZXNzaW9uLmRpZCA9PT0gJ3N0cmluZycgPyBgJHtzZXNzaW9uLmRpZH1gIDogdW5kZWZpbmVkLAogICAgZHVyYXRpb246IHNlc3Npb24uZHVyYXRpb24sCiAgICBhYm5vcm1hbF9tZWNoYW5pc206IHNlc3Npb24uYWJub3JtYWxfbWVjaGFuaXNtLAogICAgYXR0cnM6IHsKICAgICAgcmVsZWFzZTogc2Vzc2lvbi5yZWxlYXNlLAogICAgICBlbnZpcm9ubWVudDogc2Vzc2lvbi5lbnZpcm9ubWVudCwKICAgICAgaXBfYWRkcmVzczogc2Vzc2lvbi5pcEFkZHJlc3MsCiAgICAgIHVzZXJfYWdlbnQ6IHNlc3Npb24udXNlckFnZW50LAogICAgfSwKICB9KTsKfQoKY29uc3QgU0NPUEVfU1BBTl9GSUVMRCA9ICdfc2VudHJ5U3Bhbic7CgovKioKICogU2V0IHRoZSBhY3RpdmUgc3BhbiBmb3IgYSBnaXZlbiBzY29wZS4KICogTk9URTogVGhpcyBzaG91bGQgTk9UIGJlIHVzZWQgZGlyZWN0bHksIGJ1dCBpcyBvbmx5IHVzZWQgaW50ZXJuYWxseSBieSB0aGUgdHJhY2UgbWV0aG9kcy4KICovCmZ1bmN0aW9uIF9zZXRTcGFuRm9yU2NvcGUoc2NvcGUsIHNwYW4pIHsKICBpZiAoc3BhbikgewogICAgYWRkTm9uRW51bWVyYWJsZVByb3BlcnR5KHNjb3BlICwgU0NPUEVfU1BBTl9GSUVMRCwgc3Bhbik7CiAgfSBlbHNlIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZHluYW1pYy1kZWxldGUKICAgIGRlbGV0ZSAoc2NvcGUgKVtTQ09QRV9TUEFOX0ZJRUxEXTsKICB9Cn0KCi8qKgogKiBHZXQgdGhlIGFjdGl2ZSBzcGFuIGZvciBhIGdpdmVuIHNjb3BlLgogKiBOT1RFOiBUaGlzIHNob3VsZCBOT1QgYmUgdXNlZCBkaXJlY3RseSwgYnV0IGlzIG9ubHkgdXNlZCBpbnRlcm5hbGx5IGJ5IHRoZSB0cmFjZSBtZXRob2RzLgogKi8KZnVuY3Rpb24gX2dldFNwYW5Gb3JTY29wZShzY29wZSkgewogIHJldHVybiBzY29wZVtTQ09QRV9TUEFOX0ZJRUxEXTsKfQoKLyoqCiAqIERlZmF1bHQgdmFsdWUgZm9yIG1heGltdW0gbnVtYmVyIG9mIGJyZWFkY3J1bWJzIGFkZGVkIHRvIGFuIGV2ZW50LgogKi8KY29uc3QgREVGQVVMVF9NQVhfQlJFQURDUlVNQlMgPSAxMDA7CgovKioKICogSG9sZHMgYWRkaXRpb25hbCBldmVudCBpbmZvcm1hdGlvbi4KICovCmNsYXNzIFNjb3BlICB7CiAgLyoqIEZsYWcgaWYgbm90aWZ5aW5nIGlzIGhhcHBlbmluZy4gKi8KCiAgLyoqIENhbGxiYWNrIGZvciBjbGllbnQgdG8gcmVjZWl2ZSBzY29wZSBjaGFuZ2VzLiAqLwoKICAvKiogQ2FsbGJhY2sgbGlzdCB0aGF0IHdpbGwgYmUgY2FsbGVkIGR1cmluZyBldmVudCBwcm9jZXNzaW5nLiAqLwoKICAvKiogQXJyYXkgb2YgYnJlYWRjcnVtYnMuICovCgogIC8qKiBVc2VyICovCgogIC8qKiBUYWdzICovCgogIC8qKiBFeHRyYSAqLwoKICAvKiogQ29udGV4dHMgKi8KCiAgLyoqIEF0dGFjaG1lbnRzICovCgogIC8qKiBQcm9wYWdhdGlvbiBDb250ZXh0IGZvciBkaXN0cmlidXRlZCB0cmFjaW5nICovCgogIC8qKgogICAqIEEgcGxhY2UgdG8gc3Rhc2ggZGF0YSB3aGljaCBpcyBuZWVkZWQgYXQgc29tZSBwb2ludCBpbiB0aGUgU0RLJ3MgZXZlbnQgcHJvY2Vzc2luZyBwaXBlbGluZSBidXQgd2hpY2ggc2hvdWxkbid0IGdldAogICAqIHNlbnQgdG8gU2VudHJ5CiAgICovCgogIC8qKiBGaW5nZXJwcmludCAqLwoKICAvKiogU2V2ZXJpdHkgKi8KCiAgLyoqCiAgICogVHJhbnNhY3Rpb24gTmFtZQogICAqCiAgICogSU1QT1JUQU5UOiBUaGUgdHJhbnNhY3Rpb24gbmFtZSBvbiB0aGUgc2NvcGUgaGFzIG5vdGhpbmcgdG8gZG8gd2l0aCByb290IHNwYW5zL3RyYW5zYWN0aW9uIG9iamVjdHMuCiAgICogSXQncyBwdXJwb3NlIGlzIHRvIGFzc2lnbiBhIHRyYW5zYWN0aW9uIHRvIHRoZSBzY29wZSB0aGF0J3MgYWRkZWQgdG8gbm9uLXRyYW5zYWN0aW9uIGV2ZW50cy4KICAgKi8KCiAgLyoqIFNlc3Npb24gKi8KCiAgLyoqIFJlcXVlc3QgTW9kZSBTZXNzaW9uIFN0YXR1cyAqLwoKICAvKiogVGhlIGNsaWVudCBvbiB0aGlzIHNjb3BlICovCgogIC8vIE5PVEU6IEFueSBmaWVsZCB3aGljaCBnZXRzIGFkZGVkIGhlcmUgc2hvdWxkIGdldCBhZGRlZCBub3Qgb25seSB0byB0aGUgY29uc3RydWN0b3IgYnV0IGFsc28gdG8gdGhlIGBjbG9uZWAgbWV0aG9kLgoKICAgY29uc3RydWN0b3IoKSB7CiAgICB0aGlzLl9ub3RpZnlpbmdMaXN0ZW5lcnMgPSBmYWxzZTsKICAgIHRoaXMuX3Njb3BlTGlzdGVuZXJzID0gW107CiAgICB0aGlzLl9ldmVudFByb2Nlc3NvcnMgPSBbXTsKICAgIHRoaXMuX2JyZWFkY3J1bWJzID0gW107CiAgICB0aGlzLl9hdHRhY2htZW50cyA9IFtdOwogICAgdGhpcy5fdXNlciA9IHt9OwogICAgdGhpcy5fdGFncyA9IHt9OwogICAgdGhpcy5fZXh0cmEgPSB7fTsKICAgIHRoaXMuX2NvbnRleHRzID0ge307CiAgICB0aGlzLl9zZGtQcm9jZXNzaW5nTWV0YWRhdGEgPSB7fTsKICAgIHRoaXMuX3Byb3BhZ2F0aW9uQ29udGV4dCA9IGdlbmVyYXRlUHJvcGFnYXRpb25Db250ZXh0KCk7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBjbG9uZSgpIHsKICAgIGNvbnN0IG5ld1Njb3BlID0gbmV3IFNjb3BlKCk7CiAgICBuZXdTY29wZS5fYnJlYWRjcnVtYnMgPSBbLi4udGhpcy5fYnJlYWRjcnVtYnNdOwogICAgbmV3U2NvcGUuX3RhZ3MgPSB7IC4uLnRoaXMuX3RhZ3MgfTsKICAgIG5ld1Njb3BlLl9leHRyYSA9IHsgLi4udGhpcy5fZXh0cmEgfTsKICAgIG5ld1Njb3BlLl9jb250ZXh0cyA9IHsgLi4udGhpcy5fY29udGV4dHMgfTsKICAgIG5ld1Njb3BlLl91c2VyID0gdGhpcy5fdXNlcjsKICAgIG5ld1Njb3BlLl9sZXZlbCA9IHRoaXMuX2xldmVsOwogICAgbmV3U2NvcGUuX3Nlc3Npb24gPSB0aGlzLl9zZXNzaW9uOwogICAgbmV3U2NvcGUuX3RyYW5zYWN0aW9uTmFtZSA9IHRoaXMuX3RyYW5zYWN0aW9uTmFtZTsKICAgIG5ld1Njb3BlLl9maW5nZXJwcmludCA9IHRoaXMuX2ZpbmdlcnByaW50OwogICAgbmV3U2NvcGUuX2V2ZW50UHJvY2Vzc29ycyA9IFsuLi50aGlzLl9ldmVudFByb2Nlc3NvcnNdOwogICAgbmV3U2NvcGUuX3JlcXVlc3RTZXNzaW9uID0gdGhpcy5fcmVxdWVzdFNlc3Npb247CiAgICBuZXdTY29wZS5fYXR0YWNobWVudHMgPSBbLi4udGhpcy5fYXR0YWNobWVudHNdOwogICAgbmV3U2NvcGUuX3Nka1Byb2Nlc3NpbmdNZXRhZGF0YSA9IHsgLi4udGhpcy5fc2RrUHJvY2Vzc2luZ01ldGFkYXRhIH07CiAgICBuZXdTY29wZS5fcHJvcGFnYXRpb25Db250ZXh0ID0geyAuLi50aGlzLl9wcm9wYWdhdGlvbkNvbnRleHQgfTsKICAgIG5ld1Njb3BlLl9jbGllbnQgPSB0aGlzLl9jbGllbnQ7CgogICAgX3NldFNwYW5Gb3JTY29wZShuZXdTY29wZSwgX2dldFNwYW5Gb3JTY29wZSh0aGlzKSk7CgogICAgcmV0dXJuIG5ld1Njb3BlOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgc2V0Q2xpZW50KGNsaWVudCkgewogICAgdGhpcy5fY2xpZW50ID0gY2xpZW50OwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgZ2V0Q2xpZW50KCkgewogICAgcmV0dXJuIHRoaXMuX2NsaWVudCA7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBhZGRTY29wZUxpc3RlbmVyKGNhbGxiYWNrKSB7CiAgICB0aGlzLl9zY29wZUxpc3RlbmVycy5wdXNoKGNhbGxiYWNrKTsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGFkZEV2ZW50UHJvY2Vzc29yKGNhbGxiYWNrKSB7CiAgICB0aGlzLl9ldmVudFByb2Nlc3NvcnMucHVzaChjYWxsYmFjayk7CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIHNldFVzZXIodXNlcikgewogICAgLy8gSWYgbnVsbCBpcyBwYXNzZWQgd2Ugd2FudCB0byB1bnNldCBldmVyeXRoaW5nLCBidXQgc3RpbGwgZGVmaW5lIGtleXMsCiAgICAvLyBzbyB0aGF0IGxhdGVyIGRvd24gaW4gdGhlIHBpcGVsaW5lIGFueSBleGlzdGluZyB2YWx1ZXMgYXJlIGNsZWFyZWQuCiAgICB0aGlzLl91c2VyID0gdXNlciB8fCB7CiAgICAgIGVtYWlsOiB1bmRlZmluZWQsCiAgICAgIGlkOiB1bmRlZmluZWQsCiAgICAgIGlwX2FkZHJlc3M6IHVuZGVmaW5lZCwKICAgICAgdXNlcm5hbWU6IHVuZGVmaW5lZCwKICAgIH07CgogICAgaWYgKHRoaXMuX3Nlc3Npb24pIHsKICAgICAgdXBkYXRlU2Vzc2lvbih0aGlzLl9zZXNzaW9uLCB7IHVzZXIgfSk7CiAgICB9CgogICAgdGhpcy5fbm90aWZ5U2NvcGVMaXN0ZW5lcnMoKTsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgZ2V0VXNlcigpIHsKICAgIHJldHVybiB0aGlzLl91c2VyOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgZ2V0UmVxdWVzdFNlc3Npb24oKSB7CiAgICByZXR1cm4gdGhpcy5fcmVxdWVzdFNlc3Npb247CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBzZXRSZXF1ZXN0U2Vzc2lvbihyZXF1ZXN0U2Vzc2lvbikgewogICAgdGhpcy5fcmVxdWVzdFNlc3Npb24gPSByZXF1ZXN0U2Vzc2lvbjsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgc2V0VGFncyh0YWdzKSB7CiAgICB0aGlzLl90YWdzID0gewogICAgICAuLi50aGlzLl90YWdzLAogICAgICAuLi50YWdzLAogICAgfTsKICAgIHRoaXMuX25vdGlmeVNjb3BlTGlzdGVuZXJzKCk7CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIHNldFRhZyhrZXksIHZhbHVlKSB7CiAgICB0aGlzLl90YWdzID0geyAuLi50aGlzLl90YWdzLCBba2V5XTogdmFsdWUgfTsKICAgIHRoaXMuX25vdGlmeVNjb3BlTGlzdGVuZXJzKCk7CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIHNldEV4dHJhcyhleHRyYXMpIHsKICAgIHRoaXMuX2V4dHJhID0gewogICAgICAuLi50aGlzLl9leHRyYSwKICAgICAgLi4uZXh0cmFzLAogICAgfTsKICAgIHRoaXMuX25vdGlmeVNjb3BlTGlzdGVuZXJzKCk7CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIHNldEV4dHJhKGtleSwgZXh0cmEpIHsKICAgIHRoaXMuX2V4dHJhID0geyAuLi50aGlzLl9leHRyYSwgW2tleV06IGV4dHJhIH07CiAgICB0aGlzLl9ub3RpZnlTY29wZUxpc3RlbmVycygpOwogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBzZXRGaW5nZXJwcmludChmaW5nZXJwcmludCkgewogICAgdGhpcy5fZmluZ2VycHJpbnQgPSBmaW5nZXJwcmludDsKICAgIHRoaXMuX25vdGlmeVNjb3BlTGlzdGVuZXJzKCk7CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIHNldExldmVsKGxldmVsKSB7CiAgICB0aGlzLl9sZXZlbCA9IGxldmVsOwogICAgdGhpcy5fbm90aWZ5U2NvcGVMaXN0ZW5lcnMoKTsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgc2V0VHJhbnNhY3Rpb25OYW1lKG5hbWUpIHsKICAgIHRoaXMuX3RyYW5zYWN0aW9uTmFtZSA9IG5hbWU7CiAgICB0aGlzLl9ub3RpZnlTY29wZUxpc3RlbmVycygpOwogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBzZXRDb250ZXh0KGtleSwgY29udGV4dCkgewogICAgaWYgKGNvbnRleHQgPT09IG51bGwpIHsKICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1keW5hbWljLWRlbGV0ZQogICAgICBkZWxldGUgdGhpcy5fY29udGV4dHNba2V5XTsKICAgIH0gZWxzZSB7CiAgICAgIHRoaXMuX2NvbnRleHRzW2tleV0gPSBjb250ZXh0OwogICAgfQoKICAgIHRoaXMuX25vdGlmeVNjb3BlTGlzdGVuZXJzKCk7CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIHNldFNlc3Npb24oc2Vzc2lvbikgewogICAgaWYgKCFzZXNzaW9uKSB7CiAgICAgIGRlbGV0ZSB0aGlzLl9zZXNzaW9uOwogICAgfSBlbHNlIHsKICAgICAgdGhpcy5fc2Vzc2lvbiA9IHNlc3Npb247CiAgICB9CiAgICB0aGlzLl9ub3RpZnlTY29wZUxpc3RlbmVycygpOwogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBnZXRTZXNzaW9uKCkgewogICAgcmV0dXJuIHRoaXMuX3Nlc3Npb247CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICB1cGRhdGUoY2FwdHVyZUNvbnRleHQpIHsKICAgIGlmICghY2FwdHVyZUNvbnRleHQpIHsKICAgICAgcmV0dXJuIHRoaXM7CiAgICB9CgogICAgY29uc3Qgc2NvcGVUb01lcmdlID0gdHlwZW9mIGNhcHR1cmVDb250ZXh0ID09PSAnZnVuY3Rpb24nID8gY2FwdHVyZUNvbnRleHQodGhpcykgOiBjYXB0dXJlQ29udGV4dDsKCiAgICBjb25zdCBbc2NvcGVJbnN0YW5jZSwgcmVxdWVzdFNlc3Npb25dID0KICAgICAgc2NvcGVUb01lcmdlIGluc3RhbmNlb2YgU2NvcGUKICAgICAgICA/IFtzY29wZVRvTWVyZ2UuZ2V0U2NvcGVEYXRhKCksIHNjb3BlVG9NZXJnZS5nZXRSZXF1ZXN0U2Vzc2lvbigpXQogICAgICAgIDogaXNQbGFpbk9iamVjdChzY29wZVRvTWVyZ2UpCiAgICAgICAgICA/IFtjYXB0dXJlQ29udGV4dCAsIChjYXB0dXJlQ29udGV4dCApLnJlcXVlc3RTZXNzaW9uXQogICAgICAgICAgOiBbXTsKCiAgICBjb25zdCB7IHRhZ3MsIGV4dHJhLCB1c2VyLCBjb250ZXh0cywgbGV2ZWwsIGZpbmdlcnByaW50ID0gW10sIHByb3BhZ2F0aW9uQ29udGV4dCB9ID0gc2NvcGVJbnN0YW5jZSB8fCB7fTsKCiAgICB0aGlzLl90YWdzID0geyAuLi50aGlzLl90YWdzLCAuLi50YWdzIH07CiAgICB0aGlzLl9leHRyYSA9IHsgLi4udGhpcy5fZXh0cmEsIC4uLmV4dHJhIH07CiAgICB0aGlzLl9jb250ZXh0cyA9IHsgLi4udGhpcy5fY29udGV4dHMsIC4uLmNvbnRleHRzIH07CgogICAgaWYgKHVzZXIgJiYgT2JqZWN0LmtleXModXNlcikubGVuZ3RoKSB7CiAgICAgIHRoaXMuX3VzZXIgPSB1c2VyOwogICAgfQoKICAgIGlmIChsZXZlbCkgewogICAgICB0aGlzLl9sZXZlbCA9IGxldmVsOwogICAgfQoKICAgIGlmIChmaW5nZXJwcmludC5sZW5ndGgpIHsKICAgICAgdGhpcy5fZmluZ2VycHJpbnQgPSBmaW5nZXJwcmludDsKICAgIH0KCiAgICBpZiAocHJvcGFnYXRpb25Db250ZXh0KSB7CiAgICAgIHRoaXMuX3Byb3BhZ2F0aW9uQ29udGV4dCA9IHByb3BhZ2F0aW9uQ29udGV4dDsKICAgIH0KCiAgICBpZiAocmVxdWVzdFNlc3Npb24pIHsKICAgICAgdGhpcy5fcmVxdWVzdFNlc3Npb24gPSByZXF1ZXN0U2Vzc2lvbjsKICAgIH0KCiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGNsZWFyKCkgewogICAgLy8gY2xpZW50IGlzIG5vdCBjbGVhcmVkIGhlcmUgb24gcHVycG9zZSEKICAgIHRoaXMuX2JyZWFkY3J1bWJzID0gW107CiAgICB0aGlzLl90YWdzID0ge307CiAgICB0aGlzLl9leHRyYSA9IHt9OwogICAgdGhpcy5fdXNlciA9IHt9OwogICAgdGhpcy5fY29udGV4dHMgPSB7fTsKICAgIHRoaXMuX2xldmVsID0gdW5kZWZpbmVkOwogICAgdGhpcy5fdHJhbnNhY3Rpb25OYW1lID0gdW5kZWZpbmVkOwogICAgdGhpcy5fZmluZ2VycHJpbnQgPSB1bmRlZmluZWQ7CiAgICB0aGlzLl9yZXF1ZXN0U2Vzc2lvbiA9IHVuZGVmaW5lZDsKICAgIHRoaXMuX3Nlc3Npb24gPSB1bmRlZmluZWQ7CiAgICBfc2V0U3BhbkZvclNjb3BlKHRoaXMsIHVuZGVmaW5lZCk7CiAgICB0aGlzLl9hdHRhY2htZW50cyA9IFtdOwogICAgdGhpcy5fcHJvcGFnYXRpb25Db250ZXh0ID0gZ2VuZXJhdGVQcm9wYWdhdGlvbkNvbnRleHQoKTsKCiAgICB0aGlzLl9ub3RpZnlTY29wZUxpc3RlbmVycygpOwogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBhZGRCcmVhZGNydW1iKGJyZWFkY3J1bWIsIG1heEJyZWFkY3J1bWJzKSB7CiAgICBjb25zdCBtYXhDcnVtYnMgPSB0eXBlb2YgbWF4QnJlYWRjcnVtYnMgPT09ICdudW1iZXInID8gbWF4QnJlYWRjcnVtYnMgOiBERUZBVUxUX01BWF9CUkVBRENSVU1CUzsKCiAgICAvLyBObyBkYXRhIGhhcyBiZWVuIGNoYW5nZWQsIHNvIGRvbid0IG5vdGlmeSBzY29wZSBsaXN0ZW5lcnMKICAgIGlmIChtYXhDcnVtYnMgPD0gMCkgewogICAgICByZXR1cm4gdGhpczsKICAgIH0KCiAgICBjb25zdCBtZXJnZWRCcmVhZGNydW1iID0gewogICAgICB0aW1lc3RhbXA6IGRhdGVUaW1lc3RhbXBJblNlY29uZHMoKSwKICAgICAgLi4uYnJlYWRjcnVtYiwKICAgIH07CgogICAgY29uc3QgYnJlYWRjcnVtYnMgPSB0aGlzLl9icmVhZGNydW1iczsKICAgIGJyZWFkY3J1bWJzLnB1c2gobWVyZ2VkQnJlYWRjcnVtYik7CiAgICB0aGlzLl9icmVhZGNydW1icyA9IGJyZWFkY3J1bWJzLmxlbmd0aCA+IG1heENydW1icyA/IGJyZWFkY3J1bWJzLnNsaWNlKC1tYXhDcnVtYnMpIDogYnJlYWRjcnVtYnM7CgogICAgdGhpcy5fbm90aWZ5U2NvcGVMaXN0ZW5lcnMoKTsKCiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGdldExhc3RCcmVhZGNydW1iKCkgewogICAgcmV0dXJuIHRoaXMuX2JyZWFkY3J1bWJzW3RoaXMuX2JyZWFkY3J1bWJzLmxlbmd0aCAtIDFdOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgY2xlYXJCcmVhZGNydW1icygpIHsKICAgIHRoaXMuX2JyZWFkY3J1bWJzID0gW107CiAgICB0aGlzLl9ub3RpZnlTY29wZUxpc3RlbmVycygpOwogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBhZGRBdHRhY2htZW50KGF0dGFjaG1lbnQpIHsKICAgIHRoaXMuX2F0dGFjaG1lbnRzLnB1c2goYXR0YWNobWVudCk7CiAgICByZXR1cm4gdGhpczsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGNsZWFyQXR0YWNobWVudHMoKSB7CiAgICB0aGlzLl9hdHRhY2htZW50cyA9IFtdOwogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKiogQGluaGVyaXREb2MgKi8KICAgZ2V0U2NvcGVEYXRhKCkgewogICAgcmV0dXJuIHsKICAgICAgYnJlYWRjcnVtYnM6IHRoaXMuX2JyZWFkY3J1bWJzLAogICAgICBhdHRhY2htZW50czogdGhpcy5fYXR0YWNobWVudHMsCiAgICAgIGNvbnRleHRzOiB0aGlzLl9jb250ZXh0cywKICAgICAgdGFnczogdGhpcy5fdGFncywKICAgICAgZXh0cmE6IHRoaXMuX2V4dHJhLAogICAgICB1c2VyOiB0aGlzLl91c2VyLAogICAgICBsZXZlbDogdGhpcy5fbGV2ZWwsCiAgICAgIGZpbmdlcnByaW50OiB0aGlzLl9maW5nZXJwcmludCB8fCBbXSwKICAgICAgZXZlbnRQcm9jZXNzb3JzOiB0aGlzLl9ldmVudFByb2Nlc3NvcnMsCiAgICAgIHByb3BhZ2F0aW9uQ29udGV4dDogdGhpcy5fcHJvcGFnYXRpb25Db250ZXh0LAogICAgICBzZGtQcm9jZXNzaW5nTWV0YWRhdGE6IHRoaXMuX3Nka1Byb2Nlc3NpbmdNZXRhZGF0YSwKICAgICAgdHJhbnNhY3Rpb25OYW1lOiB0aGlzLl90cmFuc2FjdGlvbk5hbWUsCiAgICAgIHNwYW46IF9nZXRTcGFuRm9yU2NvcGUodGhpcyksCiAgICB9OwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgc2V0U0RLUHJvY2Vzc2luZ01ldGFkYXRhKG5ld0RhdGEpIHsKICAgIHRoaXMuX3Nka1Byb2Nlc3NpbmdNZXRhZGF0YSA9IHsgLi4udGhpcy5fc2RrUHJvY2Vzc2luZ01ldGFkYXRhLCAuLi5uZXdEYXRhIH07CgogICAgcmV0dXJuIHRoaXM7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqLwogICBzZXRQcm9wYWdhdGlvbkNvbnRleHQoY29udGV4dCkgewogICAgdGhpcy5fcHJvcGFnYXRpb25Db250ZXh0ID0gY29udGV4dDsKICAgIHJldHVybiB0aGlzOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKi8KICAgZ2V0UHJvcGFnYXRpb25Db250ZXh0KCkgewogICAgcmV0dXJuIHRoaXMuX3Byb3BhZ2F0aW9uQ29udGV4dDsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGNhcHR1cmVFeGNlcHRpb24oZXhjZXB0aW9uLCBoaW50KSB7CiAgICBjb25zdCBldmVudElkID0gaGludCAmJiBoaW50LmV2ZW50X2lkID8gaGludC5ldmVudF9pZCA6IHV1aWQ0KCk7CgogICAgaWYgKCF0aGlzLl9jbGllbnQpIHsKICAgICAgbG9nZ2VyLndhcm4oJ05vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBleGNlcHRpb24hJyk7CiAgICAgIHJldHVybiBldmVudElkOwogICAgfQoKICAgIGNvbnN0IHN5bnRoZXRpY0V4Y2VwdGlvbiA9IG5ldyBFcnJvcignU2VudHJ5IHN5bnRoZXRpY0V4Y2VwdGlvbicpOwoKICAgIHRoaXMuX2NsaWVudC5jYXB0dXJlRXhjZXB0aW9uKAogICAgICBleGNlcHRpb24sCiAgICAgIHsKICAgICAgICBvcmlnaW5hbEV4Y2VwdGlvbjogZXhjZXB0aW9uLAogICAgICAgIHN5bnRoZXRpY0V4Y2VwdGlvbiwKICAgICAgICAuLi5oaW50LAogICAgICAgIGV2ZW50X2lkOiBldmVudElkLAogICAgICB9LAogICAgICB0aGlzLAogICAgKTsKCiAgICByZXR1cm4gZXZlbnRJZDsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGNhcHR1cmVNZXNzYWdlKG1lc3NhZ2UsIGxldmVsLCBoaW50KSB7CiAgICBjb25zdCBldmVudElkID0gaGludCAmJiBoaW50LmV2ZW50X2lkID8gaGludC5ldmVudF9pZCA6IHV1aWQ0KCk7CgogICAgaWYgKCF0aGlzLl9jbGllbnQpIHsKICAgICAgbG9nZ2VyLndhcm4oJ05vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBtZXNzYWdlIScpOwogICAgICByZXR1cm4gZXZlbnRJZDsKICAgIH0KCiAgICBjb25zdCBzeW50aGV0aWNFeGNlcHRpb24gPSBuZXcgRXJyb3IobWVzc2FnZSk7CgogICAgdGhpcy5fY2xpZW50LmNhcHR1cmVNZXNzYWdlKAogICAgICBtZXNzYWdlLAogICAgICBsZXZlbCwKICAgICAgewogICAgICAgIG9yaWdpbmFsRXhjZXB0aW9uOiBtZXNzYWdlLAogICAgICAgIHN5bnRoZXRpY0V4Y2VwdGlvbiwKICAgICAgICAuLi5oaW50LAogICAgICAgIGV2ZW50X2lkOiBldmVudElkLAogICAgICB9LAogICAgICB0aGlzLAogICAgKTsKCiAgICByZXR1cm4gZXZlbnRJZDsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICovCiAgIGNhcHR1cmVFdmVudChldmVudCwgaGludCkgewogICAgY29uc3QgZXZlbnRJZCA9IGhpbnQgJiYgaGludC5ldmVudF9pZCA/IGhpbnQuZXZlbnRfaWQgOiB1dWlkNCgpOwoKICAgIGlmICghdGhpcy5fY2xpZW50KSB7CiAgICAgIGxvZ2dlci53YXJuKCdObyBjbGllbnQgY29uZmlndXJlZCBvbiBzY29wZSAtIHdpbGwgbm90IGNhcHR1cmUgZXZlbnQhJyk7CiAgICAgIHJldHVybiBldmVudElkOwogICAgfQoKICAgIHRoaXMuX2NsaWVudC5jYXB0dXJlRXZlbnQoZXZlbnQsIHsgLi4uaGludCwgZXZlbnRfaWQ6IGV2ZW50SWQgfSwgdGhpcyk7CgogICAgcmV0dXJuIGV2ZW50SWQ7CiAgfQoKICAvKioKICAgKiBUaGlzIHdpbGwgYmUgY2FsbGVkIG9uIGV2ZXJ5IHNldCBjYWxsLgogICAqLwogICBfbm90aWZ5U2NvcGVMaXN0ZW5lcnMoKSB7CiAgICAvLyBXZSBuZWVkIHRoaXMgY2hlY2sgZm9yIHRoaXMuX25vdGlmeWluZ0xpc3RlbmVycyB0byBiZSBhYmxlIHRvIHdvcmsgb24gc2NvcGUgZHVyaW5nIHVwZGF0ZXMKICAgIC8vIElmIHRoaXMgY2hlY2sgaXMgbm90IGhlcmUgd2UnbGwgcHJvZHVjZSBlbmRsZXNzIHJlY3Vyc2lvbiB3aGVuIHNvbWV0aGluZyBpcyBkb25lIHdpdGggdGhlIHNjb3BlCiAgICAvLyBkdXJpbmcgdGhlIGNhbGxiYWNrLgogICAgaWYgKCF0aGlzLl9ub3RpZnlpbmdMaXN0ZW5lcnMpIHsKICAgICAgdGhpcy5fbm90aWZ5aW5nTGlzdGVuZXJzID0gdHJ1ZTsKICAgICAgdGhpcy5fc2NvcGVMaXN0ZW5lcnMuZm9yRWFjaChjYWxsYmFjayA9PiB7CiAgICAgICAgY2FsbGJhY2sodGhpcyk7CiAgICAgIH0pOwogICAgICB0aGlzLl9ub3RpZnlpbmdMaXN0ZW5lcnMgPSBmYWxzZTsKICAgIH0KICB9Cn0KCmZ1bmN0aW9uIGdlbmVyYXRlUHJvcGFnYXRpb25Db250ZXh0KCkgewogIHJldHVybiB7CiAgICB0cmFjZUlkOiB1dWlkNCgpLAogICAgc3BhbklkOiB1dWlkNCgpLnN1YnN0cmluZygxNiksCiAgfTsKfQoKY29uc3QgU0RLX1ZFUlNJT04gPSAnOC4wLjAtYWxwaGEuOSc7CgovKioKICogQVBJIGNvbXBhdGliaWxpdHkgdmVyc2lvbiBvZiB0aGlzIGh1Yi4KICoKICogV0FSTklORzogVGhpcyBudW1iZXIgc2hvdWxkIG9ubHkgYmUgaW5jcmVhc2VkIHdoZW4gdGhlIGdsb2JhbCBpbnRlcmZhY2UKICogY2hhbmdlcyBhbmQgbmV3IG1ldGhvZHMgYXJlIGludHJvZHVjZWQuCiAqCiAqIEBoaWRkZW4KICovCmNvbnN0IEFQSV9WRVJTSU9OID0gcGFyc2VGbG9hdChTREtfVkVSU0lPTik7CgovKioKICogRGVmYXVsdCBtYXhpbXVtIG51bWJlciBvZiBicmVhZGNydW1icyBhZGRlZCB0byBhbiBldmVudC4gQ2FuIGJlIG92ZXJ3cml0dGVuCiAqIHdpdGgge0BsaW5rIE9wdGlvbnMubWF4QnJlYWRjcnVtYnN9LgogKi8KY29uc3QgREVGQVVMVF9CUkVBRENSVU1CUyA9IDEwMDsKCi8qKgogKiBBIGxheWVyIGluIHRoZSBwcm9jZXNzIHN0YWNrLgogKiBAaGlkZGVuCiAqLwoKLyoqCiAqIEBpbmhlcml0RG9jCiAqLwpjbGFzcyBIdWIgIHsKICAvKiogSXMgYSB7QGxpbmsgTGF5ZXJ9W10gY29udGFpbmluZyB0aGUgY2xpZW50IGFuZCBzY29wZSAqLwoKICAvKioKICAgKiBDcmVhdGVzIGEgbmV3IGluc3RhbmNlIG9mIHRoZSBodWIsIHdpbGwgcHVzaCBvbmUge0BsaW5rIExheWVyfSBpbnRvIHRoZQogICAqIGludGVybmFsIHN0YWNrIG9uIGNyZWF0aW9uLgogICAqCiAgICogQHBhcmFtIGNsaWVudCBib3VuZCB0byB0aGUgaHViLgogICAqIEBwYXJhbSBzY29wZSBib3VuZCB0byB0aGUgaHViLgogICAqIEBwYXJhbSB2ZXJzaW9uIG51bWJlciwgaGlnaGVyIG51bWJlciBtZWFucyBoaWdoZXIgcHJpb3JpdHkuCiAgICoKICAgKiBAZGVwcmVjYXRlZCBJbnN0YW50aWF0aW9uIG9mIEh1YiBvYmplY3RzIGlzIGRlcHJlY2F0ZWQgYW5kIHRoZSBjb25zdHJ1Y3RvciB3aWxsIGJlIHJlbW92ZWQgaW4gdmVyc2lvbiA4IG9mIHRoZSBTREsuCiAgICoKICAgKiBJZiB5b3UgYXJlIGN1cnJlbnRseSB1c2luZyB0aGUgSHViIGZvciBtdWx0aS1jbGllbnQgdXNlIGxpa2Ugc286CiAgICoKICAgKiBgYGAKICAgKiAvLyBPTEQKICAgKiBjb25zdCBodWIgPSBuZXcgSHViKCk7CiAgICogaHViLmJpbmRDbGllbnQoY2xpZW50KTsKICAgKiBtYWtlTWFpbihodWIpCiAgICogYGBgCiAgICoKICAgKiBpbnN0ZWFkIGluaXRpYWxpemUgdGhlIGNsaWVudCBhcyBmb2xsb3dzOgogICAqCiAgICogYGBgCiAgICogLy8gTkVXCiAgICogU2VudHJ5LndpdGhJc29sYXRpb25TY29wZSgoKSA9PiB7CiAgICogICAgU2VudHJ5LnNldEN1cnJlbnRDbGllbnQoY2xpZW50KTsKICAgKiAgICBjbGllbnQuaW5pdCgpOwogICAqIH0pOwogICAqIGBgYAogICAqCiAgICogSWYgeW91IGFyZSB1c2luZyB0aGUgSHViIHRvIGNhcHR1cmUgZXZlbnRzIGxpa2Ugc286CiAgICoKICAgKiBgYGAKICAgKiAvLyBPTEQKICAgKiBjb25zdCBjbGllbnQgPSBuZXcgQ2xpZW50KCk7CiAgICogY29uc3QgaHViID0gbmV3IEh1YihjbGllbnQpOwogICAqIGh1Yi5jYXB0dXJlRXhjZXB0aW9uKCkKICAgKiBgYGAKICAgKgogICAqIGluc3RlYWQgY2FwdHVyZSBpc29sYXRlZCBldmVudHMgYXMgZm9sbG93czoKICAgKgogICAqIGBgYAogICAqIC8vIE5FVwogICAqIGNvbnN0IGNsaWVudCA9IG5ldyBDbGllbnQoKTsKICAgKiBjb25zdCBzY29wZSA9IG5ldyBTY29wZSgpOwogICAqIHNjb3BlLnNldENsaWVudChjbGllbnQpOwogICAqIHNjb3BlLmNhcHR1cmVFeGNlcHRpb24oKTsKICAgKiBgYGAKICAgKi8KICAgY29uc3RydWN0b3IoCiAgICBjbGllbnQsCiAgICBzY29wZSwKICAgIGlzb2xhdGlvblNjb3BlLAogICAgICBfdmVyc2lvbiA9IEFQSV9WRVJTSU9OLAogICkge3RoaXMuX3ZlcnNpb24gPSBfdmVyc2lvbjsKICAgIGxldCBhc3NpZ25lZFNjb3BlOwogICAgaWYgKCFzY29wZSkgewogICAgICBhc3NpZ25lZFNjb3BlID0gbmV3IFNjb3BlKCk7CiAgICAgIGFzc2lnbmVkU2NvcGUuc2V0Q2xpZW50KGNsaWVudCk7CiAgICB9IGVsc2UgewogICAgICBhc3NpZ25lZFNjb3BlID0gc2NvcGU7CiAgICB9CgogICAgbGV0IGFzc2lnbmVkSXNvbGF0aW9uU2NvcGU7CiAgICBpZiAoIWlzb2xhdGlvblNjb3BlKSB7CiAgICAgIGFzc2lnbmVkSXNvbGF0aW9uU2NvcGUgPSBuZXcgU2NvcGUoKTsKICAgICAgYXNzaWduZWRJc29sYXRpb25TY29wZS5zZXRDbGllbnQoY2xpZW50KTsKICAgIH0gZWxzZSB7CiAgICAgIGFzc2lnbmVkSXNvbGF0aW9uU2NvcGUgPSBpc29sYXRpb25TY29wZTsKICAgIH0KCiAgICB0aGlzLl9zdGFjayA9IFt7IHNjb3BlOiBhc3NpZ25lZFNjb3BlIH1dOwoKICAgIGlmIChjbGllbnQpIHsKICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICAgIHRoaXMuYmluZENsaWVudChjbGllbnQpOwogICAgfQoKICAgIHRoaXMuX2lzb2xhdGlvblNjb3BlID0gYXNzaWduZWRJc29sYXRpb25TY29wZTsKICB9CgogIC8qKgogICAqIFRoaXMgYmluZHMgdGhlIGdpdmVuIGNsaWVudCB0byB0aGUgY3VycmVudCBzY29wZS4KICAgKiBAcGFyYW0gY2xpZW50IEFuIFNESyBjbGllbnQgKGNsaWVudCkgaW5zdGFuY2UuCiAgICoKICAgKiBAZGVwcmVjYXRlZCBVc2UgYGluaXRBbmRCaW5kKClgIGRpcmVjdGx5LCBvciBgc2V0Q3VycmVudENsaWVudCgpYCBhbmQvb3IgYGNsaWVudC5pbml0KClgIGluc3RlYWQuCiAgICovCiAgIGJpbmRDbGllbnQoY2xpZW50KSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGNvbnN0IHRvcCA9IHRoaXMuZ2V0U3RhY2tUb3AoKTsKICAgIHRvcC5jbGllbnQgPSBjbGllbnQ7CiAgICB0b3Auc2NvcGUuc2V0Q2xpZW50KGNsaWVudCk7CiAgICBpZiAoY2xpZW50KSB7CiAgICAgIGNsaWVudC5pbml0KCk7CiAgICB9CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqCiAgICogQGRlcHJlY2F0ZWQgVXNlIGBTZW50cnkud2l0aFNjb3BlKClgIGluc3RlYWQuCiAgICovCiAgIHdpdGhTY29wZShjYWxsYmFjaykgewogICAgY29uc3Qgc2NvcGUgPSB0aGlzLl9wdXNoU2NvcGUoKTsKCiAgICBsZXQgbWF5YmVQcm9taXNlUmVzdWx0OwogICAgdHJ5IHsKICAgICAgbWF5YmVQcm9taXNlUmVzdWx0ID0gY2FsbGJhY2soc2NvcGUpOwogICAgfSBjYXRjaCAoZSkgewogICAgICB0aGlzLl9wb3BTY29wZSgpOwogICAgICB0aHJvdyBlOwogICAgfQoKICAgIGlmIChpc1RoZW5hYmxlKG1heWJlUHJvbWlzZVJlc3VsdCkpIHsKICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciAtIGlzVGhlbmFibGUgcmV0dXJucyB0aGUgd3JvbmcgdHlwZQogICAgICByZXR1cm4gbWF5YmVQcm9taXNlUmVzdWx0LnRoZW4oCiAgICAgICAgcmVzID0+IHsKICAgICAgICAgIHRoaXMuX3BvcFNjb3BlKCk7CiAgICAgICAgICByZXR1cm4gcmVzOwogICAgICAgIH0sCiAgICAgICAgZSA9PiB7CiAgICAgICAgICB0aGlzLl9wb3BTY29wZSgpOwogICAgICAgICAgdGhyb3cgZTsKICAgICAgICB9LAogICAgICApOwogICAgfQoKICAgIHRoaXMuX3BvcFNjb3BlKCk7CiAgICByZXR1cm4gbWF5YmVQcm9taXNlUmVzdWx0OwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKgogICAqIEBkZXByZWNhdGVkIFVzZSBgU2VudHJ5LmdldENsaWVudCgpYCBpbnN0ZWFkLgogICAqLwogICBnZXRDbGllbnQoKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHJldHVybiB0aGlzLmdldFN0YWNrVG9wKCkuY2xpZW50IDsKICB9CgogIC8qKgogICAqIFJldHVybnMgdGhlIHNjb3BlIG9mIHRoZSB0b3Agc3RhY2suCiAgICoKICAgKiBAZGVwcmVjYXRlZCBVc2UgYFNlbnRyeS5nZXRDdXJyZW50U2NvcGUoKWAgaW5zdGVhZC4KICAgKi8KICAgZ2V0U2NvcGUoKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHJldHVybiB0aGlzLmdldFN0YWNrVG9wKCkuc2NvcGU7CiAgfQoKICAvKioKICAgKiBAZGVwcmVjYXRlZCBVc2UgYFNlbnRyeS5nZXRJc29sYXRpb25TY29wZSgpYCBpbnN0ZWFkLgogICAqLwogICBnZXRJc29sYXRpb25TY29wZSgpIHsKICAgIHJldHVybiB0aGlzLl9pc29sYXRpb25TY29wZTsKICB9CgogIC8qKgogICAqIFJldHVybnMgdGhlIHNjb3BlIHN0YWNrIGZvciBkb21haW5zIG9yIHRoZSBwcm9jZXNzLgogICAqIEBkZXByZWNhdGVkIFRoaXMgd2lsbCBiZSByZW1vdmVkIGluIHY4LgogICAqLwogICBnZXRTdGFjaygpIHsKICAgIHJldHVybiB0aGlzLl9zdGFjazsKICB9CgogIC8qKgogICAqIFJldHVybnMgdGhlIHRvcG1vc3Qgc2NvcGUgbGF5ZXIgaW4gdGhlIG9yZGVyIGRvbWFpbiA+IGxvY2FsID4gcHJvY2Vzcy4KICAgKiBAZGVwcmVjYXRlZCBUaGlzIHdpbGwgYmUgcmVtb3ZlZCBpbiB2OC4KICAgKi8KICAgZ2V0U3RhY2tUb3AoKSB7CiAgICByZXR1cm4gdGhpcy5fc3RhY2tbdGhpcy5fc3RhY2subGVuZ3RoIC0gMV07CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqCiAgICogQGRlcHJlY2F0ZWQgVXNlIGBTZW50cnkuY2FwdHVyZUV4Y2VwdGlvbigpYCBpbnN0ZWFkLgogICAqLwogICBjYXB0dXJlRXhjZXB0aW9uKGV4Y2VwdGlvbiwgaGludCkgewogICAgY29uc3QgZXZlbnRJZCA9IGhpbnQgJiYgaGludC5ldmVudF9pZCA/IGhpbnQuZXZlbnRfaWQgOiB1dWlkNCgpOwogICAgY29uc3Qgc3ludGhldGljRXhjZXB0aW9uID0gbmV3IEVycm9yKCdTZW50cnkgc3ludGhldGljRXhjZXB0aW9uJyk7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHRoaXMuZ2V0U2NvcGUoKS5jYXB0dXJlRXhjZXB0aW9uKGV4Y2VwdGlvbiwgewogICAgICBvcmlnaW5hbEV4Y2VwdGlvbjogZXhjZXB0aW9uLAogICAgICBzeW50aGV0aWNFeGNlcHRpb24sCiAgICAgIC4uLmhpbnQsCiAgICAgIGV2ZW50X2lkOiBldmVudElkLAogICAgfSk7CgogICAgcmV0dXJuIGV2ZW50SWQ7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqCiAgICogQGRlcHJlY2F0ZWQgVXNlICBgU2VudHJ5LmNhcHR1cmVNZXNzYWdlKClgIGluc3RlYWQuCiAgICovCiAgIGNhcHR1cmVNZXNzYWdlKG1lc3NhZ2UsIGxldmVsLCBoaW50KSB7CiAgICBjb25zdCBldmVudElkID0gaGludCAmJiBoaW50LmV2ZW50X2lkID8gaGludC5ldmVudF9pZCA6IHV1aWQ0KCk7CiAgICBjb25zdCBzeW50aGV0aWNFeGNlcHRpb24gPSBuZXcgRXJyb3IobWVzc2FnZSk7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHRoaXMuZ2V0U2NvcGUoKS5jYXB0dXJlTWVzc2FnZShtZXNzYWdlLCBsZXZlbCwgewogICAgICBvcmlnaW5hbEV4Y2VwdGlvbjogbWVzc2FnZSwKICAgICAgc3ludGhldGljRXhjZXB0aW9uLAogICAgICAuLi5oaW50LAogICAgICBldmVudF9pZDogZXZlbnRJZCwKICAgIH0pOwoKICAgIHJldHVybiBldmVudElkOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKgogICAqIEBkZXByZWNhdGVkIFVzZSBgU2VudHJ5LmNhcHR1cmVFdmVudCgpYCBpbnN0ZWFkLgogICAqLwogICBjYXB0dXJlRXZlbnQoZXZlbnQsIGhpbnQpIHsKICAgIGNvbnN0IGV2ZW50SWQgPSBoaW50ICYmIGhpbnQuZXZlbnRfaWQgPyBoaW50LmV2ZW50X2lkIDogdXVpZDQoKTsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgdGhpcy5nZXRTY29wZSgpLmNhcHR1cmVFdmVudChldmVudCwgeyAuLi5oaW50LCBldmVudF9pZDogZXZlbnRJZCB9KTsKICAgIHJldHVybiBldmVudElkOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKgogICAqIEBkZXByZWNhdGVkIFVzZSBgU2VudHJ5LmFkZEJyZWFkY3J1bWIoKWAgaW5zdGVhZC4KICAgKi8KICAgYWRkQnJlYWRjcnVtYihicmVhZGNydW1iLCBoaW50KSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGNvbnN0IHsgY2xpZW50IH0gPSB0aGlzLmdldFN0YWNrVG9wKCk7CgogICAgaWYgKCFjbGllbnQpIHJldHVybjsKCiAgICBjb25zdCB7IGJlZm9yZUJyZWFkY3J1bWIgPSBudWxsLCBtYXhCcmVhZGNydW1icyA9IERFRkFVTFRfQlJFQURDUlVNQlMgfSA9CiAgICAgIChjbGllbnQuZ2V0T3B0aW9ucyAmJiBjbGllbnQuZ2V0T3B0aW9ucygpKSB8fCB7fTsKCiAgICBpZiAobWF4QnJlYWRjcnVtYnMgPD0gMCkgcmV0dXJuOwoKICAgIGNvbnN0IHRpbWVzdGFtcCA9IGRhdGVUaW1lc3RhbXBJblNlY29uZHMoKTsKICAgIGNvbnN0IG1lcmdlZEJyZWFkY3J1bWIgPSB7IHRpbWVzdGFtcCwgLi4uYnJlYWRjcnVtYiB9OwogICAgY29uc3QgZmluYWxCcmVhZGNydW1iID0gYmVmb3JlQnJlYWRjcnVtYgogICAgICA/IChjb25zb2xlU2FuZGJveCgoKSA9PiBiZWZvcmVCcmVhZGNydW1iKG1lcmdlZEJyZWFkY3J1bWIsIGhpbnQpKSApCiAgICAgIDogbWVyZ2VkQnJlYWRjcnVtYjsKCiAgICBpZiAoZmluYWxCcmVhZGNydW1iID09PSBudWxsKSByZXR1cm47CgogICAgY2xpZW50LmVtaXQoJ2JlZm9yZUFkZEJyZWFkY3J1bWInLCBmaW5hbEJyZWFkY3J1bWIsIGhpbnQpOwoKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgdGhpcy5nZXRJc29sYXRpb25TY29wZSgpLmFkZEJyZWFkY3J1bWIoZmluYWxCcmVhZGNydW1iLCBtYXhCcmVhZGNydW1icyk7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqIEBkZXByZWNhdGVkIFVzZSBgU2VudHJ5LnNldFVzZXIoKWAgaW5zdGVhZC4KICAgKi8KICAgc2V0VXNlcih1c2VyKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHRoaXMuZ2V0SXNvbGF0aW9uU2NvcGUoKS5zZXRVc2VyKHVzZXIpOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKiBAZGVwcmVjYXRlZCBVc2UgYFNlbnRyeS5zZXRUYWdzKClgIGluc3RlYWQuCiAgICovCiAgIHNldFRhZ3ModGFncykgewogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICB0aGlzLmdldElzb2xhdGlvblNjb3BlKCkuc2V0VGFncyh0YWdzKTsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICogQGRlcHJlY2F0ZWQgVXNlIGBTZW50cnkuc2V0RXh0cmFzKClgIGluc3RlYWQuCiAgICovCiAgIHNldEV4dHJhcyhleHRyYXMpIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgdGhpcy5nZXRJc29sYXRpb25TY29wZSgpLnNldEV4dHJhcyhleHRyYXMpOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKiBAZGVwcmVjYXRlZCBVc2UgYFNlbnRyeS5zZXRUYWcoKWAgaW5zdGVhZC4KICAgKi8KICAgc2V0VGFnKGtleSwgdmFsdWUpIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgdGhpcy5nZXRJc29sYXRpb25TY29wZSgpLnNldFRhZyhrZXksIHZhbHVlKTsKICB9CgogIC8qKgogICAqIEBpbmhlcml0RG9jCiAgICogQGRlcHJlY2F0ZWQgVXNlIGBTZW50cnkuc2V0RXh0cmEoKWAgaW5zdGVhZC4KICAgKi8KICAgc2V0RXh0cmEoa2V5LCBleHRyYSkgewogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICB0aGlzLmdldElzb2xhdGlvblNjb3BlKCkuc2V0RXh0cmEoa2V5LCBleHRyYSk7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqIEBkZXByZWNhdGVkIFVzZSBgU2VudHJ5LnNldENvbnRleHQoKWAgaW5zdGVhZC4KICAgKi8KICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueQogICBzZXRDb250ZXh0KG5hbWUsIGNvbnRleHQpIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgdGhpcy5nZXRJc29sYXRpb25TY29wZSgpLnNldENvbnRleHQobmFtZSwgY29udGV4dCk7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqIEBkZXByZWNhdGVkIFVzZSBgU2VudHJ5LmdldENsaWVudCgpLmdldEludGVncmF0aW9uQnlOYW1lKClgIGluc3RlYWQuCiAgICovCiAgIGdldEludGVncmF0aW9uKGludGVncmF0aW9uKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGNvbnN0IGNsaWVudCA9IHRoaXMuZ2V0Q2xpZW50KCk7CiAgICBpZiAoIWNsaWVudCkgcmV0dXJuIG51bGw7CiAgICB0cnkgewogICAgICByZXR1cm4gY2xpZW50LmdldEludGVncmF0aW9uQnlOYW1lKGludGVncmF0aW9uLmlkKSB8fCBudWxsOwogICAgfSBjYXRjaCAoX29PKSB7CiAgICAgIERFQlVHX0JVSUxEICYmIGxvZ2dlci53YXJuKGBDYW5ub3QgcmV0cmlldmUgaW50ZWdyYXRpb24gJHtpbnRlZ3JhdGlvbi5pZH0gZnJvbSB0aGUgY3VycmVudCBIdWJgKTsKICAgICAgcmV0dXJuIG51bGw7CiAgICB9CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqCiAgICogQGRlcHJlY2F0ZWQgVXNlIHRvcCBsZXZlbCBgY2FwdHVyZVNlc3Npb25gIGluc3RlYWQuCiAgICovCiAgIGNhcHR1cmVTZXNzaW9uKGVuZFNlc3Npb24gPSBmYWxzZSkgewogICAgLy8gYm90aCBzZW5kIHRoZSB1cGRhdGUgYW5kIHB1bGwgdGhlIHNlc3Npb24gZnJvbSB0aGUgc2NvcGUKICAgIGlmIChlbmRTZXNzaW9uKSB7CiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgICByZXR1cm4gdGhpcy5lbmRTZXNzaW9uKCk7CiAgICB9CgogICAgLy8gb25seSBzZW5kIHRoZSB1cGRhdGUKICAgIHRoaXMuX3NlbmRTZXNzaW9uVXBkYXRlKCk7CiAgfQoKICAvKioKICAgKiBAaW5oZXJpdERvYwogICAqIEBkZXByZWNhdGVkIFVzZSB0b3AgbGV2ZWwgYGVuZFNlc3Npb25gIGluc3RlYWQuCiAgICovCiAgIGVuZFNlc3Npb24oKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGNvbnN0IGxheWVyID0gdGhpcy5nZXRTdGFja1RvcCgpOwogICAgY29uc3Qgc2NvcGUgPSBsYXllci5zY29wZTsKICAgIGNvbnN0IHNlc3Npb24gPSBzY29wZS5nZXRTZXNzaW9uKCk7CiAgICBpZiAoc2Vzc2lvbikgewogICAgICBjbG9zZVNlc3Npb24oc2Vzc2lvbik7CiAgICB9CiAgICB0aGlzLl9zZW5kU2Vzc2lvblVwZGF0ZSgpOwoKICAgIC8vIHRoZSBzZXNzaW9uIGlzIG92ZXI7IHRha2UgaXQgb2ZmIG9mIHRoZSBzY29wZQogICAgc2NvcGUuc2V0U2Vzc2lvbigpOwogIH0KCiAgLyoqCiAgICogQGluaGVyaXREb2MKICAgKiBAZGVwcmVjYXRlZCBVc2UgdG9wIGxldmVsIGBzdGFydFNlc3Npb25gIGluc3RlYWQuCiAgICovCiAgIHN0YXJ0U2Vzc2lvbihjb250ZXh0KSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGNvbnN0IHsgc2NvcGUsIGNsaWVudCB9ID0gdGhpcy5nZXRTdGFja1RvcCgpOwogICAgY29uc3QgeyByZWxlYXNlLCBlbnZpcm9ubWVudCA9IERFRkFVTFRfRU5WSVJPTk1FTlQgfSA9IChjbGllbnQgJiYgY2xpZW50LmdldE9wdGlvbnMoKSkgfHwge307CgogICAgLy8gV2lsbCBmZXRjaCB1c2VyQWdlbnQgaWYgY2FsbGVkIGZyb20gYnJvd3NlciBzZGsKICAgIGNvbnN0IHsgdXNlckFnZW50IH0gPSBHTE9CQUxfT0JKLm5hdmlnYXRvciB8fCB7fTsKCiAgICBjb25zdCBzZXNzaW9uID0gbWFrZVNlc3Npb24oewogICAgICByZWxlYXNlLAogICAgICBlbnZpcm9ubWVudCwKICAgICAgdXNlcjogc2NvcGUuZ2V0VXNlcigpLAogICAgICAuLi4odXNlckFnZW50ICYmIHsgdXNlckFnZW50IH0pLAogICAgICAuLi5jb250ZXh0LAogICAgfSk7CgogICAgLy8gRW5kIGV4aXN0aW5nIHNlc3Npb24gaWYgdGhlcmUncyBvbmUKICAgIGNvbnN0IGN1cnJlbnRTZXNzaW9uID0gc2NvcGUuZ2V0U2Vzc2lvbiAmJiBzY29wZS5nZXRTZXNzaW9uKCk7CiAgICBpZiAoY3VycmVudFNlc3Npb24gJiYgY3VycmVudFNlc3Npb24uc3RhdHVzID09PSAnb2snKSB7CiAgICAgIHVwZGF0ZVNlc3Npb24oY3VycmVudFNlc3Npb24sIHsgc3RhdHVzOiAnZXhpdGVkJyB9KTsKICAgIH0KICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgdGhpcy5lbmRTZXNzaW9uKCk7CgogICAgLy8gQWZ0ZXJ3YXJkcyB3ZSBzZXQgdGhlIG5ldyBzZXNzaW9uIG9uIHRoZSBzY29wZQogICAgc2NvcGUuc2V0U2Vzc2lvbihzZXNzaW9uKTsKCiAgICByZXR1cm4gc2Vzc2lvbjsKICB9CgogIC8qKgogICAqIFNlbmRzIHRoZSBjdXJyZW50IFNlc3Npb24gb24gdGhlIHNjb3BlCiAgICovCiAgIF9zZW5kU2Vzc2lvblVwZGF0ZSgpIHsKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgY29uc3QgeyBzY29wZSwgY2xpZW50IH0gPSB0aGlzLmdldFN0YWNrVG9wKCk7CgogICAgY29uc3Qgc2Vzc2lvbiA9IHNjb3BlLmdldFNlc3Npb24oKTsKICAgIGlmIChzZXNzaW9uICYmIGNsaWVudCAmJiBjbGllbnQuY2FwdHVyZVNlc3Npb24pIHsKICAgICAgY2xpZW50LmNhcHR1cmVTZXNzaW9uKHNlc3Npb24pOwogICAgfQogIH0KCiAgLyoqCiAgICogUHVzaCBhIHNjb3BlIHRvIHRoZSBzdGFjay4KICAgKi8KICAgX3B1c2hTY29wZSgpIHsKICAgIC8vIFdlIHdhbnQgdG8gY2xvbmUgdGhlIGNvbnRlbnQgb2YgcHJldiBzY29wZQogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICBjb25zdCBzY29wZSA9IHRoaXMuZ2V0U2NvcGUoKS5jbG9uZSgpOwogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICB0aGlzLmdldFN0YWNrKCkucHVzaCh7CiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkZXByZWNhdGlvbi9kZXByZWNhdGlvbgogICAgICBjbGllbnQ6IHRoaXMuZ2V0Q2xpZW50KCksCiAgICAgIHNjb3BlLAogICAgfSk7CiAgICByZXR1cm4gc2NvcGU7CiAgfQoKICAvKioKICAgKiBQb3AgYSBzY29wZSBmcm9tIHRoZSBzdGFjay4KICAgKi8KICAgX3BvcFNjb3BlKCkgewogICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgICBpZiAodGhpcy5nZXRTdGFjaygpLmxlbmd0aCA8PSAxKSByZXR1cm4gZmFsc2U7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHJldHVybiAhIXRoaXMuZ2V0U3RhY2soKS5wb3AoKTsKICB9Cn0KCi8qKiBHZXQgdGhlIGRlZmF1bHQgY3VycmVudCBzY29wZS4gKi8KZnVuY3Rpb24gZ2V0RGVmYXVsdEN1cnJlbnRTY29wZSgpIHsKICByZXR1cm4gZ2V0R2xvYmFsU2luZ2xldG9uKCdkZWZhdWx0Q3VycmVudFNjb3BlJywgKCkgPT4gbmV3IFNjb3BlKCkpOwp9CgovKiogR2V0IHRoZSBkZWZhdWx0IGlzb2xhdGlvbiBzY29wZS4gKi8KZnVuY3Rpb24gZ2V0RGVmYXVsdElzb2xhdGlvblNjb3BlKCkgewogIHJldHVybiBnZXRHbG9iYWxTaW5nbGV0b24oJ2RlZmF1bHRJc29sYXRpb25TY29wZScsICgpID0+IG5ldyBTY29wZSgpKTsKfQoKLyoqCiAqIEdldCB0aGUgZ2xvYmFsIGh1Yi4KICogVGhpcyB3aWxsIGJlIHJlbW92ZWQgZHVyaW5nIHRoZSB2OCBjeWNsZSBhbmQgaXMgb25seSBoZXJlIHRvIG1ha2UgbWlncmF0aW9uIGVhc2llci4KICovCmZ1bmN0aW9uIGdldEdsb2JhbEh1YigpIHsKICBjb25zdCByZWdpc3RyeSA9IGdldE1haW5DYXJyaWVyKCk7CiAgY29uc3Qgc2VudHJ5ID0gZ2V0U2VudHJ5Q2FycmllcihyZWdpc3RyeSkgOwoKICAvLyBJZiB0aGVyZSdzIG5vIGh1Yiwgb3IgaXRzIGFuIG9sZCBBUEksIGFzc2lnbiBhIG5ldyBvbmUKICBpZiAoc2VudHJ5Lmh1YikgewogICAgcmV0dXJuIHNlbnRyeS5odWI7CiAgfQoKICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICBzZW50cnkuaHViID0gbmV3IEh1Yih1bmRlZmluZWQsIGdldERlZmF1bHRDdXJyZW50U2NvcGUoKSwgZ2V0RGVmYXVsdElzb2xhdGlvblNjb3BlKCkpOwogIHJldHVybiBzZW50cnkuaHViOwp9CgovKioKICogR2V0IHRoZSBjdXJyZW50IGFzeW5jIGNvbnRleHQgc3RyYXRlZ3kuCiAqIElmIG5vbmUgaGFzIGJlZW4gc2V0dXAsIHRoZSBkZWZhdWx0IHdpbGwgYmUgdXNlZC4KICovCmZ1bmN0aW9uIGdldEFzeW5jQ29udGV4dFN0cmF0ZWd5KGNhcnJpZXIpIHsKICBjb25zdCBzZW50cnkgPSBnZXRTZW50cnlDYXJyaWVyKGNhcnJpZXIpOwoKICBpZiAoc2VudHJ5LmFjcykgewogICAgcmV0dXJuIHNlbnRyeS5hY3M7CiAgfQoKICAvLyBPdGhlcndpc2UsIHVzZSB0aGUgZGVmYXVsdCBvbmUKICByZXR1cm4gZ2V0SHViU3RhY2tBc3luY0NvbnRleHRTdHJhdGVneSgpOwp9CgpmdW5jdGlvbiB3aXRoU2NvcGUoY2FsbGJhY2spIHsKICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICByZXR1cm4gZ2V0R2xvYmFsSHViKCkud2l0aFNjb3BlKGNhbGxiYWNrKTsKfQoKZnVuY3Rpb24gd2l0aFNldFNjb3BlKHNjb3BlLCBjYWxsYmFjaykgewogIGNvbnN0IGh1YiA9IGdldEdsb2JhbEh1YigpIDsKICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICByZXR1cm4gaHViLndpdGhTY29wZSgoKSA9PiB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIGh1Yi5nZXRTdGFja1RvcCgpLnNjb3BlID0gc2NvcGUgOwogICAgcmV0dXJuIGNhbGxiYWNrKHNjb3BlKTsKICB9KTsKfQoKZnVuY3Rpb24gd2l0aElzb2xhdGlvblNjb3BlKGNhbGxiYWNrKSB7CiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGRlcHJlY2F0aW9uL2RlcHJlY2F0aW9uCiAgcmV0dXJuIGdldEdsb2JhbEh1YigpLndpdGhTY29wZSgoKSA9PiB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24KICAgIHJldHVybiBjYWxsYmFjayhnZXRHbG9iYWxIdWIoKS5nZXRJc29sYXRpb25TY29wZSgpKTsKICB9KTsKfQoKLyogZXNsaW50LWRpc2FibGUgZGVwcmVjYXRpb24vZGVwcmVjYXRpb24gKi8KZnVuY3Rpb24gZ2V0SHViU3RhY2tBc3luY0NvbnRleHRTdHJhdGVneSgpIHsKICByZXR1cm4gewogICAgZ2V0Q3VycmVudEh1YjogZ2V0R2xvYmFsSHViLAogICAgd2l0aElzb2xhdGlvblNjb3BlLAogICAgd2l0aFNjb3BlLAogICAgd2l0aFNldFNjb3BlLAogICAgd2l0aFNldElzb2xhdGlvblNjb3BlOiAoX2lzb2xhdGlvblNjb3BlLCBjYWxsYmFjaykgPT4gewogICAgICByZXR1cm4gd2l0aElzb2xhdGlvblNjb3BlKGNhbGxiYWNrKTsKICAgIH0sCiAgICBnZXRDdXJyZW50U2NvcGU6ICgpID0+IGdldEdsb2JhbEh1YigpLmdldFNjb3BlKCksCiAgICBnZXRJc29sYXRpb25TY29wZTogKCkgPT4gZ2V0R2xvYmFsSHViKCkuZ2V0SXNvbGF0aW9uU2NvcGUoKSwKICB9Owp9CgovKioKICogR2V0IHRoZSBjdXJyZW50bHkgYWN0aXZlIHNjb3BlLgogKi8KZnVuY3Rpb24gZ2V0Q3VycmVudFNjb3BlKCkgewogIGNvbnN0IGNhcnJpZXIgPSBnZXRNYWluQ2FycmllcigpOwogIGNvbnN0IGFjcyA9IGdldEFzeW5jQ29udGV4dFN0cmF0ZWd5KGNhcnJpZXIpOwogIHJldHVybiBhY3MuZ2V0Q3VycmVudFNjb3BlKCk7Cn0KCi8qKgogKiBHZXQgdGhlIGN1cnJlbnRseSBhY3RpdmUgY2xpZW50LgogKi8KZnVuY3Rpb24gZ2V0Q2xpZW50KCkgewogIHJldHVybiBnZXRDdXJyZW50U2NvcGUoKS5nZXRDbGllbnQoKTsKfQoKLyoqCiAqIEZldGNoZXMgdGhlIG1ldHJpYyBzdW1tYXJ5IGlmIGl0IGV4aXN0cyBmb3IgdGhlIHBhc3NlZCBzcGFuCiAqLwpmdW5jdGlvbiBnZXRNZXRyaWNTdW1tYXJ5SnNvbkZvclNwYW4oc3BhbikgewoKICB7CiAgICByZXR1cm4gdW5kZWZpbmVkOwogIH0KfQoKLyoqCiAqIFVzZSB0aGlzIGF0dHJpYnV0ZSB0byByZXByZXNlbnQgdGhlIHNvdXJjZSBvZiBhIHNwYW4uCiAqIFNob3VsZCBiZSBvbmUgb2Y6IGN1c3RvbSwgdXJsLCByb3V0ZSwgdmlldywgY29tcG9uZW50LCB0YXNrLCB1bmtub3duCiAqCiAqLwpjb25zdCBTRU1BTlRJQ19BVFRSSUJVVEVfU0VOVFJZX1NPVVJDRSA9ICdzZW50cnkuc291cmNlJzsKCi8qKgogKiBVc2UgdGhpcyBhdHRyaWJ1dGUgdG8gcmVwcmVzZW50IHRoZSBzYW1wbGUgcmF0ZSB1c2VkIGZvciBhIHNwYW4uCiAqLwpjb25zdCBTRU1BTlRJQ19BVFRSSUJVVEVfU0VOVFJZX1NBTVBMRV9SQVRFID0gJ3NlbnRyeS5zYW1wbGVfcmF0ZSc7CgovKioKICogVXNlIHRoaXMgYXR0cmlidXRlIHRvIHJlcHJlc2VudCB0aGUgb3BlcmF0aW9uIG9mIGEgc3Bhbi4KICovCmNvbnN0IFNFTUFOVElDX0FUVFJJQlVURV9TRU5UUllfT1AgPSAnc2VudHJ5Lm9wJzsKCi8qKgogKiBVc2UgdGhpcyBhdHRyaWJ1dGUgdG8gcmVwcmVzZW50IHRoZSBvcmlnaW4gb2YgYSBzcGFuLgogKi8KY29uc3QgU0VNQU5USUNfQVRUUklCVVRFX1NFTlRSWV9PUklHSU4gPSAnc2VudHJ5Lm9yaWdpbic7Cgpjb25zdCBTUEFOX1NUQVRVU19VTlNFVCA9IDA7CmNvbnN0IFNQQU5fU1RBVFVTX09LID0gMTsKCmNvbnN0IFRSQUNFX0ZMQUdfU0FNUExFRCA9IDB4MTsKCi8qKgogKiBDb252ZXJ0IGEgc3BhbiB0byBhIHRyYWNlIGNvbnRleHQsIHdoaWNoIGNhbiBiZSBzZW50IGFzIHRoZSBgdHJhY2VgIGNvbnRleHQgaW4gYW4gZXZlbnQuCiAqLwpmdW5jdGlvbiBzcGFuVG9UcmFjZUNvbnRleHQoc3BhbikgewogIGNvbnN0IHsgc3BhbklkOiBzcGFuX2lkLCB0cmFjZUlkOiB0cmFjZV9pZCB9ID0gc3Bhbi5zcGFuQ29udGV4dCgpOwogIGNvbnN0IHsgZGF0YSwgb3AsIHBhcmVudF9zcGFuX2lkLCBzdGF0dXMsIG9yaWdpbiB9ID0gc3BhblRvSlNPTihzcGFuKTsKCiAgcmV0dXJuIGRyb3BVbmRlZmluZWRLZXlzKHsKICAgIGRhdGEsCiAgICBvcCwKICAgIHBhcmVudF9zcGFuX2lkLAogICAgc3Bhbl9pZCwKICAgIHN0YXR1cywKICAgIHRyYWNlX2lkLAogICAgb3JpZ2luLAogIH0pOwp9CgovKioKICogQ29udmVydCBhIHNwYW4gdGltZSBpbnB1dCBpbnRwIGEgdGltZXN0YW1wIGluIHNlY29uZHMuCiAqLwpmdW5jdGlvbiBzcGFuVGltZUlucHV0VG9TZWNvbmRzKGlucHV0KSB7CiAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ251bWJlcicpIHsKICAgIHJldHVybiBlbnN1cmVUaW1lc3RhbXBJblNlY29uZHMoaW5wdXQpOwogIH0KCiAgaWYgKEFycmF5LmlzQXJyYXkoaW5wdXQpKSB7CiAgICAvLyBTZWUge0BsaW5rIEhyVGltZX0gZm9yIHRoZSBhcnJheS1iYXNlZCB0aW1lIGZvcm1hdAogICAgcmV0dXJuIGlucHV0WzBdICsgaW5wdXRbMV0gLyAxZTk7CiAgfQoKICBpZiAoaW5wdXQgaW5zdGFuY2VvZiBEYXRlKSB7CiAgICByZXR1cm4gZW5zdXJlVGltZXN0YW1wSW5TZWNvbmRzKGlucHV0LmdldFRpbWUoKSk7CiAgfQoKICByZXR1cm4gdGltZXN0YW1wSW5TZWNvbmRzKCk7Cn0KCi8qKgogKiBDb252ZXJ0cyBhIHRpbWVzdGFtcCB0byBzZWNvbmQsIGlmIGl0IHdhcyBpbiBtaWxsaXNlY29uZHMsIG9yIGtlZXBzIGl0IGFzIHNlY29uZC4KICovCmZ1bmN0aW9uIGVuc3VyZVRpbWVzdGFtcEluU2Vjb25kcyh0aW1lc3RhbXApIHsKICBjb25zdCBpc01zID0gdGltZXN0YW1wID4gOTk5OTk5OTk5OTsKICByZXR1cm4gaXNNcyA/IHRpbWVzdGFtcCAvIDEwMDAgOiB0aW1lc3RhbXA7Cn0KCi8qKgogKiBDb252ZXJ0IGEgc3BhbiB0byBhIEpTT04gcmVwcmVzZW50YXRpb24uCiAqLwovLyBOb3RlOiBCZWNhdXNlIG9mIHRoaXMsIHdlIGN1cnJlbnRseSBoYXZlIGEgY2lyY3VsYXIgdHlwZSBkZXBlbmRlbmN5ICh3aGljaCB3ZSBvcHRlZCBvdXQgb2YgaW4gcGFja2FnZS5qc29uKS4KLy8gVGhpcyBpcyBub3QgYXZvaWRhYmxlIGFzIHdlIG5lZWQgYHNwYW5Ub0pTT05gIGluIGBzcGFuVXRpbHMudHNgLCB3aGljaCBpbiB0dXJuIGlzIG5lZWRlZCBieSBgc3Bhbi50c2AgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5LgovLyBBbmQgYHNwYW5Ub0pTT05gIG5lZWRzIHRoZSBTcGFuIGNsYXNzIGZyb20gYHNwYW4udHNgIHRvIGNoZWNrIGhlcmUuCmZ1bmN0aW9uIHNwYW5Ub0pTT04oc3BhbikgewogIGlmIChzcGFuSXNTZW50cnlTcGFuKHNwYW4pKSB7CiAgICByZXR1cm4gc3Bhbi5nZXRTcGFuSlNPTigpOwogIH0KCiAgdHJ5IHsKICAgIGNvbnN0IHsgc3BhbklkOiBzcGFuX2lkLCB0cmFjZUlkOiB0cmFjZV9pZCB9ID0gc3Bhbi5zcGFuQ29udGV4dCgpOwoKICAgIC8vIEhhbmRsZSBhIHNwYW4gZnJvbSBAb3BlbnRlbGVtZXRyeS9zZGstYmFzZS10cmFjZSdzIGBTcGFuYCBjbGFzcwogICAgaWYgKHNwYW5Jc09wZW5UZWxlbWV0cnlTZGtUcmFjZUJhc2VTcGFuKHNwYW4pKSB7CiAgICAgIGNvbnN0IHsgYXR0cmlidXRlcywgc3RhcnRUaW1lLCBuYW1lLCBlbmRUaW1lLCBwYXJlbnRTcGFuSWQsIHN0YXR1cyB9ID0gc3BhbjsKCiAgICAgIHJldHVybiBkcm9wVW5kZWZpbmVkS2V5cyh7CiAgICAgICAgc3Bhbl9pZCwKICAgICAgICB0cmFjZV9pZCwKICAgICAgICBkYXRhOiBhdHRyaWJ1dGVzLAogICAgICAgIGRlc2NyaXB0aW9uOiBuYW1lLAogICAgICAgIHBhcmVudF9zcGFuX2lkOiBwYXJlbnRTcGFuSWQsCiAgICAgICAgc3RhcnRfdGltZXN0YW1wOiBzcGFuVGltZUlucHV0VG9TZWNvbmRzKHN0YXJ0VGltZSksCiAgICAgICAgLy8gVGhpcyBpcyBbMCwwXSBieSBkZWZhdWx0IGluIE9URUwsIGluIHdoaWNoIGNhc2Ugd2Ugd2FudCB0byBpbnRlcnByZXQgdGhpcyBhcyBubyBlbmQgdGltZQogICAgICAgIHRpbWVzdGFtcDogc3BhblRpbWVJbnB1dFRvU2Vjb25kcyhlbmRUaW1lKSB8fCB1bmRlZmluZWQsCiAgICAgICAgc3RhdHVzOiBnZXRTdGF0dXNNZXNzYWdlKHN0YXR1cyksCiAgICAgICAgb3A6IGF0dHJpYnV0ZXNbU0VNQU5USUNfQVRUUklCVVRFX1NFTlRSWV9PUF0sCiAgICAgICAgb3JpZ2luOiBhdHRyaWJ1dGVzW1NFTUFOVElDX0FUVFJJQlVURV9TRU5UUllfT1JJR0lOXSAsCiAgICAgICAgX21ldHJpY3Nfc3VtbWFyeTogZ2V0TWV0cmljU3VtbWFyeUpzb25Gb3JTcGFuKCksCiAgICAgIH0pOwogICAgfQoKICAgIC8vIEZpbmFsbHksIGF0IGxlYXN0IHdlIGhhdmUgYHNwYW5Db250ZXh0KClgLi4uLgogICAgcmV0dXJuIHsKICAgICAgc3Bhbl9pZCwKICAgICAgdHJhY2VfaWQsCiAgICB9OwogIH0gY2F0Y2ggKGUpIHsKICAgIHJldHVybiB7fTsKICB9Cn0KCmZ1bmN0aW9uIHNwYW5Jc09wZW5UZWxlbWV0cnlTZGtUcmFjZUJhc2VTcGFuKHNwYW4pIHsKICBjb25zdCBjYXN0U3BhbiA9IHNwYW4gOwogIHJldHVybiAhIWNhc3RTcGFuLmF0dHJpYnV0ZXMgJiYgISFjYXN0U3Bhbi5zdGFydFRpbWUgJiYgISFjYXN0U3Bhbi5uYW1lICYmICEhY2FzdFNwYW4uZW5kVGltZSAmJiAhIWNhc3RTcGFuLnN0YXR1czsKfQoKLyoqIEV4cG9ydGVkIG9ubHkgZm9yIHRlc3RzLiAqLwoKLyoqCiAqIFNhZGx5LCBkdWUgdG8gY2lyY3VsYXIgZGVwZW5kZW5jeSBjaGVja3Mgd2UgY2Fubm90IGFjdHVhbGx5IGltcG9ydCB0aGUgU3BhbiBjbGFzcyBoZXJlIGFuZCBjaGVjayBmb3IgaW5zdGFuY2VvZi4KICogOiggU28gaW5zdGVhZCB3ZSBhcHByb3hpbWF0ZSB0aGlzIGJ5IGNoZWNraW5nIGlmIGl0IGhhcyB0aGUgYGdldFNwYW5KU09OYCBtZXRob2QuCiAqLwpmdW5jdGlvbiBzcGFuSXNTZW50cnlTcGFuKHNwYW4pIHsKICByZXR1cm4gdHlwZW9mIChzcGFuICkuZ2V0U3BhbkpTT04gPT09ICdmdW5jdGlvbic7Cn0KCi8qKgogKiBSZXR1cm5zIHRydWUgaWYgYSBzcGFuIGlzIHNhbXBsZWQuCiAqIEluIG1vc3QgY2FzZXMsIHlvdSBzaG91bGQganVzdCB1c2UgYHNwYW4uaXNSZWNvcmRpbmcoKWAgaW5zdGVhZC4KICogSG93ZXZlciwgdGhpcyBoYXMgYSBzbGlnaHRseSBkaWZmZXJlbnQgc2VtYW50aWMsIGFzIGl0IGFsc28gcmV0dXJucyBmYWxzZSBpZiB0aGUgc3BhbiBpcyBmaW5pc2hlZC4KICogU28gaW4gdGhlIGNhc2Ugd2hlcmUgdGhpcyBkaXN0aW5jdGlvbiBpcyBpbXBvcnRhbnQsIHVzZSB0aGlzIG1ldGhvZC4KICovCmZ1bmN0aW9uIHNwYW5Jc1NhbXBsZWQoc3BhbikgewogIC8vIFdlIGFsaWduIG91ciB0cmFjZSBmbGFncyB3aXRoIHRoZSBvbmVzIE9wZW5UZWxlbWV0cnkgdXNlCiAgLy8gU28gd2UgYWxzbyBjaGVjayBmb3Igc2FtcGxlZCB0aGUgc2FtZSB3YXkgdGhleSBkby4KICBjb25zdCB7IHRyYWNlRmxhZ3MgfSA9IHNwYW4uc3BhbkNvbnRleHQoKTsKICByZXR1cm4gdHJhY2VGbGFncyA9PT0gVFJBQ0VfRkxBR19TQU1QTEVEOwp9CgovKiogR2V0IHRoZSBzdGF0dXMgbWVzc2FnZSB0byB1c2UgZm9yIGEgSlNPTiByZXByZXNlbnRhdGlvbiBvZiBhIHNwYW4uICovCmZ1bmN0aW9uIGdldFN0YXR1c01lc3NhZ2Uoc3RhdHVzKSB7CiAgaWYgKCFzdGF0dXMgfHwgc3RhdHVzLmNvZGUgPT09IFNQQU5fU1RBVFVTX1VOU0VUKSB7CiAgICByZXR1cm4gdW5kZWZpbmVkOwogIH0KCiAgaWYgKHN0YXR1cy5jb2RlID09PSBTUEFOX1NUQVRVU19PSykgewogICAgcmV0dXJuICdvayc7CiAgfQoKICByZXR1cm4gc3RhdHVzLm1lc3NhZ2UgfHwgJ3Vua25vd25fZXJyb3InOwp9CmNvbnN0IFJPT1RfU1BBTl9GSUVMRCA9ICdfc2VudHJ5Um9vdFNwYW4nOwoKLyoqCiAqIFJldHVybnMgdGhlIHJvb3Qgc3BhbiBvZiBhIGdpdmVuIHNwYW4uCiAqLwpmdW5jdGlvbiBnZXRSb290U3BhbihzcGFuKSB7CiAgcmV0dXJuIHNwYW5bUk9PVF9TUEFOX0ZJRUxEXSB8fCBzcGFuOwp9CgovKioKICogSWYgeW91IGNoYW5nZSB0aGlzIHZhbHVlLCBhbHNvIHVwZGF0ZSB0aGUgdGVyc2VyIHBsdWdpbiBjb25maWcgdG8KICogYXZvaWQgbWluaWZpY2F0aW9uIG9mIHRoZSBvYmplY3QgcHJvcGVydHkhCiAqLwpjb25zdCBGUk9aRU5fRFNDX0ZJRUxEID0gJ19mcm96ZW5Ec2MnOwoKLyoqCiAqIENyZWF0ZXMgYSBkeW5hbWljIHNhbXBsaW5nIGNvbnRleHQgZnJvbSBhIGNsaWVudC4KICoKICogRGlzcGF0Y2hlcyB0aGUgYGNyZWF0ZURzY2AgbGlmZWN5Y2xlIGhvb2sgYXMgYSBzaWRlIGVmZmVjdC4KICovCmZ1bmN0aW9uIGdldER5bmFtaWNTYW1wbGluZ0NvbnRleHRGcm9tQ2xpZW50KHRyYWNlX2lkLCBjbGllbnQpIHsKICBjb25zdCBvcHRpb25zID0gY2xpZW50LmdldE9wdGlvbnMoKTsKCiAgY29uc3QgeyBwdWJsaWNLZXk6IHB1YmxpY19rZXkgfSA9IGNsaWVudC5nZXREc24oKSB8fCB7fTsKCiAgY29uc3QgZHNjID0gZHJvcFVuZGVmaW5lZEtleXMoewogICAgZW52aXJvbm1lbnQ6IG9wdGlvbnMuZW52aXJvbm1lbnQgfHwgREVGQVVMVF9FTlZJUk9OTUVOVCwKICAgIHJlbGVhc2U6IG9wdGlvbnMucmVsZWFzZSwKICAgIHB1YmxpY19rZXksCiAgICB0cmFjZV9pZCwKICB9KSA7CgogIGNsaWVudC5lbWl0KCdjcmVhdGVEc2MnLCBkc2MpOwoKICByZXR1cm4gZHNjOwp9CgovKioKICogQ3JlYXRlcyBhIGR5bmFtaWMgc2FtcGxpbmcgY29udGV4dCBmcm9tIGEgc3BhbiAoYW5kIGNsaWVudCBhbmQgc2NvcGUpCiAqCiAqIEBwYXJhbSBzcGFuIHRoZSBzcGFuIGZyb20gd2hpY2ggYSBmZXcgdmFsdWVzIGxpa2UgdGhlIHJvb3Qgc3BhbiBuYW1lIGFuZCBzYW1wbGUgcmF0ZSBhcmUgZXh0cmFjdGVkLgogKgogKiBAcmV0dXJucyBhIGR5bmFtaWMgc2FtcGxpbmcgY29udGV4dAogKi8KZnVuY3Rpb24gZ2V0RHluYW1pY1NhbXBsaW5nQ29udGV4dEZyb21TcGFuKHNwYW4pIHsKICBjb25zdCBjbGllbnQgPSBnZXRDbGllbnQoKTsKICBpZiAoIWNsaWVudCkgewogICAgcmV0dXJuIHt9OwogIH0KCiAgY29uc3QgZHNjID0gZ2V0RHluYW1pY1NhbXBsaW5nQ29udGV4dEZyb21DbGllbnQoc3BhblRvSlNPTihzcGFuKS50cmFjZV9pZCB8fCAnJywgY2xpZW50KTsKCiAgY29uc3Qgcm9vdFNwYW4gPSBnZXRSb290U3BhbihzcGFuKTsKICBpZiAoIXJvb3RTcGFuKSB7CiAgICByZXR1cm4gZHNjOwogIH0KCiAgY29uc3QgZnJvemVuRHNjID0gKHJvb3RTcGFuIClbRlJPWkVOX0RTQ19GSUVMRF07CiAgaWYgKGZyb3plbkRzYykgewogICAgcmV0dXJuIGZyb3plbkRzYzsKICB9CgogIGNvbnN0IGpzb25TcGFuID0gc3BhblRvSlNPTihyb290U3Bhbik7CiAgY29uc3QgYXR0cmlidXRlcyA9IGpzb25TcGFuLmRhdGEgfHwge307CiAgY29uc3QgbWF5YmVTYW1wbGVSYXRlID0gYXR0cmlidXRlc1tTRU1BTlRJQ19BVFRSSUJVVEVfU0VOVFJZX1NBTVBMRV9SQVRFXTsKCiAgaWYgKG1heWJlU2FtcGxlUmF0ZSAhPSBudWxsKSB7CiAgICBkc2Muc2FtcGxlX3JhdGUgPSBgJHttYXliZVNhbXBsZVJhdGV9YDsKICB9CgogIC8vIFdlIGRvbid0IHdhbnQgdG8gaGF2ZSBhIHRyYW5zYWN0aW9uIG5hbWUgaW4gdGhlIERTQyBpZiB0aGUgc291cmNlIGlzICJ1cmwiIGJlY2F1c2UgVVJMcyBtaWdodCBjb250YWluIFBJSQogIGNvbnN0IHNvdXJjZSA9IGF0dHJpYnV0ZXNbU0VNQU5USUNfQVRUUklCVVRFX1NFTlRSWV9TT1VSQ0VdOwoKICAvLyBhZnRlciBKU09OIGNvbnZlcnNpb24sIHR4bi5uYW1lIGJlY29tZXMganNvblNwYW4uZGVzY3JpcHRpb24KICBpZiAoc291cmNlICYmIHNvdXJjZSAhPT0gJ3VybCcpIHsKICAgIGRzYy50cmFuc2FjdGlvbiA9IGpzb25TcGFuLmRlc2NyaXB0aW9uOwogIH0KCiAgZHNjLnNhbXBsZWQgPSBTdHJpbmcoc3BhbklzU2FtcGxlZChyb290U3BhbikpOwoKICBjbGllbnQuZW1pdCgnY3JlYXRlRHNjJywgZHNjKTsKCiAgcmV0dXJuIGRzYzsKfQoKLyoqCiAqIEFwcGx5IFNka0luZm8gKG5hbWUsIHZlcnNpb24sIHBhY2thZ2VzLCBpbnRlZ3JhdGlvbnMpIHRvIHRoZSBjb3JyZXNwb25kaW5nIGV2ZW50IGtleS4KICogTWVyZ2Ugd2l0aCBleGlzdGluZyBkYXRhIGlmIGFueS4KICoqLwpmdW5jdGlvbiBlbmhhbmNlRXZlbnRXaXRoU2RrSW5mbyhldmVudCwgc2RrSW5mbykgewogIGlmICghc2RrSW5mbykgewogICAgcmV0dXJuIGV2ZW50OwogIH0KICBldmVudC5zZGsgPSBldmVudC5zZGsgfHwge307CiAgZXZlbnQuc2RrLm5hbWUgPSBldmVudC5zZGsubmFtZSB8fCBzZGtJbmZvLm5hbWU7CiAgZXZlbnQuc2RrLnZlcnNpb24gPSBldmVudC5zZGsudmVyc2lvbiB8fCBzZGtJbmZvLnZlcnNpb247CiAgZXZlbnQuc2RrLmludGVncmF0aW9ucyA9IFsuLi4oZXZlbnQuc2RrLmludGVncmF0aW9ucyB8fCBbXSksIC4uLihzZGtJbmZvLmludGVncmF0aW9ucyB8fCBbXSldOwogIGV2ZW50LnNkay5wYWNrYWdlcyA9IFsuLi4oZXZlbnQuc2RrLnBhY2thZ2VzIHx8IFtdKSwgLi4uKHNka0luZm8ucGFja2FnZXMgfHwgW10pXTsKICByZXR1cm4gZXZlbnQ7Cn0KCi8qKiBDcmVhdGVzIGFuIGVudmVsb3BlIGZyb20gYSBTZXNzaW9uICovCmZ1bmN0aW9uIGNyZWF0ZVNlc3Npb25FbnZlbG9wZSgKICBzZXNzaW9uLAogIGRzbiwKICBtZXRhZGF0YSwKICB0dW5uZWwsCikgewogIGNvbnN0IHNka0luZm8gPSBnZXRTZGtNZXRhZGF0YUZvckVudmVsb3BlSGVhZGVyKG1ldGFkYXRhKTsKICBjb25zdCBlbnZlbG9wZUhlYWRlcnMgPSB7CiAgICBzZW50X2F0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksCiAgICAuLi4oc2RrSW5mbyAmJiB7IHNkazogc2RrSW5mbyB9KSwKICAgIC4uLighIXR1bm5lbCAmJiBkc24gJiYgeyBkc246IGRzblRvU3RyaW5nKGRzbikgfSksCiAgfTsKCiAgY29uc3QgZW52ZWxvcGVJdGVtID0KICAgICdhZ2dyZWdhdGVzJyBpbiBzZXNzaW9uID8gW3sgdHlwZTogJ3Nlc3Npb25zJyB9LCBzZXNzaW9uXSA6IFt7IHR5cGU6ICdzZXNzaW9uJyB9LCBzZXNzaW9uLnRvSlNPTigpXTsKCiAgcmV0dXJuIGNyZWF0ZUVudmVsb3BlKGVudmVsb3BlSGVhZGVycywgW2VudmVsb3BlSXRlbV0pOwp9CgovKioKICogQ3JlYXRlIGFuIEVudmVsb3BlIGZyb20gYW4gZXZlbnQuCiAqLwpmdW5jdGlvbiBjcmVhdGVFdmVudEVudmVsb3BlKAogIGV2ZW50LAogIGRzbiwKICBtZXRhZGF0YSwKICB0dW5uZWwsCikgewogIGNvbnN0IHNka0luZm8gPSBnZXRTZGtNZXRhZGF0YUZvckVudmVsb3BlSGVhZGVyKG1ldGFkYXRhKTsKCiAgLyoKICAgIE5vdGU6IER1ZSB0byBUUywgZXZlbnQudHlwZSBtYXkgYmUgYHJlcGxheV9ldmVudGAsIHRoZW9yZXRpY2FsbHkuCiAgICBJbiBwcmFjdGljZSwgd2UgbmV2ZXIgY2FsbCBgY3JlYXRlRXZlbnRFbnZlbG9wZWAgd2l0aCBgcmVwbGF5X2V2ZW50YCB0eXBlLAogICAgYW5kIHdlJ2QgaGF2ZSB0byBhZGp1dCBhIGxvb290IG9mIHR5cGVzIHRvIG1ha2UgdGhpcyB3b3JrIHByb3Blcmx5LgogICAgV2Ugd2FudCB0byBhdm9pZCBjYXN0aW5nIHRoaXMgYXJvdW5kLCBhcyB0aGF0IGNvdWxkIGxlYWQgdG8gYnVncyAoZS5nLiB3aGVuIHdlIGFkZCBhbm90aGVyIHR5cGUpCiAgICBTbyB0aGUgc2FmZSBjaG9pY2UgaXMgdG8gcmVhbGx5IGd1YXJkIGFnYWluc3QgdGhlIHJlcGxheV9ldmVudCB0eXBlIGhlcmUuCiAgKi8KICBjb25zdCBldmVudFR5cGUgPSBldmVudC50eXBlICYmIGV2ZW50LnR5cGUgIT09ICdyZXBsYXlfZXZlbnQnID8gZXZlbnQudHlwZSA6ICdldmVudCc7CgogIGVuaGFuY2VFdmVudFdpdGhTZGtJbmZvKGV2ZW50LCBtZXRhZGF0YSAmJiBtZXRhZGF0YS5zZGspOwoKICBjb25zdCBlbnZlbG9wZUhlYWRlcnMgPSBjcmVhdGVFdmVudEVudmVsb3BlSGVhZGVycyhldmVudCwgc2RrSW5mbywgdHVubmVsLCBkc24pOwoKICAvLyBQcmV2ZW50IHRoaXMgZGF0YSAod2hpY2gsIGlmIGl0IGV4aXN0cywgd2FzIHVzZWQgaW4gZWFybGllciBzdGVwcyBpbiB0aGUgcHJvY2Vzc2luZyBwaXBlbGluZSkgZnJvbSBiZWluZyBzZW50IHRvCiAgLy8gc2VudHJ5LiAoTm90ZTogT3VyIHVzZSBvZiB0aGlzIHByb3BlcnR5IGNvbWVzIGFuZCBnb2VzIHdpdGggd2hhdGV2ZXIgd2UgbWlnaHQgYmUgZGVidWdnaW5nLCB3aGF0ZXZlciBoYWNrcyB3ZSBtYXkKICAvLyBoYXZlIHRlbXBvcmFyaWx5IGFkZGVkLCBldGMuIEV2ZW4gaWYgd2UgZG9uJ3QgaGFwcGVuIHRvIGJlIHVzaW5nIGl0IGF0IHNvbWUgcG9pbnQgaW4gdGhlIGZ1dHVyZSwgbGV0J3Mgbm90IGdldCByaWQKICAvLyBvZiB0aGlzIGBkZWxldGVgLCBsZXN0IHdlIG1pc3MgcHV0dGluZyBpdCBiYWNrIGluIHRoZSBuZXh0IHRpbWUgdGhlIHByb3BlcnR5IGlzIGluIHVzZS4pCiAgZGVsZXRlIGV2ZW50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YTsKCiAgY29uc3QgZXZlbnRJdGVtID0gW3sgdHlwZTogZXZlbnRUeXBlIH0sIGV2ZW50XTsKICByZXR1cm4gY3JlYXRlRW52ZWxvcGUoZW52ZWxvcGVIZWFkZXJzLCBbZXZlbnRJdGVtXSk7Cn0KCi8qKgogKiBBcHBsaWVzIGRhdGEgZnJvbSB0aGUgc2NvcGUgdG8gdGhlIGV2ZW50IGFuZCBydW5zIGFsbCBldmVudCBwcm9jZXNzb3JzIG9uIGl0LgogKi8KZnVuY3Rpb24gYXBwbHlTY29wZURhdGFUb0V2ZW50KGV2ZW50LCBkYXRhKSB7CiAgY29uc3QgeyBmaW5nZXJwcmludCwgc3BhbiwgYnJlYWRjcnVtYnMsIHNka1Byb2Nlc3NpbmdNZXRhZGF0YSB9ID0gZGF0YTsKCiAgLy8gQXBwbHkgZ2VuZXJhbCBkYXRhCiAgYXBwbHlEYXRhVG9FdmVudChldmVudCwgZGF0YSk7CgogIC8vIFdlIHdhbnQgdG8gc2V0IHRoZSB0cmFjZSBjb250ZXh0IGZvciBub3JtYWwgZXZlbnRzIG9ubHkgaWYgdGhlcmUgaXNuJ3QgYWxyZWFkeQogIC8vIGEgdHJhY2UgY29udGV4dCBvbiB0aGUgZXZlbnQuIFRoZXJlIGlzIGEgcHJvZHVjdCBmZWF0dXJlIGluIHBsYWNlIHdoZXJlIHdlIGxpbmsKICAvLyBlcnJvcnMgd2l0aCB0cmFuc2FjdGlvbiBhbmQgaXQgcmVsaWVzIG9uIHRoYXQuCiAgaWYgKHNwYW4pIHsKICAgIGFwcGx5U3BhblRvRXZlbnQoZXZlbnQsIHNwYW4pOwogIH0KCiAgYXBwbHlGaW5nZXJwcmludFRvRXZlbnQoZXZlbnQsIGZpbmdlcnByaW50KTsKICBhcHBseUJyZWFkY3J1bWJzVG9FdmVudChldmVudCwgYnJlYWRjcnVtYnMpOwogIGFwcGx5U2RrTWV0YWRhdGFUb0V2ZW50KGV2ZW50LCBzZGtQcm9jZXNzaW5nTWV0YWRhdGEpOwp9CgpmdW5jdGlvbiBhcHBseURhdGFUb0V2ZW50KGV2ZW50LCBkYXRhKSB7CiAgY29uc3QgeyBleHRyYSwgdGFncywgdXNlciwgY29udGV4dHMsIGxldmVsLCB0cmFuc2FjdGlvbk5hbWUgfSA9IGRhdGE7CgogIGNvbnN0IGNsZWFuZWRFeHRyYSA9IGRyb3BVbmRlZmluZWRLZXlzKGV4dHJhKTsKICBpZiAoY2xlYW5lZEV4dHJhICYmIE9iamVjdC5rZXlzKGNsZWFuZWRFeHRyYSkubGVuZ3RoKSB7CiAgICBldmVudC5leHRyYSA9IHsgLi4uY2xlYW5lZEV4dHJhLCAuLi5ldmVudC5leHRyYSB9OwogIH0KCiAgY29uc3QgY2xlYW5lZFRhZ3MgPSBkcm9wVW5kZWZpbmVkS2V5cyh0YWdzKTsKICBpZiAoY2xlYW5lZFRhZ3MgJiYgT2JqZWN0LmtleXMoY2xlYW5lZFRhZ3MpLmxlbmd0aCkgewogICAgZXZlbnQudGFncyA9IHsgLi4uY2xlYW5lZFRhZ3MsIC4uLmV2ZW50LnRhZ3MgfTsKICB9CgogIGNvbnN0IGNsZWFuZWRVc2VyID0gZHJvcFVuZGVmaW5lZEtleXModXNlcik7CiAgaWYgKGNsZWFuZWRVc2VyICYmIE9iamVjdC5rZXlzKGNsZWFuZWRVc2VyKS5sZW5ndGgpIHsKICAgIGV2ZW50LnVzZXIgPSB7IC4uLmNsZWFuZWRVc2VyLCAuLi5ldmVudC51c2VyIH07CiAgfQoKICBjb25zdCBjbGVhbmVkQ29udGV4dHMgPSBkcm9wVW5kZWZpbmVkS2V5cyhjb250ZXh0cyk7CiAgaWYgKGNsZWFuZWRDb250ZXh0cyAmJiBPYmplY3Qua2V5cyhjbGVhbmVkQ29udGV4dHMpLmxlbmd0aCkgewogICAgZXZlbnQuY29udGV4dHMgPSB7IC4uLmNsZWFuZWRDb250ZXh0cywgLi4uZXZlbnQuY29udGV4dHMgfTsKICB9CgogIGlmIChsZXZlbCkgewogICAgZXZlbnQubGV2ZWwgPSBsZXZlbDsKICB9CgogIC8vIHRyYW5zYWN0aW9uIGV2ZW50cyBnZXQgdGhlaXIgYHRyYW5zYWN0aW9uYCBmcm9tIHRoZSByb290IHNwYW4gbmFtZQogIGlmICh0cmFuc2FjdGlvbk5hbWUgJiYgZXZlbnQudHlwZSAhPT0gJ3RyYW5zYWN0aW9uJykgewogICAgZXZlbnQudHJhbnNhY3Rpb24gPSB0cmFuc2FjdGlvbk5hbWU7CiAgfQp9CgpmdW5jdGlvbiBhcHBseUJyZWFkY3J1bWJzVG9FdmVudChldmVudCwgYnJlYWRjcnVtYnMpIHsKICBjb25zdCBtZXJnZWRCcmVhZGNydW1icyA9IFsuLi4oZXZlbnQuYnJlYWRjcnVtYnMgfHwgW10pLCAuLi5icmVhZGNydW1ic107CiAgZXZlbnQuYnJlYWRjcnVtYnMgPSBtZXJnZWRCcmVhZGNydW1icy5sZW5ndGggPyBtZXJnZWRCcmVhZGNydW1icyA6IHVuZGVmaW5lZDsKfQoKZnVuY3Rpb24gYXBwbHlTZGtNZXRhZGF0YVRvRXZlbnQoZXZlbnQsIHNka1Byb2Nlc3NpbmdNZXRhZGF0YSkgewogIGV2ZW50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YSA9IHsKICAgIC4uLmV2ZW50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YSwKICAgIC4uLnNka1Byb2Nlc3NpbmdNZXRhZGF0YSwKICB9Owp9CgpmdW5jdGlvbiBhcHBseVNwYW5Ub0V2ZW50KGV2ZW50LCBzcGFuKSB7CiAgZXZlbnQuY29udGV4dHMgPSB7IHRyYWNlOiBzcGFuVG9UcmFjZUNvbnRleHQoc3BhbiksIC4uLmV2ZW50LmNvbnRleHRzIH07CgogIGV2ZW50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YSA9IHsKICAgIGR5bmFtaWNTYW1wbGluZ0NvbnRleHQ6IGdldER5bmFtaWNTYW1wbGluZ0NvbnRleHRGcm9tU3BhbihzcGFuKSwKICAgIC4uLmV2ZW50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YSwKICB9OwoKICBjb25zdCByb290U3BhbiA9IGdldFJvb3RTcGFuKHNwYW4pOwogIGNvbnN0IHRyYW5zYWN0aW9uTmFtZSA9IHNwYW5Ub0pTT04ocm9vdFNwYW4pLmRlc2NyaXB0aW9uOwogIGlmICh0cmFuc2FjdGlvbk5hbWUgJiYgIWV2ZW50LnRyYW5zYWN0aW9uICYmIGV2ZW50LnR5cGUgPT09ICd0cmFuc2FjdGlvbicpIHsKICAgIGV2ZW50LnRyYW5zYWN0aW9uID0gdHJhbnNhY3Rpb25OYW1lOwogIH0KfQoKLyoqCiAqIEFwcGxpZXMgZmluZ2VycHJpbnQgZnJvbSB0aGUgc2NvcGUgdG8gdGhlIGV2ZW50IGlmIHRoZXJlJ3Mgb25lLAogKiB1c2VzIG1lc3NhZ2UgaWYgdGhlcmUncyBvbmUgaW5zdGVhZCBvciBnZXQgcmlkIG9mIGVtcHR5IGZpbmdlcnByaW50CiAqLwpmdW5jdGlvbiBhcHBseUZpbmdlcnByaW50VG9FdmVudChldmVudCwgZmluZ2VycHJpbnQpIHsKICAvLyBNYWtlIHN1cmUgaXQncyBhbiBhcnJheSBmaXJzdCBhbmQgd2UgYWN0dWFsbHkgaGF2ZSBzb21ldGhpbmcgaW4gcGxhY2UKICBldmVudC5maW5nZXJwcmludCA9IGV2ZW50LmZpbmdlcnByaW50ID8gYXJyYXlpZnkoZXZlbnQuZmluZ2VycHJpbnQpIDogW107CgogIC8vIElmIHdlIGhhdmUgc29tZXRoaW5nIG9uIHRoZSBzY29wZSwgdGhlbiBtZXJnZSBpdCB3aXRoIGV2ZW50CiAgaWYgKGZpbmdlcnByaW50KSB7CiAgICBldmVudC5maW5nZXJwcmludCA9IGV2ZW50LmZpbmdlcnByaW50LmNvbmNhdChmaW5nZXJwcmludCk7CiAgfQoKICAvLyBJZiB3ZSBoYXZlIG5vIGRhdGEgYXQgYWxsLCByZW1vdmUgZW1wdHkgYXJyYXkgZGVmYXVsdAogIGlmIChldmVudC5maW5nZXJwcmludCAmJiAhZXZlbnQuZmluZ2VycHJpbnQubGVuZ3RoKSB7CiAgICBkZWxldGUgZXZlbnQuZmluZ2VycHJpbnQ7CiAgfQp9Cgpjb25zdCBTRU5UUllfQVBJX1ZFUlNJT04gPSAnNyc7CgovKiogUmV0dXJucyB0aGUgcHJlZml4IHRvIGNvbnN0cnVjdCBTZW50cnkgaW5nZXN0aW9uIEFQSSBlbmRwb2ludHMuICovCmZ1bmN0aW9uIGdldEJhc2VBcGlFbmRwb2ludChkc24pIHsKICBjb25zdCBwcm90b2NvbCA9IGRzbi5wcm90b2NvbCA/IGAke2Rzbi5wcm90b2NvbH06YCA6ICcnOwogIGNvbnN0IHBvcnQgPSBkc24ucG9ydCA/IGA6JHtkc24ucG9ydH1gIDogJyc7CiAgcmV0dXJuIGAke3Byb3RvY29sfS8vJHtkc24uaG9zdH0ke3BvcnR9JHtkc24ucGF0aCA/IGAvJHtkc24ucGF0aH1gIDogJyd9L2FwaS9gOwp9CgovKiogUmV0dXJucyB0aGUgaW5nZXN0IEFQSSBlbmRwb2ludCBmb3IgdGFyZ2V0LiAqLwpmdW5jdGlvbiBfZ2V0SW5nZXN0RW5kcG9pbnQoZHNuKSB7CiAgcmV0dXJuIGAke2dldEJhc2VBcGlFbmRwb2ludChkc24pfSR7ZHNuLnByb2plY3RJZH0vZW52ZWxvcGUvYDsKfQoKLyoqIFJldHVybnMgYSBVUkwtZW5jb2RlZCBzdHJpbmcgd2l0aCBhdXRoIGNvbmZpZyBzdWl0YWJsZSBmb3IgYSBxdWVyeSBzdHJpbmcuICovCmZ1bmN0aW9uIF9lbmNvZGVkQXV0aChkc24sIHNka0luZm8pIHsKICByZXR1cm4gdXJsRW5jb2RlKHsKICAgIC8vIFdlIHNlbmQgb25seSB0aGUgbWluaW11bSBzZXQgb2YgcmVxdWlyZWQgaW5mb3JtYXRpb24uIFNlZQogICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdC9pc3N1ZXMvMjU3Mi4KICAgIHNlbnRyeV9rZXk6IGRzbi5wdWJsaWNLZXksCiAgICBzZW50cnlfdmVyc2lvbjogU0VOVFJZX0FQSV9WRVJTSU9OLAogICAgLi4uKHNka0luZm8gJiYgeyBzZW50cnlfY2xpZW50OiBgJHtzZGtJbmZvLm5hbWV9LyR7c2RrSW5mby52ZXJzaW9ufWAgfSksCiAgfSk7Cn0KCi8qKgogKiBSZXR1cm5zIHRoZSBlbnZlbG9wZSBlbmRwb2ludCBVUkwgd2l0aCBhdXRoIGluIHRoZSBxdWVyeSBzdHJpbmcuCiAqCiAqIFNlbmRpbmcgYXV0aCBhcyBwYXJ0IG9mIHRoZSBxdWVyeSBzdHJpbmcgYW5kIG5vdCBhcyBjdXN0b20gSFRUUCBoZWFkZXJzIGF2b2lkcyBDT1JTIHByZWZsaWdodCByZXF1ZXN0cy4KICovCmZ1bmN0aW9uIGdldEVudmVsb3BlRW5kcG9pbnRXaXRoVXJsRW5jb2RlZEF1dGgoZHNuLCB0dW5uZWwsIHNka0luZm8pIHsKICByZXR1cm4gdHVubmVsID8gdHVubmVsIDogYCR7X2dldEluZ2VzdEVuZHBvaW50KGRzbil9PyR7X2VuY29kZWRBdXRoKGRzbiwgc2RrSW5mbyl9YDsKfQoKY29uc3QgREVGQVVMVF9UUkFOU1BPUlRfQlVGRkVSX1NJWkUgPSAzMDsKCi8qKgogKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIGEgU2VudHJ5IGBUcmFuc3BvcnRgCiAqCiAqIEBwYXJhbSBvcHRpb25zCiAqIEBwYXJhbSBtYWtlUmVxdWVzdAogKi8KZnVuY3Rpb24gY3JlYXRlVHJhbnNwb3J0KAogIG9wdGlvbnMsCiAgbWFrZVJlcXVlc3QsCiAgYnVmZmVyID0gbWFrZVByb21pc2VCdWZmZXIoCiAgICBvcHRpb25zLmJ1ZmZlclNpemUgfHwgREVGQVVMVF9UUkFOU1BPUlRfQlVGRkVSX1NJWkUsCiAgKSwKKSB7CiAgbGV0IHJhdGVMaW1pdHMgPSB7fTsKICBjb25zdCBmbHVzaCA9ICh0aW1lb3V0KSA9PiBidWZmZXIuZHJhaW4odGltZW91dCk7CgogIGZ1bmN0aW9uIHNlbmQoZW52ZWxvcGUpIHsKICAgIGNvbnN0IGZpbHRlcmVkRW52ZWxvcGVJdGVtcyA9IFtdOwoKICAgIC8vIERyb3AgcmF0ZSBsaW1pdGVkIGl0ZW1zIGZyb20gZW52ZWxvcGUKICAgIGZvckVhY2hFbnZlbG9wZUl0ZW0oZW52ZWxvcGUsIChpdGVtLCB0eXBlKSA9PiB7CiAgICAgIGNvbnN0IGVudmVsb3BlSXRlbURhdGFDYXRlZ29yeSA9IGVudmVsb3BlSXRlbVR5cGVUb0RhdGFDYXRlZ29yeSh0eXBlKTsKICAgICAgaWYgKGlzUmF0ZUxpbWl0ZWQocmF0ZUxpbWl0cywgZW52ZWxvcGVJdGVtRGF0YUNhdGVnb3J5KSkgewogICAgICAgIGNvbnN0IGV2ZW50ID0gZ2V0RXZlbnRGb3JFbnZlbG9wZUl0ZW0oaXRlbSwgdHlwZSk7CiAgICAgICAgb3B0aW9ucy5yZWNvcmREcm9wcGVkRXZlbnQoJ3JhdGVsaW1pdF9iYWNrb2ZmJywgZW52ZWxvcGVJdGVtRGF0YUNhdGVnb3J5LCBldmVudCk7CiAgICAgIH0gZWxzZSB7CiAgICAgICAgZmlsdGVyZWRFbnZlbG9wZUl0ZW1zLnB1c2goaXRlbSk7CiAgICAgIH0KICAgIH0pOwoKICAgIC8vIFNraXAgc2VuZGluZyBpZiBlbnZlbG9wZSBpcyBlbXB0eSBhZnRlciBmaWx0ZXJpbmcgb3V0IHJhdGUgbGltaXRlZCBldmVudHMKICAgIGlmIChmaWx0ZXJlZEVudmVsb3BlSXRlbXMubGVuZ3RoID09PSAwKSB7CiAgICAgIHJldHVybiByZXNvbHZlZFN5bmNQcm9taXNlKHt9KTsKICAgIH0KCiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueQogICAgY29uc3QgZmlsdGVyZWRFbnZlbG9wZSA9IGNyZWF0ZUVudmVsb3BlKGVudmVsb3BlWzBdLCBmaWx0ZXJlZEVudmVsb3BlSXRlbXMgKTsKCiAgICAvLyBDcmVhdGVzIGNsaWVudCByZXBvcnQgZm9yIGVhY2ggaXRlbSBpbiBhbiBlbnZlbG9wZQogICAgY29uc3QgcmVjb3JkRW52ZWxvcGVMb3NzID0gKHJlYXNvbikgPT4gewogICAgICBmb3JFYWNoRW52ZWxvcGVJdGVtKGZpbHRlcmVkRW52ZWxvcGUsIChpdGVtLCB0eXBlKSA9PiB7CiAgICAgICAgY29uc3QgZXZlbnQgPSBnZXRFdmVudEZvckVudmVsb3BlSXRlbShpdGVtLCB0eXBlKTsKICAgICAgICBvcHRpb25zLnJlY29yZERyb3BwZWRFdmVudChyZWFzb24sIGVudmVsb3BlSXRlbVR5cGVUb0RhdGFDYXRlZ29yeSh0eXBlKSwgZXZlbnQpOwogICAgICB9KTsKICAgIH07CgogICAgY29uc3QgcmVxdWVzdFRhc2sgPSAoKSA9PgogICAgICBtYWtlUmVxdWVzdCh7IGJvZHk6IHNlcmlhbGl6ZUVudmVsb3BlKGZpbHRlcmVkRW52ZWxvcGUpIH0pLnRoZW4oCiAgICAgICAgcmVzcG9uc2UgPT4gewogICAgICAgICAgLy8gV2UgZG9uJ3Qgd2FudCB0byB0aHJvdyBvbiBOT0sgcmVzcG9uc2VzLCBidXQgd2Ugd2FudCB0byBhdCBsZWFzdCBsb2cgdGhlbQogICAgICAgICAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgIT09IHVuZGVmaW5lZCAmJiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA8IDIwMCB8fCByZXNwb25zZS5zdGF0dXNDb2RlID49IDMwMCkpIHsKICAgICAgICAgICAgREVCVUdfQlVJTEQgJiYgbG9nZ2VyLndhcm4oYFNlbnRyeSByZXNwb25kZWQgd2l0aCBzdGF0dXMgY29kZSAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9IHRvIHNlbnQgZXZlbnQuYCk7CiAgICAgICAgICB9CgogICAgICAgICAgcmF0ZUxpbWl0cyA9IHVwZGF0ZVJhdGVMaW1pdHMocmF0ZUxpbWl0cywgcmVzcG9uc2UpOwogICAgICAgICAgcmV0dXJuIHJlc3BvbnNlOwogICAgICAgIH0sCiAgICAgICAgZXJyb3IgPT4gewogICAgICAgICAgcmVjb3JkRW52ZWxvcGVMb3NzKCduZXR3b3JrX2Vycm9yJyk7CiAgICAgICAgICB0aHJvdyBlcnJvcjsKICAgICAgICB9LAogICAgICApOwoKICAgIHJldHVybiBidWZmZXIuYWRkKHJlcXVlc3RUYXNrKS50aGVuKAogICAgICByZXN1bHQgPT4gcmVzdWx0LAogICAgICBlcnJvciA9PiB7CiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgU2VudHJ5RXJyb3IpIHsKICAgICAgICAgIERFQlVHX0JVSUxEICYmIGxvZ2dlci5lcnJvcignU2tpcHBlZCBzZW5kaW5nIGV2ZW50IGJlY2F1c2UgYnVmZmVyIGlzIGZ1bGwuJyk7CiAgICAgICAgICByZWNvcmRFbnZlbG9wZUxvc3MoJ3F1ZXVlX292ZXJmbG93Jyk7CiAgICAgICAgICByZXR1cm4gcmVzb2x2ZWRTeW5jUHJvbWlzZSh7fSk7CiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHRocm93IGVycm9yOwogICAgICAgIH0KICAgICAgfSwKICAgICk7CiAgfQoKICByZXR1cm4gewogICAgc2VuZCwKICAgIGZsdXNoLAogIH07Cn0KCmZ1bmN0aW9uIGdldEV2ZW50Rm9yRW52ZWxvcGVJdGVtKGl0ZW0sIHR5cGUpIHsKICBpZiAodHlwZSAhPT0gJ2V2ZW50JyAmJiB0eXBlICE9PSAndHJhbnNhY3Rpb24nKSB7CiAgICByZXR1cm4gdW5kZWZpbmVkOwogIH0KCiAgcmV0dXJuIEFycmF5LmlzQXJyYXkoaXRlbSkgPyAoaXRlbSApWzFdIDogdW5kZWZpbmVkOwp9CgovKgogKiBDb3B5cmlnaHQgVGhlIE9wZW5UZWxlbWV0cnkgQXV0aG9ycwogKgogKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgogKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKICoKICogICAgICBodHRwczovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiAqCiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUKICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiAqLwovKiogb25seSBnbG9iYWxzIHRoYXQgY29tbW9uIHRvIG5vZGUgYW5kIGJyb3dzZXJzIGFyZSBhbGxvd2VkICovCi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBub2RlL25vLXVuc3VwcG9ydGVkLWZlYXR1cmVzL2VzLWJ1aWx0aW5zCnZhciBfZ2xvYmFsVGhpcyA9IHR5cGVvZiBnbG9iYWxUaGlzID09PSAnb2JqZWN0JyA/IGdsb2JhbFRoaXMgOiBnbG9iYWw7CgovKgogKiBDb3B5cmlnaHQgVGhlIE9wZW5UZWxlbWV0cnkgQXV0aG9ycwogKgogKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgogKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKICoKICogICAgICBodHRwczovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiAqCiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUKICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiAqLwovLyB0aGlzIGlzIGF1dG9nZW5lcmF0ZWQgZmlsZSwgc2VlIHNjcmlwdHMvdmVyc2lvbi11cGRhdGUuanMKdmFyIFZFUlNJT04gPSAnMS43LjAnOwoKLyoKICogQ29weXJpZ2h0IFRoZSBPcGVuVGVsZW1ldHJ5IEF1dGhvcnMKICoKICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiAqCiAqICAgICAgaHR0cHM6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAogKgogKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgogKi8KdmFyIHJlID0gL14oXGQrKVwuKFxkKylcLihcZCspKC0oLispKT8kLzsKLyoqCiAqIENyZWF0ZSBhIGZ1bmN0aW9uIHRvIHRlc3QgYW4gQVBJIHZlcnNpb24gdG8gc2VlIGlmIGl0IGlzIGNvbXBhdGlibGUgd2l0aCB0aGUgcHJvdmlkZWQgb3duVmVyc2lvbi4KICoKICogVGhlIHJldHVybmVkIGZ1bmN0aW9uIGhhcyB0aGUgZm9sbG93aW5nIHNlbWFudGljczoKICogLSBFeGFjdCBtYXRjaCBpcyBhbHdheXMgY29tcGF0aWJsZQogKiAtIE1ham9yIHZlcnNpb25zIG11c3QgbWF0Y2ggZXhhY3RseQogKiAgICAtIDEueCBwYWNrYWdlIGNhbm5vdCB1c2UgZ2xvYmFsIDIueCBwYWNrYWdlCiAqICAgIC0gMi54IHBhY2thZ2UgY2Fubm90IHVzZSBnbG9iYWwgMS54IHBhY2thZ2UKICogLSBUaGUgbWlub3IgdmVyc2lvbiBvZiB0aGUgQVBJIG1vZHVsZSByZXF1ZXN0aW5nIGFjY2VzcyB0byB0aGUgZ2xvYmFsIEFQSSBtdXN0IGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byB0aGUgbWlub3IgdmVyc2lvbiBvZiB0aGlzIEFQSQogKiAgICAtIDEuMyBwYWNrYWdlIG1heSB1c2UgMS40IGdsb2JhbCBiZWNhdXNlIHRoZSBsYXRlciBnbG9iYWwgY29udGFpbnMgYWxsIGZ1bmN0aW9ucyAxLjMgZXhwZWN0cwogKiAgICAtIDEuNCBwYWNrYWdlIG1heSBOT1QgdXNlIDEuMyBnbG9iYWwgYmVjYXVzZSBpdCBtYXkgdHJ5IHRvIGNhbGwgZnVuY3Rpb25zIHdoaWNoIGRvbid0IGV4aXN0IG9uIDEuMwogKiAtIElmIHRoZSBtYWpvciB2ZXJzaW9uIGlzIDAsIHRoZSBtaW5vciB2ZXJzaW9uIGlzIHRyZWF0ZWQgYXMgdGhlIG1ham9yIGFuZCB0aGUgcGF0Y2ggaXMgdHJlYXRlZCBhcyB0aGUgbWlub3IKICogLSBQYXRjaCBhbmQgYnVpbGQgdGFnIGRpZmZlcmVuY2VzIGFyZSBub3QgY29uc2lkZXJlZCBhdCB0aGlzIHRpbWUKICoKICogQHBhcmFtIG93blZlcnNpb24gdmVyc2lvbiB3aGljaCBzaG91bGQgYmUgY2hlY2tlZCBhZ2FpbnN0CiAqLwpmdW5jdGlvbiBfbWFrZUNvbXBhdGliaWxpdHlDaGVjayhvd25WZXJzaW9uKSB7CiAgICB2YXIgYWNjZXB0ZWRWZXJzaW9ucyA9IG5ldyBTZXQoW293blZlcnNpb25dKTsKICAgIHZhciByZWplY3RlZFZlcnNpb25zID0gbmV3IFNldCgpOwogICAgdmFyIG15VmVyc2lvbk1hdGNoID0gb3duVmVyc2lvbi5tYXRjaChyZSk7CiAgICBpZiAoIW15VmVyc2lvbk1hdGNoKSB7CiAgICAgICAgLy8gd2UgY2Fubm90IGd1YXJhbnRlZSBjb21wYXRpYmlsaXR5IHNvIHdlIGFsd2F5cyByZXR1cm4gbm9vcAogICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7IHJldHVybiBmYWxzZTsgfTsKICAgIH0KICAgIHZhciBvd25WZXJzaW9uUGFyc2VkID0gewogICAgICAgIG1ham9yOiArbXlWZXJzaW9uTWF0Y2hbMV0sCiAgICAgICAgbWlub3I6ICtteVZlcnNpb25NYXRjaFsyXSwKICAgICAgICBwYXRjaDogK215VmVyc2lvbk1hdGNoWzNdLAogICAgICAgIHByZXJlbGVhc2U6IG15VmVyc2lvbk1hdGNoWzRdLAogICAgfTsKICAgIC8vIGlmIG93blZlcnNpb24gaGFzIGEgcHJlcmVsZWFzZSB0YWcsIHZlcnNpb25zIG11c3QgbWF0Y2ggZXhhY3RseQogICAgaWYgKG93blZlcnNpb25QYXJzZWQucHJlcmVsZWFzZSAhPSBudWxsKSB7CiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIGlzRXhhY3RtYXRjaChnbG9iYWxWZXJzaW9uKSB7CiAgICAgICAgICAgIHJldHVybiBnbG9iYWxWZXJzaW9uID09PSBvd25WZXJzaW9uOwogICAgICAgIH07CiAgICB9CiAgICBmdW5jdGlvbiBfcmVqZWN0KHYpIHsKICAgICAgICByZWplY3RlZFZlcnNpb25zLmFkZCh2KTsKICAgICAgICByZXR1cm4gZmFsc2U7CiAgICB9CiAgICBmdW5jdGlvbiBfYWNjZXB0KHYpIHsKICAgICAgICBhY2NlcHRlZFZlcnNpb25zLmFkZCh2KTsKICAgICAgICByZXR1cm4gdHJ1ZTsKICAgIH0KICAgIHJldHVybiBmdW5jdGlvbiBpc0NvbXBhdGlibGUoZ2xvYmFsVmVyc2lvbikgewogICAgICAgIGlmIChhY2NlcHRlZFZlcnNpb25zLmhhcyhnbG9iYWxWZXJzaW9uKSkgewogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CiAgICAgICAgaWYgKHJlamVjdGVkVmVyc2lvbnMuaGFzKGdsb2JhbFZlcnNpb24pKSB7CiAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICB9CiAgICAgICAgdmFyIGdsb2JhbFZlcnNpb25NYXRjaCA9IGdsb2JhbFZlcnNpb24ubWF0Y2gocmUpOwogICAgICAgIGlmICghZ2xvYmFsVmVyc2lvbk1hdGNoKSB7CiAgICAgICAgICAgIC8vIGNhbm5vdCBwYXJzZSBvdGhlciB2ZXJzaW9uCiAgICAgICAgICAgIC8vIHdlIGNhbm5vdCBndWFyYW50ZWUgY29tcGF0aWJpbGl0eSBzbyB3ZSBhbHdheXMgbm9vcAogICAgICAgICAgICByZXR1cm4gX3JlamVjdChnbG9iYWxWZXJzaW9uKTsKICAgICAgICB9CiAgICAgICAgdmFyIGdsb2JhbFZlcnNpb25QYXJzZWQgPSB7CiAgICAgICAgICAgIG1ham9yOiArZ2xvYmFsVmVyc2lvbk1hdGNoWzFdLAogICAgICAgICAgICBtaW5vcjogK2dsb2JhbFZlcnNpb25NYXRjaFsyXSwKICAgICAgICAgICAgcGF0Y2g6ICtnbG9iYWxWZXJzaW9uTWF0Y2hbM10sCiAgICAgICAgICAgIHByZXJlbGVhc2U6IGdsb2JhbFZlcnNpb25NYXRjaFs0XSwKICAgICAgICB9OwogICAgICAgIC8vIGlmIGdsb2JhbFZlcnNpb24gaGFzIGEgcHJlcmVsZWFzZSB0YWcsIHZlcnNpb25zIG11c3QgbWF0Y2ggZXhhY3RseQogICAgICAgIGlmIChnbG9iYWxWZXJzaW9uUGFyc2VkLnByZXJlbGVhc2UgIT0gbnVsbCkgewogICAgICAgICAgICByZXR1cm4gX3JlamVjdChnbG9iYWxWZXJzaW9uKTsKICAgICAgICB9CiAgICAgICAgLy8gbWFqb3IgdmVyc2lvbnMgbXVzdCBtYXRjaAogICAgICAgIGlmIChvd25WZXJzaW9uUGFyc2VkLm1ham9yICE9PSBnbG9iYWxWZXJzaW9uUGFyc2VkLm1ham9yKSB7CiAgICAgICAgICAgIHJldHVybiBfcmVqZWN0KGdsb2JhbFZlcnNpb24pOwogICAgICAgIH0KICAgICAgICBpZiAob3duVmVyc2lvblBhcnNlZC5tYWpvciA9PT0gMCkgewogICAgICAgICAgICBpZiAob3duVmVyc2lvblBhcnNlZC5taW5vciA9PT0gZ2xvYmFsVmVyc2lvblBhcnNlZC5taW5vciAmJgogICAgICAgICAgICAgICAgb3duVmVyc2lvblBhcnNlZC5wYXRjaCA8PSBnbG9iYWxWZXJzaW9uUGFyc2VkLnBhdGNoKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gX2FjY2VwdChnbG9iYWxWZXJzaW9uKTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gX3JlamVjdChnbG9iYWxWZXJzaW9uKTsKICAgICAgICB9CiAgICAgICAgaWYgKG93blZlcnNpb25QYXJzZWQubWlub3IgPD0gZ2xvYmFsVmVyc2lvblBhcnNlZC5taW5vcikgewogICAgICAgICAgICByZXR1cm4gX2FjY2VwdChnbG9iYWxWZXJzaW9uKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIF9yZWplY3QoZ2xvYmFsVmVyc2lvbik7CiAgICB9Owp9Ci8qKgogKiBUZXN0IGFuIEFQSSB2ZXJzaW9uIHRvIHNlZSBpZiBpdCBpcyBjb21wYXRpYmxlIHdpdGggdGhpcyBBUEkuCiAqCiAqIC0gRXhhY3QgbWF0Y2ggaXMgYWx3YXlzIGNvbXBhdGlibGUKICogLSBNYWpvciB2ZXJzaW9ucyBtdXN0IG1hdGNoIGV4YWN0bHkKICogICAgLSAxLnggcGFja2FnZSBjYW5ub3QgdXNlIGdsb2JhbCAyLnggcGFja2FnZQogKiAgICAtIDIueCBwYWNrYWdlIGNhbm5vdCB1c2UgZ2xvYmFsIDEueCBwYWNrYWdlCiAqIC0gVGhlIG1pbm9yIHZlcnNpb24gb2YgdGhlIEFQSSBtb2R1bGUgcmVxdWVzdGluZyBhY2Nlc3MgdG8gdGhlIGdsb2JhbCBBUEkgbXVzdCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gdGhlIG1pbm9yIHZlcnNpb24gb2YgdGhpcyBBUEkKICogICAgLSAxLjMgcGFja2FnZSBtYXkgdXNlIDEuNCBnbG9iYWwgYmVjYXVzZSB0aGUgbGF0ZXIgZ2xvYmFsIGNvbnRhaW5zIGFsbCBmdW5jdGlvbnMgMS4zIGV4cGVjdHMKICogICAgLSAxLjQgcGFja2FnZSBtYXkgTk9UIHVzZSAxLjMgZ2xvYmFsIGJlY2F1c2UgaXQgbWF5IHRyeSB0byBjYWxsIGZ1bmN0aW9ucyB3aGljaCBkb24ndCBleGlzdCBvbiAxLjMKICogLSBJZiB0aGUgbWFqb3IgdmVyc2lvbiBpcyAwLCB0aGUgbWlub3IgdmVyc2lvbiBpcyB0cmVhdGVkIGFzIHRoZSBtYWpvciBhbmQgdGhlIHBhdGNoIGlzIHRyZWF0ZWQgYXMgdGhlIG1pbm9yCiAqIC0gUGF0Y2ggYW5kIGJ1aWxkIHRhZyBkaWZmZXJlbmNlcyBhcmUgbm90IGNvbnNpZGVyZWQgYXQgdGhpcyB0aW1lCiAqCiAqIEBwYXJhbSB2ZXJzaW9uIHZlcnNpb24gb2YgdGhlIEFQSSByZXF1ZXN0aW5nIGFuIGluc3RhbmNlIG9mIHRoZSBnbG9iYWwgQVBJCiAqLwp2YXIgaXNDb21wYXRpYmxlID0gX21ha2VDb21wYXRpYmlsaXR5Q2hlY2soVkVSU0lPTik7CgovKgogKiBDb3B5cmlnaHQgVGhlIE9wZW5UZWxlbWV0cnkgQXV0aG9ycwogKgogKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgogKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKICoKICogICAgICBodHRwczovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiAqCiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUKICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiAqLwp2YXIgbWFqb3IgPSBWRVJTSU9OLnNwbGl0KCcuJylbMF07CnZhciBHTE9CQUxfT1BFTlRFTEVNRVRSWV9BUElfS0VZID0gU3ltYm9sLmZvcigib3BlbnRlbGVtZXRyeS5qcy5hcGkuIiArIG1ham9yKTsKdmFyIF9nbG9iYWwgPSBfZ2xvYmFsVGhpczsKZnVuY3Rpb24gcmVnaXN0ZXJHbG9iYWwodHlwZSwgaW5zdGFuY2UsIGRpYWcsIGFsbG93T3ZlcnJpZGUpIHsKICAgIHZhciBfYTsKICAgIGlmIChhbGxvd092ZXJyaWRlID09PSB2b2lkIDApIHsgYWxsb3dPdmVycmlkZSA9IGZhbHNlOyB9CiAgICB2YXIgYXBpID0gKF9nbG9iYWxbR0xPQkFMX09QRU5URUxFTUVUUllfQVBJX0tFWV0gPSAoX2EgPSBfZ2xvYmFsW0dMT0JBTF9PUEVOVEVMRU1FVFJZX0FQSV9LRVldKSAhPT0gbnVsbCAmJiBfYSAhPT0gdm9pZCAwID8gX2EgOiB7CiAgICAgICAgdmVyc2lvbjogVkVSU0lPTiwKICAgIH0pOwogICAgaWYgKCFhbGxvd092ZXJyaWRlICYmIGFwaVt0eXBlXSkgewogICAgICAgIC8vIGFscmVhZHkgcmVnaXN0ZXJlZCBhbiBBUEkgb2YgdGhpcyB0eXBlCiAgICAgICAgdmFyIGVyciA9IG5ldyBFcnJvcigiQG9wZW50ZWxlbWV0cnkvYXBpOiBBdHRlbXB0ZWQgZHVwbGljYXRlIHJlZ2lzdHJhdGlvbiBvZiBBUEk6ICIgKyB0eXBlKTsKICAgICAgICBkaWFnLmVycm9yKGVyci5zdGFjayB8fCBlcnIubWVzc2FnZSk7CiAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgfQogICAgaWYgKGFwaS52ZXJzaW9uICE9PSBWRVJTSU9OKSB7CiAgICAgICAgLy8gQWxsIHJlZ2lzdGVyZWQgQVBJcyBtdXN0IGJlIG9mIHRoZSBzYW1lIHZlcnNpb24gZXhhY3RseQogICAgICAgIHZhciBlcnIgPSBuZXcgRXJyb3IoIkBvcGVudGVsZW1ldHJ5L2FwaTogUmVnaXN0cmF0aW9uIG9mIHZlcnNpb24gdiIgKyBhcGkudmVyc2lvbiArICIgZm9yICIgKyB0eXBlICsgIiBkb2VzIG5vdCBtYXRjaCBwcmV2aW91c2x5IHJlZ2lzdGVyZWQgQVBJIHYiICsgVkVSU0lPTik7CiAgICAgICAgZGlhZy5lcnJvcihlcnIuc3RhY2sgfHwgZXJyLm1lc3NhZ2UpOwogICAgICAgIHJldHVybiBmYWxzZTsKICAgIH0KICAgIGFwaVt0eXBlXSA9IGluc3RhbmNlOwogICAgZGlhZy5kZWJ1ZygiQG9wZW50ZWxlbWV0cnkvYXBpOiBSZWdpc3RlcmVkIGEgZ2xvYmFsIGZvciAiICsgdHlwZSArICIgdiIgKyBWRVJTSU9OICsgIi4iKTsKICAgIHJldHVybiB0cnVlOwp9CmZ1bmN0aW9uIGdldEdsb2JhbCh0eXBlKSB7CiAgICB2YXIgX2EsIF9iOwogICAgdmFyIGdsb2JhbFZlcnNpb24gPSAoX2EgPSBfZ2xvYmFsW0dMT0JBTF9PUEVOVEVMRU1FVFJZX0FQSV9LRVldKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EudmVyc2lvbjsKICAgIGlmICghZ2xvYmFsVmVyc2lvbiB8fCAhaXNDb21wYXRpYmxlKGdsb2JhbFZlcnNpb24pKSB7CiAgICAgICAgcmV0dXJuOwogICAgfQogICAgcmV0dXJuIChfYiA9IF9nbG9iYWxbR0xPQkFMX09QRU5URUxFTUVUUllfQVBJX0tFWV0pID09PSBudWxsIHx8IF9iID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYlt0eXBlXTsKfQpmdW5jdGlvbiB1bnJlZ2lzdGVyR2xvYmFsKHR5cGUsIGRpYWcpIHsKICAgIGRpYWcuZGVidWcoIkBvcGVudGVsZW1ldHJ5L2FwaTogVW5yZWdpc3RlcmluZyBhIGdsb2JhbCBmb3IgIiArIHR5cGUgKyAiIHYiICsgVkVSU0lPTiArICIuIik7CiAgICB2YXIgYXBpID0gX2dsb2JhbFtHTE9CQUxfT1BFTlRFTEVNRVRSWV9BUElfS0VZXTsKICAgIGlmIChhcGkpIHsKICAgICAgICBkZWxldGUgYXBpW3R5cGVdOwogICAgfQp9CgovKgogKiBDb3B5cmlnaHQgVGhlIE9wZW5UZWxlbWV0cnkgQXV0aG9ycwogKgogKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgogKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKICoKICogICAgICBodHRwczovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiAqCiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUKICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiAqLwp2YXIgX19yZWFkJDMgPSAodW5kZWZpbmVkICYmIHVuZGVmaW5lZC5fX3JlYWQpIHx8IGZ1bmN0aW9uIChvLCBuKSB7CiAgICB2YXIgbSA9IHR5cGVvZiBTeW1ib2wgPT09ICJmdW5jdGlvbiIgJiYgb1tTeW1ib2wuaXRlcmF0b3JdOwogICAgaWYgKCFtKSByZXR1cm4gbzsKICAgIHZhciBpID0gbS5jYWxsKG8pLCByLCBhciA9IFtdLCBlOwogICAgdHJ5IHsKICAgICAgICB3aGlsZSAoKG4gPT09IHZvaWQgMCB8fCBuLS0gPiAwKSAmJiAhKHIgPSBpLm5leHQoKSkuZG9uZSkgYXIucHVzaChyLnZhbHVlKTsKICAgIH0KICAgIGNhdGNoIChlcnJvcikgeyBlID0geyBlcnJvcjogZXJyb3IgfTsgfQogICAgZmluYWxseSB7CiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgaWYgKHIgJiYgIXIuZG9uZSAmJiAobSA9IGlbInJldHVybiJdKSkgbS5jYWxsKGkpOwogICAgICAgIH0KICAgICAgICBmaW5hbGx5IHsgaWYgKGUpIHRocm93IGUuZXJyb3I7IH0KICAgIH0KICAgIHJldHVybiBhcjsKfTsKdmFyIF9fc3ByZWFkQXJyYXkkMyA9ICh1bmRlZmluZWQgJiYgdW5kZWZpbmVkLl9fc3ByZWFkQXJyYXkpIHx8IGZ1bmN0aW9uICh0bywgZnJvbSwgcGFjaykgewogICAgaWYgKHBhY2sgfHwgYXJndW1lbnRzLmxlbmd0aCA9PT0gMikgZm9yICh2YXIgaSA9IDAsIGwgPSBmcm9tLmxlbmd0aCwgYXI7IGkgPCBsOyBpKyspIHsKICAgICAgICBpZiAoYXIgfHwgIShpIGluIGZyb20pKSB7CiAgICAgICAgICAgIGlmICghYXIpIGFyID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoZnJvbSwgMCwgaSk7CiAgICAgICAgICAgIGFyW2ldID0gZnJvbVtpXTsKICAgICAgICB9CiAgICB9CiAgICByZXR1cm4gdG8uY29uY2F0KGFyIHx8IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGZyb20pKTsKfTsKLyoqCiAqIENvbXBvbmVudCBMb2dnZXIgd2hpY2ggaXMgbWVhbnQgdG8gYmUgdXNlZCBhcyBwYXJ0IG9mIGFueSBjb21wb25lbnQgd2hpY2gKICogd2lsbCBhZGQgYXV0b21hdGljYWxseSBhZGRpdGlvbmFsIG5hbWVzcGFjZSBpbiBmcm9udCBvZiB0aGUgbG9nIG1lc3NhZ2UuCiAqIEl0IHdpbGwgdGhlbiBmb3J3YXJkIGFsbCBtZXNzYWdlIHRvIGdsb2JhbCBkaWFnIGxvZ2dlcgogKiBAZXhhbXBsZQogKiBjb25zdCBjTG9nZ2VyID0gZGlhZy5jcmVhdGVDb21wb25lbnRMb2dnZXIoeyBuYW1lc3BhY2U6ICdAb3BlbnRlbGVtZXRyeS9pbnN0cnVtZW50YXRpb24taHR0cCcgfSk7CiAqIGNMb2dnZXIuZGVidWcoJ3Rlc3QnKTsKICogLy8gQG9wZW50ZWxlbWV0cnkvaW5zdHJ1bWVudGF0aW9uLWh0dHAgdGVzdAogKi8KdmFyIERpYWdDb21wb25lbnRMb2dnZXIgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7CiAgICBmdW5jdGlvbiBEaWFnQ29tcG9uZW50TG9nZ2VyKHByb3BzKSB7CiAgICAgICAgdGhpcy5fbmFtZXNwYWNlID0gcHJvcHMubmFtZXNwYWNlIHx8ICdEaWFnQ29tcG9uZW50TG9nZ2VyJzsKICAgIH0KICAgIERpYWdDb21wb25lbnRMb2dnZXIucHJvdG90eXBlLmRlYnVnID0gZnVuY3Rpb24gKCkgewogICAgICAgIHZhciBhcmdzID0gW107CiAgICAgICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IGFyZ3VtZW50cy5sZW5ndGg7IF9pKyspIHsKICAgICAgICAgICAgYXJnc1tfaV0gPSBhcmd1bWVudHNbX2ldOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbG9nUHJveHkoJ2RlYnVnJywgdGhpcy5fbmFtZXNwYWNlLCBhcmdzKTsKICAgIH07CiAgICBEaWFnQ29tcG9uZW50TG9nZ2VyLnByb3RvdHlwZS5lcnJvciA9IGZ1bmN0aW9uICgpIHsKICAgICAgICB2YXIgYXJncyA9IFtdOwogICAgICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBhcmd1bWVudHMubGVuZ3RoOyBfaSsrKSB7CiAgICAgICAgICAgIGFyZ3NbX2ldID0gYXJndW1lbnRzW19pXTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGxvZ1Byb3h5KCdlcnJvcicsIHRoaXMuX25hbWVzcGFjZSwgYXJncyk7CiAgICB9OwogICAgRGlhZ0NvbXBvbmVudExvZ2dlci5wcm90b3R5cGUuaW5mbyA9IGZ1bmN0aW9uICgpIHsKICAgICAgICB2YXIgYXJncyA9IFtdOwogICAgICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBhcmd1bWVudHMubGVuZ3RoOyBfaSsrKSB7CiAgICAgICAgICAgIGFyZ3NbX2ldID0gYXJndW1lbnRzW19pXTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIGxvZ1Byb3h5KCdpbmZvJywgdGhpcy5fbmFtZXNwYWNlLCBhcmdzKTsKICAgIH07CiAgICBEaWFnQ29tcG9uZW50TG9nZ2VyLnByb3RvdHlwZS53YXJuID0gZnVuY3Rpb24gKCkgewogICAgICAgIHZhciBhcmdzID0gW107CiAgICAgICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IGFyZ3VtZW50cy5sZW5ndGg7IF9pKyspIHsKICAgICAgICAgICAgYXJnc1tfaV0gPSBhcmd1bWVudHNbX2ldOwogICAgICAgIH0KICAgICAgICByZXR1cm4gbG9nUHJveHkoJ3dhcm4nLCB0aGlzLl9uYW1lc3BhY2UsIGFyZ3MpOwogICAgfTsKICAgIERpYWdDb21wb25lbnRMb2dnZXIucHJvdG90eXBlLnZlcmJvc2UgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgdmFyIGFyZ3MgPSBbXTsKICAgICAgICBmb3IgKHZhciBfaSA9IDA7IF9pIDwgYXJndW1lbnRzLmxlbmd0aDsgX2krKykgewogICAgICAgICAgICBhcmdzW19pXSA9IGFyZ3VtZW50c1tfaV07CiAgICAgICAgfQogICAgICAgIHJldHVybiBsb2dQcm94eSgndmVyYm9zZScsIHRoaXMuX25hbWVzcGFjZSwgYXJncyk7CiAgICB9OwogICAgcmV0dXJuIERpYWdDb21wb25lbnRMb2dnZXI7Cn0oKSk7CmZ1bmN0aW9uIGxvZ1Byb3h5KGZ1bmNOYW1lLCBuYW1lc3BhY2UsIGFyZ3MpIHsKICAgIHZhciBsb2dnZXIgPSBnZXRHbG9iYWwoJ2RpYWcnKTsKICAgIC8vIHNob3J0Y3V0IGlmIGxvZ2dlciBub3Qgc2V0CiAgICBpZiAoIWxvZ2dlcikgewogICAgICAgIHJldHVybjsKICAgIH0KICAgIGFyZ3MudW5zaGlmdChuYW1lc3BhY2UpOwogICAgcmV0dXJuIGxvZ2dlcltmdW5jTmFtZV0uYXBwbHkobG9nZ2VyLCBfX3NwcmVhZEFycmF5JDMoW10sIF9fcmVhZCQzKGFyZ3MpLCBmYWxzZSkpOwp9CgovKgogKiBDb3B5cmlnaHQgVGhlIE9wZW5UZWxlbWV0cnkgQXV0aG9ycwogKgogKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsKICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLgogKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXQKICoKICogICAgICBodHRwczovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCiAqCiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUKICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywKICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuCiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuCiAqLwovKioKICogRGVmaW5lcyB0aGUgYXZhaWxhYmxlIGludGVybmFsIGxvZ2dpbmcgbGV2ZWxzIGZvciB0aGUgZGlhZ25vc3RpYyBsb2dnZXIsIHRoZSBudW1lcmljIHZhbHVlcwogKiBvZiB0aGUgbGV2ZWxzIGFyZSBkZWZpbmVkIHRvIG1hdGNoIHRoZSBvcmlnaW5hbCB2YWx1ZXMgZnJvbSB0aGUgaW5pdGlhbCBMb2dMZXZlbCB0byBhdm9pZAogKiBjb21wYXRpYmlsaXR5L21pZ3JhdGlvbiBpc3N1ZXMgZm9yIGFueSBpbXBsZW1lbnRhdGlvbiB0aGF0IGFzc3VtZSB0aGUgbnVtZXJpYyBvcmRlcmluZy4KICovCnZhciBEaWFnTG9nTGV2ZWw7CihmdW5jdGlvbiAoRGlhZ0xvZ0xldmVsKSB7CiAgICAvKiogRGlhZ25vc3RpYyBMb2dnaW5nIGxldmVsIHNldHRpbmcgdG8gZGlzYWJsZSBhbGwgbG9nZ2luZyAoZXhjZXB0IGFuZCBmb3JjZWQgbG9ncykgKi8KICAgIERpYWdMb2dMZXZlbFtEaWFnTG9nTGV2ZWxbIk5PTkUiXSA9IDBdID0gIk5PTkUiOwogICAgLyoqIElkZW50aWZpZXMgYW4gZXJyb3Igc2NlbmFyaW8gKi8KICAgIERpYWdMb2dMZXZlbFtEaWFnTG9nTGV2ZWxbIkVSUk9SIl0gPSAzMF0gPSAiRVJST1IiOwogICAgLyoqIElkZW50aWZpZXMgYSB3YXJuaW5nIHNjZW5hcmlvICovCiAgICBEaWFnTG9nTGV2ZWxbRGlhZ0xvZ0xldmVsWyJXQVJOIl0gPSA1MF0gPSAiV0FSTiI7CiAgICAvKiogR2VuZXJhbCBpbmZvcm1hdGlvbmFsIGxvZyBtZXNzYWdlICovCiAgICBEaWFnTG9nTGV2ZWxbRGlhZ0xvZ0xldmVsWyJJTkZPIl0gPSA2MF0gPSAiSU5GTyI7CiAgICAvKiogR2VuZXJhbCBkZWJ1ZyBsb2cgbWVzc2FnZSAqLwogICAgRGlhZ0xvZ0xldmVsW0RpYWdMb2dMZXZlbFsiREVCVUciXSA9IDcwXSA9ICJERUJVRyI7CiAgICAvKioKICAgICAqIERldGFpbGVkIHRyYWNlIGxldmVsIGxvZ2dpbmcgc2hvdWxkIG9ubHkgYmUgdXNlZCBmb3IgZGV2ZWxvcG1lbnQsIHNob3VsZCBvbmx5IGJlIHNldAogICAgICogaW4gYSBkZXZlbG9wbWVudCBlbnZpcm9ubWVudC4KICAgICAqLwogICAgRGlhZ0xvZ0xldmVsW0RpYWdMb2dMZXZlbFsiVkVSQk9TRSJdID0gODBdID0gIlZFUkJPU0UiOwogICAgLyoqIFVzZWQgdG8gc2V0IHRoZSBsb2dnaW5nIGxldmVsIHRvIGluY2x1ZGUgYWxsIGxvZ2dpbmcgKi8KICAgIERpYWdMb2dMZXZlbFtEaWFnTG9nTGV2ZWxbIkFMTCJdID0gOTk5OV0gPSAiQUxMIjsKfSkoRGlhZ0xvZ0xldmVsIHx8IChEaWFnTG9nTGV2ZWwgPSB7fSkpOwoKLyoKICogQ29weXJpZ2h0IFRoZSBPcGVuVGVsZW1ldHJ5IEF1dGhvcnMKICoKICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiAqCiAqICAgICAgaHR0cHM6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAogKgogKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgogKi8KZnVuY3Rpb24gY3JlYXRlTG9nTGV2ZWxEaWFnTG9nZ2VyKG1heExldmVsLCBsb2dnZXIpIHsKICAgIGlmIChtYXhMZXZlbCA8IERpYWdMb2dMZXZlbC5OT05FKSB7CiAgICAgICAgbWF4TGV2ZWwgPSBEaWFnTG9nTGV2ZWwuTk9ORTsKICAgIH0KICAgIGVsc2UgaWYgKG1heExldmVsID4gRGlhZ0xvZ0xldmVsLkFMTCkgewogICAgICAgIG1heExldmVsID0gRGlhZ0xvZ0xldmVsLkFMTDsKICAgIH0KICAgIC8vIEluIGNhc2UgdGhlIGxvZ2dlciBpcyBudWxsIG9yIHVuZGVmaW5lZAogICAgbG9nZ2VyID0gbG9nZ2VyIHx8IHt9OwogICAgZnVuY3Rpb24gX2ZpbHRlckZ1bmMoZnVuY05hbWUsIHRoZUxldmVsKSB7CiAgICAgICAgdmFyIHRoZUZ1bmMgPSBsb2dnZXJbZnVuY05hbWVdOwogICAgICAgIGlmICh0eXBlb2YgdGhlRnVuYyA9PT0gJ2Z1bmN0aW9uJyAmJiBtYXhMZXZlbCA+PSB0aGVMZXZlbCkgewogICAgICAgICAgICByZXR1cm4gdGhlRnVuYy5iaW5kKGxvZ2dlcik7CiAgICAgICAgfQogICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7IH07CiAgICB9CiAgICByZXR1cm4gewogICAgICAgIGVycm9yOiBfZmlsdGVyRnVuYygnZXJyb3InLCBEaWFnTG9nTGV2ZWwuRVJST1IpLAogICAgICAgIHdhcm46IF9maWx0ZXJGdW5jKCd3YXJuJywgRGlhZ0xvZ0xldmVsLldBUk4pLAogICAgICAgIGluZm86IF9maWx0ZXJGdW5jKCdpbmZvJywgRGlhZ0xvZ0xldmVsLklORk8pLAogICAgICAgIGRlYnVnOiBfZmlsdGVyRnVuYygnZGVidWcnLCBEaWFnTG9nTGV2ZWwuREVCVUcpLAogICAgICAgIHZlcmJvc2U6IF9maWx0ZXJGdW5jKCd2ZXJib3NlJywgRGlhZ0xvZ0xldmVsLlZFUkJPU0UpLAogICAgfTsKfQoKLyoKICogQ29weXJpZ2h0IFRoZSBPcGVuVGVsZW1ldHJ5IEF1dGhvcnMKICoKICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiAqCiAqICAgICAgaHR0cHM6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAogKgogKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgogKi8KdmFyIF9fcmVhZCQyID0gKHVuZGVmaW5lZCAmJiB1bmRlZmluZWQuX19yZWFkKSB8fCBmdW5jdGlvbiAobywgbikgewogICAgdmFyIG0gPSB0eXBlb2YgU3ltYm9sID09PSAiZnVuY3Rpb24iICYmIG9bU3ltYm9sLml0ZXJhdG9yXTsKICAgIGlmICghbSkgcmV0dXJuIG87CiAgICB2YXIgaSA9IG0uY2FsbChvKSwgciwgYXIgPSBbXSwgZTsKICAgIHRyeSB7CiAgICAgICAgd2hpbGUgKChuID09PSB2b2lkIDAgfHwgbi0tID4gMCkgJiYgIShyID0gaS5uZXh0KCkpLmRvbmUpIGFyLnB1c2goci52YWx1ZSk7CiAgICB9CiAgICBjYXRjaCAoZXJyb3IpIHsgZSA9IHsgZXJyb3I6IGVycm9yIH07IH0KICAgIGZpbmFsbHkgewogICAgICAgIHRyeSB7CiAgICAgICAgICAgIGlmIChyICYmICFyLmRvbmUgJiYgKG0gPSBpWyJyZXR1cm4iXSkpIG0uY2FsbChpKTsKICAgICAgICB9CiAgICAgICAgZmluYWxseSB7IGlmIChlKSB0aHJvdyBlLmVycm9yOyB9CiAgICB9CiAgICByZXR1cm4gYXI7Cn07CnZhciBfX3NwcmVhZEFycmF5JDIgPSAodW5kZWZpbmVkICYmIHVuZGVmaW5lZC5fX3NwcmVhZEFycmF5KSB8fCBmdW5jdGlvbiAodG8sIGZyb20sIHBhY2spIHsKICAgIGlmIChwYWNrIHx8IGFyZ3VtZW50cy5sZW5ndGggPT09IDIpIGZvciAodmFyIGkgPSAwLCBsID0gZnJvbS5sZW5ndGgsIGFyOyBpIDwgbDsgaSsrKSB7CiAgICAgICAgaWYgKGFyIHx8ICEoaSBpbiBmcm9tKSkgewogICAgICAgICAgICBpZiAoIWFyKSBhciA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGZyb20sIDAsIGkpOwogICAgICAgICAgICBhcltpXSA9IGZyb21baV07CiAgICAgICAgfQogICAgfQogICAgcmV0dXJuIHRvLmNvbmNhdChhciB8fCBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChmcm9tKSk7Cn07CnZhciBBUElfTkFNRSQxID0gJ2RpYWcnOwovKioKICogU2luZ2xldG9uIG9iamVjdCB3aGljaCByZXByZXNlbnRzIHRoZSBlbnRyeSBwb2ludCB0byB0aGUgT3BlblRlbGVtZXRyeSBpbnRlcm5hbAogKiBkaWFnbm9zdGljIEFQSQogKi8KdmFyIERpYWdBUEkgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7CiAgICAvKioKICAgICAqIFByaXZhdGUgaW50ZXJuYWwgY29uc3RydWN0b3IKICAgICAqIEBwcml2YXRlCiAgICAgKi8KICAgIGZ1bmN0aW9uIERpYWdBUEkoKSB7CiAgICAgICAgZnVuY3Rpb24gX2xvZ1Byb3h5KGZ1bmNOYW1lKSB7CiAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgICAgICB2YXIgYXJncyA9IFtdOwogICAgICAgICAgICAgICAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IGFyZ3VtZW50cy5sZW5ndGg7IF9pKyspIHsKICAgICAgICAgICAgICAgICAgICBhcmdzW19pXSA9IGFyZ3VtZW50c1tfaV07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB2YXIgbG9nZ2VyID0gZ2V0R2xvYmFsKCdkaWFnJyk7CiAgICAgICAgICAgICAgICAvLyBzaG9ydGN1dCBpZiBsb2dnZXIgbm90IHNldAogICAgICAgICAgICAgICAgaWYgKCFsb2dnZXIpCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAgICAgcmV0dXJuIGxvZ2dlcltmdW5jTmFtZV0uYXBwbHkobG9nZ2VyLCBfX3NwcmVhZEFycmF5JDIoW10sIF9fcmVhZCQyKGFyZ3MpLCBmYWxzZSkpOwogICAgICAgICAgICB9OwogICAgICAgIH0KICAgICAgICAvLyBVc2luZyBzZWxmIGxvY2FsIHZhcmlhYmxlIGZvciBtaW5pZmljYXRpb24gcHVycG9zZXMgYXMgJ3RoaXMnIGNhbm5vdCBiZSBtaW5pZmllZAogICAgICAgIHZhciBzZWxmID0gdGhpczsKICAgICAgICAvLyBEaWFnQVBJIHNwZWNpZmljIGZ1bmN0aW9ucwogICAgICAgIHZhciBzZXRMb2dnZXIgPSBmdW5jdGlvbiAobG9nZ2VyLCBvcHRpb25zT3JMb2dMZXZlbCkgewogICAgICAgICAgICB2YXIgX2EsIF9iLCBfYzsKICAgICAgICAgICAgaWYgKG9wdGlvbnNPckxvZ0xldmVsID09PSB2b2lkIDApIHsgb3B0aW9uc09yTG9nTGV2ZWwgPSB7IGxvZ0xldmVsOiBEaWFnTG9nTGV2ZWwuSU5GTyB9OyB9CiAgICAgICAgICAgIGlmIChsb2dnZXIgPT09IHNlbGYpIHsKICAgICAgICAgICAgICAgIC8vIFRoZXJlIGlzbid0IG11Y2ggd2UgY2FuIGRvIGhlcmUuCiAgICAgICAgICAgICAgICAvLyBMb2dnaW5nIHRvIHRoZSBjb25zb2xlIG1pZ2h0IGJyZWFrIHRoZSB1c2VyIGFwcGxpY2F0aW9uLgogICAgICAgICAgICAgICAgLy8gVHJ5IHRvIGxvZyB0byBzZWxmLiBJZiBhIGxvZ2dlciB3YXMgcHJldmlvdXNseSByZWdpc3RlcmVkIGl0IHdpbGwgcmVjZWl2ZSB0aGUgbG9nLgogICAgICAgICAgICAgICAgdmFyIGVyciA9IG5ldyBFcnJvcignQ2Fubm90IHVzZSBkaWFnIGFzIHRoZSBsb2dnZXIgZm9yIGl0c2VsZi4gUGxlYXNlIHVzZSBhIERpYWdMb2dnZXIgaW1wbGVtZW50YXRpb24gbGlrZSBDb25zb2xlRGlhZ0xvZ2dlciBvciBhIGN1c3RvbSBpbXBsZW1lbnRhdGlvbicpOwogICAgICAgICAgICAgICAgc2VsZi5lcnJvcigoX2EgPSBlcnIuc3RhY2spICE9PSBudWxsICYmIF9hICE9PSB2b2lkIDAgPyBfYSA6IGVyci5tZXNzYWdlKTsKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAodHlwZW9mIG9wdGlvbnNPckxvZ0xldmVsID09PSAnbnVtYmVyJykgewogICAgICAgICAgICAgICAgb3B0aW9uc09yTG9nTGV2ZWwgPSB7CiAgICAgICAgICAgICAgICAgICAgbG9nTGV2ZWw6IG9wdGlvbnNPckxvZ0xldmVsLAogICAgICAgICAgICAgICAgfTsKICAgICAgICAgICAgfQogICAgICAgICAgICB2YXIgb2xkTG9nZ2VyID0gZ2V0R2xvYmFsKCdkaWFnJyk7CiAgICAgICAgICAgIHZhciBuZXdMb2dnZXIgPSBjcmVhdGVMb2dMZXZlbERpYWdMb2dnZXIoKF9iID0gb3B0aW9uc09yTG9nTGV2ZWwubG9nTGV2ZWwpICE9PSBudWxsICYmIF9iICE9PSB2b2lkIDAgPyBfYiA6IERpYWdMb2dMZXZlbC5JTkZPLCBsb2dnZXIpOwogICAgICAgICAgICAvLyBUaGVyZSBhbHJlYWR5IGlzIGFuIGxvZ2dlciByZWdpc3RlcmVkLiBXZSdsbCBsZXQgaXQga25vdyBiZWZvcmUgb3ZlcndyaXRpbmcgaXQuCiAgICAgICAgICAgIGlmIChvbGRMb2dnZXIgJiYgIW9wdGlvbnNPckxvZ0xldmVsLnN1cHByZXNzT3ZlcnJpZGVNZXNzYWdlKSB7CiAgICAgICAgICAgICAgICB2YXIgc3RhY2sgPSAoX2MgPSBuZXcgRXJyb3IoKS5zdGFjaykgIT09IG51bGwgJiYgX2MgIT09IHZvaWQgMCA/IF9jIDogJzxmYWlsZWQgdG8gZ2VuZXJhdGUgc3RhY2t0cmFjZT4nOwogICAgICAgICAgICAgICAgb2xkTG9nZ2VyLndhcm4oIkN1cnJlbnQgbG9nZ2VyIHdpbGwgYmUgb3ZlcndyaXR0ZW4gZnJvbSAiICsgc3RhY2spOwogICAgICAgICAgICAgICAgbmV3TG9nZ2VyLndhcm4oIkN1cnJlbnQgbG9nZ2VyIHdpbGwgb3ZlcndyaXRlIG9uZSBhbHJlYWR5IHJlZ2lzdGVyZWQgZnJvbSAiICsgc3RhY2spOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiByZWdpc3Rlckdsb2JhbCgnZGlhZycsIG5ld0xvZ2dlciwgc2VsZiwgdHJ1ZSk7CiAgICAgICAgfTsKICAgICAgICBzZWxmLnNldExvZ2dlciA9IHNldExvZ2dlcjsKICAgICAgICBzZWxmLmRpc2FibGUgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgICAgIHVucmVnaXN0ZXJHbG9iYWwoQVBJX05BTUUkMSwgc2VsZik7CiAgICAgICAgfTsKICAgICAgICBzZWxmLmNyZWF0ZUNvbXBvbmVudExvZ2dlciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7CiAgICAgICAgICAgIHJldHVybiBuZXcgRGlhZ0NvbXBvbmVudExvZ2dlcihvcHRpb25zKTsKICAgICAgICB9OwogICAgICAgIHNlbGYudmVyYm9zZSA9IF9sb2dQcm94eSgndmVyYm9zZScpOwogICAgICAgIHNlbGYuZGVidWcgPSBfbG9nUHJveHkoJ2RlYnVnJyk7CiAgICAgICAgc2VsZi5pbmZvID0gX2xvZ1Byb3h5KCdpbmZvJyk7CiAgICAgICAgc2VsZi53YXJuID0gX2xvZ1Byb3h5KCd3YXJuJyk7CiAgICAgICAgc2VsZi5lcnJvciA9IF9sb2dQcm94eSgnZXJyb3InKTsKICAgIH0KICAgIC8qKiBHZXQgdGhlIHNpbmdsZXRvbiBpbnN0YW5jZSBvZiB0aGUgRGlhZ0FQSSBBUEkgKi8KICAgIERpYWdBUEkuaW5zdGFuY2UgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgaWYgKCF0aGlzLl9pbnN0YW5jZSkgewogICAgICAgICAgICB0aGlzLl9pbnN0YW5jZSA9IG5ldyBEaWFnQVBJKCk7CiAgICAgICAgfQogICAgICAgIHJldHVybiB0aGlzLl9pbnN0YW5jZTsKICAgIH07CiAgICByZXR1cm4gRGlhZ0FQSTsKfSgpKTsKCi8qCiAqIENvcHlyaWdodCBUaGUgT3BlblRlbGVtZXRyeSBBdXRob3JzCiAqCiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAogKgogKiAgICAgIGh0dHBzOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKICoKICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KICovCi8qKiBHZXQgYSBrZXkgdG8gdW5pcXVlbHkgaWRlbnRpZnkgYSBjb250ZXh0IHZhbHVlICovCmZ1bmN0aW9uIGNyZWF0ZUNvbnRleHRLZXkoZGVzY3JpcHRpb24pIHsKICAgIC8vIFRoZSBzcGVjaWZpY2F0aW9uIHN0YXRlcyB0aGF0IGZvciB0aGUgc2FtZSBpbnB1dCwgbXVsdGlwbGUgY2FsbHMgc2hvdWxkCiAgICAvLyByZXR1cm4gZGlmZmVyZW50IGtleXMuIER1ZSB0byB0aGUgbmF0dXJlIG9mIHRoZSBKUyBkZXBlbmRlbmN5IG1hbmFnZW1lbnQKICAgIC8vIHN5c3RlbSwgdGhpcyBjcmVhdGVzIHByb2JsZW1zIHdoZXJlIG11bHRpcGxlIHZlcnNpb25zIG9mIHNvbWUgcGFja2FnZQogICAgLy8gY291bGQgaG9sZCBkaWZmZXJlbnQga2V5cyBmb3IgdGhlIHNhbWUgcHJvcGVydHkuCiAgICAvLwogICAgLy8gVGhlcmVmb3JlLCB3ZSB1c2UgU3ltYm9sLmZvciB3aGljaCByZXR1cm5zIHRoZSBzYW1lIGtleSBmb3IgdGhlIHNhbWUgaW5wdXQuCiAgICByZXR1cm4gU3ltYm9sLmZvcihkZXNjcmlwdGlvbik7Cn0KdmFyIEJhc2VDb250ZXh0ID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkgewogICAgLyoqCiAgICAgKiBDb25zdHJ1Y3QgYSBuZXcgY29udGV4dCB3aGljaCBpbmhlcml0cyB2YWx1ZXMgZnJvbSBhbiBvcHRpb25hbCBwYXJlbnQgY29udGV4dC4KICAgICAqCiAgICAgKiBAcGFyYW0gcGFyZW50Q29udGV4dCBhIGNvbnRleHQgZnJvbSB3aGljaCB0byBpbmhlcml0IHZhbHVlcwogICAgICovCiAgICBmdW5jdGlvbiBCYXNlQ29udGV4dChwYXJlbnRDb250ZXh0KSB7CiAgICAgICAgLy8gZm9yIG1pbmlmaWNhdGlvbgogICAgICAgIHZhciBzZWxmID0gdGhpczsKICAgICAgICBzZWxmLl9jdXJyZW50Q29udGV4dCA9IHBhcmVudENvbnRleHQgPyBuZXcgTWFwKHBhcmVudENvbnRleHQpIDogbmV3IE1hcCgpOwogICAgICAgIHNlbGYuZ2V0VmFsdWUgPSBmdW5jdGlvbiAoa2V5KSB7IHJldHVybiBzZWxmLl9jdXJyZW50Q29udGV4dC5nZXQoa2V5KTsgfTsKICAgICAgICBzZWxmLnNldFZhbHVlID0gZnVuY3Rpb24gKGtleSwgdmFsdWUpIHsKICAgICAgICAgICAgdmFyIGNvbnRleHQgPSBuZXcgQmFzZUNvbnRleHQoc2VsZi5fY3VycmVudENvbnRleHQpOwogICAgICAgICAgICBjb250ZXh0Ll9jdXJyZW50Q29udGV4dC5zZXQoa2V5LCB2YWx1ZSk7CiAgICAgICAgICAgIHJldHVybiBjb250ZXh0OwogICAgICAgIH07CiAgICAgICAgc2VsZi5kZWxldGVWYWx1ZSA9IGZ1bmN0aW9uIChrZXkpIHsKICAgICAgICAgICAgdmFyIGNvbnRleHQgPSBuZXcgQmFzZUNvbnRleHQoc2VsZi5fY3VycmVudENvbnRleHQpOwogICAgICAgICAgICBjb250ZXh0Ll9jdXJyZW50Q29udGV4dC5kZWxldGUoa2V5KTsKICAgICAgICAgICAgcmV0dXJuIGNvbnRleHQ7CiAgICAgICAgfTsKICAgIH0KICAgIHJldHVybiBCYXNlQ29udGV4dDsKfSgpKTsKLyoqIFRoZSByb290IGNvbnRleHQgaXMgdXNlZCBhcyB0aGUgZGVmYXVsdCBwYXJlbnQgY29udGV4dCB3aGVuIHRoZXJlIGlzIG5vIGFjdGl2ZSBjb250ZXh0ICovCnZhciBST09UX0NPTlRFWFQgPSBuZXcgQmFzZUNvbnRleHQoKTsKCi8qCiAqIENvcHlyaWdodCBUaGUgT3BlblRlbGVtZXRyeSBBdXRob3JzCiAqCiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAogKgogKiAgICAgIGh0dHBzOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKICoKICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KICovCnZhciBfX3JlYWQkMSA9ICh1bmRlZmluZWQgJiYgdW5kZWZpbmVkLl9fcmVhZCkgfHwgZnVuY3Rpb24gKG8sIG4pIHsKICAgIHZhciBtID0gdHlwZW9mIFN5bWJvbCA9PT0gImZ1bmN0aW9uIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl07CiAgICBpZiAoIW0pIHJldHVybiBvOwogICAgdmFyIGkgPSBtLmNhbGwobyksIHIsIGFyID0gW10sIGU7CiAgICB0cnkgewogICAgICAgIHdoaWxlICgobiA9PT0gdm9pZCAwIHx8IG4tLSA+IDApICYmICEociA9IGkubmV4dCgpKS5kb25lKSBhci5wdXNoKHIudmFsdWUpOwogICAgfQogICAgY2F0Y2ggKGVycm9yKSB7IGUgPSB7IGVycm9yOiBlcnJvciB9OyB9CiAgICBmaW5hbGx5IHsKICAgICAgICB0cnkgewogICAgICAgICAgICBpZiAociAmJiAhci5kb25lICYmIChtID0gaVsicmV0dXJuIl0pKSBtLmNhbGwoaSk7CiAgICAgICAgfQogICAgICAgIGZpbmFsbHkgeyBpZiAoZSkgdGhyb3cgZS5lcnJvcjsgfQogICAgfQogICAgcmV0dXJuIGFyOwp9Owp2YXIgX19zcHJlYWRBcnJheSQxID0gKHVuZGVmaW5lZCAmJiB1bmRlZmluZWQuX19zcHJlYWRBcnJheSkgfHwgZnVuY3Rpb24gKHRvLCBmcm9tLCBwYWNrKSB7CiAgICBpZiAocGFjayB8fCBhcmd1bWVudHMubGVuZ3RoID09PSAyKSBmb3IgKHZhciBpID0gMCwgbCA9IGZyb20ubGVuZ3RoLCBhcjsgaSA8IGw7IGkrKykgewogICAgICAgIGlmIChhciB8fCAhKGkgaW4gZnJvbSkpIHsKICAgICAgICAgICAgaWYgKCFhcikgYXIgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChmcm9tLCAwLCBpKTsKICAgICAgICAgICAgYXJbaV0gPSBmcm9tW2ldOwogICAgICAgIH0KICAgIH0KICAgIHJldHVybiB0by5jb25jYXQoYXIgfHwgQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoZnJvbSkpOwp9Owp2YXIgTm9vcENvbnRleHRNYW5hZ2VyID0gLyoqIEBjbGFzcyAqLyAoZnVuY3Rpb24gKCkgewogICAgZnVuY3Rpb24gTm9vcENvbnRleHRNYW5hZ2VyKCkgewogICAgfQogICAgTm9vcENvbnRleHRNYW5hZ2VyLnByb3RvdHlwZS5hY3RpdmUgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgcmV0dXJuIFJPT1RfQ09OVEVYVDsKICAgIH07CiAgICBOb29wQ29udGV4dE1hbmFnZXIucHJvdG90eXBlLndpdGggPSBmdW5jdGlvbiAoX2NvbnRleHQsIGZuLCB0aGlzQXJnKSB7CiAgICAgICAgdmFyIGFyZ3MgPSBbXTsKICAgICAgICBmb3IgKHZhciBfaSA9IDM7IF9pIDwgYXJndW1lbnRzLmxlbmd0aDsgX2krKykgewogICAgICAgICAgICBhcmdzW19pIC0gM10gPSBhcmd1bWVudHNbX2ldOwogICAgICAgIH0KICAgICAgICByZXR1cm4gZm4uY2FsbC5hcHBseShmbiwgX19zcHJlYWRBcnJheSQxKFt0aGlzQXJnXSwgX19yZWFkJDEoYXJncyksIGZhbHNlKSk7CiAgICB9OwogICAgTm9vcENvbnRleHRNYW5hZ2VyLnByb3RvdHlwZS5iaW5kID0gZnVuY3Rpb24gKF9jb250ZXh0LCB0YXJnZXQpIHsKICAgICAgICByZXR1cm4gdGFyZ2V0OwogICAgfTsKICAgIE5vb3BDb250ZXh0TWFuYWdlci5wcm90b3R5cGUuZW5hYmxlID0gZnVuY3Rpb24gKCkgewogICAgICAgIHJldHVybiB0aGlzOwogICAgfTsKICAgIE5vb3BDb250ZXh0TWFuYWdlci5wcm90b3R5cGUuZGlzYWJsZSA9IGZ1bmN0aW9uICgpIHsKICAgICAgICByZXR1cm4gdGhpczsKICAgIH07CiAgICByZXR1cm4gTm9vcENvbnRleHRNYW5hZ2VyOwp9KCkpOwoKLyoKICogQ29weXJpZ2h0IFRoZSBPcGVuVGVsZW1ldHJ5IEF1dGhvcnMKICoKICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiAqCiAqICAgICAgaHR0cHM6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAogKgogKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgogKi8KdmFyIF9fcmVhZCA9ICh1bmRlZmluZWQgJiYgdW5kZWZpbmVkLl9fcmVhZCkgfHwgZnVuY3Rpb24gKG8sIG4pIHsKICAgIHZhciBtID0gdHlwZW9mIFN5bWJvbCA9PT0gImZ1bmN0aW9uIiAmJiBvW1N5bWJvbC5pdGVyYXRvcl07CiAgICBpZiAoIW0pIHJldHVybiBvOwogICAgdmFyIGkgPSBtLmNhbGwobyksIHIsIGFyID0gW10sIGU7CiAgICB0cnkgewogICAgICAgIHdoaWxlICgobiA9PT0gdm9pZCAwIHx8IG4tLSA+IDApICYmICEociA9IGkubmV4dCgpKS5kb25lKSBhci5wdXNoKHIudmFsdWUpOwogICAgfQogICAgY2F0Y2ggKGVycm9yKSB7IGUgPSB7IGVycm9yOiBlcnJvciB9OyB9CiAgICBmaW5hbGx5IHsKICAgICAgICB0cnkgewogICAgICAgICAgICBpZiAociAmJiAhci5kb25lICYmIChtID0gaVsicmV0dXJuIl0pKSBtLmNhbGwoaSk7CiAgICAgICAgfQogICAgICAgIGZpbmFsbHkgeyBpZiAoZSkgdGhyb3cgZS5lcnJvcjsgfQogICAgfQogICAgcmV0dXJuIGFyOwp9Owp2YXIgX19zcHJlYWRBcnJheSA9ICh1bmRlZmluZWQgJiYgdW5kZWZpbmVkLl9fc3ByZWFkQXJyYXkpIHx8IGZ1bmN0aW9uICh0bywgZnJvbSwgcGFjaykgewogICAgaWYgKHBhY2sgfHwgYXJndW1lbnRzLmxlbmd0aCA9PT0gMikgZm9yICh2YXIgaSA9IDAsIGwgPSBmcm9tLmxlbmd0aCwgYXI7IGkgPCBsOyBpKyspIHsKICAgICAgICBpZiAoYXIgfHwgIShpIGluIGZyb20pKSB7CiAgICAgICAgICAgIGlmICghYXIpIGFyID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoZnJvbSwgMCwgaSk7CiAgICAgICAgICAgIGFyW2ldID0gZnJvbVtpXTsKICAgICAgICB9CiAgICB9CiAgICByZXR1cm4gdG8uY29uY2F0KGFyIHx8IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGZyb20pKTsKfTsKdmFyIEFQSV9OQU1FID0gJ2NvbnRleHQnOwp2YXIgTk9PUF9DT05URVhUX01BTkFHRVIgPSBuZXcgTm9vcENvbnRleHRNYW5hZ2VyKCk7Ci8qKgogKiBTaW5nbGV0b24gb2JqZWN0IHdoaWNoIHJlcHJlc2VudHMgdGhlIGVudHJ5IHBvaW50IHRvIHRoZSBPcGVuVGVsZW1ldHJ5IENvbnRleHQgQVBJCiAqLwp2YXIgQ29udGV4dEFQSSA9IC8qKiBAY2xhc3MgKi8gKGZ1bmN0aW9uICgpIHsKICAgIC8qKiBFbXB0eSBwcml2YXRlIGNvbnN0cnVjdG9yIHByZXZlbnRzIGVuZCB1c2VycyBmcm9tIGNvbnN0cnVjdGluZyBhIG5ldyBpbnN0YW5jZSBvZiB0aGUgQVBJICovCiAgICBmdW5jdGlvbiBDb250ZXh0QVBJKCkgewogICAgfQogICAgLyoqIEdldCB0aGUgc2luZ2xldG9uIGluc3RhbmNlIG9mIHRoZSBDb250ZXh0IEFQSSAqLwogICAgQ29udGV4dEFQSS5nZXRJbnN0YW5jZSA9IGZ1bmN0aW9uICgpIHsKICAgICAgICBpZiAoIXRoaXMuX2luc3RhbmNlKSB7CiAgICAgICAgICAgIHRoaXMuX2luc3RhbmNlID0gbmV3IENvbnRleHRBUEkoKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIHRoaXMuX2luc3RhbmNlOwogICAgfTsKICAgIC8qKgogICAgICogU2V0IHRoZSBjdXJyZW50IGNvbnRleHQgbWFuYWdlci4KICAgICAqCiAgICAgKiBAcmV0dXJucyB0cnVlIGlmIHRoZSBjb250ZXh0IG1hbmFnZXIgd2FzIHN1Y2Nlc3NmdWxseSByZWdpc3RlcmVkLCBlbHNlIGZhbHNlCiAgICAgKi8KICAgIENvbnRleHRBUEkucHJvdG90eXBlLnNldEdsb2JhbENvbnRleHRNYW5hZ2VyID0gZnVuY3Rpb24gKGNvbnRleHRNYW5hZ2VyKSB7CiAgICAgICAgcmV0dXJuIHJlZ2lzdGVyR2xvYmFsKEFQSV9OQU1FLCBjb250ZXh0TWFuYWdlciwgRGlhZ0FQSS5pbnN0YW5jZSgpKTsKICAgIH07CiAgICAvKioKICAgICAqIEdldCB0aGUgY3VycmVudGx5IGFjdGl2ZSBjb250ZXh0CiAgICAgKi8KICAgIENvbnRleHRBUEkucHJvdG90eXBlLmFjdGl2ZSA9IGZ1bmN0aW9uICgpIHsKICAgICAgICByZXR1cm4gdGhpcy5fZ2V0Q29udGV4dE1hbmFnZXIoKS5hY3RpdmUoKTsKICAgIH07CiAgICAvKioKICAgICAqIEV4ZWN1dGUgYSBmdW5jdGlvbiB3aXRoIGFuIGFjdGl2ZSBjb250ZXh0CiAgICAgKgogICAgICogQHBhcmFtIGNvbnRleHQgY29udGV4dCB0byBiZSBhY3RpdmUgZHVyaW5nIGZ1bmN0aW9uIGV4ZWN1dGlvbgogICAgICogQHBhcmFtIGZuIGZ1bmN0aW9uIHRvIGV4ZWN1dGUgaW4gYSBjb250ZXh0CiAgICAgKiBAcGFyYW0gdGhpc0FyZyBvcHRpb25hbCByZWNlaXZlciB0byBiZSB1c2VkIGZvciBjYWxsaW5nIGZuCiAgICAgKiBAcGFyYW0gYXJncyBvcHRpb25hbCBhcmd1bWVudHMgZm9yd2FyZGVkIHRvIGZuCiAgICAgKi8KICAgIENvbnRleHRBUEkucHJvdG90eXBlLndpdGggPSBmdW5jdGlvbiAoY29udGV4dCwgZm4sIHRoaXNBcmcpIHsKICAgICAgICB2YXIgX2E7CiAgICAgICAgdmFyIGFyZ3MgPSBbXTsKICAgICAgICBmb3IgKHZhciBfaSA9IDM7IF9pIDwgYXJndW1lbnRzLmxlbmd0aDsgX2krKykgewogICAgICAgICAgICBhcmdzW19pIC0gM10gPSBhcmd1bWVudHNbX2ldOwogICAgICAgIH0KICAgICAgICByZXR1cm4gKF9hID0gdGhpcy5fZ2V0Q29udGV4dE1hbmFnZXIoKSkud2l0aC5hcHBseShfYSwgX19zcHJlYWRBcnJheShbY29udGV4dCwgZm4sIHRoaXNBcmddLCBfX3JlYWQoYXJncyksIGZhbHNlKSk7CiAgICB9OwogICAgLyoqCiAgICAgKiBCaW5kIGEgY29udGV4dCB0byBhIHRhcmdldCBmdW5jdGlvbiBvciBldmVudCBlbWl0dGVyCiAgICAgKgogICAgICogQHBhcmFtIGNvbnRleHQgY29udGV4dCB0byBiaW5kIHRvIHRoZSBldmVudCBlbWl0dGVyIG9yIGZ1bmN0aW9uLiBEZWZhdWx0cyB0byB0aGUgY3VycmVudGx5IGFjdGl2ZSBjb250ZXh0CiAgICAgKiBAcGFyYW0gdGFyZ2V0IGZ1bmN0aW9uIG9yIGV2ZW50IGVtaXR0ZXIgdG8gYmluZAogICAgICovCiAgICBDb250ZXh0QVBJLnByb3RvdHlwZS5iaW5kID0gZnVuY3Rpb24gKGNvbnRleHQsIHRhcmdldCkgewogICAgICAgIHJldHVybiB0aGlzLl9nZXRDb250ZXh0TWFuYWdlcigpLmJpbmQoY29udGV4dCwgdGFyZ2V0KTsKICAgIH07CiAgICBDb250ZXh0QVBJLnByb3RvdHlwZS5fZ2V0Q29udGV4dE1hbmFnZXIgPSBmdW5jdGlvbiAoKSB7CiAgICAgICAgcmV0dXJuIGdldEdsb2JhbChBUElfTkFNRSkgfHwgTk9PUF9DT05URVhUX01BTkFHRVI7CiAgICB9OwogICAgLyoqIERpc2FibGUgYW5kIHJlbW92ZSB0aGUgZ2xvYmFsIGNvbnRleHQgbWFuYWdlciAqLwogICAgQ29udGV4dEFQSS5wcm90b3R5cGUuZGlzYWJsZSA9IGZ1bmN0aW9uICgpIHsKICAgICAgICB0aGlzLl9nZXRDb250ZXh0TWFuYWdlcigpLmRpc2FibGUoKTsKICAgICAgICB1bnJlZ2lzdGVyR2xvYmFsKEFQSV9OQU1FLCBEaWFnQVBJLmluc3RhbmNlKCkpOwogICAgfTsKICAgIHJldHVybiBDb250ZXh0QVBJOwp9KCkpOwoKLyoKICogQ29weXJpZ2h0IFRoZSBPcGVuVGVsZW1ldHJ5IEF1dGhvcnMKICoKICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CiAqCiAqICAgICAgaHR0cHM6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAogKgogKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgogKi8KLy8gU3BsaXQgbW9kdWxlLWxldmVsIHZhcmlhYmxlIGRlZmluaXRpb24gaW50byBzZXBhcmF0ZSBmaWxlcyB0byBhbGxvdwovLyB0cmVlLXNoYWtpbmcgb24gZWFjaCBhcGkgaW5zdGFuY2UuCi8qKiBFbnRyeXBvaW50IGZvciBjb250ZXh0IEFQSSAqLwp2YXIgY29udGV4dCA9IENvbnRleHRBUEkuZ2V0SW5zdGFuY2UoKTsKCi8qCiAqIENvcHlyaWdodCBUaGUgT3BlblRlbGVtZXRyeSBBdXRob3JzCiAqCiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAogKgogKiAgICAgIGh0dHBzOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKICoKICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJBU0lTLAogKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS4KICovCnZhciBTVVBQUkVTU19UUkFDSU5HX0tFWSA9IGNyZWF0ZUNvbnRleHRLZXkoJ09wZW5UZWxlbWV0cnkgU0RLIENvbnRleHQgS2V5IFNVUFBSRVNTX1RSQUNJTkcnKTsKZnVuY3Rpb24gc3VwcHJlc3NUcmFjaW5nKGNvbnRleHQpIHsKICAgIHJldHVybiBjb250ZXh0LnNldFZhbHVlKFNVUFBSRVNTX1RSQUNJTkdfS0VZLCB0cnVlKTsKfQoKZnVuY3Rpb24gX251bGxpc2hDb2FsZXNjZSQyKGxocywgcmhzRm4pIHsgaWYgKGxocyAhPSBudWxsKSB7IHJldHVybiBsaHM7IH0gZWxzZSB7IHJldHVybiByaHNGbigpOyB9IH0vKioKICogVGhpcyBjb2RlIHdhcyBvcmlnaW5hbGx5IGZvcmtlZCBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9Ub29UYWxsTmF0ZS9wcm94eS1hZ2VudHMvdHJlZS9iMTMzMjk1ZmQxNmY2NDc1NTc4YjZiMTViZDliNGUzM2VjYjBkMGI3CiAqIFdpdGggdGhlIGZvbGxvd2luZyBsaWNlbmNlOgogKgogKiAoVGhlIE1JVCBMaWNlbnNlKQogKgogKiBDb3B5cmlnaHQgKGMpIDIwMTMgTmF0aGFuIFJhamxpY2ggPG5hdGhhbkB0b290YWxsbmF0ZS5uZXQ+KgogKgogKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcKICogYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlCiAqICdTb2Z0d2FyZScpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcKICogd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLAogKiBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8KICogcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvCiAqIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoqCiAqCiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlCiAqIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLioKICoKICogVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICdBUyBJUycsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsCiAqIEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRgogKiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuCiAqIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCiAqIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsCiAqIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFCiAqIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgogKi8KCmNvbnN0IElOVEVSTkFMID0gU3ltYm9sKCdBZ2VudEJhc2VJbnRlcm5hbFN0YXRlJyk7CgpjbGFzcyBBZ2VudCBleHRlbmRzIGh0dHAuQWdlbnQgewoKICAvLyBTZXQgYnkgYGh0dHAuQWdlbnRgIC0gbWlzc2luZyBmcm9tIGBAdHlwZXMvbm9kZWAKCiAgY29uc3RydWN0b3Iob3B0cykgewogICAgc3VwZXIob3B0cyk7CiAgICB0aGlzW0lOVEVSTkFMXSA9IHt9OwogIH0KCiAgLyoqCiAgICogRGV0ZXJtaW5lIHdoZXRoZXIgdGhpcyBpcyBhbiBgaHR0cGAgb3IgYGh0dHBzYCByZXF1ZXN0LgogICAqLwogIGlzU2VjdXJlRW5kcG9pbnQob3B0aW9ucykgewogICAgaWYgKG9wdGlvbnMpIHsKICAgICAgLy8gRmlyc3QgY2hlY2sgdGhlIGBzZWN1cmVFbmRwb2ludGAgcHJvcGVydHkgZXhwbGljaXRseSwgc2luY2UgdGhpcwogICAgICAvLyBtZWFucyB0aGF0IGEgcGFyZW50IGBBZ2VudGAgaXMgInBhc3NpbmcgdGhyb3VnaCIgdG8gdGhpcyBpbnN0YW5jZS4KICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnksIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtbWVtYmVyLWFjY2VzcwogICAgICBpZiAodHlwZW9mIChvcHRpb25zICkuc2VjdXJlRW5kcG9pbnQgPT09ICdib29sZWFuJykgewogICAgICAgIHJldHVybiBvcHRpb25zLnNlY3VyZUVuZHBvaW50OwogICAgICB9CgogICAgICAvLyBJZiBubyBleHBsaWNpdCBgc2VjdXJlYCBlbmRwb2ludCwgY2hlY2sgaWYgYHByb3RvY29sYCBwcm9wZXJ0eSBpcwogICAgICAvLyBzZXQuIFRoaXMgd2lsbCB1c3VhbGx5IGJlIHRoZSBjYXNlIHNpbmNlIHVzaW5nIGEgZnVsbCBzdHJpbmcgVVJMCiAgICAgIC8vIG9yIGBVUkxgIGluc3RhbmNlIHNob3VsZCBiZSB0aGUgbW9zdCBjb21tb24gdXNhZ2UuCiAgICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5wcm90b2NvbCA9PT0gJ3N0cmluZycpIHsKICAgICAgICByZXR1cm4gb3B0aW9ucy5wcm90b2NvbCA9PT0gJ2h0dHBzOic7CiAgICAgIH0KICAgIH0KCiAgICAvLyBGaW5hbGx5LCBpZiBubyBgcHJvdG9jb2xgIHByb3BlcnR5IHdhcyBzZXQsIHRoZW4gZmFsbCBiYWNrIHRvCiAgICAvLyBjaGVja2luZyB0aGUgc3RhY2sgdHJhY2Ugb2YgdGhlIGN1cnJlbnQgY2FsbCBzdGFjaywgYW5kIHRyeSB0bwogICAgLy8gZGV0ZWN0IHRoZSAiaHR0cHMiIG1vZHVsZS4KICAgIGNvbnN0IHsgc3RhY2sgfSA9IG5ldyBFcnJvcigpOwogICAgaWYgKHR5cGVvZiBzdGFjayAhPT0gJ3N0cmluZycpIHJldHVybiBmYWxzZTsKICAgIHJldHVybiBzdGFjay5zcGxpdCgnXG4nKS5zb21lKGwgPT4gbC5pbmRleE9mKCcoaHR0cHMuanM6JykgIT09IC0xIHx8IGwuaW5kZXhPZignbm9kZTpodHRwczonKSAhPT0gLTEpOwogIH0KCiAgY3JlYXRlU29ja2V0KHJlcSwgb3B0aW9ucywgY2IpIHsKICAgIGNvbnN0IGNvbm5lY3RPcHRzID0gewogICAgICAuLi5vcHRpb25zLAogICAgICBzZWN1cmVFbmRwb2ludDogdGhpcy5pc1NlY3VyZUVuZHBvaW50KG9wdGlvbnMpLAogICAgfTsKICAgIFByb21pc2UucmVzb2x2ZSgpCiAgICAgIC50aGVuKCgpID0+IHRoaXMuY29ubmVjdChyZXEsIGNvbm5lY3RPcHRzKSkKICAgICAgLnRoZW4oc29ja2V0ID0+IHsKICAgICAgICBpZiAoc29ja2V0IGluc3RhbmNlb2YgaHR0cC5BZ2VudCkgewogICAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciBgYWRkUmVxdWVzdCgpYCBpc24ndCBkZWZpbmVkIGluIGBAdHlwZXMvbm9kZWAKICAgICAgICAgIHJldHVybiBzb2NrZXQuYWRkUmVxdWVzdChyZXEsIGNvbm5lY3RPcHRzKTsKICAgICAgICB9CiAgICAgICAgdGhpc1tJTlRFUk5BTF0uY3VycmVudFNvY2tldCA9IHNvY2tldDsKICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIGBjcmVhdGVTb2NrZXQoKWAgaXNuJ3QgZGVmaW5lZCBpbiBgQHR5cGVzL25vZGVgCiAgICAgICAgc3VwZXIuY3JlYXRlU29ja2V0KHJlcSwgb3B0aW9ucywgY2IpOwogICAgICB9LCBjYik7CiAgfQoKICBjcmVhdGVDb25uZWN0aW9uKCkgewogICAgY29uc3Qgc29ja2V0ID0gdGhpc1tJTlRFUk5BTF0uY3VycmVudFNvY2tldDsKICAgIHRoaXNbSU5URVJOQUxdLmN1cnJlbnRTb2NrZXQgPSB1bmRlZmluZWQ7CiAgICBpZiAoIXNvY2tldCkgewogICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHNvY2tldCB3YXMgcmV0dXJuZWQgaW4gdGhlIGBjb25uZWN0KClgIGZ1bmN0aW9uJyk7CiAgICB9CiAgICByZXR1cm4gc29ja2V0OwogIH0KCiAgZ2V0IGRlZmF1bHRQb3J0KCkgewogICAgcmV0dXJuIF9udWxsaXNoQ29hbGVzY2UkMih0aGlzW0lOVEVSTkFMXS5kZWZhdWx0UG9ydCwgKCkgPT4gKCAodGhpcy5wcm90b2NvbCA9PT0gJ2h0dHBzOicgPyA0NDMgOiA4MCkpKTsKICB9CgogIHNldCBkZWZhdWx0UG9ydCh2KSB7CiAgICBpZiAodGhpc1tJTlRFUk5BTF0pIHsKICAgICAgdGhpc1tJTlRFUk5BTF0uZGVmYXVsdFBvcnQgPSB2OwogICAgfQogIH0KCiAgZ2V0IHByb3RvY29sKCkgewogICAgcmV0dXJuIF9udWxsaXNoQ29hbGVzY2UkMih0aGlzW0lOVEVSTkFMXS5wcm90b2NvbCwgKCkgPT4gKCAodGhpcy5pc1NlY3VyZUVuZHBvaW50KCkgPyAnaHR0cHM6JyA6ICdodHRwOicpKSk7CiAgfQoKICBzZXQgcHJvdG9jb2wodikgewogICAgaWYgKHRoaXNbSU5URVJOQUxdKSB7CiAgICAgIHRoaXNbSU5URVJOQUxdLnByb3RvY29sID0gdjsKICAgIH0KICB9Cn0KCmZ1bmN0aW9uIGRlYnVnJDEoLi4uYXJncykgewogIGxvZ2dlci5sb2coJ1todHRwcy1wcm94eS1hZ2VudDpwYXJzZS1wcm94eS1yZXNwb25zZV0nLCAuLi5hcmdzKTsKfQoKZnVuY3Rpb24gcGFyc2VQcm94eVJlc3BvbnNlKHNvY2tldCkgewogIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7CiAgICAvLyB3ZSBuZWVkIHRvIGJ1ZmZlciBhbnkgSFRUUCB0cmFmZmljIHRoYXQgaGFwcGVucyB3aXRoIHRoZSBwcm94eSBiZWZvcmUgd2UgZ2V0CiAgICAvLyB0aGUgQ09OTkVDVCByZXNwb25zZSwgc28gdGhhdCBpZiB0aGUgcmVzcG9uc2UgaXMgYW55dGhpbmcgb3RoZXIgdGhhbiBhbiAiMjAwIgogICAgLy8gcmVzcG9uc2UgY29kZSwgdGhlbiB3ZSBjYW4gcmUtcGxheSB0aGUgImRhdGEiIGV2ZW50cyBvbiB0aGUgc29ja2V0IG9uY2UgdGhlCiAgICAvLyBIVFRQIHBhcnNlciBpcyBob29rZWQgdXAuLi4KICAgIGxldCBidWZmZXJzTGVuZ3RoID0gMDsKICAgIGNvbnN0IGJ1ZmZlcnMgPSBbXTsKCiAgICBmdW5jdGlvbiByZWFkKCkgewogICAgICBjb25zdCBiID0gc29ja2V0LnJlYWQoKTsKICAgICAgaWYgKGIpIG9uZGF0YShiKTsKICAgICAgZWxzZSBzb2NrZXQub25jZSgncmVhZGFibGUnLCByZWFkKTsKICAgIH0KCiAgICBmdW5jdGlvbiBjbGVhbnVwKCkgewogICAgICBzb2NrZXQucmVtb3ZlTGlzdGVuZXIoJ2VuZCcsIG9uZW5kKTsKICAgICAgc29ja2V0LnJlbW92ZUxpc3RlbmVyKCdlcnJvcicsIG9uZXJyb3IpOwogICAgICBzb2NrZXQucmVtb3ZlTGlzdGVuZXIoJ3JlYWRhYmxlJywgcmVhZCk7CiAgICB9CgogICAgZnVuY3Rpb24gb25lbmQoKSB7CiAgICAgIGNsZWFudXAoKTsKICAgICAgZGVidWckMSgnb25lbmQnKTsKICAgICAgcmVqZWN0KG5ldyBFcnJvcignUHJveHkgY29ubmVjdGlvbiBlbmRlZCBiZWZvcmUgcmVjZWl2aW5nIENPTk5FQ1QgcmVzcG9uc2UnKSk7CiAgICB9CgogICAgZnVuY3Rpb24gb25lcnJvcihlcnIpIHsKICAgICAgY2xlYW51cCgpOwogICAgICBkZWJ1ZyQxKCdvbmVycm9yICVvJywgZXJyKTsKICAgICAgcmVqZWN0KGVycik7CiAgICB9CgogICAgZnVuY3Rpb24gb25kYXRhKGIpIHsKICAgICAgYnVmZmVycy5wdXNoKGIpOwogICAgICBidWZmZXJzTGVuZ3RoICs9IGIubGVuZ3RoOwoKICAgICAgY29uc3QgYnVmZmVyZWQgPSBCdWZmZXIuY29uY2F0KGJ1ZmZlcnMsIGJ1ZmZlcnNMZW5ndGgpOwogICAgICBjb25zdCBlbmRPZkhlYWRlcnMgPSBidWZmZXJlZC5pbmRleE9mKCdcclxuXHJcbicpOwoKICAgICAgaWYgKGVuZE9mSGVhZGVycyA9PT0gLTEpIHsKICAgICAgICAvLyBrZWVwIGJ1ZmZlcmluZwogICAgICAgIGRlYnVnJDEoJ2hhdmUgbm90IHJlY2VpdmVkIGVuZCBvZiBIVFRQIGhlYWRlcnMgeWV0Li4uJyk7CiAgICAgICAgcmVhZCgpOwogICAgICAgIHJldHVybjsKICAgICAgfQoKICAgICAgY29uc3QgaGVhZGVyUGFydHMgPSBidWZmZXJlZC5zbGljZSgwLCBlbmRPZkhlYWRlcnMpLnRvU3RyaW5nKCdhc2NpaScpLnNwbGl0KCdcclxuJyk7CiAgICAgIGNvbnN0IGZpcnN0TGluZSA9IGhlYWRlclBhcnRzLnNoaWZ0KCk7CiAgICAgIGlmICghZmlyc3RMaW5lKSB7CiAgICAgICAgc29ja2V0LmRlc3Ryb3koKTsKICAgICAgICByZXR1cm4gcmVqZWN0KG5ldyBFcnJvcignTm8gaGVhZGVyIHJlY2VpdmVkIGZyb20gcHJveHkgQ09OTkVDVCByZXNwb25zZScpKTsKICAgICAgfQogICAgICBjb25zdCBmaXJzdExpbmVQYXJ0cyA9IGZpcnN0TGluZS5zcGxpdCgnICcpOwogICAgICBjb25zdCBzdGF0dXNDb2RlID0gK2ZpcnN0TGluZVBhcnRzWzFdOwogICAgICBjb25zdCBzdGF0dXNUZXh0ID0gZmlyc3RMaW5lUGFydHMuc2xpY2UoMikuam9pbignICcpOwogICAgICBjb25zdCBoZWFkZXJzID0ge307CiAgICAgIGZvciAoY29uc3QgaGVhZGVyIG9mIGhlYWRlclBhcnRzKSB7CiAgICAgICAgaWYgKCFoZWFkZXIpIGNvbnRpbnVlOwogICAgICAgIGNvbnN0IGZpcnN0Q29sb24gPSBoZWFkZXIuaW5kZXhPZignOicpOwogICAgICAgIGlmIChmaXJzdENvbG9uID09PSAtMSkgewogICAgICAgICAgc29ja2V0LmRlc3Ryb3koKTsKICAgICAgICAgIHJldHVybiByZWplY3QobmV3IEVycm9yKGBJbnZhbGlkIGhlYWRlciBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2U6ICIke2hlYWRlcn0iYCkpOwogICAgICAgIH0KICAgICAgICBjb25zdCBrZXkgPSBoZWFkZXIuc2xpY2UoMCwgZmlyc3RDb2xvbikudG9Mb3dlckNhc2UoKTsKICAgICAgICBjb25zdCB2YWx1ZSA9IGhlYWRlci5zbGljZShmaXJzdENvbG9uICsgMSkudHJpbVN0YXJ0KCk7CiAgICAgICAgY29uc3QgY3VycmVudCA9IGhlYWRlcnNba2V5XTsKICAgICAgICBpZiAodHlwZW9mIGN1cnJlbnQgPT09ICdzdHJpbmcnKSB7CiAgICAgICAgICBoZWFkZXJzW2tleV0gPSBbY3VycmVudCwgdmFsdWVdOwogICAgICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShjdXJyZW50KSkgewogICAgICAgICAgY3VycmVudC5wdXNoKHZhbHVlKTsKICAgICAgICB9IGVsc2UgewogICAgICAgICAgaGVhZGVyc1trZXldID0gdmFsdWU7CiAgICAgICAgfQogICAgICB9CiAgICAgIGRlYnVnJDEoJ2dvdCBwcm94eSBzZXJ2ZXIgcmVzcG9uc2U6ICVvICVvJywgZmlyc3RMaW5lLCBoZWFkZXJzKTsKICAgICAgY2xlYW51cCgpOwogICAgICByZXNvbHZlKHsKICAgICAgICBjb25uZWN0OiB7CiAgICAgICAgICBzdGF0dXNDb2RlLAogICAgICAgICAgc3RhdHVzVGV4dCwKICAgICAgICAgIGhlYWRlcnMsCiAgICAgICAgfSwKICAgICAgICBidWZmZXJlZCwKICAgICAgfSk7CiAgICB9CgogICAgc29ja2V0Lm9uKCdlcnJvcicsIG9uZXJyb3IpOwogICAgc29ja2V0Lm9uKCdlbmQnLCBvbmVuZCk7CgogICAgcmVhZCgpOwogIH0pOwp9CgpmdW5jdGlvbiBfbnVsbGlzaENvYWxlc2NlJDEobGhzLCByaHNGbikgeyBpZiAobGhzICE9IG51bGwpIHsgcmV0dXJuIGxoczsgfSBlbHNlIHsgcmV0dXJuIHJoc0ZuKCk7IH0gfSBmdW5jdGlvbiBfb3B0aW9uYWxDaGFpbiQxKG9wcykgeyBsZXQgbGFzdEFjY2Vzc0xIUyA9IHVuZGVmaW5lZDsgbGV0IHZhbHVlID0gb3BzWzBdOyBsZXQgaSA9IDE7IHdoaWxlIChpIDwgb3BzLmxlbmd0aCkgeyBjb25zdCBvcCA9IG9wc1tpXTsgY29uc3QgZm4gPSBvcHNbaSArIDFdOyBpICs9IDI7IGlmICgob3AgPT09ICdvcHRpb25hbEFjY2VzcycgfHwgb3AgPT09ICdvcHRpb25hbENhbGwnKSAmJiB2YWx1ZSA9PSBudWxsKSB7IHJldHVybiB1bmRlZmluZWQ7IH0gaWYgKG9wID09PSAnYWNjZXNzJyB8fCBvcCA9PT0gJ29wdGlvbmFsQWNjZXNzJykgeyBsYXN0QWNjZXNzTEhTID0gdmFsdWU7IHZhbHVlID0gZm4odmFsdWUpOyB9IGVsc2UgaWYgKG9wID09PSAnY2FsbCcgfHwgb3AgPT09ICdvcHRpb25hbENhbGwnKSB7IHZhbHVlID0gZm4oKC4uLmFyZ3MpID0+IHZhbHVlLmNhbGwobGFzdEFjY2Vzc0xIUywgLi4uYXJncykpOyBsYXN0QWNjZXNzTEhTID0gdW5kZWZpbmVkOyB9IH0gcmV0dXJuIHZhbHVlOyB9CgpmdW5jdGlvbiBkZWJ1ZyguLi5hcmdzKSB7CiAgbG9nZ2VyLmxvZygnW2h0dHBzLXByb3h5LWFnZW50XScsIC4uLmFyZ3MpOwp9CgovKioKICogVGhlIGBIdHRwc1Byb3h5QWdlbnRgIGltcGxlbWVudHMgYW4gSFRUUCBBZ2VudCBzdWJjbGFzcyB0aGF0IGNvbm5lY3RzIHRvCiAqIHRoZSBzcGVjaWZpZWQgIkhUVFAocykgcHJveHkgc2VydmVyIiBpbiBvcmRlciB0byBwcm94eSBIVFRQUyByZXF1ZXN0cy4KICoKICogT3V0Z29pbmcgSFRUUCByZXF1ZXN0cyBhcmUgZmlyc3QgdHVubmVsZWQgdGhyb3VnaCB0aGUgcHJveHkgc2VydmVyIHVzaW5nIHRoZQogKiBgQ09OTkVDVGAgSFRUUCByZXF1ZXN0IG1ldGhvZCB0byBlc3RhYmxpc2ggYSBjb25uZWN0aW9uIHRvIHRoZSBwcm94eSBzZXJ2ZXIsCiAqIGFuZCB0aGVuIHRoZSBwcm94eSBzZXJ2ZXIgY29ubmVjdHMgdG8gdGhlIGRlc3RpbmF0aW9uIHRhcmdldCBhbmQgaXNzdWVzIHRoZQogKiBIVFRQIHJlcXVlc3QgZnJvbSB0aGUgcHJveHkgc2VydmVyLgogKgogKiBgaHR0cHM6YCByZXF1ZXN0cyBoYXZlIHRoZWlyIHNvY2tldCBjb25uZWN0aW9uIHVwZ3JhZGVkIHRvIFRMUyBvbmNlCiAqIHRoZSBjb25uZWN0aW9uIHRvIHRoZSBwcm94eSBzZXJ2ZXIgaGFzIGJlZW4gZXN0YWJsaXNoZWQuCiAqLwpjbGFzcyBIdHRwc1Byb3h5QWdlbnQgZXh0ZW5kcyBBZ2VudCB7CiAgc3RhdGljIF9faW5pdFN0YXRpYygpIHt0aGlzLnByb3RvY29scyA9IFsnaHR0cCcsICdodHRwcyddOyB9CgogIGNvbnN0cnVjdG9yKHByb3h5LCBvcHRzKSB7CiAgICBzdXBlcihvcHRzKTsKICAgIHRoaXMub3B0aW9ucyA9IHt9OwogICAgdGhpcy5wcm94eSA9IHR5cGVvZiBwcm94eSA9PT0gJ3N0cmluZycgPyBuZXcgVVJMKHByb3h5KSA6IHByb3h5OwogICAgdGhpcy5wcm94eUhlYWRlcnMgPSBfbnVsbGlzaENvYWxlc2NlJDEoX29wdGlvbmFsQ2hhaW4kMShbb3B0cywgJ29wdGlvbmFsQWNjZXNzJywgXzIgPT4gXzIuaGVhZGVyc10pLCAoKSA9PiAoIHt9KSk7CiAgICBkZWJ1ZygnQ3JlYXRpbmcgbmV3IEh0dHBzUHJveHlBZ2VudCBpbnN0YW5jZTogJW8nLCB0aGlzLnByb3h5LmhyZWYpOwoKICAgIC8vIFRyaW0gb2ZmIHRoZSBicmFja2V0cyBmcm9tIElQdjYgYWRkcmVzc2VzCiAgICBjb25zdCBob3N0ID0gKHRoaXMucHJveHkuaG9zdG5hbWUgfHwgdGhpcy5wcm94eS5ob3N0KS5yZXBsYWNlKC9eXFt8XF0kL2csICcnKTsKICAgIGNvbnN0IHBvcnQgPSB0aGlzLnByb3h5LnBvcnQgPyBwYXJzZUludCh0aGlzLnByb3h5LnBvcnQsIDEwKSA6IHRoaXMucHJveHkucHJvdG9jb2wgPT09ICdodHRwczonID8gNDQzIDogODA7CiAgICB0aGlzLmNvbm5lY3RPcHRzID0gewogICAgICAvLyBBdHRlbXB0IHRvIG5lZ290aWF0ZSBodHRwLzEuMSBmb3IgcHJveHkgc2VydmVycyB0aGF0IHN1cHBvcnQgaHR0cC8yCiAgICAgIEFMUE5Qcm90b2NvbHM6IFsnaHR0cC8xLjEnXSwKICAgICAgLi4uKG9wdHMgPyBvbWl0KG9wdHMsICdoZWFkZXJzJykgOiBudWxsKSwKICAgICAgaG9zdCwKICAgICAgcG9ydCwKICAgIH07CiAgfQoKICAvKioKICAgKiBDYWxsZWQgd2hlbiB0aGUgbm9kZS1jb3JlIEhUVFAgY2xpZW50IGxpYnJhcnkgaXMgY3JlYXRpbmcgYQogICAqIG5ldyBIVFRQIHJlcXVlc3QuCiAgICovCiAgYXN5bmMgY29ubmVjdChyZXEsIG9wdHMpIHsKICAgIGNvbnN0IHsgcHJveHkgfSA9IHRoaXM7CgogICAgaWYgKCFvcHRzLmhvc3QpIHsKICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignTm8gImhvc3QiIHByb3ZpZGVkJyk7CiAgICB9CgogICAgLy8gQ3JlYXRlIGEgc29ja2V0IGNvbm5lY3Rpb24gdG8gdGhlIHByb3h5IHNlcnZlci4KICAgIGxldCBzb2NrZXQ7CiAgICBpZiAocHJveHkucHJvdG9jb2wgPT09ICdodHRwczonKSB7CiAgICAgIGRlYnVnKCdDcmVhdGluZyBgdGxzLlNvY2tldGA6ICVvJywgdGhpcy5jb25uZWN0T3B0cyk7CiAgICAgIGNvbnN0IHNlcnZlcm5hbWUgPSB0aGlzLmNvbm5lY3RPcHRzLnNlcnZlcm5hbWUgfHwgdGhpcy5jb25uZWN0T3B0cy5ob3N0OwogICAgICBzb2NrZXQgPSB0bHMuY29ubmVjdCh7CiAgICAgICAgLi4udGhpcy5jb25uZWN0T3B0cywKICAgICAgICBzZXJ2ZXJuYW1lOiBzZXJ2ZXJuYW1lICYmIG5ldC5pc0lQKHNlcnZlcm5hbWUpID8gdW5kZWZpbmVkIDogc2VydmVybmFtZSwKICAgICAgfSk7CiAgICB9IGVsc2UgewogICAgICBkZWJ1ZygnQ3JlYXRpbmcgYG5ldC5Tb2NrZXRgOiAlbycsIHRoaXMuY29ubmVjdE9wdHMpOwogICAgICBzb2NrZXQgPSBuZXQuY29ubmVjdCh0aGlzLmNvbm5lY3RPcHRzKTsKICAgIH0KCiAgICBjb25zdCBoZWFkZXJzID0KICAgICAgdHlwZW9mIHRoaXMucHJveHlIZWFkZXJzID09PSAnZnVuY3Rpb24nID8gdGhpcy5wcm94eUhlYWRlcnMoKSA6IHsgLi4udGhpcy5wcm94eUhlYWRlcnMgfTsKICAgIGNvbnN0IGhvc3QgPSBuZXQuaXNJUHY2KG9wdHMuaG9zdCkgPyBgWyR7b3B0cy5ob3N0fV1gIDogb3B0cy5ob3N0OwogICAgbGV0IHBheWxvYWQgPSBgQ09OTkVDVCAke2hvc3R9OiR7b3B0cy5wb3J0fSBIVFRQLzEuMVxyXG5gOwoKICAgIC8vIEluamVjdCB0aGUgYFByb3h5LUF1dGhvcml6YXRpb25gIGhlYWRlciBpZiBuZWNlc3NhcnkuCiAgICBpZiAocHJveHkudXNlcm5hbWUgfHwgcHJveHkucGFzc3dvcmQpIHsKICAgICAgY29uc3QgYXV0aCA9IGAke2RlY29kZVVSSUNvbXBvbmVudChwcm94eS51c2VybmFtZSl9OiR7ZGVjb2RlVVJJQ29tcG9uZW50KHByb3h5LnBhc3N3b3JkKX1gOwogICAgICBoZWFkZXJzWydQcm94eS1BdXRob3JpemF0aW9uJ10gPSBgQmFzaWMgJHtCdWZmZXIuZnJvbShhdXRoKS50b1N0cmluZygnYmFzZTY0Jyl9YDsKICAgIH0KCiAgICBoZWFkZXJzLkhvc3QgPSBgJHtob3N0fToke29wdHMucG9ydH1gOwoKICAgIGlmICghaGVhZGVyc1snUHJveHktQ29ubmVjdGlvbiddKSB7CiAgICAgIGhlYWRlcnNbJ1Byb3h5LUNvbm5lY3Rpb24nXSA9IHRoaXMua2VlcEFsaXZlID8gJ0tlZXAtQWxpdmUnIDogJ2Nsb3NlJzsKICAgIH0KICAgIGZvciAoY29uc3QgbmFtZSBvZiBPYmplY3Qua2V5cyhoZWFkZXJzKSkgewogICAgICBwYXlsb2FkICs9IGAke25hbWV9OiAke2hlYWRlcnNbbmFtZV19XHJcbmA7CiAgICB9CgogICAgY29uc3QgcHJveHlSZXNwb25zZVByb21pc2UgPSBwYXJzZVByb3h5UmVzcG9uc2Uoc29ja2V0KTsKCiAgICBzb2NrZXQud3JpdGUoYCR7cGF5bG9hZH1cclxuYCk7CgogICAgY29uc3QgeyBjb25uZWN0LCBidWZmZXJlZCB9ID0gYXdhaXQgcHJveHlSZXNwb25zZVByb21pc2U7CiAgICByZXEuZW1pdCgncHJveHlDb25uZWN0JywgY29ubmVjdCk7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L2Jhbi10cy1jb21tZW50CiAgICAvLyBAdHMtaWdub3JlIE5vdCBFdmVudEVtaXR0ZXIgaW4gTm9kZSB0eXBlcwogICAgdGhpcy5lbWl0KCdwcm94eUNvbm5lY3QnLCBjb25uZWN0LCByZXEpOwoKICAgIGlmIChjb25uZWN0LnN0YXR1c0NvZGUgPT09IDIwMCkgewogICAgICByZXEub25jZSgnc29ja2V0JywgcmVzdW1lKTsKCiAgICAgIGlmIChvcHRzLnNlY3VyZUVuZHBvaW50KSB7CiAgICAgICAgLy8gVGhlIHByb3h5IGlzIGNvbm5lY3RpbmcgdG8gYSBUTFMgc2VydmVyLCBzbyB1cGdyYWRlCiAgICAgICAgLy8gdGhpcyBzb2NrZXQgY29ubmVjdGlvbiB0byBhIFRMUyBjb25uZWN0aW9uLgogICAgICAgIGRlYnVnKCdVcGdyYWRpbmcgc29ja2V0IGNvbm5lY3Rpb24gdG8gVExTJyk7CiAgICAgICAgY29uc3Qgc2VydmVybmFtZSA9IG9wdHMuc2VydmVybmFtZSB8fCBvcHRzLmhvc3Q7CiAgICAgICAgcmV0dXJuIHRscy5jb25uZWN0KHsKICAgICAgICAgIC4uLm9taXQob3B0cywgJ2hvc3QnLCAncGF0aCcsICdwb3J0JyksCiAgICAgICAgICBzb2NrZXQsCiAgICAgICAgICBzZXJ2ZXJuYW1lOiBuZXQuaXNJUChzZXJ2ZXJuYW1lKSA/IHVuZGVmaW5lZCA6IHNlcnZlcm5hbWUsCiAgICAgICAgfSk7CiAgICAgIH0KCiAgICAgIHJldHVybiBzb2NrZXQ7CiAgICB9CgogICAgLy8gU29tZSBvdGhlciBzdGF0dXMgY29kZSB0aGF0J3Mgbm90IDIwMC4uLiBuZWVkIHRvIHJlLXBsYXkgdGhlIEhUVFAKICAgIC8vIGhlYWRlciAiZGF0YSIgZXZlbnRzIG9udG8gdGhlIHNvY2tldCBvbmNlIHRoZSBIVFRQIG1hY2hpbmVyeSBpcwogICAgLy8gYXR0YWNoZWQgc28gdGhhdCB0aGUgbm9kZSBjb3JlIGBodHRwYCBjYW4gcGFyc2UgYW5kIGhhbmRsZSB0aGUKICAgIC8vIGVycm9yIHN0YXR1cyBjb2RlLgoKICAgIC8vIENsb3NlIHRoZSBvcmlnaW5hbCBzb2NrZXQsIGFuZCBhIG5ldyAiZmFrZSIgc29ja2V0IGlzIHJldHVybmVkCiAgICAvLyBpbnN0ZWFkLCBzbyB0aGF0IHRoZSBwcm94eSBkb2Vzbid0IGdldCB0aGUgSFRUUCByZXF1ZXN0CiAgICAvLyB3cml0dGVuIHRvIGl0ICh3aGljaCBtYXkgY29udGFpbiBgQXV0aG9yaXphdGlvbmAgaGVhZGVycyBvciBvdGhlcgogICAgLy8gc2Vuc2l0aXZlIGRhdGEpLgogICAgLy8KICAgIC8vIFNlZTogaHR0cHM6Ly9oYWNrZXJvbmUuY29tL3JlcG9ydHMvNTQxNTAyCiAgICBzb2NrZXQuZGVzdHJveSgpOwoKICAgIGNvbnN0IGZha2VTb2NrZXQgPSBuZXcgbmV0LlNvY2tldCh7IHdyaXRhYmxlOiBmYWxzZSB9KTsKICAgIGZha2VTb2NrZXQucmVhZGFibGUgPSB0cnVlOwoKICAgIC8vIE5lZWQgdG8gd2FpdCBmb3IgdGhlICJzb2NrZXQiIGV2ZW50IHRvIHJlLXBsYXkgdGhlICJkYXRhIiBldmVudHMuCiAgICByZXEub25jZSgnc29ja2V0JywgKHMpID0+IHsKICAgICAgZGVidWcoJ1JlcGxheWluZyBwcm94eSBidWZmZXIgZm9yIGZhaWxlZCByZXF1ZXN0Jyk7CiAgICAgIC8vIFJlcGxheSB0aGUgImJ1ZmZlcmVkIiBCdWZmZXIgb250byB0aGUgZmFrZSBgc29ja2V0YCwgc2luY2UgYXQKICAgICAgLy8gdGhpcyBwb2ludCB0aGUgSFRUUCBtb2R1bGUgbWFjaGluZXJ5IGhhcyBiZWVuIGhvb2tlZCB1cCBmb3IKICAgICAgLy8gdGhlIHVzZXIuCiAgICAgIHMucHVzaChidWZmZXJlZCk7CiAgICAgIHMucHVzaChudWxsKTsKICAgIH0pOwoKICAgIHJldHVybiBmYWtlU29ja2V0OwogIH0KfSBIdHRwc1Byb3h5QWdlbnQuX19pbml0U3RhdGljKCk7CgpmdW5jdGlvbiByZXN1bWUoc29ja2V0KSB7CiAgc29ja2V0LnJlc3VtZSgpOwp9CgpmdW5jdGlvbiBvbWl0KAogIG9iaiwKICAuLi5rZXlzCikKCiB7CiAgY29uc3QgcmV0ID0ge30KCjsKICBsZXQga2V5OwogIGZvciAoa2V5IGluIG9iaikgewogICAgaWYgKCFrZXlzLmluY2x1ZGVzKGtleSkpIHsKICAgICAgcmV0W2tleV0gPSBvYmpba2V5XTsKICAgIH0KICB9CiAgcmV0dXJuIHJldDsKfQoKZnVuY3Rpb24gX251bGxpc2hDb2FsZXNjZShsaHMsIHJoc0ZuKSB7IGlmIChsaHMgIT0gbnVsbCkgeyByZXR1cm4gbGhzOyB9IGVsc2UgeyByZXR1cm4gcmhzRm4oKTsgfSB9Ci8vIEVzdGltYXRlZCBtYXhpbXVtIHNpemUgZm9yIHJlYXNvbmFibGUgc3RhbmRhbG9uZSBldmVudApjb25zdCBHWklQX1RIUkVTSE9MRCA9IDEwMjQgKiAzMjsKCi8qKgogKiBHZXRzIGEgc3RyZWFtIGZyb20gYSBVaW50OEFycmF5IG9yIHN0cmluZwogKiBSZWFkYWJsZS5mcm9tIGlzIGlkZWFsIGJ1dCB3YXMgYWRkZWQgaW4gbm9kZS5qcyB2MTIuMy4wIGFuZCB2MTAuMTcuMAogKi8KZnVuY3Rpb24gc3RyZWFtRnJvbUJvZHkoYm9keSkgewogIHJldHVybiBuZXcgUmVhZGFibGUoewogICAgcmVhZCgpIHsKICAgICAgdGhpcy5wdXNoKGJvZHkpOwogICAgICB0aGlzLnB1c2gobnVsbCk7CiAgICB9LAogIH0pOwp9CgovKioKICogQ3JlYXRlcyBhIFRyYW5zcG9ydCB0aGF0IHVzZXMgbmF0aXZlIHRoZSBuYXRpdmUgJ2h0dHAnIGFuZCAnaHR0cHMnIG1vZHVsZXMgdG8gc2VuZCBldmVudHMgdG8gU2VudHJ5LgogKi8KZnVuY3Rpb24gbWFrZU5vZGVUcmFuc3BvcnQob3B0aW9ucykgewogIGxldCB1cmxTZWdtZW50czsKCiAgdHJ5IHsKICAgIHVybFNlZ21lbnRzID0gbmV3IFVSTChvcHRpb25zLnVybCk7CiAgfSBjYXRjaCAoZSkgewogICAgY29uc29sZVNhbmRib3goKCkgPT4gewogICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZQogICAgICBjb25zb2xlLndhcm4oCiAgICAgICAgJ1tAc2VudHJ5L25vZGVdOiBJbnZhbGlkIGRzbiBvciB0dW5uZWwgb3B0aW9uLCB3aWxsIG5vdCBzZW5kIGFueSBldmVudHMuIFRoZSB0dW5uZWwgb3B0aW9uIG11c3QgYmUgYSBmdWxsIFVSTCB3aGVuIHVzZWQuJywKICAgICAgKTsKICAgIH0pOwogICAgcmV0dXJuIGNyZWF0ZVRyYW5zcG9ydChvcHRpb25zLCAoKSA9PiBQcm9taXNlLnJlc29sdmUoe30pKTsKICB9CgogIGNvbnN0IGlzSHR0cHMgPSB1cmxTZWdtZW50cy5wcm90b2NvbCA9PT0gJ2h0dHBzOic7CgogIC8vIFByb3h5IHByaW9yaXRpemF0aW9uOiBodHRwID0+IGBvcHRpb25zLnByb3h5YCB8IGBwcm9jZXNzLmVudi5odHRwX3Byb3h5YAogIC8vIFByb3h5IHByaW9yaXRpemF0aW9uOiBodHRwcyA9PiBgb3B0aW9ucy5wcm94eWAgfCBgcHJvY2Vzcy5lbnYuaHR0cHNfcHJveHlgIHwgYHByb2Nlc3MuZW52Lmh0dHBfcHJveHlgCiAgY29uc3QgcHJveHkgPSBhcHBseU5vUHJveHlPcHRpb24oCiAgICB1cmxTZWdtZW50cywKICAgIG9wdGlvbnMucHJveHkgfHwgKGlzSHR0cHMgPyBwcm9jZXNzLmVudi5odHRwc19wcm94eSA6IHVuZGVmaW5lZCkgfHwgcHJvY2Vzcy5lbnYuaHR0cF9wcm94eSwKICApOwoKICBjb25zdCBuYXRpdmVIdHRwTW9kdWxlID0gaXNIdHRwcyA/IGh0dHBzIDogaHR0cCQxOwogIGNvbnN0IGtlZXBBbGl2ZSA9IG9wdGlvbnMua2VlcEFsaXZlID09PSB1bmRlZmluZWQgPyBmYWxzZSA6IG9wdGlvbnMua2VlcEFsaXZlOwoKICAvLyBUT0RPKHY3KTogRXZhbHVhdGUgaWYgd2UgY2FuIHNldCBrZWVwQWxpdmUgdG8gdHJ1ZS4gVGhpcyB3b3VsZCBpbnZvbHZlIHRlc3RpbmcgZm9yIG1lbW9yeSBsZWFrcyBpbiBvbGRlciBub2RlCiAgLy8gdmVyc2lvbnMoPj0gOCkgYXMgdGhleSBoYWQgbWVtb3J5IGxlYWtzIHdoZW4gdXNpbmcgaXQ6ICMyNTU1CiAgY29uc3QgYWdlbnQgPSBwcm94eQogICAgPyAobmV3IEh0dHBzUHJveHlBZ2VudChwcm94eSkgKQogICAgOiBuZXcgbmF0aXZlSHR0cE1vZHVsZS5BZ2VudCh7IGtlZXBBbGl2ZSwgbWF4U29ja2V0czogMzAsIHRpbWVvdXQ6IDIwMDAgfSk7CgogIC8vIFRoaXMgZW5zdXJlcyB3ZSBkbyBub3QgZ2VuZXJhdGUgYW55IHNwYW5zIGluIE9wZW5UZWxlbWV0cnkgZm9yIHRoZSB0cmFuc3BvcnQKICByZXR1cm4gY29udGV4dC53aXRoKHN1cHByZXNzVHJhY2luZyhjb250ZXh0LmFjdGl2ZSgpKSwgKCkgPT4gewogICAgY29uc3QgcmVxdWVzdEV4ZWN1dG9yID0gY3JlYXRlUmVxdWVzdEV4ZWN1dG9yKG9wdGlvbnMsIF9udWxsaXNoQ29hbGVzY2Uob3B0aW9ucy5odHRwTW9kdWxlLCAoKSA9PiAoIG5hdGl2ZUh0dHBNb2R1bGUpKSwgYWdlbnQpOwogICAgcmV0dXJuIGNyZWF0ZVRyYW5zcG9ydChvcHRpb25zLCByZXF1ZXN0RXhlY3V0b3IpOwogIH0pOwp9CgovKioKICogSG9ub3JzIHRoZSBgbm9fcHJveHlgIGVudiB2YXJpYWJsZSB3aXRoIHRoZSBoaWdoZXN0IHByaW9yaXR5IHRvIGFsbG93IGZvciBob3N0cyBleGNsdXNpb24uCiAqCiAqIEBwYXJhbSB0cmFuc3BvcnRVcmwgVGhlIFVSTCB0aGUgdHJhbnNwb3J0IGludGVuZHMgdG8gc2VuZCBldmVudHMgdG8uCiAqIEBwYXJhbSBwcm94eSBUaGUgY2xpZW50IGNvbmZpZ3VyZWQgcHJveHkuCiAqIEByZXR1cm5zIEEgcHJveHkgdGhlIHRyYW5zcG9ydCBzaG91bGQgdXNlLgogKi8KZnVuY3Rpb24gYXBwbHlOb1Byb3h5T3B0aW9uKHRyYW5zcG9ydFVybFNlZ21lbnRzLCBwcm94eSkgewogIGNvbnN0IHsgbm9fcHJveHkgfSA9IHByb2Nlc3MuZW52OwoKICBjb25zdCB1cmxJc0V4ZW1wdEZyb21Qcm94eSA9CiAgICBub19wcm94eSAmJgogICAgbm9fcHJveHkKICAgICAgLnNwbGl0KCcsJykKICAgICAgLnNvbWUoCiAgICAgICAgZXhlbXB0aW9uID0+IHRyYW5zcG9ydFVybFNlZ21lbnRzLmhvc3QuZW5kc1dpdGgoZXhlbXB0aW9uKSB8fCB0cmFuc3BvcnRVcmxTZWdtZW50cy5ob3N0bmFtZS5lbmRzV2l0aChleGVtcHRpb24pLAogICAgICApOwoKICBpZiAodXJsSXNFeGVtcHRGcm9tUHJveHkpIHsKICAgIHJldHVybiB1bmRlZmluZWQ7CiAgfSBlbHNlIHsKICAgIHJldHVybiBwcm94eTsKICB9Cn0KCi8qKgogKiBDcmVhdGVzIGEgUmVxdWVzdEV4ZWN1dG9yIHRvIGJlIHVzZWQgd2l0aCBgY3JlYXRlVHJhbnNwb3J0YC4KICovCmZ1bmN0aW9uIGNyZWF0ZVJlcXVlc3RFeGVjdXRvcigKICBvcHRpb25zLAogIGh0dHBNb2R1bGUsCiAgYWdlbnQsCikgewogIGNvbnN0IHsgaG9zdG5hbWUsIHBhdGhuYW1lLCBwb3J0LCBwcm90b2NvbCwgc2VhcmNoIH0gPSBuZXcgVVJMKG9wdGlvbnMudXJsKTsKICByZXR1cm4gZnVuY3Rpb24gbWFrZVJlcXVlc3QocmVxdWVzdCkgewogICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHsKICAgICAgbGV0IGJvZHkgPSBzdHJlYW1Gcm9tQm9keShyZXF1ZXN0LmJvZHkpOwoKICAgICAgY29uc3QgaGVhZGVycyA9IHsgLi4ub3B0aW9ucy5oZWFkZXJzIH07CgogICAgICBpZiAocmVxdWVzdC5ib2R5Lmxlbmd0aCA+IEdaSVBfVEhSRVNIT0xEKSB7CiAgICAgICAgaGVhZGVyc1snY29udGVudC1lbmNvZGluZyddID0gJ2d6aXAnOwogICAgICAgIGJvZHkgPSBib2R5LnBpcGUoY3JlYXRlR3ppcCgpKTsKICAgICAgfQoKICAgICAgY29uc3QgcmVxID0gaHR0cE1vZHVsZS5yZXF1ZXN0KAogICAgICAgIHsKICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLAogICAgICAgICAgYWdlbnQsCiAgICAgICAgICBoZWFkZXJzLAogICAgICAgICAgaG9zdG5hbWUsCiAgICAgICAgICBwYXRoOiBgJHtwYXRobmFtZX0ke3NlYXJjaH1gLAogICAgICAgICAgcG9ydCwKICAgICAgICAgIHByb3RvY29sLAogICAgICAgICAgY2E6IG9wdGlvbnMuY2FDZXJ0cywKICAgICAgICB9LAogICAgICAgIHJlcyA9PiB7CiAgICAgICAgICByZXMub24oJ2RhdGEnLCAoKSA9PiB7CiAgICAgICAgICAgIC8vIERyYWluIHNvY2tldAogICAgICAgICAgfSk7CgogICAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7CiAgICAgICAgICAgIC8vIERyYWluIHNvY2tldAogICAgICAgICAgfSk7CgogICAgICAgICAgcmVzLnNldEVuY29kaW5nKCd1dGY4Jyk7CgogICAgICAgICAgLy8gIktleS12YWx1ZSBwYWlycyBvZiBoZWFkZXIgbmFtZXMgYW5kIHZhbHVlcy4gSGVhZGVyIG5hbWVzIGFyZSBsb3dlci1jYXNlZC4iCiAgICAgICAgICAvLyBodHRwczovL25vZGVqcy5vcmcvYXBpL2h0dHAuaHRtbCNodHRwX21lc3NhZ2VfaGVhZGVycwogICAgICAgICAgY29uc3QgcmV0cnlBZnRlckhlYWRlciA9IF9udWxsaXNoQ29hbGVzY2UocmVzLmhlYWRlcnNbJ3JldHJ5LWFmdGVyJ10sICgpID0+ICggbnVsbCkpOwogICAgICAgICAgY29uc3QgcmF0ZUxpbWl0c0hlYWRlciA9IF9udWxsaXNoQ29hbGVzY2UocmVzLmhlYWRlcnNbJ3gtc2VudHJ5LXJhdGUtbGltaXRzJ10sICgpID0+ICggbnVsbCkpOwoKICAgICAgICAgIHJlc29sdmUoewogICAgICAgICAgICBzdGF0dXNDb2RlOiByZXMuc3RhdHVzQ29kZSwKICAgICAgICAgICAgaGVhZGVyczogewogICAgICAgICAgICAgICdyZXRyeS1hZnRlcic6IHJldHJ5QWZ0ZXJIZWFkZXIsCiAgICAgICAgICAgICAgJ3gtc2VudHJ5LXJhdGUtbGltaXRzJzogQXJyYXkuaXNBcnJheShyYXRlTGltaXRzSGVhZGVyKSA/IHJhdGVMaW1pdHNIZWFkZXJbMF0gOiByYXRlTGltaXRzSGVhZGVyLAogICAgICAgICAgICB9LAogICAgICAgICAgfSk7CiAgICAgICAgfSwKICAgICAgKTsKCiAgICAgIHJlcS5vbignZXJyb3InLCByZWplY3QpOwogICAgICBib2R5LnBpcGUocmVxKTsKICAgIH0pOwogIH07Cn0KCi8qKiBub3JtYWxpemVzIFdpbmRvd3MgcGF0aHMgKi8KZnVuY3Rpb24gbm9ybWFsaXplV2luZG93c1BhdGgocGF0aCkgewogIHJldHVybiBwYXRoCiAgICAucmVwbGFjZSgvXltBLVpdOi8sICcnKSAvLyByZW1vdmUgV2luZG93cy1zdHlsZSBwcmVmaXgKICAgIC5yZXBsYWNlKC9cXC9nLCAnLycpOyAvLyByZXBsYWNlIGFsbCBgXGAgaW5zdGFuY2VzIHdpdGggYC9gCn0KCi8qKiBDcmVhdGVzIGEgZnVuY3Rpb24gdGhhdCBnZXRzIHRoZSBtb2R1bGUgbmFtZSBmcm9tIGEgZmlsZW5hbWUgKi8KZnVuY3Rpb24gY3JlYXRlR2V0TW9kdWxlRnJvbUZpbGVuYW1lKAogIGJhc2VQYXRoID0gcHJvY2Vzcy5hcmd2WzFdID8gZGlybmFtZShwcm9jZXNzLmFyZ3ZbMV0pIDogcHJvY2Vzcy5jd2QoKSwKICBpc1dpbmRvd3MgPSBzZXAgPT09ICdcXCcsCikgewogIGNvbnN0IG5vcm1hbGl6ZWRCYXNlID0gaXNXaW5kb3dzID8gbm9ybWFsaXplV2luZG93c1BhdGgoYmFzZVBhdGgpIDogYmFzZVBhdGg7CgogIHJldHVybiAoZmlsZW5hbWUpID0+IHsKICAgIGlmICghZmlsZW5hbWUpIHsKICAgICAgcmV0dXJuOwogICAgfQoKICAgIGNvbnN0IG5vcm1hbGl6ZWRGaWxlbmFtZSA9IGlzV2luZG93cyA/IG5vcm1hbGl6ZVdpbmRvd3NQYXRoKGZpbGVuYW1lKSA6IGZpbGVuYW1lOwoKICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBwcmVmZXItY29uc3QKICAgIGxldCB7IGRpciwgYmFzZTogZmlsZSwgZXh0IH0gPSBwb3NpeC5wYXJzZShub3JtYWxpemVkRmlsZW5hbWUpOwoKICAgIGlmIChleHQgPT09ICcuanMnIHx8IGV4dCA9PT0gJy5tanMnIHx8IGV4dCA9PT0gJy5janMnKSB7CiAgICAgIGZpbGUgPSBmaWxlLnNsaWNlKDAsIGV4dC5sZW5ndGggKiAtMSk7CiAgICB9CgogICAgaWYgKCFkaXIpIHsKICAgICAgLy8gTm8gZGlybmFtZSB3aGF0c29ldmVyCiAgICAgIGRpciA9ICcuJzsKICAgIH0KCiAgICBjb25zdCBuID0gZGlyLmxhc3RJbmRleE9mKCcvbm9kZV9tb2R1bGVzJyk7CiAgICBpZiAobiA+IC0xKSB7CiAgICAgIHJldHVybiBgJHtkaXIuc2xpY2UobiArIDE0KS5yZXBsYWNlKC9cLy9nLCAnLicpfToke2ZpbGV9YDsKICAgIH0KCiAgICAvLyBMZXQncyBzZWUgaWYgaXQncyBhIHBhcnQgb2YgdGhlIG1haW4gbW9kdWxlCiAgICAvLyBUbyBiZSBhIHBhcnQgb2YgbWFpbiBtb2R1bGUsIGl0IGhhcyB0byBzaGFyZSB0aGUgc2FtZSBiYXNlCiAgICBpZiAoZGlyLnN0YXJ0c1dpdGgobm9ybWFsaXplZEJhc2UpKSB7CiAgICAgIGxldCBtb2R1bGVOYW1lID0gZGlyLnNsaWNlKG5vcm1hbGl6ZWRCYXNlLmxlbmd0aCArIDEpLnJlcGxhY2UoL1wvL2csICcuJyk7CgogICAgICBpZiAobW9kdWxlTmFtZSkgewogICAgICAgIG1vZHVsZU5hbWUgKz0gJzonOwogICAgICB9CiAgICAgIG1vZHVsZU5hbWUgKz0gZmlsZTsKCiAgICAgIHJldHVybiBtb2R1bGVOYW1lOwogICAgfQoKICAgIHJldHVybiBmaWxlOwogIH07Cn0KCmZ1bmN0aW9uIF9vcHRpb25hbENoYWluKG9wcykgeyBsZXQgbGFzdEFjY2Vzc0xIUyA9IHVuZGVmaW5lZDsgbGV0IHZhbHVlID0gb3BzWzBdOyBsZXQgaSA9IDE7IHdoaWxlIChpIDwgb3BzLmxlbmd0aCkgeyBjb25zdCBvcCA9IG9wc1tpXTsgY29uc3QgZm4gPSBvcHNbaSArIDFdOyBpICs9IDI7IGlmICgob3AgPT09ICdvcHRpb25hbEFjY2VzcycgfHwgb3AgPT09ICdvcHRpb25hbENhbGwnKSAmJiB2YWx1ZSA9PSBudWxsKSB7IHJldHVybiB1bmRlZmluZWQ7IH0gaWYgKG9wID09PSAnYWNjZXNzJyB8fCBvcCA9PT0gJ29wdGlvbmFsQWNjZXNzJykgeyBsYXN0QWNjZXNzTEhTID0gdmFsdWU7IHZhbHVlID0gZm4odmFsdWUpOyB9IGVsc2UgaWYgKG9wID09PSAnY2FsbCcgfHwgb3AgPT09ICdvcHRpb25hbENhbGwnKSB7IHZhbHVlID0gZm4oKC4uLmFyZ3MpID0+IHZhbHVlLmNhbGwobGFzdEFjY2Vzc0xIUywgLi4uYXJncykpOyBsYXN0QWNjZXNzTEhTID0gdW5kZWZpbmVkOyB9IH0gcmV0dXJuIHZhbHVlOyB9CmNvbnN0IG9wdGlvbnMgPSB3b3JrZXJEYXRhOwpsZXQgc2Vzc2lvbjsKbGV0IGhhc1NlbnRBbnJFdmVudCA9IGZhbHNlOwoKZnVuY3Rpb24gbG9nKG1zZykgewogIGlmIChvcHRpb25zLmRlYnVnKSB7CiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZQogICAgY29uc29sZS5sb2coYFtBTlIgV29ya2VyXSAke21zZ31gKTsKICB9Cn0KCmNvbnN0IHVybCA9IGdldEVudmVsb3BlRW5kcG9pbnRXaXRoVXJsRW5jb2RlZEF1dGgob3B0aW9ucy5kc24sIG9wdGlvbnMudHVubmVsLCBvcHRpb25zLnNka01ldGFkYXRhLnNkayk7CmNvbnN0IHRyYW5zcG9ydCA9IG1ha2VOb2RlVHJhbnNwb3J0KHsKICB1cmwsCiAgcmVjb3JkRHJvcHBlZEV2ZW50OiAoKSA9PiB7CiAgICAvLwogIH0sCn0pOwoKYXN5bmMgZnVuY3Rpb24gc2VuZEFibm9ybWFsU2Vzc2lvbigpIHsKICAvLyBvZiB3ZSBoYXZlIGFuIGV4aXN0aW5nIHNlc3Npb24gcGFzc2VkIGZyb20gdGhlIG1haW4gdGhyZWFkLCBzZW5kIGl0IGFzIGFibm9ybWFsCiAgaWYgKHNlc3Npb24pIHsKICAgIGxvZygnU2VuZGluZyBhYm5vcm1hbCBzZXNzaW9uJyk7CiAgICB1cGRhdGVTZXNzaW9uKHNlc3Npb24sIHsgc3RhdHVzOiAnYWJub3JtYWwnLCBhYm5vcm1hbF9tZWNoYW5pc206ICdhbnJfZm9yZWdyb3VuZCcgfSk7CgogICAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVTZXNzaW9uRW52ZWxvcGUoc2Vzc2lvbiwgb3B0aW9ucy5kc24sIG9wdGlvbnMuc2RrTWV0YWRhdGEsIG9wdGlvbnMudHVubmVsKTsKICAgIC8vIExvZyB0aGUgZW52ZWxvcGUgc28gdG8gYWlkIGluIHRlc3RpbmcKICAgIGxvZyhKU09OLnN0cmluZ2lmeShlbnZlbG9wZSkpOwoKICAgIGF3YWl0IHRyYW5zcG9ydC5zZW5kKGVudmVsb3BlKTsKCiAgICB0cnkgewogICAgICAvLyBOb3RpZnkgdGhlIG1haW4gcHJvY2VzcyB0aGF0IHRoZSBzZXNzaW9uIGhhcyBlbmRlZCBzbyB0aGUgc2Vzc2lvbiBjYW4gYmUgY2xlYXJlZCBmcm9tIHRoZSBzY29wZQogICAgICBfb3B0aW9uYWxDaGFpbihbcGFyZW50UG9ydCwgJ29wdGlvbmFsQWNjZXNzJywgXzIgPT4gXzIucG9zdE1lc3NhZ2UsICdjYWxsJywgXzMgPT4gXzMoJ3Nlc3Npb24tZW5kZWQnKV0pOwogICAgfSBjYXRjaCAoXykgewogICAgICAvLyBpZ25vcmUKICAgIH0KICB9Cn0KCmxvZygnU3RhcnRlZCcpOwoKZnVuY3Rpb24gcHJlcGFyZVN0YWNrRnJhbWVzKHN0YWNrRnJhbWVzKSB7CiAgaWYgKCFzdGFja0ZyYW1lcykgewogICAgcmV0dXJuIHVuZGVmaW5lZDsKICB9CgogIC8vIFN0cmlwIFNlbnRyeSBmcmFtZXMgYW5kIHJldmVyc2UgdGhlIHN0YWNrIGZyYW1lcyBzbyB0aGV5IGFyZSBpbiB0aGUgY29ycmVjdCBvcmRlcgogIGNvbnN0IHN0cmlwcGVkRnJhbWVzID0gc3RyaXBTZW50cnlGcmFtZXNBbmRSZXZlcnNlKHN0YWNrRnJhbWVzKTsKCiAgLy8gSWYgd2UgaGF2ZSBhbiBhcHAgcm9vdCBwYXRoLCByZXdyaXRlIHRoZSBmaWxlbmFtZXMgdG8gYmUgcmVsYXRpdmUgdG8gdGhlIGFwcCByb290CiAgaWYgKG9wdGlvbnMuYXBwUm9vdFBhdGgpIHsKICAgIGZvciAoY29uc3QgZnJhbWUgb2Ygc3RyaXBwZWRGcmFtZXMpIHsKICAgICAgaWYgKCFmcmFtZS5maWxlbmFtZSkgewogICAgICAgIGNvbnRpbnVlOwogICAgICB9CgogICAgICBmcmFtZS5maWxlbmFtZSA9IG5vcm1hbGl6ZVVybFRvQmFzZShmcmFtZS5maWxlbmFtZSwgb3B0aW9ucy5hcHBSb290UGF0aCk7CiAgICB9CiAgfQoKICByZXR1cm4gc3RyaXBwZWRGcmFtZXM7Cn0KCmZ1bmN0aW9uIGFwcGx5U2NvcGVUb0V2ZW50KGV2ZW50LCBzY29wZSkgewogIGFwcGx5U2NvcGVEYXRhVG9FdmVudChldmVudCwgc2NvcGUpOwoKICBpZiAoIV9vcHRpb25hbENoYWluKFtldmVudCwgJ2FjY2VzcycsIF80ID0+IF80LmNvbnRleHRzLCAnb3B0aW9uYWxBY2Nlc3MnLCBfNSA9PiBfNS50cmFjZV0pKSB7CiAgICBjb25zdCB7IHRyYWNlSWQsIHNwYW5JZCwgcGFyZW50U3BhbklkIH0gPSBzY29wZS5wcm9wYWdhdGlvbkNvbnRleHQ7CiAgICBldmVudC5jb250ZXh0cyA9IHsKICAgICAgdHJhY2U6IHsKICAgICAgICB0cmFjZV9pZDogdHJhY2VJZCwKICAgICAgICBzcGFuX2lkOiBzcGFuSWQsCiAgICAgICAgcGFyZW50X3NwYW5faWQ6IHBhcmVudFNwYW5JZCwKICAgICAgfSwKICAgICAgLi4uZXZlbnQuY29udGV4dHMsCiAgICB9OwogIH0KfQoKYXN5bmMgZnVuY3Rpb24gc2VuZEFuckV2ZW50KGZyYW1lcywgc2NvcGUpIHsKICBpZiAoaGFzU2VudEFuckV2ZW50KSB7CiAgICByZXR1cm47CiAgfQoKICBoYXNTZW50QW5yRXZlbnQgPSB0cnVlOwoKICBhd2FpdCBzZW5kQWJub3JtYWxTZXNzaW9uKCk7CgogIGxvZygnU2VuZGluZyBldmVudCcpOwoKICBjb25zdCBldmVudCA9IHsKICAgIGV2ZW50X2lkOiB1dWlkNCgpLAogICAgY29udGV4dHM6IG9wdGlvbnMuY29udGV4dHMsCiAgICByZWxlYXNlOiBvcHRpb25zLnJlbGVhc2UsCiAgICBlbnZpcm9ubWVudDogb3B0aW9ucy5lbnZpcm9ubWVudCwKICAgIGRpc3Q6IG9wdGlvbnMuZGlzdCwKICAgIHBsYXRmb3JtOiAnbm9kZScsCiAgICBsZXZlbDogJ2Vycm9yJywKICAgIGV4Y2VwdGlvbjogewogICAgICB2YWx1ZXM6IFsKICAgICAgICB7CiAgICAgICAgICB0eXBlOiAnQXBwbGljYXRpb25Ob3RSZXNwb25kaW5nJywKICAgICAgICAgIHZhbHVlOiBgQXBwbGljYXRpb24gTm90IFJlc3BvbmRpbmcgZm9yIGF0IGxlYXN0ICR7b3B0aW9ucy5hbnJUaHJlc2hvbGR9IG1zYCwKICAgICAgICAgIHN0YWNrdHJhY2U6IHsgZnJhbWVzOiBwcmVwYXJlU3RhY2tGcmFtZXMoZnJhbWVzKSB9LAogICAgICAgICAgLy8gVGhpcyBlbnN1cmVzIHRoZSBVSSBkb2Vzbid0IHNheSAnQ3Jhc2hlZCBpbicgZm9yIHRoZSBzdGFjayB0cmFjZQogICAgICAgICAgbWVjaGFuaXNtOiB7IHR5cGU6ICdBTlInIH0sCiAgICAgICAgfSwKICAgICAgXSwKICAgIH0sCiAgICB0YWdzOiBvcHRpb25zLnN0YXRpY1RhZ3MsCiAgfTsKCiAgaWYgKHNjb3BlKSB7CiAgICBhcHBseVNjb3BlVG9FdmVudChldmVudCwgc2NvcGUpOwogIH0KCiAgY29uc3QgZW52ZWxvcGUgPSBjcmVhdGVFdmVudEVudmVsb3BlKGV2ZW50LCBvcHRpb25zLmRzbiwgb3B0aW9ucy5zZGtNZXRhZGF0YSwgb3B0aW9ucy50dW5uZWwpOwogIC8vIExvZyB0aGUgZW52ZWxvcGUgdG8gYWlkIGluIHRlc3RpbmcKICBsb2coSlNPTi5zdHJpbmdpZnkoZW52ZWxvcGUpKTsKCiAgYXdhaXQgdHJhbnNwb3J0LnNlbmQoZW52ZWxvcGUpOwogIGF3YWl0IHRyYW5zcG9ydC5mbHVzaCgyMDAwKTsKCiAgLy8gRGVsYXkgZm9yIDUgc2Vjb25kcyBzbyB0aGF0IHN0ZGlvIGNhbiBmbHVzaCBpZiB0aGUgbWFpbiBldmVudCBsb29wIGV2ZXIgcmVzdGFydHMuCiAgLy8gVGhpcyBpcyBtYWlubHkgZm9yIHRoZSBiZW5lZml0IG9mIGxvZ2dpbmcgb3IgZGVidWdnaW5nLgogIHNldFRpbWVvdXQoKCkgPT4gewogICAgcHJvY2Vzcy5leGl0KDApOwogIH0sIDUwMDApOwp9CgpsZXQgZGVidWdnZXJQYXVzZTsKCmlmIChvcHRpb25zLmNhcHR1cmVTdGFja1RyYWNlKSB7CiAgbG9nKCdDb25uZWN0aW5nIHRvIGRlYnVnZ2VyJyk7CgogIGNvbnN0IHNlc3Npb24gPSBuZXcgU2Vzc2lvbigpOwogIHNlc3Npb24uY29ubmVjdFRvTWFpblRocmVhZCgpOwoKICBsb2coJ0Nvbm5lY3RlZCB0byBkZWJ1Z2dlcicpOwoKICAvLyBDb2xsZWN0IHNjcmlwdElkIC0+IHVybCBtYXAgc28gd2UgY2FuIGxvb2sgdXAgdGhlIGZpbGVuYW1lcyBsYXRlcgogIGNvbnN0IHNjcmlwdHMgPSBuZXcgTWFwKCk7CgogIHNlc3Npb24ub24oJ0RlYnVnZ2VyLnNjcmlwdFBhcnNlZCcsIGV2ZW50ID0+IHsKICAgIHNjcmlwdHMuc2V0KGV2ZW50LnBhcmFtcy5zY3JpcHRJZCwgZXZlbnQucGFyYW1zLnVybCk7CiAgfSk7CgogIHNlc3Npb24ub24oJ0RlYnVnZ2VyLnBhdXNlZCcsIGV2ZW50ID0+IHsKICAgIGlmIChldmVudC5wYXJhbXMucmVhc29uICE9PSAnb3RoZXInKSB7CiAgICAgIHJldHVybjsKICAgIH0KCiAgICB0cnkgewogICAgICBsb2coJ0RlYnVnZ2VyIHBhdXNlZCcpOwoKICAgICAgLy8gY29weSB0aGUgZnJhbWVzCiAgICAgIGNvbnN0IGNhbGxGcmFtZXMgPSBbLi4uZXZlbnQucGFyYW1zLmNhbGxGcmFtZXNdOwoKICAgICAgY29uc3QgZ2V0TW9kdWxlTmFtZSA9IG9wdGlvbnMuYXBwUm9vdFBhdGggPyBjcmVhdGVHZXRNb2R1bGVGcm9tRmlsZW5hbWUob3B0aW9ucy5hcHBSb290UGF0aCkgOiAoKSA9PiB1bmRlZmluZWQ7CiAgICAgIGNvbnN0IHN0YWNrRnJhbWVzID0gY2FsbEZyYW1lcy5tYXAoZnJhbWUgPT4KICAgICAgICBjYWxsRnJhbWVUb1N0YWNrRnJhbWUoZnJhbWUsIHNjcmlwdHMuZ2V0KGZyYW1lLmxvY2F0aW9uLnNjcmlwdElkKSwgZ2V0TW9kdWxlTmFtZSksCiAgICAgICk7CgogICAgICAvLyBFdmFsdWF0ZSBhIHNjcmlwdCBpbiB0aGUgY3VycmVudGx5IHBhdXNlZCBjb250ZXh0CiAgICAgIHNlc3Npb24ucG9zdCgKICAgICAgICAnUnVudGltZS5ldmFsdWF0ZScsCiAgICAgICAgewogICAgICAgICAgLy8gR3JhYiB0aGUgdHJhY2UgY29udGV4dCBmcm9tIHRoZSBjdXJyZW50IHNjb3BlCiAgICAgICAgICBleHByZXNzaW9uOiAnZ2xvYmFsLl9fU0VOVFJZX0dFVF9TQ09QRVNfXygpOycsCiAgICAgICAgICAvLyBEb24ndCByZS10cmlnZ2VyIHRoZSBkZWJ1Z2dlciBpZiB0aGlzIGNhdXNlcyBhbiBlcnJvcgogICAgICAgICAgc2lsZW50OiB0cnVlLAogICAgICAgICAgLy8gU2VyaWFsaXplIHRoZSByZXN1bHQgdG8ganNvbiBvdGhlcndpc2Ugb25seSBwcmltaXRpdmVzIGFyZSBzdXBwb3J0ZWQKICAgICAgICAgIHJldHVybkJ5VmFsdWU6IHRydWUsCiAgICAgICAgfSwKICAgICAgICAoZXJyLCBwYXJhbSkgPT4gewogICAgICAgICAgaWYgKGVycikgewogICAgICAgICAgICBsb2coYEVycm9yIGV4ZWN1dGluZyBzY3JpcHQ6ICcke2Vyci5tZXNzYWdlfSdgKTsKICAgICAgICAgIH0KCiAgICAgICAgICBjb25zdCBzY29wZXMgPSBwYXJhbSAmJiBwYXJhbS5yZXN1bHQgPyAocGFyYW0ucmVzdWx0LnZhbHVlICkgOiB1bmRlZmluZWQ7CgogICAgICAgICAgc2Vzc2lvbi5wb3N0KCdEZWJ1Z2dlci5yZXN1bWUnKTsKICAgICAgICAgIHNlc3Npb24ucG9zdCgnRGVidWdnZXIuZGlzYWJsZScpOwoKICAgICAgICAgIHNlbmRBbnJFdmVudChzdGFja0ZyYW1lcywgc2NvcGVzKS50aGVuKG51bGwsICgpID0+IHsKICAgICAgICAgICAgbG9nKCdTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQuJyk7CiAgICAgICAgICB9KTsKICAgICAgICB9LAogICAgICApOwogICAgfSBjYXRjaCAoZSkgewogICAgICBzZXNzaW9uLnBvc3QoJ0RlYnVnZ2VyLnJlc3VtZScpOwogICAgICBzZXNzaW9uLnBvc3QoJ0RlYnVnZ2VyLmRpc2FibGUnKTsKICAgICAgdGhyb3cgZTsKICAgIH0KICB9KTsKCiAgZGVidWdnZXJQYXVzZSA9ICgpID0+IHsKICAgIHRyeSB7CiAgICAgIHNlc3Npb24ucG9zdCgnRGVidWdnZXIuZW5hYmxlJywgKCkgPT4gewogICAgICAgIHNlc3Npb24ucG9zdCgnRGVidWdnZXIucGF1c2UnKTsKICAgICAgfSk7CiAgICB9IGNhdGNoIChfKSB7CiAgICAgIC8vCiAgICB9CiAgfTsKfQoKZnVuY3Rpb24gY3JlYXRlSHJUaW1lcigpIHsKICAvLyBUT0RPICh2OCk6IFdlIGNhbiB1c2UgcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgYWZ0ZXIgd2UgZHJvcCBub2RlIHY4CiAgbGV0IGxhc3RQb2xsID0gcHJvY2Vzcy5ocnRpbWUoKTsKCiAgcmV0dXJuIHsKICAgIGdldFRpbWVNczogKCkgPT4gewogICAgICBjb25zdCBbc2Vjb25kcywgbmFub1NlY29uZHNdID0gcHJvY2Vzcy5ocnRpbWUobGFzdFBvbGwpOwogICAgICByZXR1cm4gTWF0aC5mbG9vcihzZWNvbmRzICogMWUzICsgbmFub1NlY29uZHMgLyAxZTYpOwogICAgfSwKICAgIHJlc2V0OiAoKSA9PiB7CiAgICAgIGxhc3RQb2xsID0gcHJvY2Vzcy5ocnRpbWUoKTsKICAgIH0sCiAgfTsKfQoKZnVuY3Rpb24gd2F0Y2hkb2dUaW1lb3V0KCkgewogIGxvZygnV2F0Y2hkb2cgdGltZW91dCcpOwoKICBpZiAoZGVidWdnZXJQYXVzZSkgewogICAgbG9nKCdQYXVzaW5nIGRlYnVnZ2VyIHRvIGNhcHR1cmUgc3RhY2sgdHJhY2UnKTsKICAgIGRlYnVnZ2VyUGF1c2UoKTsKICB9IGVsc2UgewogICAgbG9nKCdDYXB0dXJpbmcgZXZlbnQgd2l0aG91dCBhIHN0YWNrIHRyYWNlJyk7CiAgICBzZW5kQW5yRXZlbnQoKS50aGVuKG51bGwsICgpID0+IHsKICAgICAgbG9nKCdTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQgb24gd2F0Y2hkb2cgdGltZW91dC4nKTsKICAgIH0pOwogIH0KfQoKY29uc3QgeyBwb2xsIH0gPSB3YXRjaGRvZ1RpbWVyKGNyZWF0ZUhyVGltZXIsIG9wdGlvbnMucG9sbEludGVydmFsLCBvcHRpb25zLmFuclRocmVzaG9sZCwgd2F0Y2hkb2dUaW1lb3V0KTsKCl9vcHRpb25hbENoYWluKFtwYXJlbnRQb3J0LCAnb3B0aW9uYWxBY2Nlc3MnLCBfNiA9PiBfNi5vbiwgJ2NhbGwnLCBfNyA9PiBfNygnbWVzc2FnZScsIChtc2cpID0+IHsKICBpZiAobXNnLnNlc3Npb24pIHsKICAgIHNlc3Npb24gPSBtYWtlU2Vzc2lvbihtc2cuc2Vzc2lvbik7CiAgfQoKICBwb2xsKCk7Cn0pXSk7';
|
|
1795
|
+
const base64WorkerScript = 'LyohIEBzZW50cnkvbm9kZSA4LjAuMC1iZXRhLjIgKGYyMTViYWIpIHwgaHR0cHM6Ly9naXRodWIuY29tL2dldHNlbnRyeS9zZW50cnktamF2YXNjcmlwdCAqLwppbXBvcnR7U2Vzc2lvbiBhcyB0fWZyb20iaW5zcGVjdG9yIjtpbXBvcnR7cGFyZW50UG9ydCBhcyBuLHdvcmtlckRhdGEgYXMgZX1mcm9tIndvcmtlcl90aHJlYWRzIjtpbXBvcnR7cG9zaXggYXMgcixzZXAgYXMgb31mcm9tInBhdGgiO2ltcG9ydCphcyBzIGZyb20ibm9kZTpodHRwIjtpbXBvcnQqYXMgaSBmcm9tIm5vZGU6aHR0cHMiO2ltcG9ydHtSZWFkYWJsZSBhcyBjfWZyb20ic3RyZWFtIjtpbXBvcnR7Y3JlYXRlR3ppcCBhcyB1fWZyb20iemxpYiI7aW1wb3J0KmFzIGEgZnJvbSJuZXQiO2ltcG9ydCphcyBmIGZyb20idGxzIjtpbXBvcnQqYXMgaCBmcm9tImh0dHAiO2NvbnN0IHA9T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztmdW5jdGlvbiBsKHQsbil7cmV0dXJuIHAuY2FsbCh0KT09PWBbb2JqZWN0ICR7bn1dYH1mdW5jdGlvbiBkKHQpe3JldHVybiBsKHQsIk9iamVjdCIpfWZ1bmN0aW9uIG0odCl7cmV0dXJuIEJvb2xlYW4odCYmdC50aGVuJiYiZnVuY3Rpb24iPT10eXBlb2YgdC50aGVuKX1mdW5jdGlvbiBnKHQsbil7dHJ5e3JldHVybiB0IGluc3RhbmNlb2Ygbn1jYXRjaCh0KXtyZXR1cm4hMX19Y29uc3QgeT1nbG9iYWxUaGlzO2Z1bmN0aW9uIGIodCxuLGUpe2NvbnN0IHI9ZXx8eSxvPXIuX19TRU5UUllfXz1yLl9fU0VOVFJZX198fHt9O3JldHVybiBvW3RdfHwob1t0XT1uKCkpfWNvbnN0IHY9eSxfPTgwO2Z1bmN0aW9uIHcodCxuKXtjb25zdCBlPXQscj1bXTtsZXQgbyxzLGksYyx1O2lmKCFlfHwhZS50YWdOYW1lKXJldHVybiIiO2lmKHYuSFRNTEVsZW1lbnQmJmUgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCYmZS5kYXRhc2V0KXtpZihlLmRhdGFzZXQuc2VudHJ5Q29tcG9uZW50KXJldHVybiBlLmRhdGFzZXQuc2VudHJ5Q29tcG9uZW50O2lmKGUuZGF0YXNldC5zZW50cnlFbGVtZW50KXJldHVybiBlLmRhdGFzZXQuc2VudHJ5RWxlbWVudH1yLnB1c2goZS50YWdOYW1lLnRvTG93ZXJDYXNlKCkpO2NvbnN0IGE9biYmbi5sZW5ndGg/bi5maWx0ZXIoKHQ9PmUuZ2V0QXR0cmlidXRlKHQpKSkubWFwKCh0PT5bdCxlLmdldEF0dHJpYnV0ZSh0KV0pKTpudWxsO2lmKGEmJmEubGVuZ3RoKWEuZm9yRWFjaCgodD0+e3IucHVzaChgWyR7dFswXX09IiR7dFsxXX0iXWApfSkpO2Vsc2UgaWYoZS5pZCYmci5wdXNoKGAjJHtlLmlkfWApLG89ZS5jbGFzc05hbWUsbyYmbChvLCJTdHJpbmciKSlmb3Iocz1vLnNwbGl0KC9ccysvKSx1PTA7dTxzLmxlbmd0aDt1Kyspci5wdXNoKGAuJHtzW3VdfWApO2NvbnN0IGY9WyJhcmlhLWxhYmVsIiwidHlwZSIsIm5hbWUiLCJ0aXRsZSIsImFsdCJdO2Zvcih1PTA7dTxmLmxlbmd0aDt1KyspaT1mW3VdLGM9ZS5nZXRBdHRyaWJ1dGUoaSksYyYmci5wdXNoKGBbJHtpfT0iJHtjfSJdYCk7cmV0dXJuIHIuam9pbigiIil9Y29uc3QgUz0idW5kZWZpbmVkIj09dHlwZW9mIF9fU0VOVFJZX0RFQlVHX198fF9fU0VOVFJZX0RFQlVHX18sJD1bImRlYnVnIiwiaW5mbyIsIndhcm4iLCJlcnJvciIsImxvZyIsImFzc2VydCIsInRyYWNlIl0sRT17fTtmdW5jdGlvbiB4KHQpe2lmKCEoImNvbnNvbGUiaW4geSkpcmV0dXJuIHQoKTtjb25zdCBuPXkuY29uc29sZSxlPXt9LHI9T2JqZWN0LmtleXMoRSk7ci5mb3JFYWNoKCh0PT57Y29uc3Qgcj1FW3RdO2VbdF09blt0XSxuW3RdPXJ9KSk7dHJ5e3JldHVybiB0KCl9ZmluYWxseXtyLmZvckVhY2goKHQ9PntuW3RdPWVbdF19KSl9fWNvbnN0IE49ZnVuY3Rpb24oKXtsZXQgdD0hMTtjb25zdCBuPXtlbmFibGU6KCk9Pnt0PSEwfSxkaXNhYmxlOigpPT57dD0hMX0saXNFbmFibGVkOigpPT50fTtyZXR1cm4gUz8kLmZvckVhY2goKGU9PntuW2VdPSguLi5uKT0+e3QmJngoKCgpPT57eS5jb25zb2xlW2VdKGBTZW50cnkgTG9nZ2VyIFske2V9XTpgLC4uLm4pfSkpfX0pKTokLmZvckVhY2goKHQ9PntuW3RdPSgpPT57fX0pKSxufSgpO2Z1bmN0aW9uIGsodCxuPSExKXtjb25zdHtob3N0OmUscGF0aDpyLHBhc3M6byxwb3J0OnMscHJvamVjdElkOmkscHJvdG9jb2w6YyxwdWJsaWNLZXk6dX09dDtyZXR1cm5gJHtjfTovLyR7dX0ke24mJm8/YDoke299YDoiIn1AJHtlfSR7cz9gOiR7c31gOiIifS8ke3I/YCR7cn0vYDpyfSR7aX1gfWNsYXNzIEMgZXh0ZW5kcyBFcnJvcntjb25zdHJ1Y3Rvcih0LG49Indhcm4iKXtzdXBlcih0KSx0aGlzLm1lc3NhZ2U9dCx0aGlzLm5hbWU9bmV3LnRhcmdldC5wcm90b3R5cGUuY29uc3RydWN0b3IubmFtZSxPYmplY3Quc2V0UHJvdG90eXBlT2YodGhpcyxuZXcudGFyZ2V0LnByb3RvdHlwZSksdGhpcy5sb2dMZXZlbD1ufX1mdW5jdGlvbiBEKHQpe2lmKGZ1bmN0aW9uKHQpe3N3aXRjaChwLmNhbGwodCkpe2Nhc2UiW29iamVjdCBFcnJvcl0iOmNhc2UiW29iamVjdCBFeGNlcHRpb25dIjpjYXNlIltvYmplY3QgRE9NRXhjZXB0aW9uXSI6cmV0dXJuITA7ZGVmYXVsdDpyZXR1cm4gZyh0LEVycm9yKX19KHQpKXJldHVybnttZXNzYWdlOnQubWVzc2FnZSxuYW1lOnQubmFtZSxzdGFjazp0LnN0YWNrLC4uLk8odCl9O2lmKG49dCwidW5kZWZpbmVkIiE9dHlwZW9mIEV2ZW50JiZnKG4sRXZlbnQpKXtjb25zdCBuPXt0eXBlOnQudHlwZSx0YXJnZXQ6VCh0LnRhcmdldCksY3VycmVudFRhcmdldDpUKHQuY3VycmVudFRhcmdldCksLi4uTyh0KX07cmV0dXJuInVuZGVmaW5lZCIhPXR5cGVvZiBDdXN0b21FdmVudCYmZyh0LEN1c3RvbUV2ZW50KSYmKG4uZGV0YWlsPXQuZGV0YWlsKSxufXJldHVybiB0O3ZhciBufWZ1bmN0aW9uIFQodCl7dHJ5e3JldHVybiBuPXQsInVuZGVmaW5lZCIhPXR5cGVvZiBFbGVtZW50JiZnKG4sRWxlbWVudCk/ZnVuY3Rpb24odCxuPXt9KXtpZighdClyZXR1cm4iPHVua25vd24+Ijt0cnl7bGV0IGU9dDtjb25zdCByPTUsbz1bXTtsZXQgcz0wLGk9MDtjb25zdCBjPSIgPiAiLHU9Yy5sZW5ndGg7bGV0IGE7Y29uc3QgZj1BcnJheS5pc0FycmF5KG4pP246bi5rZXlBdHRycyxoPSFBcnJheS5pc0FycmF5KG4pJiZuLm1heFN0cmluZ0xlbmd0aHx8Xztmb3IoO2UmJnMrKzxyJiYoYT13KGUsZiksISgiaHRtbCI9PT1hfHxzPjEmJmkrby5sZW5ndGgqdSthLmxlbmd0aD49aCkpOylvLnB1c2goYSksaSs9YS5sZW5ndGgsZT1lLnBhcmVudE5vZGU7cmV0dXJuIG8ucmV2ZXJzZSgpLmpvaW4oYyl9Y2F0Y2godCl7cmV0dXJuIjx1bmtub3duPiJ9fSh0KTpPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodCl9Y2F0Y2godCl7cmV0dXJuIjx1bmtub3duPiJ9dmFyIG59ZnVuY3Rpb24gTyh0KXtpZigib2JqZWN0Ij09dHlwZW9mIHQmJm51bGwhPT10KXtjb25zdCBuPXt9O2Zvcihjb25zdCBlIGluIHQpT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHQsZSkmJihuW2VdPXRbZV0pO3JldHVybiBufXJldHVybnt9fWZ1bmN0aW9uIGoodCl7cmV0dXJuIFIodCxuZXcgTWFwKX1mdW5jdGlvbiBSKHQsbil7aWYoZnVuY3Rpb24odCl7aWYoIWQodCkpcmV0dXJuITE7dHJ5e2NvbnN0IG49T2JqZWN0LmdldFByb3RvdHlwZU9mKHQpLmNvbnN0cnVjdG9yLm5hbWU7cmV0dXJuIW58fCJPYmplY3QiPT09bn1jYXRjaCh0KXtyZXR1cm4hMH19KHQpKXtjb25zdCBlPW4uZ2V0KHQpO2lmKHZvaWQgMCE9PWUpcmV0dXJuIGU7Y29uc3Qgcj17fTtuLnNldCh0LHIpO2Zvcihjb25zdCBlIG9mIE9iamVjdC5rZXlzKHQpKXZvaWQgMCE9PXRbZV0mJihyW2VdPVIodFtlXSxuKSk7cmV0dXJuIHJ9aWYoQXJyYXkuaXNBcnJheSh0KSl7Y29uc3QgZT1uLmdldCh0KTtpZih2b2lkIDAhPT1lKXJldHVybiBlO2NvbnN0IHI9W107cmV0dXJuIG4uc2V0KHQsciksdC5mb3JFYWNoKCh0PT57ci5wdXNoKFIodCxuKSl9KSkscn1yZXR1cm4gdH1jb25zdCBBPTUwLEk9Ij8iLFA9L2NhcHR1cmVNZXNzYWdlfGNhcHR1cmVFeGNlcHRpb24vO2NvbnN0IFU9Ijxhbm9ueW1vdXM+IjtmdW5jdGlvbiBNKCl7Y29uc3QgdD15LG49dC5jcnlwdG98fHQubXNDcnlwdG87bGV0IGU9KCk9PjE2Kk1hdGgucmFuZG9tKCk7dHJ5e2lmKG4mJm4ucmFuZG9tVVVJRClyZXR1cm4gbi5yYW5kb21VVUlEKCkucmVwbGFjZSgvLS9nLCIiKTtuJiZuLmdldFJhbmRvbVZhbHVlcyYmKGU9KCk9Pntjb25zdCB0PW5ldyBVaW50OEFycmF5KDEpO3JldHVybiBuLmdldFJhbmRvbVZhbHVlcyh0KSx0WzBdfSl9Y2F0Y2godCl7fXJldHVybihbMWU3XSsxZTMrNGUzKzhlMysxZTExKS5yZXBsYWNlKC9bMDE4XS9nLCh0PT4odF4oMTUmZSgpKT4+dC80KS50b1N0cmluZygxNikpKX1mdW5jdGlvbiBMKHQsbj0xMDAsZT0xLzApe3RyeXtyZXR1cm4gQigiIix0LG4sZSl9Y2F0Y2godCl7cmV0dXJue0VSUk9SOmAqKm5vbi1zZXJpYWxpemFibGUqKiAoJHt0fSlgfX19ZnVuY3Rpb24gQih0LG4sZT0xLzAscj0xLzAsbz1mdW5jdGlvbigpe2NvbnN0IHQ9ImZ1bmN0aW9uIj09dHlwZW9mIFdlYWtTZXQsbj10P25ldyBXZWFrU2V0OltdO3JldHVybltmdW5jdGlvbihlKXtpZih0KXJldHVybiEhbi5oYXMoZSl8fChuLmFkZChlKSwhMSk7Zm9yKGxldCB0PTA7dDxuLmxlbmd0aDt0KyspaWYoblt0XT09PWUpcmV0dXJuITA7cmV0dXJuIG4ucHVzaChlKSwhMX0sZnVuY3Rpb24oZSl7aWYodCluLmRlbGV0ZShlKTtlbHNlIGZvcihsZXQgdD0wO3Q8bi5sZW5ndGg7dCsrKWlmKG5bdF09PT1lKXtuLnNwbGljZSh0LDEpO2JyZWFrfX1dfSgpKXtjb25zdFtzLGldPW87aWYobnVsbD09bnx8WyJudW1iZXIiLCJib29sZWFuIiwic3RyaW5nIl0uaW5jbHVkZXModHlwZW9mIG4pJiYhTnVtYmVyLmlzTmFOKG4pKXJldHVybiBuO2NvbnN0IGM9ZnVuY3Rpb24odCxuKXt0cnl7aWYoImRvbWFpbiI9PT10JiZuJiYib2JqZWN0Ij09dHlwZW9mIG4mJm4udClyZXR1cm4iW0RvbWFpbl0iO2lmKCJkb21haW5FbWl0dGVyIj09PXQpcmV0dXJuIltEb21haW5FbWl0dGVyXSI7aWYoInVuZGVmaW5lZCIhPXR5cGVvZiBnbG9iYWwmJm49PT1nbG9iYWwpcmV0dXJuIltHbG9iYWxdIjtpZigidW5kZWZpbmVkIiE9dHlwZW9mIHdpbmRvdyYmbj09PXdpbmRvdylyZXR1cm4iW1dpbmRvd10iO2lmKCJ1bmRlZmluZWQiIT10eXBlb2YgZG9jdW1lbnQmJm49PT1kb2N1bWVudClyZXR1cm4iW0RvY3VtZW50XSI7aWYoIm9iamVjdCI9PXR5cGVvZihlPW4pJiZudWxsIT09ZSYmKGUuX19pc1Z1ZXx8ZS5vKSlyZXR1cm4iW1Z1ZVZpZXdNb2RlbF0iO2lmKGZ1bmN0aW9uKHQpe3JldHVybiBkKHQpJiYibmF0aXZlRXZlbnQiaW4gdCYmInByZXZlbnREZWZhdWx0ImluIHQmJiJzdG9wUHJvcGFnYXRpb24iaW4gdH0obikpcmV0dXJuIltTeW50aGV0aWNFdmVudF0iO2lmKCJudW1iZXIiPT10eXBlb2YgbiYmbiE9bilyZXR1cm4iW05hTl0iO2lmKCJmdW5jdGlvbiI9PXR5cGVvZiBuKXJldHVybmBbRnVuY3Rpb246ICR7ZnVuY3Rpb24odCl7dHJ5e3JldHVybiB0JiYiZnVuY3Rpb24iPT10eXBlb2YgdCYmdC5uYW1lfHxVfWNhdGNoKHQpe3JldHVybiBVfX0obil9XWA7aWYoInN5bWJvbCI9PXR5cGVvZiBuKXJldHVybmBbJHtTdHJpbmcobil9XWA7aWYoImJpZ2ludCI9PXR5cGVvZiBuKXJldHVybmBbQmlnSW50OiAke1N0cmluZyhuKX1dYDtjb25zdCByPWZ1bmN0aW9uKHQpe2NvbnN0IG49T2JqZWN0LmdldFByb3RvdHlwZU9mKHQpO3JldHVybiBuP24uY29uc3RydWN0b3IubmFtZToibnVsbCBwcm90b3R5cGUifShuKTtyZXR1cm4vXkhUTUwoXHcqKUVsZW1lbnQkLy50ZXN0KHIpP2BbSFRNTEVsZW1lbnQ6ICR7cn1dYDpgW29iamVjdCAke3J9XWB9Y2F0Y2godCl7cmV0dXJuYCoqbm9uLXNlcmlhbGl6YWJsZSoqICgke3R9KWB9dmFyIGV9KHQsbik7aWYoIWMuc3RhcnRzV2l0aCgiW29iamVjdCAiKSlyZXR1cm4gYztpZihuLl9fc2VudHJ5X3NraXBfbm9ybWFsaXphdGlvbl9fKXJldHVybiBuO2NvbnN0IHU9Im51bWJlciI9PXR5cGVvZiBuLl9fc2VudHJ5X292ZXJyaWRlX25vcm1hbGl6YXRpb25fZGVwdGhfXz9uLl9fc2VudHJ5X292ZXJyaWRlX25vcm1hbGl6YXRpb25fZGVwdGhfXzplO2lmKDA9PT11KXJldHVybiBjLnJlcGxhY2UoIm9iamVjdCAiLCIiKTtpZihzKG4pKXJldHVybiJbQ2lyY3VsYXIgfl0iO2NvbnN0IGE9bjtpZihhJiYiZnVuY3Rpb24iPT10eXBlb2YgYS50b0pTT04pdHJ5e3JldHVybiBCKCIiLGEudG9KU09OKCksdS0xLHIsbyl9Y2F0Y2godCl7fWNvbnN0IGY9QXJyYXkuaXNBcnJheShuKT9bXTp7fTtsZXQgaD0wO2NvbnN0IHA9RChuKTtmb3IoY29uc3QgdCBpbiBwKXtpZighT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHAsdCkpY29udGludWU7aWYoaD49cil7Zlt0XT0iW01heFByb3BlcnRpZXMgfl0iO2JyZWFrfWNvbnN0IG49cFt0XTtmW3RdPUIodCxuLHUtMSxyLG8pLGgrK31yZXR1cm4gaShuKSxmfWZ1bmN0aW9uIEcodCxuKXtjb25zdCBlPW4ucmVwbGFjZSgvXFwvZywiLyIpLnJlcGxhY2UoL1t8XFx7fSgpW1xdXiQrKj8uXS9nLCJcXCQmIik7bGV0IHI9dDt0cnl7cj1kZWNvZGVVUkkodCl9Y2F0Y2godCl7fXJldHVybiByLnJlcGxhY2UoL1xcL2csIi8iKS5yZXBsYWNlKC93ZWJwYWNrOlwvPy9nLCIiKS5yZXBsYWNlKG5ldyBSZWdFeHAoYChmaWxlOi8vKT8vKiR7ZX0vKmAsImlnIiksImFwcDovLy8iKX1jb25zdCBKPS9eKFxTKzpcXHxcLz8pKFtcc1xTXSo/KSgoPzpcLnsxLDJ9fFteL1xcXSs/fCkoXC5bXi4vXFxdKnwpKSg/OlsvXFxdKikkLztmdW5jdGlvbiB6KHQpe2NvbnN0IG49ZnVuY3Rpb24odCl7Y29uc3Qgbj10Lmxlbmd0aD4xMDI0P2A8dHJ1bmNhdGVkPiR7dC5zbGljZSgtMTAyNCl9YDp0LGU9Si5leGVjKG4pO3JldHVybiBlP2Uuc2xpY2UoMSk6W119KHQpLGU9blswXTtsZXQgcj1uWzFdO3JldHVybiBlfHxyPyhyJiYocj1yLnNsaWNlKDAsci5sZW5ndGgtMSkpLGUrcik6Ii4ifXZhciBIO2Z1bmN0aW9uIFcodCl7cmV0dXJuIG5ldyBZKChuPT57bih0KX0pKX0hZnVuY3Rpb24odCl7dFt0LlBFTkRJTkc9MF09IlBFTkRJTkciO3RbdC5SRVNPTFZFRD0xXT0iUkVTT0xWRUQiO3RbdC5SRUpFQ1RFRD0yXT0iUkVKRUNURUQifShIfHwoSD17fSkpO2NsYXNzIFl7Y29uc3RydWN0b3IodCl7WS5wcm90b3R5cGUuX19pbml0LmNhbGwodGhpcyksWS5wcm90b3R5cGUuX19pbml0Mi5jYWxsKHRoaXMpLFkucHJvdG90eXBlLl9faW5pdDMuY2FsbCh0aGlzKSxZLnByb3RvdHlwZS5fX2luaXQ0LmNhbGwodGhpcyksdGhpcy5pPUguUEVORElORyx0aGlzLnU9W107dHJ5e3QodGhpcy5oLHRoaXMucCl9Y2F0Y2godCl7dGhpcy5wKHQpfX10aGVuKHQsbil7cmV0dXJuIG5ldyBZKCgoZSxyKT0+e3RoaXMudS5wdXNoKFshMSxuPT57aWYodCl0cnl7ZSh0KG4pKX1jYXRjaCh0KXtyKHQpfWVsc2UgZShuKX0sdD0+e2lmKG4pdHJ5e2Uobih0KSl9Y2F0Y2godCl7cih0KX1lbHNlIHIodCl9XSksdGhpcy5sKCl9KSl9Y2F0Y2godCl7cmV0dXJuIHRoaXMudGhlbigodD0+dCksdCl9ZmluYWxseSh0KXtyZXR1cm4gbmV3IFkoKChuLGUpPT57bGV0IHIsbztyZXR1cm4gdGhpcy50aGVuKChuPT57bz0hMSxyPW4sdCYmdCgpfSksKG49PntvPSEwLHI9bix0JiZ0KCl9KSkudGhlbigoKCk9PntvP2Uocik6bihyKX0pKX0pKX1fX2luaXQoKXt0aGlzLmg9dD0+e3RoaXMubShILlJFU09MVkVELHQpfX1fX2luaXQyKCl7dGhpcy5wPXQ9Pnt0aGlzLm0oSC5SRUpFQ1RFRCx0KX19X19pbml0Mygpe3RoaXMubT0odCxuKT0+e3RoaXMuaT09PUguUEVORElORyYmKG0obik/bi50aGVuKHRoaXMuaCx0aGlzLnApOih0aGlzLmk9dCx0aGlzLnY9bix0aGlzLmwoKSkpfX1fX2luaXQ0KCl7dGhpcy5sPSgpPT57aWYodGhpcy5pPT09SC5QRU5ESU5HKXJldHVybjtjb25zdCB0PXRoaXMudS5zbGljZSgpO3RoaXMudT1bXSx0LmZvckVhY2goKHQ9Pnt0WzBdfHwodGhpcy5pPT09SC5SRVNPTFZFRCYmdFsxXSh0aGlzLnYpLHRoaXMuaT09PUguUkVKRUNURUQmJnRbMl0odGhpcy52KSx0WzBdPSEwKX0pKX19fWZ1bmN0aW9uIHEodCl7Y29uc3Qgbj1bXTtmdW5jdGlvbiBlKHQpe3JldHVybiBuLnNwbGljZShuLmluZGV4T2YodCksMSlbMF19cmV0dXJueyQ6bixhZGQ6ZnVuY3Rpb24ocil7aWYoISh2b2lkIDA9PT10fHxuLmxlbmd0aDx0KSlyZXR1cm4gbz1uZXcgQygiTm90IGFkZGluZyBQcm9taXNlIGJlY2F1c2UgYnVmZmVyIGxpbWl0IHdhcyByZWFjaGVkLiIpLG5ldyBZKCgodCxuKT0+e24obyl9KSk7dmFyIG87Y29uc3Qgcz1yKCk7cmV0dXJuLTE9PT1uLmluZGV4T2YocykmJm4ucHVzaChzKSxzLnRoZW4oKCgpPT5lKHMpKSkudGhlbihudWxsLCgoKT0+ZShzKS50aGVuKG51bGwsKCgpPT57fSkpKSksc30sZHJhaW46ZnVuY3Rpb24odCl7cmV0dXJuIG5ldyBZKCgoZSxyKT0+e2xldCBvPW4ubGVuZ3RoO2lmKCFvKXJldHVybiBlKCEwKTtjb25zdCBzPXNldFRpbWVvdXQoKCgpPT57dCYmdD4wJiZlKCExKX0pLHQpO24uZm9yRWFjaCgodD0+e1codCkudGhlbigoKCk9PnstLW98fChjbGVhclRpbWVvdXQocyksZSghMCkpfSkscil9KSl9KSl9fX1mdW5jdGlvbiBGKHQsbj0hMSl7cmV0dXJuIShufHx0JiYhdC5zdGFydHNXaXRoKCIvIikmJiF0Lm1hdGNoKC9eW0EtWl06LykmJiF0LnN0YXJ0c1dpdGgoIi4iKSYmIXQubWF0Y2goL15bYS16QS1aXShbYS16QS1aMC05LlwtK10pKjpcL1wvLykpJiZ2b2lkIDAhPT10JiYhdC5pbmNsdWRlcygibm9kZV9tb2R1bGVzLyIpfWNvbnN0IEs9MWUzO2Z1bmN0aW9uIFYoKXtyZXR1cm4gRGF0ZS5ub3coKS9LfWNvbnN0IFo9ZnVuY3Rpb24oKXtjb25zdHtwZXJmb3JtYW5jZTp0fT15O2lmKCF0fHwhdC5ub3cpcmV0dXJuIFY7Y29uc3Qgbj1EYXRlLm5vdygpLXQubm93KCksZT1udWxsPT10LnRpbWVPcmlnaW4/bjp0LnRpbWVPcmlnaW47cmV0dXJuKCk9PihlK3Qubm93KCkpL0t9KCk7ZnVuY3Rpb24gUSh0LG49W10pe3JldHVyblt0LG5dfWZ1bmN0aW9uIFgodCxuKXtjb25zdCBlPXRbMV07Zm9yKGNvbnN0IHQgb2YgZSl7aWYobih0LHRbMF0udHlwZSkpcmV0dXJuITB9cmV0dXJuITF9ZnVuY3Rpb24gdHQodCl7cmV0dXJuIHkuX19TRU5UUllfXyYmeS5fX1NFTlRSWV9fLmVuY29kZVBvbHlmaWxsP3kuX19TRU5UUllfXy5lbmNvZGVQb2x5ZmlsbCh0KToobmV3IFRleHRFbmNvZGVyKS5lbmNvZGUodCl9ZnVuY3Rpb24gbnQodCl7Y29uc3RbbixlXT10O2xldCByPUpTT04uc3RyaW5naWZ5KG4pO2Z1bmN0aW9uIG8odCl7InN0cmluZyI9PXR5cGVvZiByP3I9InN0cmluZyI9PXR5cGVvZiB0P3IrdDpbdHQociksdF06ci5wdXNoKCJzdHJpbmciPT10eXBlb2YgdD90dCh0KTp0KX1mb3IoY29uc3QgdCBvZiBlKXtjb25zdFtuLGVdPXQ7aWYobyhgXG4ke0pTT04uc3RyaW5naWZ5KG4pfVxuYCksInN0cmluZyI9PXR5cGVvZiBlfHxlIGluc3RhbmNlb2YgVWludDhBcnJheSlvKGUpO2Vsc2V7bGV0IHQ7dHJ5e3Q9SlNPTi5zdHJpbmdpZnkoZSl9Y2F0Y2gobil7dD1KU09OLnN0cmluZ2lmeShMKGUpKX1vKHQpfX1yZXR1cm4ic3RyaW5nIj09dHlwZW9mIHI/cjpmdW5jdGlvbih0KXtjb25zdCBuPXQucmVkdWNlKCgodCxuKT0+dCtuLmxlbmd0aCksMCksZT1uZXcgVWludDhBcnJheShuKTtsZXQgcj0wO2Zvcihjb25zdCBuIG9mIHQpZS5zZXQobixyKSxyKz1uLmxlbmd0aDtyZXR1cm4gZX0ocil9KCgpPT57Y29uc3R7cGVyZm9ybWFuY2U6dH09eTtpZighdHx8IXQubm93KXJldHVybjtjb25zdCBuPTM2ZTUsZT10Lm5vdygpLHI9RGF0ZS5ub3coKSxvPXQudGltZU9yaWdpbj9NYXRoLmFicyh0LnRpbWVPcmlnaW4rZS1yKTpuLHM9bzxuLGk9dC50aW1pbmcmJnQudGltaW5nLm5hdmlnYXRpb25TdGFydCxjPSJudW1iZXIiPT10eXBlb2YgaT9NYXRoLmFicyhpK2Utcik6bjsoc3x8YzxuKSYmKG88PWMmJnQudGltZU9yaWdpbil9KSgpO2NvbnN0IGV0PXtzZXNzaW9uOiJzZXNzaW9uIixzZXNzaW9uczoic2Vzc2lvbiIsYXR0YWNobWVudDoiYXR0YWNobWVudCIsdHJhbnNhY3Rpb246InRyYW5zYWN0aW9uIixldmVudDoiZXJyb3IiLGNsaWVudF9yZXBvcnQ6ImludGVybmFsIix1c2VyX3JlcG9ydDoiZGVmYXVsdCIscHJvZmlsZToicHJvZmlsZSIscmVwbGF5X2V2ZW50OiJyZXBsYXkiLHJlcGxheV9yZWNvcmRpbmc6InJlcGxheSIsY2hlY2tfaW46Im1vbml0b3IiLGZlZWRiYWNrOiJmZWVkYmFjayIsc3Bhbjoic3BhbiIsc3RhdHNkOiJtZXRyaWNfYnVja2V0In07ZnVuY3Rpb24gcnQodCl7cmV0dXJuIGV0W3RdfWZ1bmN0aW9uIG90KHQpe2lmKCF0fHwhdC5zZGspcmV0dXJuO2NvbnN0e25hbWU6bix2ZXJzaW9uOmV9PXQuc2RrO3JldHVybntuYW1lOm4sdmVyc2lvbjplfX1jb25zdCBzdD02ZTQ7ZnVuY3Rpb24gaXQodCx7c3RhdHVzQ29kZTpuLGhlYWRlcnM6ZX0scj1EYXRlLm5vdygpKXtjb25zdCBvPXsuLi50fSxzPWUmJmVbIngtc2VudHJ5LXJhdGUtbGltaXRzIl0saT1lJiZlWyJyZXRyeS1hZnRlciJdO2lmKHMpZm9yKGNvbnN0IHQgb2Ygcy50cmltKCkuc3BsaXQoIiwiKSl7Y29uc3RbbixlLCwsc109dC5zcGxpdCgiOiIsNSksaT1wYXJzZUludChuLDEwKSxjPTFlMyooaXNOYU4oaSk/NjA6aSk7aWYoZSlmb3IoY29uc3QgdCBvZiBlLnNwbGl0KCI7IikpIm1ldHJpY19idWNrZXQiPT09dCYmcyYmIXMuc3BsaXQoIjsiKS5pbmNsdWRlcygiY3VzdG9tIil8fChvW3RdPXIrYyk7ZWxzZSBvLmFsbD1yK2N9ZWxzZSBpP28uYWxsPXIrZnVuY3Rpb24odCxuPURhdGUubm93KCkpe2NvbnN0IGU9cGFyc2VJbnQoYCR7dH1gLDEwKTtpZighaXNOYU4oZSkpcmV0dXJuIDFlMyplO2NvbnN0IHI9RGF0ZS5wYXJzZShgJHt0fWApO3JldHVybiBpc05hTihyKT9zdDpyLW59KGkscik6NDI5PT09biYmKG8uYWxsPXIrNmU0KTtyZXR1cm4gb31jb25zdCBjdD0idW5kZWZpbmVkIj09dHlwZW9mIF9fU0VOVFJZX0RFQlVHX198fF9fU0VOVFJZX0RFQlVHX187ZnVuY3Rpb24gdXQoKXtyZXR1cm4gYXQoeSkseX1mdW5jdGlvbiBhdCh0KXtyZXR1cm4gdC5fX1NFTlRSWV9ffHwodC5fX1NFTlRSWV9fPXtleHRlbnNpb25zOnt9fSksdC5fX1NFTlRSWV9ffWZ1bmN0aW9uIGZ0KHQpe2NvbnN0IG49WigpLGU9e3NpZDpNKCksaW5pdDohMCx0aW1lc3RhbXA6bixzdGFydGVkOm4sZHVyYXRpb246MCxzdGF0dXM6Im9rIixlcnJvcnM6MCxpZ25vcmVEdXJhdGlvbjohMSx0b0pTT046KCk9PmZ1bmN0aW9uKHQpe3JldHVybiBqKHtzaWQ6YCR7dC5zaWR9YCxpbml0OnQuaW5pdCxzdGFydGVkOm5ldyBEYXRlKDFlMyp0LnN0YXJ0ZWQpLnRvSVNPU3RyaW5nKCksdGltZXN0YW1wOm5ldyBEYXRlKDFlMyp0LnRpbWVzdGFtcCkudG9JU09TdHJpbmcoKSxzdGF0dXM6dC5zdGF0dXMsZXJyb3JzOnQuZXJyb3JzLGRpZDoibnVtYmVyIj09dHlwZW9mIHQuZGlkfHwic3RyaW5nIj09dHlwZW9mIHQuZGlkP2Ake3QuZGlkfWA6dm9pZCAwLGR1cmF0aW9uOnQuZHVyYXRpb24sYWJub3JtYWxfbWVjaGFuaXNtOnQuYWJub3JtYWxfbWVjaGFuaXNtLGF0dHJzOntyZWxlYXNlOnQucmVsZWFzZSxlbnZpcm9ubWVudDp0LmVudmlyb25tZW50LGlwX2FkZHJlc3M6dC5pcEFkZHJlc3MsdXNlcl9hZ2VudDp0LnVzZXJBZ2VudH19KX0oZSl9O3JldHVybiB0JiZodChlLHQpLGV9ZnVuY3Rpb24gaHQodCxuPXt9KXtpZihuLnVzZXImJighdC5pcEFkZHJlc3MmJm4udXNlci5pcF9hZGRyZXNzJiYodC5pcEFkZHJlc3M9bi51c2VyLmlwX2FkZHJlc3MpLHQuZGlkfHxuLmRpZHx8KHQuZGlkPW4udXNlci5pZHx8bi51c2VyLmVtYWlsfHxuLnVzZXIudXNlcm5hbWUpKSx0LnRpbWVzdGFtcD1uLnRpbWVzdGFtcHx8WigpLG4uYWJub3JtYWxfbWVjaGFuaXNtJiYodC5hYm5vcm1hbF9tZWNoYW5pc209bi5hYm5vcm1hbF9tZWNoYW5pc20pLG4uaWdub3JlRHVyYXRpb24mJih0Lmlnbm9yZUR1cmF0aW9uPW4uaWdub3JlRHVyYXRpb24pLG4uc2lkJiYodC5zaWQ9MzI9PT1uLnNpZC5sZW5ndGg/bi5zaWQ6TSgpKSx2b2lkIDAhPT1uLmluaXQmJih0LmluaXQ9bi5pbml0KSwhdC5kaWQmJm4uZGlkJiYodC5kaWQ9YCR7bi5kaWR9YCksIm51bWJlciI9PXR5cGVvZiBuLnN0YXJ0ZWQmJih0LnN0YXJ0ZWQ9bi5zdGFydGVkKSx0Lmlnbm9yZUR1cmF0aW9uKXQuZHVyYXRpb249dm9pZCAwO2Vsc2UgaWYoIm51bWJlciI9PXR5cGVvZiBuLmR1cmF0aW9uKXQuZHVyYXRpb249bi5kdXJhdGlvbjtlbHNle2NvbnN0IG49dC50aW1lc3RhbXAtdC5zdGFydGVkO3QuZHVyYXRpb249bj49MD9uOjB9bi5yZWxlYXNlJiYodC5yZWxlYXNlPW4ucmVsZWFzZSksbi5lbnZpcm9ubWVudCYmKHQuZW52aXJvbm1lbnQ9bi5lbnZpcm9ubWVudCksIXQuaXBBZGRyZXNzJiZuLmlwQWRkcmVzcyYmKHQuaXBBZGRyZXNzPW4uaXBBZGRyZXNzKSwhdC51c2VyQWdlbnQmJm4udXNlckFnZW50JiYodC51c2VyQWdlbnQ9bi51c2VyQWdlbnQpLCJudW1iZXIiPT10eXBlb2Ygbi5lcnJvcnMmJih0LmVycm9ycz1uLmVycm9ycyksbi5zdGF0dXMmJih0LnN0YXR1cz1uLnN0YXR1cyl9Y29uc3QgcHQ9Il9zZW50cnlTcGFuIjtmdW5jdGlvbiBsdCh0LG4pe24/ZnVuY3Rpb24odCxuLGUpe3RyeXtPYmplY3QuZGVmaW5lUHJvcGVydHkodCxuLHt2YWx1ZTplLHdyaXRhYmxlOiEwLGNvbmZpZ3VyYWJsZTohMH0pfWNhdGNoKGUpe1MmJk4ubG9nKGBGYWlsZWQgdG8gYWRkIG5vbi1lbnVtZXJhYmxlIHByb3BlcnR5ICIke259IiB0byBvYmplY3RgLHQpfX0odCxwdCxuKTpkZWxldGUgdFtwdF19ZnVuY3Rpb24gZHQodCl7cmV0dXJuIHRbcHRdfWNsYXNzIG10e2NvbnN0cnVjdG9yKCl7dGhpcy5fPSExLHRoaXMuUz1bXSx0aGlzLk49W10sdGhpcy5rPVtdLHRoaXMuQz1bXSx0aGlzLkQ9e30sdGhpcy5UPXt9LHRoaXMuTz17fSx0aGlzLmo9e30sdGhpcy5SPXt9LHRoaXMuQT1ndCgpfWNsb25lKCl7Y29uc3QgdD1uZXcgbXQ7cmV0dXJuIHQuaz1bLi4udGhpcy5rXSx0LlQ9ey4uLnRoaXMuVH0sdC5PPXsuLi50aGlzLk99LHQuaj17Li4udGhpcy5qfSx0LkQ9dGhpcy5ELHQuST10aGlzLkksdC5QPXRoaXMuUCx0LlU9dGhpcy5VLHQuTT10aGlzLk0sdC5OPVsuLi50aGlzLk5dLHQuTD10aGlzLkwsdC5DPVsuLi50aGlzLkNdLHQuUj17Li4udGhpcy5SfSx0LkE9ey4uLnRoaXMuQX0sdC5CPXRoaXMuQixsdCh0LGR0KHRoaXMpKSx0fXNldENsaWVudCh0KXt0aGlzLkI9dH1nZXRDbGllbnQoKXtyZXR1cm4gdGhpcy5CfWFkZFNjb3BlTGlzdGVuZXIodCl7dGhpcy5TLnB1c2godCl9YWRkRXZlbnRQcm9jZXNzb3IodCl7cmV0dXJuIHRoaXMuTi5wdXNoKHQpLHRoaXN9c2V0VXNlcih0KXtyZXR1cm4gdGhpcy5EPXR8fHtlbWFpbDp2b2lkIDAsaWQ6dm9pZCAwLGlwX2FkZHJlc3M6dm9pZCAwLHVzZXJuYW1lOnZvaWQgMH0sdGhpcy5QJiZodCh0aGlzLlAse3VzZXI6dH0pLHRoaXMuRygpLHRoaXN9Z2V0VXNlcigpe3JldHVybiB0aGlzLkR9Z2V0UmVxdWVzdFNlc3Npb24oKXtyZXR1cm4gdGhpcy5MfXNldFJlcXVlc3RTZXNzaW9uKHQpe3JldHVybiB0aGlzLkw9dCx0aGlzfXNldFRhZ3ModCl7cmV0dXJuIHRoaXMuVD17Li4udGhpcy5ULC4uLnR9LHRoaXMuRygpLHRoaXN9c2V0VGFnKHQsbil7cmV0dXJuIHRoaXMuVD17Li4udGhpcy5ULFt0XTpufSx0aGlzLkcoKSx0aGlzfXNldEV4dHJhcyh0KXtyZXR1cm4gdGhpcy5PPXsuLi50aGlzLk8sLi4udH0sdGhpcy5HKCksdGhpc31zZXRFeHRyYSh0LG4pe3JldHVybiB0aGlzLk89ey4uLnRoaXMuTyxbdF06bn0sdGhpcy5HKCksdGhpc31zZXRGaW5nZXJwcmludCh0KXtyZXR1cm4gdGhpcy5NPXQsdGhpcy5HKCksdGhpc31zZXRMZXZlbCh0KXtyZXR1cm4gdGhpcy5JPXQsdGhpcy5HKCksdGhpc31zZXRUcmFuc2FjdGlvbk5hbWUodCl7cmV0dXJuIHRoaXMuVT10LHRoaXMuRygpLHRoaXN9c2V0Q29udGV4dCh0LG4pe3JldHVybiBudWxsPT09bj9kZWxldGUgdGhpcy5qW3RdOnRoaXMualt0XT1uLHRoaXMuRygpLHRoaXN9c2V0U2Vzc2lvbih0KXtyZXR1cm4gdD90aGlzLlA9dDpkZWxldGUgdGhpcy5QLHRoaXMuRygpLHRoaXN9Z2V0U2Vzc2lvbigpe3JldHVybiB0aGlzLlB9dXBkYXRlKHQpe2lmKCF0KXJldHVybiB0aGlzO2NvbnN0IG49ImZ1bmN0aW9uIj09dHlwZW9mIHQ/dCh0aGlzKTp0LFtlLHJdPW4gaW5zdGFuY2VvZiBtdD9bbi5nZXRTY29wZURhdGEoKSxuLmdldFJlcXVlc3RTZXNzaW9uKCldOmQobik/W3QsdC5yZXF1ZXN0U2Vzc2lvbl06W10se3RhZ3M6byxleHRyYTpzLHVzZXI6aSxjb250ZXh0czpjLGxldmVsOnUsZmluZ2VycHJpbnQ6YT1bXSxwcm9wYWdhdGlvbkNvbnRleHQ6Zn09ZXx8e307cmV0dXJuIHRoaXMuVD17Li4udGhpcy5ULC4uLm99LHRoaXMuTz17Li4udGhpcy5PLC4uLnN9LHRoaXMuaj17Li4udGhpcy5qLC4uLmN9LGkmJk9iamVjdC5rZXlzKGkpLmxlbmd0aCYmKHRoaXMuRD1pKSx1JiYodGhpcy5JPXUpLGEubGVuZ3RoJiYodGhpcy5NPWEpLGYmJih0aGlzLkE9ZiksciYmKHRoaXMuTD1yKSx0aGlzfWNsZWFyKCl7cmV0dXJuIHRoaXMuaz1bXSx0aGlzLlQ9e30sdGhpcy5PPXt9LHRoaXMuRD17fSx0aGlzLmo9e30sdGhpcy5JPXZvaWQgMCx0aGlzLlU9dm9pZCAwLHRoaXMuTT12b2lkIDAsdGhpcy5MPXZvaWQgMCx0aGlzLlA9dm9pZCAwLGx0KHRoaXMsdm9pZCAwKSx0aGlzLkM9W10sdGhpcy5BPWd0KCksdGhpcy5HKCksdGhpc31hZGRCcmVhZGNydW1iKHQsbil7Y29uc3QgZT0ibnVtYmVyIj09dHlwZW9mIG4/bjoxMDA7aWYoZTw9MClyZXR1cm4gdGhpcztjb25zdCByPXt0aW1lc3RhbXA6VigpLC4uLnR9LG89dGhpcy5rO3JldHVybiBvLnB1c2gociksdGhpcy5rPW8ubGVuZ3RoPmU/by5zbGljZSgtZSk6byx0aGlzLkcoKSx0aGlzfWdldExhc3RCcmVhZGNydW1iKCl7cmV0dXJuIHRoaXMua1t0aGlzLmsubGVuZ3RoLTFdfWNsZWFyQnJlYWRjcnVtYnMoKXtyZXR1cm4gdGhpcy5rPVtdLHRoaXMuRygpLHRoaXN9YWRkQXR0YWNobWVudCh0KXtyZXR1cm4gdGhpcy5DLnB1c2godCksdGhpc31jbGVhckF0dGFjaG1lbnRzKCl7cmV0dXJuIHRoaXMuQz1bXSx0aGlzfWdldFNjb3BlRGF0YSgpe3JldHVybnticmVhZGNydW1iczp0aGlzLmssYXR0YWNobWVudHM6dGhpcy5DLGNvbnRleHRzOnRoaXMuaix0YWdzOnRoaXMuVCxleHRyYTp0aGlzLk8sdXNlcjp0aGlzLkQsbGV2ZWw6dGhpcy5JLGZpbmdlcnByaW50OnRoaXMuTXx8W10sZXZlbnRQcm9jZXNzb3JzOnRoaXMuTixwcm9wYWdhdGlvbkNvbnRleHQ6dGhpcy5BLHNka1Byb2Nlc3NpbmdNZXRhZGF0YTp0aGlzLlIsdHJhbnNhY3Rpb25OYW1lOnRoaXMuVSxzcGFuOmR0KHRoaXMpfX1zZXRTREtQcm9jZXNzaW5nTWV0YWRhdGEodCl7cmV0dXJuIHRoaXMuUj17Li4udGhpcy5SLC4uLnR9LHRoaXN9c2V0UHJvcGFnYXRpb25Db250ZXh0KHQpe3JldHVybiB0aGlzLkE9dCx0aGlzfWdldFByb3BhZ2F0aW9uQ29udGV4dCgpe3JldHVybiB0aGlzLkF9Y2FwdHVyZUV4Y2VwdGlvbih0LG4pe2NvbnN0IGU9biYmbi5ldmVudF9pZD9uLmV2ZW50X2lkOk0oKTtpZighdGhpcy5CKXJldHVybiBOLndhcm4oIk5vIGNsaWVudCBjb25maWd1cmVkIG9uIHNjb3BlIC0gd2lsbCBub3QgY2FwdHVyZSBleGNlcHRpb24hIiksZTtjb25zdCByPW5ldyBFcnJvcigiU2VudHJ5IHN5bnRoZXRpY0V4Y2VwdGlvbiIpO3JldHVybiB0aGlzLkIuY2FwdHVyZUV4Y2VwdGlvbih0LHtvcmlnaW5hbEV4Y2VwdGlvbjp0LHN5bnRoZXRpY0V4Y2VwdGlvbjpyLC4uLm4sZXZlbnRfaWQ6ZX0sdGhpcyksZX1jYXB0dXJlTWVzc2FnZSh0LG4sZSl7Y29uc3Qgcj1lJiZlLmV2ZW50X2lkP2UuZXZlbnRfaWQ6TSgpO2lmKCF0aGlzLkIpcmV0dXJuIE4ud2FybigiTm8gY2xpZW50IGNvbmZpZ3VyZWQgb24gc2NvcGUgLSB3aWxsIG5vdCBjYXB0dXJlIG1lc3NhZ2UhIikscjtjb25zdCBvPW5ldyBFcnJvcih0KTtyZXR1cm4gdGhpcy5CLmNhcHR1cmVNZXNzYWdlKHQsbix7b3JpZ2luYWxFeGNlcHRpb246dCxzeW50aGV0aWNFeGNlcHRpb246bywuLi5lLGV2ZW50X2lkOnJ9LHRoaXMpLHJ9Y2FwdHVyZUV2ZW50KHQsbil7Y29uc3QgZT1uJiZuLmV2ZW50X2lkP24uZXZlbnRfaWQ6TSgpO3JldHVybiB0aGlzLkI/KHRoaXMuQi5jYXB0dXJlRXZlbnQodCx7Li4ubixldmVudF9pZDplfSx0aGlzKSxlKTooTi53YXJuKCJObyBjbGllbnQgY29uZmlndXJlZCBvbiBzY29wZSAtIHdpbGwgbm90IGNhcHR1cmUgZXZlbnQhIiksZSl9Rygpe3RoaXMuX3x8KHRoaXMuXz0hMCx0aGlzLlMuZm9yRWFjaCgodD0+e3QodGhpcyl9KSksdGhpcy5fPSExKX19ZnVuY3Rpb24gZ3QoKXtyZXR1cm57dHJhY2VJZDpNKCksc3BhbklkOk0oKS5zdWJzdHJpbmcoMTYpfX1mdW5jdGlvbiB5dCgpe3JldHVybiAkdCh1dCgpKS5nZXRDdXJyZW50U2NvcGUoKS5nZXRDbGllbnQoKX1jbGFzcyBidHtjb25zdHJ1Y3Rvcih0LG4pe2xldCBlLHI7ZT10fHxuZXcgbXQscj1ufHxuZXcgbXQsdGhpcy5KPVt7c2NvcGU6ZX1dLHRoaXMuSD1yfXdpdGhTY29wZSh0KXtjb25zdCBuPXRoaXMuVygpO2xldCBlO3RyeXtlPXQobil9Y2F0Y2godCl7dGhyb3cgdGhpcy5ZKCksdH1yZXR1cm4gbShlKT9lLnRoZW4oKHQ9Pih0aGlzLlkoKSx0KSksKHQ9Pnt0aHJvdyB0aGlzLlkoKSx0fSkpOih0aGlzLlkoKSxlKX1nZXRDbGllbnQoKXtyZXR1cm4gdGhpcy5nZXRTdGFja1RvcCgpLmNsaWVudH1nZXRTY29wZSgpe3JldHVybiB0aGlzLmdldFN0YWNrVG9wKCkuc2NvcGV9Z2V0SXNvbGF0aW9uU2NvcGUoKXtyZXR1cm4gdGhpcy5IfWdldFN0YWNrKCl7cmV0dXJuIHRoaXMuSn1nZXRTdGFja1RvcCgpe3JldHVybiB0aGlzLkpbdGhpcy5KLmxlbmd0aC0xXX1XKCl7Y29uc3QgdD10aGlzLmdldFNjb3BlKCkuY2xvbmUoKTtyZXR1cm4gdGhpcy5nZXRTdGFjaygpLnB1c2goe2NsaWVudDp0aGlzLmdldENsaWVudCgpLHNjb3BlOnR9KSx0fVkoKXtyZXR1cm4hKHRoaXMuZ2V0U3RhY2soKS5sZW5ndGg8PTEpJiYhIXRoaXMuZ2V0U3RhY2soKS5wb3AoKX19ZnVuY3Rpb24gdnQoKXtjb25zdCB0PWF0KHV0KCkpO3JldHVybiB0Lmh1Ynx8KHQuaHViPW5ldyBidChiKCJkZWZhdWx0Q3VycmVudFNjb3BlIiwoKCk9Pm5ldyBtdCkpLGIoImRlZmF1bHRJc29sYXRpb25TY29wZSIsKCgpPT5uZXcgbXQpKSkpLHQuaHVifWZ1bmN0aW9uIF90KHQpe3JldHVybiB2dCgpLndpdGhTY29wZSh0KX1mdW5jdGlvbiB3dCh0LG4pe2NvbnN0IGU9dnQoKTtyZXR1cm4gZS53aXRoU2NvcGUoKCgpPT4oZS5nZXRTdGFja1RvcCgpLnNjb3BlPXQsbih0KSkpKX1mdW5jdGlvbiBTdCh0KXtyZXR1cm4gdnQoKS53aXRoU2NvcGUoKCgpPT50KHZ0KCkuZ2V0SXNvbGF0aW9uU2NvcGUoKSkpKX1mdW5jdGlvbiAkdCh0KXtjb25zdCBuPWF0KHQpO3JldHVybiBuLmFjcz9uLmFjczp7d2l0aElzb2xhdGlvblNjb3BlOlN0LHdpdGhTY29wZTpfdCx3aXRoU2V0U2NvcGU6d3Qsd2l0aFNldElzb2xhdGlvblNjb3BlOih0LG4pPT5TdChuKSxnZXRDdXJyZW50U2NvcGU6KCk9PnZ0KCkuZ2V0U2NvcGUoKSxnZXRJc29sYXRpb25TY29wZTooKT0+dnQoKS5nZXRJc29sYXRpb25TY29wZSgpfX1jb25zdCBFdD0ic2VudHJ5LnNvdXJjZSIseHQ9InNlbnRyeS5zYW1wbGVfcmF0ZSIsTnQ9InNlbnRyeS5vcCIsa3Q9InNlbnRyeS5vcmlnaW4iLEN0PTAsRHQ9MSxUdD0xO2Z1bmN0aW9uIE90KHQpe2NvbnN0e3NwYW5JZDpuLHRyYWNlSWQ6ZX09dC5zcGFuQ29udGV4dCgpLHtkYXRhOnIsb3A6byxwYXJlbnRfc3Bhbl9pZDpzLHN0YXR1czppLG9yaWdpbjpjfT1BdCh0KTtyZXR1cm4gaih7ZGF0YTpyLG9wOm8scGFyZW50X3NwYW5faWQ6cyxzcGFuX2lkOm4sc3RhdHVzOmksdHJhY2VfaWQ6ZSxvcmlnaW46Y30pfWZ1bmN0aW9uIGp0KHQpe3JldHVybiJudW1iZXIiPT10eXBlb2YgdD9SdCh0KTpBcnJheS5pc0FycmF5KHQpP3RbMF0rdFsxXS8xZTk6dCBpbnN0YW5jZW9mIERhdGU/UnQodC5nZXRUaW1lKCkpOlooKX1mdW5jdGlvbiBSdCh0KXtyZXR1cm4gdD45OTk5OTk5OTk5P3QvMWUzOnR9ZnVuY3Rpb24gQXQodCl7aWYoZnVuY3Rpb24odCl7cmV0dXJuImZ1bmN0aW9uIj09dHlwZW9mIHQuZ2V0U3BhbkpTT059KHQpKXJldHVybiB0LmdldFNwYW5KU09OKCk7dHJ5e2NvbnN0e3NwYW5JZDpuLHRyYWNlSWQ6ZX09dC5zcGFuQ29udGV4dCgpO2lmKGZ1bmN0aW9uKHQpe2NvbnN0IG49dDtyZXR1cm4hIShuLmF0dHJpYnV0ZXMmJm4uc3RhcnRUaW1lJiZuLm5hbWUmJm4uZW5kVGltZSYmbi5zdGF0dXMpfSh0KSl7Y29uc3R7YXR0cmlidXRlczpyLHN0YXJ0VGltZTpvLG5hbWU6cyxlbmRUaW1lOmkscGFyZW50U3BhbklkOmMsc3RhdHVzOnV9PXQ7cmV0dXJuIGooe3NwYW5faWQ6bix0cmFjZV9pZDplLGRhdGE6cixkZXNjcmlwdGlvbjpzLHBhcmVudF9zcGFuX2lkOmMsc3RhcnRfdGltZXN0YW1wOmp0KG8pLHRpbWVzdGFtcDpqdChpKXx8dm9pZCAwLHN0YXR1czpJdCh1KSxvcDpyW050XSxvcmlnaW46cltrdF0scTp2b2lkIDB9KX1yZXR1cm57c3Bhbl9pZDpuLHRyYWNlX2lkOmV9fWNhdGNoKHQpe3JldHVybnt9fX1mdW5jdGlvbiBJdCh0KXtpZih0JiZ0LmNvZGUhPT1DdClyZXR1cm4gdC5jb2RlPT09RHQ/Im9rIjp0Lm1lc3NhZ2V8fCJ1bmtub3duX2Vycm9yIn1jb25zdCBQdD0iX3NlbnRyeVJvb3RTcGFuIjtmdW5jdGlvbiBVdCh0KXtyZXR1cm4gdFtQdF18fHR9Y29uc3QgTXQ9InByb2R1Y3Rpb24iLEx0PSJfZnJvemVuRHNjIjtmdW5jdGlvbiBCdCh0KXtjb25zdCBuPXl0KCk7aWYoIW4pcmV0dXJue307Y29uc3QgZT1mdW5jdGlvbih0LG4pe2NvbnN0IGU9bi5nZXRPcHRpb25zKCkse3B1YmxpY0tleTpyfT1uLmdldERzbigpfHx7fSxvPWooe2Vudmlyb25tZW50OmUuZW52aXJvbm1lbnR8fE10LHJlbGVhc2U6ZS5yZWxlYXNlLHB1YmxpY19rZXk6cix0cmFjZV9pZDp0fSk7cmV0dXJuIG4uZW1pdCgiY3JlYXRlRHNjIixvKSxvfShBdCh0KS50cmFjZV9pZHx8IiIsbikscj1VdCh0KTtpZighcilyZXR1cm4gZTtjb25zdCBvPXJbTHRdO2lmKG8pcmV0dXJuIG87Y29uc3Qgcz1BdChyKSxpPXMuZGF0YXx8e30sYz1pW3h0XTtudWxsIT1jJiYoZS5zYW1wbGVfcmF0ZT1gJHtjfWApO2NvbnN0IHU9aVtFdF07cmV0dXJuIHUmJiJ1cmwiIT09dSYmKGUudHJhbnNhY3Rpb249cy5kZXNjcmlwdGlvbiksZS5zYW1wbGVkPVN0cmluZyhmdW5jdGlvbih0KXtjb25zdHt0cmFjZUZsYWdzOm59PXQuc3BhbkNvbnRleHQoKTtyZXR1cm4gbj09PVR0fShyKSksbi5lbWl0KCJjcmVhdGVEc2MiLGUpLGV9Y29uc3QgR3Q9Il9fU0VOVFJZX1NVUFBSRVNTX1RSQUNJTkdfXyI7ZnVuY3Rpb24gSnQodCl7Y29uc3Qgbj0kdCh1dCgpKTtyZXR1cm4gbi5zdXBwcmVzc1RyYWNpbmc/bi5zdXBwcmVzc1RyYWNpbmcodCk6ZnVuY3Rpb24oLi4udCl7Y29uc3Qgbj0kdCh1dCgpKTtpZigyPT09dC5sZW5ndGgpe2NvbnN0W2Uscl09dDtyZXR1cm4gZT9uLndpdGhTZXRTY29wZShlLHIpOm4ud2l0aFNjb3BlKHIpfXJldHVybiBuLndpdGhTY29wZSh0WzBdKX0oKG49PihuLnNldFNES1Byb2Nlc3NpbmdNZXRhZGF0YSh7W0d0XTohMH0pLHQoKSkpKX1mdW5jdGlvbiB6dCh0LG4sZSxyKXtjb25zdCBvPW90KGUpLHM9dC50eXBlJiYicmVwbGF5X2V2ZW50IiE9PXQudHlwZT90LnR5cGU6ImV2ZW50IjshZnVuY3Rpb24odCxuKXtuJiYodC5zZGs9dC5zZGt8fHt9LHQuc2RrLm5hbWU9dC5zZGsubmFtZXx8bi5uYW1lLHQuc2RrLnZlcnNpb249dC5zZGsudmVyc2lvbnx8bi52ZXJzaW9uLHQuc2RrLmludGVncmF0aW9ucz1bLi4udC5zZGsuaW50ZWdyYXRpb25zfHxbXSwuLi5uLmludGVncmF0aW9uc3x8W11dLHQuc2RrLnBhY2thZ2VzPVsuLi50LnNkay5wYWNrYWdlc3x8W10sLi4ubi5wYWNrYWdlc3x8W11dKX0odCxlJiZlLnNkayk7Y29uc3QgaT1mdW5jdGlvbih0LG4sZSxyKXtjb25zdCBvPXQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhJiZ0LnNka1Byb2Nlc3NpbmdNZXRhZGF0YS5keW5hbWljU2FtcGxpbmdDb250ZXh0O3JldHVybntldmVudF9pZDp0LmV2ZW50X2lkLHNlbnRfYXQ6KG5ldyBEYXRlKS50b0lTT1N0cmluZygpLC4uLm4mJntzZGs6bn0sLi4uISFlJiZyJiZ7ZHNuOmsocil9LC4uLm8mJnt0cmFjZTpqKHsuLi5vfSl9fX0odCxvLHIsbik7ZGVsZXRlIHQuc2RrUHJvY2Vzc2luZ01ldGFkYXRhO3JldHVybiBRKGksW1t7dHlwZTpzfSx0XV0pfWZ1bmN0aW9uIEh0KHQsbil7Y29uc3R7ZmluZ2VycHJpbnQ6ZSxzcGFuOnIsYnJlYWRjcnVtYnM6byxzZGtQcm9jZXNzaW5nTWV0YWRhdGE6c309bjshZnVuY3Rpb24odCxuKXtjb25zdHtleHRyYTplLHRhZ3M6cix1c2VyOm8sY29udGV4dHM6cyxsZXZlbDppLHRyYW5zYWN0aW9uTmFtZTpjfT1uLHU9aihlKTt1JiZPYmplY3Qua2V5cyh1KS5sZW5ndGgmJih0LmV4dHJhPXsuLi51LC4uLnQuZXh0cmF9KTtjb25zdCBhPWoocik7YSYmT2JqZWN0LmtleXMoYSkubGVuZ3RoJiYodC50YWdzPXsuLi5hLC4uLnQudGFnc30pO2NvbnN0IGY9aihvKTtmJiZPYmplY3Qua2V5cyhmKS5sZW5ndGgmJih0LnVzZXI9ey4uLmYsLi4udC51c2VyfSk7Y29uc3QgaD1qKHMpO2gmJk9iamVjdC5rZXlzKGgpLmxlbmd0aCYmKHQuY29udGV4dHM9ey4uLmgsLi4udC5jb250ZXh0c30pO2kmJih0LmxldmVsPWkpO2MmJiJ0cmFuc2FjdGlvbiIhPT10LnR5cGUmJih0LnRyYW5zYWN0aW9uPWMpfSh0LG4pLHImJmZ1bmN0aW9uKHQsbil7dC5jb250ZXh0cz17dHJhY2U6T3QobiksLi4udC5jb250ZXh0c30sdC5zZGtQcm9jZXNzaW5nTWV0YWRhdGE9e2R5bmFtaWNTYW1wbGluZ0NvbnRleHQ6QnQobiksLi4udC5zZGtQcm9jZXNzaW5nTWV0YWRhdGF9O2NvbnN0IGU9VXQobikscj1BdChlKS5kZXNjcmlwdGlvbjtyJiYhdC50cmFuc2FjdGlvbiYmInRyYW5zYWN0aW9uIj09PXQudHlwZSYmKHQudHJhbnNhY3Rpb249cil9KHQsciksZnVuY3Rpb24odCxuKXt0LmZpbmdlcnByaW50PXQuZmluZ2VycHJpbnQ/ZnVuY3Rpb24odCl7cmV0dXJuIEFycmF5LmlzQXJyYXkodCk/dDpbdF19KHQuZmluZ2VycHJpbnQpOltdLG4mJih0LmZpbmdlcnByaW50PXQuZmluZ2VycHJpbnQuY29uY2F0KG4pKTt0LmZpbmdlcnByaW50JiYhdC5maW5nZXJwcmludC5sZW5ndGgmJmRlbGV0ZSB0LmZpbmdlcnByaW50fSh0LGUpLGZ1bmN0aW9uKHQsbil7Y29uc3QgZT1bLi4udC5icmVhZGNydW1ic3x8W10sLi4ubl07dC5icmVhZGNydW1icz1lLmxlbmd0aD9lOnZvaWQgMH0odCxvKSxmdW5jdGlvbih0LG4pe3Quc2RrUHJvY2Vzc2luZ01ldGFkYXRhPXsuLi50LnNka1Byb2Nlc3NpbmdNZXRhZGF0YSwuLi5ufX0odCxzKX1jb25zdCBXdD0iNyI7ZnVuY3Rpb24gWXQodCxuKXtyZXR1cm4gZT17c2VudHJ5X2tleTp0LnB1YmxpY0tleSxzZW50cnlfdmVyc2lvbjpXdCwuLi5uJiZ7c2VudHJ5X2NsaWVudDpgJHtuLm5hbWV9LyR7bi52ZXJzaW9ufWB9fSxPYmplY3Qua2V5cyhlKS5tYXAoKHQ9PmAke2VuY29kZVVSSUNvbXBvbmVudCh0KX09JHtlbmNvZGVVUklDb21wb25lbnQoZVt0XSl9YCkpLmpvaW4oIiYiKTt2YXIgZX1jb25zdCBxdD0zMDtmdW5jdGlvbiBGdCh0LG4sZT1xKHQuYnVmZmVyU2l6ZXx8cXQpKXtsZXQgcj17fTtyZXR1cm57c2VuZDpmdW5jdGlvbihvKXtjb25zdCBzPVtdO2lmKFgobywoKG4sZSk9Pntjb25zdCBvPXJ0KGUpO2lmKGZ1bmN0aW9uKHQsbixlPURhdGUubm93KCkpe3JldHVybiBmdW5jdGlvbih0LG4pe3JldHVybiB0W25dfHx0LmFsbHx8MH0odCxuKT5lfShyLG8pKXtjb25zdCByPUt0KG4sZSk7dC5yZWNvcmREcm9wcGVkRXZlbnQoInJhdGVsaW1pdF9iYWNrb2ZmIixvLHIpfWVsc2Ugcy5wdXNoKG4pfSkpLDA9PT1zLmxlbmd0aClyZXR1cm4gVyh7fSk7Y29uc3QgaT1RKG9bMF0scyksYz1uPT57WChpLCgoZSxyKT0+e2NvbnN0IG89S3QoZSxyKTt0LnJlY29yZERyb3BwZWRFdmVudChuLHJ0KHIpLG8pfSkpfTtyZXR1cm4gZS5hZGQoKCgpPT5uKHtib2R5Om50KGkpfSkudGhlbigodD0+KHZvaWQgMCE9PXQuc3RhdHVzQ29kZSYmKHQuc3RhdHVzQ29kZTwyMDB8fHQuc3RhdHVzQ29kZT49MzAwKSYmY3QmJk4ud2FybihgU2VudHJ5IHJlc3BvbmRlZCB3aXRoIHN0YXR1cyBjb2RlICR7dC5zdGF0dXNDb2RlfSB0byBzZW50IGV2ZW50LmApLHI9aXQocix0KSx0KSksKHQ9Pnt0aHJvdyBjKCJuZXR3b3JrX2Vycm9yIiksdH0pKSkpLnRoZW4oKHQ9PnQpLCh0PT57aWYodCBpbnN0YW5jZW9mIEMpcmV0dXJuIGN0JiZOLmVycm9yKCJTa2lwcGVkIHNlbmRpbmcgZXZlbnQgYmVjYXVzZSBidWZmZXIgaXMgZnVsbC4iKSxjKCJxdWV1ZV9vdmVyZmxvdyIpLFcoe30pO3Rocm93IHR9KSl9LGZsdXNoOnQ9PmUuZHJhaW4odCl9fWZ1bmN0aW9uIEt0KHQsbil7aWYoImV2ZW50Ij09PW58fCJ0cmFuc2FjdGlvbiI9PT1uKXJldHVybiBBcnJheS5pc0FycmF5KHQpP3RbMV06dm9pZCAwfWNvbnN0IFZ0PVN5bWJvbCgiQWdlbnRCYXNlSW50ZXJuYWxTdGF0ZSIpO2NsYXNzIFp0IGV4dGVuZHMgaC5BZ2VudHtbVnRdO29wdGlvbnM7a2VlcEFsaXZlO2NvbnN0cnVjdG9yKHQpe3N1cGVyKHQpLHRoaXNbVnRdPXt9fWlzU2VjdXJlRW5kcG9pbnQodCl7aWYodCl7aWYoImJvb2xlYW4iPT10eXBlb2YgdC5zZWN1cmVFbmRwb2ludClyZXR1cm4gdC5zZWN1cmVFbmRwb2ludDtpZigic3RyaW5nIj09dHlwZW9mIHQucHJvdG9jb2wpcmV0dXJuImh0dHBzOiI9PT10LnByb3RvY29sfWNvbnN0e3N0YWNrOm59PW5ldyBFcnJvcjtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIG4mJm4uc3BsaXQoIlxuIikuc29tZSgodD0+LTEhPT10LmluZGV4T2YoIihodHRwcy5qczoiKXx8LTEhPT10LmluZGV4T2YoIm5vZGU6aHR0cHM6IikpKX1jcmVhdGVTb2NrZXQodCxuLGUpe2NvbnN0IHI9ey4uLm4sc2VjdXJlRW5kcG9pbnQ6dGhpcy5pc1NlY3VyZUVuZHBvaW50KG4pfTtQcm9taXNlLnJlc29sdmUoKS50aGVuKCgoKT0+dGhpcy5jb25uZWN0KHQscikpKS50aGVuKChvPT57aWYobyBpbnN0YW5jZW9mIGguQWdlbnQpcmV0dXJuIG8uYWRkUmVxdWVzdCh0LHIpO3RoaXNbVnRdLmN1cnJlbnRTb2NrZXQ9byxzdXBlci5jcmVhdGVTb2NrZXQodCxuLGUpfSksZSl9Y3JlYXRlQ29ubmVjdGlvbigpe2NvbnN0IHQ9dGhpc1tWdF0uY3VycmVudFNvY2tldDtpZih0aGlzW1Z0XS5jdXJyZW50U29ja2V0PXZvaWQgMCwhdCl0aHJvdyBuZXcgRXJyb3IoIk5vIHNvY2tldCB3YXMgcmV0dXJuZWQgaW4gdGhlIGBjb25uZWN0KClgIGZ1bmN0aW9uIik7cmV0dXJuIHR9Z2V0IGRlZmF1bHRQb3J0KCl7cmV0dXJuIHRoaXNbVnRdLmRlZmF1bHRQb3J0Pz8oImh0dHBzOiI9PT10aGlzLnByb3RvY29sPzQ0Mzo4MCl9c2V0IGRlZmF1bHRQb3J0KHQpe3RoaXNbVnRdJiYodGhpc1tWdF0uZGVmYXVsdFBvcnQ9dCl9Z2V0IHByb3RvY29sKCl7cmV0dXJuIHRoaXNbVnRdLnByb3RvY29sPz8odGhpcy5pc1NlY3VyZUVuZHBvaW50KCk/Imh0dHBzOiI6Imh0dHA6Iil9c2V0IHByb3RvY29sKHQpe3RoaXNbVnRdJiYodGhpc1tWdF0ucHJvdG9jb2w9dCl9fWZ1bmN0aW9uIFF0KC4uLnQpe04ubG9nKCJbaHR0cHMtcHJveHktYWdlbnQ6cGFyc2UtcHJveHktcmVzcG9uc2VdIiwuLi50KX1mdW5jdGlvbiBYdCh0KXtyZXR1cm4gbmV3IFByb21pc2UoKChuLGUpPT57bGV0IHI9MDtjb25zdCBvPVtdO2Z1bmN0aW9uIHMoKXtjb25zdCBjPXQucmVhZCgpO2M/ZnVuY3Rpb24oYyl7by5wdXNoKGMpLHIrPWMubGVuZ3RoO2NvbnN0IHU9QnVmZmVyLmNvbmNhdChvLHIpLGE9dS5pbmRleE9mKCJcclxuXHJcbiIpO2lmKC0xPT09YSlyZXR1cm4gUXQoImhhdmUgbm90IHJlY2VpdmVkIGVuZCBvZiBIVFRQIGhlYWRlcnMgeWV0Li4uIiksdm9pZCBzKCk7Y29uc3QgZj11LnNsaWNlKDAsYSkudG9TdHJpbmcoImFzY2lpIikuc3BsaXQoIlxyXG4iKSxoPWYuc2hpZnQoKTtpZighaClyZXR1cm4gdC5kZXN0cm95KCksZShuZXcgRXJyb3IoIk5vIGhlYWRlciByZWNlaXZlZCBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2UiKSk7Y29uc3QgcD1oLnNwbGl0KCIgIiksbD0rcFsxXSxkPXAuc2xpY2UoMikuam9pbigiICIpLG09e307Zm9yKGNvbnN0IG4gb2YgZil7aWYoIW4pY29udGludWU7Y29uc3Qgcj1uLmluZGV4T2YoIjoiKTtpZigtMT09PXIpcmV0dXJuIHQuZGVzdHJveSgpLGUobmV3IEVycm9yKGBJbnZhbGlkIGhlYWRlciBmcm9tIHByb3h5IENPTk5FQ1QgcmVzcG9uc2U6ICIke259ImApKTtjb25zdCBvPW4uc2xpY2UoMCxyKS50b0xvd2VyQ2FzZSgpLHM9bi5zbGljZShyKzEpLnRyaW1TdGFydCgpLGk9bVtvXTsic3RyaW5nIj09dHlwZW9mIGk/bVtvXT1baSxzXTpBcnJheS5pc0FycmF5KGkpP2kucHVzaChzKTptW29dPXN9UXQoImdvdCBwcm94eSBzZXJ2ZXIgcmVzcG9uc2U6ICVvICVvIixoLG0pLGkoKSxuKHtjb25uZWN0OntzdGF0dXNDb2RlOmwsc3RhdHVzVGV4dDpkLGhlYWRlcnM6bX0sYnVmZmVyZWQ6dX0pfShjKTp0Lm9uY2UoInJlYWRhYmxlIixzKX1mdW5jdGlvbiBpKCl7dC5yZW1vdmVMaXN0ZW5lcigiZW5kIixjKSx0LnJlbW92ZUxpc3RlbmVyKCJlcnJvciIsdSksdC5yZW1vdmVMaXN0ZW5lcigicmVhZGFibGUiLHMpfWZ1bmN0aW9uIGMoKXtpKCksUXQoIm9uZW5kIiksZShuZXcgRXJyb3IoIlByb3h5IGNvbm5lY3Rpb24gZW5kZWQgYmVmb3JlIHJlY2VpdmluZyBDT05ORUNUIHJlc3BvbnNlIikpfWZ1bmN0aW9uIHUodCl7aSgpLFF0KCJvbmVycm9yICVvIix0KSxlKHQpfXQub24oImVycm9yIix1KSx0Lm9uKCJlbmQiLGMpLHMoKX0pKX1mdW5jdGlvbiB0biguLi50KXtOLmxvZygiW2h0dHBzLXByb3h5LWFnZW50XSIsLi4udCl9Y2xhc3Mgbm4gZXh0ZW5kcyBadHtzdGF0aWMgcHJvdG9jb2xzPVsiaHR0cCIsImh0dHBzIl07cHJveHk7cHJveHlIZWFkZXJzO2Nvbm5lY3RPcHRzO2NvbnN0cnVjdG9yKHQsbil7c3VwZXIobiksdGhpcy5vcHRpb25zPXt9LHRoaXMucHJveHk9InN0cmluZyI9PXR5cGVvZiB0P25ldyBVUkwodCk6dCx0aGlzLnByb3h5SGVhZGVycz1uPy5oZWFkZXJzPz97fSx0bigiQ3JlYXRpbmcgbmV3IEh0dHBzUHJveHlBZ2VudCBpbnN0YW5jZTogJW8iLHRoaXMucHJveHkuaHJlZik7Y29uc3QgZT0odGhpcy5wcm94eS5ob3N0bmFtZXx8dGhpcy5wcm94eS5ob3N0KS5yZXBsYWNlKC9eXFt8XF0kL2csIiIpLHI9dGhpcy5wcm94eS5wb3J0P3BhcnNlSW50KHRoaXMucHJveHkucG9ydCwxMCk6Imh0dHBzOiI9PT10aGlzLnByb3h5LnByb3RvY29sPzQ0Mzo4MDt0aGlzLmNvbm5lY3RPcHRzPXtBTFBOUHJvdG9jb2xzOlsiaHR0cC8xLjEiXSwuLi5uP3JuKG4sImhlYWRlcnMiKTpudWxsLGhvc3Q6ZSxwb3J0OnJ9fWFzeW5jIGNvbm5lY3QodCxuKXtjb25zdHtwcm94eTplfT10aGlzO2lmKCFuLmhvc3QpdGhyb3cgbmV3IFR5cGVFcnJvcignTm8gImhvc3QiIHByb3ZpZGVkJyk7bGV0IHI7aWYoImh0dHBzOiI9PT1lLnByb3RvY29sKXt0bigiQ3JlYXRpbmcgYHRscy5Tb2NrZXRgOiAlbyIsdGhpcy5jb25uZWN0T3B0cyk7Y29uc3QgdD10aGlzLmNvbm5lY3RPcHRzLnNlcnZlcm5hbWV8fHRoaXMuY29ubmVjdE9wdHMuaG9zdDtyPWYuY29ubmVjdCh7Li4udGhpcy5jb25uZWN0T3B0cyxzZXJ2ZXJuYW1lOnQmJmEuaXNJUCh0KT92b2lkIDA6dH0pfWVsc2UgdG4oIkNyZWF0aW5nIGBuZXQuU29ja2V0YDogJW8iLHRoaXMuY29ubmVjdE9wdHMpLHI9YS5jb25uZWN0KHRoaXMuY29ubmVjdE9wdHMpO2NvbnN0IG89ImZ1bmN0aW9uIj09dHlwZW9mIHRoaXMucHJveHlIZWFkZXJzP3RoaXMucHJveHlIZWFkZXJzKCk6ey4uLnRoaXMucHJveHlIZWFkZXJzfSxzPWEuaXNJUHY2KG4uaG9zdCk/YFske24uaG9zdH1dYDpuLmhvc3Q7bGV0IGk9YENPTk5FQ1QgJHtzfToke24ucG9ydH0gSFRUUC8xLjFcclxuYDtpZihlLnVzZXJuYW1lfHxlLnBhc3N3b3JkKXtjb25zdCB0PWAke2RlY29kZVVSSUNvbXBvbmVudChlLnVzZXJuYW1lKX06JHtkZWNvZGVVUklDb21wb25lbnQoZS5wYXNzd29yZCl9YDtvWyJQcm94eS1BdXRob3JpemF0aW9uIl09YEJhc2ljICR7QnVmZmVyLmZyb20odCkudG9TdHJpbmcoImJhc2U2NCIpfWB9by5Ib3N0PWAke3N9OiR7bi5wb3J0fWAsb1siUHJveHktQ29ubmVjdGlvbiJdfHwob1siUHJveHktQ29ubmVjdGlvbiJdPXRoaXMua2VlcEFsaXZlPyJLZWVwLUFsaXZlIjoiY2xvc2UiKTtmb3IoY29uc3QgdCBvZiBPYmplY3Qua2V5cyhvKSlpKz1gJHt0fTogJHtvW3RdfVxyXG5gO2NvbnN0IGM9WHQocik7ci53cml0ZShgJHtpfVxyXG5gKTtjb25zdHtjb25uZWN0OnUsYnVmZmVyZWQ6aH09YXdhaXQgYztpZih0LmVtaXQoInByb3h5Q29ubmVjdCIsdSksdGhpcy5lbWl0KCJwcm94eUNvbm5lY3QiLHUsdCksMjAwPT09dS5zdGF0dXNDb2RlKXtpZih0Lm9uY2UoInNvY2tldCIsZW4pLG4uc2VjdXJlRW5kcG9pbnQpe3RuKCJVcGdyYWRpbmcgc29ja2V0IGNvbm5lY3Rpb24gdG8gVExTIik7Y29uc3QgdD1uLnNlcnZlcm5hbWV8fG4uaG9zdDtyZXR1cm4gZi5jb25uZWN0KHsuLi5ybihuLCJob3N0IiwicGF0aCIsInBvcnQiKSxzb2NrZXQ6cixzZXJ2ZXJuYW1lOmEuaXNJUCh0KT92b2lkIDA6dH0pfXJldHVybiByfXIuZGVzdHJveSgpO2NvbnN0IHA9bmV3IGEuU29ja2V0KHt3cml0YWJsZTohMX0pO3JldHVybiBwLnJlYWRhYmxlPSEwLHQub25jZSgic29ja2V0IiwodD0+e3RuKCJSZXBsYXlpbmcgcHJveHkgYnVmZmVyIGZvciBmYWlsZWQgcmVxdWVzdCIpLHQucHVzaChoKSx0LnB1c2gobnVsbCl9KSkscH19ZnVuY3Rpb24gZW4odCl7dC5yZXN1bWUoKX1mdW5jdGlvbiBybih0LC4uLm4pe2NvbnN0IGU9e307bGV0IHI7Zm9yKHIgaW4gdCluLmluY2x1ZGVzKHIpfHwoZVtyXT10W3JdKTtyZXR1cm4gZX1jb25zdCBvbj0zMjc2ODtmdW5jdGlvbiBzbih0KXtyZXR1cm4gdC5yZXBsYWNlKC9eW0EtWl06LywiIikucmVwbGFjZSgvXFwvZywiLyIpfWNvbnN0IGNuPWU7bGV0IHVuLGFuPSExO2Z1bmN0aW9uIGZuKHQpe2NuLmRlYnVnJiZjb25zb2xlLmxvZyhgW0FOUiBXb3JrZXJdICR7dH1gKX12YXIgaG4scG4sbG47Y29uc3QgZG49ZnVuY3Rpb24odCl7bGV0IG47dHJ5e249bmV3IFVSTCh0LnVybCl9Y2F0Y2gobil7cmV0dXJuIHgoKCgpPT57Y29uc29sZS53YXJuKCJbQHNlbnRyeS9ub2RlXTogSW52YWxpZCBkc24gb3IgdHVubmVsIG9wdGlvbiwgd2lsbCBub3Qgc2VuZCBhbnkgZXZlbnRzLiBUaGUgdHVubmVsIG9wdGlvbiBtdXN0IGJlIGEgZnVsbCBVUkwgd2hlbiB1c2VkLiIpfSkpLEZ0KHQsKCgpPT5Qcm9taXNlLnJlc29sdmUoe30pKSl9Y29uc3QgZT0iaHR0cHM6Ij09PW4ucHJvdG9jb2wscj1mdW5jdGlvbih0LG4pe2NvbnN0e25vX3Byb3h5OmV9PXByb2Nlc3MuZW52O3JldHVybiBlJiZlLnNwbGl0KCIsIikuc29tZSgobj0+dC5ob3N0LmVuZHNXaXRoKG4pfHx0Lmhvc3RuYW1lLmVuZHNXaXRoKG4pKSk/dm9pZCAwOm59KG4sdC5wcm94eXx8KGU/cHJvY2Vzcy5lbnYuaHR0cHNfcHJveHk6dm9pZCAwKXx8cHJvY2Vzcy5lbnYuaHR0cF9wcm94eSksbz1lP2k6cyxhPXZvaWQgMCE9PXQua2VlcEFsaXZlJiZ0LmtlZXBBbGl2ZSxmPXI/bmV3IG5uKHIpOm5ldyBvLkFnZW50KHtrZWVwQWxpdmU6YSxtYXhTb2NrZXRzOjMwLHRpbWVvdXQ6MmUzfSk7cmV0dXJuIEp0KCgoKT0+e2NvbnN0IG49ZnVuY3Rpb24odCxuLGUpe2NvbnN0e2hvc3RuYW1lOnIscGF0aG5hbWU6byxwb3J0OnMscHJvdG9jb2w6aSxzZWFyY2g6YX09bmV3IFVSTCh0LnVybCk7cmV0dXJuIGZ1bmN0aW9uKGYpe3JldHVybiBuZXcgUHJvbWlzZSgoKGgscCk9PntsZXQgbD1mdW5jdGlvbih0KXtyZXR1cm4gbmV3IGMoe3JlYWQoKXt0aGlzLnB1c2godCksdGhpcy5wdXNoKG51bGwpfX0pfShmLmJvZHkpO2NvbnN0IGQ9ey4uLnQuaGVhZGVyc307Zi5ib2R5Lmxlbmd0aD5vbiYmKGRbImNvbnRlbnQtZW5jb2RpbmciXT0iZ3ppcCIsbD1sLnBpcGUodSgpKSk7Y29uc3QgbT1uLnJlcXVlc3Qoe21ldGhvZDoiUE9TVCIsYWdlbnQ6ZSxoZWFkZXJzOmQsaG9zdG5hbWU6cixwYXRoOmAke299JHthfWAscG9ydDpzLHByb3RvY29sOmksY2E6dC5jYUNlcnRzfSwodD0+e3Qub24oImRhdGEiLCgoKT0+e30pKSx0Lm9uKCJlbmQiLCgoKT0+e30pKSx0LnNldEVuY29kaW5nKCJ1dGY4Iik7Y29uc3Qgbj10LmhlYWRlcnNbInJldHJ5LWFmdGVyIl0/P251bGwsZT10LmhlYWRlcnNbIngtc2VudHJ5LXJhdGUtbGltaXRzIl0/P251bGw7aCh7c3RhdHVzQ29kZTp0LnN0YXR1c0NvZGUsaGVhZGVyczp7InJldHJ5LWFmdGVyIjpuLCJ4LXNlbnRyeS1yYXRlLWxpbWl0cyI6QXJyYXkuaXNBcnJheShlKT9lWzBdOmV9fSl9KSk7bS5vbigiZXJyb3IiLHApLGwucGlwZShtKX0pKX19KHQsdC5odHRwTW9kdWxlPz9vLGYpO3JldHVybiBGdCh0LG4pfSkpfSh7dXJsOihobj1jbi5kc24scG49Y24udHVubmVsLGxuPWNuLnNka01ldGFkYXRhLnNkayxwbnx8YCR7ZnVuY3Rpb24odCl7cmV0dXJuYCR7ZnVuY3Rpb24odCl7Y29uc3Qgbj10LnByb3RvY29sP2Ake3QucHJvdG9jb2x9OmA6IiIsZT10LnBvcnQ/YDoke3QucG9ydH1gOiIiO3JldHVybmAke259Ly8ke3QuaG9zdH0ke2V9JHt0LnBhdGg/YC8ke3QucGF0aH1gOiIifS9hcGkvYH0odCl9JHt0LnByb2plY3RJZH0vZW52ZWxvcGUvYH0oaG4pfT8ke1l0KGhuLGxuKX1gKSxyZWNvcmREcm9wcGVkRXZlbnQ6KCk9Pnt9fSk7YXN5bmMgZnVuY3Rpb24gbW4oKXtpZih1bil7Zm4oIlNlbmRpbmcgYWJub3JtYWwgc2Vzc2lvbiIpLGh0KHVuLHtzdGF0dXM6ImFibm9ybWFsIixhYm5vcm1hbF9tZWNoYW5pc206ImFucl9mb3JlZ3JvdW5kIn0pO2NvbnN0IHQ9ZnVuY3Rpb24odCxuLGUscil7Y29uc3Qgbz1vdChlKTtyZXR1cm4gUSh7c2VudF9hdDoobmV3IERhdGUpLnRvSVNPU3RyaW5nKCksLi4ubyYme3NkazpvfSwuLi4hIXImJm4mJntkc246ayhuKX19LFsiYWdncmVnYXRlcyJpbiB0P1t7dHlwZToic2Vzc2lvbnMifSx0XTpbe3R5cGU6InNlc3Npb24ifSx0LnRvSlNPTigpXV0pfSh1bixjbi5kc24sY24uc2RrTWV0YWRhdGEsY24udHVubmVsKTtmbihKU09OLnN0cmluZ2lmeSh0KSksYXdhaXQgZG4uc2VuZCh0KTt0cnl7bj8ucG9zdE1lc3NhZ2UoInNlc3Npb24tZW5kZWQiKX1jYXRjaCh0KXt9fX1mdW5jdGlvbiBnbih0KXtpZighdClyZXR1cm47Y29uc3Qgbj1mdW5jdGlvbih0KXtpZighdC5sZW5ndGgpcmV0dXJuW107Y29uc3Qgbj1BcnJheS5mcm9tKHQpO3JldHVybi9zZW50cnlXcmFwcGVkLy50ZXN0KG5bbi5sZW5ndGgtMV0uZnVuY3Rpb258fCIiKSYmbi5wb3AoKSxuLnJldmVyc2UoKSxQLnRlc3QobltuLmxlbmd0aC0xXS5mdW5jdGlvbnx8IiIpJiYobi5wb3AoKSxQLnRlc3QobltuLmxlbmd0aC0xXS5mdW5jdGlvbnx8IiIpJiZuLnBvcCgpKSxuLnNsaWNlKDAsQSkubWFwKCh0PT4oey4uLnQsZmlsZW5hbWU6dC5maWxlbmFtZXx8bltuLmxlbmd0aC0xXS5maWxlbmFtZSxmdW5jdGlvbjp0LmZ1bmN0aW9ufHxJfSkpKX0odCk7aWYoY24uYXBwUm9vdFBhdGgpZm9yKGNvbnN0IHQgb2Ygbil0LmZpbGVuYW1lJiYodC5maWxlbmFtZT1HKHQuZmlsZW5hbWUsY24uYXBwUm9vdFBhdGgpKTtyZXR1cm4gbn1hc3luYyBmdW5jdGlvbiB5bih0LG4pe2lmKGFuKXJldHVybjthbj0hMCxhd2FpdCBtbigpLGZuKCJTZW5kaW5nIGV2ZW50Iik7Y29uc3QgZT17ZXZlbnRfaWQ6TSgpLGNvbnRleHRzOmNuLmNvbnRleHRzLHJlbGVhc2U6Y24ucmVsZWFzZSxlbnZpcm9ubWVudDpjbi5lbnZpcm9ubWVudCxkaXN0OmNuLmRpc3QscGxhdGZvcm06Im5vZGUiLGxldmVsOiJlcnJvciIsZXhjZXB0aW9uOnt2YWx1ZXM6W3t0eXBlOiJBcHBsaWNhdGlvbk5vdFJlc3BvbmRpbmciLHZhbHVlOmBBcHBsaWNhdGlvbiBOb3QgUmVzcG9uZGluZyBmb3IgYXQgbGVhc3QgJHtjbi5hbnJUaHJlc2hvbGR9IG1zYCxzdGFja3RyYWNlOntmcmFtZXM6Z24odCl9LG1lY2hhbmlzbTp7dHlwZToiQU5SIn19XX0sdGFnczpjbi5zdGF0aWNUYWdzfTtuJiZmdW5jdGlvbih0LG4pe2lmKEh0KHQsbiksIXQuY29udGV4dHM/LnRyYWNlKXtjb25zdHt0cmFjZUlkOmUsc3BhbklkOnIscGFyZW50U3BhbklkOm99PW4ucHJvcGFnYXRpb25Db250ZXh0O3QuY29udGV4dHM9e3RyYWNlOnt0cmFjZV9pZDplLHNwYW5faWQ6cixwYXJlbnRfc3Bhbl9pZDpvfSwuLi50LmNvbnRleHRzfX19KGUsbik7Y29uc3Qgcj16dChlLGNuLmRzbixjbi5zZGtNZXRhZGF0YSxjbi50dW5uZWwpO2ZuKEpTT04uc3RyaW5naWZ5KHIpKSxhd2FpdCBkbi5zZW5kKHIpLGF3YWl0IGRuLmZsdXNoKDJlMyksc2V0VGltZW91dCgoKCk9Pntwcm9jZXNzLmV4aXQoMCl9KSw1ZTMpfWxldCBibjtpZihmbigiU3RhcnRlZCIpLGNuLmNhcHR1cmVTdGFja1RyYWNlKXtmbigiQ29ubmVjdGluZyB0byBkZWJ1Z2dlciIpO2NvbnN0IG49bmV3IHQ7bi5jb25uZWN0VG9NYWluVGhyZWFkKCksZm4oIkNvbm5lY3RlZCB0byBkZWJ1Z2dlciIpO2NvbnN0IGU9bmV3IE1hcDtuLm9uKCJEZWJ1Z2dlci5zY3JpcHRQYXJzZWQiLCh0PT57ZS5zZXQodC5wYXJhbXMuc2NyaXB0SWQsdC5wYXJhbXMudXJsKX0pKSxuLm9uKCJEZWJ1Z2dlci5wYXVzZWQiLCh0PT57aWYoIm90aGVyIj09PXQucGFyYW1zLnJlYXNvbil0cnl7Zm4oIkRlYnVnZ2VyIHBhdXNlZCIpO2NvbnN0IHM9Wy4uLnQucGFyYW1zLmNhbGxGcmFtZXNdLGk9Y24uYXBwUm9vdFBhdGg/ZnVuY3Rpb24odD0ocHJvY2Vzcy5hcmd2WzFdP3oocHJvY2Vzcy5hcmd2WzFdKTpwcm9jZXNzLmN3ZCgpKSxuPSJcXCI9PT1vKXtjb25zdCBlPW4/c24odCk6dDtyZXR1cm4gdD0+e2lmKCF0KXJldHVybjtjb25zdCBvPW4/c24odCk6dDtsZXR7ZGlyOnMsYmFzZTppLGV4dDpjfT1yLnBhcnNlKG8pOyIuanMiIT09YyYmIi5tanMiIT09YyYmIi5janMiIT09Y3x8KGk9aS5zbGljZSgwLC0xKmMubGVuZ3RoKSksc3x8KHM9Ii4iKTtjb25zdCB1PXMubGFzdEluZGV4T2YoIi9ub2RlX21vZHVsZXMiKTtpZih1Pi0xKXJldHVybmAke3Muc2xpY2UodSsxNCkucmVwbGFjZSgvXC8vZywiLiIpfToke2l9YDtpZihzLnN0YXJ0c1dpdGgoZSkpe2xldCB0PXMuc2xpY2UoZS5sZW5ndGgrMSkucmVwbGFjZSgvXC8vZywiLiIpO3JldHVybiB0JiYodCs9IjoiKSx0Kz1pLHR9cmV0dXJuIGl9fShjbi5hcHBSb290UGF0aCk6KCk9Pnt9LGM9cy5tYXAoKHQ9PmZ1bmN0aW9uKHQsbixlKXtjb25zdCByPW4/bi5yZXBsYWNlKC9eZmlsZTpcL1wvLywiIik6dm9pZCAwLG89dC5sb2NhdGlvbi5jb2x1bW5OdW1iZXI/dC5sb2NhdGlvbi5jb2x1bW5OdW1iZXIrMTp2b2lkIDAscz10LmxvY2F0aW9uLmxpbmVOdW1iZXI/dC5sb2NhdGlvbi5saW5lTnVtYmVyKzE6dm9pZCAwO3JldHVybiBqKHtmaWxlbmFtZTpyLG1vZHVsZTplKHIpLGZ1bmN0aW9uOnQuZnVuY3Rpb25OYW1lfHxJLGNvbG5vOm8sbGluZW5vOnMsaW5fYXBwOnI/RihyKTp2b2lkIDB9KX0odCxlLmdldCh0LmxvY2F0aW9uLnNjcmlwdElkKSxpKSkpLHU9c2V0VGltZW91dCgoKCk9Pnt5bihjKS50aGVuKG51bGwsKCgpPT57Zm4oIlNlbmRpbmcgQU5SIGV2ZW50IGZhaWxlZC4iKX0pKX0pLDVlMyk7bi5wb3N0KCJSdW50aW1lLmV2YWx1YXRlIix7ZXhwcmVzc2lvbjoiZ2xvYmFsLl9fU0VOVFJZX0dFVF9TQ09QRVNfXygpOyIsc2lsZW50OiEwLHJldHVybkJ5VmFsdWU6ITB9LCgodCxlKT0+e3QmJmZuKGBFcnJvciBleGVjdXRpbmcgc2NyaXB0OiAnJHt0Lm1lc3NhZ2V9J2ApLGNsZWFyVGltZW91dCh1KTtjb25zdCByPWUmJmUucmVzdWx0P2UucmVzdWx0LnZhbHVlOnZvaWQgMDtuLnBvc3QoIkRlYnVnZ2VyLnJlc3VtZSIpLG4ucG9zdCgiRGVidWdnZXIuZGlzYWJsZSIpLHluKGMscikudGhlbihudWxsLCgoKT0+e2ZuKCJTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQuIil9KSl9KSl9Y2F0Y2godCl7dGhyb3cgbi5wb3N0KCJEZWJ1Z2dlci5yZXN1bWUiKSxuLnBvc3QoIkRlYnVnZ2VyLmRpc2FibGUiKSx0fX0pKSxibj0oKT0+e3RyeXtuLnBvc3QoIkRlYnVnZ2VyLmVuYWJsZSIsKCgpPT57bi5wb3N0KCJEZWJ1Z2dlci5wYXVzZSIpfSkpfWNhdGNoKHQpe319fWNvbnN0e3BvbGw6dm59PWZ1bmN0aW9uKHQsbixlLHIpe2NvbnN0IG89dCgpO2xldCBzPSExLGk9ITA7cmV0dXJuIHNldEludGVydmFsKCgoKT0+e2NvbnN0IHQ9by5nZXRUaW1lTXMoKTshMT09PXMmJnQ+bitlJiYocz0hMCxpJiZyKCkpLHQ8bitlJiYocz0hMSl9KSwyMCkse3BvbGw6KCk9PntvLnJlc2V0KCl9LGVuYWJsZWQ6dD0+e2k9dH19fSgoZnVuY3Rpb24oKXtsZXQgdD1wcm9jZXNzLmhydGltZSgpO3JldHVybntnZXRUaW1lTXM6KCk9Pntjb25zdFtuLGVdPXByb2Nlc3MuaHJ0aW1lKHQpO3JldHVybiBNYXRoLmZsb29yKDFlMypuK2UvMWU2KX0scmVzZXQ6KCk9Pnt0PXByb2Nlc3MuaHJ0aW1lKCl9fX0pLGNuLnBvbGxJbnRlcnZhbCxjbi5hbnJUaHJlc2hvbGQsKGZ1bmN0aW9uKCl7Zm4oIldhdGNoZG9nIHRpbWVvdXQiKSxibj8oZm4oIlBhdXNpbmcgZGVidWdnZXIgdG8gY2FwdHVyZSBzdGFjayB0cmFjZSIpLGJuKCkpOihmbigiQ2FwdHVyaW5nIGV2ZW50IHdpdGhvdXQgYSBzdGFjayB0cmFjZSIpLHluKCkudGhlbihudWxsLCgoKT0+e2ZuKCJTZW5kaW5nIEFOUiBldmVudCBmYWlsZWQgb24gd2F0Y2hkb2cgdGltZW91dC4iKX0pKSl9KSk7bj8ub24oIm1lc3NhZ2UiLCh0PT57dC5zZXNzaW9uJiYodW49ZnQodC5zZXNzaW9uKSksdm4oKX0pKTs=';
|
|
1635
1796
|
|
|
1636
|
-
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; }
|
|
1637
1797
|
const DEFAULT_INTERVAL = 50;
|
|
1638
1798
|
const DEFAULT_HANG_THRESHOLD = 5000;
|
|
1639
1799
|
|
|
@@ -1671,7 +1831,7 @@ async function getContexts(client) {
|
|
|
1671
1831
|
event = await processor(event, eventHint);
|
|
1672
1832
|
}
|
|
1673
1833
|
|
|
1674
|
-
return _optionalChain$
|
|
1834
|
+
return _optionalChain$7([event, 'optionalAccess', _2 => _2.contexts]) || {};
|
|
1675
1835
|
}
|
|
1676
1836
|
|
|
1677
1837
|
const INTEGRATION_NAME$1 = 'Anr';
|
|
@@ -1824,7 +1984,7 @@ async function _startWorker(
|
|
|
1824
1984
|
};
|
|
1825
1985
|
}
|
|
1826
1986
|
|
|
1827
|
-
function _optionalChain$
|
|
1987
|
+
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; }
|
|
1828
1988
|
|
|
1829
1989
|
const _expressIntegration = (() => {
|
|
1830
1990
|
return {
|
|
@@ -1836,6 +1996,20 @@ const _expressIntegration = (() => {
|
|
|
1836
1996
|
requestHook(span) {
|
|
1837
1997
|
addOriginToSpan(span, 'auto.http.otel.express');
|
|
1838
1998
|
},
|
|
1999
|
+
spanNameHook(info, defaultName) {
|
|
2000
|
+
if (getIsolationScope() === getDefaultIsolationScope()) {
|
|
2001
|
+
DEBUG_BUILD &&
|
|
2002
|
+
logger.warn('Isolation scope is still default isolation scope - skipping setting transactionName');
|
|
2003
|
+
return defaultName;
|
|
2004
|
+
}
|
|
2005
|
+
if (info.layerType === 'request_handler') {
|
|
2006
|
+
// type cast b/c Otel unfortunately types info.request as any :(
|
|
2007
|
+
const req = info.request ;
|
|
2008
|
+
const method = req.method ? req.method.toUpperCase() : 'GET';
|
|
2009
|
+
getIsolationScope().setTransactionName(`${method} ${info.route}`);
|
|
2010
|
+
}
|
|
2011
|
+
return defaultName;
|
|
2012
|
+
},
|
|
1839
2013
|
}),
|
|
1840
2014
|
],
|
|
1841
2015
|
});
|
|
@@ -1863,7 +2037,7 @@ function expressErrorHandler(options
|
|
|
1863
2037
|
res,
|
|
1864
2038
|
next,
|
|
1865
2039
|
) {
|
|
1866
|
-
const shouldHandleError = _optionalChain$
|
|
2040
|
+
const shouldHandleError = _optionalChain$6([options, 'optionalAccess', _ => _.shouldHandleError]) || defaultShouldHandleError;
|
|
1867
2041
|
|
|
1868
2042
|
if (shouldHandleError(error)) {
|
|
1869
2043
|
const client = getClient$1();
|
|
@@ -1914,6 +2088,7 @@ function defaultShouldHandleError(error) {
|
|
|
1914
2088
|
return status >= 500;
|
|
1915
2089
|
}
|
|
1916
2090
|
|
|
2091
|
+
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; }
|
|
1917
2092
|
const _fastifyIntegration = (() => {
|
|
1918
2093
|
return {
|
|
1919
2094
|
name: 'Fastify',
|
|
@@ -1945,11 +2120,25 @@ const fastifyIntegration = defineIntegration(_fastifyIntegration);
|
|
|
1945
2120
|
*/
|
|
1946
2121
|
function setupFastifyErrorHandler(fastify) {
|
|
1947
2122
|
const plugin = Object.assign(
|
|
1948
|
-
function (fastify,
|
|
2123
|
+
function (fastify, _options, done) {
|
|
1949
2124
|
fastify.addHook('onError', async (_request, _reply, error) => {
|
|
1950
2125
|
captureException(error);
|
|
1951
2126
|
});
|
|
1952
2127
|
|
|
2128
|
+
// registering `onRequest` hook here instead of using Otel `onRequest` callback b/c `onRequest` hook
|
|
2129
|
+
// is ironically called in the fastify `preHandler` hook which is called later in the lifecycle:
|
|
2130
|
+
// https://fastify.dev/docs/latest/Reference/Lifecycle/
|
|
2131
|
+
fastify.addHook('onRequest', async (request, _reply) => {
|
|
2132
|
+
const reqWithRouteInfo = request ;
|
|
2133
|
+
|
|
2134
|
+
// Taken from Otel Fastify instrumentation:
|
|
2135
|
+
// https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/plugins/node/opentelemetry-instrumentation-fastify/src/instrumentation.ts#L94-L96
|
|
2136
|
+
const routeName = _optionalChain$5([reqWithRouteInfo, 'access', _ => _.routeOptions, 'optionalAccess', _2 => _2.url]) || reqWithRouteInfo.routerPath;
|
|
2137
|
+
const method = _optionalChain$5([reqWithRouteInfo, 'access', _3 => _3.routeOptions, 'optionalAccess', _4 => _4.method]) || 'GET';
|
|
2138
|
+
|
|
2139
|
+
getIsolationScope().setTransactionName(`${method} ${routeName}`);
|
|
2140
|
+
});
|
|
2141
|
+
|
|
1953
2142
|
done();
|
|
1954
2143
|
},
|
|
1955
2144
|
{
|
|
@@ -2076,6 +2265,7 @@ const _mysql2Integration = (() => {
|
|
|
2076
2265
|
*/
|
|
2077
2266
|
const mysql2Integration = defineIntegration(_mysql2Integration);
|
|
2078
2267
|
|
|
2268
|
+
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; }
|
|
2079
2269
|
const _nestIntegration = (() => {
|
|
2080
2270
|
return {
|
|
2081
2271
|
name: 'Nest',
|
|
@@ -2103,9 +2293,22 @@ const SentryNestExceptionFilter = {
|
|
|
2103
2293
|
/**
|
|
2104
2294
|
* Setup an error handler for Nest.
|
|
2105
2295
|
*/
|
|
2106
|
-
function setupNestErrorHandler(app
|
|
2296
|
+
function setupNestErrorHandler(app) {
|
|
2297
|
+
app.useGlobalInterceptors({
|
|
2298
|
+
intercept(context, next) {
|
|
2299
|
+
if (getIsolationScope() === getDefaultIsolationScope()) {
|
|
2300
|
+
logger.warn('Isolation scope is still the default isolation scope, skipping setting transactionName.');
|
|
2301
|
+
return next.handle();
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
const req = context.switchToHttp().getRequest();
|
|
2305
|
+
if (req.route) {
|
|
2306
|
+
getIsolationScope().setTransactionName(`${_optionalChain$4([req, 'access', _ => _.method, 'optionalAccess', _2 => _2.toUpperCase, 'call', _3 => _3()]) || 'GET'} ${req.route.path}`);
|
|
2307
|
+
}
|
|
2308
|
+
return next.handle();
|
|
2309
|
+
},
|
|
2310
|
+
});
|
|
2107
2311
|
|
|
2108
|
-
) {
|
|
2109
2312
|
app.useGlobalFilters(SentryNestExceptionFilter);
|
|
2110
2313
|
}
|
|
2111
2314
|
|
|
@@ -2159,6 +2362,7 @@ const _prismaIntegration = (() => {
|
|
|
2159
2362
|
*/
|
|
2160
2363
|
const prismaIntegration = defineIntegration(_prismaIntegration);
|
|
2161
2364
|
|
|
2365
|
+
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; }
|
|
2162
2366
|
const _hapiIntegration = (() => {
|
|
2163
2367
|
return {
|
|
2164
2368
|
name: 'Hapi',
|
|
@@ -2206,6 +2410,16 @@ const hapiErrorPlugin = {
|
|
|
2206
2410
|
const server = serverArg ;
|
|
2207
2411
|
|
|
2208
2412
|
server.events.on('request', (request, event) => {
|
|
2413
|
+
if (getIsolationScope() !== getDefaultIsolationScope()) {
|
|
2414
|
+
const route = request.route;
|
|
2415
|
+
if (route && route.path) {
|
|
2416
|
+
getIsolationScope().setTransactionName(`${_optionalChain$3([route, 'access', _ => _.method, 'optionalAccess', _2 => _2.toUpperCase, 'call', _3 => _3()]) || 'GET'} ${route.path}`);
|
|
2417
|
+
}
|
|
2418
|
+
} else {
|
|
2419
|
+
DEBUG_BUILD &&
|
|
2420
|
+
logger.warn('Isolation scope is still the default isolation scope - skipping setting transactionName');
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2209
2423
|
const activeSpan = getActiveSpan();
|
|
2210
2424
|
const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;
|
|
2211
2425
|
|
|
@@ -2235,7 +2449,23 @@ const _koaIntegration = (() => {
|
|
|
2235
2449
|
name: 'Koa',
|
|
2236
2450
|
setupOnce() {
|
|
2237
2451
|
registerInstrumentations({
|
|
2238
|
-
instrumentations: [
|
|
2452
|
+
instrumentations: [
|
|
2453
|
+
new KoaInstrumentation({
|
|
2454
|
+
requestHook(span, info) {
|
|
2455
|
+
if (getIsolationScope() === getDefaultIsolationScope()) {
|
|
2456
|
+
DEBUG_BUILD &&
|
|
2457
|
+
logger.warn('Isolation scope is default isolation scope - skipping setting transactionName');
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
const attributes = spanToJSON(span).data;
|
|
2461
|
+
const route = attributes && attributes[SEMATTRS_HTTP_ROUTE];
|
|
2462
|
+
const method = info.context.request.method.toUpperCase() || 'GET';
|
|
2463
|
+
if (route) {
|
|
2464
|
+
getIsolationScope().setTransactionName(`${method} ${route}`);
|
|
2465
|
+
}
|
|
2466
|
+
},
|
|
2467
|
+
}),
|
|
2468
|
+
],
|
|
2239
2469
|
});
|
|
2240
2470
|
},
|
|
2241
2471
|
};
|
|
@@ -2807,7 +3037,7 @@ function makeNodeTransport(options) {
|
|
|
2807
3037
|
: new nativeHttpModule.Agent({ keepAlive, maxSockets: 30, timeout: 2000 });
|
|
2808
3038
|
|
|
2809
3039
|
// This ensures we do not generate any spans in OpenTelemetry for the transport
|
|
2810
|
-
return
|
|
3040
|
+
return suppressTracing(() => {
|
|
2811
3041
|
const requestExecutor = createRequestExecutor(options, _nullishCoalesce(options.httpModule, () => ( nativeHttpModule)), agent);
|
|
2812
3042
|
return createTransport(options, requestExecutor);
|
|
2813
3043
|
});
|
|
@@ -3075,9 +3305,9 @@ function setupOtel(client) {
|
|
|
3075
3305
|
const provider = new BasicTracerProvider({
|
|
3076
3306
|
sampler: new SentrySampler(client),
|
|
3077
3307
|
resource: new Resource({
|
|
3078
|
-
[
|
|
3079
|
-
[
|
|
3080
|
-
[
|
|
3308
|
+
[SEMRESATTRS_SERVICE_NAME]: 'node',
|
|
3309
|
+
[SEMRESATTRS_SERVICE_NAMESPACE]: 'sentry',
|
|
3310
|
+
[SEMRESATTRS_SERVICE_VERSION]: SDK_VERSION,
|
|
3081
3311
|
}),
|
|
3082
3312
|
forceFlushTimeoutMillis: 500,
|
|
3083
3313
|
});
|