angular-calendar-timeline
Version:
A timeline for angular that shows events on a timeline board in different modes: days, weeks, and months.
70 lines • 18.5 kB
JavaScript
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from "@angular/core";
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "angular-resizable-element";
export class TimelinePanelComponent {
constructor(_cdr) {
this._cdr = _cdr;
this.items = [];
this.childGroupOffset = 15;
this.widthChanged = new EventEmitter();
}
ngOnChanges(changes) {
if (Object.keys(changes).some(key => ['width', 'minWidth', 'maxWidth'].includes(key))) {
this._validateWidth();
}
}
trackById(index, item) {
return item.id;
}
handleResize(event) {
const newWidth = event.rectangle.width;
if (newWidth < this.minWidth || newWidth > this.maxWidth)
return;
this.width = newWidth;
this.widthChanged.emit(this.width);
}
toggleExpand(item) {
item.childrenItemsExpanded = !item.childrenItemsExpanded;
this._cdr.markForCheck();
}
_validateWidth() {
if (this.width < this.minWidth) {
this.width = this.minWidth;
}
if (this.width > this.maxWidth) {
this.width = this.maxWidth;
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimelinePanelComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TimelinePanelComponent, selector: "timeline-panel", inputs: { items: "items", label: "label", width: "width", resizable: "resizable", minWidth: "minWidth", maxWidth: "maxWidth", headerHeight: "headerHeight", rowHeight: "rowHeight", locale: "locale", childGroupOffset: "childGroupOffset", itemTemplate: "itemTemplate" }, outputs: { widthChanged: "widthChanged" }, usesOnChanges: true, ngImport: i0, template: "<div class='panel resize-handle-right'\r\n mwlResizable\r\n (resizing)='handleResize($event)'\r\n [style.width.px]='width'>\r\n\r\n <div mwlResizeHandle [resizeEdges]=\"{right: resizable}\"></div>\r\n\r\n <div class='label' [style.height.px]=\"headerHeight\">{{label}}</div>\r\n\r\n <ng-container *ngFor='let item of items; trackBy: trackById; let index = index'\r\n [ngTemplateOutlet]='itemsIterationTemplate'\r\n [ngTemplateOutletContext]='{item: item, index: index, depth: 0}'>\r\n </ng-container>\r\n\r\n <ng-template #itemsIterationTemplate let-item='item' let-index='index' let-depth='depth'>\r\n\r\n <ng-container [ngTemplateOutlet]='itemTemplate || defaultItemTemplate'\r\n [ngTemplateOutletContext]='{item: item, index: index, depth: depth, locale: locale}'>\r\n </ng-container>\r\n \r\n <div *ngIf='item.childrenItemsExpanded'>\r\n <ng-container *ngFor='let innerItem of (item.childrenItems || []); trackBy: trackById; let index = index'\r\n [ngTemplateOutletContext]='{item: innerItem, index: index, depth: depth + 1, locale: locale}'\r\n [ngTemplateOutlet]='itemsIterationTemplate'\r\n ></ng-container>\r\n </div>\r\n </ng-template>\r\n</div>\r\n\r\n<ng-template #defaultItemTemplate let-item='item' let-index='index' let-depth='depth'>\r\n <div [style.height.px]='rowHeight * (item.streamItems ? item?._streamLevels?.length || 1 : 1)'\r\n [style.width.px]='width'\r\n [class.can-collapse]='item.childrenItems && item.childrenItems.length'\r\n class='panel-item'>\r\n\r\n <div [style.marginLeft.px]='depth * childGroupOffset' (click)='toggleExpand(item)' class='item-content'>\r\n <div class='collapse-icon'\r\n [class.collapsed]='!item.childrenItemsExpanded'>\r\n </div>\r\n\r\n <span class='item-name' title=\"{{item.name}}\">{{item.name}}</span>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host{display:contents}.panel{height:100%;display:flex;flex-direction:column;position:sticky;left:0;z-index:1001;flex-shrink:0;background-color:#f8f8f8;border-right:1px solid #d0d0d0}.label{display:flex;justify-content:center;align-items:center;width:100%;position:sticky;top:0;left:0;z-index:100;flex-shrink:0;border-bottom:#d0d0d0 1px solid}.panel-item{border-bottom:#d0d0d0 1px solid;padding:5px 10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box;display:flex}.panel-item.can-collapse .collapse-icon{display:inline-block!important}.panel-item.can-collapse .item-content{cursor:pointer}.panel-item .item-content{display:inline-flex;align-items:center;box-sizing:border-box;max-width:100%}.panel-item .item-content .collapse-icon{border:solid #5a5a5a;border-width:0 2px 2px 0;display:none;padding:2.5px;margin-right:8px;transform:rotate(45deg)}.panel-item .item-content .collapse-icon.collapsed{transform:rotate(-45deg)}.panel-item .item-content .item-name{text-overflow:ellipsis;white-space:nowrap;overflow:hidden;width:auto}[mwlResizeHandle]{position:absolute;top:0;right:0;box-sizing:border-box;width:5px;height:100%;cursor:col-resize;z-index:10000}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.ResizableDirective, selector: "[mwlResizable]", inputs: ["validateResize", "enableGhostResize", "resizeSnapGrid", "resizeCursors", "ghostElementPositioning", "allowNegativeResizes", "mouseMoveThrottleMS"], outputs: ["resizeStart", "resizing", "resizeEnd"], exportAs: ["mwlResizable"] }, { kind: "directive", type: i2.ResizeHandleDirective, selector: "[mwlResizeHandle]", inputs: ["resizeEdges", "resizableContainer"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimelinePanelComponent, decorators: [{
type: Component,
args: [{ selector: 'timeline-panel', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class='panel resize-handle-right'\r\n mwlResizable\r\n (resizing)='handleResize($event)'\r\n [style.width.px]='width'>\r\n\r\n <div mwlResizeHandle [resizeEdges]=\"{right: resizable}\"></div>\r\n\r\n <div class='label' [style.height.px]=\"headerHeight\">{{label}}</div>\r\n\r\n <ng-container *ngFor='let item of items; trackBy: trackById; let index = index'\r\n [ngTemplateOutlet]='itemsIterationTemplate'\r\n [ngTemplateOutletContext]='{item: item, index: index, depth: 0}'>\r\n </ng-container>\r\n\r\n <ng-template #itemsIterationTemplate let-item='item' let-index='index' let-depth='depth'>\r\n\r\n <ng-container [ngTemplateOutlet]='itemTemplate || defaultItemTemplate'\r\n [ngTemplateOutletContext]='{item: item, index: index, depth: depth, locale: locale}'>\r\n </ng-container>\r\n \r\n <div *ngIf='item.childrenItemsExpanded'>\r\n <ng-container *ngFor='let innerItem of (item.childrenItems || []); trackBy: trackById; let index = index'\r\n [ngTemplateOutletContext]='{item: innerItem, index: index, depth: depth + 1, locale: locale}'\r\n [ngTemplateOutlet]='itemsIterationTemplate'\r\n ></ng-container>\r\n </div>\r\n </ng-template>\r\n</div>\r\n\r\n<ng-template #defaultItemTemplate let-item='item' let-index='index' let-depth='depth'>\r\n <div [style.height.px]='rowHeight * (item.streamItems ? item?._streamLevels?.length || 1 : 1)'\r\n [style.width.px]='width'\r\n [class.can-collapse]='item.childrenItems && item.childrenItems.length'\r\n class='panel-item'>\r\n\r\n <div [style.marginLeft.px]='depth * childGroupOffset' (click)='toggleExpand(item)' class='item-content'>\r\n <div class='collapse-icon'\r\n [class.collapsed]='!item.childrenItemsExpanded'>\r\n </div>\r\n\r\n <span class='item-name' title=\"{{item.name}}\">{{item.name}}</span>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host{display:contents}.panel{height:100%;display:flex;flex-direction:column;position:sticky;left:0;z-index:1001;flex-shrink:0;background-color:#f8f8f8;border-right:1px solid #d0d0d0}.label{display:flex;justify-content:center;align-items:center;width:100%;position:sticky;top:0;left:0;z-index:100;flex-shrink:0;border-bottom:#d0d0d0 1px solid}.panel-item{border-bottom:#d0d0d0 1px solid;padding:5px 10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box;display:flex}.panel-item.can-collapse .collapse-icon{display:inline-block!important}.panel-item.can-collapse .item-content{cursor:pointer}.panel-item .item-content{display:inline-flex;align-items:center;box-sizing:border-box;max-width:100%}.panel-item .item-content .collapse-icon{border:solid #5a5a5a;border-width:0 2px 2px 0;display:none;padding:2.5px;margin-right:8px;transform:rotate(45deg)}.panel-item .item-content .collapse-icon.collapsed{transform:rotate(-45deg)}.panel-item .item-content .item-name{text-overflow:ellipsis;white-space:nowrap;overflow:hidden;width:auto}[mwlResizeHandle]{position:absolute;top:0;right:0;box-sizing:border-box;width:5px;height:100%;cursor:col-resize;z-index:10000}\n"] }]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { items: [{
type: Input
}], label: [{
type: Input
}], width: [{
type: Input
}], resizable: [{
type: Input
}], minWidth: [{
type: Input
}], maxWidth: [{
type: Input
}], headerHeight: [{
type: Input
}], rowHeight: [{
type: Input
}], locale: [{
type: Input
}], childGroupOffset: [{
type: Input
}], itemTemplate: [{
type: Input
}], widthChanged: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZWxpbmUtcGFuZWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1jYWxlbmRhci10aW1lbGluZS9zcmMvbGliL2NvbXBvbmVudHMvcGFuZWwvdGltZWxpbmUtcGFuZWwuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1jYWxlbmRhci10aW1lbGluZS9zcmMvbGliL2NvbXBvbmVudHMvcGFuZWwvdGltZWxpbmUtcGFuZWwuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixTQUFTLEVBQ1QsWUFBWSxFQUNaLEtBQUssRUFFTCxNQUFNLEVBR1AsTUFBTSxlQUFlLENBQUM7Ozs7QUFVdkIsTUFBTSxPQUFPLHNCQUFzQjtJQXlCakMsWUFBb0IsSUFBdUI7UUFBdkIsU0FBSSxHQUFKLElBQUksQ0FBbUI7UUF4QmxDLFVBQUssR0FBb0IsRUFBRSxDQUFDO1FBa0I1QixxQkFBZ0IsR0FBVyxFQUFFLENBQUM7UUFJN0IsaUJBQVksR0FBRyxJQUFJLFlBQVksRUFBVSxDQUFDO0lBR3BELENBQUM7SUFFRCxXQUFXLENBQUMsT0FBc0I7UUFDaEMsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxVQUFVLENBQUMsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ3RGLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN4QixDQUFDO0lBQ0gsQ0FBQztJQUVELFNBQVMsQ0FBQyxLQUFhLEVBQUUsSUFBZTtRQUN0QyxPQUFPLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDakIsQ0FBQztJQUVELFlBQVksQ0FBQyxLQUFrQjtRQUM3QixNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQztRQUV2QyxJQUFJLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxJQUFJLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUTtZQUN0RCxPQUFPO1FBRVQsSUFBSSxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUM7UUFDdEIsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFRCxZQUFZLENBQUMsSUFBbUI7UUFDOUIsSUFBSSxDQUFDLHFCQUFxQixHQUFHLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDO1FBQ3pELElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVPLGNBQWM7UUFDcEIsSUFBSSxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUMvQixJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7UUFDN0IsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDL0IsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDO1FBQzdCLENBQUM7SUFDSCxDQUFDOytHQTdEVSxzQkFBc0I7bUdBQXRCLHNCQUFzQixrWUNuQm5DLGs4REE0Q0E7OzRGRHpCYSxzQkFBc0I7a0JBTmxDLFNBQVM7K0JBQ0UsZ0JBQWdCLG1CQUdULHVCQUF1QixDQUFDLE1BQU07c0ZBR3RDLEtBQUs7c0JBQWIsS0FBSztnQkFFRyxLQUFLO3NCQUFiLEtBQUs7Z0JBRUcsS0FBSztzQkFBYixLQUFLO2dCQUVHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBRUcsUUFBUTtzQkFBaEIsS0FBSztnQkFFRyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBRUcsU0FBUztzQkFBakIsS0FBSztnQkFFRyxNQUFNO3NCQUFkLEtBQUs7Z0JBRUcsZ0JBQWdCO3NCQUF4QixLQUFLO2dCQUVHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBRUksWUFBWTtzQkFBckIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENoYW5nZURldGVjdG9yUmVmLFxyXG4gIENvbXBvbmVudCxcclxuICBFdmVudEVtaXR0ZXIsXHJcbiAgSW5wdXQsXHJcbiAgT25DaGFuZ2VzLFxyXG4gIE91dHB1dCxcclxuICBTaW1wbGVDaGFuZ2VzLFxyXG4gIFRlbXBsYXRlUmVmXHJcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcclxuaW1wb3J0IHsgUmVzaXplRXZlbnQgfSBmcm9tIFwiYW5ndWxhci1yZXNpemFibGUtZWxlbWVudFwiO1xyXG5pbXBvcnQgeyBJVGltZWxpbmVJdGVtLCBJSWRPYmplY3QgfSBmcm9tIFwiLi4vLi4vbW9kZWxzXCI7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ3RpbWVsaW5lLXBhbmVsJyxcclxuICB0ZW1wbGF0ZVVybDogJ3RpbWVsaW5lLXBhbmVsLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsndGltZWxpbmUtcGFuZWwuY29tcG9uZW50LnNjc3MnXSxcclxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaFxyXG59KVxyXG5leHBvcnQgY2xhc3MgVGltZWxpbmVQYW5lbENvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XHJcbiAgQElucHV0KCkgaXRlbXM6IElUaW1lbGluZUl0ZW1bXSA9IFtdO1xyXG5cclxuICBASW5wdXQoKSBsYWJlbDogc3RyaW5nO1xyXG5cclxuICBASW5wdXQoKSB3aWR0aDogbnVtYmVyO1xyXG5cclxuICBASW5wdXQoKSByZXNpemFibGU6IGJvb2xlYW47XHJcblxyXG4gIEBJbnB1dCgpIG1pbldpZHRoOiBudW1iZXI7XHJcblxyXG4gIEBJbnB1dCgpIG1heFdpZHRoOiBudW1iZXI7XHJcblxyXG4gIEBJbnB1dCgpIGhlYWRlckhlaWdodDogbnVtYmVyO1xyXG5cclxuICBASW5wdXQoKSByb3dIZWlnaHQ6IG51bWJlcjtcclxuXHJcbiAgQElucHV0KCkgbG9jYWxlOiBzdHJpbmc7XHJcblxyXG4gIEBJbnB1dCgpIGNoaWxkR3JvdXBPZmZzZXQ6IG51bWJlciA9IDE1O1xyXG5cclxuICBASW5wdXQoKSBpdGVtVGVtcGxhdGU6IFRlbXBsYXRlUmVmPHsgaXRlbTogSVRpbWVsaW5lSXRlbSwgaW5kZXg6IG51bWJlciwgZGVwdGg6IG51bWJlciwgbG9jYWxlOiBzdHJpbmcgfT5cclxuXHJcbiAgQE91dHB1dCgpIHdpZHRoQ2hhbmdlZCA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIF9jZHI6IENoYW5nZURldGVjdG9yUmVmKSB7XHJcbiAgfVxyXG5cclxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XHJcbiAgICBpZiAoT2JqZWN0LmtleXMoY2hhbmdlcykuc29tZShrZXkgPT4gWyd3aWR0aCcsICdtaW5XaWR0aCcsICdtYXhXaWR0aCddLmluY2x1ZGVzKGtleSkpKSB7XHJcbiAgICAgIHRoaXMuX3ZhbGlkYXRlV2lkdGgoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyYWNrQnlJZChpbmRleDogbnVtYmVyLCBpdGVtOiBJSWRPYmplY3QpOiBudW1iZXIgfCBzdHJpbmcge1xyXG4gICAgcmV0dXJuIGl0ZW0uaWQ7XHJcbiAgfVxyXG5cclxuICBoYW5kbGVSZXNpemUoZXZlbnQ6IFJlc2l6ZUV2ZW50KSB7XHJcbiAgICBjb25zdCBuZXdXaWR0aCA9IGV2ZW50LnJlY3RhbmdsZS53aWR0aDtcclxuXHJcbiAgICBpZiAobmV3V2lkdGggPCB0aGlzLm1pbldpZHRoIHx8IG5ld1dpZHRoID4gdGhpcy5tYXhXaWR0aClcclxuICAgICAgcmV0dXJuO1xyXG5cclxuICAgIHRoaXMud2lkdGggPSBuZXdXaWR0aDtcclxuICAgIHRoaXMud2lkdGhDaGFuZ2VkLmVtaXQodGhpcy53aWR0aCk7XHJcbiAgfVxyXG5cclxuICB0b2dnbGVFeHBhbmQoaXRlbTogSVRpbWVsaW5lSXRlbSk6IHZvaWQge1xyXG4gICAgaXRlbS5jaGlsZHJlbkl0ZW1zRXhwYW5kZWQgPSAhaXRlbS5jaGlsZHJlbkl0ZW1zRXhwYW5kZWQ7XHJcbiAgICB0aGlzLl9jZHIubWFya0ZvckNoZWNrKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIF92YWxpZGF0ZVdpZHRoKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMud2lkdGggPCB0aGlzLm1pbldpZHRoKSB7XHJcbiAgICAgIHRoaXMud2lkdGggPSB0aGlzLm1pbldpZHRoO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLndpZHRoID4gdGhpcy5tYXhXaWR0aCkge1xyXG4gICAgICB0aGlzLndpZHRoID0gdGhpcy5tYXhXaWR0aDtcclxuICAgIH1cclxuICB9XHJcbn1cclxuIiwiPGRpdiBjbGFzcz0ncGFuZWwgcmVzaXplLWhhbmRsZS1yaWdodCdcclxuICAgICBtd2xSZXNpemFibGVcclxuICAgICAocmVzaXppbmcpPSdoYW5kbGVSZXNpemUoJGV2ZW50KSdcclxuICAgICBbc3R5bGUud2lkdGgucHhdPSd3aWR0aCc+XHJcblxyXG4gIDxkaXYgbXdsUmVzaXplSGFuZGxlIFtyZXNpemVFZGdlc109XCJ7cmlnaHQ6IHJlc2l6YWJsZX1cIj48L2Rpdj5cclxuXHJcbiAgPGRpdiBjbGFzcz0nbGFiZWwnIFtzdHlsZS5oZWlnaHQucHhdPVwiaGVhZGVySGVpZ2h0XCI+e3tsYWJlbH19PC9kaXY+XHJcblxyXG4gIDxuZy1jb250YWluZXIgKm5nRm9yPSdsZXQgaXRlbSBvZiBpdGVtczsgdHJhY2tCeTogdHJhY2tCeUlkOyBsZXQgaW5kZXggPSBpbmRleCdcclxuICAgICAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT0naXRlbXNJdGVyYXRpb25UZW1wbGF0ZSdcclxuICAgICAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0Q29udGV4dF09J3tpdGVtOiBpdGVtLCBpbmRleDogaW5kZXgsIGRlcHRoOiAwfSc+XHJcbiAgPC9uZy1jb250YWluZXI+XHJcblxyXG4gIDxuZy10ZW1wbGF0ZSAjaXRlbXNJdGVyYXRpb25UZW1wbGF0ZSBsZXQtaXRlbT0naXRlbScgbGV0LWluZGV4PSdpbmRleCcgbGV0LWRlcHRoPSdkZXB0aCc+XHJcblxyXG4gICAgPG5nLWNvbnRhaW5lciBbbmdUZW1wbGF0ZU91dGxldF09J2l0ZW1UZW1wbGF0ZSB8fCBkZWZhdWx0SXRlbVRlbXBsYXRlJ1xyXG4gICAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPSd7aXRlbTogaXRlbSwgaW5kZXg6IGluZGV4LCBkZXB0aDogZGVwdGgsIGxvY2FsZTogbG9jYWxlfSc+XHJcbiAgICA8L25nLWNvbnRhaW5lcj5cclxuICAgIFxyXG4gICAgPGRpdiAqbmdJZj0naXRlbS5jaGlsZHJlbkl0ZW1zRXhwYW5kZWQnPlxyXG4gICAgICA8bmctY29udGFpbmVyICpuZ0Zvcj0nbGV0IGlubmVySXRlbSBvZiAoaXRlbS5jaGlsZHJlbkl0ZW1zIHx8IFtdKTsgdHJhY2tCeTogdHJhY2tCeUlkOyAgbGV0IGluZGV4ID0gaW5kZXgnXHJcbiAgICAgICAgICAgICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT0ne2l0ZW06IGlubmVySXRlbSwgaW5kZXg6IGluZGV4LCBkZXB0aDogZGVwdGggKyAxLCBsb2NhbGU6IGxvY2FsZX0nXHJcbiAgICAgICAgICAgICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRdPSdpdGVtc0l0ZXJhdGlvblRlbXBsYXRlJ1xyXG4gICAgICA+PC9uZy1jb250YWluZXI+XHJcbiAgICA8L2Rpdj5cclxuICA8L25nLXRlbXBsYXRlPlxyXG48L2Rpdj5cclxuXHJcbjxuZy10ZW1wbGF0ZSAjZGVmYXVsdEl0ZW1UZW1wbGF0ZSBsZXQtaXRlbT0naXRlbScgbGV0LWluZGV4PSdpbmRleCcgbGV0LWRlcHRoPSdkZXB0aCc+XHJcbiAgPGRpdiBbc3R5bGUuaGVpZ2h0LnB4XT0ncm93SGVpZ2h0ICogKGl0ZW0uc3RyZWFtSXRlbXMgPyBpdGVtPy5fc3RyZWFtTGV2ZWxzPy5sZW5ndGggfHwgMSA6IDEpJ1xyXG4gICAgICAgW3N0eWxlLndpZHRoLnB4XT0nd2lkdGgnXHJcbiAgICAgICBbY2xhc3MuY2FuLWNvbGxhcHNlXT0naXRlbS5jaGlsZHJlbkl0ZW1zICYmIGl0ZW0uY2hpbGRyZW5JdGVtcy5sZW5ndGgnXHJcbiAgICAgICBjbGFzcz0ncGFuZWwtaXRlbSc+XHJcblxyXG4gICAgPGRpdiBbc3R5bGUubWFyZ2luTGVmdC5weF09J2RlcHRoICogY2hpbGRHcm91cE9mZnNldCcgKGNsaWNrKT0ndG9nZ2xlRXhwYW5kKGl0ZW0pJyBjbGFzcz0naXRlbS1jb250ZW50Jz5cclxuICAgICAgPGRpdiBjbGFzcz0nY29sbGFwc2UtaWNvbidcclxuICAgICAgICAgICBbY2xhc3MuY29sbGFwc2VkXT0nIWl0ZW0uY2hpbGRyZW5JdGVtc0V4cGFuZGVkJz5cclxuICAgICAgPC9kaXY+XHJcblxyXG4gICAgICA8c3BhbiBjbGFzcz0naXRlbS1uYW1lJyB0aXRsZT1cInt7aXRlbS5uYW1lfX1cIj57e2l0ZW0ubmFtZX19PC9zcGFuPlxyXG4gICAgPC9kaXY+XHJcbiAgPC9kaXY+XHJcbjwvbmctdGVtcGxhdGU+XHJcbiJdfQ==