@crediblefinance/credible-ui
Version:
Credible's standard UI library
200 lines • 34.3 kB
JavaScript
import { Component, EventEmitter, HostListener, Input, Output } from '@angular/core';
import { getDocument, getWindow } from 'ssr-window';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
export class CfOtpComponent {
length = 6;
changed = new EventEmitter();
label = '';
showLabel = true;
prefillCode = '';
theme = 'dark';
numbers = [];
otp = [];
focus = [];
allowedKeys;
currentIndex = 0;
width;
window;
platform = 'web';
document = getDocument();
constructor() {
this.window = getWindow();
this.width = this.window.outerWidth;
if (this.width < 768)
this.platform = 'mobile';
const allowedKeys = [
'Backspace',
'Digit0',
'Digit1',
'Digit2',
'Digit3',
'Digit4',
'Digit5',
'Digit6',
'Digit7',
'Digit8',
'Digit9',
'KeyV',
'MetaLeft',
'MetaRight' // left command key in mac
];
for (let i = 65; i <= 90; i++)
allowedKeys.push(`Key${String.fromCharCode(i)}`);
this.allowedKeys = new Set(allowedKeys);
}
onResize(event) {
this.width = event.target.outerWidth;
console.log('width on resize', this.width);
if (this.width < 768)
this.platform = 'mobile';
}
getInputId(index) {
if (this.width < 768)
return `cf-otp-input-mobile-${index}`;
else
return `cf-otp-input-web-${index}`;
}
ngOnInit() {
this.numbers = Array.from({
length: this.length
}, (_, i) => i);
this.otp = Array(this.length).fill('');
this.changeInputFocus();
if (this.prefillCode)
this.prefillOtp(this.prefillCode);
}
prefillOtp(text, index = 0) {
// const text = event.clipboardData?.getData('Text') || '';
console.log('prefill', text);
// const characters = text.split('').filter(char => /^[a-zA-Z0-9]$/.test(char)).slice(0, this.length - index);
// const text = event.clipboardData?.getData('Text') || '';
const characters = text.split('').filter(char => /^[a-zA-Z0-9]$/.test(char)).slice(0, this.length - index);
// Update OTP array and the corresponding input fields
characters.forEach((char, i) => {
if (index + i < this.length) {
this.setOtpArray(index + i, char);
const input = this.document.getElementById(this.getInputId(index + i));
if (input)
input.value = char; // Directly set value
}
});
// Update currentIndex and focus
this.currentIndex = Math.min(index + characters.length, this.length - 1);
this.changeInputFocus();
// event.preventDefault();
}
handleKeyDown(event, index) {
const allowed = this.allowedKeys.has(event.code);
if (!allowed)
event.preventDefault();
return allowed;
}
handleKeyUp(event, index) {
const currentKey = event.key;
const isAlphanumeric = /^[a-zA-Z0-9]$/.test(currentKey);
if (isAlphanumeric) {
this.setOtpArray(index, currentKey);
if (index < this.length - 1) {
this.currentIndex = index + 1;
this.changeInputFocus();
}
}
else if (event.code === 'Backspace') {
if (this.otp[index] !== '') {
// Clear the current input value
this.setOtpArray(index, '');
}
else if (index > 0) {
// Move to the previous input field if the current field is empty
this.currentIndex = index - 1;
this.changeInputFocus();
this.setOtpArray(this.currentIndex, ''); // Clear the previous field
}
}
}
handlePaste(event, index) {
const text = event.clipboardData?.getData('Text') || '';
const characters = text.split('').filter(char => /^[a-zA-Z0-9]$/.test(char)).slice(0, this.length - index);
// Update OTP array and the corresponding input fields
characters.forEach((char, i) => {
if (index + i < this.length) {
this.setOtpArray(index + i, char);
const input = this.document.getElementById(this.getInputId(index + i));
if (input)
input.value = char; // Directly set value
}
});
// Update currentIndex and focus
this.currentIndex = Math.min(index + characters.length, this.length - 1);
this.changeInputFocus();
event.preventDefault();
}
changeInputFocus() {
console.log('changeInputFocus', this.currentIndex);
// Clear focus from all input fields
this.focus.fill(false);
// Ensure the currentIndex is within the valid range
if (this.currentIndex >= 0 && this.currentIndex < this.length) {
this.focus[this.currentIndex] = true;
// Manually focus on the input element
const id = this.getInputId(this.currentIndex);
console.log('id', id);
const inputElement = this.document.getElementById(id);
console.log('inputElement', inputElement);
if (inputElement) {
inputElement.focus();
// Set the cursor to the end of the input field if there's text
if (inputElement.value.length > 0) {
console.log('inputElement.value.length', inputElement.value.length);
inputElement.setSelectionRange(inputElement.value.length, inputElement.value.length);
}
}
}
}
// setOtpArray(index: number, value: string): void {
// console.log('index', index, 'value', value);
// this.otp[index] = value;
// const validOtp = this.otp.join('');
// console.log('validOtp', validOtp);
// this.changed.emit(validOtp);
// }
setOtpArray(index, value) {
console.log('setOtpArray index:', index, 'value:', value);
if (index < 0 || index >= this.length) {
console.error('Index out of bounds:', index);
return;
}
console.log('index:', index, 'value:', value);
// Update the OTP array
this.otp[index] = value || '';
// Emit the updated OTP
const validOtp = this.otp.map(char => char || '').join('');
console.log('validOtp:', validOtp);
this.changed.emit(validOtp);
// Optionally force Angular to detect changes
// this.changeDetectorRef.detectChanges();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: CfOtpComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.9", type: CfOtpComponent, selector: "cf-otp", inputs: { length: "length", label: "label", showLabel: "showLabel", prefillCode: "prefillCode", theme: "theme" }, outputs: { changed: "changed" }, host: { listeners: { "window:resize": "onResize($event)" } }, ngImport: i0, template: "<div class=\"cf-otp\">\n <div class=\"container-fluid\">\n <div class=\"row\" *ngIf=\"showLabel\">\n <div class=\"col-md-12\">\n <label class=\"heading\" [ngClass]=\"theme\">{{ label }}</label>\n </div>\n </div>\n <div class=\"inputs\">\n <div *ngFor=\"let item of numbers; let i = index\" class=\"input-holder\">\n <input type=\"text\" [autofocus]=\"focus[i]\" (keydown)=\"handleKeyDown($event, i)\"\n [ngClass]=\"{'autofocus': focus[i], dark: theme === 'dark', light: theme === 'light'}\"\n (keyup)=\"handleKeyUp($event, i)\" (paste)=\"handlePaste($event, i)\" [id]=\"'cf-otp-input-web-' + i\"\n autocomplete=\"off\" maxlength=\"1\" class=\"web\" *ngIf=\"platform === 'web'\" />\n\n <input type=\"text\" [autofocus]=\"focus[i]\" (keydown)=\"handleKeyDown($event, i)\"\n [ngClass]=\"{'autofocus': focus[i], dark: theme === 'dark', light: theme === 'light'}\"\n (keyup)=\"handleKeyUp($event, i)\" (paste)=\"handlePaste($event, i)\" [id]=\"'cf-otp-input-mobile-' + i\"\n autocomplete=\"off\" maxlength=\"1\" class=\"mobile\" [value]=\"otp[i]\" *ngIf=\"platform === 'mobile'\" />\n </div>\n </div>\n </div>\n</div>", styles: [".cf-otp{padding-left:1rem;padding-right:1rem}.cf-otp .container-fluid{padding-left:0;padding-right:0}.cf-otp .heading{font-weight:500;font-size:.8rem;padding-left:.5rem;display:flex}.cf-otp .heading.dark{color:gray}.cf-otp .heading.light{color:#000}.cf-otp .inputs{display:flex}.cf-otp .inputs .heading{font-weight:700}.cf-otp .inputs .input-holder{padding-left:.5rem;padding-right:.5rem}.cf-otp .inputs .input-holder input{padding:.4rem 0rem;justify-content:center;width:100%;line-height:2rem;text-align:center;border-radius:2px;font-size:1rem}.cf-otp .inputs .input-holder input.dark{color:#d3d3d3;background-color:#1d1e22;border:.5px solid grey}.cf-otp .inputs .input-holder input.light{color:#000;background-color:transparent;border:.1px solid lightgrey}input::-webkit-inner-spin-button,input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}input[type=number]{appearance:textfield}@media only screen and (max-width: 768px){.heading{font-size:1rem!important}}.autofocus.dark{border:2px solid lightgrey!important}.autofocus.light{border:2px solid grey!important}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.9", ngImport: i0, type: CfOtpComponent, decorators: [{
type: Component,
args: [{ selector: 'cf-otp', template: "<div class=\"cf-otp\">\n <div class=\"container-fluid\">\n <div class=\"row\" *ngIf=\"showLabel\">\n <div class=\"col-md-12\">\n <label class=\"heading\" [ngClass]=\"theme\">{{ label }}</label>\n </div>\n </div>\n <div class=\"inputs\">\n <div *ngFor=\"let item of numbers; let i = index\" class=\"input-holder\">\n <input type=\"text\" [autofocus]=\"focus[i]\" (keydown)=\"handleKeyDown($event, i)\"\n [ngClass]=\"{'autofocus': focus[i], dark: theme === 'dark', light: theme === 'light'}\"\n (keyup)=\"handleKeyUp($event, i)\" (paste)=\"handlePaste($event, i)\" [id]=\"'cf-otp-input-web-' + i\"\n autocomplete=\"off\" maxlength=\"1\" class=\"web\" *ngIf=\"platform === 'web'\" />\n\n <input type=\"text\" [autofocus]=\"focus[i]\" (keydown)=\"handleKeyDown($event, i)\"\n [ngClass]=\"{'autofocus': focus[i], dark: theme === 'dark', light: theme === 'light'}\"\n (keyup)=\"handleKeyUp($event, i)\" (paste)=\"handlePaste($event, i)\" [id]=\"'cf-otp-input-mobile-' + i\"\n autocomplete=\"off\" maxlength=\"1\" class=\"mobile\" [value]=\"otp[i]\" *ngIf=\"platform === 'mobile'\" />\n </div>\n </div>\n </div>\n</div>", styles: [".cf-otp{padding-left:1rem;padding-right:1rem}.cf-otp .container-fluid{padding-left:0;padding-right:0}.cf-otp .heading{font-weight:500;font-size:.8rem;padding-left:.5rem;display:flex}.cf-otp .heading.dark{color:gray}.cf-otp .heading.light{color:#000}.cf-otp .inputs{display:flex}.cf-otp .inputs .heading{font-weight:700}.cf-otp .inputs .input-holder{padding-left:.5rem;padding-right:.5rem}.cf-otp .inputs .input-holder input{padding:.4rem 0rem;justify-content:center;width:100%;line-height:2rem;text-align:center;border-radius:2px;font-size:1rem}.cf-otp .inputs .input-holder input.dark{color:#d3d3d3;background-color:#1d1e22;border:.5px solid grey}.cf-otp .inputs .input-holder input.light{color:#000;background-color:transparent;border:.1px solid lightgrey}input::-webkit-inner-spin-button,input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}input[type=number]{appearance:textfield}@media only screen and (max-width: 768px){.heading{font-size:1rem!important}}.autofocus.dark{border:2px solid lightgrey!important}.autofocus.light{border:2px solid grey!important}\n"] }]
}], ctorParameters: () => [], propDecorators: { length: [{
type: Input
}], changed: [{
type: Output
}], label: [{
type: Input
}], showLabel: [{
type: Input
}], prefillCode: [{
type: Input
}], theme: [{
type: Input
}], onResize: [{
type: HostListener,
args: ['window:resize', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2Ytb3RwLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NyZWRpYmxlLXVpL3NyYy9saWIvY2Ytb3RwL2NmLW90cC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jcmVkaWJsZS11aS9zcmMvbGliL2NmLW90cC9jZi1vdHAuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNILFNBQVMsRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBVSxNQUFNLEVBQy9ELE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLE1BQU0sWUFBWSxDQUFDOzs7QUFPcEQsTUFBTSxPQUFPLGNBQWM7SUFDZCxNQUFNLEdBQVcsQ0FBQyxDQUFDO0lBQ2xCLE9BQU8sR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO0lBQ3RDLEtBQUssR0FBVyxFQUFFLENBQUM7SUFDbkIsU0FBUyxHQUFZLElBQUksQ0FBQztJQUMxQixXQUFXLEdBQVcsRUFBRSxDQUFDO0lBQ3pCLEtBQUssR0FBVyxNQUFNLENBQUM7SUFFaEMsT0FBTyxHQUFhLEVBQUUsQ0FBQztJQUN2QixHQUFHLEdBQWEsRUFBRSxDQUFDO0lBQ25CLEtBQUssR0FBYyxFQUFFLENBQUM7SUFDdEIsV0FBVyxDQUFjO0lBQ3pCLFlBQVksR0FBVyxDQUFDLENBQUM7SUFDekIsS0FBSyxDQUFNO0lBQ1gsTUFBTSxDQUFTO0lBQ2YsUUFBUSxHQUFXLEtBQUssQ0FBQztJQUN6QixRQUFRLEdBQUcsV0FBVyxFQUFFLENBQUM7SUFFekI7UUFDSSxJQUFJLENBQUMsTUFBTSxHQUFHLFNBQVMsRUFBRSxDQUFDO1FBRTFCLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7UUFFcEMsSUFBSSxJQUFJLENBQUMsS0FBSyxHQUFHLEdBQUc7WUFDaEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFFN0IsTUFBTSxXQUFXLEdBQUc7WUFDaEIsV0FBVztZQUNYLFFBQVE7WUFDUixRQUFRO1lBQ1IsUUFBUTtZQUNSLFFBQVE7WUFDUixRQUFRO1lBQ1IsUUFBUTtZQUNSLFFBQVE7WUFDUixRQUFRO1lBQ1IsUUFBUTtZQUNSLFFBQVE7WUFDUixNQUFNO1lBQ04sVUFBVTtZQUNWLFdBQVcsQ0FBQywwQkFBMEI7U0FDekMsQ0FBQztRQUVGLEtBQUssSUFBSSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxFQUFFO1lBQ3pCLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUVyRCxJQUFJLENBQUMsV0FBVyxHQUFHLElBQUksR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFHRCxRQUFRLENBQUMsS0FBVTtRQUNmLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7UUFFckMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFM0MsSUFBSSxJQUFJLENBQUMsS0FBSyxHQUFHLEdBQUc7WUFDaEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7SUFDakMsQ0FBQztJQUVELFVBQVUsQ0FBQyxLQUFhO1FBQ3BCLElBQUksSUFBSSxDQUFDLEtBQUssR0FBRyxHQUFHO1lBQ2hCLE9BQU8sdUJBQXVCLEtBQUssRUFBRSxDQUFDOztZQUV0QyxPQUFPLG9CQUFvQixLQUFLLEVBQUUsQ0FBQztJQUMzQyxDQUFDO0lBRUQsUUFBUTtRQUNKLElBQUksQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztZQUN0QixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07U0FDdEIsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2hCLElBQUksQ0FBQyxHQUFHLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFFeEIsSUFBSSxJQUFJLENBQUMsV0FBVztZQUNoQixJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBQ0QsVUFBVSxDQUFDLElBQVksRUFBRSxLQUFLLEdBQUcsQ0FBQztRQUM5QiwyREFBMkQ7UUFDM0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDN0IsOEdBQThHO1FBRTlHLDJEQUEyRDtRQUMzRCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUM7UUFFM0csc0RBQXNEO1FBQ3RELFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDM0IsSUFBSSxLQUFLLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUU7Z0JBQ3pCLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztnQkFFbEMsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQXFCLENBQUM7Z0JBRTNGLElBQUksS0FBSztvQkFDTCxLQUFLLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxDQUFDLHFCQUFxQjthQUNoRDtRQUNMLENBQUMsQ0FBQyxDQUFDO1FBRUgsZ0NBQWdDO1FBQ2hDLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsVUFBVSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQ3pFLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBRXhCLDBCQUEwQjtJQUM5QixDQUFDO0lBRUQsYUFBYSxDQUFDLEtBQW9CLEVBQUUsS0FBYTtRQUM3QyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFakQsSUFBSSxDQUFDLE9BQU87WUFDUixLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7UUFFM0IsT0FBTyxPQUFPLENBQUM7SUFDbkIsQ0FBQztJQUVELFdBQVcsQ0FBQyxLQUFvQixFQUFFLEtBQWE7UUFDM0MsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQztRQUM3QixNQUFNLGNBQWMsR0FBRyxlQUFlLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBRXhELElBQUksY0FBYyxFQUFFO1lBQ2hCLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBRXBDLElBQUksS0FBSyxHQUFHLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO2dCQUN6QixJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssR0FBRyxDQUFDLENBQUM7Z0JBQzlCLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO2FBQzNCO1NBQ0o7YUFDSSxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssV0FBVyxFQUFFO1lBQ2pDLElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUU7Z0JBQ3hCLGdDQUFnQztnQkFDaEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7YUFDL0I7aUJBQ0ksSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFO2dCQUNoQixpRUFBaUU7Z0JBQ2pFLElBQUksQ0FBQyxZQUFZLEdBQUcsS0FBSyxHQUFHLENBQUMsQ0FBQztnQkFDOUIsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7Z0JBQ3hCLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLDJCQUEyQjthQUN2RTtTQUNKO0lBQ0wsQ0FBQztJQUVELFdBQVcsQ0FBQyxLQUFxQixFQUFFLEtBQWE7UUFDNUMsTUFBTSxJQUFJLEdBQUcsS0FBSyxDQUFDLGFBQWEsRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3hELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQztRQUUzRyxzREFBc0Q7UUFDdEQsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUMzQixJQUFJLEtBQUssR0FBRyxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRTtnQkFDekIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO2dCQUVsQyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBcUIsQ0FBQztnQkFFM0YsSUFBSSxLQUFLO29CQUNMLEtBQUssQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLENBQUMscUJBQXFCO2FBQ2hEO1FBQ0wsQ0FBQyxDQUFDLENBQUM7UUFFSCxnQ0FBZ0M7UUFDaEMsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssR0FBRyxVQUFVLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7UUFDekUsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7UUFFeEIsS0FBSyxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRCxnQkFBZ0I7UUFDWixPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUVuRCxvQ0FBb0M7UUFDcEMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFdkIsb0RBQW9EO1FBQ3BELElBQUksSUFBSSxDQUFDLFlBQVksSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQzNELElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLElBQUksQ0FBQztZQUVyQyxzQ0FBc0M7WUFDdEMsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7WUFFOUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFFdEIsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFxQixDQUFDO1lBRTFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxFQUFFLFlBQVksQ0FBQyxDQUFDO1lBRTFDLElBQUksWUFBWSxFQUFFO2dCQUNkLFlBQVksQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFFckIsK0RBQStEO2dCQUMvRCxJQUFJLFlBQVksQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtvQkFDL0IsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsRUFBRSxZQUFZLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO29CQUVwRSxZQUFZLENBQUMsaUJBQWlCLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsWUFBWSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztpQkFDeEY7YUFDSjtTQUNKO0lBQ0wsQ0FBQztJQUVELG9EQUFvRDtJQUNwRCxtREFBbUQ7SUFFbkQsK0JBQStCO0lBRS9CLDBDQUEwQztJQUUxQyx5Q0FBeUM7SUFFekMsbUNBQW1DO0lBQ25DLElBQUk7SUFFSixXQUFXLENBQUMsS0FBYSxFQUFFLEtBQXlCO1FBQ2hELE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUUxRCxJQUFJLEtBQUssR0FBRyxDQUFDLElBQUksS0FBSyxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUU7WUFDbkMsT0FBTyxDQUFDLEtBQUssQ0FBQyxzQkFBc0IsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUU3QyxPQUFPO1NBQ1Y7UUFFRCxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRTlDLHVCQUF1QjtRQUN2QixJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLEtBQUssSUFBSSxFQUFFLENBQUM7UUFFOUIsdUJBQXVCO1FBQ3ZCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUUzRCxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUNuQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUU1Qiw2Q0FBNkM7UUFDN0MsMENBQTBDO0lBQzlDLENBQUM7dUdBbk9RLGNBQWM7MkZBQWQsY0FBYywrUENWM0IsdTBDQXFCTTs7MkZEWE8sY0FBYztrQkFMMUIsU0FBUzsrQkFDSSxRQUFRO3dEQUtULE1BQU07c0JBQWQsS0FBSztnQkFDSSxPQUFPO3NCQUFoQixNQUFNO2dCQUNFLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csS0FBSztzQkFBYixLQUFLO2dCQTRDTixRQUFRO3NCQURQLFlBQVk7dUJBQUMsZUFBZSxFQUFFLENBQUUsUUFBUSxDQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgICBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSG9zdExpc3RlbmVyLCBJbnB1dCwgT25Jbml0LCBPdXRwdXRcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBnZXREb2N1bWVudCwgZ2V0V2luZG93IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnY2Ytb3RwJyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vY2Ytb3RwLmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsgJy4vY2Ytb3RwLmNvbXBvbmVudC5zY3NzJyBdXG59KVxuZXhwb3J0IGNsYXNzIENmT3RwQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgICBASW5wdXQoKSBsZW5ndGg6IG51bWJlciA9IDY7XG4gICAgQE91dHB1dCgpIGNoYW5nZWQgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcbiAgICBASW5wdXQoKSBsYWJlbDogc3RyaW5nID0gJyc7XG4gICAgQElucHV0KCkgc2hvd0xhYmVsOiBib29sZWFuID0gdHJ1ZTtcbiAgICBASW5wdXQoKSBwcmVmaWxsQ29kZTogc3RyaW5nID0gJyc7XG4gICAgQElucHV0KCkgdGhlbWU6IHN0cmluZyA9ICdkYXJrJztcblxuICAgIG51bWJlcnM6IG51bWJlcltdID0gW107XG4gICAgb3RwOiBzdHJpbmdbXSA9IFtdO1xuICAgIGZvY3VzOiBib29sZWFuW10gPSBbXTtcbiAgICBhbGxvd2VkS2V5czogU2V0PHN0cmluZz47XG4gICAgY3VycmVudEluZGV4OiBudW1iZXIgPSAwO1xuICAgIHdpZHRoOiBhbnk7XG4gICAgd2luZG93OiBXaW5kb3c7XG4gICAgcGxhdGZvcm06IHN0cmluZyA9ICd3ZWInO1xuICAgIGRvY3VtZW50ID0gZ2V0RG9jdW1lbnQoKTtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLndpbmRvdyA9IGdldFdpbmRvdygpO1xuXG4gICAgICAgIHRoaXMud2lkdGggPSB0aGlzLndpbmRvdy5vdXRlcldpZHRoO1xuXG4gICAgICAgIGlmICh0aGlzLndpZHRoIDwgNzY4KVxuICAgICAgICAgICAgdGhpcy5wbGF0Zm9ybSA9ICdtb2JpbGUnO1xuICAgICAgICBcbiAgICAgICAgY29uc3QgYWxsb3dlZEtleXMgPSBbXG4gICAgICAgICAgICAnQmFja3NwYWNlJywgLy8gYmFja3NwYWNlXG4gICAgICAgICAgICAnRGlnaXQwJywgLy8gemVyb1xuICAgICAgICAgICAgJ0RpZ2l0MScsIC8vIG9uZVxuICAgICAgICAgICAgJ0RpZ2l0MicsIC8vIHR3b1xuICAgICAgICAgICAgJ0RpZ2l0MycsIC8vIHRocmVlXG4gICAgICAgICAgICAnRGlnaXQ0JywgLy8gZm91clxuICAgICAgICAgICAgJ0RpZ2l0NScsIC8vIGZpdmVcbiAgICAgICAgICAgICdEaWdpdDYnLCAvLyBzaXhcbiAgICAgICAgICAgICdEaWdpdDcnLCAvLyBzZXZlblxuICAgICAgICAgICAgJ0RpZ2l0OCcsIC8vIGVpZ2h0XG4gICAgICAgICAgICAnRGlnaXQ5JywgLy8gbmluZVxuICAgICAgICAgICAgJ0tleVYnLCAvLyBmb3IgY29weSBwYXN0ZVxuICAgICAgICAgICAgJ01ldGFMZWZ0JywgLy8gbGVmdCBjb21tYW5kIGtleSBpbiBtYWNcbiAgICAgICAgICAgICdNZXRhUmlnaHQnIC8vIGxlZnQgY29tbWFuZCBrZXkgaW4gbWFjXG4gICAgICAgIF07XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDY1OyBpIDw9IDkwOyBpKyspXG4gICAgICAgICAgICBhbGxvd2VkS2V5cy5wdXNoKGBLZXkke1N0cmluZy5mcm9tQ2hhckNvZGUoaSl9YCk7XG5cbiAgICAgICAgdGhpcy5hbGxvd2VkS2V5cyA9IG5ldyBTZXQoYWxsb3dlZEtleXMpO1xuICAgIH1cblxuICAgIEBIb3N0TGlzdGVuZXIoJ3dpbmRvdzpyZXNpemUnLCBbICckZXZlbnQnIF0pXG4gICAgb25SZXNpemUoZXZlbnQ6IGFueSkge1xuICAgICAgICB0aGlzLndpZHRoID0gZXZlbnQudGFyZ2V0Lm91dGVyV2lkdGg7XG5cbiAgICAgICAgY29uc29sZS5sb2coJ3dpZHRoIG9uIHJlc2l6ZScsIHRoaXMud2lkdGgpO1xuXG4gICAgICAgIGlmICh0aGlzLndpZHRoIDwgNzY4KVxuICAgICAgICAgICAgdGhpcy5wbGF0Zm9ybSA9ICdtb2JpbGUnO1xuICAgIH1cblxuICAgIGdldElucHV0SWQoaW5kZXg6IG51bWJlcik6IHN0cmluZyB7XG4gICAgICAgIGlmICh0aGlzLndpZHRoIDwgNzY4KVxuICAgICAgICAgICAgcmV0dXJuIGBjZi1vdHAtaW5wdXQtbW9iaWxlLSR7aW5kZXh9YDtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgcmV0dXJuIGBjZi1vdHAtaW5wdXQtd2ViLSR7aW5kZXh9YDtcbiAgICB9XG5cbiAgICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5udW1iZXJzID0gQXJyYXkuZnJvbSh7XG4gICAgICAgICAgICBsZW5ndGg6IHRoaXMubGVuZ3RoXG4gICAgICAgIH0sIChfLCBpKSA9PiBpKTtcbiAgICAgICAgdGhpcy5vdHAgPSBBcnJheSh0aGlzLmxlbmd0aCkuZmlsbCgnJyk7XG4gICAgICAgIHRoaXMuY2hhbmdlSW5wdXRGb2N1cygpO1xuXG4gICAgICAgIGlmICh0aGlzLnByZWZpbGxDb2RlKVxuICAgICAgICAgICAgdGhpcy5wcmVmaWxsT3RwKHRoaXMucHJlZmlsbENvZGUpO1xuICAgIH1cbiAgICBwcmVmaWxsT3RwKHRleHQ6IHN0cmluZywgaW5kZXggPSAwKTogdm9pZCB7XG4gICAgICAgIC8vIGNvbnN0IHRleHQgPSBldmVudC5jbGlwYm9hcmREYXRhPy5nZXREYXRhKCdUZXh0JykgfHwgJyc7XG4gICAgICAgIGNvbnNvbGUubG9nKCdwcmVmaWxsJywgdGV4dCk7XG4gICAgICAgIC8vIGNvbnN0IGNoYXJhY3RlcnMgPSB0ZXh0LnNwbGl0KCcnKS5maWx0ZXIoY2hhciA9PiAvXlthLXpBLVowLTldJC8udGVzdChjaGFyKSkuc2xpY2UoMCwgdGhpcy5sZW5ndGggLSBpbmRleCk7XG5cbiAgICAgICAgLy8gY29uc3QgdGV4dCA9IGV2ZW50LmNsaXBib2FyZERhdGE/LmdldERhdGEoJ1RleHQnKSB8fCAnJztcbiAgICAgICAgY29uc3QgY2hhcmFjdGVycyA9IHRleHQuc3BsaXQoJycpLmZpbHRlcihjaGFyID0+IC9eW2EtekEtWjAtOV0kLy50ZXN0KGNoYXIpKS5zbGljZSgwLCB0aGlzLmxlbmd0aCAtIGluZGV4KTtcblxuICAgICAgICAvLyBVcGRhdGUgT1RQIGFycmF5IGFuZCB0aGUgY29ycmVzcG9uZGluZyBpbnB1dCBmaWVsZHNcbiAgICAgICAgY2hhcmFjdGVycy5mb3JFYWNoKChjaGFyLCBpKSA9PiB7XG4gICAgICAgICAgICBpZiAoaW5kZXggKyBpIDwgdGhpcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldE90cEFycmF5KGluZGV4ICsgaSwgY2hhcik7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBpbnB1dCA9IHRoaXMuZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5nZXRJbnB1dElkKGluZGV4ICsgaSkpIGFzIEhUTUxJbnB1dEVsZW1lbnQ7XG5cbiAgICAgICAgICAgICAgICBpZiAoaW5wdXQpXG4gICAgICAgICAgICAgICAgICAgIGlucHV0LnZhbHVlID0gY2hhcjsgLy8gRGlyZWN0bHkgc2V0IHZhbHVlXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFVwZGF0ZSBjdXJyZW50SW5kZXggYW5kIGZvY3VzXG4gICAgICAgIHRoaXMuY3VycmVudEluZGV4ID0gTWF0aC5taW4oaW5kZXggKyBjaGFyYWN0ZXJzLmxlbmd0aCwgdGhpcy5sZW5ndGggLSAxKTtcbiAgICAgICAgdGhpcy5jaGFuZ2VJbnB1dEZvY3VzKCk7XG5cbiAgICAgICAgLy8gZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICBoYW5kbGVLZXlEb3duKGV2ZW50OiBLZXlib2FyZEV2ZW50LCBpbmRleDogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IGFsbG93ZWQgPSB0aGlzLmFsbG93ZWRLZXlzLmhhcyhldmVudC5jb2RlKTtcblxuICAgICAgICBpZiAoIWFsbG93ZWQpXG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICAgIHJldHVybiBhbGxvd2VkO1xuICAgIH1cblxuICAgIGhhbmRsZUtleVVwKGV2ZW50OiBLZXlib2FyZEV2ZW50LCBpbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRLZXkgPSBldmVudC5rZXk7XG4gICAgICAgIGNvbnN0IGlzQWxwaGFudW1lcmljID0gL15bYS16QS1aMC05XSQvLnRlc3QoY3VycmVudEtleSk7XG5cbiAgICAgICAgaWYgKGlzQWxwaGFudW1lcmljKSB7XG4gICAgICAgICAgICB0aGlzLnNldE90cEFycmF5KGluZGV4LCBjdXJyZW50S2V5KTtcblxuICAgICAgICAgICAgaWYgKGluZGV4IDwgdGhpcy5sZW5ndGggLSAxKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50SW5kZXggPSBpbmRleCArIDE7XG4gICAgICAgICAgICAgICAgdGhpcy5jaGFuZ2VJbnB1dEZvY3VzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZXZlbnQuY29kZSA9PT0gJ0JhY2tzcGFjZScpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLm90cFtpbmRleF0gIT09ICcnKSB7XG4gICAgICAgICAgICAgICAgLy8gQ2xlYXIgdGhlIGN1cnJlbnQgaW5wdXQgdmFsdWVcbiAgICAgICAgICAgICAgICB0aGlzLnNldE90cEFycmF5KGluZGV4LCAnJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChpbmRleCA+IDApIHtcbiAgICAgICAgICAgICAgICAvLyBNb3ZlIHRvIHRoZSBwcmV2aW91cyBpbnB1dCBmaWVsZCBpZiB0aGUgY3VycmVudCBmaWVsZCBpcyBlbXB0eVxuICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudEluZGV4ID0gaW5kZXggLSAxO1xuICAgICAgICAgICAgICAgIHRoaXMuY2hhbmdlSW5wdXRGb2N1cygpO1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0T3RwQXJyYXkodGhpcy5jdXJyZW50SW5kZXgsICcnKTsgLy8gQ2xlYXIgdGhlIHByZXZpb3VzIGZpZWxkXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBoYW5kbGVQYXN0ZShldmVudDogQ2xpcGJvYXJkRXZlbnQsIGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgdGV4dCA9IGV2ZW50LmNsaXBib2FyZERhdGE/LmdldERhdGEoJ1RleHQnKSB8fCAnJztcbiAgICAgICAgY29uc3QgY2hhcmFjdGVycyA9IHRleHQuc3BsaXQoJycpLmZpbHRlcihjaGFyID0+IC9eW2EtekEtWjAtOV0kLy50ZXN0KGNoYXIpKS5zbGljZSgwLCB0aGlzLmxlbmd0aCAtIGluZGV4KTtcblxuICAgICAgICAvLyBVcGRhdGUgT1RQIGFycmF5IGFuZCB0aGUgY29ycmVzcG9uZGluZyBpbnB1dCBmaWVsZHNcbiAgICAgICAgY2hhcmFjdGVycy5mb3JFYWNoKChjaGFyLCBpKSA9PiB7XG4gICAgICAgICAgICBpZiAoaW5kZXggKyBpIDwgdGhpcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldE90cEFycmF5KGluZGV4ICsgaSwgY2hhcik7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBpbnB1dCA9IHRoaXMuZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5nZXRJbnB1dElkKGluZGV4ICsgaSkpIGFzIEhUTUxJbnB1dEVsZW1lbnQ7XG5cbiAgICAgICAgICAgICAgICBpZiAoaW5wdXQpXG4gICAgICAgICAgICAgICAgICAgIGlucHV0LnZhbHVlID0gY2hhcjsgLy8gRGlyZWN0bHkgc2V0IHZhbHVlXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFVwZGF0ZSBjdXJyZW50SW5kZXggYW5kIGZvY3VzXG4gICAgICAgIHRoaXMuY3VycmVudEluZGV4ID0gTWF0aC5taW4oaW5kZXggKyBjaGFyYWN0ZXJzLmxlbmd0aCwgdGhpcy5sZW5ndGggLSAxKTtcbiAgICAgICAgdGhpcy5jaGFuZ2VJbnB1dEZvY3VzKCk7XG5cbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICBjaGFuZ2VJbnB1dEZvY3VzKCk6IHZvaWQge1xuICAgICAgICBjb25zb2xlLmxvZygnY2hhbmdlSW5wdXRGb2N1cycsIHRoaXMuY3VycmVudEluZGV4KTtcblxuICAgICAgICAvLyBDbGVhciBmb2N1cyBmcm9tIGFsbCBpbnB1dCBmaWVsZHNcbiAgICAgICAgdGhpcy5mb2N1cy5maWxsKGZhbHNlKTtcblxuICAgICAgICAvLyBFbnN1cmUgdGhlIGN1cnJlbnRJbmRleCBpcyB3aXRoaW4gdGhlIHZhbGlkIHJhbmdlXG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRJbmRleCA+PSAwICYmIHRoaXMuY3VycmVudEluZGV4IDwgdGhpcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRoaXMuZm9jdXNbdGhpcy5jdXJyZW50SW5kZXhdID0gdHJ1ZTtcblxuICAgICAgICAgICAgLy8gTWFudWFsbHkgZm9jdXMgb24gdGhlIGlucHV0IGVsZW1lbnRcbiAgICAgICAgICAgIGNvbnN0IGlkID0gdGhpcy5nZXRJbnB1dElkKHRoaXMuY3VycmVudEluZGV4KTtcblxuICAgICAgICAgICAgY29uc29sZS5sb2coJ2lkJywgaWQpO1xuXG4gICAgICAgICAgICBjb25zdCBpbnB1dEVsZW1lbnQgPSB0aGlzLmRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlkKSBhcyBIVE1MSW5wdXRFbGVtZW50O1xuXG4gICAgICAgICAgICBjb25zb2xlLmxvZygnaW5wdXRFbGVtZW50JywgaW5wdXRFbGVtZW50KTtcblxuICAgICAgICAgICAgaWYgKGlucHV0RWxlbWVudCkge1xuICAgICAgICAgICAgICAgIGlucHV0RWxlbWVudC5mb2N1cygpO1xuXG4gICAgICAgICAgICAgICAgLy8gU2V0IHRoZSBjdXJzb3IgdG8gdGhlIGVuZCBvZiB0aGUgaW5wdXQgZmllbGQgaWYgdGhlcmUncyB0ZXh0XG4gICAgICAgICAgICAgICAgaWYgKGlucHV0RWxlbWVudC52YWx1ZS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdpbnB1dEVsZW1lbnQudmFsdWUubGVuZ3RoJywgaW5wdXRFbGVtZW50LnZhbHVlLmxlbmd0aCk7XG5cbiAgICAgICAgICAgICAgICAgICAgaW5wdXRFbGVtZW50LnNldFNlbGVjdGlvblJhbmdlKGlucHV0RWxlbWVudC52YWx1ZS5sZW5ndGgsIGlucHV0RWxlbWVudC52YWx1ZS5sZW5ndGgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIHNldE90cEFycmF5KGluZGV4OiBudW1iZXIsIHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAvLyAgICAgY29uc29sZS5sb2coJ2luZGV4JywgaW5kZXgsICd2YWx1ZScsIHZhbHVlKTtcblxuICAgIC8vICAgICB0aGlzLm90cFtpbmRleF0gPSB2YWx1ZTtcblxuICAgIC8vICAgICBjb25zdCB2YWxpZE90cCA9IHRoaXMub3RwLmpvaW4oJycpO1xuXG4gICAgLy8gICAgIGNvbnNvbGUubG9nKCd2YWxpZE90cCcsIHZhbGlkT3RwKTtcblxuICAgIC8vICAgICB0aGlzLmNoYW5nZWQuZW1pdCh2YWxpZE90cCk7XG4gICAgLy8gfVxuXG4gICAgc2V0T3RwQXJyYXkoaW5kZXg6IG51bWJlciwgdmFsdWU6IHN0cmluZyB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgICAgICBjb25zb2xlLmxvZygnc2V0T3RwQXJyYXkgaW5kZXg6JywgaW5kZXgsICd2YWx1ZTonLCB2YWx1ZSk7XG5cbiAgICAgICAgaWYgKGluZGV4IDwgMCB8fCBpbmRleCA+PSB0aGlzLmxlbmd0aCkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignSW5kZXggb3V0IG9mIGJvdW5kczonLCBpbmRleCk7XG5cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnNvbGUubG9nKCdpbmRleDonLCBpbmRleCwgJ3ZhbHVlOicsIHZhbHVlKTtcblxuICAgICAgICAvLyBVcGRhdGUgdGhlIE9UUCBhcnJheVxuICAgICAgICB0aGlzLm90cFtpbmRleF0gPSB2YWx1ZSB8fCAnJztcblxuICAgICAgICAvLyBFbWl0IHRoZSB1cGRhdGVkIE9UUFxuICAgICAgICBjb25zdCB2YWxpZE90cCA9IHRoaXMub3RwLm1hcChjaGFyID0+IGNoYXIgfHwgJycpLmpvaW4oJycpO1xuXG4gICAgICAgIGNvbnNvbGUubG9nKCd2YWxpZE90cDonLCB2YWxpZE90cCk7XG4gICAgICAgIHRoaXMuY2hhbmdlZC5lbWl0KHZhbGlkT3RwKTtcblxuICAgICAgICAvLyBPcHRpb25hbGx5IGZvcmNlIEFuZ3VsYXIgdG8gZGV0ZWN0IGNoYW5nZXNcbiAgICAgICAgLy8gdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgfVxufVxuIiwiPGRpdiBjbGFzcz1cImNmLW90cFwiPlxuICAgIDxkaXYgY2xhc3M9XCJjb250YWluZXItZmx1aWRcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInJvd1wiICpuZ0lmPVwic2hvd0xhYmVsXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTEyXCI+XG4gICAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiaGVhZGluZ1wiIFtuZ0NsYXNzXT1cInRoZW1lXCI+e3sgbGFiZWwgfX08L2xhYmVsPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiaW5wdXRzXCI+XG4gICAgICAgICAgICA8ZGl2ICpuZ0Zvcj1cImxldCBpdGVtIG9mIG51bWJlcnM7IGxldCBpID0gaW5kZXhcIiBjbGFzcz1cImlucHV0LWhvbGRlclwiPlxuICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIFthdXRvZm9jdXNdPVwiZm9jdXNbaV1cIiAoa2V5ZG93bik9XCJoYW5kbGVLZXlEb3duKCRldmVudCwgaSlcIlxuICAgICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7J2F1dG9mb2N1cyc6IGZvY3VzW2ldLCBkYXJrOiB0aGVtZSA9PT0gJ2RhcmsnLCBsaWdodDogdGhlbWUgPT09ICdsaWdodCd9XCJcbiAgICAgICAgICAgICAgICAgICAgKGtleXVwKT1cImhhbmRsZUtleVVwKCRldmVudCwgaSlcIiAocGFzdGUpPVwiaGFuZGxlUGFzdGUoJGV2ZW50LCBpKVwiIFtpZF09XCInY2Ytb3RwLWlucHV0LXdlYi0nICsgaVwiXG4gICAgICAgICAgICAgICAgICAgIGF1dG9jb21wbGV0ZT1cIm9mZlwiIG1heGxlbmd0aD1cIjFcIiBjbGFzcz1cIndlYlwiICpuZ0lmPVwicGxhdGZvcm0gPT09ICd3ZWInXCIgLz5cblxuICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIFthdXRvZm9jdXNdPVwiZm9jdXNbaV1cIiAoa2V5ZG93bik9XCJoYW5kbGVLZXlEb3duKCRldmVudCwgaSlcIlxuICAgICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7J2F1dG9mb2N1cyc6IGZvY3VzW2ldLCBkYXJrOiB0aGVtZSA9PT0gJ2RhcmsnLCBsaWdodDogdGhlbWUgPT09ICdsaWdodCd9XCJcbiAgICAgICAgICAgICAgICAgICAgKGtleXVwKT1cImhhbmRsZUtleVVwKCRldmVudCwgaSlcIiAocGFzdGUpPVwiaGFuZGxlUGFzdGUoJGV2ZW50LCBpKVwiIFtpZF09XCInY2Ytb3RwLWlucHV0LW1vYmlsZS0nICsgaVwiXG4gICAgICAgICAgICAgICAgICAgIGF1dG9jb21wbGV0ZT1cIm9mZlwiIG1heGxlbmd0aD1cIjFcIiBjbGFzcz1cIm1vYmlsZVwiIFt2YWx1ZV09XCJvdHBbaV1cIiAqbmdJZj1cInBsYXRmb3JtID09PSAnbW9iaWxlJ1wiIC8+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG48L2Rpdj4iXX0=