@esfaenza/es-table 12.2.28 → 13.1.2

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