ngx-multi-selector
Version:
A small plugin which generates multi-selector control, it supports web api loading. Only supported angular 5.
620 lines • 68.1 kB
JavaScript
import * as tslib_1 from "tslib";
import { Component, ElementRef, Input, ViewChild, TemplateRef, forwardRef } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { EMPTY, of, ReplaySubject, timer } from 'rxjs';
import { debounce, distinctUntilChanged, map, switchMap } from 'rxjs/operators';
var NgxMultiSelectorComponent = /** @class */ (function () {
//#endregion
//#region Constructor
/*
* Initiate components with injectors (as available)
* */
function NgxMultiSelectorComponent() {
var _this = this;
//#region Properties
/*
* Delay time between 2 item search requests.
* */
this._defaultItemsInterval = 150;
/*
* Character which is used for separating selected items.
* Default: ,
* */
this._separationCharacter = ',';
/*
* Maximum items that can be displayed in context menu.
* */
this._maximumContextItems = 0;
/*
* How many items can be selected.
* */
this._maximumSelectableItems = 0;
/*
* How much time should component raise another one about its changes.
* */
this._loadItemsInterval = this._defaultItemsInterval;
this._selectedItems = [];
this.items = [];
// By default, items amount is limited to 10.
this._maximumSelectableItems = 10;
this._updateAvailableItemsSubject = new ReplaySubject(1);
this._updateAvailableItemsSubscription = this._updateAvailableItemsSubject
.pipe(debounce(function (command) {
if (command.shouldIgnoreInterval) {
return EMPTY;
}
return timer(_this._loadItemsInterval);
}), map(function (command) {
// Format keyword.
var keyword = _this._keyword;
if (keyword && keyword.length) {
keyword = keyword.trim();
}
return {
keyword: keyword,
command: command
};
}), distinctUntilChanged(function (previous, next) {
// Get current command.
var nextCommand = next.command;
if (!nextCommand.shouldIgnoreDuplicate) {
// Values are equal, it will not emit the current value
return previous.keyword === next.keyword;
}
// Values are different, so it will emit
return false;
}), switchMap(function (model) {
return _this.loadAvailableItemsAsync(model.keyword);
}))
.subscribe(function (availableItems) {
_this._availableItems = tslib_1.__spread(availableItems);
});
}
NgxMultiSelectorComponent_1 = NgxMultiSelectorComponent;
Object.defineProperty(NgxMultiSelectorComponent.prototype, "keyword", {
//#endregion
//#region Accessors
/*
* Keyword is used for searching for items.
* */
get: function () {
return this._keyword;
},
/*
* Keyword is used for searching for items.
* */
set: function (value) {
this._keyword = value;
// Initialize control update command.
var command = {
shouldIgnoreDuplicate: false,
shouldIgnoreInterval: false
};
this._updateAvailableItemsSubject
.next(command);
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMultiSelectorComponent.prototype, "separationCharacter", {
/*
* Character which is used for dividing searched items.
* */
set: function (value) {
if (!value || !value.length) {
this._separationCharacter = ',';
return;
}
this._separationCharacter = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMultiSelectorComponent.prototype, "selectedItems", {
/*
* Items which have been selected.
* */
get: function () {
return this._selectedItems;
},
/*
* Get selected items.
* */
set: function (values) {
if (!values || values.length < 0) {
this._selectedItems = [];
return;
}
this._selectedItems = values;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMultiSelectorComponent.prototype, "interval", {
/*
* How much time should component raise another one about its changes.
* */
set: function (value) {
if (value < this._defaultItemsInterval) {
this._loadItemsInterval = this._defaultItemsInterval;
return;
}
this._loadItemsInterval = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMultiSelectorComponent.prototype, "items", {
/*
* Get available items for displaying in drop-down list.
* */
get: function () {
return this._availableItems;
},
/*
* List of item which should be displayed on drop-down menu.
* */
set: function (values) {
if (this.loadAvailableItemsAsyncHandler && this._updateAvailableItemsSubject) {
this._updateAvailableItemsSubject.next(null);
return;
}
if (!values || !values.length || !(values instanceof Array)) {
this._originalItems = [];
this._availableItems = [];
return;
}
this._originalItems = values;
this._availableItems = values;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMultiSelectorComponent.prototype, "maximumContextItem", {
/*
* Get the maximum items that can be displayed in context menu.
* */
get: function () {
return this._maximumContextItems;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMultiSelectorComponent.prototype, "maximumContextItems", {
/*
* How many items should be shown to be selected.
* */
set: function (maximumItems) {
if (maximumItems < 0) {
maximumItems = 0;
}
this._maximumContextItems = maximumItems;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMultiSelectorComponent.prototype, "maximumSelectableItems", {
/*
* Get maximum selectable items.
* */
get: function () {
return this._maximumSelectableItems;
},
/*
* Update the maximum selectable items.
* */
set: function (value) {
if (value < 0 || isNaN(value)) {
this._maximumSelectableItems = 0;
return;
}
this._maximumSelectableItems = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMultiSelectorComponent.prototype, "key", {
/*
* @deprecated
* Please consider using key-property instead.
* Key which is for recognizing whether item is in the chosen list or not.
* */
set: function (value) {
this._key = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMultiSelectorComponent.prototype, "keyProperty", {
/*
* Please consider using key-property instead.
* Key which is for recognizing whether item is in the chosen list or not.
* */
set: function (value) {
this._key = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMultiSelectorComponent.prototype, "displayProperty", {
/*
* Which property should be used as display.
* Null is about using object as display.
* */
set: function (value) {
this._displayProperty = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(NgxMultiSelectorComponent.prototype, "valueProperty", {
/*
* Which property should be used as selected value.
* Null is about using object as selected value.
* */
set: function (value) {
this._valueProperty = value;
},
enumerable: true,
configurable: true
});
//#endregion
//#region Methods
NgxMultiSelectorComponent.prototype.ngOnDestroy = function () {
if (this._updateAvailableItemsSubscription && !this._updateAvailableItemsSubscription.closed) {
this._updateAvailableItemsSubscription.unsubscribe();
}
};
/*
* Check whether item has been chosen or not.
* */
NgxMultiSelectorComponent.prototype.hasItemSelected = function (item) {
return this.loadSelectedItemIndex(item) != -1;
};
/*
* Find chosen item index in array.
* */
NgxMultiSelectorComponent.prototype.loadSelectedItemIndex = function (item) {
var _this = this;
// Items list is empty.
if (this._selectedItems == null || this._selectedItems.length < 1) {
return -1;
}
// Get item index.
var itemIndex = this._selectedItems.findIndex(function (selectedItem) { return _this.loadItemUniqueValue(selectedItem) === _this.loadItemUniqueValue(item); });
return itemIndex;
};
/*
* Get title which is used for being displayed on search box.
* */
NgxMultiSelectorComponent.prototype.loadSelectedItemsTitle = function () {
var _this = this;
if (this.selectedItems == null || this.selectedItems.length < 1) {
return '';
}
// Find separation character.
var separationCharacter = this._separationCharacter;
if (!separationCharacter) {
separationCharacter = ',';
}
return this.selectedItems
.map(function (selectedItem) { return _this.loadItemDisplay(selectedItem); })
.join(separationCharacter)
.slice(0, 255);
};
/*
* Clear chosen items list.
* */
NgxMultiSelectorComponent.prototype.deleteSelectedItems = function (shouldRaiseOnChangeCallback) {
// Initiate new array.
this.selectedItems = new Array();
if (shouldRaiseOnChangeCallback) {
this.ngOnChangeCallback(this.selectedItems);
}
};
/*
* Find selected value and delete it.
* */
NgxMultiSelectorComponent.prototype.deleteSelectedValue = function (value) {
var _this = this;
// Get index of value.
if (!this.selectedItems || !this.selectedItems.length) {
return;
}
var itemIndex = this.selectedItems.findIndex(function (selectedItem) { return _this.loadItemValue(selectedItem) == value; });
if (itemIndex < 0) {
return;
}
// Remove item from list.
var selectedValues = tslib_1.__spread(this.selectedItems);
selectedValues.splice(itemIndex, 1);
if (!selectedValues || !selectedValues.length) {
this.selectedItems = null;
this.ngOnChangeCallback(null);
}
else {
this.selectedItems = selectedValues;
this.ngOnChangeCallback(this.selectedItems.map(function (selectedItem) { return _this.loadItemValue(selectedItem); }));
}
};
/*
* Select an item in list.
* */
NgxMultiSelectorComponent.prototype.clickSelectItem = function (item) {
var _this = this;
// Enlist of selected items.
var selectedItems;
if (!this.selectedItems) {
selectedItems = [];
}
else {
selectedItems = tslib_1.__spread(this.selectedItems);
}
// Get item in the selected value.
var itemIndex = this.loadSelectedItemIndex(item);
// Item hasn't been chosen.
if (itemIndex == null || itemIndex < 0) {
// Maximum selected item exceeded.
if (this.maximumSelectableItems != null && (this.maximumSelectableItems > 0 && selectedItems.length >= this.maximumSelectableItems)) {
return;
}
// Get item value.
selectedItems.push(item);
this.selectedItems = selectedItems;
this.ngOnChangeCallback(selectedItems.map(function (selectedItem) { return _this.loadItemValue(selectedItem); }));
return;
}
selectedItems.splice(itemIndex, 1);
if (!selectedItems || !selectedItems.length) {
this.selectedItems = null;
this.ngOnChangeCallback(this.selectedItems);
}
else {
this.selectedItems = selectedItems;
this.ngOnChangeCallback(this.selectedItems);
}
};
/*
* Close drop-down menu.
* */
NgxMultiSelectorComponent.prototype.close = function () {
// Drop-down menu is invalid.
if (this.multiSelectorDropDown == null) {
return;
}
// Find drop-down native element.
var nativeElement = this.multiSelectorDropDown.nativeElement;
if (nativeElement == null) {
return;
}
// Remove class .open from classes list.
nativeElement.classList.remove('open');
};
/*
* Open drop-down menu.
* */
NgxMultiSelectorComponent.prototype.open = function () {
// Component has been disabled.
if (this.disabled) {
return;
}
// Drop-down menu is invalid.
if (this.multiSelectorDropDown == null) {
return;
}
// Find drop-down native element.
var nativeElement = this.multiSelectorDropDown.nativeElement;
if (nativeElement == null) {
return;
}
// Remove class .open from classes list.
this.multiSelectorDropDown.nativeElement.classList.add('open');
};
/*
* Callback which is fired when component receives information from external source.
* */
NgxMultiSelectorComponent.prototype.writeValue = function (selectedValues) {
// No value has been selected.
if (!selectedValues || !selectedValues.length) {
this.selectedItems = null;
return;
}
this.selectedItems = selectedValues;
};
/*
* Callback which is fired when on-change register has been initiated.
* */
NgxMultiSelectorComponent.prototype.registerOnChange = function (fn) {
this.ngOnChangeCallback = fn;
};
/*
* Callback which is fired when on-touch register has been initiated.
* */
NgxMultiSelectorComponent.prototype.registerOnTouched = function (fn) {
this.ngOnTouchedCallback = fn;
};
/*
* Set item to be disabled | enabled.
* */
NgxMultiSelectorComponent.prototype.setDisabledState = function (isDisabled) {
this.disabled = isDisabled;
};
/*
* Load available items asynchronously.
* This function will be used in offline mode.
* */
NgxMultiSelectorComponent.prototype.loadAvailableItemsAsync = function (keyword) {
var _this = this;
// Make the keyword to be upper cased.
var upperCasedKeyword = (keyword == null) ? null : keyword.toUpperCase();
// Get the handler.
var loadAvailableItemsAsyncHandler = this.loadAvailableItemsAsyncHandler;
// No handler is defined for remote data loading.
if (!loadAvailableItemsAsyncHandler) {
// Load available items locally.
return of(tslib_1.__spread(this._originalItems))
.pipe(map(function (items) {
if (!items || !items.length) {
return [];
}
return items
.filter(function (item) {
// Get the display property.
var itemDisplay = _this.loadItemDisplay(item);
if (!upperCasedKeyword) {
return items;
}
return itemDisplay.toString().toUpperCase().indexOf(upperCasedKeyword) !== -1;
});
}));
}
// Load available items remotely.
return this.loadAvailableItemsAsyncHandler(keyword);
};
/*
* Load item display.
* */
NgxMultiSelectorComponent.prototype.loadItemDisplay = function (item) {
// Get the display property.
var displayProperty = this._displayProperty;
if (!displayProperty || !displayProperty.length) {
return item.toString();
}
return item[displayProperty];
};
/*
* Load item value.
* */
NgxMultiSelectorComponent.prototype.loadItemValue = function (item) {
// Get defined key.
var valueProperty = this._valueProperty;
if (!valueProperty || !valueProperty.length) {
return item;
}
return item[valueProperty];
};
/*
* Base on key to get item unique value.
* */
NgxMultiSelectorComponent.prototype.loadItemUniqueValue = function (item) {
if (!item) {
return item;
}
// Get key.
var key = this._key;
if (!key || key.length < 1) {
return item;
}
return item[key];
};
NgxMultiSelectorComponent.prototype.ngOnInit = function () {
if (!this.loadAvailableItemsAsyncHandler) {
return;
}
if (!this._updateAvailableItemsSubject) {
return;
}
var updateControlCommand = {
shouldIgnoreDuplicate: true,
shouldIgnoreInterval: true
};
return this._updateAvailableItemsSubject.next(updateControlCommand);
};
var NgxMultiSelectorComponent_1;
tslib_1.__decorate([
Input('load-available-items-handler'),
tslib_1.__metadata("design:type", Function)
], NgxMultiSelectorComponent.prototype, "loadAvailableItemsAsyncHandler", void 0);
tslib_1.__decorate([
ViewChild('multiSelectorDropdownMenu', { static: false }),
tslib_1.__metadata("design:type", ElementRef)
], NgxMultiSelectorComponent.prototype, "multiSelectorDropDown", void 0);
tslib_1.__decorate([
Input('is-clear-button-available'),
tslib_1.__metadata("design:type", Boolean)
], NgxMultiSelectorComponent.prototype, "shouldClearButtonAvailable", void 0);
tslib_1.__decorate([
Input('is-search-box-available'),
tslib_1.__metadata("design:type", Boolean)
], NgxMultiSelectorComponent.prototype, "shouldSearchBoxAvailable", void 0);
tslib_1.__decorate([
Input('placeholder-search-drop-down'),
tslib_1.__metadata("design:type", String)
], NgxMultiSelectorComponent.prototype, "placeholderSearchDropDown", void 0);
tslib_1.__decorate([
Input('placeholder-title-drop-down'),
tslib_1.__metadata("design:type", String)
], NgxMultiSelectorComponent.prototype, "placeholderTitleDropDown", void 0);
tslib_1.__decorate([
Input('disabled'),
tslib_1.__metadata("design:type", Boolean)
], NgxMultiSelectorComponent.prototype, "disabled", void 0);
tslib_1.__decorate([
Input('item-template'),
tslib_1.__metadata("design:type", TemplateRef)
], NgxMultiSelectorComponent.prototype, "itemTemplate", void 0);
tslib_1.__decorate([
Input('separation-character'),
tslib_1.__metadata("design:type", String),
tslib_1.__metadata("design:paramtypes", [String])
], NgxMultiSelectorComponent.prototype, "separationCharacter", null);
tslib_1.__decorate([
Input('interval'),
tslib_1.__metadata("design:type", Number),
tslib_1.__metadata("design:paramtypes", [Number])
], NgxMultiSelectorComponent.prototype, "interval", null);
tslib_1.__decorate([
Input('items'),
tslib_1.__metadata("design:type", Array),
tslib_1.__metadata("design:paramtypes", [Array])
], NgxMultiSelectorComponent.prototype, "items", null);
tslib_1.__decorate([
Input('limit-item-amount'),
tslib_1.__metadata("design:type", Number),
tslib_1.__metadata("design:paramtypes", [Number])
], NgxMultiSelectorComponent.prototype, "maximumContextItems", null);
tslib_1.__decorate([
Input('limit-item-selection'),
tslib_1.__metadata("design:type", Number),
tslib_1.__metadata("design:paramtypes", [Number])
], NgxMultiSelectorComponent.prototype, "maximumSelectableItems", null);
tslib_1.__decorate([
Input('key'),
tslib_1.__metadata("design:type", String),
tslib_1.__metadata("design:paramtypes", [String])
], NgxMultiSelectorComponent.prototype, "key", null);
tslib_1.__decorate([
Input('key-property'),
tslib_1.__metadata("design:type", String),
tslib_1.__metadata("design:paramtypes", [String])
], NgxMultiSelectorComponent.prototype, "keyProperty", null);
tslib_1.__decorate([
Input('display-property'),
tslib_1.__metadata("design:type", String),
tslib_1.__metadata("design:paramtypes", [String])
], NgxMultiSelectorComponent.prototype, "displayProperty", null);
tslib_1.__decorate([
Input('value-property'),
tslib_1.__metadata("design:type", String),
tslib_1.__metadata("design:paramtypes", [String])
], NgxMultiSelectorComponent.prototype, "valueProperty", null);
NgxMultiSelectorComponent = NgxMultiSelectorComponent_1 = tslib_1.__decorate([
Component({
selector: 'ngx-multi-selector',
exportAs: 'ngx-multi-selector',
template: "<div class=\"dropdown\">\r\n\r\n <!--Text input-->\r\n <div #multiSelectorDropdownMenu\r\n class=\"input-group ngx-multi-selector\">\r\n <div class=\"dropdown-toggle\"\r\n [attr.data-toggle]=\"disabled ? '': 'dropdown'\"\r\n aria-haspopup=\"true\"\r\n aria-expanded=\"false\"\r\n [attr.disabled]=\"disabled\">\r\n <input class=\"form-control ngx-multi-selector-title-box\"\r\n [class.disabled]=\"disabled\"\r\n [placeholder]=\"!placeholderTitleDropDown ? '' : placeholderTitleDropDown\"\r\n readonly=\"readonly\"\r\n [value]=\"loadSelectedItemsTitle()\">\r\n </div>\r\n <span class=\"input-group-addon\"\r\n *ngIf=\"shouldClearButtonAvailable\"\r\n [class.disabled]=\"disabled\"\r\n (click)=\"deleteSelectedItems()\">\r\n <span class=\"glyphicon glyphicon-remove\"></span>\r\n </span>\r\n\r\n <!--Dropdown-->\r\n <span class=\"input-group-addon dropdown-toggle\"\r\n [attr.data-toggle]=\"disabled ? '': 'dropdown'\"\r\n [class.disabled]=\"disabled\"\r\n aria-haspopup=\"true\"\r\n aria-expanded=\"false\">\r\n <span class=\"caret\"></span>\r\n </span>\r\n\r\n <!--Dropdown menu-->\r\n <ul class=\"dropdown-menu\"\r\n (click)=\"$event.stopPropagation();\">\r\n <li *ngIf=\"shouldSearchBoxAvailable\">\r\n <div class=\"col-lg-12\">\r\n <div class=\"form-group\">\r\n <div class=\"input-group\">\r\n <input class=\"form-control\"\r\n [(ngModel)]=\"keyword\"\r\n [placeholder]=\"!placeholderSearchDropDown ? '' : placeholderSearchDropDown\">\r\n <span class=\"input-group-addon\">\r\n <span class=\"glyphicon glyphicon-search\"></span>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </li>\r\n\r\n <ng-template ngFor\r\n let-item\r\n let-i=\"index\"\r\n [ngForOf]=\"items\">\r\n\r\n <ng-container *ngIf=\"maximumContextItem < 1 || (maximumContextItem > 0 && i < maximumContextItem)\">\r\n <!--Item template-->\r\n <ng-template [ngTemplateOutlet]=\"itemTemplate || defaultItemTemplate\"\r\n [ngTemplateOutletContext]=\"{item:item, index:i, selected: hasItemSelected(item), instance: this}\">\r\n </ng-template>\r\n </ng-container>\r\n\r\n </ng-template>\r\n </ul>\r\n </div>\r\n</div>\r\n\r\n<!--Default item template-->\r\n<ng-template #defaultItemTemplate\r\n let-item=\"item\"\r\n let-i=\"index\"\r\n let-selected=\"selected\"\r\n let-instance=\"instance\">\r\n\r\n <li [class.active]=\"hasItemSelected(item)\"\r\n (click)=\"instance.clickSelectItem(item)\">\r\n <a href=\"javascript:void(0);\">\r\n <span class=\"glyphicon glyphicon-check\"\r\n *ngIf=\"selected\"></span>\r\n {{loadItemDisplay(item)}}\r\n </a>\r\n </li>\r\n</ng-template>\r\n",
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(function () { return NgxMultiSelectorComponent_1; }),
multi: true
}
],
styles: [".ngx-multi-selector .dropdown-menu{width:100%}.ngx-multi-selector input.ngx-multi-selector-title-box{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;background-color:#fff!important;cursor:default}.ngx-multi-selector .input-group-addon.disabled,.ngx-multi-selector .input-group-addon:disabled,.ngx-multi-selector input.ngx-multi-selector-title-box.disabled,.ngx-multi-selector input.ngx-multi-selector-title-box:disabled{background-color:#eee!important;cursor:not-allowed;pointer-events:none}"]
}),
tslib_1.__metadata("design:paramtypes", [])
], NgxMultiSelectorComponent);
return NgxMultiSelectorComponent;
}());
export { NgxMultiSelectorComponent };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW11bHRpLXNlbGVjdG9yLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL25neC1tdWx0aS1zZWxlY3Rvci8iLCJzb3VyY2VzIjpbImxpYi9uZ3gtbXVsdGktc2VsZWN0b3IuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULFVBQVUsRUFDVixLQUFLLEVBQ0wsU0FBUyxFQUNULFdBQVcsRUFBRSxVQUFVLEVBQ3hCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBdUIsaUJBQWlCLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUN2RSxPQUFPLEVBQWtCLEtBQUssRUFBYyxFQUFFLEVBQUUsYUFBYSxFQUF5QixLQUFLLEVBQUMsTUFBTSxNQUFNLENBQUM7QUFDekcsT0FBTyxFQUFDLFFBQVEsRUFBRSxvQkFBb0IsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFDLE1BQU0sZ0JBQWdCLENBQUE7QUFpQjdFO0lBc1RFLFlBQVk7SUFFWixxQkFBcUI7SUFFckI7O1FBRUk7SUFDSjtRQUFBLGlCQW1EQztRQTlXRCxvQkFBb0I7UUFFcEI7O1lBRUk7UUFDYSwwQkFBcUIsR0FBRyxHQUFHLENBQUM7UUFPN0M7OztZQUdJO1FBQ0kseUJBQW9CLEdBQUcsR0FBRyxDQUFDO1FBa0JuQzs7WUFFSTtRQUNJLHlCQUFvQixHQUFHLENBQUMsQ0FBQztRQUVqQzs7WUFFSTtRQUNJLDRCQUF1QixHQUFHLENBQUMsQ0FBQztRQW9GcEM7O1lBRUk7UUFDSSx1QkFBa0IsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUM7UUEyTHRELElBQUksQ0FBQyxjQUFjLEdBQUcsRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBRWhCLDZDQUE2QztRQUM3QyxJQUFJLENBQUMsdUJBQXVCLEdBQUcsRUFBRSxDQUFDO1FBRWxDLElBQUksQ0FBQyw0QkFBNEIsR0FBRyxJQUFJLGFBQWEsQ0FB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Q1UsS0FBSztpREFBTCxLQUFLOzBEQWM3QjtJQW9CRDtRQURDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQzs7O3dFQU8xQjtJQWFEO1FBREMsS0FBSyxDQUFDLHNCQUFzQixDQUFDOzs7MkVBUTdCO0lBUUQ7UUFEQyxLQUFLLENBQUMsS0FBSyxDQUFDOzs7d0RBR1o7SUFPRDtRQURDLEtBQUssQ0FBQyxjQUFjLENBQUM7OztnRUFHckI7SUFPRDtRQURDLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQzs7O29FQUd6QjtJQU9EO1FBREMsS0FBSyxDQUFDLGdCQUFnQixDQUFDOzs7a0VBR3ZCO0lBblRVLHlCQUF5QjtRQWRyQyxTQUFTLENBQUM7WUFDVCxRQUFRLEVBQUUsb0JBQW9CO1lBQzlCLFFBQVEsRUFBRSxvQkFBb0I7WUFDOUIsdWpHQUFnRDtZQUVoRCxTQUFTLEVBQUU7Z0JBQ1Q7b0JBQ0UsT0FBTyxFQUFFLGlCQUFpQjtvQkFDMUIsV0FBVyxFQUFFLFVBQVUsQ0FBQyxjQUFNLE9BQUEsMkJBQXlCLEVBQXpCLENBQXlCLENBQUM7b0JBQ3hELEtBQUssRUFBRSxJQUFJO2lCQUNaO2FBQ0Y7O1NBQ0YsQ0FBQzs7T0FFVyx5QkFBeUIsQ0FxckJyQztJQUFELGdDQUFDO0NBQUEsQUFyckJELElBcXJCQztTQXJyQlkseUJBQXlCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBDb21wb25lbnQsXHJcbiAgRWxlbWVudFJlZixcclxuICBJbnB1dCxcclxuICBWaWV3Q2hpbGQsXHJcbiAgVGVtcGxhdGVSZWYsIGZvcndhcmRSZWYsIE9uRGVzdHJveSwgT25Jbml0XHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7Q29udHJvbFZhbHVlQWNjZXNzb3IsIE5HX1ZBTFVFX0FDQ0VTU09SfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7QmVoYXZpb3JTdWJqZWN0LCBFTVBUWSwgT2JzZXJ2YWJsZSwgb2YsIFJlcGxheVN1YmplY3QsIFN1YmplY3QsIFN1YnNjcmlwdGlvbiwgdGltZXJ9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQge2RlYm91bmNlLCBkaXN0aW5jdFVudGlsQ2hhbmdlZCwgbWFwLCBzd2l0Y2hNYXB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJ1xyXG5pbXBvcnQge0lVcGRhdGVNdWx0aVNlbGVjdG9yQ29tbWFuZH0gZnJvbSAnLi91cGRhdGUtbXVsdGktc2VsZWN0b3ItY29tbWFuZC5pbnRlcmZhY2UnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduZ3gtbXVsdGktc2VsZWN0b3InLFxyXG4gIGV4cG9ydEFzOiAnbmd4LW11bHRpLXNlbGVjdG9yJyxcclxuICB0ZW1wbGF0ZVVybDogJ25neC1tdWx0aS1zZWxlY3Rvci5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJ25neC1tdWx0aS1zZWxlY3Rvci5jb21wb25lbnQuc2NzcyddLFxyXG4gIHByb3ZpZGVyczogW1xyXG4gICAge1xyXG4gICAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcclxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gTmd4TXVsdGlTZWxlY3RvckNvbXBvbmVudCksXHJcbiAgICAgIG11bHRpOiB0cnVlXHJcbiAgICB9XHJcbiAgXVxyXG59KVxyXG5cclxuZXhwb3J0IGNsYXNzIE5neE11bHRpU2VsZWN0b3JDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSwgQ29udHJvbFZhbHVlQWNjZXNzb3Ige1xyXG5cclxuICAvLyNyZWdpb24gUHJvcGVydGllc1xyXG5cclxuICAvKlxyXG4gICogRGVsYXkgdGltZSBiZXR3ZWVuIDIgaXRlbSBzZWFyY2ggcmVxdWVzdHMuXHJcbiAgKiAqL1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgX2RlZmF1bHRJdGVtc0ludGVydmFsID0gMTUwO1xyXG5cclxuICAvKlxyXG4gICogTGlzdCBvZiBpdGVtcyB3aGljaCBoYXZlIGJlZW4gc2VsZWN0ZWQuXHJcbiAgKiAqL1xyXG4gIHByaXZhdGUgX3NlbGVjdGVkSXRlbXM6IEFycmF5PGFueT47XHJcblxyXG4gIC8qXHJcbiAgKiBDaGFyYWN0ZXIgd2hpY2ggaXMgdXNlZCBmb3Igc2VwYXJhdGluZyBzZWxlY3RlZCBpdGVtcy5cclxuICAqIERlZmF1bHQ6ICxcclxuICAqICovXHJcbiAgcHJpdmF0ZSBfc2VwYXJhdGlvbkNoYXJhY3RlciA9ICcsJztcclxuXHJcbiAgLypcclxuICAqIEtleXdvcmQgd2hpY2ggaXMgZm9yIHNlYXJjaGluZyBmb3IgYXZhaWxhYmxlIGl0ZW1zLlxyXG4gICogRGVmYXVsdDogbnVsbC5cclxuICAqICovXHJcbiAgcHJpdmF0ZSBfa2V5d29yZDogc3RyaW5nO1xyXG5cclxuICAvKlxyXG4gICogTGlzdCBvZiBpdGVtcyB0aGF0IG9yaWdpbmFsbHkgc2V0LlxyXG4gICogKi9cclxuICBwcml2YXRlIF9vcmlnaW5hbEl0ZW1zOiBhbnlbXTtcclxuXHJcbiAgLypcclxuICAqIExpc3Qgb2YgaXRlbSB3aGljaCBzaG91bGQgYmUgZGlzcGxheWVkIG9uIGRyb3AtZG93biBtZW51LlxyXG4gICogKi9cclxuICBwcml2YXRlIF9hdmFpbGFibGVJdGVtczogYW55W107XHJcblxyXG4gIC8qXHJcbiAgKiBNYXhpbXVtIGl0ZW1zIHRoYXQgY2FuIGJlIGRpc3BsYXllZCBpbiBjb250ZXh0IG1lbnUuXHJcbiAgKiAqL1xyXG4gIHByaXZhdGUgX21heGltdW1Db250ZXh0SXRlbXMgPSAwO1xyXG5cclxuICAvKlxyXG4gICogSG93IG1hbnkgaXRlbXMgY2FuIGJlIHNlbGVjdGVkLlxyXG4gICogKi9cclxuICBwcml2YXRlIF9tYXhpbXVtU2VsZWN0YWJsZUl0ZW1zID0gMDtcclxuXHJcbiAgLypcclxuICAqIFByb3BlcnR5IHdoaWNoIGlzIGZvciBkZXRlcm1pbmluZyB3aGV0aGVyIGl0ZW0gaXMgc2VsZWN0ZWQgb3Igbm90LlxyXG4gICogKi9cclxuICBwcml2YXRlIF9rZXk6IHN0cmluZztcclxuXHJcbiAgLypcclxuICAqIFByb3BlcnR5IHdoaWNoIGlzIGZvciBkZXRlcm1pbmluZyB3aGF0IHByb3BlcnR5IHNob3VsZCBiZSB1c2VkIGZvciBkaXNwbGF5LlxyXG4gICogKi9cclxuICBwcml2YXRlIF9kaXNwbGF5UHJvcGVydHk6IHN0cmluZztcclxuXHJcbiAgLypcclxuICAqIFByb3BlcnR5IHdoaWNoIGlzIGZvciBkZXRlcm1pbmluZyB3aGF0IHByb3BlcnR5IHNob3VsZCBiZSB1c2VkIGFzIHNlbGVjdGVkIHZhbHVlLlxyXG4gICogKi9cclxuICBwcml2YXRlIF92YWx1ZVByb3BlcnR5OiBzdHJpbmc7XHJcblxyXG4gIC8qXHJcbiAgKiBIYW5kbGUgZm9yIGxvYWRpbmcgYXZhaWxhYmxlIGl0ZW1zIGFzeW5jaHJvbm91c2x5LlxyXG4gICogKi9cclxuICBASW5wdXQoJ2xvYWQtYXZhaWxhYmxlLWl0ZW1zLWhhbmRsZXInKVxyXG4gIHB1YmxpYyByZWFkb25seSBsb2FkQXZhaWxhYmxlSXRlbXNBc3luY0hhbmRsZXI6IChrZXl3b3JkOiBzdHJpbmcpID0+IE9ic2VydmFibGU8YW55W10+O1xyXG5cclxuICAvKlxyXG4gICogRW1pdCBhIGtleXdvcmQgZm9yIHVwZGF0aW5nIGF2YWlsYWJsZSBpdGVtcy5cclxuICAqICovXHJcbiAgcHJpdmF0ZSBfdXBkYXRlQXZhaWxhYmxlSXRlbXNTdWJqZWN0OiBTdWJqZWN0PElVcGRhdGVNdWx0aVNlbGVjdG9yQ29tbWFuZD47XHJcblxyXG4gIC8qXHJcbiAgKiBTdWJzY3JpcHRpb24gYWJvdXQgY29udHJvbCB1cGRhdGUgbWFuYWdlbWVudC5cclxuICAqICovXHJcbiAgcHJpdmF0ZSBfdXBkYXRlQXZhaWxhYmxlSXRlbXNTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcclxuXHJcbiAgLypcclxuICAqIEluamVjdG9yIG9mIG11bHRpLXNlbGVjdG9yIGRyb3AtZG93biBtZW51LlxyXG4gICogKi9cclxuICBAVmlld0NoaWxkKCdtdWx0aVNlbGVjdG9yRHJvcGRvd25NZW51Jywge3N0YXRpYzogZmFsc2V9KVxyXG4gIHB1YmxpYyBtdWx0aVNlbGVjdG9yRHJvcERvd246IEVsZW1lbnRSZWY7XHJcblxyXG4gIC8qXHJcbiAgKiBXaGV0aGVyIGNsZWFyIGJ1dHRvbiBzaG91bGQgYmUgYXZhaWxhYmxlIG9yIG5vdC5cclxuICAqICovXHJcbiAgQElucHV0KCdpcy1jbGVhci1idXR0b24tYXZhaWxhYmxlJylcclxuICBwdWJsaWMgc2hvdWxkQ2xlYXJCdXR0b25BdmFpbGFibGU6IGJvb2xlYW47XHJcblxyXG4gIC8qXHJcbiAgKiBXaGV0aGVyIHNlYXJjaCBib3ggc2hvdWxkIGJlIGF2YWlsYWJsZSBvciBub3QuXHJcbiAgKiAqL1xyXG4gIEBJbnB1dCgnaXMtc2VhcmNoLWJveC1hdmFpbGFibGUnKVxyXG4gIHB1YmxpYyBzaG91bGRTZWFyY2hCb3hBdmFpbGFibGU6IGJvb2xlYW47XHJcblxyXG4gIC8qXHJcbiAgKiBQbGFjZSBob2xkZXIgb2Ygc2VhcmNoIGJveCBpbiBkcm9wLWRvd24gbGlzdC5cclxuICAqICovXHJcbiAgQElucHV0KCdwbGFjZWhvbGRlci1zZWFyY2gtZHJvcC1kb3duJylcclxuICBwdWJsaWMgcGxhY2Vob2xkZXJTZWFyY2hEcm9wRG93bjogc3RyaW5nO1xyXG5cclxuICAvKlxyXG4gICogUGxhY2UgaG9sZGVyIG9mIHRpdGxlLlxyXG4gICogKi9cclxuICBASW5wdXQoJ3BsYWNlaG9sZGVyLXRpdGxlLWRyb3AtZG93bicpXHJcbiAgcHVibGljIHBsYWNlaG9sZGVyVGl0bGVEcm9wRG93bjogc3RyaW5nO1xyXG5cclxuICAvKlxyXG4gICogIFdoZXRoZXIgY29tcG9uZW50IGlzIGRpc2FibGVkIG9yIG5vdC5cclxuICAqICovXHJcbiAgQElucHV0KCdkaXNhYmxlZCcpXHJcbiAgcHVibGljIGRpc2FibGVkOiBib29sZWFuO1xyXG4gIC8qXHJcbiAgKiBDdXN0b20gaXRlbSB0ZW1wbGF0ZS5cclxuICAqICovXHJcbiAgQElucHV0KCdpdGVtLXRlbXBsYXRlJylcclxuICBwdWJsaWMgaXRlbVRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+O1xyXG5cclxuICAvKlxyXG4gICogQ2FsbGJhY2sgd2hpY2ggaXMgZm9yIHJhaXNpbmcgdG91Y2hlZCBldmVudCBmcm9tIHRoZSBjdXJyZW50IGNvbXBvbmVudC5cclxuICAqICovXHJcbiAgcHJvdGVjdGVkIG5nT25Ub3VjaGVkQ2FsbGJhY2s6ICgpID0+IHZvaWQ7XHJcblxyXG4gIC8qXHJcbiAgKiBDYWxsYmFjayB3aGljaCBpcyBmb3IgcmFpc2luZyBtb2RlbCBjaGFuZ2UgZXZlbnQgZnJvbSB0aGUgY3VycmVudCBjb21wb25lbnQuXHJcbiAgKiAqL1xyXG4gIHByb3RlY3RlZCBuZ09uQ2hhbmdlQ2FsbGJhY2s6IChfOiBhbnkpID0+IHZvaWQ7XHJcblxyXG4gIC8qXHJcbiAgKiBIb3cgbXVjaCB0aW1lIHNob3VsZCBjb21wb25lbnQgcmFpc2UgYW5vdGhlciBvbmUgYWJvdXQgaXRzIGNoYW5nZXMuXHJcbiAgKiAqL1xyXG4gIHByaXZhdGUgX2xvYWRJdGVtc0ludGVydmFsID0gdGhpcy5fZGVmYXVsdEl0ZW1zSW50ZXJ2YWw7XHJcblxyXG4gIC8vI2VuZHJlZ2lvblxyXG5cclxuICAvLyNyZWdpb24gQWNjZXNzb3JzXHJcblxyXG4gIC8qXHJcbiAgKiBLZXl3b3JkIGlzIHVzZWQgZm9yIHNlYXJjaGluZyBmb3IgaXRlbXMuXHJcbiAgKiAqL1xyXG4gIHB1YmxpYyBnZXQga2V5d29yZCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHRoaXMuX2tleXdvcmQ7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICogS2V5d29yZCBpcyB1c2VkIGZvciBzZWFyY2hpbmcgZm9yIGl0ZW1zLlxyXG4gICogKi9cclxuICBwdWJsaWMgc2V0IGtleXdvcmQodmFsdWU6IHN0cmluZykge1xyXG4gICAgdGhpcy5fa2V5d29yZCA9IHZhbHVlO1xyXG5cclxuICAgIC8vIEluaXRpYWxpemUgY29udHJvbCB1cGRhdGUgY29tbWFuZC5cclxuICAgIGNvbnN0IGNvbW1hbmQ6IElVcGRhdGVNdWx0aVNlbGVjdG9yQ29tbWFuZCA9IHtcclxuICAgICAgc2hvdWxkSWdub3JlRHVwbGljYXRlOiBmYWxzZSxcclxuICAgICAgc2hvdWxkSWdub3JlSW50ZXJ2YWw6IGZhbHNlXHJcbiAgICB9O1xyXG5cclxuICAgIHRoaXMuX3VwZGF0ZUF2YWlsYWJsZUl0ZW1zU3ViamVjdFxyXG4gICAgICAubmV4dChjb21tYW5kKTtcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgKiBDaGFyYWN0ZXIgd2hpY2ggaXMgdXNlZCBmb3IgZGl2aWRpbmcgc2VhcmNoZWQgaXRlbXMuXHJcbiAgKiAqL1xyXG4gIEBJbnB1dCgnc2VwYXJhdGlvbi1jaGFyYWN0ZXInKVxyXG4gIHB1YmxpYyBzZXQgc2VwYXJhdGlvbkNoYXJhY3Rlcih2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICBpZiAoIXZhbHVlIHx8ICF2YWx1ZS5sZW5ndGgpIHtcclxuICAgICAgdGhpcy5fc2VwYXJhdGlvbkNoYXJhY3RlciA9ICcsJztcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuX3NlcGFyYXRpb25DaGFyYWN0ZXIgPSB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgKiBJdGVtcyB3aGljaCBoYXZlIGJlZW4gc2VsZWN0ZWQuXHJcbiAgKiAqL1xyXG4gIHB1YmxpYyBnZXQgc2VsZWN0ZWRJdGVtcygpOiBhbnlbXSB7XHJcbiAgICByZXR1cm4gdGhpcy5fc2VsZWN0ZWRJdGVtcztcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgKiBHZXQgc2VsZWN0ZWQgaXRlbXMuXHJcbiAgKiAqL1xyXG4gIHB1YmxpYyBzZXQgc2VsZWN0ZWRJdGVtcyh2YWx1ZXM6IGFueVtdKSB7XHJcbiAgICBpZiAoIXZhbHVlcyB8fCB2YWx1ZXMubGVuZ3RoIDwgMCkge1xyXG4gICAgICB0aGlzLl9zZWxlY3RlZEl0ZW1zID0gW107XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLl9zZWxlY3RlZEl0ZW1zID0gdmFsdWVzO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAqIEhvdyBtdWNoIHRpbWUgc2hvdWxkIGNvbXBvbmVudCByYWlzZSBhbm90aGVyIG9uZSBhYm91dCBpdHMgY2hhbmdlcy5cclxuICAqICovXHJcbiAgQElucHV0KCdpbnRlcnZhbCcpXHJcbiAgcHVibGljIHNldCBpbnRlcnZhbCh2YWx1ZTogbnVtYmVyKSB7XHJcblxyXG4gICAgaWYgKH