@firestitch/filter
Version:
703 lines • 60.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 { FsStore } from '@firestitch/store';
import { cloneDeep } from 'lodash-es';
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { isAfter, subMinutes } from 'date-fns';
import { FsFilterConfig } from '../../models/filter-config';
import { ItemType } from '../../models/filter-item';
import { objectsAreEquals } from '../../helpers/compare';
import { QueryParams } from '../../models/query-params';
import { FsDocumentScrollService } from '@firestitch/scroll';
import { FsFilterOverlayService } from '../../services/filter-overlay.service';
import { Subject } from 'rxjs';
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._query = {};
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._searchTextItem = this.config.items.find((/**
* @param {?} item
* @return {?}
*/
(item) => item.type === ItemType.Keyword));
this.searchText = this._searchTextItem.model;
if (this.config.queryParam) {
this._queryParams = new QueryParams(this._router, this._route, this.config.items);
}
// Count active filters after restore
this.updateFilledCounter();
this.storePersistValues();
}
/**
* @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
* @param {?} index
* @return {?}
*/
(item, index) => {
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() {
this._query = this.config.gets({ flatten: true });
this._sort = this.config.getSort();
this.config.init(this._query, 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 query = this.config.gets({ flatten: true });
if (this.config.reload) {
this.config.reload(cloneDeep(query), this.config.getSort());
}
}
/**
* Reset filter
* @param {?} item
* @return {?}
*/
resetFilter(item) {
/** @type {?} */
const index = this.changedFilters.indexOf(item);
if (index > -1) {
this.changedFilters.splice(index, 1);
item.clear();
}
this.change();
}
/**
* Call change callback and apply new filter values
* @return {?}
*/
change() {
this.config.updateModelValues();
/** @type {?} */
const query = this.config.gets({ flatten: true });
/** @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(cloneDeep(query), 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._query = query;
this.storePersistValues();
this.updateFilledCounter();
if (this.config.change) {
this.config.change(cloneDeep(query), sort);
}
if (this.config.queryParam) {
this._queryParams.updateQueryParams(query);
}
}
/**
* 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.config.gets({ expand: true, names: false }),
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>\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}@media screen and (max-width:1199px){.main-filter-bar .filter-input-field .filter{display:block!important}}@media screen and (min-width:1200px){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._filterDrawerRef;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._searchTextItem;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._searchTextInput;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._firstOpen;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._query;
/**
* @type {?}
* @private
*/
FilterComponent.prototype._queryParams;
/**
* @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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsdGVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0BmaXJlc3RpdGNoL2ZpbHRlci8iLCJzb3VyY2VzIjpbImFwcC9jb21wb25lbnRzL2ZpbHRlci9maWx0ZXIuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUVULFlBQVksRUFDWixLQUFLLEVBR0wsU0FBUyxFQUNULGlCQUFpQixFQUNqQixZQUFZLEVBQ1osY0FBYyxFQUNkLFFBQVEsRUFDVCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUV6RCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFNUMsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUN0QyxPQUFPLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQy9FLE9BQU8sRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRS9DLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUM1RCxPQUFPLEVBQXNCLFFBQVEsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM3RCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUMvRSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBWS9CLE1BQU0sT0FBTyxlQUFl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QVksU0FBQyxlQUFlOzhCQUs1QixTQUFTLFNBQUMsaUJBQWlCOzs7Ozs7O0lBMUI1QixrQ0FBeUM7O0lBVXpDLHFDQUFxRDs7SUFDckQscUNBQXVDOztJQUN2QywwQ0FBdUM7O0lBbUJ2Qyx5Q0FBMkI7O0lBQzNCLHFDQUF1Qjs7SUFDdkIsbUNBQXVCOztJQUN2Qiw2Q0FBOEI7O0lBQzlCLHNEQUF1Qzs7SUFDdkMseUNBQThCOztJQUM5Qix1Q0FBeUM7O0lBQ3pDLHdDQUE2Qjs7Ozs7SUFFN0IsMkNBQXlCOzs7OztJQUN6QiwwQ0FBNEM7Ozs7O0lBQzVDLDJDQUE0Qzs7Ozs7SUFDNUMscUNBQTBCOzs7OztJQUMxQixpQ0FBb0I7Ozs7O0lBQ3BCLHVDQUFrQzs7Ozs7SUFDbEMsZ0NBQW1COzs7OztJQUNuQixvQ0FBa0M7Ozs7O0lBR2hDLGlDQUF1Qjs7Ozs7SUFDdkIsb0NBQTJCOzs7OztJQUMzQixpQ0FBOEI7Ozs7O0lBQzlCLGtDQUF1Qjs7Ozs7SUFDdkIsa0NBQStCOzs7OztJQUMvQixvQ0FBMkI7Ozs7O0lBQzNCLGlEQUF1RDs7Ozs7SUFDdkQseUNBQThDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgVmlld0NoaWxkLFxuICBWaWV3RW5jYXBzdWxhdGlvbixcbiAgSG9zdExpc3RlbmVyLFxuICBBcHBsaWNhdGlvblJlZixcbiAgSW5qZWN0b3Jcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBMb2NhdGlvbiB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBBY3RpdmF0ZWRSb3V0ZSwgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcblxuaW1wb3J0IHsgRnNTdG9yZSB9IGZyb20gJ0BmaXJlc3RpdGNoL3N0b3JlJztcblxuaW1wb3J0IHsgY2xvbmVEZWVwIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgZGlzdGluY3RVbnRpbENoYW5nZWQsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IGlzQWZ0ZXIsIHN1Yk1pbnV0ZXMgfSBmcm9tICdkYXRlLWZucyc7XG5cbmltcG9ydCB7IEZzRmlsdGVyQ29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWxzL2ZpbHRlci1jb25maWcnO1xuaW1wb3J0IHsgRnNGaWx0ZXJDb25maWdJdGVtLCBJdGVtVHlwZSB9IGZyb20gJy4uLy4uL21vZGVscy9maWx0ZXItaXRlbSc7XG5pbXBvcnQgeyBvYmplY3RzQXJlRXF1YWxzIH0gZnJvbSAnLi4vLi4vaGVscGVycy9jb21wYXJlJztcbmltcG9ydCB7IFF1ZXJ5UGFyYW1zIH0gZnJvbSAnLi4vLi4vbW9kZWxzL3F1ZXJ5LXBhcmFtcyc7XG5pbXBvcnQgeyBGc0RvY3VtZW50U2Nyb2xsU2VydmljZSB9IGZyb20gJ0BmaXJlc3RpdGNoL3Njcm9sbCc7XG5pbXBvcnQgeyBGc0ZpbHRlck92ZXJsYXlTZXJ2aWNlIH0gZnJvbSAnLi4vLi4vc2VydmljZXMvZmlsdGVyLW92ZXJsYXkuc2VydmljZSc7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnZnMtZmlsdGVyJyxcbiAgc3R5bGVVcmxzOiBbICcuL2ZpbHRlci5jb21wb25lbnQuc2NzcycgXSxcbiAgdGVtcGxhdGVVcmw6ICcuL2ZpbHRlci5jb21wb25lbnQuaHRtbCcsXG4gIGVuY2Fwc3VsYXRpb246IFZpZXdFbmNhcHN1bGF0aW9uLk5vbmUsXG4gIHByb3ZpZGVyczogW1xuICAgIEZzRmlsdGVyT3ZlcmxheVNlcnZpY2UsXG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgRmlsdGVyQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuXG4gIHByb3RlY3RlZCBfY29uZmlnOiBGc0ZpbHRlckNvbmZpZyA9IG51bGw7XG5cbiAgQElucHV0KCdjb25maWcnKSBzZXQgc2V0Q29uZmlnKGNvbmZpZykge1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICB9XG5cbiAgQElucHV0KCdmaWx0ZXInKSBzZXQgc2V0RmlsdGVyKGNvbmZpZykge1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICB9XG5cbiAgQElucHV0KCkgcHVibGljIHNvcnRVcGRhdGU6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbnVsbDtcbiAgQElucHV0KCkgcHVibGljIHNob3dTb3J0Qnk6IGFueSA9IHRydWU7XG4gIEBJbnB1dCgpIHB1YmxpYyBzaG93RmlsdGVySW5wdXQgPSB0cnVlO1xuXG4gIEBIb3N0TGlzdGVuZXIoJ3dpbmRvdzprZXl1cCcsIFsnJGV2ZW50J10pXG4gIGtleUV2ZW50KGV2ZW50OiBLZXlib2FyZEV2ZW50KSB7XG4gICAgaWYgKGV2ZW50LmNvZGUgPT09ICdFc2NhcGUnICYmIHRoaXMuc2hvd0ZpbHRlck1lbnUpIHtcbiAgICAgIHRoaXMuY2hhbmdlVmlzaWJpbGl0eShmYWxzZSk7XG4gICAgfVxuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignd2luZG93OnJlc2l6ZScpXG4gIHVwZGF0ZVdpbmRvd1dpZHRoKCkge1xuICAgIHRoaXMud2luZG93RGVza3RvcCA9IHdpbmRvdy5pbm5lcldpZHRoID4gMTIwMDtcbiAgfVxuXG4gIEBWaWV3Q2hpbGQoJ3NlYXJjaFRleHRJbnB1dCcpXG4gIHNldCBzZWFyY2hUZXh0SW5wdXQodmFsdWUpIHtcbiAgICB0aGlzLl9zZWFyY2hUZXh0SW5wdXQgPSB2YWx1ZTtcbiAgfVxuXG4gIHB1YmxpYyBjaGFuZ2VkRmlsdGVycyA9IFtdO1xuICBwdWJsaWMgc2VhcmNoVGV4dCA9ICcnO1xuICBwdWJsaWMgcGVyc2lzdHMgPSBudWxsO1xuICBwdWJsaWMgYWN0aXZlRmlsdGVyc0NvdW50ID0gMDtcbiAgcHVibGljIGFjdGl2ZUZpbHRlcnNXaXRoSW5wdXRDb3VudCA9IDA7XG4gIHB1YmxpYyBzaG93RmlsdGVyTWVudSA9IGZhbHNlO1xuICBwdWJsaWMgbW9kZWxDaGFuZ2VkID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBwdWJsaWMgd2luZG93RGVza3RvcCA9IGZhbHNlO1xuXG4gIHByaXZhdGUgX2ZpbHRlckRyYXdlclJlZjtcbiAgcHJpdmF0ZSBfc2VhcmNoVGV4dEl0ZW06IEZzRmlsdGVyQ29uZmlnSXRlbTtcbiAgcHJpdmF0ZSBfc2VhcmNoVGV4dElucHV0OiBFbGVtZW50UmVmID0gbnVsbDtcbiAgcHJpdmF0ZSBfZmlyc3RPcGVuID0gdHJ1ZTtcbiAgcHJpdmF0ZSBfcXVlcnkgPSB7fTtcbiAgcHJpdmF0ZSBfcXVlcnlQYXJhbXM6IFF1ZXJ5UGFyYW1zO1xuICBwcml2YXRlIF9zb3J0ID0ge307XG4gIHByaXZhdGUgX2Rlc3Ryb3kkID0gbmV3IFN1YmplY3QoKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIF9zdG9yZTogRnNTdG9yZSxcbiAgICBwcml2YXRlIF9sb2NhdGlvbjogTG9jYXRpb24sXG4gICAgcHJpdmF0ZSBfcm91dGU6IEFjdGl2YXRlZFJvdXRlLFxuICAgIHByaXZhdGUgX3JvdXRlcjogUm91dGVyLFxuICAgIHByaXZhdGUgX2FwcFJlZjogQXBwbGljYXRpb25SZWYsXG4gICAgcHJpdmF0ZSBfaW5qZWN0b3I6IEluamVjdG9yLFxuICAgIHByaXZhdGUgX2RvY3VtZW50U2Nyb2xsU2VydmljZTogRnNEb2N1bWVudFNjcm9sbFNlcnZpY2UsXG4gICAgcHJpdmF0ZSBfZmlsdGVyT3ZlcmxheTogRnNGaWx0ZXJPdmVybGF5U2VydmljZSxcbiAgKSB7XG4gICAgdGhpcy51cGRhdGVXaW5kb3dXaWR0aCgpO1xuXG4gICAgdGhpcy5fZmlsdGVyT3ZlcmxheS5hdHRhY2gkXG4gICAgLnBpcGUoXG4gICAgIHRha2VVbnRpbCh0aGlzLl9kZXN0cm95JClcbiAgICApXG4gICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLnNob3dGaWx0ZXJNZW51ID0gdHJ1ZTtcbiAgICB9KTtcblxuICAgIHRoaXMuX2ZpbHRlck92ZXJsYXkuZGV0YWNoJFxuICAgIC5waXBlKFxuICAgICAgdGFrZVVudGlsKHRoaXMuX2Rlc3Ryb3kkKVxuICAgIClcbiAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIHRoaXMudXBkYXRlRmlsbGVkQ291bnRlcigpO1xuICAgICAgdGhpcy5zaG93RmlsdGVyTWVudSA9IGZhbHNlO1xuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIHNldCBjb25maWcoY29uZmlnKSB7XG4gICAgdGhpcy5fY29uZmlnID0gbmV3IEZzRmlsdGVyQ29uZmlnKGNvbmZpZyk7XG4gICAgdGhpcy5yZXN0b3JlUGVyc2lzdFZhbHVlcygpO1xuICAgIHRoaXMuY29uZmlnLmluaXRJdGVtcyhjb25maWcuaXRlbXMsIHRoaXMuX3JvdXRlLCB0aGlzLnBlcnNpc3RzKTtcblxuICAgIHRoaXMuX3NlYXJjaFRleHRJdGVtID0gdGhpcy5jb25maWcuaXRlbXMuZmluZCgoaXRlbSkgPT4gaXRlbS50eXBlID09PSBJdGVtVHlwZS5LZXl3b3JkKTtcbiAgICB0aGlzLnNlYXJjaFRleHQgPSB0aGlzLl9zZWFyY2hUZXh0SXRlbS5tb2RlbDtcblxuICAgIGlmICh0aGlzLmNvbmZpZy5xdWVyeVBhcmFtKSB7XG4gICAgICB0aGlzLl9xdWVyeVBhcmFtcyA9IG5ldyBRdWVyeVBhcmFtcyh0aGlzLl9yb3V0ZXIsIHRoaXMuX3JvdXRlLCB0aGlzLmNvbmZpZy5pdGVtcyk7XG4gICAgfVxuXG4gICAgLy8gQ291bnQgYWN0aXZlIGZpbHRlcnMgYWZ0ZXIgcmVzdG9yZVxuICAgIHRoaXMudXBkYXRlRmlsbGVkQ291bnRlcigpO1xuXG4gICAgdGhpcy5zdG9yZVBlcnNpc3RWYWx1ZXMoKTtcbiAgfVxuXG4gIHB1YmxpYyBnZXQgY29uZmlnKCkge1xuICAgIHJldHVybiB0aGlzLl9jb25maWc7XG4gIH1cblxuICBwdWJsaWMgbmdPbkluaXQoKSB7XG5cbiAgICAvLyBBdm9pZCBuZ0NoYW5nZXMgZXJyb3JcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMuZm9jdXMoKTtcbiAgICB9KTtcblxuICAgIHRoaXMud2F0Y2hTZWFyY2hJbnB1dCgpO1xuXG4gICAgaWYgKHRoaXMuc29ydFVwZGF0ZSkge1xuICAgICAgdGhpcy5zb3J0VXBkYXRlXG4gICAgICAgIC5waXBlKFxuICAgICAgICAgIHRha2VVbnRpbCh0aGlzLmNvbmZpZy5kZXN0cm95JCksXG4gICAgICAgIClcbiAgICAgICAgLnN1YnNjcmliZSgoZGF0YSkgPT4ge1xuICAgICAgICAgIHRoaXMuY29uZmlnLnVwZGF0ZVNvcnQoZGF0YSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmNvbmZpZy5pbml0KSB7XG4gICAgICB0aGlzLmluaXQoKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgZm9jdXMoKSB7XG4gICAgaWYgKHRoaXMuX3NlYXJjaFRleHRJbnB1dCAmJiB0aGlzLmNvbmZpZy5hdXRvZm9jdXMpIHtcbiAgICAgIHRoaXMuX3NlYXJjaFRleHRJbnB1dC5uYXRpdmVFbGVtZW50LmZvY3VzKCk7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIG5nT25EZXN0cm95KCkge1xuXG4gICAgdGhpcy5kZXN0cm95RmlsdGVyRHJhd2VyKCk7XG4gICAgdGhpcy5fZGVzdHJveSQubmV4dCgpO1xuICAgIHRoaXMuX2Rlc3Ryb3kkLmNvbXBsZXRlKCk7XG5cbiAgICBpZiAodGhpcy5jb25maWcpIHtcbiAgICAgIHRoaXMuY29uZmlnLmRlc3Ryb3koKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICpcbiAgICogRG8gdXBkYXRlIHZhbHVlIG9mIHNvbWUgZmllbGRcbiAgICpcbiAgICogQHBhcmFtIHthbnl9IHZhbHVlcyAtIHZhbHVlcyBmb3IgdXBkYXRlXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gY2hhbmdlRXZlbnQgLSBzaG91bGQgY2hhbmdlIGV2ZW50IHRvIGJlIGZpcmVkXG4gICAqXG4gICAqIFRvIHVwZGF0ZSB0ZXh0IHZhbHVlIGp1c3QgcGFzcyBuZXcgdGV4dCB2YWx1ZVxuICAgKlxuICAgKiBwdWJsaWMgdXBkYXRlU2VsZWN0VmFsdWUodmFsKSB7XG4gICAqICAgdGhpcy5maWx0ZXJFbC51cGRhdGVWYWx1ZXMoeyBrZXl3b3JkOiB2YWwgfSk7XG4gICAqIH1cbiAgICpcbiAgICogVG8gdXBkYXRlIHNlbGVjdCBvciBvYnNlcnZhYmxlIHNlbGVjdCB5b3UgY291bGQgcGFzcyBzdWl0YWJsZSB2YWx1ZVxuICAgKlxuICAgKiBwdWJsaWMgdXBkYXRlU2VsZWN0VmFsdWUodmFsOiBudW1iZXIpIHtcbiAgICogICB0aGlzLmZpbHRlckVsLnVwZGF0ZVZhbHVlcyh7IHNpbXBsZV9zZWxlY3Q6IHZhbCB9LCB7IG9ic2VydmFibGVfc2VsZWN0OiB2YWwgfSk7XG4gICAqIH1cbiAgICpcbiAgICogVG8gdXBkYXRlIGNoZWNrYm94IHZhbHVlIGp1c3QgcGFzcyB0cnVlL2ZhbHNlIGFzIHZhbHVlXG4gICAqXG4gICAqIHB1YmxpYyB1cGRhdGVDaGVja294KHZhbDogYm9vbGVhbikge1xuICAgKiAgIHRoaXMuZmlsdGVyRWwudXBkYXRlVmFsdWVzKHsgY2hlY2tib3g6IHZhbCB9KTtcbiAgICogfVxuICAgKlxuICAgKiBUbyB1cGRhdGUgcmFuZ2UgdmFsdWUganVzdCBwYXNzIG9iamVjd