@acrodata/gradient-picker
Version:
A powerful and beautiful gradient picker.
100 lines • 23.8 kB
JavaScript
import { booleanAttribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, forwardRef, inject, Input, ViewEncapsulation, } from '@angular/core';
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import { GradientCheckbox, GradientFormGroup, GradientIconButton, GradientInputField, GradientUnitInput, } from './form-controls';
import { GradientStops } from './gradient-stops';
import { parseLinearGradient, stringifyLinearGradient } from './parser';
import { angleUnits, hueInterpolationMethods, polarColorSpaces, rectangularColorSpaces, reverseColorStops, } from './utils';
import * as i0 from "@angular/core";
import * as i1 from "@angular/forms";
export class LinearGradientPicker {
cdr = inject(ChangeDetectorRef);
disabled = false;
linearGradient = {
repeating: false,
orientation: { type: 'directional', value: '' },
stops: [{ color: '#000000' }],
};
value = '';
angleUnits = angleUnits;
directionOptions = [
{ label: '↑ top', value: 'top' },
{ label: '↗ top right', value: 'top right' },
{ label: '→ right', value: 'right' },
{ label: '↘ bottom right', value: 'bottom right' },
{ label: '↓ bottom', value: 'bottom' },
{ label: '↙ bottom left', value: 'bottom left' },
{ label: '← left', value: 'left' },
{ label: '↖ top left', value: 'top left' },
];
colorSpaceOptgroups = [
{ label: 'Rectangular', options: rectangularColorSpaces },
{ label: 'Polar', options: polarColorSpaces },
];
hueInterpolationMethodOptions = hueInterpolationMethods;
get isPolarColorSpace() {
return polarColorSpaces.includes(this.linearGradient.color?.space || '');
}
onChange = () => { };
onTouched = () => { };
writeValue(value) {
this.value = value || 'linear-gradient(transparent, #000000)';
this.linearGradient = parseLinearGradient(this.value);
this.cdr.markForCheck();
}
registerOnChange(fn) {
this.onChange = fn;
}
registerOnTouched(fn) {
this.onTouched = fn;
}
setDisabledState(isDisabled) {
this.disabled = isDisabled;
this.cdr.markForCheck();
}
onGradientChange() {
this.value = stringifyLinearGradient(this.linearGradient);
this.onChange(this.value);
}
reverseStops() {
this.linearGradient.stops = reverseColorStops(this.linearGradient.stops);
this.onGradientChange();
}
onColorSpaceChange() {
if (!this.isPolarColorSpace && this.linearGradient.color) {
this.linearGradient.color.method = undefined;
}
this.onGradientChange();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: LinearGradientPicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: LinearGradientPicker, isStandalone: true, selector: "linear-gradient-picker", inputs: { disabled: ["disabled", "disabled", booleanAttribute] }, host: { classAttribute: "linear-gradient-picker" }, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => LinearGradientPicker),
multi: true,
},
], ngImport: i0, template: "<gradient-form-group label=\"Angle\">\n @if (linearGradient.orientation.type === 'angular') {\n <gradient-unit-input\n [units]=\"angleUnits\"\n [(ngModel)]=\"linearGradient.orientation.value\"\n (ngModelChange)=\"onGradientChange()\"\n />\n } @else {\n <gradient-input-field>\n <select [(ngModel)]=\"linearGradient.orientation.value\" (change)=\"onGradientChange()\">\n @for (direction of directionOptions; track $index) {\n <option [value]=\"direction.value\">{{ direction.label }}</option>\n }\n </select>\n </gradient-input-field>\n }\n</gradient-form-group>\n\n@if (linearGradient.color) {\n <gradient-form-group label=\"Color interpolation\">\n <gradient-input-field>\n <select [(ngModel)]=\"linearGradient.color.space\" (change)=\"onColorSpaceChange()\">\n @for (colorSpaceGroup of colorSpaceOptgroups; track $index) {\n <optgroup [label]=\"colorSpaceGroup.label\">\n @for (colorSpace of colorSpaceGroup.options; track $index) {\n <option [value]=\"colorSpace\">{{ colorSpace }}</option>\n }\n </optgroup>\n }\n </select>\n </gradient-input-field>\n @if (isPolarColorSpace) {\n <gradient-input-field>\n <select [(ngModel)]=\"linearGradient.color.method\" (change)=\"onGradientChange()\">\n @for (hueInterp of hueInterpolationMethodOptions; track $index) {\n <option [value]=\"hueInterp\">{{ hueInterp }}</option>\n }\n </select>\n </gradient-input-field>\n }\n </gradient-form-group>\n}\n\n<gradient-form-group>\n <label gradientCheckbox>\n <input type=\"checkbox\" [(ngModel)]=\"linearGradient.repeating\" (change)=\"onGradientChange()\" />\n <span>Repeat</span>\n </label>\n\n <gradient-icon-button>\n <button type=\"button\" (click)=\"reverseStops()\" title=\"Reverse stops\" aria-label=\"Reverse stops\">\n <svg viewBox=\"0 0 24 24\">\n <path\n fill=\"currentColor\"\n d=\"M8.354 6.354a.5.5 0 1 0-.708-.708l-2.5 2.5a.5.5 0 0 0 0 .708l2.5 2.5a.5.5 0 0 0 .708-.708L6.707 9H18.5a.5.5 0 0 0 0-1H6.707zm7.292 7a.5.5 0 0 1 .708-.708l2.5 2.5a.5.5 0 0 1 0 .708l-2.5 2.5a.5.5 0 0 1-.708-.708L17.293 16H5.5a.5.5 0 0 1 0-1h11.793z\"\n />\n </svg>\n </button>\n </gradient-icon-button>\n</gradient-form-group>\n\n<gradient-stops [ngModel]=\"linearGradient.stops\" (ngModelChange)=\"onGradientChange()\" />\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: GradientStops, selector: "gradient-stops", inputs: ["disabled", "colorStops"], outputs: ["colorStopsChange"] }, { kind: "component", type: GradientInputField, selector: "gradient-input-field" }, { kind: "component", type: GradientFormGroup, selector: "gradient-form-group", inputs: ["label"] }, { kind: "component", type: GradientUnitInput, selector: "gradient-unit-input", inputs: ["disabled", "units"] }, { kind: "component", type: GradientCheckbox, selector: "[gradientCheckbox]" }, { kind: "component", type: GradientIconButton, selector: "gradient-icon-button" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: LinearGradientPicker, decorators: [{
type: Component,
args: [{ selector: 'linear-gradient-picker', standalone: true, imports: [
FormsModule,
GradientStops,
GradientInputField,
GradientFormGroup,
GradientUnitInput,
GradientCheckbox,
GradientIconButton,
], host: {
class: 'linear-gradient-picker',
}, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => LinearGradientPicker),
multi: true,
},
], template: "<gradient-form-group label=\"Angle\">\n @if (linearGradient.orientation.type === 'angular') {\n <gradient-unit-input\n [units]=\"angleUnits\"\n [(ngModel)]=\"linearGradient.orientation.value\"\n (ngModelChange)=\"onGradientChange()\"\n />\n } @else {\n <gradient-input-field>\n <select [(ngModel)]=\"linearGradient.orientation.value\" (change)=\"onGradientChange()\">\n @for (direction of directionOptions; track $index) {\n <option [value]=\"direction.value\">{{ direction.label }}</option>\n }\n </select>\n </gradient-input-field>\n }\n</gradient-form-group>\n\n@if (linearGradient.color) {\n <gradient-form-group label=\"Color interpolation\">\n <gradient-input-field>\n <select [(ngModel)]=\"linearGradient.color.space\" (change)=\"onColorSpaceChange()\">\n @for (colorSpaceGroup of colorSpaceOptgroups; track $index) {\n <optgroup [label]=\"colorSpaceGroup.label\">\n @for (colorSpace of colorSpaceGroup.options; track $index) {\n <option [value]=\"colorSpace\">{{ colorSpace }}</option>\n }\n </optgroup>\n }\n </select>\n </gradient-input-field>\n @if (isPolarColorSpace) {\n <gradient-input-field>\n <select [(ngModel)]=\"linearGradient.color.method\" (change)=\"onGradientChange()\">\n @for (hueInterp of hueInterpolationMethodOptions; track $index) {\n <option [value]=\"hueInterp\">{{ hueInterp }}</option>\n }\n </select>\n </gradient-input-field>\n }\n </gradient-form-group>\n}\n\n<gradient-form-group>\n <label gradientCheckbox>\n <input type=\"checkbox\" [(ngModel)]=\"linearGradient.repeating\" (change)=\"onGradientChange()\" />\n <span>Repeat</span>\n </label>\n\n <gradient-icon-button>\n <button type=\"button\" (click)=\"reverseStops()\" title=\"Reverse stops\" aria-label=\"Reverse stops\">\n <svg viewBox=\"0 0 24 24\">\n <path\n fill=\"currentColor\"\n d=\"M8.354 6.354a.5.5 0 1 0-.708-.708l-2.5 2.5a.5.5 0 0 0 0 .708l2.5 2.5a.5.5 0 0 0 .708-.708L6.707 9H18.5a.5.5 0 0 0 0-1H6.707zm7.292 7a.5.5 0 0 1 .708-.708l2.5 2.5a.5.5 0 0 1 0 .708l-2.5 2.5a.5.5 0 0 1-.708-.708L17.293 16H5.5a.5.5 0 0 1 0-1h11.793z\"\n />\n </svg>\n </button>\n </gradient-icon-button>\n</gradient-form-group>\n\n<gradient-stops [ngModel]=\"linearGradient.stops\" (ngModelChange)=\"onGradientChange()\" />\n" }]
}], propDecorators: { disabled: [{
type: Input,
args: [{ transform: booleanAttribute }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGluZWFyLWdyYWRpZW50LXBpY2tlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2dyYWRpZW50LXBpY2tlci9zcmMvbGliL2xpbmVhci1ncmFkaWVudC1waWNrZXIudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9ncmFkaWVudC1waWNrZXIvc3JjL2xpYi9saW5lYXItZ3JhZGllbnQtcGlja2VyLmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLGdCQUFnQixFQUNoQix1QkFBdUIsRUFDdkIsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxVQUFVLEVBQ1YsTUFBTSxFQUNOLEtBQUssRUFDTCxpQkFBaUIsR0FDbEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUF3QixXQUFXLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN0RixPQUFPLEVBQ0wsZ0JBQWdCLEVBQ2hCLGlCQUFpQixFQUNqQixrQkFBa0IsRUFDbEIsa0JBQWtCLEVBQ2xCLGlCQUFpQixHQUNsQixNQUFNLGlCQUFpQixDQUFDO0FBQ3pCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNqRCxPQUFPLEVBQXdCLG1CQUFtQixFQUFFLHVCQUF1QixFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQzlGLE9BQU8sRUFDTCxVQUFVLEVBQ1YsdUJBQXVCLEVBQ3ZCLGdCQUFnQixFQUNoQixzQkFBc0IsRUFDdEIsaUJBQWlCLEdBQ2xCLE1BQU0sU0FBUyxDQUFDOzs7QUE2QmpCLE1BQU0sT0FBTyxvQkFBb0I7SUFDdkIsR0FBRyxHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBRUEsUUFBUSxHQUFHLEtBQUssQ0FBQztJQUV6RCxjQUFjLEdBQXlCO1FBQ3JDLFNBQVMsRUFBRSxLQUFLO1FBQ2hCLFdBQVcsRUFBRSxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLEVB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LEVBQUUsQ0FBQztJQUMxQixDQUFDO3VHQTFFVSxvQkFBb0I7MkZBQXBCLG9CQUFvQix1R0FHWCxnQkFBZ0Isb0VBWHpCO1lBQ1Q7Z0JBQ0UsT0FBTyxFQUFFLGlCQUFpQjtnQkFDMUIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxvQkFBb0IsQ0FBQztnQkFDbkQsS0FBSyxFQUFFLElBQUk7YUFDWjtTQUNGLDBCQ3JESCx3NkVBOERBLHlERDlCSSxXQUFXLDI2QkFDWCxhQUFhLDhIQUNiLGtCQUFrQixpRUFDbEIsaUJBQWlCLG1GQUNqQixpQkFBaUIsK0ZBQ2pCLGdCQUFnQiwrREFDaEIsa0JBQWtCOzsyRkFpQlQsb0JBQW9CO2tCQTNCaEMsU0FBUzsrQkFDRSx3QkFBd0IsY0FDdEIsSUFBSSxXQUNQO3dCQUNQLFdBQVc7d0JBQ1gsYUFBYTt3QkFDYixrQkFBa0I7d0JBQ2xCLGlCQUFpQjt3QkFDakIsaUJBQWlCO3dCQUNqQixnQkFBZ0I7d0JBQ2hCLGtCQUFrQjtxQkFDbkIsUUFHSzt3QkFDSixLQUFLLEVBQUUsd0JBQXdCO3FCQUNoQyxpQkFDYyxpQkFBaUIsQ0FBQyxJQUFJLG1CQUNwQix1QkFBdUIsQ0FBQyxNQUFNLGFBQ3BDO3dCQUNUOzRCQUNFLE9BQU8sRUFBRSxpQkFBaUI7NEJBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLHFCQUFxQixDQUFDOzRCQUNuRCxLQUFLLEVBQUUsSUFBSTt5QkFDWjtxQkFDRjs4QkFLdUMsUUFBUTtzQkFBL0MsS0FBSzt1QkFBQyxFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIGJvb2xlYW5BdHRyaWJ1dGUsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBmb3J3YXJkUmVmLFxuICBpbmplY3QsXG4gIElucHV0LFxuICBWaWV3RW5jYXBzdWxhdGlvbixcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgRm9ybXNNb2R1bGUsIE5HX1ZBTFVFX0FDQ0VTU09SIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHtcbiAgR3JhZGllbnRDaGVja2JveCxcbiAgR3JhZGllbnRGb3JtR3JvdXAsXG4gIEdyYWRpZW50SWNvbkJ1dHRvbixcbiAgR3JhZGllbnRJbnB1dEZpZWxkLFxuICBHcmFkaWVudFVuaXRJbnB1dCxcbn0gZnJvbSAnLi9mb3JtLWNvbnRyb2xzJztcbmltcG9ydCB7IEdyYWRpZW50U3RvcHMgfSBmcm9tICcuL2dyYWRpZW50LXN0b3BzJztcbmltcG9ydCB7IExpbmVhckdyYWRpZW50UmVzdWx0LCBwYXJzZUxpbmVhckdyYWRpZW50LCBzdHJpbmdpZnlMaW5lYXJHcmFkaWVudCB9IGZyb20gJy4vcGFyc2VyJztcbmltcG9ydCB7XG4gIGFuZ2xlVW5pdHMsXG4gIGh1ZUludGVycG9sYXRpb25NZXRob2RzLFxuICBwb2xhckNvbG9yU3BhY2VzLFxuICByZWN0YW5ndWxhckNvbG9yU3BhY2VzLFxuICByZXZlcnNlQ29sb3JTdG9wcyxcbn0gZnJvbSAnLi91dGlscyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpbmVhci1ncmFkaWVudC1waWNrZXInLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXG4gICAgRm9ybXNNb2R1bGUsXG4gICAgR3JhZGllbnRTdG9wcyxcbiAgICBHcmFkaWVudElucHV0RmllbGQsXG4gICAgR3JhZGllbnRGb3JtR3JvdXAsXG4gICAgR3JhZGllbnRVbml0SW5wdXQsXG4gICAgR3JhZGllbnRDaGVja2JveCxcbiAgICBHcmFkaWVudEljb25CdXR0b24sXG4gIF0sXG4gIHRlbXBsYXRlVXJsOiAnLi9saW5lYXItZ3JhZGllbnQtcGlja2VyLmh0bWwnLFxuICBzdHlsZVVybDogJy4vbGluZWFyLWdyYWRpZW50LXBpY2tlci5zY3NzJyxcbiAgaG9zdDoge1xuICAgIGNsYXNzOiAnbGluZWFyLWdyYWRpZW50LXBpY2tlcicsXG4gIH0sXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBwcm92aWRlcnM6IFtcbiAgICB7XG4gICAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcbiAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IExpbmVhckdyYWRpZW50UGlja2VyKSxcbiAgICAgIG11bHRpOiB0cnVlLFxuICAgIH0sXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIExpbmVhckdyYWRpZW50UGlja2VyIGltcGxlbWVudHMgQ29udHJvbFZhbHVlQWNjZXNzb3Ige1xuICBwcml2YXRlIGNkciA9IGluamVjdChDaGFuZ2VEZXRlY3RvclJlZik7XG5cbiAgQElucHV0KHsgdHJhbnNmb3JtOiBib29sZWFuQXR0cmlidXRlIH0pIGRpc2FibGVkID0gZmFsc2U7XG5cbiAgbGluZWFyR3JhZGllbnQ6IExpbmVhckdyYWRpZW50UmVzdWx0ID0ge1xuICAgIHJlcGVhdGluZzogZmFsc2UsXG4gICAgb3JpZW50YXRpb246IHsgdHlwZTogJ2RpcmVjdGlvbmFsJywgdmFsdWU6ICcnIH0sXG4gICAgc3RvcHM6IFt7IGNvbG9yOiAnIzAwMDAwMCcgfV0sXG4gIH07XG5cbiAgdmFsdWUgPSAnJztcblxuICBhbmdsZVVuaXRzID0gYW5nbGVVbml0cztcblxuICBkaXJlY3Rpb25PcHRpb25zID0gW1xuICAgIHsgbGFiZWw6ICfihpEgdG9wJywgdmFsdWU6ICd0b3AnIH0sXG4gICAgeyBsYWJlbDogJ+KGlyB0b3AgcmlnaHQnLCB2YWx1ZTogJ3RvcCByaWdodCcgfSxcbiAgICB7IGxhYmVsOiAn4oaSIHJpZ2h0JywgdmFsdWU6ICdyaWdodCcgfSxcbiAgICB7IGxhYmVsOiAn4oaYIGJvdHRvbSByaWdodCcsIHZhbHVlOiAnYm90dG9tIHJpZ2h0JyB9LFxuICAgIHsgbGFiZWw6ICfihpMgYm90dG9tJywgdmFsdWU6ICdib3R0b20nIH0sXG4gICAgeyBsYWJlbDogJ+KGmSBib3R0b20gbGVmdCcsIHZhbHVlOiAnYm90dG9tIGxlZnQnIH0sXG4gICAgeyBsYWJlbDogJ+KGkCBsZWZ0JywgdmFsdWU6ICdsZWZ0JyB9LFxuICAgIHsgbGFiZWw6ICfihpYgdG9wIGxlZnQnLCB2YWx1ZTogJ3RvcCBsZWZ0JyB9LFxuICBdO1xuXG4gIGNvbG9yU3BhY2VPcHRncm91cHMgPSBbXG4gICAgeyBsYWJlbDogJ1JlY3Rhbmd1bGFyJywgb3B0aW9uczogcmVjdGFuZ3VsYXJDb2xvclNwYWNlcyB9LFxuICAgIHsgbGFiZWw6ICdQb2xhcicsIG9wdGlvbnM6IHBvbGFyQ29sb3JTcGFjZXMgfSxcbiAgXTtcblxuICBodWVJbnRlcnBvbGF0aW9uTWV0aG9kT3B0aW9ucyA9IGh1ZUludGVycG9sYXRpb25NZXRob2RzO1xuXG4gIGdldCBpc1BvbGFyQ29sb3JTcGFjZSgpIHtcbiAgICByZXR1cm4gcG9sYXJDb2xvclNwYWNlcy5pbmNsdWRlcyh0aGlzLmxpbmVhckdyYWRpZW50LmNvbG9yPy5zcGFjZSB8fCAnJyk7XG4gIH1cblxuICBwcml2YXRlIG9uQ2hhbmdlOiAodmFsdWU6IHN0cmluZykgPT4gdm9pZCA9ICgpID0+IHt9O1xuICBwcml2YXRlIG9uVG91Y2hlZDogKCkgPT4gdm9pZCA9ICgpID0+IHt9O1xuXG4gIHdyaXRlVmFsdWUodmFsdWU6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMudmFsdWUgPSB2YWx1ZSB8fCAnbGluZWFyLWdyYWRpZW50KHRyYW5zcGFyZW50LCAjMDAwMDAwKSc7XG4gICAgdGhpcy5saW5lYXJHcmFkaWVudCA9IHBhcnNlTGluZWFyR3JhZGllbnQodGhpcy52YWx1ZSk7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICByZWdpc3Rlck9uQ2hhbmdlKGZuOiAodmFsdWU6IHN0cmluZykgPT4gdm9pZCk6IHZvaWQge1xuICAgIHRoaXMub25DaGFuZ2UgPSBmbjtcbiAgfVxuXG4gIHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiAoKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdGhpcy5vblRvdWNoZWQgPSBmbjtcbiAgfVxuXG4gIHNldERpc2FibGVkU3RhdGUoaXNEaXNhYmxlZDogYm9vbGVhbikge1xuICAgIHRoaXMuZGlzYWJsZWQgPSBpc0Rpc2FibGVkO1xuICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICB9XG5cbiAgb25HcmFkaWVudENoYW5nZSgpIHtcbiAgICB0aGlzLnZhbHVlID0gc3RyaW5naWZ5TGluZWFyR3JhZGllbnQodGhpcy5saW5lYXJHcmFkaWVudCk7XG4gICAgdGhpcy5vbkNoYW5nZSh0aGlzLnZhbHVlKTtcbiAgfVxuXG4gIHJldmVyc2VTdG9wcygpIHtcbiAgICB0aGlzLmxpbmVhckdyYWRpZW50LnN0b3BzID0gcmV2ZXJzZUNvbG9yU3RvcHModGhpcy5saW5lYXJHcmFkaWVudC5zdG9wcyk7XG4gICAgdGhpcy5vbkdyYWRpZW50Q2hhbmdlKCk7XG4gIH1cblxuICBvbkNvbG9yU3BhY2VDaGFuZ2UoKSB7XG4gICAgaWYgKCF0aGlzLmlzUG9sYXJDb2xvclNwYWNlICYmIHRoaXMubGluZWFyR3JhZGllbnQuY29sb3IpIHtcbiAgICAgIHRoaXMubGluZWFyR3JhZGllbnQuY29sb3IubWV0aG9kID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgICB0aGlzLm9uR3JhZGllbnRDaGFuZ2UoKTtcbiAgfVxufVxuIiwiPGdyYWRpZW50LWZvcm0tZ3JvdXAgbGFiZWw9XCJBbmdsZVwiPlxuICBAaWYgKGxpbmVhckdyYWRpZW50Lm9yaWVudGF0aW9uLnR5cGUgPT09ICdhbmd1bGFyJykge1xuICAgIDxncmFkaWVudC11bml0LWlucHV0XG4gICAgICBbdW5pdHNdPVwiYW5nbGVVbml0c1wiXG4gICAgICBbKG5nTW9kZWwpXT1cImxpbmVhckdyYWRpZW50Lm9yaWVudGF0aW9uLnZhbHVlXCJcbiAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uR3JhZGllbnRDaGFuZ2UoKVwiXG4gICAgLz5cbiAgfSBAZWxzZSB7XG4gICAgPGdyYWRpZW50LWlucHV0LWZpZWxkPlxuICAgICAgPHNlbGVjdCBbKG5nTW9kZWwpXT1cImxpbmVhckdyYWRpZW50Lm9yaWVudGF0aW9uLnZhbHVlXCIgKGNoYW5nZSk9XCJvbkdyYWRpZW50Q2hhbmdlKClcIj5cbiAgICAgICAgQGZvciAoZGlyZWN0aW9uIG9mIGRpcmVjdGlvbk9wdGlvbnM7IHRyYWNrICRpbmRleCkge1xuICAgICAgICAgIDxvcHRpb24gW3ZhbHVlXT1cImRpcmVjdGlvbi52YWx1ZVwiPnt7IGRpcmVjdGlvbi5sYWJlbCB9fTwvb3B0aW9uPlxuICAgICAgICB9XG4gICAgICA8L3NlbGVjdD5cbiAgICA8L2dyYWRpZW50LWlucHV0LWZpZWxkPlxuICB9XG48L2dyYWRpZW50LWZvcm0tZ3JvdXA+XG5cbkBpZiAobGluZWFyR3JhZGllbnQuY29sb3IpIHtcbiAgPGdyYWRpZW50LWZvcm0tZ3JvdXAgbGFiZWw9XCJDb2xvciBpbnRlcnBvbGF0aW9uXCI+XG4gICAgPGdyYWRpZW50LWlucHV0LWZpZWxkPlxuICAgICAgPHNlbGVjdCBbKG5nTW9kZWwpXT1cImxpbmVhckdyYWRpZW50LmNvbG9yLnNwYWNlXCIgKGNoYW5nZSk9XCJvbkNvbG9yU3BhY2VDaGFuZ2UoKVwiPlxuICAgICAgICBAZm9yIChjb2xvclNwYWNlR3JvdXAgb2YgY29sb3JTcGFjZU9wdGdyb3VwczsgdHJhY2sgJGluZGV4KSB7XG4gICAgICAgICAgPG9wdGdyb3VwIFtsYWJlbF09XCJjb2xvclNwYWNlR3JvdXAubGFiZWxcIj5cbiAgICAgICAgICAgIEBmb3IgKGNvbG9yU3BhY2Ugb2YgY29sb3JTcGFjZUdyb3VwLm9wdGlvbnM7IHRyYWNrICRpbmRleCkge1xuICAgICAgICAgICAgICA8b3B0aW9uIFt2YWx1ZV09XCJjb2xvclNwYWNlXCI+e3sgY29sb3JTcGFjZSB9fTwvb3B0aW9uPlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvb3B0Z3JvdXA+XG4gICAgICAgIH1cbiAgICAgIDwvc2VsZWN0PlxuICAgIDwvZ3JhZGllbnQtaW5wdXQtZmllbGQ+XG4gICAgQGlmIChpc1BvbGFyQ29sb3JTcGFjZSkge1xuICAgICAgPGdyYWRpZW50LWlucHV0LWZpZWxkPlxuICAgICAgICA8c2VsZWN0IFsobmdNb2RlbCldPVwibGluZWFyR3JhZGllbnQuY29sb3IubWV0aG9kXCIgKGNoYW5nZSk9XCJvbkdyYWRpZW50Q2hhbmdlKClcIj5cbiAgICAgICAgICBAZm9yIChodWVJbnRlcnAgb2YgaHVlSW50ZXJwb2xhdGlvbk1ldGhvZE9wdGlvbnM7IHRyYWNrICRpbmRleCkge1xuICAgICAgICAgICAgPG9wdGlvbiBbdmFsdWVdPVwiaHVlSW50ZXJwXCI+e3sgaHVlSW50ZXJwIH19PC9vcHRpb24+XG4gICAgICAgICAgfVxuICAgICAgICA8L3NlbGVjdD5cbiAgICAgIDwvZ3JhZGllbnQtaW5wdXQtZmllbGQ+XG4gICAgfVxuICA8L2dyYWRpZW50LWZvcm0tZ3JvdXA+XG59XG5cbjxncmFkaWVudC1mb3JtLWdyb3VwPlxuICA8bGFiZWwgZ3JhZGllbnRDaGVja2JveD5cbiAgICA8aW5wdXQgdHlwZT1cImNoZWNrYm94XCIgWyhuZ01vZGVsKV09XCJsaW5lYXJHcmFkaWVudC5yZXBlYXRpbmdcIiAoY2hhbmdlKT1cIm9uR3JhZGllbnRDaGFuZ2UoKVwiIC8+XG4gICAgPHNwYW4+UmVwZWF0PC9zcGFuPlxuICA8L2xhYmVsPlxuXG4gIDxncmFkaWVudC1pY29uLWJ1dHRvbj5cbiAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiAoY2xpY2spPVwicmV2ZXJzZVN0b3BzKClcIiB0aXRsZT1cIlJldmVyc2Ugc3RvcHNcIiBhcmlhLWxhYmVsPVwiUmV2ZXJzZSBzdG9wc1wiPlxuICAgICAgPHN2ZyB2aWV3Qm94PVwiMCAwIDI0IDI0XCI+XG4gICAgICAgIDxwYXRoXG4gICAgICAgICAgZmlsbD1cImN1cnJlbnRDb2xvclwiXG4gICAgICAgICAgZD1cIk04LjM1NCA2LjM1NGEuNS41IDAgMSAwLS43MDgtLjcwOGwtMi41IDIuNWEuNS41IDAgMCAwIDAgLjcwOGwyLjUgMi41YS41LjUgMCAwIDAgLjcwOC0uNzA4TDYuNzA3IDlIMTguNWEuNS41IDAgMCAwIDAtMUg2LjcwN3ptNy4yOTIgN2EuNS41IDAgMCAxIC43MDgtLjcwOGwyLjUgMi41YS41LjUgMCAwIDEgMCAuNzA4bC0yLjUgMi41YS41LjUgMCAwIDEtLjcwOC0uNzA4TDE3LjI5MyAxNkg1LjVhLjUuNSAwIDAgMSAwLTFoMTEuNzkzelwiXG4gICAgICAgIC8+XG4gICAgICA8L3N2Zz5cbiAgICA8L2J1dHRvbj5cbiAgPC9ncmFkaWVudC1pY29uLWJ1dHRvbj5cbjwvZ3JhZGllbnQtZm9ybS1ncm91cD5cblxuPGdyYWRpZW50LXN0b3BzIFtuZ01vZGVsXT1cImxpbmVhckdyYWRpZW50LnN0b3BzXCIgKG5nTW9kZWxDaGFuZ2UpPVwib25HcmFkaWVudENoYW5nZSgpXCIgLz5cbiJdfQ==