ng-spinner-wheel
Version:
A customizable standalone Angular spinner wheel component that supports weighted items. Useful for raffles, lucky draws, and gamified selections where some items have higher chances of winning.
294 lines (292 loc) • 39.8 kB
JavaScript
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import * as i0 from "@angular/core";
import * as i1 from "./ng-spinner-wheel.service";
export class NgSpinnerWheelComponent {
util;
ctx;
canvasEl;
allItems = [];
btnWidth = 30;
width = 260;
spinCompleted = new EventEmitter();
center;
deg = 0;
speed = 10;
isStopped = false;
lock = false;
isSpinning = false;
slowDownRand = 0;
canvas;
currentWinner;
fontSize = 15;
forceStop = false;
constructor(util) {
this.util = util;
}
async ngAfterViewInit() {
this.regenerate();
}
regenerate() {
setTimeout(() => {
this.onInIt2();
this.loadDataInit();
this.createSpinner();
}, 1000);
}
ngOnChanges(changes) {
if (changes['allItems']) {
this.regenerate();
}
}
onInIt2() {
this.canvas = this.canvasEl.nativeElement;
this.ctx = this.canvas.getContext('2d');
this.width = this.canvas.width;
this.center = this.width / 2;
}
async loadDataInit() {
const totalWeight = this.allItems.reduce((sum, item) => sum + (item.menuWeight ?? 1), 0);
await this.allItems.forEach((element) => {
if (!element.menuWeight)
element.menuWeight = 1;
element.percentage = ((element.menuWeight / totalWeight) * 100);
if (!element.backColor) {
element.backColor = this.util.getRandomColor();
}
if (!element.textColor) {
element.textColor = this.util.getTextColor(element.backColor);
}
if (!element.fontSize) {
element.fontSize = "15px";
}
});
this.allItems = this.shuffleArray(this.allItems);
console.log(this.allItems);
}
startSpin() {
if (this.lock || this.isStopped || this.isSpinning) {
return;
}
const randomNumber = Math.floor(Math.random() * (8501 - 5000) + 5000);
setTimeout(() => {
this.stops();
}, randomNumber);
this.lock = false;
this.forceStop = false;
this.isStopped = false;
this.isSpinning = true;
this.spin();
}
spin() {
let spin = () => {
let slicesData = this.allItems;
// const color = slicesData.map(slice => slice.color);
const label = slicesData.map((slice) => slice.menuTitle);
const slices = label.length;
// const sliceDeg = 360 / slices;
this.deg += this.speed;
this.deg %= 360;
if (this.forceStop) {
this.lock = false;
this.isStopped = false;
this.isSpinning = false;
this.speed = 0;
return;
}
// Increment speed
if (!this.isStopped && this.speed < 6) {
this.speed = this.speed + 1 * 0.1;
}
// Decrement Speed
if (this.isStopped) {
if (!this.lock) {
this.lock = true;
this.slowDownRand = this.rand(0.990, 0.970);
}
this.speed = this.speed > 0.2 ? this.speed *= this.slowDownRand : 0;
}
if (this.lock && !this.speed) {
this.lock = false;
this.isStopped = false;
this.isSpinning = false;
// Determine winner based on final degree
const finalDeg = (360 - this.deg + 270) % 360; // 270 is the top pointer
let angleAccumulator = 0;
for (let slice of slicesData) {
const sliceAngle = (slice.percentage ?? 0) * 3.6;
if (finalDeg >= angleAccumulator && finalDeg < angleAccumulator + sliceAngle) {
this.currentWinner = slice;
break;
}
angleAccumulator += sliceAngle;
}
this.spinCompleted.emit(this.currentWinner);
// alert(this.currentWinner?.menu_title || 'No winner found!');
return;
}
this.ctx?.clearRect(0, 0, this.width, this.width);
this.currentWinner = null;
let allTtl = this.deg;
slicesData.forEach((slice, i) => {
if (this.ctx) {
this.ctx.beginPath();
this.ctx.fillStyle = slice.backColor || "#000000";
this.ctx.moveTo(this.center, this.center);
this.ctx.arc(this.center, this.center, this.width / 2, this.deg2rad(this.deg), this.deg2rad(this.deg + ((slice.percentage ?? 0) * 3.6)));
this.ctx.lineTo(this.center, this.center);
this.ctx.fill();
allTtl += ((slice.percentage ?? 0) * 3.6);
const drawText_deg = this.deg + ((slice.percentage ?? 0) * 3.6) / 2;
// console.log(this.deg,this.deg%360,slice.menu_title);
if ((allTtl % 360) > 270 && !this.currentWinner) {
this.currentWinner = slice;
}
this.ctx.save();
this.ctx.translate(this.center, this.center);
this.ctx.rotate(this.deg2rad(drawText_deg));
this.ctx.textAlign = "right";
this.ctx.fillStyle = slice.textColor || "#000000";
;
var textvalArr = this.toMultiLine(slice.menuTitle);
var linespacing = 15;
var startX = (this.width / 2) - 10;
var startY = 5;
for (var i = 0; i < textvalArr.length; i++) {
this.ctx.fillText(textvalArr[i], startX, startY, (this.width / 2) - 20);
startY += linespacing;
}
// this.ctx.font = 'bold ' + this.fontSize + 'px sans-serif';
// this.ctx.fillText(slice.menu_title, 100, 5);
this.ctx.restore();
this.deg += ((slice.percentage ?? 0) * 3.6);
}
});
window.requestAnimationFrame(() => spin());
};
spin();
//window.requestAnimationFrame(spin);
}
stops() {
if (!this.isSpinning || this.isStopped) {
return;
}
this.isStopped = true;
}
deg2rad(deg) {
return deg * Math.PI / 180;
}
rand(min, max) {
return Math.random() * (max - min) + min;
}
setFontSize() {
const baseFontSize = this.width / 20; // adjust divisor as needed
const itemCount = this.allItems?.length || 0;
if (itemCount <= 5) {
this.fontSize = baseFontSize;
}
else if (itemCount <= 10) {
this.fontSize = baseFontSize * 0.8;
}
else {
this.fontSize = baseFontSize * 0.6;
}
}
createSpinner() {
this.setFontSize();
let slicesData = this.allItems;
const ctx = this.ctx;
const width = this.width;
const center = width / 2;
if (ctx) {
ctx.clearRect(0, 0, width, width);
const totalDegrees = 360;
let currentDegrees = 0;
slicesData.forEach((slice) => {
const name = slice.menuTitle;
// const id = slice.id;
const degree = (slice.percentage ?? 0) * 3.6;
// const color = slice.color;
// const { name, id, degree, color } = {1,1,1,1};
ctx.beginPath();
ctx.fillStyle = slice.backColor || "#000000";
ctx.moveTo(center, center);
ctx.arc(center, center, width / 2, this.deg2rad(currentDegrees), this.deg2rad(currentDegrees + degree));
ctx.lineTo(center, center);
ctx.fill();
const drawText_deg = currentDegrees + degree / 2;
ctx.save();
ctx.translate(center, center);
ctx.rotate(this.deg2rad(drawText_deg));
ctx.textAlign = "right";
ctx.fillStyle = slice.textColor || "#000000";
;
ctx.font = `bold ${slice.fontSize} sans-serif`;
var textvalArr = this.toMultiLine(name);
var linespacing = 15;
var startX = (this.width / 2) - 5;
var startY = 5;
for (var i = 0; i < textvalArr.length; i++) {
ctx.fillText(textvalArr[i], startX, startY, (this.width / 2) - 20);
startY += linespacing;
}
ctx.restore();
currentDegrees += degree;
});
}
}
toMultiLine(text) {
var textArr = new Array();
text = text.replace(/\n\r?/g, '<br/>');
textArr = text.split("<br/>");
return textArr;
}
shuffleArray(array) {
const shuffled = [...array]; // copy to avoid mutating original array
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgSpinnerWheelComponent, deps: [{ token: i1.NgSpinnerWheelService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: NgSpinnerWheelComponent, isStandalone: true, selector: "lib-ng-spinner-wheel", inputs: { allItems: "allItems", btnWidth: "btnWidth", width: "width" }, outputs: { spinCompleted: "spinCompleted" }, viewQueries: [{ propertyName: "canvasEl", first: true, predicate: ["canvas"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
<div id="wheel" class="ion-text-center">
<div style="position: relative;">
<canvas id="canvas" #canvas [width]="width" [height]="width"></canvas>
<div>
<img [style.height]="btnWidth+'px'" [style.width]="btnWidth+'px'" [style.top]="(width/2)-(btnWidth/2)+'px'"
[style.left]="(width/2)-(btnWidth/2)+'px'" style="position: absolute;" (click)="startSpin()" src="https://i.postimg.cc/hj1XkSfG/spin.png" />
</div>
</div>
</div>
`, isInline: true, styles: [""] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgSpinnerWheelComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-ng-spinner-wheel', standalone: true, imports: [], template: `
<div id="wheel" class="ion-text-center">
<div style="position: relative;">
<canvas id="canvas" #canvas [width]="width" [height]="width"></canvas>
<div>
<img [style.height]="btnWidth+'px'" [style.width]="btnWidth+'px'" [style.top]="(width/2)-(btnWidth/2)+'px'"
[style.left]="(width/2)-(btnWidth/2)+'px'" style="position: absolute;" (click)="startSpin()" src="https://i.postimg.cc/hj1XkSfG/spin.png" />
</div>
</div>
</div>
` }]
}], ctorParameters: () => [{ type: i1.NgSpinnerWheelService }], propDecorators: { canvasEl: [{
type: ViewChild,
args: ['canvas']
}], allItems: [{
type: Input,
args: ["allItems"]
}], btnWidth: [{
type: Input,
args: ["btnWidth"]
}], width: [{
type: Input,
args: ["width"]
}], spinCompleted: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctc3Bpbm5lci13aGVlbC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy1zcGlubmVyLXdoZWVsL3NyYy9saWIvbmctc3Bpbm5lci13aGVlbC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBYyxZQUFZLEVBQVUsS0FBSyxFQUFhLE1BQU0sRUFBaUIsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDOzs7QUFnQ2hJLE1BQU0sT0FBTyx1QkFBdUI7SUFtQmY7SUFsQlgsR0FBRyxDQUFtQztJQUN6QixRQUFRLENBQWM7SUFDeEIsUUFBUSxHQUFnQixFQUFFLENBQUM7SUFDcEIsUUFBUSxHQUFXLEVBQUUsQ0FBQztJQUN6QixLQUFLLEdBQVcsR0FBRyxDQUFDO0lBQ2pDLGFBQWEsR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBQ2hELE1BQU0sQ0FBVTtJQUNoQixHQUFHLEdBQVcsQ0FBQyxDQUFDO0lBQ2hCLEtBQUssR0FBVyxFQUFFLENBQUM7SUFDbkIsU0FBUyxHQUFZLEtBQUssQ0FBQztJQUMzQixJQUFJLEdBQVksS0FBSyxDQUFDO0lBQ3RCLFVBQVUsR0FBWSxLQUFLLENBQUM7SUFDNUIsWUFBWSxHQUFXLENBQUMsQ0FBQztJQUN6QixNQUFNLENBQU07SUFDWixhQUFhLENBQU07SUFDbkIsUUFBUSxHQUFHLEVBQUUsQ0FBQztJQUNkLFNBQVMsR0FBRyxLQUFLLENBQUM7SUFFMUIsWUFBbUIsSUFBMkI7UUFBM0IsU0FBSSxHQUFKLElBQUksQ0FBdUI7SUFBSSxDQUFDO0lBQ25ELEtBQUssQ0FBQyxlQUFlO1FBQ25CLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUNwQixDQUFDO0lBRU0sVUFBVTtRQUNmLFVBQVUsQ0FBQyxHQUFHLEVBQUU7WUFDZCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDZixJQUFJLENBQUMsWUFBWSxF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MUQsQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7d0dBOVJVLHVCQUF1Qjs0RkFBdkIsdUJBQXVCLDhUQWR4Qjs7Ozs7Ozs7Ozs7R0FXVDs7NEZBR1UsdUJBQXVCO2tCQWxCbkMsU0FBUzsrQkFDRSxzQkFBc0IsY0FDcEIsSUFBSSxXQUNQLEVBQUUsWUFDRDs7Ozs7Ozs7Ozs7R0FXVDswRkFLb0IsUUFBUTtzQkFBNUIsU0FBUzt1QkFBQyxRQUFRO2dCQUNBLFFBQVE7c0JBQTFCLEtBQUs7dUJBQUMsVUFBVTtnQkFDUyxRQUFRO3NCQUFqQyxLQUFLO3VCQUFDLFVBQVU7Z0JBQ00sS0FBSztzQkFBM0IsS0FBSzt1QkFBQyxPQUFPO2dCQUNKLGFBQWE7c0JBQXRCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEVsZW1lbnRSZWYsIEV2ZW50RW1pdHRlciwgSW5qZWN0LCBJbnB1dCwgT25DaGFuZ2VzLCBPdXRwdXQsIFNpbXBsZUNoYW5nZXMsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBOZ1NwaW5uZXJXaGVlbFNlcnZpY2UgfSBmcm9tICcuL25nLXNwaW5uZXItd2hlZWwuc2VydmljZSc7XHJcbi8vIGltcG9ydCB7IE5nU3Bpbm5lcldoZWVsU2VydmljZSB9IGZyb20gJ25nLXNwaW5uZXItd2hlZWwnO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBNZW51SXRlbXMge1xyXG4gIG1lbnVUaXRsZTogc3RyaW5nO1xyXG4gIElkPzogc3RyaW5nO1xyXG4gIG1lbnVXZWlnaHQ/OiBudW1iZXI7XHJcbiAgcGVyY2VudGFnZT86IG51bWJlcjtcclxuICBiYWNrQ29sb3I/OiBzdHJpbmc7XHJcbiAgZm9udFNpemU/OiBzdHJpbmc7XHJcbiAgdGV4dENvbG9yPzogc3RyaW5nO1xyXG59XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2xpYi1uZy1zcGlubmVyLXdoZWVsJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtdLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgIDxkaXYgaWQ9XCJ3aGVlbFwiIGNsYXNzPVwiaW9uLXRleHQtY2VudGVyXCI+XHJcbiAgICAgIDxkaXYgc3R5bGU9XCJwb3NpdGlvbjogcmVsYXRpdmU7XCI+XHJcbiAgICAgICAgPGNhbnZhcyBpZD1cImNhbnZhc1wiICNjYW52YXMgW3dpZHRoXT1cIndpZHRoXCIgW2hlaWdodF09XCJ3aWR0aFwiPjwvY2FudmFzPlxyXG5cclxuICAgICAgICA8ZGl2PlxyXG4gICAgICAgICAgPGltZyBbc3R5bGUuaGVpZ2h0XT1cImJ0bldpZHRoKydweCdcIiBbc3R5bGUud2lkdGhdPVwiYnRuV2lkdGgrJ3B4J1wiIFtzdHlsZS50b3BdPVwiKHdpZHRoLzIpLShidG5XaWR0aC8yKSsncHgnXCJcclxuICAgICAgICAgICAgW3N0eWxlLmxlZnRdPVwiKHdpZHRoLzIpLShidG5XaWR0aC8yKSsncHgnXCIgc3R5bGU9XCJwb3NpdGlvbjogYWJzb2x1dGU7XCIgKGNsaWNrKT1cInN0YXJ0U3BpbigpXCIgc3JjPVwiaHR0cHM6Ly9pLnBvc3RpbWcuY2MvaGoxWGtTZkcvc3Bpbi5wbmdcIiAvPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICA8L2Rpdj5cclxuICAgIDwvZGl2PlxyXG4gIGAsXHJcbiAgc3R5bGVzOiBgYFxyXG59KVxyXG5leHBvcnQgY2xhc3MgTmdTcGlubmVyV2hlZWxDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMge1xyXG4gIHByaXZhdGUgY3R4ITogQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJEIHwgbnVsbDtcclxuICBAVmlld0NoaWxkKCdjYW52YXMnKSBjYW52YXNFbCE6IEVsZW1lbnRSZWY7XHJcbiAgQElucHV0KFwiYWxsSXRlbXNcIikgYWxsSXRlbXM6IE1lbnVJdGVtc1tdID0gW107XHJcbiAgQElucHV0KFwiYnRuV2lkdGhcIikgcHVibGljIGJ0bldpZHRoOiBudW1iZXIgPSAzMDtcclxuICBASW5wdXQoXCJ3aWR0aFwiKSBwdWJsaWMgd2lkdGg6IG51bWJlciA9IDI2MDtcclxuICBAT3V0cHV0KCkgc3BpbkNvbXBsZXRlZCA9IG5ldyBFdmVudEVtaXR0ZXI8TWVudUl0ZW1zPigpO1xyXG4gIHByaXZhdGUgY2VudGVyITogbnVtYmVyO1xyXG4gIHByaXZhdGUgZGVnOiBudW1iZXIgPSAwO1xyXG4gIHByaXZhdGUgc3BlZWQ6IG51bWJlciA9IDEwO1xyXG4gIHByaXZhdGUgaXNTdG9wcGVkOiBib29sZWFuID0gZmFsc2U7XHJcbiAgcHJpdmF0ZSBsb2NrOiBib29sZWFuID0gZmFsc2U7XHJcbiAgcHJpdmF0ZSBpc1NwaW5uaW5nOiBib29sZWFuID0gZmFsc2U7XHJcbiAgcHJpdmF0ZSBzbG93RG93blJhbmQ6IG51bWJlciA9IDA7XHJcbiAgcHJpdmF0ZSBjYW52YXM6IGFueTtcclxuICBwcml2YXRlIGN1cnJlbnRXaW5uZXI6IGFueTtcclxuICBwcml2YXRlIGZvbnRTaXplID0gMTU7XHJcbiAgcHJpdmF0ZSBmb3JjZVN0b3AgPSBmYWxzZTtcclxuXHJcbiAgY29uc3RydWN0b3IocHVibGljIHV0aWw6IE5nU3Bpbm5lcldoZWVsU2VydmljZSkgeyB9XHJcbiAgYXN5bmMgbmdBZnRlclZpZXdJbml0KCk6IFByb21pc2U8dm9pZD4ge1xyXG4gICAgdGhpcy5yZWdlbmVyYXRlKCk7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgcmVnZW5lcmF0ZSgpIHtcclxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICB0aGlzLm9uSW5JdDIoKTtcclxuICAgICAgdGhpcy5sb2FkRGF0YUluaXQoKTtcclxuICAgICAgdGhpcy5jcmVhdGVTcGlubmVyKCk7XHJcbiAgICB9LCAxMDAwKTtcclxuICB9XHJcblxyXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcclxuICAgIGlmIChjaGFuZ2VzWydhbGxJdGVtcyddKSB7XHJcbiAgICAgIHRoaXMucmVnZW5lcmF0ZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgb25Jbkl0MigpIHtcclxuICAgIHRoaXMuY2FudmFzID0gdGhpcy5jYW52YXNFbC5uYXRpdmVFbGVtZW50O1xyXG4gICAgdGhpcy5jdHggPSB0aGlzLmNhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xyXG4gICAgdGhpcy53aWR0aCA9IHRoaXMuY2FudmFzLndpZHRoO1xyXG4gICAgdGhpcy5jZW50ZXIgPSB0aGlzLndpZHRoIC8gMjtcclxuXHJcbiAgfVxyXG5cclxuICBhc3luYyBsb2FkRGF0YUluaXQoKSB7XHJcbiAgICBjb25zdCB0b3RhbFdlaWdodCA9IHRoaXMuYWxsSXRlbXMucmVkdWNlKChzdW06IG51bWJlciwgaXRlbTogTWVudUl0ZW1zKSA9PiBzdW0gKyAoaXRlbS5tZW51V2VpZ2h0ID8/IDEpLCAwKTtcclxuICAgIGF3YWl0IHRoaXMuYWxsSXRlbXMuZm9yRWFjaCgoZWxlbWVudDogTWVudUl0ZW1zKSA9PiB7XHJcblxyXG5cclxuICAgICAgaWYgKCFlbGVtZW50Lm1lbnVXZWlnaHQpIGVsZW1lbnQubWVudVdlaWdodCA9IDE7XHJcblxyXG4gICAgICBlbGVtZW50LnBlcmNlbnRhZ2UgPSAoKGVsZW1lbnQubWVudVdlaWdodCAvIHRvdGFsV2VpZ2h0KSAqIDEwMClcclxuICAgICAgaWYgKCFlbGVtZW50LmJhY2tDb2xvcikge1xyXG4gICAgICAgIGVsZW1lbnQuYmFja0NvbG9yID0gdGhpcy51dGlsLmdldFJhbmRvbUNvbG9yKCk7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKCFlbGVtZW50LnRleHRDb2xvcikge1xyXG4gICAgICAgIGVsZW1lbnQudGV4dENvbG9yID0gdGhpcy51dGlsLmdldFRleHRDb2xvcihlbGVtZW50LmJhY2tDb2xvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICghZWxlbWVudC5mb250U2l6ZSkge1xyXG4gICAgICAgIGVsZW1lbnQuZm9udFNpemUgPSBcIjE1cHhcIjtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgdGhpcy5hbGxJdGVtcyA9IHRoaXMuc2h1ZmZsZUFycmF5KHRoaXMuYWxsSXRlbXMpO1xyXG5cclxuICAgIGNvbnNvbGUubG9nKHRoaXMuYWxsSXRlbXMpO1xyXG4gIH1cclxuXHJcbiAgc3RhcnRTcGluKCkge1xyXG4gICAgaWYgKHRoaXMubG9jayB8fCB0aGlzLmlzU3RvcHBlZCB8fCB0aGlzLmlzU3Bpbm5pbmcpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgY29uc3QgcmFuZG9tTnVtYmVyID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogKDg1MDEgLSA1MDAwKSArIDUwMDApO1xyXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgIHRoaXMuc3RvcHMoKTtcclxuICAgIH0sIHJhbmRvbU51bWJlcik7XHJcbiAgICB0aGlzLmxvY2sgPSBmYWxzZTtcclxuICAgIHRoaXMuZm9yY2VTdG9wID0gZmFsc2U7XHJcbiAgICB0aGlzLmlzU3RvcHBlZCA9IGZhbHNlO1xyXG4gICAgdGhpcy5pc1NwaW5uaW5nID0gdHJ1ZTtcclxuICAgIHRoaXMuc3BpbigpO1xyXG4gIH1cclxuXHJcbiAgc3BpbigpIHtcclxuXHJcblxyXG4gICAgbGV0IHNwaW4gPSAoKSA9PiB7XHJcbiAgICAgIGxldCBzbGljZXNEYXRhID0gdGhpcy5hbGxJdGVtcztcclxuICAgICAgLy8gY29uc3QgY29sb3IgPSBzbGljZXNEYXRhLm1hcChzbGljZSA9PiBzbGljZS5jb2xvcik7XHJcbiAgICAgIGNvbnN0IGxhYmVsID0gc2xpY2VzRGF0YS5tYXAoKHNsaWNlOiBNZW51SXRlbXMpID0+IHNsaWNlLm1lbnVUaXRsZSk7XHJcbiAgICAgIGNvbnN0IHNsaWNlcyA9IGxhYmVsLmxlbmd0aDtcclxuICAgICAgLy8gY29uc3Qgc2xpY2VEZWcgPSAzNjAgLyBzbGljZXM7XHJcblxyXG4gICAgICB0aGlzLmRlZyArPSB0aGlzLnNwZWVkO1xyXG4gICAgICB0aGlzLmRlZyAlPSAzNjA7XHJcblxyXG4gICAgICBpZiAodGhpcy5mb3JjZVN0b3ApIHtcclxuICAgICAgICB0aGlzLmxvY2sgPSBmYWxzZTtcclxuICAgICAgICB0aGlzLmlzU3RvcHBlZCA9IGZhbHNlO1xyXG4gICAgICAgIHRoaXMuaXNTcGlubmluZyA9IGZhbHNlO1xyXG4gICAgICAgIHRoaXMuc3BlZWQgPSAwO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG4gICAgICAvLyBJbmNyZW1lbnQgc3BlZWRcclxuICAgICAgaWYgKCF0aGlzLmlzU3RvcHBlZCAmJiB0aGlzLnNwZWVkIDwgNikge1xyXG4gICAgICAgIHRoaXMuc3BlZWQgPSB0aGlzLnNwZWVkICsgMSAqIDAuMTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRGVjcmVtZW50IFNwZWVkXHJcbiAgICAgIGlmICh0aGlzLmlzU3RvcHBlZCkge1xyXG4gICAgICAgIGlmICghdGhpcy5sb2NrKSB7XHJcbiAgICAgICAgICB0aGlzLmxvY2sgPSB0cnVlO1xyXG4gICAgICAgICAgdGhpcy5zbG93RG93blJhbmQgPSB0aGlzLnJhbmQoMC45OTAsIDAuOTcwKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5zcGVlZCA9IHRoaXMuc3BlZWQgPiAwLjIgPyB0aGlzLnNwZWVkICo9IHRoaXMuc2xvd0Rvd25SYW5kIDogMDtcclxuICAgICAgfVxyXG5cclxuXHJcblxyXG4gICAgICBpZiAodGhpcy5sb2NrICYmICF0aGlzLnNwZWVkKSB7XHJcbiAgICAgICAgdGhpcy5sb2NrID0gZmFsc2U7XHJcbiAgICAgICAgdGhpcy5pc1N0b3BwZWQgPSBmYWxzZTtcclxuICAgICAgICB0aGlzLmlzU3Bpbm5pbmcgPSBmYWxzZTtcclxuXHJcbiAgICAgICAgLy8gRGV0ZXJtaW5lIHdpbm5lciBiYXNlZCBvbiBmaW5hbCBkZWdyZWVcclxuICAgICAgICBjb25zdCBmaW5hbERlZyA9ICgzNjAgLSB0aGlzLmRlZyArIDI3MCkgJSAzNjA7IC8vIDI3MCBpcyB0aGUgdG9wIHBvaW50ZXJcclxuICAgICAgICBsZXQgYW5nbGVBY2N1bXVsYXRvciA9IDA7XHJcbiAgICAgICAgZm9yIChsZXQgc2xpY2Ugb2Ygc2xpY2VzRGF0YSkge1xyXG5cclxuICAgICAgICAgIGNvbnN0IHNsaWNlQW5nbGUgPSAoc2xpY2UucGVyY2VudGFnZSA/PyAwKSAqIDMuNjtcclxuICAgICAgICAgIGlmIChmaW5hbERlZyA+PSBhbmdsZUFjY3VtdWxhdG9yICYmIGZpbmFsRGVnIDwgYW5nbGVBY2N1bXVsYXRvciArIHNsaWNlQW5nbGUpIHtcclxuICAgICAgICAgICAgdGhpcy5jdXJyZW50V2lubmVyID0gc2xpY2U7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgYW5nbGVBY2N1bXVsYXRvciArPSBzbGljZUFuZ2xlO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnNwaW5Db21wbGV0ZWQuZW1pdCh0aGlzLmN1cnJlbnRXaW5uZXIpO1xyXG4gICAgICAgIC8vIGFsZXJ0KHRoaXMuY3VycmVudFdpbm5lcj8ubWVudV90aXRsZSB8fCAnTm8gd2lubmVyIGZvdW5kIScpO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5jdHg/LmNsZWFyUmVjdCgwLCAwLCB0aGlzLndpZHRoLCB0aGlzLndpZHRoKTtcclxuICAgICAgdGhpcy5jdXJyZW50V2lubmVyID0gbnVsbDtcclxuICAgICAgbGV0IGFsbFR0bCA9IHRoaXMuZGVnO1xyXG4gICAgICBzbGljZXNEYXRhLmZvckVhY2goKHNsaWNlOiBNZW51SXRlbXMsIGk6IG51bWJlcikgPT4ge1xyXG4gICAgICAgIGlmICh0aGlzLmN0eCkge1xyXG4gICAgICAgICAgdGhpcy5jdHguYmVnaW5QYXRoKCk7XHJcbiAgICAgICAgICB0aGlzLmN0eC5maWxsU3R5bGUgPSBzbGljZS5iYWNrQ29sb3IgfHwgXCIjMDAwMDAwXCJcclxuICAgICAgICAgIHRoaXMuY3R4Lm1vdmVUbyh0aGlzLmNlbnRlciwgdGhpcy5jZW50ZXIpO1xyXG4gICAgICAgICAgdGhpcy5jdHguYXJjKHRoaXMuY2VudGVyLCB0aGlzLmNlbnRlciwgdGhpcy53aWR0aCAvIDIsIHRoaXMuZGVnMnJhZCh0aGlzLmRlZyksIHRoaXMuZGVnMnJhZCh0aGlzLmRlZyArICgoc2xpY2UucGVyY2VudGFnZSA/PyAwKSAqIDMuNikpKTtcclxuICAgICAgICAgIHRoaXMuY3R4LmxpbmVUbyh0aGlzLmNlbnRlciwgdGhpcy5jZW50ZXIpO1xyXG4gICAgICAgICAgdGhpcy5jdHguZmlsbCgpO1xyXG4gICAgICAgICAgYWxsVHRsICs9ICgoc2xpY2UucGVyY2VudGFnZSA/PyAwKSAqIDMuNik7XHJcbiAgICAgICAgICBjb25zdCBkcmF3VGV4dF9kZWcgPSB0aGlzLmRlZyArICgoc2xpY2UucGVyY2VudGFnZSA/PyAwKSAqIDMuNikgLyAyO1xyXG5cclxuICAgICAgICAgIC8vIGNvbnNvbGUubG9nKHRoaXMuZGVnLHRoaXMuZGVnJTM2MCxzbGljZS5tZW51X3RpdGxlKTtcclxuICAgICAgICAgIGlmICgoYWxsVHRsICUgMzYwKSA+IDI3MCAmJiAhdGhpcy5jdXJyZW50V2lubmVyKSB7XHJcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFdpbm5lciA9IHNsaWNlO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHRoaXMuY3R4LnNhdmUoKTtcclxuICAgICAgICAgIHRoaXMuY3R4LnRyYW5zbGF0ZSh0aGlzLmNlbnRlciwgdGhpcy5jZW50ZXIpO1xyXG4gICAgICAgICAgdGhpcy5jdHgucm90YXRlKHRoaXMuZGVnMnJhZChkcmF3VGV4dF9kZWcpKTtcclxuICAgICAgICAgIHRoaXMuY3R4LnRleHRBbGlnbiA9IFwicmlnaHRcIjtcclxuICAgICAgICAgIHRoaXMuY3R4LmZpbGxTdHlsZSA9IHNsaWNlLnRleHRDb2xvciB8fCBcIiMwMDAwMDBcIjs7XHJcbiAgICAgICAgICB2YXIgdGV4dHZhbEFyciA9IHRoaXMudG9NdWx0aUxpbmUoc2xpY2UubWVudVRpdGxlKTtcclxuICAgICAgICAgIHZhciBsaW5lc3BhY2luZyA9IDE1O1xyXG4gICAgICAgICAgdmFyIHN0YXJ0WCA9ICh0aGlzLndpZHRoIC8gMikgLSAxMDtcclxuICAgICAgICAgIHZhciBzdGFydFkgPSA1O1xyXG5cclxuICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGV4dHZhbEFyci5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICB0aGlzLmN0eC5maWxsVGV4dCh0ZXh0dmFsQXJyW2ldLCBzdGFydFgsIHN0YXJ0WSwgKHRoaXMud2lkdGggLyAyKSAtIDIwKTtcclxuICAgICAgICAgICAgc3RhcnRZICs9IGxpbmVzcGFjaW5nO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIC8vIHRoaXMuY3R4LmZvbnQgPSAnYm9sZCAnICsgdGhpcy5mb250U2l6ZSArICdweCBzYW5zLXNlcmlmJztcclxuICAgICAgICAgIC8vIHRoaXMuY3R4LmZpbGxUZXh0KHNsaWNlLm1lbnVfdGl0bGUsIDEwMCwgNSk7XHJcbiAgICAgICAgICB0aGlzLmN0eC5yZXN0b3JlKCk7XHJcbiAgICAgICAgICB0aGlzLmRlZyArPSAoKHNsaWNlLnBlcmNlbnRhZ2UgPz8gMCkgKiAzLjYpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHNwaW4oKSk7XHJcbiAgICB9O1xyXG4gICAgc3BpbigpO1xyXG4gICAgLy93aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKHNwaW4pO1xyXG4gIH1cclxuICBzdG9wcygpIHtcclxuICAgIGlmICghdGhpcy5pc1NwaW5uaW5nIHx8IHRoaXMuaXNTdG9wcGVkKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIHRoaXMuaXNTdG9wcGVkID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIGRlZzJyYWQoZGVnOiBudW1iZXIpOiBudW1iZXIge1xyXG4gICAgcmV0dXJuIGRlZyAqIE1hdGguUEkgLyAxODA7XHJcbiAgfVxyXG5cclxuICByYW5kKG1pbjogbnVtYmVyLCBtYXg6IG51bWJlcik6IG51bWJlciB7XHJcbiAgICByZXR1cm4gTWF0aC5yYW5kb20oKSAqIChtYXggLSBtaW4pICsgbWluO1xyXG4gIH1cclxuXHJcblxyXG5cclxuICBzZXRGb250U2l6ZSgpIHtcclxuICAgIGNvbnN0IGJhc2VGb250U2l6ZSA9IHRoaXMud2lkdGggLyAyMDsgLy8gYWRqdXN0IGRpdmlzb3IgYXMgbmVlZGVkXHJcblxyXG4gICAgY29uc3QgaXRlbUNvdW50ID0gdGhpcy5hbGxJdGVtcz8ubGVuZ3RoIHx8IDA7XHJcblxyXG4gICAgaWYgKGl0ZW1Db3VudCA8PSA1KSB7XHJcbiAgICAgIHRoaXMuZm9udFNpemUgPSBiYXNlRm9udFNpemU7XHJcbiAgICB9IGVsc2UgaWYgKGl0ZW1Db3VudCA8PSAxMCkge1xyXG4gICAgICB0aGlzLmZvbnRTaXplID0gYmFzZUZvbnRTaXplICogMC44O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5mb250U2l6ZSA9IGJhc2VGb250U2l6ZSAqIDAuNjtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGNyZWF0ZVNwaW5uZXIoKSB7XHJcbiAgICB0aGlzLnNldEZvbnRTaXplKCk7XHJcbiAgICBsZXQgc2xpY2VzRGF0YSA9IHRoaXMuYWxsSXRlbXM7XHJcbiAgICBjb25zdCBjdHggPSB0aGlzLmN0eDtcclxuICAgIGNvbnN0IHdpZHRoID0gdGhpcy53aWR0aDtcclxuICAgIGNvbnN0IGNlbnRlciA9IHdpZHRoIC8gMjtcclxuXHJcbiAgICBpZiAoY3R4KSB7XHJcbiAgICAgIGN0eC5jbGVhclJlY3QoMCwgMCwgd2lkdGgsIHdpZHRoKTtcclxuXHJcbiAgICAgIGNvbnN0IHRvdGFsRGVncmVlcyA9IDM2MDtcclxuICAgICAgbGV0IGN1cnJlbnREZWdyZWVzID0gMDtcclxuXHJcbiAgICAgIHNsaWNlc0RhdGEuZm9yRWFjaCgoc2xpY2U6IE1lbnVJdGVtcykgPT4ge1xyXG4gICAgICAgIGNvbnN0IG5hbWUgPSBzbGljZS5tZW51VGl0bGU7XHJcbiAgICAgICAgLy8gY29uc3QgaWQgPSBzbGljZS5pZDtcclxuICAgICAgICBjb25zdCBkZWdyZWUgPSAoc2xpY2UucGVyY2VudGFnZSA/PyAwKSAqIDMuNjtcclxuICAgICAgICAvLyBjb25zdCBjb2xvciA9IHNsaWNlLmNvbG9yO1xyXG4gICAgICAgIC8vIGNvbnN0IHsgbmFtZSwgaWQsIGRlZ3JlZSwgY29sb3IgfSA9IHsxLDEsMSwxfTtcclxuXHJcbiAgICAgICAgY3R4LmJlZ2luUGF0aCgpO1xyXG4gICAgICAgIGN0eC5maWxsU3R5bGUgPSBzbGljZS5iYWNrQ29sb3IgfHwgXCIjMDAwMDAwXCI7XHJcbiAgICAgICAgY3R4Lm1vdmVUbyhjZW50ZXIsIGNlbnRlcik7XHJcbiAgICAgICAgY3R4LmFyYyhjZW50ZXIsIGNlbnRlciwgd2lkdGggLyAyLCB0aGlzLmRlZzJyYWQoY3VycmVudERlZ3JlZXMpLCB0aGlzLmRlZzJyYWQoY3VycmVudERlZ3JlZXMgKyBkZWdyZWUpKTtcclxuICAgICAgICBjdHgubGluZVRvKGNlbnRlciwgY2VudGVyKTtcclxuICAgICAgICBjdHguZmlsbCgpO1xyXG5cclxuICAgICAgICBjb25zdCBkcmF3VGV4dF9kZWcgPSBjdXJyZW50RGVncmVlcyArIGRlZ3JlZSAvIDI7XHJcbiAgICAgICAgY3R4LnNhdmUoKTtcclxuICAgICAgICBjdHgudHJhbnNsYXRlKGNlbnRlciwgY2VudGVyKTtcclxuICAgICAgICBjdHgucm90YXRlKHRoaXMuZGVnMnJhZChkcmF3VGV4dF9kZWcpKTtcclxuICAgICAgICBjdHgudGV4dEFsaWduID0gXCJyaWdodFwiO1xyXG4gICAgICAgIGN0eC5maWxsU3R5bGUgPSBzbGljZS50ZXh0Q29sb3IgfHwgXCIjMDAwMDAwXCI7O1xyXG5cclxuICAgICAgICBjdHguZm9udCA9IGBib2xkICR7c2xpY2UuZm9udFNpemV9IHNhbnMtc2VyaWZgO1xyXG5cclxuICAgICAgICB2YXIgdGV4dHZhbEFyciA9IHRoaXMudG9NdWx0aUxpbmUobmFtZSk7XHJcbiAgICAgICAgdmFyIGxpbmVzcGFjaW5nID0gMTU7XHJcbiAgICAgICAgdmFyIHN0YXJ0WCA9ICh0aGlzLndpZHRoIC8gMikgLSA1O1xyXG4gICAgICAgIHZhciBzdGFydFkgPSA1O1xyXG5cclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRleHR2YWxBcnIubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgIGN0eC5maWxsVGV4dCh0ZXh0dmFsQXJyW2ldLCBzdGFydFgsIHN0YXJ0WSwgKHRoaXMud2lkdGggLyAyKSAtIDIwKTtcclxuICAgICAgICAgIHN0YXJ0WSArPSBsaW5lc3BhY2luZztcclxuICAgICAgICB9XHJcbiAgICAgICAgY3R4LnJlc3RvcmUoKTtcclxuICAgICAgICBjdXJyZW50RGVncmVlcyArPSBkZWdyZWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxuICB0b011bHRpTGluZSh0ZXh0OiBzdHJpbmcpIHtcclxuICAgIHZhciB0ZXh0QXJyID0gbmV3IEFycmF5KCk7XHJcbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXG5cXHI/L2csICc8YnIvPicpO1xyXG4gICAgdGV4dEFyciA9IHRleHQuc3BsaXQoXCI8YnIvPlwiKTtcclxuICAgIHJldHVybiB0ZXh0QXJyO1xyXG4gIH1cclxuXHJcblxyXG4gIHNodWZmbGVBcnJheTxUPihhcnJheTogVFtdKTogVFtdIHtcclxuICAgIGNvbnN0IHNodWZmbGVkID0gWy4uLmFycmF5XTsgLy8gY29weSB0byBhdm9pZCBtdXRhdGluZyBvcmlnaW5hbCBhcnJheVxyXG4gICAgZm9yIChsZXQgaSA9IHNodWZmbGVkLmxlbmd0aCAtIDE7IGkgPiAwOyBpLS0pIHtcclxuICAgICAgY29uc3QgaiA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIChpICsgMSkpO1xyXG4gICAgICBbc2h1ZmZsZWRbaV0sIHNodWZmbGVkW2pdXSA9IFtzaHVmZmxlZFtqXSwgc2h1ZmZsZWRbaV1dO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHNodWZmbGVkO1xyXG4gIH1cclxufVxyXG4iXX0=