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.

360 lines 55.5 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) { 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); } } } // #2691 modified by ngx-extended-pdf-viewer // After programmatically setting form values, update the baseline for change detection if (this.PDFViewerApplication?.setInitialAnnotationValues) { setTimeout(() => { this.PDFViewerApplication?.setInitialAnnotationValues?.(); }, 10); // Small delay to ensure all form updates are processed } // #2691 end of modification by ngx-extended-pdf-viewer } 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWZvcm0tc3VwcG9ydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1leHRlbmRlZC1wZGYtdmlld2VyL3NyYy9saWIvbmd4LWZvcm0tc3VwcG9ydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQXFCLFlBQVksRUFBVSxNQUFNLGVBQWUsQ0FBQztBQU14RSxNQUFNLE9BQU8sY0FBYztJQUN6Qiw2RUFBNkU7SUFDckUscUJBQXFCLEdBQThCLEVBQUUsQ0FBQztJQUV0RCxhQUFhLEdBQXVDLEVBQUUsQ0FBQztJQUV2RCxZQUFZLEdBQStDLEVBQUUsQ0FBQztJQUUvRCxRQUFRLEdBQWlCLEVBQUUsQ0FBQztJQUU1Qiw2QkFBNkIsR0FBaUIsRUFBRSxDQUFDO0lBRWpELGNBQWMsR0FBRyxJQUFJLFlBQVksRUFBZ0IsQ0FBQztJQUVqRCxvQkFBb0IsQ0FBb0M7SUFFekQsTUFBTSxDQUFVLENBQUMsaURBQWlEO0lBRWxFLEdBQUcsQ0FBcUIsQ0FBQyxpREFBaUQ7SUFFMUUsS0FBSztRQUNWLElBQUksQ0FBQyxRQUFRLEdBQUcsRUFBRSxDQUFDO1FBQ25CLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxFQUFFLENBQUM7SUFDbEMsQ0FBQztJQUVNLDRCQUE0QixDQUFDLG9CQUEyQztRQUM3RSxJQUFJLENBQUMsb0JBQW9CLEdBQUcsb0JBQW9CLENBQUM7UUFDaEQsVUFBa0IsQ0FBQyx1QkFBdUIsR0FBRyxDQUFDLEdBQVcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLHVCQUF1QixDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2hHLFVBQWtCLENBQUMsc0JBQXNCLEdBQUcsQ0FBQyxHQUF3RSxFQUFFLEtBQXdCLEVBQUUsRUFBRSxDQUNsSixJQUFJLENBQUMsbUNBQW1DLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3RELFVBQWtCLENBQUMscUJBQXFCLEdBQUcsQ0FDMUMsRUFBVSxFQUNWLE9BQXdCLEVBQ3hCLEtBQTZCLEVBQzdCLG9CQUE0QixFQUM1QixtQkFBMkIsRUFDM0IsRUFBRSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxvQkFBb0IsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO1FBRTlGLFVBQWtCLENBQUMsZ0JBQWdCLEdBQUcsQ0FBQyxPQUF3QixFQUFFLEtBQXdCLEVBQUUsbUJBQTJCLEVBQUUsRUFBRSxDQUN6SCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO0lBQy9ELENBQUM7SUFFTyxxQkFBcUIsQ0FDM0IsRUFBVSxFQUNWLE9BQXdCLEVBQ3hCLEtBQW9DLEVBQ3BDLG9CQUE0QixFQUM1Qix1QkFBK0I7UUFFL0IsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztRQUMvQixJQUFJLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQyxHQUFHLE9BQU8sQ0FBQztRQUNqQyxJQUFJLENBQUMscUJBQXFCLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDO1FBQzNDLElBQUksT0FBTyxZQUFZLGdCQUFnQixJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssT0FBTyxFQUFFO1lBQ25FLE1BQU0sU0FBUyxHQUFHLFNBQVMsQ0FBQztZQUM1QixJQUFJLENBQUMscUJBQXFCLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDO1lBQzNDLElBQUksS0FBSyxFQUFFO2dCQUNULElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEdBQUcsb0JBQW9CLENBQUM7Z0JBQ2hELElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxTQUFTLENBQUMsR0FBRyx1QkFBdUIsQ0FBQzthQUN6RTtZQUNELE9BQU8sQ0FBQyxZQUFZLENBQUMsYUFBYSxFQUFFLG9CQUFvQixDQUFDLENBQUM7WUFDMUQsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLEVBQUU7Z0JBQ2pDLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxDQUFDO2FBQ25DO1lBQ0QsSUFBSSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7U0FDNUM7YUFBTSxJQUFJLE9BQU8sWUFBWSxpQkFBaUIsRUFBRTtZQUMvQyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxHQUFHLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNoRSxJQUFJLENBQUMsNkJBQTZCLENBQUMsU0FBUyxDQUFDLEdBQUcsdUJBQXVCLENBQUM7U0FDekU7YUFBTTtZQUNMLElBQUksS0FBSyxLQUFLLFNBQVMsRUFBRTtnQkFDdkIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsR0FBRyxLQUFLLENBQUM7YUFDbEM7WUFDRCxJQUFJLENBQUMsNkJBQTZCLENBQUMsU0FBUyxDQUFDLEdBQUcsdUJBQXVCLENBQUM7U0FDekU7SUFDSCxDQUFDO0lBRU8sZ0JBQWdCLENBQUMsT0FBb0IsRUFBRSxLQUF3QixFQUFFLHVCQUErQjtRQUN0RyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3BELElBQUksT0FBTyxZQUFZLGdCQUFnQixJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssT0FBTyxFQUFFO1lBQ25FLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2pELHNFQUFzRTtZQUN0RSwrRUFBK0U7WUFDL0UsTUFBTSxTQUFTLEdBQUcsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsYUFBYSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQzdFLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLENBQUM7WUFDM0MsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsR0FBRyxLQUFLLEVBQUUsS0FBSyxDQUFDO1lBQ3hDLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxTQUFTLENBQUMsR0FBRyx1QkFBdUIsQ0FBQztZQUV4RSxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsRUFBRTtnQkFDakMsSUFBSSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUM7YUFDbkM7WUFDRCxJQUFJLENBQUMsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztTQUM1QzthQUFNLElBQUksT0FBTyxZQUFZLGdCQUFnQixFQUFFO1lBQzlDLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2pELElBQUksQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDO1lBQ2pDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLENBQUMsR0FBRyxhQUFhLENBQUM7WUFDL0MsSUFBSSxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsR0FBRyxLQUFLLEVBQUUsS0FBSyxDQUFDO1lBQzVDLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxhQUFhLENBQUMsR0FBRyx1QkFBdUIsQ0FBQztTQUM3RTthQUFNLElBQUksT0FBTyxZQUFZLGlCQUFpQixFQUFFO1lBQy9DLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2pELElBQUksQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDO1lBQ2pDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLENBQUMsR0FBRyxhQUFhLENBQUM7WUFDL0MsSUFBSSxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsR0FBRyxLQUFLLEVBQUUsS0FBSyxDQUFDO1lBQzVDLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxhQUFhLENBQUMsR0FBRyx1QkFBdUIsQ0FBQztTQUM3RTthQUFNLElBQUksT0FBTyxZQUFZLG1CQUFtQixFQUFFO1lBQ2pELE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2pELElBQUksQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDO1lBQ2pDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLENBQUMsR0FBRyxhQUFhLENBQUM7WUFDL0MsSUFBSSxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsR0FBRyxLQUFLLEVBQUUsS0FBSyxDQUFDO1lBQzVDLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxhQUFhLENBQUMsR0FBRyx1QkFBdUIsQ0FBQztTQUM3RTthQUFNO1lBQ0wsT0FBTyxDQUFDLEtBQUssQ0FBQyxxQ0FBcUMsRUFBRSxPQUFPLENBQUMsQ0FBQztTQUMvRDtJQUNILENBQUM7SUFFTyxzQkFBc0IsQ0FBQyxhQUFnQztRQUM3RCxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxHQUFHLGFBQWEsQ0FBQztRQUM1QyxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ2IsT0FBTyxPQUFPLENBQUMsYUFBYSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUM7U0FDdEY7UUFDRCxPQUFPLEtBQUssQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQzVHLENBQUM7SUFFTyx1QkFBdUIsQ0FBQyxPQUE2QjtRQUMzRCxJQUFJLEdBQVcsQ0FBQztRQUNoQixJQUFJLE9BQU8sWUFBWSxXQUFXLEVBQUU7WUFDbEMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUM1QyxJQUFJLFNBQVMsRUFBRTtnQkFDYixJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxFQUFFO29CQUMzQyxHQUFHLEdBQUcsU0FBUyxDQUFDO2lCQUNqQjtxQkFBTTtvQkFDTCxHQUFHLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQztpQkFDckM7YUFDRjtpQkFBTTtnQkFDTCxPQUFPLENBQUMsS0FBSyxDQUFDLDREQUE0RCxFQUFFLE9BQU8sQ0FBQyxDQUFDO2dCQUNyRixPQUFPLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDO2FBQ3hCO1NBQ0Y7YUFBTTtZQUNMLEdBQUcsR0FBRyxPQUFPLENBQUM7U0FDZjtRQUNELE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO0lBQ3ZDLENBQUM7SUFFTyxXQUFXLENBQUMsT0FBb0I7UUFDdEMsSUFBSSxhQUFhLEdBQW1DLE9BQU8sQ0FBQztRQUM1RCxPQUFPLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsSUFBSSxhQUFhLENBQUMsYUFBYSxFQUFFO1lBQzVFLGFBQWEsR0FBRyxhQUFhLENBQUMsYUFBYSxDQUFDO1NBQzdDO1FBQ0QsSUFBSSxPQUFPLFlBQVksZ0JBQWdCLElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxPQUFPLEVBQUU7WUFDbkUsR0FBRztnQkFDRCxhQUFhLEdBQUcsYUFBYSxFQUFFLGFBQWEsQ0FBQzthQUM5QyxRQUFRLENBQUMsYUFBYSxFQUFFLFlBQVksQ0FBQyxTQUFTLENBQUMsSUFBSSxhQUFhLEVBQUU7U0FDcEU7UUFDRCxJQUFJLFNBQVMsR0FBRyxhQUFhLEVBQUUsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3ZELElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDZCxNQUFNLElBQUksS0FBSyxDQUFDLHdDQUF3QyxDQUFDLENBQUM7U0FDM0Q7UUFDRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRU8sZUFBZSxDQUFDLE9BQW9CO1FBQzFDLElBQUksYUFBYSxHQUFHLE9BQU8sQ0FBQztRQUM1QixJQUFJLFNBQVMsR0FBRyxFQUFFLENBQUM7UUFDbkIsT0FBTyxhQUFhLFlBQVksV0FBVyxJQUFJLGFBQWEsQ0FBQyxhQUFhLEVBQUU7WUFDMUUsTUFBTSxPQUFPLEdBQUcsYUFBYSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUN0RCxJQUFJLE9BQU8sRUFBRTtnQkFDWCxTQUFTLEdBQUcsT0FBTyxHQUFHLEdBQUcsR0FBRyxTQUFTLENBQUM7YUFDdkM7WUFDRCxhQUFhLEdBQUcsYUFBYSxDQUFDLGFBQWEsQ0FBQztTQUM3QztRQUNELElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDZCxNQUFNLElBQUksS0FBSyxDQUFDLHdDQUF3QyxDQUFDLENBQUM7U0FDM0Q7UUFDRCxTQUFTLEdBQUcsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztRQUN6RCxJQUFJLE9BQU8sWUFBWSxnQkFBZ0IsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLE9BQU8sRUFBRTtZQUNuRSxtRkFBbUY7WUFDbkYsT0FBTyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7U0FDM0Q7UUFDRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRU8sbUNBQW1DLENBQ3pDLEdBQXdFLEVBQ3hFLEtBQWtEO1FBRWxELElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ2xCLElBQUksQ0FBQyxRQUFRLEdBQUcsRUFBRSxDQUFDO1NBQ3BCO1FBRUQsMkVBQTJFO1FBQzNFLDJFQUEyRTtRQUMzRSxJQUFJLEtBQUssQ0FBQyxjQUFjLEtBQUssU0FBUyxJQUFJLEtBQUssQ0FBQyxLQUFLLEtBQUssU0FBUyxFQUFFO1lBQ25FLE9BQU87U0FDUjtRQUVELElBQUksT0FBTyxHQUFHLEtBQUssUUFBUSxFQUFFO1lBQzNCLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNwRCxNQUFNLE9BQU8sR0FBRyxXQUFXLElBQUksTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxDQUFDLFFBQVEsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUN6SCxJQUFJLE9BQU8sRUFBRTtnQkFDWCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUN0QyxJQUFJLE1BQU0sR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztnQkFDbEUsSUFBSSxNQUFNLEVBQUU7b0JBQ1YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFO3dCQUNuQixJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7d0JBQ3hDLElBQUksQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLENBQUM7b0JBQzNCLENBQUMsQ0FBQyxDQUFDO2lCQUNKO2FBQ0Y7aUJBQU07Z0JBQ0wsT0FBTyxDQUFDLEtBQUssQ0FBQyx3Q0FBd0MsR0FBRyxHQUFHLENBQUMsQ0FBQzthQUMvRDtTQUNGO2FBQU07WUFDTCxJQUFJLE1BQU0sR0FBRyxLQUFLLENBQUM7WUFDbkIsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUM3QyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDLGNBQWMsQ0FBQyxFQUFFO2dCQUNoRCxNQUFNLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsY0FBYyxDQUFDLENBQUM7YUFDcEU7WUFDRCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ2hELElBQUksYUFBYSxLQUFLLGNBQWMsRUFBRTtnQkFDcEMsTUFBTSxLQUFLLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLGFBQWEsQ0FBQyxDQUFDO2FBQ3JFO1lBQ0QsSUFBSSxNQUFNLEVBQUU7Z0JBQ1YsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFO29CQUNuQixJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7b0JBQ3hDLElBQUksQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLENBQUM7Z0JBQzNCLENBQUMsQ0FBQyxDQUFDO2FBQ0o7U0FDRjtJQUNILENBQUM7SUFFTyx3QkFBd0IsQ0FBQyxLQUFzQixFQUFFLEtBQWtELEVBQUUsT0FBZTtRQUMxSCxJQUFJLE1BQU0sR0FBRyxLQUFLLENBQUM7UUFDbkIsbUVBQW1FO1FBQ25FLE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUM7UUFDaEMsSUFBSSxLQUFLLFlBQVksZ0JBQWdCLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxVQUFVLEVBQUU7WUFDbEUsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDLFlBQVksQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUN0RCxJQUFJLFdBQVcsRUFBRTtnQkFDZixJQUFJLFdBQVcsRUFBRTtvQkFDZixJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEtBQUssV0FBVyxFQUFFO3dCQUMxQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLFdBQVcsQ0FBQzt3QkFDckMsTUFBTSxHQUFHLElBQUksQ0FBQztxQkFDZjtpQkFDRjtxQkFBTTtvQkFDTCxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEtBQUssS0FBSyxFQUFFO3dCQUNwQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEtBQUssQ0FBQzt3QkFDL0IsTUFBTSxHQUFHLElBQUksQ0FBQztxQkFDZjtpQkFDRjthQUNGO2lCQUFNLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsS0FBSyxXQUFXLEVBQUU7Z0JBQ2pELElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsV0FBVyxJQUFJLEVBQUUsQ0FBQztnQkFDM0MsTUFBTSxHQUFHLElBQUksQ0FBQzthQUNmO1NBQ0Y7YUFBTSxJQUFJLEtBQUssWUFBWSxnQkFBZ0IsSUFBSSxLQUFLLENBQUMsSUFBSSxLQUFLLE9BQU8sRUFBRTtZQUN0RSxNQUFNLFdBQVcsR0FBRyxLQUFLLENBQUMsWUFBWSxDQUFDLGFBQWEsQ0FBQyxJQUFJLEtBQUssQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDckYsSUFBSSxXQUFXLEVBQUU7Z0JBQ2YsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLFdBQVcsRUFBRTtvQkFDMUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxXQUFXLENBQUM7b0JBQ3JDLE1BQU0sR0FBRyxJQUFJLENBQUM7aUJBQ2Y7YUFDRjtTQUNGO2FBQU0sSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLFdBQVcsRUFBRTtZQUNqRCxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLFdBQVcsSUFBSSxFQUFFLENBQUM7WUFDM0MsTUFBTSxHQUFHLElBQUksQ0FBQztTQUNmO1FBQ0QsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVNLHdDQUF3QyxDQUFDLGdCQUF3QjtRQUN0RSxJQUFJLENBQUMsSUFBSSxDQUFDLG9CQUFvQixFQUFFLFdBQVcsRUFBRSxpQkFBaUIsRUFBRTtZQUM5RCw4REFBOEQ7WUFDOUQsT0FBTztTQUNSO1FBRUQsS0FBSyxNQUFNLEdBQUcsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFO1lBQy9CLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLEVBQUU7Z0JBQ3JDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQ3BDLElBQUksUUFBUSxLQUFLLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxFQUFFO29CQUN0QyxJQUFJLENBQUMsdUNBQXVDLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxDQUFDO2lCQUM3RDthQUNGO1NBQ0Y7UUFFRCxLQUFLLE1BQU0sR0FBRyxJQUFJLGdCQUFnQixFQUFFO1lBQ2xDLElBQUksZ0JBQWdCLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxJQUFJLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxFQUFFO2dCQUNqRSxJQUFJLGdCQUFnQixHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUN6RCxJQUFJLENBQUMsZ0JBQWdCLEVBQUU7b0JBQ3JCLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLENBQUMsUUFBUSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDO29CQUMzRixJQUFJLE9BQU8sRUFBRTt3QkFDWCxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQztxQkFDMUQ7aUJBQ0Y7Z0JBRUQsSUFBSSxDQUFDLGdCQUFnQixFQUFFO29CQUNyQixJQUFJLENBQUMsdUNBQXVDLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO2lCQUN6RDthQUNGO1NBQ0Y7UUFFRCw0Q0FBNEM7UUFDNUMsdUZBQXVGO1FBQ3ZGLElBQUksSUFBSSxDQUFDLG9CQUFvQixFQUFFLDBCQUEwQixFQUFFO1lBQ3pELFVBQVUsQ0FBQyxHQUFHLEVBQUU7Z0JBQ2QsSUFBSSxDQUFDLG9CQUFvQixFQUFFLDBCQUEwQixFQUFFLEVBQUUsQ0FBQztZQUM1RCxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyx1REFBdUQ7U0FDaEU7UUFDRCx1REFBdUQ7SUFDekQsQ0FBQztJQUVPLHVDQUF1QyxDQUFDLEdBQVcsRUFBRSxRQUFhO1FBQ3hFLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM5QyxJQUFJLE1BQU0sRUFBRTtZQUNWLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtnQkFDbkIsTUFBTSxXQUFXLEdBQUcsQ0FBQyxDQUFDLFlBQVksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUM3RSxDQUFDLENBQUMsT0FBTyxHQUFHLFdBQVcsS0FBSyxRQUFRLENBQUM7WUFDdkMsQ0FBQyxDQUFDLENBQUM7WUFDSCxNQUFNLGlCQUFpQixHQUFHLElBQUksV0FBVyxDQUFDLG1CQUFtQixFQUFFO2dCQUM3RCxNQUFNLEVBQUUsUUFBUTthQUNqQixDQUFDLENBQUM7WUFDSCxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLGlCQUFpQixDQUFDLENBQUM7U0FDNUM7YUFBTTtZQUNMLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNwRCxJQUFJLFFBQVEsRUFBRTtnQkFDWixRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUU7b0JBQzNCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUM7b0JBRTlDLElBQUksU0FBUyxFQUFFO3dCQUNiLElBQUksU0FBUyxZQUFZLGdCQUFnQixJQUFJLFNBQVMsQ0FBQyxJQUFJLEtBQUssVUFBVSxFQUFFOzRCQUMxRSxJQUFJLFdBQVcsR0FBRyxTQUFTLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLFNBQVMsQ0FBQyxZQUFZLENBQUMsYUFBYSxDQUFDLElBQUksSUFBSSxDQUFDOzRCQUNuRyxJQUFJLFFBQVEsS0FBSyxJQUFJLElBQUksUUFBUSxLQUFLLEtBQUssRUFBRTtnQ0FDM0MsV0FBVyxHQUFHLElBQUksQ0FBQzs2QkFDcEI7NEJBQ0QsU0FBUyxDQUFDLE9BQU8sR0FBRyxXQUFXLEtBQUssUUFBUSxDQUFDO3lCQUM5Qzs2QkFBTSxJQUFJLFNBQVMsWUFBWSxpQkFBaUIsRUFBRTs0QkFDakQsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQzt5QkFDL0M7NkJBQU07NEJBQ0wsNkJBQTZCOzRCQUM3QixTQUFTLENBQUMsS0FBSyxHQUFHLFFBQVEsQ0FBQzt5QkFDNUI7d0JBQ0QsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLFdBQVcsQ0FBQyxtQkFBbUIsRUFBRTs0QkFDN0QsTUFBTSxFQUFFLFFBQVE7eUJBQ2pCLENBQUMsQ0FBQzt3QkFDSCxTQUFTLENBQUMsYUFBYSxDQUFDLGlCQUFpQixDQUFDLENBQUM7cUJBQzVDO3lCQUFNO3dCQUNMLE9BQU8sQ0FBQyxLQUFLLENBQUMscUNBQXFDLEVBQUUsR0FBRyxDQUFDLENBQUM7cUJBQzNEO2dCQUNILENBQUMsQ0FBQyxDQUFDO2FBQ0o7U0FDRjtJQUNILENBQUM7SUFFTyxtQkFBbUIsQ0FBQyxTQUE0QixFQUFFLFFBQWE7UUFDckUsSUFBSSxTQUFTLENBQUMsUUFBUSxFQUFFO1lBQ3RCLE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxTQUFTLENBQUM7WUFDOUIsTUFBTSxhQUFhLEdBQUcsUUFBeUIsQ0FBQztZQUNoRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtnQkFDdkMsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDL0IsSUFBSSxNQUFNLEVBQUU7b0JBQ1YsTUFBTSxDQUFDLFFBQVEsR0FBRyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEtBQUssTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO2lCQUNqRTthQUNGO1NBQ0Y7YUFBTTtZQUNMLFNBQVMsQ0FBQyxLQUFLLEdBQUcsUUFBUSxDQUFDO1NBQzVCO0lBQ0gsQ0FBQztJQUVPLHdCQUF3QixDQUFDLFNBQWlCO1FBQ2hELElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQzNELHNFQUFzRTtZQUN0RSxPQUFPLFNBQVMsQ0FBQztTQUNsQjtRQUNELE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssU0FBUyxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsR0FBRyxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDbkosSUFBSSxlQUFlLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUNoQyxPQUFPLENBQUMsR0FBRyxDQUFDLDBCQUEwQixHQUFHLFNBQVMsQ0FBQyxDQUFDO1lBQ3BELE9BQU8sU0FBUyxDQUFDO1NBQ2xCO1FBQ0QsT0FBTyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRU8sb0JBQW9CLENBQUMsU0FBaUI7UUFDNUMsTUFBTSxlQUFlLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEdBQUcsR0FBRyxTQUFTLENBQUMsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssU0FBUyxDQUFDLENBQUM7UUFDMUksSUFBSSxlQUFlLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUNoQyxPQUFPLElBQUksQ0FBQztTQUNiO1FBQ0QsSUFBSSxlQUFlLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtZQUM5QixPQUFPLENBQUMsR0FBRyxDQUNULDhGQUE4RixFQUM5RixlQUFlLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FDekMsQ0FBQztZQUNGLE9BQU8sQ0FBQyxHQUFHLENBQUMsK0dBQStHLEdBQUcsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDdEo7UUFDRCxPQUFPLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMvQixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGFuZ2VEZXRlY3RvclJlZiwgRXZlbnRFbWl0dGVyLCBOZ1pvbmUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1EYXRhVHlwZSB9IGZyb20gJy4vbmd4LWV4dGVuZGVkLXBkZi12aWV3ZXIuY29tcG9uZW50JztcbmltcG9ydCB7IElQREZWaWV3ZXJBcHBsaWNhdGlvbiB9IGZyb20gJy4vb3B0aW9ucy9wZGYtdmlld2VyLWFwcGxpY2F0aW9uJztcblxuZXhwb3J0IHR5cGUgSHRtbEZvcm1FbGVtZW50ID0gSFRNTElucHV0RWxlbWVudCB8IEhUTUxTZWxlY3RFbGVtZW50IHwgSFRNTFRleHRBcmVhRWxlbWVudDtcblxuZXhwb3J0IGNsYXNzIE5neEZvcm1TdXBwb3J0IHtcbiAgLyoqIE1hcHMgdGhlIGludGVybmFsIGlkcyBvZiB0aGUgYW5ub3RhdGlvbnMgb2YgcGRmLmpzIHRvIHRoZWlyIGZpZWxkIG5hbWUgKi9cbiAgcHJpdmF0ZSBmb3JtSWRUb0Z1bGxGaWVsZE5hbWU6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH0gPSB7fTtcblxuICBwcml2YXRlIGZvcm1JZFRvRmllbGQ6IHsgW2tleTogc3RyaW5nXTogSHRtbEZvcm1FbGVtZW50IH0gPSB7fTtcblxuICBwcml2YXRlIHJhZGlvQnV0dG9uczogeyBba2V5OiBzdHJpbmddOiBBcnJheTxIVE1MSW5wdXRFbGVtZW50PiB9ID0ge307XG5cbiAgcHVibGljIGZvcm1EYXRhOiBGb3JtRGF0YVR5cGUgPSB7fTtcblxuICBwdWJsaWMgaW5pdGlhbEZvcm1EYXRhU3RvcmVkSW5UaGVQREY6IEZvcm1EYXRhVHlwZSA9IHt9O1xuXG4gIHB1YmxpYyBmb3JtRGF0YUNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8Rm9ybURhdGFUeXBlPigpO1xuXG4gIHByaXZhdGUgUERGVmlld2VyQXBwbGljYXRpb246IElQREZWaWV3ZXJBcHBsaWNhdGlvbiB8IHVuZGVmaW5lZDtcblxuICBwdWJsaWMgbmdab25lITogTmdab25lOyAvLyBzZXQgZHVyaW5nIHRoZSBpbml0aWFsaXphaW9uIG9mIHRoZSBQREYgdmlld2VyXG5cbiAgcHVibGljIGNkciE6IENoYW5nZURldGVjdG9yUmVmOyAvLyBzZXQgZHVyaW5nIHRoZSBpbml0aWFsaXphaW9uIG9mIHRoZSBQREYgdmlld2VyXG5cbiAgcHVibGljIHJlc2V0KCkge1xuICAgIHRoaXMuZm9ybURhdGEgPSB7fTtcbiAgICB0aGlzLmZvcm1JZFRvRnVsbEZpZWxkTmFtZSA9IHt9O1xuICB9XG5cbiAgcHVibGljIHJlZ2lzdGVyRm9ybVN1cHBvcnRXaXRoUGRmanMoUERGVmlld2VyQXBwbGljYXRpb246IElQREZWaWV3ZXJBcHBsaWNhdGlvbik6IHZvaWQge1xuICAgIHRoaXMuUERGVmlld2VyQXBwbGljYXRpb24gPSBQREZWaWV3ZXJBcHBsaWNhdGlvbjtcbiAgICAoZ2xvYmFsVGhpcyBhcyBhbnkpLmdldEZvcm1WYWx1ZUZyb21Bbmd1bGFyID0gKGtleTogc3RyaW5nKSA9PiB0aGlzLmdldEZvcm1WYWx1ZUZyb21Bbmd1bGFyKGtleSk7XG4gICAgKGdsb2JhbFRoaXMgYXMgYW55KS51cGRhdGVBbmd1bGFyRm9ybVZhbHVlID0gKGtleTogc3RyaW5nIHwgSFRNTElucHV0RWxlbWVudCB8IEhUTUxTZWxlY3RFbGVtZW50IHwgSFRNTFRleHRBcmVhRWxlbWVudCwgdmFsdWU6IHsgdmFsdWU6IHN0cmluZyB9KSA9PlxuICAgICAgdGhpcy51cGRhdGVBbmd1bGFyRm9ybVZhbHVlQ2FsbGVkQnlQZGZqcyhrZXksIHZhbHVlKTtcbiAgICAoZ2xvYmFsVGhpcyBhcyBhbnkpLnJlZ2lzdGVyQWNyb2Zvcm1GaWVsZCA9IChcbiAgICAgIGlkOiBzdHJpbmcsXG4gICAgICBlbGVtZW50OiBIdG1sRm9ybUVsZW1lbnQsXG4gICAgICB2YWx1ZTogc3RyaW5nIHwgQXJyYXk8c3RyaW5nPixcbiAgICAgIHJhZGlvQnV0dG9uVmFsdWVOYW1lOiBzdHJpbmcsXG4gICAgICBpbml0aWFsVmFsdWVGcm9tUERGOiBzdHJpbmcsXG4gICAgKSA9PiB0aGlzLnJlZ2lzdGVyQWNyb2Zvcm1GaWVsZChpZCwgZWxlbWVudCwgdmFsdWUsIHJhZGlvQnV0dG9uVmFsdWVOYW1lLCBpbml0aWFsVmFsdWVGcm9tUERGKTtcblxuICAgIChnbG9iYWxUaGlzIGFzIGFueSkucmVnaXN0ZXJYRkFGaWVsZCA9IChlbGVtZW50OiBIdG1sRm9ybUVsZW1lbnQsIHZhbHVlOiB7IHZhbHVlOiBzdHJpbmcgfSwgaW5pdGlhbFZhbHVlRnJvbVBERjogc3RyaW5nKSA9PlxuICAgICAgdGhpcy5yZWdpc3RlclhGQUZpZWxkKGVsZW1lbnQsIHZhbHVlLCBpbml0aWFsVmFsdWVGcm9tUERGKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVnaXN0ZXJBY3JvZm9ybUZpZWxkKFxuICAgIGlkOiBzdHJpbmcsXG4gICAgZWxlbWVudDogSHRtbEZvcm1FbGVtZW50LFxuICAgIHZhbHVlOiBudWxsIHwgc3RyaW5nIHwgQXJyYXk8c3RyaW5nPixcbiAgICByYWRpb0J1dHRvblZhbHVlTmFtZTogc3RyaW5nLFxuICAgIGluaXRpYWxGb3JtVmFsdWVGcm9tUERGOiBzdHJpbmcsXG4gICk6IHZvaWQge1xuICAgIGNvbnN0IGZpZWxkTmFtZSA9IGVsZW1lbnQubmFtZTtcbiAgICB0aGlzLmZvcm1JZFRvRmllbGRbaWRdID0gZWxlbWVudDtcbiAgICB0aGlzLmZvcm1JZFRvRnVsbEZpZWxkTmFtZVtpZF0gPSBmaWVsZE5hbWU7XG4gICAgaWYgKGVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MSW5wdXRFbGVtZW50ICYmIGVsZW1lbnQudHlwZSA9PT0gJ3JhZGlvJykge1xuICAgICAgY29uc3QgZ3JvdXBOYW1lID0gZmllbGROYW1lO1xuICAgICAgdGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWVbaWRdID0gZ3JvdXBOYW1lO1xuICAgICAgaWYgKHZhbHVlKSB7XG4gICAgICAgIHRoaXMuZm9ybURhdGFbZ3JvdXBOYW1lXSA9IHJhZGlvQnV0dG9uVmFsdWVOYW1lO1xuICAgICAgICB0aGlzLmluaXRpYWxGb3JtRGF0YVN0b3JlZEluVGhlUERGW2dyb3VwTmFtZV0gPSBpbml0aWFsRm9ybVZhbHVlRnJvbVBERjtcbiAgICAgIH1cbiAgICAgIGVsZW1lbnQuc2V0QXR0cmlidXRlKCdleHBvcnRWYWx1ZScsIHJhZGlvQnV0dG9uVmFsdWVOYW1lKTtcbiAgICAgIGlmICghdGhpcy5yYWRpb0J1dHRvbnNbZ3JvdXBOYW1lXSkge1xuICAgICAgICB0aGlzLnJhZGlvQnV0dG9uc1tncm91cE5hbWVdID0gW107XG4gICAgICB9XG4gICAgICB0aGlzLnJhZGlvQnV0dG9uc1tncm91cE5hbWVdLnB1c2goZWxlbWVudCk7XG4gICAgfSBlbHNlIGlmIChlbGVtZW50IGluc3RhbmNlb2YgSFRNTFNlbGVjdEVsZW1lbnQpIHtcbiAgICAgIHRoaXMuZm9ybURhdGFbZmllbGROYW1lXSA9IHRoaXMuZ2V0VmFsdWVPZkFTZWxlY3RGaWVsZChlbGVtZW50KTtcbiAgICAgIHRoaXMuaW5pdGlhbEZvcm1EYXRhU3RvcmVkSW5UaGVQREZbZmllbGROYW1lXSA9IGluaXRpYWxGb3JtVmFsdWVGcm9tUERGO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLmZvcm1EYXRhW2ZpZWxkTmFtZV0gPSB2YWx1ZTtcbiAgICAgIH1cbiAgICAgIHRoaXMuaW5pdGlhbEZvcm1EYXRhU3RvcmVkSW5UaGVQREZbZmllbGROYW1lXSA9IGluaXRpYWxGb3JtVmFsdWVGcm9tUERGO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcmVnaXN0ZXJYRkFGaWVsZChlbGVtZW50OiBIVE1MRWxlbWVudCwgdmFsdWU6IHsgdmFsdWU6IHN0cmluZyB9LCBpbml0aWFsRm9ybVZhbHVlRnJvbVBERjogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgZnVsbEZpZWxkTmFtZSA9IHRoaXMuZmluZEZ1bGxYRkFOYW1lKGVsZW1lbnQpO1xuICAgIGlmIChlbGVtZW50IGluc3RhbmNlb2YgSFRNTElucHV0RWxlbWVudCAmJiBlbGVtZW50LnR5cGUgPT09ICdyYWRpbycpIHtcbiAgICAgIGNvbnN0IGlkID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2ZpZWxkaWQnKSA/PyAnJztcbiAgICAgIC8vIHJlbW92ZSB0aGUgeGZhIG5hbWUgb2YgdGhlIHJhZGlvIGJ1dHRvbiBpdHNlbGYgZm9ybSB0aGUgZmllbGQgbmFtZSxcbiAgICAgIC8vIGJlY2F1c2UgdGhlIGZpZWxkIG5hbWUgcmVmZXJzIHRvIHRoZSBlbnRpcmUgZ3JvdXAgb2YgcmVsYXRhdGVkIHJhZGlvIGJ1dHRvbnNcbiAgICAgIGNvbnN0IGdyb3VwTmFtZSA9IGZ1bGxGaWVsZE5hbWUuc3Vic3RyaW5nKDAsIGZ1bGxGaWVsZE5hbWUubGFzdEluZGV4T2YoJy4nKSk7XG4gICAgICB0aGlzLmZvcm1JZFRvRnVsbEZpZWxkTmFtZVtpZF0gPSBncm91cE5hbWU7XG4gICAgICB0aGlzLmZvcm1EYXRhW2dyb3VwTmFtZV0gPSB2YWx1ZT8udmFsdWU7XG4gICAgICB0aGlzLmluaXRpYWxGb3JtRGF0YVN0b3JlZEluVGhlUERGW2dyb3VwTmFtZV0gPSBpbml0aWFsRm9ybVZhbHVlRnJvbVBERjtcblxuICAgICAgaWYgKCF0aGlzLnJhZGlvQnV0dG9uc1tncm91cE5hbWVdKSB7XG4gICAgICAgIHRoaXMucmFkaW9CdXR0b25zW2dyb3VwTmFtZV0gPSBbXTtcbiAgICAgIH1cbiAgICAgIHRoaXMucmFkaW9CdXR0b25zW2dyb3VwTmFtZV0ucHVzaChlbGVtZW50KTtcbiAgICB9IGVsc2UgaWYgKGVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MSW5wdXRFbGVtZW50KSB7XG4gICAgICBjb25zdCBpZCA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdmaWVsZGlkJykgPz8gJyc7XG4gICAgICB0aGlzLmZvcm1JZFRvRmllbGRbaWRdID0gZWxlbWVudDtcbiAgICAgIHRoaXMuZm9ybUlkVG9GdWxsRmllbGROYW1lW2lkXSA9IGZ1bGxGaWVsZE5hbWU7XG4gICAgICB0aGlzLmZvcm1EYXRhW2Z1bGxGaWVsZE5hbWVdID0gdmFsdWU/LnZhbHVlO1xuICAgICAgdGhpcy5pbml0aWFsRm9ybURhdGFTdG9yZWRJblRoZVBERltmdWxsRmllbGROYW1lXSA9IGluaXRpYWxGb3JtVmFsdWVGcm9tUERGO1xuICAgIH0gZWxzZSBpZiAoZWxlbWVudCBpbnN0YW5jZW9mIEhUTUxTZWxlY3RFbGVtZW50KSB7XG4gICAgICBjb25zdCBpZCA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdmaWVsZGlkJykgPz8gJyc7XG4gICAgICB0aGlzLmZvcm1JZFRvRmllbGRbaWRdID0gZWxlbWVudDtcbiAgICAgIHRoaXMuZm9ybUlkVG9GdWxsRmllbGROYW1lW2lkXSA9IGZ1bGxGaWVsZE5hbWU7XG4gICAgICB0aGlzLmZvcm1EYXRhW2Z1bGxGaWVsZE5hbWVdID0gdmFsdWU/LnZhbHVlO1xuICAgICAgdGhpcy5pbml0aWFsRm9ybURhdGFTdG9yZWRJblRoZVBERltmdWxsRmllbGROYW1lXSA9IGluaXRpYWxGb3JtVmFsdWVGcm9tUERGO1xuICAgIH0gZWxzZSBpZiAoZWxlbWVudCBpbnN0YW5jZW9mIEhUTUxUZXh0QXJlYUVsZW1lbnQpIHtcbiAgICAgIGNvbnN0IGlkID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2ZpZWxkaWQnKSA/PyAnJztcbiAgICAgIHRoaXMuZm9ybUlkVG9GaWVsZFtpZF0gPSBlbGVtZW50O1xuICAgICAgdGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWVbaWRdID0gZnVsbEZpZWxkTmFtZTtcbiAgICAgIHRoaXMuZm9ybURhdGFbZnVsbEZpZWxkTmFtZV0gPSB2YWx1ZT8udmFsdWU7XG4gICAgICB0aGlzLmluaXRpYWxGb3JtRGF0YVN0b3JlZEluVGhlUERGW2Z1bGxGaWVsZE5hbWVdID0gaW5pdGlhbEZvcm1WYWx1ZUZyb21QREY7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJDb3VsZG4ndCByZWdpc3RlciBhbiBYRkEgZm9ybSBmaWVsZFwiLCBlbGVtZW50KTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGdldFZhbHVlT2ZBU2VsZWN0RmllbGQoc2VsZWN0RWxlbWVudDogSFRNTFNlbGVjdEVsZW1lbnQpOiBudWxsIHwgc3RyaW5nIHwgQXJyYXk8c3RyaW5nPiB7XG4gICAgY29uc3QgeyBvcHRpb25zLCBtdWx0aXBsZSB9ID0gc2VsZWN0RWxlbWVudDtcbiAgICBpZiAoIW11bHRpcGxlKSB7XG4gICAgICByZXR1cm4gb3B0aW9ucy5zZWxlY3RlZEluZGV4ID09PSAtMSA/IG51bGwgOiBvcHRpb25zW29wdGlvbnMuc2VsZWN0ZWRJbmRleF1bJ3ZhbHVlJ107XG4gICAgfVxuICAgIHJldHVybiBBcnJheS5wcm90b3R5cGUuZmlsdGVyLmNhbGwob3B0aW9ucywgKG9wdGlvbikgPT4gb3B0aW9uLnNlbGVjdGVkKS5tYXAoKG9wdGlvbikgPT4gb3B0aW9uWyd2YWx1ZSddKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0Rm9ybVZhbHVlRnJvbUFuZ3VsYXIoZWxlbWVudDogSFRNTEVsZW1lbnQgfCBzdHJpbmcpOiBPYmplY3Qge1xuICAgIGxldCBrZXk6IHN0cmluZztcbiAgICBpZiAoZWxlbWVudCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSB7XG4gICAgICBjb25zdCBmaWVsZE5hbWUgPSB0aGlzLmZpbmRYRkFOYW1lKGVsZW1lbnQpO1xuICAgICAgaWYgKGZpZWxkTmFtZSkge1xuICAgICAgICBpZiAodGhpcy5mb3JtRGF0YS5oYXNPd25Qcm9wZXJ0eShmaWVsZE5hbWUpKSB7XG4gICAgICAgICAga2V5ID0gZmllbGROYW1lO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGtleSA9IHRoaXMuZmluZEZ1bGxYRkFOYW1lKGVsZW1lbnQpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiQ291bGRuJ3QgZmluZCB0aGUgZmllbGQgbmFtZSBvciBYRkEgbmFtZSBvZiB0aGUgZm9ybSBmaWVsZFwiLCBlbGVtZW50KTtcbiAgICAgICAgcmV0dXJuIHsgdmFsdWU6IG51bGwgfTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAga2V5ID0gZWxlbWVudDtcbiAgICB9XG4gICAgcmV0dXJuIHsgdmFsdWU6IHRoaXMuZm9ybURhdGFba2V5XSB9O1xuICB9XG5cbiAgcHJpdmF0ZSBmaW5kWEZBTmFtZShlbGVtZW50OiBIVE1MRWxlbWVudCk6IHN0cmluZyB7XG4gICAgbGV0IHBhcmVudEVsZW1lbnQ6IEhUTUxFbGVtZW50IHwgbnVsbCB8IHVuZGVmaW5lZCA9IGVsZW1lbnQ7XG4gICAgd2hpbGUgKCFwYXJlbnRFbGVtZW50LmdldEF0dHJpYnV0ZSgneGZhbmFtZScpICYmIHBhcmVudEVsZW1lbnQucGFyZW50RWxlbWVudCkge1xuICAgICAgcGFyZW50RWxlbWVudCA9IHBhcmVudEVsZW1lbnQucGFyZW50RWxlbWVudDtcbiAgICB9XG4gICAgaWYgKGVsZW1lbnQgaW5zdGFuY2VvZiBIVE1MSW5wdXRFbGVtZW50ICYmIGVsZW1lbnQudHlwZSA9PT0gJ3JhZGlvJykge1xuICAgICAgZG8ge1xuICAgICAgICBwYXJlbnRFbGVtZW50ID0gcGFyZW50RWxlbWVudD8ucGFyZW50RWxlbWVudDtcbiAgICAgIH0gd2hpbGUgKCFwYXJlbnRFbGVtZW50Py5nZXRBdHRyaWJ1dGUoJ3hmYW5hbWUnKSAmJiBwYXJlbnRFbGVtZW50KTtcbiAgICB9XG4gICAgbGV0IGZpZWxkTmFtZSA9IHBhcmVudEVsZW1lbnQ/LmdldEF0dHJpYnV0ZSgneGZhbmFtZScpO1xuICAgIGlmICghZmllbGROYW1lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb3VsZG4ndCBmaW5kIHRoZSB4ZmFuYW1lIG9mIHRoZSBmaWVsZFwiKTtcbiAgICB9XG4gICAgcmV0dXJuIGZpZWxkTmFtZTtcbiAgfVxuXG4gIHByaXZhdGUgZmluZEZ1bGxYRkFOYW1lKGVsZW1lbnQ6IEhUTUxFbGVtZW50KTogc3RyaW5nIHtcbiAgICBsZXQgcGFyZW50RWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgbGV0IGZpZWxkTmFtZSA9ICcnO1xuICAgIHdoaWxlIChwYXJlbnRFbGVtZW50IGluc3RhbmNlb2YgSFRNTEVsZW1lbnQgJiYgcGFyZW50RWxlbWVudC5wYXJlbnRFbGVtZW50KSB7XG4gICAgICBjb25zdCB4ZmFOYW1lID0gcGFyZW50RWxlbWVudC5nZXRBdHRyaWJ1dGUoJ3hmYW5hbWUnKTtcbiAgICAgIGlmICh4ZmFOYW1lKSB7XG4gICAgICAgIGZpZWxkTmFtZSA9IHhmYU5hbWUgKyAnLicgKyBmaWVsZE5hbWU7XG4gICAgICB9XG4gICAgICBwYXJlbnRFbGVtZW50ID0gcGFyZW50RWxlbWVudC5wYXJlbnRFbGVtZW50O1xuICAgIH1cbiAgICBpZiAoIWZpZWxkTmFtZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ291bGRuJ3QgZmluZCB0aGUgeGZhbmFtZSBvZiB0aGUgZmllbGRcIik7XG4gICAgfVxuICAgIGZpZWxkTmFtZSA9IGZpZWxkTmFtZS5zdWJzdHJpbmcoMCwgZmllbGROYW1lLmxlbmd0aCAtIDEpO1xuICAgIGlmIChlbGVtZW50IGluc3RhbmNlb2YgSFRNTElucHV0RWxlbWVudCAmJiBlbGVtZW50LnR5cGUgPT09ICdyYWRpbycpIHtcbiAgICAgIC8vIGlnbm9yZSB0aGUgbGFzdCBwYXJ0IG9mIHRoZSB4ZmFOYW1lIGJlY2F1c2UgaXQncyBhY3R1YWxseSB0aGUgdmFsdWUgb2YgdGhlIGZpZWxkXG4gICAgICByZXR1cm4gZmllbGROYW1lLnN1YnN0cmluZygwLCBmaWVsZE5hbWUubGFzdEluZGV4T2YoJy4nKSk7XG4gICAgfVxuICAgIHJldHVybiBmaWVsZE5hbWU7XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZUFuZ3VsYXJGb3JtVmFsdWVDYWxsZWRCeVBkZmpzKFxuICAgIGtleTogc3RyaW5nIHwgSFRNTFNlbGVjdEVsZW1lbnQgfCBIVE1MSW5wdXRFbGVtZW50IHwgSFRNTFRleHRBcmVhRWxlbWVudCxcbiAgICB2YWx1ZTogeyB2YWx1ZT86IHN0cmluZzsgZm9ybWF0dGVkVmFsdWU/OiBzdHJpbmcgfSxcbiAgKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmZvcm1EYXRhKSB7XG4gICAgICB0aGlzLmZvcm1EYXRhID0ge307XG4gICAgfVxuXG4gICAgLy8gSWdub3JlIGZvcm1hdHRlZFZhbHVlLW9ubHkgdXBkYXRlcyB0byBwcmV2ZW50IGNsZWFyaW5nIEFuZ3VsYXIgZm9ybSBkYXRhXG4gICAgLy8gVGhlIGZvcm1hdHRlZFZhbHVlIGlzIGp1c3QgZm9yIGRpc3BsYXkgZm9ybWF0dGluZywgbm90IGFjdHVhbCB1c2VyIGlucHV0XG4gICAgaWYgKHZhbHVlLmZvcm1hdHRlZFZhbHVlICE9PSB1bmRlZmluZWQgJiYgdmFsdWUudmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2Yga2V5ID09PSAnc3RyaW5nJykge1xuICAgICAgY29uc3QgYWNyb0Zvcm1LZXkgPSB0aGlzLmZvcm1JZFRvRnVsbEZpZWxkTmFtZVtrZXldO1xuICAgICAgY29uc3QgZnVsbEtleSA9IGFjcm9Gb3JtS2V5ID8/IE9iamVjdC52YWx1ZXModGhpcy5mb3JtSWRUb0Z1bGxGaWVsZE5hbWUpLmZpbmQoKGspID0+IGsgPT09IGtleSB8fCBrLmVuZHNXaXRoKCcuJyArIGtleSkpO1xuICAgICAgaWYgKGZ1bGxLZXkpIHtcbiAgICAgICAgY29uc3QgZmllbGQgPSB0aGlzLmZvcm1JZFRvRmllbGRba2V5XTtcbiAgICAgICAgbGV0IGNoYW5nZSA9IHRoaXMuZG9VcGRhdGVBbmd1bGFyRm9ybVZhbHVlKGZpZWxkLCB2YWx1ZSwgZnVsbEtleSk7XG4gICAgICAgIGlmIChjaGFuZ2UpIHtcbiAgICAgICAgICB0aGlzLm5nWm9uZS5ydW4oKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5mb3JtRGF0YUNoYW5nZS5lbWl0KHRoaXMuZm9ybURhdGEpO1xuICAgICAgICAgICAgdGhpcy5jZHIuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiQ291bGRuJ3QgZmluZCB0aGUgZmllbGQgd2l0aCB0aGUgbmFtZSBcIiArIGtleSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGxldCBjaGFuZ2UgPSBmYWxzZTtcbiAgICAgIGNvbnN0IHNob3J0RmllbGROYW1lID0gdGhpcy5maW5kWEZBTmFtZShrZXkpO1xuICAgICAgaWYgKHRoaXMuZm9ybURhdGEuaGFzT3duUHJvcGVydHkoc2hvcnRGaWVsZE5hbWUpKSB7XG4gICAgICAgIGNoYW5nZSA9IHRoaXMuZG9VcGRhdGVBbmd1bGFyRm9ybVZhbHVlKGtleSwgdmFsdWUsIHNob3J0RmllbGROYW1lKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGZ1bGxGaWVsZE5hbWUgPSB0aGlzLmZpbmRGdWxsWEZBTmFtZShrZXkpO1xuICAgICAgaWYgKGZ1bGxGaWVsZE5hbWUgIT09IHNob3J0RmllbGROYW1lKSB7XG4gICAgICAgIGNoYW5nZSB8fD0gdGhpcy5kb1VwZGF0ZUFuZ3VsYXJGb3JtVmFsdWUoa2V5LCB2YWx1ZSwgZnVsbEZpZWxkTmFtZSk7XG4gICAgICB9XG4gICAgICBpZiAoY2hhbmdlKSB7XG4gICAgICAgIHRoaXMubmdab25lLnJ1bigoKSA9PiB7XG4gICAgICAgICAgdGhpcy5mb3JtRGF0YUNoYW5nZS5lbWl0KHRoaXMuZm9ybURhdGEpO1xuICAgICAgICAgIHRoaXMuY2RyLmRldGVjdENoYW5nZXMoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBkb1VwZGF0ZUFuZ3VsYXJGb3JtVmFsdWUoZmllbGQ6IEh0bWxGb3JtRWxlbWVudCwgdmFsdWU6IHsgdmFsdWU/OiBzdHJpbmc7IGZvcm1hdHRlZFZhbHVlPzogc3RyaW5nIH0sIGZ1bGxLZXk6IHN0cmluZykge1xuICAgIGxldCBjaGFuZ2UgPSBmYWxzZTtcbiAgICAvLyBVc2UgdGhlIGFjdHVhbCB1c2VyIGlucHV0IHZhbHVlLCBub3QgdGhlIGZvcm1hdHRlZCBkaXNwbGF5IHZhbHVlXG4gICAgY29uc3QgYWN0dWFsVmFsdWUgPSB2YWx1ZS52YWx1ZTtcbiAgICBpZiAoZmllbGQgaW5zdGFuY2VvZiBIVE1MSW5wdXRFbGVtZW50ICYmIGZpZWxkLnR5cGUgPT09ICdjaGVja2JveCcpIHtcbiAgICAgIGNvbnN0IGV4cG9ydFZhbHVlID0gZmllbGQuZ2V0QXR0cmlidXRlKCdleHBvcnR2YWx1ZScpO1xuICAgICAgaWYgKGV4cG9ydFZhbHVlKSB7XG4gICAgICAgIGlmIChhY3R1YWxWYWx1ZSkge1xuICAgICAgICAgIGlmICh0aGlzLmZvcm1EYXRhW2Z1bGxLZXldICE9PSBleHBvcnRWYWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5mb3JtRGF0YVtmdWxsS2V5XSA9IGV4cG9ydFZhbHVlO1xuICAgICAgICAgICAgY2hhbmdlID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaWYgKHRoaXMuZm9ybURhdGFbZnVsbEtleV0gIT09IGZhbHNlKSB7XG4gICAgICAgICAgICB0aGlzLmZvcm1EYXRhW2Z1bGxLZXldID0gZmFsc2U7XG4gICAgICAgICAgICBjaGFuZ2UgPSB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh0aGlzLmZvcm1EYXRhW2Z1bGxLZXldICE9PSBhY3R1YWxWYWx1ZSkge1xuICAgICAgICB0aGlzLmZvcm1EYXRhW2Z1bGxLZXldID0gYWN0dWFsVmFsdWUgPz8gJyc7XG4gICAgICAgIGNoYW5nZSA9IHRydWU7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChmaWVsZCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQgJiYgZmllbGQudHlwZSA9PT0gJ3JhZGlvJykge1xuICAgICAgY29uc3QgZXhwb3J0VmFsdWUgPSBmaWVsZC5nZXRBdHRyaWJ1dGUoJ2V4cG9ydHZhbHVlJykgPz8gZmllbGQuZ2V0QXR0cmlidXRlKCd4ZmFvbicpO1xuICAgICAgaWYgKGFjdHVhbFZhbHVlKSB7XG4gICAgICAgIGlmICh0aGlzLmZvcm1EYXRhW2Z1bGxLZXldICE9PSBleHBvcnRWYWx1ZSkge1xuICAgICAgICAgIHRoaXMuZm9ybURhdGFbZnVsbEtleV0gPSBleHBvcnRWYWx1ZTtcbiAgICAgICAgICBjaGFuZ2UgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICh0aGlzLmZvcm1EYXRhW2Z1bGxLZXldICE9PSBhY3R1YWxWYWx1ZSkge1xuICAgICAgdGhpcy5mb3JtRGF0YVtmdWxsS2V5XSA9IGFjdHVhbFZhbHVlID8/ICcnO1xuICAgICAgY2hhbmdlID0gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGNoYW5nZTtcbiAgfVxuXG4gIHB1YmxpYyB1cGRhdGVGb3JtRmllbGRzSW5QZGZDYWxsZWRCeU5nT25DaGFuZ2VzKHByZXZpb3VzRm9ybURhdGE6IE9iamVjdCkge1xuICAgIGlmICghdGhpcy5QREZWaWV3ZXJBcHBsaWNhdGlvbj8ucGRmRG9jdW1lbnQ/LmFubm90YXRpb25TdG9yYWdlKSB7XG4gICAgICAvLyBuZ09uQ2hhbmdlcyBjYWxscyB0aGlzIG1ldGhvZCB0b28gZWFybHkgLSBzbyBqdXN0IGlnbm9yZSBpdFxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGZvciAoY29uc3Qga2V5IGluIHRoaXMuZm9ybURhdGEpIHtcbiAgICAgIGlmICh0aGlzLmZvcm1EYXRhLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgICAgY29uc3QgbmV3VmFsdWUgPSB0aGlzLmZvcm1EYXRhW2tleV07XG4gICAgICAgIGlmIChuZXdWYWx1ZSAhPT0gcHJldmlvdXNGb3JtRGF0YVtrZXldKSB7XG4gICAgICAgICAgdGhpcy5zZXRGaWVsZFZhbHVlQW5kVXBkYXRlQW5ub3RhdGlvblN0b3JhZ2Uoa2V5LCBuZXdWYWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGtleSBpbiBwcmV2aW91c0Zvcm1EYXRhKSB7XG4gICAgICBpZiAocHJldmlvdXNGb3JtRGF0YS5oYXNPd25Qcm9wZXJ0eShrZXkpICYmIHByZXZpb3VzRm9ybURhdGFba2V5XSkge1xuICAgICAgICBsZXQgaGFzUHJldmlvdXNWYWx1ZSA9IHRoaXMuZm9ybURhdGEuaGFzT3duUHJvcGVydHkoa2V5KTtcbiAgICAgICAgaWYgKCFoYXNQcmV2aW91c1ZhbHVlKSB7XG4gICAgICAgICAgY29uc3QgZnVsbEtleSA9IE9iamVjdC5rZXlzKHRoaXMuZm9ybURhdGEpLmZpbmQoKGspID0+IGsgPT09IGtleSB8fCBrLmVuZHNXaXRoKCcuJyArIGtleSkpO1xuICAgICAgICAgIGlmIChmdWxsS2V5KSB7XG4gICAgICAgICAgICBoYXNQcmV2aW91c1ZhbHVlID0gdGhpcy5m