@firestitch/filter
Version:
710 lines • 62.7 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Component, EventEmitter, Input, ViewChild, ViewEncapsulation, HostListener, ApplicationRef, Injector } from '@angular/core';
import { Location } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router';
import { FsDocumentScrollService } from '@firestitch/scroll';
import { FsStore } from '@firestitch/store';
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { isAfter, subMinutes } from 'date-fns';
import { FsFilterConfig } from '../../models/filter-config';
import { objectsAreEquals } from '../../helpers/compare';
import { FilterParams } from '../../models/filter-params';
import { FsFilterOverlayService } from '../../services/filter-overlay.service';
import { ItemType } from '../../enums/item-type.enum';
export class FilterComponent {
/**
* @param {?} _store
* @param {?} _location
* @param {?} _route
* @param {?} _router
* @param {?} _appRef
* @param {?} _injector
* @param {?} _documentScrollService
* @param {?} _filterOverlay
*/
constructor(_store, _location, _route, _router, _appRef, _injector, _documentScrollService, _filterOverlay) {
this._store = _store;
this._location = _location;
this._route = _route;
this._router = _router;
this._appRef = _appRef;
this._injector = _injector;
this._documentScrollService = _documentScrollService;
this._filterOverlay = _filterOverlay;
this._config = null;
this.sortUpdate = null;
this.showSortBy = true;
this.showFilterInput = true;
this.changedFilters = [];
this.searchText = '';
this.persists = null;
this.activeFiltersCount = 0;
this.activeFiltersWithInputCount = 0;
this.showFilterMenu = false;
this.modelChanged = new EventEmitter();
this.windowDesktop = false;
this._searchTextInput = null;
this._firstOpen = true;
this._sort = {};
this._destroy$ = new Subject();
this.updateWindowWidth();
this._filterOverlay.attach$
.pipe(takeUntil(this._destroy$))
.subscribe((/**
* @return {?}
*/
() => {
this.showFilterMenu = true;
}));
this._filterOverlay.detach$
.pipe(takeUntil(this._destroy$))
.subscribe((/**
* @return {?}
*/
() => {
this.updateFilledCounter();
this.showFilterMenu = false;
}));
}
/**
* @param {?} config
* @return {?}
*/
set setConfig(config) {
this.config = config;
}
/**
* @param {?} config
* @return {?}
*/
set setFilter(config) {
this.config = config;
}
/**
* @param {?} event
* @return {?}
*/
keyEvent(event) {
if (event.code === 'Escape' && this.showFilterMenu) {
this.changeVisibility(false);
}
}
/**
* @return {?}
*/
updateWindowWidth() {
this.windowDesktop = window.innerWidth > 1200;
}
/**
* @param {?} value
* @return {?}
*/
set searchTextInput(value) {
this._searchTextInput = value;
}
/**
* @param {?} config
* @return {?}
*/
set config(config) {
this._config = new FsFilterConfig(config);
this._restorePersistValues();
this.config.initItems(config.items, this._route, this.persists);
this._filterParams = new FilterParams(this._router, this._route, this.config.items);
if (this.config.queryParam) {
this._filterParams.updateFromQueryParams(this._route.snapshot.queryParams);
}
this._searchTextItem = this.config.items.find((/**
* @param {?} item
* @return {?}
*/
(item) => item.isTypeKeyword));
if (this._searchTextItem) {
this.searchText = this._searchTextItem.model;
}
// Count active filters after restore
this.updateFilledCounter();
if (this.config.persist) {
this._storePersistValues();
}
if (!!this.config.reloadWhenConfigChanged) {
this.change();
}
}
/**
* @return {?}
*/
get config() {
return this._config;
}
/**
* @return {?}
*/
ngOnInit() {
// Avoid ngChanges error
setTimeout((/**
* @return {?}
*/
() => {
this.focus();
}));
this._watchSearchInput();
if (this.sortUpdate) {
this.sortUpdate
.pipe(takeUntil(this.config.destroy$))
.subscribe((/**
* @param {?} data
* @return {?}
*/
(data) => {
this.config.updateSort(data);
}));
}
if (this.config.init) {
this.init();
}
}
/**
* @return {?}
*/
focus() {
if (this._searchTextInput && this.config.autofocus) {
this._searchTextInput.nativeElement.focus();
}
}
/**
* @return {?}
*/
ngOnDestroy() {
this._destroyFilterDrawer();
this._destroy$.next();
this._destroy$.complete();
if (this.config) {
this.config.destroy();
}
}
/**
*
* Do update value of some field
*
*
* To update text value just pass new text value
*
* public updateSelectValue(val) {
* this.filterEl.updateValues({ keyword: val });
* }
*
* To update select or observable select you could pass suitable value
*
* public updateSelectValue(val: number) {
* this.filterEl.updateValues({ simple_select: val }, { observable_select: val });
* }
*
* To update checkbox value just pass true/false as value
*
* public updateCheckox(val: boolean) {
* this.filterEl.updateValues({ checkbox: val });
* }
*
* To update range value just pass object with min&max object or just with one of targets
*
* Ex.: { min: 10, max 15 }, { min: 5 }, { max 5 }
*
* public updateRange(val) {
* this.filterEl.updateValues({ range: val });
* }
*
* To update autocomplete just pass object with name/value fields
*
* Ex.: { name: 'John Doe', value: 1 }
*
* public updateAutocomplete(val) {
* this.filterEl.updateValues({ autocomplete_user_id: val });
* }
*
* To update autocompletechips just pass:
*
* 1) object with name/value fields - will be appended to existing set of values
*
* { name: 'John Doe', value: 1 }
*
* 2) array of objects - will be appended to existing set of values
*
* [{ name: 'John Doe', value: 1 }, { name: 'Darya Filipova', value: 2 }]
*
* 3) null - clear existing set of values
*
* public updateAutocomplete(val) {
* this.filterEl.updateValues({ autocompletechips_user_id: val });
* }
*
* @param {?} values
* @param {?=} changeEvent
* @return {?}
*/
updateValues(values, changeEvent = true) {
Object.keys(values).forEach((/**
* @param {?} key
* @return {?}
*/
(key) => {
/** @type {?} */
const filterItem = this.config.items.find((/**
* @param {?} item
* @return {?}
*/
(item) => item.name === key));
if (!filterItem) {
return;
}
filterItem.updateValue(values[key]);
}));
this.updateFilledCounter();
if (changeEvent) {
this._filterChange();
}
}
/**
* @param {?} text
* @return {?}
*/
modelChange(text) {
this.modelChanged.next(text);
}
/**
* @return {?}
*/
hide() {
this.changeVisibility(false);
}
/**
* @return {?}
*/
show() {
this.changeVisibility(true);
}
/**
* @param {?} value
* @param {?=} event
* @return {?}
*/
changeVisibilityClick(value, event = null) {
if (event) {
event.stopPropagation();
}
this.changeVisibility(value);
}
/**
* @param {?} event
* @return {?}
*/
filterInputEvent(event) {
if (!this.windowDesktop) {
return;
}
if (['Enter', 'NumpadEnter', 'Escape'].indexOf(event.code) >= 0) {
this.changeVisibility(false);
if (this._searchTextInput) {
this._searchTextInput.nativeElement.blur();
}
}
else {
this.changeVisibility(true);
}
}
/**
* @param {?} state
* @return {?}
*/
changeVisibility(state) {
if (state === this.showFilterMenu) {
return;
}
if (!state) {
return this._destroyFilterDrawer();
}
/** @type {?} */
const notTextItem = this.config.items.find((/**
* @param {?} item
* @return {?}
*/
(item) => {
return item.type !== ItemType.Keyword;
}));
if (!notTextItem) {
return;
}
this._filterOverlay.open(this._injector, {
items: this.config.items,
showSortBy: 'showSortBy',
sortBy: this.config.sortByItem,
sortDirection: this.config.sortDirectionItem,
filterChanged: this._filterChange.bind(this),
search: this.search.bind(this),
done: this.hide.bind(this),
clear: this.clear.bind(this)
});
if (this._firstOpen) {
this.config.loadValuesForPendingItems();
this._firstOpen = false;
}
}
/**
* @param {?} event
* @return {?}
*/
clearSearchText(event) {
event.stopPropagation();
this.searchText = '';
this.modelChanged.next('');
}
/**
* @return {?}
*/
init() {
/** @type {?} */
const data = this._filterParams.getFlattenedParams();
this._sort = this.config.getSort();
this.config.init(data, this.config.getSort());
}
/**
* @param {?=} event
* @return {?}
*/
clear(event = null) {
if (event) {
event.stopPropagation();
}
this.searchText = '';
this.changedFilters = [];
this.config.filtersClear();
this.activeFiltersCount = 0;
this.activeFiltersWithInputCount = 0;
this._filterChange();
this.changeVisibility(false);
}
/**
* Close filter window and do change callback
* @param {?} event
* @return {?}
*/
search(event) {
this.changeVisibilityClick(false, event);
this._filterChange();
}
/**
* @param {?=} event
* @return {?}
*/
reload(event = null) {
if (event) {
event.stopPropagation();
}
/** @type {?} */
const data = this._filterParams.getFlattenedParams();
if (this.config.reload) {
this.config.reload(data, this.config.getSort());
}
}
/**
* Reset filter
* @param {?} event
* @return {?}
*/
resetFilter(event) {
/** @type {?} */
const item = event.item;
/** @type {?} */
const type = event.type;
/** @type {?} */
const index = this.changedFilters.indexOf(item);
if (index > -1) {
if (type) {
item.partialClear(type);
if (!item.valueChanged) {
this.changedFilters.splice(index, 1);
}
}
else {
this.changedFilters.splice(index, 1);
item.clear();
}
}
this.change();
}
/**
* Call change callback and apply new filter values
* @return {?}
*/
change() {
this.config.updateModelValues();
/** @type {?} */
const data = this._filterParams.getFlattenedParams();
/** @type {?} */
const sort = this.config.getSort();
/** @type {?} */
const sortingChanged = ((!sort || !this._sort) && sort !== this._sort)
|| (sort && this._sort && !objectsAreEquals(this._sort, sort));
if (sortingChanged) {
this._sort = sort;
if (this.config.sortChange) {
this.config.sortChange(data, sort);
}
}
// This should be an option or a done with an wrapping helper function
// because it restricts functionality ie. reload
// const queryChanged = !objectsAreEquals(this._query, query);
// if (queryChanged) {
this._storePersistValues();
this.updateFilledCounter();
if (this.config.change) {
this.config.change(data, sort);
}
if (this.config.queryParam) {
this._filterParams.updateQueryParams();
}
}
/**
* Do update count of filled filters
* @private
* @return {?}
*/
updateFilledCounter() {
this.changedFilters = this.config.getFilledItems();
this.changedFilters
.filter((/**
* @param {?} item
* @return {?}
*/
(item) => item.hasPendingValues))
.forEach((/**
* @param {?} item
* @return {?}
*/
(item) => item.loadValues(false)));
this.activeFiltersWithInputCount = this.changedFilters
.filter((/**
* @param {?} item
* @return {?}
*/
(item) => item.type !== ItemType.Keyword))
.length;
}
/**
* Store updated filter data into localstorage
* @private
* @param {?=} changedItem
* @return {?}
*/
_filterChange(changedItem = null) {
if (changedItem) {
changedItem.checkIfValueChanged();
}
this._storePersistValues();
this.change();
}
/**
* @private
* @return {?}
*/
_destroyFilterDrawer() {
this._filterOverlay.close();
}
/**
* @private
* @return {?}
*/
_watchSearchInput() {
this.modelChanged
.pipe(distinctUntilChanged(), debounceTime(500), takeUntil(this.config.destroy$))
.subscribe((/**
* @param {?} value
* @return {?}
*/
(value) => {
if (this._searchTextItem) {
this._searchTextItem.model = value;
}
this._filterChange();
}));
}
/**
* Restoring values from local storage
* @private
* @return {?}
*/
_restorePersistValues() {
this.persists = this._store.get(this.config.namespace + '-persist', {});
if (this.persists === undefined) {
this.persists = {};
}
if (this.config.persist) {
if (typeof this.config.persist.persist !== 'object') {
this.config.persist = { name: this.config.persist };
}
if (!this.config.persist.name) {
this.config.persist.name = this._location.path();
}
if (!this.persists[this.config.persist.name] || !this.persists[this.config.persist.name].data) {
this.persists[this.config.persist.name] = { data: {}, date: new Date() };
}
if (this.config.persist.timeout) {
/** @type {?} */
const date = new Date(this.persists[this.config.persist.name].date);
if (isAfter(subMinutes(date, this.config.persist.timeout), new Date())) {
this.persists[this.config.persist.name] = { data: {}, date: new Date() };
}
}
}
}
/**
* Store values to local storage
* @private
* @return {?}
*/
_storePersistValues() {
if (this.config.persist) {
this.persists[this.config.persist.name] = {
data: this._filterParams.getValues(),
date: new Date()
};
this._store.set(this.config.namespace + '-persist', this.persists, {});
}
}
}
FilterComponent.decorators = [
{ type: Component, args: [{
selector: 'fs-filter',
template: "<div class=\"fs-filter\"\n *ngIf=\"config?.items?.length\"\n [ngClass]=\"{\n 'filters-open': showFilterMenu,\n 'no-input': !showFilterInput,\n 'window-desktop': windowDesktop,\n 'keyword-filter': config.keywordFilter\n }\">\n <div fxLayou=\"row\" fxLayoutAlign=\"start center\" class=\"menu-filter\" fxFlex=\"1 1 0\">\n <div class=\"menu-filter-input\" fxFlex=\"grow\">\n <div class=\"main-filter-bar\" fxLayout=\"row\" fxLayoutAlign=\"start center\">\n <form autocomplete=\"off\" role=\"presentation\">\n <mat-form-field\n class=\"filter-input-field\"\n (click)=\"($event)\"\n floatLabel=\"never\">\n <span matPrefix>\n <mat-icon\n matPrefix\n (click)=\"changeVisibilityClick(true, $event)\">search</mat-icon>\n </span>\n\n <input matInput\n [(ngModel)]=\"searchText\"\n name=\"filter-input\"\n #searchTextInput\n (keydown)=\"filterInputEvent($event)\"\n (click)=\"filterInputEvent($event)\"\n class=\"filter-input\"\n (ngModelChange)=\"modelChange(searchText)\">\n\n <mat-placeholder>Search</mat-placeholder>\n <a matSuffix\n *ngIf=\"searchText && showFilterInput\"\n (click)=\"clearSearchText($event)\"\n href=\"javascript:void(0)\"\n class=\"clear\">\n <mat-icon>clear</mat-icon>\n </a>\n <a matSuffix\n (click)=\"reload($event)\"\n href=\"javascript:void(0)\"\n class=\"reload\"\n *ngIf=\"config.reload\">\n <mat-icon>refresh</mat-icon>\n </a>\n <!-- <a (click)=\"changeVisibilityClick(true, $event)\"\n matSuffix\n href=\"javascript:void(0)\"\n class=\"filter\"\n *ngIf=\"config.nonKeywordFilters\">\n <mat-icon>filter_list</mat-icon>\n </a>\n <span class=\"active-filters-counter\"\n matSuffix\n (click)=\"changeVisibilityClick(true,$event)\"\n *ngIf=\"!config.chips && activeFiltersCount > 0\">\n {{ activeFiltersCount }}\n </span>\n <span class=\"active-filters-counter\"\n matSuffix\n (click)=\"changeVisibilityClick(true,$event)\"\n *ngIf=\"!config.chips && activeFiltersWithInputCount > 0\">\n {{ activeFiltersWithInputCount }}\n </span> -->\n </mat-form-field>\n </form>\n </div>\n </div>\n <div class=\"filter-actions\">\n <button (click)=\"changeVisibilityClick(true, $event)\"\n mat-raised-button\n class=\"filter\">\n <mat-icon>tune</mat-icon>\n FILTER\n </button>\n </div>\n </div>\n\n <fs-filter-chips\n class=\"filter-chips\"\n *ngIf=\"config.chips\"\n [filters]=\"changedFilters\"\n (remove)=\"resetFilter($event)\"\n [ngClass]=\"{ 'has-filter-chips': activeFiltersWithInputCount }\">\n </fs-filter-chips>\n</div>\n",
encapsulation: ViewEncapsulation.None,
providers: [
FsFilterOverlayService,
],
styles: [".fs-filter{flex-direction:column;box-sizing:border-box;place-content:stretch flex-start;align-items:stretch;max-width:100%;position:relative;margin-bottom:20px}.fs-filter .title{display:none}.fs-filter.no-input .filter-input-field .mat-input-infix,.fs-filter.no-input .filter-input-field .mat-input-prefix,.fs-filter.no-input .filter-input-field .mat-input-underline{display:none!important}.fs-filter .results{min-height:90px;position:relative;overflow-x:auto;overflow-y:hidden}.fs-filter .status{position:relative}.fs-filter .status .progress-infinite{position:absolute;top:0;width:100%}.fs-filter .filter-chips{display:block}.fs-filter .menu-filter{position:relative}.fs-filter .menu-filter .search{top:8px;position:absolute;margin-left:1px;left:0}.fs-filter .menu-filter .search mat-icon{-webkit-transform:scale(.9);transform:scale(.9)}.fs-filter .menu-filter .menu-filter-input{width:100%}.fs-filter .menu-filter .menu-filter-input .main-filter-bar{height:40px}.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-input-infix{padding-bottom:.3em}.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-form-field-prefix,.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-form-field-suffix{align-self:flex-end;display:flex;align-items:center;white-space:nowrap}.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-form-field-prefix a,.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-form-field-prefix mat-icon,.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-form-field-suffix a,.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-form-field-suffix mat-icon{cursor:pointer;color:initial}.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-form-field-prefix a:hover,.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-form-field-prefix mat-icon:hover,.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-form-field-suffix a:hover,.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-form-field-suffix mat-icon:hover{color:inherit}.fs-filter .menu-filter .menu-filter-input .main-filter-bar .mat-form-field-infix{width:auto}.fs-filter .infinite-records{color:#999;font-size:13px;margin-left:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}.fs-filter .infinite-records .order-toggle{cursor:pointer;padding-left:4px}.fs-filter.keyword-filter .filter-input-field .filter{display:none}.fs-filter.keyword-filter .filter-input-field .mat-form-field-infix,.fs-filter.keyword-filter .filter-input-field .mat-form-field-prefix,.fs-filter.keyword-filter .filter-input-field .mat-form-field-underline{visibility:visible}.main-filter-bar{overflow:hidden}.main-filter-bar .filter-input-field,.main-filter-bar form{width:100%}.main-filter-bar .filter-input-field .mat-form-field-infix,.main-filter-bar .filter-input-field .mat-form-field-prefix,.main-filter-bar .filter-input-field .mat-form-field-underline{visibility:hidden}.main-filter-bar .filter-input-field .mat-form-field-underline{bottom:auto}.main-filter-bar .filter-input-field .mat-form-field-infix{border-top:0}.main-filter-bar .filter-input-field .mat-form-field-wrapper{padding-bottom:0}.main-filter-bar .filter-input-field .mat-form-field-flex{align-items:center}.active-filters-counter{min-width:22px;line-height:22px;height:22px;-webkit-transform:scale(.65);transform:scale(.65);font-size:116%;margin-left:-2px;background:#ccc;border-radius:50%;text-align:center;padding:3px;color:#fff;cursor:pointer}.active-filters-counter.with-input{display:none}button.filter{margin-left:10px}button.reload{margin-left:-40px;right:-9px}@media screen and (max-width:1199px){.fs-filter .reload{display:none}.main-filter-bar .filter-input-field .filter{display:block!important}}@media screen and (min-width:1200px){button.filter{display:none}body.fs-filter-open{margin-right:350px}.fs-filter-backdrop{display:none}}body.fs-filter-open::-webkit-scrollbar{width:0;background:0 0}"]
}] }
];
/** @nocollapse */
FilterComponent.ctorParameters = () => [
{ type: FsStore },
{ type: Location },
{ type: ActivatedRoute },
{ type: Router },
{ type: ApplicationRef },
{ type: Injector },
{ type: FsDocumentScrollService },
{ type: FsFilterOverlayService }
];
FilterComponent.propDecorators = {
setConfig: [{ type: Input, args: ['config',] }],
setFilter: [{ type: Input, args: ['filter',] }],
sortUpdate: [{ type: Input }],
showSortBy: [{ type: Input }],
showFilterInput: [{ type: Input }],
keyEvent: [{ type: HostListener, args: ['window:keyup', ['$event'],] }],
updateWindowWidth: [{ type: HostListener, args: ['window:resize',] }],
searchTextInput: [{ type: ViewChild, args: ['searchTextInput',] }]
};
if (false) {
/**
* @type {?}
* @protected
*/
FilterComponent.prototype._config;
/** @type {?} */
FilterComponent.prototype.sortUpdate;
/** @type {?} */
FilterComponent.prototype.showSortBy;
/** @type {?} */
FilterComponent.prototype.showFilterInput;
/** @type {?} */
FilterComponent.prototype.changedFilters;
/** @type {?} */
FilterComponent.prototype.searchText;
/** @type {?} */
FilterComponent.prototype.persists;
/** @type {?} */
FilterComponent.prototype.activeFiltersCount;
/** @type {?} */
FilterComponent.prototype.activeFiltersWithInputCount;
/** @type {?} */
FilterComponent.prototype.showFilterMenu;
/** @type {?} */
FilterComponent.prototype.modelChanged;
/** @type {?} */
FilterComponent.prototype.windowDesktop;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._searchTextItem;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._searchTextInput;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._firstOpen;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._filterParams;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._sort;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._destroy$;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._store;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._location;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._route;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._router;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._appRef;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._injector;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._documentScrollService;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._filterOverlay;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsdGVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0BmaXJlc3RpdGNoL2ZpbHRlci8iLCJzb3VyY2VzIjpbImFwcC9jb21wb25lbnRzL2ZpbHRlci9maWx0ZXIuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUVULFlBQVksRUFDWixLQUFLLEVBR0wsU0FBUyxFQUNULGlCQUFpQixFQUNqQixZQUFZLEVBQ1osY0FBYyxFQUNkLFFBQVEsRUFDVCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUV6RCxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM3RCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFNUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQy9FLE9BQU8sRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRS9DLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUU1RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDMUQsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDL0UsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBWXRELE1BQU0sT0FBTyxlQUFlOzs7Ozs7Ozs7OztJQWlEMUIsWUFDVSxNQUFlLEVBQ2YsU0FBbUIsRUFD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UTtZQUtELHVCQUF1QjtZQVd2QixzQkFBc0I7Ozt3QkFpQjVCLEtBQUssU0FBQyxRQUFRO3dCQUlkLEtBQUssU0FBQyxRQUFRO3lCQUlkLEtBQUs7eUJBQ0wsS0FBSzs4QkFDTCxLQUFLO3VCQUVMLFlBQVksU0FBQyxjQUFjLEVBQUUsQ0FBQyxRQUFRLENBQUM7Z0NBT3ZDLFlBQVksU0FBQyxlQUFlOzhCQUs1QixTQUFTLFNBQUMsaUJBQWlCOzs7Ozs7O0lBMUI1QixrQ0FBeUM7O0lBVXpDLHFDQUFxRDs7SUFDckQscUNBQXVDOztJQUN2QywwQ0FBdUM7O0lBbUJ2Qyx5Q0FBMkI7O0lBQzNCLHFDQUF1Qjs7SUFDdkIsbUNBQXVCOztJQUN2Qiw2Q0FBOEI7O0lBQzlCLHNEQUF1Qzs7SUFDdkMseUNBQThCOztJQUM5Qix1Q0FBeUM7O0lBQ3pDLHdDQUE2Qjs7Ozs7SUFFN0IsMENBQTRDOzs7OztJQUM1QywyQ0FBNEM7Ozs7O0lBQzVDLHFDQUEwQjs7Ozs7SUFDMUIsd0NBQW9DOzs7OztJQUNwQyxnQ0FBbUI7Ozs7O0lBQ25CLG9DQUFrQzs7Ozs7SUFHaEMsaUNBQXVCOzs7OztJQUN2QixvQ0FBMkI7Ozs7O0lBQzNCLGlDQUE4Qjs7Ozs7SUFDOUIsa0NBQXVCOzs7OztJQUN2QixrQ0FBK0I7Ozs7O0lBQy9CLG9DQUEyQjs7Ozs7SUFDM0IsaURBQXVEOzs7OztJQUN2RCx5Q0FBOEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5wdXQsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBWaWV3Q2hpbGQsXG4gIFZpZXdFbmNhcHN1bGF0aW9uLFxuICBIb3N0TGlzdGVuZXIsXG4gIEFwcGxpY2F0aW9uUmVmLFxuICBJbmplY3RvclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IExvY2F0aW9uIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlLCBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuXG5pbXBvcnQgeyBGc0RvY3VtZW50U2Nyb2xsU2VydmljZSB9IGZyb20gJ0BmaXJlc3RpdGNoL3Njcm9sbCc7XG5pbXBvcnQgeyBGc1N0b3JlIH0gZnJvbSAnQGZpcmVzdGl0Y2gvc3RvcmUnO1xuXG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUsIGRpc3RpbmN0VW50aWxDaGFuZ2VkLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBpc0FmdGVyLCBzdWJNaW51dGVzIH0gZnJvbSAnZGF0ZS1mbnMnO1xuXG5pbXBvcnQgeyBGc0ZpbHRlckNvbmZpZyB9IGZyb20gJy4uLy4uL21vZGVscy9maWx0ZXItY29uZmlnJztcbmltcG9ydCB7IEZzRmlsdGVyQ29uZmlnSXRlbSB9IGZyb20gJy4uLy4uL21vZGVscy9maWx0ZXItaXRlbSc7XG5pbXBvcnQgeyBvYmplY3RzQXJlRXF1YWxzIH0gZnJvbSAnLi4vLi4vaGVscGVycy9jb21wYXJlJztcbmltcG9ydCB7IEZpbHRlclBhcmFtcyB9IGZyb20gJy4uLy4uL21vZGVscy9maWx0ZXItcGFyYW1zJztcbmltcG9ydCB7IEZzRmlsdGVyT3ZlcmxheVNlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9maWx0ZXItb3ZlcmxheS5zZXJ2aWNlJztcbmltcG9ydCB7IEl0ZW1UeXBlIH0gZnJvbSAnLi4vLi4vZW51bXMvaXRlbS10eXBlLmVudW0nO1xuXG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2ZzLWZpbHRlcicsXG4gIHN0eWxlVXJsczogWyAnLi9maWx0ZXIuY29tcG9uZW50LnNjc3MnIF0sXG4gIHRlbXBsYXRlVXJsOiAnLi9maWx0ZXIuY29tcG9uZW50Lmh0bWwnLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICBwcm92aWRlcnM6IFtcbiAgICBGc0ZpbHRlck92ZXJsYXlTZXJ2aWNlLFxuICBdXG59KVxuZXhwb3J0IGNsYXNzIEZpbHRlckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcblxuICBwcm90ZWN0ZWQgX2NvbmZpZzogRnNGaWx0ZXJDb25maWcgPSBudWxsO1xuXG4gIEBJbnB1dCgnY29uZmlnJykgc2V0IHNldENvbmZpZyhjb25maWcpIHtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgfVxuXG4gIEBJbnB1dCgnZmlsdGVyJykgc2V0IHNldEZpbHRlcihjb25maWcpIHtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgfVxuXG4gIEBJbnB1dCgpIHB1YmxpYyBzb3J0VXBkYXRlOiBFdmVudEVtaXR0ZXI8YW55PiA9IG51bGw7XG4gIEBJbnB1dCgpIHB1YmxpYyBzaG93U29ydEJ5OiBhbnkgPSB0cnVlO1xuICBASW5wdXQoKSBwdWJsaWMgc2hvd0ZpbHRlcklucHV0ID0gdHJ1ZTtcblxuICBASG9zdExpc3RlbmVyKCd3aW5kb3c6a2V5dXAnLCBbJyRldmVudCddKVxuICBrZXlFdmVudChldmVudDogS2V5Ym9hcmRFdmVudCkge1xuICAgIGlmIChldmVudC5jb2RlID09PSAnRXNjYXBlJyAmJiB0aGlzLnNob3dGaWx0ZXJNZW51KSB7XG4gICAgICB0aGlzLmNoYW5nZVZpc2liaWxpdHkoZmFsc2UpO1xuICAgIH1cbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ3dpbmRvdzpyZXNpemUnKVxuICB1cGRhdGVXaW5kb3dXaWR0aCgpIHtcbiAgICB0aGlzLndpbmRvd0Rlc2t0b3AgPSB3aW5kb3cuaW5uZXJXaWR0aCA+IDEyMDA7XG4gIH1cblxuICBAVmlld0NoaWxkKCdzZWFyY2hUZXh0SW5wdXQnKVxuICBzZXQgc2VhcmNoVGV4dElucHV0KHZhbHVlKSB7XG4gICAgdGhpcy5fc2VhcmNoVGV4dElucHV0ID0gdmFsdWU7XG4gIH1cblxuICBwdWJsaWMgY2hhbmdlZEZpbHRlcnMgPSBbXTtcbiAgcHVibGljIHNlYXJjaFRleHQgPSAnJztcbiAgcHVibGljIHBlcnNpc3RzID0gbnVsbDtcbiAgcHVibGljIGFjdGl2ZUZpbHRlcnNDb3VudCA9IDA7XG4gIHB1YmxpYyBhY3RpdmVGaWx0ZXJzV2l0aElucHV0Q291bnQgPSAwO1xuICBwdWJsaWMgc2hvd0ZpbHRlck1lbnUgPSBmYWxzZTtcbiAgcHVibGljIG1vZGVsQ2hhbmdlZCA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbiAgcHVibGljIHdpbmRvd0Rlc2t0b3AgPSBmYWxzZTtcblxuICBwcml2YXRlIF9zZWFyY2hUZXh0SXRlbTogRnNGaWx0ZXJDb25maWdJdGVtO1xuICBwcml2YXRlIF9zZWFyY2hUZXh0SW5wdXQ6IEVsZW1lbnRSZWYgPSBudWxsO1xuICBwcml2YXRlIF9maXJzdE9wZW4gPSB0cnVlO1xuICBwcml2YXRlIF9maWx0ZXJQYXJhbXM6IEZpbHRlclBhcmFtcztcbiAgcHJpdmF0ZSBfc29ydCA9IHt9O1xuICBwcml2YXRlIF9kZXN0cm95JCA9IG5ldyBTdWJqZWN0KCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBfc3RvcmU6IEZzU3RvcmUsXG4gICAgcHJpdmF0ZSBfbG9jYXRpb246IExvY2F0aW9uLFxuICAgIHByaXZhdGUgX3JvdXRlOiBBY3RpdmF0ZWRSb3V0ZSxcbiAgICBwcml2YXRlIF9yb3V0ZXI6IFJvdXRlcixcbiAgICBwcml2YXRlIF9hcHBSZWY6IEFwcGxpY2F0aW9uUmVmLFxuICAgIHByaXZhdGUgX2luamVjdG9yOiBJbmplY3RvcixcbiAgICBwcml2YXRlIF9kb2N1bWVudFNjcm9sbFNlcnZpY2U6IEZzRG9jdW1lbnRTY3JvbGxTZXJ2aWNlLFxuICAgIHByaXZhdGUgX2ZpbHRlck92ZXJsYXk6IEZzRmlsdGVyT3ZlcmxheVNlcnZpY2UsXG4gICkge1xuICAgIHRoaXMudXBkYXRlV2luZG93V2lkdGgoKTtcblxuICAgIHRoaXMuX2ZpbHRlck92ZXJsYXkuYXR0YWNoJFxuICAgIC5waXBlKFxuICAgICB0YWtlVW50aWwodGhpcy5fZGVzdHJveSQpXG4gICAgKVxuICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgdGhpcy5zaG93RmlsdGVyTWVudSA9IHRydWU7XG4gICAgfSk7XG5cbiAgICB0aGlzLl9maWx0ZXJPdmVybGF5LmRldGFjaCRcbiAgICAucGlwZShcbiAgICAgIHRha2VVbnRpbCh0aGlzLl9kZXN0cm95JClcbiAgICApXG4gICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLnVwZGF0ZUZpbGxlZENvdW50ZXIoKTtcbiAgICAgIHRoaXMuc2hvd0ZpbHRlck1lbnUgPSBmYWxzZTtcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBzZXQgY29uZmlnKGNvbmZpZykge1xuICAgIHRoaXMuX2NvbmZpZyA9IG5ldyBGc0ZpbHRlckNvbmZpZyhjb25maWcpO1xuICAgIHRoaXMuX3Jlc3RvcmVQZXJzaXN0VmFsdWVzKCk7XG4gICAgdGhpcy5jb25maWcuaW5pdEl0ZW1zKGNvbmZpZy5pdGVtcywgdGhpcy5fcm91dGUsIHRoaXMucGVyc2lzdHMpO1xuXG4gICAgdGhpcy5fZmlsdGVyUGFyYW1zID0gbmV3IEZpbHRlclBhcmFtcyh0aGlzLl9yb3V0ZXIsIHRoaXMuX3JvdXRlLCB0aGlzLmNvbmZpZy5pdGVtcyk7XG4gICAgaWYgKHRoaXMuY29uZmlnLnF1ZXJ5UGFyYW0pIHtcbiAgICAgIHRoaXMuX2ZpbHRlclBhcmFtcy51cGRhdGVGcm9tUXVlcnlQYXJhbXModGhpcy5fcm91dGUuc25hcHNob3QucXVlcnlQYXJhbXMpO1xuICAgIH1cblxuICAgIHRoaXMuX3NlYXJjaFRleHRJdGVtID0gdGhpcy5jb25maWcuaXRlbXMuZmluZCgoaXRlbSkgPT4gaXRlbS5pc1R5cGVLZXl3b3JkKTtcbiAgICBpZiAodGhpcy5fc2VhcmNoVGV4dEl0ZW0pIHtcbiAgICAgIHRoaXMuc2VhcmNoVGV4dCA9IHRoaXMuX3NlYXJjaFRleHRJdGVtLm1vZGVsO1xuICAgIH1cblxuICAgIC8vIENvdW50IGFjdGl2ZSBmaWx0ZXJzIGFmdGVyIHJlc3RvcmVcbiAgICB0aGlzLnVwZGF0ZUZpbGxlZENvdW50ZXIoKTtcblxuICAgIGlmICh0aGlzLmNvbmZpZy5wZXJzaXN0KSB7XG4gICAgICB0aGlzLl9zdG9yZVBlcnNpc3RWYWx1ZXMoKTtcbiAgICB9XG5cbiAgICBpZiAoISF0aGlzLmNvbmZpZy5yZWxvYWRXaGVuQ29uZmlnQ2hhbmdlZCkge1xuICAgICAgdGhpcy5jaGFuZ2UoKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgZ2V0IGNvbmZpZygpIHtcbiAgICByZXR1cm4gdGhpcy5fY29uZmlnO1xuICB9XG5cbiAgcHVibGljIG5nT25Jbml0KCkge1xuXG4gICAgLy8gQXZvaWQgbmdDaGFuZ2VzIGVycm9yXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLmZvY3VzKCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLl93YXRjaFNlYXJjaElucHV0KCk7XG5cbiAgICBpZiAodGhpcy5zb3J0VXBkYXRlKSB7XG4gICAgICB0aGlzLnNvcnRVcGRhdGVc