@data-client/endpoint
Version:
Declarative Network Interface Definitions
339 lines (315 loc) • 44.4 kB
JavaScript
import { INVALID } from '../special.js';
/**
* Turns any class into an Entity.
* @see https://dataclient.io/rest/api/EntityMixin
*/
// id is in Instance, so we default to that as pk
// pk was specified in options, so we don't need to redefine
export default function EntityMixin(Base, options = {}) {
/**
* Entity defines a single (globally) unique object.
* @see https://dataclient.io/rest/api/Entity
*/
class EntityMixin extends Base {
static toString() {
return this.key;
}
static toJSON() {
return {
key: this.key,
schema: this.schema
};
}
/** Defines nested entities */
/**
* A unique identifier for each Entity
*
* @see https://dataclient.io/rest/api/Entity#pk
* @param [parent] When normalizing, the object which included the entity
* @param [key] When normalizing, the key where this entity was found
* @param [args] ...args sent to Endpoint
*/
/** Returns the globally unique identifier for the static Entity */
// default implementation in class static block at bottom of definition
/** Defines indexes to enable lookup by */
/**
* A unique identifier for each Entity
*
* @see https://dataclient.io/rest/api/Entity#pk
* @param [value] POJO of the entity or subset used
* @param [parent] When normalizing, the object which included the entity
* @param [key] When normalizing, the key where this entity was found
* @param [args] ...args sent to Endpoint
*/
static pk(value, parent, key, args) {
return this.prototype.pk.call(value, parent, key, args);
}
/** Return true to merge incoming data; false keeps existing entity
*
* @see https://dataclient.io/rest/api/Entity#shouldUpdate
*/
static shouldUpdate(existingMeta, incomingMeta, existing, incoming) {
return true;
}
/** Determines the order of incoming entity vs entity already in store\
*
* @see https://dataclient.io/rest/api/Entity#shouldReorder
* @returns true if incoming entity should be first argument of merge()
*/
static shouldReorder(existingMeta, incomingMeta, existing, incoming) {
return incomingMeta.fetchedAt < existingMeta.fetchedAt;
}
/** Creates new instance copying over defined values of arguments
*
* @see https://dataclient.io/rest/api/Entity#merge
*/
static merge(existing, incoming) {
return {
...existing,
...incoming
};
}
/** Run when an existing entity is found in the store
*
* @see https://dataclient.io/rest/api/Entity#mergeWithStore
*/
static mergeWithStore(existingMeta, incomingMeta, existing, incoming) {
const shouldUpdate = this.shouldUpdate(existingMeta, incomingMeta, existing, incoming);
if (shouldUpdate) {
// distinct types are not mergeable (like delete symbol), so just replace
if (typeof incoming !== typeof existing) {
return incoming;
} else {
return this.shouldReorder(existingMeta, incomingMeta, existing, incoming) ? this.merge(incoming, existing) : this.merge(existing, incoming);
}
} else {
return existing;
}
}
/** Run when an existing entity is found in the store
*
* @see https://dataclient.io/rest/api/Entity#mergeMetaWithStore
*/
static mergeMetaWithStore(existingMeta, incomingMeta, existing, incoming) {
return this.shouldReorder(existingMeta, incomingMeta, existing, incoming) ? existingMeta : incomingMeta;
}
/** Factory method to convert from Plain JS Objects.
*
* @param [props] Plain Object of properties to assign.
*/
static fromJS(
// TODO: this should only accept members that are not functions
props = {}) {
// we type guarded abstract case above, so ok to force typescript to allow constructor call
const instance = new this(props);
// we can't rely on constructors and override the defaults provided as property assignments
// all occur after the constructor
Object.assign(instance, props);
return instance;
}
/** Called when denormalizing an entity to create an instance when 'valid'
*
* @see https://dataclient.io/rest/api/Entity#createIfValid
* @param [props] Plain Object of properties to assign.
*/
static createIfValid(
// TODO: this should only accept members that are not functions
props) {
if (this.validate(props)) {
return undefined;
}
return this.fromJS(props);
}
/** Do any transformations when first receiving input
*
* @see https://dataclient.io/rest/api/Entity#process
*/
static process(input, parent, key, args) {
return {
...input
};
}
static normalize(input, parent, key, args, visit, addEntity, getEntity, checkLoop) {
const processedEntity = this.process(input, parent, key, args);
let id;
if (typeof processedEntity === 'undefined') {
id = this.pk(input, parent, key, args);
addEntity(this, INVALID, id);
return id;
}
id = this.pk(processedEntity, parent, key, args);
if (id === undefined || id === '' || id === 'undefined') {
// create a random id if a valid one cannot be computed
// this is useful for optimistic creates that don't need real ids - just something to hold their place
id = `MISS-${Math.random()}`;
// 'creates' conceptually should allow missing PK to make optimistic creates easy
if (process.env.NODE_ENV !== 'production' && !visit.creating) {
let why;
if (!('pk' in options) && EntityMixin.prototype.pk === this.prototype.pk && !('id' in processedEntity)) {
why = `'id' missing but needed for default pk(). Try defining pk() for your Entity.`;
} else {
why = `This is likely due to a malformed response.
Try inspecting the network response or fetch() return value.
Or use debugging tools: https://dataclient.io/docs/getting-started/debugging`;
}
const error = new Error(`Missing usable primary key when normalizing response.
${why}
Learn more about primary keys: https://dataclient.io/rest/api/Entity#pk
Entity: ${this.key}
Value (processed): ${processedEntity && JSON.stringify(processedEntity, null, 2)}
`);
error.status = 400;
throw error;
}
} else {
id = `${id}`;
}
/* Circular reference short-circuiter */
if (checkLoop(this.key, id, input)) return id;
const errorMessage = this.validate(processedEntity);
throwValidationError(errorMessage);
Object.keys(this.schema).forEach(key => {
if (Object.hasOwn(processedEntity, key)) {
processedEntity[key] = visit(this.schema[key], processedEntity[key], processedEntity, key, args);
}
});
addEntity(this, processedEntity, id);
return id;
}
static validate(processedEntity) {
return;
}
static queryKey(args, queryKey, getEntity, getIndex) {
if (!args[0]) return;
const id = queryKeyCandidate(this, args, getIndex);
// ensure this actually has entity or we shouldn't try to use it in our query
if (getEntity(this.key, id)) return id;
}
static denormalize(input, args, unvisit) {
if (typeof input === 'symbol') {
return input;
}
// note: iteration order must be stable
for (const key of Object.keys(this.schema)) {
const schema = this.schema[key];
const value = unvisit(schema, input[key]);
if (typeof value === 'symbol') {
// if default is not 'falsy', then this is required, so propagate INVALID symbol
if (this.defaults[key]) {
return value;
}
input[key] = undefined;
} else {
input[key] = value;
}
}
return input;
}
/** All instance defaults set */
static get defaults() {
// we use hasOwn because we don't want to use a parents' defaults
if (!Object.hasOwn(this, '__defaults')) Object.defineProperty(this, '__defaults', {
value: new this(),
writable: true,
configurable: true
});
return this.__defaults;
}
}
const {
pk,
schema,
key,
...staticProps
} = options;
// remaining options
Object.assign(EntityMixin, staticProps);
if ('schema' in options) {
EntityMixin.schema = options.schema;
} else if (!Base.schema) {
EntityMixin.schema = {};
}
if ('pk' in options) {
if (typeof options.pk === 'function') {
EntityMixin.prototype.pk = function (parent, key) {
return options.pk(this, parent, key);
};
} else {
EntityMixin.prototype.pk = function () {
return this[options.pk];
};
}
// default to 'id' field if the base class doesn't have a pk
} else if (typeof Base.prototype.pk !== 'function') {
EntityMixin.prototype.pk = function () {
return this.id;
};
}
if ('key' in options) {
Object.defineProperty(EntityMixin, 'key', {
value: options.key,
configurable: true,
writable: true,
enumerable: true
});
} else if (!('key' in Base)) {
function set(value) {
Object.defineProperty(this, 'key', {
value,
writable: true,
enumerable: true,
configurable: true
});
}
const baseGet = function () {
const name = this.name === 'EntityMixin' ? Base.name : this.name;
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'production' && (name === '' || name === 'EntityMixin' || name === '_temp')) throw new Error('Entity classes without a name must define `static key`\nSee: https://dataclient.io/rest/api/Entity#key');
return name;
};
const get = /* istanbul ignore if */
typeof document !== 'undefined' && document.CLS_MANGLE ? /* istanbul ignore next */function () {
document.CLS_MANGLE == null || document.CLS_MANGLE(this);
Object.defineProperty(EntityMixin, 'key', {
get: baseGet,
set,
enumerable: true,
configurable: true
});
return baseGet.call(this);
} : baseGet;
Object.defineProperty(EntityMixin, 'key', {
get,
set,
enumerable: true,
configurable: true
});
}
return EntityMixin;
}
function indexFromParams(params, indexes) {
if (!indexes) return undefined;
return indexes.find(index => Object.hasOwn(params, index));
}
// part of the reason for pulling this out is that all functions that throw are deoptimized
function throwValidationError(errorMessage) {
if (errorMessage) {
const error = new Error(errorMessage);
error.status = 400;
throw error;
}
}
function queryKeyCandidate(schema, args, getIndex) {
if (['string', 'number'].includes(typeof args[0])) {
return `${args[0]}`;
}
const id = schema.pk(args[0], undefined, '', args);
// Was able to infer the entity's primary key from params
if (id !== undefined && id !== '') return id;
// now attempt lookup in indexes
const indexName = indexFromParams(args[0], schema.indexes);
if (!indexName) return;
const value = args[0][indexName];
return getIndex(schema.key, indexName, value)[value];
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJJTlZBTElEIiwiRW50aXR5TWl4aW4iLCJCYXNlIiwib3B0aW9ucyIsInRvU3RyaW5nIiwia2V5IiwidG9KU09OIiwic2NoZW1hIiwicGsiLCJ2YWx1ZSIsInBhcmVudCIsImFyZ3MiLCJwcm90b3R5cGUiLCJjYWxsIiwic2hvdWxkVXBkYXRlIiwiZXhpc3RpbmdNZXRhIiwiaW5jb21pbmdNZXRhIiwiZXhpc3RpbmciLCJpbmNvbWluZyIsInNob3VsZFJlb3JkZXIiLCJmZXRjaGVkQXQiLCJtZXJnZSIsIm1lcmdlV2l0aFN0b3JlIiwibWVyZ2VNZXRhV2l0aFN0b3JlIiwiZnJvbUpTIiwicHJvcHMiLCJpbnN0YW5jZSIsIk9iamVjdCIsImFzc2lnbiIsImNyZWF0ZUlmVmFsaWQiLCJ2YWxpZGF0ZSIsInVuZGVmaW5lZCIsInByb2Nlc3MiLCJpbnB1dCIsIm5vcm1hbGl6ZSIsInZpc2l0IiwiYWRkRW50aXR5IiwiZ2V0RW50aXR5IiwiY2hlY2tMb29wIiwicHJvY2Vzc2VkRW50aXR5IiwiaWQiLCJNYXRoIiwicmFuZG9tIiwiZW52IiwiTk9ERV9FTlYiLCJjcmVhdGluZyIsIndoeSIsImVycm9yIiwiRXJyb3IiLCJKU09OIiwic3RyaW5naWZ5Iiwic3RhdHVzIiwiZXJyb3JNZXNzYWdlIiwidGhyb3dWYWxpZGF0aW9uRXJyb3IiLCJrZXlzIiwiZm9yRWFjaCIsImhhc093biIsInF1ZXJ5S2V5IiwiZ2V0SW5kZXgiLCJxdWVyeUtleUNhbmRpZGF0ZSIsImRlbm9ybWFsaXplIiwidW52aXNpdCIsImRlZmF1bHRzIiwiZGVmaW5lUHJvcGVydHkiLCJ3cml0YWJsZSIsImNvbmZpZ3VyYWJsZSIsIl9fZGVmYXVsdHMiLCJzdGF0aWNQcm9wcyIsImVudW1lcmFibGUiLCJzZXQiLCJiYXNlR2V0IiwibmFtZSIsImdldCIsImRvY3VtZW50IiwiQ0xTX01BTkdMRSIsImluZGV4RnJvbVBhcmFtcyIsInBhcmFtcyIsImluZGV4ZXMiLCJmaW5kIiwiaW5kZXgiLCJpbmNsdWRlcyIsImluZGV4TmFtZSJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zY2hlbWFzL0VudGl0eU1peGluLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHtcbiAgU2NoZW1hLFxuICBHZXRJbmRleCxcbiAgR2V0RW50aXR5LFxuICBDaGVja0xvb3AsXG4gIFZpc2l0LFxufSBmcm9tICcuLi9pbnRlcmZhY2UuanMnO1xuaW1wb3J0IHsgQWJzdHJhY3RJbnN0YW5jZVR5cGUgfSBmcm9tICcuLi9ub3JtYWwuanMnO1xuaW1wb3J0IHsgSU5WQUxJRCB9IGZyb20gJy4uL3NwZWNpYWwuanMnO1xuaW1wb3J0IHR5cGUge1xuICBJRW50aXR5Q2xhc3MsXG4gIElFbnRpdHlJbnN0YW5jZSxcbiAgRW50aXR5T3B0aW9ucyxcbiAgUmVxdWlyZWRQS09wdGlvbnMsXG4gIElEQ2xhc3MsXG4gIENvbnN0cnVjdG9yLFxuICBQS0NsYXNzLFxufSBmcm9tICcuL0VudGl0eVR5cGVzLmpzJztcblxuLyoqXG4gKiBUdXJucyBhbnkgY2xhc3MgaW50byBhbiBFbnRpdHkuXG4gKiBAc2VlIGh0dHBzOi8vZGF0YWNsaWVudC5pby9yZXN0L2FwaS9FbnRpdHlNaXhpblxuICovXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBFbnRpdHlNaXhpbjxUQmFzZSBleHRlbmRzIFBLQ2xhc3M+KFxuICBCYXNlOiBUQmFzZSxcbiAgb3B0PzogRW50aXR5T3B0aW9uczxJbnN0YW5jZVR5cGU8VEJhc2U+Pixcbik6IElFbnRpdHlDbGFzczxUQmFzZT4gJiBUQmFzZTtcblxuLy8gaWQgaXMgaW4gSW5zdGFuY2UsIHNvIHdlIGRlZmF1bHQgdG8gdGhhdCBhcyBwa1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gRW50aXR5TWl4aW48VEJhc2UgZXh0ZW5kcyBJRENsYXNzPihcbiAgQmFzZTogVEJhc2UsXG4gIG9wdD86IEVudGl0eU9wdGlvbnM8SW5zdGFuY2VUeXBlPFRCYXNlPj4sXG4pOiBJRW50aXR5Q2xhc3M8VEJhc2U+ICYgVEJhc2UgJiAobmV3ICguLi5hcmdzOiBhbnlbXSkgPT4gSUVudGl0eUluc3RhbmNlKTtcblxuLy8gcGsgd2FzIHNwZWNpZmllZCBpbiBvcHRpb25zLCBzbyB3ZSBkb24ndCBuZWVkIHRvIHJlZGVmaW5lXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBFbnRpdHlNaXhpbjxUQmFzZSBleHRlbmRzIENvbnN0cnVjdG9yPihcbiAgQmFzZTogVEJhc2UsXG4gIG9wdDogUmVxdWlyZWRQS09wdGlvbnM8SW5zdGFuY2VUeXBlPFRCYXNlPj4sXG4pOiBJRW50aXR5Q2xhc3M8VEJhc2U+ICYgVEJhc2UgJiAobmV3ICguLi5hcmdzOiBhbnlbXSkgPT4gSUVudGl0eUluc3RhbmNlKTtcblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gRW50aXR5TWl4aW48VEJhc2UgZXh0ZW5kcyBDb25zdHJ1Y3Rvcj4oXG4gIEJhc2U6IFRCYXNlLFxuICBvcHRpb25zOiBFbnRpdHlPcHRpb25zPEluc3RhbmNlVHlwZTxUQmFzZT4+ID0ge30sXG4pIHtcbiAgLyoqXG4gICAqIEVudGl0eSBkZWZpbmVzIGEgc2luZ2xlIChnbG9iYWxseSkgdW5pcXVlIG9iamVjdC5cbiAgICogQHNlZSBodHRwczovL2RhdGFjbGllbnQuaW8vcmVzdC9hcGkvRW50aXR5XG4gICAqL1xuICBhYnN0cmFjdCBjbGFzcyBFbnRpdHlNaXhpbiBleHRlbmRzIEJhc2Uge1xuICAgIHN0YXRpYyB0b1N0cmluZygpIHtcbiAgICAgIHJldHVybiB0aGlzLmtleTtcbiAgICB9XG5cbiAgICBzdGF0aWMgdG9KU09OKCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAga2V5OiB0aGlzLmtleSxcbiAgICAgICAgc2NoZW1hOiB0aGlzLnNjaGVtYSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqIERlZmluZXMgbmVzdGVkIGVudGl0aWVzICovXG4gICAgZGVjbGFyZSBzdGF0aWMgc2NoZW1hOiB7IFtrOiBzdHJpbmddOiBTY2hlbWEgfTtcblxuICAgIC8qKlxuICAgICAqIEEgdW5pcXVlIGlkZW50aWZpZXIgZm9yIGVhY2ggRW50aXR5XG4gICAgICpcbiAgICAgKiBAc2VlIGh0dHBzOi8vZGF0YWNsaWVudC5pby9yZXN0L2FwaS9FbnRpdHkjcGtcbiAgICAgKiBAcGFyYW0gW3BhcmVudF0gV2hlbiBub3JtYWxpemluZywgdGhlIG9iamVjdCB3aGljaCBpbmNsdWRlZCB0aGUgZW50aXR5XG4gICAgICogQHBhcmFtIFtrZXldIFdoZW4gbm9ybWFsaXppbmcsIHRoZSBrZXkgd2hlcmUgdGhpcyBlbnRpdHkgd2FzIGZvdW5kXG4gICAgICogQHBhcmFtIFthcmdzXSAuLi5hcmdzIHNlbnQgdG8gRW5kcG9pbnRcbiAgICAgKi9cbiAgICBkZWNsYXJlIHBrOiAoXG4gICAgICBwYXJlbnQ/OiBhbnksXG4gICAgICBrZXk/OiBzdHJpbmcsXG4gICAgICBhcmdzPzogcmVhZG9ubHkgYW55W10sXG4gICAgKSA9PiBzdHJpbmcgfCBudW1iZXIgfCB1bmRlZmluZWQ7XG5cbiAgICAvKiogUmV0dXJucyB0aGUgZ2xvYmFsbHkgdW5pcXVlIGlkZW50aWZpZXIgZm9yIHRoZSBzdGF0aWMgRW50aXR5ICovXG4gICAgZGVjbGFyZSBzdGF0aWMga2V5OiBzdHJpbmc7XG4gICAgLy8gZGVmYXVsdCBpbXBsZW1lbnRhdGlvbiBpbiBjbGFzcyBzdGF0aWMgYmxvY2sgYXQgYm90dG9tIG9mIGRlZmluaXRpb25cblxuICAgIC8qKiBEZWZpbmVzIGluZGV4ZXMgdG8gZW5hYmxlIGxvb2t1cCBieSAqL1xuICAgIGRlY2xhcmUgc3RhdGljIGluZGV4ZXM/OiByZWFkb25seSBzdHJpbmdbXTtcblxuICAgIC8qKlxuICAgICAqIEEgdW5pcXVlIGlkZW50aWZpZXIgZm9yIGVhY2ggRW50aXR5XG4gICAgICpcbiAgICAgKiBAc2VlIGh0dHBzOi8vZGF0YWNsaWVudC5pby9yZXN0L2FwaS9FbnRpdHkjcGtcbiAgICAgKiBAcGFyYW0gW3ZhbHVlXSBQT0pPIG9mIHRoZSBlbnRpdHkgb3Igc3Vic2V0IHVzZWRcbiAgICAgKiBAcGFyYW0gW3BhcmVudF0gV2hlbiBub3JtYWxpemluZywgdGhlIG9iamVjdCB3aGljaCBpbmNsdWRlZCB0aGUgZW50aXR5XG4gICAgICogQHBhcmFtIFtrZXldIFdoZW4gbm9ybWFsaXppbmcsIHRoZSBrZXkgd2hlcmUgdGhpcyBlbnRpdHkgd2FzIGZvdW5kXG4gICAgICogQHBhcmFtIFthcmdzXSAuLi5hcmdzIHNlbnQgdG8gRW5kcG9pbnRcbiAgICAgKi9cbiAgICBzdGF0aWMgcGs8VCBleHRlbmRzIHR5cGVvZiBFbnRpdHlNaXhpbj4oXG4gICAgICB0aGlzOiBULFxuICAgICAgdmFsdWU6IFBhcnRpYWw8QWJzdHJhY3RJbnN0YW5jZVR5cGU8VD4+LFxuICAgICAgcGFyZW50PzogYW55LFxuICAgICAga2V5Pzogc3RyaW5nLFxuICAgICAgYXJncz86IHJlYWRvbmx5IGFueVtdLFxuICAgICk6IHN0cmluZyB8IG51bWJlciB8IHVuZGVmaW5lZCB7XG4gICAgICByZXR1cm4gdGhpcy5wcm90b3R5cGUucGsuY2FsbCh2YWx1ZSwgcGFyZW50LCBrZXksIGFyZ3MpO1xuICAgIH1cblxuICAgIC8qKiBSZXR1cm4gdHJ1ZSB0byBtZXJnZSBpbmNvbWluZyBkYXRhOyBmYWxzZSBrZWVwcyBleGlzdGluZyBlbnRpdHlcbiAgICAgKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kYXRhY2xpZW50LmlvL3Jlc3QvYXBpL0VudGl0eSNzaG91bGRVcGRhdGVcbiAgICAgKi9cbiAgICBzdGF0aWMgc2hvdWxkVXBkYXRlKFxuICAgICAgZXhpc3RpbmdNZXRhOiB7IGRhdGU6IG51bWJlcjsgZmV0Y2hlZEF0OiBudW1iZXIgfSxcbiAgICAgIGluY29taW5nTWV0YTogeyBkYXRlOiBudW1iZXI7IGZldGNoZWRBdDogbnVtYmVyIH0sXG4gICAgICBleGlzdGluZzogYW55LFxuICAgICAgaW5jb21pbmc6IGFueSxcbiAgICApIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8qKiBEZXRlcm1pbmVzIHRoZSBvcmRlciBvZiBpbmNvbWluZyBlbnRpdHkgdnMgZW50aXR5IGFscmVhZHkgaW4gc3RvcmVcXFxuICAgICAqXG4gICAgICogQHNlZSBodHRwczovL2RhdGFjbGllbnQuaW8vcmVzdC9hcGkvRW50aXR5I3Nob3VsZFJlb3JkZXJcbiAgICAgKiBAcmV0dXJucyB0cnVlIGlmIGluY29taW5nIGVudGl0eSBzaG91bGQgYmUgZmlyc3QgYXJndW1lbnQgb2YgbWVyZ2UoKVxuICAgICAqL1xuICAgIHN0YXRpYyBzaG91bGRSZW9yZGVyKFxuICAgICAgZXhpc3RpbmdNZXRhOiB7IGRhdGU6IG51bWJlcjsgZmV0Y2hlZEF0OiBudW1iZXIgfSxcbiAgICAgIGluY29taW5nTWV0YTogeyBkYXRlOiBudW1iZXI7IGZldGNoZWRBdDogbnVtYmVyIH0sXG4gICAgICBleGlzdGluZzogYW55LFxuICAgICAgaW5jb21pbmc6IGFueSxcbiAgICApIHtcbiAgICAgIHJldHVybiBpbmNvbWluZ01ldGEuZmV0Y2hlZEF0IDwgZXhpc3RpbmdNZXRhLmZldGNoZWRBdDtcbiAgICB9XG5cbiAgICAvKiogQ3JlYXRlcyBuZXcgaW5zdGFuY2UgY29weWluZyBvdmVyIGRlZmluZWQgdmFsdWVzIG9mIGFyZ3VtZW50c1xuICAgICAqXG4gICAgICogQHNlZSBodHRwczovL2RhdGFjbGllbnQuaW8vcmVzdC9hcGkvRW50aXR5I21lcmdlXG4gICAgICovXG4gICAgc3RhdGljIG1lcmdlKGV4aXN0aW5nOiBhbnksIGluY29taW5nOiBhbnkpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIC4uLmV4aXN0aW5nLFxuICAgICAgICAuLi5pbmNvbWluZyxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqIFJ1biB3aGVuIGFuIGV4aXN0aW5nIGVudGl0eSBpcyBmb3VuZCBpbiB0aGUgc3RvcmVcbiAgICAgKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kYXRhY2xpZW50LmlvL3Jlc3QvYXBpL0VudGl0eSNtZXJnZVdpdGhTdG9yZVxuICAgICAqL1xuICAgIHN0YXRpYyBtZXJnZVdpdGhTdG9yZShcbiAgICAgIGV4aXN0aW5nTWV0YToge1xuICAgICAgICBkYXRlOiBudW1iZXI7XG4gICAgICAgIGZldGNoZWRBdDogbnVtYmVyO1xuICAgICAgfSxcbiAgICAgIGluY29taW5nTWV0YTogeyBkYXRlOiBudW1iZXI7IGZldGNoZWRBdDogbnVtYmVyIH0sXG4gICAgICBleGlzdGluZzogYW55LFxuICAgICAgaW5jb21pbmc6IGFueSxcbiAgICApIHtcbiAgICAgIGNvbnN0IHNob3VsZFVwZGF0ZSA9IHRoaXMuc2hvdWxkVXBkYXRlKFxuICAgICAgICBleGlzdGluZ01ldGEsXG4gICAgICAgIGluY29taW5nTWV0YSxcbiAgICAgICAgZXhpc3RpbmcsXG4gICAgICAgIGluY29taW5nLFxuICAgICAgKTtcblxuICAgICAgaWYgKHNob3VsZFVwZGF0ZSkge1xuICAgICAgICAvLyBkaXN0aW5jdCB0eXBlcyBhcmUgbm90IG1lcmdlYWJsZSAobGlrZSBkZWxldGUgc3ltYm9sKSwgc28ganVzdCByZXBsYWNlXG4gICAgICAgIGlmICh0eXBlb2YgaW5jb21pbmcgIT09IHR5cGVvZiBleGlzdGluZykge1xuICAgICAgICAgIHJldHVybiBpbmNvbWluZztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgICB0aGlzLnNob3VsZFJlb3JkZXIoZXhpc3RpbmdNZXRhLCBpbmNvbWluZ01ldGEsIGV4aXN0aW5nLCBpbmNvbWluZylcbiAgICAgICAgICAgICkgP1xuICAgICAgICAgICAgICB0aGlzLm1lcmdlKGluY29taW5nLCBleGlzdGluZylcbiAgICAgICAgICAgIDogdGhpcy5tZXJnZShleGlzdGluZywgaW5jb21pbmcpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gZXhpc3Rpbmc7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLyoqIFJ1biB3aGVuIGFuIGV4aXN0aW5nIGVudGl0eSBpcyBmb3VuZCBpbiB0aGUgc3RvcmVcbiAgICAgKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kYXRhY2xpZW50LmlvL3Jlc3QvYXBpL0VudGl0eSNtZXJnZU1ldGFXaXRoU3RvcmVcbiAgICAgKi9cbiAgICBzdGF0aWMgbWVyZ2VNZXRhV2l0aFN0b3JlKFxuICAgICAgZXhpc3RpbmdNZXRhOiB7XG4gICAgICAgIGZldGNoZWRBdDogbnVtYmVyO1xuICAgICAgICBkYXRlOiBudW1iZXI7XG4gICAgICAgIGV4cGlyZXNBdDogbnVtYmVyO1xuICAgICAgfSxcbiAgICAgIGluY29taW5nTWV0YTogeyBmZXRjaGVkQXQ6IG51bWJlcjsgZGF0ZTogbnVtYmVyOyBleHBpcmVzQXQ6IG51bWJlciB9LFxuICAgICAgZXhpc3Rpbmc6IGFueSxcbiAgICAgIGluY29taW5nOiBhbnksXG4gICAgKSB7XG4gICAgICByZXR1cm4gKFxuICAgICAgICAgIHRoaXMuc2hvdWxkUmVvcmRlcihleGlzdGluZ01ldGEsIGluY29taW5nTWV0YSwgZXhpc3RpbmcsIGluY29taW5nKVxuICAgICAgICApID9cbiAgICAgICAgICBleGlzdGluZ01ldGFcbiAgICAgICAgOiBpbmNvbWluZ01ldGE7XG4gICAgfVxuXG4gICAgLyoqIEZhY3RvcnkgbWV0aG9kIHRvIGNvbnZlcnQgZnJvbSBQbGFpbiBKUyBPYmplY3RzLlxuICAgICAqXG4gICAgICogQHBhcmFtIFtwcm9wc10gUGxhaW4gT2JqZWN0IG9mIHByb3BlcnRpZXMgdG8gYXNzaWduLlxuICAgICAqL1xuICAgIHN0YXRpYyBmcm9tSlM8VCBleHRlbmRzIHR5cGVvZiBFbnRpdHlNaXhpbj4oXG4gICAgICB0aGlzOiBULFxuICAgICAgLy8gVE9ETzogdGhpcyBzaG91bGQgb25seSBhY2NlcHQgbWVtYmVycyB0aGF0IGFyZSBub3QgZnVuY3Rpb25zXG4gICAgICBwcm9wczogUGFydGlhbDxBYnN0cmFjdEluc3RhbmNlVHlwZTxUPj4gPSB7fSxcbiAgICApOiBBYnN0cmFjdEluc3RhbmNlVHlwZTxUPiB7XG4gICAgICAvLyB3ZSB0eXBlIGd1YXJkZWQgYWJzdHJhY3QgY2FzZSBhYm92ZSwgc28gb2sgdG8gZm9yY2UgdHlwZXNjcmlwdCB0byBhbGxvdyBjb25zdHJ1Y3RvciBjYWxsXG4gICAgICBjb25zdCBpbnN0YW5jZSA9IG5ldyAodGhpcyBhcyBhbnkpKHByb3BzKSBhcyBBYnN0cmFjdEluc3RhbmNlVHlwZTxUPjtcbiAgICAgIC8vIHdlIGNhbid0IHJlbHkgb24gY29uc3RydWN0b3JzIGFuZCBvdmVycmlkZSB0aGUgZGVmYXVsdHMgcHJvdmlkZWQgYXMgcHJvcGVydHkgYXNzaWdubWVudHNcbiAgICAgIC8vIGFsbCBvY2N1ciBhZnRlciB0aGUgY29uc3RydWN0b3JcbiAgICAgIE9iamVjdC5hc3NpZ24oaW5zdGFuY2UsIHByb3BzKTtcbiAgICAgIHJldHVybiBpbnN0YW5jZTtcbiAgICB9XG5cbiAgICAvKiogQ2FsbGVkIHdoZW4gZGVub3JtYWxpemluZyBhbiBlbnRpdHkgdG8gY3JlYXRlIGFuIGluc3RhbmNlIHdoZW4gJ3ZhbGlkJ1xuICAgICAqXG4gICAgICogQHNlZSBodHRwczovL2RhdGFjbGllbnQuaW8vcmVzdC9hcGkvRW50aXR5I2NyZWF0ZUlmVmFsaWRcbiAgICAgKiBAcGFyYW0gW3Byb3BzXSBQbGFpbiBPYmplY3Qgb2YgcHJvcGVydGllcyB0byBhc3NpZ24uXG4gICAgICovXG4gICAgc3RhdGljIGNyZWF0ZUlmVmFsaWQ8VCBleHRlbmRzIHR5cGVvZiBFbnRpdHlNaXhpbj4oXG4gICAgICB0aGlzOiBULFxuICAgICAgLy8gVE9ETzogdGhpcyBzaG91bGQgb25seSBhY2NlcHQgbWVtYmVycyB0aGF0IGFyZSBub3QgZnVuY3Rpb25zXG4gICAgICBwcm9wczogUGFydGlhbDxBYnN0cmFjdEluc3RhbmNlVHlwZTxUPj4sXG4gICAgKTogQWJzdHJhY3RJbnN0YW5jZVR5cGU8VD4gfCB1bmRlZmluZWQge1xuICAgICAgaWYgKHRoaXMudmFsaWRhdGUocHJvcHMpKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQgYXMgYW55O1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXMuZnJvbUpTKHByb3BzKTtcbiAgICB9XG5cbiAgICAvKiogRG8gYW55IHRyYW5zZm9ybWF0aW9ucyB3aGVuIGZpcnN0IHJlY2VpdmluZyBpbnB1dFxuICAgICAqXG4gICAgICogQHNlZSBodHRwczovL2RhdGFjbGllbnQuaW8vcmVzdC9hcGkvRW50aXR5I3Byb2Nlc3NcbiAgICAgKi9cbiAgICBzdGF0aWMgcHJvY2VzcyhcbiAgICAgIGlucHV0OiBhbnksXG4gICAgICBwYXJlbnQ6IGFueSxcbiAgICAgIGtleTogc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgICAgYXJnczogYW55LFxuICAgICk6IGFueSB7XG4gICAgICByZXR1cm4geyAuLi5pbnB1dCB9O1xuICAgIH1cblxuICAgIHN0YXRpYyBub3JtYWxpemUoXG4gICAgICBpbnB1dDogYW55LFxuICAgICAgcGFyZW50OiBhbnksXG4gICAgICBrZXk6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICAgIGFyZ3M6IHJlYWRvbmx5IGFueVtdLFxuICAgICAgdmlzaXQ6IFZpc2l0LFxuICAgICAgYWRkRW50aXR5OiAoLi4uYXJnczogYW55KSA9PiBhbnksXG4gICAgICBnZXRFbnRpdHk6IEdldEVudGl0eSxcbiAgICAgIGNoZWNrTG9vcDogQ2hlY2tMb29wLFxuICAgICk6IGFueSB7XG4gICAgICBjb25zdCBwcm9jZXNzZWRFbnRpdHkgPSB0aGlzLnByb2Nlc3MoaW5wdXQsIHBhcmVudCwga2V5LCBhcmdzKTtcbiAgICAgIGxldCBpZDogc3RyaW5nIHwgbnVtYmVyIHwgdW5kZWZpbmVkO1xuICAgICAgaWYgKHR5cGVvZiBwcm9jZXNzZWRFbnRpdHkgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIGlkID0gdGhpcy5wayhpbnB1dCwgcGFyZW50LCBrZXksIGFyZ3MpO1xuICAgICAgICBhZGRFbnRpdHkodGhpcywgSU5WQUxJRCwgaWQpO1xuICAgICAgICByZXR1cm4gaWQ7XG4gICAgICB9XG4gICAgICBpZCA9IHRoaXMucGsocHJvY2Vzc2VkRW50aXR5LCBwYXJlbnQsIGtleSwgYXJncyk7XG4gICAgICBpZiAoaWQgPT09IHVuZGVmaW5lZCB8fCBpZCA9PT0gJycgfHwgaWQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIC8vIGNyZWF0ZSBhIHJhbmRvbSBpZCBpZiBhIHZhbGlkIG9uZSBjYW5ub3QgYmUgY29tcHV0ZWRcbiAgICAgICAgLy8gdGhpcyBpcyB1c2VmdWwgZm9yIG9wdGltaXN0aWMgY3JlYXRlcyB0aGF0IGRvbid0IG5lZWQgcmVhbCBpZHMgLSBqdXN0IHNvbWV0aGluZyB0byBob2xkIHRoZWlyIHBsYWNlXG4gICAgICAgIGlkID0gYE1JU1MtJHtNYXRoLnJhbmRvbSgpfWA7XG4gICAgICAgIC8vICdjcmVhdGVzJyBjb25jZXB0dWFsbHkgc2hvdWxkIGFsbG93IG1pc3NpbmcgUEsgdG8gbWFrZSBvcHRpbWlzdGljIGNyZWF0ZXMgZWFzeVxuICAgICAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJyAmJiAhdmlzaXQuY3JlYXRpbmcpIHtcbiAgICAgICAgICBsZXQgd2h5OiBzdHJpbmc7XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgISgncGsnIGluIG9wdGlvbnMpICYmXG4gICAgICAgICAgICBFbnRpdHlNaXhpbi5wcm90b3R5cGUucGsgPT09IHRoaXMucHJvdG90eXBlLnBrICYmXG4gICAgICAgICAgICAhKCdpZCcgaW4gcHJvY2Vzc2VkRW50aXR5KVxuICAgICAgICAgICkge1xuICAgICAgICAgICAgd2h5ID0gYCdpZCcgbWlzc2luZyBidXQgbmVlZGVkIGZvciBkZWZhdWx0IHBrKCkuIFRyeSBkZWZpbmluZyBwaygpIGZvciB5b3VyIEVudGl0eS5gO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB3aHkgPSBgVGhpcyBpcyBsaWtlbHkgZHVlIHRvIGEgbWFsZm9ybWVkIHJlc3BvbnNlLlxuICBUcnkgaW5zcGVjdGluZyB0aGUgbmV0d29yayByZXNwb25zZSBvciBmZXRjaCgpIHJldHVybiB2YWx1ZS5cbiAgT3IgdXNlIGRlYnVnZ2luZyB0b29sczogaHR0cHM6Ly9kYXRhY2xpZW50LmlvL2RvY3MvZ2V0dGluZy1zdGFydGVkL2RlYnVnZ2luZ2A7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IGVycm9yID0gbmV3IEVycm9yKFxuICAgICAgICAgICAgYE1pc3NpbmcgdXNhYmxlIHByaW1hcnkga2V5IHdoZW4gbm9ybWFsaXppbmcgcmVzcG9uc2UuXG5cbiAgJHt3aHl9XG4gIExlYXJuIG1vcmUgYWJvdXQgcHJpbWFyeSBrZXlzOiBodHRwczovL2RhdGFjbGllbnQuaW8vcmVzdC9hcGkvRW50aXR5I3BrXG5cbiAgRW50aXR5OiAke3RoaXMua2V5fVxuICBWYWx1ZSAocHJvY2Vzc2VkKTogJHtcbiAgICBwcm9jZXNzZWRFbnRpdHkgJiYgSlNPTi5zdHJpbmdpZnkocHJvY2Vzc2VkRW50aXR5LCBudWxsLCAyKVxuICB9XG5gLFxuICAgICAgICAgICk7XG4gICAgICAgICAgKGVycm9yIGFzIGFueSkuc3RhdHVzID0gNDAwO1xuICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZCA9IGAke2lkfWA7XG4gICAgICB9XG5cbiAgICAgIC8qIENpcmN1bGFyIHJlZmVyZW5jZSBzaG9ydC1jaXJjdWl0ZXIgKi9cbiAgICAgIGlmIChjaGVja0xvb3AodGhpcy5rZXksIGlkLCBpbnB1dCkpIHJldHVybiBpZDtcblxuICAgICAgY29uc3QgZXJyb3JNZXNzYWdlID0gdGhpcy52YWxpZGF0ZShwcm9jZXNzZWRFbnRpdHkpO1xuICAgICAgdGhyb3dWYWxpZGF0aW9uRXJyb3IoZXJyb3JNZXNzYWdlKTtcblxuICAgICAgT2JqZWN0LmtleXModGhpcy5zY2hlbWEpLmZvckVhY2goa2V5ID0+IHtcbiAgICAgICAgaWYgKE9iamVjdC5oYXNPd24ocHJvY2Vzc2VkRW50aXR5LCBrZXkpKSB7XG4gICAgICAgICAgcHJvY2Vzc2VkRW50aXR5W2tleV0gPSB2aXNpdChcbiAgICAgICAgICAgIHRoaXMuc2NoZW1hW2tleV0sXG4gICAgICAgICAgICBwcm9jZXNzZWRFbnRpdHlba2V5XSxcbiAgICAgICAgICAgIHByb2Nlc3NlZEVudGl0eSxcbiAgICAgICAgICAgIGtleSxcbiAgICAgICAgICAgIGFyZ3MsXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIGFkZEVudGl0eSh0aGlzLCBwcm9jZXNzZWRFbnRpdHksIGlkKTtcbiAgICAgIHJldHVybiBpZDtcbiAgICB9XG5cbiAgICBzdGF0aWMgdmFsaWRhdGUocHJvY2Vzc2VkRW50aXR5OiBhbnkpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHN0YXRpYyBxdWVyeUtleShcbiAgICAgIGFyZ3M6IHJlYWRvbmx5IGFueVtdLFxuICAgICAgcXVlcnlLZXk6IGFueSxcbiAgICAgIGdldEVudGl0eTogR2V0RW50aXR5LFxuICAgICAgZ2V0SW5kZXg6IEdldEluZGV4LFxuICAgICk6IGFueSB7XG4gICAgICBpZiAoIWFyZ3NbMF0pIHJldHVybjtcbiAgICAgIGNvbnN0IGlkID0gcXVlcnlLZXlDYW5kaWRhdGUodGhpcywgYXJncywgZ2V0SW5kZXgpO1xuICAgICAgLy8gZW5zdXJlIHRoaXMgYWN0dWFsbHkgaGFzIGVudGl0eSBvciB3ZSBzaG91bGRuJ3QgdHJ5IHRvIHVzZSBpdCBpbiBvdXIgcXVlcnlcbiAgICAgIGlmIChnZXRFbnRpdHkodGhpcy5rZXksIGlkKSkgcmV0dXJuIGlkO1xuICAgIH1cblxuICAgIHN0YXRpYyBkZW5vcm1hbGl6ZTxUIGV4dGVuZHMgdHlwZW9mIEVudGl0eU1peGluPihcbiAgICAgIHRoaXM6IFQsXG4gICAgICBpbnB1dDogYW55LFxuICAgICAgYXJnczogYW55W10sXG4gICAgICB1bnZpc2l0OiAoc2NoZW1hOiBhbnksIGlucHV0OiBhbnkpID0+IGFueSxcbiAgICApOiBBYnN0cmFjdEluc3RhbmNlVHlwZTxUPiB7XG4gICAgICBpZiAodHlwZW9mIGlucHV0ID09PSAnc3ltYm9sJykge1xuICAgICAgICByZXR1cm4gaW5wdXQgYXMgYW55O1xuICAgICAgfVxuXG4gICAgICAvLyBub3RlOiBpdGVyYXRpb24gb3JkZXIgbXVzdCBiZSBzdGFibGVcbiAgICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKHRoaXMuc2NoZW1hKSkge1xuICAgICAgICBjb25zdCBzY2hlbWEgPSB0aGlzLnNjaGVtYVtrZXldO1xuICAgICAgICBjb25zdCB2YWx1ZSA9IHVudmlzaXQoc2NoZW1hLCBpbnB1dFtrZXldKTtcblxuICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3ltYm9sJykge1xuICAgICAgICAgIC8vIGlmIGRlZmF1bHQgaXMgbm90ICdmYWxzeScsIHRoZW4gdGhpcyBpcyByZXF1aXJlZCwgc28gcHJvcGFnYXRlIElOVkFMSUQgc3ltYm9sXG4gICAgICAgICAgaWYgKHRoaXMuZGVmYXVsdHNba2V5XSkge1xuICAgICAgICAgICAgcmV0dXJuIHZhbHVlIGFzIGFueTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaW5wdXRba2V5XSA9IHVuZGVmaW5lZDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpbnB1dFtrZXldID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBpbnB1dDtcbiAgICB9XG5cbiAgICAvKiogQWxsIGluc3RhbmNlIGRlZmF1bHRzIHNldCAqL1xuICAgIHN0YXRpYyBnZXQgZGVmYXVsdHMoKSB7XG4gICAgICAvLyB3ZSB1c2UgaGFzT3duIGJlY2F1c2Ugd2UgZG9uJ3Qgd2FudCB0byB1c2UgYSBwYXJlbnRzJyBkZWZhdWx0c1xuICAgICAgaWYgKCFPYmplY3QuaGFzT3duKHRoaXMsICdfX2RlZmF1bHRzJykpXG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAnX19kZWZhdWx0cycsIHtcbiAgICAgICAgICB2YWx1ZTogbmV3ICh0aGlzIGFzIGFueSkoKSxcbiAgICAgICAgICB3cml0YWJsZTogdHJ1ZSxcbiAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgIH0pO1xuICAgICAgcmV0dXJuICh0aGlzIGFzIGFueSkuX19kZWZhdWx0cztcbiAgICB9XG4gIH1cblxuICBjb25zdCB7IHBrLCBzY2hlbWEsIGtleSwgLi4uc3RhdGljUHJvcHMgfSA9IG9wdGlvbnM7XG4gIC8vIHJlbWFpbmluZyBvcHRpb25zXG4gIE9iamVjdC5hc3NpZ24oRW50aXR5TWl4aW4sIHN0YXRpY1Byb3BzKTtcblxuICBpZiAoJ3NjaGVtYScgaW4gb3B0aW9ucykge1xuICAgIEVudGl0eU1peGluLnNjaGVtYSA9IG9wdGlvbnMuc2NoZW1hIGFzIGFueTtcbiAgfSBlbHNlIGlmICghKEJhc2UgYXMgYW55KS5zY2hlbWEpIHtcbiAgICBFbnRpdHlNaXhpbi5zY2hlbWEgPSB7fTtcbiAgfVxuICBpZiAoJ3BrJyBpbiBvcHRpb25zKSB7XG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLnBrID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICBFbnRpdHlNaXhpbi5wcm90b3R5cGUucGsgPSBmdW5jdGlvbiAocGFyZW50PzogYW55LCBrZXk/OiBzdHJpbmcpIHtcbiAgICAgICAgcmV0dXJuIChvcHRpb25zLnBrIGFzIGFueSkodGhpcywgcGFyZW50LCBrZXkpO1xuICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgRW50aXR5TWl4aW4ucHJvdG90eXBlLnBrID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gKHRoaXMgYXMgYW55KVtvcHRpb25zLnBrXTtcbiAgICAgIH07XG4gICAgfVxuICAgIC8vIGRlZmF1bHQgdG8gJ2lkJyBmaWVsZCBpZiB0aGUgYmFzZSBjbGFzcyBkb2Vzbid0IGhhdmUgYSBwa1xuICB9IGVsc2UgaWYgKHR5cGVvZiBCYXNlLnByb3RvdHlwZS5wayAhPT0gJ2Z1bmN0aW9uJykge1xuICAgIEVudGl0eU1peGluLnByb3RvdHlwZS5wayA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiAodGhpcyBhcyBhbnkpLmlkO1xuICAgIH07XG4gIH1cbiAgaWYgKCdrZXknIGluIG9wdGlvbnMpIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRW50aXR5TWl4aW4sICdrZXknLCB7XG4gICAgICB2YWx1ZTogb3B0aW9ucy5rZXksXG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICB3cml0YWJsZTogdHJ1ZSxcbiAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgfSk7XG4gIH0gZWxzZSBpZiAoISgna2V5JyBpbiBCYXNlKSkge1xuICAgIGZ1bmN0aW9uIHNldCh0aGlzOiBhbnksIHZhbHVlOiBzdHJpbmcpIHtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCAna2V5Jywge1xuICAgICAgICB2YWx1ZSxcbiAgICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgIH0pO1xuICAgIH1cbiAgICBjb25zdCBiYXNlR2V0ID0gZnVuY3Rpb24gKHRoaXM6IHsgbmFtZTogc3RyaW5nIH0pOiBzdHJpbmcge1xuICAgICAgY29uc3QgbmFtZSA9IHRoaXMubmFtZSA9PT0gJ0VudGl0eU1peGluJyA/IEJhc2UubmFtZSA6IHRoaXMubmFtZTtcbiAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICBpZiAoXG4gICAgICAgIHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicgJiZcbiAgICAgICAgKG5hbWUgPT09ICcnIHx8IG5hbWUgPT09ICdFbnRpdHlNaXhpbicgfHwgbmFtZSA9PT0gJ190ZW1wJylcbiAgICAgIClcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICdFbnRpdHkgY2xhc3NlcyB3aXRob3V0IGEgbmFtZSBtdXN0IGRlZmluZSBgc3RhdGljIGtleWBcXG5TZWU6IGh0dHBzOi8vZGF0YWNsaWVudC5pby9yZXN0L2FwaS9FbnRpdHkja2V5JyxcbiAgICAgICAgKTtcbiAgICAgIHJldHVybiBuYW1lO1xuICAgIH07XG4gICAgY29uc3QgZ2V0ID1cbiAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBpZiAqL1xuICAgICAgdHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJyAmJiAoZG9jdW1lbnQgYXMgYW55KS5DTFNfTUFOR0xFID9cbiAgICAgICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi8gZnVuY3Rpb24gKHRoaXM6IHtcbiAgICAgICAgICBuYW1lOiBzdHJpbmc7XG4gICAgICAgICAga2V5OiBzdHJpbmc7XG4gICAgICAgIH0pOiBzdHJpbmcge1xuICAgICAgICAgIChkb2N1bWVudCBhcyBhbnkpLkNMU19NQU5HTEU/Lih0aGlzKTtcbiAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRW50aXR5TWl4aW4sICdrZXknLCB7XG4gICAgICAgICAgICBnZXQ6IGJhc2VHZXQsXG4gICAgICAgICAgICBzZXQsXG4gICAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHJldHVybiBiYXNlR2V0LmNhbGwodGhpcyk7XG4gICAgICAgIH1cbiAgICAgIDogYmFzZUdldDtcblxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShFbnRpdHlNaXhpbiwgJ2tleScsIHtcbiAgICAgIGdldCxcbiAgICAgIHNldCxcbiAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gRW50aXR5TWl4aW4gYXMgYW55O1xufVxuXG5mdW5jdGlvbiBpbmRleEZyb21QYXJhbXM8SSBleHRlbmRzIHN0cmluZz4oXG4gIHBhcmFtczogUmVhZG9ubHk8b2JqZWN0PixcbiAgaW5kZXhlcz86IFJlYWRvbmx5PElbXT4sXG4pIHtcbiAgaWYgKCFpbmRleGVzKSByZXR1cm4gdW5kZWZpbmVkO1xuICByZXR1cm4gaW5kZXhlcy5maW5kKGluZGV4ID0+IE9iamVjdC5oYXNPd24ocGFyYW1zLCBpbmRleCkpO1xufVxuXG4vLyBwYXJ0IG9mIHRoZSByZWFzb24gZm9yIHB1bGxpbmcgdGhpcyBvdXQgaXMgdGhhdCBhbGwgZnVuY3Rpb25zIHRoYXQgdGhyb3cgYXJlIGRlb3B0aW1pemVkXG5mdW5jdGlvbiB0aHJvd1ZhbGlkYXRpb25FcnJvcihlcnJvck1lc3NhZ2U6IHN0cmluZyB8IHVuZGVmaW5lZCkge1xuICBpZiAoZXJyb3JNZXNzYWdlKSB7XG4gICAgY29uc3QgZXJyb3IgPSBuZXcgRXJyb3IoZXJyb3JNZXNzYWdlKTtcbiAgICAoZXJyb3IgYXMgYW55KS5zdGF0dXMgPSA0MDA7XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cbn1cblxuZnVuY3Rpb24gcXVlcnlLZXlDYW5kaWRhdGUoXG4gIHNjaGVtYTogYW55LFxuICBhcmdzOiByZWFkb25seSBhbnlbXSxcbiAgZ2V0SW5kZXg6IEdldEluZGV4LFxuKSB7XG4gIGlmIChbJ3N0cmluZycsICdudW1iZXInXS5pbmNsdWRlcyh0eXBlb2YgYXJnc1swXSkpIHtcbiAgICByZXR1cm4gYCR7YXJnc1swXX1gO1xuICB9XG4gIGNvbnN0IGlkID0gc2NoZW1hLnBrKGFyZ3NbMF0sIHVuZGVmaW5lZCwgJycsIGFyZ3MpO1xuICAvLyBXYXMgYWJsZSB0byBpbmZlciB0aGUgZW50aXR5J3MgcHJpbWFyeSBrZXkgZnJvbSBwYXJhbXNcbiAgaWYgKGlkICE9PSB1bmRlZmluZWQgJiYgaWQgIT09ICcnKSByZXR1cm4gaWQ7XG4gIC8vIG5vdyBhdHRlbXB0IGxvb2t1cCBpbiBpbmRleGVzXG4gIGNvbnN0IGluZGV4TmFtZSA9IGluZGV4RnJvbVBhcmFtcyhhcmdzWzBdLCBzY2hlbWEuaW5kZXhlcyk7XG4gIGlmICghaW5kZXhOYW1lKSByZXR1cm47XG4gIGNvbnN0IHZhbHVlID0gKGFyZ3NbMF0gYXMgUmVjb3JkPHN0cmluZywgYW55PilbaW5kZXhOYW1lXTtcbiAgcmV0dXJuIGdldEluZGV4KHNjaGVtYS5rZXksIGluZGV4TmFtZSwgdmFsdWUpW3ZhbHVlXTtcbn1cbiJdLCJtYXBwaW5ncyI6IkFBUUEsU0FBU0EsT0FBTyxRQUFRLGVBQWU7O0FBV3ZDO0FBQ0E7QUFDQTtBQUNBOztBQU1BOztBQU1BOztBQU1BLGVBQWUsU0FBU0MsV0FBV0EsQ0FDakNDLElBQVcsRUFDWEMsT0FBMkMsR0FBRyxDQUFDLENBQUMsRUFDaEQ7RUFDQTtBQUNGO0FBQ0E7QUFDQTtFQUNFLE1BQWVGLFdBQVcsU0FBU0MsSUFBSSxDQUFDO0lBQ3RDLE9BQU9FLFFBQVFBLENBQUEsRUFBRztNQUNoQixPQUFPLElBQUksQ0FBQ0MsR0FBRztJQUNqQjtJQUVBLE9BQU9DLE1BQU1BLENBQUEsRUFBRztNQUNkLE9BQU87UUFDTEQsR0FBRyxFQUFFLElBQUksQ0FBQ0EsR0FBRztRQUNiRSxNQUFNLEVBQUUsSUFBSSxDQUFDQTtNQUNmLENBQUM7SUFDSDs7SUFFQTs7SUFHQTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztJQU9JOztJQUVBOztJQUVBOztJQUdBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtJQUNJLE9BQU9DLEVBQUVBLENBRVBDLEtBQXVDLEVBQ3ZDQyxNQUFZLEVBQ1pMLEdBQVksRUFDWk0sSUFBcUIsRUFDUTtNQUM3QixPQUFPLElBQUksQ0FBQ0MsU0FBUyxDQUFDSixFQUFFLENBQUNLLElBQUksQ0FBQ0osS0FBSyxFQUFFQyxNQUFNLEVBQUVMLEdBQUcsRUFBRU0sSUFBSSxDQUFDO0lBQ3pEOztJQUVBO0FBQ0o7QUFDQTtBQUNBO0lBQ0ksT0FBT0csWUFBWUEsQ0FDakJDLFlBQWlELEVBQ2pEQyxZQUFpRCxFQUNqREMsUUFBYSxFQUNiQyxRQUFhLEVBQ2I7TUFD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