carbon-components-angular
Version:
Next generation components
349 lines (345 loc) • 32.4 kB
JavaScript
import { ChangeDetectionStrategy, Component, EventEmitter, HostBinding, HostListener, Input, Output, ViewChild } from "@angular/core";
import { AILabelPopoverDirective } from "./ai-label-popover.directive";
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "carbon-components-angular/button";
import * as i3 from "carbon-components-angular/icon";
import * as i4 from "./ai-label-popover.directive";
/**
* AI-branded toggletip control (`cds-ai-label`). Renders an "AI" badge that opens a
* popover; projected content and optional actions use `ng-content`.
*
* Get started with importing the module:
*
* ```typescript
* import { AILabelModule } from 'carbon-components-angular';
* ```
*
* ```html
* <cds-ai-label size="md">
* <div>
* <p>AI Explained</p>
* <h2>84%</h2>
* <p>Confidence score</p>
* </div>
* <div cdsAILabelActions>
* <button cdsButton="ghost" size="sm">View details</button>
* </div>
* </cds-ai-label>
* ```
*
* `[cdsAILabelActions]` adds `cds--toggletip-actions` and `cds--ai-label-actions`
* to its host. Place it as a **sibling** of the body content, both direct
* children of `<cds-ai-label>`. `[cdsAILabelContent]` is an optional marker; the
* `cds--ai-label-content` / `cds--toggletip-content` classes come from this
* component’s template.
*
* [See demo](../../?path=/story/components-ai-label--default)
*/
export class AILabelComponent {
constructor(elementRef) {
this.elementRef = elementRef;
this.aiLabelClass = true;
/**
* Show caret at the alignment position.
*/
this.caret = true;
/**
* Enable drop shadow around the popover container.
*/
this.dropShadow = false;
/**
* Enable high contrast for popover container.
*/
this.highContrast = true;
/**
* **Experimental**: Use floating-ui to position the tooltip.
*/
this.autoAlign = false;
/**
* Whether the callout is open.
*/
this.isOpen = false;
/**
* Emits when the callout is closed.
*/
this.onClose = new EventEmitter();
/**
* Emits when the callout is opened.
*/
this.onOpen = new EventEmitter();
/**
* Emits when `isOpen` changes (two-way binding).
*/
this.isOpenChange = new EventEmitter();
/**
* Unique id used to associate the trigger button with the popover panel
* via `aria-controls` / `id`.
*/
this.id = `ai-label-${AILabelComponent.labelCounter++}`;
/**
* Text inside the AI badge.
*/
this.aiText = "AI";
/**
* Set badge shape: `"default"` (circular) or `"inline"` (pill, optional `textLabel`).
*/
this.kind = "default";
/**
* Set badge size
*/
this.size = "xs";
/**
* When `true`, shows the revert icon instead of the badge (AI-generated value
* is active and can be reverted).
*/
this.revertActive = false;
/**
* Accessible label / tooltip for the revert icon button.
*/
this.revertLabel = "Revert to AI input";
/**
* `aria-label` for the AI badge trigger (combined with `aiText` in `computedAriaLabel`).
*/
this.ariaLabel = "Show information";
/**
* Emitted when the revert icon is clicked.
*/
this.revertClick = new EventEmitter();
this.documentClick = this.handleOutsideClick.bind(this);
}
get revertClass() {
return this.revertActive;
}
/**
* Horizontal shift along the alignment axis when `autoAlign` is on, matching
* React `AILabel` (`alignmentAxisOffset={isSmallIcon ? -24 : 0}` on `Toggletip`).
*/
get alignmentAxisOffset() {
return ["mini", "2xs", "xs"].includes(this.size) ? -24 : 0;
}
onPopoverIsOpenChange(open) {
this.isOpen = open;
this.isOpenChange.emit(open);
}
get triggerClasses() {
return {
"cds--toggletip-button": true,
"cds--ai-label__button": true,
[`cds--ai-label__button--${this.size}`]: true,
[`cds--ai-label__button--${this.kind}`]: true,
"cds--ai-label__button--inline-with-content": this.kind === "inline" && !!this.textLabel
};
}
/**
* Trigger `aria-label`: `"${aiText} ${ariaLabel}"`, or
* `"${aiText} ${textLabel}"` when `kind` is `"inline"` and `textLabel` is set.
*/
get computedAriaLabel() {
const suffix = (this.kind === "inline" && this.textLabel) ? this.textLabel : this.ariaLabel;
return `${this.aiText} ${suffix}`;
}
ngAfterViewInit() {
if (this.isOpen) {
document.addEventListener("click", this.documentClick);
}
}
ngOnChanges(changes) {
if (changes.revertActive && !changes.revertActive.firstChange && changes.revertActive.currentValue) {
this.isOpen = false;
document.removeEventListener("click", this.documentClick);
}
}
ngOnDestroy() {
document.removeEventListener("click", this.documentClick);
}
onTriggerClick(event) {
const opening = !this.isOpen;
if (opening) {
document.addEventListener("click", this.documentClick);
}
else {
document.removeEventListener("click", this.documentClick);
}
this.aiLabelPopover?.handleChange(opening, event);
}
onRevertButtonClick(event) {
this.revertClick.emit(event);
}
hostkeys(event) {
if (this.isOpen && event.key === "Escape") {
event.stopPropagation();
document.removeEventListener("click", this.documentClick);
this.aiLabelPopover?.handleChange(false, event);
}
}
/**
* Dismisses the popover when a click lands outside the host element.
*/
handleOutsideClick(event) {
if (!this.elementRef.nativeElement.contains(event.target)) {
this.aiLabelPopover?.handleChange(false, event);
document.removeEventListener("click", this.documentClick);
}
}
}
AILabelComponent.labelCounter = 0;
AILabelComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: AILabelComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
AILabelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: AILabelComponent, selector: "cds-ai-label, ibm-ai-label", inputs: { align: "align", caret: "caret", dropShadow: "dropShadow", highContrast: "highContrast", autoAlign: "autoAlign", isOpen: "isOpen", id: "id", aiText: "aiText", textLabel: "textLabel", kind: "kind", size: "size", revertActive: "revertActive", revertLabel: "revertLabel", ariaLabel: "ariaLabel" }, outputs: { onClose: "onClose", onOpen: "onOpen", isOpenChange: "isOpenChange", revertClick: "revertClick" }, host: { listeners: { "keyup": "hostkeys($event)" }, properties: { "class.cds--ai-label": "this.aiLabelClass", "class.cds--ai-label--revert": "this.revertClass" } }, viewQueries: [{ propertyName: "aiLabelPopover", first: true, predicate: ["aiLabelPopoverHost"], descendants: true, read: AILabelPopoverDirective }], usesOnChanges: true, ngImport: i0, template: `
<ng-container *ngIf="!revertActive">
<span
#aiLabelPopoverHost
cdsAILabelPopover
class="cds--toggletip"
[isOpen]="isOpen"
(isOpenChange)="onPopoverIsOpenChange($event)"
(onOpen)="onOpen.emit($event)"
(onClose)="onClose.emit($event)"
[align]="align"
[caret]="caret"
[dropShadow]="dropShadow"
[highContrast]="highContrast"
[autoAlign]="autoAlign"
[alignmentAxisOffset]="alignmentAxisOffset">
<button
type="button"
[attr.aria-label]="computedAriaLabel"
[attr.aria-expanded]="isOpen"
[attr.aria-controls]="id"
[ngClass]="triggerClasses"
(click)="onTriggerClick($event)">
<span class="cds--ai-label__text">{{aiText}}</span>
<span *ngIf="kind === 'inline' && textLabel" class="cds--ai-label__additional-text">{{textLabel}}</span>
</button>
<span
[id]="id"
class="cds--popover"
aria-live="polite">
<span class="cds--popover-content cds--ai-label-content">
<div class="cds--toggletip-content">
<ng-content></ng-content>
</div>
<span *ngIf="autoAlign" class="cds--popover-caret cds--popover--auto-align"></span>
</span>
<span *ngIf="!autoAlign" class="cds--popover-caret"></span>
</span>
</span>
</ng-container>
<cds-icon-button
*ngIf="revertActive"
kind="ghost"
size="sm"
[description]="revertLabel"
[autoAlign]="autoAlign"
[buttonAttributes]="{ 'aria-label': revertLabel }"
(click)="onRevertButtonClick($event)">
<svg cdsIcon="undo" size="16"></svg>
</cds-icon-button>
`, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IconButton, selector: "cds-icon-button, ibm-icon-button", inputs: ["buttonNgClass", "buttonAttributes", "buttonId", "kind", "size", "type", "isExpressive", "disabled", "description", "showTooltipWhenDisabled"], outputs: ["click", "focus", "blur", "tooltipClick"] }, { kind: "directive", type: i3.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "directive", type: i4.AILabelPopoverDirective, selector: "[cdsAILabelPopover]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: AILabelComponent, decorators: [{
type: Component,
args: [{
selector: "cds-ai-label, ibm-ai-label",
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<ng-container *ngIf="!revertActive">
<span
#aiLabelPopoverHost
cdsAILabelPopover
class="cds--toggletip"
[isOpen]="isOpen"
(isOpenChange)="onPopoverIsOpenChange($event)"
(onOpen)="onOpen.emit($event)"
(onClose)="onClose.emit($event)"
[align]="align"
[caret]="caret"
[dropShadow]="dropShadow"
[highContrast]="highContrast"
[autoAlign]="autoAlign"
[alignmentAxisOffset]="alignmentAxisOffset">
<button
type="button"
[attr.aria-label]="computedAriaLabel"
[attr.aria-expanded]="isOpen"
[attr.aria-controls]="id"
[ngClass]="triggerClasses"
(click)="onTriggerClick($event)">
<span class="cds--ai-label__text">{{aiText}}</span>
<span *ngIf="kind === 'inline' && textLabel" class="cds--ai-label__additional-text">{{textLabel}}</span>
</button>
<span
[id]="id"
class="cds--popover"
aria-live="polite">
<span class="cds--popover-content cds--ai-label-content">
<div class="cds--toggletip-content">
<ng-content></ng-content>
</div>
<span *ngIf="autoAlign" class="cds--popover-caret cds--popover--auto-align"></span>
</span>
<span *ngIf="!autoAlign" class="cds--popover-caret"></span>
</span>
</span>
</ng-container>
<cds-icon-button
*ngIf="revertActive"
kind="ghost"
size="sm"
[description]="revertLabel"
[autoAlign]="autoAlign"
[buttonAttributes]="{ 'aria-label': revertLabel }"
(click)="onRevertButtonClick($event)">
<svg cdsIcon="undo" size="16"></svg>
</cds-icon-button>
`
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { aiLabelClass: [{
type: HostBinding,
args: ["class.cds--ai-label"]
}], revertClass: [{
type: HostBinding,
args: ["class.cds--ai-label--revert"]
}], align: [{
type: Input
}], caret: [{
type: Input
}], dropShadow: [{
type: Input
}], highContrast: [{
type: Input
}], autoAlign: [{
type: Input
}], isOpen: [{
type: Input
}], onClose: [{
type: Output
}], onOpen: [{
type: Output
}], isOpenChange: [{
type: Output
}], id: [{
type: Input
}], aiText: [{
type: Input
}], textLabel: [{
type: Input
}], kind: [{
type: Input
}], size: [{
type: Input
}], revertActive: [{
type: Input
}], revertLabel: [{
type: Input
}], ariaLabel: [{
type: Input
}], revertClick: [{
type: Output
}], aiLabelPopover: [{
type: ViewChild,
args: ["aiLabelPopoverHost", { read: AILabelPopoverDirective }]
}], hostkeys: [{
type: HostListener,
args: ["keyup", ["$event"]]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWktbGFiZWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FpLWxhYmVsL2FpLWxhYmVsLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRU4sdUJBQXVCLEVBQ3ZCLFNBQVMsRUFFVCxZQUFZLEVBQ1osV0FBVyxFQUNYLFlBQVksRUFDWixLQUFLLEVBR0wsTUFBTSxFQUVOLFNBQVMsRUFDVCxNQUFNLGVBQWUsQ0FBQztBQUd2QixPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQzs7Ozs7O0FBZXZFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E4Qkc7QUEwREgsTUFBTSxPQUFPLGdCQUFnQjtJQWtINUIsWUFBb0IsVUFBc0I7UUFBdEIsZUFBVSxHQUFWLFVBQVUsQ0FBWTtRQS9HTixpQkFBWSxHQUFHLElBQUksQ0FBQztRQVd4RDs7V0FFRztRQUNNLFVBQUssR0FBRyxJQUFJLENBQUM7UUFFdEI7O1dBRUc7UUFDTSxlQUFVLEdBQUcsS0FBSyxDQUFDO1FBRTVCOztXQUVHO1FBQ00saUJBQVksR0FBRyxJQUFJLENBQUM7UUFFN0I7O1dBRUc7UUFDTSxjQUFTLEdBQUcsS0FBSyxDQUFDO1FBRTNCOztXQUVHO1FBQ00sV0FBTSxHQUFHLEtBQUssQ0FBQztRQUV4Qjs7V0FFRztRQUNPLFlBQU8sR0FBRyxJQUFJLFlBQVksRUFBUyxDQUFDO1FBRTlDOztXQUVHO1FBQ08sV0FBTSxHQUFHLElBQUksWUFBWSxFQUFTLENBQUM7UUFFN0M7O1dBRUc7UUFDTyxpQkFBWSxHQUFHLElBQUksWUFBWSxFQUFXLENBQUM7UUFFckQ7OztXQUdHO1FBQ00sT0FBRSxHQUFHLFlBQVksZ0JBQWdCLENBQUMsWUFBWSxFQUFFLEVBQUUsQ0FBQztRQUU1RDs7V0FFRztRQUNNLFdBQU0sR0FBRyxJQUFJLENBQUM7UUFPdkI7O1dBRUc7UUFDTSxTQUFJLEdBQXlCLFNB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LFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQW9EVDtpQkFDRDtpR0FJb0MsWUFBWTtzQkFBL0MsV0FBVzt1QkFBQyxxQkFBcUI7Z0JBQ2MsV0FBVztzQkFBMUQsV0FBVzt1QkFBQyw2QkFBNkI7Z0JBUWpDLEtBQUs7c0JBQWIsS0FBSztnQkFLRyxLQUFLO3NCQUFiLEtBQUs7Z0JBS0csVUFBVTtzQkFBbEIsS0FBSztnQkFLRyxZQUFZO3NCQUFwQixLQUFLO2dCQUtHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBS0csTUFBTTtzQkFBZCxLQUFLO2dCQUtJLE9BQU87c0JBQWhCLE1BQU07Z0JBS0csTUFBTTtzQkFBZixNQUFNO2dCQUtHLFlBQVk7c0JBQXJCLE1BQU07Z0JBTUUsRUFBRTtzQkFBVixLQUFLO2dCQUtHLE1BQU07c0JBQWQsS0FBSztnQkFLRyxTQUFTO3NCQUFqQixLQUFLO2dCQUtHLElBQUk7c0JBQVosS0FBSztnQkFLRyxJQUFJO3NCQUFaLEtBQUs7Z0JBY0csWUFBWTtzQkFBcEIsS0FBSztnQkFLRyxXQUFXO3NCQUFuQixLQUFLO2dCQUtHLFNBQVM7c0JBQWpCLEtBQUs7Z0JBS0ksV0FBVztzQkFBcEIsTUFBTTtnQkFHQyxjQUFjO3NCQURyQixTQUFTO3VCQUFDLG9CQUFvQixFQUFFLEVBQUUsSUFBSSxFQUFFLHVCQUF1QixFQUFFO2dCQStEbEUsUUFBUTtzQkFEUCxZQUFZO3VCQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcblx0QWZ0ZXJWaWV3SW5pdCxcclxuXHRDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcclxuXHRDb21wb25lbnQsXHJcblx0RWxlbWVudFJlZixcclxuXHRFdmVudEVtaXR0ZXIsXHJcblx0SG9zdEJpbmRpbmcsXHJcblx0SG9zdExpc3RlbmVyLFxyXG5cdElucHV0LFxyXG5cdE9uQ2hhbmdlcyxcclxuXHRPbkRlc3Ryb3ksXHJcblx0T3V0cHV0LFxyXG5cdFNpbXBsZUNoYW5nZXMsXHJcblx0Vmlld0NoaWxkXHJcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcclxuaW1wb3J0IHsgUGxhY2VtZW50IH0gZnJvbSBcIkBmbG9hdGluZy11aS9kb21cIjtcclxuXHJcbmltcG9ydCB7IEFJTGFiZWxQb3BvdmVyRGlyZWN0aXZlIH0gZnJvbSBcIi4vYWktbGFiZWwtcG9wb3Zlci5kaXJlY3RpdmVcIjtcclxuXHJcbi8qKlxyXG4gKiBAZGVwcmVjYXRlZCBhbGlnbm1lbnRzIOKAlCB1c2UgYFBsYWNlbWVudGAgbmFtZXNcclxuICovXHJcbnR5cGUgRGVwcmVjYXRlZEFJTGFiZWxBbGlnbiA9XHJcblx0fCBcInRvcC1sZWZ0XCJcclxuXHR8IFwidG9wLXJpZ2h0XCJcclxuXHR8IFwiYm90dG9tLWxlZnRcIlxyXG5cdHwgXCJib3R0b20tcmlnaHRcIlxyXG5cdHwgXCJsZWZ0LWJvdHRvbVwiXHJcblx0fCBcImxlZnQtdG9wXCJcclxuXHR8IFwicmlnaHQtYm90dG9tXCJcclxuXHR8IFwicmlnaHQtdG9wXCI7XHJcblxyXG4vKipcclxuICogQUktYnJhbmRlZCB0b2dnbGV0aXAgY29udHJvbCAoYGNkcy1haS1sYWJlbGApLiBSZW5kZXJzIGFuIFwiQUlcIiBiYWRnZSB0aGF0IG9wZW5zIGFcclxuICogcG9wb3ZlcjsgcHJvamVjdGVkIGNvbnRlbnQgYW5kIG9wdGlvbmFsIGFjdGlvbnMgdXNlIGBuZy1jb250ZW50YC5cclxuICpcclxuICogR2V0IHN0YXJ0ZWQgd2l0aCBpbXBvcnRpbmcgdGhlIG1vZHVsZTpcclxuICpcclxuICogYGBgdHlwZXNjcmlwdFxyXG4gKiBpbXBvcnQgeyBBSUxhYmVsTW9kdWxlIH0gZnJvbSAnY2FyYm9uLWNvbXBvbmVudHMtYW5ndWxhcic7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBgYGBodG1sXHJcbiAqIDxjZHMtYWktbGFiZWwgc2l6ZT1cIm1kXCI+XHJcbiAqICAgPGRpdj5cclxuICogICAgIDxwPkFJIEV4cGxhaW5lZDwvcD5cclxuICogICAgIDxoMj44NCU8L2gyPlxyXG4gKiAgICAgPHA+Q29uZmlkZW5jZSBzY29yZTwvcD5cclxuICogICA8L2Rpdj5cclxuICogICA8ZGl2IGNkc0FJTGFiZWxBY3Rpb25zPlxyXG4gKiAgICAgPGJ1dHRvbiBjZHNCdXR0b249XCJnaG9zdFwiIHNpemU9XCJzbVwiPlZpZXcgZGV0YWlsczwvYnV0dG9uPlxyXG4gKiAgIDwvZGl2PlxyXG4gKiA8L2Nkcy1haS1sYWJlbD5cclxuICogYGBgXHJcbiAqXHJcbiAqIGBbY2RzQUlMYWJlbEFjdGlvbnNdYCBhZGRzIGBjZHMtLXRvZ2dsZXRpcC1hY3Rpb25zYCBhbmQgYGNkcy0tYWktbGFiZWwtYWN0aW9uc2BcclxuICogdG8gaXRzIGhvc3QuIFBsYWNlIGl0IGFzIGEgKipzaWJsaW5nKiogb2YgdGhlIGJvZHkgY29udGVudCwgYm90aCBkaXJlY3RcclxuICogY2hpbGRyZW4gb2YgYDxjZHMtYWktbGFiZWw+YC4gYFtjZHNBSUxhYmVsQ29udGVudF1gIGlzIGFuIG9wdGlvbmFsIG1hcmtlcjsgdGhlXHJcbiAqIGBjZHMtLWFpLWxhYmVsLWNvbnRlbnRgIC8gYGNkcy0tdG9nZ2xldGlwLWNvbnRlbnRgIGNsYXNzZXMgY29tZSBmcm9tIHRoaXNcclxuICogY29tcG9uZW504oCZcyB0ZW1wbGF0ZS5cclxuICpcclxuICogW1NlZSBkZW1vXSguLi8uLi8/cGF0aD0vc3RvcnkvY29tcG9uZW50cy1haS1sYWJlbC0tZGVmYXVsdClcclxuICovXHJcbkBDb21wb25lbnQoe1xyXG5cdHNlbGVjdG9yOiBcImNkcy1haS1sYWJlbCwgaWJtLWFpLWxhYmVsXCIsXHJcblx0Y2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXHJcblx0dGVtcGxhdGU6IGBcclxuXHRcdDxuZy1jb250YWluZXIgKm5nSWY9XCIhcmV2ZXJ0QWN0aXZlXCI+XHJcblx0XHRcdDxzcGFuXHJcblx0XHRcdFx0I2FpTGFiZWxQb3BvdmVySG9zdFxyXG5cdFx0XHRcdGNkc0FJTGFiZWxQb3BvdmVyXHJcblx0XHRcdFx0Y2xhc3M9XCJjZHMtLXRvZ2dsZXRpcFwiXHJcblx0XHRcdFx0W2lzT3Blbl09XCJpc09wZW5cIlxyXG5cdFx0XHRcdChpc09wZW5DaGFuZ2UpPVwib25Qb3BvdmVySXNPcGVuQ2hhbmdlKCRldmVudClcIlxyXG5cdFx0XHRcdChvbk9wZW4pPVwib25PcGVuLmVtaXQoJGV2ZW50KVwiXHJcblx0XHRcdFx0KG9uQ2xvc2UpPVwib25DbG9zZS5lbWl0KCRldmVudClcIlxyXG5cdFx0XHRcdFthbGlnbl09XCJhbGlnblwiXHJcblx0XHRcdFx0W2NhcmV0XT1cImNhcmV0XCJcclxuXHRcdFx0XHRbZHJvcFNoYWRvd109XCJkcm9wU2hhZG93XCJcclxuXHRcdFx0XHRbaGlnaENvbnRyYXN0XT1cImhpZ2hDb250cmFzdFwiXHJcblx0XHRcdFx0W2F1dG9BbGlnbl09XCJhdXRvQWxpZ25cIlxyXG5cdFx0XHRcdFthbGlnbm1lbnRBeGlzT2Zmc2V0XT1cImFsaWdubWVudEF4aXNPZmZzZXRcIj5cclxuXHRcdFx0XHQ8YnV0dG9uXHJcblx0XHRcdFx0XHR0eXBlPVwiYnV0dG9uXCJcclxuXHRcdFx0XHRcdFthdHRyLmFyaWEtbGFiZWxdPVwiY29tcHV0ZWRBcmlhTGFiZWxcIlxyXG5cdFx0XHRcdFx0W2F0dHIuYXJpYS1leHBhbmRlZF09XCJpc09wZW5cIlxyXG5cdFx0XHRcdFx0W2F0dHIuYXJpYS1jb250cm9sc109XCJpZFwiXHJcblx0XHRcdFx0XHRbbmdDbGFzc109XCJ0cmlnZ2VyQ2xhc3Nlc1wiXHJcblx0XHRcdFx0XHQoY2xpY2spPVwib25UcmlnZ2VyQ2xpY2soJGV2ZW50KVwiPlxyXG5cdFx0XHRcdFx0PHNwYW4gY2xhc3M9XCJjZHMtLWFpLWxhYmVsX190ZXh0XCI+e3thaVRleHR9fTwvc3Bhbj5cclxuXHRcdFx0XHRcdDxzcGFuICpuZ0lmPVwia2luZCA9PT0gJ2lubGluZScgJiYgdGV4dExhYmVsXCIgY2xhc3M9XCJjZHMtLWFpLWxhYmVsX19hZGRpdGlvbmFsLXRleHRcIj57e3RleHRMYWJlbH19PC9zcGFuPlxyXG5cdFx0XHRcdDwvYnV0dG9uPlxyXG5cclxuXHRcdFx0XHQ8c3BhblxyXG5cdFx0XHRcdFx0W2lkXT1cImlkXCJcclxuXHRcdFx0XHRcdGNsYXNzPVwiY2RzLS1wb3BvdmVyXCJcclxuXHRcdFx0XHRcdGFyaWEtbGl2ZT1cInBvbGl0ZVwiPlxyXG5cdFx0XHRcdFx0PHNwYW4gY2xhc3M9XCJjZHMtLXBvcG92ZXItY29udGVudCBjZHMtLWFpLWxhYmVsLWNvbnRlbnRcIj5cclxuXHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cImNkcy0tdG9nZ2xldGlwLWNvbnRlbnRcIj5cclxuXHRcdFx0XHRcdFx0XHQ8bmctY29udGVudD48L25nLWNvbnRlbnQ+XHJcblx0XHRcdFx0XHRcdDwvZGl2PlxyXG5cdFx0XHRcdFx0XHQ8c3BhbiAqbmdJZj1cImF1dG9BbGlnblwiIGNsYXNzPVwiY2RzLS1wb3BvdmVyLWNhcmV0IGNkcy0tcG9wb3Zlci0tYXV0by1hbGlnblwiPjwvc3Bhbj5cclxuXHRcdFx0XHRcdDwvc3Bhbj5cclxuXHRcdFx0XHRcdDxzcGFuICpuZ0lmPVwiIWF1dG9BbGlnblwiIGNsYXNzPVwiY2RzLS1wb3BvdmVyLWNhcmV0XCI+PC9zcGFuPlxyXG5cdFx0XHRcdDwvc3Bhbj5cclxuXHRcdFx0PC9zcGFuPlxyXG5cdFx0PC9uZy1jb250YWluZXI+XHJcblxyXG5cdFx0PGNkcy1pY29uLWJ1dHRvblxyXG5cdFx0XHQqbmdJZj1cInJldmVydEFjdGl2ZVwiXHJcblx0XHRcdGtpbmQ9XCJnaG9zdFwiXHJcblx0XHRcdHNpemU9XCJzbVwiXHJcblx0XHRcdFtkZXNjcmlwdGlvbl09XCJyZXZlcnRMYWJlbFwiXHJcblx0XHRcdFthdXRvQWxpZ25dPVwiYXV0b0FsaWduXCJcclxuXHRcdFx0W2J1dHRvbkF0dHJpYnV0ZXNdPVwieyAnYXJpYS1sYWJlbCc6IHJldmVydExhYmVsIH1cIlxyXG5cdFx0XHQoY2xpY2spPVwib25SZXZlcnRCdXR0b25DbGljaygkZXZlbnQpXCI+XHJcblx0XHRcdDxzdmcgY2RzSWNvbj1cInVuZG9cIiBzaXplPVwiMTZcIj48L3N2Zz5cclxuXHRcdDwvY2RzLWljb24tYnV0dG9uPlxyXG5cdGBcclxufSlcclxuZXhwb3J0IGNsYXNzIEFJTGFiZWxDb21wb25lbnQgaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XHJcblx0c3RhdGljIGxhYmVsQ291bnRlciA9IDA7XHJcblxyXG5cdEBIb3N0QmluZGluZyhcImNsYXNzLmNkcy0tYWktbGFiZWxcIikgYWlMYWJlbENsYXNzID0gdHJ1ZTtcclxuXHRASG9zdEJpbmRpbmcoXCJjbGFzcy5jZHMtLWFpLWxhYmVsLS1yZXZlcnRcIikgZ2V0IHJldmVydENsYXNzKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMucmV2ZXJ0QWN0aXZlO1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogU2V0IGFsaWdubWVudCBvZiBwb3BvdmVyLiBEZXByZWNhdGVkIENhcmJvbiBhbGlnbm1lbnRzIGFyZSBtYXBwZWQgdG9cclxuXHQgKiBmbG9hdGluZy11aSBwbGFjZW1lbnRzLlxyXG5cdCAqL1xyXG5cdEBJbnB1dCgpIGFsaWduOiBEZXByZWNhdGVkQUlMYWJlbEFsaWduIHwgUGxhY2VtZW50O1xyXG5cclxuXHQvKipcclxuXHQgKiBTaG93IGNhcmV0IGF0IHRoZSBhbGlnbm1lbnQgcG9zaXRpb24uXHJcblx0ICovXHJcblx0QElucHV0KCkgY2FyZXQgPSB0cnVlO1xyXG5cclxuXHQvKipcclxuXHQgKiBFbmFibGUgZHJvcCBzaGFkb3cgYXJvdW5kIHRoZSBwb3BvdmVyIGNvbnRhaW5lci5cclxuXHQgKi9cclxuXHRASW5wdXQoKSBkcm9wU2hhZG93ID0gZmFsc2U7XHJcblxyXG5cdC8qKlxyXG5cdCAqIEVuYWJsZSBoaWdoIGNvbnRyYXN0IGZvciBwb3BvdmVyIGNvbnRhaW5lci5cclxuXHQgKi9cclxuXHRASW5wdXQoKSBoaWdoQ29udHJhc3QgPSB0cnVlO1xyXG5cclxuXHQvKipcclxuXHQgKiAqKkV4cGVyaW1lbnRhbCoqOiBVc2UgZmxvYXRpbmctdWkgdG8gcG9zaXRpb24gdGhlIHRvb2x0aXAuXHJcblx0ICovXHJcblx0QElucHV0KCkgYXV0b0FsaWduID0gZmFsc2U7XHJcblxyXG5cdC8qKlxyXG5cdCAqIFdoZXRoZXIgdGhlIGNhbGxvdXQgaXMgb3Blbi5cclxuXHQgKi9cclxuXHRASW5wdXQoKSBpc09wZW4gPSBmYWxzZTtcclxuXHJcblx0LyoqXHJcblx0ICogRW1pdHMgd2hlbiB0aGUgY2FsbG91dCBpcyBjbG9zZWQuXHJcblx0ICovXHJcblx0QE91dHB1dCgpIG9uQ2xvc2UgPSBuZXcgRXZlbnRFbWl0dGVyPEV2ZW50PigpO1xyXG5cclxuXHQvKipcclxuXHQgKiBFbWl0cyB3aGVuIHRoZSBjYWxsb3V0IGlzIG9wZW5lZC5cclxuXHQgKi9cclxuXHRAT3V0cHV0KCkgb25PcGVuID0gbmV3IEV2ZW50RW1pdHRlcjxFdmVudD4oKTtcclxuXHJcblx0LyoqXHJcblx0ICogRW1pdHMgd2hlbiBgaXNPcGVuYCBjaGFuZ2VzICh0d28td2F5IGJpbmRpbmcpLlxyXG5cdCAqL1xyXG5cdEBPdXRwdXQoKSBpc09wZW5DaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XHJcblxyXG5cdC8qKlxyXG5cdCAqIFVuaXF1ZSBpZCB1c2VkIHRvIGFzc29jaWF0ZSB0aGUgdHJpZ2dlciBidXR0b24gd2l0aCB0aGUgcG9wb3ZlciBwYW5lbFxyXG5cdCAqIHZpYSBgYXJpYS1jb250cm9sc2AgLyBgaWRgLlxyXG5cdCAqL1xyXG5cdEBJbnB1dCgpIGlkID0gYGFpLWxhYmVsLSR7QUlMYWJlbENvbXBvbmVudC5sYWJlbENvdW50ZXIrK31gO1xyXG5cclxuXHQvKipcclxuXHQgKiBUZXh0IGluc2lkZSB0aGUgQUkgYmFkZ2UuXHJcblx0ICovXHJcblx0QElucHV0KCkgYWlUZXh0ID0gXCJBSVwiO1xyXG5cclxuXHQvKipcclxuXHQgKiBFeHRyYSB0ZXh0IGJlc2lkZSB0aGUgYmFkZ2Ugd2hlbiBga2luZGAgaXMgYFwiaW5saW5lXCJgLlxyXG5cdCAqL1xyXG5cdEBJbnB1dCgpIHRleHRMYWJlbDogc3RyaW5nO1xyXG5cclxuXHQvKipcclxuXHQgKiBTZXQgYmFkZ2Ugc2hhcGU6IGBcImRlZmF1bHRcImAgKGNpcmN1bGFyKSBvciBgXCJpbmxpbmVcImAgKHBpbGwsIG9wdGlvbmFsIGB0ZXh0TGFiZWxgKS5cclxuXHQgKi9cclxuXHRASW5wdXQoKSBraW5kOiBcImRlZmF1bHRcIiB8IFwiaW5saW5lXCIgPSBcImRlZmF1bHRcIjtcclxuXHJcblx0LyoqXHJcblx0ICogU2V0IGJhZGdlIHNpemVcclxuXHQgKi9cclxuXHRASW5wdXQoKSBzaXplOiBcIm1pbmlcIiB8IFwiMnhzXCIgfCBcInhzXCIgfCBcInNtXCIgfCBcIm1kXCIgfCBcImxnXCIgfCBcInhsXCIgPSBcInhzXCI7XHJcblxyXG5cdC8qKlxyXG5cdCAqIEhvcml6b250YWwgc2hpZnQgYWxvbmcgdGhlIGFsaWdubWVudCBheGlzIHdoZW4gYGF1dG9BbGlnbmAgaXMgb24sIG1hdGNoaW5nXHJcblx0ICogUmVhY3QgYEFJTGFiZWxgIChgYWxpZ25tZW50QXhpc09mZnNldD17aXNTbWFsbEljb24gPyAtMjQgOiAwfWAgb24gYFRvZ2dsZXRpcGApLlxyXG5cdCAqL1xyXG5cdGdldCBhbGlnbm1lbnRBeGlzT2Zmc2V0KCk6IG51bWJlciB7XHJcblx0XHRyZXR1cm4gW1wibWluaVwiLCBcIjJ4c1wiLCBcInhzXCJdLmluY2x1ZGVzKHRoaXMuc2l6ZSkgPyAtMjQgOiAwO1xyXG5cdH1cclxuXHJcblx0LyoqXHJcblx0ICogV2hlbiBgdHJ1ZWAsIHNob3dzIHRoZSByZXZlcnQgaWNvbiBpbnN0ZWFkIG9mIHRoZSBiYWRnZSAoQUktZ2VuZXJhdGVkIHZhbHVlXHJcblx0ICogaXMgYWN0aXZlIGFuZCBjYW4gYmUgcmV2ZXJ0ZWQpLlxyXG5cdCAqL1xyXG5cdEBJbnB1dCgpIHJldmVydEFjdGl2ZSA9IGZhbHNlO1xyXG5cclxuXHQvKipcclxuXHQgKiBBY2Nlc3NpYmxlIGxhYmVsIC8gdG9vbHRpcCBmb3IgdGhlIHJldmVydCBpY29uIGJ1dHRvbi5cclxuXHQgKi9cclxuXHRASW5wdXQoKSByZXZlcnRMYWJlbCA9IFwiUmV2ZXJ0IHRvIEFJIGlucHV0XCI7XHJcblxyXG5cdC8qKlxyXG5cdCAqIGBhcmlhLWxhYmVsYCBmb3IgdGhlIEFJIGJhZGdlIHRyaWdnZXIgKGNvbWJpbmVkIHdpdGggYGFpVGV4dGAgaW4gYGNvbXB1dGVkQXJpYUxhYmVsYCkuXHJcblx0ICovXHJcblx0QElucHV0KCkgYXJpYUxhYmVsID0gXCJTaG93IGluZm9ybWF0aW9uXCI7XHJcblxyXG5cdC8qKlxyXG5cdCAqIEVtaXR0ZWQgd2hlbiB0aGUgcmV2ZXJ0IGljb24gaXMgY2xpY2tlZC5cclxuXHQgKi9cclxuXHRAT3V0cHV0KCkgcmV2ZXJ0Q2xpY2sgPSBuZXcgRXZlbnRFbWl0dGVyPE1vdXNlRXZlbnQ+KCk7XHJcblxyXG5cdEBWaWV3Q2hpbGQoXCJhaUxhYmVsUG9wb3Zlckhvc3RcIiwgeyByZWFkOiBBSUxhYmVsUG9wb3ZlckRpcmVjdGl2ZSB9KVxyXG5cdHByaXZhdGUgYWlMYWJlbFBvcG92ZXI6IEFJTGFiZWxQb3BvdmVyRGlyZWN0aXZlO1xyXG5cclxuXHRwcml2YXRlIHJlYWRvbmx5IGRvY3VtZW50Q2xpY2sgPSB0aGlzLmhhbmRsZU91dHNpZGVDbGljay5iaW5kKHRoaXMpO1xyXG5cclxuXHRjb25zdHJ1Y3Rvcihwcml2YXRlIGVsZW1lbnRSZWY6IEVsZW1lbnRSZWYpIHt9XHJcblxyXG5cdG9uUG9wb3ZlcklzT3BlbkNoYW5nZShvcGVuOiBib29sZWFuKTogdm9pZCB7XHJcblx0XHR0aGlzLmlzT3BlbiA9IG9wZW47XHJcblx0XHR0aGlzLmlzT3BlbkNoYW5nZS5lbWl0KG9wZW4pO1xyXG5cdH1cclxuXHJcblx0Z2V0IHRyaWdnZXJDbGFzc2VzKCk6IFJlY29yZDxzdHJpbmcsIGJvb2xlYW4+IHtcclxuXHRcdHJldHVybiB7XHJcblx0XHRcdFwiY2RzLS10b2dnbGV0aXAtYnV0dG9uXCI6IHRydWUsXHJcblx0XHRcdFwiY2RzLS1haS1sYWJlbF9fYnV0dG9uXCI6IHRydWUsXHJcblx0XHRcdFtgY2RzLS1haS1sYWJlbF9fYnV0dG9uLS0ke3RoaXMuc2l6ZX1gXTogdHJ1ZSxcclxuXHRcdFx0W2BjZHMtLWFpLWxhYmVsX19idXR0b24tLSR7dGhpcy5raW5kfWBdOiB0cnVlLFxyXG5cdFx0XHRcImNkcy0tYWktbGFiZWxfX2J1dHRvbi0taW5saW5lLXdpdGgtY29udGVudFwiOiB0aGlzLmtpbmQgPT09IFwiaW5saW5lXCIgJiYgISF0aGlzLnRleHRMYWJlbFxyXG5cdFx0fTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFRyaWdnZXIgYGFyaWEtbGFiZWxgOiBgXCIke2FpVGV4dH0gJHthcmlhTGFiZWx9XCJgLCBvclxyXG5cdCAqIGBcIiR7YWlUZXh0fSAke3RleHRMYWJlbH1cImAgd2hlbiBga2luZGAgaXMgYFwiaW5saW5lXCJgIGFuZCBgdGV4dExhYmVsYCBpcyBzZXQuXHJcblx0ICovXHJcblx0Z2V0IGNvbXB1dGVkQXJpYUxhYmVsKCk6IHN0cmluZyB7XHJcblx0XHRjb25zdCBzdWZmaXggPSAodGhpcy5raW5kID09PSBcImlubGluZVwiICYmIHRoaXMudGV4dExhYmVsKSA/IHRoaXMudGV4dExhYmVsIDogdGhpcy5hcmlhTGFiZWw7XHJcblx0XHRyZXR1cm4gYCR7dGhpcy5haVRleHR9ICR7c3VmZml4fWA7XHJcblx0fVxyXG5cclxuXHRuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XHJcblx0XHRpZiAodGhpcy5pc09wZW4pIHtcclxuXHRcdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIHRoaXMuZG9jdW1lbnRDbGljayk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XHJcblx0XHRpZiAoY2hhbmdlcy5yZXZlcnRBY3RpdmUgJiYgIWNoYW5nZXMucmV2ZXJ0QWN0aXZlLmZpcnN0Q2hhbmdlICYmIGNoYW5nZXMucmV2ZXJ0QWN0aXZlLmN1cnJlbnRWYWx1ZSkge1xyXG5cdFx0XHR0aGlzLmlzT3BlbiA9IGZhbHNlO1xyXG5cdFx0XHRkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgdGhpcy5kb2N1bWVudENsaWNrKTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdG5nT25EZXN0cm95KCk6IHZvaWQge1xyXG5cdFx0ZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIHRoaXMuZG9jdW1lbnRDbGljayk7XHJcblx0fVxyXG5cclxuXHRvblRyaWdnZXJDbGljayhldmVudDogTW91c2VFdmVudCk6IHZvaWQge1xyXG5cdFx0Y29uc3Qgb3BlbmluZyA9ICF0aGlzLmlzT3BlbjtcclxuXHRcdGlmIChvcGVuaW5nKSB7XHJcblx0XHRcdGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCB0aGlzLmRvY3VtZW50Q2xpY2spO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0ZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIHRoaXMuZG9jdW1lbnRDbGljayk7XHJcblx0XHR9XHJcblx0XHR0aGlzLmFpTGFiZWxQb3BvdmVyPy5oYW5kbGVDaGFuZ2Uob3BlbmluZywgZXZlbnQpO1xyXG5cdH1cclxuXHJcblx0b25SZXZlcnRCdXR0b25DbGljayhldmVudDogTW91c2VFdmVudCk6IHZvaWQge1xyXG5cdFx0dGhpcy5yZXZlcnRDbGljay5lbWl0KGV2ZW50KTtcclxuXHR9XHJcblxyXG5cdEBIb3N0TGlzdGVuZXIoXCJrZXl1cFwiLCBbXCIkZXZlbnRcIl0pXHJcblx0aG9zdGtleXMoZXZlbnQ6IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcclxuXHRcdGlmICh0aGlzLmlzT3BlbiAmJiBldmVudC5rZXkgPT09IFwiRXNjYXBlXCIpIHtcclxuXHRcdFx0ZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XHJcblx0XHRcdGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCB0aGlzLmRvY3VtZW50Q2xpY2spO1xyXG5cdFx0XHR0aGlzLmFpTGFiZWxQb3BvdmVyPy5oYW5kbGVDaGFuZ2UoZmFsc2UsIGV2ZW50KTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIERpc21pc3NlcyB0aGUgcG9wb3ZlciB3aGVuIGEgY2xpY2sgbGFuZHMgb3V0c2lkZSB0aGUgaG9zdCBlbGVtZW50LlxyXG5cdCAqL1xyXG5cdHByaXZhdGUgaGFuZGxlT3V0c2lkZUNsaWNrKGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XHJcblx0XHRpZiAoIXRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50LmNvbnRhaW5zKGV2ZW50LnRhcmdldCBhcyBOb2RlKSkge1xyXG5cdFx0XHR0aGlzLmFpTGFiZWxQb3BvdmVyPy5oYW5kbGVDaGFuZ2UoZmFsc2UsIGV2ZW50KTtcclxuXHRcdFx0ZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIHRoaXMuZG9jdW1lbnRDbGljayk7XHJcblx0XHR9XHJcblx0fVxyXG59XHJcbiJdfQ==