ngx-dynamic-hooks
Version:
Automatically insert live Angular components into a dynamic string of content (based on their selector or any pattern of your choice) and render the result in the DOM.
147 lines • 18.7 kB
JavaScript
import { Injectable } from '@angular/core';
import { getParseOptionDefaults } from '../settings/options';
import * as i0 from "@angular/core";
import * as i1 from "./logger";
/**
* A service for comparing two variables by value instead of by reference
*/
export class DeepComparer {
// 1. Inputs
// -----------------------------------------------------------------
constructor(logger) {
this.logger = logger;
}
/**
* Tests if two objects are equal by value
*
* @param a - The first object
* @param b - The second object
* @param compareDepth - How many levels deep to compare
* @param options - The current parseOptions
*/
isEqual(a, b, compareDepth, options = getParseOptionDefaults()) {
const aStringified = this.detailedStringify(a, compareDepth);
const bStringified = this.detailedStringify(b, compareDepth);
if (aStringified.result === null || bStringified.result === null) {
this.logger.warn([
'Objects could not be compared by value as one or both of them could not be stringified. Returning false. \n',
'Objects:', a, b
], options);
return false;
}
return aStringified.result === bStringified.result;
}
/**
* Like JSON.stringify, but stringifies additional datatypes that would have been
* nulled otherwise. It also doesn't throw errors on cyclic property paths.
*
* If obj can't be stringified for whatever reason, returns null.
*
* @param obj - The object to stringify
* @param depth - How many levels deep to stringify
*/
detailedStringify(obj, depth) {
try {
// Null cyclic paths
const depthReached = { count: 0 };
const decylcedObj = this.decycle(obj, [], depth, depthReached);
const stringified = JSON.stringify(decylcedObj, (key, value) => {
// If undefined
if (value === undefined) {
return 'undefined';
}
// If function or class
if (typeof value === 'function') {
return value.toString();
}
// If symbol
if (typeof value === 'symbol') {
return value.toString();
}
return value;
});
return { result: stringified, depthReachedCount: depthReached.count };
}
catch (e) {
return { result: null, depthReachedCount: 0 };
}
}
/**
* Travels on object and replaces cyclical references with null
*
* @param obj - The object to travel
* @param stack - To keep track of already travelled objects
* @param depth - How many levels deep to decycle
* @param depthReached - An object to track the number of times the max depth was reached
*/
decycle(obj, stack = [], depth = 5, depthReached) {
if (stack.length > depth) {
depthReached.count++;
return null;
}
if (!obj || typeof obj !== 'object' || obj instanceof Date) {
return obj;
}
// Check if cyclical and we've traveled this obj already
//
// Note: Test this not by object reference, but by object PROPERTY reference/equality. If an object has identical properties,
// the object is to be considered identical even if it has a different reference itself.
//
// Explanation: This is to prevent a sneaky bug when comparing by value and a parser returns an object as an input that contains a reference to the object holding it
// (like returning the context object that contains a reference to the parent component holding the context object).
// In this example, when the context object changes by reference, the old input will be compared with the new input. However, as the old input consists of
// the old context object that now (through the parent component) contains a reference to the new context object, while the new input references the new context
// object exclusively, the decycle function would produce different results for them if it only checked cyclical paths by reference (even if the context object
// remained identical in value!)
//
// Though an unlikely scenario, checking cyclical paths via object properties rather than the object reference itself solves this problem.
for (const stackObj of stack) {
if (this.objEqualsProperties(obj, stackObj)) {
return null;
}
}
const s = stack.concat([obj]);
if (Array.isArray(obj)) {
const newArray = [];
for (const entry of obj) {
newArray.push(this.decycle(entry, s, depth, depthReached));
}
return newArray;
}
else {
const newObj = {};
for (const key of Object.keys(obj)) {
newObj[key] = this.decycle(obj[key], s, depth, depthReached);
}
return newObj;
}
}
/**
* Returns true when all the properties of one object equal those of another object, otherwise false.
*
* @param a - The first object
* @param b - The second object
*/
objEqualsProperties(a, b) {
const aKeys = Object.keys(a);
const bKeys = Object.keys(b);
if (aKeys.length !== bKeys.length) {
return false;
}
for (const aKey of aKeys) {
if (a[aKey] !== b[aKey]) {
return false;
}
}
return true;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DeepComparer, deps: [{ token: i1.Logger }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DeepComparer, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DeepComparer, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: i1.Logger }] });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVlcENvbXBhcmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWR5bmFtaWMtaG9va3Mvc3JjL2xpYi9zZXJ2aWNlcy91dGlscy9kZWVwQ29tcGFyZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEVBQUUsc0JBQXNCLEVBQWdCLE1BQU0scUJBQXFCLENBQUM7OztBQVkzRTs7R0FFRztBQUlILE1BQU0sT0FBTyxZQUFZO0lBRXZCLFlBQVk7SUFDWixvRUFBb0U7SUFFcEUsWUFBb0IsTUFBYztRQUFkLFdBQU0sR0FBTixNQUFNLENBQVE7SUFDbEMsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxPQUFPLENBQUMsQ0FBTSxFQUFFLENBQU0sRUFBRSxZQUFxQixFQUFFLFVBQXdCLHNCQUFzQixFQUFFO1FBQzdGLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLEVBQUUsWUFBWSxDQUFDLENBQUM7UUFDN0QsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUMsRUFBRSxZQUFZLENBQUMsQ0FBQztRQUU3RCxJQUFJLFlBQVksQ0FBQyxNQUFNLEtBQUssSUFBSSxJQUFJLFlBQVksQ0FBQyxNQUFNLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDakUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUM7Z0JBQ2YsNkdBQTZHO2dCQUM3RyxVQUFVLEVBQUUsQ0FBQyxFQUFFLENBQUM7YUFDakIsRUFBRSxPQUFPLENBQUMsQ0FBQztZQUNaLE9BQU8sS0FBSyxDQUFDO1FBQ2YsQ0FBQztRQUVELE9BQU8sWUFBWSxDQUFDLE1BQU0sS0FBSyxZQUFZLENBQUMsTUFBTSxDQUFDO0lBQ3JELENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNILGlCQUFpQixDQUFDLEdBQVEsRUFBRSxLQUFjO1FBQ3hDLElBQUksQ0FBQztZQUNILG9CQUFvQjtZQUNwQixNQUFNLFlBQVksR0FBRyxFQUFDLEtBQUssRUFBRSxDQUFDLEVBQUMsQ0FBQztZQUNoQyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLEVBQUUsS0FBSyxFQUFFLFlBQVksQ0FBQyxDQUFDO1lBRS9ELE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxFQUFFLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxFQUFFO2dCQUM3RCxlQUFlO2dCQUNmLElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO29CQUN4QixPQUFPLFdBQVcsQ0FBQztnQkFDckIsQ0FBQztnQkFDRCx1QkFBdUI7Z0JBQ3ZCLElBQUksT0FBTyxLQUFLLEtBQUssVUFBVSxFQUFFLENBQUM7b0JBQ2hDLE9BQU8sS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUMxQixDQUFDO2dCQUNELFlBQVk7Z0JBQ1osSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztvQkFDOUIsT0FBTyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQzFCLENBQUM7Z0JBQ0QsT0FBTyxLQUFLLENBQUM7WUFDZixDQUFDLENBQUMsQ0FBQztZQUVILE9BQU8sRUFBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLGlCQUFpQixFQUFFLFlBQVksQ0FBQyxLQUFLLEVBQUMsQ0FBQztRQUN0RSxDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNYLE9BQU8sRUFBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixFQUFFLENBQUMsRUFBQyxDQUFDO1FBQzlDLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILE9BQU8sQ0FBQyxHQUFRLEVBQUUsUUFBZSxFQUFFLEVBQUUsUUFBZ0IsQ0FBQyxFQUFFLFlBQWdDO1FBQ3RGLElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxLQUFLLEVBQUUsQ0FBQztZQUN6QixZQUFZLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDckIsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBRUQsSUFBSSxDQUFDLEdBQUcsSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRLElBQUksR0FBRyxZQUFZLElBQUksRUFBRSxDQUFDO1lBQ3pELE9BQU8sR0FBRyxDQUFDO1FBQ2YsQ0FBQztRQUVELHdEQUF3RDtRQUN4RCxFQUFFO1FBQ0YsNkhBQTZIO1FBQzdILHdGQUF3RjtRQUN4RixFQUFFO1FBQ0YscUtBQXFLO1FBQ3JLLG9IQUFvSDtRQUNwSCwwSkFBMEo7UUFDMUosZ0tBQWdLO1FBQ2hLLCtKQUErSjtRQUMvSixnQ0FBZ0M7UUFDaEMsRUFBRTtRQUNGLDBJQUEwSTtRQUMxSSxLQUFLLE1BQU0sUUFBUSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQzdCLElBQUksSUFBSSxDQUFDLG1CQUFtQixDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUM1QyxPQUFPLElBQUksQ0FBQztZQUNkLENBQUM7UUFDSCxDQUFDO1FBRUQsTUFBTSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFFOUIsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdkIsTUFBTSxRQUFRLEdBQUcsRUFBRSxDQUFDO1lBQ3BCLEtBQUssTUFBTSxLQUFLLElBQUksR0FBRyxFQUFFLENBQUM7Z0JBQ3hCLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxZQUFZLENBQUMsQ0FBQyxDQUFDO1lBQzdELENBQUM7WUFDRCxPQUFPLFFBQVEsQ0FBQztRQUNsQixDQUFDO2FBQU0sQ0FBQztZQUNOLE1BQU0sTUFBTSxHQUFRLEVBQUUsQ0FBQztZQUN2QixLQUFLLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDbkMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsWUFBWSxDQUFDLENBQUM7WUFDL0QsQ0FBQztZQUNELE9BQU8sTUFBTSxDQUFDO1FBQ2hCLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxtQkFBbUIsQ0FBQyxDQUFNLEVBQUUsQ0FBTTtRQUNoQyxNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdCLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFN0IsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNsQyxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFFRCxLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3pCLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUN4QixPQUFPLEtBQUssQ0FBQztZQUNmLENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDOytHQS9JVSxZQUFZO21IQUFaLFlBQVksY0FGWCxNQUFNOzs0RkFFUCxZQUFZO2tCQUh4QixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4vbG9nZ2VyJztcbmltcG9ydCB7IGdldFBhcnNlT3B0aW9uRGVmYXVsdHMsIFBhcnNlT3B0aW9ucyB9IGZyb20gJy4uL3NldHRpbmdzL29wdGlvbnMnO1xuXG5cbi8qKlxuICogVGhlIG9iamVjdCByZXR1cm5lZCBieSB0aGUgZGV0YWlsZWRTdHJpbmdpZnkgZnVuY3Rpb24gaW4gRGVlcENvbXBhcmVyLlxuICogQ29udGFpbnMgdGhlIHN0cmluZ2lmaWVkIHZhbHVlIGFzIHdlbGwgYXMgdGhlIG51bWJlciBvZiB0aW1lcyB0aGUgbWF4aW11bSBzdHJpbmdpZnkgZGVwdGggd2FzIHJlYWNoZWQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGV0YWlsZWRTdHJpbmdpZnlSZXN1bHQge1xuICByZXN1bHQ6IHN0cmluZ3xudWxsO1xuICBkZXB0aFJlYWNoZWRDb3VudDogbnVtYmVyO1xufVxuXG4vKipcbiAqIEEgc2VydmljZSBmb3IgY29tcGFyaW5nIHR3byB2YXJpYWJsZXMgYnkgdmFsdWUgaW5zdGVhZCBvZiBieSByZWZlcmVuY2VcbiAqL1xuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCdcbn0pXG5leHBvcnQgY2xhc3MgRGVlcENvbXBhcmVyIHtcblxuICAvLyAxLiBJbnB1dHNcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGxvZ2dlcjogTG9nZ2VyKSB7XG4gIH1cblxuICAvKipcbiAgICogVGVzdHMgaWYgdHdvIG9iamVjdHMgYXJlIGVxdWFsIGJ5IHZhbHVlXG4gICAqXG4gICAqIEBwYXJhbSBhIC0gVGhlIGZpcnN0IG9iamVjdFxuICAgKiBAcGFyYW0gYiAtIFRoZSBzZWNvbmQgb2JqZWN0XG4gICAqIEBwYXJhbSBjb21wYXJlRGVwdGggLSBIb3cgbWFueSBsZXZlbHMgZGVlcCB0byBjb21wYXJlXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gVGhlIGN1cnJlbnQgcGFyc2VPcHRpb25zXG4gICAqL1xuICBpc0VxdWFsKGE6IGFueSwgYjogYW55LCBjb21wYXJlRGVwdGg/OiBudW1iZXIsIG9wdGlvbnM6IFBhcnNlT3B0aW9ucyA9IGdldFBhcnNlT3B0aW9uRGVmYXVsdHMoKSk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGFTdHJpbmdpZmllZCA9IHRoaXMuZGV0YWlsZWRTdHJpbmdpZnkoYSwgY29tcGFyZURlcHRoKTtcbiAgICBjb25zdCBiU3RyaW5naWZpZWQgPSB0aGlzLmRldGFpbGVkU3RyaW5naWZ5KGIsIGNvbXBhcmVEZXB0aCk7XG5cbiAgICBpZiAoYVN0cmluZ2lmaWVkLnJlc3VsdCA9PT0gbnVsbCB8fCBiU3RyaW5naWZpZWQucmVzdWx0ID09PSBudWxsKSB7XG4gICAgICB0aGlzLmxvZ2dlci53YXJuKFtcbiAgICAgICAgJ09iamVjdHMgY291bGQgbm90IGJlIGNvbXBhcmVkIGJ5IHZhbHVlIGFzIG9uZSBvciBib3RoIG9mIHRoZW0gY291bGQgbm90IGJlIHN0cmluZ2lmaWVkLiBSZXR1cm5pbmcgZmFsc2UuIFxcbicsXG4gICAgICAgICdPYmplY3RzOicsIGEsIGJcbiAgICAgIF0sIG9wdGlvbnMpO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHJldHVybiBhU3RyaW5naWZpZWQucmVzdWx0ID09PSBiU3RyaW5naWZpZWQucmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIExpa2UgSlNPTi5zdHJpbmdpZnksIGJ1dCBzdHJpbmdpZmllcyBhZGRpdGlvbmFsIGRhdGF0eXBlcyB0aGF0IHdvdWxkIGhhdmUgYmVlblxuICAgKiBudWxsZWQgb3RoZXJ3aXNlLiBJdCBhbHNvIGRvZXNuJ3QgdGhyb3cgZXJyb3JzIG9uIGN5Y2xpYyBwcm9wZXJ0eSBwYXRocy5cbiAgICpcbiAgICogSWYgb2JqIGNhbid0IGJlIHN0cmluZ2lmaWVkIGZvciB3aGF0ZXZlciByZWFzb24sIHJldHVybnMgbnVsbC5cbiAgICpcbiAgICogQHBhcmFtIG9iaiAtIFRoZSBvYmplY3QgdG8gc3RyaW5naWZ5XG4gICAqIEBwYXJhbSBkZXB0aCAtIEhvdyBtYW55IGxldmVscyBkZWVwIHRvIHN0cmluZ2lmeVxuICAgKi9cbiAgZGV0YWlsZWRTdHJpbmdpZnkob2JqOiBhbnksIGRlcHRoPzogbnVtYmVyKTogRGV0YWlsZWRTdHJpbmdpZnlSZXN1bHQge1xuICAgIHRyeSB7XG4gICAgICAvLyBOdWxsIGN5Y2xpYyBwYXRoc1xuICAgICAgY29uc3QgZGVwdGhSZWFjaGVkID0ge2NvdW50OiAwfTtcbiAgICAgIGNvbnN0IGRlY3lsY2VkT2JqID0gdGhpcy5kZWN5Y2xlKG9iaiwgW10sIGRlcHRoLCBkZXB0aFJlYWNoZWQpO1xuXG4gICAgICBjb25zdCBzdHJpbmdpZmllZCA9IEpTT04uc3RyaW5naWZ5KGRlY3lsY2VkT2JqLCAoa2V5LCB2YWx1ZSkgPT4ge1xuICAgICAgICAvLyBJZiB1bmRlZmluZWRcbiAgICAgICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICByZXR1cm4gJ3VuZGVmaW5lZCc7XG4gICAgICAgIH1cbiAgICAgICAgLy8gSWYgZnVuY3Rpb24gb3IgY2xhc3NcbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgIHJldHVybiB2YWx1ZS50b1N0cmluZygpO1xuICAgICAgICB9XG4gICAgICAgIC8vIElmIHN5bWJvbFxuICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3ltYm9sJykge1xuICAgICAgICAgIHJldHVybiB2YWx1ZS50b1N0cmluZygpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICAgIH0pO1xuXG4gICAgICByZXR1cm4ge3Jlc3VsdDogc3RyaW5naWZpZWQsIGRlcHRoUmVhY2hlZENvdW50OiBkZXB0aFJlYWNoZWQuY291bnR9O1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiB7cmVzdWx0OiBudWxsLCBkZXB0aFJlYWNoZWRDb3VudDogMH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRyYXZlbHMgb24gb2JqZWN0IGFuZCByZXBsYWNlcyBjeWNsaWNhbCByZWZlcmVuY2VzIHdpdGggbnVsbFxuICAgKlxuICAgKiBAcGFyYW0gb2JqIC0gVGhlIG9iamVjdCB0byB0cmF2ZWxcbiAgICogQHBhcmFtIHN0YWNrIC0gVG8ga2VlcCB0cmFjayBvZiBhbHJlYWR5IHRyYXZlbGxlZCBvYmplY3RzXG4gICAqIEBwYXJhbSBkZXB0aCAtIEhvdyBtYW55IGxldmVscyBkZWVwIHRvIGRlY3ljbGVcbiAgICogQHBhcmFtIGRlcHRoUmVhY2hlZCAtIEFuIG9iamVjdCB0byB0cmFjayB0aGUgbnVtYmVyIG9mIHRpbWVzIHRoZSBtYXggZGVwdGggd2FzIHJlYWNoZWRcbiAgICovXG4gIGRlY3ljbGUob2JqOiBhbnksIHN0YWNrOiBhbnlbXSA9IFtdLCBkZXB0aDogbnVtYmVyID0gNSwgZGVwdGhSZWFjaGVkOiB7IGNvdW50OiBudW1iZXI7IH0pOiBhbnkge1xuICAgIGlmIChzdGFjay5sZW5ndGggPiBkZXB0aCkge1xuICAgICAgZGVwdGhSZWFjaGVkLmNvdW50Kys7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAoIW9iaiB8fCB0eXBlb2Ygb2JqICE9PSAnb2JqZWN0JyB8fCBvYmogaW5zdGFuY2VvZiBEYXRlKSB7XG4gICAgICAgIHJldHVybiBvYmo7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgaWYgY3ljbGljYWwgYW5kIHdlJ3ZlIHRyYXZlbGVkIHRoaXMgb2JqIGFscmVhZHlcbiAgICAvL1xuICAgIC8vIE5vdGU6IFRlc3QgdGhpcyBub3QgYnkgb2JqZWN0IHJlZmVyZW5jZSwgYnV0IGJ5IG9iamVjdCBQUk9QRVJUWSByZWZlcmVuY2UvZXF1YWxpdHkuIElmIGFuIG9iamVjdCBoYXMgaWRlbnRpY2FsIHByb3BlcnRpZXMsXG4gICAgLy8gdGhlIG9iamVjdCBpcyB0byBiZSBjb25zaWRlcmVkIGlkZW50aWNhbCBldmVuIGlmIGl0IGhhcyBhIGRpZmZlcmVudCByZWZlcmVuY2UgaXRzZWxmLlxuICAgIC8vXG4gICAgLy8gRXhwbGFuYXRpb246IFRoaXMgaXMgdG8gcHJldmVudCBhIHNuZWFreSBidWcgd2hlbiBjb21wYXJpbmcgYnkgdmFsdWUgYW5kIGEgcGFyc2VyIHJldHVybnMgYW4gb2JqZWN0IGFzIGFuIGlucHV0IHRoYXQgY29udGFpbnMgYSByZWZlcmVuY2UgdG8gdGhlIG9iamVjdCBob2xkaW5nIGl0XG4gICAgLy8gKGxpa2UgcmV0dXJuaW5nIHRoZSBjb250ZXh0IG9iamVjdCB0aGF0IGNvbnRhaW5zIGEgcmVmZXJlbmNlIHRvIHRoZSBwYXJlbnQgY29tcG9uZW50IGhvbGRpbmcgdGhlIGNvbnRleHQgb2JqZWN0KS5cbiAgICAvLyBJbiB0aGlzIGV4YW1wbGUsIHdoZW4gdGhlIGNvbnRleHQgb2JqZWN0IGNoYW5nZXMgYnkgcmVmZXJlbmNlLCB0aGUgb2xkIGlucHV0IHdpbGwgYmUgY29tcGFyZWQgd2l0aCB0aGUgbmV3IGlucHV0LiBIb3dldmVyLCBhcyB0aGUgb2xkIGlucHV0IGNvbnNpc3RzIG9mXG4gICAgLy8gdGhlIG9sZCBjb250ZXh0IG9iamVjdCB0aGF0IG5vdyAodGhyb3VnaCB0aGUgcGFyZW50IGNvbXBvbmVudCkgY29udGFpbnMgYSByZWZlcmVuY2UgdG8gdGhlIG5ldyBjb250ZXh0IG9iamVjdCwgd2hpbGUgdGhlIG5ldyBpbnB1dCByZWZlcmVuY2VzIHRoZSBuZXcgY29udGV4dFxuICAgIC8vIG9iamVjdCBleGNsdXNpdmVseSwgdGhlIGRlY3ljbGUgZnVuY3Rpb24gd291bGQgcHJvZHVjZSBkaWZmZXJlbnQgcmVzdWx0cyBmb3IgdGhlbSBpZiBpdCBvbmx5IGNoZWNrZWQgY3ljbGljYWwgcGF0aHMgYnkgcmVmZXJlbmNlIChldmVuIGlmIHRoZSBjb250ZXh0IG9iamVjdFxuICAgIC8vIHJlbWFpbmVkIGlkZW50aWNhbCBpbiB2YWx1ZSEpXG4gICAgLy9cbiAgICAvLyBUaG91Z2ggYW4gdW5saWtlbHkgc2NlbmFyaW8sIGNoZWNraW5nIGN5Y2xpY2FsIHBhdGhzIHZpYSBvYmplY3QgcHJvcGVydGllcyByYXRoZXIgdGhhbiB0aGUgb2JqZWN0IHJlZmVyZW5jZSBpdHNlbGYgc29sdmVzIHRoaXMgcHJvYmxlbS5cbiAgICBmb3IgKGNvbnN0IHN0YWNrT2JqIG9mIHN0YWNrKSB7XG4gICAgICBpZiAodGhpcy5vYmpFcXVhbHNQcm9wZXJ0aWVzKG9iaiwgc3RhY2tPYmopKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IHMgPSBzdGFjay5jb25jYXQoW29ial0pO1xuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkob2JqKSkge1xuICAgICAgY29uc3QgbmV3QXJyYXkgPSBbXTtcbiAgICAgIGZvciAoY29uc3QgZW50cnkgb2Ygb2JqKSB7XG4gICAgICAgIG5ld0FycmF5LnB1c2godGhpcy5kZWN5Y2xlKGVudHJ5LCBzLCBkZXB0aCwgZGVwdGhSZWFjaGVkKSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbmV3QXJyYXk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IG5ld09iajogYW55ID0ge307XG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhvYmopKSB7XG4gICAgICAgIG5ld09ialtrZXldID0gdGhpcy5kZWN5Y2xlKG9ialtrZXldLCBzLCBkZXB0aCwgZGVwdGhSZWFjaGVkKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBuZXdPYmo7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSB3aGVuIGFsbCB0aGUgcHJvcGVydGllcyBvZiBvbmUgb2JqZWN0IGVxdWFsIHRob3NlIG9mIGFub3RoZXIgb2JqZWN0LCBvdGhlcndpc2UgZmFsc2UuXG4gICAqXG4gICAqIEBwYXJhbSBhIC0gVGhlIGZpcnN0IG9iamVjdFxuICAgKiBAcGFyYW0gYiAtIFRoZSBzZWNvbmQgb2JqZWN0XG4gICAqL1xuICBvYmpFcXVhbHNQcm9wZXJ0aWVzKGE6IGFueSwgYjogYW55KTogYm9vbGVhbiB7XG4gICAgY29uc3QgYUtleXMgPSBPYmplY3Qua2V5cyhhKTtcbiAgICBjb25zdCBiS2V5cyA9IE9iamVjdC5rZXlzKGIpO1xuXG4gICAgaWYgKGFLZXlzLmxlbmd0aCAhPT0gYktleXMubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBhS2V5IG9mIGFLZXlzKSB7XG4gICAgICBpZiAoYVthS2V5XSAhPT0gYlthS2V5XSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbn1cbiJdfQ==