@data-client/endpoint
Version:
Declarative Network Interface Definitions
332 lines (308 loc) • 44.6 kB
JavaScript
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
import _extends from "@babel/runtime/helpers/esm/extends";
const _excluded = ["pk", "schema", "key"];
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 _extends({}, 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 _extends({}, 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 staticProps = _objectWithoutPropertiesLoose(options, _excluded);
// 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 baseGet() {
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,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJJTlZBTElEIiwiRW50aXR5TWl4aW4iLCJCYXNlIiwib3B0aW9ucyIsInRvU3RyaW5nIiwia2V5IiwidG9KU09OIiwic2NoZW1hIiwicGsiLCJ2YWx1ZSIsInBhcmVudCIsImFyZ3MiLCJwcm90b3R5cGUiLCJjYWxsIiwic2hvdWxkVXBkYXRlIiwiZXhpc3RpbmdNZXRhIiwiaW5jb21pbmdNZXRhIiwiZXhpc3RpbmciLCJpbmNvbWluZyIsInNob3VsZFJlb3JkZXIiLCJmZXRjaGVkQXQiLCJtZXJnZSIsIl9leHRlbmRzIiwibWVyZ2VXaXRoU3RvcmUiLCJtZXJnZU1ldGFXaXRoU3RvcmUiLCJmcm9tSlMiLCJwcm9wcyIsImluc3RhbmNlIiwiT2JqZWN0IiwiYXNzaWduIiwiY3JlYXRlSWZWYWxpZCIsInZhbGlkYXRlIiwidW5kZWZpbmVkIiwicHJvY2VzcyIsImlucHV0Iiwibm9ybWFsaXplIiwidmlzaXQiLCJhZGRFbnRpdHkiLCJnZXRFbnRpdHkiLCJjaGVja0xvb3AiLCJwcm9jZXNzZWRFbnRpdHkiLCJpZCIsIk1hdGgiLCJyYW5kb20iLCJlbnYiLCJOT0RFX0VOViIsImNyZWF0aW5nIiwid2h5IiwiZXJyb3IiLCJFcnJvciIsIkpTT04iLCJzdHJpbmdpZnkiLCJzdGF0dXMiLCJlcnJvck1lc3NhZ2UiLCJ0aHJvd1ZhbGlkYXRpb25FcnJvciIsImtleXMiLCJmb3JFYWNoIiwiaGFzT3duIiwicXVlcnlLZXkiLCJnZXRJbmRleCIsInF1ZXJ5S2V5Q2FuZGlkYXRlIiwiZGVub3JtYWxpemUiLCJ1bnZpc2l0IiwiZGVmYXVsdHMiLCJkZWZpbmVQcm9wZXJ0eSIsIndyaXRhYmxlIiwiY29uZmlndXJhYmxlIiwiX19kZWZhdWx0cyIsInN0YXRpY1Byb3BzIiwiX29iamVjdFdpdGhvdXRQcm9wZXJ0aWVzTG9vc2UiLCJfZXhjbHVkZWQiLCJlbnVtZXJhYmxlIiwic2V0IiwiYmFzZUdldCIsIm5hbWUiLCJnZXQiLCJkb2N1bWVudCIsIkNMU19NQU5HTEUiLCJpbmRleEZyb21QYXJhbXMiLCJwYXJhbXMiLCJpbmRleGVzIiwiZmluZCIsImluZGV4IiwiaW5jbHVkZXMiLCJpbmRleE5hbWUiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvc2NoZW1hcy9FbnRpdHlNaXhpbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7XG4gIFNjaGVtYSxcbiAgR2V0SW5kZXgsXG4gIEdldEVudGl0eSxcbiAgQ2hlY2tMb29wLFxuICBWaXNpdCxcbn0gZnJvbSAnLi4vaW50ZXJmYWNlLmpzJztcbmltcG9ydCB7IEFic3RyYWN0SW5zdGFuY2VUeXBlIH0gZnJvbSAnLi4vbm9ybWFsLmpzJztcbmltcG9ydCB7IElOVkFMSUQgfSBmcm9tICcuLi9zcGVjaWFsLmpzJztcbmltcG9ydCB0eXBlIHtcbiAgSUVudGl0eUNsYXNzLFxuICBJRW50aXR5SW5zdGFuY2UsXG4gIEVudGl0eU9wdGlvbnMsXG4gIFJlcXVpcmVkUEtPcHRpb25zLFxuICBJRENsYXNzLFxuICBDb25zdHJ1Y3RvcixcbiAgUEtDbGFzcyxcbn0gZnJvbSAnLi9FbnRpdHlUeXBlcy5qcyc7XG5cbi8qKlxuICogVHVybnMgYW55IGNsYXNzIGludG8gYW4gRW50aXR5LlxuICogQHNlZSBodHRwczovL2RhdGFjbGllbnQuaW8vcmVzdC9hcGkvRW50aXR5TWl4aW5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gRW50aXR5TWl4aW48VEJhc2UgZXh0ZW5kcyBQS0NsYXNzPihcbiAgQmFzZTogVEJhc2UsXG4gIG9wdD86IEVudGl0eU9wdGlvbnM8SW5zdGFuY2VUeXBlPFRCYXNlPj4sXG4pOiBJRW50aXR5Q2xhc3M8VEJhc2U+ICYgVEJhc2U7XG5cbi8vIGlkIGlzIGluIEluc3RhbmNlLCBzbyB3ZSBkZWZhdWx0IHRvIHRoYXQgYXMgcGtcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIEVudGl0eU1peGluPFRCYXNlIGV4dGVuZHMgSURDbGFzcz4oXG4gIEJhc2U6IFRCYXNlLFxuICBvcHQ/OiBFbnRpdHlPcHRpb25zPEluc3RhbmNlVHlwZTxUQmFzZT4+LFxuKTogSUVudGl0eUNsYXNzPFRCYXNlPiAmIFRCYXNlICYgKG5ldyAoLi4uYXJnczogYW55W10pID0+IElFbnRpdHlJbnN0YW5jZSk7XG5cbi8vIHBrIHdhcyBzcGVjaWZpZWQgaW4gb3B0aW9ucywgc28gd2UgZG9uJ3QgbmVlZCB0byByZWRlZmluZVxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gRW50aXR5TWl4aW48VEJhc2UgZXh0ZW5kcyBDb25zdHJ1Y3Rvcj4oXG4gIEJhc2U6IFRCYXNlLFxuICBvcHQ6IFJlcXVpcmVkUEtPcHRpb25zPEluc3RhbmNlVHlwZTxUQmFzZT4+LFxuKTogSUVudGl0eUNsYXNzPFRCYXNlPiAmIFRCYXNlICYgKG5ldyAoLi4uYXJnczogYW55W10pID0+IElFbnRpdHlJbnN0YW5jZSk7XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIEVudGl0eU1peGluPFRCYXNlIGV4dGVuZHMgQ29uc3RydWN0b3I+KFxuICBCYXNlOiBUQmFzZSxcbiAgb3B0aW9uczogRW50aXR5T3B0aW9uczxJbnN0YW5jZVR5cGU8VEJhc2U+PiA9IHt9LFxuKSB7XG4gIC8qKlxuICAgKiBFbnRpdHkgZGVmaW5lcyBhIHNpbmdsZSAoZ2xvYmFsbHkpIHVuaXF1ZSBvYmplY3QuXG4gICAqIEBzZWUgaHR0cHM6Ly9kYXRhY2xpZW50LmlvL3Jlc3QvYXBpL0VudGl0eVxuICAgKi9cbiAgYWJzdHJhY3QgY2xhc3MgRW50aXR5TWl4aW4gZXh0ZW5kcyBCYXNlIHtcbiAgICBzdGF0aWMgdG9TdHJpbmcoKSB7XG4gICAgICByZXR1cm4gdGhpcy5rZXk7XG4gICAgfVxuXG4gICAgc3RhdGljIHRvSlNPTigpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGtleTogdGhpcy5rZXksXG4gICAgICAgIHNjaGVtYTogdGhpcy5zY2hlbWEsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8qKiBEZWZpbmVzIG5lc3RlZCBlbnRpdGllcyAqL1xuICAgIGRlY2xhcmUgc3RhdGljIHNjaGVtYTogeyBbazogc3RyaW5nXTogU2NoZW1hIH07XG5cbiAgICAvKipcbiAgICAgKiBBIHVuaXF1ZSBpZGVudGlmaWVyIGZvciBlYWNoIEVudGl0eVxuICAgICAqXG4gICAgICogQHNlZSBodHRwczovL2RhdGFjbGllbnQuaW8vcmVzdC9hcGkvRW50aXR5I3BrXG4gICAgICogQHBhcmFtIFtwYXJlbnRdIFdoZW4gbm9ybWFsaXppbmcsIHRoZSBvYmplY3Qgd2hpY2ggaW5jbHVkZWQgdGhlIGVudGl0eVxuICAgICAqIEBwYXJhbSBba2V5XSBXaGVuIG5vcm1hbGl6aW5nLCB0aGUga2V5IHdoZXJlIHRoaXMgZW50aXR5IHdhcyBmb3VuZFxuICAgICAqIEBwYXJhbSBbYXJnc10gLi4uYXJncyBzZW50IHRvIEVuZHBvaW50XG4gICAgICovXG4gICAgZGVjbGFyZSBwazogKFxuICAgICAgcGFyZW50PzogYW55LFxuICAgICAga2V5Pzogc3RyaW5nLFxuICAgICAgYXJncz86IHJlYWRvbmx5IGFueVtdLFxuICAgICkgPT4gc3RyaW5nIHwgbnVtYmVyIHwgdW5kZWZpbmVkO1xuXG4gICAgLyoqIFJldHVybnMgdGhlIGdsb2JhbGx5IHVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgc3RhdGljIEVudGl0eSAqL1xuICAgIGRlY2xhcmUgc3RhdGljIGtleTogc3RyaW5nO1xuICAgIC8vIGRlZmF1bHQgaW1wbGVtZW50YXRpb24gaW4gY2xhc3Mgc3RhdGljIGJsb2NrIGF0IGJvdHRvbSBvZiBkZWZpbml0aW9uXG5cbiAgICAvKiogRGVmaW5lcyBpbmRleGVzIHRvIGVuYWJsZSBsb29rdXAgYnkgKi9cbiAgICBkZWNsYXJlIHN0YXRpYyBpbmRleGVzPzogcmVhZG9ubHkgc3RyaW5nW107XG5cbiAgICAvKipcbiAgICAgKiBBIHVuaXF1ZSBpZGVudGlmaWVyIGZvciBlYWNoIEVudGl0eVxuICAgICAqXG4gICAgICogQHNlZSBodHRwczovL2RhdGFjbGllbnQuaW8vcmVzdC9hcGkvRW50aXR5I3BrXG4gICAgICogQHBhcmFtIFt2YWx1ZV0gUE9KTyBvZiB0aGUgZW50aXR5IG9yIHN1YnNldCB1c2VkXG4gICAgICogQHBhcmFtIFtwYXJlbnRdIFdoZW4gbm9ybWFsaXppbmcsIHRoZSBvYmplY3Qgd2hpY2ggaW5jbHVkZWQgdGhlIGVudGl0eVxuICAgICAqIEBwYXJhbSBba2V5XSBXaGVuIG5vcm1hbGl6aW5nLCB0aGUga2V5IHdoZXJlIHRoaXMgZW50aXR5IHdhcyBmb3VuZFxuICAgICAqIEBwYXJhbSBbYXJnc10gLi4uYXJncyBzZW50IHRvIEVuZHBvaW50XG4gICAgICovXG4gICAgc3RhdGljIHBrPFQgZXh0ZW5kcyB0eXBlb2YgRW50aXR5TWl4aW4+KFxuICAgICAgdGhpczogVCxcbiAgICAgIHZhbHVlOiBQYXJ0aWFsPEFic3RyYWN0SW5zdGFuY2VUeXBlPFQ+PixcbiAgICAgIHBhcmVudD86IGFueSxcbiAgICAgIGtleT86IHN0cmluZyxcbiAgICAgIGFyZ3M/OiByZWFkb25seSBhbnlbXSxcbiAgICApOiBzdHJpbmcgfCBudW1iZXIgfCB1bmRlZmluZWQge1xuICAgICAgcmV0dXJuIHRoaXMucHJvdG90eXBlLnBrLmNhbGwodmFsdWUsIHBhcmVudCwga2V5LCBhcmdzKTtcbiAgICB9XG5cbiAgICAvKiogUmV0dXJuIHRydWUgdG8gbWVyZ2UgaW5jb21pbmcgZGF0YTsgZmFsc2Uga2VlcHMgZXhpc3RpbmcgZW50aXR5XG4gICAgICpcbiAgICAgKiBAc2VlIGh0dHBzOi8vZGF0YWNsaWVudC5pby9yZXN0L2FwaS9FbnRpdHkjc2hvdWxkVXBkYXRlXG4gICAgICovXG4gICAgc3RhdGljIHNob3VsZFVwZGF0ZShcbiAgICAgIGV4aXN0aW5nTWV0YTogeyBkYXRlOiBudW1iZXI7IGZldGNoZWRBdDogbnVtYmVyIH0sXG4gICAgICBpbmNvbWluZ01ldGE6IHsgZGF0ZTogbnVtYmVyOyBmZXRjaGVkQXQ6IG51bWJlciB9LFxuICAgICAgZXhpc3Rpbmc6IGFueSxcbiAgICAgIGluY29taW5nOiBhbnksXG4gICAgKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvKiogRGV0ZXJtaW5lcyB0aGUgb3JkZXIgb2YgaW5jb21pbmcgZW50aXR5IHZzIGVudGl0eSBhbHJlYWR5IGluIHN0b3JlXFxcbiAgICAgKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kYXRhY2xpZW50LmlvL3Jlc3QvYXBpL0VudGl0eSNzaG91bGRSZW9yZGVyXG4gICAgICogQHJldHVybnMgdHJ1ZSBpZiBpbmNvbWluZyBlbnRpdHkgc2hvdWxkIGJlIGZpcnN0IGFyZ3VtZW50IG9mIG1lcmdlKClcbiAgICAgKi9cbiAgICBzdGF0aWMgc2hvdWxkUmVvcmRlcihcbiAgICAgIGV4aXN0aW5nTWV0YTogeyBkYXRlOiBudW1iZXI7IGZldGNoZWRBdDogbnVtYmVyIH0sXG4gICAgICBpbmNvbWluZ01ldGE6IHsgZGF0ZTogbnVtYmVyOyBmZXRjaGVkQXQ6IG51bWJlciB9LFxuICAgICAgZXhpc3Rpbmc6IGFueSxcbiAgICAgIGluY29taW5nOiBhbnksXG4gICAgKSB7XG4gICAgICByZXR1cm4gaW5jb21pbmdNZXRhLmZldGNoZWRBdCA8IGV4aXN0aW5nTWV0YS5mZXRjaGVkQXQ7XG4gICAgfVxuXG4gICAgLyoqIENyZWF0ZXMgbmV3IGluc3RhbmNlIGNvcHlpbmcgb3ZlciBkZWZpbmVkIHZhbHVlcyBvZiBhcmd1bWVudHNcbiAgICAgKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kYXRhY2xpZW50LmlvL3Jlc3QvYXBpL0VudGl0eSNtZXJnZVxuICAgICAqL1xuICAgIHN0YXRpYyBtZXJnZShleGlzdGluZzogYW55LCBpbmNvbWluZzogYW55KSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICAuLi5leGlzdGluZyxcbiAgICAgICAgLi4uaW5jb21pbmcsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8qKiBSdW4gd2hlbiBhbiBleGlzdGluZyBlbnRpdHkgaXMgZm91bmQgaW4gdGhlIHN0b3JlXG4gICAgICpcbiAgICAgKiBAc2VlIGh0dHBzOi8vZGF0YWNsaWVudC5pby9yZXN0L2FwaS9FbnRpdHkjbWVyZ2VXaXRoU3RvcmVcbiAgICAgKi9cbiAgICBzdGF0aWMgbWVyZ2VXaXRoU3RvcmUoXG4gICAgICBleGlzdGluZ01ldGE6IHtcbiAgICAgICAgZGF0ZTogbnVtYmVyO1xuICAgICAgICBmZXRjaGVkQXQ6IG51bWJlcjtcbiAgICAgIH0sXG4gICAgICBpbmNvbWluZ01ldGE6IHsgZGF0ZTogbnVtYmVyOyBmZXRjaGVkQXQ6IG51bWJlciB9LFxuICAgICAgZXhpc3Rpbmc6IGFueSxcbiAgICAgIGluY29taW5nOiBhbnksXG4gICAgKSB7XG4gICAgICBjb25zdCBzaG91bGRVcGRhdGUgPSB0aGlzLnNob3VsZFVwZGF0ZShcbiAgICAgICAgZXhpc3RpbmdNZXRhLFxuICAgICAgICBpbmNvbWluZ01ldGEsXG4gICAgICAgIGV4aXN0aW5nLFxuICAgICAgICBpbmNvbWluZyxcbiAgICAgICk7XG5cbiAgICAgIGlmIChzaG91bGRVcGRhdGUpIHtcbiAgICAgICAgLy8gZGlzdGluY3QgdHlwZXMgYXJlIG5vdCBtZXJnZWFibGUgKGxpa2UgZGVsZXRlIHN5bWJvbCksIHNvIGp1c3QgcmVwbGFjZVxuICAgICAgICBpZiAodHlwZW9mIGluY29taW5nICE9PSB0eXBlb2YgZXhpc3RpbmcpIHtcbiAgICAgICAgICByZXR1cm4gaW5jb21pbmc7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgdGhpcy5zaG91bGRSZW9yZGVyKGV4aXN0aW5nTWV0YSwgaW5jb21pbmdNZXRhLCBleGlzdGluZywgaW5jb21pbmcpXG4gICAgICAgICAgICApID9cbiAgICAgICAgICAgICAgdGhpcy5tZXJnZShpbmNvbWluZywgZXhpc3RpbmcpXG4gICAgICAgICAgICA6IHRoaXMubWVyZ2UoZXhpc3RpbmcsIGluY29taW5nKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGV4aXN0aW5nO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBSdW4gd2hlbiBhbiBleGlzdGluZyBlbnRpdHkgaXMgZm91bmQgaW4gdGhlIHN0b3JlXG4gICAgICpcbiAgICAgKiBAc2VlIGh0dHBzOi8vZGF0YWNsaWVudC5pby9yZXN0L2FwaS9FbnRpdHkjbWVyZ2VNZXRhV2l0aFN0b3JlXG4gICAgICovXG4gICAgc3RhdGljIG1lcmdlTWV0YVdpdGhTdG9yZShcbiAgICAgIGV4aXN0aW5nTWV0YToge1xuICAgICAgICBmZXRjaGVkQXQ6IG51bWJlcjtcbiAgICAgICAgZGF0ZTogbnVtYmVyO1xuICAgICAgICBleHBpcmVzQXQ6IG51bWJlcjtcbiAgICAgIH0sXG4gICAgICBpbmNvbWluZ01ldGE6IHsgZmV0Y2hlZEF0OiBudW1iZXI7IGRhdGU6IG51bWJlcjsgZXhwaXJlc0F0OiBudW1iZXIgfSxcbiAgICAgIGV4aXN0aW5nOiBhbnksXG4gICAgICBpbmNvbWluZzogYW55LFxuICAgICkge1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgICB0aGlzLnNob3VsZFJlb3JkZXIoZXhpc3RpbmdNZXRhLCBpbmNvbWluZ01ldGEsIGV4aXN0aW5nLCBpbmNvbWluZylcbiAgICAgICAgKSA/XG4gICAgICAgICAgZXhpc3RpbmdNZXRhXG4gICAgICAgIDogaW5jb21pbmdNZXRhO1xuICAgIH1cblxuICAgIC8qKiBGYWN0b3J5IG1ldGhvZCB0byBjb252ZXJ0IGZyb20gUGxhaW4gSlMgT2JqZWN0cy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBbcHJvcHNdIFBsYWluIE9iamVjdCBvZiBwcm9wZXJ0aWVzIHRvIGFzc2lnbi5cbiAgICAgKi9cbiAgICBzdGF0aWMgZnJvbUpTPFQgZXh0ZW5kcyB0eXBlb2YgRW50aXR5TWl4aW4+KFxuICAgICAgdGhpczogVCxcbiAgICAgIC8vIFRPRE86IHRoaXMgc2hvdWxkIG9ubHkgYWNjZXB0IG1lbWJlcnMgdGhhdCBhcmUgbm90IGZ1bmN0aW9uc1xuICAgICAgcHJvcHM6IFBhcnRpYWw8QWJzdHJhY3RJbnN0YW5jZVR5cGU8VD4+ID0ge30sXG4gICAgKTogQWJzdHJhY3RJbnN0YW5jZVR5cGU8VD4ge1xuICAgICAgLy8gd2UgdHlwZSBndWFyZGVkIGFic3RyYWN0IGNhc2UgYWJvdmUsIHNvIG9rIHRvIGZvcmNlIHR5cGVzY3JpcHQgdG8gYWxsb3cgY29uc3RydWN0b3IgY2FsbFxuICAgICAgY29uc3QgaW5zdGFuY2UgPSBuZXcgKHRoaXMgYXMgYW55KShwcm9wcykgYXMgQWJzdHJhY3RJbnN0YW5jZVR5cGU8VD47XG4gICAgICAvLyB3ZSBjYW4ndCByZWx5IG9uIGNvbnN0cnVjdG9ycyBhbmQgb3ZlcnJpZGUgdGhlIGRlZmF1bHRzIHByb3ZpZGVkIGFzIHByb3BlcnR5IGFzc2lnbm1lbnRzXG4gICAgICAvLyBhbGwgb2NjdXIgYWZ0ZXIgdGhlIGNvbnN0cnVjdG9yXG4gICAgICBPYmplY3QuYXNzaWduKGluc3RhbmNlLCBwcm9wcyk7XG4gICAgICByZXR1cm4gaW5zdGFuY2U7XG4gICAgfVxuXG4gICAgLyoqIENhbGxlZCB3aGVuIGRlbm9ybWFsaXppbmcgYW4gZW50aXR5IHRvIGNyZWF0ZSBhbiBpbnN0YW5jZSB3aGVuICd2YWxpZCdcbiAgICAgKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kYXRhY2xpZW50LmlvL3Jlc3QvYXBpL0VudGl0eSNjcmVhdGVJZlZhbGlkXG4gICAgICogQHBhcmFtIFtwcm9wc10gUGxhaW4gT2JqZWN0IG9mIHByb3BlcnRpZXMgdG8gYXNzaWduLlxuICAgICAqL1xuICAgIHN0YXRpYyBjcmVhdGVJZlZhbGlkPFQgZXh0ZW5kcyB0eXBlb2YgRW50aXR5TWl4aW4+KFxuICAgICAgdGhpczogVCxcbiAgICAgIC8vIFRPRE86IHRoaXMgc2hvdWxkIG9ubHkgYWNjZXB0IG1lbWJlcnMgdGhhdCBhcmUgbm90IGZ1bmN0aW9uc1xuICAgICAgcHJvcHM6IFBhcnRpYWw8QWJzdHJhY3RJbnN0YW5jZVR5cGU8VD4+LFxuICAgICk6IEFic3RyYWN0SW5zdGFuY2VUeXBlPFQ+IHwgdW5kZWZpbmVkIHtcbiAgICAgIGlmICh0aGlzLnZhbGlkYXRlKHByb3BzKSkge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkIGFzIGFueTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLmZyb21KUyhwcm9wcyk7XG4gICAgfVxuXG4gICAgLyoqIERvIGFueSB0cmFuc2Zvcm1hdGlvbnMgd2hlbiBmaXJzdCByZWNlaXZpbmcgaW5wdXRcbiAgICAgKlxuICAgICAqIEBzZWUgaHR0cHM6Ly9kYXRhY2xpZW50LmlvL3Jlc3QvYXBpL0VudGl0eSNwcm9jZXNzXG4gICAgICovXG4gICAgc3RhdGljIHByb2Nlc3MoXG4gICAgICBpbnB1dDogYW55LFxuICAgICAgcGFyZW50OiBhbnksXG4gICAgICBrZXk6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICAgIGFyZ3M6IGFueSxcbiAgICApOiBhbnkge1xuICAgICAgcmV0dXJuIHsgLi4uaW5wdXQgfTtcbiAgICB9XG5cbiAgICBzdGF0aWMgbm9ybWFsaXplKFxuICAgICAgaW5wdXQ6IGFueSxcbiAgICAgIHBhcmVudDogYW55LFxuICAgICAga2V5OiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgICBhcmdzOiByZWFkb25seSBhbnlbXSxcbiAgICAgIHZpc2l0OiBWaXNpdCxcbiAgICAgIGFkZEVudGl0eTogKC4uLmFyZ3M6IGFueSkgPT4gYW55LFxuICAgICAgZ2V0RW50aXR5OiBHZXRFbnRpdHksXG4gICAgICBjaGVja0xvb3A6IENoZWNrTG9vcCxcbiAgICApOiBhbnkge1xuICAgICAgY29uc3QgcHJvY2Vzc2VkRW50aXR5ID0gdGhpcy5wcm9jZXNzKGlucHV0LCBwYXJlbnQsIGtleSwgYXJncyk7XG4gICAgICBsZXQgaWQ6IHN0cmluZyB8IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgICAgIGlmICh0eXBlb2YgcHJvY2Vzc2VkRW50aXR5ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICBpZCA9IHRoaXMucGsoaW5wdXQsIHBhcmVudCwga2V5LCBhcmdzKTtcbiAgICAgICAgYWRkRW50aXR5KHRoaXMsIElOVkFMSUQsIGlkKTtcbiAgICAgICAgcmV0dXJuIGlkO1xuICAgICAgfVxuICAgICAgaWQgPSB0aGlzLnBrKHByb2Nlc3NlZEVudGl0eSwgcGFyZW50LCBrZXksIGFyZ3MpO1xuICAgICAgaWYgKGlkID09PSB1bmRlZmluZWQgfHwgaWQgPT09ICcnIHx8IGlkID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAvLyBjcmVhdGUgYSByYW5kb20gaWQgaWYgYSB2YWxpZCBvbmUgY2Fubm90IGJlIGNvbXB1dGVkXG4gICAgICAgIC8vIHRoaXMgaXMgdXNlZnVsIGZvciBvcHRpbWlzdGljIGNyZWF0ZXMgdGhhdCBkb24ndCBuZWVkIHJlYWwgaWRzIC0ganVzdCBzb21ldGhpbmcgdG8gaG9sZCB0aGVpciBwbGFjZVxuICAgICAgICBpZCA9IGBNSVNTLSR7TWF0aC5yYW5kb20oKX1gO1xuICAgICAgICAvLyAnY3JlYXRlcycgY29uY2VwdHVhbGx5IHNob3VsZCBhbGxvdyBtaXNzaW5nIFBLIHRvIG1ha2Ugb3B0aW1pc3RpYyBjcmVhdGVzIGVhc3lcbiAgICAgICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicgJiYgIXZpc2l0LmNyZWF0aW5nKSB7XG4gICAgICAgICAgbGV0IHdoeTogc3RyaW5nO1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICEoJ3BrJyBpbiBvcHRpb25zKSAmJlxuICAgICAgICAgICAgRW50aXR5TWl4aW4ucHJvdG90eXBlLnBrID09PSB0aGlzLnByb3RvdHlwZS5wayAmJlxuICAgICAgICAgICAgISgnaWQnIGluIHByb2Nlc3NlZEVudGl0eSlcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIHdoeSA9IGAnaWQnIG1pc3NpbmcgYnV0IG5lZWRlZCBmb3IgZGVmYXVsdCBwaygpLiBUcnkgZGVmaW5pbmcgcGsoKSBmb3IgeW91ciBFbnRpdHkuYDtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgd2h5ID0gYFRoaXMgaXMgbGlrZWx5IGR1ZSB0byBhIG1hbGZvcm1lZCByZXNwb25zZS5cbiAgVHJ5IGluc3BlY3RpbmcgdGhlIG5ldHdvcmsgcmVzcG9uc2Ugb3IgZmV0Y2goKSByZXR1cm4gdmFsdWUuXG4gIE9yIHVzZSBkZWJ1Z2dpbmcgdG9vbHM6IGh0dHBzOi8vZGF0YWNsaWVudC5pby9kb2NzL2dldHRpbmctc3RhcnRlZC9kZWJ1Z2dpbmdgO1xuICAgICAgICAgIH1cbiAgICAgICAgICBjb25zdCBlcnJvciA9IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBNaXNzaW5nIHVzYWJsZSBwcmltYXJ5IGtleSB3aGVuIG5vcm1hbGl6aW5nIHJlc3BvbnNlLlxuXG4gICR7d2h5fVxuICBMZWFybiBtb3JlIGFib3V0IHByaW1hcnkga2V5czogaHR0cHM6Ly9kYXRhY2xpZW50LmlvL3Jlc3QvYXBpL0VudGl0eSNwa1xuXG4gIEVudGl0eTogJHt0aGlzLmtleX1cbiAgVmFsdWUgKHByb2Nlc3NlZCk6ICR7XG4gICAgcHJvY2Vzc2VkRW50aXR5ICYmIEpTT04uc3RyaW5naWZ5KHByb2Nlc3NlZEVudGl0eSwgbnVsbCwgMilcbiAgfVxuYCxcbiAgICAgICAgICApO1xuICAgICAgICAgIChlcnJvciBhcyBhbnkpLnN0YXR1cyA9IDQwMDtcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWQgPSBgJHtpZH1gO1xuICAgICAgfVxuXG4gICAgICAvKiBDaXJjdWxhciByZWZlcmVuY2Ugc2hvcnQtY2lyY3VpdGVyICovXG4gICAgICBpZiAoY2hlY2tMb29wKHRoaXMua2V5LCBpZCwgaW5wdXQpKSByZXR1cm4gaWQ7XG5cbiAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IHRoaXMudmFsaWRhdGUocHJvY2Vzc2VkRW50aXR5KTtcbiAgICAgIHRocm93VmFsaWRhdGlvbkVycm9yKGVycm9yTWVzc2FnZSk7XG5cbiAgICAgIE9iamVjdC5rZXlzKHRoaXMuc2NoZW1hKS5mb3JFYWNoKGtleSA9PiB7XG4gICAgICAgIGlmIChPYmplY3QuaGFzT3duKHByb2Nlc3NlZEVudGl0eSwga2V5KSkge1xuICAgICAgICAgIHByb2Nlc3NlZEVudGl0eVtrZXldID0gdmlzaXQoXG4gICAgICAgICAgICB0aGlzLnNjaGVtYVtrZXldLFxuICAgICAgICAgICAgcHJvY2Vzc2VkRW50aXR5W2tleV0sXG4gICAgICAgICAgICBwcm9jZXNzZWRFbnRpdHksXG4gICAgICAgICAgICBrZXksXG4gICAgICAgICAgICBhcmdzLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBhZGRFbnRpdHkodGhpcywgcHJvY2Vzc2VkRW50aXR5LCBpZCk7XG4gICAgICByZXR1cm4gaWQ7XG4gICAgfVxuXG4gICAgc3RhdGljIHZhbGlkYXRlKHByb2Nlc3NlZEVudGl0eTogYW55KTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBzdGF0aWMgcXVlcnlLZXkoXG4gICAgICBhcmdzOiByZWFkb25seSBhbnlbXSxcbiAgICAgIHF1ZXJ5S2V5OiBhbnksXG4gICAgICBnZXRFbnRpdHk6IEdldEVudGl0eSxcbiAgICAgIGdldEluZGV4OiBHZXRJbmRleCxcbiAgICApOiBhbnkge1xuICAgICAgaWYgKCFhcmdzWzBdKSByZXR1cm47XG4gICAgICBjb25zdCBpZCA9IHF1ZXJ5S2V5Q2FuZGlkYXRlKHRoaXMsIGFyZ3MsIGdldEluZGV4KTtcbiAgICAgIC8vIGVuc3VyZSB0aGlzIGFjdHVhbGx5IGhhcyBlbnRpdHkgb3Igd2Ugc2hvdWxkbid0IHRyeSB0byB1c2UgaXQgaW4gb3VyIHF1ZXJ5XG4gICAgICBpZiAoZ2V0RW50aXR5KHRoaXMua2V5LCBpZCkpIHJldHVybiBpZDtcbiAgICB9XG5cbiAgICBzdGF0aWMgZGVub3JtYWxpemU8VCBleHRlbmRzIHR5cGVvZiBFbnRpdHlNaXhpbj4oXG4gICAgICB0aGlzOiBULFxuICAgICAgaW5wdXQ6IGFueSxcbiAgICAgIGFyZ3M6IGFueVtdLFxuICAgICAgdW52aXNpdDogKHNjaGVtYTogYW55LCBpbnB1dDogYW55KSA9PiBhbnksXG4gICAgKTogQWJzdHJhY3RJbnN0YW5jZVR5cGU8VD4ge1xuICAgICAgaWYgKHR5cGVvZiBpbnB1dCA9PT0gJ3N5bWJvbCcpIHtcbiAgICAgICAgcmV0dXJuIGlucHV0IGFzIGFueTtcbiAgICAgIH1cblxuICAgICAgLy8gbm90ZTogaXRlcmF0aW9uIG9yZGVyIG11c3QgYmUgc3RhYmxlXG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyh0aGlzLnNjaGVtYSkpIHtcbiAgICAgICAgY29uc3Qgc2NoZW1hID0gdGhpcy5zY2hlbWFba2V5XTtcbiAgICAgICAgY29uc3QgdmFsdWUgPSB1bnZpc2l0KHNjaGVtYSwgaW5wdXRba2V5XSk7XG5cbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N5bWJvbCcpIHtcbiAgICAgICAgICAvLyBpZiBkZWZhdWx0IGlzIG5vdCAnZmFsc3knLCB0aGVuIHRoaXMgaXMgcmVxdWlyZWQsIHNvIHByb3BhZ2F0ZSBJTlZBTElEIHN5bWJvbFxuICAgICAgICAgIGlmICh0aGlzLmRlZmF1bHRzW2tleV0pIHtcbiAgICAgICAgICAgIHJldHVybiB2YWx1ZSBhcyBhbnk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlucHV0W2tleV0gPSB1bmRlZmluZWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaW5wdXRba2V5XSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gaW5wdXQ7XG4gICAgfVxuXG4gICAgLyoqIEFsbCBpbnN0YW5jZSBkZWZhdWx0cyBzZXQgKi9cbiAgICBzdGF0aWMgZ2V0IGRlZmF1bHRzKCkge1xuICAgICAgLy8gd2UgdXNlIGhhc093biBiZWNhdXNlIHdlIGRvbid0IHdhbnQgdG8gdXNlIGEgcGFyZW50cycgZGVmYXVsdHNcbiAgICAgIGlmICghT2JqZWN0Lmhhc093bih0aGlzLCAnX19kZWZhdWx0cycpKVxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ19fZGVmYXVsdHMnLCB7XG4gICAgICAgICAgdmFsdWU6IG5ldyAodGhpcyBhcyBhbnkpKCksXG4gICAgICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgICB9KTtcbiAgICAgIHJldHVybiAodGhpcyBhcyBhbnkpLl9fZGVmYXVsdHM7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgeyBwaywgc2NoZW1hLCBrZXksIC4uLnN0YXRpY1Byb3BzIH0gPSBvcHRpb25zO1xuICAvLyByZW1haW5pbmcgb3B0aW9uc1xuICBPYmplY3QuYXNzaWduKEVudGl0eU1peGluLCBzdGF0aWNQcm9wcyk7XG5cbiAgaWYgKCdzY2hlbWEnIGluIG9wdGlvbnMpIHtcbiAgICBFbnRpdHlNaXhpbi5zY2hlbWEgPSBvcHRpb25zLnNjaGVtYSBhcyBhbnk7XG4gIH0gZWxzZSBpZiAoIShCYXNlIGFzIGFueSkuc2NoZW1hKSB7XG4gICAgRW50aXR5TWl4aW4uc2NoZW1hID0ge307XG4gIH1cbiAgaWYgKCdwaycgaW4gb3B0aW9ucykge1xuICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5wayA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgRW50aXR5TWl4aW4ucHJvdG90eXBlLnBrID0gZnVuY3Rpb24gKHBhcmVudD86IGFueSwga2V5Pzogc3RyaW5nKSB7XG4gICAgICAgIHJldHVybiAob3B0aW9ucy5wayBhcyBhbnkpKHRoaXMsIHBhcmVudCwga2V5KTtcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIEVudGl0eU1peGluLnByb3RvdHlwZS5wayA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuICh0aGlzIGFzIGFueSlbb3B0aW9ucy5wa107XG4gICAgICB9O1xuICAgIH1cbiAgICAvLyBkZWZhdWx0IHRvICdpZCcgZmllbGQgaWYgdGhlIGJhc2UgY2xhc3MgZG9lc24ndCBoYXZlIGEgcGtcbiAgfSBlbHNlIGlmICh0eXBlb2YgQmFzZS5wcm90b3R5cGUucGsgIT09ICdmdW5jdGlvbicpIHtcbiAgICBFbnRpdHlNaXhpbi5wcm90b3R5cGUucGsgPSBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gKHRoaXMgYXMgYW55KS5pZDtcbiAgICB9O1xuICB9XG4gIGlmICgna2V5JyBpbiBvcHRpb25zKSB7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEVudGl0eU1peGluLCAna2V5Jywge1xuICAgICAgdmFsdWU6IG9wdGlvbnMua2V5LFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgIH0pO1xuICB9IGVsc2UgaWYgKCEoJ2tleScgaW4gQmFzZSkpIHtcbiAgICBmdW5jdGlvbiBzZXQodGhpczogYW55LCB2YWx1ZTogc3RyaW5nKSB7XG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ2tleScsIHtcbiAgICAgICAgdmFsdWUsXG4gICAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICB9KTtcbiAgICB9XG4gICAgY29uc3QgYmFzZUdldCA9IGZ1bmN0aW9uICh0aGlzOiB7IG5hbWU6IHN0cmluZyB9KTogc3RyaW5nIHtcbiAgICAgIGNvbnN0IG5hbWUgPSB0aGlzLm5hbWUgPT09ICdFbnRpdHlNaXhpbicgPyBCYXNlLm5hbWUgOiB0aGlzLm5hbWU7XG4gICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgaWYgKFxuICAgICAgICBwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nICYmXG4gICAgICAgIChuYW1lID09PSAnJyB8fCBuYW1lID09PSAnRW50aXR5TWl4aW4nIHx8IG5hbWUgPT09ICdfdGVtcCcpXG4gICAgICApXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAnRW50aXR5IGNsYXNzZXMgd2l0aG91dCBhIG5hbWUgbXVzdCBkZWZpbmUgYHN0YXRpYyBrZXlgXFxuU2VlOiBodHRwczovL2RhdGFjbGllbnQuaW8vcmVzdC9hcGkvRW50aXR5I2tleScsXG4gICAgICAgICk7XG4gICAgICByZXR1cm4gbmFtZTtcbiAgICB9O1xuICAgIGNvbnN0IGdldCA9XG4gICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgaWYgKi9cbiAgICAgIHR5cGVvZiBkb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgKGRvY3VtZW50IGFzIGFueSkuQ0xTX01BTkdMRSA/XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovIGZ1bmN0aW9uICh0aGlzOiB7XG4gICAgICAgICAgbmFtZTogc3RyaW5nO1xuICAgICAgICAgIGtleTogc3RyaW5nO1xuICAgICAgICB9KTogc3RyaW5nIHtcbiAgICAgICAgICAoZG9jdW1lbnQgYXMgYW55KS5DTFNfTUFOR0xFPy4odGhpcyk7XG4gICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KEVudGl0eU1peGluLCAna2V5Jywge1xuICAgICAgICAgICAgZ2V0OiBiYXNlR2V0LFxuICAgICAgICAgICAgc2V0LFxuICAgICAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm4gYmFzZUdldC5jYWxsKHRoaXMpO1xuICAgICAgICB9XG4gICAgICA6IGJhc2VHZXQ7XG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRW50aXR5TWl4aW4sICdrZXknLCB7XG4gICAgICBnZXQsXG4gICAgICBzZXQsXG4gICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIEVudGl0eU1peGluIGFzIGFueTtcbn1cblxuZnVuY3Rpb24gaW5kZXhGcm9tUGFyYW1zPEkgZXh0ZW5kcyBzdHJpbmc+KFxuICBwYXJhbXM6IFJlYWRvbmx5PG9iamVjdD4sXG4gIGluZGV4ZXM/OiBSZWFkb25seTxJW10+LFxuKSB7XG4gIGlmICghaW5kZXhlcykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIGluZGV4ZXMuZmluZChpbmRleCA9PiBPYmplY3QuaGFzT3duKHBhcmFtcywgaW5kZXgpKTtcbn1cblxuLy8gcGFydCBvZiB0aGUgcmVhc29uIGZvciBwdWxsaW5nIHRoaXMgb3V0IGlzIHRoYXQgYWxsIGZ1bmN0aW9ucyB0aGF0IHRocm93IGFyZSBkZW9wdGltaXplZFxuZnVuY3Rpb24gdGhyb3dWYWxpZGF0aW9uRXJyb3IoZXJyb3JNZXNzYWdlOiBzdHJpbmcgfCB1bmRlZmluZWQpIHtcbiAgaWYgKGVycm9yTWVzc2FnZSkge1xuICAgIGNvbnN0IGVycm9yID0gbmV3IEVycm9yKGVycm9yTWVzc2FnZSk7XG4gICAgKGVycm9yIGFzIGFueSkuc3RhdHVzID0gNDAwO1xuICAgIHRocm93IGVycm9yO1xuICB9XG59XG5cbmZ1bmN0aW9uIHF1ZXJ5S2V5Q2FuZGlkYXRlKFxuICBzY2hlbWE6IGFueSxcbiAgYXJnczogcmVhZG9ubHkgYW55W10sXG4gIGdldEluZGV4OiBHZXRJbmRleCxcbikge1xuICBpZiAoWydzdHJpbmcnLCAnbnVtYmVyJ10uaW5jbHVkZXModHlwZW9mIGFyZ3NbMF0pKSB7XG4gICAgcmV0dXJuIGAke2FyZ3NbMF19YDtcbiAgfVxuICBjb25zdCBpZCA9IHNjaGVtYS5wayhhcmdzWzBdLCB1bmRlZmluZWQsICcnLCBhcmdzKTtcbiAgLy8gV2FzIGFibGUgdG8gaW5mZXIgdGhlIGVudGl0eSdzIHByaW1hcnkga2V5IGZyb20gcGFyYW1zXG4gIGlmIChpZCAhPT0gdW5kZWZpbmVkICYmIGlkICE9PSAnJykgcmV0dXJuIGlkO1xuICAvLyBub3cgYXR0ZW1wdCBsb29rdXAgaW4gaW5kZXhlc1xuICBjb25zdCBpbmRleE5hbWUgPSBpbmRleEZyb21QYXJhbXMoYXJnc1swXSwgc2NoZW1hLmluZGV4ZXMpO1xuICBpZiAoIWluZGV4TmFtZSkgcmV0dXJuO1xuICBjb25zdCB2YWx1ZSA9IChhcmdzWzBdIGFzIFJlY29yZDxzdHJpbmcsIGFueT4pW2luZGV4TmFtZV07XG4gIHJldHVybiBnZXRJbmRleChzY2hlbWEua2V5LCBpbmRleE5hbWUsIHZhbHVlKVt2YWx1ZV07XG59XG4iXSwibWFwcGluZ3MiOiI7OztBQVFBLFNBQVNBLE9BQU8sUUFBUSxlQUFlOztBQVd2QztBQUNBO0FBQ0E7QUFDQTs7QUFNQTs7QUFNQTs7QUFNQSxlQUFlLFNBQVNDLFdBQVdBLENBQ2pDQyxJQUFXLEVBQ1hDLE9BQTJDLEdBQUcsQ0FBQyxDQUFDLEVBQ2hEO0VBQ0E7QUFDRjtBQUNBO0FBQ0E7RUFDRSxNQUFlRixXQUFXLFNBQVNDLElBQUksQ0FBQztJQUN0QyxPQUFPRSxRQUFRQSxDQUFBLEVBQUc7TUFDaEIsT0FBTyxJQUFJLENBQUNDLEdBQUc7SUFDakI7SUFFQSxPQUFPQyxNQUFNQSxDQUFBLEVBQUc7TUFDZCxPQUFPO1FBQ0xELEdBQUcsRUFBRSxJQUFJLENBQUNBLEdBQUc7UUFDYkUsTUFBTSxFQUFFLElBQUksQ0FBQ0E7TUFDZixDQUFDO0lBQ0g7O0lBRUE7O0lBR0E7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7SUFPSTs7SUFFQTs7SUFFQTs7SUFHQTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7SUFDSSxPQUFPQyxFQUFFQSxDQUVQQyxLQUF1QyxFQUN2Q0MsTUFBWSxFQUNaTCxHQUFZLEVBQ1pNLElBQXFCLEVBQ1E7TUFDN0IsT0FBTyxJQUFJLENBQUNDLFNBQVMsQ0FBQ0osRUFBRSxDQUFDSyxJQUFJLENBQUNKLEtBQUssRUFBRUMsTUFBTSxFQUFFTCxHQUFHLEVBQUVNLElBQUksQ0FBQztJQUN6RDs7SUFFQTtBQUNKO0FBQ0E7QUFDQTtJQUNJLE9BQU9HLFlBQVlB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