UNPKG

m-truncate

Version:

`mTruncate` is a lightweight and customizable Angular directive for truncating text with support for tooltips. It allows you to truncate text based on width or a specified number of lines and display a tooltip when the full text is not visible.

390 lines 56.5 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']) { this.fullText = this.textChange; setTimeout(() => { this.truncateMethod(); }); } } truncateMethod() { setTimeout(() => { if (this.truncateChar > 0) { this.truncateByChar(); } else { if (this.truncateLines > 1) { this.applyRowsTruncate(); } else { setTimeout(() => { 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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QyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUMzQixDQUFDOzhHQW5jVSxrQkFBa0I7a0dBQWxCLGtCQUFrQjs7MkZBQWxCLGtCQUFrQjtrQkFKOUIsU0FBUzttQkFBQztvQkFDVCxRQUFRLEVBQUUsYUFBYTtvQkFDdkIsVUFBVSxFQUFFLElBQUk7aUJBQ2pCO3NJQUdVLFdBQVc7c0JBQW5CLEtBQUs7Z0JBRUcsYUFBYTtzQkFBckIsS0FBSztnQkFFRyxnQkFBZ0I7c0JBQXhCLEtBQUs7Z0JBRUcsZUFBZTtzQkFBdkIsS0FBSztnQkFFRyxPQUFPO3NCQUFmLEtBQUs7Z0JBRUcsS0FBSztzQkFBYixLQUFLO2dCQUVHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBRUcsZ0JBQWdCO3NCQUF4QixLQUFLO2dCQUVHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBRUcsRUFBRTtzQkFBVixLQUFLO2dCQUVHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBRUcsTUFBTTtzQkFBZCxLQUFLO2dCQUdHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBNllOLGVBQWU7c0JBRGQsWUFBWTt1QkFBQyxZQUFZLEVBQUUsQ0FBQyxRQUFRLENBQUM7Z0JBbUJ0QyxjQUFjO3NCQURiLFlBQVk7dUJBQUMsWUFBWSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgRGlyZWN0aXZlLFxyXG4gIEVsZW1lbnRSZWYsXHJcbiAgQWZ0ZXJWaWV3SW5pdCxcclxuICBSZW5kZXJlcjIsXHJcbiAgSW5wdXQsXHJcbiAgSG9zdExpc3RlbmVyLFxyXG4gIFNpbXBsZUNoYW5nZXMsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgZnJvbUV2ZW50LCBTdWJqZWN0LCB0YWtlVW50aWwgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgTVRydW5jYXRlU2VydmljZSB9IGZyb20gJy4vbS10cnVuY2F0ZS5zZXJ2aWNlJztcclxuXHJcbkBEaXJlY3RpdmUoe1xyXG4gIHNlbGVjdG9yOiAnW21UcnVuY2F0ZV0nLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBNVHJ1bmNhdGVEaXJlY3RpdmUgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0IHtcclxuICAvKiogV2hldGhlciB0byBzaG93IHRvb2x0aXAgb24gdHJ1bmNhdGVkIHRleHQgaG92ZXIgKi9cclxuICBASW5wdXQoKSBzaG93VG9vbHRpcDogYm9vbGVhbiA9IHRydWU7XHJcbiAgLyoqIE51bWJlciBvZiBsaW5lcyB0byB0cnVuY2F0ZSB0aGUgdGV4dCB0byAqL1xyXG4gIEBJbnB1dCgpIHRydW5jYXRlTGluZXM6IG51bWJlciA9IDA7XHJcbiAgLyoqIE1heGltdW0gd2lkdGggZm9yIHRydW5jYXRpb24gKi9cclxuICBASW5wdXQoKSBtYXhUcnVuY2F0ZVdpZHRoOiBudW1iZXIgPSAwO1xyXG4gIC8qKiBNYXhpbXVtIHdpZHRoIGZvciB0b29sdGlwICovXHJcbiAgQElucHV0KCkgbWF4VG9vbHRpcFdpZHRoOiBudW1iZXIgPSAwO1xyXG4gIC8qKiBCYWNrZ3JvdW5kIGNvbG9yIG9mIHRoZSB0b29sdGlwICovXHJcbiAgQElucHV0KCkgYmdDb2xvcjogc3RyaW5nID0gJyNmZmYnO1xyXG4gIC8qKiBUZXh0IGNvbG9yIG9mIHRoZSB0b29sdGlwICovXHJcbiAgQElucHV0KCkgY29sb3I6IHN0cmluZyA9ICcjMWMxYzI4JztcclxuICAvKiogVG9vbHRpcCBwb3NpdGlvbiAodG9wLCBib3R0b20sIGxlZnQsIHJpZ2h0KSAqL1xyXG4gIEBJbnB1dCgpIHRvb2x0aXBQb3NpdGlvbjogc3RyaW5nID0gJ3RvcCc7XHJcbiAgLyoqIFRleHQgZGlyZWN0aW9uIChMVFIsIFJUTCkgKi9cclxuICBASW5wdXQoKSB0b29sdGlwRGlyZWN0aW9uOiBzdHJpbmcgPSAnbHRyJztcclxuICAvKiogU3VmZml4IHRvIGFwcGVuZCB3aGVuIHRleHQgaXMgdHJ1bmNhdGVkICovXHJcbiAgQElucHV0KCkgdHJ1bmNhdGVTdWZmaXg6IHN0cmluZyA9ICcuLi4nO1xyXG4gIC8qKiBJRCBmb3IgdGhlIHRvb2x0aXAgZWxlbWVudCAqL1xyXG4gIEBJbnB1dCgpIGlkOiBzdHJpbmcgPSAnbUlkJztcclxuICAvKiogTWF4aW11bSBudW1iZXIgb2YgY2hhcmFjdGVycyBiZWZvcmUgdHJ1bmNhdGlvbiAqL1xyXG4gIEBJbnB1dCgpIHRydW5jYXRlQ2hhcjogbnVtYmVyID0gMDtcclxuICAvKiogV2hldGhlciB0byByZXNpemUgdGhlIHRydW5jYXRlZCBvbiByZXNpemUgKi9cclxuICBASW5wdXQoKSByZXNpemUhOiBCb29sZWFuO1xyXG5cclxuICAvKiogdG8gZGV0ZWN0IHRoYXQgdGhlIHRleHQgd2hlbiBjaGFuZ2UgKi9cclxuICBASW5wdXQoKSB0ZXh0Q2hhbmdlITogc3RyaW5nO1xyXG5cclxuICBlbGVtZW50ITogSFRNTEVsZW1lbnQ7XHJcbiAgcHJpdmF0ZSBmdWxsVGV4dDogc3RyaW5nID0gJyc7XHJcbiAgcHJpdmF0ZSB0b29sdGlwOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xyXG4gIHByaXZhdGUgdG9vbHRpcEFycm93OiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xyXG5cclxuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcclxuXHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBwcml2YXRlIGVsOiBFbGVtZW50UmVmLFxyXG4gICAgcHJpdmF0ZSByZW5kZXJlcjogUmVuZGVyZXIyLFxyXG4gICAgcHJpdmF0ZSBtVHJ1bmNhdGVTZXJ2aWNlOiBNVHJ1bmNhdGVTZXJ2aWNlXHJcbiAgKSB7fVxyXG5cclxuICBuZ0FmdGVyVmlld0luaXQoKSB7XHJcbiAgICB0aGlzLmVsZW1lbnQgPSB0aGlzLmVsLm5hdGl2ZUVsZW1lbnQ7XHJcbiAgICB0aGlzLmZ1bGxUZXh0ID0gdGhpcy5lbC5uYXRpdmVFbGVtZW50LmlubmVyVGV4dC50cmltKCk7XHJcblxyXG4gICAgdGhpcy50b29sdGlwRGlyZWN0aW9uID0gdGhpcy5tVHJ1bmNhdGVTZXJ2aWNlLmdldERpcmVjdGlvbigpO1xyXG4gICAgaWYgKCF0aGlzLmZ1bGxUZXh0IHx8IHRoaXMuZnVsbFRleHQudHJpbSgpLmxlbmd0aCA8PSAzKSByZXR1cm47XHJcblxyXG4gICAgZnJvbUV2ZW50KHdpbmRvdywgJ3Jlc2l6ZScpXHJcbiAgICAgIC5waXBlKGRlYm91bmNlVGltZSg1MDApLCB0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpXHJcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4gKHRoaXMucmVzaXplID8gdGhpcy5vblJlc2l6ZSgpIDogJycpKTtcclxuXHJcbiAgICB0aGlzLnRydW5jYXRlTWV0aG9kKCk7XHJcbiAgfVxyXG5cclxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XHJcbiAgICBpZiAoY2hhbmdlc1sndHJ1bmNhdGVDaGFyJ10pIHtcclxuICAgICAgdGhpcy50cnVuY2F0ZU1ldGhvZCgpO1xyXG4gICAgfVxyXG4gICAgaWYgKGNoYW5nZXNbJ3RydW5jYXRlTGluZXMnXSkge1xyXG4gICAgICB0aGlzLnRydW5jYXRlTWV0aG9kKCk7XHJcbiAgICB9XHJcbiAgICBpZiAoY2hhbmdlc1snbWF4VHJ1bmNhdGVXaWR0aCddKSB7XHJcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgIHRoaXMudHJ1bmNhdGVNZXRob2QoKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBpZiAoY2hhbmdlc1sndGV4dENoYW5nZSddKSB7XHJcbiAgICAgIHRoaXMuZnVsbFRleHQgPSB0aGlzLnRleHRDaGFuZ2U7XHJcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgIHRoaXMudHJ1bmNhdGVNZXRob2QoKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICB0cnVuY2F0ZU1ldGhvZCgpIHtcclxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICBpZiAodGhpcy50cnVuY2F0ZUNoYXIgPiAwKSB7XHJcbiAgICAgICAgdGhpcy50cnVuY2F0ZUJ5Q2hhcigpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGlmICh0aGlzLnRydW5jYXRlTGluZXMgPiAxKSB7XHJcbiAgICAgICAgICB0aGlzLmFwcGx5Um93c1RydW5jYXRlKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLmFwcGx5VHJ1bmNhdGUoKTtcclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfVxyXG4gIHByaXZhdGUgdHJ1bmNhdGVCeUNoYXIoKTogc3RyaW5nIHtcclxuICAgIHJldHVybiB0aGlzLmZ1bGxUZXh0Lmxlbmd0aCA8PSB0aGlzLnRydW5jYXRlQ2hhclxyXG4gICAgICA/IHRoaXMuZnVsbFRleHRcclxuICAgICAgOiAodGhpcy5lbGVtZW50LmlubmVyVGV4dCA9XHJcbiAgICAgICAgICB0aGlzLmZ1bGxUZXh0LnNsaWNlKDAsIHRoaXMudHJ1bmNhdGVDaGFyKSArIHRoaXMudHJ1bmNhdGVTdWZmaXgpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhcHBseVRydW5jYXRlKCkge1xyXG4gICAgY29uc3QgZWxlbWVudCA9IHRoaXMuZWwubmF0aXZlRWxlbWVudDtcclxuICAgIGVsZW1lbnQuaW5uZXJUZXh0ID0gdGhpcy5mdWxsVGV4dDsgLy8gUmVzZXQgdG8gZnVsbCB0ZXh0XHJcbiAgICBpZiAodGhpcy5tYXhUcnVuY2F0ZVdpZHRoKSB7XHJcbiAgICAgIGVsZW1lbnQuc3R5bGUubWF4V2lkdGggPSB0aGlzLm1heFRydW5jYXRlV2lkdGggKyAncHgnO1xyXG4gICAgfVxyXG4gICAgY29uc3QgbWF4V2lkdGggPSBlbGVtZW50LmNsaWVudFdpZHRoOyAvLyBHZXQgYXZhaWxhYmxlIHdpZHRoXHJcblxyXG4gICAgZWxlbWVudC5zdHlsZS50ZXh0V3JhcCA9ICdub3dyYXAnO1xyXG4gICAgZWxlbWVudC5zdHlsZS53b3JkQnJlYWsgPSAnYnJlYWstd29yZCc7XHJcbiAgICBsZXQgbGVmdCA9IDA7XHJcbiAgICBsZXQgcmlnaHQgPSB0aGlzLmZ1bGxUZXh0Lmxlbmd0aDtcclxuICAgIGxldCB0cnVuY2F0ZWRUZXh0ID0gdGhpcy5mdWxsVGV4dDtcclxuXHJcbiAgICBpZiAoZWxlbWVudC5zY3JvbGxXaWR0aCAhPSBtYXhXaWR0aCkge1xyXG4gICAgICB3aGlsZSAobGVmdCA8PSByaWdodCkge1xyXG4gICAgICAgIGxldCBtaWQgPSBNYXRoLmZsb29yKChsZWZ0ICsgcmlnaHQpIC8gMik7XHJcbiAgICAgICAgZWxlbWVudC5pbm5lclRleHQgPVxyXG4gICAgICAgICAgdGhpcy5mdWxsVGV4dC5zdWJzdHJpbmcoMCwgbWlkKSArIHRoaXMudHJ1bmNhdGVTdWZmaXg7XHJcblxyXG4gICAgICAgIGlmIChlbGVtZW50LnNjcm9sbFdpZHRoID4gbWF4V2lkdGgpIHtcclxuICAgICAgICAgIHJpZ2h0ID0gbWlkIC0gMTsgLy8gVG9vIGxvbmcsIHJlZHVjZSBzaXplXHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGxlZnQgPSBtaWQgKyAxOyAvLyBUb28gc2hvcnQsIGluY3JlYXNlIHNpemVcclxuICAgICAgICAgIHRydW5jYXRlZFRleHQgPSB0aGlzLmZ1bGxUZXh0LnN1YnN0cmluZygwLCBtaWQpICsgdGhpcy50cnVuY2F0ZVN1ZmZpeDtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBlbGVtZW50LmlubmVyVGV4dCA9IHRydW5jYXRlZFRleHQ7IC8vIFNldCBmaW5hbCB0cnVuY2F0ZWQgdGV4dFxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhcHBseVJvd3NUcnVuY2F0ZSgpIHtcclxuICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLmVsLm5hdGl2ZUVsZW1lbnQ7XHJcbiAgICBlbGVtZW50LmlubmVyVGV4dCA9IHRoaXMuZnVsbFRleHQ7IC8vIFJlc2V0IHRvIGZ1bGwgdGV4dFxyXG5cclxuICAgIGNvbnN0IGxpbmVIZWlnaHQgPSBwYXJzZUZsb2F0KHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsZW1lbnQpLmxpbmVIZWlnaHQpO1xyXG5cclxuICAgIGNvbnN0IG1heEhlaWdodCA9IGxpbmVIZWlnaHQgKiB0aGlzLnRydW5jYXRlTGluZXM7XHJcblxyXG4gICAgaWYgKGVsZW1lbnQuc2Nyb2xsSGVpZ2h0ID4gbWF4SGVpZ2h0KSB7XHJcbiAgICAgIGxldCBsZWZ0ID0gMDtcclxuICAgICAgbGV0IHJpZ2h0ID0gdGhpcy5mdWxsVGV4dC5sZW5ndGg7XHJcbiAgICAgIGxldCB0cnVuY2F0ZWRUZXh0ID0gdGhpcy5mdWxsVGV4dDtcclxuXHJcbiAgICAgIHdoaWxlIChsZWZ0IDw9IHJpZ2h0KSB7XHJcbiAgICAgICAgbGV0IG1pZCA9IE1hdGguZmxvb3IoKGxlZnQgKyByaWdodCkgLyAyKTtcclxuICAgICAgICBlbGVtZW50LmlubmVyVGV4dCA9XHJcbiAgICAgICAgICB0aGlzLmZ1bGxUZXh0LnN1YnN0cmluZygwLCBtaWQpICsgdGhpcy50cnVuY2F0ZVN1ZmZpeDtcclxuXHJcbiAgICAgICAgaWYgKGVsZW1lbnQuc2Nyb2xsSGVpZ2h0ID4gbWF4SGVpZ2h0KSB7XHJcbiAgICAgICAgICByaWdodCA9IG1pZCAtIDE7IC8vIFRvbyBsb25nLCByZWR1Y2UgdGV4dFxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBsZWZ0ID0gbWlkICsgMTsgLy8gVG9vIHNob3J0LCBpbmNyZWFzZSB0ZXh0XHJcbiAgICAgICAgICB0cnVuY2F0ZWRUZXh0ID0gdGhpcy5mdWxsVGV4dC5zdWJzdHJpbmcoMCwgbWlkKSArIHRoaXMudHJ1bmNhdGVTdWZmaXg7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBlbGVtZW50LmlubmVyVGV4dCA9IHRydW5jYXRlZFRleHQ7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXRUb29sdGlwRGlyZWN0aW9uKGRpcjogc3RyaW5nKSB7XHJcbiAgICB0aGlzLnRvb2x0aXBEaXJlY3Rpb24gPSBkaXI7XHJcbiAgfVxyXG5cclxuICBvblJlc2l6ZSgpIHtcclxuICAgIGlmICh0aGlzLnRydW5jYXRlQ2hhciA+IDApIHtcclxuICAgICAgdGhpcy50cnVuY2F0ZUJ5Q2hhcigpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgaWYgKHRoaXMudHJ1bmNhdGVMaW5lcyA+IDEpIHtcclxuICAgICAgICB0aGlzLmFwcGx5Um93c1RydW5jYXRlKCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhpcy5hcHBseVRydW5jYXRlKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgY3JlYXRlVG9vbHRpcCgpIHtcclxuICAgIGlmICh0aGlzLnRvb2x0aXApIHJldHVybjsgLy8gQXZvaWQgY3JlYXRpbmcgbXVsdGlwbGUgdG9vbHRpcHNcclxuXHJcbiAgICBsZXQgbWF4V2lkdGggPSB0aGlzLmVsLm5hdGl2ZUVsZW1lbnQuY2xpZW50V2lkdGg7XHJcblxyXG4gICAgdGhpcy50b29sdGlwID0gdGhpcy5yZW5kZXJlci5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuICAgIHRoaXMudG9vbHRpcD8uY2xhc3NMaXN0LmFkZCgnbVRvb2x0aXAnKTtcclxuICAgIHRoaXMudG9vbHRpcD8uc2V0QXR0cmlidXRlKCdpZCcsIHRoaXMuaWQpO1xyXG5cclxuICAgIHRoaXMucmVuZGVyZXIuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuYm9keSwgdGhpcy50b29sdGlwKTtcclxuICAgIHRoaXMucmVuZGVyZXIuc2V0UHJvcGVydHkodGhpcy50b29sdGlwLCAnaW5uZXJUZXh0JywgdGhpcy5mdWxsVGV4dCk7XHJcblxyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXAsICdvcGFjaXR5JywgJzAnKTsgLy8gU3RhcnQgaGlkZGVuXHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKFxyXG4gICAgICB0aGlzLnRvb2x0aXAsXHJcbiAgICAgICdhbmltYXRpb24nLFxyXG4gICAgICAnZmFkZUluIDAuMzVzIGVhc2Utb3V0IGZvcndhcmRzJ1xyXG4gICAgKTsgLy8gQXBwbHkgYW5pbWF0aW9uXHJcblxyXG4gICAgLy8gQXBwbHkgc3R5bGVzXHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcCwgJ3Bvc2l0aW9uJywgJ2ZpeGVkJyk7XHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcCwgJ2JhY2tncm91bmQnLCB0aGlzLmJnQ29sb3IpO1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXAsICdjb2xvcicsIHRoaXMuY29sb3IpO1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXAsICd3aGl0ZVNwYWNlJywgJ3ByZS13cmFwJyk7IC8vIEFsbG93cyBtdWx0aS1saW5lIHRleHRcclxuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy50b29sdGlwLCAnd29yZFdyYXAnLCAnYnJlYWstd29yZCcpOyAvLyBXcmFwIGxvbmcgd29yZHNcclxuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy50b29sdGlwLCAnZGlyZWN0aW9uJywgdGhpcy50b29sdGlwRGlyZWN0aW9uKTsgLy8gZGlyZWN0aW9uXHJcblxyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShcclxuICAgICAgdGhpcy50b29sdGlwLFxyXG4gICAgICAnYm94LXNoYWRvdycsXHJcbiAgICAgICcwcHggNHB4IDE1cHggMHB4IHJnYmEoMCwgMCwgMCwgMC4yKSdcclxuICAgICk7XHJcblxyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXAsICd3aWR0aCcsICdmaXQtY29udGVudCcpO1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShcclxuICAgICAgdGhpcy50b29sdGlwLFxyXG4gICAgICAnbWF4LXdpZHRoJyxcclxuICAgICAgdGhpcy5tYXhUb29sdGlwV2lkdGggPyB0aGlzLm1heFRvb2x0aXBXaWR0aCArICdweCcgOiBtYXhXaWR0aCArICdweCdcclxuICAgICk7XHJcblxyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXAsICd0ZXh0T3ZlcmZsb3cnLCAnZWxsaXBzaXMnKTtcclxuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy50b29sdGlwLCAncGFkZGluZycsICcxMHB4Jyk7XHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcCwgJ2JvcmRlclJhZGl1cycsICc2cHgnKTtcclxuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy50b29sdGlwLCAnZm9udFNpemUnLCAnMTRweCcpO1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXAsICd6SW5kZXgnLCAnOTk5OTk5OTk5OTk5OTk5Jyk7XHJcbiAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHRoaXMudG9vbHRpcCwgJ3BvaW50ZXJFdmVudHMnLCAnbm9uZScpOyAvLyBQcmV2ZW50IGludGVyZmVyZW5jZVxyXG5cclxuICAgIC8vIFRvb2x0aXAgQXJyb3dcclxuICAgIHRoaXMudG9vbHRpcEFycm93ID0gdGhpcy5yZW5kZXJlci5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuICAgIHRoaXMudG9vbHRpcEFycm93Py5jbGFzc0xpc3QuYWRkKCdtVG9vbHRpcEFycm93Jyk7XHJcblxyXG4gICAgdGhpcy5yZW5kZXJlci5hcHBlbmRDaGlsZCh0aGlzLnRvb2x0aXAsIHRoaXMudG9vbHRpcEFycm93KTtcclxuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy50b29sdGlwQXJyb3csICdwb3NpdGlvbicsICdhYnNvbHV0ZScpO1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXBBcnJvdywgJ3dpZHRoJywgJzAnKTtcclxuICAgIHRoaXMucmVuZGVyZXIuc2V0U3R5bGUodGhpcy50b29sdGlwQXJyb3csICdoZWlnaHQnLCAnMCcpO1xyXG4gICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnRvb2x0aXBBcnJvdywgJ2JvcmRlclN0eWxlJywgJ3NvbGlkJyk7XHJcblxyXG4gICAgdGhpcy5wb3NpdGlvblRvb2x0aXAoKTtcclxuXHJcbiAgICAvLyBBbmltYXRpb25cclxuICAgIHRoaXMuYWRkS2V5ZnJhbWVzKCk7XHJcbiAgfVxyXG4gIHByaXZhdGUgcmVtb3ZlVG9vbHRpcCgpIHtcclxuICAgIGlmICh0aGlzLnRvb2x0aXApIHtcclxuICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShcclxuICAgICAgICB0aGlzLnRvb2x0aXAsXHJcbiAgICAgICAgJ2FuaW1hdGlvbicsXHJcbiAgICAgICAgJ2ZhZGVPdXQgMC41cyBlYXNlLW91dCBmb3J3YXJkcydcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgIHRoaXMucmVuZGVyZXIucmVtb3ZlQ2hpbGQoZG9jdW1lbnQuYm9keSwgdGhpcy50b29sdGlwKTtcclxuICAgICAgICB0aGlzLnRvb2x0aXAgPSBudWxsO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgcG9zaXRpb25Ub29sdGlwKCkge1xyXG4gICAgaWYgKCF0aGlzLnRvb2x0aXApIHJldHVybjtcclxuXHJcbiAgICBjb25zdCByZWN0ID0gdGhpcy5lbC5uYXRpdmVFbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgY29uc3QgdG9vbHRpcFJlY3QgPSB0aGlzLnRvb2x0aXAuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcblxyXG4gICAgbGV0IHRvcCA9IDAsXHJcbiAgICAgIGxlZnQgPSAwO1xyXG5cclxuICAgIHN3aXRjaCAodGhpcy50b29sdGlwUG9zaXRpb24pIHtcclxuICAgICAgY2FzZSAndG9wJzpcclxuICAgICAgICB0b3AgPSByZWN0LnRvcCAtIHRvb2x0aXBSZWN0LmhlaWdodCAtIDU7XHJcbiAgICAgICAgbGVmdCA9IHJlY3QubGVmdCArIChyZWN0LndpZHRoIC0gdG9vbHRpcFJlY3Qud2lkdGgpIC8gMjtcclxuICAgICAgICBpZiAodG9wIDwgMCkge1xyXG4gICAgICAgICAgdG9wID0gcmVjdC5ib3R0b20gKyA1OyAvLyBNb3ZlIGJlbG93IGlmIG5vdCBlbm91Z2ggc3BhY2VcclxuICAgICAgICAgIHRoaXMuYXJyb3dQb3NpdGlvblVwKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIC8vIEFycm93IHBvaW50aW5nICoqZG93bioqIChwbGFjZWQgYXQgYm90dG9tKVxyXG4gICAgICAgICAgdGhpcy5hcnJvd1Bvc2l0aW9uRG93bigpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICBjYXNlICdib3R0b20nOlxyXG4gICAgICAgIHRvcCA9IHJlY3QuYm90dG9tICsgNTtcclxuICAgICAgICBsZWZ0ID0gcmVjdC5sZWZ0ICsgKHJlY3Qud2lkdGggLSB0b29sdGlwUmVjdC53aWR0aCkgLyAyO1xyXG4gICAgICAgIGlmICh0b3AgKyB0b29sdGlwUmVjdC5oZWlnaHQgPiB3aW5kb3cuaW5uZXJIZWlnaHQpIHtcclxuICAgICAgICAgIHRvcCA9IHJlY3QudG9wIC0gdG9vbHRpcFJlY3QuaGVpZ2h0IC0gNTtcclxuICAgICAgICAgIHRoaXMuYXJyb3dQb3NpdGlvbkRvd24oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gQXJyb3cgcG9pbnRpbmcgKip1cCoqIChwbGFjZWQgYXQgdG9wKVxyXG4gICAgICAgICAgdGhpcy5hcnJvd1Bvc2l0aW9uVXAoKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGJyZWFrO1xyXG5cclxuICAgICAgY2FzZSAnaW5zZXQtaW5saW5lLXN0YXJ0JzpcclxuICAgICAgY2FzZSAncmlnaHQnOlxyXG4gICAgICAgIHRvcCA9IHJlY3QudG9wICsgKHJlY3QuaGVpZ2h0IC0gdG9vbHRpcFJlY3QuaGVpZ2h0KSAvIDI7XHJcbiAgICAgICAgbGVmdCA9IHJlY3QubGVmdCAtIHRvb2x0aXBSZWN0LndpZHRoIC0gNTtcclxuICAgICAgICBpZiAobGVmdCA8IDApIHtcclxuICAgICAgICAgIGxlZnQgPSByZWN0LnJpZ2h0ICsgNTsgLy8gTW92ZSB0byB0aGUgcmlnaHQgaWYgbm90IGVub3VnaCBzcGFjZVxyXG4gICAgICAgICAgdGhpcy5hcnJvd1Bv