faastjs
Version:
Serverless batch computing made simple.
177 lines • 26.1 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.receiveMessages = exports.processAwsErrorMessage = exports.createSQSQueue = exports.publishFunctionCallMessage = exports.sendResponseQueueMessage = exports.createSNSTopic = void 0;
const abort_controller_1 = require("@aws-sdk/abort-controller");
const error_1 = require("../error");
const log_1 = require("../log");
const serialize_1 = require("../serialize");
const shared_1 = require("../shared");
const throttle_1 = require("../throttle");
const wrapper_1 = require("../wrapper");
async function createSNSTopic(sns, Name) {
const topic = await sns.createTopic({ Name });
return topic.TopicArn;
}
exports.createSNSTopic = createSNSTopic;
function countRequests(bytes) {
return Math.ceil(bytes / (64 * 1024));
}
async function sendResponseQueueMessage(sqs, QueueUrl, message, cc) {
try {
const request = { QueueUrl, MessageBody: (0, serialize_1.serialize)(message) };
const len = request.MessageBody.length;
if (len > 262144) {
throw new Error(`Response length (${len} bytes) exceeds limit of 256KiB`);
}
await sqs.sendMessage(request);
}
catch (err) {
log_1.log.warn(`sendResponseQueueMessage failed: ${err}`);
const errorResponse = (0, wrapper_1.createErrorResponse)(err, cc);
const errorRequest = { QueueUrl, MessageBody: (0, serialize_1.serialize)(errorResponse) };
try {
await sqs.sendMessage(errorRequest);
}
catch (errorResponseError) {
log_1.log.warn(`Error sending error response to response queue: ${errorResponseError}`);
}
}
}
exports.sendResponseQueueMessage = sendResponseQueueMessage;
function publishFunctionCallMessage(sns, TopicArn, message, metrics) {
const serialized = (0, serialize_1.serialize)(message);
metrics.sns64kRequests += countRequests(serialized.length);
return (0, throttle_1.retryOp)((err, n) => n < 6 && err?.message?.match(/does not exist/), () => sns.publish({ TopicArn, Message: serialized }));
}
exports.publishFunctionCallMessage = publishFunctionCallMessage;
async function createSQSQueue(QueueName, VTimeout, sqs) {
try {
const createQueueRequest = {
QueueName,
Attributes: {
VisibilityTimeout: `${VTimeout}`
}
};
const response = await sqs.createQueue(createQueueRequest);
const QueueUrl = response.QueueUrl;
const arnResponse = await sqs.getQueueAttributes({
QueueUrl,
AttributeNames: ["QueueArn"]
});
const QueueArn = arnResponse.Attributes?.QueueArn;
return { QueueUrl, QueueArn };
}
catch (err) {
throw new error_1.FaastError(err, "create sqs queue");
}
}
exports.createSQSQueue = createSQSQueue;
/* c8 ignore next */
function processAwsErrorMessage(message) {
let err = new error_1.FaastError(message);
if (message?.match(/Process exited before completing/) ||
message?.match(/signal: killed/) ||
message?.match(/Runtime exited/)) {
err = new error_1.FaastError({ cause: err, name: error_1.FaastErrorNames.EMEMORY }, "possibly out of memory");
}
else if (message?.match(/time/)) {
err = new error_1.FaastError({ cause: err, name: error_1.FaastErrorNames.ETIMEOUT }, "timeout");
}
else if (message?.match(/EventAgeExceeded/)) {
err = new error_1.FaastError({ cause: err, name: error_1.FaastErrorNames.ECONCURRENCY }, "concurrency limit exceeded");
}
return err;
}
exports.processAwsErrorMessage = processAwsErrorMessage;
async function receiveMessages(sqs, ResponseQueueUrl, metrics, cancel) {
try {
const MaxNumberOfMessages = 10;
const abortController = new abort_controller_1.AbortController();
const request = sqs.receiveMessage({
QueueUrl: ResponseQueueUrl,
WaitTimeSeconds: 20,
MaxNumberOfMessages,
MessageAttributeNames: ["All"],
AttributeNames: ["SentTimestamp"]
}, { abortSignal: abortController.signal });
const response = await Promise.race([request, cancel]);
if (!response) {
abortController.abort();
return { Messages: [] };
}
const { Messages = [] } = response;
const receivedBytes = Messages.reduce((sum, m) => sum + (m.Body?.length ?? 0), 0);
metrics.outboundBytes += receivedBytes;
const inferredSqsRequestsReceived = countRequests(receivedBytes);
// Each request is counted as both sent and received.
metrics.sqs64kRequests += inferredSqsRequestsReceived * 2;
if (Messages.length > 0) {
sqs.deleteMessageBatch({
QueueUrl: ResponseQueueUrl,
Entries: Messages.map(m => ({
Id: m.MessageId,
ReceiptHandle: m.ReceiptHandle
}))
}).catch(_ => { });
metrics.sqs64kRequests++;
}
return {
Messages: Messages.map(processIncomingQueueMessage).filter(shared_1.defined),
isFullMessageBatch: Messages.length === MaxNumberOfMessages
};
}
catch (err) {
throw new error_1.FaastError(err, "receiveMessages");
}
}
exports.receiveMessages = receiveMessages;
function processIncomingQueueMessage(m) {
// AWS Lambda Destinations
// (https://aws.amazon.com/blogs/compute/introducing-aws-lambda-destinations/)
// are used to route failures to the response queue. These
// messages are generated by AWS Lambda and are constrained to the format it
// provides.
const raw = (0, serialize_1.deserialize)(m.Body);
if (raw.responseContext) {
const message = raw;
const snsMessage = message.requestPayload;
const record = snsMessage.Records[0];
const sCall = (0, serialize_1.deserialize)(record.Sns.Message);
let error;
const destinationError = message.responsePayload;
if (destinationError) {
error = processAwsErrorMessage(destinationError.errorMessage);
error.stack = destinationError.stackTrace?.join("\n");
}
else {
error = processAwsErrorMessage(message.requestContext.condition);
}
const executionId = message.requestContext.requestId;
return {
...(0, wrapper_1.createErrorResponse)(error, {
call: sCall,
startTime: new Date(record.Sns.Timestamp).getTime(),
executionId
}),
timestamp: new Date(message.timestamp).getTime()
};
}
else {
const message = raw;
switch (message.kind) {
case "promise":
case "iterator":
message.timestamp = Number(m.Attributes.SentTimestamp);
break;
case "cpumetrics":
break;
case "functionstarted":
break;
default: {
console.warn(`Unknown message received from response queue`);
}
}
return raw;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXdzLXF1ZXVlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2F3cy9hd3MtcXVldWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsZ0VBQTREO0FBSTVELG9DQUF1RDtBQUN2RCxnQ0FBNkI7QUFFN0IsNENBQXNEO0FBQ3RELHNDQUFvQztBQUNwQywwQ0FBc0M7QUFDdEMsd0NBQStFO0FBR3hFLEtBQUssVUFBVSxjQUFjLENBQUMsR0FBUSxFQUFFLElBQVk7SUFDdkQsTUFBTSxLQUFLLEdBQUcsTUFBTSxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUM5QyxPQUFPLEtBQUssQ0FBQyxRQUFTLENBQUM7QUFDM0IsQ0FBQztBQUhELHdDQUdDO0FBRUQsU0FBUyxhQUFhLENBQUMsS0FBYTtJQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxHQUFHLENBQUMsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUM7QUFDMUMsQ0FBQztBQUVNLEtBQUssVUFBVSx3QkFBd0IsQ0FDMUMsR0FBUSxFQUNSLFFBQWdCLEVBQ2hCLE9BQWdCLEVBQ2hCLEVBQWtCO0lBRWxCLElBQUksQ0FBQztRQUNELE1BQU0sT0FBTyxHQUFHLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxJQUFBLHFCQUFTLEVBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUM5RCxNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQztRQUN2QyxJQUFJLEdBQUcsR0FBRyxNQUFNLEVBQUUsQ0FBQztZQUNmLE1BQU0sSUFBSSxLQUFLLENBQUMsb0JBQW9CLEdBQUcsaUNBQWlDLENBQUMsQ0FBQztRQUM5RSxDQUFDO1FBQ0QsTUFBTSxHQUFHLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ25DLENBQUM7SUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ1gsU0FBRyxDQUFDLElBQUksQ0FBQyxvQ0FBb0MsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUNwRCxNQUFNLGFBQWEsR0FBRyxJQUFBLDZCQUFtQixFQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNuRCxNQUFNLFlBQVksR0FBRyxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsSUFBQSxxQkFBUyxFQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUM7UUFDekUsSUFBSSxDQUFDO1lBQ0QsTUFBTSxHQUFHLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3hDLENBQUM7UUFBQyxPQUFPLGtCQUF1QixFQUFFLENBQUM7WUFDL0IsU0FBRyxDQUFDLElBQUksQ0FDSixtREFBbUQsa0JBQWtCLEVBQUUsQ0FDMUUsQ0FBQztRQUNOLENBQUM7SUFDTCxDQUFDO0FBQ0wsQ0FBQztBQXpCRCw0REF5QkM7QUFFRCxTQUFnQiwwQkFBMEIsQ0FDdEMsR0FBUSxFQUNSLFFBQWdCLEVBQ2hCLE9BQXFCLEVBQ3JCLE9BQW1CO0lBRW5CLE1BQU0sVUFBVSxHQUFHLElBQUEscUJBQVMsRUFBQyxPQUFPLENBQUMsQ0FBQztJQUN0QyxPQUFPLENBQUMsY0FBYyxJQUFJLGFBQWEsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDM0QsT0FBTyxJQUFBLGtCQUFPLEVBQ1YsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLGdCQUFnQixDQUFDLEVBQzFELEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQ3ZELENBQUM7QUFDTixDQUFDO0FBWkQsZ0VBWUM7QUFFTSxLQUFLLFVBQVUsY0FBYyxDQUFDLFNBQWlCLEVBQUUsUUFBZ0IsRUFBRSxHQUFRO0lBQzlFLElBQUksQ0FBQztRQUNELE1BQU0sa0JBQWtCLEdBQXVCO1lBQzNDLFNBQVM7WUFDVCxVQUFVLEVBQUU7Z0JBQ1IsaUJBQWlCLEVBQUUsR0FBRyxRQUFRLEVBQUU7YUFDbkM7U0FDSixDQUFDO1FBQ0YsTUFBTSxRQUFRLEdBQUcsTUFBTSxHQUFHLENBQUMsV0FBVyxDQUFDLGtCQUFrQixDQUFDLENBQUM7UUFDM0QsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLFFBQVMsQ0FBQztRQUNwQyxNQUFNLFdBQVcsR0FBRyxNQUFNLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQztZQUM3QyxRQUFRO1lBQ1IsY0FBYyxFQUFFLENBQUMsVUFBVSxDQUFDO1NBQy9CLENBQUMsQ0FBQztRQUNILE1BQU0sUUFBUSxHQUFHLFdBQVcsQ0FBQyxVQUFVLEVBQUUsUUFBUSxDQUFDO1FBQ2xELE9BQU8sRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLENBQUM7SUFDbEMsQ0FBQztJQUFDLE9BQU8sR0FBUSxFQUFFLENBQUM7UUFDaEIsTUFBTSxJQUFJLGtCQUFVLENBQUMsR0FBRyxFQUFFLGtCQUFrQixDQUFDLENBQUM7SUFDbEQsQ0FBQztBQUNMLENBQUM7QUFuQkQsd0NBbUJDO0FBRUQscUJBQXFCO0FBQ3JCLFNBQWdCLHNCQUFzQixDQUFDLE9BQWdCO0lBQ25ELElBQUksR0FBRyxHQUFHLElBQUksa0JBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNsQyxJQUNJLE9BQU8sRUFBRSxLQUFLLENBQUMsa0NBQWtDLENBQUM7UUFDbEQsT0FBTyxFQUFFLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQztRQUNoQyxPQUFPLEVBQUUsS0FBSyxDQUFDLGdCQUFnQixDQUFDLEVBQ2xDLENBQUM7UUFDQyxHQUFHLEdBQUcsSUFBSSxrQkFBVSxDQUNoQixFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLHVCQUFlLENBQUMsT0FBTyxFQUFFLEVBQzdDLHdCQUF3QixDQUMzQixDQUFDO0lBQ04sQ0FBQztTQUFNLElBQUksT0FBTyxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQ2hDLEdBQUcsR0FBRyxJQUFJLGtCQUFVLENBQUMsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSx1QkFBZSxDQUFDLFFBQVEsRUFBRSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBQ3BGLENBQUM7U0FBTSxJQUFJLE9BQU8sRUFBRSxLQUFLLENBQUMsa0JBQWtCLENBQUMsRUFBRSxDQUFDO1FBQzVDLEdBQUcsR0FBRyxJQUFJLGtCQUFVLENBQ2hCLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsdUJBQWUsQ0FBQyxZQUFZLEVBQUUsRUFDbEQsNEJBQTRCLENBQy9CLENBQUM7SUFDTixDQUFDO0lBQ0QsT0FBTyxHQUFHLENBQUM7QUFDZixDQUFDO0FBcEJELHdEQW9CQztBQUVNLEtBQUssVUFBVSxlQUFlLENBQ2pDLEdBQVEsRUFDUixnQkFBd0IsRUFDeEIsT0FBbUIsRUFDbkIsTUFBcUI7SUFFckIsSUFBSSxDQUFDO1FBQ0QsTUFBTSxtQkFBbUIsR0FBRyxFQUFFLENBQUM7UUFDL0IsTUFBTSxlQUFlLEdBQUcsSUFBSSxrQ0FBZSxFQUFFLENBQUM7UUFDOUMsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLGNBQWMsQ0FDOUI7WUFDSSxRQUFRLEVBQUUsZ0JBQWlCO1lBQzNCLGVBQWUsRUFBRSxFQUFFO1lBQ25CLG1CQUFtQjtZQUNuQixxQkFBcUIsRUFBRSxDQUFDLEtBQUssQ0FBQztZQUM5QixjQUFjLEVBQUUsQ0FBQyxlQUFlLENBQUM7U0FDcEMsRUFDRCxFQUFFLFdBQVcsRUFBRSxlQUFlLENBQUMsTUFBTSxFQUFFLENBQzFDLENBQUM7UUFDRixNQUFNLFFBQVEsR0FBRyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUN2RCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDWixlQUFlLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDeEIsT0FBTyxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsQ0FBQztRQUM1QixDQUFDO1FBRUQsTUFBTSxFQUFFLFFBQVEsR0FBRyxFQUFFLEVBQUUsR0FBRyxRQUFRLENBQUM7UUFDbkMsTUFBTSxhQUFhLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsTUFBTSxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ2xGLE9BQU8sQ0FBQyxhQUFhLElBQUksYUFBYSxDQUFDO1FBQ3ZDLE1BQU0sMkJBQTJCLEdBQUcsYUFBYSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ2pFLHFEQUFxRDtRQUNyRCxPQUFPLENBQUMsY0FBYyxJQUFJLDJCQUEyQixHQUFHLENBQUMsQ0FBQztRQUUxRCxJQUFJLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdEIsR0FBRyxDQUFDLGtCQUFrQixDQUFDO2dCQUNuQixRQUFRLEVBQUUsZ0JBQWlCO2dCQUMzQixPQUFPLEVBQUUsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7b0JBQ3hCLEVBQUUsRUFBRSxDQUFDLENBQUMsU0FBVTtvQkFDaEIsYUFBYSxFQUFFLENBQUMsQ0FBQyxhQUFjO2lCQUNsQyxDQUFDLENBQUM7YUFDTixDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUUsQ0FBQyxDQUFDLENBQUM7WUFDbEIsT0FBTyxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQzdCLENBQUM7UUFDRCxPQUFPO1lBQ0gsUUFBUSxFQUFFLFFBQVEsQ0FBQyxHQUFHLENBQUMsMkJBQTJCLENBQUMsQ0FBQyxNQUFNLENBQUMsZ0JBQU8sQ0FBQztZQUNuRSxrQkFBa0IsRUFBRSxRQUFRLENBQUMsTUFBTSxLQUFLLG1CQUFtQjtTQUM5RCxDQUFDO0lBQ04sQ0FBQztJQUFDLE9BQU8sR0FBUSxFQUFFLENBQUM7UUFDaEIsTUFBTSxJQUFJLGtCQUFVLENBQUMsR0FBRyxFQUFFLGlCQUFpQixDQUFDLENBQUM7SUFDakQsQ0FBQztBQUNMLENBQUM7QUFqREQsMENBaURDO0FBMEJELFNBQVMsMkJBQTJCLENBQUMsQ0FBYTtJQUM5QywwQkFBMEI7SUFDMUIsOEVBQThFO0lBQzlFLDBEQUEwRDtJQUMxRCw0RUFBNEU7SUFDNUUsWUFBWTtJQUNaLE1BQU0sR0FBRyxHQUFHLElBQUEsdUJBQVcsRUFBQyxDQUFDLENBQUMsSUFBSyxDQUFDLENBQUM7SUFDakMsSUFBSSxHQUFHLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDdEIsTUFBTSxPQUFPLEdBQUcsR0FBK0IsQ0FBQztRQUNoRCxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsY0FBMEIsQ0FBQztRQUN0RCxNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JDLE1BQU0sS0FBSyxHQUFpQixJQUFBLHVCQUFXLEVBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM1RCxJQUFJLEtBQXdCLENBQUM7UUFDN0IsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsZUFBeUMsQ0FBQztRQUMzRSxJQUFJLGdCQUFnQixFQUFFLENBQUM7WUFDbkIsS0FBSyxHQUFHLHNCQUFzQixDQUFDLGdCQUFnQixDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQzlELEtBQUssQ0FBQyxLQUFLLEdBQUcsZ0JBQWdCLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMxRCxDQUFDO2FBQU0sQ0FBQztZQUNKLEtBQUssR0FBRyxzQkFBc0IsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3JFLENBQUM7UUFDRCxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQztRQUNyRCxPQUFPO1lBQ0gsR0FBRyxJQUFBLDZCQUFtQixFQUFDLEtBQUssRUFBRTtnQkFDMUIsSUFBSSxFQUFFLEtBQUs7Z0JBQ1gsU0FBUyxFQUFFLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsT0FBTyxFQUFFO2dCQUNuRCxXQUFXO2FBQ2QsQ0FBQztZQUNGLFNBQVMsRUFBRSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsT0FBTyxFQUFFO1NBQ25ELENBQUM7SUFDTixDQUFDO1NBQU0sQ0FBQztRQUNKLE1BQU0sT0FBTyxHQUFHLEdBQWMsQ0FBQztRQUMvQixRQUFRLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNuQixLQUFLLFNBQVMsQ0FBQztZQUNmLEtBQUssVUFBVTtnQkFDWCxPQUFPLENBQUMsU0FBUyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsVUFBVyxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUN4RCxNQUFNO1lBQ1YsS0FBSyxZQUFZO2dCQUNiLE1BQU07WUFDVixLQUFLLGlCQUFpQjtnQkFDbEIsTUFBTTtZQUNWLE9BQU8sQ0FBQyxDQUFDLENBQUM7Z0JBQ04sT0FBTyxDQUFDLElBQUksQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDO1lBQ2pFLENBQUM7UUFDTCxDQUFDO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDZixDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFib3J0Q29udHJvbGxlciB9IGZyb20gXCJAYXdzLXNkay9hYm9ydC1jb250cm9sbGVyXCI7XG5pbXBvcnQgeyBTTlMgfSBmcm9tIFwiQGF3cy1zZGsvY2xpZW50LXNuc1wiO1xuaW1wb3J0IHsgQ3JlYXRlUXVldWVSZXF1ZXN0LCBTUVMsIE1lc3NhZ2UgYXMgU1FTTWVzc2FnZSB9IGZyb20gXCJAYXdzLXNkay9jbGllbnQtc3FzXCI7XG5pbXBvcnQgeyBTTlNFdmVudCB9IGZyb20gXCJhd3MtbGFtYmRhL3RyaWdnZXIvc25zXCI7XG5pbXBvcnQgeyBGYWFzdEVycm9yLCBGYWFzdEVycm9yTmFtZXMgfSBmcm9tIFwiLi4vZXJyb3JcIjtcbmltcG9ydCB7IGxvZyB9IGZyb20gXCIuLi9sb2dcIjtcbmltcG9ydCB7IE1lc3NhZ2UsIFBvbGxSZXN1bHQgfSBmcm9tIFwiLi4vcHJvdmlkZXJcIjtcbmltcG9ydCB7IGRlc2VyaWFsaXplLCBzZXJpYWxpemUgfSBmcm9tIFwiLi4vc2VyaWFsaXplXCI7XG5pbXBvcnQgeyBkZWZpbmVkIH0gZnJvbSBcIi4uL3NoYXJlZFwiO1xuaW1wb3J0IHsgcmV0cnlPcCB9IGZyb20gXCIuLi90aHJvdHRsZVwiO1xuaW1wb3J0IHsgQ2FsbGluZ0NvbnRleHQsIEZ1bmN0aW9uQ2FsbCwgY3JlYXRlRXJyb3JSZXNwb25zZSB9IGZyb20gXCIuLi93cmFwcGVyXCI7XG5pbXBvcnQgeyBBd3NNZXRyaWNzIH0gZnJvbSBcIi4vYXdzLWZhYXN0XCI7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVTTlNUb3BpYyhzbnM6IFNOUywgTmFtZTogc3RyaW5nKSB7XG4gICAgY29uc3QgdG9waWMgPSBhd2FpdCBzbnMuY3JlYXRlVG9waWMoeyBOYW1lIH0pO1xuICAgIHJldHVybiB0b3BpYy5Ub3BpY0FybiE7XG59XG5cbmZ1bmN0aW9uIGNvdW50UmVxdWVzdHMoYnl0ZXM6IG51bWJlcikge1xuICAgIHJldHVybiBNYXRoLmNlaWwoYnl0ZXMgLyAoNjQgKiAxMDI0KSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZW5kUmVzcG9uc2VRdWV1ZU1lc3NhZ2UoXG4gICAgc3FzOiBTUVMsXG4gICAgUXVldWVVcmw6IHN0cmluZyxcbiAgICBtZXNzYWdlOiBNZXNzYWdlLFxuICAgIGNjOiBDYWxsaW5nQ29udGV4dFxuKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVxdWVzdCA9IHsgUXVldWVVcmwsIE1lc3NhZ2VCb2R5OiBzZXJpYWxpemUobWVzc2FnZSkgfTtcbiAgICAgICAgY29uc3QgbGVuID0gcmVxdWVzdC5NZXNzYWdlQm9keS5sZW5ndGg7XG4gICAgICAgIGlmIChsZW4gPiAyNjIxNDQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgUmVzcG9uc2UgbGVuZ3RoICgke2xlbn0gYnl0ZXMpIGV4Y2VlZHMgbGltaXQgb2YgMjU2S2lCYCk7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgc3FzLnNlbmRNZXNzYWdlKHJlcXVlc3QpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBsb2cud2Fybihgc2VuZFJlc3BvbnNlUXVldWVNZXNzYWdlIGZhaWxlZDogJHtlcnJ9YCk7XG4gICAgICAgIGNvbnN0IGVycm9yUmVzcG9uc2UgPSBjcmVhdGVFcnJvclJlc3BvbnNlKGVyciwgY2MpO1xuICAgICAgICBjb25zdCBlcnJvclJlcXVlc3QgPSB7IFF1ZXVlVXJsLCBNZXNzYWdlQm9keTogc2VyaWFsaXplKGVycm9yUmVzcG9uc2UpIH07XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBzcXMuc2VuZE1lc3NhZ2UoZXJyb3JSZXF1ZXN0KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3JSZXNwb25zZUVycm9yOiBhbnkpIHtcbiAgICAgICAgICAgIGxvZy53YXJuKFxuICAgICAgICAgICAgICAgIGBFcnJvciBzZW5kaW5nIGVycm9yIHJlc3BvbnNlIHRvIHJlc3BvbnNlIHF1ZXVlOiAke2Vycm9yUmVzcG9uc2VFcnJvcn1gXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gcHVibGlzaEZ1bmN0aW9uQ2FsbE1lc3NhZ2UoXG4gICAgc25zOiBTTlMsXG4gICAgVG9waWNBcm46IHN0cmluZyxcbiAgICBtZXNzYWdlOiBGdW5jdGlvbkNhbGwsXG4gICAgbWV0cmljczogQXdzTWV0cmljc1xuKSB7XG4gICAgY29uc3Qgc2VyaWFsaXplZCA9IHNlcmlhbGl6ZShtZXNzYWdlKTtcbiAgICBtZXRyaWNzLnNuczY0a1JlcXVlc3RzICs9IGNvdW50UmVxdWVzdHMoc2VyaWFsaXplZC5sZW5ndGgpO1xuICAgIHJldHVybiByZXRyeU9wKFxuICAgICAgICAoZXJyLCBuKSA9PiBuIDwgNiAmJiBlcnI/Lm1lc3NhZ2U/Lm1hdGNoKC9kb2VzIG5vdCBleGlzdC8pLFxuICAgICAgICAoKSA9PiBzbnMucHVibGlzaCh7IFRvcGljQXJuLCBNZXNzYWdlOiBzZXJpYWxpemVkIH0pXG4gICAgKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZVNRU1F1ZXVlKFF1ZXVlTmFtZTogc3RyaW5nLCBWVGltZW91dDogbnVtYmVyLCBzcXM6IFNRUykge1xuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGNyZWF0ZVF1ZXVlUmVxdWVzdDogQ3JlYXRlUXVldWVSZXF1ZXN0ID0ge1xuICAgICAgICAgICAgUXVldWVOYW1lLFxuICAgICAgICAgICAgQXR0cmlidXRlczoge1xuICAgICAgICAgICAgICAgIFZpc2liaWxpdHlUaW1lb3V0OiBgJHtWVGltZW91dH1gXG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgc3FzLmNyZWF0ZVF1ZXVlKGNyZWF0ZVF1ZXVlUmVxdWVzdCk7XG4gICAgICAgIGNvbnN0IFF1ZXVlVXJsID0gcmVzcG9uc2UuUXVldWVVcmwhO1xuICAgICAgICBjb25zdCBhcm5SZXNwb25zZSA9IGF3YWl0IHNxcy5nZXRRdWV1ZUF0dHJpYnV0ZXMoe1xuICAgICAgICAgICAgUXVldWVVcmwsXG4gICAgICAgICAgICBBdHRyaWJ1dGVOYW1lczogW1wiUXVldWVBcm5cIl1cbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IFF1ZXVlQXJuID0gYXJuUmVzcG9uc2UuQXR0cmlidXRlcz8uUXVldWVBcm47XG4gICAgICAgIHJldHVybiB7IFF1ZXVlVXJsLCBRdWV1ZUFybiB9O1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIHRocm93IG5ldyBGYWFzdEVycm9yKGVyciwgXCJjcmVhdGUgc3FzIHF1ZXVlXCIpO1xuICAgIH1cbn1cblxuLyogYzggaWdub3JlIG5leHQgICovXG5leHBvcnQgZnVuY3Rpb24gcHJvY2Vzc0F3c0Vycm9yTWVzc2FnZShtZXNzYWdlPzogc3RyaW5nKTogRXJyb3Ige1xuICAgIGxldCBlcnIgPSBuZXcgRmFhc3RFcnJvcihtZXNzYWdlKTtcbiAgICBpZiAoXG4gICAgICAgIG1lc3NhZ2U/Lm1hdGNoKC9Qcm9jZXNzIGV4aXRlZCBiZWZvcmUgY29tcGxldGluZy8pIHx8XG4gICAgICAgIG1lc3NhZ2U/Lm1hdGNoKC9zaWduYWw6IGtpbGxlZC8pIHx8XG4gICAgICAgIG1lc3NhZ2U/Lm1hdGNoKC9SdW50aW1lIGV4aXRlZC8pXG4gICAgKSB7XG4gICAgICAgIGVyciA9IG5ldyBGYWFzdEVycm9yKFxuICAgICAgICAgICAgeyBjYXVzZTogZXJyLCBuYW1lOiBGYWFzdEVycm9yTmFtZXMuRU1FTU9SWSB9LFxuICAgICAgICAgICAgXCJwb3NzaWJseSBvdXQgb2YgbWVtb3J5XCJcbiAgICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKG1lc3NhZ2U/Lm1hdGNoKC90aW1lLykpIHtcbiAgICAgICAgZXJyID0gbmV3IEZhYXN0RXJyb3IoeyBjYXVzZTogZXJyLCBuYW1lOiBGYWFzdEVycm9yTmFtZXMuRVRJTUVPVVQgfSwgXCJ0aW1lb3V0XCIpO1xuICAgIH0gZWxzZSBpZiAobWVzc2FnZT8ubWF0Y2goL0V2ZW50QWdlRXhjZWVkZWQvKSkge1xuICAgICAgICBlcnIgPSBuZXcgRmFhc3RFcnJvcihcbiAgICAgICAgICAgIHsgY2F1c2U6IGVyciwgbmFtZTogRmFhc3RFcnJvck5hbWVzLkVDT05DVVJSRU5DWSB9LFxuICAgICAgICAgICAgXCJjb25jdXJyZW5jeSBsaW1pdCBleGNlZWRlZFwiXG4gICAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBlcnI7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWNlaXZlTWVzc2FnZXMoXG4gICAgc3FzOiBTUVMsXG4gICAgUmVzcG9uc2VRdWV1ZVVybDogc3RyaW5nLFxuICAgIG1ldHJpY3M6IEF3c01ldHJpY3MsXG4gICAgY2FuY2VsOiBQcm9taXNlPHZvaWQ+XG4pOiBQcm9taXNlPFBvbGxSZXN1bHQ+IHtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCBNYXhOdW1iZXJPZk1lc3NhZ2VzID0gMTA7XG4gICAgICAgIGNvbnN0IGFib3J0Q29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgICAgICAgY29uc3QgcmVxdWVzdCA9IHNxcy5yZWNlaXZlTWVzc2FnZShcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBRdWV1ZVVybDogUmVzcG9uc2VRdWV1ZVVybCEsXG4gICAgICAgICAgICAgICAgV2FpdFRpbWVTZWNvbmRzOiAyMCxcbiAgICAgICAgICAgICAgICBNYXhOdW1iZXJPZk1lc3NhZ2VzLFxuICAgICAgICAgICAgICAgIE1lc3NhZ2VBdHRyaWJ1dGVOYW1lczogW1wiQWxsXCJdLFxuICAgICAgICAgICAgICAgIEF0dHJpYnV0ZU5hbWVzOiBbXCJTZW50VGltZXN0YW1wXCJdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgeyBhYm9ydFNpZ25hbDogYWJvcnRDb250cm9sbGVyLnNpZ25hbCB9XG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgUHJvbWlzZS5yYWNlKFtyZXF1ZXN0LCBjYW5jZWxdKTtcbiAgICAgICAgaWYgKCFyZXNwb25zZSkge1xuICAgICAgICAgICAgYWJvcnRDb250cm9sbGVyLmFib3J0KCk7XG4gICAgICAgICAgICByZXR1cm4geyBNZXNzYWdlczogW10gfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHsgTWVzc2FnZXMgPSBbXSB9ID0gcmVzcG9uc2U7XG4gICAgICAgIGNvbnN0IHJlY2VpdmVkQnl0ZXMgPSBNZXNzYWdlcy5yZWR1Y2UoKHN1bSwgbSkgPT4gc3VtICsgKG0uQm9keT8ubGVuZ3RoID8/IDApLCAwKTtcbiAgICAgICAgbWV0cmljcy5vdXRib3VuZEJ5dGVzICs9IHJlY2VpdmVkQnl0ZXM7XG4gICAgICAgIGNvbnN0IGluZmVycmVkU3FzUmVxdWVzdHNSZWNlaXZlZCA9IGNvdW50UmVxdWVzdHMocmVjZWl2ZWRCeXRlcyk7XG4gICAgICAgIC8vIEVhY2ggcmVxdWVzdCBpcyBjb3VudGVkIGFzIGJvdGggc2VudCBhbmQgcmVjZWl2ZWQuXG4gICAgICAgIG1ldHJpY3Muc3FzNjRrUmVxdWVzdHMgKz0gaW5mZXJyZWRTcXNSZXF1ZXN0c1JlY2VpdmVkICogMjtcblxuICAgICAgICBpZiAoTWVzc2FnZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgc3FzLmRlbGV0ZU1lc3NhZ2VCYXRjaCh7XG4gICAgICAgICAgICAgICAgUXVldWVVcmw6IFJlc3BvbnNlUXVldWVVcmwhLFxuICAgICAgICAgICAgICAgIEVudHJpZXM6IE1lc3NhZ2VzLm1hcChtID0+ICh7XG4gICAgICAgICAgICAgICAgICAgIElkOiBtLk1lc3NhZ2VJZCEsXG4gICAgICAgICAgICAgICAgICAgIFJlY2VpcHRIYW5kbGU6IG0uUmVjZWlwdEhhbmRsZSFcbiAgICAgICAgICAgICAgICB9KSlcbiAgICAgICAgICAgIH0pLmNhdGNoKF8gPT4ge30pO1xuICAgICAgICAgICAgbWV0cmljcy5zcXM2NGtSZXF1ZXN0cysrO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBNZXNzYWdlczogTWVzc2FnZXMubWFwKHByb2Nlc3NJbmNvbWluZ1F1ZXVlTWVzc2FnZSkuZmlsdGVyKGRlZmluZWQpLFxuICAgICAgICAgICAgaXNGdWxsTWVzc2FnZUJhdGNoOiBNZXNzYWdlcy5sZW5ndGggPT09IE1heE51bWJlck9mTWVzc2FnZXNcbiAgICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICB0aHJvdyBuZXcgRmFhc3RFcnJvcihlcnIsIFwicmVjZWl2ZU1lc3NhZ2VzXCIpO1xuICAgIH1cbn1cblxuaW50ZXJmYWNlIExhbWJkYURlc3RpbmF0aW9uRXJyb3Ige1xuICAgIGVycm9yTWVzc2FnZTogc3RyaW5nO1xuICAgIGVycm9yVHlwZT86IHN0cmluZztcbiAgICBzdGFja1RyYWNlPzogc3RyaW5nW107XG59XG5cbmludGVyZmFjZSBMYW1iZGFEZXN0aW5hdGlvbk1lc3NhZ2Uge1xuICAgIHZlcnNpb246IHN0cmluZztcbiAgICB0aW1lc3RhbXA6IHN0cmluZztcbiAgICByZXF1ZXN0Q29udGV4dDoge1xuICAgICAgICByZXF1ZXN0SWQ6IHN0cmluZztcbiAgICAgICAgZnVuY3Rpb25Bcm46IHN0cmluZztcbiAgICAgICAgY29uZGl0aW9uOiBcIlJldHJpZXNFeGhhdXN0ZWRcIiB8IFwiU3VjY2Vzc1wiO1xuICAgICAgICBhcHByb3hpbWF0ZUludm9rZUNvdW50OiBudW1iZXI7XG4gICAgfTtcbiAgICByZXF1ZXN0UGF5bG9hZDogb2JqZWN0O1xuICAgIHJlc3BvbnNlQ29udGV4dDoge1xuICAgICAgICBzdGF0dXNDb2RlOiBudW1iZXI7XG4gICAgICAgIGV4ZWN1dGVkVmVyc2lvbjogc3RyaW5nO1xuICAgICAgICBmdW5jdGlvbkVycm9yPzogc3RyaW5nO1xuICAgIH07XG4gICAgcmVzcG9uc2VQYXlsb2FkOiBMYW1iZGFEZXN0aW5hdGlvbkVycm9yIHwgb2JqZWN0O1xufVxuXG5mdW5jdGlvbiBwcm9jZXNzSW5jb21pbmdRdWV1ZU1lc3NhZ2UobTogU1FTTWVzc2FnZSk6IE1lc3NhZ2UgfCB2b2lkIHtcbiAgICAvLyBBV1MgTGFtYmRhIERlc3RpbmF0aW9uc1xuICAgIC8vIChodHRwczovL2F3cy5hbWF6b24uY29tL2Jsb2dzL2NvbXB1dGUvaW50cm9kdWNpbmctYXdzLWxhbWJkYS1kZXN0aW5hdGlvbnMvKVxuICAgIC8vIGFyZSB1c2VkIHRvIHJvdXRlIGZhaWx1cmVzIHRvIHRoZSByZXNwb25zZSBxdWV1ZS4gVGhlc2VcbiAgICAvLyBtZXNzYWdlcyBhcmUgZ2VuZXJhdGVkIGJ5IEFXUyBMYW1iZGEgYW5kIGFyZSBjb25zdHJhaW5lZCB0byB0aGUgZm9ybWF0IGl0XG4gICAgLy8gcHJvdmlkZXMuXG4gICAgY29uc3QgcmF3ID0gZGVzZXJpYWxpemUobS5Cb2R5ISk7XG4gICAgaWYgKHJhdy5yZXNwb25zZUNvbnRleHQpIHtcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9IHJhdyBhcyBMYW1iZGFEZXN0aW5hdGlvbk1lc3NhZ2U7XG4gICAgICAgIGNvbnN0IHNuc01lc3NhZ2UgPSBtZXNzYWdlLnJlcXVlc3RQYXlsb2FkIGFzIFNOU0V2ZW50O1xuICAgICAgICBjb25zdCByZWNvcmQgPSBzbnNNZXNzYWdlLlJlY29yZHNbMF07XG4gICAgICAgIGNvbnN0IHNDYWxsOiBGdW5jdGlvbkNhbGwgPSBkZXNlcmlhbGl6ZShyZWNvcmQuU25zLk1lc3NhZ2UpO1xuICAgICAgICBsZXQgZXJyb3I6IEVycm9yIHwgdW5kZWZpbmVkO1xuICAgICAgICBjb25zdCBkZXN0aW5hdGlvbkVycm9yID0gbWVzc2FnZS5yZXNwb25zZVBheWxvYWQgYXMgTGFtYmRhRGVzdGluYXRpb25FcnJvcjtcbiAgICAgICAgaWYgKGRlc3RpbmF0aW9uRXJyb3IpIHtcbiAgICAgICAgICAgIGVycm9yID0gcHJvY2Vzc0F3c0Vycm9yTWVzc2FnZShkZXN0aW5hdGlvbkVycm9yLmVycm9yTWVzc2FnZSk7XG4gICAgICAgICAgICBlcnJvci5zdGFjayA9IGRlc3RpbmF0aW9uRXJyb3Iuc3RhY2tUcmFjZT8uam9pbihcIlxcblwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGVycm9yID0gcHJvY2Vzc0F3c0Vycm9yTWVzc2FnZShtZXNzYWdlLnJlcXVlc3RDb250ZXh0LmNvbmRpdGlvbik7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZXhlY3V0aW9uSWQgPSBtZXNzYWdlLnJlcXVlc3RDb250ZXh0LnJlcXVlc3RJZDtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIC4uLmNyZWF0ZUVycm9yUmVzcG9uc2UoZXJyb3IsIHtcbiAgICAgICAgICAgICAgICBjYWxsOiBzQ2FsbCxcbiAgICAgICAgICAgICAgICBzdGFydFRpbWU6IG5ldyBEYXRlKHJlY29yZC5TbnMuVGltZXN0YW1wKS5nZXRUaW1lKCksXG4gICAgICAgICAgICAgICAgZXhlY3V0aW9uSWRcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZShtZXNzYWdlLnRpbWVzdGFtcCkuZ2V0VGltZSgpXG4gICAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9IHJhdyBhcyBNZXNzYWdlO1xuICAgICAgICBzd2l0Y2ggKG1lc3NhZ2Uua2luZCkge1xuICAgICAgICAgICAgY2FzZSBcInByb21pc2VcIjpcbiAgICAgICAgICAgIGNhc2UgXCJpdGVyYXRvclwiOlxuICAgICAgICAgICAgICAgIG1lc3NhZ2UudGltZXN0YW1wID0gTnVtYmVyKG0uQXR0cmlidXRlcyEuU2VudFRpbWVzdGFtcCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiY3B1bWV0cmljc1wiOlxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcImZ1bmN0aW9uc3RhcnRlZFwiOlxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDoge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihgVW5rbm93biBtZXNzYWdlIHJlY2VpdmVkIGZyb20gcmVzcG9uc2UgcXVldWVgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmF3O1xuICAgIH1cbn1cbiJdfQ==
;