@sourceloop/search-client 6.1.0 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,395 +0,0 @@
1
- // Copyright (c) 2023 Sourcefuse Technologies
2
- //
3
- // This software is released under the MIT License.
4
- // https://opensource.org/licenses/MIT
5
- import { Component, EventEmitter, Inject, Input, Optional, Output, PLATFORM_ID, ViewChild, } from '@angular/core';
6
- import { Subject } from 'rxjs';
7
- import { debounceTime, tap } from 'rxjs/operators';
8
- import { NG_VALUE_ACCESSOR } from '@angular/forms';
9
- import { SEARCH_SERVICE_TOKEN, DEBOUNCE_TIME, DEFAULT_LIMIT, DEFAULT_LIMIT_TYPE, DEFAULT_OFFSET, DEFAULT_SAVE_IN_RECENTS, DEFAULT_ORDER, isApiServiceWithPromise, } from '../types';
10
- import { isPlatformBrowser } from '@angular/common';
11
- import * as i0 from "@angular/core";
12
- import * as i1 from "./promise-api-adapter.service";
13
- import * as i2 from "@angular/common";
14
- import * as i3 from "@angular/forms";
15
- import * as i4 from "@angular/material/form-field";
16
- import * as i5 from "@angular/material/select";
17
- import * as i6 from "@angular/material/core";
18
- import * as i7 from "@angular/material/icon";
19
- import * as i8 from "@angular/material/input";
20
- import * as i9 from "@angular/flex-layout/flex";
21
- const ALL_LABEL = 'All';
22
- export class SearchComponent {
23
- constructor(searchService,
24
- // tslint:disable-next-line:ban-types
25
- platformId, cdr, promiseAdapter) {
26
- this.searchService = searchService;
27
- this.platformId = platformId;
28
- this.cdr = cdr;
29
- this.promiseAdapter = promiseAdapter;
30
- this.searchBoxInput = '';
31
- this.suggestionsDisplay = false;
32
- this.categoryDisplay = false;
33
- this.searching = false;
34
- this.suggestions = [];
35
- this.recentSearches = [];
36
- this.category = ALL_LABEL;
37
- this.searchRequest$ = new Subject();
38
- /**
39
- * configure when application has own search input and use different all label
40
- */
41
- this.customAllLabel = ALL_LABEL;
42
- /**
43
- * configure to true when to show only search result overlay without search bar
44
- */
45
- this.showOnlySearchResultOverlay = false;
46
- /**
47
- * provide custom search event when showOnlySearchResultOverlay configure to true
48
- */
49
- this.customSearchEvent = {
50
- searchValue: '',
51
- modelName: this.customAllLabel,
52
- };
53
- // emitted when user clicks one of the suggested results (including recent search sugestions)
54
- this.clicked = new EventEmitter();
55
- this.searched = new EventEmitter();
56
- /* emitted when user makes search request (including recent search requests
57
- & requests made on change in category from dropdown)
58
- In case of recent search Array of recent Search request result is emitted */
59
- this.onChange = () => { };
60
- this.onTouched = () => { };
61
- this.disabled = false;
62
- }
63
- get config() {
64
- return this._config;
65
- }
66
- set config(value) {
67
- this._config = value;
68
- if (value && value.models) {
69
- value.models.unshift({
70
- name: ALL_LABEL,
71
- displayName: this.customAllLabel ?? ALL_LABEL,
72
- });
73
- }
74
- else if (value && !value.models) {
75
- value.models = [
76
- {
77
- name: ALL_LABEL,
78
- displayName: this.customAllLabel ?? ALL_LABEL,
79
- },
80
- ];
81
- }
82
- else {
83
- // do nothing
84
- }
85
- }
86
- set searchProvider(value) {
87
- if (isApiServiceWithPromise(value)) {
88
- value = this.promiseAdapter.adapt(value);
89
- }
90
- this.searchService = value;
91
- }
92
- get searchProvider() {
93
- return this.searchService;
94
- }
95
- ngOnInit() {
96
- this.searchRequest$
97
- .pipe(tap(v => (this.suggestions = [])), debounceTime(DEBOUNCE_TIME))
98
- .subscribe((value) => {
99
- this.searched.emit({
100
- event: value.event,
101
- keyword: value.input,
102
- category: this.category,
103
- });
104
- this.getSuggestions(value);
105
- this.cdr.markForCheck();
106
- });
107
- }
108
- // ControlValueAccessor Implementation
109
- writeValue(value) {
110
- this.searchBoxInput = value;
111
- }
112
- // When the value in the UI is changed, this method will invoke a callback function
113
- registerOnChange(fn) {
114
- this.onChange = fn;
115
- }
116
- registerOnTouched(fn) {
117
- this.onTouched = fn;
118
- }
119
- setDisabledState(isDisabled) {
120
- this.disabled = isDisabled;
121
- }
122
- getSuggestions(eventValue) {
123
- eventValue.input = eventValue.input.trim();
124
- if (!eventValue.input.length) {
125
- return;
126
- }
127
- const order = this.config.order ?? DEFAULT_ORDER;
128
- let orderString = '';
129
- order.forEach(preference => (orderString = `${orderString}${preference} `));
130
- let saveInRecents = this.config.saveInRecents ?? DEFAULT_SAVE_IN_RECENTS;
131
- if (this.config.saveInRecents && this.config.saveInRecentsOnlyOnEnter) {
132
- if (!eventValue.event ||
133
- (eventValue.event instanceof KeyboardEvent &&
134
- eventValue.event.key === 'Enter')) {
135
- saveInRecents = true; // save in recents only on enter or change in category
136
- }
137
- else {
138
- // do not save in recent search on typing
139
- saveInRecents = false;
140
- }
141
- }
142
- /* need to put default value here and not in contructor
143
- because sonar was giving code smell with definite assertion as all these
144
- parameters are optional */
145
- const requestParameters = {
146
- match: eventValue.input,
147
- sources: this._categoryToSourceName(this.category),
148
- limit: this.config.limit ?? DEFAULT_LIMIT,
149
- limitByType: this.config.limitByType ?? DEFAULT_LIMIT_TYPE,
150
- order: orderString,
151
- offset: this.config.offset ?? DEFAULT_OFFSET,
152
- };
153
- this.searching = true;
154
- this.cdr.markForCheck();
155
- this.searchService
156
- .searchApiRequest(requestParameters, saveInRecents)
157
- .subscribe((value) => {
158
- this.suggestions = value;
159
- this.searching = false;
160
- this.cdr.markForCheck();
161
- }, (_error) => {
162
- this.suggestions = [];
163
- this.searching = false;
164
- this.cdr.markForCheck();
165
- });
166
- }
167
- getRecentSearches() {
168
- if (!this.config.hideRecentSearch &&
169
- this.searchService.recentSearchApiRequest) {
170
- this.searchService.recentSearchApiRequest().subscribe((value) => {
171
- this.recentSearches = value;
172
- this.cdr.markForCheck();
173
- }, (_error) => {
174
- this.recentSearches = [];
175
- this.cdr.markForCheck();
176
- });
177
- }
178
- }
179
- //event can be KeyBoardEvent or Event of type 'change'
180
- // fired on change in value of drop down for category
181
- hitSearchApi(event) {
182
- // this will happen only in case user searches something and
183
- // then erases it, we need to update recent search
184
- if (!this.searchBoxInput) {
185
- this.suggestions = [];
186
- this.getRecentSearches();
187
- return;
188
- }
189
- // no debounce time needed in case of searchOnlyOnEnter
190
- if (this.config.searchOnlyOnEnter) {
191
- if (!event || (event instanceof KeyboardEvent && event.key === 'Enter')) {
192
- this.getSuggestions({ input: this.searchBoxInput, event });
193
- }
194
- return;
195
- }
196
- // no debounce time needed in case of change in category
197
- if (!event) {
198
- this.getSuggestions({ input: this.searchBoxInput, event });
199
- return;
200
- }
201
- this.searchRequest$.next({
202
- input: this.searchBoxInput,
203
- event,
204
- });
205
- }
206
- populateValue(suggestion, event) {
207
- const value = suggestion[this.config.displayPropertyName];
208
- // converted to string to assign value to searchBoxInput
209
- this.searchBoxInput = value;
210
- this.suggestionsDisplay = false;
211
- // ngModelChange doesn't detect change in value
212
- // when populated from outside, hence calling manually
213
- this.onChange(this.searchBoxInput);
214
- // need to do this to show more search options for selected
215
- //suggestion - just in case user reopens search input
216
- this.getSuggestions({ input: this.searchBoxInput, event });
217
- this.clicked.emit({ item: suggestion, event });
218
- }
219
- populateValueRecentSearch(recentSearch, event) {
220
- event.stopPropagation();
221
- event.preventDefault();
222
- const value = recentSearch['match'];
223
- this.searchBoxInput = value;
224
- this.suggestionsDisplay = false;
225
- this.onChange(this.searchBoxInput);
226
- // need to do this to show more search options for selected
227
- // suggestion - just in case user reopens search input
228
- this.getSuggestions({ input: this.searchBoxInput, event });
229
- this.focusInput();
230
- this.showSuggestions();
231
- }
232
- fetchModelImageUrlFromSuggestion(suggestion) {
233
- const modelName = suggestion['source'];
234
- let url;
235
- this.config.models.forEach(model => {
236
- if (model.name === modelName && model.imageUrl) {
237
- url = model.imageUrl;
238
- }
239
- });
240
- return url;
241
- }
242
- boldString(str, substr) {
243
- const strRegExp = new RegExp(`(${substr})`, 'gi');
244
- const stringToMakeBold = str;
245
- return stringToMakeBold.replace(strRegExp, `<b>$1</b>`);
246
- }
247
- hideSuggestions() {
248
- this.suggestionsDisplay = false;
249
- this.onTouched();
250
- }
251
- showSuggestions() {
252
- this.suggestionsDisplay = true;
253
- this.getRecentSearches();
254
- }
255
- focusInput() {
256
- if (isPlatformBrowser(this.platformId) &&
257
- !this.showOnlySearchResultOverlay) {
258
- this.searchInputElement.nativeElement.focus();
259
- }
260
- }
261
- setCategory(category) {
262
- this.category = category;
263
- this.categoryDisplay = false;
264
- if (this.searchBoxInput) {
265
- this.hitSearchApi();
266
- this.focusInput();
267
- this.showSuggestions();
268
- }
269
- }
270
- showCategory() {
271
- this.categoryDisplay = !this.categoryDisplay;
272
- }
273
- hideCategory() {
274
- this.categoryDisplay = false;
275
- }
276
- resetInput() {
277
- this.searchBoxInput = '';
278
- this.suggestions = [];
279
- this.suggestionsDisplay = true;
280
- this.focusInput();
281
- // ngModelChange doesn't detect change in value
282
- // when populated from outside, hence calling manually
283
- this.onChange(this.searchBoxInput);
284
- this.getRecentSearches();
285
- }
286
- ngOnDestroy() {
287
- this.searchRequest$.unsubscribe();
288
- }
289
- _categoryToSourceName(category) {
290
- if ([ALL_LABEL, this.customAllLabel].includes(category)) {
291
- return [];
292
- }
293
- else {
294
- return [category];
295
- }
296
- }
297
- getModelFromModelName(name) {
298
- return this.config.models.find(item => item.name === name);
299
- }
300
- getModelsWithSuggestions() {
301
- const modelsWithSuggestions = [];
302
- const sources = [];
303
- this.suggestions.forEach(suggestion => {
304
- if (sources.indexOf(suggestion['source']) >= 0) {
305
- modelsWithSuggestions.every(modelWithSuggestions => {
306
- if (modelWithSuggestions.model.name === suggestion['source']) {
307
- modelWithSuggestions.items.push(suggestion);
308
- return false;
309
- }
310
- return true;
311
- });
312
- }
313
- else {
314
- const model = this.getModelFromModelName(suggestion['source']);
315
- modelsWithSuggestions.push({ model, items: [suggestion] });
316
- sources.push(suggestion['source']);
317
- }
318
- });
319
- return modelsWithSuggestions;
320
- }
321
- ngOnChanges(changes) {
322
- if (changes.customSearchEvent) {
323
- if (this._isCustomSearchEventChange(changes, 'searchValue')) {
324
- this.searchBoxInput = this.customSearchEvent?.searchValue ?? '';
325
- this.searchOnCustomEventValueChange(this.searchBoxInput);
326
- }
327
- if (this._isCustomSearchEventChange(changes, 'modelName') &&
328
- this.customSearchEvent?.modelName) {
329
- this.setCategory(this.customSearchEvent?.modelName);
330
- }
331
- }
332
- }
333
- searchOnCustomEventValueChange(value) {
334
- if (value?.length) {
335
- this.showSuggestions();
336
- this.hitSearchApi();
337
- }
338
- else {
339
- this.hideSuggestions();
340
- }
341
- }
342
- _isCustomSearchEventChange(changes, propertyName) {
343
- return (!changes.customSearchEvent?.previousValue ||
344
- changes.customSearchEvent?.previousValue[propertyName] !==
345
- changes.customSearchEvent?.currentValue[propertyName]);
346
- }
347
- }
348
- SearchComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SearchComponent, deps: [{ token: SEARCH_SERVICE_TOKEN, optional: true }, { token: PLATFORM_ID }, { token: i0.ChangeDetectorRef }, { token: i1.PromiseApiAdapterService }], target: i0.ɵɵFactoryTarget.Component });
349
- SearchComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: SearchComponent, selector: "sourceloop-search", inputs: { config: "config", searchProvider: "searchProvider", titleTemplate: "titleTemplate", subtitleTemplate: "subtitleTemplate", customAllLabel: "customAllLabel", showOnlySearchResultOverlay: "showOnlySearchResultOverlay", customSearchEvent: "customSearchEvent" }, outputs: { clicked: "clicked", searched: "searched" }, providers: [
350
- {
351
- provide: NG_VALUE_ACCESSOR,
352
- useExisting: SearchComponent,
353
- multi: true,
354
- },
355
- ], viewQueries: [{ propertyName: "searchInputElement", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"!showOnlySearchResultOverlay\">\n <div fxLayout fxLayoutAlign=\"start center\" class=\"toolbar-search\" *ngIf=\"config\">\n <mat-form-field appearance=\"outline\" class=\"toolbar-search-input\">\n <input\n matInput\n autocomplete=\"off\"\n type=\"text\"\n [placeholder]=\"\n config.placeholderFunction\n ? config.placeholderFunction(searchInput.value, category)\n : config.placeholder || 'Search'\n \"\n #searchInput\n name=\"searchInput\"\n (focus)=\"showSuggestions()\"\n (blur)=\"hideSuggestions()\"\n [(ngModel)]=\"searchBoxInput\"\n (keyup)=\"hitSearchApi($event)\"\n placeholder=\"Search\"\n (ngModelChange)=\"onChange(this.searchBoxInput)\"\n [disabled]=\"disabled\"\n />\n <mat-icon matPrefix [className]=\"config.searchIconClass\"></mat-icon>\n <mat-icon\n *ngIf=\"searchBoxInput\"\n matSuffix\n [className]=\"config.crossIconClass\"\n (click)=\"resetInput()\"\n ></mat-icon>\n </mat-form-field>\n \n <mat-form-field appearance=\"outline\" class=\"toolbar-search-select\">\n <mat-icon matSuffix [className]=\"config.dropDownButtonIconClass\"></mat-icon>\n <mat-select\n [value]=\"category\"\n (selectionChange)=\"setCategory($event.value)\"\n panelClass=\"search-select\"\n >\n <mat-option [value]=\"model.name\" *ngFor=\"let model of config.models\">\n {{ model.displayName }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n</ng-container>\n\n<div class=\"search-container\">\n <div\n *ngIf=\"suggestionsDisplay && (recentSearches.length || suggestions.length)\"\n class=\"search-popup\"\n >\n <ng-container *ngIf=\"searchBoxInput\">\n <span *ngIf=\"suggestions.length === 0\" class=\"search-message\">\n <ng-container *ngIf=\"searching\"> searching... </ng-container>\n <ng-container *ngIf=\"!searching\">\n {{ config.noResultMessage }}\n </ng-container>\n </span>\n <ng-container *ngIf=\"config.categorizeResults && suggestions.length\">\n <div\n class=\"search-result\"\n *ngFor=\"let modelWithSuggestions of getModelsWithSuggestions()\"\n >\n <h3 class=\"suggestions-heading\">\n <img\n *ngIf=\"modelWithSuggestions.model.imageUrl\"\n [src]=\"modelWithSuggestions.model.imageUrl\"\n [alt]=\"modelWithSuggestions.model.displayName\"\n />\n {{ modelWithSuggestions.model.displayName }} ({{\n modelWithSuggestions.items.length\n }})\n </h3>\n <ul>\n <li\n *ngFor=\"let suggestion of modelWithSuggestions.items\"\n (mousedown)=\"populateValue(suggestion, $event)\"\n class=\"suggestions\"\n >\n <ng-container *ngIf=\"subtitleTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n subtitleTemplate;\n context: {$implicit: suggestion}\n \"\n >\n </ng-container>\n </ng-container>\n <p\n *ngIf=\"!titleTemplate\"\n [innerHTML]=\"\n boldString(\n suggestion[config.displayPropertyName],\n searchBoxInput\n )\n \"\n style=\"display: inline\"\n ></p>\n <ng-container *ngIf=\"titleTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n titleTemplate;\n context: {$implicit: suggestion}\n \"\n >\n </ng-container>\n </ng-container>\n </li>\n </ul>\n </div>\n </ng-container>\n <ng-container *ngIf=\"!config.categorizeResults\">\n <div class=\"search-result\">\n <ul>\n <li\n *ngFor=\"let suggestion of suggestions\"\n (mousedown)=\"populateValue(suggestion, $event)\"\n >\n <!--Need to call fetchModelImageUrlFromSuggestion as each suggestion can come from different model-->\n <img\n *ngIf=\"\n !titleTemplate && fetchModelImageUrlFromSuggestion(suggestion)\n \"\n class=\"suggestions-categorize-false\"\n [src]=\"fetchModelImageUrlFromSuggestion(suggestion)\"\n style=\"margin-right: 5px\"\n alt=\"Img\"\n />\n <ng-container *ngIf=\"subtitleTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n subtitleTemplate;\n context: {$implicit: suggestion}\n \"\n >\n </ng-container>\n </ng-container>\n <p\n *ngIf=\"!titleTemplate\"\n [innerHTML]=\"\n boldString(\n suggestion[config.displayPropertyName],\n searchBoxInput\n )\n \"\n style=\"display: inline\"\n ></p>\n <ng-container *ngIf=\"titleTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n titleTemplate;\n context: {$implicit: suggestion}\n \"\n >\n </ng-container>\n </ng-container>\n </li>\n </ul>\n </div>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"!config.hideRecentSearch && recentSearches.length > 0\">\n <div class=\"recent-searches\">\n <h3 class=\"suggestions-heading\">Recent Searches</h3>\n <ul>\n <li\n *ngFor=\"let recentSearch of recentSearches\"\n class=\"suggestions\"\n (mousedown)=\"populateValueRecentSearch(recentSearch, $event)\"\n >\n <mat-icon\n matPrefix\n [className]=\"config.recentSearchIconClass\"\n ></mat-icon>\n\n <span>&nbsp;{{ recentSearch.match }}</span>\n </li>\n </ul>\n </div>\n </ng-container>\n </div>\n</div>\n", styles: [":host ::ng-deep .mat-form-field-wrapper{padding:0}:host ::ng-deep .mat-form-field-wrapper .mat-form-field-prefix{margin-right:12px}.toolbar-search-input{width:86%}.toolbar-search-input ::ng-deep input{margin:0}.toolbar-search-input ::ng-deep .mat-form-field-flex .mat-form-field-outline:first-child .mat-form-field-outline-start{border-color:transparent}.toolbar-search-input ::ng-deep .mat-form-field-flex .mat-form-field-outline:first-child .mat-form-field-outline-end{border:none;border-radius:0}.icomoon.Search,.icomoon.close{height:1rem;width:1rem;font-size:1rem;color:#33333380;padding-bottom:4px}.icomoon.close{cursor:pointer}.toolbar-search-select{width:14%}.toolbar-search-select ::ng-deep .mat-select-arrow{opacity:0}.toolbar-search-select ::ng-deep .mat-select-arrow-wrapper{display:inline-block;width:1px}.toolbar-search-select ::ng-deep .mat-select-value-text{font-size:9px}.toolbar-search-select ::ng-deep .mat-form-field-suffix .mat-icon{width:12px;font-size:14px}.toolbar-search-select ::ng-deep .mat-form-field-flex .mat-form-field-outline:first-child .mat-form-field-outline-start{border-color:transparent;border-radius:0}.toolbar-search-select ::ng-deep .mat-form-field-flex .mat-form-field-outline:first-child .mat-form-field-outline-end{border:none}.toolbar-search-select ::ng-deep .mat-form-field-flex .mat-form-field-infix{-webkit-padding-before:.7em}.toolbar-search{width:515px;background-color:#f7f7f7;border-radius:0 0 4px 4px}.toolbar-search ::ng-deep .mat-form-field-appearance-outline .mat-form-field-flex{height:39px;align-items:center}.toolbar-search ::ng-deep .mat-form-field-appearance-outline .mat-form-field-wrapper{margin:0}.toolbar-search ::ng-deep .mat-form-field-infix{height:auto}.search-container{position:relative;width:515px}.search-container .search-popup{padding:0 15px 15px;margin:0;max-height:80vh;overflow-x:hidden;overflow-y:auto;position:absolute;top:100%;left:0;right:0;z-index:9999;background-color:#fff;box-shadow:0 5px 4px #0003;border-radius:0 0 4px 4px}.search-container .search-popup hr{border:0;border-top:1px solid #ebebeb;margin:0;position:sticky;top:0;padding:0 0 15px;z-index:1}.search-container .search-popup .search-message{display:inline-block;width:100%;text-align:center;font-size:16px;padding-top:12px}.search-container .search-popup .search-item-info{color:#91263b;text-align:center;font-size:12px;margin-bottom:15px;padding-top:12px}.search-container .search-popup ul{padding:0;margin:0}.search-container .search-popup ul li{list-style:none;font-size:1rem;font-weight:400;line-height:1.5;color:#333}.search-container .search-popup ul li.suggestions{font-size:15px;line-height:36px;padding:0 15px 0 44px;align-items:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}.search-container .search-popup ul li.suggestions:hover{background-color:#fee8e8}.search-container .search-popup ul li.suggestions svg{margin-right:5px}.search-container .search-popup ul li.suggestions-categorize-false:hover{background-color:#fee8e8}.search-container .search-popup .search-result{padding:10px 0 0;margin:0 -15px}.search-container .search-popup .search-result.no-categorize-result ul{width:100%;padding:0;margin:0 0 10px}.search-container .search-popup .search-result.no-categorize-result ul li{font-size:15px;line-height:36px;padding:0 15px 0 31px;display:flex;align-items:center;cursor:pointer}.search-container .search-popup .search-result.no-categorize-result ul li:hover{background-color:#fee8e8}.search-container .search-popup .search-result.no-categorize-result ul li img{width:18px;margin-right:9px}.search-container .search-popup .suggestions-heading{color:#9c9c9c;font-size:14px;font-weight:400;margin:0 0 10px 17px;display:flex;align-items:center;position:relative}.search-container .search-popup .suggestions-heading .show-more{position:absolute;right:20px;color:#d1d1d1;font-size:12px;cursor:pointer;text-decoration:none}.search-container .search-popup .suggestions-heading .show-more :hover{text-decoration:underline}.search-container .search-popup .suggestions-heading img{width:18px;margin-right:9px}.search-container .search-popup .recent-searches{padding:10px 0 0;margin:0 -15px}.search-container .search-popup .recent-searches ul{display:inline-block;width:100%}.search-container .search-popup .recent-searches ul li.suggestions{display:flex}.search-container .search-popup .recent-searches ul li.suggestions span{width:100%;overflow:hidden;text-overflow:ellipsis}.search-container .search-popup .recent-searches .suggestions{display:flex}.search-container .search-popup .recent-searches .suggestions-heading{margin-left:30px}.search-container .search-popup .recent-searches li.suggestions{padding-left:31px}::ng-deep .search-select.mat-select-panel{margin-top:30px;margin-left:10px}::ng-deep .search-select .mat-option-text{display:contents}::ng-deep .toolbar-search .mat-form-field-infix{font-size:14px}::ng-deep .toolbar-search input{line-height:14px}::ng-deep .toolbar-search .mat-form-field-outline:first-child .mat-form-field-outline-start,::ng-deep .toolbar-search .mat-form-field-outline:first-child .mat-form-field-outline-end{background-color:#f1f3f4}::ng-deep .toolbar-search:hover .toolbar-search-input.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-start{border-width:1px;border-color:#a53159}::ng-deep .toolbar-search:hover .toolbar-search-input.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-end{border:1px solid #a53159;border-left-style:none;border-right-style:none;border-top-right-radius:0;border-bottom-right-radius:0}::ng-deep .toolbar-search:hover .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-start{border-radius:0;border-color:transparent;background-color:#a53159}::ng-deep .toolbar-search:hover .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-end{border-width:1px;border-color:#a53159;background-color:#a53159}::ng-deep .toolbar-search:hover .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-select{color:#fff}::ng-deep .toolbar-search:hover .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .icomoon.arrow_down{color:#fff}::ng-deep .toolbar-search:focus-within .toolbar-search-input.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-start{border-width:2px;border-color:#90003b}::ng-deep .toolbar-search:focus-within .toolbar-search-input.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-end{border:2px solid #90003b;border-left-style:none;border-right-style:none;border-top-right-radius:0;border-bottom-right-radius:0}::ng-deep .toolbar-search:focus-within .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-start{border-radius:0;border-color:transparent;background-color:#90003b}::ng-deep .toolbar-search:focus-within .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-end{border-width:2px;border-color:#90003b;background-color:#90003b}::ng-deep .toolbar-search:focus-within .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-select{color:#fff}::ng-deep .toolbar-search:focus-within .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .icomoon.arrow_down{color:#fff}::ng-deep .toolbar-search .mat-select-arrow{opacity:0}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatPrefix, selector: "[matPrefix]" }, { kind: "directive", type: i4.MatSuffix, selector: "[matSuffix]" }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i8.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: i9.DefaultLayoutDirective, selector: " [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { kind: "directive", type: i9.DefaultLayoutAlignDirective, selector: " [fxLayoutAlign], [fxLayoutAlign.xs], [fxLayoutAlign.sm], [fxLayoutAlign.md], [fxLayoutAlign.lg], [fxLayoutAlign.xl], [fxLayoutAlign.lt-sm], [fxLayoutAlign.lt-md], [fxLayoutAlign.lt-lg], [fxLayoutAlign.lt-xl], [fxLayoutAlign.gt-xs], [fxLayoutAlign.gt-sm], [fxLayoutAlign.gt-md], [fxLayoutAlign.gt-lg]", inputs: ["fxLayoutAlign", "fxLayoutAlign.xs", "fxLayoutAlign.sm", "fxLayoutAlign.md", "fxLayoutAlign.lg", "fxLayoutAlign.xl", "fxLayoutAlign.lt-sm", "fxLayoutAlign.lt-md", "fxLayoutAlign.lt-lg", "fxLayoutAlign.lt-xl", "fxLayoutAlign.gt-xs", "fxLayoutAlign.gt-sm", "fxLayoutAlign.gt-md", "fxLayoutAlign.gt-lg"] }] });
356
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: SearchComponent, decorators: [{
357
- type: Component,
358
- args: [{ selector: 'sourceloop-search', providers: [
359
- {
360
- provide: NG_VALUE_ACCESSOR,
361
- useExisting: SearchComponent,
362
- multi: true,
363
- },
364
- ], template: "<ng-container *ngIf=\"!showOnlySearchResultOverlay\">\n <div fxLayout fxLayoutAlign=\"start center\" class=\"toolbar-search\" *ngIf=\"config\">\n <mat-form-field appearance=\"outline\" class=\"toolbar-search-input\">\n <input\n matInput\n autocomplete=\"off\"\n type=\"text\"\n [placeholder]=\"\n config.placeholderFunction\n ? config.placeholderFunction(searchInput.value, category)\n : config.placeholder || 'Search'\n \"\n #searchInput\n name=\"searchInput\"\n (focus)=\"showSuggestions()\"\n (blur)=\"hideSuggestions()\"\n [(ngModel)]=\"searchBoxInput\"\n (keyup)=\"hitSearchApi($event)\"\n placeholder=\"Search\"\n (ngModelChange)=\"onChange(this.searchBoxInput)\"\n [disabled]=\"disabled\"\n />\n <mat-icon matPrefix [className]=\"config.searchIconClass\"></mat-icon>\n <mat-icon\n *ngIf=\"searchBoxInput\"\n matSuffix\n [className]=\"config.crossIconClass\"\n (click)=\"resetInput()\"\n ></mat-icon>\n </mat-form-field>\n \n <mat-form-field appearance=\"outline\" class=\"toolbar-search-select\">\n <mat-icon matSuffix [className]=\"config.dropDownButtonIconClass\"></mat-icon>\n <mat-select\n [value]=\"category\"\n (selectionChange)=\"setCategory($event.value)\"\n panelClass=\"search-select\"\n >\n <mat-option [value]=\"model.name\" *ngFor=\"let model of config.models\">\n {{ model.displayName }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n</ng-container>\n\n<div class=\"search-container\">\n <div\n *ngIf=\"suggestionsDisplay && (recentSearches.length || suggestions.length)\"\n class=\"search-popup\"\n >\n <ng-container *ngIf=\"searchBoxInput\">\n <span *ngIf=\"suggestions.length === 0\" class=\"search-message\">\n <ng-container *ngIf=\"searching\"> searching... </ng-container>\n <ng-container *ngIf=\"!searching\">\n {{ config.noResultMessage }}\n </ng-container>\n </span>\n <ng-container *ngIf=\"config.categorizeResults && suggestions.length\">\n <div\n class=\"search-result\"\n *ngFor=\"let modelWithSuggestions of getModelsWithSuggestions()\"\n >\n <h3 class=\"suggestions-heading\">\n <img\n *ngIf=\"modelWithSuggestions.model.imageUrl\"\n [src]=\"modelWithSuggestions.model.imageUrl\"\n [alt]=\"modelWithSuggestions.model.displayName\"\n />\n {{ modelWithSuggestions.model.displayName }} ({{\n modelWithSuggestions.items.length\n }})\n </h3>\n <ul>\n <li\n *ngFor=\"let suggestion of modelWithSuggestions.items\"\n (mousedown)=\"populateValue(suggestion, $event)\"\n class=\"suggestions\"\n >\n <ng-container *ngIf=\"subtitleTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n subtitleTemplate;\n context: {$implicit: suggestion}\n \"\n >\n </ng-container>\n </ng-container>\n <p\n *ngIf=\"!titleTemplate\"\n [innerHTML]=\"\n boldString(\n suggestion[config.displayPropertyName],\n searchBoxInput\n )\n \"\n style=\"display: inline\"\n ></p>\n <ng-container *ngIf=\"titleTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n titleTemplate;\n context: {$implicit: suggestion}\n \"\n >\n </ng-container>\n </ng-container>\n </li>\n </ul>\n </div>\n </ng-container>\n <ng-container *ngIf=\"!config.categorizeResults\">\n <div class=\"search-result\">\n <ul>\n <li\n *ngFor=\"let suggestion of suggestions\"\n (mousedown)=\"populateValue(suggestion, $event)\"\n >\n <!--Need to call fetchModelImageUrlFromSuggestion as each suggestion can come from different model-->\n <img\n *ngIf=\"\n !titleTemplate && fetchModelImageUrlFromSuggestion(suggestion)\n \"\n class=\"suggestions-categorize-false\"\n [src]=\"fetchModelImageUrlFromSuggestion(suggestion)\"\n style=\"margin-right: 5px\"\n alt=\"Img\"\n />\n <ng-container *ngIf=\"subtitleTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n subtitleTemplate;\n context: {$implicit: suggestion}\n \"\n >\n </ng-container>\n </ng-container>\n <p\n *ngIf=\"!titleTemplate\"\n [innerHTML]=\"\n boldString(\n suggestion[config.displayPropertyName],\n searchBoxInput\n )\n \"\n style=\"display: inline\"\n ></p>\n <ng-container *ngIf=\"titleTemplate\">\n <ng-container\n *ngTemplateOutlet=\"\n titleTemplate;\n context: {$implicit: suggestion}\n \"\n >\n </ng-container>\n </ng-container>\n </li>\n </ul>\n </div>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"!config.hideRecentSearch && recentSearches.length > 0\">\n <div class=\"recent-searches\">\n <h3 class=\"suggestions-heading\">Recent Searches</h3>\n <ul>\n <li\n *ngFor=\"let recentSearch of recentSearches\"\n class=\"suggestions\"\n (mousedown)=\"populateValueRecentSearch(recentSearch, $event)\"\n >\n <mat-icon\n matPrefix\n [className]=\"config.recentSearchIconClass\"\n ></mat-icon>\n\n <span>&nbsp;{{ recentSearch.match }}</span>\n </li>\n </ul>\n </div>\n </ng-container>\n </div>\n</div>\n", styles: [":host ::ng-deep .mat-form-field-wrapper{padding:0}:host ::ng-deep .mat-form-field-wrapper .mat-form-field-prefix{margin-right:12px}.toolbar-search-input{width:86%}.toolbar-search-input ::ng-deep input{margin:0}.toolbar-search-input ::ng-deep .mat-form-field-flex .mat-form-field-outline:first-child .mat-form-field-outline-start{border-color:transparent}.toolbar-search-input ::ng-deep .mat-form-field-flex .mat-form-field-outline:first-child .mat-form-field-outline-end{border:none;border-radius:0}.icomoon.Search,.icomoon.close{height:1rem;width:1rem;font-size:1rem;color:#33333380;padding-bottom:4px}.icomoon.close{cursor:pointer}.toolbar-search-select{width:14%}.toolbar-search-select ::ng-deep .mat-select-arrow{opacity:0}.toolbar-search-select ::ng-deep .mat-select-arrow-wrapper{display:inline-block;width:1px}.toolbar-search-select ::ng-deep .mat-select-value-text{font-size:9px}.toolbar-search-select ::ng-deep .mat-form-field-suffix .mat-icon{width:12px;font-size:14px}.toolbar-search-select ::ng-deep .mat-form-field-flex .mat-form-field-outline:first-child .mat-form-field-outline-start{border-color:transparent;border-radius:0}.toolbar-search-select ::ng-deep .mat-form-field-flex .mat-form-field-outline:first-child .mat-form-field-outline-end{border:none}.toolbar-search-select ::ng-deep .mat-form-field-flex .mat-form-field-infix{-webkit-padding-before:.7em}.toolbar-search{width:515px;background-color:#f7f7f7;border-radius:0 0 4px 4px}.toolbar-search ::ng-deep .mat-form-field-appearance-outline .mat-form-field-flex{height:39px;align-items:center}.toolbar-search ::ng-deep .mat-form-field-appearance-outline .mat-form-field-wrapper{margin:0}.toolbar-search ::ng-deep .mat-form-field-infix{height:auto}.search-container{position:relative;width:515px}.search-container .search-popup{padding:0 15px 15px;margin:0;max-height:80vh;overflow-x:hidden;overflow-y:auto;position:absolute;top:100%;left:0;right:0;z-index:9999;background-color:#fff;box-shadow:0 5px 4px #0003;border-radius:0 0 4px 4px}.search-container .search-popup hr{border:0;border-top:1px solid #ebebeb;margin:0;position:sticky;top:0;padding:0 0 15px;z-index:1}.search-container .search-popup .search-message{display:inline-block;width:100%;text-align:center;font-size:16px;padding-top:12px}.search-container .search-popup .search-item-info{color:#91263b;text-align:center;font-size:12px;margin-bottom:15px;padding-top:12px}.search-container .search-popup ul{padding:0;margin:0}.search-container .search-popup ul li{list-style:none;font-size:1rem;font-weight:400;line-height:1.5;color:#333}.search-container .search-popup ul li.suggestions{font-size:15px;line-height:36px;padding:0 15px 0 44px;align-items:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}.search-container .search-popup ul li.suggestions:hover{background-color:#fee8e8}.search-container .search-popup ul li.suggestions svg{margin-right:5px}.search-container .search-popup ul li.suggestions-categorize-false:hover{background-color:#fee8e8}.search-container .search-popup .search-result{padding:10px 0 0;margin:0 -15px}.search-container .search-popup .search-result.no-categorize-result ul{width:100%;padding:0;margin:0 0 10px}.search-container .search-popup .search-result.no-categorize-result ul li{font-size:15px;line-height:36px;padding:0 15px 0 31px;display:flex;align-items:center;cursor:pointer}.search-container .search-popup .search-result.no-categorize-result ul li:hover{background-color:#fee8e8}.search-container .search-popup .search-result.no-categorize-result ul li img{width:18px;margin-right:9px}.search-container .search-popup .suggestions-heading{color:#9c9c9c;font-size:14px;font-weight:400;margin:0 0 10px 17px;display:flex;align-items:center;position:relative}.search-container .search-popup .suggestions-heading .show-more{position:absolute;right:20px;color:#d1d1d1;font-size:12px;cursor:pointer;text-decoration:none}.search-container .search-popup .suggestions-heading .show-more :hover{text-decoration:underline}.search-container .search-popup .suggestions-heading img{width:18px;margin-right:9px}.search-container .search-popup .recent-searches{padding:10px 0 0;margin:0 -15px}.search-container .search-popup .recent-searches ul{display:inline-block;width:100%}.search-container .search-popup .recent-searches ul li.suggestions{display:flex}.search-container .search-popup .recent-searches ul li.suggestions span{width:100%;overflow:hidden;text-overflow:ellipsis}.search-container .search-popup .recent-searches .suggestions{display:flex}.search-container .search-popup .recent-searches .suggestions-heading{margin-left:30px}.search-container .search-popup .recent-searches li.suggestions{padding-left:31px}::ng-deep .search-select.mat-select-panel{margin-top:30px;margin-left:10px}::ng-deep .search-select .mat-option-text{display:contents}::ng-deep .toolbar-search .mat-form-field-infix{font-size:14px}::ng-deep .toolbar-search input{line-height:14px}::ng-deep .toolbar-search .mat-form-field-outline:first-child .mat-form-field-outline-start,::ng-deep .toolbar-search .mat-form-field-outline:first-child .mat-form-field-outline-end{background-color:#f1f3f4}::ng-deep .toolbar-search:hover .toolbar-search-input.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-start{border-width:1px;border-color:#a53159}::ng-deep .toolbar-search:hover .toolbar-search-input.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-end{border:1px solid #a53159;border-left-style:none;border-right-style:none;border-top-right-radius:0;border-bottom-right-radius:0}::ng-deep .toolbar-search:hover .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-start{border-radius:0;border-color:transparent;background-color:#a53159}::ng-deep .toolbar-search:hover .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-end{border-width:1px;border-color:#a53159;background-color:#a53159}::ng-deep .toolbar-search:hover .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-select{color:#fff}::ng-deep .toolbar-search:hover .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .icomoon.arrow_down{color:#fff}::ng-deep .toolbar-search:focus-within .toolbar-search-input.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-start{border-width:2px;border-color:#90003b}::ng-deep .toolbar-search:focus-within .toolbar-search-input.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-end{border:2px solid #90003b;border-left-style:none;border-right-style:none;border-top-right-radius:0;border-bottom-right-radius:0}::ng-deep .toolbar-search:focus-within .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-start{border-radius:0;border-color:transparent;background-color:#90003b}::ng-deep .toolbar-search:focus-within .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-form-field-outline .mat-form-field-outline-end{border-width:2px;border-color:#90003b;background-color:#90003b}::ng-deep .toolbar-search:focus-within .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .mat-select{color:#fff}::ng-deep .toolbar-search:focus-within .toolbar-search-select.mat-form-field:not(.mat-form-field-disabled) .icomoon.arrow_down{color:#fff}::ng-deep .toolbar-search .mat-select-arrow{opacity:0}\n"] }]
365
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
366
- type: Inject,
367
- args: [SEARCH_SERVICE_TOKEN]
368
- }, {
369
- type: Optional
370
- }] }, { type: Object, decorators: [{
371
- type: Inject,
372
- args: [PLATFORM_ID]
373
- }] }, { type: i0.ChangeDetectorRef }, { type: i1.PromiseApiAdapterService }]; }, propDecorators: { config: [{
374
- type: Input
375
- }], searchProvider: [{
376
- type: Input
377
- }], titleTemplate: [{
378
- type: Input
379
- }], subtitleTemplate: [{
380
- type: Input
381
- }], customAllLabel: [{
382
- type: Input
383
- }], showOnlySearchResultOverlay: [{
384
- type: Input
385
- }], customSearchEvent: [{
386
- type: Input
387
- }], clicked: [{
388
- type: Output
389
- }], searched: [{
390
- type: Output
391
- }], searchInputElement: [{
392
- type: ViewChild,
393
- args: ['searchInput']
394
- }] } });
395
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VhcmNoLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvc2VhcmNoL3NlYXJjaC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9zcmMvbGliL3NlYXJjaC9zZWFyY2guY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsNkNBQTZDO0FBQzdDLEVBQUU7QUFDRixtREFBbUQ7QUFDbkQsc0NBQXNDO0FBQ3RDLE9BQU8sRUFFTCxTQUFTLEVBRVQsWUFBWSxFQUNaLE1BQU0sRUFDTixLQUFLLEVBR0wsUUFBUSxFQUNSLE1BQU0sRUFDTixXQUFXLEVBR1gsU0FBUyxHQUNWLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFBQyxPQUFPLEVBQUMsTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFDLFlBQVksRUFBRSxHQUFHLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUNqRCxPQUFPLEVBQXVCLGlCQUFpQixFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDdkUsT0FBTyxFQUlMLG9CQUFvQixFQUNwQixhQUFhLEVBQ2IsYUFBYSxFQUNiLGtCQUFrQixFQUNsQixjQUFjLEVBQ2QsdUJBQXVCLEVBQ3ZCLGFBQWEsRUFPYix1QkFBdUIsR0FDeEIsTUFBTSxVQUFVLENBQUM7QUFDbEIsT0FBTyxFQUFDLGlCQUFpQixFQUFDLE1BQU0saUJBQWlCLENBQUM7Ozs7Ozs7Ozs7O0FBR2xELE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQztBQWF4QixNQUFNLE9BQU8sZUFBZTtJQWtGMUIsWUFHVSxhQUFnQztJQUN4QyxxQ0FBcUM7SUFFcEIsVUFBa0IsRUFDbEIsR0FBc0IsRUFDdEIsY0FBMkM7UUFMcEQsa0JBQWEsR0FBYixhQUFhLENBQW1CO1FBR3ZCLGVBQVUsR0FBVixVQUFVLENBQVE7UUFDbEIsUUFBRyxHQUFILEdBQUcsQ0FBbUI7UUFDdEIsbUJBQWMsR0FBZCxjQUFjLENBQTZCO1FB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SyxFQUFFLElBQUk7U0FDWjtLQUNGLGtLQ3pESCx3M01BdUxBOzJGRDVIYSxlQUFlO2tCQVozQixTQUFTOytCQUNFLG1CQUFtQixhQUdsQjt3QkFDVDs0QkFDRSxPQUFPLEVBQUUsaUJBQWlCOzRCQUMxQixXQUFXLGlCQUFpQjs0QkFDNUIsS0FBSyxFQUFFLElBQUk7eUJBQ1o7cUJBQ0Y7OzBCQXFGRSxNQUFNOzJCQUFDLG9CQUFvQjs7MEJBQzNCLFFBQVE7OzBCQUdSLE1BQU07MkJBQUMsV0FBVzttSEFyRVYsTUFBTTtzQkFEaEIsS0FBSztnQkFzQkssY0FBYztzQkFEeEIsS0FBSztnQkFjRyxhQUFhO3NCQUFyQixLQUFLO2dCQUNHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFJRyxjQUFjO3NCQUF0QixLQUFLO2dCQUlHLDJCQUEyQjtzQkFBbkMsS0FBSztnQkFJRyxpQkFBaUI7c0JBQXpCLEtBQUs7Z0JBS0ksT0FBTztzQkFBaEIsTUFBTTtnQkFDRyxRQUFRO3NCQUFqQixNQUFNO2dCQVMwQixrQkFBa0I7c0JBQWxELFNBQVM7dUJBQUMsYUFBYSIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAoYykgMjAyMyBTb3VyY2VmdXNlIFRlY2hub2xvZ2llc1xuLy9cbi8vIFRoaXMgc29mdHdhcmUgaXMgcmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLlxuLy8gaHR0cHM6Ly9vcGVuc291cmNlLm9yZy9saWNlbnNlcy9NSVRcbmltcG9ydCB7XG4gIENoYW5nZURldGVjdG9yUmVmLFxuICBDb21wb25lbnQsXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5qZWN0LFxuICBJbnB1dCxcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG4gIE9wdGlvbmFsLFxuICBPdXRwdXQsXG4gIFBMQVRGT1JNX0lELFxuICBTaW1wbGVDaGFuZ2VzLFxuICBUZW1wbGF0ZVJlZixcbiAgVmlld0NoaWxkLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7Q29uZmlndXJhdGlvbn0gZnJvbSAnLi4vbGliLWNvbmZpZ3VyYXRpb24nO1xuaW1wb3J0IHtTdWJqZWN0fSBmcm9tICdyeGpzJztcbmltcG9ydCB7ZGVib3VuY2VUaW1lLCB0YXB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7Q29udHJvbFZhbHVlQWNjZXNzb3IsIE5HX1ZBTFVFX0FDQ0VTU09SfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQge1xuICBDdXN0b21TZWFyY2hFdmVudCxcbiAgSVNlYXJjaFNlcnZpY2UsXG4gIElTZWFyY2hRdWVyeSxcbiAgU0VBUkNIX1NFUlZJQ0VfVE9LRU4sXG4gIERFQk9VTkNFX1RJTUUsXG4gIERFRkFVTFRfTElNSVQsXG4gIERFRkFVTFRfTElNSVRfVFlQRSxcbiAgREVGQVVMVF9PRkZTRVQsXG4gIERFRkFVTFRfU0FWRV9JTl9SRUNFTlRTLFxuICBERUZBVUxUX09SREVSLFxuICBJUmV0dXJuVHlwZSxcbiAgUmVjZW50U2VhcmNoRXZlbnQsXG4gIFR5cGVFdmVudCxcbiAgSXRlbUNsaWNrZWRFdmVudCxcbiAgSU1vZGVsLFxuICBJU2VhcmNoU2VydmljZVdpdGhQcm9taXNlcyxcbiAgaXNBcGlTZXJ2aWNlV2l0aFByb21pc2UsXG59IGZyb20gJy4uL3R5cGVzJztcbmltcG9ydCB7aXNQbGF0Zm9ybUJyb3dzZXJ9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1Byb21pc2VBcGlBZGFwdGVyU2VydmljZX0gZnJvbSAnLi9wcm9taXNlLWFwaS1hZGFwdGVyLnNlcnZpY2UnO1xuXG5jb25zdCBBTExfTEFCRUwgPSAnQWxsJztcbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3NvdXJjZWxvb3Atc2VhcmNoJyxcbiAgdGVtcGxhdGVVcmw6ICcuL3NlYXJjaC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3NlYXJjaC5jb21wb25lbnQuc2NzcyddLFxuICBwcm92aWRlcnM6IFtcbiAgICB7XG4gICAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcbiAgICAgIHVzZUV4aXN0aW5nOiBTZWFyY2hDb21wb25lbnQsXG4gICAgICBtdWx0aTogdHJ1ZSxcbiAgICB9LFxuICBdLFxufSlcbmV4cG9ydCBjbGFzcyBTZWFyY2hDb21wb25lbnQ8VCBleHRlbmRzIElSZXR1cm5UeXBlPlxuICBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95LCBDb250cm9sVmFsdWVBY2Nlc3Nvclxue1xuICBzZWFyY2hCb3hJbnB1dCA9ICcnO1xuICBzdWdnZXN0aW9uc0Rpc3BsYXkgPSBmYWxzZTtcbiAgY2F0ZWdvcnlEaXNwbGF5ID0gZmFsc2U7XG4gIHNlYXJjaGluZyA9IGZhbHNlO1xuICBzdWdnZXN0aW9uczogVFtdID0gW107XG4gIHJlY2VudFNlYXJjaGVzOiBJU2VhcmNoUXVlcnlbXSA9IFtdO1xuICBjYXRlZ29yeTogc3RyaW5nID0gQUxMX0xBQkVMO1xuICBzZWFyY2hSZXF1ZXN0JCA9IG5ldyBTdWJqZWN0PHtpbnB1dDogc3RyaW5nOyBldmVudDogRXZlbnR9PigpO1xuXG4gIHByaXZhdGUgX2NvbmZpZyE6IENvbmZpZ3VyYXRpb248VD47XG4gIHB1YmxpYyBnZXQgY29uZmlnKCk6IENvbmZpZ3VyYXRpb248VD4ge1xuICAgIHJldHVybiB0aGlzLl9jb25maWc7XG4gIH1cblxuICBASW5wdXQoKVxuICBwdWJsaWMgc2V0IGNvbmZpZyh2YWx1ZTogQ29uZmlndXJhdGlvbjxUPikge1xuICAgIHRoaXMuX2NvbmZpZyA9IHZhbHVlO1xuXG4gICAgaWYgKHZhbHVlICYmIHZhbHVlLm1vZGVscykge1xuICAgICAgdmFsdWUubW9kZWxzLnVuc2hpZnQoe1xuICAgICAgICBuYW1lOiBBTExfTEFCRUwsXG4gICAgICAgIGRpc3BsYXlOYW1lOiB0aGlzLmN1c3RvbUFsbExhYmVsID8/IEFMTF9MQUJFTCxcbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAodmFsdWUgJiYgIXZhbHVlLm1vZGVscykge1xuICAgICAgdmFsdWUubW9kZWxzID0gW1xuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogQUxMX0xBQkVMLFxuICAgICAgICAgIGRpc3BsYXlOYW1lOiB0aGlzLmN1c3RvbUFsbExhYmVsID8/IEFMTF9MQUJFTCxcbiAgICAgICAgfSxcbiAgICAgIF07XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGRvIG5vdGhpbmdcbiAgICB9XG4gIH1cblxuICBASW5wdXQoKVxuICBwdWJsaWMgc2V0IHNlYXJjaFByb3ZpZGVyKFxuICAgIHZhbHVlOiBJU2VhcmNoU2VydmljZTxUPiB8IElTZWFyY2hTZXJ2aWNlV2l0aFByb21pc2VzPFQ+LFxuICApIHtcbiAgICBpZiAoaXNBcGlTZXJ2aWNlV2l0aFByb21pc2UodmFsdWUpKSB7XG4gICAgICB2YWx1ZSA9IHRoaXMucHJvbWlzZUFkYXB0ZXIuYWRhcHQodmFsdWUpO1xuICAgIH1cbiAgICB0aGlzLnNlYXJjaFNlcnZpY2UgPSB2YWx1ZTtcbiAgfVxuXG4gIHB1YmxpYyBnZXQgc2VhcmNoUHJvdmlkZXIoKTogSVNlYXJjaFNlcnZpY2U8VD4ge1xuICAgIHJldHVybiB0aGlzLnNlYXJjaFNlcnZpY2U7XG4gIH1cblxuICBASW5wdXQoKSB0aXRsZVRlbXBsYXRlPzogVGVtcGxhdGVSZWY8YW55PjtcbiAgQElucHV0KCkgc3VidGl0bGVUZW1wbGF0ZT86IFRlbXBsYXRlUmVmPGFueT47XG4gIC8qKlxuICAgKiBjb25maWd1cmUgd2hlbiBhcHBsaWNhdGlvbiBoYXMgb3duIHNlYXJjaCBpbnB1dCBhbmQgdXNlIGRpZmZlcmVudCBhbGwgbGFiZWxcbiAgICovXG4gIEBJbnB1dCgpIGN1c3RvbUFsbExhYmVsID0gQUxMX0xBQkVMO1xuICAvKipcbiAgICogY29uZmlndXJlIHRvIHRydWUgd2hlbiB0byBzaG93IG9ubHkgc2VhcmNoIHJlc3VsdCBvdmVybGF5IHdpdGhvdXQgc2VhcmNoIGJhclxuICAgKi9cbiAgQElucHV0KCkgc2hvd09ubHlTZWFyY2hSZXN1bHRPdmVybGF5ID0gZmFsc2U7XG4gIC8qKlxuICAgKiBwcm92aWRlIGN1c3RvbSBzZWFyY2ggZXZlbnQgd2hlbiBzaG93T25seVNlYXJjaFJlc3VsdE92ZXJsYXkgY29uZmlndXJlIHRvIHRydWVcbiAgICovXG4gIEBJbnB1dCgpIGN1c3RvbVNlYXJjaEV2ZW50OiBDdXN0b21TZWFyY2hFdmVudCA9IHtcbiAgICBzZWFyY2hWYWx1ZTogJycsXG4gICAgbW9kZWxOYW1lOiB0aGlzLmN1c3RvbUFsbExhYmVsLFxuICB9O1xuICAvLyBlbWl0dGVkIHdoZW4gdXNlciBjbGlja3Mgb25lIG9mIHRoZSBzdWdnZXN0ZWQgcmVzdWx0cyAoaW5jbHVkaW5nIHJlY2VudCBzZWFyY2ggc3VnZXN0aW9ucylcbiAgQE91dHB1dCgpIGNsaWNrZWQgPSBuZXcgRXZlbnRFbWl0dGVyPEl0ZW1DbGlja2VkRXZlbnQ8VD4+KCk7XG4gIEBPdXRwdXQoKSBzZWFyY2hlZCA9IG5ldyBFdmVudEVtaXR0ZXI8UmVjZW50U2VhcmNoRXZlbnQ+KCk7XG4gIC8qIGVtaXR0ZWQgd2hlbiB1c2VyIG1ha2VzIHNlYXJjaCByZXF1ZXN0IChpbmNsdWRpbmcgcmVjZW50IHNlYXJjaCByZXF1ZXN0c1xuICAgICAmIHJlcXVlc3RzIG1hZGUgb24gY2hhbmdlIGluIGNhdGVnb3J5IGZyb20gZHJvcGRvd24pXG4gIEluIGNhc2Ugb2YgcmVjZW50IHNlYXJjaCBBcnJheSBvZiByZWNlbnQgU2VhcmNoIHJlcXVlc3QgcmVzdWx0IGlzIGVtaXR0ZWQgKi9cblxuICBvbkNoYW5nZTogKHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQpID0+IHZvaWQgPSAoKSA9PiB7fTtcbiAgb25Ub3VjaGVkOiAoKSA9PiB2b2lkID0gKCkgPT4ge307XG4gIGRpc2FibGVkID0gZmFsc2U7XG5cbiAgQFZpZXdDaGlsZCgnc2VhcmNoSW5wdXQnKSBwdWJsaWMgc2VhcmNoSW5wdXRFbGVtZW50ITogRWxlbWVudFJlZjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBASW5qZWN0KFNFQVJDSF9TRVJWSUNFX1RPS0VOKVxuICAgIEBPcHRpb25hbCgpXG4gICAgcHJpdmF0ZSBzZWFyY2hTZXJ2aWNlOiBJU2VhcmNoU2VydmljZTxUPixcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6YmFuLXR5cGVzXG4gICAgQEluamVjdChQTEFURk9STV9JRClcbiAgICBwcml2YXRlIHJlYWRvbmx5IHBsYXRmb3JtSWQ6IE9iamVjdCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNkcjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgcHJpdmF0ZSByZWFkb25seSBwcm9taXNlQWRhcHRlcjogUHJvbWlzZUFwaUFkYXB0ZXJTZXJ2aWNlPFQ+LFxuICApIHt9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5zZWFyY2hSZXF1ZXN0JFxuICAgICAgLnBpcGUoXG4gICAgICAgIHRhcCh2ID0+ICh0aGlzLnN1Z2dlc3Rpb25zID0gW10pKSxcbiAgICAgICAgZGVib3VuY2VUaW1lKERFQk9VTkNFX1RJTUUpLFxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgodmFsdWU6IFR5cGVFdmVudCkgPT4ge1xuICAgICAgICB0aGlzLnNlYXJjaGVkLmVtaXQoe1xuICAgICAgICAgIGV2ZW50OiB2YWx1ZS5ldmVudCxcbiAgICAgICAgICBrZXl3b3JkOiB2YWx1ZS5pbnB1dCxcbiAgICAgICAgICBjYXRlZ29yeTogdGhpcy5jYXRlZ29yeSxcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuZ2V0U3VnZ2VzdGlvbnModmFsdWUpO1xuICAgICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgLy8gQ29udHJvbFZhbHVlQWNjZXNzb3IgSW1wbGVtZW50YXRpb25cbiAgd3JpdGVWYWx1ZSh2YWx1ZTogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5zZWFyY2hCb3hJbnB1dCA9IHZhbHVlO1xuICB9XG4gIC8vIFdoZW4gdGhlIHZhbHVlIGluIHRoZSBVSSBpcyBjaGFuZ2VkLCB0aGlzIG1ldGhvZCB3aWxsIGludm9rZSBhIGNhbGxiYWNrIGZ1bmN0aW9uXG4gIHJlZ2lzdGVyT25DaGFuZ2UoZm46ICh2YWx1ZTogc3RyaW5nIHwgdW5kZWZpbmVkKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdGhpcy5vbkNoYW5nZSA9IGZuO1xuICB9XG4gIHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiAoKSA9PiB2b2lkKTogdm9pZCB7XG4gICAgdGhpcy5vblRvdWNoZWQgPSBmbjtcbiAgfVxuICBzZXREaXNhYmxlZFN0YXRlPyhpc0Rpc2FibGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5kaXNhYmxlZCA9IGlzRGlzYWJsZWQ7XG4gIH1cblxuICBnZXRTdWdnZXN0aW9ucyhldmVudFZhbHVlOiBUeXBlRXZlbnQpIHtcbiAgICBldmVudFZhbHVlLmlucHV0ID0gZXZlbnRWYWx1ZS5pbnB1dC50cmltKCk7XG4gICAgaWYgKCFldmVudFZhbHVlLmlucHV0Lmxlbmd0aCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBvcmRlciA9IHRoaXMuY29uZmlnLm9yZGVyID8/IERFRkFVTFRfT1JERVI7XG4gICAgbGV0IG9yZGVyU3RyaW5nID0gJyc7XG4gICAgb3JkZXIuZm9yRWFjaChwcmVmZXJlbmNlID0+IChvcmRlclN0cmluZyA9IGAke29yZGVyU3RyaW5nfSR7cHJlZmVyZW5jZX0gYCkpO1xuXG4gICAgbGV0IHNhdmVJblJlY2VudHMgPSB0aGlzLmNvbmZpZy5zYXZlSW5SZWNlbnRzID8/IERFRkFVTFRfU0FWRV9JTl9SRUNFTlRTO1xuICAgIGlmICh0aGlzLmNvbmZpZy5zYXZlSW5SZWNlbnRzICYmIHRoaXMuY29uZmlnLnNhdmVJblJlY2VudHNPbmx5T25FbnRlcikge1xuICAgICAgaWYgKFxuICAgICAgICAhZXZlbnRWYWx1ZS5ldmVudCB8fFxuICAgICAgICAoZXZlbnRWYWx1ZS5ldmVudCBpbnN0YW5jZW9mIEtleWJvYXJkRXZlbnQgJiZcbiAgICAgICAgICBldmVudFZhbHVlLmV2ZW50LmtleSA9PT0gJ0VudGVyJylcbiAgICAgICkge1xuICAgICAgICBzYXZlSW5SZWNlbnRzID0gdHJ1ZTsgLy8gc2F2ZSBpbiByZWNlbnRzIG9ubHkgb24gZW50ZXIgb3IgY2hhbmdlIGluIGNhdGVnb3J5XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBkbyBub3Qgc2F2ZSBpbiByZWNlbnQgc2VhcmNoIG9uIHR5cGluZ1xuICAgICAgICBzYXZlSW5SZWNlbnRzID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIC8qIG5lZWQgdG8gcHV0IGRlZmF1bHQgdmFsdWUgaGVyZSBhbmQgbm90IGluIGNvbnRydWN0b3JcbiAgICBiZWNhdXNlIHNvbmFyIHdhcyBnaXZpbmcgY29kZSBzbWVsbCB3aXRoIGRlZmluaXRlIGFzc2VydGlvbiBhcyBhbGwgdGhlc2VcbiAgICAgcGFyYW1ldGVycyBhcmUgb3B0aW9uYWwgKi9cbiAgICBjb25zdCByZXF1ZXN0UGFyYW1ldGVyczogSVNlYXJjaFF1ZXJ5ID0ge1xuICAgICAgbWF0Y2g6IGV2ZW50VmFsdWUuaW5wdXQsXG4gICAgICBzb3VyY2VzOiB0aGlzLl9jYXRlZ29yeVRvU291cmNlTmFtZSh0aGlzLmNhdGVnb3J5KSxcbiAgICAgIGxpbWl0OiB0aGlzLmNvbmZpZy5saW1pdCA/PyBERUZBVUxUX0xJTUlULFxuICAgICAgbGltaXRCeVR5cGU6IHRoaXMuY29uZmlnLmxpbWl0QnlUeXBlID8/IERFRkFVTFRfTElNSVRfVFlQRSxcbiAgICAgIG9yZGVyOiBvcmRlclN0cmluZyxcbiAgICAgIG9mZnNldDogdGhpcy5jb25maWcub2Zmc2V0ID8/IERFRkFVTFRfT0ZGU0VULFxuICAgIH07XG5cbiAgICB0aGlzLnNlYXJjaGluZyA9IHRydWU7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgdGhpcy5zZWFyY2hTZXJ2aWNlXG4gICAgICAuc2VhcmNoQXBpUmVxdWVzdChyZXF1ZXN0UGFyYW1ldGVycywgc2F2ZUluUmVjZW50cylcbiAgICAgIC5zdWJzY3JpYmUoXG4gICAgICAgICh2YWx1ZTogVFtdKSA9PiB7XG4gICAgICAgICAgdGhpcy5zdWdnZXN0aW9ucyA9IHZhbHVlO1xuICAgICAgICAgIHRoaXMuc2VhcmNoaW5nID0gZmFsc2U7XG4gICAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgICAgIH0sXG4gICAgICAgIChfZXJyb3I6IEVycm9yKSA9PiB7XG4gICAgICAgICAgdGhpcy5zdWdnZXN0aW9ucyA9IFtdO1xuICAgICAgICAgIHRoaXMuc2VhcmNoaW5nID0gZmFsc2U7XG4gICAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgICAgIH0sXG4gICAgICApO1xuICB9XG4gIGdldFJlY2VudFNlYXJjaGVzKCkge1xuICAgIGlmIChcbiAgICAgICF0aGlzLmNvbmZpZy5oaWRlUmVjZW50U2VhcmNoICYmXG4gICAgICB0aGlzLnNlYXJjaFNlcnZpY2UucmVjZW50U2VhcmNoQXBpUmVxdWVzdFxuICAgICkge1xuICAgICAgdGhpcy5zZWFyY2hTZXJ2aWNlLnJlY2VudFNlYXJjaEFwaVJlcXVlc3QoKS5zdWJzY3JpYmUoXG4gICAgICAgICh2YWx1ZTogSVNlYXJjaFF1ZXJ5W10pID0+IHtcbiAgICAgICAgICB0aGlzLnJlY2VudFNlYXJjaGVzID0gdmFsdWU7XG4gICAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgICAgIH0sXG4gICAgICAgIChfZXJyb3I6IEVycm9yKSA9PiB7XG4gICAgICAgICAgdGhpcy5yZWNlbnRTZWFyY2hlcyA9IFtdO1xuICAgICAgICAgIHRoaXMuY2RyLm1hcmtGb3JDaGVjaygpO1xuICAgICAgICB9LFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvL2V2ZW50IGNhbiBiZSBLZXlCb2FyZEV2ZW50IG9yIEV2ZW50IG9mIHR5cGUgJ2NoYW5nZSdcbiAgLy8gZmlyZWQgb24gY2hhbmdlIGluIHZhbHVlIG9mIGRyb3AgZG93biBmb3IgY2F0ZWdvcnlcblxuICBoaXRTZWFyY2hBcGkoZXZlbnQ/OiBFdmVudCkge1xuICAgIC8vIHRoaXMgd2lsbCBoYXBwZW4gb25seSBpbiBjYXNlIHVzZXIgc2VhcmNoZXMgc29tZXRoaW5nIGFuZFxuICAgIC8vIHRoZW4gZXJhc2VzIGl0LCB3ZSBuZWVkIHRvIHVwZGF0ZSByZWNlbnQgc2VhcmNoXG4gICAgaWYgKCF0aGlzLnNlYXJjaEJveElucHV0KSB7XG4gICAgICB0aGlzLnN1Z2dlc3Rpb25zID0gW107XG4gICAgICB0aGlzLmdldFJlY2VudFNlYXJjaGVzKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gbm8gZGVib3VuY2UgdGltZSBuZWVkZWQgaW4gY2FzZSBvZiBzZWFyY2hPbmx5T25FbnRlclxuICAgIGlmICh0aGlzLmNvbmZpZy5zZWFyY2hPbmx5T25FbnRlcikge1xuICAgICAgaWYgKCFldmVudCB8fCAoZXZlbnQgaW5zdGFuY2VvZiBLZXlib2FyZEV2ZW50ICYmIGV2ZW50LmtleSA9PT0gJ0VudGVyJykpIHtcbiAgICAgICAgdGhpcy5nZXRTdWdnZXN0aW9ucyh7aW5wdXQ6IHRoaXMuc2VhcmNoQm94SW5wdXQsIGV2ZW50fSk7XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gbm8gZGVib3VuY2UgdGltZSBuZWVkZWQgaW4gY2FzZSBvZiBjaGFuZ2UgaW4gY2F0ZWdvcnlcbiAgICBpZiAoIWV2ZW50KSB7XG4gICAgICB0aGlzLmdldFN1Z2dlc3Rpb25zKHtpbnB1dDogdGhpcy5zZWFyY2hCb3hJbnB1dCwgZXZlbnR9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnNlYXJjaFJlcXVlc3QkLm5leHQoe1xuICAgICAgaW5wdXQ6IHRoaXMuc2VhcmNoQm94SW5wdXQsXG4gICAgICBldmVudCxcbiAgICB9KTtcbiAgfVxuXG4gIHBvcHVsYXRlVmFsdWUoc3VnZ2VzdGlvbjogVCwgZXZlbnQ6IE1vdXNlRXZlbnQpIHtcbiAgICBjb25zdCB2YWx1ZSA9IHN1Z2dlc3Rpb25bXG4gICAgICB0aGlzLmNvbmZpZy5kaXNwbGF5UHJvcGVydHlOYW1lXG4gICAgXSBhcyB1bmtub3duIGFzIHN0cmluZztcbiAgICAvLyBjb252ZXJ0ZWQgdG8gc3RyaW5nIHRvIGFzc2lnbiB2YWx1ZSB0byBzZWFyY2hCb3hJbnB1dFxuICAgIHRoaXMuc2VhcmNoQm94SW5wdXQgPSB2YWx1ZTtcbiAgICB0aGlzLnN1Z2dlc3Rpb25zRGlzcGxheSA9IGZhbHNlO1xuICAgIC8vIG5nTW9kZWxDaGFuZ2UgZG9lc24ndCBkZXRlY3QgY2hhbmdlIGluIHZhbHVlXG4gICAgLy8gd2hlbiBwb3B1bGF0ZWQgZnJvbSBvdXRzaWRlLCBoZW5jZSBjYWxsaW5nIG1hbnVhbGx5XG4gICAgdGhpcy5vbkNoYW5nZSh0aGlzLnNlYXJjaEJveElucHV0KTtcbiAgICAvLyBuZWVkIHRvIGRvIHRoaXMgdG8gc2hvdyBtb3JlIHNlYXJjaCBvcHRpb25zIGZvciBzZWxlY3RlZFxuICAgIC8vc3VnZ2VzdGlvbiAtIGp1c3QgaW4gY2FzZSB1c2VyIHJlb3BlbnMgc2VhcmNoIGlucHV0XG4gICAgdGhpcy5nZXRTdWdnZXN0aW9ucyh7aW5wdXQ6IHRoaXMuc2VhcmNoQm94SW5wdXQsIGV2ZW50fSk7XG4gICAgdGhpcy5jbGlja2VkLmVtaXQoe2l0ZW06IHN1Z2dlc3Rpb24sIGV2ZW50fSk7XG4gIH1cbiAgcG9wdWxhdGVWYWx1ZVJlY2VudFNlYXJjaChyZWNlbnRTZWFyY2g6IElTZWFyY2hRdWVyeSwgZXZlbnQ6IE1vdXNlRXZlbnQpIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGNvbnN0IHZhbHVlID0gcmVjZW50U2VhcmNoWydtYXRjaCddO1xuICAgIHRoaXMuc2VhcmNoQm94SW5wdXQgPSB2YWx1ZTtcbiAgICB0aGlzLnN1Z2dlc3Rpb25zRGlzcGxheSA9IGZhbHNlO1xuICAgIHRoaXMub25DaGFuZ2UodGhpcy5zZWFyY2hCb3hJbnB1dCk7XG4gICAgLy8gbmVlZCB0byBkbyB0aGlzIHRvIHNob3cgbW9yZSBzZWFyY2ggb3B0aW9ucyBmb3Igc2VsZWN0ZWRcbiAgICAvLyBzdWdnZXN0aW9uIC0ganVzdCBpbiBjYXNlIHVzZXIgcmVvcGVucyBzZWFyY2ggaW5wdXRcbiAgICB0aGlzLmdldFN1Z2dlc3Rpb25zKHtpbnB1dDogdGhpcy5zZWFyY2hCb3hJbnB1dCwgZXZlbnR9KTtcbiAgICB0aGlzLmZvY3VzSW5wdXQoKTtcbiAgICB0aGlzLnNob3dTdWdnZXN0aW9ucygpO1xuICB9XG5cbiAgZmV0Y2hNb2RlbEltYWdlVXJsRnJvbVN1Z2dlc3Rpb24oc3VnZ2VzdGlvbjogVCkge1xuICAgIGNvbnN0IG1vZGVsTmFtZSA9IHN1Z2dlc3Rpb25bXG4gICAgICAnc291cmNlJyBhcyB1bmtub3duIGFzIGtleW9mIFRcbiAgICBdIGFzIHVua25vd24gYXMgc3RyaW5nO1xuICAgIGxldCB1cmw6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICB0aGlzLmNvbmZpZy5tb2RlbHMuZm9yRWFjaChtb2RlbCA9PiB7XG4gICAgICBpZiAobW9kZWwubmFtZSA9PT0gbW9kZWxOYW1lICYmIG1vZGVsLmltYWdlVXJsKSB7XG4gICAgICAgIHVybCA9IG1vZGVsLmltYWdlVXJsO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiB1cmw7XG4gIH1cblxuICBib2xkU3RyaW5nKHN0cjogVFtrZXlvZiBUXSB8IHN0cmluZywgc3Vic3RyOiBzdHJpbmcpIHtcbiAgICBjb25zdCBzdHJSZWdFeHAgPSBuZXcgUmVnRXhwKGAoJHtzdWJzdHJ9KWAsICdnaScpO1xuICAgIGNvbnN0IHN0cmluZ1RvTWFrZUJvbGQ6IHN0cmluZyA9IHN0ciBhcyB1bmtub3duIGFzIHN0cmluZztcbiAgICByZXR1cm4gc3RyaW5nVG9NYWtlQm9sZC5yZXBsYWNlKHN0clJlZ0V4cCwgYDxiPiQxPC9iPmApO1xuICB9XG5cbiAgaGlkZVN1Z2dlc3Rpb25zKCkge1xuICAgIHRoaXMuc3VnZ2VzdGlvbnNEaXNwbGF5ID0gZmFsc2U7XG4gICAgdGhpcy5vblRvdWNoZWQoKTtcbiAgfVxuXG4gIHNob3dTdWdnZXN0aW9ucygpIHtcbiAgICB0aGlzLnN1Z2dlc3Rpb25zRGlzcGxheSA9IHRydWU7XG4gICAgdGhpcy5nZXRSZWNlbnRTZWFyY2hlcygpO1xuICB9XG5cbiAgZm9jdXNJbnB1dCgpIHtcbiAgICBpZiAoXG4gICAgICBpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLnBsYXRmb3JtSWQpICYmXG4gICAgICAhdGhpcy5zaG93T25seVNlYXJjaFJlc3VsdE92ZXJsYXlcbiAgICApIHtcbiAgICAgIHRoaXMuc2VhcmNoSW5wdXRFbGVtZW50Lm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcbiAgICB9XG4gIH1cblxuICBzZXRDYXRlZ29yeShjYXRlZ29yeTogc3RyaW5nKSB7XG4gICAgdGhpcy5jYXRlZ29yeSA9IGNhdGVnb3J5O1xuICAgIHRoaXMuY2F0ZWdvcnlEaXNwbGF5ID0gZmFsc2U7XG4gICAgaWYgKHRoaXMuc2VhcmNoQm94SW5wdXQpIHtcbiAgICAgIHRoaXMuaGl0U2VhcmNoQXBpKCk7XG4gICAgICB0aGlzLmZvY3VzSW5wdXQoKTtcbiAgICAgIHRoaXMuc2hvd1N1Z2dlc3Rpb25zKCk7XG4gICAgfVxuICB9XG5cbiAgc2hvd0NhdGVnb3J5KCkge1xuICAgIHRoaXMuY2F0ZWdvcnlEaXNwbGF5ID0gIXRoaXMuY2F0ZWdvcnlEaXNwbGF5O1xuICB9XG5cbiAgaGlkZUNhdGVnb3J5KCkge1xuICAgIHRoaXMuY2F0ZWdvcnlEaXNwbGF5ID0gZmFsc2U7XG4gIH1cblxuICByZXNldElucHV0KCkge1xuICAgIHRoaXMuc2VhcmNoQm94SW5wdXQgPSAnJztcbiAgICB0aGlzLnN1Z2dlc3Rpb25zID0gW107XG4gICAgdGhpcy5zdWdnZXN0aW9uc0Rpc3BsYXkgPSB0cnVlO1xuICAgIHRoaXMuZm9jdXNJbnB1dCgpO1xuICAgIC8vIG5nTW9kZWxDaGFuZ2UgZG9lc24ndCBkZXRlY3QgY2hhbmdlIGluIHZhbHVlXG4gICAgLy8gd2hlbiBwb3B1bGF0ZWQgZnJvbSBvdXRzaWRlLCBoZW5jZSBjYWxsaW5nIG1hbnVhbGx5XG4gICAgdGhpcy5vbkNoYW5nZSh0aGlzLnNlYXJjaEJveElucHV0KTtcbiAgICB0aGlzLmdldFJlY2VudFNlYXJjaGVzKCk7XG4gIH1cbiAgbmdPbkRlc3Ryb3koKSB7XG4gICAgdGhpcy5zZWFyY2hSZXF1ZXN0JC51bnN1YnNjcmliZSgpO1xuICB9XG5cbiAgX2NhdGVnb3J5VG9Tb3VyY2VOYW1lKGNhdGVnb3J5OiBzdHJpbmcpIHtcbiAgICBpZiAoW0FMTF9MQUJFTCwgdGhpcy5jdXN0b21BbGxMYWJlbF0uaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBbY2F0ZWdvcnldO1xuICAgIH1cbiAgfVxuICBnZXRNb2RlbEZyb21Nb2RlbE5hbWUobmFtZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLm1vZGVscy5maW5kKGl0ZW0gPT4gaXRlbS5uYW1lID09PSBuYW1lKSBhcyBJTW9kZWw7XG4gIH1cbiAgZ2V0TW9kZWxzV2l0aFN1Z2dlc3Rpb25zKCkge1xuICAgIGNvbnN0IG1vZGVsc1dpdGhTdWdnZXN0aW9uczoge21vZGVsOiBJTW9kZWw7IGl0ZW1zOiBUW119W10gPSBbXTtcbiAgICBjb25zdCBzb3VyY2VzOiBzdHJpbmdbXSA9IFtdO1xuICAgIHRoaXMuc3VnZ2VzdGlvbnMuZm9yRWFjaChzdWdnZXN0aW9uID0+IHtcbiAgICAgIGlmIChzb3VyY2VzLmluZGV4T2Yoc3VnZ2VzdGlvblsnc291cmNlJ10pID49IDApIHtcbiAgICAgICAgbW9kZWxzV2l0aFN1Z2dlc3Rpb25zLmV2ZXJ5KG1vZGVsV2l0aFN1Z2dlc3Rpb25zID0+IHtcbiAgICAgICAgICBpZiAobW9kZWxXaXRoU3VnZ2VzdGlvbnMubW9kZWwubmFtZSA9PT0gc3VnZ2VzdGlvblsnc291cmNlJ10pIHtcbiAgICAgICAgICAgIG1vZGVsV2l0aFN1Z2dlc3Rpb25zLml0ZW1zLnB1c2goc3VnZ2VzdGlvbik7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IG1vZGVsID0gdGhpcy5nZXRNb2RlbEZyb21Nb2RlbE5hbWUoc3VnZ2VzdGlvblsnc291cmNlJ10pO1xuICAgICAgICBtb2RlbHNXaXRoU3VnZ2VzdGlvbnMucHVzaCh7bW9kZWwsIGl0ZW1zOiBbc3VnZ2VzdGlvbl19KTtcbiAgICAgICAgc291cmNlcy5wdXNoKHN1Z2dlc3Rpb25bJ3NvdXJjZSddKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gbW9kZWxzV2l0aFN1Z2dlc3Rpb25zO1xuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcykge1xuICAgIGlmIChjaGFuZ2VzLmN1c3RvbVNlYXJjaEV2ZW50KSB7XG4gICAgICBpZiAodGhpcy5faXNDdXN0b21TZWFyY2hFdmVudENoYW5nZShjaGFuZ2VzLCAnc2VhcmNoVmFsdWUnKSkge1xuICAgICAgICB0aGlzLnNlYXJjaEJveElucHV0ID0gdGhpcy5jdXN0b21TZWFyY2hFdmVudD8uc2VhcmNoVmFsdWUgPz8gJyc7XG4gICAgICAgIHRoaXMuc2VhcmNoT25DdXN0b21FdmVudFZhbHVlQ2hhbmdlKHRoaXMuc2VhcmNoQm94SW5wdXQpO1xuICAgICAgfVxuICAgICAgaWYgKFxuICAgICAgICB0aGlzLl9pc0N1c3RvbVNlYXJjaEV2ZW50Q2hhbmdlKGNoYW5nZXMsICdtb2RlbE5hbWUnKSAmJlxuICAgICAgICB0aGlzLmN1c3RvbVNlYXJjaEV2ZW50Py5tb2RlbE5hbWVcbiAgICAgICkge1xuICAgICAgICB0aGlzLnNldENhdGVnb3J5KHRoaXMuY3VzdG9tU2VhcmNoRXZlbnQ/Lm1vZGVsTmFtZSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgc2VhcmNoT25DdXN0b21FdmVudFZhbHVlQ2hhbmdlKHZhbHVlOiBzdHJpbmcpIHtcbiAgICBpZiAodmFsdWU/Lmxlbmd0aCkge1xuICAgICAgdGhpcy5zaG93U3VnZ2VzdGlvbnMoKTtcbiAgICAgIHRoaXMuaGl0U2VhcmNoQXBpKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuaGlkZVN1Z2dlc3Rpb25zKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBfaXNDdXN0b21TZWFyY2hFdmVudENoYW5nZShcbiAgICBjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzLFxuICAgIHByb3BlcnR5TmFtZTogc3RyaW5nLFxuICApIHtcbiAgICByZXR1cm4gKFxuICAgICAgIWNoYW5nZXMuY3VzdG9tU2VhcmNoRXZlbnQ/LnByZXZpb3VzVmFsdWUgfHxcbiAgICAgIGNoYW5nZXMuY3VzdG9tU2VhcmNoRXZlbnQ/LnByZXZpb3VzVmFsdWVbcHJvcGVydHlOYW1lXSAhPT1cbiAgICAgICAgY2hhbmdlcy5jdXN0b21TZWFyY2hFdmVudD8uY3VycmVudFZhbHVlW3Byb3BlcnR5TmFtZV1cbiAgICApO1xuICB9XG59XG4iLCI8bmctY29udGFpbmVyICpuZ0lmPVwiIXNob3dPbmx5U2VhcmNoUmVzdWx0T3ZlcmxheVwiPlxuICA8ZGl2IGZ4TGF5b3V0IGZ4TGF5b3V0QWxpZ249XCJzdGFydCBjZW50ZXJcIiBjbGFzcz1cInRvb2xiYXItc2VhcmNoXCIgKm5nSWY9XCJjb25maWdcIj5cbiAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBjbGFzcz1cInRvb2xiYXItc2VhcmNoLWlucHV0XCI+XG4gICAgICA8aW5wdXRcbiAgICAgICAgbWF0SW5wdXRcbiAgICAgICAgYXV0b2NvbXBsZXRlPVwib2ZmXCJcbiAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICBbcGxhY2Vob2xkZXJdPVwiXG4gICAgICAgICAgY29uZmlnLnBsYWNlaG9sZGVyRnVuY3Rpb25cbiAgICAgICAgICAgID8gY29uZmlnLnBsYWNlaG9sZGVyRnVuY3Rpb24oc2VhcmNoSW5wdXQudmFsdWUsIGNhdGVnb3J5KVxuICAgICAgICAgICAgOiBjb25maWcucGxhY2Vob2xkZXIgfHwgJ1NlYXJjaCdcbiAgICAgICAgXCJcbiAgICAgICAgI3NlYXJjaElucHV0XG4gICAgICAgIG5hbWU9XCJzZWFyY2hJbnB1dFwiXG4gICAgICAgIChmb2N1cyk9XCJzaG93U3VnZ2VzdGlvbnMoKVwiXG4gICAgICAgIChibHVyKT1cImhpZGVTdWdnZXN0aW9ucygpXCJcbiAgICAgICAgWyhuZ01vZGVsKV09XCJzZWFyY2hCb3hJbnB1dFwiXG4gICAgICAgIChrZXl1cCk9XCJoaXRTZWFyY2hBcGkoJGV2ZW50KVwiXG4gICAgICAgIHBsYWNlaG9sZGVyPVwiU2VhcmNoXCJcbiAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25DaGFuZ2UodGhpcy5zZWFyY2hCb3hJbnB1dClcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIlxuICAgICAgLz5cbiAgICAgIDxtYXQtaWNvbiBtYXRQcmVmaXggW2NsYXNzTmFtZV09XCJjb25maWcuc2VhcmNoSWNvbkNsYXNzXCI+PC9tYXQtaWNvbj5cbiAgICAgIDxtYXQtaWNvblxuICAgICAgICAqbmdJZj1cInNlYXJjaEJveElucHV0XCJcbiAgICAgICAgbWF0U3VmZml4XG4gICAgICAgIFtjbGFzc05hbWVdPVwiY29uZmlnLmNyb3NzSWNvbkNsYXNzXCJcbiAgICAgICAgKGNsaWNrKT1cInJlc2V0SW5wdXQoKVwiXG4gICAgICA+PC9tYXQtaWNvbj5cbiAgICA8L21hdC1mb3JtLWZpZWxkPlxuICBcbiAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBjbGFzcz1cInRvb2xiYXItc2VhcmNoLXNlbGVjdFwiPlxuICAgICAgPG1hdC1pY29uIG1hdFN1ZmZpeCBbY2xhc3NOYW1lXT1cImNvbmZpZy5kcm9wRG93bkJ1dHRvbkljb25DbGFzc1wiPjwvbWF0LWljb24+XG4gICAgICA8bWF0LXNlbGVjdFxuICAgICAgICBbdmFsdWVdPVwiY2F0ZWdvcnlcIlxuICAgICAgICAoc2VsZWN0aW9uQ2hhbmdlKT1cInNldENhdGVnb3J5KCRldmVudC52YWx1ZSlcIlxuICAgICAgICBwYW5lbENsYXNzPVwic2VhcmNoLXNlbGVjdFwiXG4gICAgICA+XG4gICAgICAgIDxtYXQtb3B0aW9uIFt2YWx1ZV09XCJtb2RlbC5uYW1lXCIgKm5nRm9yPVwibGV0IG1vZGVsIG9mIGNvbmZpZy5tb2RlbHNcIj5cbiAgICAgICAgICB7eyBtb2RlbC5kaXNwbGF5TmFtZSB9fVxuICAgICAgICA8L21hdC1vcHRpb24+XG4gICAgICA8L21hdC1zZWxlY3Q+XG4gICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgPC9kaXY+XG48L25nLWNvbnRhaW5lcj5cblxuPGRpdiBjbGFzcz1cInNlYXJjaC1jb250YWluZXJcIj5cbiAgPGRpdlxuICAgICpuZ0lmPVwic3VnZ2VzdGlvbnNEaXNwbGF5ICYmIChyZWNlbnRTZWFyY2hlcy5sZW5ndGggfHwgc3VnZ2VzdGlvbnMubGVuZ3RoKVwiXG4gICAgY2xhc3M9XCJzZWFyY2gtcG9wdXBcIlxuICA+XG4gICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInNlYXJjaEJveElucHV0XCI+XG4gICAgICA8c3BhbiAqbmdJZj1cInN1Z2dlc3Rpb25zLmxlbmd0aCA9PT0gMFwiIGNsYXNzPVwic2VhcmNoLW1lc3NhZ2VcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInNlYXJjaGluZ1wiPiBzZWFyY2hpbmcuLi4gPC9uZy1jb250YWluZXI+XG4gICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCIhc2VhcmNoaW5nXCI+XG4gICAgICAgICAge3sgY29uZmlnLm5vUmVzdWx0TWVzc2FnZSB9fVxuICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgIDwvc3Bhbj5cbiAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJjb25maWcuY2F0ZWdvcml6ZVJlc3VsdHMgJiYgc3VnZ2VzdGlvbnMubGVuZ3RoXCI+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBjbGFzcz1cInNlYXJjaC1yZXN1bHRcIlxuICAgICAgICAgICpuZ0Zvcj1cImxldCBtb2RlbFdpdGhTdWdnZXN0aW9ucyBvZiBnZXRNb2RlbHNXaXRoU3VnZ2VzdGlvbnMoKVwiXG4gICAgICAgID5cbiAgICAgICAgICA8aDMgY2xhc3M9XCJzdWdnZXN0aW9ucy1oZWFkaW5nXCI+XG4gICAgICAgICAgICA8aW1nXG4gICAgICAgICAgICAgICpuZ0lmPVwibW9kZWxXaXRoU3VnZ2VzdGlvbnMubW9kZWwuaW1hZ2VVcmxcIlxuICAgICAgICAgICAgICBbc3JjXT1cIm1vZGVsV2l0aFN1Z2dlc3Rpb25zLm1vZGVsLmltYWdlVXJsXCJcbiAgICAgICAgICAgICAgW2FsdF09XCJtb2RlbFdpdGhTdWdnZXN0aW9ucy5tb2RlbC5kaXNwbGF5TmFtZVwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgICAge3sgbW9kZWxXaXRoU3VnZ2VzdGlvbnMubW9kZWwuZGlzcGxheU5hbWUgfX0gKHt7XG4gICAgICAgICAgICAgIG1vZGVsV2l0aFN1Z2dlc3Rpb25zLml0ZW1zLmxlbmd0aFxuICAgICAgICAgICAgfX0pXG4gICAgICAgICAgPC9oMz5cbiAgICAgICAgICA8dWw+XG4gICAgICAgICAgICA8bGlcbiAgICAgICAgICAgICAgKm5nRm9yPVwibGV0IHN1Z2dlc3Rpb24gb2YgbW9kZWxXaXRoU3VnZ2VzdGlvbnMuaXRlbXNcIlxuICAgICAgICAgICAgICAobW91c2Vkb3duKT1cInBvcHVsYXRlVmFsdWUoc3VnZ2VzdGlvbiwgJGV2ZW50KVwiXG4gICAgICAgICAgICAgIGNsYXNzPVwic3VnZ2VzdGlvbnNcIlxuICAgICAgICAgICAgPlxuICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwic3VidGl0bGVUZW1wbGF0ZVwiPlxuICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwiXG4gICAgICAgICAgICAgICAgICAgIHN1YnRpdGxlVGVtcGxhdGU7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQ6IHskaW1wbGljaXQ6IHN1Z2dlc3Rpb259XG4gICAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgIDxwXG4gICAgICAgICAgICAgICAgKm5nSWY9XCIhdGl0bGVUZW1wbGF0ZVwiXG4gICAgICAgICAgICAgICAgW2lubmVySFRNTF09XCJcbiAgICAgICAgICAgICAgICAgIGJvbGRTdHJpbmcoXG4gICAgICAgICAgICAgICAgICAgIHN1Z2dlc3Rpb25bY29uZmlnLmRpc3BsYXlQcm9wZXJ0eU5hbWVdLFxuICAgICAgICAgICAgICAgICAgICBzZWFyY2hCb3hJbnB1dFxuICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIFwiXG4gICAgICAgICAgICAgICAgc3R5bGU9XCJkaXNwbGF5OiBpbmxpbmVcIlxuICAgICAgICAgICAgICA+PC9wPlxuICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwidGl0bGVUZW1wbGF0ZVwiPlxuICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwiXG4gICAgICAgICAgICAgICAgICAgIHRpdGxlVGVtcGxhdGU7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQ6IHskaW1wbGljaXQ6IHN1Z2dlc3Rpb259XG4gICAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICA8L2xpPlxuICAgICAgICAgIDwvdWw+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiIWNvbmZpZy5jYXRlZ29yaXplUmVzdWx0c1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwic2VhcmNoLXJlc3VsdFwiPlxuICAgICAgICAgIDx1bD5cbiAgICAgICAgICAgIDxsaVxuICAgICAgICAgICAgICAqbmdGb3I9XCJsZXQgc3VnZ2VzdGlvbiBvZiBzdWdnZXN0aW9uc1wiXG4gICAgICAgICAgICAgIChtb3VzZWRvd24pPVwicG9wdWxhdGVWYWx1ZShzdWdnZXN0aW9uLCAkZXZlbnQpXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPCEtLU5lZWQgdG8gY2FsbCBmZXRjaE1vZGVsSW1hZ2VVcmxGcm9tU3VnZ2VzdGlvbiBhcyBlYWNoIHN1Z2dlc3Rpb24gY2FuIGNvbWUgZnJvbSBkaWZmZXJlbnQgbW9kZWwtLT5cbiAgICAgICAgICAgICAgPGltZ1xuICAgICAgICAgICAgICAgICpuZ0lmPVwiXG4gICAgICAgICAgICAgICAgICAhdGl0bGVUZW1wbGF0ZSAmJiBmZXRjaE1vZGVsSW1hZ2VVcmxGcm9tU3VnZ2VzdGlvbihzdWdnZXN0aW9uKVxuICAgICAgICAgICAgICAgIFwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJzdWdnZXN0aW9ucy1jYXRlZ29yaXplLWZhbHNlXCJcbiAgICAgICAgICAgICAgICBbc3JjXT1cImZldGNoTW9kZWxJbWFnZVVybEZyb21TdWdnZXN0aW9uKHN1Z2dlc3Rpb24pXCJcbiAgICAgICAgICAgICAgICBzdHlsZT1cIm1hcmdpbi1yaWdodDogNXB4XCJcbiAgICAgICAgICAgICAgICBhbHQ9XCJJbWdcIlxuICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwic3VidGl0bGVUZW1wbGF0ZVwiPlxuICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwiXG4gICAgICAgICAgICAgICAgICAgIHN1YnRpdGxlVGVtcGxhdGU7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQ6IHskaW1wbGljaXQ6IHN1Z2dlc3Rpb259XG4gICAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICAgIDxwXG4gICAgICAgICAgICAgICAgKm5nSWY9XCIhdGl0bGVUZW1wbGF0ZVwiXG4gICAgICAgICAgICAgICAgW2lubmVySFRNTF09XCJcbiAgICAgICAgICAgICAgICAgIGJvbGRTdHJpbmcoXG4gICAgICAgICAgICAgICAgICAgIHN1Z2dlc3Rpb25bY29uZmlnLmRpc3BsYXlQcm9wZXJ0eU5hbWVdLFxuICAgICAgICAgICAgICAgICAgICBzZWFyY2hCb3hJbnB1dFxuICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIFwiXG4gICAgICAgICAgICAgICAgc3R5bGU9XCJkaXNwbGF5OiBpbmxpbmVcIlxuICAgICAgICAgICAgICA+PC9wPlxuICAgICAgICAgICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwidGl0bGVUZW1wbGF0ZVwiPlxuICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXJcbiAgICAgICAgICAgICAgICAgICpuZ1RlbXBsYXRlT3V0bGV0PVwiXG4gICAgICAgICAgICAgICAgICAgIHRpdGxlVGVtcGxhdGU7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQ6IHskaW1wbGljaXQ6IHN1Z2dlc3Rpb259XG4gICAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cbiAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgICAgICAgICA8L2xpPlxuICAgICAgICAgIDwvdWw+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9uZy1jb250YWluZXI+XG4gICAgPC9uZy1jb250YWluZXI+XG5cbiAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiIWNvbmZpZy5oaWRlUmVjZW50U2VhcmNoICYmIHJlY2VudFNlYXJjaGVzLmxlbmd0aCA+IDBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJyZWNlbnQtc2VhcmNoZXNcIj5cbiAgICAgICAgPGgzIGNsYXNzPVwic3VnZ2VzdGlvbnMtaGVhZGluZ1wiPlJlY2VudCBTZWFyY2hlczwvaDM+XG4gICAgICAgIDx1bD5cbiAgICAgICAgICA8bGlcbiAgICAgICAgICAgICpuZ0Zvcj1cImxldCByZWNlbnRTZWFyY2ggb2YgcmVjZW50U2VhcmNoZXNcIlxuICAgICAgICAgICAgY2xhc3M9XCJzdWdnZXN0aW9uc1wiXG4gICAgICAgICAgICAobW91c2Vkb3duKT1cInBvcHVsYXRlVmFsdWVSZWNlbnRTZWFyY2gocmVjZW50U2VhcmNoLCAkZXZlbnQpXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8bWF0LWljb25cbiAgICAgICAgICAgICAgbWF0UHJlZml4XG4gICAgICAgICAgICAgIFtjbGFzc05hbWVdPVwiY29uZmlnLnJlY2VudFNlYXJjaEljb25DbGFzc1wiXG4gICAgICAgICAgICA+PC9tYXQtaWNvbj5cblxuICAgICAgICAgICAgPHNwYW4+Jm5ic3A7e3sgcmVjZW50U2VhcmNoLm1hdGNoIH19PC9zcGFuPlxuICAgICAgICAgIDwvbGk+XG4gICAgICAgIDwvdWw+XG4gICAgICA8L2Rpdj5cbiAgICA8L25nLWNvbnRhaW5lcj5cbiAgPC9kaXY+XG48L2Rpdj5cbiJdfQ==