UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

209 lines 28.8 kB
import { Directionality } from '@angular/cdk/bidi'; import { CdkStepper, STEP_STATE } from '@angular/cdk/stepper'; import { ChangeDetectorRef, Component, ContentChildren, ElementRef, EventEmitter, forwardRef, Input, Output, QueryList } from '@angular/core'; import { Subject } from 'rxjs'; import { PRODUCT_EXPERIENCE_EVENT_SOURCE } from '../product-experience/product-experience.model'; import { C8yStepperIcon } from './stepper-icon.directive'; import * as i0 from "@angular/core"; import * as i1 from "@angular/cdk/bidi"; import * as i2 from "@angular/common"; import * as i3 from "./stepper-progress.component"; import * as i4 from "../i18n/c8y-translate.pipe"; /** * `C8yStepper` extends the `CdkStepper`. You can use cdk based functionality and inputs. * Additional to that you are able to modify the behavior and also the look and feel when * using the `C8yStepper`. * * The `C8yStepper` is used to present any step-based process to the user. * A stepper, `C8yStepper` and/or `CdkStepper` is the parent of cdk-steps. * Each cdk-step represents one step in the whole process that you want to provide to the user. * * The `C8yStepper` will create, based on the given `cdk-steps`, a kind of stepper-progress which looks like this: * `(1)---(2)---(3)---(n)` * The stepper will handle the state of each step and provides styles for active steps, done-steps or in edit-mode. * You are able to override icons for each step in the stepper-progress with a template. You are also able to activate * default-icons for states like 'edit' and 'done'. * * To force users through every provided step, set the stepper to 'linear'. * This will disable the possibility to move for example from step one to step three. * * Whenever it comes to validation try to use formGroups. It is possible to * assign a `formGroup` to a `cdk-step` input called `[stepControl]`, which automatically respects the * validation-rules that you created for this `formGroup`. If fields are required but not filled or * any other validation, like a pattern, is not matched the `formGroup` will be invalid. In this case * stepping in a linear stepper to the next step gets impossible. * * If there is the need to execute asynchronous code you have at least two possibilities. * First: As you learned, a cdk-step works with `formGroups` and `Validators`, so you are able to use * asyncValidators as well. * Second: The `C8yStepper` provides an event-emitter `onStepChange` which is called whenever a step-button `(1)--(2)--(n)` * in the stepper-progress is clicked. The event of this emitter holds the index of the step as number. You can * use this `EventEmitter` to call for example a custom navigate-method which performs first any async-call and then moves * on to the given step. * * ```typescript * <c8y-stepper * (onStepChange)="navigate($event)" * [disableDefaultIcons]="{ edit: true, done: false }" * [customClasses]="['m-l-40', 'm-r-40', 'm-t-32']" * linear * > * <!-- override icons --> * <ng-template c8yStepperIcon="final"> * <span [c8yIcon]="'hand-peace-o'"></span> * </ng-template> * * <cdk-step [stepControl]="formGroupStepOne" label="Name of the hero"> * <div class="m-l-40 m-r-40 m-t-32"> * <h4 class="p-b-8" translate>What is the name of your hero?</h4> * <c8y-form-group> * <div [formGroup]="formGroupStepOne"> * <input * class="form-control" * type="text" * formControlName="name" * placeholder="Mister X" * #nameRef * required * /> * <c8y-messages> * <c8y-message *ngIf="!formGroupStepOne.untouched && !nameRef.value" translate * >Enter the name of the Superhero</c8y-message * > * </c8y-messages> * </div> * </c8y-form-group> * </div> * <c8y-stepper-buttons></c8y-stepper-buttons> * </cdk-step> * <cdk-step> * ... * </cdk-step state="final"> * </c8y-stepper> * ``` */ export class C8yStepper extends CdkStepper { /** * @ignore */ constructor(dir, changeDetectorRef, elementRef) { super(dir, changeDetectorRef, elementRef); this.dir = dir; this.changeDetectorRef = changeDetectorRef; this.elementRef = elementRef; /** * Optional * Indicator if icons for edit and done state should be shown in step-header buttons */ this.disableDefaultIcons = { edit: true, done: true }; /** * Optional * Disable/enable navigation by stepper progress buttons * default: false */ this.disableProgressButtons = false; /** * Optional * Possibility to hide the stepper progress completely. */ this.hideStepProgress = false; /** * Optional * If `true`, the label defined on a cdk-step won't get rendered below each step-header button. * Instead, it will be used as a title only. */ this.useStepLabelsAsTitlesOnly = false; /** * Will emit the step index number whenever a step-header button was clicked * It listens to the stepIndex Subject. * @deprecated: Use the default `selectionChange` event emitter. */ this.onStepChange = new EventEmitter(); /** Consumer-specified template-refs to be used to override the header icons. */ this._iconOverrides = {}; this._stepIndex = new Subject(); } /** * @ignore */ ngAfterContentInit() { super.ngAfterContentInit(); this._icons.forEach(({ name, templateRef }) => (this._iconOverrides[name] = templateRef)); this._stepIndexSubscription = this.selectionChange.subscribe(event => this.onStepChange.emit(event.selectedIndex)); } /** * @ignore */ ngOnDestroy() { if (this._stepIndexSubscription && !this._stepIndexSubscription.closed) { this._stepIndexSubscription.unsubscribe(); } } /** * Manipulates the state based on the disabledDefaultIcons Input() * Changing edit or done to false will change the icons within step-header buttons * @param index step index * @param state step state, like 'done', 'edit', 'error' */ getIndicatorType(index, state) { const stepState = this._getIndicatorType(index, state); let _state = state; switch (stepState) { case STEP_STATE.EDIT: if (!this.disableDefaultIcons.edit) { _state = STEP_STATE.EDIT; } break; case STEP_STATE.DONE: if (!this.disableDefaultIcons.done) { _state = STEP_STATE.DONE; } else { _state = '_done'; } break; case STEP_STATE.ERROR: _state = STEP_STATE.ERROR; break; } return _state; } /** * Pushes the step index to the subject * @param index step index */ setIndex(index) { const steps = this.steps.toArray(); if (!steps[this.selectedIndex]?.stepControl?.invalid || index < this.selectedIndex) { this.selectedIndex = index; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: C8yStepper, deps: [{ token: i1.Directionality }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: C8yStepper, selector: "c8y-stepper", inputs: { disableDefaultIcons: "disableDefaultIcons", disableProgressButtons: "disableProgressButtons", customClasses: "customClasses", hideStepProgress: "hideStepProgress", useStepLabelsAsTitlesOnly: "useStepLabelsAsTitlesOnly" }, outputs: { onStepChange: "onStepChange" }, providers: [ { provide: CdkStepper, useExisting: C8yStepper }, { provide: PRODUCT_EXPERIENCE_EVENT_SOURCE, useExisting: forwardRef(() => C8yStepper) } ], queries: [{ propertyName: "_icons", predicate: C8yStepperIcon, descendants: true }], usesInheritance: true, ngImport: i0, template: "<ul *ngIf=\"!hideStepProgress\" class=\"c8y-stepper\" [ngClass]=\"customClasses\">\n <li *ngFor=\"let step of steps; let i = index\">\n <c8y-stepper-progress\n [iconOverrides]=\"_iconOverrides\"\n [state]=\"getIndicatorType(i, step.state)\"\n [index]=\"i\"\n [selected]=\"selectedIndex === i\"\n [disabled]=\"disableProgressButtons\"\n (onStepClicked)=\"setIndex($event)\"\n title=\"{{ step.label | translate }}\"\n [ngClass]=\"{'active': selectedIndex === i}\"\n >\n </c8y-stepper-progress>\n <div *ngIf=\"!useStepLabelsAsTitlesOnly\" class=\"c8y-step__label\" title=\"{{ step.label | translate }}\">\n {{ step.label | translate }}\n </div>\n </li>\n</ul>\n<ng-container [ngTemplateOutlet]=\"selected.content\"></ng-container>\n", dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i3.C8yStepperProgress, selector: "c8y-stepper-progress", inputs: ["iconOverrides", "index", "selected", "state", "disabled"], outputs: ["onStepClicked"] }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: C8yStepper, decorators: [{ type: Component, args: [{ selector: 'c8y-stepper', providers: [ { provide: CdkStepper, useExisting: C8yStepper }, { provide: PRODUCT_EXPERIENCE_EVENT_SOURCE, useExisting: forwardRef(() => C8yStepper) } ], template: "<ul *ngIf=\"!hideStepProgress\" class=\"c8y-stepper\" [ngClass]=\"customClasses\">\n <li *ngFor=\"let step of steps; let i = index\">\n <c8y-stepper-progress\n [iconOverrides]=\"_iconOverrides\"\n [state]=\"getIndicatorType(i, step.state)\"\n [index]=\"i\"\n [selected]=\"selectedIndex === i\"\n [disabled]=\"disableProgressButtons\"\n (onStepClicked)=\"setIndex($event)\"\n title=\"{{ step.label | translate }}\"\n [ngClass]=\"{'active': selectedIndex === i}\"\n >\n </c8y-stepper-progress>\n <div *ngIf=\"!useStepLabelsAsTitlesOnly\" class=\"c8y-step__label\" title=\"{{ step.label | translate }}\">\n {{ step.label | translate }}\n </div>\n </li>\n</ul>\n<ng-container [ngTemplateOutlet]=\"selected.content\"></ng-container>\n" }] }], ctorParameters: () => [{ type: i1.Directionality }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }], propDecorators: { disableDefaultIcons: [{ type: Input }], disableProgressButtons: [{ type: Input }], customClasses: [{ type: Input }], hideStepProgress: [{ type: Input }], useStepLabelsAsTitlesOnly: [{ type: Input }], onStepChange: [{ type: Output }], _icons: [{ type: ContentChildren, args: [C8yStepperIcon, { descendants: true }] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcHBlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9jb3JlL3N0ZXBwZXIvc3RlcHBlci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9jb3JlL3N0ZXBwZXIvc3RlcHBlci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDbkQsT0FBTyxFQUFFLFVBQVUsRUFBYSxVQUFVLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN6RSxPQUFPLEVBRUwsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxlQUFlLEVBQ2YsVUFBVSxFQUNWLFlBQVksRUFDWixVQUFVLEVBQ1YsS0FBSyxFQUVMLE1BQU0sRUFDTixTQUFTLEVBRVYsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLE9BQU8sRUFBZ0IsTUFBTSxNQUFNLENBQUM7QUFDN0MsT0FBTyxFQUdMLCtCQUErQixFQUNoQyxNQUFNLGdEQUFnRCxDQUFDO0FBQ3hELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQzs7Ozs7O0FBRTFEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F3RUc7QUFTSCxNQUFNLE9BQU8sVUFDWCxTQUFRLFVBQVU7SUF3RWxCOztPQUVHO0lBQ0gsWUFDVSxHQUFtQixFQUNuQixpQkFBb0MsRUFDcEMsVUFBb0M7UUFFNUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxpQkFBaUIsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUpsQyxRQUFHLEdBQUgsR0FBRyxDQUFnQjtRQUNuQixzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO1FBQ3BDLGVBQVUsR0FBVixVQUFVLENBQTBCO1FBM0U5Qzs7O1dBR0c7UUFDTSx3QkFBbUIsR0FBc0MsRUFBRSxJQUFJLEVBQUUs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LEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFO1NBQ3hGLGlEQWlFZ0IsY0FBYyx1RUN4S2pDLDB4QkFtQkE7OzRGRHNGYSxVQUFVO2tCQVJ0QixTQUFTOytCQUNFLGFBQWEsYUFFWjt3QkFDVCxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsV0FBVyxZQUFZLEVBQUU7d0JBQ2hELEVBQUUsT0FBTyxFQUFFLCtCQUErQixFQUFFLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLFdBQVcsQ0FBQyxFQUFFO3FCQUN4Rjs0SUFVUSxtQkFBbUI7c0JBQTNCLEtBQUs7Z0JBTUcsc0JBQXNCO3NCQUE5QixLQUFLO2dCQUtHLGFBQWE7c0JBQXJCLEtBQUs7Z0JBS0csZ0JBQWdCO3NCQUF4QixLQUFLO2dCQU1HLHlCQUF5QjtzQkFBakMsS0FBSztnQkFNSSxZQUFZO3NCQUFyQixNQUFNO2dCQTJCaUQsTUFBTTtzQkFBN0QsZUFBZTt1QkFBQyxjQUFjLEVBQUUsRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGlyZWN0aW9uYWxpdHkgfSBmcm9tICdAYW5ndWxhci9jZGsvYmlkaSc7XG5pbXBvcnQgeyBDZGtTdGVwcGVyLCBTdGVwU3RhdGUsIFNURVBfU1RBVEUgfSBmcm9tICdAYW5ndWxhci9jZGsvc3RlcHBlcic7XG5pbXBvcnQge1xuICBBZnRlckNvbnRlbnRJbml0LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBDb250ZW50Q2hpbGRyZW4sXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgZm9yd2FyZFJlZixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT3V0cHV0LFxuICBRdWVyeUxpc3QsXG4gIFRlbXBsYXRlUmVmXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3ViamVjdCwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge1xuICBQcm9kdWN0RXhwZXJpZW5jZUV2ZW50LFxuICBQcm9kdWN0RXhwZXJpZW5jZUV2ZW50U291cmNlLFxuICBQUk9EVUNUX0VYUEVSSUVOQ0VfRVZFTlRfU09VUkNFXG59IGZyb20gJy4uL3Byb2R1Y3QtZXhwZXJpZW5jZS9wcm9kdWN0LWV4cGVyaWVuY2UubW9kZWwnO1xuaW1wb3J0IHsgQzh5U3RlcHBlckljb24gfSBmcm9tICcuL3N0ZXBwZXItaWNvbi5kaXJlY3RpdmUnO1xuXG4vKipcbiAqIGBDOHlTdGVwcGVyYCBleHRlbmRzIHRoZSBgQ2RrU3RlcHBlcmAuIFlvdSBjYW4gdXNlIGNkayBiYXNlZCBmdW5jdGlvbmFsaXR5IGFuZCBpbnB1dHMuXG4gKiBBZGRpdGlvbmFsIHRvIHRoYXQgeW91IGFyZSBhYmxlIHRvIG1vZGlmeSB0aGUgYmVoYXZpb3IgYW5kIGFsc28gdGhlIGxvb2sgYW5kIGZlZWwgd2hlblxuICogdXNpbmcgdGhlIGBDOHlTdGVwcGVyYC5cbiAqXG4gKiBUaGUgYEM4eVN0ZXBwZXJgIGlzIHVzZWQgdG8gcHJlc2VudCBhbnkgc3RlcC1iYXNlZCBwcm9jZXNzIHRvIHRoZSB1c2VyLlxuICogQSBzdGVwcGVyLCBgQzh5U3RlcHBlcmAgYW5kL29yIGBDZGtTdGVwcGVyYCBpcyB0aGUgcGFyZW50IG9mIGNkay1zdGVwcy5cbiAqIEVhY2ggY2RrLXN0ZXAgcmVwcmVzZW50cyBvbmUgc3RlcCBpbiB0aGUgd2hvbGUgcHJvY2VzcyB0aGF0IHlvdSB3YW50IHRvIHByb3ZpZGUgdG8gdGhlIHVzZXIuXG4gKlxuICogVGhlIGBDOHlTdGVwcGVyYCB3aWxsIGNyZWF0ZSwgYmFzZWQgb24gdGhlIGdpdmVuIGBjZGstc3RlcHNgLCBhIGtpbmQgb2Ygc3RlcHBlci1wcm9ncmVzcyB3aGljaCBsb29rcyBsaWtlIHRoaXM6XG4gKiBgKDEpLS0tKDIpLS0tKDMpLS0tKG4pYFxuICogVGhlIHN0ZXBwZXIgd2lsbCBoYW5kbGUgdGhlIHN0YXRlIG9mIGVhY2ggc3RlcCBhbmQgcHJvdmlkZXMgc3R5bGVzIGZvciBhY3RpdmUgc3RlcHMsIGRvbmUtc3RlcHMgb3IgaW4gZWRpdC1tb2RlLlxuICogWW91IGFyZSBhYmxlIHRvIG92ZXJyaWRlIGljb25zIGZvciBlYWNoIHN0ZXAgaW4gdGhlIHN0ZXBwZXItcHJvZ3Jlc3Mgd2l0aCBhIHRlbXBsYXRlLiBZb3UgYXJlIGFsc28gYWJsZSB0byBhY3RpdmF0ZVxuICogZGVmYXVsdC1pY29ucyBmb3Igc3RhdGVzIGxpa2UgJ2VkaXQnIGFuZCAnZG9uZScuXG4gKlxuICogVG8gZm9yY2UgdXNlcnMgdGhyb3VnaCBldmVyeSBwcm92aWRlZCBzdGVwLCBzZXQgdGhlIHN0ZXBwZXIgdG8gJ2xpbmVhcicuXG4gKiBUaGlzIHdpbGwgZGlzYWJsZSB0aGUgcG9zc2liaWxpdHkgdG8gbW92ZSBmb3IgZXhhbXBsZSBmcm9tIHN0ZXAgb25lIHRvIHN0ZXAgdGhyZWUuXG4gKlxuICogV2hlbmV2ZXIgaXQgY29tZXMgdG8gdmFsaWRhdGlvbiB0cnkgdG8gdXNlIGZvcm1Hcm91cHMuIEl0IGlzIHBvc3NpYmxlIHRvXG4gKiBhc3NpZ24gYSBgZm9ybUdyb3VwYCB0byBhIGBjZGstc3RlcGAgaW5wdXQgY2FsbGVkIGBbc3RlcENvbnRyb2xdYCwgd2hpY2ggYXV0b21hdGljYWxseSByZXNwZWN0cyB0aGVcbiAqIHZhbGlkYXRpb24tcnVsZXMgdGhhdCB5b3UgY3JlYXRlZCBmb3IgdGhpcyBgZm9ybUdyb3VwYC4gSWYgZmllbGRzIGFyZSByZXF1aXJlZCBidXQgbm90IGZpbGxlZCBvclxuICogYW55IG90aGVyIHZhbGlkYXRpb24sIGxpa2UgYSBwYXR0ZXJuLCBpcyBub3QgbWF0Y2hlZCB0aGUgYGZvcm1Hcm91cGAgd2lsbCBiZSBpbnZhbGlkLiBJbiB0aGlzIGNhc2VcbiAqIHN0ZXBwaW5nIGluIGEgbGluZWFyIHN0ZXBwZXIgdG8gdGhlIG5leHQgc3RlcCBnZXRzIGltcG9zc2libGUuXG4gKlxuICogSWYgdGhlcmUgaXMgdGhlIG5lZWQgdG8gZXhlY3V0ZSBhc3luY2hyb25vdXMgY29kZSB5b3UgaGF2ZSBhdCBsZWFzdCB0d28gcG9zc2liaWxpdGllcy5cbiAqIEZpcnN0OiBBcyB5b3UgbGVhcm5lZCwgYSBjZGstc3RlcCB3b3JrcyB3aXRoIGBmb3JtR3JvdXBzYCBhbmQgYFZhbGlkYXRvcnNgLCBzbyB5b3UgYXJlIGFibGUgdG8gdXNlXG4gKiBhc3luY1ZhbGlkYXRvcnMgYXMgd2VsbC5cbiAqIFNlY29uZDogVGhlIGBDOHlTdGVwcGVyYCBwcm92aWRlcyBhbiBldmVudC1lbWl0dGVyIGBvblN0ZXBDaGFuZ2VgIHdoaWNoIGlzIGNhbGxlZCB3aGVuZXZlciBhIHN0ZXAtYnV0dG9uIGAoMSktLSgyKS0tKG4pYFxuICogaW4gdGhlIHN0ZXBwZXItcHJvZ3Jlc3MgaXMgY2xpY2tlZC4gVGhlIGV2ZW50IG9mIHRoaXMgZW1pdHRlciBob2xkcyB0aGUgaW5kZXggb2YgdGhlIHN0ZXAgYXMgbnVtYmVyLiBZb3UgY2FuXG4gKiB1c2UgdGhpcyBgRXZlbnRFbWl0dGVyYCB0byBjYWxsIGZvciBleGFtcGxlIGEgY3VzdG9tIG5hdmlnYXRlLW1ldGhvZCB3aGljaCBwZXJmb3JtcyBmaXJzdCBhbnkgYXN5bmMtY2FsbCBhbmQgdGhlbiBtb3Zlc1xuICogb24gdG8gdGhlIGdpdmVuIHN0ZXAuXG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogPGM4eS1zdGVwcGVyXG4gKiAob25TdGVwQ2hhbmdlKT1cIm5hdmlnYXRlKCRldmVudClcIlxuICogW2Rpc2FibGVEZWZhdWx0SWNvbnNdPVwieyBlZGl0OiB0cnVlLCBkb25lOiBmYWxzZSB9XCJcbiAqIFtjdXN0b21DbGFzc2VzXT1cIlsnbS1sLTQwJywgJ20tci00MCcsICdtLXQtMzInXVwiXG4gKiBsaW5lYXJcbiAqID5cbiAqIDwhLS0gb3ZlcnJpZGUgaWNvbnMgLS0+XG4gKiA8bmctdGVtcGxhdGUgYzh5U3RlcHBlckljb249XCJmaW5hbFwiPlxuICogICA8c3BhbiBbYzh5SWNvbl09XCInaGFuZC1wZWFjZS1vJ1wiPjwvc3Bhbj5cbiAqIDwvbmctdGVtcGxhdGU+XG4gKlxuICogPGNkay1zdGVwIFtzdGVwQ29udHJvbF09XCJmb3JtR3JvdXBTdGVwT25lXCIgbGFiZWw9XCJOYW1lIG9mIHRoZSBoZXJvXCI+XG4gKiAgIDxkaXYgY2xhc3M9XCJtLWwtNDAgbS1yLTQwIG0tdC0zMlwiPlxuICogICAgIDxoNCBjbGFzcz1cInAtYi04XCIgdHJhbnNsYXRlPldoYXQgaXMgdGhlIG5hbWUgb2YgeW91ciBoZXJvPzwvaDQ+XG4gKiAgICAgPGM4eS1mb3JtLWdyb3VwPlxuICogICAgICA8ZGl2IFtmb3JtR3JvdXBdPVwiZm9ybUdyb3VwU3RlcE9uZVwiPlxuICogICAgICAgPGlucHV0XG4gKiAgICAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sXCJcbiAqICAgICAgICAgdHlwZT1cInRleHRcIlxuICogICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJuYW1lXCJcbiAqICAgICAgICAgcGxhY2Vob2xkZXI9XCJNaXN0ZXIgWFwiXG4gKiAgICAgICAgICNuYW1lUmVmXG4gKiAgICAgICAgIHJlcXVpcmVkXG4gKiAgICAgICAvPlxuICogICAgICAgPGM4eS1tZXNzYWdlcz5cbiAqICAgICAgICAgPGM4eS1tZXNzYWdlICpuZ0lmPVwiIWZvcm1Hcm91cFN0ZXBPbmUudW50b3VjaGVkICYmICFuYW1lUmVmLnZhbHVlXCIgdHJhbnNsYXRlXG4gKiAgICAgICAgICAgPkVudGVyIHRoZSBuYW1lIG9mIHRoZSBTdXBlcmhlcm88L2M4eS1tZXNzYWdlXG4gKiAgICAgICAgID5cbiAqICAgICAgIDwvYzh5LW1lc3NhZ2VzPlxuICogICAgICA8L2Rpdj5cbiAqICAgICA8L2M4eS1mb3JtLWdyb3VwPlxuICogICA8L2Rpdj5cbiAqICAgPGM4eS1zdGVwcGVyLWJ1dHRvbnM+PC9jOHktc3RlcHBlci1idXR0b25zPlxuICogPC9jZGstc3RlcD5cbiAqIDxjZGstc3RlcD5cbiAqICAuLi5cbiAqIDwvY2RrLXN0ZXAgc3RhdGU9XCJmaW5hbFwiPlxuICogPC9jOHktc3RlcHBlcj5cbiAqIGBgYFxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktc3RlcHBlcicsXG4gIHRlbXBsYXRlVXJsOiAnLi9zdGVwcGVyLmNvbXBvbmVudC5odG1sJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAgeyBwcm92aWRlOiBDZGtTdGVwcGVyLCB1c2VFeGlzdGluZzogQzh5U3RlcHBlciB9LFxuICAgIHsgcHJvdmlkZTogUFJPRFVDVF9FWFBFUklFTkNFX0VWRU5UX1NPVVJDRSwgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gQzh5U3RlcHBlcikgfVxuICBdXG59KVxuZXhwb3J0IGNsYXNzIEM4eVN0ZXBwZXJcbiAgZXh0ZW5kcyBDZGtTdGVwcGVyXG4gIGltcGxlbWVudHMgQWZ0ZXJDb250ZW50SW5pdCwgT25EZXN0cm95LCBQcm9kdWN0RXhwZXJpZW5jZUV2ZW50U291cmNlXG57XG4gIC8qKlxuICAgKiBPcHRpb25hbFxuICAgKiBJbmRpY2F0b3IgaWYgaWNvbnMgZm9yIGVkaXQgYW5kIGRvbmUgc3RhdGUgc2hvdWxkIGJlIHNob3duIGluIHN0ZXAtaGVhZGVyIGJ1dHRvbnNcbiAgICovXG4gIEBJbnB1dCgpIGRpc2FibGVEZWZhdWx0SWNvbnM/OiB7IGVkaXQ6IGJvb2xlYW47IGRvbmU6IGJvb2xlYW4gfSA9IHsgZWRpdDogdHJ1ZSwgZG9uZTogdHJ1ZSB9O1xuICAvKipcbiAgICogT3B0aW9uYWxcbiAgICogRGlzYWJsZS9lbmFibGUgbmF2aWdhdGlvbiBieSBzdGVwcGVyIHByb2dyZXNzIGJ1dHRvbnNcbiAgICogZGVmYXVsdDogZmFsc2VcbiAgICovXG4gIEBJbnB1dCgpIGRpc2FibGVQcm9ncmVzc0J1dHRvbnM/OiBib29sZWFuID0gZmFsc2U7XG4gIC8qKlxuICAgKiBPcHRpb25hbFxuICAgKiBQb3NzaWJpbGl0eSB0byBhZGQgYW55IGtpbmQgb2YgY3VzdG9tIGNzcyBjbGFzc2VzIHRvIHRoZSBzdGVwLWhlYWRlclxuICAgKi9cbiAgQElucHV0KCkgY3VzdG9tQ2xhc3Nlcz86IHN0cmluZ1tdO1xuICAvKipcbiAgICogT3B0aW9uYWxcbiAgICogUG9zc2liaWxpdHkgdG8gaGlkZSB0aGUgc3RlcHBlciBwcm9ncmVzcyBjb21wbGV0ZWx5LlxuICAgKi9cbiAgQElucHV0KCkgaGlkZVN0ZXBQcm9ncmVzcz86IGJvb2xlYW4gPSBmYWxzZTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsXG4gICAqIElmIGB0cnVlYCwgdGhlIGxhYmVsIGRlZmluZWQgb24gYSBjZGstc3RlcCB3b24ndCBnZXQgcmVuZGVyZWQgYmVsb3cgZWFjaCBzdGVwLWhlYWRlciBidXR0b24uXG4gICAqIEluc3RlYWQsIGl0IHdpbGwgYmUgdXNlZCBhcyBhIHRpdGxlIG9ubHkuXG4gICAqL1xuICBASW5wdXQoKSB1c2VTdGVwTGFiZWxzQXNUaXRsZXNPbmx5PzogYm9vbGVhbiA9IGZhbHNlO1xuICAvKipcbiAgICogV2lsbCBlbWl0IHRoZSBzdGVwIGluZGV4IG51bWJlciB3aGVuZXZlciBhIHN0ZXAtaGVhZGVyIGJ1dHRvbiB3YXMgY2xpY2tlZFxuICAgKiBJdCBsaXN0ZW5zIHRvIHRoZSBzdGVwSW5kZXggU3ViamVjdC5cbiAgICogQGRlcHJlY2F0ZWQ6IFVzZSB0aGUgZGVmYXVsdCBgc2VsZWN0aW9uQ2hhbmdlYCBldmVudCBlbWl0dGVyLlxuICAgKi9cbiAgQE91dHB1dCgpIG9uU3RlcENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8bnVtYmVyPigpO1xuXG4gIC8qKlxuICAgKiBIb2xkaW5nIGEgUXVlcnlMaXN0IG9mIEM4eVN0ZXBwZXJJY29uc1xuICAgKiBUaGVzZSBhcmUgdGVtcGxhdGVSZWZzIHdoaWNoIG92ZXJyaWRlcyBhbnkgc3RlcC1oZWFkZXIgYnV0dG9uIGljb24gd2l0aCBtYXRjaGluZyBzdGF0ZSBvZiBjZGstc3RlcFxuICAgKlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIDwhLS0gb3ZlcnJpZGUgaWNvbnMgLS0+XG4gICAqICA8bmctdGVtcGxhdGUgYzh5U3RlcHBlckljb249XCJmaW5hbFwiPlxuICAgKiAgIDxzcGFuIFtjOHlJY29uXT1cIidoYW5kLXBlYWNlLW8nXCI+PC9zcGFuPlxuICAgKiAgPC9uZy10ZW1wbGF0ZT5cbiAgICpcbiAgICogPGNkay1zdGVwIHN0YXRlPVwiZmluYWxcIiBsYWJlbD1cIkpvYiBkb25lIVwiPlxuICAgKiAgPGRpdiBjbGFzcz1cIm0tbC00MCBtLXItNDAgbS10LTMyXCI+XG4gICAqICAgIDxoNCBjbGFzcz1cInAtYi0zMlwiIHN0eWxlPVwidGV4dC1hbGlnbjogY2VudGVyO1wiIHRyYW5zbGF0ZT5cbiAgICogICAgIFlvdXIgU3VwZXJoZXJvIGlzIG5vdyByZWFkeSB0byBzYXZlIHRoZSB3b3JsZCFcbiAgICogICA8L2g0PlxuICAgKiAgPC9kaXY+XG4gICAqICA8Yzh5LXN0ZXBwZXItYnV0dG9uc1xuICAgKiAgICBbaGlkZGVuXT1cIiFpc01vZGFsXCJcbiAgICogICAgKG9uQmFjayk9XCJjbG9zZSgpXCJcbiAgICogICAgW2xhYmVsc109XCJ7IGJhY2s6ICdHb3QgaXQhJyB9XCJcbiAgICogID48L2M4eS1zdGVwcGVyLWJ1dHRvbnM+XG4gICAqICA8Yzh5LXN0ZXBwZXItYnV0dG9ucyBbaGlkZGVuXT1cImlzTW9kYWxcIj48L2M4eS1zdGVwcGVyLWJ1dHRvbnM+XG4gICAqIDwvY2RrLXN0ZXA+XG4gICAqIGBgYFxuICAgKi9cbiAgQENvbnRlbnRDaGlsZHJlbihDOHlTdGVwcGVySWNvbiwgeyBkZXNjZW5kYW50czogdHJ1ZSB9KSBfaWNvbnM6IFF1ZXJ5TGlzdDxDOHlTdGVwcGVySWNvbj47XG5cbiAgLyoqIENvbnN1bWVyLXNwZWNpZmllZCB0ZW1wbGF0ZS1yZWZzIHRvIGJlIHVzZWQgdG8gb3ZlcnJpZGUgdGhlIGhlYWRlciBpY29ucy4gKi9cbiAgX2ljb25PdmVycmlkZXM6IHsgW2tleTogc3RyaW5nXTogVGVtcGxhdGVSZWY8YW55PiB9ID0ge307XG5cbiAgcHJvZHVjdEV4cGVyaWVuY2VFdmVudDogUHJvZHVjdEV4cGVyaWVuY2VFdmVudDtcblxuICBwcml2YXRlIF9zdGVwSW5kZXg6IFN1YmplY3Q8bnVtYmVyPiA9IG5ldyBTdWJqZWN0KCk7XG4gIHByaXZhdGUgX3N0ZXBJbmRleFN1YnNjcmlwdGlvbjogU3Vic2NyaXB0aW9uO1xuXG4gIC8qKlxuICAgKiBAaWdub3JlXG4gICAqL1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGRpcjogRGlyZWN0aW9uYWxpdHksXG4gICAgcHJpdmF0ZSBjaGFuZ2VEZXRlY3RvclJlZjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgcHJpdmF0ZSBlbGVtZW50UmVmPzogRWxlbWVudFJlZjxIVE1MRWxlbWVudD5cbiAgKSB7XG4gICAgc3VwZXIoZGlyLCBjaGFuZ2VEZXRlY3RvclJlZiwgZWxlbWVudFJlZik7XG4gIH1cblxuICAvKipcbiAgICogQGlnbm9yZVxuICAgKi9cbiAgbmdBZnRlckNvbnRlbnRJbml0KCkge1xuICAgIHN1cGVyLm5nQWZ0ZXJDb250ZW50SW5pdCgpO1xuICAgIHRoaXMuX2ljb25zLmZvckVhY2goKHsgbmFtZSwgdGVtcGxhdGVSZWYgfSkgPT4gKHRoaXMuX2ljb25PdmVycmlkZXNbbmFtZV0gPSB0ZW1wbGF0ZVJlZikpO1xuICAgIHRoaXMuX3N0ZXBJbmRleFN1YnNjcmlwdGlvbiA9IHRoaXMuc2VsZWN0aW9uQ2hhbmdlLnN1YnNjcmliZShldmVudCA9PlxuICAgICAgdGhpcy5vblN0ZXBDaGFuZ2UuZW1pdChldmVudC5zZWxlY3RlZEluZGV4KVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQGlnbm9yZVxuICAgKi9cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgaWYgKHRoaXMuX3N0ZXBJbmRleFN1YnNjcmlwdGlvbiAmJiAhdGhpcy5fc3RlcEluZGV4U3Vic2NyaXB0aW9uLmNsb3NlZCkge1xuICAgICAgdGhpcy5fc3RlcEluZGV4U3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIE1hbmlwdWxhdGVzIHRoZSBzdGF0ZSBiYXNlZCBvbiB0aGUgZGlzYWJsZWREZWZhdWx0SWNvbnMgSW5wdXQoKVxuICAgKiBDaGFuZ2luZyBlZGl0IG9yIGRvbmUgdG8gZmFsc2Ugd2lsbCBjaGFuZ2UgdGhlIGljb25zIHdpdGhpbiBzdGVwLWhlYWRlciBidXR0b25zXG4gICAqIEBwYXJhbSBpbmRleCBzdGVwIGluZGV4XG4gICAqIEBwYXJhbSBzdGF0ZSBzdGVwIHN0YXRlLCBsaWtlICdkb25lJywgJ2VkaXQnLCAnZXJyb3InXG4gICAqL1xuICBnZXRJbmRpY2F0b3JUeXBlKGluZGV4OiBudW1iZXIsIHN0YXRlOiBTdGVwU3RhdGUpIHtcbiAgICBjb25zdCBzdGVwU3RhdGUgPSB0aGlzLl9nZXRJbmRpY2F0b3JUeXBlKGluZGV4LCBzdGF0ZSk7XG4gICAgbGV0IF9zdGF0ZSA9IHN0YXRlO1xuICAgIHN3aXRjaCAoc3RlcFN0YXRlKSB7XG4gICAgICBjYXNlIFNURVBfU1RBVEUuRURJVDpcbiAgICAgICAgaWYgKCF0aGlzLmRpc2FibGVEZWZhdWx0SWNvbnMuZWRpdCkge1xuICAgICAgICAgIF9zdGF0ZSA9IFNURVBfU1RBVEUuRURJVDtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSBTVEVQX1NUQVRFLkRPTkU6XG4gICAgICAgIGlmICghdGhpcy5kaXNhYmxlRGVmYXVsdEljb25zLmRvbmUpIHtcbiAgICAgICAgICBfc3RhdGUgPSBTVEVQX1NUQVRFLkRPTkU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgX3N0YXRlID0gJ19kb25lJztcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSBTVEVQX1NUQVRFLkVSUk9SOlxuICAgICAgICBfc3RhdGUgPSBTVEVQX1NUQVRFLkVSUk9SO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gICAgcmV0dXJuIF9zdGF0ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQdXNoZXMgdGhlIHN0ZXAgaW5kZXggdG8gdGhlIHN1YmplY3RcbiAgICogQHBhcmFtIGluZGV4IHN0ZXAgaW5kZXhcbiAgICovXG4gIHNldEluZGV4KGluZGV4OiBudW1iZXIpIHtcbiAgICBjb25zdCBzdGVwcyA9IHRoaXMuc3RlcHMudG9BcnJheSgpO1xuICAgIGlmICghc3RlcHNbdGhpcy5zZWxlY3RlZEluZGV4XT8uc3RlcENvbnRyb2w/LmludmFsaWQgfHwgaW5kZXggPCB0aGlzLnNlbGVjdGVkSW5kZXgpIHtcbiAgICAgIHRoaXMuc2VsZWN0ZWRJbmRleCA9IGluZGV4O1xuICAgIH1cbiAgfVxufVxuIiwiPHVsICpuZ0lmPVwiIWhpZGVTdGVwUHJvZ3Jlc3NcIiBjbGFzcz1cImM4eS1zdGVwcGVyXCIgW25nQ2xhc3NdPVwiY3VzdG9tQ2xhc3Nlc1wiPlxuICA8bGkgKm5nRm9yPVwibGV0IHN0ZXAgb2Ygc3RlcHM7IGxldCBpID0gaW5kZXhcIj5cbiAgICA8Yzh5LXN0ZXBwZXItcHJvZ3Jlc3NcbiAgICAgIFtpY29uT3ZlcnJpZGVzXT1cIl9pY29uT3ZlcnJpZGVzXCJcbiAgICAgIFtzdGF0ZV09XCJnZXRJbmRpY2F0b3JUeXBlKGksIHN0ZXAuc3RhdGUpXCJcbiAgICAgIFtpbmRleF09XCJpXCJcbiAgICAgIFtzZWxlY3RlZF09XCJzZWxlY3RlZEluZGV4ID09PSBpXCJcbiAgICAgIFtkaXNhYmxlZF09XCJkaXNhYmxlUHJvZ3Jlc3NCdXR0b25zXCJcbiAgICAgIChvblN0ZXBDbGlja2VkKT1cInNldEluZGV4KCRldmVudClcIlxuICAgICAgdGl0bGU9XCJ7eyBzdGVwLmxhYmVsIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgIFtuZ0NsYXNzXT1cInsnYWN0aXZlJzogc2VsZWN0ZWRJbmRleCA9PT0gaX1cIlxuICAgID5cbiAgICA8L2M4eS1zdGVwcGVyLXByb2dyZXNzPlxuICAgIDxkaXYgKm5nSWY9XCIhdXNlU3RlcExhYmVsc0FzVGl0bGVzT25seVwiIGNsYXNzPVwiYzh5LXN0ZXBfX2xhYmVsXCIgIHRpdGxlPVwie3sgc3RlcC5sYWJlbCB8IHRyYW5zbGF0ZSB9fVwiPlxuICAgICAge3sgc3RlcC5sYWJlbCB8IHRyYW5zbGF0ZSB9fVxuICAgIDwvZGl2PlxuICA8L2xpPlxuPC91bD5cbjxuZy1jb250YWluZXIgW25nVGVtcGxhdGVPdXRsZXRdPVwic2VsZWN0ZWQuY29udGVudFwiPjwvbmctY29udGFpbmVyPlxuIl19