UNPKG

ngx-extended-pdf-viewer

Version:

Embedding PDF files in your Angular application. Highly configurable viewer including the toolbar, sidebar, and all the features you're used to.

353 lines 54.2 kB
import { EventEmitter } from '@angular/core';
export class NgxFormSupport {
    /** Maps the internal ids of the annotations of pdf.js to their field name */
    formIdToFullFieldName = {};
    formIdToField = {};
    radioButtons = {};
    formData = {};
    initialFormDataStoredInThePDF = {};
    formDataChange = new EventEmitter();
    PDFViewerApplication;
    ngZone; // set during the initializaion of the PDF viewer
    cdr; // set during the initializaion of the PDF viewer
    reset() {
        this.formData = {};
        this.formIdToFullFieldName = {};
    }
    registerFormSupportWithPdfjs(PDFViewerApplication) {
        this.PDFViewerApplication = PDFViewerApplication;
        globalThis.getFormValueFromAngular = (key) => this.getFormValueFromAngular(key);
        globalThis.updateAngularFormValue = (key, value) => this.updateAngularFormValueCalledByPdfjs(key, value);
        globalThis.registerAcroformField = (id, element, value, radioButtonValueName, initialValueFromPDF) => this.registerAcroformField(id, element, value, radioButtonValueName, initialValueFromPDF);
        globalThis.registerXFAField = (element, value, initialValueFromPDF) => this.registerXFAField(element, value, initialValueFromPDF);
    }
    registerAcroformField(id, element, value, radioButtonValueName, initialFormValueFromPDF) {
        const fieldName = element.name;
        this.formIdToField[id] = element;
        this.formIdToFullFieldName[id] = fieldName;
        if (element instanceof HTMLInputElement && element.type === 'radio') {
            const groupName = fieldName;
            this.formIdToFullFieldName[id] = groupName;
            if (value) {
                this.formData[groupName] = radioButtonValueName;
                this.initialFormDataStoredInThePDF[groupName] = initialFormValueFromPDF;
            }
            element.setAttribute('exportValue', radioButtonValueName);
            if (!this.radioButtons[groupName]) {
                this.radioButtons[groupName] = [];
            }
            this.radioButtons[groupName].push(element);
        }
        else if (element instanceof HTMLSelectElement) {
            this.formData[fieldName] = this.getValueOfASelectField(element);
            this.initialFormDataStoredInThePDF[fieldName] = initialFormValueFromPDF;
        }
        else {
            if (value !== undefined) {
                this.formData[fieldName] = value;
            }
            this.initialFormDataStoredInThePDF[fieldName] = initialFormValueFromPDF;
        }
    }
    registerXFAField(element, value, initialFormValueFromPDF) {
        const fullFieldName = this.findFullXFAName(element);
        if (element instanceof HTMLInputElement && element.type === 'radio') {
            const id = element.getAttribute('fieldid') ?? '';
            // remove the xfa name of the radio button itself form the field name,
            // because the field name refers to the entire group of relatated radio buttons
            const groupName = fullFieldName.substring(0, fullFieldName.lastIndexOf('.'));
            this.formIdToFullFieldName[id] = groupName;
            this.formData[groupName] = value?.value;
            this.initialFormDataStoredInThePDF[groupName] = initialFormValueFromPDF;
            if (!this.radioButtons[groupName]) {
                this.radioButtons[groupName] = [];
            }
            this.radioButtons[groupName].push(element);
        }
        else if (element instanceof HTMLInputElement) {
            const id = element.getAttribute('fieldid') ?? '';
            this.formIdToField[id] = element;
            this.formIdToFullFieldName[id] = fullFieldName;
            this.formData[fullFieldName] = value?.value;
            this.initialFormDataStoredInThePDF[fullFieldName] = initialFormValueFromPDF;
        }
        else if (element instanceof HTMLSelectElement) {
            const id = element.getAttribute('fieldid') ?? '';
            this.formIdToField[id] = element;
            this.formIdToFullFieldName[id] = fullFieldName;
            this.formData[fullFieldName] = value?.value;
            this.initialFormDataStoredInThePDF[fullFieldName] = initialFormValueFromPDF;
        }
        else if (element instanceof HTMLTextAreaElement) {
            const id = element.getAttribute('fieldid') ?? '';
            this.formIdToField[id] = element;
            this.formIdToFullFieldName[id] = fullFieldName;
            this.formData[fullFieldName] = value?.value;
            this.initialFormDataStoredInThePDF[fullFieldName] = initialFormValueFromPDF;
        }
        else {
            console.error("Couldn't register an XFA form field", element);
        }
    }
    getValueOfASelectField(selectElement) {
        const { options, multiple } = selectElement;
        if (!multiple) {
            return options.selectedIndex === -1 ? null : options[options.selectedIndex]['value'];
        }
        return Array.prototype.filter.call(options, (option) => option.selected).map((option) => option['value']);
    }
    getFormValueFromAngular(element) {
        let key;
        if (element instanceof HTMLElement) {
            const fieldName = this.findXFAName(element);
            if (fieldName) {
                if (this.formData.hasOwnProperty(fieldName)) {
                    key = fieldName;
                }
                else {
                    key = this.findFullXFAName(element);
                }
            }
            else {
                console.error("Couldn't find the field name or XFA name of the form field", element);
                return { value: null };
            }
        }
        else {
            key = element;
        }
        return { value: this.formData[key] };
    }
    findXFAName(element) {
        let parentElement = element;
        while (!parentElement.getAttribute('xfaname') && parentElement.parentElement) {
            parentElement = parentElement.parentElement;
        }
        if (element instanceof HTMLInputElement && element.type === 'radio') {
            do {
                parentElement = parentElement?.parentElement;
            } while (!parentElement?.getAttribute('xfaname') && parentElement);
        }
        let fieldName = parentElement?.getAttribute('xfaname');
        if (!fieldName) {
            throw new Error("Couldn't find the xfaname of the field");
        }
        return fieldName;
    }
    findFullXFAName(element) {
        let parentElement = element;
        let fieldName = '';
        while (parentElement instanceof HTMLElement && parentElement.parentElement) {
            const xfaName = parentElement.getAttribute('xfaname');
            if (xfaName) {
                fieldName = xfaName + '.' + fieldName;
            }
            parentElement = parentElement.parentElement;
        }
        if (!fieldName) {
            throw new Error("Couldn't find the xfaname of the field");
        }
        fieldName = fieldName.substring(0, fieldName.length - 1);
        if (element instanceof HTMLInputElement && element.type === 'radio') {
            // ignore the last part of the xfaName because it's actually the value of the field
            return fieldName.substring(0, fieldName.lastIndexOf('.'));
        }
        return fieldName;
    }
    updateAngularFormValueCalledByPdfjs(key, value) {
        if (!this.formData) {
            this.formData = {};
        }
        // Ignore formattedValue-only updates to prevent clearing Angular form data
        // The formattedValue is just for display formatting, not actual user input
        if (value.formattedValue !== undefined && value.value === undefined) {
            debugger;
            return;
        }
        if (typeof key === 'string') {
            const acroFormKey = this.formIdToFullFieldName[key];
            const fullKey = acroFormKey ?? Object.values(this.formIdToFullFieldName).find((k) => k === key || k.endsWith('.' + key));
            if (fullKey) {
                const field = this.formIdToField[key];
                let change = this.doUpdateAngularFormValue(field, value, fullKey);
                if (change) {
                    this.ngZone.run(() => {
                        this.formDataChange.emit(this.formData);
                        this.cdr.detectChanges();
                    });
                }
            }
            else {
                console.error("Couldn't find the field with the name " + key);
            }
        }
        else {
            let change = false;
            const shortFieldName = this.findXFAName(key);
            if (this.formData.hasOwnProperty(shortFieldName)) {
                change = this.doUpdateAngularFormValue(key, value, shortFieldName);
            }
            const fullFieldName = this.findFullXFAName(key);
            if (fullFieldName !== shortFieldName) {
                change ||= this.doUpdateAngularFormValue(key, value, fullFieldName);
            }
            if (change) {
                this.ngZone.run(() => {
                    this.formDataChange.emit(this.formData);
                    this.cdr.detectChanges();
                });
            }
        }
    }
    doUpdateAngularFormValue(field, value, fullKey) {
        let change = false;
        // Use the actual user input value, not the formatted display value
        const actualValue = value.value;
        if (field instanceof HTMLInputElement && field.type === 'checkbox') {
            const exportValue = field.getAttribute('exportvalue');
            if (exportValue) {
                if (actualValue) {
                    if (this.formData[fullKey] !== exportValue) {
                        this.formData[fullKey] = exportValue;
                        change = true;
                    }
                }
                else {
                    if (this.formData[fullKey] !== false) {
                        this.formData[fullKey] = false;
                        change = true;
                    }
                }
            }
            else if (this.formData[fullKey] !== actualValue) {
                this.formData[fullKey] = actualValue ?? '';
                change = true;
            }
        }
        else if (field instanceof HTMLInputElement && field.type === 'radio') {
            const exportValue = field.getAttribute('exportvalue') ?? field.getAttribute('xfaon');
            if (actualValue) {
                if (this.formData[fullKey] !== exportValue) {
                    this.formData[fullKey] = exportValue;
                    change = true;
                }
            }
        }
        else if (this.formData[fullKey] !== actualValue) {
            this.formData[fullKey] = actualValue ?? '';
            change = true;
        }
        return change;
    }
    updateFormFieldsInPdfCalledByNgOnChanges(previousFormData) {
        if (!this.PDFViewerApplication?.pdfDocument?.annotationStorage) {
            // ngOnChanges calls this method too early - so just ignore it
            return;
        }
        for (const key in this.formData) {
            if (this.formData.hasOwnProperty(key)) {
                const newValue = this.formData[key];
                if (newValue !== previousFormData[key]) {
                    this.setFieldValueAndUpdateAnnotationStorage(key, newValue);
                }
            }
        }
        for (const key in previousFormData) {
            if (previousFormData.hasOwnProperty(key) && previousFormData[key]) {
                let hasPreviousValue = this.formData.hasOwnProperty(key);
                if (!hasPreviousValue) {
                    const fullKey = Object.keys(this.formData).find((k) => k === key || k.endsWith('.' + key));
                    if (fullKey) {
                        hasPreviousValue = this.formData.hasOwnProperty(fullKey);
                    }
                }
                if (!hasPreviousValue) {
                    this.setFieldValueAndUpdateAnnotationStorage(key, null);
                }
            }
        }
    }
    setFieldValueAndUpdateAnnotationStorage(key, newValue) {
        const radios = this.findRadioButtonGroup(key);
        if (radios) {
            radios.forEach((r) => {
                const activeValue = r.getAttribute('exportValue') ?? r.getAttribute('xfaon');
                r.checked = activeValue === newValue;
            });
            const updateFromAngular = new CustomEvent('updateFromAngular', {
                detail: newValue,
            });
            radios[0].dispatchEvent(updateFromAngular);
        }
        else {
            const fieldIds = this.findFormIdsFromFieldName(key);
            if (fieldIds) {
                fieldIds.forEach((fieldId) => {
                    const htmlField = this.formIdToField[fieldId];
                    if (htmlField) {
                        if (htmlField instanceof HTMLInputElement && htmlField.type === 'checkbox') {
                            let activeValue = htmlField.getAttribute('xfaon') ?? htmlField.getAttribute('exportvalue') ?? true;
                            if (newValue === true || newValue === false) {
                                activeValue = true;
                            }
                            htmlField.checked = activeValue === newValue;
                        }
                        else if (htmlField instanceof HTMLSelectElement) {
                            this.populateSelectField(htmlField, newValue);
                        }
                        else {
                            // textareas and input fields
                            htmlField.value = newValue;
                        }
                        const updateFromAngular = new CustomEvent('updateFromAngular', {
                            detail: newValue,
                        });
                        htmlField.dispatchEvent(updateFromAngular);
                    }
                    else {
                        console.error("Couldn't set the value of the field", key);
                    }
                });
            }
        }
    }
    populateSelectField(htmlField, newValue) {
        if (htmlField.multiple) {
            const { options } = htmlField;
            const newValueArray = newValue;
            for (let i = 0; i < options.length; i++) {
                const option = options.item(i);
                if (option) {
                    option.selected = newValueArray.some((o) => o === option.value);
                }
            }
        }
        else {
            htmlField.value = newValue;
        }
    }
    findFormIdsFromFieldName(fieldName) {
        if (Object.entries(this.formIdToFullFieldName).length === 0) {
            // sometimes, ngOnChanges() is called before initializing the PDF file
            return undefined;
        }
        const matchingEntries = Object.entries(this.formIdToFullFieldName).filter((entry) => entry[1] === fieldName || entry[1].endsWith('.' + fieldName));
        if (matchingEntries.length === 0) {
            console.log("Couldn't find the field " + fieldName);
            return undefined;
        }
        return matchingEntries.map((e) => e[0]);
    }
    findRadioButtonGroup(fieldName) {
        const matchingEntries = Object.entries(this.radioButtons).filter((entry) => entry[0].endsWith('.' + fieldName) || entry[0] === fieldName);
        if (matchingEntries.length === 0) {
            return null;
        }
        if (matchingEntries.length > 1) {
            console.log('More than one radio button group name matches this name. Please use the qualified field name', matchingEntries.map((radio) => radio[0]));
            console.log('ngx-extended-pdf-viewer uses the first matching field (which may not be the topmost field on your PDF form): ' + matchingEntries[0][0]);
        }
        return matchingEntries[0][1];
    }
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWZvcm0tc3VwcG9ydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1leHRlbmRlZC1wZGYtdmlld2VyL3NyYy9saWIvbmd4LWZvcm0tc3VwcG9ydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQXFCLFlBQVksRUFBVSxNQUFNLGVBQWUsQ0FBQztBQU14RSxNQUFNLE9BQU8sY0FBYztJQUN6Qiw2RUFBNkU7SUFDckUscUJBQXFCLEdBQThCLEVBQUUsQ0FBQztJQUV0RCxhQUFhLEdBQXVDLEVBQUUsQ0FBQztJQUV2RCxZQUFZLEdBQStDLEVBQUUsQ0FBQztJQUUvRCxRQUFRLEdBQWlCLEVBQUUsQ0FBQztJQUU1Qiw2QkFBNkIsR0FBaUIsRUFBRSxDQUFDO0lBRWpELGNBQWMsR0FBRyxJQUFJLFlBQVksRUFBZ0IsQ0FBQztJQUVqRCxvQkFBb0IsQ0FBb0M7SUFFekQsTUFBTSxDQUFVLENBQUMsaURBQWlEO0lBRWxFLEdBQUcsQ0FBcUIsQ0FBQyxpREFBaUQ7SUFFMUUsS0FBSztRQUNWLElBQUksQ0FBQyxRQUFRLEdBQUcsRUFBRSxDQUFDO1FBQ25CLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxFQUFFLENBQUM7SUFDbEMsQ0FBQztJQUVNLDRCQUE0QixDQUFDLG9CQUEyQztRQUM3RSxJQUFJLENBQUMsb0JBQW9CLEdBQUcsb0JBQW9CLENBQUM7UUFDaEQsVUFBa0IsQ0FBQyx1QkFBdUIsR0FBRyxDQUFDLEdBQVcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2hHLFVBQWtCLENBQUMsc0JBQXNCLEdBQUcsQ0FBQyxHQUF3RSxFQUFFLEtBQXdCLEVBQUUsRUFBRSxDQUNsSixJQUFJLENBQUMsbUNBQW1DLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3RELFVBQWtCLENBQUMscUJBQXFCLEdBQUcsQ0FDMUMsRUFBVSxF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UUFDRCxJQUFJLGVBQWUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQzlCLE9BQU8sQ0FBQyxHQUFHLENBQ1QsOEZBQThGLEVBQzlGLGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUN6QyxDQUFDO1lBQ0YsT0FBTyxDQUFDLEdBQUcsQ0FBQywrR0FBK0csR0FBRyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUN0SjtRQUNELE9BQU8sZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQy9CLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdG9yUmVmLCBFdmVudEVtaXR0ZXIsIE5nWm9uZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybURhdGFUeXBlIH0gZnJvbSAnLi9uZ3gtZXh0ZW5kZWQtcGRmLXZpZXdlci5jb21wb25lbnQnO1xuaW1wb3J0IHsgSVBERlZpZXdlckFwcGxpY2F0aW9uIH0gZnJvbSAnLi9vcHRpb25zL3BkZi12aWV3ZXItYXBwbGljYXRpb24nO1xuXG5leHBvcnQgdHlwZSBIdG1sRm9ybUVsZW1lbnQgPSBIVE1MSW5wdXRFbGVtZW50IHwgSFRNTFNlbGVjdEVsZW1lbnQgfCBIVE1MVGV4dEFyZWFFbGVtZW50O1xuXG5leHBvcnQgY2xhc3MgTmd4Rm9ybVN1cHBvcnQge1xuICAvKiogTWFwcyB0aGUgaW50ZXJuYWwgaWRzIG9mIHRoZSBhbm5vdGF0aW9ucyBvZiBwZGYuanMgdG8gdGhlaXIgZmllbGQgbmFtZSAqL1xuICBwcml2YXRlIGZvcm1JZFRvRnVsbEZpZWxkTmFtZTogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfSA9IHt9O1xuXG4gIHByaXZhdGUgZm9ybUlkVG9GaWVsZDogeyBba2V5OiBzdHJpbmddOiBIdG1sRm9ybUVsZW1lbnQgfSA9IHt9O1xuXG4gIHByaXZhdGUgcmFkaW9CdXR0b25zOiB7IFtrZXk6IHN0cmluZ106IEFycmF5PEhUTUxJbnB1dEVsZW1lbnQ+IH0gPSB7fTtcblxuICBwdWJsaWMgZm9ybURhdGE6IEZvcm1EYXRhVHlwZSA9IHt9O1xuXG4gIHB1YmxpYyBpbml0aWFsRm9ybURhdGFTdG9yZWRJblRoZVBERjogRm9ybURhdGFUeXBlID0ge307XG5cbiAgcHVibGljIGZvcm1EYXRhQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxGb3JtRGF0YVR5cGU+KCk7XG5cbiAgcHJpdmF0ZSBQREZWaWV3ZXJBcHBsaWNhdGlvbjogSVBERlZpZXdlckFwcGxpY2F0aW9uIHwgdW5kZWZpbmVkO1xuXG4gIHB1YmxpYyBuZ1pvbmUhOiBOZ1pvbmU7IC8vIHNldCBkdXJpbmcgdGhlIGluaXRpYWxpemFpb24gb2YgdGhlIFBERiB2aWV3ZXJcblxuICBwdWJsaWMgY2RyITogQ2hhbmdlRGV0ZWN0b3JSZWY7IC8vIHNldCBkdXJpbmcgdGhlIGluaXRpYWxpemFpb24gb2YgdGhlIFBERiB2aWV3ZXJcblxuICBwdWJsaWMgcmVzZXQoKSB7XG4gICAgdGhpcy5mb3JtRGF0YSA9IHt9O1xuICAgIHRoaXMuZm9ybUlkVG9GdWxsRmllbGROYW1lID0ge307XG4gIH1cblxuICBwdWJsaWMgcmVnaXN0ZXJGb3JtU3VwcG9ydFdpdGhQZGZqcyhQREZWaWV3ZXJBcHBsaWNhdGlvbjogSVBERlZpZXdlckFwcGxpY2F0aW9uKTogdm9pZCB7XG4gICAgdGhpcy5QREZWaWV3ZXJBcHBsaWNhdGlvbiA9IFBERlZpZXdlckFwcGxpY2F0aW9uO1xuICAgIChnbG9iYWxUaGlzIGFzIGFueSkuZ2V0Rm9ybVZhbHVlRnJvbUFuZ3VsYXIgPSAoa2V5OiBzdHJpbmcpID0+IHRoaXMuZ2V0Rm9ybVZhbHVlRnJvbUFuZ3VsYXIoa2V5KTtcbiAgICAoZ2xvYmFsVGhpcyBhcyBhbnkpLnVwZGF0ZUFuZ3VsYXJGb3JtVmFsdWUgPSAoa2V5OiBzdHJpbmcgfCBIVE1MSW5wdXRFbGVtZW50IHwgSFRNTFNlbGVjdEVsZW1lbnQgfCBIVE1MVGV4dEFyZWFFbGVtZW50LCB2YWx1ZTogeyB2YWx1ZTogc3RyaW5nIH0pID0+XG4gICAgICB0aGlzLnVwZGF0ZUFuZ3VsYXJGb3JtVmFsdWVDYWxsZWRCeVBkZmpzKGtleSwgdmFsdWUpO1xuICAgIChnbG9iYWxUaGlzIGFzIGFueSkucmVnaXN0ZXJBY3JvZm9ybUZpZWxkID0gKFxuICAgICAgaWQ6IHN0cmluZyxcbiAgICAgIGVsZW1lbnQ6IEh0bWxGb3JtRWxlbWVudCxcbiAgICAgIHZhbHVlOiBzdHJpbmcgfCBBcnJheTxzdHJpbmc+LFxuICAgICAgcmFkaW9CdXR0b25WYWx1ZU5hbWU6IHN0cmluZyxcbiAgICAgIGluaXRpYWxWYWx1ZUZyb21QREY6IHN0cmluZyxcbiAgICApID0+IHRoaXMucmVnaXN0ZXJBY3JvZm9ybUZpZWxkKGlkLCBlbGVtZW50LCB2YWx1ZSwgcmFkaW9CdXR0b25WYWx1ZU5hbWUsIGluaXRpYWxWYWx1ZUZyb21QREYpO1xuXG4gICAgKGdsb2JhbFRoaXMgYXMgYW55KS5yZWdpc3RlclhGQUZpZWxkID0gKGVsZW1lbnQ6IEh0bWxGb3JtRWxlbWVudCwgdmFsdWU6IHsgdmFsdWU6IHN0cmluZyB9LCBpbml0aWFsVmFsdWVGcm9tUERGOiBzdHJpbmcpID0+XG4gICAgICB0aGlzLnJlZ2lzdGVyWEZBRmllbGQoZWxlbWVudCwgdmFsdWUsIGluaXRpYWxWYWx1ZUZyb21QREYpO1xuICB9XG5cbiAgcHJpdmF0ZSByZWdpc3RlckFjcm9mb3JtRmllbGQoXG4gICAgaWQ6IHN0cmluZyxcbiAgICBlbGVtZW50OiBIdG1sRm9ybUVsZW1lbnQsXG4gICAgdmFsdWU6IG51bGwgfCBzdHJpbmcgfCBBcnJheTxzdHJpbmc+LFxuICAgIHJhZGlvQnV0dG9uVmFsdWVOYW1lOiBzdHJpbmcsXG4gICAgaW5pdGlhbEZvcm1WYWx1ZUZyb21QREY6IHN0cmluZyxcbiAgKTogdm9pZCB7XG4gICAgY29uc3QgZmllbGROYW1lID0gZWxlbWVudC5uYW1lO1xuICAgIHRoaXMuZm9ybUlkVG9GaWVsZFtpZF0gPSBlbGVtZW50O1xuICAgIHRoaXMuZm9ybUlkVG9GdWxsRmllbGROYW1lW2lkXSA9IGZpZWxkTmFtZTtcbiAgICBpZiAoZWxlbWVudCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQgJiYgZWxlbWVudC50eXBlID09PSAncmFkaW8nKSB7XG4gICAgICBjb25zdCBncm91cE5hbWUgPSBmaWVsZE5hbWU7XG4gICAgICB0aGlzLmZvcm1JZFRvRnVsbEZpZWxkTmFtZVtpZF0gPSBncm91cE5hbWU7XG4gICAgICBpZiAodmFsdWUpIHtcbiAgICAgICAgdGhpcy5mb3JtRGF0YVtncm91cE5hbWVdID0gcmFkaW9CdXR0b25WYWx1ZU5hbWU7XG4gICAgICAgIHRoaXMuaW5pdGlhbEZvcm1EYXRhU3RvcmVkSW5UaGVQREZbZ3JvdXBOYW1lXSA9IGluaXRpYWxGb3JtVmFsdWVGcm9tUERGO1xuICAgICAgfVxuICAgICAgZWxlbWVudC5zZXRBdHRyaWJ1dGUoJ2V4cG9ydFZhbHVlJywgcmFkaW9CdXR0b25WYWx1ZU5hbWUpO1xuICAgICAgaWYgKCF0aGlzLnJhZGlvQnV0dG9uc1tncm91cE5hbWVdKSB7XG4gICAgICAgIHRoaXMucmFkaW9CdXR0b25zW2dyb3VwTmFtZV0gPSBbXTtcbiAgICAgIH1cbiAgICAgIHRoaXMucmFkaW9CdXR0b25zW2dyb3VwTmFtZV0ucHVzaChlbGVtZW50KTtcbiAgICB9IGVsc2UgaWYgKGVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MU2VsZWN0RWxlbWVudCkge1xuICAgICAgdGhpcy5mb3JtRGF0YVtmaWVsZE5hbWVdID0gdGhpcy5nZXRWYWx1ZU9mQVNlbGVjdEZpZWxkKGVsZW1lbnQpO1xuICAgICAgdGhpcy5pbml0aWFsRm9ybURhdGFTdG9yZWRJblRoZVBERltmaWVsZE5hbWVdID0gaW5pdGlhbEZvcm1WYWx1ZUZyb21QREY7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRoaXMuZm9ybURhdGFbZmllbGROYW1lXSA9IHZhbHVlO1xuICAgICAgfVxuICAgICAgdGhpcy5pbml0aWFsRm9ybURhdGFTdG9yZWRJblRoZVBERltmaWVsZE5hbWVdID0gaW5pdGlhbEZvcm1WYWx1ZUZyb21QREY7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZWdpc3RlclhGQUZpZWxkKGVsZW1lbnQ6IEhUTUxFbGVtZW50LCB2YWx1ZTogeyB2YWx1ZTogc3RyaW5nIH0sIGluaXRpYWxGb3JtVmFsdWVGcm9tUERGOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBmdWxsRmllbGROYW1lID0gdGhpcy5maW5kRnVsbFhGQU5hbWUoZWxlbWVudCk7XG4gICAgaWYgKGVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MSW5wdXRFbGVtZW50ICYmIGVsZW1lbnQudHlwZSA9PT0gJ3JhZGlvJykge1xuICAgICAgY29uc3QgaWQgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZmllbGRpZCcpID8/ICcnO1xuICAgICAgLy8gcmVtb3ZlIHRoZSB4ZmEgbmFtZSBvZiB0aGUgcmFkaW8gYnV0dG9uIGl0c2VsZiBmb3JtIHRoZSBmaWVsZCBuYW1lLFxuICAgICAgLy8gYmVjYXVzZSB0aGUgZmllbGQgbmFtZSByZWZlcnMgdG8gdGhlIGVudGlyZSBncm91cCBvZiByZWxhdGF0ZWQgcmFkaW8gYnV0dG9uc1xuICAgICAgY29uc3QgZ3JvdXBOYW1lID0gZnVsbEZpZWxkTmFtZS5zdWJzdHJpbmcoMCwgZnVsbEZpZWxkTmFtZS5sYXN0SW5kZXhPZignLicpKTtcbiAgICAgIHRoaXMuZm9ybUlkVG9GdWxsRmllbGROYW1lW2lkXSA9IGdyb3VwTmFtZTtcbiAgICAgIHRoaXMuZm9ybURhdGFbZ3JvdXBOYW1lXSA9IHZhbHVlPy52YWx1ZTtcbiAgICAgIHRoaXMuaW5pdGlhbEZvcm1EYXRhU3RvcmVkSW5UaGVQREZbZ3JvdXBOYW1lXSA9IGluaXRpYWxGb3JtVmFsdWVGcm9tUERGO1xuXG4gICAgICBpZiAoIXRoaXMucmFkaW9CdXR0b25zW2dyb3VwTmFtZV0pIHtcbiAgICAgICAgdGhpcy5yYWRpb0J1dHRvbnNbZ3JvdXBOYW1lXSA9IFtdO1xuICAgICAgfVxuICAgICAgdGhpcy5yYWRpb0J1dHRvbnNbZ3JvdXBOYW1lXS5wdXNoKGVsZW1lbnQpO1xuICAgIH0gZWxzZSBpZiAoZWxlbWVudCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQpIHtcbiAgICAgIGNvbnN0IGlkID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2ZpZWxkaWQnKSA/PyAnJztcbiAgICAgIHRoaXMuZm9ybUlkVG9GaWVsZFtpZF0gPSBlbGVtZW50O1xuICAgICAgdGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWVbaWRdID0gZnVsbEZpZWxkTmFtZTtcbiAgICAgIHRoaXMuZm9ybURhdGFbZnVsbEZpZWxkTmFtZV0gPSB2YWx1ZT8udmFsdWU7XG4gICAgICB0aGlzLmluaXRpYWxGb3JtRGF0YVN0b3JlZEluVGhlUERGW2Z1bGxGaWVsZE5hbWVdID0gaW5pdGlhbEZvcm1WYWx1ZUZyb21QREY7XG4gICAgfSBlbHNlIGlmIChlbGVtZW50IGluc3RhbmNlb2YgSFRNTFNlbGVjdEVsZW1lbnQpIHtcbiAgICAgIGNvbnN0IGlkID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2ZpZWxkaWQnKSA/PyAnJztcbiAgICAgIHRoaXMuZm9ybUlkVG9GaWVsZFtpZF0gPSBlbGVtZW50O1xuICAgICAgdGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWVbaWRdID0gZnVsbEZpZWxkTmFtZTtcbiAgICAgIHRoaXMuZm9ybURhdGFbZnVsbEZpZWxkTmFtZV0gPSB2YWx1ZT8udmFsdWU7XG4gICAgICB0aGlzLmluaXRpYWxGb3JtRGF0YVN0b3JlZEluVGhlUERGW2Z1bGxGaWVsZE5hbWVdID0gaW5pdGlhbEZvcm1WYWx1ZUZyb21QREY7XG4gICAgfSBlbHNlIGlmIChlbGVtZW50IGluc3RhbmNlb2YgSFRNTFRleHRBcmVhRWxlbWVudCkge1xuICAgICAgY29uc3QgaWQgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZmllbGRpZCcpID8/ICcnO1xuICAgICAgdGhpcy5mb3JtSWRUb0ZpZWxkW2lkXSA9IGVsZW1lbnQ7XG4gICAgICB0aGlzLmZvcm1JZFRvRnVsbEZpZWxkTmFtZVtpZF0gPSBmdWxsRmllbGROYW1lO1xuICAgICAgdGhpcy5mb3JtRGF0YVtmdWxsRmllbGROYW1lXSA9IHZhbHVlPy52YWx1ZTtcbiAgICAgIHRoaXMuaW5pdGlhbEZvcm1EYXRhU3RvcmVkSW5UaGVQREZbZnVsbEZpZWxkTmFtZV0gPSBpbml0aWFsRm9ybVZhbHVlRnJvbVBERjtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5lcnJvcihcIkNvdWxkbid0IHJlZ2lzdGVyIGFuIFhGQSBmb3JtIGZpZWxkXCIsIGVsZW1lbnQpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0VmFsdWVPZkFTZWxlY3RGaWVsZChzZWxlY3RFbGVtZW50OiBIVE1MU2VsZWN0RWxlbWVudCk6IG51bGwgfCBzdHJpbmcgfCBBcnJheTxzdHJpbmc+IHtcbiAgICBjb25zdCB7IG9wdGlvbnMsIG11bHRpcGxlIH0gPSBzZWxlY3RFbGVtZW50O1xuICAgIGlmICghbXVsdGlwbGUpIHtcbiAgICAgIHJldHVybiBvcHRpb25zLnNlbGVjdGVkSW5kZXggPT09IC0xID8gbnVsbCA6IG9wdGlvbnNbb3B0aW9ucy5zZWxlY3RlZEluZGV4XVsndmFsdWUnXTtcbiAgICB9XG4gICAgcmV0dXJuIEFycmF5LnByb3RvdHlwZS5maWx0ZXIuY2FsbChvcHRpb25zLCAob3B0aW9uKSA9PiBvcHRpb24uc2VsZWN0ZWQpLm1hcCgob3B0aW9uKSA9PiBvcHRpb25bJ3ZhbHVlJ10pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRGb3JtVmFsdWVGcm9tQW5ndWxhcihlbGVtZW50OiBIVE1MRWxlbWVudCB8IHN0cmluZyk6IE9iamVjdCB7XG4gICAgbGV0IGtleTogc3RyaW5nO1xuICAgIGlmIChlbGVtZW50IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHtcbiAgICAgIGNvbnN0IGZpZWxkTmFtZSA9IHRoaXMuZmluZFhGQU5hbWUoZWxlbWVudCk7XG4gICAgICBpZiAoZmllbGROYW1lKSB7XG4gICAgICAgIGlmICh0aGlzLmZvcm1EYXRhLmhhc093blByb3BlcnR5KGZpZWxkTmFtZSkpIHtcbiAgICAgICAgICBrZXkgPSBmaWVsZE5hbWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAga2V5ID0gdGhpcy5maW5kRnVsbFhGQU5hbWUoZWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJDb3VsZG4ndCBmaW5kIHRoZSBmaWVsZCBuYW1lIG9yIFhGQSBuYW1lIG9mIHRoZSBmb3JtIGZpZWxkXCIsIGVsZW1lbnQpO1xuICAgICAgICByZXR1cm4geyB2YWx1ZTogbnVsbCB9O1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBrZXkgPSBlbGVtZW50O1xuICAgIH1cbiAgICByZXR1cm4geyB2YWx1ZTogdGhpcy5mb3JtRGF0YVtrZXldIH07XG4gIH1cblxuICBwcml2YXRlIGZpbmRYRkFOYW1lKGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogc3RyaW5nIHtcbiAgICBsZXQgcGFyZW50RWxlbWVudDogSFRNTEVsZW1lbnQgfCBudWxsIHwgdW5kZWZpbmVkID0gZWxlbWVudDtcbiAgICB3aGlsZSAoIXBhcmVudEVsZW1lbnQuZ2V0QXR0cmlidXRlKCd4ZmFuYW1lJykgJiYgcGFyZW50RWxlbWVudC5wYXJlbnRFbGVtZW50KSB7XG4gICAgICBwYXJlbnRFbGVtZW50ID0gcGFyZW50RWxlbWVudC5wYXJlbnRFbGVtZW50O1xuICAgIH1cbiAgICBpZiAoZWxlbWVudCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQgJiYgZWxlbWVudC50eXBlID09PSAncmFkaW8nKSB7XG4gICAgICBkbyB7XG4gICAgICAgIHBhcmVudEVsZW1lbnQgPSBwYXJlbnRFbGVtZW50Py5wYXJlbnRFbGVtZW50O1xuICAgICAgfSB3aGlsZSAoIXBhcmVudEVsZW1lbnQ/LmdldEF0dHJpYnV0ZSgneGZhbmFtZScpICYmIHBhcmVudEVsZW1lbnQpO1xuICAgIH1cbiAgICBsZXQgZmllbGROYW1lID0gcGFyZW50RWxlbWVudD8uZ2V0QXR0cmlidXRlKCd4ZmFuYW1lJyk7XG4gICAgaWYgKCFmaWVsZE5hbWUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkNvdWxkbid0IGZpbmQgdGhlIHhmYW5hbWUgb2YgdGhlIGZpZWxkXCIpO1xuICAgIH1cbiAgICByZXR1cm4gZmllbGROYW1lO1xuICB9XG5cbiAgcHJpdmF0ZSBmaW5kRnVsbFhGQU5hbWUoZWxlbWVudDogSFRNTEVsZW1lbnQpOiBzdHJpbmcge1xuICAgIGxldCBwYXJlbnRFbGVtZW50ID0gZWxlbWVudDtcbiAgICBsZXQgZmllbGROYW1lID0gJyc7XG4gICAgd2hpbGUgKHBhcmVudEVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCAmJiBwYXJlbnRFbGVtZW50LnBhcmVudEVsZW1lbnQpIHtcbiAgICAgIGNvbnN0IHhmYU5hbWUgPSBwYXJlbnRFbGVtZW50LmdldEF0dHJpYnV0ZSgneGZhbmFtZScpO1xuICAgICAgaWYgKHhmYU5hbWUpIHtcbiAgICAgICAgZmllbGROYW1lID0geGZhTmFtZSArICcuJyArIGZpZWxkTmFtZTtcbiAgICAgIH1cbiAgICAgIHBhcmVudEVsZW1lbnQgPSBwYXJlbnRFbGVtZW50LnBhcmVudEVsZW1lbnQ7XG4gICAgfVxuICAgIGlmICghZmllbGROYW1lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZG4ndCBmaW5kIHRoZSB4ZmFuYW1lIG9mIHRoZSBmaWVsZFwiKTtcbiAgICB9XG4gICAgZmllbGROYW1lID0gZmllbGROYW1lLnN1YnN0cmluZygwLCBmaWVsZE5hbWUubGVuZ3RoIC0gMSk7XG4gICAgaWYgKGVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MSW5wdXRFbGVtZW50ICYmIGVsZW1lbnQudHlwZSA9PT0gJ3JhZGlvJykge1xuICAgICAgLy8gaWdub3JlIHRoZSBsYXN0IHBhcnQgb2YgdGhlIHhmYU5hbWUgYmVjYXVzZSBpdCdzIGFjdHVhbGx5IHRoZSB2YWx1ZSBvZiB0aGUgZmllbGRcbiAgICAgIHJldHVybiBmaWVsZE5hbWUuc3Vic3RyaW5nKDAsIGZpZWxkTmFtZS5sYXN0SW5kZXhPZignLicpKTtcbiAgICB9XG4gICAgcmV0dXJuIGZpZWxkTmFtZTtcbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlQW5ndWxhckZvcm1WYWx1ZUNhbGxlZEJ5UGRmanMoXG4gICAga2V5OiBzdHJpbmcgfCBIVE1MU2VsZWN0RWxlbWVudCB8IEhUTUxJbnB1dEVsZW1lbnQgfCBIVE1MVGV4dEFyZWFFbGVtZW50LFxuICAgIHZhbHVlOiB7IHZhbHVlPzogc3RyaW5nOyBmb3JtYXR0ZWRWYWx1ZT86IHN0cmluZyB9LFxuICApOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuZm9ybURhdGEpIHtcbiAgICAgIHRoaXMuZm9ybURhdGEgPSB7fTtcbiAgICB9XG5cbiAgICAvLyBJZ25vcmUgZm9ybWF0dGVkVmFsdWUtb25seSB1cGRhdGVzIHRvIHByZXZlbnQgY2xlYXJpbmcgQW5ndWxhciBmb3JtIGRhdGFcbiAgICAvLyBUaGUgZm9ybWF0dGVkVmFsdWUgaXMganVzdCBmb3IgZGlzcGxheSBmb3JtYXR0aW5nLCBub3QgYWN0dWFsIHVzZXIgaW5wdXRcbiAgICBpZiAodmFsdWUuZm9ybWF0dGVkVmFsdWUgIT09IHVuZGVmaW5lZCAmJiB2YWx1ZS52YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBkZWJ1Z2dlcjtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGtleSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGNvbnN0IGFjcm9Gb3JtS2V5ID0gdGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWVba2V5XTtcbiAgICAgIGNvbnN0IGZ1bGxLZXkgPSBhY3JvRm9ybUtleSA/PyBPYmplY3QudmFsdWVzKHRoaXMuZm9ybUlkVG9GdWxsRmllbGROYW1lKS5maW5kKChrKSA9PiBrID09PSBrZXkgfHwgay5lbmRzV2l0aCgnLicgKyBrZXkpKTtcbiAgICAgIGlmIChmdWxsS2V5KSB7XG4gICAgICAgIGNvbnN0IGZpZWxkID0gdGhpcy5mb3JtSWRUb0ZpZWxkW2tleV07XG4gICAgICAgIGxldCBjaGFuZ2UgPSB0aGlzLmRvVXBkYXRlQW5ndWxhckZvcm1WYWx1ZShmaWVsZCwgdmFsdWUsIGZ1bGxLZXkpO1xuICAgICAgICBpZiAoY2hhbmdlKSB7XG4gICAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuZm9ybURhdGFDaGFuZ2UuZW1pdCh0aGlzLmZvcm1EYXRhKTtcbiAgICAgICAgICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkNvdWxkbid0IGZpbmQgdGhlIGZpZWxkIHdpdGggdGhlIG5hbWUgXCIgKyBrZXkpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgY2hhbmdlID0gZmFsc2U7XG4gICAgICBjb25zdCBzaG9ydEZpZWxkTmFtZSA9IHRoaXMuZmluZFhGQU5hbWUoa2V5KTtcbiAgICAgIGlmICh0aGlzLmZvcm1EYXRhLmhhc093blByb3BlcnR5KHNob3J0RmllbGROYW1lKSkge1xuICAgICAgICBjaGFuZ2UgPSB0aGlzLmRvVXBkYXRlQW5ndWxhckZvcm1WYWx1ZShrZXksIHZhbHVlLCBzaG9ydEZpZWxkTmFtZSk7XG4gICAgICB9XG4gICAgICBjb25zdCBmdWxsRmllbGROYW1lID0gdGhpcy5maW5kRnVsbFhGQU5hbWUoa2V5KTtcbiAgICAgIGlmIChmdWxsRmllbGROYW1lICE9PSBzaG9ydEZpZWxkTmFtZSkge1xuICAgICAgICBjaGFuZ2UgfHw9IHRoaXMuZG9VcGRhdGVBbmd1bGFyRm9ybVZhbHVlKGtleSwgdmFsdWUsIGZ1bGxGaWVsZE5hbWUpO1xuICAgICAgfVxuICAgICAgaWYgKGNoYW5nZSkge1xuICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgIHRoaXMuZm9ybURhdGFDaGFuZ2UuZW1pdCh0aGlzLmZvcm1EYXRhKTtcbiAgICAgICAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZG9VcGRhdGVBbmd1bGFyRm9ybVZhbHVlKGZpZWxkOiBIdG1sRm9ybUVsZW1lbnQsIHZhbHVlOiB7IHZhbHVlPzogc3RyaW5nOyBmb3JtYXR0ZWRWYWx1ZT86IHN0cmluZyB9LCBmdWxsS2V5OiBzdHJpbmcpIHtcbiAgICBsZXQgY2hhbmdlID0gZmFsc2U7XG4gICAgLy8gVXNlIHRoZSBhY3R1YWwgdXNlciBpbnB1dCB2YWx1ZSwgbm90IHRoZSBmb3JtYXR0ZWQgZGlzcGxheSB2YWx1ZVxuICAgIGNvbnN0IGFjdHVhbFZhbHVlID0gdmFsdWUudmFsdWU7XG4gICAgaWYgKGZpZWxkIGluc3RhbmNlb2YgSFRNTElucHV0RWxlbWVudCAmJiBmaWVsZC50eXBlID09PSAnY2hlY2tib3gnKSB7XG4gICAgICBjb25zdCBleHBvcnRWYWx1ZSA9IGZpZWxkLmdldEF0dHJpYnV0ZSgnZXhwb3J0dmFsdWUnKTtcbiAgICAgIGlmIChleHBvcnRWYWx1ZSkge1xuICAgICAgICBpZiAoYWN0dWFsVmFsdWUpIHtcbiAgICAgICAgICBpZiAodGhpcy5mb3JtRGF0YVtmdWxsS2V5XSAhPT0gZXhwb3J0VmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuZm9ybURhdGFbZnVsbEtleV0gPSBleHBvcnRWYWx1ZTtcbiAgICAgICAgICAgIGNoYW5nZSA9IHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGlmICh0aGlzLmZvcm1EYXRhW2Z1bGxLZXldICE9PSBmYWxzZSkge1xuICAgICAgICAgICAgdGhpcy5mb3JtRGF0YVtmdWxsS2V5XSA9IGZhbHNlO1xuICAgICAgICAgICAgY2hhbmdlID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodGhpcy5mb3JtRGF0YVtmdWxsS2V5XSAhPT0gYWN0dWFsVmFsdWUpIHtcbiAgICAgICAgdGhpcy5mb3JtRGF0YVtmdWxsS2V5XSA9IGFjdHVhbFZhbHVlID8/ICcnO1xuICAgICAgICBjaGFuZ2UgPSB0cnVlO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoZmllbGQgaW5zdGFuY2VvZiBIVE1MSW5wdXRFbGVtZW50ICYmIGZpZWxkLnR5cGUgPT09ICdyYWRpbycpIHtcbiAgICAgIGNvbnN0IGV4cG9ydFZhbHVlID0gZmllbGQuZ2V0QXR0cmlidXRlKCdleHBvcnR2YWx1ZScpID8/IGZpZWxkLmdldEF0dHJpYnV0ZSgneGZhb24nKTtcbiAgICAgIGlmIChhY3R1YWxWYWx1ZSkge1xuICAgICAgICBpZiAodGhpcy5mb3JtRGF0YVtmdWxsS2V5XSAhPT0gZXhwb3J0VmFsdWUpIHtcbiAgICAgICAgICB0aGlzLmZvcm1EYXRhW2Z1bGxLZXldID0gZXhwb3J0VmFsdWU7XG4gICAgICAgICAgY2hhbmdlID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAodGhpcy5mb3JtRGF0YVtmdWxsS2V5XSAhPT0gYWN0dWFsVmFsdWUpIHtcbiAgICAgIHRoaXMuZm9ybURhdGFbZnVsbEtleV0gPSBhY3R1YWxWYWx1ZSA/PyAnJztcbiAgICAgIGNoYW5nZSA9IHRydWU7XG4gICAgfVxuICAgIHJldHVybiBjaGFuZ2U7XG4gIH1cblxuICBwdWJsaWMgdXBkYXRlRm9ybUZpZWxkc0luUGRmQ2FsbGVkQnlOZ09uQ2hhbmdlcyhwcmV2aW91c0Zvcm1EYXRhOiBPYmplY3QpIHtcbiAgICBpZiAoIXRoaXMuUERGVmlld2VyQXBwbGljYXRpb24/LnBkZkRvY3VtZW50Py5hbm5vdGF0aW9uU3RvcmFnZSkge1xuICAgICAgLy8gbmdPbkNoYW5nZXMgY2FsbHMgdGhpcyBtZXRob2QgdG9vIGVhcmx5IC0gc28ganVzdCBpZ25vcmUgaXRcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGtleSBpbiB0aGlzLmZvcm1EYXRhKSB7XG4gICAgICBpZiAodGhpcy5mb3JtRGF0YS5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgIGNvbnN0IG5ld1ZhbHVlID0gdGhpcy5mb3JtRGF0YVtrZXldO1xuICAgICAgICBpZiAobmV3VmFsdWUgIT09IHByZXZpb3VzRm9ybURhdGFba2V5XSkge1xuICAgICAgICAgIHRoaXMuc2V0RmllbGRWYWx1ZUFuZFVwZGF0ZUFubm90YXRpb25TdG9yYWdlKGtleSwgbmV3VmFsdWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBrZXkgaW4gcHJldmlvdXNGb3JtRGF0YSkge1xuICAgICAgaWYgKHByZXZpb3VzRm9ybURhdGEuaGFzT3duUHJvcGVydHkoa2V5KSAmJiBwcmV2aW91c0Zvcm1EYXRhW2tleV0pIHtcbiAgICAgICAgbGV0IGhhc1ByZXZpb3VzVmFsdWUgPSB0aGlzLmZvcm1EYXRhLmhhc093blByb3BlcnR5KGtleSk7XG4gICAgICAgIGlmICghaGFzUHJldmlvdXNWYWx1ZSkge1xuICAgICAgICAgIGNvbnN0IGZ1bGxLZXkgPSBPYmplY3Qua2V5cyh0aGlzLmZvcm1EYXRhKS5maW5kKChrKSA9PiBrID09PSBrZXkgfHwgay5lbmRzV2l0aCgnLicgKyBrZXkpKTtcbiAgICAgICAgICBpZiAoZnVsbEtleSkge1xuICAgICAgICAgICAgaGFzUHJldmlvdXNWYWx1ZSA9IHRoaXMuZm9ybURhdGEuaGFzT3duUHJvcGVydHkoZnVsbEtleSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFoYXNQcmV2aW91c1ZhbHVlKSB7XG4gICAgICAgICAgdGhpcy5zZXRGaWVsZFZhbHVlQW5kVXBkYXRlQW5ub3RhdGlvblN0b3JhZ2Uoa2V5LCBudWxsKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc2V0RmllbGRWYWx1ZUFuZFVwZGF0ZUFubm90YXRpb25TdG9yYWdlKGtleTogc3RyaW5nLCBuZXdWYWx1ZTogYW55KSB7XG4gICAgY29uc3QgcmFkaW9zID0gdGhpcy5maW5kUmFkaW9CdXR0b25Hcm91cChrZXkpO1xuICAgIGlmIChyYWRpb3MpIHtcbiAgICAgIHJhZGlvcy5mb3JFYWNoKChyKSA9PiB7XG4gICAgICAgIGNvbnN0IGFjdGl2ZVZhbHVlID0gci5nZXRBdHRyaWJ1dGUoJ2V4cG9ydFZhbHVlJykgPz8gci5nZXRBdHRyaWJ1dGUoJ3hmYW9uJyk7XG4gICAgICAgIHIuY2hlY2tlZCA9IGFjdGl2ZVZhbHVlID09PSBuZXdWYWx1ZTtcbiAgICAgIH0pO1xuICAgICAgY29uc3QgdXBkYXRlRnJvbUFuZ3VsYXIgPSBuZXcgQ3VzdG9tRXZlbnQoJ3VwZGF0ZUZyb21Bbmd1bGFyJywge1xuICAgICAgICBkZXRhaWw6IG5ld1ZhbHVlLFxuICAgICAgfSk7XG4gICAgICByYWRpb3NbMF0uZGlzcGF0Y2hFdmVudCh1cGRhdGVGcm9tQW5ndWxhcik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGZpZWxkSWRzID0gdGhpcy5maW5kRm9ybUlkc0Zyb21GaWVsZE5hbWUoa2V5KTtcbiAgICAgIGlmIChmaWVsZElkcykge1xuICAgICAgICBmaWVsZElkcy5mb3JFYWNoKChmaWVsZElkKSA9PiB7XG4gICAgICAgICAgY29uc3QgaHRtbEZpZWxkID0gdGhpcy5mb3JtSWRUb0ZpZWxkW2ZpZWxkSWRdO1xuXG4gICAgICAgICAgaWYgKGh0bWxGaWVsZCkge1xuICAgICAgICAgICAgaWYgKGh0bWxGaWVsZCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQgJiYgaHRtbEZpZWxkLnR5cGUgPT09ICdjaGVja2JveCcpIHtcbiAgICAgICAgICAgICAgbGV0IGFjdGl2ZVZhbHVlID0gaHRtbEZpZWxkLmdldEF0dHJpYnV0ZSgneGZhb24nKSA/PyBodG1sRmllbGQuZ2V0QXR0cmlidXRlKCdleHBvcnR2YWx1ZScpID8/IHRydWU7XG4gICAgICAgICAgICAgIGlmIChuZXdWYWx1ZSA9PT0gdHJ1ZSB8fCBuZXdWYWx1ZSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICBhY3RpdmVWYWx1ZSA9IHRydWU7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgaHRtbEZpZWxkLmNoZWNrZWQgPSBhY3RpdmVWYWx1ZSA9PT0gbmV3VmFsdWU7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGh0bWxGaWVsZCBpbnN0YW5jZW9mIEhUTUxTZWxlY3RFbGVtZW50KSB7XG4gICAgICAgICAgICAgIHRoaXMucG9wdWxhdGVTZWxlY3RGaWVsZChodG1sRmllbGQsIG5ld1ZhbHVlKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIC8vIHRleHRhcmVhcyBhbmQgaW5wdXQgZmllbGRzXG4gICAgICAgICAgICAgIGh0bWxGaWVsZC52YWx1ZSA9IG5ld1ZhbHVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgdXBkYXRlRnJvbUFuZ3VsYXIgPSBuZXcgQ3VzdG9tRXZlbnQoJ3VwZGF0ZUZyb21Bbmd1bGFyJywge1xuICAgICAgICAgICAgICBkZXRhaWw6IG5ld1ZhbHVlLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBodG1sRmllbGQuZGlzcGF0Y2hFdmVudCh1cGRhdGVGcm9tQW5ndWxhcik7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJDb3VsZG4ndCBzZXQgdGhlIHZhbHVlIG9mIHRoZSBmaWVsZFwiLCBrZXkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBwb3B1bGF0ZVNlbGVjdEZpZWxkKGh0bWxGaWVsZDogSFRNTFNlbGVjdEVsZW1lbnQsIG5ld1ZhbHVlOiBhbnkpIHtcbiAgICBpZiAoaHRtbEZpZWxkLm11bHRpcGxlKSB7XG4gICAgICBjb25zdCB7IG9wdGlvbnMgfSA9IGh0bWxGaWVsZDtcbiAgICAgIGNvbnN0IG5ld1ZhbHVlQXJyYXkgPSBuZXdWYWx1ZSBhcyBBcnJheTxzdHJpbmc+O1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBvcHRpb25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGNvbnN0IG9wdGlvbiA9IG9wdGlvbnMuaXRlbShpKTtcbiAgICAgICAgaWYgKG9wdGlvbikge1xuICAgICAgICAgIG9wdGlvbi5zZWxlY3RlZCA9IG5ld1ZhbHVlQXJyYXkuc29tZSgobykgPT4gbyA9PT0gb3B0aW9uLnZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBodG1sRmllbGQudmFsdWUgPSBuZXdWYWx1ZTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGZpbmRGb3JtSWRzRnJvbUZpZWxkTmFtZShmaWVsZE5hbWU6IHN0cmluZyk6IHN0cmluZ1tdIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoT2JqZWN0LmVudHJpZXModGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWUpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgLy8gc29tZXRpbWVzLCBuZ09uQ2hhbmdlcygpIGlzIGNhbGxlZCBiZWZvcmUgaW5pdGlhbGl6aW5nIHRoZSBQREYgZmlsZVxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgY29uc3QgbWF0Y2hpbmdFbnRyaWVzID0gT2JqZWN0LmVudHJpZXModGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWUpLmZpbHRlcigoZW50cnkpID0+IGVudHJ5WzFdID09PSBmaWVsZE5hbWUgfHwgZW50cnlbMV0uZW5kc1dpdGgoJy4nICsgZmllbGROYW1lKSk7XG4gICAgaWYgKG1hdGNoaW5nRW50cmllcy5sZW5ndGggPT09IDApIHtcbiAgICAgIGNvbnNvbGUubG9nKFwiQ291bGRuJ3QgZmluZCB0aGUgZmllbGQgXCIgKyBmaWVsZE5hbWUpO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcmV0dXJuIG1hdGNoaW5nRW50cmllcy5tYXAoKGUpID0+IGVbMF0pO1xuICB9XG5cbiAgcHJpdmF0ZSBmaW5kUmFkaW9CdXR0b25Hcm91cChmaWVsZE5hbWU6IHN0cmluZyk6IEFycmF5PEhUTUxJbnB1dEVsZW1lbnQ+IHwgbnVsbCB7XG4gICAgY29uc3QgbWF0Y2hpbmdFbnRyaWVzID0gT2JqZWN0LmVudHJpZXModGhpcy5yYWRpb0J1dHRvbnMpLmZpbHRlcigoZW50cnkpID0+IGVudHJ5WzBdLmVuZHNXaXRoKCcuJyArIGZpZWxkTmFtZSkgfHwgZW50cnlbMF0gPT09IGZpZWxkTmFtZSk7XG4gICAgaWYgKG1hdGNoaW5nRW50cmllcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBpZiAobWF0Y2hpbmdFbnRyaWVzLmxlbmd0aCA+IDEpIHtcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAnTW9yZSB0aGFuIG9uZSByYWRpbyBidXR0b24gZ3JvdXAgbmFtZSBtYXRjaGVzIHRoaXMgbmFtZS4gUGxlYXNlIHVzZSB0aGUgcXVhbGlmaWVkIGZpZWxkIG5hbWUnLFxuICAgICAgICBtYXRjaGluZ0VudHJpZXMubWFwKChyYWRpbykgPT4gcmFkaW9bMF0pLFxuICAgICAgKTtcbiAgICAgIGNvbnNvbGUubG9nKCduZ3gtZXh0ZW5kZWQtcGRmLXZpZXdlciB1c2VzIHRoZSBmaXJzdCBtYXRjaGluZyBmaWVsZCAod2hpY2ggbWF5IG5vdCBiZSB0aGUgdG9wbW9zdCBmaWVsZCBvbiB5b3VyIFBERiBmb3JtKTogJyArIG1hdGNoaW5nRW50cmllc1swXVswXSk7XG4gICAgfVxuICAgIHJldHVybiBtYXRjaGluZ0VudHJpZXNbMF1bMV07XG4gIH1cbn1cbiJdfQ==