@bespunky/angular-zen
Version:
The Angular tools you always wished were there.
178 lines • 30.9 kB
JavaScript
import { Injectable, ElementRef } from '@angular/core';
import { DocumentRef } from '../document-ref/document-ref.service';
import * as i0 from "@angular/core";
import * as i1 from "../document-ref/document-ref.service";
/**
* Provides tools for dynamically interacting with the head element.
*/
export class HeadService {
constructor(document) {
this.document = document;
}
/**
* Creates a <script> element, configures it and adds it to the <head> element.
*
* @param {string} type The type of script being added (e.g. 'text/javascript', 'application/javascript', etc.).
* @param {string} src The source of the script being added.
* @param {ScriptConfigurator} [config] (Optional) The configurator for the element. If an object was specified, the element's properties will be overwritten by the
* configurator's properties. If a function was specified, the function is run on the element without any other intervention.
* @returns {ElementRef<HTMLScriptElement>} A reference to the new element which has already been added to the <head> element.
*/
addScriptElement(type, src, config) {
return this.addElement('script', (script) => {
// Config the script
script.type = type;
script.src = src;
this.applyConfiguration(script, config);
});
}
/**
* Creates a <link> element, configures it and adds it to the <head> element.
*
* @param {(LinkRel | LinkRel[])} rel The relationship(s) of the link with the current document.
* @param {LinkConfigurator} [config] (Optional) The configurator for the element. If an object was specified, the element's properties will be overwritten by the
* configurator's properties. If a function was specified, the function is run on the element without any other intervention.
* @returns {ElementRef<HTMLLinkElement>} A reference to the new element which has already been added to the <head> element.
*/
addLinkElement(rel, config) {
return this.addElement('link', link => {
link.rel = Array.isArray(rel) ? rel.join(' ') : rel;
this.applyConfiguration(link, config);
});
}
/**
* Removes the first <link> element matching the specified params.
*
* @param {(LinkRel | LinkRel[])} rel The rel attribute value to look for.
* @param {ElementConfig<HTMLLinkElement>} lookup A map of attribute names and values to match with the element. All must match for the element to be detected.
* To match all elements containing a specific attribute regardless of the attribute's value, use the `'**'` value.
* @returns {(HTMLLinkElement | null)} The removed element, or null if none found.
*/
removeLinkElement(rel, lookup) {
return this.removeElement('link', this.buildLinkLookup(rel, lookup));
}
/**
* Removes all <link> elements matching the specified params.
*
* @param {(LinkRel | LinkRel[])} rel The rel attribute value to look for.
* @param {ElementConfig<HTMLLinkElement>} lookup A map of attribute names and values to match with the element. All must match for the element to be detected.
* To match all elements containing a specific attribute regardless of the attribute's value, use the `'**'` value.
* @returns {NodeListOf<HTMLLinkElement>} The list of removed elements.
*/
removeLinkElements(rel, lookup) {
return this.removeElements('link', this.buildLinkLookup(rel, lookup));
}
buildLinkLookup(rel, lookup) {
// If rel is an array, join to a space-separated string
const fullRel = Array.isArray(rel) ? rel.join(' ') : rel;
// Combine with the lookup object and return
return Object.assign(lookup, { rel: fullRel });
}
/**
* Creates an element of the given name, configures it and adds it to the <head> element.
*
* @template TElement The type of element being created.
* @param {string} name The name of the tag to create.
* @param {ElementConfigurator<TElement>} [config] (Optional) The configurator for the element. If an object was specified, the element's properties will be overwritten by the
* configurator's properties. If a function was specified, the function is run on the element without any other intervention.
* @returns {ElementRef<TElement>} A reference to the new element which has already been added to the <head> element.
*/
addElement(name, config) {
// Get DOM elements
const document = this.document.nativeDocument;
const head = document.head;
// Create the element tag
const element = document.createElement(name);
// Apply configuration on the element
this.applyConfiguration(element, config);
// Add the element tag to the <head> element
head.appendChild(element);
return new ElementRef(element);
}
/**
* Applies a configurator on an element.
*
* @private
* @template TElement The type of html element being configured.
* @param {TElement} element The element to configure.
* @param {ElementConfigurator<TElement>} [config] (Optional) The configurator for the element. If an object was specified, the element's properties will be overwritten by the
* configurator's properties. If a function was specified, the function is run on the element without any other intervention.
*/
applyConfiguration(element, config) {
config instanceof Function ? config(element) : Object.assign(element, config);
}
/**
* Finds the first element matching in name and attributes to the specified params and removes it from the <head> element.
*
* @template TElement The type of element being searched for.
* @param {string} name The name of the tag to look for.
* @param {ElementConfig<TElement>} lookup A map of attribute names and values to match with the element. All must match for the element to be detected.
* To match all elements containing a specific attribute regardless of the attribute's value, use the `'**'` value.
* @returns The removed element, or null if none found.
*/
removeElement(name, lookup) {
const element = this.findElements(name, lookup)[0];
element?.remove();
return element || null;
}
/**
* Finds all elements matching in name and attributes to the specified params and removes them from the <head> element.
*
* @template TElement The type of element being searched for.
* @param {string} name The name of the tag to look for.
* @param {ElementConfig<TElement>} lookup A map of attribute names and values to match with the element. All must match for the element to be detected.
* To match all elements containing a specific attribute regardless of the attribute's value, use the `'**'` value.
* @returns The list of removed elements.
*/
removeElements(name, lookup) {
const elements = this.findElements(name, lookup);
elements.forEach(element => element.remove());
return elements;
}
/**
* Finds all elements inside of <head> which match in name and attributes to the specified params.
*
* @template TElement The type of element being searched for.
* @param {string} name The name of the tag to look for.
* @param {ElementConfig<TElement>} lookup A map of attribute names and values to match with the element. All must match for the element to be detected.
* To match all elements containing a specific attribute regardless of the attribute's value, use the `'**'` value.
* @returns A node list of all matching elements inside of <head>.
*/
findElements(name, lookup) {
// Get DOM elements
const document = this.document.nativeDocument;
const head = document.head;
const attributes = Object.keys(lookup).map(key => {
const attribute = key;
const value = lookup[attribute];
// If a wildcard was specified for the attribute...
return value === '**' ?
// ... Query only by attribute name
`[${String(attribute)}]` :
// Otherwise, match the exact value
`[${String(attribute)}="${value}"]`;
}).join('');
return head.querySelectorAll(`${name}${attributes}`);
}
/**
* Checks whether an element with the given tag name and attributes exists in <head>.
*
* @template TElement The type of element being searched for.
* @param {string} name The name of the tag to look for.
* @param {ElementConfig<TElement>} lookup A map of attribute names and values to match with the element. All must match for the element to be detected.
* To match all elements containing a specific attribute regardless of the attribute's value, use the `'**'` value.
* @returns {boolean} `true` if <head> contains a matching element; otherwise `false.
*/
contains(name, lookup) {
return !!this.findElements(name, lookup).length;
}
}
HeadService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: HeadService, deps: [{ token: i1.DocumentRef }], target: i0.ɵɵFactoryTarget.Injectable });
HeadService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: HeadService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: HeadService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: function () { return [{ type: i1.DocumentRef }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVhZC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9hbmd1bGFyLXplbi9jb3JlL3NyYy9oZWFkL2hlYWQuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUV2RCxPQUFPLEVBQUUsV0FBVyxFQUFpQyxNQUFNLHNDQUFzQyxDQUFDOzs7QUErQmxHOztHQUVHO0FBSUgsTUFBTSxPQUFPLFdBQVc7SUFFcEIsWUFBb0IsUUFBcUI7UUFBckIsYUFBUSxHQUFSLFFBQVEsQ0FBYTtJQUFJLENBQUM7SUFFOUM7Ozs7Ozs7O09BUUc7SUFDSSxnQkFBZ0IsQ0FBQyxJQUFZLEVBQUUsR0FBVyxFQUFFLE1BQTJCO1FBRTFFLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxNQUFNLEVBQUUsRUFBRTtZQUV4QyxvQkFBb0I7WUFDcEIsTUFBTSxDQUFDLElBQUksR0FBSSxJQUFJLENBQUM7WUFDcEIsTUFBTSxDQUFDLEdBQUcsR0FBSyxHQUFHLENBQUM7WUFFbkIsSUFBSSxDQUFDLGtCQUFrQixDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUM1QyxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0ksY0FBYyxDQUFDLEdBQXdCLEVBQUUsTUFBeUI7UUFFckUsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFrQixNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUU7WUFFbkQsSUFBSSxDQUFDLEdBQUcsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7WUFFcEQsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksRUFBRSxN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QyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFO1lBRTdDLE1BQU0sU0FBUyxHQUFHLEdBQW9DLENBQUM7WUFDdkQsTUFBTSxLQUFLLEdBQU8sTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBRXBDLG1EQUFtRDtZQUNuRCxPQUFPLEtBQUssS0FBSyxJQUFJLENBQUMsQ0FBQztnQkFDbkIsbUNBQW1DO2dCQUNuQyxJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQzFCLG1DQUFtQztnQkFDbkMsSUFBSSxNQUFNLENBQUMsU0FBUyxDQUFDLEtBQUssS0FBSyxJQUFJLENBQUM7UUFDNUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRVosT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxJQUFJLEdBQUcsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSSxRQUFRLENBQStCLElBQVksRUFBRSxNQUErQjtRQUV2RixPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDcEQsQ0FBQzs7eUdBck1RLFdBQVc7NkdBQVgsV0FBVyxjQUZSLE1BQU07NEZBRVQsV0FBVztrQkFIdkIsVUFBVTttQkFBQztvQkFDUixVQUFVLEVBQUUsTUFBTTtpQkFDckIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBFbGVtZW50UmVmIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IERvY3VtZW50UmVmICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGZyb20gJy4uL2RvY3VtZW50LXJlZi9kb2N1bWVudC1yZWYuc2VydmljZSc7XG5pbXBvcnQgeyBFbGVtZW50Q29uZmlnLCBMb2FkRXZlbnRIYW5kbGluZ0F0dHJpYnV0ZXMgfSBmcm9tICcuL2VsZW1lbnQtY29uZmlncyc7XG5cbi8qKiBBIGZ1bmN0aW9uIHRoYXQgbW9kaWZpZXMgdGhlIGF0dHJpYnV0ZXMgb2YgYSBuZXdseSBjcmVhdGVkIGVsZW1lbnQgYmVmb3JlIGl0J3MgYWRkZWQgdG8gdGhlIGRvY3VtZW50LiAqL1xuZXhwb3J0IHR5cGUgRWxlbWVudENvbmZpZ0ZuPFRFbGVtZW50IGV4dGVuZHMgSFRNTEVsZW1lbnQ+ID0gKGVsZW1lbnQ6IFRFbGVtZW50KSA9PiB2b2lkO1xuXG4vKiogVGhlIHdlbGwta25vd24gJ3JlbCcgdmFsdWVzIGZvciBhIDxsaW5rPiBlbGVtZW50LiAqL1xuZXhwb3J0IHR5cGUgTGlua1JlbCA9ICdhbHRlcm5hdGUnIHwgJ2F1dGhvcicgfCAnY2Fub25pY2FsJyB8ICdkbnMtcHJlZmV0Y2gnIHwgJ2hlbHAnIHwgJ2ljb24nIHwgJ2xpY2Vuc2UnIHwgJ25leHQnIHwgJ3BpbmdiYWNrJyB8ICdwcmVjb25uZWN0JyB8ICdwcmVmZXRjaCcgfCAncHJlbG9hZCcgfCAncHJlcmVuZGVyJyB8ICdwcmV2JyB8ICdzZWFyY2gnIHwgJ3N0eWxlc2hlZXQnO1xuXG4vKipcbiAqIEVpdGhlciBhIGNvbmZpZ3VyYXRpbmcgZnVuY3Rpb24gb3IgYSBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgbmV3IGVsZW1lbnRzLlxuICogRm9yIG9iamVjdHMsIHRoZSBlbGVtZW50J3MgcHJvcGVydGllcyBzaG91bGQgYmUgb3ZlcndyaXR0ZW4gYnkgdGhlIGNvbmZpZ3VyYXRvcidzIHByb3BlcnRpZXMuXG4gKiBGb3IgZnVuY3Rpb25zLCB0aGUgZnVuY3Rpb24gc2hvdWxkIGJlIHJ1biBvbiB0aGUgZWxlbWVudCB3aXRob3V0IGFueSBvdGhlciBpbnRlcnZlbnRpb24uXG4gKiBcbiAqIEB0eXBlIHtURWxlbWVudH0gVGhlIHR5cGUgb2YgaHRtbCBlbGVtZW50IGJlaW5nIGNvbmZpZ3VyZWQuXG4gKiBAdHlwZSB7VEtlZXB9IChPcHRpb25hbCkgQSB1bmlvbiB0eXBlIG9mIGdlbmVyYWwgaHRtbCBlbGVtZW50IGF0dHJpYnV0ZXMgdG8ga2VlcC4gU2VlIGBFbGVtZW50Q29uZmlnYC5cbiAqL1xuZXhwb3J0IHR5cGUgRWxlbWVudENvbmZpZ3VyYXRvcjxURWxlbWVudCBleHRlbmRzIEhUTUxFbGVtZW50LCBUS2VlcCBleHRlbmRzIGtleW9mIEhUTUxFbGVtZW50ID0gbmV2ZXI+ID0gRWxlbWVudENvbmZpZzxURWxlbWVudCwgVEtlZXA+IHwgRWxlbWVudENvbmZpZ0ZuPFRFbGVtZW50PlxuLyoqXG4gKiBFaXRoZXIgYSBjb25maWd1cmF0aW5nIGZ1bmN0aW9uIG9yIGEgY29uZmlndXJhdGlvbiBvYmplY3QgZm9yIDxzY3JpcHQ+IHRhZ3MuXG4gKiBGb3Igb2JqZWN0cywgdGhlIGVsZW1lbnQncyBwcm9wZXJ0aWVzIHNob3VsZCBiZSBvdmVyd3JpdHRlbiBieSB0aGUgY29uZmlndXJhdG9yJ3MgcHJvcGVydGllcy5cbiAqIEZvciBmdW5jdGlvbnMsIHRoZSBmdW5jdGlvbiBzaG91bGQgYmUgcnVuIG9uIHRoZSBlbGVtZW50IHdpdGhvdXQgYW55IG90aGVyIGludGVydmVudGlvbi5cbiAqL1xuZXhwb3J0IHR5cGUgU2NyaXB0Q29uZmlndXJhdG9yID0gRWxlbWVudENvbmZpZ3VyYXRvcjxIVE1MU2NyaXB0RWxlbWVudCwgTG9hZEV2ZW50SGFuZGxpbmdBdHRyaWJ1dGVzPjtcbi8qKlxuICogRWl0aGVyIGEgY29uZmlndXJhdGluZyBmdW5jdGlvbiBvciBhIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciA8bGluaz4gdGFncy5cbiAqIEZvciBvYmplY3RzLCB0aGUgZWxlbWVudCdzIHByb3BlcnRpZXMgc2hvdWxkIGJlIG92ZXJ3cml0dGVuIGJ5IHRoZSBjb25maWd1cmF0b3IncyBwcm9wZXJ0aWVzLlxuICogRm9yIGZ1bmN0aW9ucywgdGhlIGZ1bmN0aW9uIHNob3VsZCBiZSBydW4gb24gdGhlIGVsZW1lbnQgd2l0aG91dCBhbnkgb3RoZXIgaW50ZXJ2ZW50aW9uLlxuICovXG5leHBvcnQgdHlwZSBMaW5rQ29uZmlndXJhdG9yICAgPSBFbGVtZW50Q29uZmlndXJhdG9yPEhUTUxMaW5rRWxlbWVudCwgICBMb2FkRXZlbnRIYW5kbGluZ0F0dHJpYnV0ZXM+O1xuXG4vKipcbiAqIFByb3ZpZGVzIHRvb2xzIGZvciBkeW5hbWljYWxseSBpbnRlcmFjdGluZyB3aXRoIHRoZSBoZWFkIGVsZW1lbnQuXG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgICBwcm92aWRlZEluOiAncm9vdCdcbn0pXG5leHBvcnQgY2xhc3MgSGVhZFNlcnZpY2VcbntcbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIGRvY3VtZW50OiBEb2N1bWVudFJlZikgeyB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgPHNjcmlwdD4gZWxlbWVudCwgY29uZmlndXJlcyBpdCBhbmQgYWRkcyBpdCB0byB0aGUgPGhlYWQ+IGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdHlwZSBUaGUgdHlwZSBvZiBzY3JpcHQgYmVpbmcgYWRkZWQgKGUuZy4gJ3RleHQvamF2YXNjcmlwdCcsICdhcHBsaWNhdGlvbi9qYXZhc2NyaXB0JywgZXRjLikuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHNyYyBUaGUgc291cmNlIG9mIHRoZSBzY3JpcHQgYmVpbmcgYWRkZWQuXG4gICAgICogQHBhcmFtIHtTY3JpcHRDb25maWd1cmF0b3J9IFtjb25maWddIChPcHRpb25hbCkgVGhlIGNvbmZpZ3VyYXRvciBmb3IgdGhlIGVsZW1lbnQuIElmIGFuIG9iamVjdCB3YXMgc3BlY2lmaWVkLCB0aGUgZWxlbWVudCdzIHByb3BlcnRpZXMgd2lsbCBiZSBvdmVyd3JpdHRlbiBieSB0aGVcbiAgICAgKiBjb25maWd1cmF0b3IncyBwcm9wZXJ0aWVzLiBJZiBhIGZ1bmN0aW9uIHdhcyBzcGVjaWZpZWQsIHRoZSBmdW5jdGlvbiBpcyBydW4gb24gdGhlIGVsZW1lbnQgd2l0aG91dCBhbnkgb3RoZXIgaW50ZXJ2ZW50aW9uLlxuICAgICAqIEByZXR1cm5zIHtFbGVtZW50UmVmPEhUTUxTY3JpcHRFbGVtZW50Pn0gQSByZWZlcmVuY2UgdG8gdGhlIG5ldyBlbGVtZW50IHdoaWNoIGhhcyBhbHJlYWR5IGJlZW4gYWRkZWQgdG8gdGhlIDxoZWFkPiBlbGVtZW50LlxuICAgICAqL1xuICAgIHB1YmxpYyBhZGRTY3JpcHRFbGVtZW50KHR5cGU6IHN0cmluZywgc3JjOiBzdHJpbmcsIGNvbmZpZz86IFNjcmlwdENvbmZpZ3VyYXRvcik6IEVsZW1lbnRSZWY8SFRNTFNjcmlwdEVsZW1lbnQ+XG4gICAge1xuICAgICAgICByZXR1cm4gdGhpcy5hZGRFbGVtZW50KCdzY3JpcHQnLCAoc2NyaXB0KSA9PlxuICAgICAgICB7XG4gICAgICAgICAgICAvLyBDb25maWcgdGhlIHNjcmlwdFxuICAgICAgICAgICAgc2NyaXB0LnR5cGUgID0gdHlwZTtcbiAgICAgICAgICAgIHNjcmlwdC5zcmMgICA9IHNyYztcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgdGhpcy5hcHBseUNvbmZpZ3VyYXRpb24oc2NyaXB0LCBjb25maWcpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgPGxpbms+IGVsZW1lbnQsIGNvbmZpZ3VyZXMgaXQgYW5kIGFkZHMgaXQgdG8gdGhlIDxoZWFkPiBlbGVtZW50LlxuICAgICAqXG4gICAgICogQHBhcmFtIHsoTGlua1JlbCB8IExpbmtSZWxbXSl9IHJlbCBUaGUgcmVsYXRpb25zaGlwKHMpIG9mIHRoZSBsaW5rIHdpdGggdGhlIGN1cnJlbnQgZG9jdW1lbnQuXG4gICAgICogQHBhcmFtIHtMaW5rQ29uZmlndXJhdG9yfSBbY29uZmlnXSAoT3B0aW9uYWwpIFRoZSBjb25maWd1cmF0b3IgZm9yIHRoZSBlbGVtZW50LiBJZiBhbiBvYmplY3Qgd2FzIHNwZWNpZmllZCwgdGhlIGVsZW1lbnQncyBwcm9wZXJ0aWVzIHdpbGwgYmUgb3ZlcndyaXR0ZW4gYnkgdGhlXG4gICAgICogY29uZmlndXJhdG9yJ3MgcHJvcGVydGllcy4gSWYgYSBmdW5jdGlvbiB3YXMgc3BlY2lmaWVkLCB0aGUgZnVuY3Rpb24gaXMgcnVuIG9uIHRoZSBlbGVtZW50IHdpdGhvdXQgYW55IG90aGVyIGludGVydmVudGlvbi5cbiAgICAgKiBAcmV0dXJucyB7RWxlbWVudFJlZjxIVE1MTGlua0VsZW1lbnQ+fSBBIHJlZmVyZW5jZSB0byB0aGUgbmV3IGVsZW1lbnQgd2hpY2ggaGFzIGFscmVhZHkgYmVlbiBhZGRlZCB0byB0aGUgPGhlYWQ+IGVsZW1lbnQuXG4gICAgICovXG4gICAgcHVibGljIGFkZExpbmtFbGVtZW50KHJlbDogTGlua1JlbCB8IExpbmtSZWxbXSwgY29uZmlnPzogTGlua0NvbmZpZ3VyYXRvcik6IEVsZW1lbnRSZWY8SFRNTExpbmtFbGVtZW50PlxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRkRWxlbWVudDxIVE1MTGlua0VsZW1lbnQ+KCdsaW5rJywgbGluayA9PlxuICAgICAgICB7XG4gICAgICAgICAgICBsaW5rLnJlbCA9IEFycmF5LmlzQXJyYXkocmVsKSA/IHJlbC5qb2luKCcgJykgOiByZWw7XG5cbiAgICAgICAgICAgIHRoaXMuYXBwbHlDb25maWd1cmF0aW9uKGxpbmssIGNvbmZpZyk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgdGhlIGZpcnN0IDxsaW5rPiBlbGVtZW50IG1hdGNoaW5nIHRoZSBzcGVjaWZpZWQgcGFyYW1zLlxuICAgICAqXG4gICAgICogQHBhcmFtIHsoTGlua1JlbCB8IExpbmtSZWxbXSl9IHJlbCBUaGUgcmVsIGF0dHJpYnV0ZSB2YWx1ZSB0byBsb29rIGZvci5cbiAgICAgKiBAcGFyYW0ge0VsZW1lbnRDb25maWc8SFRNTExpbmtFbGVtZW50Pn0gbG9va3VwIEEgbWFwIG9mIGF0dHJpYnV0ZSBuYW1lcyBhbmQgdmFsdWVzIHRvIG1hdGNoIHdpdGggdGhlIGVsZW1lbnQuIEFsbCBtdXN0IG1hdGNoIGZvciB0aGUgZWxlbWVudCB0byBiZSBkZXRlY3RlZC5cbiAgICAgKiBUbyBtYXRjaCBhbGwgZWxlbWVudHMgY29udGFpbmluZyBhIHNwZWNpZmljIGF0dHJpYnV0ZSByZWdhcmRsZXNzIG9mIHRoZSBhdHRyaWJ1dGUncyB2YWx1ZSwgdXNlIHRoZSBgJyoqJ2AgdmFsdWUuXG4gICAgICogQHJldHVybnMgeyhIVE1MTGlua0VsZW1lbnQgfCBudWxsKX0gVGhlIHJlbW92ZWQgZWxlbWVudCwgb3IgbnVsbCBpZiBub25lIGZvdW5kLlxuICAgICAqL1xuICAgIHB1YmxpYyByZW1vdmVMaW5rRWxlbWVudChyZWw6IExpbmtSZWwgfCBMaW5rUmVsW10sIGxvb2t1cDogRWxlbWVudENvbmZpZzxIVE1MTGlua0VsZW1lbnQ+KTogSFRNTExpbmtFbGVtZW50IHwgbnVsbFxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVtb3ZlRWxlbWVudCgnbGluaycsIHRoaXMuYnVpbGRMaW5rTG9va3VwKHJlbCwgbG9va3VwKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyBhbGwgPGxpbms+IGVsZW1lbnRzIG1hdGNoaW5nIHRoZSBzcGVjaWZpZWQgcGFyYW1zLlxuICAgICAqXG4gICAgICogQHBhcmFtIHsoTGlua1JlbCB8IExpbmtSZWxbXSl9IHJlbCBUaGUgcmVsIGF0dHJpYnV0ZSB2YWx1ZSB0byBsb29rIGZvci5cbiAgICAgKiBAcGFyYW0ge0VsZW1lbnRDb25maWc8SFRNTExpbmtFbGVtZW50Pn0gbG9va3VwIEEgbWFwIG9mIGF0dHJpYnV0ZSBuYW1lcyBhbmQgdmFsdWVzIHRvIG1hdGNoIHdpdGggdGhlIGVsZW1lbnQuIEFsbCBtdXN0IG1hdGNoIGZvciB0aGUgZWxlbWVudCB0byBiZSBkZXRlY3RlZC5cbiAgICAgKiBUbyBtYXRjaCBhbGwgZWxlbWVudHMgY29udGFpbmluZyBhIHNwZWNpZmljIGF0dHJpYnV0ZSByZWdhcmRsZXNzIG9mIHRoZSBhdHRyaWJ1dGUncyB2YWx1ZSwgdXNlIHRoZSBgJyoqJ2AgdmFsdWUuXG4gICAgICogQHJldHVybnMge05vZGVMaXN0T2Y8SFRNTExpbmtFbGVtZW50Pn0gVGhlIGxpc3Qgb2YgcmVtb3ZlZCBlbGVtZW50cy5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVtb3ZlTGlua0VsZW1lbnRzKHJlbDogTGlua1JlbCB8IExpbmtSZWxbXSwgbG9va3VwOiBFbGVtZW50Q29uZmlnPEhUTUxMaW5rRWxlbWVudD4pOiBOb2RlTGlzdE9mPEhUTUxMaW5rRWxlbWVudD5cbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLnJlbW92ZUVsZW1lbnRzKCdsaW5rJywgdGhpcy5idWlsZExpbmtMb29rdXAocmVsLCBsb29rdXApKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGJ1aWxkTGlua0xvb2t1cChyZWw6IExpbmtSZWwgfCBMaW5rUmVsW10sIGxvb2t1cDogRWxlbWVudENvbmZpZzxIVE1MTGlua0VsZW1lbnQ+KTogRWxlbWVudENvbmZpZzxIVE1MTGlua0VsZW1lbnQ+XG4gICAge1xuICAgICAgICAvLyBJZiByZWwgaXMgYW4gYXJyYXksIGpvaW4gdG8gYSBzcGFjZS1zZXBhcmF0ZWQgc3RyaW5nXG4gICAgICAgIGNvbnN0IGZ1bGxSZWwgPSBBcnJheS5pc0FycmF5KHJlbCkgPyByZWwuam9pbignICcpIDogcmVsO1xuXG4gICAgICAgIC8vIENvbWJpbmUgd2l0aCB0aGUgbG9va3VwIG9iamVjdCBhbmQgcmV0dXJuXG4gICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKGxvb2t1cCwgeyByZWw6IGZ1bGxSZWwgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBlbGVtZW50IG9mIHRoZSBnaXZlbiBuYW1lLCBjb25maWd1cmVzIGl0IGFuZCBhZGRzIGl0IHRvIHRoZSA8aGVhZD4gZWxlbWVudC5cbiAgICAgKlxuICAgICAqIEB0ZW1wbGF0ZSBURWxlbWVudCBUaGUgdHlwZSBvZiBlbGVtZW50IGJlaW5nIGNyZWF0ZWQuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgVGhlIG5hbWUgb2YgdGhlIHRhZyB0byBjcmVhdGUuXG4gICAgICogQHBhcmFtIHtFbGVtZW50Q29uZmlndXJhdG9yPFRFbGVtZW50Pn0gW2NvbmZpZ10gKE9wdGlvbmFsKSBUaGUgY29uZmlndXJhdG9yIGZvciB0aGUgZWxlbWVudC4gSWYgYW4gb2JqZWN0IHdhcyBzcGVjaWZpZWQsIHRoZSBlbGVtZW50J3MgcHJvcGVydGllcyB3aWxsIGJlIG92ZXJ3cml0dGVuIGJ5IHRoZVxuICAgICAqIGNvbmZpZ3VyYXRvcidzIHByb3BlcnRpZXMuIElmIGEgZnVuY3Rpb24gd2FzIHNwZWNpZmllZCwgdGhlIGZ1bmN0aW9uIGlzIHJ1biBvbiB0aGUgZWxlbWVudCB3aXRob3V0IGFueSBvdGhlciBpbnRlcnZlbnRpb24uXG4gICAgICogQHJldHVybnMge0VsZW1lbnRSZWY8VEVsZW1lbnQ+fSBBIHJlZmVyZW5jZSB0byB0aGUgbmV3IGVsZW1lbnQgd2hpY2ggaGFzIGFscmVhZHkgYmVlbiBhZGRlZCB0byB0aGUgPGhlYWQ+IGVsZW1lbnQuXG4gICAgICovXG4gICAgcHVibGljIGFkZEVsZW1lbnQ8VEVsZW1lbnQgZXh0ZW5kcyBIVE1MRWxlbWVudD4obmFtZTogc3RyaW5nLCBjb25maWc/OiBFbGVtZW50Q29uZmlndXJhdG9yPFRFbGVtZW50Pik6IEVsZW1lbnRSZWY8VEVsZW1lbnQ+XG4gICAge1xuICAgICAgICAvLyBHZXQgRE9NIGVsZW1lbnRzXG4gICAgICAgIGNvbnN0IGRvY3VtZW50ID0gdGhpcy5kb2N1bWVudC5uYXRpdmVEb2N1bWVudCBhcyBEb2N1bWVudDtcbiAgICAgICAgY29uc3QgaGVhZCAgICAgPSBkb2N1bWVudC5oZWFkO1xuICAgICAgICAvLyBDcmVhdGUgdGhlIGVsZW1lbnQgdGFnXG4gICAgICAgIGNvbnN0IGVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KG5hbWUpIGFzIFRFbGVtZW50O1xuXG4gICAgICAgIC8vIEFwcGx5IGNvbmZpZ3VyYXRpb24gb24gdGhlIGVsZW1lbnRcbiAgICAgICAgdGhpcy5hcHBseUNvbmZpZ3VyYXRpb24oZWxlbWVudCwgY29uZmlnKTtcblxuICAgICAgICAvLyBBZGQgdGhlIGVsZW1lbnQgdGFnIHRvIHRoZSA8aGVhZD4gZWxlbWVudFxuICAgICAgICBoZWFkLmFwcGVuZENoaWxkKGVsZW1lbnQpO1xuXG4gICAgICAgIHJldHVybiBuZXcgRWxlbWVudFJlZihlbGVtZW50KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBcHBsaWVzIGEgY29uZmlndXJhdG9yIG9uIGFuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEB0ZW1wbGF0ZSBURWxlbWVudCBUaGUgdHlwZSBvZiBodG1sIGVsZW1lbnQgYmVpbmcgY29uZmlndXJlZC5cbiAgICAgKiBAcGFyYW0ge1RFbGVtZW50fSBlbGVtZW50IFRoZSBlbGVtZW50IHRvIGNvbmZpZ3VyZS5cbiAgICAgKiBAcGFyYW0ge0VsZW1lbnRDb25maWd1cmF0b3I8VEVsZW1lbnQ+fSBbY29uZmlnXSAoT3B0aW9uYWwpIFRoZSBjb25maWd1cmF0b3IgZm9yIHRoZSBlbGVtZW50LiBJZiBhbiBvYmplY3Qgd2FzIHNwZWNpZmllZCwgdGhlIGVsZW1lbnQncyBwcm9wZXJ0aWVzIHdpbGwgYmUgb3ZlcndyaXR0ZW4gYnkgdGhlXG4gICAgICogY29uZmlndXJhdG9yJ3MgcHJvcGVydGllcy4gSWYgYSBmdW5jdGlvbiB3YXMgc3BlY2lmaWVkLCB0aGUgZnVuY3Rpb24gaXMgcnVuIG9uIHRoZSBlbGVtZW50IHdpdGhvdXQgYW55IG90aGVyIGludGVydmVudGlvbi5cbiAgICAgKi9cbiAgICBwcml2YXRlIGFwcGx5Q29uZmlndXJhdGlvbjxURWxlbWVudCBleHRlbmRzIEhUTUxFbGVtZW50PihlbGVtZW50OiBURWxlbWVudCwgY29uZmlnPzogRWxlbWVudENvbmZpZ3VyYXRvcjxURWxlbWVudD4pOiB2b2lkXG4gICAge1xuICAgICAgICBjb25maWcgaW5zdGFuY2VvZiBGdW5jdGlvbiA/IGNvbmZpZyhlbGVtZW50KSA6IE9iamVjdC5hc3NpZ24oZWxlbWVudCwgY29uZmlnKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBGaW5kcyB0aGUgZmlyc3QgZWxlbWVudCBtYXRjaGluZyBpbiBuYW1lIGFuZCBhdHRyaWJ1dGVzIHRvIHRoZSBzcGVjaWZpZWQgcGFyYW1zIGFuZCByZW1vdmVzIGl0IGZyb20gdGhlIDxoZWFkPiBlbGVtZW50LlxuICAgICAqXG4gICAgICogQHRlbXBsYXRlIFRFbGVtZW50IFRoZSB0eXBlIG9mIGVsZW1lbnQgYmVpbmcgc2VhcmNoZWQgZm9yLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIFRoZSBuYW1lIG9mIHRoZSB0YWcgdG8gbG9vayBmb3IuXG4gICAgICogQHBhcmFtIHtFbGVtZW50Q29uZmlnPFRFbGVtZW50Pn0gbG9va3VwIEEgbWFwIG9mIGF0dHJpYnV0ZSBuYW1lcyBhbmQgdmFsdWVzIHRvIG1hdGNoIHdpdGggdGhlIGVsZW1lbnQuIEFsbCBtdXN0IG1hdGNoIGZvciB0aGUgZWxlbWVudCB0byBiZSBkZXRlY3RlZC5cbiAgICAgKiBUbyBtYXRjaCBhbGwgZWxlbWVudHMgY29udGFpbmluZyBhIHNwZWNpZmljIGF0dHJpYnV0ZSByZWdhcmRsZXNzIG9mIHRoZSBhdHRyaWJ1dGUncyB2YWx1ZSwgdXNlIHRoZSBgJyoqJ2AgdmFsdWUuXG4gICAgICogQHJldHVybnMgVGhlIHJlbW92ZWQgZWxlbWVudCwgb3IgbnVsbCBpZiBub25lIGZvdW5kLlxuICAgICAqL1xuICAgIHB1YmxpYyByZW1vdmVFbGVtZW50PFRFbGVtZW50IGV4dGVuZHMgSFRNTEVsZW1lbnQ+KG5hbWU6IHN0cmluZywgbG9va3VwOiBFbGVtZW50Q29uZmlnPFRFbGVtZW50Pik6IFRFbGVtZW50IHwgbnVsbFxuICAgIHtcbiAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZmluZEVsZW1lbnRzKG5hbWUsIGxvb2t1cClbMF07XG5cbiAgICAgICAgZWxlbWVudD8ucmVtb3ZlKCk7XG5cbiAgICAgICAgcmV0dXJuIGVsZW1lbnQgfHwgbnVsbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBGaW5kcyBhbGwgZWxlbWVudHMgbWF0Y2hpbmcgaW4gbmFtZSBhbmQgYXR0cmlidXRlcyB0byB0aGUgc3BlY2lmaWVkIHBhcmFtcyBhbmQgcmVtb3ZlcyB0aGVtIGZyb20gdGhlIDxoZWFkPiBlbGVtZW50LlxuICAgICAqXG4gICAgICogQHRlbXBsYXRlIFRFbGVtZW50IFRoZSB0eXBlIG9mIGVsZW1lbnQgYmVpbmcgc2VhcmNoZWQgZm9yLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIFRoZSBuYW1lIG9mIHRoZSB0YWcgdG8gbG9vayBmb3IuXG4gICAgICogQHBhcmFtIHtFbGVtZW50Q29uZmlnPFRFbGVtZW50Pn0gbG9va3VwIEEgbWFwIG9mIGF0dHJpYnV0ZSBuYW1lcyBhbmQgdmFsdWVzIHRvIG1hdGNoIHdpdGggdGhlIGVsZW1lbnQuIEFsbCBtdXN0IG1hdGNoIGZvciB0aGUgZWxlbWVudCB0byBiZSBkZXRlY3RlZC5cbiAgICAgKiBUbyBtYXRjaCBhbGwgZWxlbWVudHMgY29udGFpbmluZyBhIHNwZWNpZmljIGF0dHJpYnV0ZSByZWdhcmRsZXNzIG9mIHRoZSBhdHRyaWJ1dGUncyB2YWx1ZSwgdXNlIHRoZSBgJyoqJ2AgdmFsdWUuXG4gICAgICogQHJldHVybnMgVGhlIGxpc3Qgb2YgcmVtb3ZlZCBlbGVtZW50cy5cbiAgICAgKi9cbiAgICBwdWJsaWMgcmVtb3ZlRWxlbWVudHM8VEVsZW1lbnQgZXh0ZW5kcyBIVE1MRWxlbWVudD4obmFtZTogc3RyaW5nLCBsb29rdXA6IEVsZW1lbnRDb25maWc8VEVsZW1lbnQ+KTogTm9kZUxpc3RPZjxURWxlbWVudD5cbiAgICB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRzID0gdGhpcy5maW5kRWxlbWVudHMobmFtZSwgbG9va3VwKTtcblxuICAgICAgICBlbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4gZWxlbWVudC5yZW1vdmUoKSk7XG5cbiAgICAgICAgcmV0dXJuIGVsZW1lbnRzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZpbmRzIGFsbCBlbGVtZW50cyBpbnNpZGUgb2YgPGhlYWQ+IHdoaWNoIG1hdGNoIGluIG5hbWUgYW5kIGF0dHJpYnV0ZXMgdG8gdGhlIHNwZWNpZmllZCBwYXJhbXMuXG4gICAgICpcbiAgICAgKiBAdGVtcGxhdGUgVEVsZW1lbnQgVGhlIHR5cGUgb2YgZWxlbWVudCBiZWluZyBzZWFyY2hlZCBmb3IuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgVGhlIG5hbWUgb2YgdGhlIHRhZyB0byBsb29rIGZvci5cbiAgICAgKiBAcGFyYW0ge0VsZW1lbnRDb25maWc8VEVsZW1lbnQ+fSBsb29rdXAgQSBtYXAgb2YgYXR0cmlidXRlIG5hbWVzIGFuZCB2YWx1ZXMgdG8gbWF0Y2ggd2l0aCB0aGUgZWxlbWVudC4gQWxsIG11c3QgbWF0Y2ggZm9yIHRoZSBlbGVtZW50IHRvIGJlIGRldGVjdGVkLlxuICAgICAqIFRvIG1hdGNoIGFsbCBlbGVtZW50cyBjb250YWluaW5nIGEgc3BlY2lmaWMgYXR0cmlidXRlIHJlZ2FyZGxlc3Mgb2YgdGhlIGF0dHJpYnV0ZSdzIHZhbHVlLCB1c2UgdGhlIGAnKionYCB2YWx1ZS5cbiAgICAgKiBAcmV0dXJucyBBIG5vZGUgbGlzdCBvZiBhbGwgbWF0Y2hpbmcgZWxlbWVudHMgaW5zaWRlIG9mIDxoZWFkPi5cbiAgICAgKi9cbiAgICBwdWJsaWMgZmluZEVsZW1lbnRzPFRFbGVtZW50IGV4dGVuZHMgSFRNTEVsZW1lbnQ+KG5hbWU6IHN0cmluZywgbG9va3VwOiBFbGVtZW50Q29uZmlnPFRFbGVtZW50Pik6IE5vZGVMaXN0T2Y8VEVsZW1lbnQ+XG4gICAge1xuICAgICAgICAvLyBHZXQgRE9NIGVsZW1lbnRzXG4gICAgICAgIGNvbnN0IGRvY3VtZW50ID0gdGhpcy5kb2N1bWVudC5uYXRpdmVEb2N1bWVudCBhcyBEb2N1bWVudDtcbiAgICAgICAgY29uc3QgaGVhZCAgICAgPSBkb2N1bWVudC5oZWFkO1xuICAgICAgICBcbiAgICAgICAgY29uc3QgYXR0cmlidXRlcyA9IE9iamVjdC5rZXlzKGxvb2t1cCkubWFwKGtleSA9PlxuICAgICAgICB7XG4gICAgICAgICAgICBjb25zdCBhdHRyaWJ1dGUgPSBrZXkgYXMga2V5b2YgRWxlbWVudENvbmZpZzxURWxlbWVudD47XG4gICAgICAgICAgICBjb25zdCB2YWx1ZSAgICAgPSBsb29rdXBbYXR0cmlidXRlXTtcblxuICAgICAgICAgICAgLy8gSWYgYSB3aWxkY2FyZCB3YXMgc3BlY2lmaWVkIGZvciB0aGUgYXR0cmlidXRlLi4uXG4gICAgICAgICAgICByZXR1cm4gdmFsdWUgPT09ICcqKicgP1xuICAgICAgICAgICAgICAgIC8vIC4uLiBRdWVyeSBvbmx5IGJ5IGF0dHJpYnV0ZSBuYW1lXG4gICAgICAgICAgICAgICAgYFske1N0cmluZyhhdHRyaWJ1dGUpfV1gIDpcbiAgICAgICAgICAgICAgICAvLyBPdGhlcndpc2UsIG1hdGNoIHRoZSBleGFjdCB2YWx1ZVxuICAgICAgICAgICAgICAgIGBbJHtTdHJpbmcoYXR0cmlidXRlKX09XCIke3ZhbHVlfVwiXWA7XG4gICAgICAgIH0pLmpvaW4oJycpO1xuXG4gICAgICAgIHJldHVybiBoZWFkLnF1ZXJ5U2VsZWN0b3JBbGwoYCR7bmFtZX0ke2F0dHJpYnV0ZXN9YCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIHdoZXRoZXIgYW4gZWxlbWVudCB3aXRoIHRoZSBnaXZlbiB0YWcgbmFtZSBhbmQgYXR0cmlidXRlcyBleGlzdHMgaW4gPGhlYWQ+LlxuICAgICAqXG4gICAgICogQHRlbXBsYXRlIFRFbGVtZW50IFRoZSB0eXBlIG9mIGVsZW1lbnQgYmVpbmcgc2VhcmNoZWQgZm9yLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIFRoZSBuYW1lIG9mIHRoZSB0YWcgdG8gbG9vayBmb3IuXG4gICAgICogQHBhcmFtIHtFbGVtZW50Q29uZmlnPFRFbGVtZW50Pn0gbG9va3VwIEEgbWFwIG9mIGF0dHJpYnV0ZSBuYW1lcyBhbmQgdmFsdWVzIHRvIG1hdGNoIHdpdGggdGhlIGVsZW1lbnQuIEFsbCBtdXN0IG1hdGNoIGZvciB0aGUgZWxlbWVudCB0byBiZSBkZXRlY3RlZC5cbiAgICAgKiBUbyBtYXRjaCBhbGwgZWxlbWVudHMgY29udGFpbmluZyBhIHNwZWNpZmljIGF0dHJpYnV0ZSByZWdhcmRsZXNzIG9mIHRoZSBhdHRyaWJ1dGUncyB2YWx1ZSwgdXNlIHRoZSBgJyoqJ2AgdmFsdWUuXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IGB0cnVlYCBpZiA8aGVhZD4gY29udGFpbnMgYSBtYXRjaGluZyBlbGVtZW50OyBvdGhlcndpc2UgYGZhbHNlLlxuICAgICAqL1xuICAgIHB1YmxpYyBjb250YWluczxURWxlbWVudCBleHRlbmRzIEhUTUxFbGVtZW50PihuYW1lOiBzdHJpbmcsIGxvb2t1cDogRWxlbWVudENvbmZpZzxURWxlbWVudD4pOiBib29sZWFuXG4gICAge1xuICAgICAgICByZXR1cm4gISF0aGlzLmZpbmRFbGVtZW50cyhuYW1lLCBsb29rdXApLmxlbmd0aDtcbiAgICB9XG59XG4iXX0=