@decaf-ts/for-couchdb
Version:
template for ts projects
384 lines • 47.3 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CouchDBAdapter = void 0;
const core_1 = require("@decaf-ts/core");
const constants_1 = require("./constants.cjs");
const db_decorators_1 = require("@decaf-ts/db-decorators");
require("reflect-metadata");
const Sequence_1 = require("./sequences/Sequence.cjs");
const errors_1 = require("./errors.cjs");
const query_1 = require("./query/index.cjs");
const core_2 = require("@decaf-ts/core");
/**
* @description Abstract adapter for CouchDB database operations
* @summary Provides a base implementation for CouchDB database operations, including CRUD operations, sequence management, and error handling
* @template Y - The scope type
* @template F - The repository flags type
* @template C - The context type
* @param {Y} scope - The scope for the adapter
* @param {string} flavour - The flavour of the adapter
* @param {string} [alias] - Optional alias for the adapter
* @class
* @example
* // Example of extending CouchDBAdapter
* class MyCouchDBAdapter extends CouchDBAdapter<MyScope, MyFlags, MyContext> {
* constructor(scope: MyScope) {
* super(scope, 'my-couchdb', 'my-alias');
* }
*
* // Implement abstract methods
* async index<M extends Model>(...models: Constructor<M>[]): Promise<void> {
* // Implementation
* }
*
* async raw<R>(rawInput: MangoQuery, docsOnly: boolean): Promise<R> {
* // Implementation
* }
*
* async create(tableName: string, id: string | number, model: Record<string, any>, ...args: any[]): Promise<Record<string, any>> {
* // Implementation
* }
*
* async read(tableName: string, id: string | number, ...args: any[]): Promise<Record<string, any>> {
* // Implementation
* }
*
* async update(tableName: string, id: string | number, model: Record<string, any>, ...args: any[]): Promise<Record<string, any>> {
* // Implementation
* }
*
* async delete(tableName: string, id: string | number, ...args: any[]): Promise<Record<string, any>> {
* // Implementation
* }
* }
*/
class CouchDBAdapter extends core_1.Adapter {
constructor(scope, flavour, alias) {
super(scope, flavour, alias);
[this.create, this.createAll, this.update, this.updateAll].forEach((m) => {
const name = m.name;
(0, db_decorators_1.prefixMethod)(this, m, this[name + "Prefix"]);
});
}
/**
* @description Creates a new CouchDB statement for querying
* @summary Factory method that creates a new CouchDBStatement instance for building queries
* @template M - The model type
* @return {CouchDBStatement<M, any>} A new CouchDBStatement instance
*/
Statement() {
return new query_1.CouchDBStatement(this);
}
/**
* @description Creates a new CouchDB sequence
* @summary Factory method that creates a new CouchDBSequence instance for managing sequences
* @param {SequenceOptions} options - The options for the sequence
* @return {Promise<Sequence>} A promise that resolves to a new Sequence instance
*/
async Sequence(options) {
return new Sequence_1.CouchDBSequence(options, this);
}
/**
* @description Initializes the adapter by creating indexes for all managed models
* @summary Sets up the necessary database indexes for all models managed by this adapter
* @return {Promise<void>} A promise that resolves when initialization is complete
*/
async initialize() {
const managedModels = core_1.Adapter.models(this.flavour);
return this.index(...managedModels);
}
/**
* @description Assigns metadata to a model
* @summary Adds revision metadata to a model as a non-enumerable property
* @param {Record<string, any>} model - The model to assign metadata to
* @param {string} rev - The revision string to assign
* @return {Record<string, any>} The model with metadata assigned
*/
assignMetadata(model, rev) {
Object.defineProperty(model, core_1.PersistenceKeys.METADATA, {
enumerable: false,
configurable: false,
writable: false,
value: rev,
});
return model;
}
/**
* @description Assigns metadata to multiple models
* @summary Adds revision metadata to multiple models as non-enumerable properties
* @param models - The models to assign metadata to
* @param {string[]} revs - The revision strings to assign
* @return The models with metadata assigned
*/
assignMultipleMetadata(models, revs) {
models.forEach((m, i) => {
core_1.Repository.setMetadata(m, revs[i]);
return m;
});
return models;
}
/**
* @description Prepares a record for creation
* @summary Adds necessary CouchDB fields to a record before creation
* @param {string} tableName - The name of the table
* @param {string|number} id - The ID of the record
* @param {Record<string, any>} model - The model to prepare
* @return A tuple containing the tableName, id, and prepared record
*/
createPrefix(tableName, id, model) {
const record = {};
record[constants_1.CouchDBKeys.TABLE] = tableName;
record[constants_1.CouchDBKeys.ID] = this.generateId(tableName, id);
Object.assign(record, model);
return [tableName, id, record];
}
/**
* @description Prepares multiple records for creation
* @summary Adds necessary CouchDB fields to multiple records before creation
* @param {string} tableName - The name of the table
* @param {string[]|number[]} ids - The IDs of the records
* @param models - The models to prepare
* @return A tuple containing the tableName, ids, and prepared records
* @throws {InternalError} If ids and models arrays have different lengths
*/
createAllPrefix(tableName, ids, models) {
if (ids.length !== models.length)
throw new db_decorators_1.InternalError("Ids and models must have the same length");
const records = ids.map((id, count) => {
const record = {};
record[constants_1.CouchDBKeys.TABLE] = tableName;
record[constants_1.CouchDBKeys.ID] = this.generateId(tableName, id);
Object.assign(record, models[count]);
return record;
});
return [tableName, ids, records];
}
/**
* @description Prepares a record for update
* @summary Adds necessary CouchDB fields to a record before update
* @param {string} tableName - The name of the table
* @param {string|number} id - The ID of the record
* @param model - The model to prepare
* @return A tuple containing the tableName, id, and prepared record
* @throws {InternalError} If no revision number is found in the model
*/
updatePrefix(tableName, id, model) {
const record = {};
record[constants_1.CouchDBKeys.TABLE] = tableName;
record[constants_1.CouchDBKeys.ID] = this.generateId(tableName, id);
const rev = model[core_1.PersistenceKeys.METADATA];
if (!rev)
throw new db_decorators_1.InternalError(`No revision number found for record with id ${id}`);
Object.assign(record, model);
record[constants_1.CouchDBKeys.REV] = rev;
return [tableName, id, record];
}
/**
* @description Prepares multiple records for update
* @summary Adds necessary CouchDB fields to multiple records before update
* @param {string} tableName - The name of the table
* @param {string[]|number[]} ids - The IDs of the records
* @param models - The models to prepare
* @return A tuple containing the tableName, ids, and prepared records
* @throws {InternalError} If ids and models arrays have different lengths or if no revision number is found in a model
*/
updateAllPrefix(tableName, ids, models) {
if (ids.length !== models.length)
throw new db_decorators_1.InternalError("Ids and models must have the same length");
const records = ids.map((id, count) => {
const record = {};
record[constants_1.CouchDBKeys.TABLE] = tableName;
record[constants_1.CouchDBKeys.ID] = this.generateId(tableName, id);
const rev = models[count][core_1.PersistenceKeys.METADATA];
if (!rev)
throw new db_decorators_1.InternalError(`No revision number found for record with id ${id}`);
Object.assign(record, models[count]);
record[constants_1.CouchDBKeys.REV] = rev;
return record;
});
return [tableName, ids, records];
}
/**
* @description Generates a CouchDB document ID
* @summary Combines the table name and ID to create a CouchDB document ID
* @param {string} tableName - The name of the table
* @param {string|number} id - The ID of the record
* @return {string} The generated CouchDB document ID
*/
generateId(tableName, id) {
return [tableName, id].join(constants_1.CouchDBKeys.SEPARATOR);
}
/**
* @description Parses an error and converts it to a BaseError
* @summary Converts various error types to appropriate BaseError subtypes
* @param {Error|string} err - The error to parse
* @param {string} [reason] - Optional reason for the error
* @return {BaseError} The parsed error as a BaseError
*/
parseError(err, reason) {
return CouchDBAdapter.parseError(err, reason);
}
/**
* @description Checks if an attribute is reserved
* @summary Determines if an attribute name is reserved in CouchDB
* @param {string} attr - The attribute name to check
* @return {boolean} True if the attribute is reserved, false otherwise
*/
isReserved(attr) {
return !!attr.match(constants_1.reservedAttributes);
}
/**
* @description Static method to parse an error and convert it to a BaseError
* @summary Converts various error types to appropriate BaseError subtypes based on error codes and messages
* @param {Error|string} err - The error to parse
* @param {string} [reason] - Optional reason for the error
* @return {BaseError} The parsed error as a BaseError
* @mermaid
* sequenceDiagram
* participant Caller
* participant parseError
* participant ErrorTypes
*
* Caller->>parseError: err, reason
* Note over parseError: Check if err is already a BaseError
* alt err is BaseError
* parseError-->>Caller: return err
* else err is string
* Note over parseError: Extract code from string
* alt code matches "already exist|update conflict"
* parseError->>ErrorTypes: new ConflictError(code)
* ErrorTypes-->>Caller: ConflictError
* else code matches "missing|deleted"
* parseError->>ErrorTypes: new NotFoundError(code)
* ErrorTypes-->>Caller: NotFoundError
* end
* else err has code property
* Note over parseError: Extract code and reason
* else err has statusCode property
* Note over parseError: Extract code and reason
* else
* Note over parseError: Use err.message as code
* end
*
* Note over parseError: Switch on code
* alt code is 401, 412, or 409
* parseError->>ErrorTypes: new ConflictError(reason)
* ErrorTypes-->>Caller: ConflictError
* else code is 404
* parseError->>ErrorTypes: new NotFoundError(reason)
* ErrorTypes-->>Caller: NotFoundError
* else code is 400
* alt code matches "No index exists"
* parseError->>ErrorTypes: new IndexError(err)
* ErrorTypes-->>Caller: IndexError
* else
* parseError->>ErrorTypes: new InternalError(err)
* ErrorTypes-->>Caller: InternalError
* end
* else code matches "ECONNREFUSED"
* parseError->>ErrorTypes: new ConnectionError(err)
* ErrorTypes-->>Caller: ConnectionError
* else
* parseError->>ErrorTypes: new InternalError(err)
* ErrorTypes-->>Caller: InternalError
* end
*/
static parseError(err, reason) {
if (err instanceof db_decorators_1.BaseError)
return err;
let code = "";
if (typeof err === "string") {
code = err;
if (code.match(/already exist|update conflict/g))
return new db_decorators_1.ConflictError(code);
if (code.match(/missing|deleted/g))
return new db_decorators_1.NotFoundError(code);
}
else if (err.code) {
code = err.code;
reason = reason || err.message;
}
else if (err.statusCode) {
code = err.statusCode;
reason = reason || err.message;
}
else {
code = err.message;
}
switch (code.toString()) {
case "401":
case "412":
case "409":
return new db_decorators_1.ConflictError(reason);
case "404":
return new db_decorators_1.NotFoundError(reason);
case "400":
if (code.toString().match(/No\sindex\sexists/g))
return new errors_1.IndexError(err);
return new db_decorators_1.InternalError(err);
default:
if (code.toString().match(/ECONNREFUSED/g))
return new core_1.ConnectionError(err);
return new db_decorators_1.InternalError(err);
}
}
}
exports.CouchDBAdapter = CouchDBAdapter;
__decorate([
(0, core_2.final)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", query_1.CouchDBStatement)
], CouchDBAdapter.prototype, "Statement", null);
__decorate([
(0, core_2.final)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", Promise)
], CouchDBAdapter.prototype, "Sequence", null);
__decorate([
(0, core_2.final)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, String]),
__metadata("design:returntype", Object)
], CouchDBAdapter.prototype, "assignMetadata", null);
__decorate([
(0, core_2.final)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Array, Array]),
__metadata("design:returntype", Array)
], CouchDBAdapter.prototype, "assignMultipleMetadata", null);
__decorate([
(0, core_2.final)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object, Object]),
__metadata("design:returntype", void 0)
], CouchDBAdapter.prototype, "createPrefix", null);
__decorate([
(0, core_2.final)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Array, Array]),
__metadata("design:returntype", void 0)
], CouchDBAdapter.prototype, "createAllPrefix", null);
__decorate([
(0, core_2.final)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Object, Object]),
__metadata("design:returntype", void 0)
], CouchDBAdapter.prototype, "updatePrefix", null);
__decorate([
(0, core_2.final)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String, Array, Array]),
__metadata("design:returntype", void 0)
], CouchDBAdapter.prototype, "updateAllPrefix", null);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRhcHRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9hZGFwdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQUFBLHlDQU93QjtBQUN4QiwrQ0FBOEQ7QUFDOUQsMkRBUWlDO0FBQ2pDLDRCQUEwQjtBQUUxQix1REFBdUQ7QUFFdkQseUNBQXNDO0FBRXRDLDZDQUEyQztBQUMzQyx5Q0FBdUM7QUFFdkM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTBDRztBQUNILE1BQXNCLGNBSXBCLFNBQVEsY0FBNEI7SUFDcEMsWUFBc0IsS0FBUSxFQUFFLE9BQWUsRUFBRSxLQUFjO1FBQzdELEtBQUssQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzdCLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO1lBQ3ZFLE1BQU0sSUFBSSxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFDcEIsSUFBQSw0QkFBWSxFQUFDLElBQUksRUFBRSxDQUFDLEVBQUcsSUFBWSxDQUFDLElBQUksR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDO1FBQ3hELENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7OztPQUtHO0lBRUgsU0FBUztRQUNQLE9BQU8sSUFBSSx3QkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwQyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFFRyxBQUFOLEtBQUssQ0FBQyxRQUFRLENBQUMsT0FBd0I7UUFDckMsT0FBTyxJQUFJLDBCQUFlLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLFVBQVU7UUFDZCxNQUFN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REwsSUFBQSxZQUFLLEdBQUU7Ozs7OENBR1A7QUF5Q1M7SUFEVCxJQUFBLFlBQUssR0FBRTs7OztvREFZUDtBQVVTO0lBRFQsSUFBQSxZQUFLLEdBQUU7Ozs7NERBVVA7QUFXUztJQURULElBQUEsWUFBSyxHQUFFOzs7O2tEQVdQO0FBNEJTO0lBRFQsSUFBQSxZQUFLLEdBQUU7Ozs7cURBaUJQO0FBMEJEO0lBREMsSUFBQSxZQUFLLEdBQUU7Ozs7a0RBaUJQO0FBNEJTO0lBRFQsSUFBQSxZQUFLLEdBQUU7Ozs7cURBdUJQIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQWRhcHRlcixcbiAgU2VxdWVuY2UsXG4gIHR5cGUgU2VxdWVuY2VPcHRpb25zLFxuICBQZXJzaXN0ZW5jZUtleXMsXG4gIENvbm5lY3Rpb25FcnJvcixcbiAgUmVwb3NpdG9yeSxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBDb3VjaERCS2V5cywgcmVzZXJ2ZWRBdHRyaWJ1dGVzIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQge1xuICBCYXNlRXJyb3IsXG4gIENvbmZsaWN0RXJyb3IsXG4gIENvbnRleHQsXG4gIEludGVybmFsRXJyb3IsXG4gIE5vdEZvdW5kRXJyb3IsXG4gIHByZWZpeE1ldGhvZCxcbiAgUmVwb3NpdG9yeUZsYWdzLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCBcInJlZmxlY3QtbWV0YWRhdGFcIjtcblxuaW1wb3J0IHsgQ291Y2hEQlNlcXVlbmNlIH0gZnJvbSBcIi4vc2VxdWVuY2VzL1NlcXVlbmNlXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciwgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBJbmRleEVycm9yIH0gZnJvbSBcIi4vZXJyb3JzXCI7XG5pbXBvcnQgeyBNYW5nb1F1ZXJ5IH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IENvdWNoREJTdGF0ZW1lbnQgfSBmcm9tIFwiLi9xdWVyeVwiO1xuaW1wb3J0IHsgZmluYWwgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQWJzdHJhY3QgYWRhcHRlciBmb3IgQ291Y2hEQiBkYXRhYmFzZSBvcGVyYXRpb25zXG4gKiBAc3VtbWFyeSBQcm92aWRlcyBhIGJhc2UgaW1wbGVtZW50YXRpb24gZm9yIENvdWNoREIgZGF0YWJhc2Ugb3BlcmF0aW9ucywgaW5jbHVkaW5nIENSVUQgb3BlcmF0aW9ucywgc2VxdWVuY2UgbWFuYWdlbWVudCwgYW5kIGVycm9yIGhhbmRsaW5nXG4gKiBAdGVtcGxhdGUgWSAtIFRoZSBzY29wZSB0eXBlXG4gKiBAdGVtcGxhdGUgRiAtIFRoZSByZXBvc2l0b3J5IGZsYWdzIHR5cGVcbiAqIEB0ZW1wbGF0ZSBDIC0gVGhlIGNvbnRleHQgdHlwZVxuICogQHBhcmFtIHtZfSBzY29wZSAtIFRoZSBzY29wZSBmb3IgdGhlIGFkYXB0ZXJcbiAqIEBwYXJhbSB7c3RyaW5nfSBmbGF2b3VyIC0gVGhlIGZsYXZvdXIgb2YgdGhlIGFkYXB0ZXJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbYWxpYXNdIC0gT3B0aW9uYWwgYWxpYXMgZm9yIHRoZSBhZGFwdGVyXG4gKiBAY2xhc3NcbiAqIEBleGFtcGxlXG4gKiAvLyBFeGFtcGxlIG9mIGV4dGVuZGluZyBDb3VjaERCQWRhcHRlclxuICogY2xhc3MgTXlDb3VjaERCQWRhcHRlciBleHRlbmRzIENvdWNoREJBZGFwdGVyPE15U2NvcGUsIE15RmxhZ3MsIE15Q29udGV4dD4ge1xuICogICBjb25zdHJ1Y3RvcihzY29wZTogTXlTY29wZSkge1xuICogICAgIHN1cGVyKHNjb3BlLCAnbXktY291Y2hkYicsICdteS1hbGlhcycpO1xuICogICB9XG4gKlxuICogICAvLyBJbXBsZW1lbnQgYWJzdHJhY3QgbWV0aG9kc1xuICogICBhc3luYyBpbmRleDxNIGV4dGVuZHMgTW9kZWw+KC4uLm1vZGVsczogQ29uc3RydWN0b3I8TT5bXSk6IFByb21pc2U8dm9pZD4ge1xuICogICAgIC8vIEltcGxlbWVudGF0aW9uXG4gKiAgIH1cbiAqXG4gKiAgIGFzeW5jIHJhdzxSPihyYXdJbnB1dDogTWFuZ29RdWVyeSwgZG9jc09ubHk6IGJvb2xlYW4pOiBQcm9taXNlPFI+IHtcbiAqICAgICAvLyBJbXBsZW1lbnRhdGlvblxuICogICB9XG4gKlxuICogICBhc3luYyBjcmVhdGUodGFibGVOYW1lOiBzdHJpbmcsIGlkOiBzdHJpbmcgfCBudW1iZXIsIG1vZGVsOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LCAuLi5hcmdzOiBhbnlbXSk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj4ge1xuICogICAgIC8vIEltcGxlbWVudGF0aW9uXG4gKiAgIH1cbiAqXG4gKiAgIGFzeW5jIHJlYWQodGFibGVOYW1lOiBzdHJpbmcsIGlkOiBzdHJpbmcgfCBudW1iZXIsIC4uLmFyZ3M6IGFueVtdKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+PiB7XG4gKiAgICAgLy8gSW1wbGVtZW50YXRpb25cbiAqICAgfVxuICpcbiAqICAgYXN5bmMgdXBkYXRlKHRhYmxlTmFtZTogc3RyaW5nLCBpZDogc3RyaW5nIHwgbnVtYmVyLCBtb2RlbDogUmVjb3JkPHN0cmluZywgYW55PiwgLi4uYXJnczogYW55W10pOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+IHtcbiAqICAgICAvLyBJbXBsZW1lbnRhdGlvblxuICogICB9XG4gKlxuICogICBhc3luYyBkZWxldGUodGFibGVOYW1lOiBzdHJpbmcsIGlkOiBzdHJpbmcgfCBudW1iZXIsIC4uLmFyZ3M6IGFueVtdKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCBhbnk+PiB7XG4gKiAgICAgLy8gSW1wbGVtZW50YXRpb25cbiAqICAgfVxuICogfVxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgQ291Y2hEQkFkYXB0ZXI8XG4gIFksXG4gIEYgZXh0ZW5kcyBSZXBvc2l0b3J5RmxhZ3MsXG4gIEMgZXh0ZW5kcyBDb250ZXh0PEY+LFxuPiBleHRlbmRzIEFkYXB0ZXI8WSwgTWFuZ29RdWVyeSwgRiwgQz4ge1xuICBwcm90ZWN0ZWQgY29uc3RydWN0b3Ioc2NvcGU6IFksIGZsYXZvdXI6IHN0cmluZywgYWxpYXM/OiBzdHJpbmcpIHtcbiAgICBzdXBlcihzY29wZSwgZmxhdm91ciwgYWxpYXMpO1xuICAgIFt0aGlzLmNyZWF0ZSwgdGhpcy5jcmVhdGVBbGwsIHRoaXMudXBkYXRlLCB0aGlzLnVwZGF0ZUFsbF0uZm9yRWFjaCgobSkgPT4ge1xuICAgICAgY29uc3QgbmFtZSA9IG0ubmFtZTtcbiAgICAgIHByZWZpeE1ldGhvZCh0aGlzLCBtLCAodGhpcyBhcyBhbnkpW25hbWUgKyBcIlByZWZpeFwiXSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIENyZWF0ZXMgYSBuZXcgQ291Y2hEQiBzdGF0ZW1lbnQgZm9yIHF1ZXJ5aW5nXG4gICAqIEBzdW1tYXJ5IEZhY3RvcnkgbWV0aG9kIHRoYXQgY3JlYXRlcyBhIG5ldyBDb3VjaERCU3RhdGVtZW50IGluc3RhbmNlIGZvciBidWlsZGluZyBxdWVyaWVzXG4gICAqIEB0ZW1wbGF0ZSBNIC0gVGhlIG1vZGVsIHR5cGVcbiAgICogQHJldHVybiB7Q291Y2hEQlN0YXRlbWVudDxNLCBhbnk+fSBBIG5ldyBDb3VjaERCU3RhdGVtZW50IGluc3RhbmNlXG4gICAqL1xuICBAZmluYWwoKVxuICBTdGF0ZW1lbnQ8TSBleHRlbmRzIE1vZGVsPigpOiBDb3VjaERCU3RhdGVtZW50PE0sIGFueT4ge1xuICAgIHJldHVybiBuZXcgQ291Y2hEQlN0YXRlbWVudCh0aGlzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIG5ldyBDb3VjaERCIHNlcXVlbmNlXG4gICAqIEBzdW1tYXJ5IEZhY3RvcnkgbWV0aG9kIHRoYXQgY3JlYXRlcyBhIG5ldyBDb3VjaERCU2VxdWVuY2UgaW5zdGFuY2UgZm9yIG1hbmFnaW5nIHNlcXVlbmNlc1xuICAgKiBAcGFyYW0ge1NlcXVlbmNlT3B0aW9uc30gb3B0aW9ucyAtIFRoZSBvcHRpb25zIGZvciB0aGUgc2VxdWVuY2VcbiAgICogQHJldHVybiB7UHJvbWlzZTxTZXF1ZW5jZT59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgbmV3IFNlcXVlbmNlIGluc3RhbmNlXG4gICAqL1xuICBAZmluYWwoKVxuICBhc3luYyBTZXF1ZW5jZShvcHRpb25zOiBTZXF1ZW5jZU9wdGlvbnMpOiBQcm9taXNlPFNlcXVlbmNlPiB7XG4gICAgcmV0dXJuIG5ldyBDb3VjaERCU2VxdWVuY2Uob3B0aW9ucywgdGhpcyk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEluaXRpYWxpemVzIHRoZSBhZGFwdGVyIGJ5IGNyZWF0aW5nIGluZGV4ZXMgZm9yIGFsbCBtYW5hZ2VkIG1vZGVsc1xuICAgKiBAc3VtbWFyeSBTZXRzIHVwIHRoZSBuZWNlc3NhcnkgZGF0YWJhc2UgaW5kZXhlcyBmb3IgYWxsIG1vZGVscyBtYW5hZ2VkIGJ5IHRoaXMgYWRhcHRlclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGluaXRpYWxpemF0aW9uIGlzIGNvbXBsZXRlXG4gICAqL1xuICBhc3luYyBpbml0aWFsaXplKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG1hbmFnZWRNb2RlbHMgPSBBZGFwdGVyLm1vZGVscyh0aGlzLmZsYXZvdXIpO1xuICAgIHJldHVybiB0aGlzLmluZGV4KC4uLm1hbmFnZWRNb2RlbHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGluZGV4ZXMgZm9yIHRoZSBnaXZlbiBtb2RlbHNcbiAgICogQHN1bW1hcnkgQWJzdHJhY3QgbWV0aG9kIHRoYXQgbXVzdCBiZSBpbXBsZW1lbnRlZCB0byBjcmVhdGUgZGF0YWJhc2UgaW5kZXhlcyBmb3IgdGhlIHNwZWNpZmllZCBtb2RlbHNcbiAgICogQHRlbXBsYXRlIE0gLSBUaGUgbW9kZWwgdHlwZVxuICAgKiBAcGFyYW0gey4uLkNvbnN0cnVjdG9yPE0+fSBtb2RlbHMgLSBUaGUgbW9kZWwgY29uc3RydWN0b3JzIHRvIGNyZWF0ZSBpbmRleGVzIGZvclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGFsbCBpbmRleGVzIGFyZSBjcmVhdGVkXG4gICAqL1xuICBwcm90ZWN0ZWQgYWJzdHJhY3QgaW5kZXg8TSBleHRlbmRzIE1vZGVsPihcbiAgICAuLi5tb2RlbHM6IENvbnN0cnVjdG9yPE0+W11cbiAgKTogUHJvbWlzZTx2b2lkPjtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEV4ZWN1dGVzIGEgcmF3IE1hbmdvIHF1ZXJ5IGFnYWluc3QgdGhlIGRhdGFiYXNlXG4gICAqIEBzdW1tYXJ5IEFic3RyYWN0IG1ldGhvZCB0aGF0IG11c3QgYmUgaW1wbGVtZW50ZWQgdG8gZXhlY3V0ZSByYXcgTWFuZ28gcXVlcmllc1xuICAgKiBAdGVtcGxhdGUgUiAtIFRoZSByZXN1bHQgdHlwZVxuICAgKiBAcGFyYW0ge01hbmdvUXVlcnl9IHJhd0lucHV0IC0gVGhlIHJhdyBNYW5nbyBxdWVyeSB0byBleGVjdXRlXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gZG9jc09ubHkgLSBXaGV0aGVyIHRvIHJldHVybiBvbmx5IHRoZSBkb2N1bWVudHMgb3IgdGhlIGZ1bGwgcmVzcG9uc2VcbiAgICogQHJldHVybiB7UHJvbWlzZTxSPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHF1ZXJ5IHJlc3VsdFxuICAgKi9cbiAgYWJzdHJhY3Qgb3ZlcnJpZGUgcmF3PFI+KHJhd0lucHV0OiBNYW5nb1F1ZXJ5LCBkb2NzT25seTogYm9vbGVhbik6IFByb21pc2U8Uj47XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBBc3NpZ25zIG1ldGFkYXRhIHRvIGEgbW9kZWxcbiAgICogQHN1bW1hcnkgQWRkcyByZXZpc2lvbiBtZXRhZGF0YSB0byBhIG1vZGVsIGFzIGEgbm9uLWVudW1lcmFibGUgcHJvcGVydHlcbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSBtb2RlbCAtIFRoZSBtb2RlbCB0byBhc3NpZ24gbWV0YWRhdGEgdG9cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJldiAtIFRoZSByZXZpc2lvbiBzdHJpbmcgdG8gYXNzaWduXG4gICAqIEByZXR1cm4ge1JlY29yZDxzdHJpbmcsIGFueT59IFRoZSBtb2RlbCB3aXRoIG1ldGFkYXRhIGFzc2lnbmVkXG4gICAqL1xuICBAZmluYWwoKVxuICBwcm90ZWN0ZWQgYXNzaWduTWV0YWRhdGEoXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT4sXG4gICAgcmV2OiBzdHJpbmdcbiAgKTogUmVjb3JkPHN0cmluZywgYW55PiB7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG1vZGVsLCBQZXJzaXN0ZW5jZUtleXMuTUVUQURBVEEsIHtcbiAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgY29uZmlndXJhYmxlOiBmYWxzZSxcbiAgICAgIHdyaXRhYmxlOiBmYWxzZSxcbiAgICAgIHZhbHVlOiByZXYsXG4gICAgfSk7XG4gICAgcmV0dXJuIG1vZGVsO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBBc3NpZ25zIG1ldGFkYXRhIHRvIG11bHRpcGxlIG1vZGVsc1xuICAgKiBAc3VtbWFyeSBBZGRzIHJldmlzaW9uIG1ldGFkYXRhIHRvIG11bHRpcGxlIG1vZGVscyBhcyBub24tZW51bWVyYWJsZSBwcm9wZXJ0aWVzXG4gICAqIEBwYXJhbSBtb2RlbHMgLSBUaGUgbW9kZWxzIHRvIGFzc2lnbiBtZXRhZGF0YSB0b1xuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSByZXZzIC0gVGhlIHJldmlzaW9uIHN0cmluZ3MgdG8gYXNzaWduXG4gICAqIEByZXR1cm4gVGhlIG1vZGVscyB3aXRoIG1ldGFkYXRhIGFzc2lnbmVkXG4gICAqL1xuICBAZmluYWwoKVxuICBwcm90ZWN0ZWQgYXNzaWduTXVsdGlwbGVNZXRhZGF0YShcbiAgICBtb2RlbHM6IFJlY29yZDxzdHJpbmcsIGFueT5bXSxcbiAgICByZXZzOiBzdHJpbmdbXVxuICApOiBSZWNvcmQ8c3RyaW5nLCBhbnk+W10ge1xuICAgIG1vZGVscy5mb3JFYWNoKChtLCBpKSA9PiB7XG4gICAgICBSZXBvc2l0b3J5LnNldE1ldGFkYXRhKG0gYXMgYW55LCByZXZzW2ldKTtcbiAgICAgIHJldHVybiBtO1xuICAgIH0pO1xuICAgIHJldHVybiBtb2RlbHM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByZXBhcmVzIGEgcmVjb3JkIGZvciBjcmVhdGlvblxuICAgKiBAc3VtbWFyeSBBZGRzIG5lY2Vzc2FyeSBDb3VjaERCIGZpZWxkcyB0byBhIHJlY29yZCBiZWZvcmUgY3JlYXRpb25cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZVxuICAgKiBAcGFyYW0ge3N0cmluZ3xudW1iZXJ9IGlkIC0gVGhlIElEIG9mIHRoZSByZWNvcmRcbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSBtb2RlbCAtIFRoZSBtb2RlbCB0byBwcmVwYXJlXG4gICAqIEByZXR1cm4gQSB0dXBsZSBjb250YWluaW5nIHRoZSB0YWJsZU5hbWUsIGlkLCBhbmQgcHJlcGFyZWQgcmVjb3JkXG4gICAqL1xuICBAZmluYWwoKVxuICBwcm90ZWN0ZWQgY3JlYXRlUHJlZml4KFxuICAgIHRhYmxlTmFtZTogc3RyaW5nLFxuICAgIGlkOiBzdHJpbmcgfCBudW1iZXIsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT5cbiAgKSB7XG4gICAgY29uc3QgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgcmVjb3JkW0NvdWNoREJLZXlzLlRBQkxFXSA9IHRhYmxlTmFtZTtcbiAgICByZWNvcmRbQ291Y2hEQktleXMuSURdID0gdGhpcy5nZW5lcmF0ZUlkKHRhYmxlTmFtZSwgaWQpO1xuICAgIE9iamVjdC5hc3NpZ24ocmVjb3JkLCBtb2RlbCk7XG4gICAgcmV0dXJuIFt0YWJsZU5hbWUsIGlkLCByZWNvcmRdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDcmVhdGVzIGEgbmV3IHJlY29yZCBpbiB0aGUgZGF0YWJhc2VcbiAgICogQHN1bW1hcnkgQWJzdHJhY3QgbWV0aG9kIHRoYXQgbXVzdCBiZSBpbXBsZW1lbnRlZCB0byBjcmVhdGUgYSBuZXcgcmVjb3JkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWJsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdGFibGVcbiAgICogQHBhcmFtIHtzdHJpbmd8bnVtYmVyfSBpZCAtIFRoZSBJRCBvZiB0aGUgcmVjb3JkXG4gICAqIEBwYXJhbSB7UmVjb3JkPHN0cmluZywgYW55Pn0gbW9kZWwgLSBUaGUgbW9kZWwgdG8gY3JlYXRlXG4gICAqIEBwYXJhbSB7Li4uYW55W119IGFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50c1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgY3JlYXRlZCByZWNvcmRcbiAgICovXG4gIGFic3RyYWN0IG92ZXJyaWRlIGNyZWF0ZShcbiAgICB0YWJsZU5hbWU6IHN0cmluZyxcbiAgICBpZDogc3RyaW5nIHwgbnVtYmVyLFxuICAgIG1vZGVsOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj47XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcmVwYXJlcyBtdWx0aXBsZSByZWNvcmRzIGZvciBjcmVhdGlvblxuICAgKiBAc3VtbWFyeSBBZGRzIG5lY2Vzc2FyeSBDb3VjaERCIGZpZWxkcyB0byBtdWx0aXBsZSByZWNvcmRzIGJlZm9yZSBjcmVhdGlvblxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlXG4gICAqIEBwYXJhbSB7c3RyaW5nW118bnVtYmVyW119IGlkcyAtIFRoZSBJRHMgb2YgdGhlIHJlY29yZHNcbiAgICogQHBhcmFtIG1vZGVscyAtIFRoZSBtb2RlbHMgdG8gcHJlcGFyZVxuICAgKiBAcmV0dXJuIEEgdHVwbGUgY29udGFpbmluZyB0aGUgdGFibGVOYW1lLCBpZHMsIGFuZCBwcmVwYXJlZCByZWNvcmRzXG4gICAqIEB0aHJvd3Mge0ludGVybmFsRXJyb3J9IElmIGlkcyBhbmQgbW9kZWxzIGFycmF5cyBoYXZlIGRpZmZlcmVudCBsZW5ndGhzXG4gICAqL1xuICBAZmluYWwoKVxuICBwcm90ZWN0ZWQgY3JlYXRlQWxsUHJlZml4KFxuICAgIHRhYmxlTmFtZTogc3RyaW5nLFxuICAgIGlkczogc3RyaW5nW10gfCBudW1iZXJbXSxcbiAgICBtb2RlbHM6IFJlY29yZDxzdHJpbmcsIGFueT5bXVxuICApIHtcbiAgICBpZiAoaWRzLmxlbmd0aCAhPT0gbW9kZWxzLmxlbmd0aClcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiSWRzIGFuZCBtb2RlbHMgbXVzdCBoYXZlIHRoZSBzYW1lIGxlbmd0aFwiKTtcblxuICAgIGNvbnN0IHJlY29yZHMgPSBpZHMubWFwKChpZCwgY291bnQpID0+IHtcbiAgICAgIGNvbnN0IHJlY29yZDogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgICAgcmVjb3JkW0NvdWNoREJLZXlzLlRBQkxFXSA9IHRhYmxlTmFtZTtcbiAgICAgIHJlY29yZFtDb3VjaERCS2V5cy5JRF0gPSB0aGlzLmdlbmVyYXRlSWQodGFibGVOYW1lLCBpZCk7XG4gICAgICBPYmplY3QuYXNzaWduKHJlY29yZCwgbW9kZWxzW2NvdW50XSk7XG4gICAgICByZXR1cm4gcmVjb3JkO1xuICAgIH0pO1xuICAgIHJldHVybiBbdGFibGVOYW1lLCBpZHMsIHJlY29yZHNdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBSZWFkcyBhIHJlY29yZCBmcm9tIHRoZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBBYnN0cmFjdCBtZXRob2QgdGhhdCBtdXN0IGJlIGltcGxlbWVudGVkIHRvIHJlYWQgYSByZWNvcmRcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZVxuICAgKiBAcGFyYW0ge3N0cmluZ3xudW1iZXJ9IGlkIC0gVGhlIElEIG9mIHRoZSByZWNvcmRcbiAgICogQHBhcmFtIHsuLi5hbnlbXX0gYXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZWFkIHJlY29yZFxuICAgKi9cbiAgYWJzdHJhY3Qgb3ZlcnJpZGUgcmVhZChcbiAgICB0YWJsZU5hbWU6IHN0cmluZyxcbiAgICBpZDogc3RyaW5nIHwgbnVtYmVyLFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj47XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcmVwYXJlcyBhIHJlY29yZCBmb3IgdXBkYXRlXG4gICAqIEBzdW1tYXJ5IEFkZHMgbmVjZXNzYXJ5IENvdWNoREIgZmllbGRzIHRvIGEgcmVjb3JkIGJlZm9yZSB1cGRhdGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhYmxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSB0YWJsZVxuICAgKiBAcGFyYW0ge3N0cmluZ3xudW1iZXJ9IGlkIC0gVGhlIElEIG9mIHRoZSByZWNvcmRcbiAgICogQHBhcmFtIG1vZGVsIC0gVGhlIG1vZGVsIHRvIHByZXBhcmVcbiAgICogQHJldHVybiBBIHR1cGxlIGNvbnRhaW5pbmcgdGhlIHRhYmxlTmFtZSwgaWQsIGFuZCBwcmVwYXJlZCByZWNvcmRcbiAgICogQHRocm93cyB7SW50ZXJuYWxFcnJvcn0gSWYgbm8gcmV2aXNpb24gbnVtYmVyIGlzIGZvdW5kIGluIHRoZSBtb2RlbFxuICAgKi9cbiAgQGZpbmFsKClcbiAgdXBkYXRlUHJlZml4KFxuICAgIHRhYmxlTmFtZTogc3RyaW5nLFxuICAgIGlkOiBzdHJpbmcgfCBudW1iZXIsXG4gICAgbW9kZWw6IFJlY29yZDxzdHJpbmcsIGFueT5cbiAgKSB7XG4gICAgY29uc3QgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgcmVjb3JkW0NvdWNoREJLZXlzLlRBQkxFXSA9IHRhYmxlTmFtZTtcbiAgICByZWNvcmRbQ291Y2hEQktleXMuSURdID0gdGhpcy5nZW5lcmF0ZUlkKHRhYmxlTmFtZSwgaWQpO1xuICAgIGNvbnN0IHJldiA9IG1vZGVsW1BlcnNpc3RlbmNlS2V5cy5NRVRBREFUQV07XG4gICAgaWYgKCFyZXYpXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgYE5vIHJldmlzaW9uIG51bWJlciBmb3VuZCBmb3IgcmVjb3JkIHdpdGggaWQgJHtpZH1gXG4gICAgICApO1xuICAgIE9iamVjdC5hc3NpZ24ocmVjb3JkLCBtb2RlbCk7XG4gICAgcmVjb3JkW0NvdWNoREJLZXlzLlJFVl0gPSByZXY7XG4gICAgcmV0dXJuIFt0YWJsZU5hbWUsIGlkLCByZWNvcmRdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBVcGRhdGVzIGEgcmVjb3JkIGluIHRoZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBBYnN0cmFjdCBtZXRob2QgdGhhdCBtdXN0IGJlIGltcGxlbWVudGVkIHRvIHVwZGF0ZSBhIHJlY29yZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlXG4gICAqIEBwYXJhbSB7c3RyaW5nfG51bWJlcn0gaWQgLSBUaGUgSUQgb2YgdGhlIHJlY29yZFxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIGFueT59IG1vZGVsIC0gVGhlIG1vZGVsIHRvIHVwZGF0ZVxuICAgKiBAcGFyYW0ge2FueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgICogQHJldHVybiBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgdXBkYXRlZCByZWNvcmRcbiAgICovXG4gIGFic3RyYWN0IG92ZXJyaWRlIHVwZGF0ZShcbiAgICB0YWJsZU5hbWU6IHN0cmluZyxcbiAgICBpZDogc3RyaW5nIHwgbnVtYmVyLFxuICAgIG1vZGVsOiBSZWNvcmQ8c3RyaW5nLCBhbnk+LFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj47XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQcmVwYXJlcyBtdWx0aXBsZSByZWNvcmRzIGZvciB1cGRhdGVcbiAgICogQHN1bW1hcnkgQWRkcyBuZWNlc3NhcnkgQ291Y2hEQiBmaWVsZHMgdG8gbXVsdGlwbGUgcmVjb3JkcyBiZWZvcmUgdXBkYXRlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWJsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdGFibGVcbiAgICogQHBhcmFtIHtzdHJpbmdbXXxudW1iZXJbXX0gaWRzIC0gVGhlIElEcyBvZiB0aGUgcmVjb3Jkc1xuICAgKiBAcGFyYW0gbW9kZWxzIC0gVGhlIG1vZGVscyB0byBwcmVwYXJlXG4gICAqIEByZXR1cm4gQSB0dXBsZSBjb250YWluaW5nIHRoZSB0YWJsZU5hbWUsIGlkcywgYW5kIHByZXBhcmVkIHJlY29yZHNcbiAgICogQHRocm93cyB7SW50ZXJuYWxFcnJvcn0gSWYgaWRzIGFuZCBtb2RlbHMgYXJyYXlzIGhhdmUgZGlmZmVyZW50IGxlbmd0aHMgb3IgaWYgbm8gcmV2aXNpb24gbnVtYmVyIGlzIGZvdW5kIGluIGEgbW9kZWxcbiAgICovXG4gIEBmaW5hbCgpXG4gIHByb3RlY3RlZCB1cGRhdGVBbGxQcmVmaXgoXG4gICAgdGFibGVOYW1lOiBzdHJpbmcsXG4gICAgaWRzOiBzdHJpbmdbXSB8IG51bWJlcltdLFxuICAgIG1vZGVsczogUmVjb3JkPHN0cmluZywgYW55PltdXG4gICkge1xuICAgIGlmIChpZHMubGVuZ3RoICE9PSBtb2RlbHMubGVuZ3RoKVxuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXCJJZHMgYW5kIG1vZGVscyBtdXN0IGhhdmUgdGhlIHNhbWUgbGVuZ3RoXCIpO1xuXG4gICAgY29uc3QgcmVjb3JkcyA9IGlkcy5tYXAoKGlkLCBjb3VudCkgPT4ge1xuICAgICAgY29uc3QgcmVjb3JkOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgICByZWNvcmRbQ291Y2hEQktleXMuVEFCTEVdID0gdGFibGVOYW1lO1xuICAgICAgcmVjb3JkW0NvdWNoREJLZXlzLklEXSA9IHRoaXMuZ2VuZXJhdGVJZCh0YWJsZU5hbWUsIGlkKTtcbiAgICAgIGNvbnN0IHJldiA9IG1vZGVsc1tjb3VudF1bUGVyc2lzdGVuY2VLZXlzLk1FVEFEQVRBXTtcbiAgICAgIGlmICghcmV2KVxuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICBgTm8gcmV2aXNpb24gbnVtYmVyIGZvdW5kIGZvciByZWNvcmQgd2l0aCBpZCAke2lkfWBcbiAgICAgICAgKTtcbiAgICAgIE9iamVjdC5hc3NpZ24ocmVjb3JkLCBtb2RlbHNbY291bnRdKTtcbiAgICAgIHJlY29yZFtDb3VjaERCS2V5cy5SRVZdID0gcmV2O1xuICAgICAgcmV0dXJuIHJlY29yZDtcbiAgICB9KTtcbiAgICByZXR1cm4gW3RhYmxlTmFtZSwgaWRzLCByZWNvcmRzXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gRGVsZXRlcyBhIHJlY29yZCBmcm9tIHRoZSBkYXRhYmFzZVxuICAgKiBAc3VtbWFyeSBBYnN0cmFjdCBtZXRob2QgdGhhdCBtdXN0IGJlIGltcGxlbWVudGVkIHRvIGRlbGV0ZSBhIHJlY29yZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFibGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHRhYmxlXG4gICAqIEBwYXJhbSB7c3RyaW5nfG51bWJlcn0gaWQgLSBUaGUgSUQgb2YgdGhlIHJlY29yZFxuICAgKiBAcGFyYW0ge2FueVtdfSBhcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcbiAgICogQHJldHVybiBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZGVsZXRlZCByZWNvcmRcbiAgICovXG4gIGFic3RyYWN0IG92ZXJyaWRlIGRlbGV0ZShcbiAgICB0YWJsZU5hbWU6IHN0cmluZyxcbiAgICBpZDogc3RyaW5nIHwgbnVtYmVyLFxuICAgIC4uLmFyZ3M6IGFueVtdXG4gICk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgYW55Pj47XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBHZW5lcmF0ZXMgYSBDb3VjaERCIGRvY3VtZW50IElEXG4gICAqIEBzdW1tYXJ5IENvbWJpbmVzIHRoZSB0YWJsZSBuYW1lIGFuZCBJRCB0byBjcmVhdGUgYSBDb3VjaERCIGRvY3VtZW50IElEXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWJsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgdGFibGVcbiAgICogQHBhcmFtIHtzdHJpbmd8bnVtYmVyfSBpZCAtIFRoZSBJRCBvZiB0aGUgcmVjb3JkXG4gICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGdlbmVyYXRlZCBDb3VjaERCIGRvY3VtZW50IElEXG4gICAqL1xuICBwcm90ZWN0ZWQgZ2VuZXJhdGVJZCh0YWJsZU5hbWU6IHN0cmluZywgaWQ6IHN0cmluZyB8IG51bWJlcikge1xuICAgIHJldHVybiBbdGFibGVOYW1lLCBpZF0uam9pbihDb3VjaERCS2V5cy5TRVBBUkFUT1IpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBQYXJzZXMgYW4gZXJyb3IgYW5kIGNvbnZlcnRzIGl0IHRvIGEgQmFzZUVycm9yXG4gICAqIEBzdW1tYXJ5IENvbnZlcnRzIHZhcmlvdXMgZXJyb3IgdHlwZXMgdG8gYXBwcm9wcmlhdGUgQmFzZUVycm9yIHN1YnR5cGVzXG4gICAqIEBwYXJhbSB7RXJyb3J8c3RyaW5nfSBlcnIgLSBUaGUgZXJyb3IgdG8gcGFyc2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtyZWFzb25dIC0gT3B0aW9uYWwgcmVhc29uIGZvciB0aGUgZXJyb3JcbiAgICogQHJldHVybiB7QmFzZUVycm9yfSBUaGUgcGFyc2VkIGVycm9yIGFzIGEgQmFzZUVycm9yXG4gICAqL1xuICBwYXJzZUVycm9yKGVycjogRXJyb3IgfCBzdHJpbmcsIHJlYXNvbj86IHN0cmluZyk6IEJhc2VFcnJvciB7XG4gICAgcmV0dXJuIENvdWNoREJBZGFwdGVyLnBhcnNlRXJyb3IoZXJyLCByZWFzb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBDaGVja3MgaWYgYW4gYXR0cmlidXRlIGlzIHJlc2VydmVkXG4gICAqIEBzdW1tYXJ5IERldGVybWluZXMgaWYgYW4gYXR0cmlidXRlIG5hbWUgaXMgcmVzZXJ2ZWQgaW4gQ291Y2hEQlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXR0ciAtIFRoZSBhdHRyaWJ1dGUgbmFtZSB0byBjaGVja1xuICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBhdHRyaWJ1dGUgaXMgcmVzZXJ2ZWQsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGlzUmVzZXJ2ZWQoYXR0cjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICEhYXR0ci5tYXRjaChyZXNlcnZlZEF0dHJpYnV0ZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBTdGF0aWMgbWV0aG9kIHRvIHBhcnNlIGFuIGVycm9yIGFuZCBjb252ZXJ0IGl0IHRvIGEgQmFzZUVycm9yXG4gICAqIEBzdW1tYXJ5IENvbnZlcnRzIHZhcmlvdXMgZXJyb3IgdHlwZXMgdG8gYXBwcm9wcmlhdGUgQmFzZUVycm9yIHN1YnR5cGVzIGJhc2VkIG9uIGVycm9yIGNvZGVzIGFuZCBtZXNzYWdlc1xuICAgKiBAcGFyYW0ge0Vycm9yfHN0cmluZ30gZXJyIC0gVGhlIGVycm9yIHRvIHBhcnNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcmVhc29uXSAtIE9wdGlvbmFsIHJlYXNvbiBmb3IgdGhlIGVycm9yXG4gICAqIEByZXR1cm4ge0Jhc2VFcnJvcn0gVGhlIHBhcnNlZCBlcnJvciBhcyBhIEJhc2VFcnJvclxuICAgKiBAbWVybWFpZFxuICAgKiBzZXF1ZW5jZURpYWdyYW1cbiAgICogICBwYXJ0aWNpcGFudCBDYWxsZXJcbiAgICogICBwYXJ0aWNpcGFudCBwYXJzZUVycm9yXG4gICAqICAgcGFydGljaXBhbnQgRXJyb3JUeXBlc1xuICAgKlxuICAgKiAgIENhbGxlci0+PnBhcnNlRXJyb3I6IGVyciwgcmVhc29uXG4gICAqICAgTm90ZSBvdmVyIHBhcnNlRXJyb3I6IENoZWNrIGlmIGVyciBpcyBhbHJlYWR5IGEgQmFzZUVycm9yXG4gICAqICAgYWx0IGVyciBpcyBCYXNlRXJyb3JcbiAgICogICAgIHBhcnNlRXJyb3ItLT4+Q2FsbGVyOiByZXR1cm4gZXJyXG4gICAqICAgZWxzZSBlcnIgaXMgc3RyaW5nXG4gICAqICAgICBOb3RlIG92ZXIgcGFyc2VFcnJvcjogRXh0cmFjdCBjb2RlIGZyb20gc3RyaW5nXG4gICAqICAgICBhbHQgY29kZSBtYXRjaGVzIFwiYWxyZWFkeSBleGlzdHx1cGRhdGUgY29uZmxpY3RcIlxuICAgKiAgICAgICBwYXJzZUVycm9yLT4+RXJyb3JUeXBlczogbmV3IENvbmZsaWN0RXJyb3IoY29kZSlcbiAgICogICAgICAgRXJyb3JUeXBlcy0tPj5DYWxsZXI6IENvbmZsaWN0RXJyb3JcbiAgICogICAgIGVsc2UgY29kZSBtYXRjaGVzIFwibWlzc2luZ3xkZWxldGVkXCJcbiAgICogICAgICAgcGFyc2VFcnJvci0+PkVycm9yVHlwZXM6IG5ldyBOb3RGb3VuZEVycm9yKGNvZGUpXG4gICAqICAgICAgIEVycm9yVHlwZXMtLT4+Q2FsbGVyOiBOb3RGb3VuZEVycm9yXG4gICAqICAgICBlbmRcbiAgICogICBlbHNlIGVyciBoYXMgY29kZSBwcm9wZXJ0eVxuICAgKiAgICAgTm90ZSBvdmVyIHBhcnNlRXJyb3I6IEV4dHJhY3QgY29kZSBhbmQgcmVhc29uXG4gICAqICAgZWxzZSBlcnIgaGFzIHN0YXR1c0NvZGUgcHJvcGVydHlcbiAgICogICAgIE5vdGUgb3ZlciBwYXJzZUVycm9yOiBFeHRyYWN0IGNvZGUgYW5kIHJlYXNvblxuICAgKiAgIGVsc2VcbiAgICogICAgIE5vdGUgb3ZlciBwYXJzZUVycm9yOiBVc2UgZXJyLm1lc3NhZ2UgYXMgY29kZVxuICAgKiAgIGVuZFxuICAgKlxuICAgKiAgIE5vdGUgb3ZlciBwYXJzZUVycm9yOiBTd2l0Y2ggb24gY29kZVxuICAgKiAgIGFsdCBjb2RlIGlzIDQwMSwgNDEyLCBvciA0MDlcbiAgICogICAgIHBhcnNlRXJyb3ItPj5FcnJvclR5cGVzOiBuZXcgQ29uZmxpY3RFcnJvcihyZWFzb24pXG4gICAqICAgICBFcnJvclR5cGVzLS0+PkNhbGxlcjogQ29uZmxpY3RFcnJvclxuICAgKiAgIGVsc2UgY29kZSBpcyA0MDRcbiAgICogICAgIHBhcnNlRXJyb3ItPj5FcnJvclR5cGVzOiBuZXcgTm90Rm91bmRFcnJvcihyZWFzb24pXG4gICAqICAgICBFcnJvclR5cGVzLS0+PkNhbGxlcjogTm90Rm91bmRFcnJvclxuICAgKiAgIGVsc2UgY29kZSBpcyA0MDBcbiAgICogICAgIGFsdCBjb2RlIG1hdGNoZXMgXCJObyBpbmRleCBleGlzdHNcIlxuICAgKiAgICAgICBwYXJzZUVycm9yLT4+RXJyb3JUeXBlczogbmV3IEluZGV4RXJyb3IoZXJyKVxuICAgKiAgICAgICBFcnJvclR5cGVzLS0+PkNhbGxlcjogSW5kZXhFcnJvclxuICAgKiAgICAgZWxzZVxuICAgKiAgICAgICBwYXJzZUVycm9yLT4+RXJyb3JUeXBlczogbmV3IEludGVybmFsRXJyb3IoZXJyKVxuICAgKiAgICAgICBFcnJvclR5cGVzLS0+PkNhbGxlcjogSW50ZXJuYWxFcnJvclxuICAgKiAgICAgZW5kXG4gICAqICAgZWxzZSBjb2RlIG1hdGNoZXMgXCJFQ09OTlJFRlVTRURcIlxuICAgKiAgICAgcGFyc2VFcnJvci0+PkVycm9yVHlwZXM6IG5ldyBDb25uZWN0aW9uRXJyb3IoZXJyKVxuICAgKiAgICAgRXJyb3JUeXBlcy0tPj5DYWxsZXI6IENvbm5lY3Rpb25FcnJvclxuICAgKiAgIGVsc2VcbiAgICogICAgIHBhcnNlRXJyb3ItPj5FcnJvclR5cGVzOiBuZXcgSW50ZXJuYWxFcnJvcihlcnIpXG4gICAqICAgICBFcnJvclR5cGVzLS0+PkNhbGxlcjogSW50ZXJuYWxFcnJvclxuICAgKiAgIGVuZFxuICAgKi9cbiAgcHJvdGVjdGVkIHN0YXRpYyBwYXJzZUVycm9yKGVycjogRXJyb3IgfCBzdHJpbmcsIHJlYXNvbj86IHN0cmluZyk6IEJhc2VFcnJvciB7XG4gICAgaWYgKGVyciBpbnN0YW5jZW9mIEJhc2VFcnJvcikgcmV0dXJuIGVyciBhcyBhbnk7XG4gICAgbGV0IGNvZGU6IHN0cmluZyA9IFwiXCI7XG4gICAgaWYgKHR5cGVvZiBlcnIgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIGNvZGUgPSBlcnI7XG4gICAgICBpZiAoY29kZS5tYXRjaCgvYWxyZWFkeSBleGlzdHx1cGRhdGUgY29uZmxpY3QvZykpXG4gICAgICAgIHJldHVybiBuZXcgQ29uZmxpY3RFcnJvcihjb2RlKTtcbiAgICAgIGlmIChjb2RlLm1hdGNoKC9taXNzaW5nfGRlbGV0ZWQvZykpIHJldHVybiBuZXcgTm90Rm91bmRFcnJvcihjb2RlKTtcbiAgICB9IGVsc2UgaWYgKChlcnIgYXMgYW55KS5jb2RlKSB7XG4gICAgICBjb2RlID0gKGVyciBhcyBhbnkpLmNvZGU7XG4gICAgICByZWFzb24gPSByZWFzb24gfHwgZXJyLm1lc3NhZ2U7XG4gICAgfSBlbHNlIGlmICgoZXJyIGFzIGFueSkuc3RhdHVzQ29kZSkge1xuICAgICAgY29kZSA9IChlcnIgYXMgYW55KS5zdGF0dXNDb2RlO1xuICAgICAgcmVhc29uID0gcmVhc29uIHx8IGVyci5tZXNzYWdlO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb2RlID0gZXJyLm1lc3NhZ2U7XG4gICAgfVxuXG4gICAgc3dpdGNoIChjb2RlLnRvU3RyaW5nKCkpIHtcbiAgICAgIGNhc2UgXCI0MDFcIjpcbiAgICAgIGNhc2UgXCI0MTJcIjpcbiAgICAgIGNhc2UgXCI0MDlcIjpcbiAgICAgICAgcmV0dXJuIG5ldyBDb25mbGljdEVycm9yKHJlYXNvbiBhcyBzdHJpbmcpO1xuICAgICAgY2FzZSBcIjQwNFwiOlxuICAgICAgICByZXR1cm4gbmV3IE5vdEZvdW5kRXJyb3IocmVhc29uIGFzIHN0cmluZyk7XG4gICAgICBjYXNlIFwiNDAwXCI6XG4gICAgICAgIGlmIChjb2RlLnRvU3RyaW5nKCkubWF0Y2goL05vXFxzaW5kZXhcXHNleGlzdHMvZykpXG4gICAgICAgICAgcmV0dXJuIG5ldyBJbmRleEVycm9yKGVycik7XG4gICAgICAgIHJldHVybiBuZXcgSW50ZXJuYWxFcnJvcihlcnIpO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgaWYgKGNvZGUudG9TdHJpbmcoKS5tYXRjaCgvRUNPTk5SRUZVU0VEL2cpKVxuICAgICAgICAgIHJldHVybiBuZXcgQ29ubmVjdGlvbkVycm9yKGVycik7XG4gICAgICAgIHJldHVybiBuZXcgSW50ZXJuYWxFcnJvcihlcnIpO1xuICAgIH1cbiAgfVxufVxuIl19