package.dist.src.internal.leaderboard-data-client.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sdk Show documentation
Show all versions of sdk Show documentation
Client SDK for Momento services
The newest version!
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LeaderboardDataClient = exports.CONNECTION_ID_KEY = void 0;
const sdk_core_1 = require("@gomomento/sdk-core");
const utils_1 = require("@gomomento/sdk-core/dist/src/internal/utils");
const leaderboard_1 = require("@gomomento/generated-types/dist/leaderboard");
var _Element = leaderboard_1.leaderboard._Element;
const idle_grpc_client_wrapper_1 = require("./grpc/idle-grpc-client-wrapper");
const headers_interceptor_1 = require("./grpc/headers-interceptor");
const cache_service_error_mapper_1 = require("../errors/cache-service-error-mapper");
const grpc_js_1 = require("@grpc/grpc-js");
const package_json_1 = require("../../package.json");
const middlewares_interceptor_1 = require("./grpc/middlewares-interceptor");
const grpc_channel_options_1 = require("./grpc/grpc-channel-options");
const common_1 = require("@gomomento/generated-types/dist/common");
const retry_interceptor_1 = require("./grpc/retry-interceptor");
exports.CONNECTION_ID_KEY = Symbol('connectionID');
class LeaderboardDataClient {
/**
* @param {LeaderboardClientAllProps} props
* @param dataClientID
*/
constructor(props, dataClientID) {
this.configuration = props.configuration;
this.cacheServiceErrorMapper = new cache_service_error_mapper_1.CacheServiceErrorMapper(props.configuration.getThrowOnErrors());
this.credentialProvider = props.credentialProvider;
this.logger = this.configuration.getLoggerFactory().getLogger(this);
const grpcConfig = this.configuration
.getTransportStrategy()
.getGrpcConfig();
this.requestTimeoutMs = grpcConfig.getDeadlineMillis();
this.validateRequestTimeout(this.requestTimeoutMs);
this.logger.debug(`Creating leaderboard client using endpoint: '${this.credentialProvider.getCacheEndpoint()}'`);
const numDataClients = grpcConfig.getNumClients();
// We round-robin the requests through all of our clients. Since javascript
// is single-threaded, we don't have to worry about thread safety on this
// index variable.
this.nextDataClientIndex = 0;
const channelOptions = (0, grpc_channel_options_1.grpcChannelOptionsFromGrpcConfig)(grpcConfig);
this.clientWrappers = (0, utils_1.range)(numDataClients).map(() => new idle_grpc_client_wrapper_1.IdleGrpcClientWrapper({
clientFactoryFn: () => new leaderboard_1.leaderboard.LeaderboardClient(this.credentialProvider.getCacheEndpoint(), this.credentialProvider.isCacheEndpointSecure()
? grpc_js_1.ChannelCredentials.createSsl()
: grpc_js_1.ChannelCredentials.createInsecure(), channelOptions),
loggerFactory: this.configuration.getLoggerFactory(),
maxIdleMillis: this.configuration
.getTransportStrategy()
.getMaxIdleMillis(),
}));
const context = {};
context[exports.CONNECTION_ID_KEY] = dataClientID;
this.interceptors = this.initializeInterceptors(this.configuration.getLoggerFactory(), this.configuration.getMiddlewares(), context);
}
close() {
this.logger.debug('Closing leaderboard data clients');
this.clientWrappers.map(wrapper => wrapper.getClient().close());
}
validateRequestTimeout(timeout) {
this.logger.debug(`Request timeout ms: ${String(timeout)}`);
if (timeout !== undefined && timeout <= 0) {
throw new sdk_core_1.InvalidArgumentError('request timeout must be greater than zero.');
}
}
initializeInterceptors(_loggerFactory, middlewares, middlewareRequestContext) {
const headers = [
new headers_interceptor_1.Header('Authorization', this.credentialProvider.getAuthToken()),
new headers_interceptor_1.Header('agent', `nodejs:leaderboard:${package_json_1.version}`),
new headers_interceptor_1.Header('runtime-version', `nodejs:${process.versions.node}`),
];
return [
(0, middlewares_interceptor_1.middlewaresInterceptor)(_loggerFactory, middlewares, middlewareRequestContext),
headers_interceptor_1.HeaderInterceptor.createHeadersInterceptor(headers),
retry_interceptor_1.RetryInterceptor.createRetryInterceptor({
clientName: 'LeaderboardDataClient',
loggerFactory: _loggerFactory,
overallRequestTimeoutMs: this.requestTimeoutMs,
}),
];
}
createMetadata(cacheName) {
const metadata = new grpc_js_1.Metadata();
metadata.set('cache', cacheName);
return metadata;
}
convertMapOrRecordToElementsList(elements) {
const convertedElements = [];
if (elements instanceof Map) {
elements.forEach((score, id) => convertedElements.push(new _Element({ id: id, score: score })));
}
else {
Object.entries(elements).forEach(element => convertedElements.push(new _Element({ id: Number(element[0]), score: element[1] })));
}
return convertedElements;
}
async upsert(cacheName, leaderboardName, elements) {
const size = elements instanceof Map ? elements.size : Object.keys(elements).length;
try {
(0, utils_1.validateLeaderboardNumberOfElements)(size);
}
catch (err) {
return this.cacheServiceErrorMapper.returnOrThrowError(err, err => new sdk_core_1.LeaderboardUpsert.Error(err));
}
this.logger.trace(`Issuing 'upsert' request; cache: ${cacheName}, leaderboard: ${leaderboardName}, number of elements: ${size}`);
return await this.sendUpsert(cacheName, leaderboardName, elements);
}
async sendUpsert(cacheName, leaderboardName, elements) {
const request = new leaderboard_1.leaderboard._UpsertElementsRequest({
cache_name: cacheName,
leaderboard: leaderboardName,
elements: this.convertMapOrRecordToElementsList(elements),
});
const metadata = this.createMetadata(cacheName);
return await new Promise((resolve, reject) => {
this.getNextDataClient().UpsertElements(request, metadata, {
interceptors: this.interceptors,
}, (err, resp) => {
if (resp) {
resolve(new sdk_core_1.LeaderboardUpsert.Success());
}
else {
this.cacheServiceErrorMapper.resolveOrRejectError({
err: err,
errorResponseFactoryFn: e => new sdk_core_1.LeaderboardUpsert.Error(e),
resolveFn: resolve,
rejectFn: reject,
});
}
});
});
}
async fetchByScore(cacheName, leaderboardName, minScore, maxScore, order, offset, count) {
var _a;
const offsetValue = offset === undefined ? 0 : offset;
const countValue = count === undefined ? 8192 : count;
const orderValue = order !== null && order !== void 0 ? order : sdk_core_1.LeaderboardOrder.Ascending;
try {
(0, utils_1.validateSortedSetScores)(minScore, maxScore);
(0, utils_1.validateLeaderboardOffset)(offsetValue);
(0, utils_1.validateLeaderboardCount)(countValue);
}
catch (err) {
return this.cacheServiceErrorMapper.returnOrThrowError(err, err => new sdk_core_1.LeaderboardFetch.Error(err));
}
this.logger.trace(`Issuing 'fetchByScore' request; cache: ${cacheName}, leaderboard: ${leaderboardName}, order: ${orderValue.toString()}, minScore: ${minScore !== null && minScore !== void 0 ? minScore : 'null'}, maxScore: ${(_a = maxScore === null || maxScore === void 0 ? void 0 : maxScore.toString()) !== null && _a !== void 0 ? _a : 'null'}, offset: ${offsetValue.toString()}, count: ${countValue.toString()}`);
return await this.sendFetchByScore(cacheName, leaderboardName, orderValue, offsetValue, countValue, minScore, maxScore);
}
async sendFetchByScore(cacheName, leaderboardName, order, offset, count, minScore, maxScore) {
const protoBufOrder = order === sdk_core_1.LeaderboardOrder.Descending
? leaderboard_1.leaderboard._Order.DESCENDING
: leaderboard_1.leaderboard._Order.ASCENDING;
const protoBufScoreRange = new leaderboard_1.leaderboard._ScoreRange();
if (minScore !== undefined) {
protoBufScoreRange.min_inclusive = minScore;
}
else {
protoBufScoreRange.unbounded_min = new common_1.common._Unbounded();
}
if (maxScore !== undefined) {
protoBufScoreRange.max_exclusive = maxScore;
}
else {
protoBufScoreRange.unbounded_max = new common_1.common._Unbounded();
}
const request = new leaderboard_1.leaderboard._GetByScoreRequest({
cache_name: cacheName,
leaderboard: leaderboardName,
score_range: protoBufScoreRange,
order: protoBufOrder,
offset: offset,
limit_elements: count,
});
const metadata = this.createMetadata(cacheName);
return await new Promise((resolve, reject) => {
this.getNextDataClient().GetByScore(request, metadata, {
interceptors: this.interceptors,
}, (err, resp) => {
if (resp) {
const foundElements = resp
.elements;
resolve(new sdk_core_1.LeaderboardFetch.Success(foundElements));
}
else {
this.cacheServiceErrorMapper.resolveOrRejectError({
err: err,
errorResponseFactoryFn: e => new sdk_core_1.LeaderboardFetch.Error(e),
resolveFn: resolve,
rejectFn: reject,
});
}
});
});
}
async fetchByRank(cacheName, leaderboardName, startRank, endRank, order) {
const rankOrder = order !== null && order !== void 0 ? order : sdk_core_1.LeaderboardOrder.Ascending;
try {
(0, utils_1.validateLeaderboardRanks)(startRank, endRank);
}
catch (err) {
return this.cacheServiceErrorMapper.returnOrThrowError(err, err => new sdk_core_1.LeaderboardFetch.Error(err));
}
this.logger.trace(`Issuing 'fetchByRank' request; cache: ${cacheName}, leaderboard: ${leaderboardName}, order: ${rankOrder.toString()}, startRank: ${startRank}, endRank: ${endRank}`);
return await this.sendFetchByRank(cacheName, leaderboardName, startRank, endRank, rankOrder);
}
async sendFetchByRank(cacheName, leaderboardName, startRank, endRank, order) {
const protoBufOrder = order === sdk_core_1.LeaderboardOrder.Descending
? leaderboard_1.leaderboard._Order.DESCENDING
: leaderboard_1.leaderboard._Order.ASCENDING;
const protoBufRankRange = new leaderboard_1.leaderboard._RankRange({
start_inclusive: startRank,
end_exclusive: endRank,
});
const request = new leaderboard_1.leaderboard._GetByRankRequest({
cache_name: cacheName,
leaderboard: leaderboardName,
rank_range: protoBufRankRange,
order: protoBufOrder,
});
const metadata = this.createMetadata(cacheName);
return await new Promise((resolve, reject) => {
this.getNextDataClient().GetByRank(request, metadata, {
interceptors: this.interceptors,
}, (err, resp) => {
if (resp) {
const foundElements = resp
.elements;
resolve(new sdk_core_1.LeaderboardFetch.Success(foundElements));
}
else {
this.cacheServiceErrorMapper.resolveOrRejectError({
err: err,
errorResponseFactoryFn: e => new sdk_core_1.LeaderboardFetch.Error(e),
resolveFn: resolve,
rejectFn: reject,
});
}
});
});
}
async getRank(cacheName, leaderboardName, ids, order) {
const orderValue = order !== null && order !== void 0 ? order : sdk_core_1.LeaderboardOrder.Ascending;
this.logger.trace(`Issuing 'getRank' request; cache: ${cacheName}, leaderboard: ${leaderboardName}, order: ${orderValue.toString()}, number of ids: ${ids.length}`);
return await this.sendGetRank(cacheName, leaderboardName, ids, orderValue);
}
async sendGetRank(cacheName, leaderboardName, ids, order) {
const protoBufOrder = order === sdk_core_1.LeaderboardOrder.Descending
? leaderboard_1.leaderboard._Order.DESCENDING
: leaderboard_1.leaderboard._Order.ASCENDING;
const request = new leaderboard_1.leaderboard._GetRankRequest({
cache_name: cacheName,
leaderboard: leaderboardName,
ids: ids,
order: protoBufOrder,
});
const metadata = this.createMetadata(cacheName);
return await new Promise((resolve, reject) => {
this.getNextDataClient().GetRank(request, metadata, {
interceptors: this.interceptors,
}, (err, resp) => {
if (resp) {
const foundElements = resp
.elements;
resolve(new sdk_core_1.LeaderboardFetch.Success(foundElements));
}
else {
this.cacheServiceErrorMapper.resolveOrRejectError({
err: err,
errorResponseFactoryFn: e => new sdk_core_1.LeaderboardFetch.Error(e),
resolveFn: resolve,
rejectFn: reject,
});
}
});
});
}
async length(cacheName, leaderboardName) {
this.logger.trace(`Issuing 'length' request; cache: ${cacheName}, leaderboard: ${leaderboardName}`);
return await this.sendLength(cacheName, leaderboardName);
}
async sendLength(cacheName, leaderboardName) {
const request = new leaderboard_1.leaderboard._GetLeaderboardLengthRequest({
cache_name: cacheName,
leaderboard: leaderboardName,
});
const metadata = this.createMetadata(cacheName);
return await new Promise((resolve, reject) => {
this.getNextDataClient().GetLeaderboardLength(request, metadata, {
interceptors: this.interceptors,
}, (err, resp) => {
if (resp) {
const length = resp
.count;
resolve(new sdk_core_1.LeaderboardLength.Success(length));
}
else {
this.cacheServiceErrorMapper.resolveOrRejectError({
err: err,
errorResponseFactoryFn: e => new sdk_core_1.LeaderboardLength.Error(e),
resolveFn: resolve,
rejectFn: reject,
});
}
});
});
}
async removeElements(cacheName, leaderboardName, ids) {
try {
(0, utils_1.validateLeaderboardNumberOfElements)(ids.length);
}
catch (err) {
return this.cacheServiceErrorMapper.returnOrThrowError(err, err => new sdk_core_1.LeaderboardRemoveElements.Error(err));
}
this.logger.trace(`Issuing 'removeElements' request; cache: ${cacheName}, leaderboard: ${leaderboardName}, number of elements: ${ids.length.toString()}`);
return await this.sendRemoveElements(cacheName, leaderboardName, ids);
}
async sendRemoveElements(cacheName, leaderboardName, ids) {
const request = new leaderboard_1.leaderboard._RemoveElementsRequest({
cache_name: cacheName,
leaderboard: leaderboardName,
ids: ids,
});
const metadata = this.createMetadata(cacheName);
return await new Promise((resolve, reject) => {
this.getNextDataClient().RemoveElements(request, metadata, {
interceptors: this.interceptors,
}, (err, resp) => {
if (resp) {
resolve(new sdk_core_1.LeaderboardRemoveElements.Success());
}
else {
this.cacheServiceErrorMapper.resolveOrRejectError({
err: err,
errorResponseFactoryFn: e => new sdk_core_1.LeaderboardRemoveElements.Error(e),
resolveFn: resolve,
rejectFn: reject,
});
}
});
});
}
async delete(cacheName, leaderboardName) {
this.logger.trace(`Issuing 'delete' request; cache: ${cacheName}, leaderboard: ${leaderboardName}`);
return await this.sendDelete(cacheName, leaderboardName);
}
async sendDelete(cacheName, leaderboardName) {
const request = new leaderboard_1.leaderboard._DeleteLeaderboardRequest({
cache_name: cacheName,
leaderboard: leaderboardName,
});
const metadata = this.createMetadata(cacheName);
return await new Promise((resolve, reject) => {
this.getNextDataClient().DeleteLeaderboard(request, metadata, {
interceptors: this.interceptors,
}, (err, resp) => {
if (resp) {
resolve(new sdk_core_1.LeaderboardDelete.Success());
}
else {
this.cacheServiceErrorMapper.resolveOrRejectError({
err: err,
errorResponseFactoryFn: e => new sdk_core_1.LeaderboardDelete.Error(e),
resolveFn: resolve,
rejectFn: reject,
});
}
});
});
}
getNextDataClient() {
const clientWrapper = this.clientWrappers[this.nextDataClientIndex];
this.nextDataClientIndex =
(this.nextDataClientIndex + 1) % this.clientWrappers.length;
return clientWrapper.getClient();
}
}
exports.LeaderboardDataClient = LeaderboardDataClient;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGVhZGVyYm9hcmQtZGF0YS1jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW50ZXJuYWwvbGVhZGVyYm9hcmQtZGF0YS1jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsa0RBVzZCO0FBQzdCLHVFQU9xRDtBQUVyRCw2RUFBd0U7QUFDeEUsSUFBTyxRQUFRLEdBQUcseUJBQVcsQ0FBQyxRQUFRLENBQUM7QUFDdkMsOEVBQXNFO0FBRXRFLG9FQUFxRTtBQUNyRSxxRkFBNkU7QUFDN0UsMkNBS3VCO0FBQ3ZCLHFEQUEyQztBQUczQyw0RUFBc0U7QUFLdEUsc0VBQTZFO0FBQzdFLG1FQUE4RDtBQUM5RCxnRUFBMEQ7QUFFN0MsUUFBQSxpQkFBaUIsR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7QUFFeEQsTUFBYSxxQkFBcUI7SUFVaEM7OztPQUdHO0lBQ0gsWUFBWSxLQUFnQyxFQUFFLFlBQW9CO1FBQ2hFLElBQUksQ0FBQyxhQUFhLEdBQUcsS0FBSyxDQUFDLGFBQWEsQ0FBQztRQUN6QyxJQUFJLENBQUMsdUJBQXVCLEdBQUcsSUFBSSxvREFBdUIsQ0FDeEQsS0FBSyxDQUFDLGFBQWEsQ0FBQyxnQkFBZ0IsRUFBRSxDQUN2QyxDQUFDO1FBQ0YsSUFBSSxDQUFDLGtCQUFrQixHQUFHLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQztRQUNuRCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDcEUsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLGFBQWE7YUFDbEMsb0JBQW9CLEVBQUU7YUFDdEIsYUFBYSxFQUFFLENBQUM7UUFFbkIsSUFBSSxDQUFDLGdCQUFnQixHQUFHLFVBQVUsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ3ZELElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxJQUFJLENBQUMsZ0JB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SUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUNwRSxJQUFJLENBQUMsbUJBQW1CO1lBQ3RCLENBQUMsSUFBSSxDQUFDLG1CQUFtQixHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDO1FBQzlELE9BQU8sYUFBYSxDQUFDLFNBQVMsRUFBRSxDQUFDO0lBQ25DLENBQUM7Q0FDRjtBQXRqQkQsc0RBc2pCQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENyZWRlbnRpYWxQcm92aWRlcixcbiAgSW52YWxpZEFyZ3VtZW50RXJyb3IsXG4gIExlYWRlcmJvYXJkRGVsZXRlLFxuICBMZWFkZXJib2FyZEZldGNoLFxuICBMZWFkZXJib2FyZExlbmd0aCxcbiAgTGVhZGVyYm9hcmRSZW1vdmVFbGVtZW50cyxcbiAgTGVhZGVyYm9hcmRVcHNlcnQsXG4gIE1vbWVudG9Mb2dnZXIsXG4gIE1vbWVudG9Mb2dnZXJGYWN0b3J5LFxuICBMZWFkZXJib2FyZE9yZGVyLFxufSBmcm9tICdAZ29tb21lbnRvL3Nkay1jb3JlJztcbmltcG9ydCB7XG4gIHZhbGlkYXRlTGVhZGVyYm9hcmROdW1iZXJPZkVsZW1lbnRzLFxuICB2YWxpZGF0ZVNvcnRlZFNldFNjb3JlcyxcbiAgdmFsaWRhdGVMZWFkZXJib2FyZE9mZnNldCxcbiAgdmFsaWRhdGVMZWFkZXJib2FyZENvdW50LFxuICB2YWxpZGF0ZUxlYWRlcmJvYXJkUmFua3MsXG4gIHJhbmdlLFxufSBmcm9tICdAZ29tb21lbnRvL3Nkay1jb3JlL2Rpc3Qvc3JjL2ludGVybmFsL3V0aWxzJztcbmltcG9ydCB7TGVhZGVyYm9hcmRDb25maWd1cmF0aW9ufSBmcm9tICcuLi9jb25maWcvbGVhZGVyYm9hcmQtY29uZmlndXJhdGlvbic7XG5pbXBvcnQge2xlYWRlcmJvYXJkfSBmcm9tICdAZ29tb21lbnRvL2dlbmVyYXRlZC10eXBlcy9kaXN0L2xlYWRlcmJvYXJkJztcbmltcG9ydCBfRWxlbWVudCA9IGxlYWRlcmJvYXJkLl9FbGVtZW50O1xuaW1wb3J0IHtJZGxlR3JwY0NsaWVudFdyYXBwZXJ9IGZyb20gJy4vZ3JwYy9pZGxlLWdycGMtY2xpZW50LXdyYXBwZXInO1xuaW1wb3J0IHtHcnBjQ2xpZW50V3JhcHBlcn0gZnJvbSAnLi9ncnBjL2dycGMtY2xpZW50LXdyYXBwZXInO1xuaW1wb3J0IHtIZWFkZXIsIEhlYWRlckludGVyY2VwdG9yfSBmcm9tICcuL2dycGMvaGVhZGVycy1pbnRlcmNlcHRvcic7XG5pbXBvcnQge0NhY2hlU2VydmljZUVycm9yTWFwcGVyfSBmcm9tICcuLi9lcnJvcnMvY2FjaGUtc2VydmljZS1lcnJvci1tYXBwZXInO1xuaW1wb3J0IHtcbiAgQ2hhbm5lbENyZWRlbnRpYWxzLFxuICBJbnRlcmNlcHRvcixcbiAgTWV0YWRhdGEsXG4gIFNlcnZpY2VFcnJvcixcbn0gZnJvbSAnQGdycGMvZ3JwYy1qcyc7XG5pbXBvcnQge3ZlcnNpb259IGZyb20gJy4uLy4uL3BhY2thZ2UuanNvbic7XG5pbXBvcnQge0lMZWFkZXJib2FyZERhdGFDbGllbnR9IGZyb20gJ0Bnb21vbWVudG8vc2RrLWNvcmUvZGlzdC9zcmMvaW50ZXJuYWwvY2xpZW50cy9sZWFkZXJib2FyZC9JTGVhZGVyYm9hcmREYXRhQ2xpZW50JztcbmltcG9ydCB7TGVhZGVyYm9hcmRDbGllbnRBbGxQcm9wc30gZnJvbSAnLi9sZWFkZXJib2FyZC1jbGllbnQtYWxsLXByb3BzJztcbmltcG9ydCB7bWlkZGxld2FyZXNJbnRlcmNlcHRvcn0gZnJvbSAnLi9ncnBjL21pZGRsZXdhcmVzLWludGVyY2VwdG9yJztcbmltcG9ydCB7XG4gIE1pZGRsZXdhcmUsXG4gIE1pZGRsZXdhcmVSZXF1ZXN0SGFuZGxlckNvbnRleHQsXG59IGZyb20gJy4uL2NvbmZpZy9taWRkbGV3YXJlL21pZGRsZXdhcmUnO1xuaW1wb3J0IHtncnBjQ2hhbm5lbE9wdGlvbnNGcm9tR3JwY0NvbmZpZ30gZnJvbSAnLi9ncnBjL2dycGMtY2hhbm5lbC1vcHRpb25zJztcbmltcG9ydCB7Y29tbW9ufSBmcm9tICdAZ29tb21lbnRvL2dlbmVyYXRlZC10eXBlcy9kaXN0L2NvbW1vbic7XG5pbXBvcnQge1JldHJ5SW50ZXJjZXB0b3J9IGZyb20gJy4vZ3JwYy9yZXRyeS1pbnRlcmNlcHRvcic7XG5cbmV4cG9ydCBjb25zdCBDT05ORUNUSU9OX0lEX0tFWSA9IFN5bWJvbCgnY29ubmVjdGlvbklEJyk7XG5cbmV4cG9ydCBjbGFzcyBMZWFkZXJib2FyZERhdGFDbGllbnQgaW1wbGVtZW50cyBJTGVhZGVyYm9hcmREYXRhQ2xpZW50IHtcbiAgcHJpdmF0ZSByZWFkb25seSBjb25maWd1cmF0aW9uOiBMZWFkZXJib2FyZENvbmZpZ3VyYXRpb247XG4gIHByaXZhdGUgcmVhZG9ubHkgY3JlZGVudGlhbFByb3ZpZGVyOiBDcmVkZW50aWFsUHJvdmlkZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgbG9nZ2VyOiBNb21lbnRvTG9nZ2VyO1xuICBwcml2YXRlIHJlYWRvbmx5IGNhY2hlU2VydmljZUVycm9yTWFwcGVyOiBDYWNoZVNlcnZpY2VFcnJvck1hcHBlcjtcbiAgcHJpdmF0ZSByZWFkb25seSByZXF1ZXN0VGltZW91dE1zOiBudW1iZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgY2xpZW50V3JhcHBlcnM6IEdycGNDbGllbnRXcmFwcGVyPGxlYWRlcmJvYXJkLkxlYWRlcmJvYXJkQ2xpZW50PltdO1xuICBwcm90ZWN0ZWQgbmV4dERhdGFDbGllbnRJbmRleDogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IGludGVyY2VwdG9yczogSW50ZXJjZXB0b3JbXTtcblxuICAvKipcbiAgICogQHBhcmFtIHtMZWFkZXJib2FyZENsaWVudEFsbFByb3BzfSBwcm9wc1xuICAgKiBAcGFyYW0gZGF0YUNsaWVudElEXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihwcm9wczogTGVhZGVyYm9hcmRDbGllbnRBbGxQcm9wcywgZGF0YUNsaWVudElEOiBzdHJpbmcpIHtcbiAgICB0aGlzLmNvbmZpZ3VyYXRpb24gPSBwcm9wcy5jb25maWd1cmF0aW9uO1xuICAgIHRoaXMuY2FjaGVTZXJ2aWNlRXJyb3JNYXBwZXIgPSBuZXcgQ2FjaGVTZXJ2aWNlRXJyb3JNYXBwZXIoXG4gICAgICBwcm9wcy5jb25maWd1cmF0aW9uLmdldFRocm93T25FcnJvcnMoKVxuICAgICk7XG4gICAgdGhpcy5jcmVkZW50aWFsUHJvdmlkZXIgPSBwcm9wcy5jcmVkZW50aWFsUHJvdmlkZXI7XG4gICAgdGhpcy5sb2dnZXIgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0TG9nZ2VyRmFjdG9yeSgpLmdldExvZ2dlcih0aGlzKTtcbiAgICBjb25zdCBncnBjQ29uZmlnID0gdGhpcy5jb25maWd1cmF0aW9uXG4gICAgICAuZ2V0VHJhbnNwb3J0U3RyYXRlZ3koKVxuICAgICAgLmdldEdycGNDb25maWcoKTtcblxuICAgIHRoaXMucmVxdWVzdFRpbWVvdXRNcyA9IGdycGNDb25maWcuZ2V0RGVhZGxpbmVNaWxsaXMoKTtcbiAgICB0aGlzLnZhbGlkYXRlUmVxdWVzdFRpbWVvdXQodGhpcy5yZXF1ZXN0VGltZW91dE1zKTtcbiAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhcbiAgICAgIGBDcmVhdGluZyBsZWFkZXJib2FyZCBjbGllbnQgdXNpbmcgZW5kcG9pbnQ6ICcke3RoaXMuY3JlZGVudGlhbFByb3ZpZGVyLmdldENhY2hlRW5kcG9pbnQoKX0nYFxuICAgICk7XG5cbiAgICBjb25zdCBudW1EYXRhQ2xpZW50cyA9IGdycGNDb25maWcuZ2V0TnVtQ2xpZW50cygpO1xuXG4gICAgLy8gV2Ugcm91bmQtcm9iaW4gdGhlIHJlcXVlc3RzIHRocm91Z2ggYWxsIG9mIG91ciBjbGllbnRzLiAgU2luY2UgamF2YXNjcmlwdFxuICAgIC8vIGlzIHNpbmdsZS10aHJlYWRlZCwgd2UgZG9uJ3QgaGF2ZSB0byB3b3JyeSBhYm91dCB0aHJlYWQgc2FmZXR5IG9uIHRoaXNcbiAgICAvLyBpbmRleCB2YXJpYWJsZS5cbiAgICB0aGlzLm5leHREYXRhQ2xpZW50SW5kZXggPSAwO1xuXG4gICAgY29uc3QgY2hhbm5lbE9wdGlvbnMgPSBncnBjQ2hhbm5lbE9wdGlvbnNGcm9tR3JwY0NvbmZpZyhncnBjQ29uZmlnKTtcblxuICAgIHRoaXMuY2xpZW50V3JhcHBlcnMgPSByYW5nZShudW1EYXRhQ2xpZW50cykubWFwKFxuICAgICAgKCkgPT5cbiAgICAgICAgbmV3IElkbGVHcnBjQ2xpZW50V3JhcHBlcih7XG4gICAgICAgICAgY2xpZW50RmFjdG9yeUZuOiAoKSA9PlxuICAgICAgICAgICAgbmV3IGxlYWRlcmJvYXJkLkxlYWRlcmJvYXJkQ2xpZW50KFxuICAgICAgICAgICAgICB0aGlzLmNyZWRlbnRpYWxQcm92aWRlci5nZXRDYWNoZUVuZHBvaW50KCksXG4gICAgICAgICAgICAgIHRoaXMuY3JlZGVudGlhbFByb3ZpZGVyLmlzQ2FjaGVFbmRwb2ludFNlY3VyZSgpXG4gICAgICAgICAgICAgICAgPyBDaGFubmVsQ3JlZGVudGlhbHMuY3JlYXRlU3NsKClcbiAgICAgICAgICAgICAgICA6IENoYW5uZWxDcmVkZW50aWFscy5jcmVhdGVJbnNlY3VyZSgpLFxuICAgICAgICAgICAgICBjaGFubmVsT3B0aW9uc1xuICAgICAgICAgICAgKSxcbiAgICAgICAgICBsb2dnZXJGYWN0b3J5OiB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0TG9nZ2VyRmFjdG9yeSgpLFxuICAgICAgICAgIG1heElkbGVNaWxsaXM6IHRoaXMuY29uZmlndXJhdGlvblxuICAgICAgICAgICAgLmdldFRyYW5zcG9ydFN0cmF0ZWd5KClcbiAgICAgICAgICAgIC5nZXRNYXhJZGxlTWlsbGlzKCksXG4gICAgICAgIH0pXG4gICAgKTtcblxuICAgIGNvbnN0IGNvbnRleHQ6IE1pZGRsZXdhcmVSZXF1ZXN0SGFuZGxlckNvbnRleHQgPSB7fTtcbiAgICBjb250ZXh0W0NPTk5FQ1RJT05fSURfS0VZXSA9IGRhdGFDbGllbnRJRDtcbiAgICB0aGlzLmludGVyY2VwdG9ycyA9IHRoaXMuaW5pdGlhbGl6ZUludGVyY2VwdG9ycyhcbiAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5nZXRMb2dnZXJGYWN0b3J5KCksXG4gICAgICB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0TWlkZGxld2FyZXMoKSxcbiAgICAgIGNvbnRleHRcbiAgICApO1xuICB9XG5cbiAgY2xvc2UoKSB7XG4gICAgdGhpcy5sb2dnZXIuZGVidWcoJ0Nsb3NpbmcgbGVhZGVyYm9hcmQgZGF0YSBjbGllbnRzJyk7XG4gICAgdGhpcy5jbGllbnRXcmFwcGVycy5tYXAod3JhcHBlciA9PiB3cmFwcGVyLmdldENsaWVudCgpLmNsb3NlKCkpO1xuICB9XG5cbiAgcHJpdmF0ZSB2YWxpZGF0ZVJlcXVlc3RUaW1lb3V0KHRpbWVvdXQ/OiBudW1iZXIpIHtcbiAgICB0aGlzLmxvZ2dlci5kZWJ1ZyhgUmVxdWVzdCB0aW1lb3V0IG1zOiAke1N0cmluZyh0aW1lb3V0KX1gKTtcbiAgICBpZiAodGltZW91dCAhPT0gdW5kZWZpbmVkICYmIHRpbWVvdXQgPD0gMCkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRBcmd1bWVudEVycm9yKFxuICAgICAgICAncmVxdWVzdCB0aW1lb3V0IG11c3QgYmUgZ3JlYXRlciB0aGFuIHplcm8uJ1xuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGluaXRpYWxpemVJbnRlcmNlcHRvcnMoXG4gICAgX2xvZ2dlckZhY3Rvcnk6IE1vbWVudG9Mb2dnZXJGYWN0b3J5LFxuICAgIG1pZGRsZXdhcmVzOiBNaWRkbGV3YXJlW10sXG4gICAgbWlkZGxld2FyZVJlcXVlc3RDb250ZXh0OiBNaWRkbGV3YXJlUmVxdWVzdEhhbmRsZXJDb250ZXh0XG4gICk6IEludGVyY2VwdG9yW10ge1xuICAgIGNvbnN0IGhlYWRlcnMgPSBbXG4gICAgICBuZXcgSGVhZGVyKCdBdXRob3JpemF0aW9uJywgdGhpcy5jcmVkZW50aWFsUHJvdmlkZXIuZ2V0QXV0aFRva2VuKCkpLFxuICAgICAgbmV3IEhlYWRlcignYWdlbnQnLCBgbm9kZWpzOmxlYWRlcmJvYXJkOiR7dmVyc2lvbn1gKSxcbiAgICAgIG5ldyBIZWFkZXIoJ3J1bnRpbWUtdmVyc2lvbicsIGBub2RlanM6JHtwcm9jZXNzLnZlcnNpb25zLm5vZGV9YCksXG4gICAgXTtcbiAgICByZXR1cm4gW1xuICAgICAgbWlkZGxld2FyZXNJbnRlcmNlcHRvcihcbiAgICAgICAgX2xvZ2dlckZhY3RvcnksXG4gICAgICAgIG1pZGRsZXdhcmVzLFxuICAgICAgICBtaWRkbGV3YXJlUmVxdWVzdENvbnRleHRcbiAgICAgICksXG4gICAgICBIZWFkZXJJbnRlcmNlcHRvci5jcmVhdGVIZWFkZXJzSW50ZXJjZXB0b3IoaGVhZGVycyksXG4gICAgICBSZXRyeUludGVyY2VwdG9yLmNyZWF0ZVJldHJ5SW50ZXJjZXB0b3Ioe1xuICAgICAgICBjbGllbnROYW1lOiAnTGVhZGVyYm9hcmREYXRhQ2xpZW50JyxcbiAgICAgICAgbG9nZ2VyRmFjdG9yeTogX2xvZ2dlckZhY3RvcnksXG4gICAgICAgIG92ZXJhbGxSZXF1ZXN0VGltZW91dE1zOiB0aGlzLnJlcXVlc3RUaW1lb3V0TXMsXG4gICAgICB9KSxcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVNZXRhZGF0YShjYWNoZU5hbWU6IHN0cmluZyk6IE1ldGFkYXRhIHtcbiAgICBjb25zdCBtZXRhZGF0YSA9IG5ldyBNZXRhZGF0YSgpO1xuICAgIG1ldGFkYXRhLnNldCgnY2FjaGUnLCBjYWNoZU5hbWUpO1xuICAgIHJldHVybiBtZXRhZGF0YTtcbiAgfVxuXG4gIHByaXZhdGUgY29udmVydE1hcE9yUmVjb3JkVG9FbGVtZW50c0xpc3QoXG4gICAgZWxlbWVudHM6IFJlY29yZDxudW1iZXIsIG51bWJlcj4gfCBNYXA8bnVtYmVyLCBudW1iZXI+XG4gICk6IF9FbGVtZW50W10ge1xuICAgIGNvbnN0IGNvbnZlcnRlZEVsZW1lbnRzOiBfRWxlbWVudFtdID0gW107XG4gICAgaWYgKGVsZW1lbnRzIGluc3RhbmNlb2YgTWFwKSB7XG4gICAgICBlbGVtZW50cy5mb3JFYWNoKChzY29yZSwgaWQpID0+XG4gICAgICAgIGNvbnZlcnRlZEVsZW1lbnRzLnB1c2gobmV3IF9FbGVtZW50KHtpZDogaWQsIHNjb3JlOiBzY29yZX0pKVxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgT2JqZWN0LmVudHJpZXMoZWxlbWVudHMpLmZvckVhY2goZWxlbWVudCA9PlxuICAgICAgICBjb252ZXJ0ZWRFbGVtZW50cy5wdXNoKFxuICAgICAgICAgIG5ldyBfRWxlbWVudCh7aWQ6IE51bWJlcihlbGVtZW50WzBdKSwgc2NvcmU6IGVsZW1lbnRbMV19KVxuICAgICAgICApXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gY29udmVydGVkRWxlbWVudHM7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgdXBzZXJ0KFxuICAgIGNhY2hlTmFtZTogc3RyaW5nLFxuICAgIGxlYWRlcmJvYXJkTmFtZTogc3RyaW5nLFxuICAgIGVsZW1lbnRzOiBSZWNvcmQ8bnVtYmVyLCBudW1iZXI+IHwgTWFwPG51bWJlciwgbnVtYmVyPlxuICApOiBQcm9taXNlPExlYWRlcmJvYXJkVXBzZXJ0LlJlc3BvbnNlPiB7XG4gICAgY29uc3Qgc2l6ZSA9XG4gICAgICBlbGVtZW50cyBpbnN0YW5jZW9mIE1hcCA/IGVsZW1lbnRzLnNpemUgOiBPYmplY3Qua2V5cyhlbGVtZW50cykubGVuZ3RoO1xuICAgIHRyeSB7XG4gICAgICB2YWxpZGF0ZUxlYWRlcmJvYXJkTnVtYmVyT2ZFbGVtZW50cyhzaXplKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHJldHVybiB0aGlzLmNhY2hlU2VydmljZUVycm9yTWFwcGVyLnJldHVybk9yVGhyb3dFcnJvcihcbiAgICAgICAgZXJyIGFzIEVycm9yLFxuICAgICAgICBlcnIgPT4gbmV3IExlYWRlcmJvYXJkVXBzZXJ0LkVycm9yKGVycilcbiAgICAgICk7XG4gICAgfVxuICAgIHRoaXMubG9nZ2VyLnRyYWNlKFxuICAgICAgYElzc3VpbmcgJ3Vwc2VydCcgcmVxdWVzdDsgY2FjaGU6ICR7Y2FjaGVOYW1lfSwgbGVhZGVyYm9hcmQ6ICR7bGVhZGVyYm9hcmROYW1lfSwgbnVtYmVyIG9mIGVsZW1lbnRzOiAke3NpemV9YFxuICAgICk7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuc2VuZFVwc2VydChjYWNoZU5hbWUsIGxlYWRlcmJvYXJkTmFtZSwgZWxlbWVudHMpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzZW5kVXBzZXJ0KFxuICAgIGNhY2hlTmFtZTogc3RyaW5nLFxuICAgIGxlYWRlcmJvYXJkTmFtZTogc3RyaW5nLFxuICAgIGVsZW1lbnRzOiBSZWNvcmQ8bnVtYmVyLCBudW1iZXI+IHwgTWFwPG51bWJlciwgbnVtYmVyPlxuICApOiBQcm9taXNlPExlYWRlcmJvYXJkVXBzZXJ0LlJlc3BvbnNlPiB7XG4gICAgY29uc3QgcmVxdWVzdCA9IG5ldyBsZWFkZXJib2FyZC5fVXBzZXJ0RWxlbWVudHNSZXF1ZXN0KHtcbiAgICAgIGNhY2hlX25hbWU6IGNhY2hlTmFtZSxcbiAgICAgIGxlYWRlcmJvYXJkOiBsZWFkZXJib2FyZE5hbWUsXG4gICAgICBlbGVtZW50czogdGhpcy5jb252ZXJ0TWFwT3JSZWNvcmRUb0VsZW1lbnRzTGlzdChlbGVtZW50cyksXG4gICAgfSk7XG4gICAgY29uc3QgbWV0YWRhdGEgPSB0aGlzLmNyZWF0ZU1ldGFkYXRhKGNhY2hlTmFtZSk7XG4gICAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHRoaXMuZ2V0TmV4dERhdGFDbGllbnQoKS5VcHNlcnRFbGVtZW50cyhcbiAgICAgICAgcmVxdWVzdCxcbiAgICAgICAgbWV0YWRhdGEsXG4gICAgICAgIHtcbiAgICAgICAgICBpbnRlcmNlcHRvcnM6IHRoaXMuaW50ZXJjZXB0b3JzLFxuICAgICAgICB9LFxuICAgICAgICAoZXJyOiBTZXJ2aWNlRXJyb3IgfCBudWxsLCByZXNwOiB1bmtub3duKSA9PiB7XG4gICAgICAgICAgaWYgKHJlc3ApIHtcbiAgICAgICAgICAgIHJlc29sdmUobmV3IExlYWRlcmJvYXJkVXBzZXJ0LlN1Y2Nlc3MoKSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuY2FjaGVTZXJ2aWNlRXJyb3JNYXBwZXIucmVzb2x2ZU9yUmVqZWN0RXJyb3Ioe1xuICAgICAgICAgICAgICBlcnI6IGVycixcbiAgICAgICAgICAgICAgZXJyb3JSZXNwb25zZUZhY3RvcnlGbjogZSA9PiBuZXcgTGVhZGVyYm9hcmRVcHNlcnQuRXJyb3IoZSksXG4gICAgICAgICAgICAgIHJlc29sdmVGbjogcmVzb2x2ZSxcbiAgICAgICAgICAgICAgcmVqZWN0Rm46IHJlamVjdCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBmZXRjaEJ5U2NvcmUoXG4gICAgY2FjaGVOYW1lOiBzdHJpbmcsXG4gICAgbGVhZGVyYm9hcmROYW1lOiBzdHJpbmcsXG4gICAgbWluU2NvcmU/OiBudW1iZXIsXG4gICAgbWF4U2NvcmU/OiBudW1iZXIsXG4gICAgb3JkZXI/OiBMZWFkZXJib2FyZE9yZGVyLFxuICAgIG9mZnNldD86IG51bWJlcixcbiAgICBjb3VudD86IG51bWJlclxuICApOiBQcm9taXNlPExlYWRlcmJvYXJkRmV0Y2guUmVzcG9uc2U+IHtcbiAgICBjb25zdCBvZmZzZXRWYWx1ZSA9IG9mZnNldCA9PT0gdW5kZWZpbmVkID8gMCA6IG9mZnNldDtcbiAgICBjb25zdCBjb3VudFZhbHVlID0gY291bnQgPT09IHVuZGVmaW5lZCA/IDgxOTIgOiBjb3VudDtcbiAgICBjb25zdCBvcmRlclZhbHVlID0gb3JkZXIgPz8gTGVhZGVyYm9hcmRPcmRlci5Bc2NlbmRpbmc7XG4gICAgdHJ5IHtcbiAgICAgIHZhbGlkYXRlU29ydGVkU2V0U2NvcmVzKG1pblNjb3JlLCBtYXhTY29yZSk7XG4gICAgICB2YWxpZGF0ZUxlYWRlcmJvYXJkT2Zmc2V0KG9mZnNldFZhbHVlKTtcbiAgICAgIHZhbGlkYXRlTGVhZGVyYm9hcmRDb3VudChjb3VudFZhbHVlKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHJldHVybiB0aGlzLmNhY2hlU2VydmljZUVycm9yTWFwcGVyLnJldHVybk9yVGhyb3dFcnJvcihcbiAgICAgICAgZXJyIGFzIEVycm9yLFxuICAgICAgICBlcnIgPT4gbmV3IExlYWRlcmJvYXJkRmV0Y2guRXJyb3IoZXJyKVxuICAgICAgKTtcbiAgICB9XG4gICAgdGhpcy5sb2dnZXIudHJhY2UoXG4gICAgICBgSXNzdWluZyAnZmV0Y2hCeVNjb3JlJyByZXF1ZXN0OyBjYWNoZTogJHtjYWNoZU5hbWV9LCBsZWFkZXJib2FyZDogJHtsZWFkZXJib2FyZE5hbWV9LCBvcmRlcjogJHtvcmRlclZhbHVlLnRvU3RyaW5nKCl9LCBtaW5TY29yZTogJHtcbiAgICAgICAgbWluU2NvcmUgPz8gJ251bGwnXG4gICAgICB9LCBtYXhTY29yZTogJHtcbiAgICAgICAgbWF4U2NvcmU/LnRvU3RyaW5nKCkgPz8gJ251bGwnXG4gICAgICB9LCBvZmZzZXQ6ICR7b2Zmc2V0VmFsdWUudG9TdHJpbmcoKX0sIGNvdW50OiAke2NvdW50VmFsdWUudG9TdHJpbmcoKX1gXG4gICAgKTtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5zZW5kRmV0Y2hCeVNjb3JlKFxuICAgICAgY2FjaGVOYW1lLFxuICAgICAgbGVhZGVyYm9hcmROYW1lLFxuICAgICAgb3JkZXJWYWx1ZSxcbiAgICAgIG9mZnNldFZhbHVlLFxuICAgICAgY291bnRWYWx1ZSxcbiAgICAgIG1pblNjb3JlLFxuICAgICAgbWF4U2NvcmVcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzZW5kRmV0Y2hCeVNjb3JlKFxuICAgIGNhY2hlTmFtZTogc3RyaW5nLFxuICAgIGxlYWRlcmJvYXJkTmFtZTogc3RyaW5nLFxuICAgIG9yZGVyOiBMZWFkZXJib2FyZE9yZGVyLFxuICAgIG9mZnNldDogbnVtYmVyLFxuICAgIGNvdW50OiBudW1iZXIsXG4gICAgbWluU2NvcmU/OiBudW1iZXIsXG4gICAgbWF4U2NvcmU/OiBudW1iZXJcbiAgKTogUHJvbWlzZTxMZWFkZXJib2FyZEZldGNoLlJlc3BvbnNlPiB7XG4gICAgY29uc3QgcHJvdG9CdWZPcmRlciA9XG4gICAgICBvcmRlciA9PT0gTGVhZGVyYm9hcmRPcmRlci5EZXNjZW5kaW5nXG4gICAgICAgID8gbGVhZGVyYm9hcmQuX09yZGVyLkRFU0NFTkRJTkdcbiAgICAgICAgOiBsZWFkZXJib2FyZC5fT3JkZXIuQVNDRU5ESU5HO1xuXG4gICAgY29uc3QgcHJvdG9CdWZTY29yZVJhbmdlID0gbmV3IGxlYWRlcmJvYXJkLl9TY29yZVJhbmdlKCk7XG4gICAgaWYgKG1pblNjb3JlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHByb3RvQnVmU2NvcmVSYW5nZS5taW5faW5jbHVzaXZlID0gbWluU2NvcmU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHByb3RvQnVmU2NvcmVSYW5nZS51bmJvdW5kZWRfbWluID0gbmV3IGNvbW1vbi5fVW5ib3VuZGVkKCk7XG4gICAgfVxuICAgIGlmIChtYXhTY29yZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBwcm90b0J1ZlNjb3JlUmFuZ2UubWF4X2V4Y2x1c2l2ZSA9IG1heFNjb3JlO1xuICAgIH0gZWxzZSB7XG4gICAgICBwcm90b0J1ZlNjb3JlUmFuZ2UudW5ib3VuZGVkX21heCA9IG5ldyBjb21tb24uX1VuYm91bmRlZCgpO1xuICAgIH1cblxuICAgIGNvbnN0IHJlcXVlc3QgPSBuZXcgbGVhZGVyYm9hcmQuX0dldEJ5U2NvcmVSZXF1ZXN0KHtcbiAgICAgIGNhY2hlX25hbWU6IGNhY2hlTmFtZSxcbiAgICAgIGxlYWRlcmJvYXJkOiBsZWFkZXJib2FyZE5hbWUsXG4gICAgICBzY29yZV9yYW5nZTogcHJvdG9CdWZTY29yZVJhbmdlLFxuICAgICAgb3JkZXI6IHByb3RvQnVmT3JkZXIsXG4gICAgICBvZmZzZXQ6IG9mZnNldCxcbiAgICAgIGxpbWl0X2VsZW1lbnRzOiBjb3VudCxcbiAgICB9KTtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHRoaXMuY3JlYXRlTWV0YWRhdGEoY2FjaGVOYW1lKTtcbiAgICByZXR1cm4gYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgdGhpcy5nZXROZXh0RGF0YUNsaWVudCgpLkdldEJ5U2NvcmUoXG4gICAgICAgIHJlcXVlc3QsXG4gICAgICAgIG1ldGFkYXRhLFxuICAgICAgICB7XG4gICAgICAgICAgaW50ZXJjZXB0b3JzOiB0aGlzLmludGVyY2VwdG9ycyxcbiAgICAgICAgfSxcbiAgICAgICAgKGVycjogU2VydmljZUVycm9yIHwgbnVsbCwgcmVzcDogdW5rbm93bikgPT4ge1xuICAgICAgICAgIGlmIChyZXNwKSB7XG4gICAgICAgICAgICBjb25zdCBmb3VuZEVsZW1lbnRzID0gKHJlc3AgYXMgbGVhZGVyYm9hcmQuX0dldEJ5U2NvcmVSZXNwb25zZSlcbiAgICAgICAgICAgICAgLmVsZW1lbnRzO1xuICAgICAgICAgICAgcmVzb2x2ZShuZXcgTGVhZGVyYm9hcmRGZXRjaC5TdWNjZXNzKGZvdW5kRWxlbWVudHMpKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jYWNoZVNlcnZpY2VFcnJvck1hcHBlci5yZXNvbHZlT3JSZWplY3RFcnJvcih7XG4gICAgICAgICAgICAgIGVycjogZXJyLFxuICAgICAgICAgICAgICBlcnJvclJlc3BvbnNlRmFjdG9yeUZuOiBlID0+IG5ldyBMZWFkZXJib2FyZEZldGNoLkVycm9yKGUpLFxuICAgICAgICAgICAgICByZXNvbHZlRm46IHJlc29sdmUsXG4gICAgICAgICAgICAgIHJlamVjdEZuOiByZWplY3QsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZmV0Y2hCeVJhbmsoXG4gICAgY2FjaGVOYW1lOiBzdHJpbmcsXG4gICAgbGVhZGVyYm9hcmROYW1lOiBzdHJpbmcsXG4gICAgc3RhcnRSYW5rOiBudW1iZXIsXG4gICAgZW5kUmFuazogbnVtYmVyLFxuICAgIG9yZGVyPzogTGVhZGVyYm9hcmRPcmRlclxuICApOiBQcm9taXNlPExlYWRlcmJvYXJkRmV0Y2guUmVzcG9uc2U+IHtcbiAgICBjb25zdCByYW5rT3JkZXIgPSBvcmRlciA/PyBMZWFkZXJib2FyZE9yZGVyLkFzY2VuZGluZztcbiAgICB0cnkge1xuICAgICAgdmFsaWRhdGVMZWFkZXJib2FyZFJhbmtzKHN0YXJ0UmFuaywgZW5kUmFuayk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICByZXR1cm4gdGhpcy5jYWNoZVNlcnZpY2VFcnJvck1hcHBlci5yZXR1cm5PclRocm93RXJyb3IoXG4gICAgICAgIGVyciBhcyBFcnJvcixcbiAgICAgICAgZXJyID0+IG5ldyBMZWFkZXJib2FyZEZldGNoLkVycm9yKGVycilcbiAgICAgICk7XG4gICAgfVxuICAgIHRoaXMubG9nZ2VyLnRyYWNlKFxuICAgICAgYElzc3VpbmcgJ2ZldGNoQnlSYW5rJyByZXF1ZXN0OyBjYWNoZTogJHtjYWNoZU5hbWV9LCBsZWFkZXJib2FyZDogJHtsZWFkZXJib2FyZE5hbWV9LCBvcmRlcjogJHtyYW5rT3JkZXIudG9TdHJpbmcoKX0sIHN0YXJ0UmFuazogJHtzdGFydFJhbmt9LCBlbmRSYW5rOiAke2VuZFJhbmt9YFxuICAgICk7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuc2VuZEZldGNoQnlSYW5rKFxuICAgICAgY2FjaGVOYW1lLFxuICAgICAgbGVhZGVyYm9hcmROYW1lLFxuICAgICAgc3RhcnRSYW5rLFxuICAgICAgZW5kUmFuayxcbiAgICAgIHJhbmtPcmRlclxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHNlbmRGZXRjaEJ5UmFuayhcbiAgICBjYWNoZU5hbWU6IHN0cmluZyxcbiAgICBsZWFkZXJib2FyZE5hbWU6IHN0cmluZyxcbiAgICBzdGFydFJhbms6IG51bWJlcixcbiAgICBlbmRSYW5rOiBudW1iZXIsXG4gICAgb3JkZXI6IExlYWRlcmJvYXJkT3JkZXJcbiAgKTogUHJvbWlzZTxMZWFkZXJib2FyZEZldGNoLlJlc3BvbnNlPiB7XG4gICAgY29uc3QgcHJvdG9CdWZPcmRlciA9XG4gICAgICBvcmRlciA9PT0gTGVhZGVyYm9hcmRPcmRlci5EZXNjZW5kaW5nXG4gICAgICAgID8gbGVhZGVyYm9hcmQuX09yZGVyLkRFU0NFTkRJTkdcbiAgICAgICAgOiBsZWFkZXJib2FyZC5fT3JkZXIuQVNDRU5ESU5HO1xuXG4gICAgY29uc3QgcHJvdG9CdWZSYW5rUmFuZ2UgPSBuZXcgbGVhZGVyYm9hcmQuX1JhbmtSYW5nZSh7XG4gICAgICBzdGFydF9pbmNsdXNpdmU6IHN0YXJ0UmFuayxcbiAgICAgIGVuZF9leGNsdXNpdmU6IGVuZFJhbmssXG4gICAgfSk7XG5cbiAgICBjb25zdCByZXF1ZXN0ID0gbmV3IGxlYWRlcmJvYXJkLl9HZXRCeVJhbmtSZXF1ZXN0KHtcbiAgICAgIGNhY2hlX25hbWU6IGNhY2hlTmFtZSxcbiAgICAgIGxlYWRlcmJvYXJkOiBsZWFkZXJib2FyZE5hbWUsXG4gICAgICByYW5rX3JhbmdlOiBwcm90b0J1ZlJhbmtSYW5nZSxcbiAgICAgIG9yZGVyOiBwcm90b0J1Zk9yZGVyLFxuICAgIH0pO1xuICAgIGNvbnN0IG1ldGFkYXRhID0gdGhpcy5jcmVhdGVNZXRhZGF0YShjYWNoZU5hbWUpO1xuICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICB0aGlzLmdldE5leHREYXRhQ2xpZW50KCkuR2V0QnlSYW5rKFxuICAgICAgICByZXF1ZXN0LFxuICAgICAgICBtZXRhZGF0YSxcbiAgICAgICAge1xuICAgICAgICAgIGludGVyY2VwdG9yczogdGhpcy5pbnRlcmNlcHRvcnMsXG4gICAgICAgIH0sXG4gICAgICAgIChlcnI6IFNlcnZpY2VFcnJvciB8IG51bGwsIHJlc3A6IHVua25vd24pID0+IHtcbiAgICAgICAgICBpZiAocmVzcCkge1xuICAgICAgICAgICAgY29uc3QgZm91bmRFbGVtZW50cyA9IChyZXNwIGFzIGxlYWRlcmJvYXJkLl9HZXRCeVJhbmtSZXNwb25zZSlcbiAgICAgICAgICAgICAgLmVsZW1lbnRzO1xuICAgICAgICAgICAgcmVzb2x2ZShuZXcgTGVhZGVyYm9hcmRGZXRjaC5TdWNjZXNzKGZvdW5kRWxlbWVudHMpKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jYWNoZVNlcnZpY2VFcnJvck1hcHBlci5yZXNvbHZlT3JSZWplY3RFcnJvcih7XG4gICAgICAgICAgICAgIGVycjogZXJyLFxuICAgICAgICAgICAgICBlcnJvclJlc3BvbnNlRmFjdG9yeUZuOiBlID0+IG5ldyBMZWFkZXJib2FyZEZldGNoLkVycm9yKGUpLFxuICAgICAgICAgICAgICByZXNvbHZlRm46IHJlc29sdmUsXG4gICAgICAgICAgICAgIHJlamVjdEZuOiByZWplY3QsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZ2V0UmFuayhcbiAgICBjYWNoZU5hbWU6IHN0cmluZyxcbiAgICBsZWFkZXJib2FyZE5hbWU6IHN0cmluZyxcbiAgICBpZHM6IEFycmF5PG51bWJlcj4sXG4gICAgb3JkZXI/OiBMZWFkZXJib2FyZE9yZGVyXG4gICk6IFByb21pc2U8TGVhZGVyYm9hcmRGZXRjaC5SZXNwb25zZT4ge1xuICAgIGNvbnN0IG9yZGVyVmFsdWUgPSBvcmRlciA/PyBMZWFkZXJib2FyZE9yZGVyLkFzY2VuZGluZztcbiAgICB0aGlzLmxvZ2dlci50cmFjZShcbiAgICAgIGBJc3N1aW5nICdnZXRSYW5rJyByZXF1ZXN0OyBjYWNoZTogJHtjYWNoZU5hbWV9LCBsZWFkZXJib2FyZDogJHtsZWFkZXJib2FyZE5hbWV9LCBvcmRlcjogJHtvcmRlclZhbHVlLnRvU3RyaW5nKCl9LCBudW1iZXIgb2YgaWRzOiAke1xuICAgICAgICBpZHMubGVuZ3RoXG4gICAgICB9YFxuICAgICk7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuc2VuZEdldFJhbmsoY2FjaGVOYW1lLCBsZWFkZXJib2FyZE5hbWUsIGlkcywgb3JkZXJWYWx1ZSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHNlbmRHZXRSYW5rKFxuICAgIGNhY2hlTmFtZTogc3RyaW5nLFxuICAgIGxlYWRlcmJvYXJkTmFtZTogc3RyaW5nLFxuICAgIGlkczogQXJyYXk8bnVtYmVyPixcbiAgICBvcmRlcjogTGVhZGVyYm9hcmRPcmRlclxuICApOiBQcm9taXNlPExlYWRlcmJvYXJkRmV0Y2guUmVzcG9uc2U+IHtcbiAgICBjb25zdCBwcm90b0J1Zk9yZGVyID1cbiAgICAgIG9yZGVyID09PSBMZWFkZXJib2FyZE9yZGVyLkRlc2NlbmRpbmdcbiAgICAgICAgPyBsZWFkZXJib2FyZC5fT3JkZXIuREVTQ0VORElOR1xuICAgICAgICA6IGxlYWRlcmJvYXJkLl9PcmRlci5BU0NFTkRJTkc7XG5cbiAgICBjb25zdCByZXF1ZXN0ID0gbmV3IGxlYWRlcmJvYXJkLl9HZXRSYW5rUmVxdWVzdCh7XG4gICAgICBjYWNoZV9uYW1lOiBjYWNoZU5hbWUsXG4gICAgICBsZWFkZXJib2FyZDogbGVhZGVyYm9hcmROYW1lLFxuICAgICAgaWRzOiBpZHMsXG4gICAgICBvcmRlcjogcHJvdG9CdWZPcmRlcixcbiAgICB9KTtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHRoaXMuY3JlYXRlTWV0YWRhdGEoY2FjaGVOYW1lKTtcbiAgICByZXR1cm4gYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgdGhpcy5nZXROZXh0RGF0YUNsaWVudCgpLkdldFJhbmsoXG4gICAgICAgIHJlcXVlc3QsXG4gICAgICAgIG1ldGFkYXRhLFxuICAgICAgICB7XG4gICAgICAgICAgaW50ZXJjZXB0b3JzOiB0aGlzLmludGVyY2VwdG9ycyxcbiAgICAgICAgfSxcbiAgICAgICAgKGVycjogU2VydmljZUVycm9yIHwgbnVsbCwgcmVzcDogdW5rbm93bikgPT4ge1xuICAgICAgICAgIGlmIChyZXNwKSB7XG4gICAgICAgICAgICBjb25zdCBmb3VuZEVsZW1lbnRzID0gKHJlc3AgYXMgbGVhZGVyYm9hcmQuX0dldFJhbmtSZXNwb25zZSlcbiAgICAgICAgICAgICAgLmVsZW1lbnRzO1xuICAgICAgICAgICAgcmVzb2x2ZShuZXcgTGVhZGVyYm9hcmRGZXRjaC5TdWNjZXNzKGZvdW5kRWxlbWVudHMpKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jYWNoZVNlcnZpY2VFcnJvck1hcHBlci5yZXNvbHZlT3JSZWplY3RFcnJvcih7XG4gICAgICAgICAgICAgIGVycjogZXJyLFxuICAgICAgICAgICAgICBlcnJvclJlc3BvbnNlRmFjdG9yeUZuOiBlID0+IG5ldyBMZWFkZXJib2FyZEZldGNoLkVycm9yKGUpLFxuICAgICAgICAgICAgICByZXNvbHZlRm46IHJlc29sdmUsXG4gICAgICAgICAgICAgIHJlamVjdEZuOiByZWplY3QsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgbGVuZ3RoKFxuICAgIGNhY2hlTmFtZTogc3RyaW5nLFxuICAgIGxlYWRlcmJvYXJkTmFtZTogc3RyaW5nXG4gICk6IFByb21pc2U8TGVhZGVyYm9hcmRMZW5ndGguUmVzcG9uc2U+IHtcbiAgICB0aGlzLmxvZ2dlci50cmFjZShcbiAgICAgIGBJc3N1aW5nICdsZW5ndGgnIHJlcXVlc3Q7IGNhY2hlOiAke2NhY2hlTmFtZX0sIGxlYWRlcmJvYXJkOiAke2xlYWRlcmJvYXJkTmFtZX1gXG4gICAgKTtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5zZW5kTGVuZ3RoKGNhY2hlTmFtZSwgbGVhZGVyYm9hcmROYW1lKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgc2VuZExlbmd0aChcbiAgICBjYWNoZU5hbWU6IHN0cmluZyxcbiAgICBsZWFkZXJib2FyZE5hbWU6IHN0cmluZ1xuICApOiBQcm9taXNlPExlYWRlcmJvYXJkTGVuZ3RoLlJlc3BvbnNlPiB7XG4gICAgY29uc3QgcmVxdWVzdCA9IG5ldyBsZWFkZXJib2FyZC5fR2V0TGVhZGVyYm9hcmRMZW5ndGhSZXF1ZXN0KHtcbiAgICAgIGNhY2hlX25hbWU6IGNhY2hlTmFtZSxcbiAgICAgIGxlYWRlcmJvYXJkOiBsZWFkZXJib2FyZE5hbWUsXG4gICAgfSk7XG4gICAgY29uc3QgbWV0YWRhdGEgPSB0aGlzLmNyZWF0ZU1ldGFkYXRhKGNhY2hlTmFtZSk7XG4gICAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHRoaXMuZ2V0TmV4dERhdGFDbGllbnQoKS5HZXRMZWFkZXJib2FyZExlbmd0aChcbiAgICAgICAgcmVxdWVzdCxcbiAgICAgICAgbWV0YWRhdGEsXG4gICAgICAgIHtcbiAgICAgICAgICBpbnRlcmNlcHRvcnM6IHRoaXMuaW50ZXJjZXB0b3JzLFxuICAgICAgICB9LFxuICAgICAgICAoZXJyOiBTZXJ2aWNlRXJyb3IgfCBudWxsLCByZXNwOiB1bmtub3duKSA9PiB7XG4gICAgICAgICAgaWYgKHJlc3ApIHtcbiAgICAgICAgICAgIGNvbnN0IGxlbmd0aCA9IChyZXNwIGFzIGxlYWRlcmJvYXJkLl9HZXRMZWFkZXJib2FyZExlbmd0aFJlc3BvbnNlKVxuICAgICAgICAgICAgICAuY291bnQ7XG4gICAgICAgICAgICByZXNvbHZlKG5ldyBMZWFkZXJib2FyZExlbmd0aC5TdWNjZXNzKGxlbmd0aCkpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmNhY2hlU2VydmljZUVycm9yTWFwcGVyLnJlc29sdmVPclJlamVjdEVycm9yKHtcbiAgICAgICAgICAgICAgZXJyOiBlcnIsXG4gICAgICAgICAgICAgIGVycm9yUmVzcG9uc2VGYWN0b3J5Rm46IGUgPT4gbmV3IExlYWRlcmJvYXJkTGVuZ3RoLkVycm9yKGUpLFxuICAgICAgICAgICAgICByZXNvbHZlRm46IHJlc29sdmUsXG4gICAgICAgICAgICAgIHJlamVjdEZuOiByZWplY3QsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgcmVtb3ZlRWxlbWVudHMoXG4gICAgY2FjaGVOYW1lOiBzdHJpbmcsXG4gICAgbGVhZGVyYm9hcmROYW1lOiBzdHJpbmcsXG4gICAgaWRzOiBBcnJheTxudW1iZXI+XG4gICk6IFByb21pc2U8TGVhZGVyYm9hcmRSZW1vdmVFbGVtZW50cy5SZXNwb25zZT4ge1xuICAgIHRyeSB7XG4gICAgICB2YWxpZGF0ZUxlYWRlcmJvYXJkTnVtYmVyT2ZFbGVtZW50cyhpZHMubGVuZ3RoKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHJldHVybiB0aGlzLmNhY2hlU2VydmljZUVycm9yTWFwcGVyLnJldHVybk9yVGhyb3dFcnJvcihcbiAgICAgICAgZXJyIGFzIEVycm9yLFxuICAgICAgICBlcnIgPT4gbmV3IExlYWRlcmJvYXJkUmVtb3ZlRWxlbWVudHMuRXJyb3IoZXJyKVxuICAgICAgKTtcbiAgICB9XG4gICAgdGhpcy5sb2dnZXIudHJhY2UoXG4gICAgICBgSXNzdWluZyAncmVtb3ZlRWxlbWVudHMnIHJlcXVlc3Q7IGNhY2hlOiAke2NhY2hlTmFtZX0sIGxlYWRlcmJvYXJkOiAke2xlYWRlcmJvYXJkTmFtZX0sIG51bWJlciBvZiBlbGVtZW50czogJHtpZHMubGVuZ3RoLnRvU3RyaW5nKCl9YFxuICAgICk7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuc2VuZFJlbW92ZUVsZW1lbnRzKGNhY2hlTmFtZSwgbGVhZGVyYm9hcmROYW1lLCBpZHMpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzZW5kUmVtb3ZlRWxlbWVudHMoXG4gICAgY2FjaGVOYW1lOiBzdHJpbmcsXG4gICAgbGVhZGVyYm9hcmROYW1lOiBzdHJpbmcsXG4gICAgaWRzOiBBcnJheTxudW1iZXI+XG4gICk6IFByb21pc2U8TGVhZGVyYm9hcmRSZW1vdmVFbGVtZW50cy5SZXNwb25zZT4ge1xuICAgIGNvbnN0IHJlcXVlc3QgPSBuZXcgbGVhZGVyYm9hcmQuX1JlbW92ZUVsZW1lbnRzUmVxdWVzdCh7XG4gICAgICBjYWNoZV9uYW1lOiBjYWNoZU5hbWUsXG4gICAgICBsZWFkZXJib2FyZDogbGVhZGVyYm9hcmROYW1lLFxuICAgICAgaWRzOiBpZHMsXG4gICAgfSk7XG4gICAgY29uc3QgbWV0YWRhdGEgPSB0aGlzLmNyZWF0ZU1ldGFkYXRhKGNhY2hlTmFtZSk7XG4gICAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHRoaXMuZ2V0TmV4dERhdGFDbGllbnQoKS5SZW1vdmVFbGVtZW50cyhcbiAgICAgICAgcmVxdWVzdCxcbiAgICAgICAgbWV0YWRhdGEsXG4gICAgICAgIHtcbiAgICAgICAgICBpbnRlcmNlcHRvcnM6IHRoaXMuaW50ZXJjZXB0b3JzLFxuICAgICAgICB9LFxuICAgICAgICAoZXJyOiBTZXJ2aWNlRXJyb3IgfCBudWxsLCByZXNwOiB1bmtub3duKSA9PiB7XG4gICAgICAgICAgaWYgKHJlc3ApIHtcbiAgICAgICAgICAgIHJlc29sdmUobmV3IExlYWRlcmJvYXJkUmVtb3ZlRWxlbWVudHMuU3VjY2VzcygpKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jYWNoZVNlcnZpY2VFcnJvck1hcHBlci5yZXNvbHZlT3JSZWplY3RFcnJvcih7XG4gICAgICAgICAgICAgIGVycjogZXJyLFxuICAgICAgICAgICAgICBlcnJvclJlc3BvbnNlRmFjdG9yeUZuOiBlID0+XG4gICAgICAgICAgICAgICAgbmV3IExlYWRlcmJvYXJkUmVtb3ZlRWxlbWVudHMuRXJyb3IoZSksXG4gICAgICAgICAgICAgIHJlc29sdmVGbjogcmVzb2x2ZSxcbiAgICAgICAgICAgICAgcmVqZWN0Rm46IHJlamVjdCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBkZWxldGUoXG4gICAgY2FjaGVOYW1lOiBzdHJpbmcsXG4gICAgbGVhZGVyYm9hcmROYW1lOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxMZWFkZXJib2FyZERlbGV0ZS5SZXNwb25zZT4ge1xuICAgIHRoaXMubG9nZ2VyLnRyYWNlKFxuICAgICAgYElzc3VpbmcgJ2RlbGV0ZScgcmVxdWVzdDsgY2FjaGU6ICR7Y2FjaGVOYW1lfSwgbGVhZGVyYm9hcmQ6ICR7bGVhZGVyYm9hcmROYW1lfWBcbiAgICApO1xuICAgIHJldHVybiBhd2FpdCB0aGlzLnNlbmREZWxldGUoY2FjaGVOYW1lLCBsZWFkZXJib2FyZE5hbWUpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBzZW5kRGVsZXRlKFxuICAgIGNhY2hlTmFtZTogc3RyaW5nLFxuICAgIGxlYWRlcmJvYXJkTmFtZTogc3RyaW5nXG4gICk6IFByb21pc2U8TGVhZGVyYm9hcmREZWxldGUuUmVzcG9uc2U+IHtcbiAgICBjb25zdCByZXF1ZXN0ID0gbmV3IGxlYWRlcmJvYXJkLl9EZWxldGVMZWFkZXJib2FyZFJlcXVlc3Qoe1xuICAgICAgY2FjaGVfbmFtZTogY2FjaGVOYW1lLFxuICAgICAgbGVhZGVyYm9hcmQ6IGxlYWRlcmJvYXJkTmFtZSxcbiAgICB9KTtcbiAgICBjb25zdCBtZXRhZGF0YSA9IHRoaXMuY3JlYXRlTWV0YWRhdGEoY2FjaGVOYW1lKTtcbiAgICByZXR1cm4gYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgdGhpcy5nZXROZXh0RGF0YUNsaWVudCgpLkRlbGV0ZUxlYWRlcmJvYXJkKFxuICAgICAgICByZXF1ZXN0LFxuICAgICAgICBtZXRhZGF0YSxcbiAgICAgICAge1xuICAgICAgICAgIGludGVyY2VwdG9yczogdGhpcy5pbnRlcmNlcHRvcnMsXG4gICAgICAgIH0sXG4gICAgICAgIChlcnI6IFNlcnZpY2VFcnJvciB8IG51bGwsIHJlc3A6IHVua25vd24pID0+IHtcbiAgICAgICAgICBpZiAocmVzcCkge1xuICAgICAgICAgICAgcmVzb2x2ZShuZXcgTGVhZGVyYm9hcmREZWxldGUuU3VjY2VzcygpKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jYWNoZVNlcnZpY2VFcnJvck1hcHBlci5yZXNvbHZlT3JSZWplY3RFcnJvcih7XG4gICAgICAgICAgICAgIGVycjogZXJyLFxuICAgICAgICAgICAgICBlcnJvclJlc3BvbnNlRmFjdG9yeUZuOiBlID0+IG5ldyBMZWFkZXJib2FyZERlbGV0ZS5FcnJvcihlKSxcbiAgICAgICAgICAgICAgcmVzb2x2ZUZuOiByZXNvbHZlLFxuICAgICAgICAgICAgICByZWplY3RGbjogcmVqZWN0LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICApO1xuICAgIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldE5leHREYXRhQ2xpZW50KCk6IGxlYWRlcmJvYXJkLkxlYWRlcmJvYXJkQ2xpZW50IHtcbiAgICBjb25zdCBjbGllbnRXcmFwcGVyID0gdGhpcy5jbGllbnRXcmFwcGVyc1t0aGlzLm5leHREYXRhQ2xpZW50SW5kZXhdO1xuICAgIHRoaXMubmV4dERhdGFDbGllbnRJbmRleCA9XG4gICAgICAodGhpcy5uZXh0RGF0YUNsaWVudEluZGV4ICsgMSkgJSB0aGlzLmNsaWVudFdyYXBwZXJzLmxlbmd0aDtcbiAgICByZXR1cm4gY2xpZW50V3JhcHBlci5nZXRDbGllbnQoKTtcbiAgfVxufVxuIl19