UNPKG

@data-client/endpoint

Version:

Declarative Network Interface Definitions

339 lines (315 loc) 44.4 kB
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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