UNPKG

m-truncate

Version:

`mTruncate` is a **lightweight, flexible, and fully standalone Angular directive** that truncates text dynamically and optionally displays a **tooltip** with the full text. It supports **character-based**, **line-based**, and **width-based** truncation

386 lines 56.1 kB
import { Directive, Input, HostListener, } from '@angular/core'; import { debounceTime, fromEvent, Subject, takeUntil } from 'rxjs'; import * as i0 from "@angular/core"; import * as i1 from "./m-truncate.service"; export class MTruncateDirective { constructor(el, renderer, mTruncateService) { this.el = el; this.renderer = renderer; this.mTruncateService = mTruncateService; /** Whether to show tooltip on truncated text hover */ this.showTooltip = true; /** Number of lines to truncate the text to */ this.truncateLines = 0; /** Maximum width for truncation */ this.maxTruncateWidth = 0; /** Maximum width for tooltip */ this.maxTooltipWidth = 0; /** Background color of the tooltip */ this.bgColor = '#fff'; /** Text color of the tooltip */ this.color = '#1c1c28'; /** Tooltip position (top, bottom, left, right) */ this.tooltipPosition = 'top'; /** Text direction (LTR, RTL) */ this.tooltipDirection = 'ltr'; /** Suffix to append when text is truncated */ this.truncateSuffix = '...'; /** ID for the tooltip element */ this.id = 'mId'; /** Maximum number of characters before truncation */ this.truncateChar = 0; this.fullText = ''; this.tooltip = null; this.tooltipArrow = null; this.destroy$ = new Subject(); } ngAfterViewInit() { this.element = this.el.nativeElement; this.fullText = this.el.nativeElement.innerText.trim(); this.tooltipDirection = this.mTruncateService.getDirection(); if (!this.fullText || this.fullText.trim().length <= 3) return; fromEvent(window, 'resize') .pipe(debounceTime(500), takeUntil(this.destroy$)) .subscribe(() => (this.resize ? this.onResize() : '')); this.truncateMethod(); } ngOnChanges(changes) { if (changes['truncateChar']) { this.truncateMethod(); } if (changes['truncateLines']) { this.truncateMethod(); } if (changes['maxTruncateWidth']) { setTimeout(() => { this.truncateMethod(); }); } if (changes['textChange']) { setTimeout(() => { this.fullText = this.textChange; this.truncateMethod(); }); } } truncateMethod() { if (this.truncateChar > 0) { this.truncateByChar(); } else { if (this.truncateLines > 1) { this.applyRowsTruncate(); } else { this.applyTruncate(); } } } truncateByChar() { return this.fullText.length <= this.truncateChar ? this.fullText : (this.element.innerText = this.fullText.slice(0, this.truncateChar) + this.truncateSuffix); } applyTruncate() { const element = this.el.nativeElement; element.innerText = this.fullText; // Reset to full text if (this.maxTruncateWidth) { element.style.maxWidth = this.maxTruncateWidth + 'px'; } const maxWidth = element.clientWidth; // Get available width element.style.textWrap = 'nowrap'; element.style.wordBreak = 'break-word'; let left = 0; let right = this.fullText.length; let truncatedText = this.fullText; if (element.scrollWidth != maxWidth) { while (left <= right) { let mid = Math.floor((left + right) / 2); element.innerText = this.fullText.substring(0, mid) + this.truncateSuffix; if (element.scrollWidth > maxWidth) { right = mid - 1; // Too long, reduce size } else { left = mid + 1; // Too short, increase size truncatedText = this.fullText.substring(0, mid) + this.truncateSuffix; } } } element.innerText = truncatedText; // Set final truncated text } applyRowsTruncate() { const element = this.el.nativeElement; element.innerText = this.fullText; // Reset to full text const lineHeight = parseFloat(window.getComputedStyle(element).lineHeight); const maxHeight = lineHeight * this.truncateLines; if (element.scrollHeight > maxHeight) { let left = 0; let right = this.fullText.length; let truncatedText = this.fullText; while (left <= right) { let mid = Math.floor((left + right) / 2); element.innerText = this.fullText.substring(0, mid) + this.truncateSuffix; if (element.scrollHeight > maxHeight) { right = mid - 1; // Too long, reduce text } else { left = mid + 1; // Too short, increase text truncatedText = this.fullText.substring(0, mid) + this.truncateSuffix; } } element.innerText = truncatedText; } } getTooltipDirection(dir) { this.tooltipDirection = dir; } onResize() { if (this.truncateChar > 0) { this.truncateByChar(); } else { if (this.truncateLines > 1) { this.applyRowsTruncate(); } else { this.applyTruncate(); } } } createTooltip() { if (this.tooltip) return; // Avoid creating multiple tooltips let maxWidth = this.el.nativeElement.clientWidth; this.tooltip = this.renderer.createElement('div'); this.tooltip?.classList.add('mTooltip'); this.tooltip?.setAttribute('id', this.id); this.renderer.appendChild(document.body, this.tooltip); this.renderer.setProperty(this.tooltip, 'innerText', this.fullText); this.renderer.setStyle(this.tooltip, 'opacity', '0'); // Start hidden this.renderer.setStyle(this.tooltip, 'animation', 'fadeIn 0.35s ease-out forwards'); // Apply animation // Apply styles this.renderer.setStyle(this.tooltip, 'position', 'fixed'); this.renderer.setStyle(this.tooltip, 'background', this.bgColor); this.renderer.setStyle(this.tooltip, 'color', this.color); this.renderer.setStyle(this.tooltip, 'whiteSpace', 'pre-wrap'); // Allows multi-line text this.renderer.setStyle(this.tooltip, 'wordWrap', 'break-word'); // Wrap long words this.renderer.setStyle(this.tooltip, 'direction', this.tooltipDirection); // direction this.renderer.setStyle(this.tooltip, 'box-shadow', '0px 4px 15px 0px rgba(0, 0, 0, 0.2)'); this.renderer.setStyle(this.tooltip, 'width', 'fit-content'); this.renderer.setStyle(this.tooltip, 'max-width', this.maxTooltipWidth ? this.maxTooltipWidth + 'px' : maxWidth + 'px'); this.renderer.setStyle(this.tooltip, 'textOverflow', 'ellipsis'); this.renderer.setStyle(this.tooltip, 'padding', '10px'); this.renderer.setStyle(this.tooltip, 'borderRadius', '6px'); this.renderer.setStyle(this.tooltip, 'fontSize', '14px'); this.renderer.setStyle(this.tooltip, 'zIndex', '999999999999999'); this.renderer.setStyle(this.tooltip, 'pointerEvents', 'none'); // Prevent interference // Tooltip Arrow this.tooltipArrow = this.renderer.createElement('div'); this.tooltipArrow?.classList.add('mTooltipArrow'); this.renderer.appendChild(this.tooltip, this.tooltipArrow); this.renderer.setStyle(this.tooltipArrow, 'position', 'absolute'); this.renderer.setStyle(this.tooltipArrow, 'width', '0'); this.renderer.setStyle(this.tooltipArrow, 'height', '0'); this.renderer.setStyle(this.tooltipArrow, 'borderStyle', 'solid'); this.positionTooltip(); // Animation this.addKeyframes(); } removeTooltip() { if (this.tooltip) { this.renderer.setStyle(this.tooltip, 'animation', 'fadeOut 0.5s ease-out forwards'); setTimeout(() => { this.renderer.removeChild(document.body, this.tooltip); this.tooltip = null; }); } } positionTooltip() { if (!this.tooltip) return; const rect = this.el.nativeElement.getBoundingClientRect(); const tooltipRect = this.tooltip.getBoundingClientRect(); let top = 0, left = 0; switch (this.tooltipPosition) { case 'top': top = rect.top - tooltipRect.height - 5; left = rect.left + (rect.width - tooltipRect.width) / 2; if (top < 0) { top = rect.bottom + 5; // Move below if not enough space this.arrowPositionUp(); } else { // Arrow pointing **down** (placed at bottom) this.arrowPositionDown(); } break; case 'bottom': top = rect.bottom + 5; left = rect.left + (rect.width - tooltipRect.width) / 2; if (top + tooltipRect.height > window.innerHeight) { top = rect.top - tooltipRect.height - 5; this.arrowPositionDown(); } else { // Arrow pointing **up** (placed at top) this.arrowPositionUp(); } break; case 'inset-inline-start': case 'right': top = rect.top + (rect.height - tooltipRect.height) / 2; left = rect.left - tooltipRect.width - 5; if (left < 0) { left = rect.right + 5; // Move to the right if not enough space this.arrowPositionLeft(); } else { this.arrowPositionRight(); } // Arrow pointing **right** (placed at end) break; case 'inset-inline-end': case 'left': top = rect.top + (rect.height - tooltipRect.height) / 2; left = rect.right + 5; if (left + tooltipRect.width > window.innerWidth) { left = rect.left - tooltipRect.width - 5; this.arrowPositionRight(); } else { // Arrow pointing **left** (placed at start) this.arrowPositionLeft(); } break; default: top = rect.top - tooltipRect.height - 5; left = rect.left + (rect.width - tooltipRect.width) / 2; if (top < 0) { top = rect.bottom + 5; // Move below if not enough space this.arrowPositionUp(); } else { // Arrow pointing **down** (placed at bottom) this.arrowPositionDown(); } break; } this.renderer.setStyle(this.tooltip, 'top', `${top}px`); this.renderer.setStyle(this.tooltip, 'left', `${left}px`); } arrowPositionDown() { this.renderer.setStyle(this.tooltipArrow, 'borderWidth', '10px 10px 0 10px'); this.renderer.setStyle(this.tooltipArrow, 'borderColor', `${this.bgColor} transparent transparent transparent`); this.renderer.setStyle(this.tooltipArrow, 'left', '50%'); this.renderer.setStyle(this.tooltipArrow, 'bottom', '-8px'); this.renderer.setStyle(this.tooltipArrow, 'transform', 'translateX(-50%)'); } arrowPositionUp() { this.renderer.setStyle(this.tooltipArrow, 'borderWidth', '0 10px 10px 10px'); this.renderer.setStyle(this.tooltipArrow, 'borderColor', `transparent transparent ${this.bgColor} transparent`); this.renderer.setStyle(this.tooltipArrow, 'left', '50%'); this.renderer.setStyle(this.tooltipArrow, 'top', '-8px'); this.renderer.setStyle(this.tooltipArrow, 'transform', 'translateX(-50%)'); } arrowPositionRight() { this.renderer.setStyle(this.tooltipArrow, 'borderWidth', '10px 0 10px 10px'); this.renderer.setStyle(this.tooltipArrow, 'borderColor', `transparent transparent transparent ${this.bgColor}`); this.renderer.setStyle(this.tooltipArrow, 'top', '50%'); this.renderer.setStyle(this.tooltipArrow, 'right', '-8px'); this.renderer.setStyle(this.tooltipArrow, 'transform', 'translateY(-50%)'); } arrowPositionLeft() { this.renderer.setStyle(this.tooltipArrow, 'borderWidth', '10px 10px 10px 0'); this.renderer.setStyle(this.tooltipArrow, 'borderColor', `transparent ${this.bgColor} transparent transparent`); this.renderer.setStyle(this.tooltipArrow, 'top', '50%'); this.renderer.setStyle(this.tooltipArrow, 'left', '-8px'); this.renderer.setStyle(this.tooltipArrow, 'transform', 'translateY(-50%)'); } addKeyframes() { if (document.getElementById('fadeInKeyframes')) return; // Avoid duplicates const styleSheet = this.renderer.createElement('style'); styleSheet.id = 'fadeInKeyframes'; this.renderer.setProperty(styleSheet, 'innerHTML', ` @keyframes fadeIn { from { opacity: 0; transform: translateY(-5px); } to { opacity: 1; transform: translateY(0); } } `); this.renderer.appendChild(document.head, styleSheet); } handleMouseOver(event) { const target = event.target; if (target === this.el.nativeElement) { let currentText = this.element.innerText; // Remove truncateSuffix only if it exists at the end if (currentText.endsWith(this.truncateSuffix)) { currentText = currentText.slice(0, -this.truncateSuffix.length); } if (currentText.length < this.fullText.length && this.showTooltip) { this.createTooltip(); } } } handleMouseOut(event) { this.removeTooltip(); } // Unsubscribe when the directive is destroyed ngOnDestroy() { this.removeTooltip(); this.destroy$.next(); this.destroy$.complete(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: MTruncateDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1.MTruncateService }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.1", type: MTruncateDirective, isStandalone: true, selector: "[mTruncate]", inputs: { showTooltip: "showTooltip", truncateLines: "truncateLines", maxTruncateWidth: "maxTruncateWidth", maxTooltipWidth: "maxTooltipWidth", bgColor: "bgColor", color: "color", tooltipPosition: "tooltipPosition", tooltipDirection: "tooltipDirection", truncateSuffix: "truncateSuffix", id: "id", truncateChar: "truncateChar", resize: "resize", textChange: "textChange" }, host: { listeners: { "mouseenter": "handleMouseOver($event)", "mouseleave": "handleMouseOut()" } }, usesOnChanges: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: MTruncateDirective, decorators: [{ type: Directive, args: [{ selector: '[mTruncate]', standalone: true, }] }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i1.MTruncateService }], propDecorators: { showTooltip: [{ type: Input }], truncateLines: [{ type: Input }], maxTruncateWidth: [{ type: Input }], maxTooltipWidth: [{ type: Input }], bgColor: [{ type: Input }], color: [{ type: Input }], tooltipPosition: [{ type: Input }], tooltipDirection: [{ type: Input }], truncateSuffix: [{ type: Input }], id: [{ type: Input }], truncateChar: [{ type: Input }], resize: [{ type: Input }], textChange: [{ type: Input }], handleMouseOver: [{ type: HostListener, args: ['mouseenter', ['$event']] }], handleMouseOut: [{ type: HostListener, args: ['mouseleave'] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibS10cnVuY2F0ZS5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9tLXRydW5jYXRlL3NyYy9saWIvbS10cnVuY2F0ZS5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFJVCxLQUFLLEVBQ0wsWUFBWSxHQUViLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxNQUFNLENBQUM7OztBQU9uRSxNQUFNLE9BQU8sa0JBQWtCO0lBb0M3QixZQUNVLEVBQWMsRUFDZCxRQUFtQixFQUNuQixnQkFBa0M7UUFGbEMsT0FBRSxHQUFGLEVBQUUsQ0FBWTtRQUNkLGFBQVEsR0FBUixRQUFRLENBQVc7UUFDbkIscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFrQjtRQXRDNUMsc0RBQXNEO1FBQzdDLGdCQUFXLEdBQVksSUFBSSxDQUFDO1FBQ3JDLDhDQUE4QztRQUNyQyxrQkFBYSxHQUFXLENBQUMsQ0FBQztRQUNuQyxtQ0FBbUM7UUFDMUIscUJBQWdCLEdBQVcsQ0FBQyxDQUFDO1FBQ3RDLGdDQUFnQztRQUN2QixvQkFBZSxHQUFXLENBQUMsQ0FBQztRQUNyQyxzQ0FBc0M7UUFDN0IsWUFBTyxHQUFXLE1BQU0sQ0FBQztRQUNsQyxnQ0FBZ0M7UUFDdkIsVUFBSyxHQUFXLFNBQVMsQ0FBQztRQUNuQyxrREFBa0Q7UUFDekMsb0JBQWUsR0FBVyxLQUFLLENBQUM7UUFDekMsZ0NBQWdDO1FBQ3ZCLHFCQUFnQixHQUFXLEtBQUssQ0FBQztRQUMxQyw4Q0FBOEM7UUFDckMsbUJBQWMsR0FBVyxLQUFLLENBQUM7UUFDeEMsaUNBQWlDO1FBQ3hCLE9BQUUsR0FBVyxLQUFLLENBQUM7UUFDNUIscURBQXFEO1FBQzVDLGlCQUFZLEdBQVcsQ0FBQyxDQUFDO1FBUTFCLGFBQVEsR0FBVyxF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QWxCLGtCQUFrQjs7MkZBQWxCLGtCQUFrQjtrQkFKOUIsU0FBUzttQkFBQztvQkFDVCxRQUFRLEVBQUUsYUFBYTtvQkFDdkIsVUFBVSxFQUFFLElBQUk7aUJBQ2pCO3NJQUdVLFdBQVc7c0JBQW5CLEtBQUs7Z0JBRUcsYUFBYTtzQkFBckIsS0FBSztnQkFFRyxnQkFBZ0I7c0JBQXhCLEtBQUs7Z0JBRUcsZUFBZTtzQkFBdkIsS0FBSztnQkFFRyxPQUFPO3NCQUFmLEtBQUs7Z0JBRUcsS0FBSztzQkFBYixLQUFLO2dCQUVHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBRUcsZ0JBQWdCO3NCQUF4QixLQUFLO2dCQUVHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBRUcsRUFBRTtzQkFBVixLQUFLO2dCQUVHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBRUcsTUFBTTtzQkFBZCxLQUFLO2dCQUdHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBMFlOLGVBQWU7c0JBRGQsWUFBWTt1QkFBQyxZQUFZLEVBQUUsQ0FBQyxRQUFRLENBQUM7Z0JBbUJ0QyxjQUFjO3NCQURiLFlBQVk7dUJBQUMsWUFBWSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgRGlyZWN0aXZlLFxyXG4gIEVsZW1lbnRSZWYsXHJcbiAgQWZ0ZXJWaWV3SW5pdCxcclxuICBSZW5kZXJlcjIsXHJcbiAgSW5wdXQsXHJcbiAgSG9zdExpc3RlbmVyLFxyXG4gIFNpbXBsZUNoYW5nZXMsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgZnJvbUV2ZW50LCBTdWJqZWN0LCB0YWtlVW50aWwgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgTVRydW5jYXRlU2VydmljZSB9IGZyb20gJy4vbS10cnVuY2F0ZS5zZXJ2aWNlJztcclxuXHJcbkBEaXJlY3RpdmUoe1xyXG4gIHNlbGVjdG9yOiAnW21UcnVuY2F0ZV0nLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBNVHJ1bmNhdGVEaXJlY3RpdmUgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0IHtcclxuICAvKiogV2hldGhlciB0byBzaG93IHRvb2x0aXAgb24gdHJ1bmNhdGVkIHRleHQgaG92ZXIgKi9cclxuICBASW5wdXQoKSBzaG93VG9vbHRpcDogYm9vbGVhbiA9IHRydWU7XHJcbiAgLyoqIE51bWJlciBvZiBsaW5lcyB0byB0cnVuY2F0ZSB0aGUgdGV4dCB0byAqL1xyXG4gIEBJbnB1dCgpIHRydW5jYXRlTGluZXM6IG51bWJlciA9IDA7XHJcbiAgLyoqIE1heGltdW0gd2lkdGggZm9yIHRydW5jYXRpb24gKi9cclxuICBASW5wdXQoKSBtYXhUcnVuY2F0ZVdpZHRoOiBudW1iZXIgPSAwO1xyXG4gIC8qKiBNYXhpbXVtIHdpZHRoIGZvciB0b29sdGlwICovXHJcbiAgQElucHV0KCkgbWF4VG9vbHRpcFdpZHRoOiBudW1iZXIgPSAwO1xyXG4gIC8qKiBCYWNrZ3JvdW5kIGNvbG9yIG9mIHRoZSB0b29sdGlwICovXHJcbiAgQElucHV0KCkgYmdDb2xvcjogc3RyaW5nID0gJyNmZmYnO1xyXG4gIC8qKiBUZXh0IGNvbG9yIG9mIHRoZSB0b29sdGlwICovXHJcbiAgQElucHV0KCkgY29sb3I6IHN0cmluZyA9ICcjMWMxYzI4JztcclxuICAvKiogVG9vbHRpcCBwb3NpdGlvbiAodG9wLCBib3R0b20sIGxlZnQsIHJpZ2h0KSAqL1xyXG4gIEBJbnB1dCgpIHRvb2x0aXBQb3NpdGlvbjogc3RyaW5nID0gJ3RvcCc7XHJcbiAgLyoqIFRleHQgZGlyZWN0aW9uIChMVFIsIFJUTCkgKi9cclxuICBASW5wdXQoKSB0b29sdGlwRGlyZWN0aW9uOiBzdHJpbmcgPSAnbHRyJztcclxuICAvKiogU3VmZml4IHRvIGFwcGVuZCB3aGVuIHRleHQgaXMgdHJ1bmNhdGVkICovXHJcbiAgQElucHV0KCkgdHJ1bmNhdGVTdWZmaXg6IHN0cmluZyA9ICcuLi4nO1xyXG4gIC8qKiBJRCBmb3IgdGhlIHRvb2x0aXAgZWxlbWVudCAqL1xyXG4gIEBJbnB1dCgpIGlkOiBzdHJpbmcgPSAnbUlkJztcclxuICAvKiogTWF4aW11bSBudW1iZXIgb2YgY2hhcmFjdGVycyBiZWZvcmUgdHJ1bmNhdGlvbiAqL1xyXG4gIEBJbnB1dCgpIHRydW5jYXRlQ2hhcjogbnVtYmVyID0gMDtcclxuICAvKiogV2hldGhlciB0byByZXNpemUgdGhlIHRydW5jYXRlZCBvbiByZXNpemUgKi9cclxuICBASW5wdXQoKSByZXNpemUhOiBCb29sZWFuO1xyXG5cclxuICAvKiogdG8gZGV0ZWN0IHRoYXQgdGhlIHRleHQgd2hlbiBjaGFuZ2UgKi9cclxuICBASW5wdXQoKSB0ZXh0Q2hhbmdlITogc3RyaW5nO1xyXG5cclxuICBlbGVtZW50ITogSFRNTEVsZW1lbnQ7XHJcbiAgcHJpdmF0ZSBmdWxsVGV4dDogc3RyaW5nID0gJyc7XHJcbiAgcHJpdmF0ZSB0b29sdGlwOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xyXG4gIHByaXZhdGUgdG9vbHRpcEFycm93OiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xyXG5cclxuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcclxuXHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBwcml2YXRlIGVsOiBFbGVtZW50UmVmLFxyXG4gICAgcHJpdmF0ZSByZW5kZXJlcjogUmVuZGVyZXIyLFxyXG4gICAgcHJpdmF0ZSBtVHJ1bmNhdGVTZXJ2aWNlOiBNVHJ1bmNhdGVTZXJ2aWNlXHJcbiAgKSB7fVxyXG5cclxuICBuZ0FmdGVyVmlld0luaXQoKSB7XHJcbiAgICB0aGlzLmVsZW1lbnQgPSB0aGlzLmVsLm5hdGl2ZUVsZW1lbnQ7XHJcbiAgICB0aGlzLmZ1bGxUZXh0ID0gdGhpcy5lbC5uYXRpdmVFbGVtZW50LmlubmVyVGV4dC50cmltKCk7XHJcblxyXG4gICAgdGhpcy50b29sdGlwRGlyZWN0aW9uID0gdGhpcy5tVHJ1bmNhdGVTZXJ2aWNlLmdldERpcmVjdGlvbigpO1xyXG4gICAgaWYgKCF0aGlzLmZ1bGxUZXh0IHx8IHRoaXMuZnVsbFRleHQudHJpbSgpLmxlbmd0aCA8PSAzKSByZXR1cm47XHJcblxyXG4gICAgZnJvbUV2ZW50KHdpbmRvdywgJ3Jlc2l6ZScpXHJcbiAgICAgIC5waXBlKGRlYm91bmNlVGltZSg1MDApLCB0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpXHJcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gKHRoaXMucmVzaXplID8gdGhpcy5vblJlc2l6ZSgpIDogJycpKTtcclxuXHJcbiAgICB0aGlzLnRydW5jYXRlTWV0aG9kKCk7XHJcbiAgfVxyXG5cclxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XHJcbiAgICBpZiAoY2hhbmdlc1sndHJ1bmNhdGVDaGFyJ10pIHtcclxuICAgICAgdGhpcy50cnVuY2F0ZU1ldGhvZCgpO1xyXG4gICAgfVxyXG4gICAgaWYgKGNoYW5nZXNbJ3RydW5jYXRlTGluZXMnXSkge1xyXG4gICAgICB0aGlzLnRydW5jYXRlTWV0aG9kKCk7XHJcbiAgICB9XHJcbiAgICBpZiAoY2hhbmdlc1snbWF4VHJ1bmNhdGVXaWR0aCddKSB7XHJcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgIHRoaXMudHJ1bmNhdGVNZXRob2QoKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBpZiAoY2hhbmdlc1sndGV4dENoYW5nZSddKSB7XHJcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgIHRoaXMuZnVsbFRleHQgPSB0aGlzLnRleHRDaGFuZ2U7XHJcbiAgICAgICAgdGhpcy50cnVuY2F0ZU1ldGhvZCgpO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRydW5jYXRlTWV0aG9kKCkge1xyXG4gICAgaWYgKHRoaXMudHJ1bmNhdGVDaGFyID4gMCkge1xyXG4gICAgICB0aGlzLnRydW5jYXRlQnlDaGFyKCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBpZiAodGhpcy50cnVuY2F0ZUxpbmVzID4gMSkge1xyXG4gICAgICAgIHRoaXMuYXBwbHlSb3dzVHJ1bmNhdGUoKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLmFwcGx5VHJ1bmNhdGUoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB0cnVuY2F0ZUJ5Q2hhcigpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHRoaXMuZnVsbFRleHQubGVuZ3RoIDw9IHRoaXMudHJ1bmNhdGVDaGFyXHJcbiAgICAgID8gdGhpcy5mdWxsVGV4dFxyXG4gICAgICA6ICh0aGlzLmVsZW1lbnQuaW5uZXJUZXh0ID1cclxuICAgICAgICAgIHRoaXMuZnVsbFRleHQuc2xpY2UoMCwgdGhpcy50cnVuY2F0ZUNoYXIpICsgdGhpcy50cnVuY2F0ZVN1ZmZpeCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGFwcGx5VHJ1bmNhdGUoKSB7XHJcbiAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5lbC5uYXRpdmVFbGVtZW50O1xyXG4gICAgZWxlbWVudC5pbm5lclRleHQgPSB0aGlzLmZ1bGxUZXh0OyAvLyBSZXNldCB0byBmdWxsIHRleHRcclxuICAgIGlmICh0aGlzLm1heFRydW5jYXRlV2lkdGgpIHtcclxuICAgICAgZWxlbWVudC5zdHlsZS5tYXhXaWR0aCA9IHRoaXMubWF4VHJ1bmNhdGVXaWR0aCArICdweCc7XHJcbiAgICB9XHJcbiAgICBjb25zdCBtYXhXaWR0aCA9IGVsZW1lbnQuY2xpZW50V2lkdGg7IC8vIEdldCBhdmFpbGFibGUgd2lkdGhcclxuXHJcbiAgICBlbGVtZW50LnN0eWxlLnRleHRXcmFwID0gJ25vd3JhcCc7XHJcbiAgICBlbGVtZW50LnN0eWxlLndvcmRCcmVhayA9ICdicmVhay13b3JkJztcclxuICAgIGxldCBsZWZ0ID0gMDtcclxuICAgIGxldCByaWdodCA9IHRoaXMuZnVsbFRleHQubGVuZ3RoO1xyXG4gICAgbGV0IHRydW5jYXRlZFRleHQgPSB0aGlzLmZ1bGxUZXh0O1xyXG5cclxuICAgIGlmIChlbGVtZW50LnNjcm9sbFdpZHRoICE9IG1heFdpZHRoKSB7XHJcbiAgICAgIHdoaWxlIChsZWZ0IDw9IHJpZ2h0KSB7XHJcbiAgICAgICAgbGV0IG1pZCA9IE1hdGguZmxvb3IoKGxlZnQgKyByaWdodCkgLyAyKTtcclxuICAgICAgICBlbGVtZW50LmlubmVyVGV4dCA9XHJcbiAgICAgICAgICB0aGlzLmZ1bGxUZXh0LnN1YnN0cmluZygwLCBtaWQpICsgdGhpcy50cnVuY2F0ZVN1ZmZpeDtcclxuXHJcbiAgICAgICAgaWYgKGVsZW1lbnQuc2Nyb2xsV2lkdGggPiBtYXhXaWR0aCkge1xyXG4gICAgICAgICAgcmlnaHQgPSBtaWQgLSAxOyAvLyBUb28gbG9uZywgcmVkdWNlIHNpemVcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgbGVmdCA9IG1pZCArIDE7IC8vIFRvbyBzaG9ydCwgaW5jcmVhc2Ugc2l6ZVxyXG4gICAgICAgICAgdHJ1bmNhdGVkVGV4dCA9IHRoaXMuZnVsbFRleHQuc3Vic3RyaW5nKDAsIG1pZCkgKyB0aGlzLnRydW5jYXRlU3VmZml4O1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGVsZW1lbnQuaW5uZXJUZXh0ID0gdHJ1bmNhdGVkVGV4dDsgLy8gU2V0IGZpbmFsIHRydW5jYXRlZCB0ZXh0XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGFwcGx5Um93c1RydW5jYXRlKCkge1xyXG4gICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZWwubmF0aXZlRWxlbWVudDtcclxuICAgIGVsZW1lbnQuaW5uZXJUZXh0ID0gdGhpcy5mdWxsVGV4dDsgLy8gUmVzZXQgdG8gZnVsbCB0ZXh0XHJcblxyXG4gICAgY29uc3QgbGluZUhlaWdodCA9IHBhcnNlRmxvYXQod2luZG93LmdldENvbXB1dGVkU3R5bGUoZWxlbWVudCkubGluZUhlaWdodCk7XHJcblxyXG4gICAgY29uc3QgbWF4SGVpZ2h0ID0gbGluZUhlaWdodCAqIHRoaXMudHJ1bmNhdGVMaW5lcztcclxuXHJcbiAgICBpZiAoZWxlbWVudC5zY3JvbGxIZWlnaHQgPiBtYXhIZWlnaHQpIHtcclxuICAgICAgbGV0IGxlZnQgPSAwO1xyXG4gICAgICBsZXQgcmlnaHQgPSB0aGlzLmZ1bGxUZXh0Lmxlbmd0aDtcclxuICAgICAgbGV0IHRydW5jYXRlZFRleHQgPSB0aGlzLmZ1bGxUZXh0O1xyXG5cclxuICAgICAgd2hpbGUgKGxlZnQgPD0gcmlnaHQpIHtcclxuICAgICAgICBsZXQgbWlkID0gTWF0aC5mbG9vcigobGVmdCArIHJpZ2h0KSAvIDIpO1xyXG4gICAgICAgIGVsZW1lbnQuaW5uZXJUZXh0ID1cclxuICAgICAgICAgIHRoaXMuZnVsbFRleHQuc3Vic3RyaW5nKDAsIG1pZCkgKyB0aGlzLnRydW5jYXRlU3VmZml4O1xyXG5cclxuICAgICAgICBpZiAoZWxlbWVudC5zY3JvbGxIZWlnaHQgPiBtYXhIZWlnaHQpIHtcclxuICAgICAgICAgIHJpZ2h0ID0gbWlkIC0gMTsgLy8gVG9vIGxvbmcsIHJlZHVjZSB0ZXh0XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGxlZnQgPSBtaWQgKyAxOyAvLyBUb28gc2hvcnQsIGluY3JlYXNlIHRleHRcclxuICAgICAgICAgIHRydW5jYXRlZFRleHQgPSB0aGlzLmZ1bGxUZXh0LnN1YnN0cmluZygwLCBtaWQpICsgdGhpcy50cnVuY2F0ZVN1ZmZpeDtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGVsZW1lbnQuaW5uZXJUZXh0ID0gdHJ1bmNhdGVkVGV4dDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGdldFRvb2x0aXBEaXJlY3Rpb24oZGlyOiBzdHJpbmcpIHtcclxuICAgIHRoaXMudG9vbHRpcERpcmVjdGlvbiA9IGRpcjtcclxuICB9XHJcblxyXG4gIG9uUmVzaXplKCkge1xyXG4gICAgaWYgKHRoaXMudHJ1bmNhdGVDaGFyID4gMCkge1xyXG4gICAgICB0aGlzLnRydW5jYXRlQnlDaGFyKCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBpZiAodGhpcy50cnVuY2F0ZUxpbmVzID4gMSkge1xyXG4gICAgICAgIHRoaXMuYXBwbHlSb3dzVHJ1bmNhdGUoKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLmFwcGx5VHJ1bmNhdGUoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBjcmVhdGVUb29sdGlwKCkge1xyXG4gICAgaWYgKHRoaXMudG9vbHRpcCkgcmV0dXJuOyAvLyBBdm9pZCBjcmVhdGluZyBtdWx0aXBsZSB0b29sdGlwc1xyXG5cclxuICAgIGxldCBtYXhXaWR0aCA9IHRoaXMuZWwubmF0aXZlRWxlbWVudC5jbGllbnRXaWR0aDtcclxuXHJcbiAgICB0aGlzLnRvb2x0aXAgPSB0aGlzLnJlbmRlcmVyLmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgdGhpcy50b29sdGlwPy5jbGFzc0xpc3QuYWRkKCdtVG9vbHRpcCcpO1xyXG4gICAgdGhpcy50b29sdGlwPy5zZXRBdHRyaWJ1dGUoJ2lkJywgdGhpcy5pZCk7XHJcblxyXG4gICAgdGhpcy5yZW5kZXJlci5hcHBlbmRDaGlsZChkb2N1bWVudC5ib2R5LCB0aGlzLnRvb2x0aXApO1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRQcm9wZXJ0eSh0aGlzLnRvb2x0aXAsICdpbm5lclRleHQnLCB0aGlzLmZ1bGxUZXh0KTtcclxuXHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcCwgJ29wYWNpdHknLCAnMCcpOyAvLyBTdGFydCBoaWRkZW5cclxuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUoXHJcbiAgICAgIHRoaXMudG9vbHRpcCxcclxuICAgICAgJ2FuaW1hdGlvbicsXHJcbiAgICAgICdmYWRlSW4gMC4zNXMgZWFzZS1vdXQgZm9yd2FyZHMnXHJcbiAgICApOyAvLyBBcHBseSBhbmltYXRpb25cclxuXHJcbiAgICAvLyBBcHBseSBzdHlsZXNcclxuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy50b29sdGlwLCAncG9zaXRpb24nLCAnZml4ZWQnKTtcclxuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy50b29sdGlwLCAnYmFja2dyb3VuZCcsIHRoaXMuYmdDb2xvcik7XHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcCwgJ2NvbG9yJywgdGhpcy5jb2xvcik7XHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcCwgJ3doaXRlU3BhY2UnLCAncHJlLXdyYXAnKTsgLy8gQWxsb3dzIG11bHRpLWxpbmUgdGV4dFxyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXAsICd3b3JkV3JhcCcsICdicmVhay13b3JkJyk7IC8vIFdyYXAgbG9uZyB3b3Jkc1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXAsICdkaXJlY3Rpb24nLCB0aGlzLnRvb2x0aXBEaXJlY3Rpb24pOyAvLyBkaXJlY3Rpb25cclxuXHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKFxyXG4gICAgICB0aGlzLnRvb2x0aXAsXHJcbiAgICAgICdib3gtc2hhZG93JyxcclxuICAgICAgJzBweCA0cHggMTVweCAwcHggcmdiYSgwLCAwLCAwLCAwLjIpJ1xyXG4gICAgKTtcclxuXHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcCwgJ3dpZHRoJywgJ2ZpdC1jb250ZW50Jyk7XHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKFxyXG4gICAgICB0aGlzLnRvb2x0aXAsXHJcbiAgICAgICdtYXgtd2lkdGgnLFxyXG4gICAgICB0aGlzLm1heFRvb2x0aXBXaWR0aCA/IHRoaXMubWF4VG9vbHRpcFdpZHRoICsgJ3B4JyA6IG1heFdpZHRoICsgJ3B4J1xyXG4gICAgKTtcclxuXHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcCwgJ3RleHRPdmVyZmxvdycsICdlbGxpcHNpcycpO1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXAsICdwYWRkaW5nJywgJzEwcHgnKTtcclxuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy50b29sdGlwLCAnYm9yZGVyUmFkaXVzJywgJzZweCcpO1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXAsICdmb250U2l6ZScsICcxNHB4Jyk7XHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcCwgJ3pJbmRleCcsICc5OTk5OTk5OTk5OTk5OTknKTtcclxuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy50b29sdGlwLCAncG9pbnRlckV2ZW50cycsICdub25lJyk7IC8vIFByZXZlbnQgaW50ZXJmZXJlbmNlXHJcblxyXG4gICAgLy8gVG9vbHRpcCBBcnJvd1xyXG4gICAgdGhpcy50b29sdGlwQXJyb3cgPSB0aGlzLnJlbmRlcmVyLmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG4gICAgdGhpcy50b29sdGlwQXJyb3c/LmNsYXNzTGlzdC5hZGQoJ21Ub29sdGlwQXJyb3cnKTtcclxuXHJcbiAgICB0aGlzLnJlbmRlcmVyLmFwcGVuZENoaWxkKHRoaXMudG9vbHRpcCwgdGhpcy50b29sdGlwQXJyb3cpO1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXBBcnJvdywgJ3Bvc2l0aW9uJywgJ2Fic29sdXRlJyk7XHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcEFycm93LCAnd2lkdGgnLCAnMCcpO1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXBBcnJvdywgJ2hlaWdodCcsICcwJyk7XHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcEFycm93LCAnYm9yZGVyU3R5bGUnLCAnc29saWQnKTtcclxuXHJcbiAgICB0aGlzLnBvc2l0aW9uVG9vbHRpcCgpO1xyXG5cclxuICAgIC8vIEFuaW1hdGlvblxyXG4gICAgdGhpcy5hZGRLZXlmcmFtZXMoKTtcclxuICB9XHJcbiAgcHJpdmF0ZSByZW1vdmVUb29sdGlwKCkge1xyXG4gICAgaWYgKHRoaXMudG9vbHRpcCkge1xyXG4gICAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKFxyXG4gICAgICAgIHRoaXMudG9vbHRpcCxcclxuICAgICAgICAnYW5pbWF0aW9uJyxcclxuICAgICAgICAnZmFkZU91dCAwLjVzIGVhc2Utb3V0IGZvcndhcmRzJ1xyXG4gICAgICApO1xyXG5cclxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgdGhpcy5yZW5kZXJlci5yZW1vdmVDaGlsZChkb2N1bWVudC5ib2R5LCB0aGlzLnRvb2x0aXApO1xyXG4gICAgICAgIHRoaXMudG9vbHRpcCA9IG51bGw7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBwb3NpdGlvblRvb2x0aXAoKSB7XHJcbiAgICBpZiAoIXRoaXMudG9vbHRpcCkgcmV0dXJuO1xyXG5cclxuICAgIGNvbnN0IHJlY3QgPSB0aGlzLmVsLm5hdGl2ZUVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICBjb25zdCB0b29sdGlwUmVjdCA9IHRoaXMudG9vbHRpcC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuXHJcbiAgICBsZXQgdG9wID0gMCxcclxuICAgICAgbGVmdCA9IDA7XHJcblxyXG4gICAgc3dpdGNoICh0aGlzLnRvb2x0aXBQb3NpdGlvbikge1xyXG4gICAgICBjYXNlICd0b3AnOlxyXG4gICAgICAgIHRvcCA9IHJlY3QudG9wIC0gdG9vbHRpcFJlY3QuaGVpZ2h0IC0gNTtcclxuICAgICAgICBsZWZ0ID0gcmVjdC5sZWZ0ICsgKHJlY3Qud2lkdGggLSB0b29sdGlwUmVjdC53aWR0aCkgLyAyO1xyXG4gICAgICAgIGlmICh0b3AgPCAwKSB7XHJcbiAgICAgICAgICB0b3AgPSByZWN0LmJvdHRvbSArIDU7IC8vIE1vdmUgYmVsb3cgaWYgbm90IGVub3VnaCBzcGFjZVxyXG4gICAgICAgICAgdGhpcy5hcnJvd1Bvc2l0aW9uVXAoKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gQXJyb3cgcG9pbnRpbmcgKipkb3duKiogKHBsYWNlZCBhdCBib3R0b20pXHJcbiAgICAgICAgICB0aGlzLmFycm93UG9zaXRpb25Eb3duKCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBicmVhaztcclxuXHJcbiAgICAgIGNhc2UgJ2JvdHRvbSc6XHJcbiAgICAgICAgdG9wID0gcmVjdC5ib3R0b20gKyA1O1xyXG4gICAgICAgIGxlZnQgPSByZWN0LmxlZnQgKyAocmVjdC53aWR0aCAtIHRvb2x0aXBSZWN0LndpZHRoKSAvIDI7XHJcbiAgICAgICAgaWYgKHRvcCArIHRvb2x0aXBSZWN0LmhlaWdodCA+IHdpbmRvdy5pbm5lckhlaWdodCkge1xyXG4gICAgICAgICAgdG9wID0gcmVjdC50b3AgLSB0b29sdGlwUmVjdC5oZWlnaHQgLSA1O1xyXG4gICAgICAgICAgdGhpcy5hcnJvd1Bvc2l0aW9uRG93bigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBBcnJvdyBwb2ludGluZyAqKnVwKiogKHBsYWNlZCBhdCB0b3ApXHJcbiAgICAgICAgICB0aGlzLmFycm93UG9zaXRpb25VcCgpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICBjYXNlICdpbnNldC1pbmxpbmUtc3RhcnQnOlxyXG4gICAgICBjYXNlICdyaWdodCc6XHJcbiAgICAgICAgdG9wID0gcmVjdC50b3AgKyAocmVjdC5oZWlnaHQgLSB0b29sdGlwUmVjdC5oZWlnaHQpIC8gMjtcclxuICAgICAgICBsZWZ0ID0gcmVjdC5sZWZ0IC0gdG9vbHRpcFJlY3Qud2lkdGggLSA1O1xyXG4gICAgICAgIGlmIChsZWZ0IDwgMCkge1xyXG4gICAgICAgICAgbGVmdCA9IHJlY3QucmlnaHQgKyA1OyAvLyBNb3ZlIHRvIHRoZSByaWdodCBpZiBub3QgZW5vdWdoIHNwYWNlXHJcbiAgICAgICAgICB0aGlzLmFycm93UG9zaXRpb25MZWZ0KCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRoaXMuYXJyb3dQb3NpdGlvblJpZ2h0KCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBBcnJvdyBwb2ludGluZyAqKnJpZ2h0KiogKHBsYWNlZCBhdCBlbmQpXHJcblxyXG4gICAgICAgIGJyZWFrO1xyXG5cclxuICAgICAgY2FzZSAnaW5zZXQtaW5saW5lLWVuZCc6XHJcbiAgICAgIGNhc2UgJ2xlZnQnOlxyXG4gICAgICAgIHRvcCA9IHJlY3QudG9wICsgKHJlY3QuaGVpZ2h0IC0gdG9vbHRpcFJlY3QuaGVpZ2h0KSAvIDI7XHJcbiAgICAgIC