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.
334 lines • 50.2 kB
JavaScript
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 = {};
formDataChange = new EventEmitter();
ngZone;
reset() {
this.formData = {};
this.formIdToFullFieldName = {};
}
registerFormSupportWithPdfjs(ngZone) {
this.ngZone = ngZone;
globalThis.getFormValueFromAngular = (key) => this.getFormValueFromAngular(key);
globalThis.updateAngularFormValue = (key, value) => this.updateAngularFormValueCalledByPdfjs(key, value);
globalThis.registerAcroformField = (id, element, value, radioButtonValueName) => this.registerAcroformField(id, element, value, radioButtonValueName);
globalThis.registerXFAField = (element, value) => this.registerXFAField(element, value);
}
registerAcroformField(id, element, value, radioButtonValueName) {
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;
}
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);
}
else {
this.formData[fieldName] = value;
}
}
registerXFAField(element, value) {
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;
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;
}
else if (element instanceof HTMLSelectElement) {
const id = element.getAttribute('fieldid') ?? '';
this.formIdToField[id] = element;
this.formIdToFullFieldName[id] = fullFieldName;
this.formData[fullFieldName] = value.value;
}
else if (element instanceof HTMLTextAreaElement) {
const id = element.getAttribute('fieldid') ?? '';
this.formIdToField[id] = element;
this.formIdToFullFieldName[id] = fullFieldName;
this.formData[fullFieldName] = value.value;
}
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 = {};
}
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));
}
}
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));
}
}
}
doUpdateAngularFormValue(field, value, fullKey) {
let change = false;
if (field instanceof HTMLInputElement && field.type === 'checkbox') {
const exportValue = field.getAttribute('exportvalue');
if (exportValue) {
if (value.value) {
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] !== value.value) {
this.formData[fullKey] = value.value;
change = true;
}
}
}
else if (field instanceof HTMLInputElement && field.type === 'radio') {
const exportValue = field.getAttribute('exportvalue') ?? field.getAttribute('xfaon');
if (value.value) {
if (this.formData[fullKey] !== exportValue) {
this.formData[fullKey] = exportValue;
change = true;
}
}
}
else {
if (this.formData[fullKey] !== value.value) {
this.formData[fullKey] = value.value;
change = true;
}
}
return change;
}
updateFormFieldsInPdfCalledByNgOnChanges(previousFormData) {
const PDFViewerApplication = window.PDFViewerApplication;
if (!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 fieldId = this.findFormIdFromFieldName(key);
if (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;
}
}
findFormIdFromFieldName(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 > 1) {
console.log(`More than one field name matches the field name ${fieldName}. Please use the one of these qualified field names:`, matchingEntries.map((f) => f[1]));
console.log('ngx-extended-pdf-viewer uses the first matching field (which may or may not be the topmost field on your PDF form): ' + matchingEntries[0][0]);
}
else if (matchingEntries.length === 0) {
console.log("Couldn't find the field " + fieldName);
return undefined;
}
return matchingEntries[0][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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWZvcm0tc3VwcG9ydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1leHRlbmRlZC1wZGYtdmlld2VyL3NyYy9saWIvbmd4LWZvcm0tc3VwcG9ydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFVLE1BQU0sZUFBZSxDQUFDO0FBS3JELE1BQU0sT0FBTyxjQUFjO0lBQ3pCLDZFQUE2RTtJQUNyRSxxQkFBcUIsR0FBOEIsRUFBRSxDQUFDO0lBRXRELGFBQWEsR0FBdUMsRUFBRSxDQUFDO0lBRXZELFlBQVksR0FBK0MsRUFBRSxDQUFDO0lBRS9ELFFBQVEsR0FBaUIsRUFBRSxDQUFDO0lBRTVCLGNBQWMsR0FBRyxJQUFJLFlBQVksRUFBZ0IsQ0FBQztJQUVqRCxNQUFNLENBQVM7SUFFaEIsS0FBSztRQUNWLElBQUksQ0FBQyxRQUFRLEdBQUcsRUFBRSxDQUFDO1FBQ25CLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxFQUFFLENBQUM7SUFDbEMsQ0FBQztJQUVNLDRCQUE0QixDQUFDLE1BQWM7UUFDaEQsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDcEIsVUFBa0IsQ0FBQyx1QkFBdUIsR0FBRyxDQUFDLEdBQVcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2hHLFVBQWtCLENBQUMsc0JBQXNCLEdBQUcsQ0FBQyxHQUF3RSxFQUFFLEtBQXdCLEVBQUUsRUFBRSxDQUNsSixJQUFJLENBQUMsbUNBQW1DLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3RELFVBQWtCLENBQUMscUJBQXFCLEdBQUcsQ0FBQyxFQUFVLEVBQUUsT0FBd0IsRUFBRSxLQUE2QixFQUFFLG9CQUE2QixFQUFFLEVBQUUsQ0FDakosSUFBSSxDQUFDLHFCQUFxQixDQUFDLEVBQUUsRUFBRSxPQUFPLEVBQUUsS0FBSyxF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ZSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLEdBQUcsU0FBUyxDQUFDLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLFNBQVMsQ0FBQyxDQUFDO1FBQzFJLElBQUksZUFBZSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7WUFDaEMsT0FBTyxJQUFJLENBQUM7U0FDYjtRQUNELElBQUksZUFBZSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDOUIsT0FBTyxDQUFDLEdBQUcsQ0FDVCw4RkFBOEYsRUFDOUYsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQ3pDLENBQUM7WUFDRixPQUFPLENBQUMsR0FBRyxDQUFDLCtHQUErRyxHQUFHLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ3RKO1FBQ0QsT0FBTyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0IsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRXZlbnRFbWl0dGVyLCBOZ1pvbmUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1EYXRhVHlwZSwgSVBERlZpZXdlckFwcGxpY2F0aW9uIH0gZnJvbSAnLi4vcHVibGljX2FwaSc7XG5cbmV4cG9ydCB0eXBlIEh0bWxGb3JtRWxlbWVudCA9IEhUTUxJbnB1dEVsZW1lbnQgfCBIVE1MU2VsZWN0RWxlbWVudCB8IEhUTUxUZXh0QXJlYUVsZW1lbnQ7XG5cbmV4cG9ydCBjbGFzcyBOZ3hGb3JtU3VwcG9ydCB7XG4gIC8qKiBNYXBzIHRoZSBpbnRlcm5hbCBpZHMgb2YgdGhlIGFubm90YXRpb25zIG9mIHBkZi5qcyB0byB0aGVpciBmaWVsZCBuYW1lICovXG4gIHByaXZhdGUgZm9ybUlkVG9GdWxsRmllbGROYW1lOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9ID0ge307XG5cbiAgcHJpdmF0ZSBmb3JtSWRUb0ZpZWxkOiB7IFtrZXk6IHN0cmluZ106IEh0bWxGb3JtRWxlbWVudCB9ID0ge307XG5cbiAgcHJpdmF0ZSByYWRpb0J1dHRvbnM6IHsgW2tleTogc3RyaW5nXTogQXJyYXk8SFRNTElucHV0RWxlbWVudD4gfSA9IHt9O1xuXG4gIHB1YmxpYyBmb3JtRGF0YTogRm9ybURhdGFUeXBlID0ge307XG5cbiAgcHVibGljIGZvcm1EYXRhQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxGb3JtRGF0YVR5cGU+KCk7XG5cbiAgcHJpdmF0ZSBuZ1pvbmU6IE5nWm9uZTtcblxuICBwdWJsaWMgcmVzZXQoKSB7XG4gICAgdGhpcy5mb3JtRGF0YSA9IHt9O1xuICAgIHRoaXMuZm9ybUlkVG9GdWxsRmllbGROYW1lID0ge307XG4gIH1cblxuICBwdWJsaWMgcmVnaXN0ZXJGb3JtU3VwcG9ydFdpdGhQZGZqcyhuZ1pvbmU6IE5nWm9uZSk6IHZvaWQge1xuICAgIHRoaXMubmdab25lID0gbmdab25lO1xuICAgIChnbG9iYWxUaGlzIGFzIGFueSkuZ2V0Rm9ybVZhbHVlRnJvbUFuZ3VsYXIgPSAoa2V5OiBzdHJpbmcpID0+IHRoaXMuZ2V0Rm9ybVZhbHVlRnJvbUFuZ3VsYXIoa2V5KTtcbiAgICAoZ2xvYmFsVGhpcyBhcyBhbnkpLnVwZGF0ZUFuZ3VsYXJGb3JtVmFsdWUgPSAoa2V5OiBzdHJpbmcgfCBIVE1MSW5wdXRFbGVtZW50IHwgSFRNTFNlbGVjdEVsZW1lbnQgfCBIVE1MVGV4dEFyZWFFbGVtZW50LCB2YWx1ZTogeyB2YWx1ZTogc3RyaW5nIH0pID0+XG4gICAgICB0aGlzLnVwZGF0ZUFuZ3VsYXJGb3JtVmFsdWVDYWxsZWRCeVBkZmpzKGtleSwgdmFsdWUpO1xuICAgIChnbG9iYWxUaGlzIGFzIGFueSkucmVnaXN0ZXJBY3JvZm9ybUZpZWxkID0gKGlkOiBzdHJpbmcsIGVsZW1lbnQ6IEh0bWxGb3JtRWxlbWVudCwgdmFsdWU6IHN0cmluZyB8IEFycmF5PHN0cmluZz4sIHJhZGlvQnV0dG9uVmFsdWVOYW1lPzogc3RyaW5nKSA9PlxuICAgICAgdGhpcy5yZWdpc3RlckFjcm9mb3JtRmllbGQoaWQsIGVsZW1lbnQsIHZhbHVlLCByYWRpb0J1dHRvblZhbHVlTmFtZSk7XG5cbiAgICAoZ2xvYmFsVGhpcyBhcyBhbnkpLnJlZ2lzdGVyWEZBRmllbGQgPSAoZWxlbWVudDogSHRtbEZvcm1FbGVtZW50LCB2YWx1ZTogeyB2YWx1ZTogc3RyaW5nIH0pID0+IHRoaXMucmVnaXN0ZXJYRkFGaWVsZChlbGVtZW50LCB2YWx1ZSk7XG4gIH1cblxuICBwcml2YXRlIHJlZ2lzdGVyQWNyb2Zvcm1GaWVsZChpZDogc3RyaW5nLCBlbGVtZW50OiBIdG1sRm9ybUVsZW1lbnQsIHZhbHVlOiBudWxsIHwgc3RyaW5nIHwgQXJyYXk8c3RyaW5nPiwgcmFkaW9CdXR0b25WYWx1ZU5hbWU/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBmaWVsZE5hbWUgPSBlbGVtZW50Lm5hbWU7XG4gICAgdGhpcy5mb3JtSWRUb0ZpZWxkW2lkXSA9IGVsZW1lbnQ7XG4gICAgdGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWVbaWRdID0gZmllbGROYW1lO1xuICAgIGlmIChlbGVtZW50IGluc3RhbmNlb2YgSFRNTElucHV0RWxlbWVudCAmJiBlbGVtZW50LnR5cGUgPT09ICdyYWRpbycpIHtcbiAgICAgIGNvbnN0IGdyb3VwTmFtZSA9IGZpZWxkTmFtZTtcbiAgICAgIHRoaXMuZm9ybUlkVG9GdWxsRmllbGROYW1lW2lkXSA9IGdyb3VwTmFtZTtcbiAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICB0aGlzLmZvcm1EYXRhW2dyb3VwTmFtZV0gPSByYWRpb0J1dHRvblZhbHVlTmFtZSBhcyBzdHJpbmc7XG4gICAgICB9XG4gICAgICBlbGVtZW50LnNldEF0dHJpYnV0ZSgnZXhwb3J0VmFsdWUnLCByYWRpb0J1dHRvblZhbHVlTmFtZSBhcyBzdHJpbmcpO1xuICAgICAgaWYgKCF0aGlzLnJhZGlvQnV0dG9uc1tncm91cE5hbWVdKSB7XG4gICAgICAgIHRoaXMucmFkaW9CdXR0b25zW2dyb3VwTmFtZV0gPSBbXTtcbiAgICAgIH1cbiAgICAgIHRoaXMucmFkaW9CdXR0b25zW2dyb3VwTmFtZV0ucHVzaChlbGVtZW50KTtcbiAgICB9IGVsc2UgaWYgKGVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MU2VsZWN0RWxlbWVudCkge1xuICAgICAgdGhpcy5mb3JtRGF0YVtmaWVsZE5hbWVdID0gdGhpcy5nZXRWYWx1ZU9mQVNlbGVjdEZpZWxkKGVsZW1lbnQpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmZvcm1EYXRhW2ZpZWxkTmFtZV0gPSB2YWx1ZTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHJlZ2lzdGVyWEZBRmllbGQoZWxlbWVudDogSFRNTEVsZW1lbnQsIHZhbHVlOiB7IHZhbHVlOiBzdHJpbmcgfSk6IHZvaWQge1xuICAgIGNvbnN0IGZ1bGxGaWVsZE5hbWUgPSB0aGlzLmZpbmRGdWxsWEZBTmFtZShlbGVtZW50KTtcbiAgICBpZiAoZWxlbWVudCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQgJiYgZWxlbWVudC50eXBlID09PSAncmFkaW8nKSB7XG4gICAgICBjb25zdCBpZCA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdmaWVsZGlkJykgPz8gJyc7XG4gICAgICAvLyByZW1vdmUgdGhlIHhmYSBuYW1lIG9mIHRoZSByYWRpbyBidXR0b24gaXRzZWxmIGZvcm0gdGhlIGZpZWxkIG5hbWUsXG4gICAgICAvLyBiZWNhdXNlIHRoZSBmaWVsZCBuYW1lIHJlZmVycyB0byB0aGUgZW50aXJlIGdyb3VwIG9mIHJlbGF0YXRlZCByYWRpbyBidXR0b25zXG4gICAgICBjb25zdCBncm91cE5hbWUgPSBmdWxsRmllbGROYW1lLnN1YnN0cmluZygwLCBmdWxsRmllbGROYW1lLmxhc3RJbmRleE9mKCcuJykpO1xuICAgICAgdGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWVbaWRdID0gZ3JvdXBOYW1lO1xuICAgICAgdGhpcy5mb3JtRGF0YVtncm91cE5hbWVdID0gdmFsdWUudmFsdWU7XG4gICAgICBpZiAoIXRoaXMucmFkaW9CdXR0b25zW2dyb3VwTmFtZV0pIHtcbiAgICAgICAgdGhpcy5yYWRpb0J1dHRvbnNbZ3JvdXBOYW1lXSA9IFtdO1xuICAgICAgfVxuICAgICAgdGhpcy5yYWRpb0J1dHRvbnNbZ3JvdXBOYW1lXS5wdXNoKGVsZW1lbnQpO1xuICAgIH0gZWxzZSBpZiAoZWxlbWVudCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQpIHtcbiAgICAgIGNvbnN0IGlkID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2ZpZWxkaWQnKSA/PyAnJztcbiAgICAgIHRoaXMuZm9ybUlkVG9GaWVsZFtpZF0gPSBlbGVtZW50O1xuICAgICAgdGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWVbaWRdID0gZnVsbEZpZWxkTmFtZTtcbiAgICAgIHRoaXMuZm9ybURhdGFbZnVsbEZpZWxkTmFtZV0gPSB2YWx1ZS52YWx1ZTtcbiAgICB9IGVsc2UgaWYgKGVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MU2VsZWN0RWxlbWVudCkge1xuICAgICAgY29uc3QgaWQgPSBlbGVtZW50LmdldEF0dHJpYnV0ZSgnZmllbGRpZCcpID8/ICcnO1xuICAgICAgdGhpcy5mb3JtSWRUb0ZpZWxkW2lkXSA9IGVsZW1lbnQ7XG4gICAgICB0aGlzLmZvcm1JZFRvRnVsbEZpZWxkTmFtZVtpZF0gPSBmdWxsRmllbGROYW1lO1xuICAgICAgdGhpcy5mb3JtRGF0YVtmdWxsRmllbGROYW1lXSA9IHZhbHVlLnZhbHVlO1xuICAgIH0gZWxzZSBpZiAoZWxlbWVudCBpbnN0YW5jZW9mIEhUTUxUZXh0QXJlYUVsZW1lbnQpIHtcbiAgICAgIGNvbnN0IGlkID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2ZpZWxkaWQnKSA/PyAnJztcbiAgICAgIHRoaXMuZm9ybUlkVG9GaWVsZFtpZF0gPSBlbGVtZW50O1xuICAgICAgdGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWVbaWRdID0gZnVsbEZpZWxkTmFtZTtcbiAgICAgIHRoaXMuZm9ybURhdGFbZnVsbEZpZWxkTmFtZV0gPSB2YWx1ZS52YWx1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5lcnJvcihcIkNvdWxkbid0IHJlZ2lzdGVyIGFuIFhGQSBmb3JtIGZpZWxkXCIsIGVsZW1lbnQpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0VmFsdWVPZkFTZWxlY3RGaWVsZChzZWxlY3RFbGVtZW50OiBIVE1MU2VsZWN0RWxlbWVudCk6IG51bGwgfCBzdHJpbmcgfCBBcnJheTxzdHJpbmc+IHtcbiAgICBjb25zdCB7IG9wdGlvbnMsIG11bHRpcGxlIH0gPSBzZWxlY3RFbGVtZW50O1xuICAgIGlmICghbXVsdGlwbGUpIHtcbiAgICAgIHJldHVybiBvcHRpb25zLnNlbGVjdGVkSW5kZXggPT09IC0xID8gbnVsbCA6IG9wdGlvbnNbb3B0aW9ucy5zZWxlY3RlZEluZGV4XVsndmFsdWUnXTtcbiAgICB9XG4gICAgcmV0dXJuIEFycmF5LnByb3RvdHlwZS5maWx0ZXIuY2FsbChvcHRpb25zLCAob3B0aW9uKSA9PiBvcHRpb24uc2VsZWN0ZWQpLm1hcCgob3B0aW9uKSA9PiBvcHRpb25bJ3ZhbHVlJ10pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRGb3JtVmFsdWVGcm9tQW5ndWxhcihlbGVtZW50OiBIVE1MRWxlbWVudCB8IHN0cmluZyk6IE9iamVjdCB7XG4gICAgbGV0IGtleTogc3RyaW5nO1xuICAgIGlmIChlbGVtZW50IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHtcbiAgICAgIGNvbnN0IGZpZWxkTmFtZSA9IHRoaXMuZmluZFhGQU5hbWUoZWxlbWVudCk7XG4gICAgICBpZiAoZmllbGROYW1lKSB7XG4gICAgICAgIGlmICh0aGlzLmZvcm1EYXRhLmhhc093blByb3BlcnR5KGZpZWxkTmFtZSkpIHtcbiAgICAgICAgICBrZXkgPSBmaWVsZE5hbWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAga2V5ID0gdGhpcy5maW5kRnVsbFhGQU5hbWUoZWxlbWVudCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJDb3VsZG4ndCBmaW5kIHRoZSBmaWVsZCBuYW1lIG9yIFhGQSBuYW1lIG9mIHRoZSBmb3JtIGZpZWxkXCIsIGVsZW1lbnQpO1xuICAgICAgICByZXR1cm4geyB2YWx1ZTogbnVsbCB9O1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBrZXkgPSBlbGVtZW50O1xuICAgIH1cbiAgICByZXR1cm4geyB2YWx1ZTogdGhpcy5mb3JtRGF0YVtrZXldIH07XG4gIH1cblxuICBwcml2YXRlIGZpbmRYRkFOYW1lKGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogc3RyaW5nIHtcbiAgICBsZXQgcGFyZW50RWxlbWVudDogSFRNTEVsZW1lbnQgfCBudWxsIHwgdW5kZWZpbmVkID0gZWxlbWVudDtcbiAgICB3aGlsZSAoIXBhcmVudEVsZW1lbnQuZ2V0QXR0cmlidXRlKCd4ZmFuYW1lJykgJiYgcGFyZW50RWxlbWVudC5wYXJlbnRFbGVtZW50KSB7XG4gICAgICBwYXJlbnRFbGVtZW50ID0gcGFyZW50RWxlbWVudC5wYXJlbnRFbGVtZW50O1xuICAgIH1cbiAgICBpZiAoZWxlbWVudCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQgJiYgZWxlbWVudC50eXBlID09PSAncmFkaW8nKSB7XG4gICAgICBkbyB7XG4gICAgICAgIHBhcmVudEVsZW1lbnQgPSBwYXJlbnRFbGVtZW50Py5wYXJlbnRFbGVtZW50O1xuICAgICAgfSB3aGlsZSAoIXBhcmVudEVsZW1lbnQ/LmdldEF0dHJpYnV0ZSgneGZhbmFtZScpICYmIHBhcmVudEVsZW1lbnQpO1xuICAgIH1cbiAgICBsZXQgZmllbGROYW1lID0gcGFyZW50RWxlbWVudD8uZ2V0QXR0cmlidXRlKCd4ZmFuYW1lJyk7XG4gICAgaWYgKCFmaWVsZE5hbWUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkNvdWxkbid0IGZpbmQgdGhlIHhmYW5hbWUgb2YgdGhlIGZpZWxkXCIpO1xuICAgIH1cbiAgICByZXR1cm4gZmllbGROYW1lO1xuICB9XG5cbiAgcHJpdmF0ZSBmaW5kRnVsbFhGQU5hbWUoZWxlbWVudDogSFRNTEVsZW1lbnQpOiBzdHJpbmcge1xuICAgIGxldCBwYXJlbnRFbGVtZW50ID0gZWxlbWVudDtcbiAgICBsZXQgZmllbGROYW1lID0gJyc7XG4gICAgd2hpbGUgKHBhcmVudEVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCAmJiBwYXJlbnRFbGVtZW50LnBhcmVudEVsZW1lbnQpIHtcbiAgICAgIGNvbnN0IHhmYU5hbWUgPSBwYXJlbnRFbGVtZW50LmdldEF0dHJpYnV0ZSgneGZhbmFtZScpO1xuICAgICAgaWYgKHhmYU5hbWUpIHtcbiAgICAgICAgZmllbGROYW1lID0geGZhTmFtZSArICcuJyArIGZpZWxkTmFtZTtcbiAgICAgIH1cbiAgICAgIHBhcmVudEVsZW1lbnQgPSBwYXJlbnRFbGVtZW50LnBhcmVudEVsZW1lbnQ7XG4gICAgfVxuICAgIGlmICghZmllbGROYW1lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZG4ndCBmaW5kIHRoZSB4ZmFuYW1lIG9mIHRoZSBmaWVsZFwiKTtcbiAgICB9XG4gICAgZmllbGROYW1lID0gZmllbGROYW1lLnN1YnN0cmluZygwLCBmaWVsZE5hbWUubGVuZ3RoIC0gMSk7XG4gICAgaWYgKGVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MSW5wdXRFbGVtZW50ICYmIGVsZW1lbnQudHlwZSA9PT0gJ3JhZGlvJykge1xuICAgICAgLy8gaWdub3JlIHRoZSBsYXN0IHBhcnQgb2YgdGhlIHhmYU5hbWUgYmVjYXVzZSBpdCdzIGFjdHVhbGx5IHRoZSB2YWx1ZSBvZiB0aGUgZmllbGRcbiAgICAgIHJldHVybiBmaWVsZE5hbWUuc3Vic3RyaW5nKDAsIGZpZWxkTmFtZS5sYXN0SW5kZXhPZignLicpKTtcbiAgICB9XG4gICAgcmV0dXJuIGZpZWxkTmFtZTtcbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlQW5ndWxhckZvcm1WYWx1ZUNhbGxlZEJ5UGRmanMoa2V5OiBzdHJpbmcgfCBIVE1MU2VsZWN0RWxlbWVudCB8IEhUTUxJbnB1dEVsZW1lbnQgfCBIVE1MVGV4dEFyZWFFbGVtZW50LCB2YWx1ZTogeyB2YWx1ZTogc3RyaW5nIH0pOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuZm9ybURhdGEpIHtcbiAgICAgIHRoaXMuZm9ybURhdGEgPSB7fTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGtleSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGNvbnN0IGFjcm9Gb3JtS2V5ID0gdGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWVba2V5XTtcbiAgICAgIGNvbnN0IGZ1bGxLZXkgPSBhY3JvRm9ybUtleSA/PyBPYmplY3QudmFsdWVzKHRoaXMuZm9ybUlkVG9GdWxsRmllbGROYW1lKS5maW5kKChrKSA9PiBrID09PSBrZXkgfHwgay5lbmRzV2l0aCgnLicgKyBrZXkpKTtcbiAgICAgIGlmIChmdWxsS2V5KSB7XG4gICAgICAgIGNvbnN0IGZpZWxkID0gdGhpcy5mb3JtSWRUb0ZpZWxkW2tleV07XG4gICAgICAgIGxldCBjaGFuZ2UgPSB0aGlzLmRvVXBkYXRlQW5ndWxhckZvcm1WYWx1ZShmaWVsZCwgdmFsdWUsIGZ1bGxLZXkpO1xuICAgICAgICBpZiAoY2hhbmdlKSB7XG4gICAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHRoaXMuZm9ybURhdGFDaGFuZ2UuZW1pdCh0aGlzLmZvcm1EYXRhKSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJDb3VsZG4ndCBmaW5kIHRoZSBmaWVsZCB3aXRoIHRoZSBuYW1lIFwiICsga2V5KTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgbGV0IGNoYW5nZSA9IGZhbHNlO1xuICAgICAgY29uc3Qgc2hvcnRGaWVsZE5hbWUgPSB0aGlzLmZpbmRYRkFOYW1lKGtleSk7XG4gICAgICBpZiAodGhpcy5mb3JtRGF0YS5oYXNPd25Qcm9wZXJ0eShzaG9ydEZpZWxkTmFtZSkpIHtcbiAgICAgICAgY2hhbmdlID0gdGhpcy5kb1VwZGF0ZUFuZ3VsYXJGb3JtVmFsdWUoa2V5LCB2YWx1ZSwgc2hvcnRGaWVsZE5hbWUpO1xuICAgICAgfVxuICAgICAgY29uc3QgZnVsbEZpZWxkTmFtZSA9IHRoaXMuZmluZEZ1bGxYRkFOYW1lKGtleSk7XG4gICAgICBpZiAoZnVsbEZpZWxkTmFtZSAhPT0gc2hvcnRGaWVsZE5hbWUpIHtcbiAgICAgICAgY2hhbmdlIHx8PSB0aGlzLmRvVXBkYXRlQW5ndWxhckZvcm1WYWx1ZShrZXksIHZhbHVlLCBmdWxsRmllbGROYW1lKTtcbiAgICAgIH1cbiAgICAgIGlmIChjaGFuZ2UpIHtcbiAgICAgICAgdGhpcy5uZ1pvbmUucnVuKCgpID0+IHRoaXMuZm9ybURhdGFDaGFuZ2UuZW1pdCh0aGlzLmZvcm1EYXRhKSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBkb1VwZGF0ZUFuZ3VsYXJGb3JtVmFsdWUoZmllbGQ6IEh0bWxGb3JtRWxlbWVudCwgdmFsdWU6IHsgdmFsdWU6IHN0cmluZyB9LCBmdWxsS2V5OiBzdHJpbmcpIHtcbiAgICBsZXQgY2hhbmdlID0gZmFsc2U7XG4gICAgaWYgKGZpZWxkIGluc3RhbmNlb2YgSFRNTElucHV0RWxlbWVudCAmJiBmaWVsZC50eXBlID09PSAnY2hlY2tib3gnKSB7XG4gICAgICBjb25zdCBleHBvcnRWYWx1ZSA9IGZpZWxkLmdldEF0dHJpYnV0ZSgnZXhwb3J0dmFsdWUnKTtcbiAgICAgIGlmIChleHBvcnRWYWx1ZSkge1xuICAgICAgICBpZiAodmFsdWUudmFsdWUpIHtcbiAgICAgICAgICBpZiAodGhpcy5mb3JtRGF0YVtmdWxsS2V5XSAhPT0gZXhwb3J0VmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuZm9ybURhdGFbZnVsbEtleV0gPSBleHBvcnRWYWx1ZTtcbiAgICAgICAgICAgIGNoYW5nZSA9IHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGlmICh0aGlzLmZvcm1EYXRhW2Z1bGxLZXldICE9PSBmYWxzZSkge1xuICAgICAgICAgICAgdGhpcy5mb3JtRGF0YVtmdWxsS2V5XSA9IGZhbHNlO1xuICAgICAgICAgICAgY2hhbmdlID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICh0aGlzLmZvcm1EYXRhW2Z1bGxLZXldICE9PSB2YWx1ZS52YWx1ZSkge1xuICAgICAgICAgIHRoaXMuZm9ybURhdGFbZnVsbEtleV0gPSB2YWx1ZS52YWx1ZTtcbiAgICAgICAgICBjaGFuZ2UgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChmaWVsZCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQgJiYgZmllbGQudHlwZSA9PT0gJ3JhZGlvJykge1xuICAgICAgY29uc3QgZXhwb3J0VmFsdWUgPSBmaWVsZC5nZXRBdHRyaWJ1dGUoJ2V4cG9ydHZhbHVlJykgPz8gZmllbGQuZ2V0QXR0cmlidXRlKCd4ZmFvbicpO1xuICAgICAgaWYgKHZhbHVlLnZhbHVlKSB7XG4gICAgICAgIGlmICh0aGlzLmZvcm1EYXRhW2Z1bGxLZXldICE9PSBleHBvcnRWYWx1ZSkge1xuICAgICAgICAgIHRoaXMuZm9ybURhdGFbZnVsbEtleV0gPSBleHBvcnRWYWx1ZTtcbiAgICAgICAgICBjaGFuZ2UgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICh0aGlzLmZvcm1EYXRhW2Z1bGxLZXldICE9PSB2YWx1ZS52YWx1ZSkge1xuICAgICAgICB0aGlzLmZvcm1EYXRhW2Z1bGxLZXldID0gdmFsdWUudmFsdWU7XG4gICAgICAgIGNoYW5nZSA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjaGFuZ2U7XG4gIH1cblxuICBwdWJsaWMgdXBkYXRlRm9ybUZpZWxkc0luUGRmQ2FsbGVkQnlOZ09uQ2hhbmdlcyhwcmV2aW91c0Zvcm1EYXRhOiBPYmplY3QpIHtcbiAgICBjb25zdCBQREZWaWV3ZXJBcHBsaWNhdGlvbjogSVBERlZpZXdlckFwcGxpY2F0aW9uID0gKHdpbmRvdyBhcyBhbnkpLlBERlZpZXdlckFwcGxpY2F0aW9uO1xuXG4gICAgaWYgKCFQREZWaWV3ZXJBcHBsaWNhdGlvbj8ucGRmRG9jdW1lbnQ/LmFubm90YXRpb25TdG9yYWdlKSB7XG4gICAgICAvLyBuZ09uQ2hhbmdlcyBjYWxscyB0aGlzIG1ldGhvZCB0b28gZWFybHkgLSBzbyBqdXN0IGlnbm9yZSBpdFxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGZvciAoY29uc3Qga2V5IGluIHRoaXMuZm9ybURhdGEpIHtcbiAgICAgIGlmICh0aGlzLmZvcm1EYXRhLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgY29uc3QgbmV3VmFsdWUgPSB0aGlzLmZvcm1EYXRhW2tleV07XG4gICAgICAgIGlmIChuZXdWYWx1ZSAhPT0gcHJldmlvdXNGb3JtRGF0YVtrZXldKSB7XG4gICAgICAgICAgdGhpcy5zZXRGaWVsZFZhbHVlQW5kVXBkYXRlQW5ub3RhdGlvblN0b3JhZ2Uoa2V5LCBuZXdWYWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGtleSBpbiBwcmV2aW91c0Zvcm1EYXRhKSB7XG4gICAgICBpZiAocHJldmlvdXNGb3JtRGF0YS5oYXNPd25Qcm9wZXJ0eShrZXkpICYmIHByZXZpb3VzRm9ybURhdGFba2V5XSkge1xuICAgICAgICBsZXQgaGFzUHJldmlvdXNWYWx1ZSA9IHRoaXMuZm9ybURhdGEuaGFzT3duUHJvcGVydHkoa2V5KTtcbiAgICAgICAgaWYgKCFoYXNQcmV2aW91c1ZhbHVlKSB7XG4gICAgICAgICAgY29uc3QgZnVsbEtleSA9IE9iamVjdC5rZXlzKHRoaXMuZm9ybURhdGEpLmZpbmQoKGspID0+IGsgPT09IGtleSB8fCBrLmVuZHNXaXRoKCcuJyArIGtleSkpO1xuICAgICAgICAgIGlmIChmdWxsS2V5KSB7XG4gICAgICAgICAgICBoYXNQcmV2aW91c1ZhbHVlID0gdGhpcy5mb3JtRGF0YS5oYXNPd25Qcm9wZXJ0eShmdWxsS2V5KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWhhc1ByZXZpb3VzVmFsdWUpIHtcbiAgICAgICAgICB0aGlzLnNldEZpZWxkVmFsdWVBbmRVcGRhdGVBbm5vdGF0aW9uU3RvcmFnZShrZXksIG51bGwpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzZXRGaWVsZFZhbHVlQW5kVXBkYXRlQW5ub3RhdGlvblN0b3JhZ2Uoa2V5OiBzdHJpbmcsIG5ld1ZhbHVlOiBhbnkpIHtcbiAgICBjb25zdCByYWRpb3MgPSB0aGlzLmZpbmRSYWRpb0J1dHRvbkdyb3VwKGtleSk7XG4gICAgaWYgKHJhZGlvcykge1xuICAgICAgcmFkaW9zLmZvckVhY2goKHIpID0+IHtcbiAgICAgICAgY29uc3QgYWN0aXZlVmFsdWUgPSByLmdldEF0dHJpYnV0ZSgnZXhwb3J0VmFsdWUnKSA/PyByLmdldEF0dHJpYnV0ZSgneGZhb24nKTtcbiAgICAgICAgci5jaGVja2VkID0gYWN0aXZlVmFsdWUgPT09IG5ld1ZhbHVlO1xuICAgICAgfSk7XG4gICAgICBjb25zdCB1cGRhdGVGcm9tQW5ndWxhciA9IG5ldyBDdXN0b21FdmVudCgndXBkYXRlRnJvbUFuZ3VsYXInLCB7XG4gICAgICAgIGRldGFpbDogbmV3VmFsdWUsXG4gICAgICB9KTtcbiAgICAgIHJhZGlvc1swXS5kaXNwYXRjaEV2ZW50KHVwZGF0ZUZyb21Bbmd1bGFyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgZmllbGRJZCA9IHRoaXMuZmluZEZvcm1JZEZyb21GaWVsZE5hbWUoa2V5KTtcbiAgICAgIGlmIChmaWVsZElkKSB7XG4gICAgICAgIGNvbnN0IGh0bWxGaWVsZCA9IHRoaXMuZm9ybUlkVG9GaWVsZFtmaWVsZElkXTtcblxuICAgICAgICBpZiAoaHRtbEZpZWxkKSB7XG4gICAgICAgICAgaWYgKGh0bWxGaWVsZCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQgJiYgaHRtbEZpZWxkLnR5cGUgPT09ICdjaGVja2JveCcpIHtcbiAgICAgICAgICAgIGxldCBhY3RpdmVWYWx1ZSA9IGh0bWxGaWVsZC5nZXRBdHRyaWJ1dGUoJ3hmYW9uJykgPz8gaHRtbEZpZWxkLmdldEF0dHJpYnV0ZSgnZXhwb3J0dmFsdWUnKSA/PyB0cnVlO1xuICAgICAgICAgICAgaWYgKG5ld1ZhbHVlID09PSB0cnVlIHx8IG5ld1ZhbHVlID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICBhY3RpdmVWYWx1ZSA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBodG1sRmllbGQuY2hlY2tlZCA9IGFjdGl2ZVZhbHVlID09PSBuZXdWYWx1ZTtcbiAgICAgICAgICB9IGVsc2UgaWYgKGh0bWxGaWVsZCBpbnN0YW5jZW9mIEhUTUxTZWxlY3RFbGVtZW50KSB7XG4gICAgICAgICAgICB0aGlzLnBvcHVsYXRlU2VsZWN0RmllbGQoaHRtbEZpZWxkLCBuZXdWYWx1ZSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIHRleHRhcmVhcyBhbmQgaW5wdXQgZmllbGRzXG4gICAgICAgICAgICBodG1sRmllbGQudmFsdWUgPSBuZXdWYWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgdXBkYXRlRnJvbUFuZ3VsYXIgPSBuZXcgQ3VzdG9tRXZlbnQoJ3VwZGF0ZUZyb21Bbmd1bGFyJywge1xuICAgICAgICAgICAgZGV0YWlsOiBuZXdWYWx1ZSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBodG1sRmllbGQuZGlzcGF0Y2hFdmVudCh1cGRhdGVGcm9tQW5ndWxhcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIkNvdWxkbid0IHNldCB0aGUgdmFsdWUgb2YgdGhlIGZpZWxkXCIsIGtleSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHBvcHVsYXRlU2VsZWN0RmllbGQoaHRtbEZpZWxkOiBIVE1MU2VsZWN0RWxlbWVudCwgbmV3VmFsdWU6IGFueSkge1xuICAgIGlmIChodG1sRmllbGQubXVsdGlwbGUpIHtcbiAgICAgIGNvbnN0IHsgb3B0aW9ucyB9ID0gaHRtbEZpZWxkO1xuICAgICAgY29uc3QgbmV3VmFsdWVBcnJheSA9IG5ld1ZhbHVlIGFzIEFycmF5PHN0cmluZz47XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG9wdGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgY29uc3Qgb3B0aW9uID0gb3B0aW9ucy5pdGVtKGkpO1xuICAgICAgICBpZiAob3B0aW9uKSB7XG4gICAgICAgICAgb3B0aW9uLnNlbGVjdGVkID0gbmV3VmFsdWVBcnJheS5zb21lKChvKSA9PiBvID09PSBvcHRpb24udmFsdWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGh0bWxGaWVsZC52YWx1ZSA9IG5ld1ZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZmluZEZvcm1JZEZyb21GaWVsZE5hbWUoZmllbGROYW1lOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmIChPYmplY3QuZW50cmllcyh0aGlzLmZvcm1JZFRvRnVsbEZpZWxkTmFtZSkubGVuZ3RoID09PSAwKSB7XG4gICAgICAvLyBzb21ldGltZXMsIG5nT25DaGFuZ2VzKCkgaXMgY2FsbGVkIGJlZm9yZSBpbml0aWFsaXppbmcgdGhlIFBERiBmaWxlXG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBjb25zdCBtYXRjaGluZ0VudHJpZXMgPSBPYmplY3QuZW50cmllcyh0aGlzLmZvcm1JZFRvRnVsbEZpZWxkTmFtZSkuZmlsdGVyKChlbnRyeSkgPT4gZW50cnlbMV0gPT09IGZpZWxkTmFtZSB8fCBlbnRyeVsxXS5lbmRzV2l0aCgnLicgKyBmaWVsZE5hbWUpKTtcbiAgICBpZiAobWF0Y2hpbmdFbnRyaWVzLmxlbmd0aCA+IDEpIHtcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBgTW9yZSB0aGFuIG9uZSBmaWVsZCBuYW1lIG1hdGNoZXMgdGhlIGZpZWxkIG5hbWUgJHtmaWVsZE5hbWV9LiBQbGVhc2UgdXNlIHRoZSBvbmUgb2YgdGhlc2UgcXVhbGlmaWVkIGZpZWxkIG5hbWVzOmAsXG4gICAgICAgIG1hdGNoaW5nRW50cmllcy5tYXAoKGYpID0+IGZbMV0pXG4gICAgICApO1xuICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICduZ3gtZXh0ZW5kZWQtcGRmLXZpZXdlciB1c2VzIHRoZSBmaXJzdCBtYXRjaGluZyBmaWVsZCAod2hpY2ggbWF5IG9yIG1heSBub3QgYmUgdGhlIHRvcG1vc3QgZmllbGQgb24geW91ciBQREYgZm9ybSk6ICcgKyBtYXRjaGluZ0VudHJpZXNbMF1bMF1cbiAgICAgICk7XG4gICAgfSBlbHNlIGlmIChtYXRjaGluZ0VudHJpZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZyhcIkNvdWxkbid0IGZpbmQgdGhlIGZpZWxkIFwiICsgZmllbGROYW1lKTtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHJldHVybiBtYXRjaGluZ0VudHJpZXNbMF1bMF07XG4gIH1cblxuICBwcml2YXRlIGZpbmRSYWRpb0J1dHRvbkdyb3VwKGZpZWxkTmFtZTogc3RyaW5nKTogQXJyYXk8SFRNTElucHV0RWxlbWVudD4gfCBudWxsIHtcbiAgICBjb25zdCBtYXRjaGluZ0VudHJpZXMgPSBPYmplY3QuZW50cmllcyh0aGlzLnJhZGlvQnV0dG9ucykuZmlsdGVyKChlbnRyeSkgPT4gZW50cnlbMF0uZW5kc1dpdGgoJy4nICsgZmllbGROYW1lKSB8fCBlbnRyeVswXSA9PT0gZmllbGROYW1lKTtcbiAgICBpZiAobWF0Y2hpbmdFbnRyaWVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGlmIChtYXRjaGluZ0VudHJpZXMubGVuZ3RoID4gMSkge1xuICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICdNb3JlIHRoYW4gb25lIHJhZGlvIGJ1dHRvbiBncm91cCBuYW1lIG1hdGNoZXMgdGhpcyBuYW1lLiBQbGVhc2UgdXNlIHRoZSBxdWFsaWZpZWQgZmllbGQgbmFtZScsXG4gICAgICAgIG1hdGNoaW5nRW50cmllcy5tYXAoKHJhZGlvKSA9PiByYWRpb1swXSlcbiAgICAgICk7XG4gICAgICBjb25zb2xlLmxvZygnbmd4LWV4dGVuZGVkLXBkZi12aWV3ZXIgdXNlcyB0aGUgZmlyc3