UNPKG

@vendasta/store

Version:

Components and data for Store

172 lines 64 kB
import { Component, Input, ViewChild } from '@angular/core';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { TranslateService } from '@ngx-translate/core';
import { DateFilterOptions, DateRangeSelectorComponent, DateRangeSelectorService, } from '@vendasta/uikit';
import { BehaviorSubject, combineLatest, Observable, of, Subject } from 'rxjs';
import { debounceTime, switchMap, takeUntil } from 'rxjs/operators';
import { Columns } from './table.util';
import * as i0 from "@angular/core";
import * as i1 from "@vendasta/uikit";
import * as i2 from "@ngx-translate/core";
import * as i3 from "@angular/material/table";
import * as i4 from "@angular/material/sort";
import * as i5 from "@angular/material/icon";
import * as i6 from "@angular/material/divider";
import * as i7 from "@angular/material/button";
import * as i8 from "@angular/common";
import * as i9 from "@angular/router";
export class ManageProductTableComponent {
    constructor(dateRangeService, translateService) {
        this.dateRangeService = dateRangeService;
        this.translateService = translateService;
        this.dataSource = new MatTableDataSource(Array(5));
        this.totalProductCnt$ = of(0);
        this.showSellingInStoreColumn = false;
        this.applySearchFilter$$ = new BehaviorSubject('');
        this.filterApplied = false;
        this.productToolbarText$$ = new BehaviorSubject('');
        this.displayedColumns = [
            Columns.Product,
            Columns.SellingInStore,
            Columns.ActiveAccounts,
            Columns.VerticalLine,
            Columns.Activations,
            Columns.Cancellations,
            Columns.Deactivations,
            Columns.Growth,
            Columns.Actions,
        ];
        this.dateFilterValue = {
            key: '',
        };
        this.filters = [
            {
                icon: 'calendar_today',
                title: {
                    key: 'FILTERS.DATE.CHIP',
                },
                text: this.dateFilterValue,
                enabled: true,
                dialog: {
                    component: DateRangeSelectorComponent,
                },
            },
        ];
        this.config = [
            {
                canAddAndRemove: false,
            },
        ];
        this.Columns = Columns;
        this.unsubscribe$ = new Subject();
    }
    ngOnInit() {
        if (!this.showSellingInStoreColumn) {
            const idx = this.displayedColumns.findIndex((c) => c === Columns.SellingInStore);
            this.displayedColumns.splice(idx, 1);
        }
        this.dataSource.sort = this.sort;
        this.dataSource.sortingDataAccessor = this.sortingDataAccessor;
        this.dataSource.filterPredicate = (data, filter) => {
            const searchStringArr = [];
            searchStringArr.push(data.name);
            data.addons?.map((addon) => searchStringArr.push(addon.name));
            return searchStringArr.some((string) => {
                return string.toLowerCase().includes(filter);
            });
        };
        this.updateProductToolbarText();
        this.dateRangeService.setKey(DateFilterOptions.SevenDay);
        this.dateRangeService
            .getFilter()
            .pipe(takeUntil(this.unsubscribe$))
            .subscribe((filter) => {
            if (!filter) {
                return;
            }
            this.dateFilterValue.key = filter.i18nKey;
        });
        this.applySearchFilter$$.pipe(debounceTime(250)).subscribe((filterValue) => this.applySearchFilter(filterValue));
    }
    ngAfterViewInit() {
        this.dataSource.sort = this.sort;
    }
    getProductId(product) {
        if (!product) {
            return null;
        }
        return product.addonId || product.appId;
    }
    get productToolbarText$() {
        return combineLatest([this.productToolbarText$$.asObservable(), this.totalProductCnt$]).pipe(switchMap(([prodText, prodCnt]) => {
            const numShowing = this.filterApplied ? prodText : prodCnt;
            return this.translateService.get('FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.TOOLBAR_TEXT', {
                numShowing: numShowing,
                numTotal: prodCnt,
            });
        }));
    }
    handleSearchFilter(filterValue) {
        this.applySearchFilter$$.next(filterValue);
    }
    applySearchFilter(filterValue) {
        this.filterApplied = !!filterValue;
        // To optimize rendering, hide the addons before the filter is removed,
        // and show the addons after the filter is applied.
        if (!this.filterApplied) {
            this.dataSource.data.forEach((d) => (d.expanded = false));
        }
        this.dataSource.filter = filterValue?.trim().toLowerCase();
        if (this.filterApplied) {
            this.dataSource.data.forEach((d) => (d.expanded = true));
        }
        this.updateProductToolbarText();
    }
    updateProductToolbarText() {
        this.productToolbarText$$.next(`${this.dataSource.filteredData.length}`);
    }
    sortingDataAccessor(data, sortHeaderId) {
        switch (sortHeaderId) {
            case Columns.Product:
                return data.name;
            case Columns.Activations:
                return data.change ? data.change.activations : 0;
            case Columns.Deactivations:
                return data.change ? data.change.deactivations : 0;
            case Columns.Growth:
                return data.growth;
            case Columns.ActiveAccounts:
                return data.stats ? (data.stats.activations || 0) - (data.stats.deactivations || 0) : 0;
            case Columns.Cancellations:
                return data.change ? data.change.cancellations : 0;
            default:
                return data[sortHeaderId];
        }
    }
    ngOnDestroy() {
        this.unsubscribe$.next();
        this.unsubscribe$.complete();
    }
    trackByFn(_, item) {
        return item?.addonId || item?.appId;
    }
}
ManageProductTableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: ManageProductTableComponent, deps: [{ token: i1.DateRangeSelectorService }, { token: i2.TranslateService }], target: i0.ɵɵFactoryTarget.Component });
ManageProductTableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.0.2", type: ManageProductTableComponent, selector: "app-manage-product-table", inputs: { appIdToNameMap$: "appIdToNameMap$", dataSource: "dataSource", totalProductCnt$: "totalProductCnt$", showSellingInStoreColumn: "showSellingInStoreColumn" }, viewQueries: [{ propertyName: "sort", first: true, predicate: ["manageProductSort"], descendants: true }], ngImport: i0, template: "<va-filter-container\n  [toolbarText]=\"productToolbarText$ | async\"\n  [searchable]=\"true\"\n  (searchTermChanged)=\"handleSearchFilter($event)\"\n>\n  <p class=\"growth-header\" header>\n    {{\n      'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.SHOW_GROWTH_OVER'\n        | translate\n    }}\n  </p>\n  <span header>\n    <div class=\"filter-container\">\n      <va-filter-chip-container\n        [filters]=\"filters\"\n        [config]=\"config\"\n      ></va-filter-chip-container>\n    </div>\n  </span>\n</va-filter-container>\n<ng-container\n  *ngTemplateOutlet=\"\n    productTable;\n    context: { dataSource: dataSource, showHeaders: true }\n  \"\n></ng-container>\n<ng-template\n  #productTable\n  let-dataSource=\"dataSource\"\n  let-showHeaders=\"showHeaders\"\n>\n  <mat-table\n    class=\"product-table\"\n    content\n    matSort\n    [dataSource]=\"dataSource\"\n    multiTemplateDataRows\n    #manageProductSort=\"matSort\"\n    [matSortActive]=\"Columns.ActiveAccounts\"\n    matSortStart=\"desc\"\n    matSortDirection=\"desc\"\n    [trackBy]=\"trackByFn\"\n    matSortDisableClear\n  >\n    <!-- Product Column -->\n    <ng-container [matColumnDef]=\"Columns.Product\">\n      <mat-header-cell class=\"product-column\" *matHeaderCellDef mat-sort-header>\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.PRODUCT'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell class=\"product-column\" *matCellDef=\"let element\">\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <div class=\"product-cell\" [class.indented-column]=\"!showHeaders\">\n            <div class=\"icon-container\">\n              <a [routerLink]=\"getProductId(element)\">\n                <va-icon\n                  [diameter]=\"40\"\n                  [name]=\"element?.name\"\n                  [iconUrl]=\"element?.icon\"\n                ></va-icon>\n              </a>\n            </div>\n            <div class=\"product-info-container\">\n              <a [routerLink]=\"getProductId(element)\">{{ element.name }}</a>\n              <p class=\"product-requirements-text\" *ngIf=\"element.addonId\">\n                {{\n                  'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.PARENT_REQUIREMENT'\n                    | translate\n                      : {\n                          name: ((appIdToNameMap$ | async) || {})[element.appId]\n                        }\n                }}\n              </p>\n              <p class=\"product-tagline-text\" *ngIf=\"element.tagline\">\n                {{ element.tagline }}\n              </p>\n            </div>\n          </div>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Selling in store Column -->\n    <ng-container [matColumnDef]=\"Columns.SellingInStore\">\n      <mat-header-cell class=\"center-align small-column\" *matHeaderCellDef>\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.SELLING_IN_STORE'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell\n        class=\"stat-cell center-align small-column\"\n        *matCellDef=\"let element\"\n      >\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <span *ngIf=\"element.sellingInStore\"><mat-icon>check</mat-icon></span>\n          <span *ngIf=\"!element.sellingInStore\">&mdash;</span>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Active Accounts -->\n    <ng-container [matColumnDef]=\"Columns.ActiveAccounts\">\n      <mat-header-cell\n        class=\"right-align currently-active-column\"\n        *matHeaderCellDef\n        mat-sort-header\n        arrowPosition=\"before\"\n      >\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.ACTIVE_ACCOUNTS'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell\n        class=\"stat-cell right-align currently-active-column\"\n        *matCellDef=\"let element\"\n      >\n        <div style=\"display: flex; flex-direction: column\">\n          <ng-container *ngIf=\"element; else loadingCell\">\n            <div>\n              {{ element.stats?.activations - element.stats?.deactivations }}\n            </div>\n          </ng-container>\n        </div>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Vertical Line -->\n    <ng-container [matColumnDef]=\"Columns.VerticalLine\">\n      <mat-header-cell class=\"line-column\" *matHeaderCellDef>\n        <mat-divider [vertical]=\"true\" class=\"divider\"></mat-divider>\n      </mat-header-cell>\n      <mat-cell class=\"line-column\" *matCellDef>\n        <mat-divider [vertical]=\"true\" class=\"divider\"></mat-divider>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Activations Column -->\n    <ng-container [matColumnDef]=\"Columns.Activations\">\n      <mat-header-cell\n        class=\"right-align\"\n        *matHeaderCellDef\n        mat-sort-header\n        arrowPosition=\"before\"\n      >\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.ACTIVATIONS'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell class=\"stat-cell right-align pos\" *matCellDef=\"let element\">\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <span [ngClass]=\"element.change?.activations > 0 ? 'pos' : 'zero'\">\n            {{ element.change?.activations > 0 ? '+' : ''\n            }}{{ element.change?.activations }}\n          </span>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Pending Cancellations Column -->\n    <ng-container [matColumnDef]=\"Columns.Cancellations\">\n      <mat-header-cell\n        class=\"right-align\"\n        *matHeaderCellDef\n        mat-sort-header\n        arrowPosition=\"before\"\n      >\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.PENDING_DEACTIVATIONS'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell class=\"stat-cell right-align\" *matCellDef=\"let element\">\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <span class=\"zero\">\n            {{ element.change?.cancellations }}\n          </span>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Deactivations Column -->\n    <ng-container [matColumnDef]=\"Columns.Deactivations\">\n      <mat-header-cell\n        class=\"right-align\"\n        *matHeaderCellDef\n        mat-sort-header\n        arrowPosition=\"before\"\n      >\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.DEACTIVATIONS'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell class=\"stat-cell right-align\" *matCellDef=\"let element\">\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <span [ngClass]=\"element.change?.deactivations > 0 ? 'neg' : 'zero'\">\n            {{ element.change?.deactivations > 0 ? '-' : ''\n            }}{{ element.change?.deactivations }}\n          </span>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Growth Column -->\n    <ng-container [matColumnDef]=\"Columns.Growth\">\n      <mat-header-cell\n        class=\"right-align\"\n        *matHeaderCellDef\n        mat-sort-header\n        arrowPosition=\"before\"\n      >\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.GROWTH'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell\n        class=\"stat-cell right-align growth-cells\"\n        *matCellDef=\"let element\"\n      >\n        <ng-container\n          *ngIf=\"element && element.change && element.stats; else loadingCell\"\n        >\n          <span\n            [ngClass]=\"\n              element.growth > 0 ? 'pos' : element.growth < 0 ? 'neg' : 'zero'\n            \"\n          >\n            {{ element.growth > 0 ? '+' : '' }}{{ element.growth }}%\n          </span>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Actions Column -->\n    <ng-container [matColumnDef]=\"Columns.Actions\">\n      <mat-header-cell\n        class=\"right-align marketplace-button\"\n        *matHeaderCellDef\n      ></mat-header-cell>\n      <mat-cell\n        class=\"stat-cell right-align marketplace-button\"\n        *matCellDef=\"let element\"\n      >\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <button mat-flat-button *ngIf=\"element.addons?.length > 0\">\n            <mat-icon *ngIf=\"!element.expanded; else showLess\">\n              expand_more\n            </mat-icon>\n            <ng-template #showLess>\n              <mat-icon>expand_less</mat-icon>\n            </ng-template>\n          </button>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Expandable Addons Column -->\n    <ng-container matColumnDef=\"expandedDetail\">\n      <mat-cell\n        class=\"addons-cell\"\n        *matCellDef=\"let element\"\n        [attr.colspan]=\"displayedColumns.length\"\n      >\n        <div\n          *ngIf=\"element?.addons?.length > 0 && element?.expanded\"\n          class=\"expandable-col\"\n        >\n          <ng-template\n            *ngTemplateOutlet=\"\n              productTable;\n              context: { dataSource: element.addons, showHeaders: false }\n            \"\n          ></ng-template>\n        </div>\n      </mat-cell>\n    </ng-container>\n\n    <ng-container *ngIf=\"showHeaders\">\n      <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n    </ng-container>\n    <mat-row\n      class=\"product-row\"\n      *matRowDef=\"let row; columns: displayedColumns\"\n      [class.expandable]=\"row?.addons?.length > 0\"\n      (click)=\"row.expanded = !row.expanded\"\n    ></mat-row>\n    <mat-row\n      class=\"addons-row\"\n      *matRowDef=\"let element; columns: ['expandedDetail']\"\n    ></mat-row>\n  </mat-table>\n</ng-template>\n<ng-template #loadingCell>\n  <td class=\"stencil-container\">\n    <div class=\"stencil stencil-shimmer\"></div>\n  </td>\n</ng-template>\n", styles: [".product-table{width:100%}.product-table .mat-header-row{border-top-width:1px;border-top-color:#e0e0e0}.growth-header{margin-right:8px;font-style:italic}.icon-container{padding-right:16px}@media screen and (max-width: 769px){.icon-container{display:none}}.product-requirements-text{color:#616161;font-style:italic}.product-tagline-text{color:#616161}.mat-header-cell{height:50px;border-bottom:none}p{margin:4px 0}.stencil-container{width:100%}.stencil-container .stencil{height:18px}.product-info-container{display:flex;flex-direction:column;justify-content:center}.product-row{align-items:stretch}.addons-row{min-height:0;border:none}.addons-row .addons-table{width:100%}.addons-cell{padding:0}.product-column{padding-left:24px;flex-grow:4;min-width:125px}.product-cell{display:flex;flex-flow:row;align-items:center}.stat-cell{font-size:16px}.growth-cells{font-weight:500}.marketplace-button{max-width:85px;padding-right:24px;color:#1976d2}.product-column,.stat-cell,.growth-cells{padding-top:8px;padding-bottom:8px}.indented-column{padding-left:56px}.sub-table-cell{padding:0!important}.center-align{display:flex;justify-content:center;flex:1.4 0 0;min-width:90px}.center-align .stencil{margin-left:32px}.right-align{display:flex;justify-content:flex-end;flex:1.4 0 0;min-width:90px}.right-align .stencil{margin-left:32px}.small-column{flex-grow:0}.divider{height:100%}.currently-active-column{min-width:110px}.line-column{display:flex;justify-content:flex-end;padding:0;max-width:40px}.timeframe{font-size:12px;min-width:32px;display:flex;justify-content:flex-end;align-items:center}.timeframe .stencil{margin:0}.timeframe mat-icon{font-size:14px;width:10px;height:14px;margin-left:-4px}.timeframe span{display:flex;flex-direction:row;align-items:center}.pos{color:#388e3c}.neg{color:#d32f2f}.zero{color:#9e9e9e;font-weight:400}.sub-table-cell mat-row:last-of-type{border:none!important}.expandable{cursor:pointer}.expandable:hover{background-color:#fafafa;background-color:var(--primary-background-color, #fafafa)}.expandable-col{display:flex;width:100%;overflow:hidden}\n"], components: [{ type: i1.FilterContainerComponent, selector: "va-filter-container", inputs: ["showFilterSharing", "searchable", "toolbarText", "showToolbar", "searchDisabled", "filtersDisabled", "filterIsOpen", "filters", "savedFilters", "theme", "useCustomCase", "enabledSaveSearchTerm", "contextKey"], outputs: ["searchTermChanged", "fieldValueChanged", "savedFilterSelected", "removeSavedFilter", "saveCurrentFilter", "exportFilterDialog", "importFilterDialog"] }, { type: i1.VaFilterChipContainerComponent, selector: "va-filter-chip-container", inputs: ["filters", "config"], outputs: ["onFilterClick", "onFilterDisable", "onFilterDataChange"] }, { type: i3.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { type: i4.MatSortHeader, selector: "[mat-sort-header]", inputs: ["disabled", "mat-sort-header", "arrowPosition", "start", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { type: i1.IconComponent, selector: "va-icon", inputs: ["iconUrl", "name", "diameter", "backgroundColor", "borderColor", "fontColor"] }, { type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i6.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { type: i7.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button],             button[mat-fab], button[mat-mini-fab], button[mat-stroked-button],             button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i3.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { type: i3.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }], directives: [{ type: i8.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i4.MatSort, selector: "[matSort]", inputs: ["matSortDisabled", "matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { type: i3.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { type: i3.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { type: i3.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { type: i3.MatCellDef, selector: "[matCellDef]" }, { type: i3.MatCell, selector: "mat-cell, td[mat-cell]" }, { type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i9.RouterLinkWithHref, selector: "a[routerLink],area[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "preserveFragment", "skipLocationChange", "replaceUrl", "state", "relativeTo", "routerLink"] }, { type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i3.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { type: i3.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }], pipes: { "async": i8.AsyncPipe, "translate": i2.TranslatePipe } });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.0.2", ngImport: i0, type: ManageProductTableComponent, decorators: [{
            type: Component,
            args: [{ selector: 'app-manage-product-table', template: "<va-filter-container\n  [toolbarText]=\"productToolbarText$ | async\"\n  [searchable]=\"true\"\n  (searchTermChanged)=\"handleSearchFilter($event)\"\n>\n  <p class=\"growth-header\" header>\n    {{\n      'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.SHOW_GROWTH_OVER'\n        | translate\n    }}\n  </p>\n  <span header>\n    <div class=\"filter-container\">\n      <va-filter-chip-container\n        [filters]=\"filters\"\n        [config]=\"config\"\n      ></va-filter-chip-container>\n    </div>\n  </span>\n</va-filter-container>\n<ng-container\n  *ngTemplateOutlet=\"\n    productTable;\n    context: { dataSource: dataSource, showHeaders: true }\n  \"\n></ng-container>\n<ng-template\n  #productTable\n  let-dataSource=\"dataSource\"\n  let-showHeaders=\"showHeaders\"\n>\n  <mat-table\n    class=\"product-table\"\n    content\n    matSort\n    [dataSource]=\"dataSource\"\n    multiTemplateDataRows\n    #manageProductSort=\"matSort\"\n    [matSortActive]=\"Columns.ActiveAccounts\"\n    matSortStart=\"desc\"\n    matSortDirection=\"desc\"\n    [trackBy]=\"trackByFn\"\n    matSortDisableClear\n  >\n    <!-- Product Column -->\n    <ng-container [matColumnDef]=\"Columns.Product\">\n      <mat-header-cell class=\"product-column\" *matHeaderCellDef mat-sort-header>\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.PRODUCT'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell class=\"product-column\" *matCellDef=\"let element\">\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <div class=\"product-cell\" [class.indented-column]=\"!showHeaders\">\n            <div class=\"icon-container\">\n              <a [routerLink]=\"getProductId(element)\">\n                <va-icon\n                  [diameter]=\"40\"\n                  [name]=\"element?.name\"\n                  [iconUrl]=\"element?.icon\"\n                ></va-icon>\n              </a>\n            </div>\n            <div class=\"product-info-container\">\n              <a [routerLink]=\"getProductId(element)\">{{ element.name }}</a>\n              <p class=\"product-requirements-text\" *ngIf=\"element.addonId\">\n                {{\n                  'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.PARENT_REQUIREMENT'\n                    | translate\n                      : {\n                          name: ((appIdToNameMap$ | async) || {})[element.appId]\n                        }\n                }}\n              </p>\n              <p class=\"product-tagline-text\" *ngIf=\"element.tagline\">\n                {{ element.tagline }}\n              </p>\n            </div>\n          </div>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Selling in store Column -->\n    <ng-container [matColumnDef]=\"Columns.SellingInStore\">\n      <mat-header-cell class=\"center-align small-column\" *matHeaderCellDef>\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.SELLING_IN_STORE'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell\n        class=\"stat-cell center-align small-column\"\n        *matCellDef=\"let element\"\n      >\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <span *ngIf=\"element.sellingInStore\"><mat-icon>check</mat-icon></span>\n          <span *ngIf=\"!element.sellingInStore\">&mdash;</span>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Active Accounts -->\n    <ng-container [matColumnDef]=\"Columns.ActiveAccounts\">\n      <mat-header-cell\n        class=\"right-align currently-active-column\"\n        *matHeaderCellDef\n        mat-sort-header\n        arrowPosition=\"before\"\n      >\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.ACTIVE_ACCOUNTS'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell\n        class=\"stat-cell right-align currently-active-column\"\n        *matCellDef=\"let element\"\n      >\n        <div style=\"display: flex; flex-direction: column\">\n          <ng-container *ngIf=\"element; else loadingCell\">\n            <div>\n              {{ element.stats?.activations - element.stats?.deactivations }}\n            </div>\n          </ng-container>\n        </div>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Vertical Line -->\n    <ng-container [matColumnDef]=\"Columns.VerticalLine\">\n      <mat-header-cell class=\"line-column\" *matHeaderCellDef>\n        <mat-divider [vertical]=\"true\" class=\"divider\"></mat-divider>\n      </mat-header-cell>\n      <mat-cell class=\"line-column\" *matCellDef>\n        <mat-divider [vertical]=\"true\" class=\"divider\"></mat-divider>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Activations Column -->\n    <ng-container [matColumnDef]=\"Columns.Activations\">\n      <mat-header-cell\n        class=\"right-align\"\n        *matHeaderCellDef\n        mat-sort-header\n        arrowPosition=\"before\"\n      >\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.ACTIVATIONS'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell class=\"stat-cell right-align pos\" *matCellDef=\"let element\">\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <span [ngClass]=\"element.change?.activations > 0 ? 'pos' : 'zero'\">\n            {{ element.change?.activations > 0 ? '+' : ''\n            }}{{ element.change?.activations }}\n          </span>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Pending Cancellations Column -->\n    <ng-container [matColumnDef]=\"Columns.Cancellations\">\n      <mat-header-cell\n        class=\"right-align\"\n        *matHeaderCellDef\n        mat-sort-header\n        arrowPosition=\"before\"\n      >\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.PENDING_DEACTIVATIONS'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell class=\"stat-cell right-align\" *matCellDef=\"let element\">\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <span class=\"zero\">\n            {{ element.change?.cancellations }}\n          </span>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Deactivations Column -->\n    <ng-container [matColumnDef]=\"Columns.Deactivations\">\n      <mat-header-cell\n        class=\"right-align\"\n        *matHeaderCellDef\n        mat-sort-header\n        arrowPosition=\"before\"\n      >\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.DEACTIVATIONS'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell class=\"stat-cell right-align\" *matCellDef=\"let element\">\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <span [ngClass]=\"element.change?.deactivations > 0 ? 'neg' : 'zero'\">\n            {{ element.change?.deactivations > 0 ? '-' : ''\n            }}{{ element.change?.deactivations }}\n          </span>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Growth Column -->\n    <ng-container [matColumnDef]=\"Columns.Growth\">\n      <mat-header-cell\n        class=\"right-align\"\n        *matHeaderCellDef\n        mat-sort-header\n        arrowPosition=\"before\"\n      >\n        {{\n          'FRONTEND.STORE.MANAGE_PRODUCT.MANAGE_PRODUCT_TABLE.COLUMNS.GROWTH'\n            | translate\n        }}\n      </mat-header-cell>\n      <mat-cell\n        class=\"stat-cell right-align growth-cells\"\n        *matCellDef=\"let element\"\n      >\n        <ng-container\n          *ngIf=\"element && element.change && element.stats; else loadingCell\"\n        >\n          <span\n            [ngClass]=\"\n              element.growth > 0 ? 'pos' : element.growth < 0 ? 'neg' : 'zero'\n            \"\n          >\n            {{ element.growth > 0 ? '+' : '' }}{{ element.growth }}%\n          </span>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Actions Column -->\n    <ng-container [matColumnDef]=\"Columns.Actions\">\n      <mat-header-cell\n        class=\"right-align marketplace-button\"\n        *matHeaderCellDef\n      ></mat-header-cell>\n      <mat-cell\n        class=\"stat-cell right-align marketplace-button\"\n        *matCellDef=\"let element\"\n      >\n        <ng-container *ngIf=\"element; else loadingCell\">\n          <button mat-flat-button *ngIf=\"element.addons?.length > 0\">\n            <mat-icon *ngIf=\"!element.expanded; else showLess\">\n              expand_more\n            </mat-icon>\n            <ng-template #showLess>\n              <mat-icon>expand_less</mat-icon>\n            </ng-template>\n          </button>\n        </ng-container>\n      </mat-cell>\n    </ng-container>\n\n    <!-- Expandable Addons Column -->\n    <ng-container matColumnDef=\"expandedDetail\">\n      <mat-cell\n        class=\"addons-cell\"\n        *matCellDef=\"let element\"\n        [attr.colspan]=\"displayedColumns.length\"\n      >\n        <div\n          *ngIf=\"element?.addons?.length > 0 && element?.expanded\"\n          class=\"expandable-col\"\n        >\n          <ng-template\n            *ngTemplateOutlet=\"\n              productTable;\n              context: { dataSource: element.addons, showHeaders: false }\n            \"\n          ></ng-template>\n        </div>\n      </mat-cell>\n    </ng-container>\n\n    <ng-container *ngIf=\"showHeaders\">\n      <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n    </ng-container>\n    <mat-row\n      class=\"product-row\"\n      *matRowDef=\"let row; columns: displayedColumns\"\n      [class.expandable]=\"row?.addons?.length > 0\"\n      (click)=\"row.expanded = !row.expanded\"\n    ></mat-row>\n    <mat-row\n      class=\"addons-row\"\n      *matRowDef=\"let element; columns: ['expandedDetail']\"\n    ></mat-row>\n  </mat-table>\n</ng-template>\n<ng-template #loadingCell>\n  <td class=\"stencil-container\">\n    <div class=\"stencil stencil-shimmer\"></div>\n  </td>\n</ng-template>\n", styles: [".product-table{width:100%}.product-table .mat-header-row{border-top-width:1px;border-top-color:#e0e0e0}.growth-header{margin-right:8px;font-style:italic}.icon-container{padding-right:16px}@media screen and (max-width: 769px){.icon-container{display:none}}.product-requirements-text{color:#616161;font-style:italic}.product-tagline-text{color:#616161}.mat-header-cell{height:50px;border-bottom:none}p{margin:4px 0}.stencil-container{width:100%}.stencil-container .stencil{height:18px}.product-info-container{display:flex;flex-direction:column;justify-content:center}.product-row{align-items:stretch}.addons-row{min-height:0;border:none}.addons-row .addons-table{width:100%}.addons-cell{padding:0}.product-column{padding-left:24px;flex-grow:4;min-width:125px}.product-cell{display:flex;flex-flow:row;align-items:center}.stat-cell{font-size:16px}.growth-cells{font-weight:500}.marketplace-button{max-width:85px;padding-right:24px;color:#1976d2}.product-column,.stat-cell,.growth-cells{padding-top:8px;padding-bottom:8px}.indented-column{padding-left:56px}.sub-table-cell{padding:0!important}.center-align{display:flex;justify-content:center;flex:1.4 0 0;min-width:90px}.center-align .stencil{margin-left:32px}.right-align{display:flex;justify-content:flex-end;flex:1.4 0 0;min-width:90px}.right-align .stencil{margin-left:32px}.small-column{flex-grow:0}.divider{height:100%}.currently-active-column{min-width:110px}.line-column{display:flex;justify-content:flex-end;padding:0;max-width:40px}.timeframe{font-size:12px;min-width:32px;display:flex;justify-content:flex-end;align-items:center}.timeframe .stencil{margin:0}.timeframe mat-icon{font-size:14px;width:10px;height:14px;margin-left:-4px}.timeframe span{display:flex;flex-direction:row;align-items:center}.pos{color:#388e3c}.neg{color:#d32f2f}.zero{color:#9e9e9e;font-weight:400}.sub-table-cell mat-row:last-of-type{border:none!important}.expandable{cursor:pointer}.expandable:hover{background-color:#fafafa;background-color:var(--primary-background-color, #fafafa)}.expandable-col{display:flex;width:100%;overflow:hidden}\n"] }]
        }], ctorParameters: function () { return [{ type: i1.DateRangeSelectorService }, { type: i2.TranslateService }]; }, propDecorators: { appIdToNameMap$: [{
                type: Input
            }], dataSource: [{
                type: Input
            }], totalProductCnt$: [{
                type: Input
            }], showSellingInStoreColumn: [{
                type: Input
            }], sort: [{
                type: ViewChild,
                args: ['manageProductSort', { static: false }]
            }] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFuYWdlLXByb2R1Y3QtdGFibGUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9zdG9yZS9zcmMvbGliL21hbmFnZS1wcm9kdWN0L21hbmFnZS1wcm9kdWN0LXRhYmxlL21hbmFnZS1wcm9kdWN0LXRhYmxlLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvc3RvcmUvc3JjL2xpYi9tYW5hZ2UtcHJvZHVjdC9tYW5hZ2UtcHJvZHVjdC10YWJsZS9tYW5hZ2UtcHJvZHVjdC10YWJsZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQWlCLFNBQVMsRUFBRSxLQUFLLEVBQXFCLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUM5RixPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDakQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkQsT0FBTyxFQUNMLGlCQUFpQixFQUNqQiwwQkFBMEIsRUFDMUIsd0JBQXdCLEdBRXpCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLGVBQWUsRUFBRSxhQUFhLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0UsT0FBTyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFHcEUsT0FBTyxFQUFFLE9BQU8sRUFBbUIsTUFBTSxjQUFjLENBQUM7Ozs7Ozs7Ozs7O0FBT3hELE1BQU0sT0FBTywyQkFBMkI7SUFpRHRDLFlBQW9CLGdCQUEwQyxFQUFVLGdCQUFrQztRQUF0RixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQTBCO1FBQVUscUJBQWdCLEdBQWhC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LDBCQUEwQjs4SUFLM0IsZUFBZTtzQkFBdkIsS0FBSztnQkFDRyxVQUFVO3NCQUFsQixLQUFLO2dCQUNHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFDRyx3QkFBd0I7c0JBQWhDLEtBQUs7Z0JBRTZDLElBQUk7c0JBQXRELFNBQVM7dUJBQUMsbUJBQW1CLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQWZ0ZXJWaWV3SW5pdCwgQ29tcG9uZW50LCBJbnB1dCwgT25EZXN0cm95LCBPbkluaXQsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTWF0U29ydCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3NvcnQnO1xuaW1wb3J0IHsgTWF0VGFibGVEYXRhU291cmNlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdGFibGUnO1xuaW1wb3J0IHsgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuaW1wb3J0IHtcbiAgRGF0ZUZpbHRlck9wdGlvbnMsXG4gIERhdGVSYW5nZVNlbGVjdG9yQ29tcG9uZW50LFxuICBEYXRlUmFuZ2VTZWxlY3RvclNlcnZpY2UsXG4gIEkxOE5EZXNjcmlwdG9yLFxufSBmcm9tICdAdmVuZGFzdGEvdWlraXQnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0LCBPYnNlcnZhYmxlLCBvZiwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZGVib3VuY2VUaW1lLCBzd2l0Y2hNYXAsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IFJlc2VsbGVySXRlbSB9IGZyb20gJy4uLy4uJztcbmltcG9ydCB7IFByb2R1Y3RJbmZvcm1hdGlvbiB9IGZyb20gJy4vcHJvZHVjdC1pbmZvcm1hdGlvbic7XG5pbXBvcnQgeyBDb2x1bW5zLCBSZXNlbGxlckl0ZW1NYXAgfSBmcm9tICcuL3RhYmxlLnV0aWwnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhcHAtbWFuYWdlLXByb2R1Y3QtdGFibGUnLFxuICB0ZW1wbGF0ZVVybDogJy4vbWFuYWdlLXByb2R1Y3QtdGFibGUuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9tYW5hZ2UtcHJvZHVjdC10YWJsZS5jb21wb25lbnQuc2NzcyddLFxufSlcbmV4cG9ydCBjbGFzcyBNYW5hZ2VQcm9kdWN0VGFibGVDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XG4gIEBJbnB1dCgpIGFwcElkVG9OYW1lTWFwJDogT2JzZXJ2YWJsZTxSZXNlbGxlckl0ZW1NYXA+O1xuICBASW5wdXQoKSBkYXRhU291cmNlID0gbmV3IE1hdFRhYmxlRGF0YVNvdXJjZTxQcm9kdWN0SW5mb3JtYXRpb24+KEFycmF5KDUpKTtcbiAgQElucHV0KCkgdG90YWxQcm9kdWN0Q250JCA9IG9mKDApO1xuICBASW5wdXQoKSBzaG93U2VsbGluZ0luU3RvcmVDb2x1bW4gPSBmYWxzZTtcblxuICBAVmlld0NoaWxkKCdtYW5hZ2VQcm9kdWN0U29ydCcsIHsgc3RhdGljOiBmYWxzZSB9KSBzb3J0OiBNYXRTb3J0O1xuXG4gIHByaXZhdGUgYXBwbHlTZWFyY2hGaWx0ZXIkJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPignJyk7XG4gIGZpbHRlckFwcGxpZWQgPSBmYWxzZTtcbiAgcHJpdmF0ZSBwcm9kdWN0VG9vbGJhclRleHQkJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPignJyk7XG5cbiAgZGlzcGxheWVkQ29sdW1uczogc3RyaW5nW10gPSBbXG4gICAgQ29sdW1ucy5Qcm9kdWN0LFxuICAgIENvbHVtbnMuU2VsbGluZ0luU3RvcmUsXG4gICAgQ29sdW1ucy5BY3RpdmVBY2NvdW50cyxcbiAgICBDb2x1bW5zLlZlcnRpY2FsTGluZSxcbiAgICBDb2x1bW5zLkFjdGl2YXRpb25zLFxuICAgIENvbHVtbnMuQ2FuY2VsbGF0aW9ucyxcbiAgICBDb2x1bW5zLkRlYWN0aXZhdGlvbnMsXG4gICAgQ29sdW1ucy5Hcm93dGgsXG4gICAgQ29sdW1ucy5BY3Rpb25zLFxuICBdO1xuICBkYXRlRmlsdGVyVmFsdWU6IEkxOE5EZXNjcmlwdG9yID0ge1xuICAgIGtleTogJycsXG4gIH07XG4gIGZpbHRlcnMgPSBbXG4gICAge1xuICAgICAgaWNvbjogJ2NhbGVuZGFyX3RvZGF5JyxcbiAgICAgIHRpdGxlOiB7XG4gICAgICAgIGtleTogJ0ZJTFRFUlMuREFURS5DSElQJyxcbiAgICAgIH0sXG4gICAgICB0ZXh0OiB0aGlzLmRhdGVGaWx0ZXJWYWx1ZSxcbiAgICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgICBkaWFsb2c6IHtcbiAgICAgICAgY29tcG9uZW50OiBEYXRlUmFuZ2VTZWxlY3RvckNvbXBvbmVudCxcbiAgICAgIH0sXG4gICAgfSxcbiAgXTtcbiAgY29uZmlnID0gW1xuICAgIHtcbiAgICAgIGNhbkFkZEFuZFJlbW92ZTogZmFsc2UsXG4gICAgfSxcbiAgXTtcblxuICBDb2x1bW5zID0gQ29sdW1ucztcblxuICBwcml2YXRlIHVuc3Vic2NyaWJlJCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBkYXRlUmFuZ2VTZXJ2aWNlOiBEYXRlUmFuZ2VTZWxlY3RvclNlcnZpY2UsIHByaXZhdGUgdHJhbnNsYXRlU2VydmljZTogVHJhbnNsYXRlU2VydmljZSkge31cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuc2hvd1NlbGxpbmdJblN0b3JlQ29sdW1uKSB7XG4gICAgICBjb25zdCBpZHggPSB0aGlzLmRpc3BsYXllZENvbHVtbnMuZmluZEluZGV4KChjKSA9PiBjID09PSBDb2x1bW5zLlNlbGxpbmdJblN0b3JlKTtcbiAgICAgIHRoaXMuZGlzcGxheWVkQ29sdW1ucy5zcGxpY2UoaWR4LCAxKTtcbiAgICB9XG4gICAgdGhpcy5kYXRhU291cmNlLnNvcnQgPSB0aGlzLnNvcnQ7XG4gICAgdGhpcy5kYXRhU291cmNlLnNvcnRpbmdEYXRhQWNjZXNzb3IgPSB0aGlzLnNvcnRpbmdEYXRhQWNjZXNzb3I7XG4gICAgdGhpcy5kYXRhU291cmNlLmZpbHRlclByZWRpY2F0ZSA9IChkYXRhOiBQcm9kdWN0SW5mb3JtYXRpb24sIGZpbHRlcjogc3RyaW5nKSA9PiB7XG4gICAgICBjb25zdCBzZWFyY2hTdHJpbmdBcnIgPSBbXTtcbiAgICAgIHNlYXJjaFN0cmluZ0Fyci5wdXNoKGRhdGEubmFtZSk7XG4gICAgICBkYXRhLmFkZG9ucz8ubWFwKChhZGRvbikgPT4gc2VhcmNoU3RyaW5nQXJyLnB1c2goYWRkb24ubmFtZSkpO1xuICAgICAgcmV0dXJuIHNlYXJjaFN0cmluZ0Fyci5zb21lKChzdHJpbmcpID0+IHtcbiAgICAgICAgcmV0dXJuIHN0cmluZy50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKGZpbHRlcik7XG4gICAgICB9KTtcbiAgICB9O1xuICAgIHRoaXMudXBkYXRlUHJvZHVjdFRvb2xiYXJUZXh0KCk7XG4gICAgdGhpcy5kYXRlUmFuZ2VTZXJ2aWNlLnNldEtleShEYXRlRmlsdGVyT3B0aW9ucy5TZXZlbkRheSk7XG4gICAgdGhpcy5kYXRlUmFuZ2VTZXJ2aWNlXG4gICAgICAuZ2V0RmlsdGVyKClcbiAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLnVuc3Vic2NyaWJlJCkpXG4gICAgICAuc3Vic2NyaWJlKChmaWx0ZXIpID0+IHtcbiAgICAgICAgaWYgKCFmaWx0ZXIpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5kYXRlRmlsdGVyVmFsdWUua2V5ID0gZmlsdGVyLmkxOG5LZXk7XG4gICAgICB9KTtcbiAgICB0aGlzLmFwcGx5U2VhcmNoRmlsdGVyJCQucGlwZShkZWJvdW5jZVRpbWUoMjUwKSkuc3Vic2NyaWJlKChmaWx0ZXJWYWx1ZSkgPT4gdGhpcy5hcHBseVNlYXJjaEZpbHRlcihmaWx0ZXJWYWx1ZSkpO1xuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgIHRoaXMuZGF0YVNvdXJjZS5zb3J0ID0gdGhpcy5zb3J0O1xuICB9XG5cbiAgZ2V0UHJvZHVjdElkKHByb2R1Y3Q6IFJlc2VsbGVySXRlbSk6IHN0cmluZyB8IG51bGwge1xuICAgIGlmICghcHJvZHVjdCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHJldHVybiBwcm9kdWN0LmFkZG9uSWQgfHwgcHJvZHVjdC5hcHBJZDtcbiAgfVxuXG4gIGdldCBwcm9kdWN0VG9vbGJhclRleHQkKCk6IE9ic2VydmFibGU8c3RyaW5nPiB7XG4gICAgcmV0dXJuIGNvbWJpbmVMYXRlc3QoW3RoaXMucHJvZHVjdFRvb2xiYXJUZXh0JCQuYXNPYnNlcnZhYmxlKCksIHRoaXMudG90YWxQcm9kdWN0Q250JF0pLnBpcGUoXG4gICAgICBzd2l0Y2hNYXAoKFtwcm9kVGV4dCwgcHJvZENudF0pID0+IHtcbiAgICAgICAgY29uc3QgbnVtU2hvd2luZyA9IHRoaXMuZmlsdGVyQXBwbGllZCA/IHByb2RUZXh0IDogcHJvZENudDtcbiAgICAgICAgcmV0dXJuIHRoaXMudHJhbnNsYXRlU2VydmljZS5nZXQoJ0ZST05URU5ELlNUT1JFLk1BTkFHRV9QUk9EVUNULk1BTkFHRV9QUk9EVUNUX1RBQkxFLlRPT0xCQVJfVEVYVCcsIHtcbiAgICAgICAgICBudW1TaG93aW5nOiBudW1TaG93aW5nLFxuICAgICAgICAgIG51bVRvdGFsOiBwcm9kQ250LFxuICAgICAgICB9KTtcbiAgICAgIH0pLFxuICAgICk7XG4gIH1cblxuICBoYW5kbGVTZWFyY2hGaWx0ZXIoZmlsdGVyVmFsdWU6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuYXBwbHlTZWFyY2hGaWx0ZXIkJC5uZXh0KGZpbHRlclZhbHVlKTtcbiAgfVxuXG4gIHByaXZhdGUgYXBwbHlTZWFyY2hGaWx0ZXIoZmlsdGVyVmFsdWU6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuZmlsdGVyQXBwbGllZCA9ICEhZmlsdGVyVmFsdWU7XG4gICAgLy8gVG8gb3B0aW1pemUgcmVuZGVyaW5nLCBoaWRlIHRoZSBhZGRvbnMgYmVmb3JlIHRoZSBmaWx0ZXIgaXMgcmVtb3ZlZCxcbiAgICAvLyBhbmQgc2hvdyB0aGUgYWRkb25zIGFmdGVyIHRoZSBmaWx0ZXIgaXMgYXBwbGllZC5cbiAgICBpZiAoIXRoaXMuZmlsdGVyQXBwbGllZCkge1xuICAgICAgdGhpcy5kYXRhU291cmNlLmRhdGEuZm9yRWFjaCgoZCkgPT4gKGQuZXhwYW5kZWQgPSBmYWxzZSkpO1xuICAgIH1cbiAgICB0aGlzLmRhdGFTb3VyY2UuZmlsdGVyID0gZmlsdGVyVmFsdWU/LnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuICAgIGlmICh0aGlzLmZpbHRlckFwcGxpZWQpIHtcbiAgICAgIHRoaXMuZGF0YVNvdXJjZS5kYXRhLmZvckVhY2goKGQpID0+IChkLmV4cGFuZGVkID0gdHJ1ZSkpO1xuICAgIH1cbiAgICB0aGlzLnVwZGF0ZVByb2R1Y3RUb29sYmFyVGV4dCgpO1xuICB9XG5cbiAgcHJpdmF0ZSB1cGRhdGVQcm9kdWN0VG9vbGJhclRleHQoKTogdm9pZCB7XG4gICAgdGhpcy5wcm9kdWN0VG9vbGJhclRleHQkJC5uZXh0KGAke3RoaXMuZGF0YVNvdXJjZS5maWx0ZXJlZERhdGEubGVuZ3RofWApO1xuICB9XG5cbiAgcHJpdmF0ZSBzb3J0aW5nRGF0YUFjY2Vzc29yKGRhdGE6IFByb2R1Y3RJbmZvcm1hdGlvbiwgc29ydEhlYWRlcklkOiBDb2x1bW5zKTogc3RyaW5nIHwgbnVtYmVyIHtcbiAgICBzd2l0Y2ggKHNvcnRIZWFkZXJJZCkge1xuICAgICAgY2FzZSBDb2x1bW5zLlByb2R1Y3Q6XG4gICAgICAgIHJldHVybiBkYXRhLm5hbWU7XG4gICAgICBjYXNlIENvbHVtbnMuQWN0aXZhdGlvbnM6XG4gICAgICAgIHJldHVybiBkYXRhLmNoYW5nZSA/IGRhdGEuY2hhbmdlLmFjdGl2YXRpb25zIDogMDtcbiAgICAgIGNhc2UgQ29sdW1ucy5EZWFjdGl2YXRpb25zOlxuICAgICAgICByZXR1cm4gZGF0YS5jaGFuZ2UgPyBkYXRhLmNoYW5nZS5kZWFjdGl2YXRpb25zIDogMDtcbiAgICAgIGNhc2UgQ29sdW1ucy5Hcm93dGg6XG4gICAgICAgIHJldHVybiBkYXRhLmdyb3d0aDtcbiAgICAgIGNhc2UgQ29sdW1ucy5BY3RpdmVBY2NvdW50czpcbiAgICAgICAgcmV0dXJuIGRhdGEuc3RhdHMgPyAoZGF0YS5zdGF0cy5hY3RpdmF0aW9ucyB8fCAwKSAtIChkYXRhLnN0YXRzLmRlYWN0aXZhdGlvbnMgfHwgMCkgOiAwO1xuICAgICAgY2FzZSBDb2x1bW5zLkNhbmNlbGxhdGlvbnM6XG4gICAgICAgIHJldHVybiBkYXRhLmNoYW5nZSA/IGRhdGEuY2hhbmdlLmNhbmNlbGxhdGlvbnMgOiAwO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgcmV0dXJuIGRhdGFbc29ydEhlYWRlcklkXTtcbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLnVuc3Vic2NyaWJlJC5uZXh0KCk7XG4gICAgdGhpcy51bnN1YnNjcmliZSQuY29tcGxldGUoKTtcbiAgfVxuXG4gIHRyYWNrQnlGbihfLCBpdGVtOiBQcm9kdWN0SW5mb3JtYXRpb24pOiBzdHJpbmcge1xuICAgIHJldHVybiBpdGVtPy5hZGRvbklkIHx8IGl0ZW0/LmFwcElkO1xuICB9XG59XG4iLCI8dmEtZmlsdGVyLWNvbnRhaW5lclxuICBbdG9vbGJhclRleHRdPVwicHJvZHVjdFRvb2xiYXJUZXh0JCB8IGFzeW5jXCJcbiAgW3NlYXJjaGFibGVdPVwidHJ1ZVwiXG4gIChzZWFyY2hUZXJtQ2hhbmdlZCk9XCJoYW5kbGVTZWFyY2hGaWx0ZXIoJGV2ZW50KVwiXG4+XG4gIDxwIGNsYXNzPVwiZ3Jvd3RoLWhlYWRlclwiIGhlYWRlcj5cbiAgICB7e1xuICAgICAgJ0ZST05URU5ELlNUT1JFLk1BTkFHRV9QUk9EVUNULk1BTkFHRV9QUk9EVUNUX1RBQkxFLlNIT1dfR1JPV1RIX09WRVInXG4gICAgICAgIHwgdHJhbnNsYXRlXG4gICAgfX1cbiAgPC9wPlxuICA8c3BhbiBoZWFkZXI+XG4gICAgPGRpdiBjbGFzcz1cImZpbHRlci1jb250YWluZXJcIj5cbiAgICAgIDx2YS1maWx0ZXItY2hpcC1jb250YWluZXJcbiAgICAgICAgW2ZpbHRlcnNdPVwiZmlsdGVyc1wiXG4gICAgICAgIFtjb25maWddPVwiY29uZmlnXCJcbiAgICAgID48L3ZhLWZpbHRlci1jaGlwLWNvbnRhaW5lcj5cbiAgICA8L2Rpdj5cbiAgPC9zcGFuPlxuPC92YS1maWx0ZXItY29udGFpbmVyPlxuPG5nLWNvbnRhaW5lclxuICAqbmdUZW1wbGF0ZU91dGxldD1cIlxuICAgIHByb2R1Y3RUYWJsZTtcbiAgICBjb250ZXh0OiB7IGRhdGFTb3VyY2U6IGRhdGFTb3VyY2UsIHNob3dIZWFkZXJzOiB0cnVlIH1cbiAgXCJcbj48L25nLWNvbnRhaW5lcj5cbjxuZy10ZW1wbGF0ZVxuICAjcHJvZHVjdFRhYmxlXG4gIGxldC1kYXRhU291cmNlPVwiZGF0YVNvdXJjZVwiXG4gIGxldC1zaG93SGVhZGVycz1cInNob3dIZWFkZXJzXCJcbj5cbiAgPG1hdC10YWJsZVxuICAgIGNsYXNzPVwicHJvZHVjdC10YWJsZVwiXG4gICAgY29udGVudFxuICAgIG1hdFNvcnRcbiAgICBbZGF0YVNvdXJjZV09XCJkYXRhU291cmNlXCJcbiAgICBtdWx0aVRlbXBsYXRlRGF0YVJvd3NcbiAgICAjbWFuYWdlUHJvZHVjdFNvcnQ9XCJtYXRTb3J0XCJcbiAgICBbbWF0U29ydEFjdGl2ZV09XCJDb2x1bW5zLkFjdGl2ZUFjY291bnRzXCJcbiAgICBtYXRTb3J0U3RhcnQ9XCJkZXNjXCJcbiAgICBtYXRTb3J0RGlyZWN0aW9uPVwiZGVzY1wiXG4gICAgW3RyYWNrQnldPVwidHJhY2tCeUZuXCJcbiAgICBtYXRTb3J0RGlzYWJsZUNsZWFyXG4gID5cbiAgICA8IS0tIFByb2R1Y3QgQ29sdW1uIC0tPlxuICAgIDxuZy1jb250YWluZXIgW21hdENvbHVtbkRlZl09XCJDb2x1bW5zLlByb2R1Y3RcIj5cbiAgICAgIDxtYXQtaGVhZGVyLWNlbGwgY2xhc3M9XCJwcm9kdWN0LWNvbHVtblwiICptYXRIZWFkZXJDZWxsRGVmIG1hdC1zb3J0LWhlYWRlcj5cbiAgICAgICAge3tcbiAgICAgICAgICAnRlJPTlRFTkQuU1RPUkUuTUFOQUdFX1BST0RVQ1QuTUFOQUdFX1BST0RVQ1RfVEFCTEUuQ09MVU1OUy5QUk9EVUNUJ1xuICAgICAgICAgICAgfCB0cmFuc2xhdGVcbiAgICAgICAgfX1cbiAgICAgIDwvbWF0LWhlYWRlci1jZWxsPlxuICAgICAgPG1hdC1jZWxsIGNsYXNzPVwicHJvZHVjdC1jb2x1bW5cIiAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJlbGVtZW50OyBlbHNlIGxvYWRpbmdDZWxsXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInByb2R1Y3QtY2VsbFwiIFtjbGFzcy5pbmRlbnRlZC1jb2x1bW5dPVwiIXNob3dIZWFkZXJzXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaWNvbi1jb250YWluZXJcIj5cbiAgICAgICAgICAgICAgPGEgW3JvdXRlckxpbmtdPVwiZ2V0UHJvZHVjdElkKGVsZW1lbnQpXCI+XG4gICAgICAgICAgICAgICAgPHZhLWljb25cbiAgICAgICAgICAgICAgICAgIFtkaWFtZXRlcl09XCI0MFwiXG4gICAgICAgICAgICAgICAgICBbbmFtZV09XCJlbGVtZW50Py5uYW1lXCJcbiAgICAgICAgICAgICAgICAgIFtpY29uVXJsXT1cImVsZW1lbnQ/Lmljb25cIlxuICAgICAgICAgICAgICAgID48L3ZhLWljb24+XG4gICAgICAgICAgICAgIDwvYT5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cInByb2R1Y3QtaW5mby1jb250YWluZXJcIj5cbiAgICAgICAgICAgICAgPGEgW3JvdXRlckxpbmtdPVwiZ2V0UHJvZHVjdElkKGVsZW1lbnQpXCI+e3sgZWxlbWVudC5uYW1lIH19PC9hPlxuICAgICAgICAgICAgICA8cCBjbGFzcz1cInByb2R1Y3QtcmVxdWlyZW1lbnRzLXRleHRcIiAqbmdJZj1cImVsZW1lbnQuYWRkb25JZFwiPlxuICAgICAgICAgICAgICAgIHt7XG4gICAgICAgICAgICAgICAgICAnRlJPTlRFTkQuU1RPUkUuTUFOQUdFX1BST0RVQ1QuTUFOQUdFX1BST0RVQ1RfVEFCTEUuUEFSRU5UX1JFUVVJUkVNRU5UJ1xuICAgICAgICAgICAgICAgICAgICB8IHRyYW5zbGF0ZVxuICAgICAgICAgICAgICAgICAgICAgIDoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lOiAoKGFwcElkVG9OYW1lTWFwJCB8IGFzeW5jKSB8fCB7fSlbZWxlbWVudC5hcHBJZF1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9fVxuICAgICAgICAgICAgICA8L3A+XG4gICAgICAgICAgICAgIDxwIGNsYXNzPVwicHJvZHVjdC10YWdsaW5lLXRleHRcIiAqbmdJZj1cImVsZW1lbnQudGFnbGluZVwiPlxuICAgICAgICAgICAgICAgIHt7IGVsZW1lbnQudGFnbGluZSB9fVxuICAgICAgICAgICAgICA8L3A+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8L21hdC1jZWxsPlxuICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgPCEtLSBTZWxsaW5nIGluIHN0b3JlIENvbHVtbiAtLT5cbiAgICA8bmctY29udGFpbmVyIFttYXRDb2x1bW5EZWZdPVwiQ29sdW1ucy5TZWxsaW5nSW5TdG9yZVwiPlxuICAgICAgPG1hdC1oZWFkZXItY2VsbCBjbGFzcz1cImNlbnRlci1hbGlnbiBzbWFsbC1jb2x1bW5cIiAqbWF0SGVhZGVyQ2VsbERlZj5cbiAgICAgICAge3tcbiAgICAgICAgICAnRlJPTlRFTkQuU1RPUkUuTUFOQUdFX1BST0RVQ1QuTUFOQUdFX1BST0RVQ1RfVEFCTEUuQ09MVU1OUy5TRUxMSU5HX0lOX1NUT1JFJ1xuICAgICAgICAgICAgfCB0cmFuc2xhdGVcbiAgICAgICAgfX1cbiAgICAgIDwvbWF0LWhlYWRlci1jZWxsPlxuICAgICAgPG1hdC1jZWxsXG4gICAgICAgIGNsYXNzPVwic3RhdC1jZWxsIGNlbnRlci1hbGlnbiBzbWFsbC1jb2x1bW5cIlxuICAgICAgICAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCJcbiAgICAgID5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImVsZW1lbnQ7IGVsc2UgbG9hZGluZ0NlbGxcIj5cbiAgICAgICAgICA8c3BhbiAqbmdJZj1cImVsZW1lbnQuc2VsbGluZ0luU3RvcmVcIj48bWF0LWljb24+Y2hlY2s8L21hdC1pY29uPjwvc3Bhbj5cbiAgICAgICAgICA8c3BhbiAqbmdJZj1cIiFlbGVtZW50LnNlbGxpbmdJblN0b3JlXCI+Jm1kYXNoOzwvc3Bhbj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8L21hdC1jZWxsPlxuICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgPCEtLSBBY3RpdmUgQWNjb3VudHMgLS0+XG4gICAgPG5nLWNvbnRhaW5lciBbbWF0Q29sdW1uRGVmXT1cIkNvbHVtbnMuQWN0aXZlQWNjb3VudHNcIj5cbiAgICAgIDxtYXQtaGVhZGVyLWNlbGxcbiAgICAgICAgY2xhc3M9XCJyaWdodC1hbGlnbiBjdXJyZW50bHktYWN0aXZlLWNvbHVtblwiXG4gICAgICAgICptYXRIZWFkZXJDZWxsRGVmXG4gICAgICAgIG1hdC1zb3J0LWhlYWRlclxuICAgICAgICBhcnJvd1Bvc2l0aW9uPVwiYmVmb3JlXCJcbiAgICAgID5cbiAgICAgICAge3tcbiAgICAgICAgICAnRlJPTlRFTkQuU1RPUkUuTUFOQUdFX1BST0RVQ1QuTUFOQUdFX1BST0RVQ1RfVEFCTEUuQ09MVU1OUy5BQ1RJVkVfQUNDT1VOVFMnXG4gICAgICAgICAgICB8IHRyYW5zbGF0ZVxuICAgICAgICB9fVxuICAgICAgPC9tYXQtaGVhZGVyLWNlbGw+XG4gICAgICA8bWF0LWNlbGxcbiAgICAgICAgY2xhc3M9XCJzdGF0LWNlbGwgcmlnaHQtYWxpZ24gY3VycmVudGx5LWFjdGl2ZS1jb2x1bW5cIlxuICAgICAgICAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCJcbiAgICAgID5cbiAgICAgICAgPGRpdiBzdHlsZT1cImRpc3BsYXk6IGZsZXg7IGZsZXgtZGlyZWN0aW9uOiBjb2x1bW5cIj5cbiAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiZWxlbWVudDsgZWxzZSBsb2FkaW5nQ2VsbFwiPlxuICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAge3sgZWxlbWVudC5zdGF0cz8uYWN0aXZhdGlvbnMgLSBlbGVtZW50LnN0YXRzPy5kZWFjdGl2YXRpb25zIH19XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L21hdC1jZWxsPlxuICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgPCEtLSBWZXJ0aWNhbCBMaW5lIC0tPlxuICAgIDxuZy1jb250YWluZXIgW21hdENvbHVtbkRlZl09XCJDb2x1bW5zLlZlcnRpY2FsTGluZVwiPlxuICAgICAgPG1hdC1oZWFkZXItY2VsbCBjbGFzcz1cImxpbmUtY29sdW1uXCIgKm1hdEhlYWRlckNlbGxEZWY+XG4gICAgICAgIDxtYXQtZGl2aWRlciBbdmVydGljYWxdPVwidHJ1ZVwiIGNsYXNzPVwiZGl2aWRlclwiPjwvbWF0LWRpdmlkZXI+XG4gICAgICA8L21hdC1oZWFkZXItY2VsbD5cbiAgICAgIDxtYXQtY2VsbCBjbGFzcz1cImxpbmUtY29sdW1uXCIgKm1hdENlbGxEZWY+XG4gICAgICAgIDxtYXQtZGl2aWRlciBbdmVydGljYWxdPVwidHJ1ZVwiIGNsYXNzPVwiZGl2aWRlclwiPjwvbWF0LWRpdmlkZXI+XG4gICAgICA8L21hdC1jZWxsPlxuICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgPCEtLSBBY3RpdmF0aW9ucyBDb2x1bW4gLS0+XG4gICAgPG5nLWNvbnRhaW5lciBbbWF0Q29sdW1uRGVmXT1cIkNvbHVtbnMuQWN0aXZhdGlvbnNcIj5cbiAgICAgIDxtYXQtaGVhZGVyLWNlbGxcbiAgICAgICAgY2xhc3M9XCJyaWdodC1hbGlnblwiXG4gICAgICAgICptYXRIZWFkZXJDZWxsRGVmXG4gICAgICAgIG1hdC1zb3J0LWhlYWRlclxuICAgICAgICBhcnJvd1Bvc2l0aW9uPVwiYmVmb3JlXCJcbiAgICAgID5cbiAgICAgICAge3tcbiAgICAgICAgICAnRlJPTlRFTkQuU1RPUkUuTUFOQUdFX1BST0RVQ1QuTUFOQUdFX1BST0RVQ1RfVEFCTEUuQ09MVU1OUy5BQ1RJVkFUSU9OUydcbiAgICAgICAgICAgIHwgdHJhbnNsYXRlXG4gICAgICAgIH19XG4gICAgICA8L21hdC1oZWFkZXItY2VsbD5cbiAgICAgIDxtYXQtY2VsbCBjbGFzcz1cInN0YXQtY2VsbCByaWdodC1hbGlnbiBwb3NcIiAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJlbGVtZW50OyBlbHNlIGxvYWRpbmdDZWxsXCI+XG4gICAgICAgICAgPHNwYW4gW25nQ2xhc3NdPVwiZWxlbWVudC5jaGFuZ2U/LmFjdGl2YXRpb25zID4gMCA/ICdwb3MnIDogJ3plcm8nXCI+XG4gICAgICAgICAgICB7eyBlbGVtZW50LmNoYW5nZT8uYWN0aXZhdGlvbnMgPiAwID8gJysnIDogJydcbiAgICAgICAgICAgIH19e3sgZWxlbWVudC5jaGFuZ2U/LmFjdGl2YXRpb25zIH19XG4gICAgICAgICAgPC9zcGFuPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDwvbWF0LWNlbGw+XG4gICAgPC9uZy1jb250YWluZXI+XG5cbiAgICA8IS0tIFBlbmRpbmcgQ2FuY2VsbGF0aW9ucyBDb2x1bW4gLS0+XG4gICAgPG5nLWNvbnRhaW5lciBbbWF0Q29sdW1uRGVmXT1cIkNvbHVtbnMuQ2FuY2VsbGF0aW9uc1wiPlxuICAgICAgPG1hdC1oZWFkZXItY2VsbFxuICAgICAgICBjbGFzcz1cInJpZ2h0LWFsaWduXCJcbiAgICAgICAgKm1hdEhlYWRlckNlbGxEZWZcbiAgICAgICAgbWF0LXNvcnQtaGVhZGVyXG4gICAgICAgIGFycm93UG9zaXRpb249XCJiZWZvcmVcIlxuICAgICAgPlxuICAgICAgICB7e1xuICAgICAgICAgICdGUk9OVEVORC5TVE9SRS5NQU5BR0VfUFJPRFVDVC5NQU5BR0VfUFJPRFVDVF9UQUJMRS5DT0xVTU5TLlBFTkRJTkdfREVBQ1RJVkFUSU9OUydcbiAgICAgICAgICAgIHwgdHJhbnNsYXRlXG4gICAgICAgIH19XG4gICAgICA8L21hdC1oZWFkZXItY2VsbD5cbiAgICAgIDxtYXQtY2VsbCBjbGFzcz1cInN0YXQtY2VsbCByaWdodC1hbGlnblwiICptYXRDZWxsRGVmPVwibGV0IGVsZW1lbnRcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImVsZW1lbnQ7IGVsc2UgbG9hZGluZ0NlbGxcIj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cInplcm9cIj5cbiAgICAgICAgICAgIHt7IGVsZW1lbnQuY2hhbmdlPy5jYW5jZWxsYXRpb25zIH19XG4gICAgICAgICAgPC9zcGFuPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDwvbWF0LWNlbGw+XG4gICAgPC9uZy1jb250YWluZXI+XG5cbiAgICA8IS0tIERlYWN0aXZhdGlvbnMgQ29sdW1uIC0tPlxuICAgIDxuZy1jb250YWluZXIgW21hdENvbHVtbkRlZl09XCJDb2x1bW5zLkRlYWN0aXZhdGlvbnNcIj5cbiAgICAgIDxtYXQtaGVhZGVyLWNlbGxcbiAgICAgICAgY2xhc3M9XCJyaWdodC1hbGlnblwiXG4gICAgICAgICptYXRIZWFkZXJDZWxsRGVmXG4gICAgICAgIG1hdC1zb3J0LWhlYWRlclxuICAgICAgICBhcnJvd1Bvc2l0aW9uPVwiYmVmb3JlXCJcbiAgICAgID5cbiAgICAgICAge3tcbiAgICAgICAgICAnRlJPTlRFTkQuU1RPUkUuTUFOQUdFX1BST0RVQ1QuTUFOQUdFX1BST0RVQ1RfVEFCTEUuQ09MVU1OUy5ERUFDVElWQVRJT05TJ1xuICAgICAgICAgICAgfCB0cmFuc2xhdGVcbiAgICAgICAgfX1cbiAgICAgIDwvbWF0LWhlYWRlci1jZWxsPlxuICAgICAgPG1hdC1jZWxsIGNsYXNzPVwic3RhdC1jZWxsIHJpZ2h0LWFsaWduXCIgKm1hdENlbGxEZWY9XCJsZXQgZWxlbWVudFwiPlxuICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiZWxlbWVudDsgZWxzZSBsb2FkaW5nQ2VsbFwiPlxuICAgICAgICAgIDxzcGFuIFtuZ0NsYXNzXT1cImVsZW1lbnQuY2hhbmdlPy5kZWFjdGl2YXRpb25zID4gMCA/ICduZWcnIDogJ3plcm8nXCI+XG4gICAgICAgICAgICB7eyBlbGVtZW50LmNoYW5nZT8uZGVhY3RpdmF0aW9ucyA+IDAgPyAnLScgOiAnJ1xuICAgICAgICAgICAgfX17eyBlbGVtZW50LmNoYW5nZT8uZGVhY3RpdmF0aW9ucyB9fVxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8L21hdC1jZWxsPlxuICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgPCEtLSBHcm93dGggQ29sdW1uIC0tPlxuICAgIDxuZy1jb250YWluZXIgW21hdENvbHVtbkRlZl09XCJDb2x1bW5zLkdyb3d0aFwiPlxuICAgICAgPG1hdC1oZWFkZXItY2VsbFxuICAgICAgICBjbGFzcz1cInJpZ2h0LWFsaWduXCJcbiAgICAgICAgKm1hdEhlYWRlckNlbGxEZWZcbiAgICAgICAgbWF0LXNvcnQtaGVhZGVyXG4gICAgICAgIGFycm93UG9zaXRpb249XCJiZWZvcmVcIlxuICAgICAgPlxuICAgICAgICB7e1xuICAgICAgICAgICdGUk9OVEVORC5TVE9SRS5NQU5BR0VfUFJPRFVDVC5NQU5BR0VfUFJPRFVDVF9UQUJMRS5DT0xVTU5TLkdST1dUSCdcbiAgICAgICAgICAgIHwgdHJhbnNsYXRlXG4gICAgICAgIH19XG4gICAgICA8L21hdC1oZWFkZXItY2VsbD5cbiAgICAgIDxtYXQtY2VsbFxuICAgICAgICBjbGFzcz1cInN0YXQtY2VsbCByaWdodC1hbGlnbiBncm93dGgtY2VsbHNcIlxuICAgICAgICAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCJcbiAgICAgID5cbiAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICpuZ0lmPVwiZWxlbWVudCAmJiBlbGVtZW50LmNoYW5nZSAmJiBlbGVtZW50LnN0YXRzOyBlbHNlIGxvYWRpbmdDZWxsXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxzcGFuXG4gICAgICAgICAgICBbbmdDbGFzc109XCJcbiAgICAgICAgICAgICAgZWxlbWVudC5ncm93dGggPiAwID8gJ3BvcycgOiBlbGVtZW50Lmdyb3d0aCA8IDAgPyAnbmVnJyA6ICd6ZXJvJ1xuICAgICAgICAgICAgXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICB7eyBlbGVtZW50Lmdyb3d0aCA+IDAgPyAnKycgOiAnJyB9fXt7IGVsZW1lbnQuZ3Jvd3RoIH19JVxuICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8L21hdC1jZWxsPlxuICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgPCEtLSBBY3Rpb25zIENvbHVtbiAtLT5cbiAgICA8bmctY29udGFpbmVyIFttYXRDb2x1bW5EZWZdPVwiQ29sdW1ucy5BY3Rpb25zXCI+XG4gICAgICA8bWF0LWhlYWRlci1jZWxsXG4gICAgICAgIGNsYXNzPVwicmlnaHQtYWxpZ24gbWFya2V0cGxhY2UtYnV0dG9uXCJcbiAgICAgICAgKm1hdEhlYWRlckNlbGxEZWZcbiAgICAgID48L21hdC1oZWFkZXItY2VsbD5cbiAgICAgIDxtYXQtY2VsbFxuICAgICAgICBjbGFzcz1cInN0YXQtY2VsbCByaWdodC1hbGlnbiBtYXJrZXRwbGFjZS1idXR0b25cIlxuICAgICAgICAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCJcbiAgICAgID5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cImVsZW1lbnQ7IGVsc2UgbG9hZGluZ0NlbGxcIj5cbiAgICAgICAgICA8YnV0dG9uIG1hdC1mbGF0LWJ1dHRvbiAqbmdJZj1cImVsZW1lbnQuYWRkb25zPy5sZW5ndGggPiAwXCI+XG4gICAgICAgICAgICA8bWF0LWljb24gKm5nSWY9XCIhZWxlbWVudC5leHBhbmRlZDsgZWxzZSBzaG93TGVzc1wiPlxuICAgICAgICAgICAgICBleHBhbmRfbW9yZVxuICAgICAgICAgICAgPC9tYXQtaWNvbj5cbiAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjc2hvd0xlc3M+XG4gICAgICAgICAgICAgIDxtYXQtaWNvbj5leHBhbmRfbGVzczwvbWF0LWljb24+XG4gICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDwvbWF0LWNlbGw+XG4gICAgPC9uZy1jb250YWluZXI+XG5cbiAgICA8IS0tIEV4cGFuZGFibGUgQWRkb25zIENvbHVtbiAtLT5cbiAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cImV4cGFuZGVkRGV0YWlsXCI+XG4gICAgICA8bWF0LWNlbGxcbiAgICAgICAgY2xhc3M9XCJhZGRvbnMtY2VsbFwiXG4gICAgICAgICptYXRDZWxsRGVmPVwibGV0IGVsZW1lbnRcIlxuICAgICAgICBbYXR0ci5jb2xzcGFuXT1cImRpc3BsYXllZENvbHVtbnMubGVuZ3RoXCJcbiAgICAgID5cbiAgICAgICAgPGRpdlxuICAgICAgICAgICpuZ0lmPVwiZWxlbWVudD8uYWRkb25zPy5sZW5ndGggPiAwICYmIGVsZW1lbnQ/LmV4cGFuZGVkXCJcbiAgICAgICAgICBjbGFzcz1cImV4cGFuZGFibGUtY29sXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZVxuICAgICAgICAgICAgKm5nVGVtcGxhdGVPdXRsZXQ9XCJcbiAgICAgICAgICAgICAgcHJvZHVjdFRhYmxlO1xuICAgICAgICAgICAgICBjb250ZXh0OiB7IGRhdGFTb3VyY2U6IGVsZW1lbnQuYWRkb25zLCBzaG93SGVhZGVyczogZmFsc2UgfVxuICAgICAgICAgICAgXCJcbiAgICAgICAgICA+PC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L21hdC1jZWxsPlxuICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInNob3dIZWFkZXJzXCI+XG4gICAgICA8bWF0LWhlYWRlci1yb3cgKm1hdEhlYWRlclJvd0RlZj1cImRpc3BsYXllZENvbHVtbnNcIj48L21hdC1oZWFkZXItcm93PlxuICAgIDwvbmctY29udGFpbmVyPlxuICAgIDxtYXQtcm93XG4gICAgICBjbGFzcz1cInByb2R1Y3Qtcm93XCJcbiAgICAgICptYXRSb3dEZWY9XCJsZXQgcm93OyBjb2x1bW5zOiBkaXNwbGF5ZWRDb2x1bW5zXCJcbiAgICAgIFtjbGFzcy5leHBhbmRhYmxlXT1cInJvdz8uYWRkb25zPy5sZW5ndGggPiAwXCJcbiAgICAgIChjbGljayk9XCJyb3cuZXhwYW5kZWQgPSAhcm93LmV4cGFuZGVkXCJcbiAgICA+PC9tYXQtcm93PlxuICAgIDxtYXQtcm93XG4gICAgICBjbGFzcz1cImFkZG9ucy1yb3dcIlxuICAgICAgKm1hdFJvd0RlZj1cImxldCBlbGVtZW50OyBjb2x1bW5zOiBbJ2V4cGFuZGVkRGV0YWlsJ11cIlxuICAgID48L21hdC1yb3c+XG4gIDwvbWF0LXRhYmxlPlxuPC9uZy10ZW1wbGF0ZT5cbjxuZy10ZW1wbGF0ZSAjbG9hZGluZ0NlbGw+XG4gIDx0ZCBjbGFzcz1cInN0ZW5jaWwtY29udGFpbmVyXCI+XG4gICAgPGRpdiBjbGFzcz1cInN0ZW5jaWwgc3RlbmNpbC1zaGltbWVyXCI+PC9kaXY+XG4gIDwvdGQ+XG48L25nLXRlbXBsYXRlPlxuIl19