UNPKG

@crediblefinance/credible-ui

Version:

Credible's standard UI library

200 lines 34.3 kB
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 #f5f5f5}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 #f5f5f5}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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2Ytb3RwLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NyZWRpYmxlLXVpL3NyYy9saWIvY2Ytb3RwL2NmLW90cC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jcmVkaWJsZS11aS9zcmMvbGliL2NmLW90cC9jZi1vdHAuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNILFNBQVMsRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBVSxNQUFNLEVBQy9ELE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLE1BQU0sWUFBWSxDQUFDOzs7QUFPcEQsTUFBTSxPQUFPLGNBQWM7SUFDZCxNQUFNLEdBQVcsQ0FBQyxDQUFDO0lBQ2xCLE9BQU8sR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO0lBQ3RDLEtBQUssR0FBVyxFQUFFLENBQUM7SUFDbkIsU0FBUyxHQUFZLElBQUksQ0FBQztJQUMxQixXQUFXLEdBQVcsRUFBRSxDQUFDO0lBQ3pCLEtBQUssR0FBVyxNQUFNLENBQUM7SUFFaEMsT0FBTyxHQUFhLEVBQUUsQ0FBQztJQUN2QixHQUFHLEdBQWEsRUFBRSxDQUFDO0lBQ25CLEtBQUssR0FBYyxFQUFFLENBQUM7SUFDdEIsV0FBVyxDQUFjO0lBQ3pCLFlBQVksR0FBVyxDQUFDLENBQUM7SUFDekIsS0FBSyxDQUFNO0lBQ1gsTUFBTSxDQUFTO0lBQ2YsUUFBUSxHQUFXLEtBQUssQ0FBQztJQUN6QixRQUFRLEdBQUcsV0FBVyxFQUFFLENBQUM7SUFFekI7UUFDSSxJQUFJLENBQUMsTUFBTSxHQUFHLFNBQVMsRUFBRSxDQUFDO1FBRTFCLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7UUFFcEMsSUFBSSxJQUFJLENBQUMsS0FBSyxHQUFH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MkZBQWQsY0FBYywrUENWM0IsdTBDQXFCTTs7MkZEWE8sY0FBYztrQkFMMUIsU0FBUzsrQkFDSSxRQUFRO3dEQUtULE1BQU07c0JBQWQsS0FBSztnQkFDSSxPQUFPO3NCQUFoQixNQUFNO2dCQUNFLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csS0FBSztzQkFBYixLQUFLO2dCQTRDTixRQUFRO3NCQURQLFlBQVk7dUJBQUMsZUFBZSxFQUFFLENBQUUsUUFBUSxDQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgICBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSG9zdExpc3RlbmVyLCBJbnB1dCwgT25Jbml0LCBPdXRwdXRcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBnZXREb2N1bWVudCwgZ2V0V2luZG93IH0gZnJvbSAnc3NyLXdpbmRvdyc7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiAnY2Ytb3RwJyxcbiAgICB0ZW1wbGF0ZVVybDogJy4vY2Ytb3RwLmNvbXBvbmVudC5odG1sJyxcbiAgICBzdHlsZVVybHM6IFsgJy4vY2Ytb3RwLmNvbXBvbmVudC5zY3NzJyBdXG59KVxuZXhwb3J0IGNsYXNzIENmT3RwQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgICBASW5wdXQoKSBsZW5ndGg6IG51bWJlciA9IDY7XG4gICAgQE91dHB1dCgpIGNoYW5nZWQgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcbiAgICBASW5wdXQoKSBsYWJlbDogc3RyaW5nID0gJyc7XG4gICAgQElucHV0KCkgc2hvd0xhYmVsOiBib29sZWFuID0gdHJ1ZTtcbiAgICBASW5wdXQoKSBwcmVmaWxsQ29kZTogc3RyaW5nID0gJyc7XG4gICAgQElucHV0KCkgdGhlbWU6IHN0cmluZyA9ICdkYXJrJztcblxuICAgIG51bWJlcnM6IG51bWJlcltdID0gW107XG4gICAgb3RwOiBzdHJpbmdbXSA9IFtdO1xuICAgIGZvY3VzOiBib29sZWFuW10gPSBbXTtcbiAgICBhbGxvd2VkS2V5czogU2V0PHN0cmluZz47XG4gICAgY3VycmVudEluZGV4OiBudW1iZXIgPSAwO1xuICAgIHdpZHRoOiBhbnk7XG4gICAgd2luZG93OiBXaW5kb3c7XG4gICAgcGxhdGZvcm06IHN0cmluZyA9ICd3ZWInO1xuICAgIGRvY3VtZW50ID0gZ2V0RG9jdW1lbnQoKTtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLndpbmRvdyA9IGdldFdpbmRvdygpO1xuXG4gICAgICAgIHRoaXMud2lkdGggPSB0aGlzLndpbmRvdy5vdXRlcldpZHRoO1xuXG4gICAgICAgIGlmICh0aGlzLndpZHRoIDwgNzY4KVxuICAgICAgICAgICAgdGhpcy5wbGF0Zm9ybSA9ICdtb2JpbGUnO1xuICAgICAgICBcbiAgICAgICAgY29uc3QgYWxsb3dlZEtleXMgPSBbXG4gICAgICAgICAgICAnQmFja3NwYWNlJywgLy8gYmFja3NwYWNlXG4gICAgICAgICAgICAnRGlnaXQwJywgLy8gemVyb1xuICAgICAgICAgICAgJ0RpZ2l0MScsIC8vIG9uZVxuICAgICAgICAgICAgJ0RpZ2l0MicsIC8vIHR3b1xuICAgICAgICAgICAgJ0RpZ2l0MycsIC8vIHRocmVlXG4gICAgICAgICAgICAnRGlnaXQ0JywgLy8gZm91clxuICAgICAgICAgICAgJ0RpZ2l0NScsIC8vIGZpdmVcbiAgICAgICAgICAgICdEaWdpdDYnLCAvLyBzaXhcbiAgICAgICAgICAgICdEaWdpdDcnLCAvLyBzZXZlblxuICAgICAgICAgICAgJ0RpZ2l0OCcsIC8vIGVpZ2h0XG4gICAgICAgICAgICAnRGlnaXQ5JywgLy8gbmluZVxuICAgICAgICAgICAgJ0tleVYnLCAvLyBmb3IgY29weSBwYXN0ZVxuICAgICAgICAgICAgJ01ldGFMZWZ0JywgLy8gbGVmdCBjb21tYW5kIGtleSBpbiBtYWNcbiAgICAgICAgICAgICdNZXRhUmlnaHQnIC8vIGxlZnQgY29tbWFuZCBrZXkgaW4gbWFjXG4gICAgICAgIF07XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDY1OyBpIDw9IDkwOyBpKyspXG4gICAgICAgICAgICBhbGxvd2VkS2V5cy5wdXNoKGBLZXkke1N0cmluZy5mcm9tQ2hhckNvZGUoaSl9YCk7XG5cbiAgICAgICAgdGhpcy5hbGxvd2VkS2V5cyA9IG5ldyBTZXQoYWxsb3dlZEtleXMpO1xuICAgIH1cblxuICAgIEBIb3N0TGlzdGVuZXIoJ3dpbmRvdzpyZXNpemUnLCBbICckZXZlbnQnIF0pXG4gICAgb25SZXNpemUoZXZlbnQ6IGFueSkge1xuICAgICAgICB0aGlzLndpZHRoID0gZXZlbnQudGFyZ2V0Lm91dGVyV2lkdGg7XG5cbiAgICAgICAgY29uc29sZS5sb2coJ3dpZHRoIG9uIHJlc2l6ZScsIHRoaXMud2lkdGgpO1xuXG4gICAgICAgIGlmICh0aGlzLndpZHRoIDwgNzY4KVxuICAgICAgICAgICAgdGhpcy5wbGF0Zm9ybSA9ICdtb2JpbGUnO1xuICAgIH1cblxuICAgIGdldElucHV0SWQoaW5kZXg6IG51bWJlcik6IHN0cmluZyB7XG4gICAgICAgIGlmICh0aGlzLndpZHRoIDwgNzY4KVxuICAgICAgICAgICAgcmV0dXJuIGBjZi1vdHAtaW5wdXQtbW9iaWxlLSR7aW5kZXh9YDtcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgcmV0dXJuIGBjZi1vdHAtaW5wdXQtd2ViLSR7aW5kZXh9YDtcbiAgICB9XG5cbiAgICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5udW1iZXJzID0gQXJyYXkuZnJvbSh7XG4gICAgICAgICAgICBsZW5ndGg6IHRoaXMubGVuZ3RoXG4gICAgICAgIH0sIChfLCBpKSA9PiBpKTtcbiAgICAgICAgdGhpcy5vdHAgPSBBcnJheSh0aGlzLmxlbmd0aCkuZmlsbCgnJyk7XG4gICAgICAgIHRoaXMuY2hhbmdlSW5wdXRGb2N1cygpO1xuXG4gICAgICAgIGlmICh0aGlzLnByZWZpbGxDb2RlKVxuICAgICAgICAgICAgdGhpcy5wcmVmaWxsT3RwKHRoaXMucHJlZmlsbENvZGUpO1xuICAgIH1cbiAgICBwcmVmaWxsT3RwKHRleHQ6IHN0cmluZywgaW5kZXggPSAwKTogdm9pZCB7XG4gICAgICAgIC8vIGNvbnN0IHRleHQgPSBldmVudC5jbGlwYm9hcmREYXRhPy5nZXREYXRhKCdUZXh0JykgfHwgJyc7XG4gICAgICAgIGNvbnNvbGUubG9nKCdwcmVmaWxsJywgdGV4dCk7XG4gICAgICAgIC8vIGNvbnN0IGNoYXJhY3RlcnMgPSB0ZXh0LnNwbGl0KCcnKS5maWx0ZXIoY2hhciA9PiAvXlthLXpBLVowLTldJC8udGVzdChjaGFyKSkuc2xpY2UoMCwgdGhpcy5sZW5ndGggLSBpbmRleCk7XG5cbiAgICAgICAgLy8gY29uc3QgdGV4dCA9IGV2ZW50LmNsaXBib2FyZERhdGE/LmdldERhdGEoJ1RleHQnKSB8fCAnJztcbiAgICAgICAgY29uc3QgY2hhcmFjdGVycyA9IHRleHQuc3BsaXQoJycpLmZpbHRlcihjaGFyID0+IC9eW2EtekEtWjAtOV0kLy50ZXN0KGNoYXIpKS5zbGljZSgwLCB0aGlzLmxlbmd0aCAtIGluZGV4KTtcblxuICAgICAgICAvLyBVcGRhdGUgT1RQIGFycmF5IGFuZCB0aGUgY29ycmVzcG9uZGluZyBpbnB1dCBmaWVsZHNcbiAgICAgICAgY2hhcmFjdGVycy5mb3JFYWNoKChjaGFyLCBpKSA9PiB7XG4gICAgICAgICAgICBpZiAoaW5kZXggKyBpIDwgdGhpcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldE90cEFycmF5KGluZGV4ICsgaSwgY2hhcik7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBpbnB1dCA9IHRoaXMuZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5nZXRJbnB1dElkKGluZGV4ICsgaSkpIGFzIEhUTUxJbnB1dEVsZW1lbnQ7XG5cbiAgICAgICAgICAgICAgICBpZiAoaW5wdXQpXG4gICAgICAgICAgICAgICAgICAgIGlucHV0LnZhbHVlID0gY2hhcjsgLy8gRGlyZWN0bHkgc2V0IHZhbHVlXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFVwZGF0ZSBjdXJyZW50SW5kZXggYW5kIGZvY3VzXG4gICAgICAgIHRoaXMuY3VycmVudEluZGV4ID0gTWF0aC5taW4oaW5kZXggKyBjaGFyYWN0ZXJzLmxlbmd0aCwgdGhpcy5sZW5ndGggLSAxKTtcbiAgICAgICAgdGhpcy5jaGFuZ2VJbnB1dEZvY3VzKCk7XG5cbiAgICAgICAgLy8gZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICBoYW5kbGVLZXlEb3duKGV2ZW50OiBLZXlib2FyZEV2ZW50LCBpbmRleDogbnVtYmVyKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IGFsbG93ZWQgPSB0aGlzLmFsbG93ZWRLZXlzLmhhcyhldmVudC5jb2RlKTtcblxuICAgICAgICBpZiAoIWFsbG93ZWQpXG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICAgIHJldHVybiBhbGxvd2VkO1xuICAgIH1cblxuICAgIGhhbmRsZUtleVVwKGV2ZW50OiBLZXlib2FyZEV2ZW50LCBpbmRleDogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRLZXkgPSBldmVudC5rZXk7XG4gICAgICAgIGNvbnN0IGlzQWxwaGFudW1lcmljID0gL15bYS16QS1aMC05XSQvLnRlc3QoY3VycmVudEtleSk7XG5cbiAgICAgICAgaWYgKGlzQWxwaGFudW1lcmljKSB7XG4gICAgICAgICAgICB0aGlzLnNldE90cEFycmF5KGluZGV4LCBjdXJyZW50S2V5KTtcblxuICAgICAgICAgICAgaWYgKGluZGV4IDwgdGhpcy5sZW5ndGggLSAxKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50SW5kZXggPSBpbmRleCArIDE7XG4gICAgICAgICAgICAgICAgdGhpcy5jaGFuZ2VJbnB1dEZvY3VzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZXZlbnQuY29kZSA9PT0gJ0JhY2tzcGFjZScpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLm90cFtpbmRleF0gIT09ICcnKSB7XG4gICAgICAgICAgICAgICAgLy8gQ2xlYXIgdGhlIGN1cnJlbnQgaW5wdXQgdmFsdWVcbiAgICAgICAgICAgICAgICB0aGlzLnNldE90cEFycmF5KGluZGV4LCAnJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChpbmRleCA+IDApIHtcbiAgICAgICAgICAgICAgICAvLyBNb3ZlIHRvIHRoZSBwcmV2aW91cyBpbnB1dCBmaWVsZCBpZiB0aGUgY3VycmVudCBmaWVsZCBpcyBlbXB0eVxuICAgICAgICAgICAgICAgIHRoaXMuY3VycmVudEluZGV4ID0gaW5kZXggLSAxO1xuICAgICAgICAgICAgICAgIHRoaXMuY2hhbmdlSW5wdXRGb2N1cygpO1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0T3RwQXJyYXkodGhpcy5jdXJyZW50SW5kZXgsICcnKTsgLy8gQ2xlYXIgdGhlIHByZXZpb3VzIGZpZWxkXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBoYW5kbGVQYXN0ZShldmVudDogQ2xpcGJvYXJkRXZlbnQsIGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgdGV4dCA9IGV2ZW50LmNsaXBib2FyZERhdGE/LmdldERhdGEoJ1RleHQnKSB8fCAnJztcbiAgICAgICAgY29uc3QgY2hhcmFjdGVycyA9IHRleHQuc3BsaXQoJycpLmZpbHRlcihjaGFyID0+IC9eW2EtekEtWjAtOV0kLy50ZXN0KGNoYXIpKS5zbGljZSgwLCB0aGlzLmxlbmd0aCAtIGluZGV4KTtcblxuICAgICAgICAvLyBVcGRhdGUgT1RQIGFycmF5IGFuZCB0aGUgY29ycmVzcG9uZGluZyBpbnB1dCBmaWVsZHNcbiAgICAgICAgY2hhcmFjdGVycy5mb3JFYWNoKChjaGFyLCBpKSA9PiB7XG4gICAgICAgICAgICBpZiAoaW5kZXggKyBpIDwgdGhpcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldE90cEFycmF5KGluZGV4ICsgaSwgY2hhcik7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBpbnB1dCA9IHRoaXMuZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodGhpcy5nZXRJbnB1dElkKGluZGV4ICsgaSkpIGFzIEhUTUxJbnB1dEVsZW1lbnQ7XG5cbiAgICAgICAgICAgICAgICBpZiAoaW5wdXQpXG4gICAgICAgICAgICAgICAgICAgIGlucHV0LnZhbHVlID0gY2hhcjsgLy8gRGlyZWN0bHkgc2V0IHZhbHVlXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFVwZGF0ZSBjdXJyZW50SW5kZXggYW5kIGZvY3VzXG4gICAgICAgIHRoaXMuY3VycmVudEluZGV4ID0gTWF0aC5taW4oaW5kZXggKyBjaGFyYWN0ZXJzLmxlbmd0aCwgdGhpcy5sZW5ndGggLSAxKTtcbiAgICAgICAgdGhpcy5jaGFuZ2VJbnB1dEZvY3VzKCk7XG5cbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICBjaGFuZ2VJbnB1dEZvY3VzKCk6IHZvaWQge1xuICAgICAgICBjb25zb2xlLmxvZygnY2hhbmdlSW5wdXRGb2N1cycsIHRoaXMuY3VycmVudEluZGV4KTtcblxuICAgICAgICAvLyBDbGVhciBmb2N1cyBmcm9tIGFsbCBpbnB1dCBmaWVsZHNcbiAgICAgICAgdGhpcy5mb2N1cy5maWxsKGZhbHNlKTtcblxuICAgICAgICAvLyBFbnN1cmUgdGhlIGN1cnJlbnRJbmRleCBpcyB3aXRoaW4gdGhlIHZhbGlkIHJhbmdlXG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRJbmRleCA+PSAwICYmIHRoaXMuY3VycmVudEluZGV4IDwgdGhpcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRoaXMuZm9jdXNbdGhpcy5jdXJyZW50SW5kZXhdID0gdHJ1ZTtcblxuICAgICAgICAgICAgLy8gTWFudWFsbHkgZm9jdXMgb24gdGhlIGlucHV0IGVsZW1lbnRcbiAgICAgICAgICAgIGNvbnN0IGlkID0gdGhpcy5nZXRJbnB1dElkKHRoaXMuY3VycmVudEluZGV4KTtcblxuICAgICAgICAgICAgY29uc29sZS5sb2coJ2lkJywgaWQpO1xuXG4gICAgICAgICAgICBjb25zdCBpbnB1dEVsZW1lbnQgPSB0aGlzLmRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlkKSBhcyBIVE1MSW5wdXRFbGVtZW50O1xuXG4gICAgICAgICAgICBjb25zb2xlLmxvZygnaW5wdXRFbGVtZW50JywgaW5wdXRFbGVtZW50KTtcblxuICAgICAgICAgICAgaWYgKGlucHV0RWxlbWVudCkge1xuICAgICAgICAgICAgICAgIGlucHV0RWxlbWVudC5mb2N1cygpO1xuXG4gICAgICAgICAgICAgICAgLy8gU2V0IHRoZSBjdXJzb3IgdG8gdGhlIGVuZCBvZiB0aGUgaW5wdXQgZmllbGQgaWYgdGhlcmUncyB0ZXh0XG4gICAgICAgICAgICAgICAgaWYgKGlucHV0RWxlbWVudC52YWx1ZS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdpbnB1dEVsZW1lbnQudmFsdWUubGVuZ3RoJywgaW5wdXRFbGVtZW50LnZhbHVlLmxlbmd0aCk7XG5cbiAgICAgICAgICAgICAgICAgICAgaW5wdXRFbGVtZW50LnNldFNlbGVjdGlvblJhbmdlKGlucHV0RWxlbWVudC52YWx1ZS5sZW5ndGgsIGlucHV0RWxlbWVudC52YWx1ZS5sZW5ndGgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIHNldE90cEFycmF5KGluZGV4OiBudW1iZXIsIHZhbHVlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAvLyAgICAgY29uc29sZS5sb2coJ2luZGV4JywgaW5kZXgsICd2YWx1ZScsIHZhbHVlKTtcblxuICAgIC8vICAgICB0aGlzLm90cFtpbmRleF0gPSB2YWx1ZTtcblxuICAgIC8vICAgICBjb25zdCB2YWxpZE90cCA9IHRoaXMub3RwLmpvaW4oJycpO1xuXG4gICAgLy8gICAgIGNvbnNvbGUubG9nKCd2YWxpZE90cCcsIHZhbGlkT3RwKTtcblxuICAgIC8vICAgICB0aGlzLmNoYW5nZWQuZW1pdCh2YWxpZE90cCk7XG4gICAgLy8gfVxuXG4gICAgc2V0T3RwQXJyYXkoaW5kZXg6IG51bWJlciwgdmFsdWU6IHN0cmluZyB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgICAgICBjb25zb2xlLmxvZygnc2V0T3RwQXJyYXkgaW5kZXg6JywgaW5kZXgsICd2YWx1ZTonLCB2YWx1ZSk7XG5cbiAgICAgICAgaWYgKGluZGV4IDwgMCB8fCBpbmRleCA+PSB0aGlzLmxlbmd0aCkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignSW5kZXggb3V0IG9mIGJvdW5kczonLCBpbmRleCk7XG5cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnNvbGUubG9nKCdpbmRleDonLCBpbmRleCwgJ3ZhbHVlOicsIHZhbHVlKTtcblxuICAgICAgICAvLyBVcGRhdGUgdGhlIE9UUCBhcnJheVxuICAgICAgICB0aGlzLm90cFtpbmRleF0gPSB2YWx1ZSB8fCAnJztcblxuICAgICAgICAvLyBFbWl0IHRoZSB1cGRhdGVkIE9UUFxuICAgICAgICBjb25zdCB2YWxpZE90cCA9IHRoaXMub3RwLm1hcChjaGFyID0+IGNoYXIgfHwgJycpLmpvaW4oJycpO1xuXG4gICAgICAgIGNvbnNvbGUubG9nKCd2YWxpZE90cDonLCB2YWxpZE90cCk7XG4gICAgICAgIHRoaXMuY2hhbmdlZC5lbWl0KHZhbGlkT3RwKTtcblxuICAgICAgICAvLyBPcHRpb25hbGx5IGZvcmNlIEFuZ3VsYXIgdG8gZGV0ZWN0IGNoYW5nZXNcbiAgICAgICAgLy8gdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgfVxufVxuIiwiPGRpdiBjbGFzcz1cImNmLW90cFwiPlxuICAgIDxkaXYgY2xhc3M9XCJjb250YWluZXItZmx1aWRcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInJvd1wiICpuZ0lmPVwic2hvd0xhYmVsXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiY29sLW1kLTEyXCI+XG4gICAgICAgICAgICAgICAgPGxhYmVsIGNsYXNzPVwiaGVhZGluZ1wiIFtuZ0NsYXNzXT1cInRoZW1lXCI+e3sgbGFiZWwgfX08L2xhYmVsPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiaW5wdXRzXCI+XG4gICAgICAgICAgICA8ZGl2ICpuZ0Zvcj1cImxldCBpdGVtIG9mIG51bWJlcnM7IGxldCBpID0gaW5kZXhcIiBjbGFzcz1cImlucHV0LWhvbGRlclwiPlxuICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIFthdXRvZm9jdXNdPVwiZm9jdXNbaV1cIiAoa2V5ZG93bik9XCJoYW5kbGVLZXlEb3duKCRldmVudCwgaSlcIlxuICAgICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7J2F1dG9mb2N1cyc6IGZvY3VzW2ldLCBkYXJrOiB0aGVtZSA9PT0gJ2RhcmsnLCBsaWdodDogdGhlbWUgPT09ICdsaWdodCd9XCJcbiAgICAgICAgICAgICAgICAgICAgKGtleXVwKT1cImhhbmRsZUtleVVwKCRldmVudCwgaSlcIiAocGFzdGUpPVwiaGFuZGxlUGFzdGUoJGV2ZW50LCBpKVwiIFtpZF09XCInY2Ytb3RwLWlucHV0LXdlYi0nICsgaVwiXG4gICAgICAgICAgICAgICAgICAgIGF1dG9jb21wbGV0ZT1cIm9mZlwiIG1heGxlbmd0aD1cIjFcIiBjbGFzcz1cIndlYlwiICpuZ0lmPVwicGxhdGZvcm0gPT09ICd3ZWInXCIgLz5cblxuICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwidGV4dFwiIFthdXRvZm9jdXNdPVwiZm9jdXNbaV1cIiAoa2V5ZG93bik9XCJoYW5kbGVLZXlEb3duKCRldmVudCwgaSlcIlxuICAgICAgICAgICAgICAgICAgICBbbmdDbGFzc109XCJ7J2F1dG9mb2N1cyc6IGZvY3VzW2ldLCBkYXJrOiB0aGVtZSA9PT0gJ2RhcmsnLCBsaWdodDogdGhlbWUgPT09ICdsaWdodCd9XCJcbiAgICAgICAgICAgICAgICAgICAgKGtleXVwKT1cImhhbmRsZUtleVVwKCRldmVudCwgaSlcIiAocGFzdGUpPVwiaGFuZGxlUGFzdGUoJGV2ZW50LCBpKVwiIFtpZF09XCInY2Ytb3RwLWlucHV0LW1vYmlsZS0nICsgaVwiXG4gICAgICAgICAgICAgICAgICAgIGF1dG9jb21wbGV0ZT1cIm9mZlwiIG1heGxlbmd0aD1cIjFcIiBjbGFzcz1cIm1vYmlsZVwiIFt2YWx1ZV09XCJvdHBbaV1cIiAqbmdJZj1cInBsYXRmb3JtID09PSAnbW9iaWxlJ1wiIC8+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG48L2Rpdj4iXX0=