@hxui/angular
Version:
This README includes the steps that are necessary to import the HxUi-angular into a project or to contribute with development.
521 lines (494 loc) • 53.3 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { ITabularConfig } from './tabular-config.interface';
import { ActionConfigRouteType } from './actions-config.interface';
import { TabularSortByService, SortByDirection } from './tabular-sort-by.service';
import { TabularConfig } from './tabular.config';
import { TabularSize } from './tabular-size.enum';
import { TabularColumnTypes } from './tabular-column.interface';
import { Context } from '../enums';
import * as _ from 'lodash';
export class TabularComponent {
/**
* @param {?} conf
* @param {?} sortByService
*/
constructor(conf, sortByService) {
this.conf = conf;
this.sortByService = sortByService;
/**
* Event fired when refresh is called.
* Host should refresh data of input.
*/
this.refresh = new EventEmitter();
/**
* Event fired when a row is clicked.
*/
this.rowClick = new EventEmitter();
this.oldRows = [];
this.pagedItems = [];
this.TabularColumnTypes = TabularColumnTypes;
this.TabularSize = TabularSize;
this.ActionConfigRouteType = ActionConfigRouteType;
this.selectAll = false;
this.Context = Context;
this.SortByDirection = SortByDirection;
this.toggleSelectAll = ($event) => {
for (let /** @type {?} */ i = 0; i < this.rows.length; i++) {
this.rows[i].checked = this.selectAll;
}
};
this.toggleIndividualSelect = ($event) => {
let /** @type {?} */ count = 0;
for (let /** @type {?} */ i = 0; i < this.rows.length; i++) {
if (this.rows[i].checked) {
count++;
}
}
this.selectAll = (this.rows.length === count);
};
Object.assign(this, conf);
}
/**
* Tabular configuration
* IPaginationInstance, ISearchConfig
* @return {?}
*/
get config() {
return this._config;
}
/**
* @param {?} c
* @return {?}
*/
set config(c) {
if (!c.sortBy) {
c.sortBy = [];
}
this._config = c;
}
/**
* The function to call when a action item is clicked *
* @return {?}
*/
get callback() {
return this._callback;
}
/**
* @param {?} Fn
* @return {?}
*/
set callback(Fn) {
this._callback = Fn;
}
/**
* Search term is used in the simple search pipe
* Array of objects: *ngFor="#row of rows | simpleSearch : 'the search term'"
* @return {?}
*/
get searchTerm() {
return this._searchTerm;
}
/**
* @param {?} term
* @return {?}
*/
set searchTerm(term) {
this._searchTerm = term;
}
/**
* @return {?}
*/
ngOnInit() {
}
/**
* @return {?}
*/
ngDoCheck() {
if (!_.isEqual(this.rows, this.oldRows)) {
this.oldRows = _.cloneDeep(this.rows);
this.orderByData();
}
}
/**
* Calls the parsed callback with optional arguments
* @param {?} event
* @param {?} cb
* @return {?}
*/
executeCallback(event, cb) {
event.stopPropagation();
if (cb.length) {
if (cb.length === 1) {
// if callback has no arguments
cb[0]();
}
else {
// if callback has 1 or more arguments
const /** @type {?} */ args = [];
for (let /** @type {?} */ i = 1; i < cb.length; i++) {
args.push(cb[i]);
}
cb[0].apply(this, args);
}
}
}
/**
* @param {?=} $event
* @return {?}
*/
setPage($event = {
page: this.config.pagination.currentPage,
itemsPerPage: this.config.pagination.itemsPerPage
}) {
this.config.pagination.currentPage = $event.page;
// calculate start and end page item indexes
const /** @type {?} */ startIndex = (this.config.pagination.currentPage - 1) * this.config.pagination.itemsPerPage;
const /** @type {?} */ endIndex = Math.min(startIndex + this.config.pagination.itemsPerPage - 1, this.totalItemCount - 1);
this.pagedItems = this.rows.slice(startIndex, endIndex + 1);
}
/**
* Get the action tooltip if it exists
* @param {?} action
* @return {?}
*/
getActionTooltip(action) {
return (action && action.disabledConfig) ? action.disabledConfig.tooltip : '';
}
/**
* @param {?} action
* @return {?}
*/
getActionDisabledState(action) {
return (action && action.disabledConfig) ? action.disabledConfig.disabled : false;
}
/**
* Handles the column header click event for sorting.
* Sort order is Descending, Ascending followed by None.
* @param {?} key
* @param {?} type
* @return {?}
*/
onSortClickHandler(key, type) {
const /** @type {?} */ findPropInSortList = this.config.sortBy.filter((prop) => { return (prop.property === key); });
if (findPropInSortList.length) {
const /** @type {?} */ prop = findPropInSortList[0];
const /** @type {?} */ index = this.config.sortBy.findIndex(x => x === prop);
if (prop.direction === SortByDirection.None) {
prop.direction = SortByDirection.Descending;
}
else if (prop.direction === SortByDirection.Descending) {
prop.direction = SortByDirection.Ascending;
}
else if (prop.direction === SortByDirection.Ascending) {
if (index > -1) {
this.config.sortBy.splice(index, 1);
}
}
}
else {
this.config.sortBy.push({ property: key, direction: SortByDirection.Descending, type: type });
}
this.orderByData();
return false;
}
/**
* @param {?} key
* @param {?} direction
* @return {?}
*/
isColumnSorted(key, direction) {
const /** @type {?} */ findPropInSortList = this.config.sortBy.filter((prop) => { return (prop.property === key && prop.direction === direction); });
return (findPropInSortList.length > 0);
}
/**
* Handles the row click event.
* @param {?} $event
* @param {?} data
* @return {?}
*/
onRowClickHandler($event, data) {
const /** @type {?} */ el = $event.target;
if (this.config.clickableRows) {
if (el.parentElement.tagName === 'BUTTON' ||
el.tagName === 'BUTTON' ||
el.parentElement.classList.contains('hx-checkbox-control')) {
return;
}
this.rowClick.emit(data);
}
}
/**
* @return {?}
*/
orderByData() {
if (this.config.sortBy.length > 0) {
this.rows = [...this.rows]; // Required as array-sort-by mutates the original array
this.sortByService.sortBy(this.rows, this.config.sortBy);
}
this.setPage();
}
/**
* @return {?}
*/
get totalItemCount() {
return this.rows.length;
}
/**
* Helper to determine if tabular instance is in small mode
* @return {?}
*/
isSmall() {
return (this.config.size === TabularSize.Small);
}
/**
* @param {?} colData
* @return {?}
*/
hasValidBadgeTypeParams(colData) {
if (colData) {
if (typeof colData.label !== 'undefined') {
return true;
}
else {
console.error('Record for column type badge is invalid, make sure you have the right type. ITabularColumnTypeBadge', { columnValue: colData });
}
}
return false;
}
/**
* @param {?} colData
* @return {?}
*/
hasValidIconTypeParams(colData) {
let /** @type {?} */ hasError = false;
if (colData) {
if (typeof colData.icon !== 'undefined') {
if (typeof colData.tooltip.config !== 'undefined' && typeof colData.tooltip.content !== 'undefined') {
if (typeof colData.tooltip.config.context !== 'undefined' || typeof colData.tooltip.config.placement !== 'undefined') {
return true;
}
else {
hasError = true;
}
}
else {
hasError = true;
}
}
else {
hasError = true;
}
}
if (hasError) {
console.error('Record for column type icon is invalid, make sure you have the right type. ITabularColumnTypeIcon', { columnValue: colData });
}
return false;
}
/**
* @param {?} colData
* @return {?}
*/
getTooltipContext(colData) {
return (!this.hasValidIconTypeParams(colData)) ? colData.tooltip.config.context : Context.None;
}
/**
* @param {?} action
* @return {?}
*/
hasChildren(action) {
return (action.children && action.children.length > 0);
}
/**
* @param {?} index
* @param {?} action
* @return {?}
*/
trackByFn(index, action) {
return index; // or action.id
}
}
TabularComponent.decorators = [
{ type: Component, args: [{
selector: 'hxa-tabular',
template: `<table class="tabular hx-table is-striped" [class.is-hover]="config.clickableRows" [class.is-narrow]="config.size === TabularSize.Small">
<thead>
<tr>
<th *ngFor="let col of columns" class="{{col.cssClass}} tabular__{{col.label}}" [ngClass]="{'tabular__checkboxes': col.dataType === TabularColumnTypes.Checkbox, 'tabular__sortable': col.sortable}">
<!-- sortable column -->
<a class="tabular__sorter" href="#" *ngIf="col.sortable && col.dataType != TabularColumnTypes.Checkbox" (click)="onSortClickHandler(col.id, col.dataType)">{{col.label}} <i class="hx-icon icon-arrow-up is-small" [class.icon-arrow-up]="isColumnSorted(col.id, SortByDirection.Ascending)" [class.icon-arrow-down]="isColumnSorted(col.id, SortByDirection.Descending)" *ngIf="isColumnSorted(col.id, SortByDirection.Descending) || isColumnSorted(col.id, SortByDirection.Ascending)"></i></a>
<!-- non sortable column -->
<span *ngIf="!col.sortable && col.dataType !== TabularColumnTypes.Checkbox">{{col.label}}</span>
<!-- checkbox column -->
<div *ngIf="col.dataType === TabularColumnTypes.Checkbox" class="hx-checkbox-control">
<input id="selectAll" name="selectAll" type="checkbox" class="hx-checkbox" (change)="toggleSelectAll($event)" title="Select All" [(ngModel)]="selectAll" />
<label for="selectAll" class="hx-label"></label>
</div>
</th>
</tr>
</thead>
<tbody>
<!--<tr *ngFor="let row of rows | paginate: config.pagination | simpleSearch: searchTerm">-->
<tr *ngFor="let row of pagedItems"
(click)="onRowClickHandler($event, row)"
[class.is-selected]="row.selected"
[class.is-danger]="row.context && row.context === Context.Danger"
[class.is-warning]="row.context && row.context === Context.Warning"
[class.is-info]="row.context && row.context === Context.Info"
[class.is-success]="row.context && row.context === Context.Success"
[class.has-stripe-danger]="row.stripeContext && row.stripeContext === Context.Danger"
[class.has-stripe-warning]="row.stripeContext && row.stripeContext === Context.Warning"
[class.has-stripe-info]="row.stripeContext && row.stripeContext === Context.Info"
[class.has-stripe-success]="row.stripeContext && row.stripeContext === Context.Success"
[ngClass]="[row.cssClass? row.cssClass : '']"
[attr.title]="row.title ? row.title : ''">
<td *ngFor="let col of columns" class="{{col.cssClass}} tabular__{{col.label}}" [ngClass]="{'tabular__checkboxes': col.dataType === TabularColumnTypes.Checkbox}">
<!-- checkbox type -->
<div *ngIf="col.dataType === TabularColumnTypes.Checkbox" class="hx-checkbox-control">
<input id="checkbox-{{row.id}}" name="{{col.label}}-checkbox" type="checkbox" class="hx-checkbox" title="{{col.label}}" (change)="toggleIndividualSelect($event)" [(ngModel)]="row.checked" />
<label for="checkbox-{{row.id}}" class="hx-label"></label>
</div>
<!-- string type | number type -->
<span *ngIf="col.dataType === TabularColumnTypes.String || col.dataType === TabularColumnTypes.Number" title="{{row[col.id]}}">{{row[col.id]}}</span>
<!-- icon type -->
<i *ngIf="col.dataType === TabularColumnTypes.Icon && hasValidIconTypeParams(row[col.id])" title="" class="hx-icon {{row[col.id].icon}}" [hxTooltip]="row[col.id].tooltip.content" placement="{{row[col.id].tooltip.config.placement}}" [context]="row[col.id].tooltip.config.context"></i>
<!-- date type -->
<span *ngIf="col.dataType === TabularColumnTypes.Date">{{row[col.id] | date:'d/M/yy'}}</span>
<!-- status type -->
<span *ngIf="col.dataType === TabularColumnTypes.Status" class="hx-icon" [ngClass]="{'is-primary':row[col.id],'is-danger':!row[col.id], 'icon-check-empty': row[col.id], 'icon-close-empty':!row[col.id]}" ></span>
<!-- badge type -->
<span *ngIf="col.dataType === TabularColumnTypes.Badge && hasValidBadgeTypeParams(row[col.id])" class="hx-badge is-small {{row[col.id].cssClass}}"><span class="hx-badge-content">{{row[col.id].label}}</span></span>
<!-- date time type -->
<span *ngIf="col.dataType === TabularColumnTypes.DateTime">{{row[col.id] | date:'d/M/yy h:mm a'}}</span>
<!-- actions type -->
<div *ngIf="col.dataType === TabularColumnTypes.Actions" class="hx-dropdown tabularActions">
<div class="tabularActions__action">
<ng-container *ngFor="let action of row[col.id];trackBy: trackByFn">
<!-- single action -->
<button type="button" class="hx-button is-flat" [class.is-small]="config.size === TabularSize.Small"
*ngIf="!getActionDisabledState(action) && action.routeType === ActionConfigRouteType.Route && !hasChildren(action)"
[routerLink]="action.route"
class="hx-button is-flat {{action.css}}"
title="{{action.label}}"><span class="hx-icon {{action.icon}}"></span></button>
<button type="button" class="hx-button is-flat" [class.is-small]="config.size === TabularSize.Small"
*ngIf="!getActionDisabledState(action) && action.routeType === ActionConfigRouteType.Callback && !hasChildren(action)"
(click)='executeCallback($event,action.callback)'
class="hx-button is-flat {{action.css}}"><span class="hx-icon {{action.icon}}"></span></button>
<!-- action with children -->
<div class="hx-dropdown" hxDropdown [isRight]="true" *ngIf="hasChildren(action)">
<button class="hx-button is-flat hx-button-dropdown" [class.is-small]="config.size === TabularSize.Small" hxDropdownToggle type="button">
<i class="icon {{action.icon}}"></i>
</button>
<div class="hx-dropdown-menu" *hxDropdownMenu>
<ng-container *ngFor="let childAction of action.children;trackBy: trackByFn">
<a *ngIf="!getActionDisabledState(childAction) && childAction.routeType === ActionConfigRouteType.Route"
[routerLink]="childAction.route"
class="hx-dropdown-item {{childAction.css}}">{{childAction.label}}</a>
<a *ngIf="!getActionDisabledState(childAction) && childAction.routeType === ActionConfigRouteType.Callback"
(click)='executeCallback($event,childAction.callback)'
class="hx-dropdown-item {{childAction.css}}">{{childAction.label}}</a>
</ng-container>
</div>
</div>
</ng-container>
</div>
</div>
</td>
</tr>
</tbody>
</table>
<hx-pagination [directionLinks]="true" [boundaryLinks]="true" [rotate]="false" [maxSize]="10"
[totalItems]="totalItemCount" [itemsPerPage]="config.pagination.itemsPerPage"
[(ngModel)]="config.pagination.currentPage" (pageChanged)="setPage($event)" *ngIf="totalItemCount > config.pagination.itemsPerPage"></hx-pagination>
`,
styles: [
'.tabular__sortable {}',
'.tabular__sorter {cursor:pointer; display:flex; align-items: center;}',
'.tabular__sorter .hx-icon {margin-left:.1rem;}',
'.tabular__checkboxes{width:2%;}',
'.tabular__checkboxes .hx-checkbox-control{display:flex;}',
'.tabularActions__action button.hx-button{ width: 1rem;}',
'.tabularActions__action {display:flex;}'
]
},] },
];
/** @nocollapse */
TabularComponent.ctorParameters = () => [
{ type: TabularConfig, },
{ type: TabularSortByService, },
];
TabularComponent.propDecorators = {
"columns": [{ type: Input },],
"rows": [{ type: Input },],
"config": [{ type: Input },],
"callback": [{ type: Input },],
"searchTerm": [{ type: Input },],
"refresh": [{ type: Output },],
"rowClick": [{ type: Output },],
};
function TabularComponent_tsickle_Closure_declarations() {
/** @type {!Array<{type: !Function, args: (undefined|!Array<?>)}>} */
TabularComponent.decorators;
/**
* @nocollapse
* @type {function(): !Array<(null|{type: ?, decorators: (undefined|!Array<{type: !Function, args: (undefined|!Array<?>)}>)})>}
*/
TabularComponent.ctorParameters;
/** @type {!Object<string,!Array<{type: !Function, args: (undefined|!Array<?>)}>>} */
TabularComponent.propDecorators;
/**
* Collection of column models
* @type {?}
*/
TabularComponent.prototype.columns;
/**
* Collection of data rows
* @type {?}
*/
TabularComponent.prototype.rows;
/**
* Event fired when refresh is called.
* Host should refresh data of input.
* @type {?}
*/
TabularComponent.prototype.refresh;
/**
* Event fired when a row is clicked.
* @type {?}
*/
TabularComponent.prototype.rowClick;
/** @type {?} */
TabularComponent.prototype.oldRows;
/** @type {?} */
TabularComponent.prototype.pagedItems;
/** @type {?} */
TabularComponent.prototype.TabularColumnTypes;
/** @type {?} */
TabularComponent.prototype.TabularSize;
/** @type {?} */
TabularComponent.prototype.ActionConfigRouteType;
/** @type {?} */
TabularComponent.prototype.selectAll;
/** @type {?} */
TabularComponent.prototype.Context;
/** @type {?} */
TabularComponent.prototype.SortByDirection;
/** @type {?} */
TabularComponent.prototype._callback;
/** @type {?} */
TabularComponent.prototype._config;
/** @type {?} */
TabularComponent.prototype._searchTerm;
/** @type {?} */
TabularComponent.prototype.toggleSelectAll;
/** @type {?} */
TabularComponent.prototype.toggleIndividualSelect;
/** @type {?} */
TabularComponent.prototype.conf;
/** @type {?} */
TabularComponent.prototype.sortByService;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFidWxhci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9AaHh1aS9hbmd1bGFyLyIsInNvdXJjZXMiOlsibGliL3RhYnVsYXIvdGFidWxhci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQ3ZDLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSw0QkFBNEIsQ0FBQztBQUMxRCxPQUFPLEVBQUMscUJBQXFCLEVBQWlCLE1BQU0sNEJBQTRCLENBQUM7QUFDakYsT0FBTyxFQUFDLG9CQUFvQixFQUFFLGVBQWUsRUFBa0IsTUFBTSwyQkFBMkIsQ0FBQztBQUNqRyxPQUFPLEVBQUMsYUFBYSxFQUFDLE1BQU0sa0JBQWtCLENBQUM7QUFDL0MsT0FBTyxFQUFDLFdBQVcsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBQ2hELE9BQU8sRUFBa0Qsa0JBQWtCLEVBQUMsTUFBTSw0QkFBNEIsQ0FBQztBQUUvRyxPQUFPLEVBQUMsT0FBTyxFQUFDLE1BQU0sVUFBVSxDQUFDO0FBQ2pDLE9BQU8sS0FBSyxDQUFDLE1BQU0sUUFBUSxDQUFDO0FBb0k1QixNQUFNOzs7OztJQTBFSCxZQUNTLE1BQ0E7UUFEQSxTQUFJLEdBQUosSUFBSTtRQUNKLGtCQUFhLEdBQWIsYUFBYTs7Ozs7dUJBdEJvQixJQUFJLFlBQVksRUFBVzs7Ozt3QkFLOUIsSUFBSSxZQUFZLEVBQU87dUJBRS9CLEVBQUU7MEJBQ1AsRUFBRTtrQ0FDRCxrQkFBa0I7MkJBQ3pCLFdBQVc7cUNBQ0QscUJBQXFCO3lCQUNqQyxLQUFLO3VCQUNQLE9BQU87K0JBQ0MsZUFBZTsrQkEyQ3JCLENBQUMsTUFBTSxFQUFFLEVBQUU7WUFDNUIsR0FBRyxDQUFDLENBQUMscUJBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FB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QUFRLEVBQUU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0FtSFg7Z0JBQ0MsTUFBTSxFQUFFO29CQUNOLHVCQUF1QjtvQkFDdkIsdUVBQXVFO29CQUN2RSxnREFBZ0Q7b0JBQ2hELGlDQUFpQztvQkFDakMsMERBQTBEO29CQUMxRCx5REFBeUQ7b0JBQ3pELHlDQUF5QztpQkFDMUM7YUFDRjs7OztZQXRJTyxhQUFhO1lBRGIsb0JBQW9COzs7d0JBK0l6QixLQUFLO3FCQU1KLEtBQUs7dUJBTU4sS0FBSzt5QkFZTCxLQUFLOzJCQWFMLEtBQUs7d0JBWUwsTUFBTTt5QkFLTixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBDb21wb25lbnQsIElucHV0LCBPdXRwdXQsIEV2ZW50RW1pdHRlciwgT25Jbml0LCBEb0NoZWNrLCBPbkNoYW5nZXMsIFNpbXBsZUNoYW5nZXNcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHtUYWJ1bGFyQ29sdW1ufSBmcm9tICcuL3RhYnVsYXInO1xyXG5pbXBvcnQge0lUYWJ1bGFyQ29uZmlnfSBmcm9tICcuL3RhYnVsYXItY29uZmlnLmludGVyZmFjZSc7XHJcbmltcG9ydCB7QWN0aW9uQ29uZmlnUm91dGVUeXBlLCBJQWN0aW9uc0NvbmZpZ30gZnJvbSAnLi9hY3Rpb25zLWNvbmZpZy5pbnRlcmZhY2UnO1xyXG5pbXBvcnQge1RhYnVsYXJTb3J0QnlTZXJ2aWNlLCBTb3J0QnlEaXJlY3Rpb24sIElTb3J0QnlQcm9wZXJ0eX0gZnJvbSAnLi90YWJ1bGFyLXNvcnQtYnkuc2VydmljZSc7XHJcbmltcG9ydCB7VGFidWxhckNvbmZpZ30gZnJvbSAnLi90YWJ1bGFyLmNvbmZpZyc7XHJcbmltcG9ydCB7VGFidWxhclNpemV9IGZyb20gJy4vdGFidWxhci1zaXplLmVudW0nO1xyXG5pbXBvcnQge0lUYWJ1bGFyQ29sdW1uQmFkZ2VUeXBlLCBJVGFidWxhckNvbHVtbkljb25UeXBlLCBUYWJ1bGFyQ29sdW1uVHlwZXN9IGZyb20gJy4vdGFidWxhci1jb2x1bW4uaW50ZXJmYWNlJztcclxuaW1wb3J0IHtJVGFidWxhclJvd30gZnJvbSAnLi90YWJ1bGFyLXJvdy5pbnRlcmZhY2UnO1xyXG5pbXBvcnQge0NvbnRleHR9IGZyb20gJy4uL2VudW1zJztcclxuaW1wb3J0ICogYXMgXyBmcm9tICdsb2Rhc2gnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdoeGEtdGFidWxhcicsXHJcbiAgdGVtcGxhdGU6IGA8dGFibGUgY2xhc3M9XCJ0YWJ1bGFyIGh4LXRhYmxlIGlzLXN0cmlwZWRcIiBbY2xhc3MuaXMtaG92ZXJdPVwiY29uZmlnLmNsaWNrYWJsZVJvd3NcIiBbY2xhc3MuaXMtbmFycm93XT1cImNvbmZpZy5zaXplID09PSBUYWJ1bGFyU2l6ZS5TbWFsbFwiPlxyXG4gIDx0aGVhZD5cclxuICA8dHI+XHJcbiAgICA8dGggKm5nRm9yPVwibGV0IGNvbCBvZiBjb2x1bW5zXCIgY2xhc3M9XCJ7e2NvbC5jc3NDbGFzc319IHRhYnVsYXJfX3t7Y29sLmxhYmVsfX1cIiBbbmdDbGFzc109XCJ7J3RhYnVsYXJfX2NoZWNrYm94ZXMnOiBjb2wuZGF0YVR5cGUgPT09IFRhYnVsYXJDb2x1bW5UeXBlcy5DaGVja2JveCwgJ3RhYnVsYXJfX3NvcnRhYmxlJzogY29sLnNvcnRhYmxlfVwiPlxyXG5cclxuICAgICAgPCEtLSBzb3J0YWJsZSBjb2x1bW4gLS0+XHJcbiAgICAgIDxhIGNsYXNzPVwidGFidWxhcl9fc29ydGVyXCIgaHJlZj1cIiNcIiAqbmdJZj1cImNvbC5zb3J0YWJsZSAmJiBjb2wuZGF0YVR5cGUgIT0gVGFidWxhckNvbHVtblR5cGVzLkNoZWNrYm94XCIgKGNsaWNrKT1cIm9uU29ydENsaWNrSGFuZGxlcihjb2wuaWQsIGNvbC5kYXRhVHlwZSlcIj57e2NvbC5sYWJlbH19IDxpIGNsYXNzPVwiaHgtaWNvbiBpY29uLWFycm93LXVwIGlzLXNtYWxsXCIgW2NsYXNzLmljb24tYXJyb3ctdXBdPVwiaXNDb2x1bW5Tb3J0ZWQoY29sLmlkLCBTb3J0QnlEaXJlY3Rpb24uQXNjZW5kaW5nKVwiIFtjbGFzcy5pY29uLWFycm93LWRvd25dPVwiaXNDb2x1bW5Tb3J0ZWQoY29sLmlkLCBTb3J0QnlEaXJlY3Rpb24uRGVzY2VuZGluZylcIiAqbmdJZj1cImlzQ29sdW1uU29ydGVkKGNvbC5pZCwgU29ydEJ5RGlyZWN0aW9uLkRlc2NlbmRpbmcpIHx8IGlzQ29sdW1uU29ydGVkKGNvbC5pZCwgU29ydEJ5RGlyZWN0aW9uLkFzY2VuZGluZylcIj48L2k+PC9hPlxyXG5cclxuICAgICAgPCEtLSBub24gc29ydGFibGUgY29sdW1uIC0tPlxyXG4gICAgICA8c3BhbiAqbmdJZj1cIiFjb2wuc29ydGFibGUgJiYgY29sLmRhdGFUeXBlICE9PSBUYWJ1bGFyQ29sdW1uVHlwZXMuQ2hlY2tib3hcIj57e2NvbC5sYWJlbH19PC9zcGFuPlxyXG5cclxuICAgICAgPCEtLSBjaGVja2JveCBjb2x1bW4gLS0+XHJcbiAgICAgIDxkaXYgKm5nSWY9XCJjb2wuZGF0YVR5cGUgPT09IFRhYnVsYXJDb2x1bW5UeXBlcy5DaGVja2JveFwiIGNsYXNzPVwiaHgtY2hlY2tib3gtY29udHJvbFwiPlxyXG4gICAgICAgIDxpbnB1dCBpZD1cInNlbGVjdEFsbFwiIG5hbWU9XCJzZWxlY3RBbGxcIiB0eXBlPVwiY2hlY2tib3hcIiBjbGFzcz1cImh4LWNoZWNrYm94XCIgKGNoYW5nZSk9XCJ0b2dnbGVTZWxlY3RBbGwoJGV2ZW50KVwiIHRpdGxlPVwiU2VsZWN0IEFsbFwiIFsobmdNb2RlbCldPVwic2VsZWN0QWxsXCIgLz5cclxuICAgICAgICA8bGFiZWwgZm9yPVwic2VsZWN0QWxsXCIgY2xhc3M9XCJoeC1sYWJlbFwiPjwvbGFiZWw+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgPC90aD5cclxuICA8L3RyPlxyXG4gIDwvdGhlYWQ+XHJcblxyXG4gIDx0Ym9keT5cclxuICA8IS0tPHRyICpuZ0Zvcj1cImxldCByb3cgb2Ygcm93cyB8IHBhZ2luYXRlOiBjb25maWcucGFnaW5hdGlvbiB8IHNpbXBsZVNlYXJjaDogc2VhcmNoVGVybVwiPi0tPlxyXG4gIDx0ciAqbmdGb3I9XCJsZXQgcm93IG9mIHBhZ2VkSXRlbXNcIlxyXG4gICAgICAoY2xpY2spPVwib25Sb3dDbGlja0hhbmRsZXIoJGV2ZW50LCByb3cpXCJcclxuICAgICAgW2NsYXNzLmlzLXNlbGVjdGVkXT1cInJvdy5zZWxlY3RlZFwiXHJcbiAgICAgIFtjbGFzcy5pcy1kYW5nZXJdPVwicm93LmNvbnRleHQgJiYgcm93LmNvbnRleHQgPT09IENvbnRleHQuRGFuZ2VyXCJcclxuICAgICAgW2NsYXNzLmlzLXdhcm5pbmddPVwicm93LmNvbnRleHQgJiYgcm93LmNvbnRleHQgPT09IENvbnRleHQuV2FybmluZ1wiXHJcbiAgICAgIFtjbGFzcy5pcy1pbmZvXT1cInJvdy5jb250ZXh0ICYmIHJvdy5jb250ZXh0ID09PSBDb250ZXh0LkluZm9cIlxyXG4gICAgICBbY2xhc3MuaXMtc3VjY2Vzc109XCJyb3cuY29udGV4dCAmJiByb3cuY29udGV4dCA9PT0gQ29udGV4dC5TdWNjZXNzXCJcclxuICAgICAgW2NsYXNzLmhhcy1zdHJpcGUtZGFuZ2VyXT1cInJvdy5zdHJpcGVDb250ZXh0ICYmIHJvdy5zdHJpcGVDb250ZXh0ID09PSBDb250ZXh0LkRhbmdlclwiXHJcbiAgICAgIFtjbGFzcy5oYXMtc3RyaXBlLXdhcm5pbmddPVwicm93LnN0cmlwZUNvbnRleHQgJiYgcm93LnN0cmlwZUNvbnRleHQgPT09IENvbnRleHQuV2FybmluZ1wiXHJcbiAgICAgIFtjbGFzcy5oYXMtc3RyaXBlLWluZm9dPVwicm93LnN0cmlwZUNvbnRleHQgJiYgcm93LnN0cmlwZUNvbnRleHQgPT09IENvbnRleHQuSW5mb1wiXHJcbiAgICAgIFtjbGFzcy5oYXMtc3RyaXBlLXN1Y2Nlc3NdPVwicm93LnN0cmlwZUNvbnRleHQgJiYgcm93LnN0cmlwZUNvbnRleHQgPT09IENvbnRleHQuU3VjY2Vzc1wiXHJcbiAgICAgIFtuZ0NsYXNzXT1cIltyb3cuY3NzQ2xhc3M/IHJvdy5jc3NDbGFzcyA6ICcnXVwiXHJcbiAgICAgIFthdHRyLnRpdGxlXT1cInJvdy50aXRsZSA/IHJvdy50aXRsZSA6ICcnXCI+XHJcbiAgICA8dGQgKm5nRm9yPVwibGV0IGNvbCBvZiBjb2x1bW5zXCIgY2xhc3M9XCJ7e2NvbC5jc3NDbGFzc319IHRhYnVsYXJfX3t7Y29sLmxhYmVsfX1cIiBbbmdDbGFzc109XCJ7J3RhYnVsYXJfX2NoZWNrYm94ZXMnOiBjb2wuZGF0YVR5cGUgPT09IFRhYnVsYXJDb2x1bW5UeXBlcy5DaGVja2JveH1cIj5cclxuXHJcbiAgICAgIDwhLS0gY2hlY2tib3ggdHlwZSAtLT5cclxuICAgICAgPGRpdiAqbmdJZj1cImNvbC5kYXRhVHlwZSA9PT0gVGFidWxhckNvbHVtblR5cGVzLkNoZWNrYm94XCIgY2xhc3M9XCJoeC1jaGVja2JveC1jb250cm9sXCI+XHJcbiAgICAgICAgPGlucHV0IGlkPVwiY2hlY2tib3gte3tyb3cuaWR9fVwiIG5hbWU9XCJ7e2NvbC5sYWJlbH19LWNoZWNrYm94XCIgdHlwZT1cImNoZWNrYm94XCIgY2xhc3M9XCJoeC1jaGVja2JveFwiIHRpdGxlPVwie3tjb2wubGFiZWx9fVwiIChjaGFuZ2UpPVwidG9nZ2xlSW5kaXZpZHVhbFNlbGVjdCgkZXZlbnQpXCIgWyhuZ01vZGVsKV09XCJyb3cuY2hlY2tlZFwiIC8+XHJcbiAgICAgICAgPGxhYmVsIGZvcj1cImNoZWNrYm94LXt7cm93LmlkfX1cIiBjbGFzcz1cImh4LWxhYmVsXCI+PC9sYWJlbD5cclxuICAgICAgPC9kaXY+XHJcblxyXG4gICAgICA8IS0tIHN0cmluZyB0eXBlIHwgbnVtYmVyIHR5cGUgLS0+XHJcbiAgICAgIDxzcGFuICpuZ0lmPVwiY29sLmRhdGFUeXBlID09PSBUYWJ1bGFyQ29sdW1uVHlwZXMuU3RyaW5nIHx8IGNvbC5kYXRhVHlwZSA9PT0gVGFidWxhckNvbHVtblR5cGVzLk51bWJlclwiIHRpdGxlPVwie3tyb3dbY29sLmlkXX19XCI+e3tyb3dbY29sLmlkXX19PC9zcGFuPlxyXG5cclxuICAgICAgPCEtLSBpY29uIHR5cGUgLS0+XHJcbiAgICAgIDxpICpuZ0lmPVwiY29sLmRhdGFUeXBlID09PSBUYWJ1bGFyQ29sdW1uVHlwZXMuSWNvbiAmJiBoYXNWYWxpZEljb25UeXBlUGFyYW1zKHJvd1tjb2wuaWRdKVwiIHRpdGxlPVwiXCIgY2xhc3M9XCJoeC1pY29uIHt7cm93W2NvbC5pZF0uaWNvbn19XCIgW2h4VG9vbHRpcF09XCJyb3dbY29sLmlkXS50b29sdGlwLmNvbnRlbnRcIiBwbGFjZW1lbnQ9XCJ7e3Jvd1tjb2wuaWRdLnRvb2x0aXAuY29uZmlnLnBsYWNlbWVudH19XCIgW2NvbnRleHRdPVwicm93W2NvbC5pZF0udG9vbHRpcC5jb25maWcuY29udGV4dFwiPjwvaT5cclxuXHJcbiAgICAgIDwhLS0gZGF0ZSB0eXBlIC0tPlxyXG4gICAgICA8c3BhbiAqbmdJZj1cImNvbC5kYXRhVHlwZSA9PT0gVGFidWxhckNvbHVtblR5cGVzLkRhdGVcIj57e3Jvd1tjb2wuaWRdIHwgZGF0ZTonZC9NL3l5J319PC9zcGFuPlxyXG5cclxuICAgICAgPCEtLSBzdGF0dXMgdHlwZSAtLT5cclxuICAgICAgPHNwYW4gKm5nSWY9XCJjb2wuZGF0YVR5cGUgPT09IFRhYnVsYXJDb2x1bW5UeXBlcy5TdGF0dXNcIiBjbGFzcz1cImh4LWljb25cIiBbbmdDbGFzc109XCJ7J2lzLXByaW1hcnknOnJvd1tjb2wuaWRdLCdpcy1kYW5nZXInOiFyb3dbY29sLmlkXSwgJ2ljb24tY2hlY2stZW1wdHknOiByb3dbY29sLmlkXSwgJ2ljb24tY2xvc2UtZW1wdHknOiFyb3dbY29sLmlkXX1cIiA+PC9zcGFuPlxyXG5cclxuICAgICAgPCEtLSBiYWRnZSB0eXBlIC0tPlxyXG4gICAgICA8c3BhbiAqbmdJZj1cImNvbC5kYXRhVHlwZSA9PT0gVGFidWxhckNvbHVtblR5cGVzLkJhZGdlICYmIGhhc1ZhbGlkQmFkZ2VUeXBlUGFyYW1zKHJvd1tjb2wuaWRdKVwiIGNsYXNzPVwiaHgtYmFkZ2UgaXMtc21hbGwge3tyb3dbY29sLmlkXS5jc3NDbGFzc319XCI+PHNwYW4gY2xhc3M9XCJoeC1iYWRnZS1jb250ZW50XCI+e3tyb3dbY29sLmlkXS5sYWJlbH19PC9zcGFuPjwvc3Bhbj5cclxuXHJcbiAgICAgIDwhLS0gZGF0ZSB0aW1lIHR5cGUgLS0+XHJcbiAgICAgIDxzcGFuICpuZ0lmPVwiY29sLmRhdGFUeXBlID09PSBUYWJ1bGFyQ29sdW1uVHlwZXMuRGF0ZVRpbWVcIj57e3Jvd1tjb2wuaWRdIHwgZGF0ZTonZC9NL3l5IGg6bW0gYSd9fTwvc3Bhbj5cclxuXHJcbiAgICAgIDwhLS0gYWN0aW9ucyB0eXBlIC0tPlxyXG4gICAgICA8ZGl2ICpuZ0lmPVwiY29sLmRhdGFUeXBlID09PSBUYWJ1bGFyQ29sdW1uVHlwZXMuQWN0aW9uc1wiIGNsYXNzPVwiaHgtZHJvcGRvd24gdGFidWxhckFjdGlvbnNcIj5cclxuXHJcblxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJ0YWJ1bGFyQWN0aW9uc19fYWN0aW9uXCI+XHJcblxyXG4gICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgYWN0aW9uIG9mIHJvd1tjb2wuaWRdO3RyYWNrQnk6IHRyYWNrQnlGblwiPlxyXG5cclxuICAgICAgICAgICAgPCEtLSBzaW5nbGUgYWN0aW9uIC0tPlxyXG4gICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImh4LWJ1dHRvbiBpcy1mbGF0XCIgW2NsYXNzLmlzLXNtYWxsXT1cImNvbmZpZy5zaXplID09PSBUYWJ1bGFyU2l6ZS5TbWFsbFwiXHJcbiAgICAgICAgICAgICAgICAgICAgKm5nSWY9XCIhZ2V0QWN0aW9uRGlzYWJsZWRTdGF0ZShhY3Rpb24pICYmIGFjdGlvbi5yb3V0ZVR5cGUgPT09IEFjdGlvbkNvbmZpZ1JvdXRlVHlwZS5Sb3V0ZSAmJiAhaGFzQ2hpbGRyZW4oYWN0aW9uKVwiXHJcbiAgICAgICAgICAgICAgICAgICAgW3JvdXRlckxpbmtdPVwiYWN0aW9uLnJvdXRlXCJcclxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cImh4LWJ1dHRvbiBpcy1mbGF0IHt7YWN0aW9uLmNzc319XCJcclxuICAgICAgICAgICAgICAgICAgICB0aXRsZT1cInt7YWN0aW9uLmxhYmVsfX1cIj48c3BhbiBjbGFzcz1cImh4LWljb24ge3thY3Rpb24uaWNvbn19XCI+PC9zcGFuPjwvYnV0dG9uPlxyXG4gICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImh4LWJ1dHRvbiBpcy1mbGF0XCIgW2NsYXNzLmlzLXNtYWxsXT1cImNvbmZpZy5zaXplID09PSBUYWJ1bGFyU2l6ZS5TbWFsbFwiXHJcbiAgICAgICAgICAgICAgICAgICAgKm5nSWY9XCIhZ2V0QWN0aW9uRGlzYWJsZWRTdGF0ZShhY3Rpb24pICYmIGFjdGlvbi5yb3V0ZVR5cGUgPT09IEFjdGlvbkNvbmZpZ1JvdXRlVHlwZS5DYWxsYmFjayAmJiAhaGFzQ2hpbGRyZW4oYWN0aW9uKVwiXHJcbiAgICAgICAgICAgICAgICAgICAoY2xpY2spPSdleGVjdXRlQ2FsbGJhY2soJGV2ZW50LGFjdGlvbi5jYWxsYmFjayknXHJcbiAgICAgICAgICAgICAgICAgICBjbGFzcz1cImh4LWJ1dHRvbiBpcy1mbGF0IHt7YWN0aW9uLmNzc319XCI+PHNwYW4gY2xhc3M9XCJoeC1pY29uIHt7YWN0aW9uLmljb259fVwiPjwvc3Bhbj48L2J1dHRvbj5cclxuXHJcbiAgICAgICAgICAgIDwhLS0gYWN0aW9uIHdpdGggY2hpbGRyZW4gLS0+XHJcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJoeC1kcm9wZG93blwiIGh4RHJvcGRvd24gW2lzUmlnaHRdPVwidHJ1ZVwiICpuZ0lmPVwiaGFzQ2hpbGRyZW4oYWN0aW9uKVwiPlxyXG5cclxuICAgICAgICAgICAgICA8YnV0dG9uIGNsYXNzPVwiaHgtYnV0dG9uIGlzLWZsYXQgaHgtYnV0dG9uLWRyb3Bkb3duXCIgW2NsYXNzLmlzLXNtYWxsXT1cImNvbmZpZy5zaXplID09PSBUYWJ1bGFyU2l6ZS5TbWFsbFwiIGh4RHJvcGRvd25Ub2dnbGUgdHlwZT1cImJ1dHRvblwiPlxyXG4gICAgICAgICAgICAgICAgPGkgY2xhc3M9XCJpY29uIHt7YWN0aW9uLmljb259fVwiPjwvaT5cclxuICAgICAgICAgICAgICA8L2J1dHRvbj5cclxuXHJcbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImh4LWRyb3Bkb3duLW1lbnVcIiAqaHhEcm9wZG93bk1lbnU+XHJcblxyXG4gICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdGb3I9XCJsZXQgY2hpbGRBY3Rpb24gb2YgYWN0aW9uLmNoaWxkcmVuO3RyYWNrQnk6IHRyYWNrQnlGblwiPlxyXG4gICAgICAgICAgICAgICAgICA8YSAqbmdJZj1cIiFnZXRBY3Rpb25EaXNhYmxlZFN0YXRlKGNoaWxkQWN0aW9uKSAmJiBjaGlsZEFjdGlvbi5yb3V0ZVR5cGUgPT09IEFjdGlvbkNvbmZpZ1JvdXRlVHlwZS5Sb3V0ZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgIFtyb3V0ZXJMaW5rXT1cImNoaWxkQWN0aW9uLnJvdXRlXCJcclxuICAgICAgICAgICAgICAgICAgICAgY2xhc3M9XCJoeC1kcm9wZG93bi1pdGVtIHt7Y2hpbGRBY3Rpb24uY3NzfX1cIj57e2NoaWxkQWN0aW9uLmxhYmVsfX08L2E+XHJcbiAgICAgICAgICAgICAgICAgIDxhICpuZ0lmPVwiIWdldEFjdGlvbkRpc2FibGVkU3RhdGUoY2hpbGRBY3Rpb24pICYmIGNoaWxkQWN0aW9uLnJvdXRlVHlwZSA9PT0gQWN0aW9uQ29uZmlnUm91dGVUeXBlLkNhbGxiYWNrXCJcclxuICAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT0nZXhlY3V0ZUNhbGxiYWNrKCRldmVudCxjaGlsZEFjdGlvbi5jYWxsYmFjayknXHJcbiAgICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiaHgtZHJvcGRvd24taXRlbSB7e2NoaWxkQWN0aW9uLmNzc319XCI+e3tjaGlsZEFjdGlvbi5sYWJlbH19PC9hPlxyXG4gICAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XHJcblxyXG4gICAgICAgICAgICAgIDwvZGl2PlxyXG5cclxuICAgICAgICAgICAgPC9kaXY+XHJcblxyXG4gICAgICAgICAgPC9uZy1jb250YWluZXI+XHJcblxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICA8L2Rpdj5cclxuXHJcbiAgICA8L3RkPlxyXG4gIDwvdHI+XHJcbiAgPC90Ym9keT5cclxuPC90YWJsZT5cclxuXHJcbjxoeC1wYWdpbmF0aW9uIFtkaXJlY3Rpb25MaW5rc109XCJ0cnVlXCIgW2JvdW5kYXJ5TGlua3NdPVwidHJ1ZVwiIFtyb3RhdGVdPVwiZmFsc2VcIiBbbWF4U2l6ZV09XCIxMFwiXHJcbiAgICAgICAgICAgICAgIFt0b3RhbEl0ZW1zXT1cInRvdGFsSXRlbUNvdW50XCIgW2l0ZW1zUGVyUGFnZV09XCJjb25maWcucGFnaW5hdGlvbi5pdGVtc1BlclBhZ2VcIlxyXG4gICAgICAgICAgICAgICBbKG5nTW9kZWwpXT1cImNvbmZpZy5wYWdpbmF0aW9uLmN1cnJlbnRQYWdlXCIgKHBhZ2VDaGFuZ2VkKT1cInNldFBhZ2UoJGV2ZW50KVwiICpuZ0lmPVwidG90YWxJdGVtQ291bnQgPiBjb25maWcucGFnaW5hdGlvbi5pdGVtc1BlclBhZ2VcIj48L2h4LXBhZ2luYXRpb24+XHJcbmAsXHJcbiAgc3R5bGVzOiBbXHJcbiAgICAnLnRhYnVsYXJfX3NvcnRhYmxlIHt9JyxcclxuICAgICcudGFidWxhcl9fc29ydGVyIHtjdXJzb3I6cG9pbnRlcjsgZGlzcGxheTpmbGV4OyBhbGlnbi1pdGVtczogY2VudGVyO30nLFxyXG4gICAgJy50YWJ1bGFyX19zb3J0ZXIgLmh4LWljb24ge21hcmdpbi1sZWZ0Oi4xcmVtO30nLFxyXG4gICAgJy50YWJ1bGFyX19jaGVja2JveGVze3dpZHRoOjIlO30nLFxyXG4gICAgJy50YWJ1bGFyX19jaGVja2JveGVzIC5oeC1jaGVja2JveC1jb250cm9se2Rpc3BsYXk6ZmxleDt9JyxcclxuICAgICcudGFidWxhckFjdGlvbnNfX2FjdGlvbiBidXR0b24uaHgtYnV0dG9ueyB3aWR0aDogMXJlbTt9JyxcclxuICAgICcudGFidWxhckFjdGlvbnNfX2FjdGlvbiB7ZGlzcGxheTpmbGV4O30nXHJcbiAgXVxyXG59KVxyXG5cclxuXHJcbmV4cG9ydCBjbGFzcyBUYWJ1bGFyQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBEb0NoZWNrIHtcclxuXHJcbiAgLyoqXHJcbiAgICogQ29sbGVjdGlvbiBvZiBjb2x1bW4gbW9kZWxzXHJcbiAgICovXHJcbiAgQElucHV0KCkgY29sdW1uczogVGFidWxhckNvbHVtbltdO1xyXG5cclxuICAvKipcclxuICAgKiBDb2xsZWN0aW9uIG9mIGRhdGEgcm93c1xyXG4gICAqL1xyXG4gIC8vIHRvZG8gLSB0aGlzIGlzIG5vdCBzdHJpY3QuIHNob3VsZCBpdCBiZSB3aGVuIGl0J3MgZHluYW1pYz8uXHJcbiAgIEBJbnB1dCgpIHJvd3M6IElUYWJ1bGFyUm93W107XHJcblxyXG4gIC8qKlxyXG4gICAqIFRhYnVsYXIgY29uZmlndXJhdGlvblxyXG4gICAqIElQYWdpbmF0aW9uSW5zdGFuY2UsIElTZWFyY2hDb25maWdcclxuICAgKi9cclxuICBASW5wdXQoKVxyXG4gIHB1YmxpYyBnZXQgY29uZmlnKCk6IElUYWJ1bGFyQ29uZmlnICB7XHJcbiAgICByZXR1cm4gdGhpcy5fY29uZmlnO1xyXG4gIH1cclxuICBwdWJsaWMgc2V0IGNvbmZpZyhjOiBJVGFidWxhckNvbmZpZykgIHtcclxuICAgIGlmICghYy5zb3J0QnkpIHtcclxuICAgICAgYy5zb3J0QnkgPSBbXTtcclxuICAgIH1cclxuICAgIHRoaXMuX2NvbmZpZyA9IGM7XHJcbiAgfVxyXG5cclxuICAvKiogVGhlIGZ1bmN0aW9uIHRvIGNhbGwgd2hlbiBhIGFjdGlvbiBpdGVtIGlzIGNsaWNrZWQgKiovXHJcbiAgQElucHV0KClcclxuICBwdWJsaWMgZ2V0IGNhbGxiYWNrKCk6IEZ1bmN0aW9ue1xyXG4gICAgcmV0dXJuIHRoaXMuX2NhbGxiYWNrO1xyXG4gIH1cclxuICBwdWJsaWMgc2V0IGNhbGxiYWNrKEZuOiBGdW5jdGlvbil7XHJcbiAgICB0aGlzLl9jYWxsYmFjayA9IEZuO1xyXG4gIH1cclxuXHJcblxyXG4gIC8qKlxyXG4gICAqIFNlYXJjaCB0ZXJtIGlzIHVzZWQgaW4gdGhlIHNpbXBsZSBzZWFyY2ggcGlwZVxyXG4gICAqIEFycmF5IG9mIG9iamVjdHM6ICpuZ0Zvcj1cIiNyb3cgb2Ygcm93cyB8IHNpbXBsZVNlYXJjaCA6ICd0aGUgc2VhcmNoIHRlcm0nXCJcclxuICAgKi9cclxuICBASW5wdXQoKVxyXG4gIHB1YmxpYyBnZXQgc2VhcmNoVGVybSgpOiBzdHJpbmd7XHJcbiAgICByZXR1cm4gdGhpcy5fc2VhcmNoVGVybTtcclxuICB9XHJcbiAgcHVibGljIHNldCBzZWFyY2hUZXJtKHRlcm06IHN0cmluZyl7XHJcbiAgICB0aGlzLl9zZWFyY2hUZXJtID0gdGVybTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEV2ZW50IGZpcmVkIHdoZW4gcmVmcmVzaCBpcyBjYWxsZWQuXHJcbiAgICogSG9zdCBzaG91bGQgcmVmcmVzaCBkYXRhIG9mIGlucHV0LlxyXG4gICAqL1xyXG4gIEBPdXRwdXQoKSByZWZyZXNoOiBFdmVudEVtaXR0ZXI8Ym9vbGVhbj4gPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEV2ZW50IGZpcmVkIHdoZW4gYSByb3cgaXMgY2xpY2tlZC5cclxuICAgKi9cclxuICBAT3V0cHV0KCkgcm93Q2xpY2s6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XHJcblxyXG4gIHB1YmxpYyBvbGRSb3dzOiBJVGFidWxhclJvd1tdID0gW107XHJcbiAgcHVibGljIHBhZ2VkSXRlbXM6IGFueVtdID0gW107XHJcbiAgcHVibGljIFRhYnVsYXJDb2x1bW5UeXBlcyA9IFRhYnVsYXJDb2x1bW5UeXBlcztcclxuICBwdWJsaWMgVGFidWxhclNpemUgPSBUYWJ1bGFyU2l6ZTtcclxuICBwdWJsaWMgQWN0aW9uQ29uZmlnUm91dGVUeXBlID0gQWN0aW9uQ29uZmlnUm91dGVUeXBlO1xyXG4gIHB1YmxpYyBzZWxlY3RBbGwgPSBmYWxzZTtcclxuICBwdWJsaWMgQ29udGV4dCA9IENvbnRleHQ7XHJcbiAgcHVibGljIFNvcnRCeURpcmVjdGlvbiA9IFNvcnRCeURpcmVjdGlvbjtcclxuICBwcm90ZWN0ZWQgX2NhbGxiYWNrOiBGdW5jdGlvbjtcclxuICBwcm90ZWN0ZWQgX2NvbmZpZzogSVRhYnVsYXJDb25maWc7XHJcbiAgcHJvdGVjdGVkIF9zZWFyY2hUZXJtOiBzdHJpbmc7XHJcblxyXG5cclxuICAgY29uc3RydWN0b3IoXHJcbiAgICBwcml2YXRlIGNvbmY6IFRhYnVsYXJDb25maWcsXHJcbiAgICBwcml2YXRlIHNvcnRCeVNlcnZpY2U6IFRhYnVsYXJTb3J0QnlTZXJ2aWNlXHJcbiAgKSB7XHJcbiAgICBPYmplY3QuYXNzaWduKHRoaXMsIGNvbmYpO1xyXG4gIH1cclxuXHJcbiAgbmdPbkluaXQoKSB7XHJcblxyXG4gIH1cclxuXHJcbiAgbmdEb0NoZWNrKCkge1xyXG4gICAgaWYgKCFfLmlzRXF1YWwodGhpcy5yb3dzLCB0aGlzLm9sZFJvd3MpKSB7XHJcbiAgICAgIHRoaXMub2xkUm93cyA9IF8uY2xvbmVEZWVwKHRoaXMucm93cyk7XHJcbiAgICAgIHRoaXMub3JkZXJCeURhdGEoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENhbGxzIHRoZSBwYXJzZWQgY2FsbGJhY2sgd2l0aCBvcHRpb25hbCBhcmd1bWVudHNcclxuICAgKi9cclxuICAgZXhlY3V0ZUNhbGxiYWNrKGV2ZW50OiBFdmVudCwgY2I6IGFueVtdKSB7XHJcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgIGlmIChjYi5sZW5ndGgpIHtcclxuICAgICAgaWYgKGNiLmxlbmd0aCA9PT0gMSkgeyAvLyBpZiBjYWxsYmFjayBoYXMgbm8gYXJndW1lbnRzXHJcbiAgICAgICAgY2JbMF0oKTtcclxuICAgICAgfSBlbHNlIHsgLy8gaWYgY2FsbGJhY2sgaGFzIDEgb3IgbW9yZSBhcmd1bWVudHNcclxuICAgICAgICBjb25zdCBhcmdzOiBhbnlbXSA9IFtdO1xyXG4gICAgICAgIGZvciAobGV0IGkgPSAxOyBpIDwgY2IubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgIGFyZ3MucHVzaChjYltpXSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNiWzBdLmFwcGx5KHRoaXMsIGFyZ3MpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuXHJcbiAgIHRvZ2dsZVNlbGVjdEFsbCA9ICgkZXZlbnQpID0+IHtcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5yb3dzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIHRoaXMucm93c1tpXS5jaGVja2VkID0gdGhpcy5zZWxlY3RBbGw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuXHJcbiAgIHRvZ2dsZUluZGl2aWR1YWxTZWxlY3QgPSAoJGV2ZW50KSA9PiB7XHJcbiAgICBsZXQgY291bnQgPSAwO1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnJvd3MubGVuZ3RoOyBpKyspIHtcclxuICAgICAgaWYgKHRoaXMucm93c1tpXS5jaGVja2VkKSB7XHJcbiAgICAgICAgY291bnQrKztcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgdGhpcy5zZWxlY3RBbGwgPSAodGhpcy5yb3dzLmxlbmd0aCA9PT0gY291bnQpO1xyXG4gIH1cclxuXHJcblxyXG4gIHNldFBhZ2UoJGV2ZW50OiB7cGFnZTogbnVtYmVyLCBpdGVtc1BlclBhZ2U6IG51bWJlcn0gPSB7XHJcbiAgICBwYWdlOiB0aGlzLmNvbmZpZy5wYWdpbmF0aW9uLmN1cnJlbnRQYWdlLFxyXG4gICAgaXRlbXNQZXJQYWdlOiB0aGlzLmNvbmZpZy5wYWdpbmF0aW9uLml0ZW1zUGVyUGFnZVxyXG4gIH0pIHtcclxuICAgIHRoaXMuY29uZmlnLnBhZ2luYXRpb24uY3VycmVudFBhZ2UgPSAkZXZlbnQucGFnZTtcclxuXHJcbiAgICAvLyBjYWxjdWxhdGUgc3RhcnQgYW5kIGVuZCBwYWdlIGl0ZW0gaW5kZXhlc1xyXG4gICAgY29uc3Qgc3RhcnRJbmRleDogbnVtYmVyID0gKHRoaXMuY29uZmlnLnBhZ2luYXRpb24uY3VycmVudFBhZ2UgLSAxKSAqIHRoaXMuY29uZmlnLnBhZ2luYXRpb24uaXRlbXNQZXJQYWdlO1xyXG4gICAgY29uc3QgZW5kSW5kZXg6IG51bWJlciA9IE1hdGgubWluKHN0YXJ0SW5kZXggKyB0aGlzLmNvbmZpZy5wYWdpbmF0aW9uLml0ZW1zUGVyUGFnZSAtIDEsIHRoaXMudG90YWxJdGVtQ291bnQgLSAxKTtcclxuXHJcbiAgICB0aGlzLnBhZ2VkSXRlbXMgPSB0aGlzLnJvd3Muc2xpY2Uoc3RhcnRJbmRleCwgZW5kSW5kZXggKyAxKTtcclxuICB9XHJcblxyXG5cclxuICAvKipcclxuICAgKiBHZXQgdGhlIGFjdGlvbiB0b29sdGlwIGlmIGl0IGV4aXN0c1xyXG4gICAqL1xyXG4gIGdldEFjdGlvblRvb2x0aXAoYWN0aW9uOiBJQWN0aW9uc0NvbmZpZyk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gKGFjdGlvbiAmJiBhY3Rpb24uZGlzYWJsZWRDb25maWcpID8gYWN0aW9uLmRpc2FibGVkQ29uZmlnLnRvb2x0aXAgOiAnJztcclxuICB9XHJcblxyXG5cclxuICBnZXRBY3Rpb25EaXNhYmxlZFN0YXRlKGFjdGlvbjogSUFjdGlvbnNDb25maWcpOiBib29sZWFuIHtcclxuICAgIHJldHVybiAoYWN0aW9uICYmIGFjdGlvbi5kaXNhYmxlZENvbmZpZykgPyBhY3Rpb24uZGlzYWJsZWRDb25maWcuZGlzYWJsZWQgOiBmYWxzZTtcclxuICB9XHJcblxyXG5cclxuICAvKipcclxuICAgKiBIYW5kbGVzIHRoZSBjb2x1bW4gaGVhZGVyIGNsaWNrIGV2ZW50IGZvciBzb3J0aW5nLlxyXG4gICAqIFNvcnQgb3JkZXIgaXMgRGVzY2VuZGluZywgQXNjZW5kaW5nIGZvbGxvd2VkIGJ5IE5vbmUuXHJcbiAgICovXHJcbiAgb25Tb3J0Q2xpY2tIYW5kbGVyKGtleTogc3RyaW5nLCB0eXBlOiBUYWJ1bGFyQ29sdW1uVHlwZXMpIHtcclxuXHJcbiAgICBjb25zdCBmaW5kUHJvcEluU29ydExpc3QgPSB0aGlzLmNvbmZpZy5zb3J0QnkuZmlsdGVyKChwcm9wOiBJU29ydEJ5UHJvcGVydHkpID0+IHsgcmV0dXJuIChwcm9wLnByb3BlcnR5ID09PSBrZXkpOyB9KTtcclxuXHJcbiAgICBpZiAoZmluZFByb3BJblNvcnRMaXN0Lmxlbmd0aCkge1xyXG4gICAgICBjb25zdCBwcm9wID0gZmluZFByb3BJblNvcnRMaXN0WzBdO1xyXG4gICAgICBjb25zdCBpbmRleCA9IHRoaXMuY29uZmlnLnNvcnRCeS5maW5kSW5kZXgoeCA9PiB4ID09PSBwcm9wKTtcclxuICAgICAgaWYgKHByb3AuZGlyZWN0aW9uID09PSBTb3J0QnlEaXJlY3Rpb24uTm9uZSkge1xyXG4gICAgICAgIHByb3AuZGlyZWN0aW9uID0gU29ydEJ5RGlyZWN0aW9uLkRlc2NlbmRpbmc7XHJcbiAgICAgIH0gZWxzZSBpZiAocHJvcC5kaXJlY3Rpb24gPT09IFNvcnRCeURpcmVjdGlvbi5EZXNjZW5kaW5nKSB7XHJcbiAgICAgICAgcHJvcC5kaXJlY3Rpb24gPSBTb3J0QnlEaXJlY3Rpb24uQXNjZW5kaW5nO1xyXG4gICAgICB9ICBlbHNlIGlmIChwcm9wLmRpcmVjdGlvbiA9PT0gU29ydEJ5RGlyZWN0aW9uLkFzY2VuZGluZykge1xyXG4gICAgICAgIGlmIChpbmRleCA+IC0xKSB7XHJcbiAgICAgICAgICB0aGlzLmNvbmZpZy5zb3J0Qnkuc3BsaWNlKGluZGV4LCAxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuY29uZmlnLnNvcnRCeS5wdXNoKHtwcm9wZXJ0eToga2V5LCBkaXJlY3Rpb246IFNvcnRCeURpcmVjdGlvbi5EZXNjZW5kaW5nLCB0eXBlOiB0eXBlfSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5vcmRlckJ5RGF0YSgpO1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcblxyXG4gIGlzQ29sdW1uU29ydGVkKGtleTogc3RyaW5nLCBkaXJlY3Rpb246IFNvcnRCeURpcmVjdGlvbik6IGJvb2xlYW4ge1xyXG4gICAgY29uc3QgZmluZFByb3BJblNvcnRMaXN0ID0gdGhpcy5jb25maWcuc29ydEJ5LmZpbHRlcigocHJvcDogSVNvcnRCeVByb3BlcnR5KSA9PiB7IHJldHVybiAocHJvcC5wcm9wZXJ0eSA9PT0ga2V5ICYmIHByb3AuZGlyZWN0aW9uID09PSBkaXJlY3Rpb24pOyB9KTtcclxuICAgIHJldHVybiAoZmluZFByb3BJblNvcnRMaXN0Lmxlbmd0aCA+IDApO1xyXG4gIH1cclxuXHJcblxyXG4gIC8qKlxyXG4gICAqIEhhbmRsZXMgdGhlIHJvdyBjbGljayBldmVudC5cclxuICAgKi9cclxuICBvblJvd0NsaWNrSGFuZGxlcigkZXZlbnQ6IGFueSwgZGF0YTogYW55KSB7XHJcbiAgICBjb25zdCBlbDogRWxlbWVudCA9ICRldmVudC50YXJnZXQ7XHJcbiAgICBpZiAodGhpcy5jb25maW