select.component.mjs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { ChangeDetectionStrategy, Component, EventEmitter, forwardRef, Input, Optional, Output, ViewChild, } from '@angular/core';
  2. import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
  3. import { ButtonComponent } from '../../components/atoms/button/button.component';
  4. import { IconComponent } from '../../components/atoms/icon/icon.component';
  5. import { OptionComponent } from '../option/option.component';
  6. import { Subject, debounceTime } from 'rxjs';
  7. import { LabelComponent } from '../label/label.component';
  8. import { AlertComponent } from '../../components/atoms/alert/alert.component';
  9. import { provideControlContainer, provideValueAccessor } from '../utils/form.util';
  10. import { FormGenericComponent } from '../../services/form-generic.abstract';
  11. import { FormErrorComponent } from '../error/error.component';
  12. import * as i0 from "@angular/core";
  13. import * as i1 from "@angular/forms";
  14. export class SelectComponent extends FormGenericComponent {
  15. constructor(formGroupDirective, destroyRef) {
  16. super(formGroupDirective);
  17. this.formGroupDirective = formGroupDirective;
  18. this.destroyRef = destroyRef;
  19. this.focusOut$ = new Subject();
  20. this.isOpen = false;
  21. this.option = '';
  22. this.key = '';
  23. this.options = [];
  24. this.label = '';
  25. this.helper = '';
  26. this.placeholder = '';
  27. this.value = '';
  28. this.disposition = 'vertical';
  29. this.fullSize = true;
  30. this.showError = false;
  31. this.selected = new EventEmitter();
  32. }
  33. ngOnInit() {
  34. this.selectOption(this.value, false);
  35. this.focusOut$.pipe(takeUntilDestroyed(this.destroyRef), debounceTime(200)).subscribe(() => {
  36. this.triggerMarkCheck();
  37. this.close();
  38. });
  39. }
  40. toggle() {
  41. this.isOpen = !this.isOpen;
  42. if (!this.isOpen) {
  43. this.triggerTouched();
  44. }
  45. }
  46. close() {
  47. this.isOpen = false;
  48. this.triggerTouched();
  49. }
  50. selectOption(key, propagate = true) {
  51. const selectedOption = this.options.find(option => option.key === key);
  52. this.option = key === null ? this.placeholder : selectedOption?.label;
  53. if (propagate) {
  54. this.selected.emit(key);
  55. this.triggerChange(selectedOption?.key ?? null);
  56. this.close();
  57. }
  58. }
  59. writeValue(value) {
  60. this.triggerMarkCheck();
  61. this.selectOption(value, false);
  62. }
  63. static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: SelectComponent, deps: [{ token: i1.FormGroupDirective, optional: true }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component }); }
  64. static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.5", type: SelectComponent, isStandalone: true, selector: "ct-select", inputs: { formControlName: "formControlName", key: "key", options: "options", label: "label", helper: "helper", placeholder: "placeholder", value: "value", disposition: "disposition", fullSize: "fullSize", showError: "showError" }, outputs: { selected: "selected" }, providers: [provideValueAccessor(forwardRef(() => SelectComponent))], viewQueries: [{ propertyName: "trigger", first: true, predicate: ["triggerElement"], descendants: true }, { propertyName: "panel", first: true, predicate: ["optionsPanel"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"flex gap-1 font-primary\" [class.flex-col]=\"disposition === 'vertical'\">\n @if (label) {\n <ct-form-label [text]=\"label\" [hasError]=\"hasErrors(formControl)\" [showError]=\"showError\" />\n }\n <div class=\"flex flex-col\" [class.w-full]=\"fullSize\" [class.w-fit]=\"!fullSize\">\n <div\n tabindex=\"0\"\n #triggerElement\n class=\"flex cursor-pointer flex-row items-center justify-between rounded-md border bg-surface px-4 py-2 text-sm text-on-surface dark:bg-surface-dark dark:text-on-surface-dark\"\n [class.border-error]=\"hasErrors(formControl) && showError\"\n [class.border-neutral-300]=\"!hasErrors(formControl) || !showError\"\n [class.text-on-surface]=\"option !== placeholder\"\n (focusout)=\"focusOut$.next($event)\"\n (click)=\"toggle()\">\n <span [class.text-neutral-500]=\"option === placeholder\">{{ option }}</span>\n <ct-icon class=\"flex\" [size]=\"'sm'\" [icon]=\"isOpen ? 'chevron-up' : 'chevron-down'\" />\n </div>\n @if (isOpen) {\n <div class=\"relative flex flex-col\">\n <div\n #optionsPanel\n [class.w-full]=\"fullSize\"\n [class.w-fit]=\"!fullSize\"\n class=\"absolute top-0.5 z-10 flex max-h-72 flex-col overflow-y-auto rounded-md border border-neutral-400 bg-surface text-on-surface shadow-lg dark:bg-surface-dark dark:text-on-surface-dark\">\n <ct-option (click)=\"selectOption(null)\" [label]=\"placeholder\" />\n @for (option of options; track option) {\n <ct-option (click)=\"selectOption(option.key)\" [label]=\"option.label\" [icon]=\"option.icon!\" />\n }\n </div>\n </div>\n }\n </div>\n @if (formControl) {\n <ct-form-alert\n [hasErrors]=\"hasErrors(formControl)\"\n [helper]=\"helper\"\n [errors]=\"formControl.errors ?? {}\"\n size=\"xs\" />\n }\n</div>\n", dependencies: [{ kind: "component", type: OptionComponent, selector: "ct-option", inputs: ["label", "icon"] }, { kind: "component", type: IconComponent, selector: "ct-icon", inputs: ["icon", "fill", "strokeWidth", "strokeColor", "size", "variant"] }, { kind: "component", type: LabelComponent, selector: "ct-form-label", inputs: ["text", "type", "formControlName", "hasError", "showError"] }, { kind: "component", type: FormErrorComponent, selector: "ct-form-alert", inputs: ["errors", "size", "hasErrors", "fullSize", "helper", "errorMessages"] }], viewProviders: [provideControlContainer()], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
  65. }
  66. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: SelectComponent, decorators: [{
  67. type: Component,
  68. args: [{ selector: 'ct-select', standalone: true, imports: [OptionComponent, ButtonComponent, IconComponent, LabelComponent, AlertComponent, FormErrorComponent], providers: [provideValueAccessor(forwardRef(() => SelectComponent))], viewProviders: [provideControlContainer()], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex gap-1 font-primary\" [class.flex-col]=\"disposition === 'vertical'\">\n @if (label) {\n <ct-form-label [text]=\"label\" [hasError]=\"hasErrors(formControl)\" [showError]=\"showError\" />\n }\n <div class=\"flex flex-col\" [class.w-full]=\"fullSize\" [class.w-fit]=\"!fullSize\">\n <div\n tabindex=\"0\"\n #triggerElement\n class=\"flex cursor-pointer flex-row items-center justify-between rounded-md border bg-surface px-4 py-2 text-sm text-on-surface dark:bg-surface-dark dark:text-on-surface-dark\"\n [class.border-error]=\"hasErrors(formControl) && showError\"\n [class.border-neutral-300]=\"!hasErrors(formControl) || !showError\"\n [class.text-on-surface]=\"option !== placeholder\"\n (focusout)=\"focusOut$.next($event)\"\n (click)=\"toggle()\">\n <span [class.text-neutral-500]=\"option === placeholder\">{{ option }}</span>\n <ct-icon class=\"flex\" [size]=\"'sm'\" [icon]=\"isOpen ? 'chevron-up' : 'chevron-down'\" />\n </div>\n @if (isOpen) {\n <div class=\"relative flex flex-col\">\n <div\n #optionsPanel\n [class.w-full]=\"fullSize\"\n [class.w-fit]=\"!fullSize\"\n class=\"absolute top-0.5 z-10 flex max-h-72 flex-col overflow-y-auto rounded-md border border-neutral-400 bg-surface text-on-surface shadow-lg dark:bg-surface-dark dark:text-on-surface-dark\">\n <ct-option (click)=\"selectOption(null)\" [label]=\"placeholder\" />\n @for (option of options; track option) {\n <ct-option (click)=\"selectOption(option.key)\" [label]=\"option.label\" [icon]=\"option.icon!\" />\n }\n </div>\n </div>\n }\n </div>\n @if (formControl) {\n <ct-form-alert\n [hasErrors]=\"hasErrors(formControl)\"\n [helper]=\"helper\"\n [errors]=\"formControl.errors ?? {}\"\n size=\"xs\" />\n }\n</div>\n" }]
  69. }], ctorParameters: () => [{ type: i1.FormGroupDirective, decorators: [{
  70. type: Optional
  71. }] }, { type: i0.DestroyRef }], propDecorators: { formControlName: [{
  72. type: Input
  73. }], key: [{
  74. type: Input,
  75. args: [{ required: true }]
  76. }], options: [{
  77. type: Input,
  78. args: [{ required: true }]
  79. }], label: [{
  80. type: Input
  81. }], helper: [{
  82. type: Input
  83. }], placeholder: [{
  84. type: Input
  85. }], value: [{
  86. type: Input
  87. }], disposition: [{
  88. type: Input
  89. }], fullSize: [{
  90. type: Input
  91. }], showError: [{
  92. type: Input
  93. }], selected: [{
  94. type: Output
  95. }], trigger: [{
  96. type: ViewChild,
  97. args: ['triggerElement']
  98. }], panel: [{
  99. type: ViewChild,
  100. args: ['optionsPanel']
  101. }] } });
  102. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VsZWN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NpcmNsZXRvbmUvc3JjL2xpYi9mb3Jtcy9zZWxlY3Qvc2VsZWN0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NpcmNsZXRvbmUvc3JjL2xpYi9mb3Jtcy9zZWxlY3Qvc2VsZWN0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsU0FBUyxFQUdULFlBQVksRUFDWixVQUFVLEVBQ1YsS0FBSyxFQUVMLFFBQVEsRUFDUixNQUFNLEVBQ04sU0FBUyxHQUNWLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnREFBZ0QsQ0FBQztBQUNqRixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFFM0UsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzdELE9BQU8sRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRTdDLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMxRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sOENBQThDLENBQUM7QUFDOUUsT0FBTyxFQUFFLHVCQUF1QixFQUFFLG9CQUFvQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbkYsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFDNUUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7OztBQVk5RCxNQUFNLE9BQU8sZUFBZ0IsU0FBUSxvQkFBb0I7SUFxQnZELFlBQ2lDLGtCQUFzQyxFQUNwRCxVQUFzQjtRQUV2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YSxFQUFFLGNBQWMsRUFBRSxjQUFjLEVBQUUsa0JBQWtCLENBQUMsYUFFbkcsQ0FBQyxvQkFBb0IsQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxpQkFDckQsQ0FBQyx1QkFBdUIsRUFBRSxDQUFDLG1CQUN6Qix1QkFBdUIsQ0FBQyxNQUFNOzswQkF3QjVDLFFBQVE7a0VBakJGLGVBQWU7c0JBQXZCLEtBQUs7Z0JBQ3FCLEdBQUc7c0JBQTdCLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQUNFLE9BQU87c0JBQWpDLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQUNoQixLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csS0FBSztzQkFBYixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUVJLFFBQVE7c0JBQWpCLE1BQU07Z0JBRXNCLE9BQU87c0JBQW5DLFNBQVM7dUJBQUMsZ0JBQWdCO2dCQUNBLEtBQUs7c0JBQS9CLFNBQVM7dUJBQUMsY0FBYyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDb21wb25lbnQsXG4gIERlc3Ryb3lSZWYsXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgZm9yd2FyZFJlZixcbiAgSW5wdXQsXG4gIE9uSW5pdCxcbiAgT3B0aW9uYWwsXG4gIE91dHB1dCxcbiAgVmlld0NoaWxkLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IHRha2VVbnRpbERlc3Ryb3llZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUvcnhqcy1pbnRlcm9wJztcbmltcG9ydCB7IEJ1dHRvbkNvbXBvbmVudCB9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvYXRvbXMvYnV0dG9uL2J1dHRvbi5jb21wb25lbnQnO1xuaW1wb3J0IHsgSWNvbkNvbXBvbmVudCB9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvYXRvbXMvaWNvbi9pY29uLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBGb3JtT3B0aW9uQmFzZSB9IGZyb20gJy4uLy4uL21vZGVsL2Zvcm1zL2Zvcm0tYmFzZS5tb2RlbCc7XG5pbXBvcnQgeyBPcHRpb25Db21wb25lbnQgfSBmcm9tICcuLi9vcHRpb24vb3B0aW9uLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBTdWJqZWN0LCBkZWJvdW5jZVRpbWUgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IEZvcm1Hcm91cERpcmVjdGl2ZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IExhYmVsQ29tcG9uZW50IH0gZnJvbSAnLi4vbGFiZWwvbGFiZWwuY29tcG9uZW50JztcbmltcG9ydCB7IEFsZXJ0Q29tcG9uZW50IH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy9hdG9tcy9hbGVydC9hbGVydC5jb21wb25lbnQnO1xuaW1wb3J0IHsgcHJvdmlkZUNvbnRyb2xDb250YWluZXIsIHByb3ZpZGVWYWx1ZUFjY2Vzc29yIH0gZnJvbSAnLi4vdXRpbHMvZm9ybS51dGlsJztcbmltcG9ydCB7IEZvcm1HZW5lcmljQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vc2VydmljZXMvZm9ybS1nZW5lcmljLmFic3RyYWN0JztcbmltcG9ydCB7IEZvcm1FcnJvckNvbXBvbmVudCB9IGZyb20gJy4uL2Vycm9yL2Vycm9yLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBDb21wb25lbnREaXNwb3NpdGlvbiB9IGZyb20gJy4uLy4uL21vZGVsL2NvbXBvbmVudHMvY29tcG9uZW50LWRpc3Bvc2l0aW9uLmVudW0nO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjdC1zZWxlY3QnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbT3B0aW9uQ29tcG9uZW50LCBCdXR0b25Db21wb25lbnQsIEljb25Db21wb25lbnQsIExhYmVsQ29tcG9uZW50LCBBbGVydENvbXBvbmVudCwgRm9ybUVycm9yQ29tcG9uZW50XSxcbiAgdGVtcGxhdGVVcmw6ICcuL3NlbGVjdC5jb21wb25lbnQuaHRtbCcsXG4gIHByb3ZpZGVyczogW3Byb3ZpZGVWYWx1ZUFjY2Vzc29yKGZvcndhcmRSZWYoKCkgPT4gU2VsZWN0Q29tcG9uZW50KSldLFxuICB2aWV3UHJvdmlkZXJzOiBbcHJvdmlkZUNvbnRyb2xDb250YWluZXIoKV0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBTZWxlY3RDb21wb25lbnQgZXh0ZW5kcyBGb3JtR2VuZXJpY0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIGZvY3VzT3V0JCA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgaXNPcGVuID0gZmFsc2U7XG4gIG9wdGlvbiA9ICcnO1xuXG4gIEBJbnB1dCgpIGZvcm1Db250cm9sTmFtZSE6IHN0cmluZztcbiAgQElucHV0KHsgcmVxdWlyZWQ6IHRydWUgfSkga2V5ID0gJyc7XG4gIEBJbnB1dCh7IHJlcXVpcmVkOiB0cnVlIH0pIG9wdGlvbnM6IEZvcm1PcHRpb25CYXNlW10gPSBbXTtcbiAgQElucHV0KCkgbGFiZWwgPSAnJztcbiAgQElucHV0KCkgaGVscGVyID0gJyc7XG4gIEBJbnB1dCgpIHBsYWNlaG9sZGVyID0gJyc7XG4gIEBJbnB1dCgpIHZhbHVlOiBhbnkgPSAnJztcbiAgQElucHV0KCkgZGlzcG9zaXRpb246IENvbXBvbmVudERpc3Bvc2l0aW9uIHwgc3RyaW5nID0gJ3ZlcnRpY2FsJztcbiAgQElucHV0KCkgZnVsbFNpemU6IGJvb2xlYW4gPSB0cnVlO1xuICBASW5wdXQoKSBzaG93RXJyb3I6IGJvb2xlYW4gPSBmYWxzZTtcblxuICBAT3V0cHV0KCkgc2VsZWN0ZWQgPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcblxuICBAVmlld0NoaWxkKCd0cmlnZ2VyRWxlbWVudCcpIHRyaWdnZXIhOiBFbGVtZW50UmVmPEhUTUxCdXR0b25FbGVtZW50PjtcbiAgQFZpZXdDaGlsZCgnb3B0aW9uc1BhbmVsJykgcGFuZWwhOiBFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50PjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBAT3B0aW9uYWwoKSBwcm90ZWN0ZWQgb3ZlcnJpZGUgZm9ybUdyb3VwRGlyZWN0aXZlOiBGb3JtR3JvdXBEaXJlY3RpdmUsXG4gICAgcHJpdmF0ZSByZWFkb25seSBkZXN0cm95UmVmOiBEZXN0cm95UmVmXG4gICkge1xuICAgIHN1cGVyKGZvcm1Hcm91cERpcmVjdGl2ZSk7XG4gIH1cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLnNlbGVjdE9wdGlvbih0aGlzLnZhbHVlLCBmYWxzZSk7XG4gICAgdGhpcy5mb2N1c091dCQucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5kZXN0cm95UmVmKSwgZGVib3VuY2VUaW1lKDIwMCkpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLnRyaWdnZXJNYXJrQ2hlY2soKTtcbiAgICAgIHRoaXMuY2xvc2UoKTtcbiAgICB9KTtcbiAgfVxuXG4gIHRvZ2dsZSgpOiB2b2lkIHtcbiAgICB0aGlzLmlzT3BlbiA9ICF0aGlzLmlzT3BlbjtcbiAgICBpZiAoIXRoaXMuaXNPcGVuKSB7XG4gICAgICB0aGlzLnRyaWdnZXJUb3VjaGVkKCk7XG4gICAgfVxuICB9XG5cbiAgY2xvc2UoKTogdm9pZCB7XG4gICAgdGhpcy5pc09wZW4gPSBmYWxzZTtcbiAgICB0aGlzLnRyaWdnZXJUb3VjaGVkKCk7XG4gIH1cblxuICBzZWxlY3RPcHRpb24oa2V5OiBhbnksIHByb3BhZ2F0ZSA9IHRydWUpIHtcbiAgICBjb25zdCBzZWxlY3RlZE9wdGlvbiA9IHRoaXMub3B0aW9ucy5maW5kKG9wdGlvbiA9PiBvcHRpb24ua2V5ID09PSBrZXkpITtcbiAgICB0aGlzLm9wdGlvbiA9IGtleSA9PT0gbnVsbCA/IHRoaXMucGxhY2Vob2xkZXIgOiBzZWxlY3RlZE9wdGlvbj8ubGFiZWw7XG4gICAgaWYgKHByb3BhZ2F0ZSkge1xuICAgICAgdGhpcy5zZWxlY3RlZC5lbWl0KGtleSk7XG4gICAgICB0aGlzLnRyaWdnZXJDaGFuZ2Uoc2VsZWN0ZWRPcHRpb24/LmtleSA/PyBudWxsKTtcbiAgICAgIHRoaXMuY2xvc2UoKTtcbiAgICB9XG4gIH1cblxuICB3cml0ZVZhbHVlKHZhbHVlOiBhbnkpIHtcbiAgICB0aGlzLnRyaWdnZXJNYXJrQ2hlY2soKTtcbiAgICB0aGlzLnNlbGVjdE9wdGlvbih2YWx1ZSwgZmFsc2UpO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiZmxleCBnYXAtMSBmb250LXByaW1hcnlcIiBbY2xhc3MuZmxleC1jb2xdPVwiZGlzcG9zaXRpb24gPT09ICd2ZXJ0aWNhbCdcIj5cbiAgQGlmIChsYWJlbCkge1xuICAgIDxjdC1mb3JtLWxhYmVsIFt0ZXh0XT1cImxhYmVsXCIgW2hhc0Vycm9yXT1cImhhc0Vycm9ycyhmb3JtQ29udHJvbClcIiBbc2hvd0Vycm9yXT1cInNob3dFcnJvclwiIC8+XG4gIH1cbiAgPGRpdiBjbGFzcz1cImZsZXggZmxleC1jb2xcIiBbY2xhc3Mudy1mdWxsXT1cImZ1bGxTaXplXCIgW2NsYXNzLnctZml0XT1cIiFmdWxsU2l6ZVwiPlxuICAgIDxkaXZcbiAgICAgIHRhYmluZGV4PVwiMFwiXG4gICAgICAjdHJpZ2dlckVsZW1lbnRcbiAgICAgIGNsYXNzPVwiZmxleCBjdXJzb3ItcG9pbnRlciBmbGV4LXJvdyBpdGVtcy1jZW50ZXIganVzdGlmeS1iZXR3ZWVuIHJvdW5kZWQtbWQgYm9yZGVyIGJnLXN1cmZhY2UgcHgtNCBweS0yIHRleHQtc20gdGV4dC1vbi1zdXJmYWNlIGRhcms6Ymctc3VyZmFjZS1kYXJrIGRhcms6dGV4dC1vbi1zdXJmYWNlLWRhcmtcIlxuICAgICAgW2NsYXNzLmJvcmRlci1lcnJvcl09XCJoYXNFcnJvcnMoZm9ybUNvbnRyb2wpICYmIHNob3dFcnJvclwiXG4gICAgICBbY2xhc3MuYm9yZGVyLW5ldXRyYWwtMzAwXT1cIiFoYXNFcnJvcnMoZm9ybUNvbnRyb2wpIHx8ICFzaG93RXJyb3JcIlxuICAgICAgW2NsYXNzLnRleHQtb24tc3VyZmFjZV09XCJvcHRpb24gIT09IHBsYWNlaG9sZGVyXCJcbiAgICAgIChmb2N1c291dCk9XCJmb2N1c091dCQubmV4dCgkZXZlbnQpXCJcbiAgICAgIChjbGljayk9XCJ0b2dnbGUoKVwiPlxuICAgICAgPHNwYW4gW2NsYXNzLnRleHQtbmV1dHJhbC01MDBdPVwib3B0aW9uID09PSBwbGFjZWhvbGRlclwiPnt7IG9wdGlvbiB9fTwvc3Bhbj5cbiAgICAgIDxjdC1pY29uIGNsYXNzPVwiZmxleFwiIFtzaXplXT1cIidzbSdcIiBbaWNvbl09XCJpc09wZW4gPyAnY2hldnJvbi11cCcgOiAnY2hldnJvbi1kb3duJ1wiIC8+XG4gICAgPC9kaXY+XG4gICAgQGlmIChpc09wZW4pIHtcbiAgICAgIDxkaXYgY2xhc3M9XCJyZWxhdGl2ZSBmbGV4IGZsZXgtY29sXCI+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICAjb3B0aW9uc1BhbmVsXG4gICAgICAgICAgW2NsYXNzLnctZnVsbF09XCJmdWxsU2l6ZVwiXG4gICAgICAgICAgW2NsYXNzLnctZml0XT1cIiFmdWxsU2l6ZVwiXG4gICAgICAgICAgY2xhc3M9XCJhYnNvbHV0ZSB0b3AtMC41IHotMTAgZmxleCBtYXgtaC03MiBmbGV4LWNvbCBvdmVyZmxvdy15LWF1dG8gcm91bmRlZC1tZCBib3JkZXIgYm9yZGVyLW5ldXRyYWwtNDAwIGJnLXN1cmZhY2UgdGV4dC1vbi1zdXJmYWNlIHNoYWRvdy1sZyBkYXJrOmJnLXN1cmZhY2UtZGFyayBkYXJrOnRleHQtb24tc3VyZmFjZS1kYXJrXCI+XG4gICAgICAgICAgPGN0LW9wdGlvbiAoY2xpY2spPVwic2VsZWN0T3B0aW9uKG51bGwpXCIgW2xhYmVsXT1cInBsYWNlaG9sZGVyXCIgLz5cbiAgICAgICAgICBAZm9yIChvcHRpb24gb2Ygb3B0aW9uczsgdHJhY2sgb3B0aW9uKSB7XG4gICAgICAgICAgICA8Y3Qtb3B0aW9uIChjbGljayk9XCJzZWxlY3RPcHRpb24ob3B0aW9uLmtleSlcIiBbbGFiZWxdPVwib3B0aW9uLmxhYmVsXCIgW2ljb25dPVwib3B0aW9uLmljb24hXCIgLz5cbiAgICAgICAgICB9XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgfVxuICA8L2Rpdj5cbiAgQGlmIChmb3JtQ29udHJvbCkge1xuICAgIDxjdC1mb3JtLWFsZXJ0XG4gICAgICBbaGFzRXJyb3JzXT1cImhhc0Vycm9ycyhmb3JtQ29udHJvbClcIlxuICAgICAgW2hlbHBlcl09XCJoZWxwZXJcIlxuICAgICAgW2Vycm9yc109XCJmb3JtQ29udHJvbC5lcnJvcnMgPz8ge31cIlxuICAgICAgc2l6ZT1cInhzXCIgLz5cbiAgfVxuPC9kaXY+XG4iXX0=