UNPKG

cmp-aws-database

Version:

The package "cmp-aws-database" is for its database, which defines global tables. These tables are designed to be imported and used across multiple applications of "craft-my-plate."

245 lines 35.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GenericDAO = exports.mapper = exports.dynamoDB = void 0; const client_dynamodb_1 = require("@aws-sdk/client-dynamodb"); const mapper_1 = require("@nova-odm/mapper"); exports.dynamoDB = new client_dynamodb_1.DynamoDB({ maxAttempts: 10 }); exports.mapper = new mapper_1.DataMapper({ client: exports.dynamoDB }); class GenericDAO { async batchUpdate(items, batchSize = 100) { let success = 0, totalToUpdate = items.length; let updateItems = []; while (items.length > 0) { let promises = []; let batch = items.splice(0, batchSize); promises = batch.map(item => this.update(item)); let results = await Promise.allSettled(promises); results.forEach(result => { if (result.status == "fulfilled") { success += 1; updateItems.push(result.value); } }); console.log(`${success}/${totalToUpdate}`); } return updateItems; } async parallelBatchPut(inputItems, batchSize = 1000, maxConcurrentSegments = 20) { let startTime = Date.now(); let items = []; items = items.concat(inputItems); items = items.map(item => { item.created_time = new Date(); // item.created_user = authContext.userSub return item; }); let maxSegments = []; let putItems = []; while (items.length > 0) { let batch = items.splice(0, batchSize * maxConcurrentSegments); let segment = []; while (batch.length > 0) { segment.push(batch.splice(0, batchSize)); } maxSegments.push(segment); } for (const segment of maxSegments) { let startTime = Date.now(); let promises = []; console.log(`batch length = ${segment.length}`); for (const batch of segment) { promises.push(this.batchPut(batch)); } let result = await Promise.all(promises); console.log("segment complete"); result.forEach((res) => { putItems = putItems.concat(res); }); console.log(`time for segment put ${Date.now() - startTime}`); } console.log(`total time for complete parallel put ${Date.now() - startTime}`); return putItems; } async parallelBatchDelete(inputItems, batchSize = 1000, maxConcurrentSegments = 20) { let startTime = Date.now(); let items = []; items = items.concat(inputItems); let maxSegments = []; let putItems = []; while (items.length > 0) { let batch = items.splice(0, batchSize * maxConcurrentSegments); let segment = []; while (batch.length > 0) { segment.push(batch.splice(0, batchSize)); } maxSegments.push(segment); } for (const segment of maxSegments) { let startTime = Date.now(); let promises = []; console.log(`batch length = ${segment.length}`); for (const batch of segment) { promises.push(this.batchDelete(batch)); } let result = await Promise.all(promises); console.log("segment complete"); result.forEach((res) => { putItems = putItems.concat(res); }); console.log(`time for segment delete ${Date.now() - startTime}`); } console.log(`total time for complete parallel delete ${Date.now() - startTime}`); return putItems; } /** * This function has to be used only in the scripts. * * @param valueConstructor the model class */ async parallelScan(valueConstructor, options) { let items = []; for await (const item of exports.mapper.parallelScan(valueConstructor, 4, options)) { items.push(item); if (items.length % 100000 == 0) { console.log("read 100K"); } } return items; } async scan(valueConstructor, options) { let items = []; for await (const item of exports.mapper.scan(valueConstructor, options)) { items.push(item); } return items; } async save(item) { item.created_time = new Date(); // item.created_user = authContext.userSub const res = await exports.mapper.put(item); return res; } async update(item) { item.updated_time = new Date(); // item.updated_user = authContext.userSub const res = await exports.mapper.update(item, { onMissing: "skip" }); return res; } async delete(item) { return await exports.mapper.delete(item, { returnValues: "ALL_OLD" }); } async get(item, readConsistency = "eventual") { const res = await exports.mapper.get(item, { readConsistency: readConsistency }); return res; } async batchPut(items) { let finalItems = []; items = items.map(item => { item.created_time = new Date(); // item.created_user = authContext.userSub return item; }); // console.log( "item:", items ) for await (const item of exports.mapper.batchPut(items)) { console.log(item); finalItems.push(item); } return finalItems; } async batchDelete(items) { let deleteItems = []; for await (const item of exports.mapper.batchDelete(items)) { deleteItems.push(item); } return deleteItems; } async batchGet(items, readConsistency = "eventual") { let getItems = []; for await (const item of exports.mapper.batchGet(items, { readConsistency: readConsistency })) { getItems.push(item); } return getItems; } async parallelBatchGet(inputItems, batchSize = 1000, maxConcurrentSegments = 20, readConsistency) { let startTime = Date.now(); let items = []; items = items.concat(inputItems); let maxSegments = []; let resultItems = []; while (items.length > 0) { let batch = items.splice(0, batchSize * maxConcurrentSegments); let segment = []; while (batch.length > 0) { segment.push(batch.splice(0, batchSize)); } maxSegments.push(segment); } for (const segment of maxSegments) { let startTime = Date.now(); let promises = []; console.log(`batch length = ${segment.length}`); for (const batch of segment) { promises.push(this.batchGet(batch, readConsistency)); } let result = await Promise.all(promises); console.log("segment complete"); result.forEach((res) => { resultItems = resultItems.concat(res); }); console.log(`time for segment get ${Date.now() - startTime}`); } console.log(`total time for complete parallel get ${Date.now() - startTime}`); return resultItems; } async parallelQuery(valueConstructor, keyConditions, maxConcurrentCalls = 20, options) { const startTime = Date.now(); const results = []; while (keyConditions.length > 0) { const segmentConditions = keyConditions.splice(0, maxConcurrentCalls); const queryPromises = segmentConditions.map((keyCondition) => { return this.customQuery(valueConstructor, keyCondition, options); }); const queryResults = await Promise.all(queryPromises); for (const queryResult of queryResults) { results.push(...queryResult); } } console.log(`total time for complete parallel query ${Date.now() - startTime}`); return results; } async customQuery(valueConstructor, keyConditions, options) { const startTime = Date.now(); const items = []; for await (const item of exports.mapper.query(valueConstructor, keyConditions, options)) { items.push(item); } console.log(`total time for complete query ${Date.now() - startTime}`); return items; } decode(continuationToken) { if (continuationToken) { try { let lastEvaluatedKey = JSON.parse(Buffer.from(continuationToken, 'base64').toString('utf8')); console.log("Incoming Last Evaluated Key " + lastEvaluatedKey); return lastEvaluatedKey; } catch (error) { throw new Error('Invalid continuationToken'); } } return undefined; } async encode(lastEvaluatedKey) { return Buffer.from(JSON.stringify(lastEvaluatedKey)).toString('base64'); } } exports.GenericDAO = GenericDAO; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1kYW8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYmFzZS1kYW8udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsOERBQW9EO0FBQ3BELDZDQU8wQjtBQU1iLFFBQUEsUUFBUSxHQUFHLElBQUksMEJBQVEsQ0FBQztJQUNqQyxXQUFXLEVBQUUsRUFBRTtDQUNsQixDQUFRLENBQUE7QUFDSSxRQUFBLE1BQU0sR0FBRyxJQUFJLG1CQUFVLENBQUMsRUFBRSxNQUFNLEVBQUUsZ0JBQVEsRUFBRSxDQUFDLENBQUM7QUFFM0QsTUFBYSxVQUFVO0lBQ25CLEtBQUssQ0FBQyxXQUFXLENBQUMsS0FBVSxFQUFFLFNBQVMsR0FBRyxHQUFHO1FBQ3pDLElBQUksT0FBTyxHQUFHLENBQUMsRUFBRSxhQUFhLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQTtRQUM3QyxJQUFJLFdBQVcsR0FBUSxFQUFFLENBQUE7UUFDekIsT0FBTyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3RCLElBQUksUUFBUSxHQUFHLEVBQUUsQ0FBQTtZQUNqQixJQUFJLEtBQUssR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQTtZQUN0QyxRQUFRLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQTtZQUMvQyxJQUFJLE9BQU8sR0FBRyxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUE7WUFDaEQsT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRTtnQkFDckIsSUFBSSxNQUFNLENBQUMsTUFBTSxJQUFJLFdBQVcsRUFBRSxDQUFDO29CQUMvQixPQUFPLElBQUksQ0FBQyxDQUFBO29CQUNaLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFBO2dCQUNsQyxDQUFDO1lBQ0wsQ0FBQyxDQUFDLENBQUE7WUFDRixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsT0FBTyxJQUFJLGFBQWEsRUFBRSxDQUFDLENBQUE7UUFDOUMsQ0FBQztRQUNELE9BQU8sV0FBVyxDQUFBO0lBQ3RCLENBQUM7SUFFRCxLQUFLLENBQUMsZ0JBQWdCLENBQUMsVUFBZSxFQUFFLFlBQW9CLElBQUksRUFBRSx3QkFBZ0MsRUFBRTtRQUNoRyxJQUFJLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUE7UUFDMUIsSUFBSSxLQUFLLEdBQVEsRUFBRSxDQUFBO1FBQ25CLEtBQUssR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FBQ2hDLEtBQUssR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ3JCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQTtZQUM5QiwwQ0FBMEM7WUFDMUMsT0FBTyxJQUFJLENBQUE7UUFDZixDQUFDLENBQUMsQ0FBQTtRQUNGLElBQUksV0FBVyxHQUFZLEVBQUUsQ0FBQTtRQUM3QixJQUFJLFFBQVEsR0FBUSxFQUFFLENBQUE7UUFDdEIsT0FBTyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3RCLElBQUksS0FBSyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLFNBQVMsR0FBRyxxQkFBcUIsQ0FBQyxDQUFBO1lBQzlELElBQUksT0FBTyxHQUFVLEVBQUUsQ0FBQTtZQUN2QixPQUFPLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3RCLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQTtZQUM1QyxDQUFDO1lBQ0QsV0FBVyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUM3QixDQUFDO1FBQ0QsS0FBSyxNQUFNLE9BQU8sSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUNoQyxJQUFJLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUE7WUFDMUIsSUFBSSxRQUFRLEdBQW1CLEVBQUUsQ0FBQTtZQUNqQyxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQTtZQUMvQyxLQUFLLE1BQU0sS0FBSyxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUMxQixRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQTtZQUN2QyxDQUFDO1lBQ0QsSUFBSSxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFBO1lBQ3hDLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCLENBQUMsQ0FBQTtZQUMvQixNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUU7Z0JBQ25CLFFBQVEsR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQ25DLENBQUMsQ0FBQyxDQUFBO1lBQ0YsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFNBQVMsRUFBRSxDQUFDLENBQUE7UUFDakUsQ0FBQztRQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsd0NBQXdDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLEVBQUUsQ0FBQyxDQUFBO1FBQzdFLE9BQU8sUUFBUSxDQUFBO0lBQ25CLENBQUM7SUFFRCxLQUFLLENBQUMsbUJBQW1CLENBQUMsVUFBZSxFQUFFLFlBQW9CLElBQUksRUFBRSx3QkFBZ0MsRUFBRTtRQUNuRyxJQUFJLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUE7UUFDMUIsSUFBSSxLQUFLLEdBQVEsRUFBRSxDQUFBO1FBQ25CLEtBQUssR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FBQ2hDLElBQUksV0FBVyxHQUFZLEVBQUUsQ0FBQTtRQUM3QixJQUFJLFFBQVEsR0FBUSxFQUFFLENBQUE7UUFDdEIsT0FBTyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3RCLElBQUksS0FBSyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLFNBQVMsR0FBRyxxQkFBcUIsQ0FBQyxDQUFBO1lBQzlELElBQUksT0FBTyxHQUFVLEVBQUUsQ0FBQTtZQUN2QixPQUFPLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3RCLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQTtZQUM1QyxDQUFDO1lBQ0QsV0FBVyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUM3QixDQUFDO1FBQ0QsS0FBSyxNQUFNLE9BQU8sSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUNoQyxJQUFJLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUE7WUFDMUIsSUFBSSxRQUFRLEdBQW1CLEVBQUUsQ0FBQTtZQUNqQyxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQTtZQUMvQyxLQUFLLE1BQU0sS0FBSyxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUMxQixRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQTtZQUMxQyxDQUFDO1lBQ0QsSUFBSSxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFBO1lBQ3hDLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCLENBQUMsQ0FBQTtZQUMvQixNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUU7Z0JBQ25CLFFBQVEsR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQ25DLENBQUMsQ0FBQyxDQUFBO1lBQ0YsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFNBQVMsRUFBRSxDQUFDLENBQUE7UUFDcEUsQ0FBQztRQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsMkNBQTJDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLEVBQUUsQ0FBQyxDQUFBO1FBQ2hGLE9BQU8sUUFBUSxDQUFBO0lBQ25CLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLFlBQVksQ0FBQyxnQkFBNkMsRUFBRSxPQUE2QjtRQUMzRixJQUFJLEtBQUssR0FBUSxFQUFFLENBQUE7UUFDbkIsSUFBSSxLQUFLLEVBQUUsTUFBTSxJQUFJLElBQUksY0FBTSxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUN6RSxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1lBQ2hCLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQzdCLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUE7WUFDNUIsQ0FBQztRQUNMLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQTtJQUNoQixDQUFDO0lBRUQsS0FBSyxDQUFDLElBQUksQ0FBQyxnQkFBNkMsRUFBRSxPQUFpRDtRQUN2RyxJQUFJLEtBQUssR0FBUSxFQUFFLENBQUE7UUFDbkIsSUFBSSxLQUFLLEVBQUUsTUFBTSxJQUFJLElBQUksY0FBTSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQzlELEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDcEIsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFBO0lBQ2hCLENBQUM7SUFFRCxLQUFLLENBQUMsSUFBSSxDQUFDLElBQU87UUFDZCxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUE7UUFDOUIsMENBQTBDO1FBQzFDLE1BQU0sR0FBRyxHQUFHLE1BQU0sY0FBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNsQyxPQUFPLEdBQUcsQ0FBQTtJQUNkLENBQUM7SUFFRCxLQUFLLENBQUMsTUFBTSxDQUFDLElBQU87UUFDaEIsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLElBQUksRUFBRSxDQUFBO1FBQzlCLDBDQUEwQztRQUMxQyxNQUFNLEdBQUcsR0FBRyxNQUFNLGNBQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFO1lBQ2xDLFNBQVMsRUFBRSxNQUFNO1NBQ3BCLENBQUMsQ0FBQTtRQUNGLE9BQU8sR0FBRyxDQUFBO0lBQ2QsQ0FBQztJQUVELEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBTztRQUNoQixPQUFPLE1BQU0sY0FBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQTtJQUNqRSxDQUFDO0lBRUQsS0FBSyxDQUFDLEdBQUcsQ0FBQyxJQUFPLEVBQUUsa0JBQW1DLFVBQVU7UUFDNUQsTUFBTSxHQUFHLEdBQUcsTUFBTSxjQUFNLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRTtZQUMvQixlQUFlLEVBQUUsZUFBZTtTQUNuQyxDQUFDLENBQUE7UUFDRixPQUFPLEdBQUcsQ0FBQTtJQUNkLENBQUM7SUFFRCxLQUFLLENBQUMsUUFBUSxDQUFDLEtBQVU7UUFFckIsSUFBSSxVQUFVLEdBQVEsRUFBRSxDQUFBO1FBQ3hCLEtBQUssR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ3JCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQTtZQUM5QiwwQ0FBMEM7WUFDMUMsT0FBTyxJQUFJLENBQUE7UUFDZixDQUFDLENBQUMsQ0FBQTtRQUNGLGdDQUFnQztRQUNoQyxJQUFJLEtBQUssRUFBRSxNQUFNLElBQUksSUFBSSxjQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDOUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQTtZQUNqQixVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQ3pCLENBQUM7UUFDRCxPQUFPLFVBQVUsQ0FBQTtJQUNyQixDQUFDO0lBRUQsS0FBSyxDQUFDLFdBQVcsQ0FBQyxLQUFVO1FBQ3hCLElBQUksV0FBVyxHQUFRLEVBQUUsQ0FBQTtRQUN6QixJQUFJLEtBQUssRUFBRSxNQUFNLElBQUksSUFBSSxjQUFNLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDakQsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUMxQixDQUFDO1FBQ0QsT0FBTyxXQUFXLENBQUE7SUFDdEIsQ0FBQztJQUVELEtBQUssQ0FBQyxRQUFRLENBQUMsS0FBVSxFQUFFLGtCQUFtQyxVQUFVO1FBQ3BFLElBQUksUUFBUSxHQUFRLEVBQUUsQ0FBQTtRQUN0QixJQUFJLEtBQUssRUFBRSxNQUFNLElBQUksSUFBSSxjQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRTtZQUM1QyxlQUFlLEVBQUUsZUFBZTtTQUNuQyxDQUFDLEVBQUUsQ0FBQztZQUNELFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDdkIsQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFBO0lBQ25CLENBQUM7SUFFRCxLQUFLLENBQUMsZ0JBQWdCLENBQUMsVUFBZSxFQUFFLFlBQW9CLElBQUksRUFBRSx3QkFBZ0MsRUFBRSxFQUFFLGVBQWlDO1FBQ25JLElBQUksU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQTtRQUMxQixJQUFJLEtBQUssR0FBUSxFQUFFLENBQUE7UUFDbkIsS0FBSyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUE7UUFDaEMsSUFBSSxXQUFXLEdBQVksRUFBRSxDQUFBO1FBQzdCLElBQUksV0FBVyxHQUFRLEVBQUUsQ0FBQTtRQUN6QixPQUFPLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdEIsSUFBSSxLQUFLLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsU0FBUyxHQUFHLHFCQUFxQixDQUFDLENBQUE7WUFDOUQsSUFBSSxPQUFPLEdBQVUsRUFBRSxDQUFBO1lBQ3ZCLE9BQU8sS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDdEIsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFBO1lBQzVDLENBQUM7WUFDRCxXQUFXLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQzdCLENBQUM7UUFDRCxLQUFLLE1BQU0sT0FBTyxJQUFJLFdBQVcsRUFBRSxDQUFDO1lBQ2hDLElBQUksU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQTtZQUMxQixJQUFJLFFBQVEsR0FBbUIsRUFBRSxDQUFBO1lBQ2pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFBO1lBQy9DLEtBQUssTUFBTSxLQUFLLElBQUksT0FBTyxFQUFFLENBQUM7Z0JBQzFCLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FBQTtZQUN4RCxDQUFDO1lBQ0QsSUFBSSxNQUFNLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFBO1lBQ3hDLE9BQU8sQ0FBQyxHQUFHLENBQUMsa0JBQWtCLENBQUMsQ0FBQTtZQUMvQixNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUU7Z0JBQ25CLFdBQVcsR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBQ3pDLENBQUMsQ0FBQyxDQUFBO1lBQ0YsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFNBQVMsRUFBRSxDQUFDLENBQUE7UUFDakUsQ0FBQztRQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsd0NBQXdDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLEVBQUUsQ0FBQyxDQUFBO1FBQzdFLE9BQU8sV0FBVyxDQUFBO0lBQ3RCLENBQUM7SUFDRCxLQUFLLENBQUMsYUFBYSxDQUNmLGdCQUE2QyxFQUM3QyxhQUEwRyxFQUMxRyxxQkFBNkIsRUFBRSxFQUMvQixPQUFzQjtRQUd0QixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUE7UUFDNUIsTUFBTSxPQUFPLEdBQVEsRUFBRSxDQUFBO1FBQ3ZCLE9BQU8sYUFBYSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUM5QixNQUFNLGlCQUFpQixHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLGtCQUFrQixDQUFDLENBQUE7WUFDckUsTUFBTSxhQUFhLEdBQUcsaUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUMsWUFBWSxFQUFFLEVBQUU7Z0JBQ3pELE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxnQkFBZ0IsRUFBRSxZQUFZLEVBQUUsT0FBTyxDQUFDLENBQUE7WUFDcEUsQ0FBQyxDQUVBLENBQUE7WUFDRCxNQUFNLFlBQVksR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUE7WUFFckQsS0FBSyxNQUFNLFdBQVcsSUFBSSxZQUFZLEVBQUUsQ0FBQztnQkFDckMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLFdBQVcsQ0FBQyxDQUFBO1lBQ2hDLENBQUM7UUFDTCxDQUFDO1FBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQ0FBMEMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFNBQVMsRUFBRSxDQUFDLENBQUE7UUFDL0UsT0FBTyxPQUFPLENBQUE7SUFDbEIsQ0FBQztJQUNPLEtBQUssQ0FBQyxXQUFXLENBQ3JCLGdCQUE2QyxFQUM3QyxhQUFtRyxFQUNuRyxPQUFzQjtRQUV0QixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUE7UUFDNUIsTUFBTSxLQUFLLEdBQVEsRUFBRSxDQUFBO1FBRXJCLElBQUksS0FBSyxFQUFFLE1BQU0sSUFBSSxJQUFJLGNBQU0sQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEVBQUUsYUFBYSxFQUFFLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDOUUsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUNwQixDQUFDO1FBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQ0FBaUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFNBQVMsRUFBRSxDQUFDLENBQUE7UUFFdEUsT0FBTyxLQUFLLENBQUE7SUFDaEIsQ0FBQztJQUNELE1BQU0sQ0FBQyxpQkFBcUM7UUFDeEMsSUFBSSxpQkFBaUIsRUFBRSxDQUFDO1lBQ3BCLElBQUksQ0FBQztnQkFDRCxJQUFJLGdCQUFnQixHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxRQUFRLENBQUMsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztnQkFDN0YsT0FBTyxDQUFDLEdBQUcsQ0FBQyw4QkFBOEIsR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDO2dCQUMvRCxPQUFPLGdCQUFnQixDQUFDO1lBQzVCLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNiLE1BQU0sSUFBSSxLQUFLLENBQUMsMkJBQTJCLENBQUMsQ0FBQztZQUNqRCxDQUFDO1FBQ0wsQ0FBQztRQUNELE9BQU8sU0FBUyxDQUFBO0lBQ3BCLENBQUM7SUFFRCxLQUFLLENBQUMsTUFBTSxDQUFDLGdCQUFxQjtRQUM5QixPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFBO0lBQzNFLENBQUM7Q0FDSjtBQXJRRCxnQ0FxUUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEeW5hbW9EQiB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1keW5hbW9kYic7XG5pbXBvcnQge1xuICAgIERhdGFNYXBwZXIsXG4gICAgUGFyYWxsZWxTY2FuT3B0aW9ucyxcbiAgICBQYXJhbGxlbFNjYW5Xb3JrZXJPcHRpb25zLFxuICAgIFF1ZXJ5T3B0aW9ucyxcbiAgICBSZWFkQ29uc2lzdGVuY3ksXG4gICAgU2Nhbk9wdGlvbnNcbn0gZnJvbSAnQG5vdmEtb2RtL21hcHBlcic7XG5pbXBvcnQgeyBaZXJvQXJndW1lbnRzQ29uc3RydWN0b3IgfSBmcm9tICdAbm92YS1vZG0vbWFyc2hhbGxlcic7XG5pbXBvcnQgeyBDb25kaXRpb25FeHByZXNzaW9uLCBDb25kaXRpb25FeHByZXNzaW9uUHJlZGljYXRlIH0gZnJvbSAnQG5vdmEtb2RtL2V4cHJlc3Npb25zJztcbmltcG9ydCB7IEJhc2VNb2RlbCB9IGZyb20gJy4vYmFzZS1tb2RlbCc7XG5cblxuZXhwb3J0IGNvbnN0IGR5bmFtb0RCID0gbmV3IER5bmFtb0RCKHtcbiAgICBtYXhBdHRlbXB0czogMTBcbn0pIGFzIGFueVxuZXhwb3J0IGNvbnN0IG1hcHBlciA9IG5ldyBEYXRhTWFwcGVyKHsgY2xpZW50OiBkeW5hbW9EQiB9KTtcblxuZXhwb3J0IGNsYXNzIEdlbmVyaWNEQU88VCBleHRlbmRzIEJhc2VNb2RlbD4ge1xuICAgIGFzeW5jIGJhdGNoVXBkYXRlKGl0ZW1zOiBUW10sIGJhdGNoU2l6ZSA9IDEwMCk6IFByb21pc2U8VFtdPiB7XG4gICAgICAgIGxldCBzdWNjZXNzID0gMCwgdG90YWxUb1VwZGF0ZSA9IGl0ZW1zLmxlbmd0aFxuICAgICAgICBsZXQgdXBkYXRlSXRlbXM6IFRbXSA9IFtdXG4gICAgICAgIHdoaWxlIChpdGVtcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBsZXQgcHJvbWlzZXMgPSBbXVxuICAgICAgICAgICAgbGV0IGJhdGNoID0gaXRlbXMuc3BsaWNlKDAsIGJhdGNoU2l6ZSlcbiAgICAgICAgICAgIHByb21pc2VzID0gYmF0Y2gubWFwKGl0ZW0gPT4gdGhpcy51cGRhdGUoaXRlbSkpXG4gICAgICAgICAgICBsZXQgcmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChwcm9taXNlcylcbiAgICAgICAgICAgIHJlc3VsdHMuZm9yRWFjaChyZXN1bHQgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChyZXN1bHQuc3RhdHVzID09IFwiZnVsZmlsbGVkXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgc3VjY2VzcyArPSAxXG4gICAgICAgICAgICAgICAgICAgIHVwZGF0ZUl0ZW1zLnB1c2gocmVzdWx0LnZhbHVlKVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgJHtzdWNjZXNzfS8ke3RvdGFsVG9VcGRhdGV9YClcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXBkYXRlSXRlbXNcbiAgICB9XG5cbiAgICBhc3luYyBwYXJhbGxlbEJhdGNoUHV0KGlucHV0SXRlbXM6IFRbXSwgYmF0Y2hTaXplOiBudW1iZXIgPSAxMDAwLCBtYXhDb25jdXJyZW50U2VnbWVudHM6IG51bWJlciA9IDIwKTogUHJvbWlzZTxUW10+IHtcbiAgICAgICAgbGV0IHN0YXJ0VGltZSA9IERhdGUubm93KClcbiAgICAgICAgbGV0IGl0ZW1zOiBUW10gPSBbXVxuICAgICAgICBpdGVtcyA9IGl0ZW1zLmNvbmNhdChpbnB1dEl0ZW1zKVxuICAgICAgICBpdGVtcyA9IGl0ZW1zLm1hcChpdGVtID0+IHtcbiAgICAgICAgICAgIGl0ZW0uY3JlYXRlZF90aW1lID0gbmV3IERhdGUoKVxuICAgICAgICAgICAgLy8gaXRlbS5jcmVhdGVkX3VzZXIgPSBhdXRoQ29udGV4dC51c2VyU3ViXG4gICAgICAgICAgICByZXR1cm4gaXRlbVxuICAgICAgICB9KVxuICAgICAgICBsZXQgbWF4U2VnbWVudHM6IFRbXVtdW10gPSBbXVxuICAgICAgICBsZXQgcHV0SXRlbXM6IFRbXSA9IFtdXG4gICAgICAgIHdoaWxlIChpdGVtcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBsZXQgYmF0Y2ggPSBpdGVtcy5zcGxpY2UoMCwgYmF0Y2hTaXplICogbWF4Q29uY3VycmVudFNlZ21lbnRzKVxuICAgICAgICAgICAgbGV0IHNlZ21lbnQ6IFRbXVtdID0gW11cbiAgICAgICAgICAgIHdoaWxlIChiYXRjaC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgc2VnbWVudC5wdXNoKGJhdGNoLnNwbGljZSgwLCBiYXRjaFNpemUpKVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbWF4U2VnbWVudHMucHVzaChzZWdtZW50KVxuICAgICAgICB9XG4gICAgICAgIGZvciAoY29uc3Qgc2VnbWVudCBvZiBtYXhTZWdtZW50cykge1xuICAgICAgICAgICAgbGV0IHN0YXJ0VGltZSA9IERhdGUubm93KClcbiAgICAgICAgICAgIGxldCBwcm9taXNlczogUHJvbWlzZTxUW10+W10gPSBbXVxuICAgICAgICAgICAgY29uc29sZS5sb2coYGJhdGNoIGxlbmd0aCA9ICR7c2VnbWVudC5sZW5ndGh9YClcbiAgICAgICAgICAgIGZvciAoY29uc3QgYmF0Y2ggb2Ygc2VnbWVudCkge1xuICAgICAgICAgICAgICAgIHByb21pc2VzLnB1c2godGhpcy5iYXRjaFB1dChiYXRjaCkpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsZXQgcmVzdWx0ID0gYXdhaXQgUHJvbWlzZS5hbGwocHJvbWlzZXMpXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcInNlZ21lbnQgY29tcGxldGVcIilcbiAgICAgICAgICAgIHJlc3VsdC5mb3JFYWNoKChyZXMpID0+IHtcbiAgICAgICAgICAgICAgICBwdXRJdGVtcyA9IHB1dEl0ZW1zLmNvbmNhdChyZXMpXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgY29uc29sZS5sb2coYHRpbWUgZm9yIHNlZ21lbnQgcHV0ICR7RGF0ZS5ub3coKSAtIHN0YXJ0VGltZX1gKVxuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUubG9nKGB0b3RhbCB0aW1lIGZvciBjb21wbGV0ZSBwYXJhbGxlbCBwdXQgJHtEYXRlLm5vdygpIC0gc3RhcnRUaW1lfWApXG4gICAgICAgIHJldHVybiBwdXRJdGVtc1xuICAgIH1cblxuICAgIGFzeW5jIHBhcmFsbGVsQmF0Y2hEZWxldGUoaW5wdXRJdGVtczogVFtdLCBiYXRjaFNpemU6IG51bWJlciA9IDEwMDAsIG1heENvbmN1cnJlbnRTZWdtZW50czogbnVtYmVyID0gMjApOiBQcm9taXNlPFRbXT4ge1xuICAgICAgICBsZXQgc3RhcnRUaW1lID0gRGF0ZS5ub3coKVxuICAgICAgICBsZXQgaXRlbXM6IFRbXSA9IFtdXG4gICAgICAgIGl0ZW1zID0gaXRlbXMuY29uY2F0KGlucHV0SXRlbXMpXG4gICAgICAgIGxldCBtYXhTZWdtZW50czogVFtdW11bXSA9IFtdXG4gICAgICAgIGxldCBwdXRJdGVtczogVFtdID0gW11cbiAgICAgICAgd2hpbGUgKGl0ZW1zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGxldCBiYXRjaCA9IGl0ZW1zLnNwbGljZSgwLCBiYXRjaFNpemUgKiBtYXhDb25jdXJyZW50U2VnbWVudHMpXG4gICAgICAgICAgICBsZXQgc2VnbWVudDogVFtdW10gPSBbXVxuICAgICAgICAgICAgd2hpbGUgKGJhdGNoLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBzZWdtZW50LnB1c2goYmF0Y2guc3BsaWNlKDAsIGJhdGNoU2l6ZSkpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBtYXhTZWdtZW50cy5wdXNoKHNlZ21lbnQpXG4gICAgICAgIH1cbiAgICAgICAgZm9yIChjb25zdCBzZWdtZW50IG9mIG1heFNlZ21lbnRzKSB7XG4gICAgICAgICAgICBsZXQgc3RhcnRUaW1lID0gRGF0ZS5ub3coKVxuICAgICAgICAgICAgbGV0IHByb21pc2VzOiBQcm9taXNlPFRbXT5bXSA9IFtdXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgYmF0Y2ggbGVuZ3RoID0gJHtzZWdtZW50Lmxlbmd0aH1gKVxuICAgICAgICAgICAgZm9yIChjb25zdCBiYXRjaCBvZiBzZWdtZW50KSB7XG4gICAgICAgICAgICAgICAgcHJvbWlzZXMucHVzaCh0aGlzLmJhdGNoRGVsZXRlKGJhdGNoKSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCByZXN1bHQgPSBhd2FpdCBQcm9taXNlLmFsbChwcm9taXNlcylcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwic2VnbWVudCBjb21wbGV0ZVwiKVxuICAgICAgICAgICAgcmVzdWx0LmZvckVhY2goKHJlcykgPT4ge1xuICAgICAgICAgICAgICAgIHB1dEl0ZW1zID0gcHV0SXRlbXMuY29uY2F0KHJlcylcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgdGltZSBmb3Igc2VnbWVudCBkZWxldGUgJHtEYXRlLm5vdygpIC0gc3RhcnRUaW1lfWApXG4gICAgICAgIH1cbiAgICAgICAgY29uc29sZS5sb2coYHRvdGFsIHRpbWUgZm9yIGNvbXBsZXRlIHBhcmFsbGVsIGRlbGV0ZSAke0RhdGUubm93KCkgLSBzdGFydFRpbWV9YClcbiAgICAgICAgcmV0dXJuIHB1dEl0ZW1zXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhpcyBmdW5jdGlvbiBoYXMgdG8gYmUgdXNlZCBvbmx5IGluIHRoZSBzY3JpcHRzLlxuICAgICAqIFxuICAgICAqIEBwYXJhbSB2YWx1ZUNvbnN0cnVjdG9yIHRoZSBtb2RlbCBjbGFzc1xuICAgICAqL1xuICAgIGFzeW5jIHBhcmFsbGVsU2Nhbih2YWx1ZUNvbnN0cnVjdG9yOiBaZXJvQXJndW1lbnRzQ29uc3RydWN0b3I8VD4sIG9wdGlvbnM/OiBQYXJhbGxlbFNjYW5PcHRpb25zKTogUHJvbWlzZTxUW10+IHtcbiAgICAgICAgbGV0IGl0ZW1zOiBUW10gPSBbXVxuICAgICAgICBmb3IgYXdhaXQgKGNvbnN0IGl0ZW0gb2YgbWFwcGVyLnBhcmFsbGVsU2Nhbih2YWx1ZUNvbnN0cnVjdG9yLCA0LCBvcHRpb25zKSkge1xuICAgICAgICAgICAgaXRlbXMucHVzaChpdGVtKVxuICAgICAgICAgICAgaWYgKGl0ZW1zLmxlbmd0aCAlIDEwMDAwMCA9PSAwKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJyZWFkIDEwMEtcIilcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaXRlbXNcbiAgICB9XG5cbiAgICBhc3luYyBzY2FuKHZhbHVlQ29uc3RydWN0b3I6IFplcm9Bcmd1bWVudHNDb25zdHJ1Y3RvcjxUPiwgb3B0aW9ucz86IFNjYW5PcHRpb25zIHwgUGFyYWxsZWxTY2FuV29ya2VyT3B0aW9ucyk6IFByb21pc2U8VFtdPiB7XG4gICAgICAgIGxldCBpdGVtczogVFtdID0gW11cbiAgICAgICAgZm9yIGF3YWl0IChjb25zdCBpdGVtIG9mIG1hcHBlci5zY2FuKHZhbHVlQ29uc3RydWN0b3IsIG9wdGlvbnMpKSB7XG4gICAgICAgICAgICBpdGVtcy5wdXNoKGl0ZW0pXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGl0ZW1zXG4gICAgfVxuXG4gICAgYXN5bmMgc2F2ZShpdGVtOiBUKTogUHJvbWlzZTxUPiB7XG4gICAgICAgIGl0ZW0uY3JlYXRlZF90aW1lID0gbmV3IERhdGUoKVxuICAgICAgICAvLyBpdGVtLmNyZWF0ZWRfdXNlciA9IGF1dGhDb250ZXh0LnVzZXJTdWJcbiAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgbWFwcGVyLnB1dChpdGVtKVxuICAgICAgICByZXR1cm4gcmVzXG4gICAgfVxuXG4gICAgYXN5bmMgdXBkYXRlKGl0ZW06IFQpOiBQcm9taXNlPFQ+IHtcbiAgICAgICAgaXRlbS51cGRhdGVkX3RpbWUgPSBuZXcgRGF0ZSgpXG4gICAgICAgIC8vIGl0ZW0udXBkYXRlZF91c2VyID0gYXV0aENvbnRleHQudXNlclN1YlxuICAgICAgICBjb25zdCByZXMgPSBhd2FpdCBtYXBwZXIudXBkYXRlKGl0ZW0sIHtcbiAgICAgICAgICAgIG9uTWlzc2luZzogXCJza2lwXCJcbiAgICAgICAgfSlcbiAgICAgICAgcmV0dXJuIHJlc1xuICAgIH1cblxuICAgIGFzeW5jIGRlbGV0ZShpdGVtOiBUKTogUHJvbWlzZTxUIHwgdW5kZWZpbmVkPiB7XG4gICAgICAgIHJldHVybiBhd2FpdCBtYXBwZXIuZGVsZXRlKGl0ZW0sIHsgcmV0dXJuVmFsdWVzOiBcIkFMTF9PTERcIiB9KVxuICAgIH1cblxuICAgIGFzeW5jIGdldChpdGVtOiBULCByZWFkQ29uc2lzdGVuY3k6IFJlYWRDb25zaXN0ZW5jeSA9IFwiZXZlbnR1YWxcIik6IFByb21pc2U8VD4ge1xuICAgICAgICBjb25zdCByZXMgPSBhd2FpdCBtYXBwZXIuZ2V0KGl0ZW0sIHtcbiAgICAgICAgICAgIHJlYWRDb25zaXN0ZW5jeTogcmVhZENvbnNpc3RlbmN5XG4gICAgICAgIH0pXG4gICAgICAgIHJldHVybiByZXNcbiAgICB9XG5cbiAgICBhc3luYyBiYXRjaFB1dChpdGVtczogVFtdKTogUHJvbWlzZTxUW10+IHtcblxuICAgICAgICBsZXQgZmluYWxJdGVtczogVFtdID0gW11cbiAgICAgICAgaXRlbXMgPSBpdGVtcy5tYXAoaXRlbSA9PiB7XG4gICAgICAgICAgICBpdGVtLmNyZWF0ZWRfdGltZSA9IG5ldyBEYXRlKClcbiAgICAgICAgICAgIC8vIGl0ZW0uY3JlYXRlZF91c2VyID0gYXV0aENvbnRleHQudXNlclN1YlxuICAgICAgICAgICAgcmV0dXJuIGl0ZW1cbiAgICAgICAgfSlcbiAgICAgICAgLy8gY29uc29sZS5sb2coIFwiaXRlbTpcIiwgaXRlbXMgKVxuICAgICAgICBmb3IgYXdhaXQgKGNvbnN0IGl0ZW0gb2YgbWFwcGVyLmJhdGNoUHV0KGl0ZW1zKSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coaXRlbSlcbiAgICAgICAgICAgIGZpbmFsSXRlbXMucHVzaChpdGVtKVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmaW5hbEl0ZW1zXG4gICAgfVxuXG4gICAgYXN5bmMgYmF0Y2hEZWxldGUoaXRlbXM6IFRbXSk6IFByb21pc2U8VFtdPiB7XG4gICAgICAgIGxldCBkZWxldGVJdGVtczogVFtdID0gW11cbiAgICAgICAgZm9yIGF3YWl0IChjb25zdCBpdGVtIG9mIG1hcHBlci5iYXRjaERlbGV0ZShpdGVtcykpIHtcbiAgICAgICAgICAgIGRlbGV0ZUl0ZW1zLnB1c2goaXRlbSlcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZGVsZXRlSXRlbXNcbiAgICB9XG5cbiAgICBhc3luYyBiYXRjaEdldChpdGVtczogVFtdLCByZWFkQ29uc2lzdGVuY3k6IFJlYWRDb25zaXN0ZW5jeSA9IFwiZXZlbnR1YWxcIik6IFByb21pc2U8VFtdPiB7XG4gICAgICAgIGxldCBnZXRJdGVtczogVFtdID0gW11cbiAgICAgICAgZm9yIGF3YWl0IChjb25zdCBpdGVtIG9mIG1hcHBlci5iYXRjaEdldChpdGVtcywge1xuICAgICAgICAgICAgcmVhZENvbnNpc3RlbmN5OiByZWFkQ29uc2lzdGVuY3lcbiAgICAgICAgfSkpIHtcbiAgICAgICAgICAgIGdldEl0ZW1zLnB1c2goaXRlbSlcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZ2V0SXRlbXNcbiAgICB9XG5cbiAgICBhc3luYyBwYXJhbGxlbEJhdGNoR2V0KGlucHV0SXRlbXM6IFRbXSwgYmF0Y2hTaXplOiBudW1iZXIgPSAxMDAwLCBtYXhDb25jdXJyZW50U2VnbWVudHM6IG51bWJlciA9IDIwLCByZWFkQ29uc2lzdGVuY3k/OiBSZWFkQ29uc2lzdGVuY3kpOiBQcm9taXNlPFRbXT4ge1xuICAgICAgICBsZXQgc3RhcnRUaW1lID0gRGF0ZS5ub3coKVxuICAgICAgICBsZXQgaXRlbXM6IFRbXSA9IFtdXG4gICAgICAgIGl0ZW1zID0gaXRlbXMuY29uY2F0KGlucHV0SXRlbXMpXG4gICAgICAgIGxldCBtYXhTZWdtZW50czogVFtdW11bXSA9IFtdXG4gICAgICAgIGxldCByZXN1bHRJdGVtczogVFtdID0gW11cbiAgICAgICAgd2hpbGUgKGl0ZW1zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGxldCBiYXRjaCA9IGl0ZW1zLnNwbGljZSgwLCBiYXRjaFNpemUgKiBtYXhDb25jdXJyZW50U2VnbWVudHMpXG4gICAgICAgICAgICBsZXQgc2VnbWVudDogVFtdW10gPSBbXVxuICAgICAgICAgICAgd2hpbGUgKGJhdGNoLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBzZWdtZW50LnB1c2goYmF0Y2guc3BsaWNlKDAsIGJhdGNoU2l6ZSkpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBtYXhTZWdtZW50cy5wdXNoKHNlZ21lbnQpXG4gICAgICAgIH1cbiAgICAgICAgZm9yIChjb25zdCBzZWdtZW50IG9mIG1heFNlZ21lbnRzKSB7XG4gICAgICAgICAgICBsZXQgc3RhcnRUaW1lID0gRGF0ZS5ub3coKVxuICAgICAgICAgICAgbGV0IHByb21pc2VzOiBQcm9taXNlPFRbXT5bXSA9IFtdXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgYmF0Y2ggbGVuZ3RoID0gJHtzZWdtZW50Lmxlbmd0aH1gKVxuICAgICAgICAgICAgZm9yIChjb25zdCBiYXRjaCBvZiBzZWdtZW50KSB7XG4gICAgICAgICAgICAgICAgcHJvbWlzZXMucHVzaCh0aGlzLmJhdGNoR2V0KGJhdGNoLCByZWFkQ29uc2lzdGVuY3kpKVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UuYWxsKHByb21pc2VzKVxuICAgICAgICAgICAgY29uc29sZS5sb2coXCJzZWdtZW50IGNvbXBsZXRlXCIpXG4gICAgICAgICAgICByZXN1bHQuZm9yRWFjaCgocmVzKSA9PiB7XG4gICAgICAgICAgICAgICAgcmVzdWx0SXRlbXMgPSByZXN1bHRJdGVtcy5jb25jYXQocmVzKVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGB0aW1lIGZvciBzZWdtZW50IGdldCAke0RhdGUubm93KCkgLSBzdGFydFRpbWV9YClcbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmxvZyhgdG90YWwgdGltZSBmb3IgY29tcGxldGUgcGFyYWxsZWwgZ2V0ICR7RGF0ZS5ub3coKSAtIHN0YXJ0VGltZX1gKVxuICAgICAgICByZXR1cm4gcmVzdWx0SXRlbXNcbiAgICB9XG4gICAgYXN5bmMgcGFyYWxsZWxRdWVyeShcbiAgICAgICAgdmFsdWVDb25zdHJ1Y3RvcjogWmVyb0FyZ3VtZW50c0NvbnN0cnVjdG9yPFQ+LFxuICAgICAgICBrZXlDb25kaXRpb25zOiBBcnJheTxDb25kaXRpb25FeHByZXNzaW9uIHwgeyBbcHJvcGVydHlOYW1lOiBzdHJpbmddOiBDb25kaXRpb25FeHByZXNzaW9uUHJlZGljYXRlIHwgYW55IH0+LFxuICAgICAgICBtYXhDb25jdXJyZW50Q2FsbHM6IG51bWJlciA9IDIwLFxuICAgICAgICBvcHRpb25zPzogUXVlcnlPcHRpb25zLFxuXG4gICAgKTogUHJvbWlzZTxUW10+IHtcbiAgICAgICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKVxuICAgICAgICBjb25zdCByZXN1bHRzOiBUW10gPSBbXVxuICAgICAgICB3aGlsZSAoa2V5Q29uZGl0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb25zdCBzZWdtZW50Q29uZGl0aW9ucyA9IGtleUNvbmRpdGlvbnMuc3BsaWNlKDAsIG1heENvbmN1cnJlbnRDYWxscylcbiAgICAgICAgICAgIGNvbnN0IHF1ZXJ5UHJvbWlzZXMgPSBzZWdtZW50Q29uZGl0aW9ucy5tYXAoKGtleUNvbmRpdGlvbikgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmN1c3RvbVF1ZXJ5KHZhbHVlQ29uc3RydWN0b3IsIGtleUNvbmRpdGlvbiwgb3B0aW9ucylcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgY29uc3QgcXVlcnlSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGwocXVlcnlQcm9taXNlcylcblxuICAgICAgICAgICAgZm9yIChjb25zdCBxdWVyeVJlc3VsdCBvZiBxdWVyeVJlc3VsdHMpIHtcbiAgICAgICAgICAgICAgICByZXN1bHRzLnB1c2goLi4ucXVlcnlSZXN1bHQpXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY29uc29sZS5sb2coYHRvdGFsIHRpbWUgZm9yIGNvbXBsZXRlIHBhcmFsbGVsIHF1ZXJ5ICR7RGF0ZS5ub3coKSAtIHN0YXJ0VGltZX1gKVxuICAgICAgICByZXR1cm4gcmVzdWx0c1xuICAgIH1cbiAgICBwcml2YXRlIGFzeW5jIGN1c3RvbVF1ZXJ5KFxuICAgICAgICB2YWx1ZUNvbnN0cnVjdG9yOiBaZXJvQXJndW1lbnRzQ29uc3RydWN0b3I8VD4sXG4gICAgICAgIGtleUNvbmRpdGlvbnM6IENvbmRpdGlvbkV4cHJlc3Npb24gfCB7IFtwcm9wZXJ0eU5hbWU6IHN0cmluZ106IENvbmRpdGlvbkV4cHJlc3Npb25QcmVkaWNhdGUgfCBhbnkgfSxcbiAgICAgICAgb3B0aW9ucz86IFF1ZXJ5T3B0aW9uc1xuICAgICk6IFByb21pc2U8VFtdPiB7XG4gICAgICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KClcbiAgICAgICAgY29uc3QgaXRlbXM6IFRbXSA9IFtdXG5cbiAgICAgICAgZm9yIGF3YWl0IChjb25zdCBpdGVtIG9mIG1hcHBlci5xdWVyeSh2YWx1ZUNvbnN0cnVjdG9yLCBrZXlDb25kaXRpb25zLCBvcHRpb25zKSkge1xuICAgICAgICAgICAgaXRlbXMucHVzaChpdGVtKVxuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUubG9nKGB0b3RhbCB0aW1lIGZvciBjb21wbGV0ZSBxdWVyeSAke0RhdGUubm93KCkgLSBzdGFydFRpbWV9YClcblxuICAgICAgICByZXR1cm4gaXRlbXNcbiAgICB9XG4gICAgZGVjb2RlKGNvbnRpbnVhdGlvblRva2VuOiBzdHJpbmcgfCB1bmRlZmluZWQpIHtcbiAgICAgICAgaWYgKGNvbnRpbnVhdGlvblRva2VuKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGxldCBsYXN0RXZhbHVhdGVkS2V5ID0gSlNPTi5wYXJzZShCdWZmZXIuZnJvbShjb250aW51YXRpb25Ub2tlbiwgJ2Jhc2U2NCcpLnRvU3RyaW5nKCd1dGY4JykpO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiSW5jb21pbmcgTGFzdCBFdmFsdWF0ZWQgS2V5IFwiICsgbGFzdEV2YWx1YXRlZEtleSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGxhc3RFdmFsdWF0ZWRLZXk7XG4gICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjb250aW51YXRpb25Ub2tlbicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1bmRlZmluZWRcbiAgICB9XG5cbiAgICBhc3luYyBlbmNvZGUobGFzdEV2YWx1YXRlZEtleTogYW55KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICAgICAgcmV0dXJuIEJ1ZmZlci5mcm9tKEpTT04uc3RyaW5naWZ5KGxhc3RFdmFsdWF0ZWRLZXkpKS50b1N0cmluZygnYmFzZTY0JylcbiAgICB9XG59Il19