UNPKG

@angular/cdk

Version:

Angular Material Component Development Kit

209 lines 35.9 kB
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { parallel } from './change-detection'; import { ComponentHarness, HarnessPredicate, } from './component-harness'; /** * Base harness environment class that can be extended to allow `ComponentHarness`es to be used in * different test environments (e.g. testbed, protractor, etc.). This class implements the * functionality of both a `HarnessLoader` and `LocatorFactory`. This class is generic on the raw * element type, `E`, used by the particular test environment. */ export class HarnessEnvironment { constructor(rawRootElement) { this.rawRootElement = rawRootElement; } // Implemented as part of the `LocatorFactory` interface. get rootElement() { this._rootElement = this._rootElement || this.createTestElement(this.rawRootElement); return this._rootElement; } set rootElement(element) { this._rootElement = element; } // Implemented as part of the `LocatorFactory` interface. documentRootLocatorFactory() { return this.createEnvironment(this.getDocumentRoot()); } // Implemented as part of the `LocatorFactory` interface. locatorFor(...queries) { return () => _assertResultFound(this._getAllHarnessesAndTestElements(queries), _getDescriptionForLocatorForQueries(queries)); } // Implemented as part of the `LocatorFactory` interface. locatorForOptional(...queries) { return async () => (await this._getAllHarnessesAndTestElements(queries))[0] || null; } // Implemented as part of the `LocatorFactory` interface. locatorForAll(...queries) { return () => this._getAllHarnessesAndTestElements(queries); } // Implemented as part of the `LocatorFactory` interface. async rootHarnessLoader() { return this; } // Implemented as part of the `LocatorFactory` interface. async harnessLoaderFor(selector) { return this.createEnvironment(await _assertResultFound(this.getAllRawElements(selector), [ _getDescriptionForHarnessLoaderQuery(selector), ])); } // Implemented as part of the `LocatorFactory` interface. async harnessLoaderForOptional(selector) { const elements = await this.getAllRawElements(selector); return elements[0] ? this.createEnvironment(elements[0]) : null; } // Implemented as part of the `LocatorFactory` interface. async harnessLoaderForAll(selector) { const elements = await this.getAllRawElements(selector); return elements.map(element => this.createEnvironment(element)); } // Implemented as part of the `HarnessLoader` interface. getHarness(query) { return this.locatorFor(query)(); } // Implemented as part of the `HarnessLoader` interface. getAllHarnesses(query) { return this.locatorForAll(query)(); } // Implemented as part of the `HarnessLoader` interface. async getChildLoader(selector) { return this.createEnvironment(await _assertResultFound(this.getAllRawElements(selector), [ _getDescriptionForHarnessLoaderQuery(selector), ])); } // Implemented as part of the `HarnessLoader` interface. async getAllChildLoaders(selector) { return (await this.getAllRawElements(selector)).map(e => this.createEnvironment(e)); } /** Creates a `ComponentHarness` for the given harness type with the given raw host element. */ createComponentHarness(harnessType, element) { return new harnessType(this.createEnvironment(element)); } /** * Matches the given raw elements with the given list of element and harness queries to produce a * list of matched harnesses and test elements. */ async _getAllHarnessesAndTestElements(queries) { const { allQueries, harnessQueries, elementQueries, harnessTypes } = _parseQueries(queries); // Combine all of the queries into one large comma-delimited selector and use it to get all raw // elements matching any of the individual queries. const rawElements = await this.getAllRawElements([...elementQueries, ...harnessQueries.map(predicate => predicate.getSelector())].join(',')); // If every query is searching for the same harness subclass, we know every result corresponds // to an instance of that subclass. Likewise, if every query is for a `TestElement`, we know // every result corresponds to a `TestElement`. Otherwise we need to verify which result was // found by which selector so it can be matched to the appropriate instance. const skipSelectorCheck = (elementQueries.length === 0 && harnessTypes.size === 1) || harnessQueries.length === 0; const perElementMatches = await parallel(() => rawElements.map(async (rawElement) => { const testElement = this.createTestElement(rawElement); const allResultsForElement = await parallel( // For each query, get `null` if it doesn't match, or a `TestElement` or // `ComponentHarness` as appropriate if it does match. This gives us everything that // matches the current raw element, but it may contain duplicate entries (e.g. // multiple `TestElement` or multiple `ComponentHarness` of the same type). () => allQueries.map(query => this._getQueryResultForElement(query, rawElement, testElement, skipSelectorCheck))); return _removeDuplicateQueryResults(allResultsForElement); })); return [].concat(...perElementMatches); } /** * Check whether the given query matches the given element, if it does return the matched * `TestElement` or `ComponentHarness`, if it does not, return null. In cases where the caller * knows for sure that the query matches the element's selector, `skipSelectorCheck` can be used * to skip verification and optimize performance. */ async _getQueryResultForElement(query, rawElement, testElement, skipSelectorCheck = false) { if (typeof query === 'string') { return skipSelectorCheck || (await testElement.matchesSelector(query)) ? testElement : null; } if (skipSelectorCheck || (await testElement.matchesSelector(query.getSelector()))) { const harness = this.createComponentHarness(query.harnessType, rawElement); return (await query.evaluate(harness)) ? harness : null; } return null; } } /** * Parses a list of queries in the format accepted by the `locatorFor*` methods into an easier to * work with format. */ function _parseQueries(queries) { const allQueries = []; const harnessQueries = []; const elementQueries = []; const harnessTypes = new Set(); for (const query of queries) { if (typeof query === 'string') { allQueries.push(query); elementQueries.push(query); } else { const predicate = query instanceof HarnessPredicate ? query : new HarnessPredicate(query, {}); allQueries.push(predicate); harnessQueries.push(predicate); harnessTypes.add(predicate.harnessType); } } return { allQueries, harnessQueries, elementQueries, harnessTypes }; } /** * Removes duplicate query results for a particular element. (e.g. multiple `TestElement` * instances or multiple instances of the same `ComponentHarness` class. */ async function _removeDuplicateQueryResults(results) { let testElementMatched = false; let matchedHarnessTypes = new Set(); const dedupedMatches = []; for (const result of results) { if (!result) { continue; } if (result instanceof ComponentHarness) { if (!matchedHarnessTypes.has(result.constructor)) { matchedHarnessTypes.add(result.constructor); dedupedMatches.push(result); } } else if (!testElementMatched) { testElementMatched = true; dedupedMatches.push(result); } } return dedupedMatches; } /** Verifies that there is at least one result in an array. */ async function _assertResultFound(results, queryDescriptions) { const result = (await results)[0]; if (result == undefined) { throw Error(`Failed to find element matching one of the following queries:\n` + queryDescriptions.map(desc => `(${desc})`).join(',\n')); } return result; } /** Gets a list of description strings from a list of queries. */ function _getDescriptionForLocatorForQueries(queries) { return queries.map(query => typeof query === 'string' ? _getDescriptionForTestElementQuery(query) : _getDescriptionForComponentHarnessQuery(query)); } /** Gets a description string for a `ComponentHarness` query. */ function _getDescriptionForComponentHarnessQuery(query) { const harnessPredicate = query instanceof HarnessPredicate ? query : new HarnessPredicate(query, {}); const { name, hostSelector } = harnessPredicate.harnessType; const description = `${name} with host element matching selector: "${hostSelector}"`; const constraints = harnessPredicate.getDescription(); return (description + (constraints ? ` satisfying the constraints: ${harnessPredicate.getDescription()}` : '')); } /** Gets a description string for a `TestElement` query. */ function _getDescriptionForTestElementQuery(selector) { return `TestElement for element matching selector: "${selector}"`; } /** Gets a description string for a `HarnessLoader` query. */ function _getDescriptionForHarnessLoaderQuery(selector) { return `HarnessLoader for element matching selector: "${selector}"`; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFybmVzcy1lbnZpcm9ubWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9jZGsvdGVzdGluZy9oYXJuZXNzLWVudmlyb25tZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7R0FNRztBQUVILE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QyxPQUFPLEVBRUwsZ0JBQWdCLEVBR2hCLGdCQUFnQixHQUlqQixNQUFNLHFCQUFxQixDQUFDO0FBcUI3Qjs7Ozs7R0FLRztBQUNILE1BQU0sT0FBZ0Isa0JBQWtCO0lBV3RDLFlBQWdDLGNBQWlCO1FBQWpCLG1CQUFjLEdBQWQsY0FBYyxDQUFHO0lBQUcsQ0FBQztJQVZyRCx5REFBeUQ7SUFDekQsSUFBSSxXQUFXO1FBQ2IsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsWUFBWSxJQUFJLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDckYsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDO0lBQzNCLENBQUM7SUFDRCxJQUFJLFdBQVcsQ0FBQyxPQUFvQjtRQUNsQyxJQUFJLENBQUMsWUFBWSxHQUFHLE9BQU8sQ0FBQztJQUM5QixDQUFDO0lBS0QseURBQXlEO0lBQ3pELDBCQUEwQjtRQUN4QixPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQseURBQXlEO0lBQ3pELFVBQVUsQ0FDUixHQUFHLE9BQVU7UUFFYixPQUFPLEdBQUcsRUFBRSxDQUNWLGtCQUFrQixDQUNoQixJQUFJLENBQUMsK0JBQStCLENBQUMsT0FBTyxDQUFDLEVBQzdDLG1DQUFtQyxDQUFDLE9BQU8sQ0FBQyxDQUM3QyxDQUFDO0lBQ04sQ0FBQztJQUVELHlEQUF5RDtJQUN6RCxrQkFBa0IsQ0FDaEIsR0FBRyxPQUFVO1FB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LEVBQUUsQ0FBQyxDQUN6RixDQUFDO0FBQ0osQ0FBQztBQUVELDJEQUEyRDtBQUMzRCxTQUFTLGtDQUFrQyxDQUFDLFFBQWdCO0lBQzFELE9BQU8sK0NBQStDLFFBQVEsR0FBRyxDQUFDO0FBQ3BFLENBQUM7QUFFRCw2REFBNkQ7QUFDN0QsU0FBUyxvQ0FBb0MsQ0FBQyxRQUFnQjtJQUM1RCxPQUFPLGlEQUFpRCxRQUFRLEdBQUcsQ0FBQztBQUN0RSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7cGFyYWxsZWx9IGZyb20gJy4vY2hhbmdlLWRldGVjdGlvbic7XG5pbXBvcnQge1xuICBBc3luY0ZhY3RvcnlGbixcbiAgQ29tcG9uZW50SGFybmVzcyxcbiAgQ29tcG9uZW50SGFybmVzc0NvbnN0cnVjdG9yLFxuICBIYXJuZXNzTG9hZGVyLFxuICBIYXJuZXNzUHJlZGljYXRlLFxuICBIYXJuZXNzUXVlcnksXG4gIExvY2F0b3JGYWN0b3J5LFxuICBMb2NhdG9yRm5SZXN1bHQsXG59IGZyb20gJy4vY29tcG9uZW50LWhhcm5lc3MnO1xuaW1wb3J0IHtUZXN0RWxlbWVudH0gZnJvbSAnLi90ZXN0LWVsZW1lbnQnO1xuXG4vKiogUGFyc2VkIGZvcm0gb2YgdGhlIHF1ZXJpZXMgcGFzc2VkIHRvIHRoZSBgbG9jYXRvckZvcipgIG1ldGhvZHMuICovXG50eXBlIFBhcnNlZFF1ZXJpZXM8VCBleHRlbmRzIENvbXBvbmVudEhhcm5lc3M+ID0ge1xuICAvKiogVGhlIGZ1bGwgbGlzdCBvZiBxdWVyaWVzLCBpbiB0aGVpciBvcmlnaW5hbCBvcmRlci4gKi9cbiAgYWxsUXVlcmllczogKHN0cmluZyB8IEhhcm5lc3NQcmVkaWNhdGU8VD4pW107XG4gIC8qKlxuICAgKiBBIGZpbHRlcmVkIHZpZXcgb2YgYGFsbFF1ZXJpZXNgIGNvbnRhaW5pbmcgb25seSB0aGUgcXVlcmllcyB0aGF0IGFyZSBsb29raW5nIGZvciBhXG4gICAqIGBDb21wb25lbnRIYXJuZXNzYFxuICAgKi9cbiAgaGFybmVzc1F1ZXJpZXM6IEhhcm5lc3NQcmVkaWNhdGU8VD5bXTtcbiAgLyoqXG4gICAqIEEgZmlsdGVyZWQgdmlldyBvZiBgYWxsUXVlcmllc2AgY29udGFpbmluZyBvbmx5IHRoZSBxdWVyaWVzIHRoYXQgYXJlIGxvb2tpbmcgZm9yIGFcbiAgICogYFRlc3RFbGVtZW50YFxuICAgKi9cbiAgZWxlbWVudFF1ZXJpZXM6IHN0cmluZ1tdO1xuICAvKiogVGhlIHNldCBvZiBhbGwgYENvbXBvbmVudEhhcm5lc3NgIHN1YmNsYXNzZXMgcmVwcmVzZW50ZWQgaW4gdGhlIG9yaWdpbmFsIHF1ZXJ5IGxpc3QuICovXG4gIGhhcm5lc3NUeXBlczogU2V0PENvbXBvbmVudEhhcm5lc3NDb25zdHJ1Y3RvcjxUPj47XG59O1xuXG4vKipcbiAqIEJhc2UgaGFybmVzcyBlbnZpcm9ubWVudCBjbGFzcyB0aGF0IGNhbiBiZSBleHRlbmRlZCB0byBhbGxvdyBgQ29tcG9uZW50SGFybmVzc2BlcyB0byBiZSB1c2VkIGluXG4gKiBkaWZmZXJlbnQgdGVzdCBlbnZpcm9ubWVudHMgKGUuZy4gdGVzdGJlZCwgcHJvdHJhY3RvciwgZXRjLikuIFRoaXMgY2xhc3MgaW1wbGVtZW50cyB0aGVcbiAqIGZ1bmN0aW9uYWxpdHkgb2YgYm90aCBhIGBIYXJuZXNzTG9hZGVyYCBhbmQgYExvY2F0b3JGYWN0b3J5YC4gVGhpcyBjbGFzcyBpcyBnZW5lcmljIG9uIHRoZSByYXdcbiAqIGVsZW1lbnQgdHlwZSwgYEVgLCB1c2VkIGJ5IHRoZSBwYXJ0aWN1bGFyIHRlc3QgZW52aXJvbm1lbnQuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBIYXJuZXNzRW52aXJvbm1lbnQ8RT4gaW1wbGVtZW50cyBIYXJuZXNzTG9hZGVyLCBMb2NhdG9yRmFjdG9yeSB7XG4gIC8vIEltcGxlbWVudGVkIGFzIHBhcnQgb2YgdGhlIGBMb2NhdG9yRmFjdG9yeWAgaW50ZXJmYWNlLlxuICBnZXQgcm9vdEVsZW1lbnQoKTogVGVzdEVsZW1lbnQge1xuICAgIHRoaXMuX3Jvb3RFbGVtZW50ID0gdGhpcy5fcm9vdEVsZW1lbnQgfHwgdGhpcy5jcmVhdGVUZXN0RWxlbWVudCh0aGlzLnJhd1Jvb3RFbGVtZW50KTtcbiAgICByZXR1cm4gdGhpcy5fcm9vdEVsZW1lbnQ7XG4gIH1cbiAgc2V0IHJvb3RFbGVtZW50KGVsZW1lbnQ6IFRlc3RFbGVtZW50KSB7XG4gICAgdGhpcy5fcm9vdEVsZW1lbnQgPSBlbGVtZW50O1xuICB9XG4gIHByaXZhdGUgX3Jvb3RFbGVtZW50OiBUZXN0RWxlbWVudCB8IHVuZGVmaW5lZDtcblxuICBwcm90ZWN0ZWQgY29uc3RydWN0b3IocHJvdGVjdGVkIHJhd1Jvb3RFbGVtZW50OiBFKSB7fVxuXG4gIC8vIEltcGxlbWVudGVkIGFzIHBhcnQgb2YgdGhlIGBMb2NhdG9yRmFjdG9yeWAgaW50ZXJmYWNlLlxuICBkb2N1bWVudFJvb3RMb2NhdG9yRmFjdG9yeSgpOiBMb2NhdG9yRmFjdG9yeSB7XG4gICAgcmV0dXJuIHRoaXMuY3JlYXRlRW52aXJvbm1lbnQodGhpcy5nZXREb2N1bWVudFJvb3QoKSk7XG4gIH1cblxuICAvLyBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIHRoZSBgTG9jYXRvckZhY3RvcnlgIGludGVyZmFjZS5cbiAgbG9jYXRvckZvcjxUIGV4dGVuZHMgKEhhcm5lc3NRdWVyeTxhbnk+IHwgc3RyaW5nKVtdPihcbiAgICAuLi5xdWVyaWVzOiBUXG4gICk6IEFzeW5jRmFjdG9yeUZuPExvY2F0b3JGblJlc3VsdDxUPj4ge1xuICAgIHJldHVybiAoKSA9PlxuICAgICAgX2Fzc2VydFJlc3VsdEZvdW5kKFxuICAgICAgICB0aGlzLl9nZXRBbGxIYXJuZXNzZXNBbmRUZXN0RWxlbWVudHMocXVlcmllcyksXG4gICAgICAgIF9nZXREZXNjcmlwdGlvbkZvckxvY2F0b3JGb3JRdWVyaWVzKHF1ZXJpZXMpLFxuICAgICAgKTtcbiAgfVxuXG4gIC8vIEltcGxlbWVudGVkIGFzIHBhcnQgb2YgdGhlIGBMb2NhdG9yRmFjdG9yeWAgaW50ZXJmYWNlLlxuICBsb2NhdG9yRm9yT3B0aW9uYWw8VCBleHRlbmRzIChIYXJuZXNzUXVlcnk8YW55PiB8IHN0cmluZylbXT4oXG4gICAgLi4ucXVlcmllczogVFxuICApOiBBc3luY0ZhY3RvcnlGbjxMb2NhdG9yRm5SZXN1bHQ8VD4gfCBudWxsPiB7XG4gICAgcmV0dXJuIGFzeW5jICgpID0+IChhd2FpdCB0aGlzLl9nZXRBbGxIYXJuZXNzZXNBbmRUZXN0RWxlbWVudHMocXVlcmllcykpWzBdIHx8IG51bGw7XG4gIH1cblxuICAvLyBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIHRoZSBgTG9jYXRvckZhY3RvcnlgIGludGVyZmFjZS5cbiAgbG9jYXRvckZvckFsbDxUIGV4dGVuZHMgKEhhcm5lc3NRdWVyeTxhbnk+IHwgc3RyaW5nKVtdPihcbiAgICAuLi5xdWVyaWVzOiBUXG4gICk6IEFzeW5jRmFjdG9yeUZuPExvY2F0b3JGblJlc3VsdDxUPltdPiB7XG4gICAgcmV0dXJuICgpID0+IHRoaXMuX2dldEFsbEhhcm5lc3Nlc0FuZFRlc3RFbGVtZW50cyhxdWVyaWVzKTtcbiAgfVxuXG4gIC8vIEltcGxlbWVudGVkIGFzIHBhcnQgb2YgdGhlIGBMb2NhdG9yRmFjdG9yeWAgaW50ZXJmYWNlLlxuICBhc3luYyByb290SGFybmVzc0xvYWRlcigpOiBQcm9taXNlPEhhcm5lc3NMb2FkZXI+IHtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEltcGxlbWVudGVkIGFzIHBhcnQgb2YgdGhlIGBMb2NhdG9yRmFjdG9yeWAgaW50ZXJmYWNlLlxuICBhc3luYyBoYXJuZXNzTG9hZGVyRm9yKHNlbGVjdG9yOiBzdHJpbmcpOiBQcm9taXNlPEhhcm5lc3NMb2FkZXI+IHtcbiAgICByZXR1cm4gdGhpcy5jcmVhdGVFbnZpcm9ubWVudChcbiAgICAgIGF3YWl0IF9hc3NlcnRSZXN1bHRGb3VuZCh0aGlzLmdldEFsbFJhd0VsZW1lbnRzKHNlbGVjdG9yKSwgW1xuICAgICAgICBfZ2V0RGVzY3JpcHRpb25Gb3JIYXJuZXNzTG9hZGVyUXVlcnkoc2VsZWN0b3IpLFxuICAgICAgXSksXG4gICAgKTtcbiAgfVxuXG4gIC8vIEltcGxlbWVudGVkIGFzIHBhcnQgb2YgdGhlIGBMb2NhdG9yRmFjdG9yeWAgaW50ZXJmYWNlLlxuICBhc3luYyBoYXJuZXNzTG9hZGVyRm9yT3B0aW9uYWwoc2VsZWN0b3I6IHN0cmluZyk6IFByb21pc2U8SGFybmVzc0xvYWRlciB8IG51bGw+IHtcbiAgICBjb25zdCBlbGVtZW50cyA9IGF3YWl0IHRoaXMuZ2V0QWxsUmF3RWxlbWVudHMoc2VsZWN0b3IpO1xuICAgIHJldHVybiBlbGVtZW50c1swXSA/IHRoaXMuY3JlYXRlRW52aXJvbm1lbnQoZWxlbWVudHNbMF0pIDogbnVsbDtcbiAgfVxuXG4gIC8vIEltcGxlbWVudGVkIGFzIHBhcnQgb2YgdGhlIGBMb2NhdG9yRmFjdG9yeWAgaW50ZXJmYWNlLlxuICBhc3luYyBoYXJuZXNzTG9hZGVyRm9yQWxsKHNlbGVjdG9yOiBzdHJpbmcpOiBQcm9taXNlPEhhcm5lc3NMb2FkZXJbXT4ge1xuICAgIGNvbnN0IGVsZW1lbnRzID0gYXdhaXQgdGhpcy5nZXRBbGxSYXdFbGVtZW50cyhzZWxlY3Rvcik7XG4gICAgcmV0dXJuIGVsZW1lbnRzLm1hcChlbGVtZW50ID0+IHRoaXMuY3JlYXRlRW52aXJvbm1lbnQoZWxlbWVudCkpO1xuICB9XG5cbiAgLy8gSW1wbGVtZW50ZWQgYXMgcGFydCBvZiB0aGUgYEhhcm5lc3NMb2FkZXJgIGludGVyZmFjZS5cbiAgZ2V0SGFybmVzczxUIGV4dGVuZHMgQ29tcG9uZW50SGFybmVzcz4ocXVlcnk6IEhhcm5lc3NRdWVyeTxUPik6IFByb21pc2U8VD4ge1xuICAgIHJldHVybiB0aGlzLmxvY2F0b3JGb3IocXVlcnkpKCk7XG4gIH1cblxuICAvLyBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIHRoZSBgSGFybmVzc0xvYWRlcmAgaW50ZXJmYWNlLlxuICBnZXRBbGxIYXJuZXNzZXM8VCBleHRlbmRzIENvbXBvbmVudEhhcm5lc3M+KHF1ZXJ5OiBIYXJuZXNzUXVlcnk8VD4pOiBQcm9taXNlPFRbXT4ge1xuICAgIHJldHVybiB0aGlzLmxvY2F0b3JGb3JBbGwocXVlcnkpKCk7XG4gIH1cblxuICAvLyBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIHRoZSBgSGFybmVzc0xvYWRlcmAgaW50ZXJmYWNlLlxuICBhc3luYyBnZXRDaGlsZExvYWRlcihzZWxlY3Rvcjogc3RyaW5nKTogUHJvbWlzZTxIYXJuZXNzTG9hZGVyPiB7XG4gICAgcmV0dXJuIHRoaXMuY3JlYXRlRW52aXJvbm1lbnQoXG4gICAgICBhd2FpdCBfYXNzZXJ0UmVzdWx0Rm91bmQodGhpcy5nZXRBbGxSYXdFbGVtZW50cyhzZWxlY3RvciksIFtcbiAgICAgICAgX2dldERlc2NyaXB0aW9uRm9ySGFybmVzc0xvYWRlclF1ZXJ5KHNlbGVjdG9yKSxcbiAgICAgIF0pLFxuICAgICk7XG4gIH1cblxuICAvLyBJbXBsZW1lbnRlZCBhcyBwYXJ0IG9mIHRoZSBgSGFybmVzc0xvYWRlcmAgaW50ZXJmYWNlLlxuICBhc3luYyBnZXRBbGxDaGlsZExvYWRlcnMoc2VsZWN0b3I6IHN0cmluZyk6IFByb21pc2U8SGFybmVzc0xvYWRlcltdPiB7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLmdldEFsbFJhd0VsZW1lbnRzKHNlbGVjdG9yKSkubWFwKGUgPT4gdGhpcy5jcmVhdGVFbnZpcm9ubWVudChlKSk7XG4gIH1cblxuICAvKiogQ3JlYXRlcyBhIGBDb21wb25lbnRIYXJuZXNzYCBmb3IgdGhlIGdpdmVuIGhhcm5lc3MgdHlwZSB3aXRoIHRoZSBnaXZlbiByYXcgaG9zdCBlbGVtZW50LiAqL1xuICBwcm90ZWN0ZWQgY3JlYXRlQ29tcG9uZW50SGFybmVzczxUIGV4dGVuZHMgQ29tcG9uZW50SGFybmVzcz4oXG4gICAgaGFybmVzc1R5cGU6IENvbXBvbmVudEhhcm5lc3NDb25zdHJ1Y3RvcjxUPixcbiAgICBlbGVtZW50OiBFLFxuICApOiBUIHtcbiAgICByZXR1cm4gbmV3IGhhcm5lc3NUeXBlKHRoaXMuY3JlYXRlRW52aXJvbm1lbnQoZWxlbWVudCkpO1xuICB9XG5cbiAgLy8gUGFydCBvZiBMb2NhdG9yRmFjdG9yeSBpbnRlcmZhY2UsIHN1YmNsYXNzZXMgd2lsbCBpbXBsZW1lbnQuXG4gIGFic3RyYWN0IGZvcmNlU3RhYmlsaXplKCk6IFByb21pc2U8dm9pZD47XG5cbiAgLy8gUGFydCBvZiBMb2NhdG9yRmFjdG9yeSBpbnRlcmZhY2UsIHN1YmNsYXNzZXMgd2lsbCBpbXBsZW1lbnQuXG4gIGFic3RyYWN0IHdhaXRGb3JUYXNrc091dHNpZGVBbmd1bGFyKCk6IFByb21pc2U8dm9pZD47XG5cbiAgLyoqIEdldHMgdGhlIHJvb3QgZWxlbWVudCBmb3IgdGhlIGRvY3VtZW50LiAqL1xuICBwcm90ZWN0ZWQgYWJzdHJhY3QgZ2V0RG9jdW1lbnRSb290KCk6IEU7XG5cbiAgLyoqIENyZWF0ZXMgYSBgVGVzdEVsZW1lbnRgIGZyb20gYSByYXcgZWxlbWVudC4gKi9cbiAgcHJvdGVjdGVkIGFic3RyYWN0IGNyZWF0ZVRlc3RFbGVtZW50KGVsZW1lbnQ6IEUpOiBUZXN0RWxlbWVudDtcblxuICAvKiogQ3JlYXRlcyBhIGBIYXJuZXNzTG9hZGVyYCByb290ZWQgYXQgdGhlIGdpdmVuIHJhdyBlbGVtZW50LiAqL1xuICBwcm90ZWN0ZWQgYWJzdHJhY3QgY3JlYXRlRW52aXJvbm1lbnQoZWxlbWVudDogRSk6IEhhcm5lc3NFbnZpcm9ubWVudDxFPjtcblxuICAvKipcbiAgICogR2V0cyBhIGxpc3Qgb2YgYWxsIGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBnaXZlbiBzZWxlY3RvciB1bmRlciB0aGlzIGVudmlyb25tZW50J3Mgcm9vdCBlbGVtZW50LlxuICAgKi9cbiAgcHJvdGVjdGVkIGFic3RyYWN0IGdldEFsbFJhd0VsZW1lbnRzKHNlbGVjdG9yOiBzdHJpbmcpOiBQcm9taXNlPEVbXT47XG5cbiAgLyoqXG4gICAqIE1hdGNoZXMgdGhlIGdpdmVuIHJhdyBlbGVtZW50cyB3aXRoIHRoZSBnaXZlbiBsaXN0IG9mIGVsZW1lbnQgYW5kIGhhcm5lc3MgcXVlcmllcyB0byBwcm9kdWNlIGFcbiAgICogbGlzdCBvZiBtYXRjaGVkIGhhcm5lc3NlcyBhbmQgdGVzdCBlbGVtZW50cy5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgX2dldEFsbEhhcm5lc3Nlc0FuZFRlc3RFbGVtZW50czxUIGV4dGVuZHMgKEhhcm5lc3NRdWVyeTxhbnk+IHwgc3RyaW5nKVtdPihcbiAgICBxdWVyaWVzOiBULFxuICApOiBQcm9taXNlPExvY2F0b3JGblJlc3VsdDxUPltdPiB7XG4gICAgY29uc3Qge2FsbFF1ZXJpZXMsIGhhcm5lc3NRdWVyaWVzLCBlbGVtZW50UXVlcmllcywgaGFybmVzc1R5cGVzfSA9IF9wYXJzZVF1ZXJpZXMocXVlcmllcyk7XG5cbiAgICAvLyBDb21iaW5lIGFsbCBvZiB0aGUgcXVlcmllcyBpbnRvIG9uZSBsYXJnZSBjb21tYS1kZWxpbWl0ZWQgc2VsZWN0b3IgYW5kIHVzZSBpdCB0byBnZXQgYWxsIHJhd1xuICAgIC8vIGVsZW1lbnRzIG1hdGNoaW5nIGFueSBvZiB0aGUgaW5kaXZpZHVhbCBxdWVyaWVzLlxuICAgIGNvbnN0IHJhd0VsZW1lbnRzID0gYXdhaXQgdGhpcy5nZXRBbGxSYXdFbGVtZW50cyhcbiAgICAgIFsuLi5lbGVtZW50UXVlcmllcywgLi4uaGFybmVzc1F1ZXJpZXMubWFwKHByZWRpY2F0ZSA9PiBwcmVkaWNhdGUuZ2V0U2VsZWN0b3IoKSldLmpvaW4oJywnKSxcbiAgICApO1xuXG4gICAgLy8gSWYgZXZlcnkgcXVlcnkgaXMgc2VhcmNoaW5nIGZvciB0aGUgc2FtZSBoYXJuZXNzIHN1YmNsYXNzLCB3ZSBrbm93IGV2ZXJ5IHJlc3VsdCBjb3JyZXNwb25kc1xuICAgIC8vIHRvIGFuIGluc3RhbmNlIG9mIHRoYXQgc3ViY2xhc3MuIExpa2V3aXNlLCBpZiBldmVyeSBxdWVyeSBpcyBmb3IgYSBgVGVzdEVsZW1lbnRgLCB3ZSBrbm93XG4gICAgLy8gZXZlcnkgcmVzdWx0IGNvcnJlc3BvbmRzIHRvIGEgYFRlc3RFbGVtZW50YC4gT3RoZXJ3aXNlIHdlIG5lZWQgdG8gdmVyaWZ5IHdoaWNoIHJlc3VsdCB3YXNcbiAgICAvLyBmb3VuZCBieSB3aGljaCBzZWxlY3RvciBzbyBpdCBjYW4gYmUgbWF0Y2hlZCB0byB0aGUgYXBwcm9wcmlhdGUgaW5zdGFuY2UuXG4gICAgY29uc3Qgc2tpcFNlbGVjdG9yQ2hlY2sgPVxuICAgICAgKGVsZW1lbnRRdWVyaWVzLmxlbmd0aCA9PT0gMCAmJiBoYXJuZXNzVHlwZXMuc2l6ZSA9PT0gMSkgfHwgaGFybmVzc1F1ZXJpZXMubGVuZ3RoID09PSAwO1xuXG4gICAgY29uc3QgcGVyRWxlbWVudE1hdGNoZXMgPSBhd2FpdCBwYXJhbGxlbCgoKSA9PlxuICAgICAgcmF3RWxlbWVudHMubWFwKGFzeW5jIHJhd0VsZW1lbnQgPT4ge1xuICAgICAgICBjb25zdCB0ZXN0RWxlbWVudCA9IHRoaXMuY3JlYXRlVGVzdEVsZW1lbnQocmF3RWxlbWVudCk7XG4gICAgICAgIGNvbnN0IGFsbFJlc3VsdHNGb3JFbGVtZW50ID0gYXdhaXQgcGFyYWxsZWwoXG4gICAgICAgICAgLy8gRm9yIGVhY2ggcXVlcnksIGdldCBgbnVsbGAgaWYgaXQgZG9lc24ndCBtYXRjaCwgb3IgYSBgVGVzdEVsZW1lbnRgIG9yXG4gICAgICAgICAgLy8gYENvbXBvbmVudEhhcm5lc3NgIGFzIGFwcHJvcHJpYXRlIGlmIGl0IGRvZXMgbWF0Y2guIFRoaXMgZ2l2ZXMgdXMgZXZlcnl0aGluZyB0aGF0XG4gICAgICAgICAgLy8gbWF0Y2hlcyB0aGUgY3VycmVudCByYXcgZWxlbWVudCwgYnV0IGl0IG1heSBjb250YWluIGR1cGxpY2F0ZSBlbnRyaWVzIChlLmcuXG4gICAgICAgICAgLy8gbXVsdGlwbGUgYFRlc3RFbGVtZW50YCBvciBtdWx0aXBsZSBgQ29tcG9uZW50SGFybmVzc2Agb2YgdGhlIHNhbWUgdHlwZSkuXG4gICAgICAgICAgKCkgPT5cbiAgICAgICAgICAgIGFsbFF1ZXJpZXMubWFwKHF1ZXJ5ID0+XG4gICAgICAgICAgICAgIHRoaXMuX2dldFF1ZXJ5UmVzdWx0Rm9yRWxlbWVudChxdWVyeSwgcmF3RWxlbWVudCwgdGVzdEVsZW1lbnQsIHNraXBTZWxlY3RvckNoZWNrKSxcbiAgICAgICAgICAgICksXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBfcmVtb3ZlRHVwbGljYXRlUXVlcnlSZXN1bHRzKGFsbFJlc3VsdHNGb3JFbGVtZW50KTtcbiAgICAgIH0pLFxuICAgICk7XG4gICAgcmV0dXJuIChbXSBhcyBhbnkpLmNvbmNhdCguLi5wZXJFbGVtZW50TWF0Y2hlcyk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgd2hldGhlciB0aGUgZ2l2ZW4gcXVlcnkgbWF0Y2hlcyB0aGUgZ2l2ZW4gZWxlbWVudCwgaWYgaXQgZG9lcyByZXR1cm4gdGhlIG1hdGNoZWRcbiAgICogYFRlc3RFbGVtZW50YCBvciBgQ29tcG9uZW50SGFybmVzc2AsIGlmIGl0IGRvZXMgbm90LCByZXR1cm4gbnVsbC4gSW4gY2FzZXMgd2hlcmUgdGhlIGNhbGxlclxuICAgKiBrbm93cyBmb3Igc3VyZSB0aGF0IHRoZSBxdWVyeSBtYXRjaGVzIHRoZSBlbGVtZW50J3Mgc2VsZWN0b3IsIGBza2lwU2VsZWN0b3JDaGVja2AgY2FuIGJlIHVzZWRcbiAgICogdG8gc2tpcCB2ZXJpZmljYXRpb24gYW5kIG9wdGltaXplIHBlcmZvcm1hbmNlLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBfZ2V0UXVlcnlSZXN1bHRGb3JFbGVtZW50PFQgZXh0ZW5kcyBDb21wb25lbnRIYXJuZXNzPihcbiAgICBxdWVyeTogc3RyaW5nIHwgSGFybmVzc1ByZWRpY2F0ZTxUPixcbiAgICByYXdFbGVtZW50OiBFLFxuICAgIHRlc3RFbGVtZW50OiBUZXN0RWxlbWVudCxcbiAgICBza2lwU2VsZWN0b3JDaGVjazogYm9vbGVhbiA9IGZhbHNlLFxuICApOiBQcm9taXNlPFQgfCBUZXN0RWxlbWVudCB8IG51bGw+IHtcbiAgICBpZiAodHlwZW9mIHF1ZXJ5ID09PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIHNraXBTZWxlY3RvckNoZWNrIHx8IChhd2FpdCB0ZXN0RWxlbWVudC5tYXRjaGVzU2VsZWN0b3IocXVlcnkpKSA/IHRlc3RFbGVtZW50IDogbnVsbDtcbiAgICB9XG4gICAgaWYgKHNraXBTZWxlY3RvckNoZWNrIHx8IChhd2FpdCB0ZXN0RWxlbWVudC5tYXRjaGVzU2VsZWN0b3IocXVlcnkuZ2V0U2VsZWN0b3IoKSkpKSB7XG4gICAgICBjb25zdCBoYXJuZXNzID0gdGhpcy5jcmVhdGVDb21wb25lbnRIYXJuZXNzKHF1ZXJ5Lmhhcm5lc3NUeXBlLCByYXdFbGVtZW50KTtcbiAgICAgIHJldHVybiAoYXdhaXQgcXVlcnkuZXZhbHVhdGUoaGFybmVzcykpID8gaGFybmVzcyA6IG51bGw7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG59XG5cbi8qKlxuICogUGFyc2VzIGEgbGlzdCBvZiBxdWVyaWVzIGluIHRoZSBmb3JtYXQgYWNjZXB0ZWQgYnkgdGhlIGBsb2NhdG9yRm9yKmAgbWV0aG9kcyBpbnRvIGFuIGVhc2llciB0b1xuICogd29yayB3aXRoIGZvcm1hdC5cbiAqL1xuZnVuY3Rpb24gX3BhcnNlUXVlcmllczxUIGV4dGVuZHMgKEhhcm5lc3NRdWVyeTxhbnk+IHwgc3RyaW5nKVtdPihcbiAgcXVlcmllczogVCxcbik6IFBhcnNlZFF1ZXJpZXM8TG9jYXRvckZuUmVzdWx0PFQ+ICYgQ29tcG9uZW50SGFybmVzcz4ge1xuICBjb25zdCBhbGxRdWVyaWVzID0gW107XG4gIGNvbnN0IGhhcm5lc3NRdWVyaWVzID0gW107XG4gIGNvbnN0IGVsZW1lbnRRdWVyaWVzID0gW107XG4gIGNvbnN0IGhhcm5lc3NUeXBlcyA9IG5ldyBTZXQ8XG4gICAgQ29tcG9uZW50SGFybmVzc0NvbnN0cnVjdG9yPExvY2F0b3JGblJlc3VsdDxUPiAmIENvbXBvbmVudEhhcm5lc3M+XG4gID4oKTtcblxuICBmb3IgKGNvbnN0IHF1ZXJ5IG9mIHF1ZXJpZXMpIHtcbiAgICBpZiAodHlwZW9mIHF1ZXJ5ID09PSAnc3RyaW5nJykge1xuICAgICAgYWxsUXVlcmllcy5wdXNoKHF1ZXJ5KTtcbiAgICAgIGVsZW1lbnRRdWVyaWVzLnB1c2gocXVlcnkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBwcmVkaWNhdGUgPSBxdWVyeSBpbnN0YW5jZW9mIEhhcm5lc3NQcmVkaWNhdGUgPyBxdWVyeSA6IG5ldyBIYXJuZXNzUHJlZGljYXRlKHF1ZXJ5LCB7fSk7XG4gICAgICBhbGxRdWVyaWVzLnB1c2gocHJlZGljYXRlKTtcbiAgICAgIGhhcm5lc3NRdWVyaWVzLnB1c2gocHJlZGljYXRlKTtcbiAgICAgIGhhcm5lc3NUeXBlcy5hZGQocHJlZGljYXRlLmhhcm5lc3NUeXBlKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge2FsbFF1ZXJpZXMsIGhhcm5lc3NRdWVyaWVzLCBlbGVtZW50UXVlcmllcywgaGFybmVzc1R5cGVzfTtcbn1cblxuLyoqXG4gKiBSZW1vdmVzIGR1cGxpY2F0ZSBxdWVyeSByZXN1bHRzIGZvciBhIHBhcnRpY3VsYXIgZWxlbWVudC4gKGUuZy4gbXVsdGlwbGUgYFRlc3RFbGVtZW50YFxuICogaW5zdGFuY2VzIG9yIG11bHRpcGxlIGluc3RhbmNlcyBvZiB0aGUgc2FtZSBgQ29tcG9uZW50SGFybmVzc2AgY2xhc3MuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIF9yZW1vdmVEdXBsaWNhdGVRdWVyeVJlc3VsdHM8VCBleHRlbmRzIChDb21wb25lbnRIYXJuZXNzIHwgVGVzdEVsZW1lbnQgfCBudWxsKVtdPihcbiAgcmVzdWx0czogVCxcbik6IFByb21pc2U8VD4ge1xuICBsZXQgdGVzdEVsZW1lbnRNYXRjaGVkID0gZmFsc2U7XG4gIGxldCBtYXRjaGVkSGFybmVzc1R5cGVzID0gbmV3IFNldCgpO1xuICBjb25zdCBkZWR1cGVkTWF0Y2hlcyA9IFtdO1xuICBmb3IgKGNvbnN0IHJlc3VsdCBvZiByZXN1bHRzKSB7XG4gICAgaWYgKCFyZXN1bHQpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgQ29tcG9uZW50SGFybmVzcykge1xuICAgICAgaWYgKCFtYXRjaGVkSGFybmVzc1R5cGVzLmhhcyhyZXN1bHQuY29uc3RydWN0b3IpKSB7XG4gICAgICAgIG1hdGNoZWRIYXJuZXNzVHlwZXMuYWRkKHJlc3VsdC5jb25zdHJ1Y3Rvcik7XG4gICAgICAgIGRlZHVwZWRNYXRjaGVzLnB1c2gocmVzdWx0KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKCF0ZXN0RWxlbWVudE1hdGNoZWQpIHtcbiAgICAgIHRlc3RFbGVtZW50TWF0Y2hlZCA9IHRydWU7XG4gICAgICBkZWR1cGVkTWF0Y2hlcy5wdXNoKHJlc3VsdCk7XG4gICAgfVxuICB9XG4gIHJldHVybiBkZWR1cGVkTWF0Y2hlcyBhcyBUO1xufVxuXG4vKiogVmVyaWZpZXMgdGhhdCB0aGVyZSBpcyBhdCBsZWFzdCBvbmUgcmVzdWx0IGluIGFuIGFycmF5LiAqL1xuYXN5bmMgZnVuY3Rpb24gX2Fzc2VydFJlc3VsdEZvdW5kPFQ+KFxuICByZXN1bHRzOiBQcm9taXNlPFRbXT4sXG4gIHF1ZXJ5RGVzY3JpcHRpb25zOiBzdHJpbmdbXSxcbik6IFByb21pc2U8VD4ge1xuICBjb25zdCByZXN1bHQgPSAoYXdhaXQgcmVzdWx0cylbMF07XG4gIGlmIChyZXN1bHQgPT0gdW5kZWZpbmVkKSB7XG4gICAgdGhyb3cgRXJyb3IoXG4gICAgICBgRmFpbGVkIHRvIGZpbmQgZWxlbWVudCBtYXRjaGluZyBvbmUgb2YgdGhlIGZvbGxvd2luZyBxdWVyaWVzOlxcbmAgK1xuICAgICAgICBxdWVyeURlc2NyaXB0aW9ucy5tYXAoZGVzYyA9PiBgKCR7ZGVzY30pYCkuam9pbignLFxcbicpLFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyoqIEdldHMgYSBsaXN0IG9mIGRlc2NyaXB0aW9uIHN0cmluZ3MgZnJvbSBhIGxpc3Qgb2YgcXVlcmllcy4gKi9cbmZ1bmN0aW9uIF9nZXREZXNjcmlwdGlvbkZvckxvY2F0b3JGb3JRdWVyaWVzKHF1ZXJpZXM6IChzdHJpbmcgfCBIYXJuZXNzUXVlcnk8YW55PilbXSkge1xuICByZXR1cm4gcXVlcmllcy5tYXAocXVlcnkgPT5cbiAgICB0eXBlb2YgcXVlcnkgPT09ICdzdHJpbmcnXG4gICAgICA/IF9nZXREZXNjcmlwdGlvbkZvclRlc3RFbGVtZW50UXVlcnkocXVlcnkpXG4gICAgICA6IF9nZXREZXNjcmlwdGlvbkZvckNvbXBvbmVudEhhcm5lc3NRdWVyeShxdWVyeSksXG4gICk7XG59XG5cbi8qKiBHZXRzIGEgZGVzY3JpcHRpb24gc3RyaW5nIGZvciBhIGBDb21wb25lbnRIYXJuZXNzYCBxdWVyeS4gKi9cbmZ1bmN0aW9uIF9nZXREZXNjcmlwdGlvbkZvckNvbXBvbmVudEhhcm5lc3NRdWVyeShxdWVyeTogSGFybmVzc1F1ZXJ5PGFueT4pIHtcbiAgY29uc3QgaGFybmVzc1ByZWRpY2F0ZSA9XG4gICAgcXVlcnkgaW5zdGFuY2VvZiBIYXJuZXNzUHJlZGljYXRlID8gcXVlcnkgOiBuZXcgSGFybmVzc1ByZWRpY2F0ZShxdWVyeSwge30pO1xuICBjb25zdCB7bmFtZSwgaG9zdFNlbGVjdG9yfSA9IGhhcm5lc3NQcmVkaWNhdGUuaGFybmVzc1R5cGU7XG4gIGNvbnN0IGRlc2NyaXB0aW9uID0gYCR7bmFtZX0gd2l0aCBob3N0IGVsZW1lbnQgbWF0Y2hpbmcgc2VsZWN0b3I6IFwiJHtob3N0U2VsZWN0b3J9XCJgO1xuICBjb25zdCBjb25zdHJhaW50cyA9IGhhcm5lc3NQcmVkaWNhdGUuZ2V0RGVzY3JpcHRpb24oKTtcbiAgcmV0dXJuIChcbiAgICBkZXNjcmlwdGlvbiArXG4gICAgKGNvbnN0cmFpbnRzID8gYCBzYXRpc2Z5aW5nIHRoZSBjb25zdHJhaW50czogJHtoYXJuZXNzUHJlZGljYXRlLmdldERlc2NyaXB0aW9uKCl9YCA6ICcnKVxuICApO1xufVxuXG4vKiogR2V0cyBhIGRlc2NyaXB0aW9uIHN0cmluZyBmb3IgYSBgVGVzdEVsZW1lbnRgIHF1ZXJ5LiAqL1xuZnVuY3Rpb24gX2dldERlc2NyaXB0aW9uRm9yVGVzdEVsZW1lbnRRdWVyeShzZWxlY3Rvcjogc3RyaW5nKSB7XG4gIHJldHVybiBgVGVzdEVsZW1lbnQgZm9yIGVsZW1lbnQgbWF0Y2hpbmcgc2VsZWN0b3I6IFwiJHtzZWxlY3Rvcn1cImA7XG59XG5cbi8qKiBHZXRzIGEgZGVzY3JpcHRpb24gc3RyaW5nIGZvciBhIGBIYXJuZXNzTG9hZGVyYCBxdWVyeS4gKi9cbmZ1bmN0aW9uIF9nZXREZXNjcmlwdGlvbkZvckhhcm5lc3NMb2FkZXJRdWVyeShzZWxlY3Rvcjogc3RyaW5nKSB7XG4gIHJldHVybiBgSGFybmVzc0xvYWRlciBmb3IgZWxlbWVudCBtYXRjaGluZyBzZWxlY3RvcjogXCIke3NlbGVjdG9yfVwiYDtcbn1cbiJdfQ==