ngx-input-color
Version:
Angular color input component and color picker (with HSL, HSV, RGB, CMYK, HEX, alpha, eye-dropper, etc)
252 lines • 37.5 kB
JavaScript
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, EventEmitter, HostListener, Input, Output, ViewChild, forwardRef, } from '@angular/core';
import { getOffsetPosition } from '../utils/get-offset-position';
import { NG_VALIDATORS, NG_VALUE_ACCESSOR, } from '@angular/forms';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
export class ValueModel {
}
export class RangeSliderComponent {
constructor(changeDetectorRef) {
this.changeDetectorRef = changeDetectorRef;
/**
* The step value for the slider
*/
this.step = 1;
/**
* The minimum value for the slider
*/
this.min = 0;
/**
* The maximum value for the slider
*/
this.max = 100;
/**
* If true, the background will be transparent
*/
this.isBgTransparent = false;
/**
* If true, clicking on the slider will add a new range at that position
*/
this.addNewRangeOnClick = false;
/**
* The current value of the slider
*/
this.change = new EventEmitter();
this.selectedIndexChange = new EventEmitter();
this.isDragging = false;
this.values = [];
this.isDisabled = false;
this._onChange = (value) => { };
this._onTouched = () => { };
this._validatorOnChange = () => { };
}
ngOnInit() { }
generateId() {
let id = 'ngx-thumb-' + Math.random().toString(36).substring(2, 9);
if (this.values.findIndex((x) => x.id == id) >= 0) {
return this.generateId();
}
return id;
}
writeValue(items) {
this.values = [];
if (!items || !Array.isArray(items)) {
items = [];
}
if (items.length === 0) {
items.push({ id: this.generateId(), value: this.min });
}
for (let val of items) {
if (typeof val.value !== 'number' || isNaN(val.value)) {
throw new Error('RangeSliderComponent: value must be an array of numbers');
}
let newVal = +val.value;
if (newVal < +this.min)
newVal = +this.min;
else if (newVal > +this.max)
newVal = +this.max;
this.values.push({
...val,
id: val.id ?? this.generateId(),
value: newVal,
});
}
this.updateAllThumbPositions();
}
validate(control) {
return null; // TODO: return errors if any;
}
registerOnValidatorChange(fn) {
this._validatorOnChange = fn;
}
registerOnChange(fn) {
this._onChange = fn;
}
registerOnTouched(fn) {
this._onTouched = fn;
}
setDisabledState(disabled) {
this.isDisabled = disabled;
}
updateRects() {
this.sliderRect = this.slider.nativeElement.getBoundingClientRect();
if (this.thumb) {
this.thumbRect = this.thumb.nativeElement.getBoundingClientRect();
}
}
onDrag(ev) {
if (!this.isDragging)
return;
this.updateThumbPosition(ev);
}
onResize() {
this.writeValue(this.values);
}
dragStart(ev, index) {
ev.stopPropagation();
ev.preventDefault();
this.isDragging = true;
this.selectedIndex = index;
this.updateRects();
this.updateThumbPosition(ev);
this.selectedIndexChange.emit(this.selectedIndex);
}
addnewRangeOnSliderClick(event) {
if (!this.addNewRangeOnClick)
return;
const position = getOffsetPosition(event, this.slider.nativeElement);
const newValue = this.min + (position.x / this.sliderRect.width) * (this.max - this.min);
// must be add with order by position
const indexByOrderValue = this.values.findIndex((item) => item.value > newValue);
const insertIndex = indexByOrderValue >= 0 ? indexByOrderValue : this.values.length;
this.values.splice(insertIndex, 0, {
id: this.generateId(),
value: newValue,
});
this.dragStart(event, insertIndex);
// this.updateAllThumbPositions();
// this.valueChanged();
}
updateThumbPosition(ev) {
if (!this.isDragging || this.selectedIndex == undefined)
return;
if (!this.sliderRect || !this.thumbRect)
this.updateRects();
let position = getOffsetPosition(ev, this.slider.nativeElement);
let thumbRec = this.thumbRect;
position.x -= thumbRec.width / 2;
let sliderRec = this.sliderRect;
const thumb = this.values[this.selectedIndex];
if (position.x < 0) {
thumb.x = 0;
}
else if (position.x > sliderRec.width - thumbRec.width) {
thumb.x = sliderRec.width - thumbRec.width;
}
else {
thumb.x = position.x;
}
this.setValueByPosition(thumb, thumbRec, sliderRec);
}
updateAllThumbPositions() {
// wait to add thumbs
setTimeout(() => {
this.updateRects();
const sliderRec = this.sliderRect;
const thumbRec = this.thumbRect;
for (let item of this.values) {
item.x = ((item.value - this.min) * (sliderRec.width - thumbRec.width)) / (this.max - this.min);
}
this.changeDetectorRef.detectChanges();
});
}
setValueByPosition(thumb, thumbRec, sliderRec) {
const percentage = (thumb.x ?? 0) / (sliderRec.width - thumbRec.width);
let newValue = this.min + percentage * (this.max - this.min);
const stepDecimalPlaces = (this.step.toString().split('.')[1] || '').length;
newValue = parseFloat((Math.round(newValue / this.step) * this.step).toFixed(stepDecimalPlaces));
let value = Math.min(Math.max(newValue, this.min), this.max);
if (thumb.value !== value) {
thumb.value = value;
this.valueChanged();
}
}
onDragEnd(ev) {
this.isDragging = false;
// this.selectedIndex = undefined;
}
valueChanged() {
const v = this.values; // this.values.map(({ x, thumb, ...rest }) => ({ ...rest }));
this._onChange(v);
this.change.emit(v);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RangeSliderComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: RangeSliderComponent, isStandalone: true, selector: "range-slider", inputs: { step: "step", min: "min", max: "max", background: "background", isBgTransparent: "isBgTransparent", addNewRangeOnClick: "addNewRangeOnClick", selectedIndex: "selectedIndex" }, outputs: { change: "change", selectedIndexChange: "selectedIndexChange" }, host: { listeners: { "document:mousemove": "onDrag($event)", "document:touchmove": "onDrag($event)", "window:resize": "onResize($event)", "document:mouseup": "onDragEnd($event)", "document:touchend": "onDragEnd($event)" } }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RangeSliderComponent),
multi: true,
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => RangeSliderComponent),
multi: true,
},
], viewQueries: [{ propertyName: "slider", first: true, predicate: ["slider"], descendants: true, static: true }, { propertyName: "thumb", first: true, predicate: ["thumb"], descendants: true }], ngImport: i0, template: "<div class=\"slider-container\">\r\n <ng-content></ng-content>\r\n <div\r\n #slider\r\n class=\"slider\"\r\n [class.add-range-cursor]=\"addNewRangeOnClick\"\r\n [ngStyle]=\"{ '--ngx-slider-bg': background }\"\r\n [class.bg-transparent]=\"isBgTransparent\"\r\n (mousedown)=\"addnewRangeOnSliderClick($event)\"\r\n (touchstart)=\"addnewRangeOnSliderClick($event)\">\r\n <div\r\n class=\"thumb\"\r\n [class.is-active]=\"selectedIndex == i\"\r\n #thumb\r\n *ngFor=\"let item of values; let i = index\"\r\n [style.left.px]=\"item.x\"\r\n [style.background]=\"item.color\"\r\n [title]=\"item.value\"\r\n (mousedown)=\"dragStart($event, i)\"\r\n (touchstart)=\"dragStart($event, i)\"></div>\r\n </div>\r\n</div>\r\n\r\n<!-- {{ selectedIndex }}\r\n<pre dir=\"ltr\" style=\"text-align: left\">{{ values | json }}</pre> -->\r\n\r\n", styles: [".slider-container{max-width:100%;padding:1px 0}.slider-container .slider{position:relative;box-shadow:inset #00000013 0 0 0 1px;border-radius:10px;height:12px;width:100%;background:var(--ngx-slider-bg, rgb(140, 51, 250));margin:10px 0}.slider-container .slider.bg-transparent{background:transparent}.slider-container .slider.bg-transparent:before,.slider-container .slider.bg-transparent:after{position:absolute;inset:1px;border-radius:9px}.slider-container .slider.bg-transparent:before{content:\" \";background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:16px 16px;background-position:0 0,0 8px,8px -8px,-8px 0px}.slider-container .slider.bg-transparent:after{content:\" \";background:var(--ngx-slider-bg)}.slider-container .slider.add-range-cursor{cursor:copy}.slider-container .thumb{box-shadow:#00000026 0 0 0 1px,#0000000d 0 10px 10px -5px,inset #fff 0 0 0 6px;background:var(--ngx-slider-bg, rgb(140, 51, 250));height:var(--ngx-thumb-size, 30px);width:var(--ngx-thumb-size, 30px);display:block;border-radius:100%;top:calc(6px - var(--ngx-thumb-size, 30px) / 2);position:absolute;cursor:grab;z-index:100}.slider-container .thumb.is-active{outline:1px rgb(89,0,255) solid}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: RangeSliderComponent, decorators: [{
type: Component,
args: [{ selector: 'range-slider', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RangeSliderComponent),
multi: true,
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => RangeSliderComponent),
multi: true,
},
], template: "<div class=\"slider-container\">\r\n <ng-content></ng-content>\r\n <div\r\n #slider\r\n class=\"slider\"\r\n [class.add-range-cursor]=\"addNewRangeOnClick\"\r\n [ngStyle]=\"{ '--ngx-slider-bg': background }\"\r\n [class.bg-transparent]=\"isBgTransparent\"\r\n (mousedown)=\"addnewRangeOnSliderClick($event)\"\r\n (touchstart)=\"addnewRangeOnSliderClick($event)\">\r\n <div\r\n class=\"thumb\"\r\n [class.is-active]=\"selectedIndex == i\"\r\n #thumb\r\n *ngFor=\"let item of values; let i = index\"\r\n [style.left.px]=\"item.x\"\r\n [style.background]=\"item.color\"\r\n [title]=\"item.value\"\r\n (mousedown)=\"dragStart($event, i)\"\r\n (touchstart)=\"dragStart($event, i)\"></div>\r\n </div>\r\n</div>\r\n\r\n<!-- {{ selectedIndex }}\r\n<pre dir=\"ltr\" style=\"text-align: left\">{{ values | json }}</pre> -->\r\n\r\n", styles: [".slider-container{max-width:100%;padding:1px 0}.slider-container .slider{position:relative;box-shadow:inset #00000013 0 0 0 1px;border-radius:10px;height:12px;width:100%;background:var(--ngx-slider-bg, rgb(140, 51, 250));margin:10px 0}.slider-container .slider.bg-transparent{background:transparent}.slider-container .slider.bg-transparent:before,.slider-container .slider.bg-transparent:after{position:absolute;inset:1px;border-radius:9px}.slider-container .slider.bg-transparent:before{content:\" \";background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:16px 16px;background-position:0 0,0 8px,8px -8px,-8px 0px}.slider-container .slider.bg-transparent:after{content:\" \";background:var(--ngx-slider-bg)}.slider-container .slider.add-range-cursor{cursor:copy}.slider-container .thumb{box-shadow:#00000026 0 0 0 1px,#0000000d 0 10px 10px -5px,inset #fff 0 0 0 6px;background:var(--ngx-slider-bg, rgb(140, 51, 250));height:var(--ngx-thumb-size, 30px);width:var(--ngx-thumb-size, 30px);display:block;border-radius:100%;top:calc(6px - var(--ngx-thumb-size, 30px) / 2);position:absolute;cursor:grab;z-index:100}.slider-container .thumb.is-active{outline:1px rgb(89,0,255) solid}\n"] }]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { step: [{
type: Input
}], min: [{
type: Input
}], max: [{
type: Input
}], background: [{
type: Input
}], isBgTransparent: [{
type: Input
}], addNewRangeOnClick: [{
type: Input
}], change: [{
type: Output
}], selectedIndex: [{
type: Input
}], selectedIndexChange: [{
type: Output
}], slider: [{
type: ViewChild,
args: ['slider', { static: true }]
}], thumb: [{
type: ViewChild,
args: ['thumb', { static: false }]
}], onDrag: [{
type: HostListener,
args: ['document:mousemove', ['$event']]
}, {
type: HostListener,
args: ['document:touchmove', ['$event']]
}], onResize: [{
type: HostListener,
args: ['window:resize', ['$event']]
}], onDragEnd: [{
type: HostListener,
args: ['document:mouseup', ['$event']]
}, {
type: HostListener,
args: ['document:touchend', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmFuZ2Utc2xpZGVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1pbnB1dC1jb2xvci9zcmMvcmFuZ2Utc2xpZGVyL3JhbmdlLXNsaWRlci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtaW5wdXQtY29sb3Ivc3JjL3JhbmdlLXNsaWRlci9yYW5nZS1zbGlkZXIuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFDTCx1QkFBdUIsRUFFdkIsU0FBUyxFQUVULFlBQVksRUFDWixZQUFZLEVBQ1osS0FBSyxFQUNMLE1BQU0sRUFDTixTQUFTLEVBQ1QsVUFBVSxHQUVYLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ2pFLE9BQU8sRUFHTCxhQUFhLEVBQ2IsaUJBQWlCLEdBSWxCLE1BQU0sZ0JBQWdCLENBQUM7OztBQU14QixNQUFNLE9BQU8sVUFBVTtDQU10QjtBQXNCRCxNQUFNLE9BQU8sb0JBQW9CO0lBZ0QvQixZQUFvQixpQkFBb0M7UUFBcEMsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFtQjtRQS9DeEQ7O1dBRUc7UUFDTSxTQUFJLEdBQUcsQ0FBQyxDQUFDO1FBQ2xCOztXQUVHO1FBQ00sUUFBRyxHQUFHLENBQUMsQ0FBQztRQUNqQjs7V0FFRztRQUNNLFFBQUcsR0FBRyxHQUFHLENBQUM7UUFPbkI7O1dBRUc7UUFDTSxvQkFBZSxHQUFHLEtBQUssQ0FBQztRQUNqQzs7V0FFRztRQUNNLHVCQUFrQixHQUFHLEtBQUssQ0FBQztRQUVwQzs7V0FFRztRQUNPLFdBQU0sR0FBRyxJQUFJLFlBQVksRUFBWSxDQUFDO1FBRXRDLHdCQUFtQixHQUFHLElBQUksWUFBWSxFQUFVLENBQUM7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O2dCQU1HLFVBQVU7c0JBQWxCLEtBQUs7Z0JBSUcsZUFBZTtzQkFBdkIsS0FBSztnQkFJRyxrQkFBa0I7c0JBQTFCLEtBQUs7Z0JBS0ksTUFBTTtzQkFBZixNQUFNO2dCQUNFLGFBQWE7c0JBQXJCLEtBQUs7Z0JBQ0ksbUJBQW1CO3NCQUE1QixNQUFNO2dCQUlnQyxNQUFNO3NCQUE1QyxTQUFTO3VCQUFDLFFBQVEsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUU7Z0JBQ0UsS0FBSztzQkFBM0MsU0FBUzt1QkFBQyxPQUFPLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO2dCQW9FckMsTUFBTTtzQkFGTCxZQUFZO3VCQUFDLG9CQUFvQixFQUFFLENBQUMsUUFBUSxDQUFDOztzQkFDN0MsWUFBWTt1QkFBQyxvQkFBb0IsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFPOUMsUUFBUTtzQkFEUCxZQUFZO3VCQUFDLGVBQWUsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkEwRXpDLFNBQVM7c0JBRlIsWUFBWTt1QkFBQyxrQkFBa0IsRUFBRSxDQUFDLFFBQVEsQ0FBQzs7c0JBQzNDLFlBQVk7dUJBQUMsbUJBQW1CLEVBQUUsQ0FBQyxRQUFRLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5pbXBvcnQge1xyXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxyXG4gIENoYW5nZURldGVjdG9yUmVmLFxyXG4gIENvbXBvbmVudCxcclxuICBFbGVtZW50UmVmLFxyXG4gIEV2ZW50RW1pdHRlcixcclxuICBIb3N0TGlzdGVuZXIsXHJcbiAgSW5wdXQsXHJcbiAgT3V0cHV0LFxyXG4gIFZpZXdDaGlsZCxcclxuICBmb3J3YXJkUmVmLFxyXG4gIHR5cGUgT25Jbml0LFxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBnZXRPZmZzZXRQb3NpdGlvbiB9IGZyb20gJy4uL3V0aWxzL2dldC1vZmZzZXQtcG9zaXRpb24nO1xyXG5pbXBvcnQge1xyXG4gIEFic3RyYWN0Q29udHJvbCxcclxuICBDb250cm9sVmFsdWVBY2Nlc3NvcixcclxuICBOR19WQUxJREFUT1JTLFxyXG4gIE5HX1ZBTFVFX0FDQ0VTU09SLFxyXG4gIFZhbGlkYXRpb25FcnJvcnMsXHJcbiAgVmFsaWRhdG9yLFxyXG4gIFZhbGlkYXRvcnMsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBJVmFsdWUge1xyXG4gIGlkPzogc3RyaW5nO1xyXG4gIHZhbHVlOiBudW1iZXI7XHJcbn1cclxuZXhwb3J0IGNsYXNzIFZhbHVlTW9kZWwge1xyXG4gIGlkITogc3RyaW5nO1xyXG4gIHZhbHVlITogbnVtYmVyO1xyXG4gIHg/OiBudW1iZXI7XHJcbiAgdGh1bWI/OiBIVE1MRWxlbWVudDtcclxuICBjb2xvcj86IHN0cmluZztcclxufVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdyYW5nZS1zbGlkZXInLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZV0sXHJcbiAgdGVtcGxhdGVVcmw6ICcuL3JhbmdlLXNsaWRlci5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJy4vcmFuZ2Utc2xpZGVyLmNvbXBvbmVudC5zY3NzJ10sXHJcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXHJcbiAgcHJvdmlkZXJzOiBbXHJcbiAgICB7XHJcbiAgICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxyXG4gICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBSYW5nZVNsaWRlckNvbXBvbmVudCksXHJcbiAgICAgIG11bHRpOiB0cnVlLFxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgcHJvdmlkZTogTkdfVkFMSURBVE9SUyxcclxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gUmFuZ2VTbGlkZXJDb21wb25lbnQpLFxyXG4gICAgICBtdWx0aTogdHJ1ZSxcclxuICAgIH0sXHJcbiAgXSxcclxufSlcclxuZXhwb3J0IGNsYXNzIFJhbmdlU2xpZGVyQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBDb250cm9sVmFsdWVBY2Nlc3NvciwgVmFsaWRhdG9yIHtcclxuICAvKipcclxuICAgKiBUaGUgc3RlcCB2YWx1ZSBmb3IgdGhlIHNsaWRlclxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIHN0ZXAgPSAxO1xyXG4gIC8qKlxyXG4gICAqIFRoZSBtaW5pbXVtIHZhbHVlIGZvciB0aGUgc2xpZGVyXHJcbiAgICovXHJcbiAgQElucHV0KCkgbWluID0gMDtcclxuICAvKipcclxuICAgKiBUaGUgbWF4aW11bSB2YWx1ZSBmb3IgdGhlIHNsaWRlclxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIG1heCA9IDEwMDtcclxuICAvKipcclxuICAgKiBUaGUgYmFja2dyb3VuZCBjb2xvciBvZiB0aGUgc2xpZGVyXHJcbiAgICogLSBjYW4gdXNlIGNzcyBsaWtlIGBiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQodG8gcmlnaHQsIHJlZCwgYmx1ZSk7YFxyXG4gICAqIC0gb3IgYSBzb2xpZCBjb2xvciBsaWtlIGBiYWNrZ3JvdW5kOiByZWQ7YFxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIGJhY2tncm91bmQ/OiBzdHJpbmc7XHJcbiAgLyoqXHJcbiAgICogSWYgdHJ1ZSwgdGhlIGJhY2tncm91bmQgd2lsbCBiZSB0cmFuc3BhcmVudFxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIGlzQmdUcmFuc3BhcmVudCA9IGZhbHNlO1xyXG4gIC8qKlxyXG4gICAqIElmIHRydWUsIGNsaWNraW5nIG9uIHRoZSBzbGlkZXIgd2lsbCBhZGQgYSBuZXcgcmFuZ2UgYXQgdGhhdCBwb3NpdGlvblxyXG4gICAqL1xyXG4gIEBJbnB1dCgpIGFkZE5ld1JhbmdlT25DbGljayA9IGZhbHNlO1xyXG5cclxuICAvKipcclxuICAgKiBUaGUgY3VycmVudCB2YWx1ZSBvZiB0aGUgc2xpZGVyXHJcbiAgICovXHJcbiAgQE91dHB1dCgpIGNoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8SVZhbHVlW10+KCk7XHJcbiAgQElucHV0KCkgc2VsZWN0ZWRJbmRleD86IG51bWJlcjtcclxuICBAT3V0cHV0KCkgc2VsZWN0ZWRJbmRleENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xyXG5cclxuICBwcml2YXRlIGlzRHJhZ2dpbmcgPSBmYWxzZTtcclxuXHJcbiAgQFZpZXdDaGlsZCgnc2xpZGVyJywgeyBzdGF0aWM6IHRydWUgfSkgc2xpZGVyITogRWxlbWVudFJlZjxIVE1MRGl2RWxlbWVudD47XHJcbiAgQFZpZXdDaGlsZCgndGh1bWInLCB7IHN0YXRpYzogZmFsc2UgfSkgdGh1bWI/OiBFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50PjtcclxuXHJcbiAgdmFsdWVzOiBWYWx1ZU1vZGVsW10gPSBbXTtcclxuICBpc0Rpc2FibGVkID0gZmFsc2U7XHJcbiAgX29uQ2hhbmdlID0gKHZhbHVlOiBJVmFsdWVbXSkgPT4ge307XHJcbiAgX29uVG91Y2hlZCA9ICgpID0+IHt9O1xyXG4gIF92YWxpZGF0b3JPbkNoYW5nZSA9ICgpID0+IHt9O1xyXG4gIHByaXZhdGUgc2xpZGVyUmVjdD86IERPTVJlY3Q7XHJcbiAgcHJpdmF0ZSB0aHVtYlJlY3Q/OiBET01SZWN0O1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGNoYW5nZURldGVjdG9yUmVmOiBDaGFuZ2VEZXRlY3RvclJlZikge31cclxuICBuZ09uSW5pdCgpOiB2b2lkIHt9XHJcblxyXG4gIHByaXZhdGUgZ2VuZXJhdGVJZCgpOiBzdHJpbmcge1xyXG4gICAgbGV0IGlkID0gJ25neC10aHVtYi0nICsgTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc3Vic3RyaW5nKDIsIDkpO1xyXG4gICAgaWYgKHRoaXMudmFsdWVzLmZpbmRJbmRleCgoeCkgPT4geC5pZCA9PSBpZCkgPj0gMCkge1xyXG4gICAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZUlkKCk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gaWQ7XHJcbiAgfVxyXG5cclxuICB3cml0ZVZhbHVlKGl0ZW1zPzogSVZhbHVlW10pOiB2b2lkIHtcclxuICAgIHRoaXMudmFsdWVzID0gW107XHJcbiAgICBpZiAoIWl0ZW1zIHx8ICFBcnJheS5pc0FycmF5KGl0ZW1zKSkge1xyXG4gICAgICBpdGVtcyA9IFtdO1xyXG4gICAgfVxyXG4gICAgaWYgKGl0ZW1zLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICBpdGVtcy5wdXNoKHsgaWQ6IHRoaXMuZ2VuZXJhdGVJZCgpLCB2YWx1ZTogdGhpcy5taW4gfSk7XHJcbiAgICB9XHJcbiAgICBmb3IgKGxldCB2YWwgb2YgaXRlbXMpIHtcclxuICAgICAgaWYgKHR5cGVvZiB2YWwudmFsdWUgIT09ICdudW1iZXInIHx8IGlzTmFOKHZhbC52YWx1ZSkpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JhbmdlU2xpZGVyQ29tcG9uZW50OiB2YWx1ZSBtdXN0IGJlIGFuIGFycmF5IG9mIG51bWJlcnMnKTtcclxuICAgICAgfVxyXG4gICAgICBsZXQgbmV3VmFsID0gK3ZhbC52YWx1ZTtcclxuICAgICAgaWYgKG5ld1ZhbCA8ICt0aGlzLm1pbikgbmV3VmFsID0gK3RoaXMubWluO1xyXG4gICAgICBlbHNlIGlmIChuZXdWYWwgPiArdGhpcy5tYXgpIG5ld1ZhbCA9ICt0aGlzLm1heDtcclxuICAgICAgdGhpcy52YWx1ZXMucHVzaCh7XHJcbiAgICAgICAgLi4udmFsLFxyXG4gICAgICAgIGlkOiB2YWwuaWQgPz8gdGhpcy5nZW5lcmF0ZUlkKCksXHJcbiAgICAgICAgdmFsdWU6IG5ld1ZhbCxcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICB0aGlzLnVwZGF0ZUFsbFRodW1iUG9zaXRpb25zKCk7XHJcbiAgfVxyXG4gIHZhbGlkYXRlKGNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCk6IFZhbGlkYXRpb25FcnJvcnMgfCBudWxsIHtcclxuICAgIHJldHVybiBudWxsOyAvLyBUT0RPOiByZXR1cm4gZXJyb3JzIGlmIGFueTtcclxuICB9XHJcbiAgcmVnaXN0ZXJPblZhbGlkYXRvckNoYW5nZT8oZm46ICgpID0+IHZvaWQpOiB2b2lkIHtcclxuICAgIHRoaXMuX3ZhbGlkYXRvck9uQ2hhbmdlID0gZm47XHJcbiAgfVxyXG5cclxuICByZWdpc3Rlck9uQ2hhbmdlKGZuOiBhbnkpOiB2b2lkIHtcclxuICAgIHRoaXMuX29uQ2hhbmdlID0gZm47XHJcbiAgfVxyXG4gIHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiBhbnkpOiB2b2lkIHtcclxuICAgIHRoaXMuX29uVG91Y2hlZCA9IGZuO1xyXG4gIH1cclxuICBzZXREaXNhYmxlZFN0YXRlPyhkaXNhYmxlZDogYm9vbGVhbik6IHZvaWQge1xyXG4gICAgdGhpcy5pc0Rpc2FibGVkID0gZGlzYWJsZWQ7XHJcbiAgfVxyXG4gIHByaXZhdGUgdXBkYXRlUmVjdHMoKSB7XHJcbiAgICB0aGlzLnNsaWRlclJlY3QgPSB0aGlzLnNsaWRlci5uYXRpdmVFbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgaWYgKHRoaXMudGh1bWIpIHtcclxuICAgICAgdGhpcy50aHVtYlJlY3QgPSB0aGlzLnRodW1iLm5hdGl2ZUVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICB9XHJcbiAgfVxyXG4gIEBIb3N0TGlzdGVuZXIoJ2RvY3VtZW50Om1vdXNlbW92ZScsIFsnJGV2ZW50J10pXHJcbiAgQEhvc3RMaXN0ZW5lcignZG9jdW1lbnQ6dG91Y2htb3ZlJywgWyckZXZlbnQnXSlcclxuICBvbkRyYWcoZXY6IE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50KSB7XHJcbiAgICBpZiAoIXRoaXMuaXNEcmFnZ2luZykgcmV0dXJuO1xyXG4gICAgdGhpcy51cGRhdGVUaHVtYlBvc2l0aW9uKGV2KTtcclxuICB9XHJcblxyXG4gIEBIb3N0TGlzdGVuZXIoJ3dpbmRvdzpyZXNpemUnLCBbJyRldmVudCddKVxyXG4gIG9uUmVzaXplKCkge1xyXG4gICAgdGhpcy53cml0ZVZhbHVlKHRoaXMudmFsdWVzKTtcclxuICB9XHJcbiAgZHJhZ1N0YXJ0KGV2OiBNb3VzZUV2ZW50IHwgVG91Y2hFdmVudCwgaW5kZXg6IG51bWJlcikge1xyXG4gICAgZXYuc3RvcFByb3BhZ2F0aW9uKCk7XHJcbiAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgdGhpcy5pc0RyYWdnaW5nID0gdHJ1ZTtcclxuICAgIHRoaXMuc2VsZWN0ZWRJbmRleCA9IGluZGV4O1xyXG4gICAgdGhpcy51cGRhdGVSZWN0cygpO1xyXG4gICAgdGhpcy51cGRhdGVUaHVtYlBvc2l0aW9uKGV2KTtcclxuICAgIHRoaXMuc2VsZWN0ZWRJbmRleENoYW5nZS5lbWl0KHRoaXMuc2VsZWN0ZWRJbmRleCk7XHJcbiAgfVxyXG5cclxuICBhZGRuZXdSYW5nZU9uU2xpZGVyQ2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50KSB7XHJcbiAgICBpZiAoIXRoaXMuYWRkTmV3UmFuZ2VPbkNsaWNrKSByZXR1cm47XHJcbiAgICBjb25zdCBwb3NpdGlvbiA9IGdldE9mZnNldFBvc2l0aW9uKGV2ZW50LCB0aGlzLnNsaWRlci5uYXRpdmVFbGVtZW50KTtcclxuICAgIGNvbnN0IG5ld1ZhbHVlID0gdGhpcy5taW4gKyAocG9zaXRpb24ueCAvIHRoaXMuc2xpZGVyUmVjdCEud2lkdGgpICogKHRoaXMubWF4IC0gdGhpcy5taW4pO1xyXG4gICAgLy8gbXVzdCBiZSBhZGQgd2l0aCBvcmRlciBieSBwb3NpdGlvblxyXG4gICAgY29uc3QgaW5kZXhCeU9yZGVyVmFsdWUgPSB0aGlzLnZhbHVlcy5maW5kSW5kZXgoKGl0ZW0pID0+IGl0ZW0udmFsdWUgPiBuZXdWYWx1ZSk7XHJcbiAgICBjb25zdCBpbnNlcnRJbmRleCA9IGluZGV4QnlPcmRlclZhbHVlID49IDAgPyBpbmRleEJ5T3JkZXJWYWx1ZSA6IHRoaXMudmFsdWVzLmxlbmd0aDtcclxuICAgIHRoaXMudmFsdWVzLnNwbGljZShpbnNlcnRJbmRleCwgMCwge1xyXG4gICAgICBpZDogdGhpcy5nZW5lcmF0ZUlkKCksXHJcbiAgICAgIHZhbHVlOiBuZXdWYWx1ZSxcclxuICAgIH0pO1xyXG4gICAgdGhpcy5kcmFnU3RhcnQoZXZlbnQsIGluc2VydEluZGV4KTtcclxuICAgIC8vIHRoaXMudXBkYXRlQWxsVGh1bWJQb3NpdGlvbnMoKTtcclxuICAgIC8vIHRoaXMudmFsdWVDaGFuZ2VkKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHVwZGF0ZVRodW1iUG9zaXRpb24oZXY6IE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50KSB7XHJcbiAgICBpZiAoIXRoaXMuaXNEcmFnZ2luZyB8fCB0aGlzLnNlbGVjdGVkSW5kZXggPT0gdW5kZWZpbmVkKSByZXR1cm47XHJcbiAgICBpZiAoIXRoaXMuc2xpZGVyUmVjdCB8fCAhdGhpcy50aHVtYlJlY3QpIHRoaXMudXBkYXRlUmVjdHMoKTtcclxuICAgIGxldCBwb3NpdGlvbiA9IGdldE9mZnNldFBvc2l0aW9uKGV2LCB0aGlzLnNsaWRlci5uYXRpdmVFbGVtZW50KTtcclxuICAgIGxldCB0aHVtYlJlYyA9IHRoaXMudGh1bWJSZWN0ITtcclxuICAgIHBvc2l0aW9uLnggLT0gdGh1bWJSZWMud2lkdGggLyAyO1xyXG4gICAgbGV0IHNsaWRlclJlYyA9IHRoaXMuc2xpZGVyUmVjdCE7XHJcbiAgICBjb25zdCB0aHVtYiA9IHRoaXMudmFsdWVzW3RoaXMuc2VsZWN0ZWRJbmRleF07XHJcbiAgICBpZiAocG9zaXRpb24ueCA8IDApIHtcclxuICAgICAgdGh1bWIueCA9IDA7XHJcbiAgICB9IGVsc2UgaWYgKHBvc2l0aW9uLnggPiBzbGlkZXJSZWMud2lkdGggLSB0aHVtYlJlYy53aWR0aCkge1xyXG4gICAgICB0aHVtYi54ID0gc2xpZGVyUmVjLndpZHRoIC0gdGh1bWJSZWMud2lkdGg7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aHVtYi54ID0gcG9zaXRpb24ueDtcclxuICAgIH1cclxuICAgIHRoaXMuc2V0VmFsdWVCeVBvc2l0aW9uKHRodW1iLCB0aHVtYlJlYywgc2xpZGVyUmVjKTtcclxuICB9XHJcblxyXG4gIHVwZGF0ZUFsbFRodW1iUG9zaXRpb25zKCkge1xyXG4gICAgLy8gd2FpdCB0byBhZGQgdGh1bWJzXHJcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgdGhpcy51cGRhdGVSZWN0cygpO1xyXG4gICAgICBjb25zdCBzbGlkZXJSZWMgPSB0aGlzLnNsaWRlclJlY3QhO1xyXG4gICAgICBjb25zdCB0aHVtYlJlYyA9IHRoaXMudGh1bWJSZWN0ITtcclxuICAgICAgZm9yIChsZXQgaXRlbSBvZiB0aGlzLnZhbHVlcykge1xyXG4gICAgICAgIGl0ZW0ueCA9ICgoaXRlbS52YWx1ZSAtIHRoaXMubWluKSAqIChzbGlkZXJSZWMud2lkdGggLSB0aHVtYlJlYy53aWR0aCkpIC8gKHRoaXMubWF4IC0gdGhpcy5taW4pO1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG4gIHNldFZhbHVlQnlQb3NpdGlvbih0aHVtYjogVmFsdWVNb2RlbCwgdGh1bWJSZWM6IERPTVJlY3QsIHNsaWRlclJlYzogRE9NUmVjdCkge1xyXG4gICAgY29uc3QgcGVyY2VudGFnZSA9ICh0aHVtYi54ID8/IDApIC8gKHNsaWRlclJlYy53aWR0aCAtIHRodW1iUmVjLndpZHRoKTtcclxuICAgIGxldCBuZXdWYWx1ZSA9IHRoaXMubWluICsgcGVyY2VudGFnZSAqICh0aGlzLm1heCAtIHRoaXMubWluKTtcclxuICAgIGNvbnN0IHN0ZXBEZWNpbWFsUGxhY2VzID0gKHRoaXMuc3RlcC50b1N0cmluZygpLnNwbGl0KCcuJylbMV0gfHwgJycpLmxlbmd0aDtcclxuICAgIG5ld1ZhbHVlID0gcGFyc2VGbG9hdCgoTWF0aC5yb3VuZChuZXdWYWx1ZSAvIHRoaXMuc3RlcCkgKiB0aGlzLnN0ZXApLnRvRml4ZWQoc3RlcERlY2ltYWxQbGFjZXMpKTtcclxuICAgIGxldCB2YWx1ZSA9IE1hdGgubWluKE1hdGgubWF4KG5ld1ZhbHVlLCB0aGlzLm1pbiksIHRoaXMubWF4KTtcclxuICAgIGlmICh0aHVtYi52YWx1ZSAhPT0gdmFsdWUpIHtcclxuICAgICAgdGh1bWIudmFsdWUgPSB2YWx1ZTtcclxuICAgICAgdGhpcy52YWx1ZUNoYW5nZWQoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIEBIb3N0TGlzdGVuZXIoJ2RvY3VtZW50Om1vdXNldXAnLCBbJyRldmVudCddKVxyXG4gIEBIb3N0TGlzdGVuZXIoJ2RvY3VtZW50OnRvdWNoZW5kJywgWyckZXZlbnQnXSlcclxuICBvbkRyYWdFbmQoZXY6IE1vdXNlRXZlbnQgfCBUb3VjaEV2ZW50KSB7XHJcbiAgICB0aGlzLmlzRHJhZ2dpbmcgPSBmYWxzZTtcclxuICAgIC8vIHRoaXMuc2VsZWN0ZWRJbmRleCA9IHVuZGVmaW5lZDtcclxuICB9XHJcblxyXG4gIHZhbHVlQ2hhbmdlZCgpIHtcclxuICAgIGNvbnN0IHYgPSB0aGlzLnZhbHVlczsgLy8gdGhpcy52YWx1ZXMubWFwKCh7IHgsIHRodW1iLCAuLi5yZXN0IH0pID0+ICh7IC4uLnJlc3QgfSkpO1xyXG4gICAgdGhpcy5fb25DaGFuZ2Uodik7XHJcbiAgICB0aGlzLmNoYW5nZS5lbWl0KHYpO1xyXG4gIH1cclxufVxyXG4iLCI8ZGl2IGNsYXNzPVwic2xpZGVyLWNvbnRhaW5lclwiPlxyXG4gIDxuZy1jb250ZW50PjwvbmctY29udGVudD5cclxuICA8ZGl2XHJcbiAgICAjc2xpZGVyXHJcbiAgICBjbGFzcz1cInNsaWRlclwiXHJcbiAgICBbY2xhc3MuYWRkLXJhbmdlLWN1cnNvcl09XCJhZGROZXdSYW5nZU9uQ2xpY2tcIlxyXG4gICAgW25nU3R5bGVdPVwieyAnLS1uZ3gtc2xpZGVyLWJnJzogYmFja2dyb3VuZCB9XCJcclxuICAgIFtjbGFzcy5iZy10cmFuc3BhcmVudF09XCJpc0JnVHJhbnNwYXJlbnRcIlxyXG4gICAgKG1vdXNlZG93bik9XCJhZGRuZXdSYW5nZU9uU2xpZGVyQ2xpY2soJGV2ZW50KVwiXHJcbiAgICAodG91Y2hzdGFydCk9XCJhZGRuZXdSYW5nZU9uU2xpZGVyQ2xpY2soJGV2ZW50KVwiPlxyXG4gICAgPGRpdlxyXG4gICAgICBjbGFzcz1cInRodW1iXCJcclxuICAgICAgW2NsYXNzLmlzLWFjdGl2ZV09XCJzZWxlY3RlZEluZGV4ID09IGlcIlxyXG4gICAgICAjdGh1bWJcclxuICAgICAgKm5nRm9yPVwibGV0IGl0ZW0gb2YgdmFsdWVzOyBsZXQgaSA9IGluZGV4XCJcclxuICAgICAgW3N0eWxlLmxlZnQucHhdPVwiaXRlbS54XCJcclxuICAgICAgW3N0eWxlLmJhY2tncm91bmRdPVwiaXRlbS5jb2xvclwiXHJcbiAgICAgIFt0aXRsZV09XCJpdGVtLnZhbHVlXCJcclxuICAgICAgKG1vdXNlZG93bik9XCJkcmFnU3RhcnQoJGV2ZW50LCBpKVwiXHJcbiAgICAgICh0b3VjaHN0YXJ0KT1cImRyYWdTdGFydCgkZXZlbnQsIGkpXCI+PC9kaXY+XHJcbiAgPC9kaXY+XHJcbjwvZGl2PlxyXG5cclxuPCEtLSB7eyBzZWxlY3RlZEluZGV4IH19XHJcbjxwcmUgZGlyPVwibHRyXCIgc3R5bGU9XCJ0ZXh0LWFsaWduOiBsZWZ0XCI+e3sgdmFsdWVzIHwganNvbiB9fTwvcHJlPiAtLT5cclxuXHJcbiJdfQ==