@esfaenza/es-table 11.2.21 → 11.2.22-beta12
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.
- package/bundles/esfaenza-es-table.umd.js +3430 -1575
- package/bundles/esfaenza-es-table.umd.js.map +1 -1
- package/bundles/esfaenza-es-table.umd.min.js +1 -15
- package/bundles/esfaenza-es-table.umd.min.js.map +1 -1
- package/esfaenza-es-table.d.ts +7 -6
- package/esfaenza-es-table.metadata.json +1 -1
- package/esm2015/esfaenza-es-table.js +8 -7
- package/esm2015/lib/components/es-table/es_table.component.js +1293 -0
- package/esm2015/lib/components/es-table/es_table.component.loc.js +36 -0
- package/esm2015/lib/components/es-td/es_td.component.js +106 -0
- package/esm2015/lib/components/es-th/es_th.component.js +160 -0
- package/esm2015/lib/components/pager/table_pager.component.js +100 -0
- package/esm2015/lib/components/pager/table_pager.component.loc.js +22 -0
- package/esm2015/lib/core/handlers/classes/ColumnMetadataHandler.js +667 -0
- package/esm2015/lib/core/handlers/classes/DynamicModeHandler.js +64 -0
- package/esm2015/lib/core/handlers/classes/ExportHandler.js +43 -0
- package/esm2015/lib/core/handlers/classes/HierarchyModeHandler.js +136 -0
- package/esm2015/lib/core/handlers/classes/ItemsHandler.js +121 -0
- package/esm2015/lib/core/handlers/classes/ReportModeHandler.js +70 -0
- package/esm2015/lib/core/handlers/classes/RowGroupingHandler.js +475 -0
- package/esm2015/lib/core/handlers/classes/SelectionHandler.js +527 -0
- package/esm2015/lib/core/handlers/classes/UtilitiesHandler.js +169 -0
- package/esm2015/lib/core/handlers/index.js +10 -0
- package/esm2015/lib/directives/es_td.directive.js +2 -4
- package/esm2015/lib/directives/es_th.directive.js +23 -7
- package/esm2015/lib/domain/configuration/EsTableDefaultable.js +4 -0
- package/esm2015/lib/domain/configuration/EsTableModuleConfig.js +4 -0
- package/esm2015/lib/domain/externals/classes/CornerMenuOption.js +4 -0
- package/esm2015/lib/domain/externals/classes/EsTableColumnsDefinition.js +31 -0
- package/esm2015/lib/domain/externals/classes/EsTableOperationDefinition.js +22 -0
- package/esm2015/lib/domain/externals/classes/appsearch/AppOrdering.js +16 -0
- package/esm2015/lib/domain/externals/classes/appsearch/AppSearch.js +35 -0
- package/esm2015/lib/domain/externals/classes/appsearch/GenericItem.js +11 -0
- package/esm2015/lib/domain/externals/classes/appsearch/Group.js +17 -0
- package/esm2015/lib/domain/externals/classes/appsearch/GroupAggregation.js +16 -0
- package/esm2015/lib/domain/externals/classes/appsearch/GroupFilter.js +14 -0
- package/esm2015/lib/domain/externals/classes/appsearch/GroupOrAggregation.js +16 -0
- package/esm2015/lib/domain/externals/classes/appsearch/ItemsSelection.js +23 -0
- package/esm2015/lib/domain/externals/classes/report/ReportColumn.js +4 -0
- package/esm2015/lib/domain/externals/classes/report/ReportDefinition.js +4 -0
- package/esm2015/lib/domain/externals/classes/report/ReportOrder.js +4 -0
- package/esm2015/lib/domain/externals/classes/report/ReportParam.js +4 -0
- package/esm2015/lib/domain/externals/classes/report/ReportResult.js +4 -0
- package/esm2015/lib/domain/externals/classes/report/ReportRow.js +4 -0
- package/esm2015/lib/domain/externals/index.js +18 -0
- package/esm2015/lib/domain/index.js +3 -16
- package/esm2015/lib/domain/internals/classes/CacheTriptic.js +16 -0
- package/esm2015/lib/domain/internals/classes/EsTableColumn.js +24 -0
- package/esm2015/lib/domain/internals/classes/GroupPager.js +21 -0
- package/esm2015/lib/domain/internals/classes/GroupRouteFragment.js +17 -0
- package/esm2015/lib/domain/internals/classes/ThAggregation.js +16 -0
- package/esm2015/lib/domain/internals/classes/ThElement.js +2 -0
- package/esm2015/lib/domain/internals/index.js +7 -0
- package/esm2015/lib/es-table.module.js +13 -8
- package/esm2015/lib/tokens.js +6 -4
- package/esm2015/public-api.js +7 -6
- package/fesm2015/esfaenza-es-table.js +3416 -1692
- package/fesm2015/esfaenza-es-table.js.map +1 -1
- package/lib/{es_table.component.d.ts → components/es-table/es_table.component.d.ts} +163 -331
- package/lib/{es_table.component.loc.d.ts → components/es-table/es_table.component.loc.d.ts} +2 -6
- package/lib/{es_td.component.d.ts → components/es-td/es_td.component.d.ts} +14 -36
- package/lib/{es_th.component.d.ts → components/es-th/es_th.component.d.ts} +27 -61
- package/lib/components/pager/table_pager.component.d.ts +50 -0
- package/lib/{pager → components/pager}/table_pager.component.loc.d.ts +2 -6
- package/lib/core/handlers/classes/ColumnMetadataHandler.d.ts +159 -0
- package/lib/core/handlers/classes/DynamicModeHandler.d.ts +32 -0
- package/lib/core/handlers/classes/ExportHandler.d.ts +22 -0
- package/lib/core/handlers/classes/HierarchyModeHandler.d.ts +40 -0
- package/lib/core/handlers/classes/ItemsHandler.d.ts +41 -0
- package/lib/core/handlers/classes/ReportModeHandler.d.ts +21 -0
- package/lib/core/handlers/classes/RowGroupingHandler.d.ts +114 -0
- package/lib/core/handlers/classes/SelectionHandler.d.ts +149 -0
- package/lib/core/handlers/classes/UtilitiesHandler.d.ts +67 -0
- package/lib/core/handlers/index.d.ts +9 -0
- package/lib/directives/es_td.directive.d.ts +1 -3
- package/lib/directives/es_th.directive.d.ts +18 -5
- package/lib/domain/configuration/EsTableDefaultable.d.ts +19 -0
- package/lib/domain/configuration/EsTableModuleConfig.d.ts +10 -0
- package/lib/domain/externals/classes/CornerMenuOption.d.ts +7 -0
- package/lib/domain/{classes → externals/classes}/EsTableColumnsDefinition.d.ts +5 -7
- package/lib/domain/{classes → externals/classes}/EsTableOperationDefinition.d.ts +1 -3
- package/lib/domain/{classes → externals/classes/appsearch}/AppOrdering.d.ts +0 -0
- package/lib/domain/externals/classes/appsearch/AppSearch.d.ts +67 -0
- package/lib/domain/externals/classes/appsearch/GenericItem.d.ts +13 -0
- package/lib/domain/externals/classes/appsearch/Group.d.ts +17 -0
- package/lib/domain/externals/classes/appsearch/GroupAggregation.d.ts +14 -0
- package/lib/domain/externals/classes/appsearch/GroupFilter.d.ts +12 -0
- package/lib/domain/externals/classes/appsearch/GroupOrAggregation.d.ts +14 -0
- package/lib/domain/externals/classes/appsearch/ItemsSelection.d.ts +22 -0
- package/lib/domain/externals/classes/report/ReportColumn.d.ts +15 -0
- package/lib/domain/externals/classes/report/ReportDefinition.d.ts +24 -0
- package/lib/domain/externals/classes/report/ReportOrder.d.ts +7 -0
- package/lib/domain/externals/classes/report/ReportParam.d.ts +40 -0
- package/lib/domain/externals/classes/report/ReportResult.d.ts +12 -0
- package/lib/domain/externals/classes/report/ReportRow.d.ts +5 -0
- package/lib/domain/externals/index.d.ts +17 -0
- package/lib/domain/index.d.ts +2 -15
- package/lib/domain/internals/classes/CacheTriptic.d.ts +14 -0
- package/lib/domain/{classes → internals/classes}/EsTableColumn.d.ts +8 -4
- package/lib/domain/internals/classes/GroupPager.d.ts +22 -0
- package/lib/domain/internals/classes/GroupRouteFragment.d.ts +15 -0
- package/lib/domain/internals/classes/ThAggregation.d.ts +14 -0
- package/lib/domain/internals/classes/ThElement.d.ts +13 -0
- package/lib/domain/internals/index.d.ts +6 -0
- package/lib/es-table.module.d.ts +1 -1
- package/lib/tokens.d.ts +6 -3
- package/package.json +2 -1
- package/public-api.d.ts +6 -5
- package/esm2015/lib/domain/classes/AppOrdering.js +0 -16
- package/esm2015/lib/domain/classes/AppSearch.js +0 -35
- package/esm2015/lib/domain/classes/CornerMenuOption.js +0 -6
- package/esm2015/lib/domain/classes/EsTableColumn.js +0 -22
- package/esm2015/lib/domain/classes/EsTableColumnsDefinition.js +0 -31
- package/esm2015/lib/domain/classes/EsTableOperationDefinition.js +0 -24
- package/esm2015/lib/domain/classes/GenericItem.js +0 -15
- package/esm2015/lib/domain/classes/IAppSearch.js +0 -2
- package/esm2015/lib/domain/classes/ItemsSelection.js +0 -25
- package/esm2015/lib/domain/classes/ReportColumn.js +0 -6
- package/esm2015/lib/domain/classes/ReportDefinition.js +0 -6
- package/esm2015/lib/domain/classes/ReportOrder.js +0 -6
- package/esm2015/lib/domain/classes/ReportParam.js +0 -6
- package/esm2015/lib/domain/classes/ReportResult.js +0 -6
- package/esm2015/lib/domain/classes/ReportRow.js +0 -6
- package/esm2015/lib/es_table.component.js +0 -1958
- package/esm2015/lib/es_table.component.loc.js +0 -36
- package/esm2015/lib/es_td.component.js +0 -121
- package/esm2015/lib/es_th.component.js +0 -178
- package/esm2015/lib/models/EsTableModuleConfig.js +0 -6
- package/esm2015/lib/pager/table_pager.component.js +0 -70
- package/esm2015/lib/pager/table_pager.component.loc.js +0 -24
- package/lib/domain/classes/AppSearch.d.ts +0 -76
- package/lib/domain/classes/CornerMenuOption.d.ts +0 -13
- package/lib/domain/classes/GenericItem.d.ts +0 -25
- package/lib/domain/classes/IAppSearch.d.ts +0 -67
- package/lib/domain/classes/ItemsSelection.d.ts +0 -27
- package/lib/domain/classes/ReportColumn.d.ts +0 -29
- package/lib/domain/classes/ReportDefinition.d.ts +0 -46
- package/lib/domain/classes/ReportOrder.d.ts +0 -13
- package/lib/domain/classes/ReportParam.d.ts +0 -76
- package/lib/domain/classes/ReportResult.d.ts +0 -22
- package/lib/domain/classes/ReportRow.d.ts +0 -9
- package/lib/models/EsTableModuleConfig.d.ts +0 -9
- package/lib/pager/table_pager.component.d.ts +0 -50
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
// Modelli
|
|
2
|
+
import { Group, GroupAggregation, GroupOrAggregation, GroupPager, GroupRouteFragment } from "../../../domain";
|
|
3
|
+
/** Classe che gestisce la modalità Row Grouping dell'es-table */
|
|
4
|
+
export class RowGroupingHandler {
|
|
5
|
+
/** @ignore Costruttore */
|
|
6
|
+
constructor(est, utilities, dateExts) {
|
|
7
|
+
this.est = est;
|
|
8
|
+
this.utilities = utilities;
|
|
9
|
+
this.dateExts = dateExts;
|
|
10
|
+
/** Cache per salvare per ogni chiave di ogni gruppo chi è il gruppo rappresentato */
|
|
11
|
+
this.rgGroupCache = new Map();
|
|
12
|
+
/** Cache per salvare per ogni chiave di ogni gruppo chi sono gli oggetti sottostanti, non dei sottogruppi */
|
|
13
|
+
this.rgItemCache = new Map();
|
|
14
|
+
/** Cache per salvare per ogni chiave di ogni gruppo chi sono gli oggetti sottostanti, non dei sottogruppi */
|
|
15
|
+
this.rgChildGroupsCache = new Map();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* In modalità rowgrouping quando mi arriva un nuovo blocco di oggetti devo aggiungerlo alla vista attuale:
|
|
19
|
+
*
|
|
20
|
+
* 1) Se non viene richiesto il dettaglio di alcun gruppo significa che devo considerare mi siano arrivati tutti i gruppi principali
|
|
21
|
+
* 2) Se viene richiesto il dettaglio di un gruppo diverso dall'ultimo devo aggiungere dopo al gruppo cliccato la lista dei sottogruppi
|
|
22
|
+
* 2) Se viene richiesto il dettaglio dell'ultimo gruppo devo aggiungere dopo al gruppo cliccato la lista degli oggetti
|
|
23
|
+
*
|
|
24
|
+
* @param {any} view AppSearch<T> da cui sono arrivati gli oggetti
|
|
25
|
+
* @param {number} groupingKeys Livelli di raggruppamento da aspettarsi sui dati
|
|
26
|
+
*/
|
|
27
|
+
handleNewDataOnRowGrouping(view, groupingKeys) {
|
|
28
|
+
var _a, _b;
|
|
29
|
+
// 1) Se non viene richiesto il dettaglio di alcun gruppo significa che la chiamata restituisce la lista paginata dei gruppi principali.
|
|
30
|
+
// Li tratto come se fosse una qualsiasi altra query paginata su N elementi
|
|
31
|
+
if ((((_a = view.requestedgroups) === null || _a === void 0 ? void 0 : _a.length) || 0) == 0) {
|
|
32
|
+
this.est.boundSource = this.est.TMPBoundSource;
|
|
33
|
+
this.rgGroupCache = new Map();
|
|
34
|
+
this.rgItemCache = new Map();
|
|
35
|
+
this.rgChildGroupsCache = new Map();
|
|
36
|
+
this.est.TMPBoundSource.forEach(itm => {
|
|
37
|
+
itm._thisRoute = itm._group ? [{ column: itm.column, value: itm.value }] : [];
|
|
38
|
+
itm._thisKey = itm._group ? itm.value : null;
|
|
39
|
+
itm._grouplevel = 0;
|
|
40
|
+
this.rgGroupCache.set(itm._thisKey, itm);
|
|
41
|
+
});
|
|
42
|
+
// Resetto la ricerca alla cache di questa "sessione"
|
|
43
|
+
let firstItem = this.est.TMPBoundSource[0];
|
|
44
|
+
this.est.MainGroupView = Object.assign({}, view);
|
|
45
|
+
this.est.groupSearchRequestsCache = [{ path: '', route: [{ column: firstItem.column, value: firstItem.value }], view: this.est.MainGroupView, group_column: this.est.TMPBoundSource[0].column }];
|
|
46
|
+
this.est.BaseItemsCount = view.objectcount;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// 2) Se viene richiesto il dettaglio di un qualsiasi gruppo diverso dall'ultimo vuol dire che devo aggiungere
|
|
50
|
+
// dopo al gruppo che ho cliccato la lista dei gruppi tirata fuori questa volta (intermediateGroup = true)
|
|
51
|
+
/*
|
|
52
|
+
* GruppoA GruppoA
|
|
53
|
+
* GruppoB GruppoB
|
|
54
|
+
* GruppoC <- Clicco qui GruppoC
|
|
55
|
+
* GruppoD GruppoC1
|
|
56
|
+
* GruppoE GruppoC2
|
|
57
|
+
* GruppoD
|
|
58
|
+
* GruppoE
|
|
59
|
+
*/
|
|
60
|
+
// 3) se i gruppi richiesti dalla view sono uguali ai gruppi presenti vuol dire che sto prendendo gli oggetti veri e propri, sono in
|
|
61
|
+
// view.items e quindi in TMPBoundSource, ho inoltre le informazioni di paginazione **per il singolo sottogruppo** (intermediateGroup = false)
|
|
62
|
+
/*
|
|
63
|
+
* GruppoA GruppoA
|
|
64
|
+
* GruppoC1 GruppoC1
|
|
65
|
+
* GruppoB GruppoB
|
|
66
|
+
* GruppoC GruppoC
|
|
67
|
+
* GruppoC1 <-- Clicco qui GruppoC1
|
|
68
|
+
* Oggetto1
|
|
69
|
+
* Oggetto2
|
|
70
|
+
* Oggetto3
|
|
71
|
+
* GruppoC2 GruppoC2
|
|
72
|
+
* GruppoD GruppoD
|
|
73
|
+
* GruppoE GruppoE
|
|
74
|
+
*/
|
|
75
|
+
let intermediateGroup = view.requestedgroups.length != groupingKeys;
|
|
76
|
+
let items = this.est.boundSource;
|
|
77
|
+
let insertIndex = 0;
|
|
78
|
+
let insertGroup = null;
|
|
79
|
+
let groupKey = "";
|
|
80
|
+
let groupRoute = [];
|
|
81
|
+
// Navigo la stuttura dei gruppi ignorando ricorsivamente tutti gli indici fino ai gruppi che mi interessano in modo da non beccare il primo "GruppoC1" del caso sopra
|
|
82
|
+
for (let i = 0; i < view.requestedgroups.length; i++) {
|
|
83
|
+
let rg = view.requestedgroups[i];
|
|
84
|
+
groupKey += rg.value;
|
|
85
|
+
groupRoute.push({ column: rg.column, value: rg.value });
|
|
86
|
+
for (let i = insertIndex; i < items.length; i++) {
|
|
87
|
+
let t = items[i];
|
|
88
|
+
if (i >= insertIndex && t._group && t.column == rg.column && t.value == rg.value) {
|
|
89
|
+
insertIndex = i;
|
|
90
|
+
insertGroup = t;
|
|
91
|
+
// Lo marco expanded dato che questo click sul gruppo potrebbe non essere stato fatto
|
|
92
|
+
insertGroup._expanded = true;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
let itemsCacheReference;
|
|
98
|
+
let childGroupsCacheReference;
|
|
99
|
+
// Se non è un gruppo intermedio devo ripulire la cache del gruppo su cui ho attualmente cliccato. Gli oggetti saranno riaggiunti dopo
|
|
100
|
+
if (!intermediateGroup) {
|
|
101
|
+
this.rgItemCache.set(groupKey, []);
|
|
102
|
+
itemsCacheReference = this.rgItemCache.get(groupKey);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Se invece è un gruppo intermedio devo ripulire sia tutti i child group ricorsivamente, sia tutti gli item
|
|
106
|
+
for (let key of this.rgChildGroupsCache.keys())
|
|
107
|
+
if (key.startsWith(groupKey))
|
|
108
|
+
this.rgChildGroupsCache.delete(key);
|
|
109
|
+
for (let key of this.rgItemCache.keys())
|
|
110
|
+
if (key.startsWith(groupKey))
|
|
111
|
+
this.rgItemCache.delete(key);
|
|
112
|
+
this.rgChildGroupsCache.set(groupKey, []);
|
|
113
|
+
childGroupsCacheReference = this.rgChildGroupsCache.get(groupKey);
|
|
114
|
+
}
|
|
115
|
+
// Assegno un livello ai valori che arrivano da usare per formattare la parte grafica. Il primo gruppo cliccato sarà a livello 1,
|
|
116
|
+
// il secondo sarà a livello 2 e così via...
|
|
117
|
+
// Li marco inoltre con il parent in modo da poter eliminare i vecchi qualora servisse
|
|
118
|
+
this.est.TMPBoundSource.forEach(itm => {
|
|
119
|
+
itm._parent = groupKey;
|
|
120
|
+
itm._parentRoute = groupRoute;
|
|
121
|
+
itm._thisRoute = itm._group ? [...groupRoute, new GroupRouteFragment(itm.column, itm.value)] : [];
|
|
122
|
+
itm._thisKey = itm._group ? groupKey + itm.value : groupKey;
|
|
123
|
+
// Per le ricerca intermedie metto i gruppi nella cache dei gruppi
|
|
124
|
+
if (intermediateGroup) {
|
|
125
|
+
itm._grouplevel = view.requestedgroups.length;
|
|
126
|
+
this.rgGroupCache.set(itm._thisKey, itm);
|
|
127
|
+
childGroupsCacheReference.push(itm);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// Metto anche gli oggetti nella cache non ricorsiva
|
|
131
|
+
itemsCacheReference.push(itm);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
// Elimino gli oggetti vecchi
|
|
135
|
+
// 1) Ricerca intermedia, stato salvato - Elimino tutti gli item e tutti i gruppi la cui route è più lunga della corrente, tutti gli item relativi alla path corrente, e tutte
|
|
136
|
+
// le cache di ricerca effettuate su una path più profonda dell'attuale
|
|
137
|
+
// 2) Ricerca finale o ricerca intermedia senza stato salvato - Elimino tutti gli item relativi alla path corrente
|
|
138
|
+
// Per "stato salvato" si intendono ricerche vecchie salvate per poter essere rieffettuate in caso di ordinamenti su colonne di interesse
|
|
139
|
+
if (intermediateGroup && view.savedstate) {
|
|
140
|
+
this.est.boundSource = this.est.boundSource.filter(t => !(t._item || t._thisRoute.length > groupRoute.length));
|
|
141
|
+
this.est.groupSearchRequestsCache = this.est.groupSearchRequestsCache.filter(t => !(t.route.length > groupRoute.length));
|
|
142
|
+
}
|
|
143
|
+
this.est.boundSource = this.est.boundSource.filter(t => !(t._parent == groupKey));
|
|
144
|
+
let thisGroup = this.est.boundSource[insertIndex];
|
|
145
|
+
if (intermediateGroup)
|
|
146
|
+
thisGroup._groupscount = (_b = this.est.View) === null || _b === void 0 ? void 0 : _b.groupcount;
|
|
147
|
+
// Li sostituisco coi nuovi di questa ricerca
|
|
148
|
+
this.est.boundSource.splice(insertIndex + 1, 0, ...this.est.TMPBoundSource);
|
|
149
|
+
// Aggiungo un separatore alla fine o all'inizio di questi gruppi che dovrà occuparsi di caricare ALTRI gruppi o oggetti (se sono all'ultimo gruppo)
|
|
150
|
+
let addLast = false;
|
|
151
|
+
this.est.boundSource.splice(insertIndex + 1 + (addLast ? this.est.TMPBoundSource.length : 0), 0, this.getGroupSeparator(view, groupKey, groupRoute, view.requestedgroups.length, intermediateGroup ? 'groups' : 'items'));
|
|
152
|
+
// Aggiungo la ricerca alla cache di questa "sessione"
|
|
153
|
+
let toAdd = { path: groupKey, route: groupRoute, view: Object.assign({}, view), group_column: intermediateGroup ? this.est.TMPBoundSource[0].column : '' };
|
|
154
|
+
let prev = this.est.groupSearchRequestsCache.findIndex(t => t.path == toAdd.path && t.group_column == toAdd.group_column);
|
|
155
|
+
if (prev == -1)
|
|
156
|
+
this.est.groupSearchRequestsCache.push(toAdd);
|
|
157
|
+
else
|
|
158
|
+
this.est.groupSearchRequestsCache.splice(prev, 1, toAdd);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Se in modalità array applica i raggruppamenti definiti lato row-grouping
|
|
163
|
+
*
|
|
164
|
+
* @param {ths: EsTh[] | EsThDirective[]} ths Header
|
|
165
|
+
*/
|
|
166
|
+
arrayModeReviewGroupings(ths) {
|
|
167
|
+
if (ths.length == 0)
|
|
168
|
+
return;
|
|
169
|
+
if (this.utilities.isEsTh(ths[0]))
|
|
170
|
+
return;
|
|
171
|
+
let headerGroups = [];
|
|
172
|
+
let headerAggregations = [];
|
|
173
|
+
for (let i = 0; i < ths.length; i++) {
|
|
174
|
+
let th = ths[i];
|
|
175
|
+
if (th.thGroup)
|
|
176
|
+
headerGroups.push(new Group(th.th, 0, ""));
|
|
177
|
+
else if (th.thAggregation)
|
|
178
|
+
headerAggregations = [...headerAggregations, ...this.getGroupAggregations(th)];
|
|
179
|
+
}
|
|
180
|
+
if (headerGroups.length > 0) {
|
|
181
|
+
// Pulizia delle cache
|
|
182
|
+
this.rgGroupCache.clear();
|
|
183
|
+
this.rgItemCache.clear();
|
|
184
|
+
this.rgChildGroupsCache.clear();
|
|
185
|
+
this.est.ArrayGrouping = true;
|
|
186
|
+
this.est.boundSource = this.getGroupsRecursive(headerGroups, 0, this.est.boundSource, headerAggregations, null);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Data una direttiva EsTh restituisce la lista delle aggregazioni richiesta per questa colonna o il gruppo che rappresenta
|
|
191
|
+
*
|
|
192
|
+
* @param {EsThDirective} th Direttiva
|
|
193
|
+
*
|
|
194
|
+
* @returns {GroupOrAggregation[]} Lista dei gruppi o aggregazioni relativi alla Direttiva passata
|
|
195
|
+
*/
|
|
196
|
+
getGroupAggregations(th) {
|
|
197
|
+
let ret = [];
|
|
198
|
+
// Es: '{min:dd/MM/yyyy} - {max:dd/MM/yyyy}'
|
|
199
|
+
if (th.thAggregation) {
|
|
200
|
+
this.getEsThDirectiveListOfAggregations(th).forEach((agg) => {
|
|
201
|
+
let isdate = agg.format && ['small', 'long', 'verylong'].includes(agg.format);
|
|
202
|
+
let isnumber = agg.format && agg.format.startsWith("F") && !Number.isNaN(agg.format.charAt(1)) && agg.format.length == 2;
|
|
203
|
+
if (!isdate && !isnumber && agg.format)
|
|
204
|
+
throw "Le aggergazioni supportate dall'es-table sono solo 'small', 'long', 'verylong' per le date e 'F0-9' per i numeri";
|
|
205
|
+
ret.push(new GroupOrAggregation(th.th, agg.func, isdate ? 'date' : isnumber ? 'number' : 'string'));
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
else if (th.thGroup)
|
|
209
|
+
ret.push(new GroupOrAggregation(th.th, null));
|
|
210
|
+
return ret;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Data una direttiva con un formato restituisce tutte le coppie Funzione di Aggregazione - Formato
|
|
214
|
+
*
|
|
215
|
+
* @param {EsThDirective} th Direttiva EsTh di cui calcolare le funzioni di aggregazione usate
|
|
216
|
+
*
|
|
217
|
+
* @returns {{ func: string, format: string }[]} Lista delle funzioni di aggregazione rilevate
|
|
218
|
+
*/
|
|
219
|
+
getEsThDirectiveListOfAggregations(th) {
|
|
220
|
+
if (!th.thAggregation)
|
|
221
|
+
return [];
|
|
222
|
+
// Se ho già effettuato questo calcolo per questo th restituisco la versione in cache
|
|
223
|
+
if (th._thAggregations)
|
|
224
|
+
return th._thAggregations;
|
|
225
|
+
let ret = [];
|
|
226
|
+
let display = th.thAggregation;
|
|
227
|
+
var matches = display.match(/{[a-zA-Z0-9\/:]*}/gi);
|
|
228
|
+
if (!matches)
|
|
229
|
+
return [];
|
|
230
|
+
matches.forEach(m => {
|
|
231
|
+
let split = m.split(":");
|
|
232
|
+
let func = m, format = "";
|
|
233
|
+
if (split.length > 0) {
|
|
234
|
+
// Escludo primo e ultimo carattere (le graffe)
|
|
235
|
+
func = split[0].substr(1);
|
|
236
|
+
format = split[1].substr(0, split[1].length - 1);
|
|
237
|
+
}
|
|
238
|
+
ret.push({ func: func, format: format, match: m });
|
|
239
|
+
});
|
|
240
|
+
th._thAggregations = ret;
|
|
241
|
+
return ret;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Data la definizione dei gruppi da generare da una lista di oggetti, suddivide gli oggetti passati in gruppi e sottogruppi
|
|
245
|
+
*
|
|
246
|
+
* @param {Group[]} grps Definizione dei gruppi
|
|
247
|
+
* @param {number} currentIndex Indice di elaborazione. Al livello 0 ho tutti gli oggetti e devo generare i primi gruppi, a livello 1 ho tutti i gruppi principali e devo
|
|
248
|
+
* elaborare i sottogruppi, e così via ricorsivamente...
|
|
249
|
+
* @param {any[]} items Oggetti da raggruppare
|
|
250
|
+
* @param {GroupOrAggregation[]} aggregations Info di aggregazione
|
|
251
|
+
* @param {any} parent Riferimento al gruppo padre
|
|
252
|
+
*/
|
|
253
|
+
getGroupsRecursive(grps, currentIndex, items, aggregations, parent) {
|
|
254
|
+
// Se l'indice è 0 devo sicuramente nascondere tutti gli oggetti. Solo i gruppi saranno visualizzati
|
|
255
|
+
if (currentIndex == 0)
|
|
256
|
+
items.forEach(i => i._visible = false);
|
|
257
|
+
let grp = grps[currentIndex];
|
|
258
|
+
let ret = [];
|
|
259
|
+
let last = grps.length == currentIndex + 1;
|
|
260
|
+
let groups = this.utilities.groupBy(items, grp.column);
|
|
261
|
+
for (let prop in groups) {
|
|
262
|
+
let itms = groups[prop];
|
|
263
|
+
let gp = new Group(grp.column, itms.length, prop);
|
|
264
|
+
gp.aggregations = this.generateAggregations(itms, aggregations);
|
|
265
|
+
let anygp = gp;
|
|
266
|
+
anygp._group = true;
|
|
267
|
+
anygp._expanded = false;
|
|
268
|
+
if (!parent) {
|
|
269
|
+
anygp._thisRoute = [{ column: gp.column, value: gp.value }];
|
|
270
|
+
anygp._thisKey = gp.value;
|
|
271
|
+
anygp._grouplevel = 0;
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
anygp._parent = parent._thisKey;
|
|
275
|
+
anygp._parentRoute = parent._thisRoute;
|
|
276
|
+
anygp._thisRoute = [...parent._thisRoute, { column: gp.column, value: gp.value }];
|
|
277
|
+
anygp._thisKey = parent._thisKey + gp.value;
|
|
278
|
+
anygp._grouplevel = parent._grouplevel + 1;
|
|
279
|
+
}
|
|
280
|
+
// Pusho il gruppo, tutti i gruppi del livello sotto, o gli item se io sono l'ultimo gruppo.
|
|
281
|
+
// La visibilità è solo per il gruppo a livello 0, tutti gli altri gruppi saranno mostrati o nascosti di conseguenza
|
|
282
|
+
if (currentIndex == 0)
|
|
283
|
+
anygp._visible = true;
|
|
284
|
+
this.utilities.calculateHash([anygp]);
|
|
285
|
+
this.utilities.cacheAggregations(anygp);
|
|
286
|
+
// Aggiungo il gruppo padre
|
|
287
|
+
ret.push(anygp);
|
|
288
|
+
this.rgGroupCache.set(anygp._thisKey, anygp);
|
|
289
|
+
if (!last) {
|
|
290
|
+
//Dal gruppo padre, se non è l'ultimo gruppo della catena, calcolo ricorsivamente tutta la catena sotto
|
|
291
|
+
let subGroupsAndItems = this.getGroupsRecursive(grps, currentIndex + 1, itms, aggregations, anygp);
|
|
292
|
+
let childgroups = subGroupsAndItems.filter(t => t._group && t._parent == anygp._thisKey);
|
|
293
|
+
anygp._groupscount = childgroups.length;
|
|
294
|
+
// Aggiungo la catena del gruppo sotto, aggiungendo alla cache solo i gruppi padre
|
|
295
|
+
ret.push(...subGroupsAndItems);
|
|
296
|
+
this.rgChildGroupsCache.set(anygp._thisKey, childgroups);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
// Al gruppo padre, se è l'ultimo assegno tutte le foglie assegnandogli anche la chiave del gruppo
|
|
300
|
+
itms.forEach(i => i._thisKey = anygp._thisKey);
|
|
301
|
+
ret.push(...itms);
|
|
302
|
+
this.rgItemCache.set(anygp._thisKey, itms);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return ret;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Data una lista di oggetti genera le aggregazioni specificate. Si considera di avere tutti gli oggetti
|
|
309
|
+
*
|
|
310
|
+
* @param {any[]} items Oggetti di cui calcolare le aggregazione
|
|
311
|
+
* @param {GroupOrAggregation[]} aggregations Aggergazioni da generare
|
|
312
|
+
*/
|
|
313
|
+
generateAggregations(items, aggregations) {
|
|
314
|
+
let rets = [];
|
|
315
|
+
let aggregationValue = "", feField = null, stringAgg = null, dateAgg = null, numberAgg = null;
|
|
316
|
+
for (let i = 0; i < aggregations.length; i++) {
|
|
317
|
+
let agg = aggregations[i];
|
|
318
|
+
feField = agg.column;
|
|
319
|
+
if (!feField)
|
|
320
|
+
continue;
|
|
321
|
+
switch (agg.datatype) {
|
|
322
|
+
case 'string':
|
|
323
|
+
stringAgg = items.map(i => i[feField].toString());
|
|
324
|
+
break;
|
|
325
|
+
case 'date':
|
|
326
|
+
dateAgg = items.map(i => new Date(i[feField]).getTime());
|
|
327
|
+
break;
|
|
328
|
+
case 'number':
|
|
329
|
+
numberAgg = items.map(i => parseFloat(i[feField]));
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
switch (agg.aggregation) {
|
|
333
|
+
case 'max':
|
|
334
|
+
switch (agg.datatype) {
|
|
335
|
+
case 'string':
|
|
336
|
+
aggregationValue = stringAgg.sort().reverse()[0];
|
|
337
|
+
break;
|
|
338
|
+
case 'date':
|
|
339
|
+
aggregationValue = new Date(Math.max(...dateAgg)).toString();
|
|
340
|
+
break;
|
|
341
|
+
case 'number':
|
|
342
|
+
aggregationValue = Math.max(...numberAgg).toString();
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
break;
|
|
346
|
+
case 'min':
|
|
347
|
+
switch (agg.datatype) {
|
|
348
|
+
case 'string':
|
|
349
|
+
aggregationValue = stringAgg.sort()[0];
|
|
350
|
+
break;
|
|
351
|
+
case 'date':
|
|
352
|
+
aggregationValue = new Date(Math.min(...dateAgg)).toString();
|
|
353
|
+
break;
|
|
354
|
+
case 'number':
|
|
355
|
+
aggregationValue = Math.min(...numberAgg).toString();
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
break;
|
|
359
|
+
case 'sum':
|
|
360
|
+
switch (agg.datatype) {
|
|
361
|
+
case 'string':
|
|
362
|
+
aggregationValue = stringAgg.join(", ");
|
|
363
|
+
break;
|
|
364
|
+
case 'date':
|
|
365
|
+
aggregationValue = "";
|
|
366
|
+
break;
|
|
367
|
+
case 'number':
|
|
368
|
+
aggregationValue = numberAgg.reduce((pre, curr) => pre + curr, 0).toString();
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
rets.push(new GroupAggregation(agg.column, agg.aggregation, aggregationValue));
|
|
374
|
+
}
|
|
375
|
+
return rets;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Ottiene un elemento di separazione fra Gruppi che serve per paginare le ricerche all'interno di ogni singolo gruppo
|
|
379
|
+
*
|
|
380
|
+
* @param {AppSearch<any>} view View utilizzata per la ricerca. Me ne salvo i parametri nel separatore attuale dato che ne ho bisogno per caricare altri elementi
|
|
381
|
+
* facenti riferimento allo stesso contesto
|
|
382
|
+
* @param {string} parent Parent path che rappresenta a quale gruppo è affibbiato questo separatore
|
|
383
|
+
* @param {GroupRouteFragment[]} route Route path che rappresenta a quale gruppo è affibbiato questo separatore
|
|
384
|
+
* @param {number} level Livello del gruppo di cui questo elemento è separatore, viene usato per applicare la classe "est-lvl-{{level}}"
|
|
385
|
+
*
|
|
386
|
+
* @returns {any} Elemento di separazione contenente tutti i bind per presentare una paginazione sotto questo gruppo lato interfaccia
|
|
387
|
+
*/
|
|
388
|
+
getGroupSeparator(view, parent, route, level, searches) {
|
|
389
|
+
let item = new GroupPager(level, route, parent, Object.assign({}, view), searches);
|
|
390
|
+
item.buttons = this.utilities.getPagesArray(6, view.page, view.pages);
|
|
391
|
+
this.utilities.calculateHash([item]);
|
|
392
|
+
return item;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Data una colonna effettua la riemissione di tutte le ricerche relative.
|
|
396
|
+
*
|
|
397
|
+
* Es. Ho 2 campi di gruppo e ho espanso fino a vedere i valori fino ad un livello qualsiasi.
|
|
398
|
+
* Clicco l'ordinamento sul secondo gruppo.
|
|
399
|
+
* Tutte le ricerche relative ai primi gruppi devono essere rieseguite. Quando i risultati arriveranno ci penserà il metodo **bindDisplayToLoadedItemsOrGroups**
|
|
400
|
+
* a tagliare via gli oggetti non più visualizzati
|
|
401
|
+
*
|
|
402
|
+
* @param {string} column Colonna su cui si è effettuata un'operazione di ordinamento
|
|
403
|
+
* @param {AppOrdering[]} orderings Direttive di ordinamento da applicare alle varie sottoricerche
|
|
404
|
+
*/
|
|
405
|
+
emitRowGroupingSearches(column, orderings) {
|
|
406
|
+
// Per tutte le ricerche intermedie che devo rivalutare le re-emitto in modo da aggiornargli i dati
|
|
407
|
+
var meaningfulAppSearches = this.est.groupSearchRequestsCache.filter(t => t.group_column == column).map(t => t.view);
|
|
408
|
+
// Se non ne trovo significa che ho fatto l'ordinamento o sugli item, o su colonne relative a un sottogruppo non caricato
|
|
409
|
+
if (!meaningfulAppSearches || meaningfulAppSearches.length == 0)
|
|
410
|
+
meaningfulAppSearches = this.est.groupSearchRequestsCache.filter(t => !t.group_column).map(t => t.view);
|
|
411
|
+
// Se non ne trovo qui significa che sto ordinando su colonne relative a un sottogruppo non caricato
|
|
412
|
+
if (!meaningfulAppSearches || meaningfulAppSearches.length == 0)
|
|
413
|
+
return;
|
|
414
|
+
meaningfulAppSearches.forEach(as => {
|
|
415
|
+
// Ovviamente gli oridnamenti devono essere quelli appena generati
|
|
416
|
+
as.orders = orderings;
|
|
417
|
+
as.savedstate = true;
|
|
418
|
+
this.est.emitSearchRequest(false, as);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Helper che calcola il contenuto di una cella relativa a un gruppo riga, tenendo conto del formato delle eventuali aggregazioni
|
|
423
|
+
*
|
|
424
|
+
* @param {Group} grp Gruppo di cui mostrare le celle
|
|
425
|
+
* @param {string} cell Cella attuale di cui calcolare il testo
|
|
426
|
+
* @param {EsThDirective} header Header relativo alla cella attuale, utilizzata per identificare le informazioni di aggregazione
|
|
427
|
+
*
|
|
428
|
+
* @returns {string} Testo finale calcolato per la **cell** corrente, in base alle aggregazioni di **header**
|
|
429
|
+
*/
|
|
430
|
+
getGroupCellDisplay(grp, cell, header) {
|
|
431
|
+
if (grp._sep)
|
|
432
|
+
return "";
|
|
433
|
+
let display = header.thAggregation;
|
|
434
|
+
if (grp.column == cell) {
|
|
435
|
+
let groupsPart = grp._groupscount ? " - " + grp._groupscount + " " + this.est.lc.loc("Groups") : "";
|
|
436
|
+
return grp.value + " (" + grp.count + groupsPart + ")";
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
let agg = grp._aggregationsCache.get(cell);
|
|
440
|
+
if (!agg)
|
|
441
|
+
return "";
|
|
442
|
+
this.getEsThDirectiveListOfAggregations(header).forEach((itm) => {
|
|
443
|
+
display = display.replace(itm.match, this.formatAggregationValue(agg.get(itm.func), itm.format));
|
|
444
|
+
});
|
|
445
|
+
return display;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Funzione che dato un valore lo formatta in base al tipo
|
|
450
|
+
*
|
|
451
|
+
* @param {string} value Valore che generalemnte può essere una data o un numero
|
|
452
|
+
* @param {string} fromat Formato su cui formattare il valore. Può essere ad esempio "small", "long" "verylong" per le date o F{0-9} per i numeri decimali
|
|
453
|
+
*
|
|
454
|
+
* @returns {string} Valore dell'aggregazione formattato come si deve
|
|
455
|
+
*/
|
|
456
|
+
formatAggregationValue(value, format) {
|
|
457
|
+
if (!format)
|
|
458
|
+
return value;
|
|
459
|
+
let isNumber = !Number.isNaN(value) && (!format || format.startsWith("F"));
|
|
460
|
+
if (isNumber && format.startsWith("F") && !Number.isNaN(format.substr(1)))
|
|
461
|
+
return parseFloat(value).toFixed(parseInt(format.substr(1)));
|
|
462
|
+
let date = null;
|
|
463
|
+
// Alcune versione di extensions rischiano di crashare con cose non date... è stato risolto dopo quindi questo try - catch in realtà
|
|
464
|
+
// torna utile solo con versioni vecchie/deprecate della libreria @esfaenza/extensions
|
|
465
|
+
try {
|
|
466
|
+
date = this.dateExts.getDateConvertion(value);
|
|
467
|
+
}
|
|
468
|
+
catch (_a) { }
|
|
469
|
+
if (date)
|
|
470
|
+
return this.dateExts.getFormatted(date, format == 'small', format == 'verylong');
|
|
471
|
+
// Qui ci finisco sia per input che non sono né date né numeri, sia per formati non riconosciuti
|
|
472
|
+
return value;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUm93R3JvdXBpbmdIYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZXMtdGFibGUvc3JjL2xpYi9jb3JlL2hhbmRsZXJzL2NsYXNzZXMvUm93R3JvdXBpbmdIYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLFVBQVU7QUFDVixPQUFPLEVBQTBCLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxrQkFBa0IsRUFBRSxVQUFVLEVBQUUsa0JBQWtCLEVBQWlCLE1BQU0saUJBQWlCLENBQUM7QUFLckosaUVBQWlFO0FBQ2pFLE1BQU0sT0FBTyxrQkFBa0I7SUFTM0IsMEJBQTBCO0lBQzFCLFlBQW9CLEdBQXFCLEVBQVUsU0FBMkIsRUFBVSxRQUFxQjtRQUF6RixRQUFHLEdBQUgsR0FBRyxDQUFrQjtRQUFVLGNBQVMsR0FBVCxTQUFTLENBQWtCO1FBQVUsYUFBUSxHQUFSLFFBQVEsQ0FBYTtRQVI3RyxxRkFBcUY7UUFDOUUsaUJBQVksR0FBdUIsSUFBSSxHQUFHLEVBQWlCLENBQUM7UUFDbkUsNkdBQTZHO1FBQ3RHLGdCQUFXLEdBQXVCLElBQUksR0FBRyxFQUFpQixDQUFDO1FBQ2xFLDZHQUE2RztRQUN0Ryx1QkFBa0IsR0FBeUIsSUFBSSxHQUFHLEVBQW1CLENBQUM7SUFHb0MsQ0FBQztJQUVsSDs7Ozs7Ozs7O09BU0c7SUFDSSwwQkFBMEIsQ0FBQyxJQUFvQixFQUFFLFlBQW9COztRQUN4RSx3SUFBd0k7UUFDeEksOEVBQThFO1FBQzlFLElBQUksQ0FBQyxPQUFBLElBQUksQ0FBQyxlQUFlLDBDQUFFLE1BQU0sS0FBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDMUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUM7WUFDL0MsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBaUIsQ0FBQztZQUM3QyxJ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aEUsSUFBSSxJQUFJO1lBQ0osT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsTUFBTSxJQUFJLE9BQU8sRUFBRSxNQUFNLElBQUksVUFBVSxDQUFDLENBQUM7UUFFckYsZ0dBQWdHO1FBQ2hHLE9BQU8sS0FBSyxDQUFDO0lBQ2pCLENBQUM7Q0FDSiIsInNvdXJjZXNDb250ZW50IjpbIi8vIExpYnJlcmllXHJcbmltcG9ydCB7IERhdGVTZXJ2aWNlIH0gZnJvbSBcIkBlc2ZhZW56YS9leHRlbnNpb25zXCI7XHJcblxyXG4vLyBEaXJldHRpdmUgLyBDb21wb25lbnRpXHJcbmltcG9ydCB7IEVzVGggfSBmcm9tIFwiLi4vLi4vLi4vY29tcG9uZW50cy9lcy10aC9lc190aC5jb21wb25lbnRcIjtcclxuaW1wb3J0IHsgRXNUaERpcmVjdGl2ZSB9IGZyb20gXCIuLi8uLi8uLi9kaXJlY3RpdmVzL2VzX3RoLmRpcmVjdGl2ZVwiO1xyXG5pbXBvcnQgeyBFc1RhYmxlQ29tcG9uZW50IH0gZnJvbSBcIi4uLy4uLy4uL2NvbXBvbmVudHMvZXMtdGFibGUvZXNfdGFibGUuY29tcG9uZW50XCJcclxuXHJcbi8vIE1vZGVsbGlcclxuaW1wb3J0IHsgQXBwT3JkZXJpbmcsIEFwcFNlYXJjaCwgR3JvdXAsIEdyb3VwQWdncmVnYXRpb24sIEdyb3VwT3JBZ2dyZWdhdGlvbiwgR3JvdXBQYWdlciwgR3JvdXBSb3V0ZUZyYWdtZW50LCBUaEFnZ3JlZ2F0aW9uIH0gZnJvbSBcIi4uLy4uLy4uL2RvbWFpblwiO1xyXG5cclxuLy8gVXRpbGl0aWVzXHJcbmltcG9ydCB7IFV0aWxpdGllc0hhbmRsZXIgfSBmcm9tIFwiLi9VdGlsaXRpZXNIYW5kbGVyXCI7XHJcblxyXG4vKiogQ2xhc3NlIGNoZSBnZXN0aXNjZSBsYSBtb2RhbGl0w6AgUm93IEdyb3VwaW5nIGRlbGwnZXMtdGFibGUgKi9cclxuZXhwb3J0IGNsYXNzIFJvd0dyb3VwaW5nSGFuZGxlciB7XHJcblxyXG4gICAgLyoqIENhY2hlIHBlciBzYWx2YXJlIHBlciBvZ25pIGNoaWF2ZSBkaSBvZ25pIGdydXBwbyBjaGkgw6ggaWwgZ3J1cHBvIHJhcHByZXNlbnRhdG8gKi9cclxuICAgIHB1YmxpYyByZ0dyb3VwQ2FjaGU6IE1hcDxzdHJpbmcsIEdyb3VwPiA9IG5ldyBNYXA8c3RyaW5nLCBHcm91cD4oKTtcclxuICAgIC8qKiBDYWNoZSBwZXIgc2FsdmFyZSBwZXIgb2duaSBjaGlhdmUgZGkgb2duaSBncnVwcG8gY2hpIHNvbm8gZ2xpIG9nZ2V0dGkgc290dG9zdGFudGksIG5vbiBkZWkgc290dG9ncnVwcGkgKi9cclxuICAgIHB1YmxpYyByZ0l0ZW1DYWNoZTogTWFwPHN0cmluZywgYW55W10+ID0gbmV3IE1hcDxzdHJpbmcsIGFueVtdPigpO1xyXG4gICAgLyoqIENhY2hlIHBlciBzYWx2YXJlIHBlciBvZ25pIGNoaWF2ZSBkaSBvZ25pIGdydXBwbyBjaGkgc29ubyBnbGkgb2dnZXR0aSBzb3R0b3N0YW50aSwgbm9uIGRlaSBzb3R0b2dydXBwaSAqL1xyXG4gICAgcHVibGljIHJnQ2hpbGRHcm91cHNDYWNoZTogTWFwPHN0cmluZywgR3JvdXBbXT4gPSBuZXcgTWFwPHN0cmluZywgR3JvdXBbXT4oKTtcclxuXHJcbiAgICAvKiogQGlnbm9yZSBDb3N0cnV0dG9yZSAqL1xyXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBlc3Q6IEVzVGFibGVDb21wb25lbnQsIHByaXZhdGUgdXRpbGl0aWVzOiBVdGlsaXRpZXNIYW5kbGVyLCBwcml2YXRlIGRhdGVFeHRzOiBEYXRlU2VydmljZSkgeyB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBJbiBtb2RhbGl0w6Agcm93Z3JvdXBpbmcgcXVhbmRvIG1pIGFycml2YSB1biBudW92byBibG9jY28gZGkgb2dnZXR0aSBkZXZvIGFnZ2l1bmdlcmxvIGFsbGEgdmlzdGEgYXR0dWFsZTpcclxuICAgICAqXHJcbiAgICAgKiAxKSBTZSBub24gdmllbmUgcmljaGllc3RvIGlsIGRldHRhZ2xpbyBkaSBhbGN1biBncnVwcG8gc2lnbmlmaWNhIGNoZSBkZXZvIGNvbnNpZGVyYXJlIG1pIHNpYW5vIGFycml2YXRpIHR1dHRpIGkgZ3J1cHBpIHByaW5jaXBhbGlcclxuICAgICAqIDIpIFNlIHZpZW5lIHJpY2hpZXN0byBpbCBkZXR0YWdsaW8gZGkgdW4gZ3J1cHBvIGRpdmVyc28gZGFsbCd1bHRpbW8gZGV2byBhZ2dpdW5nZXJlIGRvcG8gYWwgZ3J1cHBvIGNsaWNjYXRvIGxhIGxpc3RhIGRlaSBzb3R0b2dydXBwaVxyXG4gICAgICogMikgU2UgdmllbmUgcmljaGllc3RvIGlsIGRldHRhZ2xpbyBkZWxsJ3VsdGltbyBncnVwcG8gZGV2byBhZ2dpdW5nZXJlIGRvcG8gYWwgZ3J1cHBvIGNsaWNjYXRvIGxhIGxpc3RhIGRlZ2xpIG9nZ2V0dGlcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0ge2FueX0gdmlldyBBcHBTZWFyY2g8VD4gZGEgY3VpIHNvbm8gYXJyaXZhdGkgZ2xpIG9nZ2V0dGlcclxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBncm91cGluZ0tleXMgTGl2ZWxsaSBkaSByYWdncnVwcGFtZW50byBkYSBhc3BldHRhcnNpIHN1aSBkYXRpXHJcbiAgICAgKi9cclxuICAgIHB1YmxpYyBoYW5kbGVOZXdEYXRhT25Sb3dHcm91cGluZyh2aWV3OiBBcHBTZWFyY2g8YW55PiwgZ3JvdXBpbmdLZXlzOiBudW1iZXIpIHtcclxuICAgICAgICAvLyAxKSBTZSBub24gdmllbmUgcmljaGllc3RvIGlsIGRldHRhZ2xpbyBkaSBhbGN1biBncnVwcG8gc2lnbmlmaWNhIGNoZSBsYSBjaGlhbWF0YSByZXN0aXR1aXNjZSBsYSBsaXN0YSBwYWdpbmF0YSBkZWkgZ3J1cHBpIHByaW5jaXBhbGkuXHJcbiAgICAgICAgLy8gICAgTGkgdHJhdHRvIGNvbWUgc2UgZm9zc2UgdW5hIHF1YWxzaWFzaSBhbHRyYSBxdWVyeSBwYWdpbmF0YSBzdSBOIGVsZW1lbnRpXHJcbiAgICAgICAgaWYgKCh2aWV3LnJlcXVlc3RlZGdyb3Vwcz8ubGVuZ3RoIHx8IDApID09IDApIHtcclxuICAgICAgICAgICAgdGhpcy5lc3QuYm91bmRTb3VyY2UgPSB0aGlzLmVzdC5UTVBCb3VuZFNvdXJjZTtcclxuICAgICAgICAgICAgdGhpcy5yZ0dyb3VwQ2FjaGUgPSBuZXcgTWFwPHN0cmluZywgR3JvdXA+KCk7XHJcbiAgICAgICAgICAgIHRoaXMucmdJdGVtQ2FjaGUgPSBuZXcgTWFwPHN0cmluZywgYW55W10+KCk7XHJcbiAgICAgICAgICAgIHRoaXMucmdDaGlsZEdyb3Vwc0NhY2hlID0gbmV3IE1hcDxzdHJpbmcsIEdyb3VwW10+KCk7XHJcblxyXG4gICAgICAgICAgICB0aGlzLmVzdC5UTVBCb3VuZFNvdXJjZS5mb3JFYWNoKGl0bSA9PiB7XHJcbiAgICAgICAgICAgICAgICBpdG0uX3RoaXNSb3V0ZSA9IGl0bS5fZ3JvdXAgPyBbeyBjb2x1bW46ICg8R3JvdXA+aXRtKS5jb2x1bW4sIHZhbHVlOiAoPEdyb3VwPml0bSkudmFsdWUgfV0gOiBbXTtcclxuICAgICAgICAgICAgICAgIGl0bS5fdGhpc0tleSA9IGl0bS5fZ3JvdXAgPyAoPEdyb3VwPml0bSkudmFsdWUgOiBudWxsO1xyXG4gICAgICAgICAgICAgICAgaXRtLl9ncm91cGxldmVsID0gMDtcclxuXHJcbiAgICAgICAgICAgICAgICB0aGlzLnJnR3JvdXBDYWNoZS5zZXQoaXRtLl90aGlzS2V5LCBpdG0pO1xyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICAgIC8vIFJlc2V0dG8gbGEgcmljZXJjYSBhbGxhIGNhY2hlIGRpIHF1ZXN0YSBcInNlc3Npb25lXCJcclxuICAgICAgICAgICAgbGV0IGZpcnN0SXRlbSA9IHRoaXMuZXN0LlRNUEJvdW5kU291cmNlWzBdO1xyXG4gICAgICAgICAgICB0aGlzLmVzdC5NYWluR3JvdXBWaWV3ID0gT2JqZWN0LmFzc2lnbih7fSwgdmlldyk7XHJcbiAgICAgICAgICAgIHRoaXMuZXN0Lmdyb3VwU2VhcmNoUmVxdWVzdHNDYWNoZSA9IFt7IHBhdGg6ICcnLCByb3V0ZTogW3sgY29sdW1uOiAoPEdyb3VwPmZpcnN0SXRlbSkuY29sdW1uLCB2YWx1ZTogKDxHcm91cD5maXJzdEl0ZW0pLnZhbHVlIH1dLCB2aWV3OiB0aGlzLmVzdC5NYWluR3JvdXBWaWV3LCBncm91cF9jb2x1bW46ICg8R3JvdXA+dGhpcy5lc3QuVE1QQm91bmRTb3VyY2VbMF0pLmNvbHVtbiB9XTtcclxuICAgICAgICAgICAgdGhpcy5lc3QuQmFzZUl0ZW1zQ291bnQgPSB2aWV3Lm9iamVjdGNvdW50O1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgLy8gMikgU2UgdmllbmUgcmljaGllc3RvIGlsIGRldHRhZ2xpbyBkaSB1biBxdWFsc2lhc2kgZ3J1cHBvIGRpdmVyc28gZGFsbCd1bHRpbW8gdnVvbCBkaXJlIGNoZSBkZXZvIGFnZ2l1bmdlcmUgXHJcbiAgICAgICAgICAgIC8vICAgIGRvcG8gYWwgZ3J1cHBvIGNoZSBobyBjbGljY2F0byBsYSBsaXN0YSBkZWkgZ3J1cHBpIHRpcmF0YSBmdW9yaSBxdWVzdGEgdm9sdGEgKGludGVybWVkaWF0ZUdyb3VwID0gdHJ1ZSlcclxuICAgICAgICAgICAgLypcclxuICAgICAgICAgICAgKiAgIEdydXBwb0EgICAgICAgICAgICAgICAgICAgICAgR3J1cHBvQVxyXG4gICAgICAgICAgICAqICAgR3J1cHBvQiAgICAgICAgICAgICAgICAgICAgICBHcnVwcG9CXHJcbiAgICAgICAgICAgICogICBHcnVwcG9DIDwtIENsaWNjbyBxdWkgICAgICAgIEdydXBwb0NcclxuICAgICAgICAgICAgKiAgIEdydXBwb0QgICAgICAgICAgICAgICAgICAgICAgICAgIEdydXBwb0MxXHJcbiAgICAgICAgICAgICogICBHcnVwcG9FICAgICAgICAgICAgICAgICAgICAgICAgICBHcnVwcG9DMlxyXG4gICAgICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHcnVwcG9EXHJcbiAgICAgICAgICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdydXBwb0VcclxuICAgICAgICAgICAgKi9cclxuICAgICAgICAgICAgLy8gMykgc2UgaSBncnVwcGkgcmljaGllc3RpIGRhbGxhIHZpZXcgc29ubyB1Z3VhbGkgYWkgZ3J1cHBpIHByZXNlbnRpIHZ1b2wgZGlyZSBjaGUgc3RvIHByZW5kZW5kbyBnbGkgb2dnZXR0aSB2ZXJpIGUgcHJvcHJpLCBzb25vIGluIFxyXG4gICAgICAgICAgICAvLyB2aWV3Lml0ZW1zIGUgcXVpbmRpIGluIFRNUEJvdW5kU291cmNlLCBobyBpbm9sdHJlIGxlIGluZm9ybWF6aW9uaSBkaSBwYWdpbmF6aW9uZSAqKnBlciBpbCBzaW5nb2xvIHNvdHRvZ3J1cHBvKiogKGludGVybWVkaWF0ZUdyb3VwID0gZmFsc2UpXHJcbiAgICAgICAgICAgIC8qXHJcbiAgICAgICAgICAgICogICBHcnVwcG9BICAgICAgICAgICAgICAgICAgICAgICAgIEdydXBwb0FcclxuICAgICAgICAgICAgKiAgICAgICBHcnVwcG9DMSAgICAgICAgICAgICAgICAgICAgICAgIEdydXBwb0MxXHJcbiAgICAgICAgICAgICogICBHcnVwcG9CICAgICAgICAgICAgICAgICAgICAgICAgIEdydXBwb0JcclxuICAgICAgICAgICAgKiAgIEdydXBwb0MgICAgICAgICAgICAgICAgICAgICAgICAgR3J1cHBvQ1xyXG4gICAgICAgICAgICAqICAgICAgIEdydXBwb0MxIDwtLSBDbGljY28gcXVpICAgICAgICAgR3J1cHBvQzFcclxuICAgICAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBPZ2dldHRvMVxyXG4gICAgICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9nZ2V0dG8yXHJcbiAgICAgICAgICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT2dnZXR0bzNcclxuICAgICAgICAgICAgKiAgICAgICBHcnVwcG9DMiAgICAgICAgICAgICAgICAgICAgICAgIEdydXBwb0MyXHJcbiAgICAgICAgICAgICogICBHcnVwcG9EICAgICAgICAgICAgICAgICAgICAgICAgIEdydXBwb0RcclxuICAgICAgICAgICAgKiAgIEdydXBwb0UgICAgICAgICAgICAgICAgICAgICAgICAgR3J1cHBvRVxyXG4gICAgICAgICAgICAqL1xyXG4gICAgICAgICAgICBsZXQgaW50ZXJtZWRpYXRlR3JvdXAgPSB2aWV3LnJlcXVlc3RlZGdyb3Vwcy5sZW5ndGggIT0gZ3JvdXBpbmdLZXlzO1xyXG5cclxuICAgICAgICAgICAgbGV0IGl0ZW1zID0gdGhpcy5lc3QuYm91bmRTb3VyY2U7XHJcbiAgICAgICAgICAgIGxldCBpbnNlcnRJbmRleCA9IDA7XHJcbiAgICAgICAgICAgIGxldCBpbnNlcnRHcm91cCA9IG51bGw7XHJcbiAgICAgICAgICAgIGxldCBncm91cEtleTogc3RyaW5nID0gXCJcIjtcclxuICAgICAgICAgICAgbGV0IGdyb3VwUm91dGU6IEdyb3VwUm91dGVGcmFnbWVudFtdID0gW107XHJcblxyXG4gICAgICAgICAgICAvLyBOYXZpZ28gbGEgc3R1dHR1cmEgZGVpIGdydXBwaSBpZ25vcmFuZG8gcmljb3JzaXZhbWVudGUgdHV0dGkgZ2xpIGluZGljaSBmaW5vIGFpIGdydXBwaSBjaGUgbWkgaW50ZXJlc3Nhbm8gaW4gbW9kbyBkYSBub24gYmVjY2FyZSBpbCBwcmltbyBcIkdydXBwb0MxXCIgZGVsIGNhc28gc29wcmFcclxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB2aWV3LnJlcXVlc3RlZGdyb3Vwcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICAgICAgbGV0IHJnID0gdmlldy5yZXF1ZXN0ZWRncm91cHNbaV07XHJcbiAgICAgICAgICAgICAgICBncm91cEtleSArPSByZy52YWx1ZTtcclxuICAgICAgICAgICAgICAgIGdyb3VwUm91dGUucHVzaCh7IGNvbHVtbjogcmcuY29sdW1uLCB2YWx1ZTogcmcudmFsdWUgfSk7XHJcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gaW5zZXJ0SW5kZXg7IGkgPCBpdGVtcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICAgICAgICAgIGxldCB0ID0gaXRlbXNbaV07XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKGkgPj0gaW5zZXJ0SW5kZXggJiYgdC5fZ3JvdXAgJiYgdC5jb2x1bW4gPT0gcmcuY29sdW1uICYmIHQudmFsdWUgPT0gcmcudmFsdWUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaW5zZXJ0SW5kZXggPSBpOyBpbnNlcnRHcm91cCA9IHQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIExvIG1hcmNvIGV4cGFuZGVkIGRhdG8gY2hlIHF1ZXN0byBjbGljayBzdWwgZ3J1cHBvIHBvdHJlYmJlIG5vbiBlc3NlcmUgc3RhdG8gZmF0dG9cclxuICAgICAgICAgICAgICAgICAgICAgICAgaW5zZXJ0R3JvdXAuX2V4cGFuZGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBsZXQgaXRlbXNDYWNoZVJlZmVyZW5jZTtcclxuICAgICAgICAgICAgbGV0IGNoaWxkR3JvdXBzQ2FjaGVSZWZlcmVuY2U7XHJcblxyXG4gICAgICAgICAgICAvLyBTZSBub24gw6ggdW4gZ3J1cHBvIGludGVybWVkaW8gZGV2byByaXB1bGlyZSBsYSBjYWNoZSBkZWwgZ3J1cHBvIHN1IGN1aSBobyBhdHR1YWxtZW50ZSBjbGljY2F0by4gR2xpIG9nZ2V0dGkgc2FyYW5ubyByaWFnZ2l1bnRpIGRvcG9cclxuICAgICAgICAgICAgaWYgKCFpbnRlcm1lZGlhdGVHcm91cCkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5yZ0l0ZW1DYWNoZS5zZXQoZ3JvdXBLZXksIFtdKTtcclxuICAgICAgICAgICAgICAgIGl0ZW1zQ2FjaGVSZWZlcmVuY2UgPSB0aGlzLnJnSXRlbUNhY2hlLmdldChncm91cEtleSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBTZSBpbnZlY2Ugw6ggdW4gZ3J1cHBvIGludGVybWVkaW8gZGV2byByaXB1bGlyZSBzaWEgdHV0dGkgaSBjaGlsZCBncm91cCByaWNvcnNpdmFtZW50ZSwgc2lhIHR1dHRpIGdsaSBpdGVtXHJcbiAgICAgICAgICAgICAgICBmb3IgKGxldCBrZXkgb2YgdGhpcy5yZ0NoaWxkR3JvdXBzQ2FjaGUua2V5cygpKVxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChrZXkuc3RhcnRzV2l0aChncm91cEtleSkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmdDaGlsZEdyb3Vwc0NhY2hlLmRlbGV0ZShrZXkpO1xyXG5cclxuICAgICAgICAgICAgICAgIGZvciAobGV0IGtleSBvZiB0aGlzLnJnSXRlbUNhY2hlLmtleXMoKSlcclxuICAgICAgICAgICAgICAgICAgICBpZiAoa2V5LnN0YXJ0c1dpdGgoZ3JvdXBLZXkpKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJnSXRlbUNhY2hlLmRlbGV0ZShrZXkpO1xyXG5cclxuICAgICAgICAgICAgICAgIHRoaXMucmdDaGlsZEdyb3Vwc0NhY2hlLnNldChncm91cEtleSwgW10pO1xyXG4gICAgICAgICAgICAgICAgY2hpbGRHcm91cHNDYWNoZVJlZmVyZW5jZSA9IHRoaXMucmdDaGlsZEdyb3Vwc0NhY2hlLmdldChncm91cEtleSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIEFzc2Vnbm8gdW4gbGl2ZWxsbyBhaSB2YWxvcmkgY2hlIGFycml2YW5vIGRhIHVzYXJlIHBlciBmb3JtYXR0YXJlIGxhIHBhcnRlIGdyYWZpY2EuIElsIHByaW1vIGdydXBwbyBjbGljY2F0byBzYXLDoCBhIGxpdmVsbG8gMSxcclxuICAgICAgICAgICAgLy8gaWwgc2Vjb25kbyBzYXLDoCBhIGxpdmVsbG8gMiBlIGNvc8OsIHZpYS4uLlxyXG4gICAgICAgICAgICAvLyBMaSBtYXJjbyBpbm9sdHJlIGNvbiBpbCBwYXJlbnQgaW4gbW9kbyBkYSBwb3RlciBlbGltaW5hcmUgaSB2ZWNjaGkgcXVhbG9yYSBzZXJ2aXNzZVxyXG4gICAgICAgICAgICB0aGlzLmVzdC5UTVBCb3VuZFNvdXJjZS5mb3JFYWNoKGl0bSA9PiB7XHJcbiAgICAgICAgICAgICAgICBpdG0uX3BhcmVudCA9IGdyb3VwS2V5O1xyXG4gICAgICAgICAgICAgICAgaXRtLl9wYXJlbnRSb3V0ZSA9IGdyb3VwUm91dGU7XHJcbiAgICAgICAgICAgICAgICBpdG0uX3RoaXNSb3V0ZSA9IGl0bS5fZ3JvdXAgPyBbLi4uZ3JvdXBSb3V0ZSwgbmV3IEdyb3VwUm91dGVGcmFnbWVudCgoPEdyb3VwPml0bSkuY29sdW1uLCAoPEdyb3VwPml0bSkudmFsdWUpXSA6IFtdO1xyXG4gICAgICAgICAgICAgICAgaXRtLl90aGlzS2V5ID0gaXRtLl9ncm91cCA/IGdyb3VwS2V5ICsgKDxHcm91cD5pdG0pLnZhbHVlIDogZ3JvdXBLZXk7XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gUGVyIGxlIHJpY2VyY2EgaW50ZXJtZWRpZSBtZXR0byBpIGdydXBwaSBuZWxsYSBjYWNoZSBkZWkgZ3J1cHBpXHJcbiAgICAgICAgICAgICAgICBpZiAoaW50ZXJtZWRpYXRlR3JvdXApIHtcclxuICAgICAgICAgICAgICAgICAgICBpdG0uX2dyb3VwbGV2ZWwgPSB2aWV3LnJlcXVlc3RlZGdyb3Vwcy5sZW5ndGg7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZ0dyb3VwQ2FjaGUuc2V0KGl0bS5fdGhpc0tleSwgaXRtKTtcclxuICAgICAgICAgICAgICAgICAgICBjaGlsZEdyb3Vwc0NhY2hlUmVmZXJlbmNlLnB1c2goaXRtKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIE1ldHRvIGFuY2hlIGdsaSBvZ2dldHRpIG5lbGxhIGNhY2hlIG5vbiByaWNvcnNpdmFcclxuICAgICAgICAgICAgICAgICAgICBpdGVtc0NhY2hlUmVmZXJlbmNlLnB1c2goaXRtKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICAvLyBFbGltaW5vIGdsaSBvZ2dldHRpIHZlY2NoaSBcclxuICAgICAgICAgICAgLy8gMSkgUmljZXJjYSBpbnRlcm1lZGlhLCBzdGF0byBzYWx2YXRvIC0gRWxpbWlubyB0dXR0aSBnbGkgaXRlbSBlIHR1dHRpIGkgZ3J1cHBpIGxhIGN1aSByb3V0ZSDDqCBwacO5IGx1bmdhIGRlbGxhIGNvcnJlbnRlLCB0dXR0aSBnbGkgaXRlbSByZWxhdGl2aSBhbGxhIHBhdGggY29ycmVudGUsIGUgdHV0dGVcclxuICAgICAgICAgICAgLy8gICAgbGUgY2FjaGUgZGkgcmljZXJjYSBlZmZldHR1YXRlIHN1IHVuYSBwYXRoIHBpw7kgcHJvZm9uZGEgZGVsbCdhdHR1YWxlXHJcbiAgICAgICAgICAgIC8vIDIpIFJpY2VyY2EgZmluYWxlIG8gcmljZXJjYSBpbnRlcm1lZGlhIHNlbnphIHN0YXRvIHNhbHZhdG8gLSBFbGltaW5vIHR1dHRpIGdsaSBpdGVtIHJlbGF0aXZpIGFsbGEgcGF0aCBjb3JyZW50ZVxyXG4gICAgICAgICAgICAvLyBQZXIgXCJzdGF0byBzYWx2YXRvXCIgc2kgaW50ZW5kb25vIHJpY2VyY2hlIHZlY2NoaWUgc2FsdmF0ZSBwZXIgcG90ZXIgZXNzZXJlIHJpZWZmZXR0dWF0ZSBpbiBjYXNvIGRpIG9yZGluYW1lbnRpIHN1IGNvbG9ubmUgZGkgaW50ZXJlc3NlIFxyXG4gICAgICAgICAgICBpZiAoaW50ZXJtZWRpYXRlR3JvdXAgJiYgdmlldy5zYXZlZHN0YXRlKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmVzdC5ib3VuZFNvdXJjZSA9IHRoaXMuZXN0LmJvdW5kU291cmNlLmZpbHRlcih0ID0+ICEodC5faXRlbSB8fCB0Ll90aGlzUm91dGUubGVuZ3RoID4gZ3JvdXBSb3V0ZS5sZW5ndGgpKTtcclxuICAgICAgICAgICAgICAgIHRoaXMuZXN0Lmdyb3VwU2VhcmNoUmVxdWVzdHNDYWNoZSA9IHRoaXMuZXN0Lmdyb3VwU2VhcmNoUmVxdWVzdHNDYWNoZS5maWx0ZXIodCA9PiAhKHQucm91dGUubGVuZ3RoID4gZ3JvdXBSb3V0ZS5sZW5ndGgpKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgdGhpcy5lc3QuYm91bmRTb3VyY2UgPSB0aGlzLmVzdC5ib3VuZFNvdXJjZS5maWx0ZXIodCA9PiAhKHQuX3BhcmVudCA9PSBncm91cEtleSkpO1xyXG5cclxuICAgICAgICAgICAgbGV0IHRoaXNHcm91cCA9IHRoaXMuZXN0LmJvdW5kU291cmNlW2luc2VydEluZGV4XTtcclxuICAgICAgICAgICAgaWYgKGludGVybWVkaWF0ZUdyb3VwKVxyXG4gICAgICAgICAgICAgICAgdGhpc0dyb3VwLl9ncm91cHNjb3VudCA9ICg8QXBwU2VhcmNoPGFueT4+dGhpcy5lc3QuVmlldyk/Lmdyb3VwY291bnQ7XHJcblxyXG4gICAgICAgICAgICAvLyBMaSBzb3N0aXR1aXNjbyBjb2kgbnVvdmkgZGkgcXVlc3RhIHJpY2VyY2FcclxuICAgICAgICAgICAgdGhpcy5lc3QuYm91bmRTb3VyY2Uuc3BsaWNlKGluc2VydEluZGV4ICsgMSwgMCwgLi4udGhpcy5lc3QuVE1QQm91bmRTb3VyY2UpO1xyXG5cclxuICAgICAgICAgICAgLy8gQWdnaXVuZ28gdW4gc2VwYXJhdG9yZSBhbGxhIGZpbmUgbyBhbGwnaW5pemlvIGRpIHF1ZXN0aSBncnVwcGkgY2hlIGRvdnLDoCBvY2N1cGFyc2kgZGkgY2FyaWNhcmUgQUxUUkkgZ3J1cHBpIG8gb2dnZXR0aSAoc2Ugc29ubyBhbGwndWx0aW1vIGdydXBwbylcclxuICAgICAgICAgICAgbGV0IGFkZExhc3QgPSBmYWxzZTtcclxuICAgICAgICAgICAgdGhpcy5lc3QuYm91bmRTb3VyY2Uuc3BsaWNlKGluc2VydEluZGV4ICsgMSArIChhZGRMYXN0ID8gdGhpcy5lc3QuVE1QQm91bmRTb3VyY2UubGVuZ3RoIDogMCksIDAsIHRoaXMuZ2V0R3JvdXBTZXBhcmF0b3IodmlldywgZ3JvdXBLZXksIGdyb3VwUm91dGUsIHZpZXcucmVxdWVzdGVkZ3JvdXBzLmxlbmd0aCwgaW50ZXJtZWRpYXRlR3JvdXAgPyAnZ3JvdXBzJyA6ICdpdGVtcycpKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFnZ2l1bmdvIGxhIHJpY2VyY2EgYWxsYSBjYWNoZSBkaSBxdWVzdGEgXCJzZXNzaW9uZVwiXHJcbiAgICAgICAgICAgIGxldCB0b0FkZCA9IHsgcGF0aDogZ3JvdXBLZXksIHJvdXRlOiBncm91cFJvdXRlLCB2aWV3OiBPYmplY3QuYXNzaWduKHt9LCB2aWV3KSwgZ3JvdXBfY29sdW1uOiBpbnRlcm1lZGlhdGVHcm91cCA/ICg8R3JvdXA+dGhpcy5lc3QuVE1QQm91bmRTb3VyY2VbMF0pLmNvbHVtbiA6ICcnIH07XHJcbiAgICAgICAgICAgIGxldCBwcmV2ID0gdGhpcy5lc3QuZ3JvdXBTZWFyY2hSZXF1ZXN0c0NhY2hlLmZpbmRJbmRleCh0ID0+IHQucGF0aCA9PSB0b0FkZC5wYXRoICYmIHQuZ3JvdXBfY29sdW1uID09IHRvQWRkLmdyb3VwX2NvbHVtbik7XHJcbiAgICAgICAgICAgIGlmIChwcmV2ID09IC0xKVxyXG4gICAgICAgICAgICAgICAgdGhpcy5lc3QuZ3JvdXBTZWFyY2hSZXF1ZXN0c0NhY2hlLnB1c2godG9BZGQpO1xyXG5cclxuICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgdGhpcy5lc3QuZ3JvdXBTZWFyY2hSZXF1ZXN0c0NhY2hlLnNwbGljZShwcmV2LCAxLCB0b0FkZCk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogU2UgaW4gbW9kYWxpdMOgIGFycmF5IGFwcGxpY2EgaSByYWdncnVwcGFtZW50aSBkZWZpbml0aSBsYXRvIHJvdy1ncm91cGluZ1xyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7dGhzOiBFc1RoW10gfCBFc1RoRGlyZWN0aXZlW119IHRocyBIZWFkZXJcclxuICAgICAqL1xyXG4gICAgcHVibGljIGFycmF5TW9kZVJldmlld0dyb3VwaW5ncyh0aHM6IEVzVGhbXSB8IEVzVGhEaXJlY3RpdmVbXSkge1xyXG4gICAgICAgIGlmICh0aHMubGVuZ3RoID09IDApXHJcbiAgICAgICAgICAgIHJldHVybjtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMudXRpbGl0aWVzLmlzRXNUaCh0aHNbMF0pKVxyXG4gICAgICAgICAgICByZXR1cm47XHJcblxyXG4gICAgICAgIGxldCBoZWFkZXJHcm91cHM6IEdyb3VwW10gPSBbXTtcclxuICAgICAgICBsZXQgaGVhZGVyQWdncmVnYXRpb25zOiBHcm91cE9yQWdncmVnYXRpb25bXSA9IFtdO1xyXG5cclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRocy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICBsZXQgdGggPSB0aHNbaV0gYXMgRXNUaERpcmVjdGl2ZTtcclxuXHJcbiAgICAgICAgICAgIGlmICh0aC50aEdyb3VwKVxyXG4gICAgICAgICAgICAgICAgaGVhZGVyR3JvdXBzLnB1c2gobmV3IEdyb3VwKHRoLnRoLCAwLCBcIlwiKSk7XHJcbiAgICAgICAgICAgIGVsc2UgaWYgKHRoLnRoQWdncmVnYXRpb24pXHJcbiAgICAgICAgICAgICAgICBoZWFkZXJBZ2dyZWdhdGlvbnMgPSBbLi4uaGVhZGVyQWdncmVnYXRpb25zLCAuLi50aGlzLmdldEdyb3VwQWdncmVnYXRpb25zKHRoKV07XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoaGVhZGVyR3JvdXBzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgLy8gUHVsaXppYSBkZWxsZSBjYWNoZVxyXG4gICAgICAgICAgICB0aGlzLnJnR3JvdXBDYWNoZS5jbGVhcigpO1xyXG4gICAgICAgICAgICB0aGlzLnJnSXRlbUNhY2hlLmNsZWFyKCk7XHJcbiAgICAgICAgICAgIHRoaXMucmdDaGlsZEdyb3Vwc0NhY2hlLmNsZWFyKCk7XHJcblxyXG4gICAgICAgICAgICB0aGlzLmVzdC5BcnJheUdyb3VwaW5nID0gdHJ1ZTtcclxuICAgICAgICAgICAgdGhpcy5lc3QuYm91bmRTb3VyY2UgPSB0aGlzLmdldEdyb3Vwc1JlY3Vyc2l2ZShoZWFkZXJHcm91cHMsIDAsIHRoaXMuZXN0LmJvdW5kU291cmNlLCBoZWFkZXJBZ2dyZWdhdGlvbnMsIG51bGwpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIERhdGEgdW5hIGRpcmV0dGl2YSBFc1RoIHJlc3RpdHVpc2NlIGxhIGxpc3RhIGRlbGxlIGFnZ3JlZ2F6aW9uaSByaWNoaWVzdGEgcGVyIHF1ZXN0YSBjb2xvbm5hIG8gaWwgZ3J1cHBvIGNoZSByYXBwcmVzZW50YVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7RXNUaERpcmVjdGl2ZX0gdGggRGlyZXR0aXZhXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybnMge0dyb3VwT3JBZ2dyZWdhdGlvbltdfSBMaXN0YSBkZWkgZ3J1cHBpIG8gYWdncmVnYXppb25pIHJlbGF0aXZpIGFsbGEgRGlyZXR0aXZhIHBhc3NhdGFcclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldEdyb3VwQWdncmVnYXRpb25zKHRoOiBFc1RoRGlyZWN0aXZlKTogR3JvdXBPckFnZ3JlZ2F0aW9uW10ge1xyXG4gICAgICAgIGxldCByZXQgPSBbXTtcclxuICAgICAgICAvLyBFczogJ3ttaW46ZGQvTU0veXl5eX0gLSB7bWF4OmRkL01NL3l5eXl9J1xyXG4gICAgICAgIGlmICh0aC50aEFnZ3JlZ2F0aW9uKSB7XHJcbiAgICAgICAgICAgIHRoaXMuZ2V0RXNUaERpcmVjdGl2ZUxpc3RPZkFnZ3JlZ2F0aW9ucyh0aCkuZm9yRWFjaCgoYWdnOiBUaEFnZ3JlZ2F0aW9uKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBsZXQgaXNkYXRlID0gYWdnLmZvcm1hdCAmJiBbJ3NtYWxsJywgJ2xvbmcnLCAndmVyeWxvbmcnXS5pbmNsdWRlcyhhZ2cuZm9ybWF0KTtcclxuICAgICAgICAgICAgICAgIGxldCBpc251bWJlciA9IGFnZy5mb3JtYXQgJiYgYWdnLmZvcm1hdC5zdGFydHNXaXRoKFwiRlwiKSAmJiAhTnVtYmVyLmlzTmFOKGFnZy5mb3JtYXQuY2hhckF0KDEpKSAmJiBhZ2cuZm9ybWF0Lmxlbmd0aCA9PSAyO1xyXG5cclxuICAgICAgICAgICAgICAgIGlmICghaXNkYXRlICYmICFpc251bWJlciAmJiBhZ2cuZm9ybWF0KVxyXG4gICAgICAgICAgICAgICAgICAgIHRocm93IFwiTGUgYWdnZXJnYXppb25pIHN1cHBvcnRhdGUgZGFsbCdlcy10YWJsZSBzb25vIHNvbG8gJ3NtYWxsJywgJ2xvbmcnLCAndmVyeWxvbmcnIHBlciBsZSBkYXRlIGUgJ0YwLTknIHBlciBpIG51bWVyaVwiO1xyXG5cclxuICAgICAgICAgICAgICAgIHJldC5wdXNoKG5ldyBHcm91cE9yQWdncmVnYXRpb24odGgudGgsIGFnZy5mdW5jLCBpc2RhdGUgPyAnZGF0ZScgOiBpc251bWJlciA/ICdudW1iZXInIDogJ3N0cmluZycpKTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2UgaWYgKHRoLnRoR3JvdXApXHJcbiAgICAgICAgICAgIHJldC5wdXNoKG5ldyBHcm91cE9yQWdncmVnYXRpb24odGgudGgsIG51bGwpKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIHJldDtcclxuICAgIH1cclxuXHJcblxyXG4gICAgLyoqXHJcbiAgICAqIERhdGEgdW5hIGRpcmV0dGl2YSBjb24gdW4gZm9ybWF0byByZXN0aXR1aXNjZSB0dXR0ZSBsZSBjb3BwaWUgRnVuemlvbmUgZGkgQWdncmVnYXppb25lIC0gRm9ybWF0b1xyXG4gICAgKlxyXG4gICAgKiBAcGFyYW0ge0VzVGhEaXJlY3RpdmV9IHRoIERpcmV0dGl2YSBFc1RoIGRpIGN1aSBjYWxjb2xhcmUgbGUgZnVuemlvbmkgZGkgYWdncmVnYXppb25lIHVzYXRlXHJcbiAgICAqXHJcbiAgICAqIEByZXR1cm5zIHt7IGZ1bmM6IHN0cmluZywgZm9ybWF0OiBzdHJpbmcgfVtdfSBMaXN0YSBkZWxsZSBmdW56aW9uaSBkaSBhZ2dyZWdhemlvbmUgcmlsZXZhdGVcclxuICAgICovXHJcbiAgICBwcml2YXRlIGdldEVzVGhEaXJlY3RpdmVMaXN0T2ZBZ2dyZWdhdGlvbnModGg6IEVzVGhEaXJlY3RpdmUpOiBUaEFnZ3JlZ2F0aW9uW10ge1xyXG4gICAgICAgIGlmICghdGgudGhBZ2dyZWdhdGlvbilcclxuICAgICAgICAgICAgcmV0dXJuIFtdO1xyXG5cclxuICAgICAgICAvLyBTZSBobyBnacOgIGVmZmV0dHVhdG8gcXVlc3RvIGNhbGNvbG8gcGVyIHF1ZXN0byB0aCByZXN0aXR1aXNjbyBsYSB2ZXJzaW9uZSBpbiBjYWNoZVxyXG4gICAgICAgIGlmICh0aC5fdGhBZ2dyZWdhdGlvbnMpXHJcbiAgICAgICAgICAgIHJldHVybiB0aC5fdGhBZ2dyZWdhdGlvbnM7XHJcblxyXG4gICAgICAgIGxldCByZXQgPSBbXTtcclxuICAgICAgICBsZXQgZGlzcGxheSA9IHRoLnRoQWdncmVnYXRpb247XHJcbiAgICAgICAgdmFyIG1hdGNoZXMgPSBkaXNwbGF5Lm1hdGNoKC97W2EtekEtWjAtOVxcLzpdKn0vZ2kpO1xyXG4gICAgICAgIGlmICghbWF0Y2hlcylcclxuICAgICAgICAgICAgcmV0dXJuIFtdO1xyXG4gICAgICAgIG1hdGNoZXMuZm9yRWFjaChtID0+IHtcclxuICAgICAgICAgICAgbGV0IHNwbGl0ID0gbS5zcGxpdChcIjpcIik7XHJcbiAgICAgICAgICAgIGxldCBmdW5jID0gbSwgZm9ybWF0ID0gXCJcIjtcclxuICAgICAgICAgICAgaWYgKHNwbGl0Lmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgICAgIC8vIEVzY2x1ZG8gcHJpbW8gZSB1bHRpbW8gY2FyYXR0ZXJlIChsZSBncmFmZmUpXHJcbiAgICAgICAgICAgICAgICBmdW5jID0gc3BsaXRbMF0uc3Vic3RyKDEpO1xyXG4gICAgICAgICAgICAgICAgZm9ybWF0ID0gc3BsaXRbMV0uc3Vic3RyKDAsIHNwbGl0WzFdLmxlbmd0aCAtIDEpO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICByZXQucHVzaCh7IGZ1bmM6IDwnbWluJyB8ICdtYXgnIHwgJ3N1bSc+ZnVuYywgZm9ybWF0OiBmb3JtYXQsIG1hdGNoOiBtIH0pO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICB0aC5fdGhBZ2dyZWdhdGlvbnMgPSByZXQ7XHJcbiAgICAgICAgcmV0dXJuIHJldDtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIERhdGEgbGEgZGVmaW5pemlvbmUgZGVpIGdydXBwaSBkYSBnZW5lcmFyZSBkYSB1bmEgbGlzdGEgZGkgb2dnZXR0aSwgc3VkZGl2aWRlIGdsaSBvZ2dldHRpIHBhc3NhdGkgaW4gZ3J1cHBpIGUgc290dG9ncnVwcGlcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0ge0dyb3VwW119IGdycHMgRGVmaW5pemlvbmUgZGVpIGdydXBwaVxyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGN1cnJlbnRJbmRleCBJbmRpY2UgZGkgZWxhYm9yYXppb25lLiBBbCBsaXZlbGxvIDAgaG8gdHV0dGkgZ2xpIG9nZ2V0dGkgZSBkZXZvIGdlbmVyYXJlIGkgcHJpbWkgZ3J1cHBpLCBhIGxpdmVsbG8gMSBobyB0dXR0aSBpIGdydXBwaSBwcmluY2lwYWxpIGUgZGV2b1xyXG4gICAgICogZWxhYm9yYXJlIGkgc290dG9ncnVwcGksIGUgY29zw6wgdmlhIHJpY29yc2l2YW1lbnRlLi4uXHJcbiAgICAgKiBAcGFyYW0ge2FueVtdfSBpdGVtcyBPZ2dldHRpIGRhIHJhZ2dydXBwYXJlXHJcbiAgICAgKiBAcGFyYW0ge0dyb3VwT3JBZ2dyZWdhdGlvbltdfSBhZ2dyZWdhdGlvbnMgSW5mbyBkaSBhZ2dyZWdhemlvbmVcclxuICAgICAqIEBwYXJhbSB7YW55fSBwYXJlbnQgUmlmZXJpbWVudG8gYWwgZ3J1cHBvIHBhZHJlXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgZ2V0R3JvdXBzUmVjdXJzaXZlKGdycHM6IEdyb3VwW10sIGN1cnJlbnRJbmRleDogbnVtYmVyLCBpdGVtczogYW55W10sIGFnZ3JlZ2F0aW9uczogR3JvdXBPckFnZ3JlZ2F0aW9uW10sIHBhcmVudD86IGFueSk6IGFueVtdIHtcclxuICAgICAgICAvLyBTZSBsJ2luZGljZSDDqCAwIGRldm8gc2ljdXJhbWVudGUgbmFzY29uZGVyZSB0dXR0aSBnbGkgb2dnZXR0aS4gU29sbyBpIGdydXBwaSBzYXJhbm5vIHZpc3VhbGl6emF0aVxyXG4gICAgICAgIGlmIChjdXJyZW50SW5kZXggPT0gMClcclxuICAgICAgICAgICAgaXRlbXMuZm9yRWFjaChpID0+IGkuX3Zpc2libGUgPSBmYWxzZSk7XHJcblxyXG4gICAgICAgIGxldCBncnAgPSBncnBzW2N1cnJlbnRJbmRleF07XHJcbiAgICAgICAgbGV0IHJldDogYW55W10gPSBbXTtcclxuICAgICAgICBsZXQgbGFzdCA9IGdycHMubGVuZ3RoID09IGN1cnJlbnRJbmRleCArIDE7XHJcbiAgICAgICAgbGV0IGdyb3VwcyA9IHRoaXMudXRpbGl0aWVzLmdyb3VwQnkoaXRlbXMsIGdycC5jb2x1bW4pO1xyXG4gICAgICAgIGZvciAobGV0IHByb3AgaW4gZ3JvdXBzKSB7XHJcbiAgICAgICAgICAgIGxldCBpdG1zID0gZ3JvdXBzW3Byb3BdO1xyXG4gICAgICAgICAgICBsZXQgZ3AgPSBuZXcgR3JvdXAoZ3JwLmNvbHVtbiwgaXRtcy5sZW5ndGgsIHByb3ApO1xyXG4gICAgICAgICAgICBncC5hZ2dyZWdhdGlvbnMgPSB0aGlzLmdlbmVyYXRlQWdncmVnYXRpb25zKGl0bXMsIGFnZ3JlZ2F0aW9ucyk7XHJcblxyXG4gICAgICAgICAgICBsZXQgYW55Z3AgPSAoPGFueT5ncCk7XHJcbiAgICAgICAgICAgIGFueWdwLl9ncm91cCA9IHRydWU7XHJcbiAgICAgICAgICAgIGFueWdwLl9leHBhbmRlZCA9IGZhbHNlO1xyXG4gICAgICAgICAgICBpZiAoIXBhcmVudCkge1xyXG4gICAgICAgICAgICAgICAgYW55Z3AuX3RoaXNSb3V0ZSA9IFt7IGNvbHVtbjogZ3AuY29sdW1uLCB2YWx1ZTogZ3AudmFsdWUgfV07XHJcbiAgICAgICAgICAgICAgICBhbnlncC5fdGhpc0tleSA9IGdwLnZhbHVlO1xyXG4gICAgICAgICAgICAgICAgYW55Z3AuX2dyb3VwbGV2ZWwgPSAwO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgYW55Z3AuX3BhcmVudCA9IHBhcmVudC5fdGhpc0tleTtcclxuICAgICAgICAgICAgICAgIGFueWdwLl9wYXJlbnRSb3V0ZSA9IHBhcmVudC5fdGhpc1JvdXRlO1xyXG4gICAgICAgICAgICAgICAgYW55Z3AuX3RoaXNSb3V0ZSA9IFsuLi5wYXJlbnQuX3RoaXNSb3V0ZSwgeyBjb2x1bW46IGdwLmNvbHVtbiwgdmFsdWU6IGdwLnZhbHVlIH1dO1xyXG4gICAgICAgICAgICAgICAgYW55Z3AuX3RoaXNLZXkgPSBwYXJlbnQuX3RoaXNLZXkgKyBncC52YWx1ZTtcclxuICAgICAgICAgICAgICAgIGFueWdwLl9ncm91cGxldmVsID0gcGFyZW50Ll9ncm91cGxldmVsICsgMTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gUHVzaG8gaWwgZ3J1cHBvLCB0dXR0aSBpIGdydXBwaSBkZWwgbGl2ZWxsbyBzb3R0bywgbyBnbGkgaXRlbSBzZSBpbyBzb25vIGwndWx0aW1vIGdydXBwby4gXHJcbiAgICAgICAgICAgIC8vIExhIHZpc2liaWxpdMOgIMOoIHNvbG8gcGVyIGlsIGdydXBwbyBhIGxpdmVsbG8gMCwgdHV0dGkgZ2xpIGFsdHJpIGdydXBwaSBzYXJhbm5vIG1vc3RyYXRpIG8gbmFzY29zdGkgZGkgY29uc2VndWVuemFcclxuICAgICAgICAgICAgaWYgKGN1cnJlbnRJbmRleCA9PSAwKVxyXG4gICAgICAgICAgICAgICAgYW55Z3AuX3Zpc2libGUgPSB0cnVlO1xyXG5cclxuICAgICAgICAgICAgdGhpcy51dGlsaXRpZXMuY2FsY3VsYXRlSGFzaChbYW55Z3BdKTtcclxuICAgICAgICAgICAgdGhpcy51dGlsaXRpZXMuY2FjaGVBZ2dyZWdhdGlvbnMoYW55Z3ApO1xyXG5cclxuICAgICAgICAgICAgLy8gQWdnaXVuZ28gaWwgZ3J1cHBvIHBhZHJlXHJcbiAgICAgICAgICAgIHJldC5wdXNoKGFueWdwKTtcclxuICAgICAgICAgICAgdGhpcy5yZ0dyb3VwQ2FjaGUuc2V0KGFueWdwLl90aGlzS2V5LCBhbnlncCk7XHJcbiAgICAgICAgICAgIGlmICghbGFzdCkge1xyXG5cclxuICAgICAgICAgICAgICAgIC8vRGFsIGdydXBwbyBwYWRyZSwgc2Ugbm9uIMOoIGwndWx0aW1vIGdydXBwbyBkZWxsYSBjYXRlbmEsIGNhbGNvbG8gcmljb3JzaXZhbWVudGUgdHV0dGEgbGEgY2F0ZW5hIHNvdHRvXHJcbiAgICAgICAgICAgICAgICBsZXQgc3ViR3JvdXBzQW5kSXRlbXMgPSB0aGlzLmdldEdyb3Vwc1JlY3Vyc2l2ZShncnBzLCBjdXJyZW50SW5kZXggKyAxLCBpdG1zLCBhZ2dyZWdhdGlvbnMsIGFueWdwKTtcclxuICAgICAgICAgICAgICAgIGxldCBjaGlsZGdyb3VwcyA9IHN1Ykdyb3Vwc0FuZEl0ZW1zLmZpbHRlcih0ID0+IHQuX2dyb3VwICYmIHQuX3BhcmVudCA9PSBhbnlncC5fdGhpc0tleSk7XHJcbiAgICAgICAgICAgICAgICBhbnlncC5fZ3JvdXBzY291bnQgPSBjaGlsZGdyb3Vwcy5sZW5ndGg7XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gQWdnaXVuZ28gbGEgY2F0ZW5hIGRlbCBncnVwcG8gc290dG8sIGFnZ2l1bmdlbmRvIGFsbGEgY2FjaGUgc29sbyBpIGdydXBwaSBwYWRyZVxyXG4gICAgICAgICAgICAgICAgcmV0LnB1c2goLi4uc3ViR3JvdXBzQW5kSXRlbXMpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5yZ0NoaWxkR3JvdXBzQ2FjaGUuc2V0KGFueWdwLl90aGlzS2V5LCBjaGlsZGdyb3Vwcyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyBBbCBncnVwcG8gcGFkcmUsIHNlIMOoIGwndWx0aW1vIGFzc2Vnbm8gdHV0dGUgbGUgZm9nbGllIGFzc2VnbmFuZG9nbGkgYW5jaGUgbGEgY2hpYXZlIGRlbCBncnVwcG9cclxuICAgICAgICAgICAgICAgIGl0bXMuZm9yRWFjaChpID0+IGkuX3RoaXNLZXkgPSBhbnlncC5fdGhpc0tleSk7XHJcblxyXG4gICAgICAgICAgICAgICAgcmV0LnB1c2goLi4uaXRtcyk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnJnSXRlbUNhY2hlLnNldChhbnlncC5fdGhpc0tleSwgaXRtcyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHJldDtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIERhdGEgdW5hIGxpc3RhIGRpIG9nZ2V0dGkgZ2VuZXJhIGxlIGFnZ3JlZ2F6aW9uaSBzcGVjaWZpY2F0ZS4gU2kgY29uc2lkZXJhIGRpIGF2ZXJlIHR1dHRpIGdsaSBvZ2dldHRpXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHthbnlbXX0gaXRlbXMgT2dnZXR0aSBkaSBjdWkgY2FsY29sYXJlIGxlIGFnZ3JlZ2F6aW9uZVxyXG4gICAgICogQHBhcmFtIHtHcm91cE9yQWdncmVnYXRpb25bXX0gYWdncmVnYXRpb25zIEFnZ2VyZ2F6aW9uaSBkYSBnZW5lcmFyZVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIGdlbmVyYXRlQWdncmVnYXRpb25zKGl0ZW1zOiBhbnlbXSwgYWdncmVnYXRpb25zOiBHcm91cE9yQWdncmVnYXRpb25bXSk6IEdyb3VwQWdncmVnYXRpb25bXSB7XHJcbiAgICAgICAgbGV0IHJldHM6IEdyb3VwQWdncmVnYXRpb25bXSA9IFtdO1xyXG4gICAgICAgIGxldCBhZ2dyZWdhdGlvblZhbHVlID0gXCJcIiwgZmVGaWVsZCA9IG51bGwsIHN0cmluZ0FnZyA9IG51bGwsIGRhdGVBZ2cgPSBudWxsLCBudW1iZXJBZ2cgPSBudWxsO1xyXG5cclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGFnZ3JlZ2F0aW9ucy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICBsZXQgYWdnID0gYWdncmVnYXRpb25zW2ldO1xyXG4gICAgICAgICAgICBmZUZpZWxkID0gYWdnLmNvbHVtbjtcclxuICAgICAgICAgICAgaWYgKCFmZUZpZWxkKVxyXG4gICAgICAgICAgICAgICAgY29udGludWU7XHJcblxyXG4gICAgICAgICAgICBzd2l0Y2ggKGFnZy5kYXRhdHlwZSkge1xyXG4gICAgICAgICAgICAgICAgY2FzZSAnc3RyaW5nJzogc3RyaW5nQWdnID0gaXRlbXMubWFwKGkgPT4gaVtmZUZpZWxkXS50b1N0cmluZygpKTsgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICBjYXNlICdkYXRlJzogZGF0ZUFnZyA9IGl0ZW1zLm1hcChpID0+IG5ldyBEYXRlKGlbZmVGaWVsZF0pLmdldFRpbWUoKSk7IGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgY2FzZSAnbnVtYmVyJzogbnVtYmVyQWdnID0gaXRlbXMubWFwKGkgPT4gcGFyc2VGbG9hdChpW2ZlRmllbGRdKSk7IGJyZWFrO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBzd2l0Y2ggKGFnZy5hZ2dyZWdhdGlvbikge1xyXG4gICAgICAgICAgICAgICAgY2FzZSAnbWF4JzpcclxuICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKGFnZy5kYXRhdHlwZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdzdHJpbmcnOiBhZ2dyZWdhdGlvblZhbHVlID0gc3RyaW5nQWdnLnNvcnQoKS5yZXZlcnNlKClbMF07IGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdkYXRlJzogYWdncmVnYXRpb25WYWx1ZSA9IG5ldyBEYXRlKE1hdGgubWF4KC4uLmRhdGVBZ2cpKS50b1N0cmluZygpOyBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnbnVtYmVyJzogYWdncmVnYXRpb25WYWx1ZSA9IE1hdGgubWF4KC4uLm51bWJlckFnZykudG9TdHJpbmcoKTsgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgY2FzZSAnbWluJzpcclxuICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKGFnZy5kYXRhdHlwZSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdzdHJpbmcnOiBhZ2dyZWdhdGlvblZhbHVlID0gc3RyaW5nQWdnLnNvcnQoKVswXTsgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ2RhdGUnOiBhZ2dyZWdhdGlvblZhbHVlID0gbmV3IERhdGUoTWF0aC5taW4oLi4uZGF0ZUFnZykpLnRvU3RyaW5nKCk7IGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdudW1iZXInOiBhZ2dyZWdhdGlvblZhbHVlID0gTWF0aC5taW4oLi4ubnVtYmVyQWdnKS50b1N0cmluZygpOyBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICBjYXNlICdzdW0nOlxyXG4gICAgICAgICAgICAgICAgICAgIHN3aXRjaCAoYWdnLmRhdGF0eXBlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ3N0cmluZyc6IGFnZ3JlZ2F0aW9uVmFsdWUgPSBzdHJpbmdBZ2cuam9pbihcIiwgXCIpOyBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnZGF0ZSc6IGFnZ3JlZ2F0aW9uVmFsdWUgPSBcIlwiOyBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnbnVtYmVyJzogYWdncmVnYXRpb25WYWx1ZSA9IG51bWJlckFnZy5yZWR1Y2UoKHByZSwgY3VycikgPT4gcHJlICsgY3VyciwgMCkudG9TdHJpbmcoKTsgYnJlYWs7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHJldHMucHVzaChuZXcgR3JvdXBBZ2dyZWdhdGlvbihhZ2cuY29sdW1uLCBhZ2cuYWdncmVnYXRpb24sIGFnZ3JlZ2F0aW9uVmFsdWUpKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiByZXRzO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgKiBPdHRpZW5lIHVuIGVsZW1lbnRvIGRpIHNlcGFyYXppb25lIGZyYSBHcnVwcGkgY2hlIHNlcnZlIHBlciBwYWdpbmFyZSBsZSByaWNlcmNoZSBhbGwnaW50ZXJubyBkaSBvZ25pIHNpbmdvbG8gZ3J1cHBvXHJcbiAgICAqXHJcbiAgICAqIEBwYXJhbSB7QXBwU2VhcmNoPGFueT59IHZpZXcgVmlldyB1dGlsaXp6YXRhIHBlciBsYSByaWNlcmNhLiBNZSBuZSBzYWx2byBpIHBhcmFtZXRyaSBuZWwgc2VwYXJhdG9yZSBhdHR1YWxlIGRhdG8gY2hlIG5lIGhvIGJpc29nbm8gcGVyIGNhcmljYXJlIGFsdHJpIGVsZW1lbnRpXHJcbiAgICAqIGZhY2VudGkgcmlmZXJpbWVudG8gYWxsbyBzdGVzc28gY29udGVzdG9cclxuICAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmVudCBQYXJlbnQgcGF0aCBjaGUgcmFwcHJlc2VudGEgYSBxdWFsZSBncnVwcG8gw6ggYWZmaWJiaWF0byBxdWVzdG8gc2VwYXJhdG9yZVxyXG4gICAgKiBAcGFyYW0ge0dyb3VwUm91dGVGcmFnbWVudFtdfSByb3V0ZSBSb3V0ZSBwYXRoIGNoZSByYXBwcmVzZW50YSBhIHF1YWxlIGdydXBwbyDDqCBhZmZpYmJpYXRvIHF1ZXN0byBzZXBhcmF0b3JlXHJcbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCBMaXZlbGxvIGRlbCBncnVwcG8gZGkgY3VpIHF1ZXN0byBlbGVtZW50byDDqCBzZXBhcmF0b3JlLCB2aWVuZSB1c2F0byBwZXIgYXBwbGljYXJlIGxhIGNsYXNzZSBcImVzdC1sdmwte3tsZXZlbH19XCJcclxuICAgICpcclxuICAgICogQHJldHVybnMge2FueX0gRWxlbWVudG8gZGkgc2VwYXJhemlvbmUgY29udGVuZW50ZSB0dXR0aSBpIGJpbmQgcGVyIHByZXNlbnRhcmUgdW5hIHBhZ2luYXppb25lIHNvdHRvIHF1ZXN0byBncnVwcG8gbGF0byBpbnRlcmZhY2NpYVxyXG4gICAgKi9cclxuICAgIHB1YmxpYyBnZXRHcm91cFNlcGFyYXRvcih2aWV3OiBBcHBTZWFyY2g8YW55PiwgcGFyZW50OiBzdHJpbmcsIHJvdXRlOiBHcm91cFJvdXRlRnJhZ21lbnRbXSwgbGV2ZWw6IG51bWJlciwgc2VhcmNoZXM6ICdncm91cHMnIHwgJ2l0ZW1zJyk6IEdyb3VwUGFnZXIge1xyXG4gICAgICAgIGxldCBpdGVtID0gbmV3IEdyb3VwUGFnZXIobGV2ZWwsIHJvdXRlLCBwYXJlbnQsIE9iamVjdC5hc3NpZ24oe30sIHZpZXcpLCBzZWFyY2hlcyk7XHJcbiAgICAgICAgaXRlbS5idXR0b25zID0gdGhpcy51dGlsaXRpZXMuZ2V0UGFnZXNBcnJheSg2LCB2aWV3LnBhZ2UsIHZpZXcucGFnZXMpO1xyXG4gICAgICAgIHRoaXMudXRpbGl0aWVzLmNhbGN1bGF0ZUhhc2goW2l0ZW1dKTtcclxuICAgICAgICByZXR1cm4gaXRlbTtcclxuICAgIH1cclxuXHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEYXRhIHVuYSBjb2xvbm5hIGVmZmV0dHVhIGxhIHJpZW1pc3Npb25lIGRpIHR1dHRlIGxlIHJpY2VyY2hlIHJlbGF0aXZlLlxyXG4gICAgICpcclxuICAgICAqIEVzLiBIbyAyIGNhbXBpIGRpIGdydXBwbyBlIGhvIGVzcGFuc28gZmlubyBhIHZlZGVyZSBpIHZhbG9yaSBmaW5vIGFkIHVuIGxpdmVsbG8gcXVhbHNpYXNpLlxyXG4gICAgICogQ2xpY2NvIGwnb3JkaW5hbWVudG8gc3VsIHNlY29uZG8gZ3J1cHBvLlxyXG4gICAgICogVHV0dGUgbGUgcmljZXJjaGUgcmVsYXRpdmUgYWkgcHJpbWkgZ3J1cHBpIGRldm9ubyBlc3NlcmUgcmllc2VndWl0ZS4gUXVhbmRvIGkgcmlzdWx0YXRpIGFycml2ZXJhbm5vIGNpIHBlbnNlcsOgIGlsIG1ldG9kbyAqKmJpbmREaXNwbGF5VG9Mb2FkZWRJdGVtc09yR3JvdXBzKipcclxuICAgICAqIGEgdGFnbGlhcmUgdmlhIGdsaSBvZ2dldHRpIG5vbiBwacO5IHZpc3VhbGl6emF0aVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBjb2x1bW4gQ29sb25uYSBzdSBjdWkgc2kgw6ggZWZmZXR0dWF0YSB1bidvcGVyYXppb25lIGRpIG9yZGluYW1lbnRvXHJcbiAgICAgKiBAcGFyYW0ge0FwcE9yZGVyaW5nW119IG9yZGVyaW5ncyBEaXJldHRpdmUgZGkgb3JkaW5hbWVudG8gZGEgYXBwbGljYXJlIGFsbGUgdmFyaWUgc290dG9yaWNlcmNoZVxyXG4gICAgICovXHJcbiAgICBwdWJsaWMgZW1pdFJvd0dyb3VwaW5nU2VhcmNoZXMoY29sdW1uOiBzdHJpbmcsIG9yZGVyaW5nczogQXBwT3JkZXJpbmdbXSkge1xyXG4gICAgICAgIC8vIFBlciB0dXR0ZSBsZSByaWNlcmNoZSBpbnRlcm1lZGllIGNoZSBkZXZvIHJpdmFsdXRhcmUgbGUgcmUtZW1pdHRvIGluIG1vZG8gZGEgYWdnaW9ybmFyZ2xpIGkgZGF0aVxyXG4gICAgICAgIHZhciBtZWFuaW5nZnVsQXBwU2VhcmNoZXMgPSB0aGlzLmVzdC5ncm91cFNlYXJjaFJlcXVlc3RzQ2FjaGUuZmlsdGVyKHQgPT4gdC5ncm91cF9jb2x1bW4gPT0gY29sdW1uKS5tYXAodCA9PiB0LnZpZXcpO1xyXG5cclxuICAgICAgICAvLyBTZSBub24gbmUgdHJvdm8gc2lnbmlmaWNhIGNoZSBobyBmYXR0byBsJ29yZGluYW1lbnRvIG8gc3VnbGkgaXRlbSwgbyBzdSBjb2xvbm5lIHJlbGF0aXZlIGEgdW4gc290dG9ncnVwcG8gbm9uIGNhcmljYXRvXHJcbiAgICAgICAgaWYgKCFtZWFuaW5nZnVsQXBwU2VhcmNoZXMgfHwgbWVhbmluZ2Z1bEFwcFNlYXJjaGVzLmxlbmd0aCA9PSAwKVxyXG4gICAgICAgICAgICBtZWFuaW5nZnVsQXBwU2VhcmNoZXMgPSB0aGlzLmVzdC5ncm91cFNlYXJjaFJlcXVlc3RzQ2FjaGUuZmlsdGVyKHQgPT4gIXQuZ3JvdXBfY29sdW1uKS5tYXAodCA9PiB0LnZpZXcpO1xyXG5cclxuICAgICAgICAvLyBTZSBub24gbmUgdHJvdm8gcXVpIHNpZ25pZmljYSBjaGUgc3RvIG9yZGluYW5kbyBzdSBjb2xvbm5lIHJlbGF0aXZlIGEgdW4gc290dG9ncnVwcG8gbm9uIGNhcmljYXRvXHJcbiAgICAgICAgaWYgKCFtZWFuaW5nZnVsQXBwU2VhcmNoZXMgfHwgbWVhbmluZ2Z1bEFwcFNlYXJjaGVzLmxlbmd0aCA9PSAwKVxyXG4gICAgICAgICAgICByZXR1cm47XHJcblxyXG4gICAgICAgIG1lYW5pbmdmdWxBcHBTZWFyY2hlcy5mb3JFYWNoKGFzID0+IHtcclxuICAgICAgICAgICAgLy8gT3Z2aWFtZW50ZSBnbGkgb3JpZG5hbWVudGkgZGV2b25vIGVzc2VyZSBxdWVsbGkgYXBwZW5hIGdlbmVyYXRpXHJcbiAgICAgICAgICAgIGFzLm9yZGVycyA9IG9yZGVyaW5ncztcclxuICAgICAgICAgICAgYXMuc2F2ZWRzdGF0ZSA9IHRydWU7XHJcbiAgICAgICAgICAgIHRoaXMuZXN0LmVtaXRTZWFyY2hSZXF1ZXN0KGZhbHNlLCBhcyk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBIZWxwZXIgY2hlIGNhbGNvbGEgaWwgY29udGVudXRvIGRpIHVuYSBjZWxsYSByZWxhdGl2YSBhIHVuIGdydXBwbyByaWdhLCB0ZW5lbmRvIGNvbnRvIGRlbCBmb3JtYXRvIGRlbGxlIGV2ZW50dWFsaSBhZ2dyZWdhemlvbmlcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0ge0dyb3VwfSBncnAgR3J1cHBvIGRpIGN1aSBtb3N0cmFyZSBsZSBjZWxsZVxyXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGNlbGwgQ2VsbGEgYXR0dWFsZSBkaSBjdWkgY2FsY29sYXJlIGlsIHRlc3RvXHJcbiAgICAgKiBAcGFyYW0ge0VzVGhEaXJlY3RpdmV9IGhlYWRlciBIZWFkZXIgcmVsYXRpdm8gYWxsYSBjZWxsYSBhdHR1YWxlLCB1dGlsaXp6YXRhIHBlciBpZGVudGlmaWNhcmUgbGUgaW5mb3JtYXppb25pIGRpIGFnZ3JlZ2F6aW9uZVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IFRlc3RvIGZpbmFsZSBjYWxjb2xhdG8gcGVyIGxhICoqY2VsbCoqIGNvcnJlbnRlLCBpbiBiYXNlIGFsbGUgYWdncmVnYXppb25pIGRpICoqaGVhZGVyKipcclxuICAgICAqL1xyXG4gICAgcHVibGljIGdldEdyb3VwQ2VsbERpc3BsYXkoZ3JwOiBHcm91cCwgY2VsbDogc3RyaW5nLCBoZWFkZXI6IEVzVGhEaXJlY3RpdmUpOiBzdHJpbmcge1xyXG4gICAgICAgIGlmICgoPGFueT5ncnApLl9zZXApXHJcbiAgICAgICAgICAgIHJldHVybiBcIlwiO1xyXG4gICAgICAgIGxldCBkaXNwbGF5ID0gaGVhZGVyLnRoQWdncmVnYXRpb247XHJcbiAgICAgICAgaWYgKGdycC5jb2x1bW4gPT0gY2VsbCkge1xyXG4gICAgICAgICAgICBsZXQgZ3JvdXBzUGFydCA9ICg8YW55PmdycCkuX2dyb3Vwc2NvdW50ID8gXCIgLSBcIiArICg8YW55PmdycCkuX2dyb3Vwc2NvdW50ICsgXCIgXCIgKyB0aGlzLmVzdC5sYy5sb2MoXCJHcm91cHNcIikgOiBcIlwiO1xyXG4gICAgICAgICAgICByZXR1cm4gZ3JwLnZhbHVlICsgXCIgKFwiICsgZ3JwLmNvdW50ICsgZ3JvdXBzUGFydCArIFwiKVwiO1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuXHJcbiAgICAgICAgICAgIGxldCBhZ2cgPSAoPE1hcDxzdHJpbmcsIE1hcDxzdHJpbmcsIHN0cmluZz4+Pig8YW55PmdycCkuX2FnZ3JlZ2F0aW9uc0NhY2hlKS5nZXQoY2VsbCk7XHJcbiAgICAgICAgICAgIGlmICghYWdnKVxyXG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiXCI7XHJcblxyXG4gICAgICAgICAgICB0aGlzLmdldEVzVGhEaXJlY3RpdmVMaXN0T2ZBZ2dyZWdhdGlvbnMoaGVhZGVyKS5mb3JFYWNoKChpdG06IFRoQWdncmVnYXRpb24pID0+IHtcclxuICAgICAgICAgICAgICAgIGRpc3BsYXkgPSBkaXNwbGF5LnJlcGxhY2UoaXRtLm1hdGNoLCB0aGlzLmZvcm1hdEFnZ3JlZ2F0aW9uVmFsdWUoYWdnLmdldChpdG0uZnVuYyksIGl0bS5mb3JtYXQpKTtcclxuICAgICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gZGlzcGxheTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBGdW56aW9uZSBjaGUgZGF0byB1biB2YWxvcmUgbG8gZm9ybWF0dGEgaW4gYmFzZSBhbCB0aXBvXHJcbiAgICAgKiBcclxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSBWYWxvcmUgY2hlIGdlbmVyYWxlbW50ZSBwdcOyIGVzc2VyZSB1bmEgZGF0YSBvIHVuIG51bWVyb1xyXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGZyb21hdCBGb3JtYXRvIHN1IGN1aSBmb3JtYXR0YXJlIGlsIHZhbG9yZS4gUHXDsiBlc3NlcmUgYWQgZXNlbXBpbyBcInNtYWxsXCIsIFwibG9uZ1wiIFwidmVyeWxvbmdcIiBwZXIgbGUgZGF0ZSBvIEZ7MC05fSBwZXIgaSBudW1lcmkgZGVjaW1hbGlcclxuICAgICAqIFxyXG4gICAgICogQHJldHVybnMge3N0cmluZ30gVmFsb3JlIGRlbGwnYWdncmVnYXppb25lIGZvcm1hdHRhdG8gY29tZSBzaSBkZXZlXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgZm9ybWF0QWdncmVnYXRpb25WYWx1ZSh2YWx1ZTogc3RyaW5nLCBmb3JtYXQ/OiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgICAgIGlmICghZm9ybWF0KVxyXG4gICAgICAgICAgICByZXR1cm4gdmFsdWU7XHJcblxyXG4gICAgICAgIGxldCBpc051bWJlciA9ICFOdW1iZXIuaXNOYU4odmFsdWUpICYmICghZm9ybWF0IHx8IGZvcm1hdC5zdGFydHNXaXRoKFwiRlwiKSk7XHJcblxyXG4gICAgICAgIGlmIChpc051bWJlciAmJiBmb3JtYXQuc3RhcnRzV2l0aChcIkZcIikgJiYgIU51bWJlci5pc05hTihmb3JtYXQuc3Vic3RyKDEpKSlcclxuICAgICAgICAgICAgcmV0dXJuIHBhcnNlRmxvYXQodmFsdWUpLnRvRml4ZWQocGFyc2VJbnQoZm9ybWF0LnN1YnN0cigxKSkpO1xyXG5cclxuICAgICAgICBsZXQgZGF0ZSA9IG51bGw7XHJcbiAgICAgICAgLy8gQWxjdW5lIHZlcnNpb25lIGRpIGV4dGVuc2lvbnMgcmlzY2hpYW5vIGRpIGNyYXNoYXJlIGNvbiBjb3NlIG5vbiBkYXRlLi4uIMOoIHN0YXRvIHJpc29sdG8gZG9wbyBxdWluZGkgcXVlc3RvIHRyeSAtIGNhdGNoIGluIHJlYWx0w6BcclxuICAgICAgICAvLyB0b3JuYSB1dGlsZSBzb2xvIGNvbiB2ZXJzaW9uaSB2ZWNjaGllL2RlcHJlY2F0ZSBkZWxsYSBsaWJyZXJpYSBAZXNmYWVuemEvZXh0ZW5zaW9uc1xyXG4gICAgICAgIHRyeSB7IGRhdGUgPSB0aGlzLmRhdGVFeHRzLmdldERhdGVDb252ZXJ0aW9uKHZhbHVlKTsgfSBjYXRjaCB7IH1cclxuXHJcbiAgICAgICAgaWYgKGRhdGUpXHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmRhdGVFeHRzLmdldEZvcm1hdHRlZChkYXRlLCBmb3JtYXQgPT0gJ3NtYWxsJywgZm9ybWF0ID09ICd2ZXJ5bG9uZycpO1xyXG5cclxuICAgICAgICAvLyBRdWkgY2kgZmluaXNjbyBzaWEgcGVyIGlucHV0IGNoZSBub24gc29ubyBuw6kgZGF0ZSBuw6kgbnVtZXJpLCBzaWEgcGVyIGZvcm1hdGkgbm9uIHJpY29ub3NjaXV0aVxyXG4gICAgICAgIHJldHVybiB2YWx1ZTtcclxuICAgIH1cclxufSJdfQ==
|