@datagrok-libraries/bio 5.9.7 → 5.9.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1111 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- /* Do not change these import lines to match external modules in webpack configuration */
11
- import * as grok from 'datagrok-api/grok';
12
- import * as DG from 'datagrok-api/dg';
13
- import { HELM_CORE_FIELDS } from './const';
14
- import { getSplitter } from './macromolecule';
15
- import { NotationConverter } from './notation-converter';
16
- // constants for parsing molfile V2000
17
- const V2K_RGP_SHIFT = 8;
18
- const V2K_RGP_LINE = 'M RGP';
19
- const V2K_A_LINE = 'A ';
20
- // constants for parsing/reconstruction of molfile V3000
21
- const V3K_COUNTS_SHIFT = 14;
22
- const V3K_IDX_SHIFT = 7;
23
- const V3K_HEADER_FIRST_LINE = '\nDatagrok macromolecule handler\n\n';
24
- const V3K_HEADER_SECOND_LINE = ' 0 0 0 0 0 0 999 V3000\n';
25
- const V3K_BEGIN_CTAB_BLOCK = 'M V30 BEGIN CTAB\n';
26
- const V3K_END_CTAB_BLOCK = 'M V30 END CTAB\n';
27
- const V3K_BEGIN_COUNTS_LINE = 'M V30 COUNTS ';
28
- const V3K_COUNTS_LINE_ENDING = ' 0 0 0\n';
29
- const V3K_BEGIN_ATOM_BLOCK = 'M V30 BEGIN ATOM\n';
30
- const V3K_END_ATOM_BLOCK = 'M V30 END ATOM\n';
31
- const V3K_BEGIN_BOND_BLOCK = 'M V30 BEGIN BOND\n';
32
- const V3K_END_BOND_BLOCK = 'M V30 END BOND\n';
33
- const V3K_BOND_CONFIG = ' CFG=';
34
- const V3K_BEGIN_DATA_LINE = 'M V30 ';
35
- const V3K_END = 'M END\n';
36
- const PRECISION_FACTOR = 10000; // HELMCoreLibrary has 4 significant digits after decimal point in atom coordinates
37
- // symbols for the corresponding monomers in HELM library
38
- const DEOXYRIBOSE = 'd';
39
- const RIBOSE = 'r';
40
- const PHOSPHATE = 'p';
41
- const OXYGEN = 'O';
42
- const HYDROGEN = 'H';
43
- // todo: verify that all functions have return types
44
- /* Convert Macromolecule column into Molecule column storing molfile V3000 with the help of a monomer library */
45
- export function _toAtomicLevel(df, macroMolCol, monomersLibList) {
46
- return __awaiter(this, void 0, void 0, function* () {
47
- if (DG.Func.find({ package: 'Chem', name: 'getRdKitModule' }).length === 0) {
48
- grok.shell.warning('Transformation to atomic level requires package "Chem" installed.');
49
- return;
50
- }
51
- if (macroMolCol.semType !== DG.SEMTYPE.MACROMOLECULE) {
52
- grok.shell.warning(`Only the ${DG.SEMTYPE.MACROMOLECULE} columns can be converted to atomic
53
- level, the chosen column has semType ${macroMolCol.semType}`);
54
- return;
55
- }
56
- // convert 'helm' to 'separator' units
57
- if (macroMolCol.getTag(DG.TAGS.UNITS) === "helm" /* NOTATION.HELM */) {
58
- const converter = new NotationConverter(macroMolCol);
59
- const separator = '/';
60
- macroMolCol = converter.convert("separator" /* NOTATION.SEPARATOR */, separator);
61
- }
62
- const alphabet = macroMolCol.getTag("alphabet" /* TAGS.alphabet */);
63
- // determine the polymer type according to HELM specifications
64
- let polymerType;
65
- // todo: an exception from dart comes before this check if the alphabet is UN
66
- if (alphabet === "PT" /* ALPHABET.PT */) {
67
- polymerType = "PEPTIDE" /* HELM_POLYMER_TYPE.PEPTIDE */;
68
- }
69
- else if (alphabet === "RNA" /* ALPHABET.RNA */ || alphabet === "DNA" /* ALPHABET.DNA */) {
70
- polymerType = "RNA" /* HELM_POLYMER_TYPE.RNA */;
71
- }
72
- else {
73
- grok.shell.warning(`Only PT, DNA and RNA alphabets are supported, while the selected column has ${polymerType} alphabet`);
74
- return;
75
- }
76
- const monomerSequencesArray = getMonomerSequencesArray(macroMolCol);
77
- // todo: consider separately backbone, terminal, branch monomer types
78
- const monomersDict = yield getMonomersDict(monomerSequencesArray, monomersLibList, polymerType, alphabet);
79
- const columnLength = macroMolCol.length;
80
- const reconstructed = new Array(columnLength);
81
- for (let row = 0; row < columnLength; ++row) {
82
- const monomerSeq = monomerSequencesArray[row];
83
- reconstructed[row] = monomerSeqToMolfile(monomerSeq, monomersDict, alphabet, polymerType);
84
- console.log(reconstructed[row]);
85
- }
86
- // exclude name collisions
87
- const name = 'molfile(' + macroMolCol.name + ')';
88
- const newColName = df.columns.getUnusedName(name);
89
- const newCol = DG.Column.fromStrings(newColName, reconstructed);
90
- newCol.semType = DG.SEMTYPE.MOLECULE;
91
- newCol.setTag(DG.TAGS.UNITS, DG.UNITS.Molecule.MOLBLOCK);
92
- df.columns.add(newCol, true);
93
- yield grok.data.detectSemanticTypes(df);
94
- });
95
- }
96
- /* Get a mapping of peptide symbols to HELM monomer library objects with
97
- * selectted fields */
98
- function getFormattedMonomerLib(monomersLibList, polymerType, alphabet) {
99
- const map = new Map();
100
- monomersLibList.forEach((it) => {
101
- if (it["polymerType" /* HELM_FIELDS.POLYMER_TYPE */] === polymerType) {
102
- if (polymerType === "RNA" /* HELM_POLYMER_TYPE.RNA */ &&
103
- (it["monomerType" /* HELM_FIELDS.MONOMER_TYPE */] === "Branch" /* HELM_MONOMER_TYPE.BRANCH */ ||
104
- alphabet === "DNA" /* ALPHABET.DNA */ && it["symbol" /* HELM_FIELDS.SYMBOL */] === DEOXYRIBOSE ||
105
- alphabet === "RNA" /* ALPHABET.RNA */ && it["symbol" /* HELM_FIELDS.SYMBOL */] === RIBOSE ||
106
- it["symbol" /* HELM_FIELDS.SYMBOL */] === PHOSPHATE) ||
107
- polymerType === "PEPTIDE" /* HELM_POLYMER_TYPE.PEPTIDE */ &&
108
- it["monomerType" /* HELM_FIELDS.MONOMER_TYPE */] !== "Branch" /* HELM_MONOMER_TYPE.BRANCH */) {
109
- const monomerObject = {};
110
- HELM_CORE_FIELDS.forEach((field) => {
111
- monomerObject[field] = it[field];
112
- });
113
- map.set(it["symbol" /* HELM_FIELDS.SYMBOL */], monomerObject);
114
- }
115
- }
116
- });
117
- return map;
118
- }
119
- /* Get jagged array of monomer symbols for the dataframe */
120
- function getMonomerSequencesArray(macroMolCol) {
121
- const columnLength = macroMolCol.length;
122
- const result = new Array(columnLength);
123
- // split the string into monomers
124
- const colUnits = macroMolCol.getTag(DG.TAGS.UNITS);
125
- const separator = macroMolCol.getTag("separator" /* TAGS.separator */);
126
- const splitterFunc = getSplitter(colUnits, separator);
127
- for (let row = 0; row < columnLength; ++row) {
128
- const macroMolecule = macroMolCol.get(row);
129
- // todo: handle the exception case when macroMolecule is null
130
- result[row] = macroMolecule ? splitterFunc(macroMolecule) : [];
131
- }
132
- return result;
133
- }
134
- /* Get a mapping of monomer symbols to MolGraph objects */
135
- function getMonomersDict(monomerSequencesArray, monomersLibList, polymerType, alphabet) {
136
- return __awaiter(this, void 0, void 0, function* () {
137
- // todo: exception - no gaps, no empty string monomers
138
- const formattedMonomerLib = getFormattedMonomerLib(monomersLibList, polymerType, alphabet);
139
- const monomersDict = new Map();
140
- const moduleRdkit = yield grok.functions.call('Chem:getRdKitModule');
141
- // add deoxyribose/ribose and phosphate for nucleotide sequences
142
- if (polymerType === "RNA" /* HELM_POLYMER_TYPE.RNA */) {
143
- const symbols = (alphabet === "RNA" /* ALPHABET.RNA */) ?
144
- [RIBOSE, PHOSPHATE] : [DEOXYRIBOSE, PHOSPHATE];
145
- for (const sym of symbols)
146
- updateMonomersDict(monomersDict, sym, formattedMonomerLib, moduleRdkit, polymerType);
147
- }
148
- for (let row = 0; row < monomerSequencesArray.length; ++row) {
149
- const monomerSeq = monomerSequencesArray[row];
150
- for (const sym of monomerSeq)
151
- updateMonomersDict(monomersDict, sym, formattedMonomerLib, moduleRdkit, polymerType);
152
- }
153
- // console.log(monomersDict);
154
- return monomersDict;
155
- });
156
- }
157
- /* Adds MolGraph object for 'sym' to the monomers dict when necessary */
158
- function updateMonomersDict(monomersDict, sym, formattedMonomerLib, moduleRdkit, polymerType) {
159
- if (!monomersDict.has(sym)) {
160
- const monomerData = getMolGraph(sym, formattedMonomerLib, moduleRdkit, polymerType);
161
- if (monomerData)
162
- monomersDict.set(sym, monomerData);
163
- else
164
- throw new Error(`Monomer with symbol '${sym}' is absent the monomer library`);
165
- // todo: handle exception
166
- }
167
- }
168
- /* Construct the MolGraph object for specified monomerSymbol: the associated
169
- * graph is adjusted in XY plane and filled with default R-groups */
170
- function getMolGraph(monomerSymbol, formattedMonomerLib, moduleRdkit, polymerType // todo: specify type for moduleRdkit
171
- ) {
172
- if (!formattedMonomerLib.has(monomerSymbol)) {
173
- return null;
174
- }
175
- else {
176
- const libObject = formattedMonomerLib.get(monomerSymbol);
177
- const capGroups = parseCapGroups(libObject["rgroups" /* HELM_FIELDS.RGROUPS */]);
178
- const capGroupIdxMap = parseCapGroupIdxMap(libObject["molfile" /* HELM_FIELDS.MOLFILE */]);
179
- const molfileV3K = convertMolfileToV3K(removeRGroupLines(libObject["molfile" /* HELM_FIELDS.MOLFILE */]), moduleRdkit);
180
- const counts = parseAtomAndBondCounts(molfileV3K);
181
- const atoms = parseAtomBlock(molfileV3K, counts.atomCount);
182
- const bonds = parseBondBlock(molfileV3K, counts.bondCount);
183
- const meta = getMonomerMetadata(atoms, bonds, capGroups, capGroupIdxMap);
184
- const monomerGraph = { atoms: atoms, bonds: bonds, meta: meta };
185
- if (polymerType === "PEPTIDE" /* HELM_POLYMER_TYPE.PEPTIDE */) {
186
- adjustPeptideMonomerGraph(monomerGraph);
187
- }
188
- else { // nucleotides
189
- if (monomerSymbol === RIBOSE || monomerSymbol === DEOXYRIBOSE)
190
- adjustSugarMonomerGraph(monomerGraph);
191
- else if (monomerSymbol === PHOSPHATE)
192
- adjustPhosphateMonomerGraph(monomerGraph);
193
- else
194
- adjustBaseMonomerGraph(monomerGraph);
195
- }
196
- // remove the 'rightmost' chain-extending r-group node in the backbone
197
- if (polymerType === "PEPTIDE" /* HELM_POLYMER_TYPE.PEPTIDE */) {
198
- setShifts(monomerGraph, polymerType);
199
- removeNodeAndBonds(monomerGraph, monomerGraph.meta.rNodes[1]);
200
- }
201
- else { // nucleotides
202
- if (monomerSymbol === RIBOSE || monomerSymbol === DEOXYRIBOSE) {
203
- // remove R2
204
- removeNodeAndBonds(monomerGraph, monomerGraph.meta.rNodes[1]);
205
- // set terminalNode2 (oxygen) as new R2
206
- monomerGraph.meta.rNodes[1] = monomerGraph.meta.terminalNodes[1];
207
- setTerminalNodes(monomerGraph.bonds, monomerGraph.meta); // set terminal nodes anew
208
- setShifts(monomerGraph, polymerType);
209
- // remove 'new' R2 (oxygen)
210
- removeNodeAndBonds(monomerGraph, monomerGraph.meta.rNodes[1]);
211
- // remove R1
212
- removeNodeAndBonds(monomerGraph, monomerGraph.meta.rNodes[0]);
213
- // remove the branching r-group
214
- removeNodeAndBonds(monomerGraph, monomerGraph.meta.rNodes[2]);
215
- }
216
- else if (monomerSymbol === PHOSPHATE) {
217
- monomerGraph.meta.terminalNodes[0] = monomerGraph.meta.rNodes[0];
218
- shiftCoordinates(monomerGraph, -monomerGraph.atoms.x[monomerGraph.meta.terminalNodes[0] - 1], -monomerGraph.atoms.y[monomerGraph.meta.terminalNodes[0] - 1]);
219
- setShifts(monomerGraph, polymerType);
220
- removeNodeAndBonds(monomerGraph, monomerGraph.meta.rNodes[1]);
221
- }
222
- else { // nucleobases
223
- removeNodeAndBonds(monomerGraph, monomerGraph.meta.rNodes[0]);
224
- }
225
- }
226
- removeHydrogen(monomerGraph);
227
- return monomerGraph;
228
- }
229
- }
230
- // todo: doc
231
- function getMonomerMetadata(atoms, bonds, capGroups, capGroupIdxMap) {
232
- const meta = {
233
- backboneShift: null,
234
- branchShift: null,
235
- terminalNodes: [],
236
- rNodes: [],
237
- };
238
- substituteCapGroups(atoms, capGroups, capGroupIdxMap);
239
- setRNodes(capGroupIdxMap, meta);
240
- setTerminalNodes(bonds, meta);
241
- return meta;
242
- }
243
- /* Parse element symbols for R-groups from the HELM monomer library R-groups
244
- * field */
245
- export function parseCapGroups(rGroupObjList) {
246
- // specifically for HELMCoreLibrary
247
- // considered only monoatomic rgroups
248
- // supposing that elements in rGroupObjList are sorted w.r.t. the rgroups idx
249
- // todo: possible generalizations
250
- const capGroupsArray = [];
251
- for (const obj of rGroupObjList) {
252
- let capGroup = obj["capGroupSmiles" /* RGROUP_FIELDS.CAP_GROUP_SMILES */];
253
- // in some cases the smiles field is written with uppercase
254
- if (!capGroup)
255
- capGroup = obj["capGroupSMILES" /* RGROUP_FIELDS.CAP_GROUP_SMILES_UPPERCASE */];
256
- // todo: verify that there are no multi-element cap groups, or consider how to
257
- // transform them
258
- capGroup = capGroup.replace(/(\[|\]|\*|:|\d)/g, '');
259
- if (capGroup.length > 1) // todo: check if such cases are possible, remove if not
260
- throw new Error('Default cap group has length more than one');
261
- capGroupsArray.push(capGroup);
262
- }
263
- return capGroupsArray;
264
- }
265
- /* Substitute the cap group elements instead of R# */
266
- function substituteCapGroups(atoms, capGroups, capGroupIdxMap) {
267
- for (const [node, capIdx] of capGroupIdxMap)
268
- atoms.atomTypes[node - 1] = capGroups[capIdx - 1]; // -1 because molfile indexing starts from 1
269
- }
270
- //todo: doc
271
- function setRNodes(capGroupIdxMap, meta) {
272
- meta.rNodes = Array.from(capGroupIdxMap.keys());
273
- for (let i = 0; i < meta.rNodes.length; i++) {
274
- for (const j of [1, 2]) { // 1 and 2 by def. correspond to 'left/rightmost' r-nodes
275
- // swap the values if necessary, so that the "leftmost" r-node is at 0,
276
- // and the 'rightmost', at 1
277
- if (capGroupIdxMap.get(meta.rNodes[i]) === j) {
278
- const tmp = meta.rNodes[j - 1];
279
- meta.rNodes[j - 1] = meta.rNodes[i];
280
- meta.rNodes[i] = tmp;
281
- }
282
- }
283
- }
284
- }
285
- //todo: doc
286
- function setTerminalNodes(bonds, meta) {
287
- const rNodes = meta.rNodes;
288
- meta.terminalNodes = new Array(rNodes.length).fill(0);
289
- const terminalNodes = meta.terminalNodes;
290
- const atomPairs = bonds.atomPairs;
291
- let i = 0;
292
- let j = 0;
293
- while ((i < atomPairs.length) && j < terminalNodes.length) {
294
- // rNodes array is sorted so that its 0th and 1st elements (if both
295
- // present) correspond to the chain extending (i.e. not branching) r-groups
296
- for (let k = 0; k < terminalNodes.length; ++k) {
297
- for (let l = 0; l < 2; ++l) {
298
- if (atomPairs[i][l] === rNodes[k]) {
299
- terminalNodes[k] = atomPairs[i][(l + 1) % 2];
300
- if (rNodes.length > 2) {
301
- }
302
- ++j;
303
- }
304
- }
305
- }
306
- ++i;
307
- }
308
- }
309
- //todo: doc
310
- function setShifts(molGraph, polymerType) {
311
- if (molGraph.meta.rNodes.length > 1) {
312
- molGraph.meta.backboneShift = [
313
- keepPrecision(molGraph.atoms.x[molGraph.meta.rNodes[1] - 1] -
314
- molGraph.atoms.x[molGraph.meta.terminalNodes[0] - 1]),
315
- keepPrecision(molGraph.atoms.y[molGraph.meta.rNodes[1] - 1] -
316
- molGraph.atoms.y[molGraph.meta.terminalNodes[0] - 1]),
317
- ];
318
- }
319
- if (polymerType === "RNA" /* HELM_POLYMER_TYPE.RNA */ && molGraph.meta.rNodes.length > 2) {
320
- molGraph.meta.branchShift = [
321
- keepPrecision(molGraph.atoms.x[molGraph.meta.rNodes[2] - 1] -
322
- molGraph.atoms.x[molGraph.meta.terminalNodes[0] - 1]),
323
- keepPrecision(molGraph.atoms.y[molGraph.meta.rNodes[2] - 1] -
324
- molGraph.atoms.y[molGraph.meta.terminalNodes[0] - 1]),
325
- ];
326
- }
327
- }
328
- /* Helper function necessary to build a correct V3000 molfile out of V2000 with
329
- * specified r-groups*/
330
- function removeRGroupLines(molfileV2K) {
331
- let begin = molfileV2K.indexOf(V2K_A_LINE, 0);
332
- if (begin === -1)
333
- begin = molfileV2K.indexOf(V2K_RGP_LINE);
334
- const end = molfileV2K.indexOf(V3K_END, begin);
335
- return molfileV2K.substring(0, begin) + molfileV2K.substring(end);
336
- }
337
- /* V2000 to V3000 converter */
338
- function convertMolfileToV3K(molfileV2K, moduleRdkit) {
339
- // todo: type of moduleRdkit
340
- // todo: consider the use of standard Chem converter (relies on creation of moduleRdkit on each iteration, though)
341
- const molObj = moduleRdkit.get_mol(molfileV2K);
342
- const molfileV3K = molObj.get_v3Kmolblock();
343
- molObj.delete();
344
- return molfileV3K;
345
- }
346
- /* Parse V3000 bond block and construct the Bonds object */
347
- function parseBondBlock(molfileV3K, bondCount) {
348
- // todo: consider the case when there is no simple leftmost/rightmost choice
349
- // todo: consider the case when there are multiple consequent M RGP lines,
350
- // like in HELMCoreLibrary nucleotides
351
- const bondTypes = new Array(bondCount);
352
- const atomPairs = new Array(bondCount);
353
- const bondConfiguration = new Map();
354
- const kwargs = new Map();
355
- let begin = molfileV3K.indexOf(V3K_BEGIN_BOND_BLOCK);
356
- begin = molfileV3K.indexOf('\n', begin);
357
- let end = begin;
358
- for (let i = 0; i < bondCount; ++i) {
359
- // parse bond type and atom pair
360
- const parsedValues = new Array(3);
361
- begin = molfileV3K.indexOf(V3K_BEGIN_DATA_LINE, end) + V3K_IDX_SHIFT;
362
- end = molfileV3K.indexOf(' ', begin);
363
- for (let k = 0; k < 3; ++k) {
364
- begin = end + 1;
365
- end = Math.min(molfileV3K.indexOf('\n', begin), molfileV3K.indexOf(' ', begin));
366
- parsedValues[k] = parseInt(molfileV3K.slice(begin, end));
367
- }
368
- bondTypes[i] = parsedValues[0];
369
- atomPairs[i] = parsedValues.slice(1);
370
- // parse keyword arguments
371
- const endOfLine = molfileV3K.indexOf('\n', begin);
372
- let lineRemainder = molfileV3K.slice(end, endOfLine);
373
- let beginCfg = lineRemainder.indexOf(V3K_BOND_CONFIG);
374
- if (beginCfg !== -1) {
375
- beginCfg = lineRemainder.indexOf('=', beginCfg) + 1;
376
- let endCfg = lineRemainder.indexOf(' ', beginCfg);
377
- if (endCfg === -1)
378
- endCfg = lineRemainder.length;
379
- const bondConfig = parseInt(lineRemainder.slice(beginCfg, endCfg));
380
- bondConfiguration.set(i, bondConfig);
381
- const removedSubstring = V3K_BOND_CONFIG + bondConfig.toString();
382
- lineRemainder = lineRemainder.replace(removedSubstring, '');
383
- }
384
- if (!lineRemainder)
385
- kwargs.set(i, lineRemainder);
386
- }
387
- return {
388
- bondTypes: bondTypes,
389
- atomPairs: atomPairs,
390
- bondConfiguration: bondConfiguration,
391
- kwargs: kwargs,
392
- };
393
- }
394
- /* Constructs mapping of r-group nodes to default capGroups, all numeration starting from 1.
395
- * According to https://pubs.acs.org/doi/10.1021/ci3001925, R1 and R2 are the chain extending attachment points,
396
- * while R3 is the branching attachment point. */
397
- function parseCapGroupIdxMap(molfileV2K) {
398
- const capGroupIdxMap = new Map();
399
- // parse A-lines (RNA)
400
- let begin = molfileV2K.indexOf(V2K_A_LINE, 0);
401
- let end = begin;
402
- while (begin !== -1) {
403
- // parse the rNode to which the cap group is attached
404
- end = molfileV2K.indexOf('\n', begin);
405
- const rNode = parseInt(molfileV2K.substring(begin, end).replace(/^A\s+/, ''));
406
- // parse the capGroup index
407
- begin = molfileV2K.indexOf('R', end);
408
- end = molfileV2K.indexOf('\n', begin);
409
- const capGroup = parseInt(molfileV2K.substring(begin, end).replace(/^R/, ''));
410
- capGroupIdxMap.set(rNode, capGroup);
411
- begin = molfileV2K.indexOf(V2K_A_LINE, end);
412
- }
413
- // parse RGP lines (may be more than one in RNA monomers)
414
- begin = molfileV2K.indexOf(V2K_RGP_LINE, 0);
415
- end = molfileV2K.indexOf('\n', begin);
416
- while (begin !== -1) {
417
- begin += V2K_RGP_SHIFT;
418
- end = molfileV2K.indexOf('\n', begin);
419
- const rgpStringParsed = molfileV2K.substring(begin, end)
420
- .replaceAll(/\s+/g, ' ')
421
- .split(' ');
422
- const rgpIndicesArray = rgpStringParsed.map((el) => parseInt(el))
423
- .slice(1); // slice from 1 because the 1st value is the number of pairs in the line
424
- for (let i = 0; i < rgpIndicesArray.length; i += 2) {
425
- // notice: there may be conflicting cap group definitions, like 3-O-Methylribose (2,5 connectivity)
426
- // (the last monomer in HELMCoreLibrary)
427
- // there the indices of cap groups are self-contradictory
428
- // todo: clarify why such situations occur in principle
429
- if (capGroupIdxMap.has(rgpIndicesArray[i]) && capGroupIdxMap.get(rgpIndicesArray[i]) !== rgpIndicesArray[i + 1])
430
- throw new Error(`r-group index ${rgpIndicesArray[i]} has already been added with a different value`);
431
- else
432
- capGroupIdxMap.set(rgpIndicesArray[i], rgpIndicesArray[i + 1]);
433
- }
434
- begin = molfileV2K.indexOf(V2K_RGP_LINE, end);
435
- }
436
- return capGroupIdxMap;
437
- }
438
- function parseAtomAndBondCounts(molfileV3K) {
439
- molfileV3K = molfileV3K.replaceAll('\r', ''); // to handle old and new sdf standards
440
- // parse atom count
441
- let begin = molfileV3K.indexOf(V3K_BEGIN_COUNTS_LINE) + V3K_COUNTS_SHIFT;
442
- let end = molfileV3K.indexOf(' ', begin);
443
- const numOfAtoms = parseInt(molfileV3K.substring(begin, end));
444
- // parse bond count
445
- begin = end + 1;
446
- end = molfileV3K.indexOf(' ', begin);
447
- const numOfBonds = parseInt(molfileV3K.substring(begin, end));
448
- return { atomCount: numOfAtoms, bondCount: numOfBonds };
449
- }
450
- /* Parse V3000 atom block and return Atoms object. NOTICE: only atomTypes, x, y
451
- * and kwargs fields are set in the return value, with other fields dummy */
452
- function parseAtomBlock(molfileV3K, atomCount) {
453
- const atomTypes = new Array(atomCount);
454
- const x = new Array(atomCount);
455
- const y = new Array(atomCount);
456
- const kwargs = new Array(atomCount);
457
- let begin = molfileV3K.indexOf(V3K_BEGIN_ATOM_BLOCK); // V3000 atoms block
458
- begin = molfileV3K.indexOf('\n', begin);
459
- let end = begin;
460
- for (let i = 0; i < atomCount; i++) {
461
- begin = molfileV3K.indexOf(V3K_BEGIN_DATA_LINE, begin) + V3K_IDX_SHIFT;
462
- end = molfileV3K.indexOf(' ', begin); // skip the idx row
463
- // parse atom type
464
- begin = end + 1;
465
- end = molfileV3K.indexOf(' ', begin);
466
- atomTypes[i] = molfileV3K.substring(begin, end);
467
- // parse X and Y coordinates of the atom
468
- const coordinate = new Array(2);
469
- for (let k = 0; k < 2; ++k) {
470
- begin = end + 1;
471
- end = molfileV3K.indexOf(' ', begin);
472
- coordinate[k] = parseFloat(molfileV3K.substring(begin, end));
473
- }
474
- x[i] = coordinate[0];
475
- y[i] = coordinate[1];
476
- // parse the remaining possible keyword arguments
477
- begin = end;
478
- end = molfileV3K.indexOf('\n', begin) + 1;
479
- kwargs[i] = molfileV3K.slice(begin, end);
480
- begin = end;
481
- }
482
- return {
483
- atomTypes: atomTypes,
484
- x: x,
485
- y: y,
486
- kwargs: kwargs,
487
- };
488
- }
489
- /* Remove hydrogen nodes */
490
- function removeHydrogen(monomerGraph) {
491
- let i = 0;
492
- while (i < monomerGraph.atoms.atomTypes.length) {
493
- if (monomerGraph.atoms.atomTypes[i] === HYDROGEN) {
494
- removeNodeAndBonds(monomerGraph, i + 1); // i + 1 because molfile node indexing starts from 1
495
- --i;
496
- // monomerGraph.atoms.atomTypes[i] = 'Li';
497
- }
498
- ++i;
499
- }
500
- }
501
- /* Remove node 'removedNode' and the associated bonds. Notice, numeration of
502
- * nodes in molfiles starts from 1, not 0 */
503
- function removeNodeAndBonds(monomerGraph, removedNode) {
504
- if (typeof removedNode !== 'undefined') {
505
- const removedNodeIdx = removedNode - 1;
506
- const atoms = monomerGraph.atoms;
507
- const bonds = monomerGraph.bonds;
508
- const meta = monomerGraph.meta;
509
- // remove the node from atoms
510
- atoms.atomTypes.splice(removedNodeIdx, 1);
511
- atoms.x.splice(removedNodeIdx, 1);
512
- atoms.y.splice(removedNodeIdx, 1);
513
- atoms.kwargs.splice(removedNodeIdx, 1);
514
- // update the values of terminal and r-group nodes if necessary
515
- for (let i = 0; i < meta.terminalNodes.length; ++i) {
516
- if (meta.terminalNodes[i] > removedNode)
517
- --meta.terminalNodes[i];
518
- else if (meta.terminalNodes[i] === removedNode)
519
- meta.terminalNodes[i] = -1; // sentinel to mark the value as removed
520
- }
521
- for (let i = 0; i < meta.rNodes.length; ++i) {
522
- if (meta.rNodes[i] > removedNode)
523
- --meta.rNodes[i];
524
- else if (meta.rNodes[i] === removedNode)
525
- meta.rNodes[i] = -1; // sentinel to mark the value as removed
526
- }
527
- // update indices of atoms in bonds
528
- let i = 0;
529
- while (i < bonds.atomPairs.length) {
530
- const firstAtom = bonds.atomPairs[i][0];
531
- const secondAtom = bonds.atomPairs[i][1];
532
- if (firstAtom === removedNode || secondAtom === removedNode) {
533
- bonds.atomPairs.splice(i, 1);
534
- bonds.bondTypes.splice(i, 1);
535
- if (bonds.bondConfiguration.has(i))
536
- bonds.bondConfiguration.delete(i);
537
- if (bonds.kwargs.has(i))
538
- bonds.kwargs.delete(i);
539
- --i;
540
- }
541
- else {
542
- bonds.atomPairs[i][0] = (firstAtom > removedNode) ? firstAtom - 1 : firstAtom;
543
- bonds.atomPairs[i][1] = (secondAtom > removedNode) ? secondAtom - 1 : secondAtom;
544
- }
545
- ++i;
546
- }
547
- // update bondConfiguration and kwargs keys
548
- let keys = Array.from(bonds.bondConfiguration.keys());
549
- keys.forEach((key) => {
550
- if (bonds.bondConfiguration.has(key) && key > removedNodeIdx) {
551
- const value = bonds.bondConfiguration.get(key);
552
- bonds.bondConfiguration.delete(key);
553
- bonds.bondConfiguration.set(key - 1, value);
554
- }
555
- });
556
- keys = Array.from(bonds.kwargs.keys());
557
- keys.forEach((key) => {
558
- if (bonds.kwargs.has(key) && key > removedNodeIdx) {
559
- const value = bonds.kwargs.get(key);
560
- bonds.kwargs.delete(key);
561
- bonds.kwargs.set(key - 1, value);
562
- }
563
- });
564
- }
565
- }
566
- // todo: rewrite description
567
- /* Adjust the (peptide) monomer graph so that it has standard form */
568
- function adjustPeptideMonomerGraph(monomer) {
569
- const nodeOneIdx = monomer.meta.terminalNodes[0] - 1; // node indexing in molfiles starts from 1
570
- const nodeTwoIdx = monomer.meta.rNodes[0] - 1;
571
- const x = monomer.atoms.x;
572
- const y = monomer.atoms.y;
573
- // place nodeOne at origin
574
- shiftCoordinates(monomer, -x[nodeOneIdx], -y[nodeOneIdx]);
575
- // angle is measured between OY and the rotated node
576
- const angle = findAngleWithOY(x[nodeTwoIdx], y[nodeTwoIdx]);
577
- // rotate the centered graph, so that 'nodeTwo' ends up on the positive ray of OY
578
- rotateCenteredGraph(monomer.atoms, -angle);
579
- if (x[monomer.meta.rNodes[1] - 1] < 0)
580
- flipMonomerAroundOY(monomer);
581
- const doubleBondedOxygen = findDoubleBondedCarbonylOxygen(monomer);
582
- // flip carboxyl and R if necessary
583
- flipCarboxylAndRadical(monomer, doubleBondedOxygen);
584
- // flip hydroxyl group with double-bound O inside carboxyl group if necessary
585
- flipHydroxilGroup(monomer, doubleBondedOxygen);
586
- }
587
- function adjustPhosphateMonomerGraph(monomer) {
588
- const nodeOneIdx = monomer.meta.terminalNodes[0] - 1; // node indexing in molfiles starts from 1
589
- const nodeTwoIdx = monomer.meta.rNodes[0] - 1;
590
- const x = monomer.atoms.x;
591
- const y = monomer.atoms.y;
592
- // place nodeOne at origin
593
- shiftCoordinates(monomer, -x[nodeOneIdx], -y[nodeOneIdx]);
594
- // // angle is measured between OY and the rotated node
595
- // const angle = findAngleWithOY(x[nodeTwoIdx], y[nodeTwoIdx]);
596
- // // rotate the centered graph, so that 'nodeTwo' ends up on the positive ray of OY
597
- // rotateCenteredGraph(monomer.atoms, -angle);
598
- // if (x[monomer.meta.rNodes[1] - 1] < 0)
599
- // flipMonomerAroundOY(monomer);
600
- // const doubleBondedOxygen = findDoubleBondedCarbonylOxygen(monomer);
601
- // // flip carboxyl and R if necessary
602
- // flipCarboxylAndRadical(monomer, doubleBondedOxygen);
603
- // // flip hydroxyl group with double-bound O inside carboxyl group if necessary
604
- // flipHydroxilGroup(monomer, doubleBondedOxygen);
605
- }
606
- function adjustSugarMonomerGraph(monomer) {
607
- const nodeOneIdx = monomer.meta.terminalNodes[0] - 1; // node indexing in molfiles starts from 1
608
- const nodeTwoIdx = monomer.meta.rNodes[0] - 1;
609
- const x = monomer.atoms.x;
610
- const y = monomer.atoms.y;
611
- // place nodeOne at origin
612
- shiftCoordinates(monomer, -x[nodeOneIdx], -y[nodeOneIdx]);
613
- // // angle is measured between OY and the rotated node
614
- // const angle = findAngleWithOY(x[nodeTwoIdx], y[nodeTwoIdx]);
615
- // // rotate the centered graph, so that 'nodeTwo' ends up on the positive ray of OY
616
- // rotateCenteredGraph(monomer.atoms, -angle);
617
- // if (x[monomer.meta.rNodes[1] - 1] < 0)
618
- // flipMonomerAroundOY(monomer);
619
- // const doubleBondedOxygen = findDoubleBondedCarbonylOxygen(monomer);
620
- // // flip carboxyl and R if necessary
621
- // flipCarboxylAndRadical(monomer, doubleBondedOxygen);
622
- // // flip hydroxyl group with double-bound O inside carboxyl group if necessary
623
- // flipHydroxilGroup(monomer, doubleBondedOxygen);
624
- }
625
- function adjustBaseMonomerGraph(monomer) {
626
- const nodeOneIdx = monomer.meta.terminalNodes[0] - 1; // node indexing in molfiles starts from 1
627
- const nodeTwoIdx = monomer.meta.rNodes[0] - 1;
628
- const x = monomer.atoms.x;
629
- const y = monomer.atoms.y;
630
- // place nodeOne at origin
631
- shiftCoordinates(monomer, -x[nodeOneIdx], -y[nodeOneIdx]);
632
- // // angle is measured between OY and the rotated node
633
- // const angle = findAngleWithOY(x[nodeTwoIdx], y[nodeTwoIdx]);
634
- // // rotate the centered graph, so that 'nodeTwo' ends up on the positive ray of OY
635
- // rotateCenteredGraph(monomer.atoms, -angle);
636
- // if (x[monomer.meta.rNodes[1] - 1] < 0)
637
- // flipMonomerAroundOY(monomer);
638
- // const doubleBondedOxygen = findDoubleBondedCarbonylOxygen(monomer);
639
- // // flip carboxyl and R if necessary
640
- // flipCarboxylAndRadical(monomer, doubleBondedOxygen);
641
- // // flip hydroxyl group with double-bound O inside carboxyl group if necessary
642
- // flipHydroxilGroup(monomer, doubleBondedOxygen);
643
- }
644
- /* Flip carboxyl group with the radical in a peptide monomer in case the
645
- * carboxyl group is in the lower half-plane */
646
- function flipCarboxylAndRadical(monomer, doubleBondedOxygen) {
647
- // verify that the carboxyl group is in the lower half-plane
648
- if (monomer.atoms.y[monomer.meta.rNodes[1] - 1] < 0 &&
649
- monomer.atoms.y[doubleBondedOxygen - 1] < 0) {
650
- flipMonomerAroundOX(monomer);
651
- rotateCenteredGraph(monomer.atoms, -findAngleWithOX(monomer.atoms.x[monomer.meta.terminalNodes[1] - 1], monomer.atoms.y[monomer.meta.terminalNodes[1] - 1]));
652
- }
653
- }
654
- /* Finds angle between OY and the ray joining origin with (x, y) */
655
- function findAngleWithOY(x, y) {
656
- let angle;
657
- if (x === 0) {
658
- angle = y > 0 ? 0 : Math.PI;
659
- }
660
- else if (y === 0) {
661
- angle = x > 0 ? -Math.PI / 2 : Math.PI / 2;
662
- }
663
- else {
664
- const tan = y / x;
665
- const atan = Math.atan(tan);
666
- angle = (x < 0) ? Math.PI / 2 + atan : -Math.PI / 2 + atan;
667
- }
668
- return angle;
669
- }
670
- /* Finds angle between OX and the ray joining origin with (x, y) */
671
- function findAngleWithOX(x, y) {
672
- return findAngleWithOY(x, y) + Math.PI / 2;
673
- }
674
- /* Rotate the graph around the origin by 'angle' */
675
- function rotateCenteredGraph(atoms, angle) {
676
- if (angle !== 0) {
677
- const x = atoms.x;
678
- const y = atoms.y;
679
- const cos = Math.cos(angle);
680
- const sin = Math.sin(angle);
681
- for (let i = 0; i < x.length; ++i) {
682
- const tmp = x[i];
683
- x[i] = keepPrecision(tmp * cos - y[i] * sin);
684
- y[i] = keepPrecision(tmp * sin + y[i] * cos);
685
- }
686
- }
687
- }
688
- /* Flip monomer graph around OX axis preserving stereometry */
689
- function flipMonomerAroundOX(monomer) {
690
- flipMolGraph(monomer, true);
691
- }
692
- /* Flip monomer graph around OY axis preserving stereometry */
693
- function flipMonomerAroundOY(monomer) {
694
- flipMolGraph(monomer, false);
695
- }
696
- /* Flip graph around a specified axis: 'true' corresponds to OX, 'false' to OY */
697
- function flipMolGraph(molGraph, axis) {
698
- if (axis) { // flipping around OX
699
- const y = molGraph.atoms.y;
700
- for (let i = 0; i < y.length; i++)
701
- y[i] = -y[i];
702
- }
703
- else { // flipping around OY
704
- const x = molGraph.atoms.x;
705
- for (let i = 0; i < x.length; i++)
706
- x[i] = -x[i];
707
- }
708
- // preserve the stereometry
709
- const orientation = molGraph.bonds.bondConfiguration;
710
- for (const [key, value] of orientation) {
711
- const newValue = value === 1 ? 3 : 1;
712
- orientation.set(key, newValue);
713
- }
714
- }
715
- /* Flips double-bonded 'O' in carbonyl group with 'OH' in order for the monomers
716
- * to have standard representation simplifying their concatenation. The
717
- * monomer must already be adjusted with adjustPeptideMonomerGraph in order for this function to be implemented */
718
- function flipHydroxilGroup(monomer, doubleBondedOxygen) {
719
- const x = monomer.atoms.x;
720
- // -1 below because indexing of nodes in molfiles starts from 1, unlike arrays
721
- if (x[monomer.meta.rNodes[1] - 1] > x[doubleBondedOxygen - 1])
722
- swapNodes(monomer, doubleBondedOxygen, monomer.meta.rNodes[1]);
723
- }
724
- /* Determine the number of node (starting from 1) corresponding to the
725
- * double-bonded oxygen of the carbonyl group */
726
- function findDoubleBondedCarbonylOxygen(monomer) {
727
- const bondsMap = constructBondsMap(monomer);
728
- let doubleBondedOxygen = 0;
729
- let i = 0;
730
- // iterate over the nodes bonded to the carbon and find the double one
731
- while (doubleBondedOxygen === 0) {
732
- const node = bondsMap.get(monomer.meta.terminalNodes[1])[i];
733
- if (monomer.atoms.atomTypes[node - 1] === OXYGEN && node !== monomer.meta.rNodes[1])
734
- doubleBondedOxygen = node;
735
- i++;
736
- }
737
- return doubleBondedOxygen;
738
- }
739
- /* Swap the Cartesian coordinates of the two specified nodes in MolGraph */
740
- function swapNodes(monomer, nodeOne, nodeTwo) {
741
- const nodeOneIdx = nodeOne - 1;
742
- const nodeTwoIdx = nodeTwo - 1;
743
- const x = monomer.atoms.x;
744
- const y = monomer.atoms.y;
745
- const tmpX = x[nodeOneIdx];
746
- const tmpY = y[nodeOneIdx];
747
- x[nodeOneIdx] = x[nodeTwoIdx];
748
- y[nodeOneIdx] = y[nodeTwoIdx];
749
- x[nodeTwoIdx] = tmpX;
750
- y[nodeTwoIdx] = tmpY;
751
- }
752
- // todo: doc
753
- function constructBondsMap(monomer) {
754
- var _a;
755
- const map = new Map();
756
- for (const atomPairs of monomer.bonds.atomPairs) {
757
- for (let i = 0; i < 2; i++) {
758
- const key = atomPairs[i];
759
- const value = atomPairs[(i + 1) % 2];
760
- if (map.has(key))
761
- (_a = map.get(key)) === null || _a === void 0 ? void 0 : _a.push(value);
762
- else
763
- map.set(key, new Array(1).fill(value));
764
- }
765
- }
766
- return map;
767
- }
768
- /* Shift molGraph in the XOY plane */
769
- function shiftCoordinates(molGraph, xShift, yShift) {
770
- const x = molGraph.atoms.x;
771
- const y = molGraph.atoms.y;
772
- for (let i = 0; i < x.length; ++i) {
773
- x[i] = keepPrecision(x[i] + xShift);
774
- if (typeof yShift !== 'undefined')
775
- y[i] = keepPrecision(y[i] + yShift);
776
- }
777
- }
778
- /* Translate a sequence of monomer symbols into Molfile V3000 */
779
- function monomerSeqToMolfile(monomerSeq, monomersDict, alphabet, polymerType) {
780
- // todo: handle the case when the polymer is empty
781
- if (monomerSeq.length === 0)
782
- throw new Error('monomerSeq is empty');
783
- // define atom and bond counts, taking into account the bond type
784
- const { atomCount, bondCount } = getResultingAtomBondCounts(monomerSeq, monomersDict, alphabet, polymerType);
785
- // create arrays to store lines of the resulting molfile
786
- const molfileAtomBlock = new Array(atomCount);
787
- const molfileBondBlock = new Array(bondCount);
788
- let addMonomerToMolblock;
789
- let capMolblock;
790
- let nodeShiftInitValue;
791
- let bondShiftInitValue;
792
- let sugar = null;
793
- let phosphate = null;
794
- if (polymerType === "PEPTIDE" /* HELM_POLYMER_TYPE.PEPTIDE */) {
795
- addMonomerToMolblock = addAminoAcidToMolblock;
796
- capMolblock = capPeptideMolblock;
797
- nodeShiftInitValue = bondShiftInitValue = 0;
798
- }
799
- else { // nucleotides
800
- addMonomerToMolblock = addNucleotideToMolblock;
801
- capMolblock = capPeptideMolblock; // todo: cleanup & refactor
802
- nodeShiftInitValue = 0;
803
- bondShiftInitValue = 0;
804
- sugar = (alphabet === "DNA" /* ALPHABET.DNA */) ? monomersDict.get(DEOXYRIBOSE) : monomersDict.get(RIBOSE);
805
- phosphate = monomersDict.get(PHOSPHATE);
806
- }
807
- const v = {
808
- i: 0,
809
- nodeShift: nodeShiftInitValue,
810
- bondShift: bondShiftInitValue,
811
- backbonePositionShift: new Array(2).fill(0),
812
- branchPositionShift: new Array(2).fill(0),
813
- backboneAttachNode: 0,
814
- branchAttachNode: 0,
815
- flipFactor: 1,
816
- };
817
- const C = {
818
- sugar: sugar,
819
- phosphate: phosphate,
820
- seqLength: monomerSeq.length,
821
- atomCount: atomCount,
822
- bondCount: bondCount,
823
- };
824
- for (v.i = 0; v.i < C.seqLength; ++v.i) {
825
- const monomer = monomersDict.get(monomerSeq[v.i]);
826
- addMonomerToMolblock(monomer, molfileAtomBlock, molfileBondBlock, v, C);
827
- }
828
- capMolblock(molfileAtomBlock, molfileBondBlock, v, C);
829
- const molfileCountsLine = V3K_BEGIN_COUNTS_LINE + atomCount + ' ' + bondCount + V3K_COUNTS_LINE_ENDING;
830
- // todo: optimize concatenation using Alexander's hint
831
- const molfileParts = [
832
- V3K_HEADER_FIRST_LINE,
833
- V3K_HEADER_SECOND_LINE,
834
- V3K_BEGIN_CTAB_BLOCK,
835
- molfileCountsLine,
836
- V3K_BEGIN_ATOM_BLOCK,
837
- molfileAtomBlock.join(''),
838
- V3K_END_ATOM_BLOCK,
839
- V3K_BEGIN_BOND_BLOCK,
840
- molfileBondBlock.join(''),
841
- V3K_END_BOND_BLOCK,
842
- V3K_END_CTAB_BLOCK,
843
- V3K_END,
844
- ];
845
- return molfileParts.join('');
846
- }
847
- // todo: doc
848
- function capPeptideMolblock(molfileAtomBlock, molfileBondBlock, v, C) {
849
- // add terminal oxygen
850
- const atomIdx = v.nodeShift + 1;
851
- molfileAtomBlock[C.atomCount] = V3K_BEGIN_DATA_LINE + atomIdx + ' ' +
852
- OXYGEN + ' ' + keepPrecision(v.backbonePositionShift[0]) + ' ' +
853
- v.flipFactor * keepPrecision(v.backbonePositionShift[1]) + ' ' + '0.000000 0' + '\n';
854
- // add terminal bond
855
- const firstAtom = v.backboneAttachNode;
856
- const secondAtom = atomIdx;
857
- molfileBondBlock[C.bondCount] = V3K_BEGIN_DATA_LINE + v.bondShift + ' ' +
858
- 1 + ' ' + firstAtom + ' ' + secondAtom + '\n';
859
- }
860
- // todo: doc
861
- function addAminoAcidToMolblock(monomer, molfileAtomBlock, molfileBondBlock, v, C) {
862
- v.flipFactor = Math.pow((-1), (v.i % 2)); // to flip every even monomer over OX
863
- addBackboneMonomerToMolblock(monomer, molfileAtomBlock, molfileBondBlock, v, C);
864
- }
865
- function addBackboneMonomerToMolblock(monomer, molfileAtomBlock, molfileBondBlock, v, C) {
866
- // todo: remove these comments to the docstrings of the corr. functions
867
- // construnct the lines of V3K molfile atom block
868
- fillAtomLines(monomer, molfileAtomBlock, v);
869
- // construct the lines of V3K molfile bond block
870
- fillBondLines(monomer, molfileBondBlock, v);
871
- // peptide bond
872
- fillChainExtendingBond(monomer, molfileBondBlock, v);
873
- // update branch variables if necessary
874
- if (monomer.meta.branchShift !== null && monomer.meta.terminalNodes.length > 2)
875
- updateBranchVariables(monomer, v);
876
- // update loop variables
877
- updateChainExtendingVariables(monomer, v, C);
878
- }
879
- // todo: doc
880
- function addNucleotideToMolblock(nucleobase, molfileAtomBlock, molfileBondBlock, v, C) {
881
- // construnct the lines of V3K molfile atom block corresponding to phosphate
882
- // and sugar
883
- for (const monomer of [C.phosphate, C.sugar])
884
- addBackboneMonomerToMolblock(monomer, molfileAtomBlock, molfileBondBlock, v, C);
885
- addBranchMonomerToMolblock(nucleobase, molfileAtomBlock, molfileBondBlock, v, C);
886
- }
887
- function addBranchMonomerToMolblock(monomer, molfileAtomBlock, molfileBondBlock, v, C) {
888
- fillBranchAtomLines(monomer, molfileAtomBlock, v);
889
- fillBondLines(monomer, molfileBondBlock, v);
890
- fillBackboneToBranchBond(monomer, molfileBondBlock, v);
891
- // C-N bond
892
- const bondIdx = v.bondShift;
893
- const firstAtom = v.branchAttachNode;
894
- const secondAtom = monomer.meta.terminalNodes[0] + v.nodeShift;
895
- molfileBondBlock[bondIdx - 1] = V3K_BEGIN_DATA_LINE + bondIdx + ' ' +
896
- 1 + ' ' + firstAtom + ' ' + secondAtom + '\n';
897
- // update loop variables
898
- v.bondShift += monomer.bonds.atomPairs.length + 1;
899
- v.nodeShift += monomer.atoms.atomTypes.length;
900
- }
901
- function updateChainExtendingVariables(monomer, v, C) {
902
- v.backboneAttachNode = v.nodeShift + monomer.meta.terminalNodes[1];
903
- v.bondShift += monomer.bonds.atomPairs.length + 1;
904
- v.nodeShift += monomer.atoms.atomTypes.length;
905
- v.backbonePositionShift[0] += monomer.meta.backboneShift[0]; // todo: non-null check
906
- v.backbonePositionShift[1] += v.flipFactor * monomer.meta.backboneShift[1];
907
- }
908
- function updateBranchVariables(monomer, v) {
909
- v.branchAttachNode = v.nodeShift + monomer.meta.terminalNodes[2];
910
- for (let i = 0; i < 2; ++i)
911
- v.branchPositionShift[i] = v.backbonePositionShift[i] + monomer.meta.branchShift[i];
912
- }
913
- function fillAtomLines(monomer, molfileAtomBlock, v) {
914
- for (let j = 0; j < monomer.atoms.atomTypes.length; ++j) {
915
- const atomIdx = v.nodeShift + j + 1;
916
- molfileAtomBlock[v.nodeShift + j] = V3K_BEGIN_DATA_LINE + atomIdx + ' ' +
917
- monomer.atoms.atomTypes[j] + ' ' +
918
- keepPrecision(v.backbonePositionShift[0] + monomer.atoms.x[j]) + ' ' +
919
- keepPrecision(v.backbonePositionShift[1] + v.flipFactor * monomer.atoms.y[j]) +
920
- ' ' + monomer.atoms.kwargs[j];
921
- }
922
- }
923
- // todo: remove as quickfix
924
- function fillBranchAtomLines(monomer, molfileAtomBlock, v) {
925
- for (let j = 0; j < monomer.atoms.atomTypes.length; ++j) {
926
- const atomIdx = v.nodeShift + j + 1;
927
- molfileAtomBlock[v.nodeShift + j] = V3K_BEGIN_DATA_LINE + atomIdx + ' ' +
928
- monomer.atoms.atomTypes[j] + ' ' +
929
- keepPrecision(v.branchPositionShift[0] + monomer.atoms.x[j]) + ' ' +
930
- keepPrecision(v.branchPositionShift[1] + v.flipFactor * monomer.atoms.y[j]) +
931
- ' ' + monomer.atoms.kwargs[j];
932
- }
933
- }
934
- function fillBondLines(monomer, molfileBondBlock, v) {
935
- // construct the lines of V3K molfile bond block
936
- for (let j = 0; j < monomer.bonds.atomPairs.length; ++j) {
937
- const bondIdx = v.bondShift + j + 1;
938
- const firstAtom = monomer.bonds.atomPairs[j][0] + v.nodeShift;
939
- const secondAtom = monomer.bonds.atomPairs[j][1] + v.nodeShift;
940
- let bondCfg = '';
941
- if (monomer.bonds.bondConfiguration.has(j)) {
942
- // flip orientation when necessary
943
- let orientation = monomer.bonds.bondConfiguration.get(j);
944
- if (v.flipFactor < 0)
945
- orientation = (orientation === 1) ? 3 : 1;
946
- bondCfg = ' CFG=' + orientation;
947
- }
948
- const kwargs = monomer.bonds.kwargs.has(j) ?
949
- ' ' + monomer.bonds.kwargs.get(j) : '';
950
- molfileBondBlock[v.bondShift + j] = V3K_BEGIN_DATA_LINE + bondIdx + ' ' +
951
- monomer.bonds.bondTypes[j] + ' ' +
952
- firstAtom + ' ' + secondAtom + bondCfg + kwargs + '\n';
953
- }
954
- }
955
- function fillChainExtendingBond(monomer, molfileBondBlock, v) {
956
- if (v.backboneAttachNode !== 0) {
957
- const bondIdx = v.bondShift;
958
- const firstAtom = v.backboneAttachNode;
959
- const secondAtom = monomer.meta.terminalNodes[0] + v.nodeShift;
960
- molfileBondBlock[v.bondShift - 1] = V3K_BEGIN_DATA_LINE + bondIdx + ' ' +
961
- 1 + ' ' + firstAtom + ' ' + secondAtom + '\n';
962
- }
963
- }
964
- // todo: remove
965
- function fillBackboneToBranchBond(branchMonomer, molfileBondBlock, v) {
966
- const bondIdx = v.bondShift;
967
- const firstAtom = v.branchAttachNode;
968
- const secondAtom = branchMonomer.meta.terminalNodes[0] + v.nodeShift;
969
- molfileBondBlock[bondIdx - 1] = V3K_BEGIN_DATA_LINE + bondIdx + ' ' +
970
- 1 + ' ' + firstAtom + ' ' + secondAtom + '\n';
971
- }
972
- /* Compute the atom/bond counts for the resulting molfile, depending on the
973
- * type of polymer (peptide/nucleotide) */
974
- function getResultingAtomBondCounts(monomerSeq, monomersDict, alphabet, polymerType) {
975
- let atomCount = 0;
976
- let bondCount = 0;
977
- // sum up all the atoms/nodes provided by the sequence
978
- for (const monomerSymbol of monomerSeq) {
979
- const monomer = monomersDict.get(monomerSymbol);
980
- atomCount += monomer.atoms.x.length;
981
- bondCount += monomer.bonds.bondTypes.length;
982
- }
983
- // add extra values depending on the polymer type
984
- if (polymerType === "PEPTIDE" /* HELM_POLYMER_TYPE.PEPTIDE */) {
985
- // add the rightmost/terminating cap group 'OH' (i.e. 'O')
986
- atomCount += 1;
987
- // add chain-extending bonds (C-NH per each monomer pair and terminal C-OH)
988
- bondCount += monomerSeq.length;
989
- }
990
- else { // nucleotides
991
- const sugar = (alphabet === "DNA" /* ALPHABET.DNA */) ?
992
- monomersDict.get(DEOXYRIBOSE) : monomersDict.get(RIBOSE);
993
- const phosphate = monomersDict.get(PHOSPHATE);
994
- // add phosphate and sugar per each nucleobase symbol
995
- atomCount += monomerSeq.length * (phosphate.atoms.x.length + sugar.atoms.x.length);
996
- // add the leftmost cap group 'OH' (i.e. 'O') to the first phosphate
997
- atomCount += 1;
998
- // add bonds from phosphate and sugar
999
- bondCount += monomerSeq.length * (phosphate.bonds.bondTypes.length + sugar.bonds.bondTypes.length);
1000
- // add chain-extending and branch bonds (O-P, C-O and C-N per each nucleotide)
1001
- bondCount += monomerSeq.length * 3;
1002
- }
1003
- return { atomCount, bondCount };
1004
- }
1005
- /* Keep precision upon floating point operations over atom coordinates */
1006
- function keepPrecision(x) {
1007
- return Math.round(PRECISION_FACTOR * x) / PRECISION_FACTOR;
1008
- }
1009
- function convertMolGraphToMolfileV3K(molGraph) {
1010
- // counts line
1011
- const atomType = molGraph.atoms.atomTypes;
1012
- const x = molGraph.atoms.x;
1013
- const y = molGraph.atoms.y;
1014
- const atomKwargs = molGraph.atoms.kwargs;
1015
- const bondType = molGraph.bonds.bondTypes;
1016
- const atomPair = molGraph.bonds.atomPairs;
1017
- const bondKwargs = molGraph.bonds.kwargs;
1018
- const bondConfig = molGraph.bonds.bondConfiguration;
1019
- const atomCount = atomType.length;
1020
- const bondCount = molGraph.bonds.bondTypes.length;
1021
- // todo rewrite using constants
1022
- const molfileCountsLine = V3K_BEGIN_COUNTS_LINE + atomCount + ' ' + bondCount + V3K_COUNTS_LINE_ENDING;
1023
- // atom block
1024
- let molfileAtomBlock = '';
1025
- for (let i = 0; i < atomCount; ++i) {
1026
- const atomIdx = i + 1;
1027
- const coordinate = [x[i].toString(), y[i].toString()];
1028
- // format coordinates so that they have 6 digits after decimal point
1029
- // for (let k = 0; k < 2; ++k) {
1030
- // const formatted = coordinate[k].toString().split('.');
1031
- // if (formatted.length === 1)
1032
- // formatted.push('0');
1033
- // formatted[1] = formatted[1].padEnd(V3K_ATOM_COORDINATE_PRECISION, '0');
1034
- // coordinate[k] = formatted.join('.');
1035
- // }
1036
- const atomLine = V3K_BEGIN_DATA_LINE + atomIdx + ' ' + atomType[i] + ' ' +
1037
- coordinate[0] + ' ' + coordinate[1] + ' ' + atomKwargs[i];
1038
- molfileAtomBlock += atomLine;
1039
- }
1040
- // bond block
1041
- let molfileBondBlock = '';
1042
- for (let i = 0; i < bondCount; ++i) {
1043
- const bondIdx = i + 1;
1044
- const firstAtom = atomPair[i][0];
1045
- const secondAtom = atomPair[i][1];
1046
- const kwargs = bondKwargs.has(i) ? ' ' + bondKwargs.get(i) : '';
1047
- const bondCfg = bondConfig.has(i) ? ' CFG=' + bondConfig.get(i) : '';
1048
- const bondLine = V3K_BEGIN_DATA_LINE + bondIdx + ' ' + bondType[i] + ' ' +
1049
- firstAtom + ' ' + secondAtom + bondCfg + kwargs + '\n';
1050
- molfileBondBlock += bondLine;
1051
- }
1052
- const molfileParts = [
1053
- V3K_HEADER_FIRST_LINE,
1054
- V3K_HEADER_SECOND_LINE,
1055
- V3K_BEGIN_CTAB_BLOCK,
1056
- molfileCountsLine,
1057
- V3K_BEGIN_ATOM_BLOCK,
1058
- molfileAtomBlock,
1059
- V3K_END_ATOM_BLOCK,
1060
- V3K_BEGIN_BOND_BLOCK,
1061
- molfileBondBlock,
1062
- V3K_END_BOND_BLOCK,
1063
- V3K_END_CTAB_BLOCK,
1064
- V3K_END,
1065
- ];
1066
- const resultingMolfile = molfileParts.join('');
1067
- // console.log(resultingMolfile);
1068
- return resultingMolfile;
1069
- }
1070
- export function getSymbolToCappedMolfileMap(monomersLibList) {
1071
- return __awaiter(this, void 0, void 0, function* () {
1072
- if (DG.Func.find({ package: 'Chem', name: 'getRdKitModule' }).length === 0) {
1073
- grok.shell.warning('Transformation to atomic level requires package "Chem" installed.');
1074
- return;
1075
- }
1076
- const symbolToCappedMolfileMap = new Map();
1077
- const moduleRdkit = yield grok.functions.call('Chem:getRdKitModule');
1078
- for (const monomerLibObject of monomersLibList) {
1079
- const monomerSymbol = monomerLibObject["symbol" /* HELM_FIELDS.SYMBOL */];
1080
- const capGroups = parseCapGroups(monomerLibObject["rgroups" /* HELM_FIELDS.RGROUPS */]);
1081
- const capGroupIdxMap = parseCapGroupIdxMap(monomerLibObject["molfile" /* HELM_FIELDS.MOLFILE */]);
1082
- const molfileV3K = convertMolfileToV3K(removeRGroupLines(monomerLibObject["molfile" /* HELM_FIELDS.MOLFILE */]), moduleRdkit);
1083
- const counts = parseAtomAndBondCounts(molfileV3K);
1084
- const atoms = parseAtomBlock(molfileV3K, counts.atomCount);
1085
- const bonds = parseBondBlock(molfileV3K, counts.bondCount);
1086
- const meta = getMonomerMetadata(atoms, bonds, capGroups, capGroupIdxMap);
1087
- const monomerGraph = { atoms: atoms, bonds: bonds, meta: meta };
1088
- removeHydrogen(monomerGraph);
1089
- const molfile = convertMolGraphToMolfileV3K(monomerGraph);
1090
- symbolToCappedMolfileMap.set(monomerSymbol, molfile);
1091
- }
1092
- return symbolToCappedMolfileMap;
1093
- });
1094
- }
1095
- /* Get the V3K molfile corresponding to the capped Monomer (default cap groups) */
1096
- export function capPeptideMonomer(monomer) {
1097
- const funcList = DG.Func.find({ package: 'Chem', name: 'getRdKitModule' });
1098
- const moduleRdkit = funcList[0].apply();
1099
- const capGroups = parseCapGroups(monomer["rgroups" /* HELM_FIELDS.RGROUPS */]);
1100
- const capGroupIdxMap = parseCapGroupIdxMap(monomer["molfile" /* HELM_FIELDS.MOLFILE */]);
1101
- const molfileV3K = convertMolfileToV3K(removeRGroupLines(monomer["molfile" /* HELM_FIELDS.MOLFILE */]), moduleRdkit);
1102
- const counts = parseAtomAndBondCounts(molfileV3K);
1103
- const atoms = parseAtomBlock(molfileV3K, counts.atomCount);
1104
- const bonds = parseBondBlock(molfileV3K, counts.bondCount);
1105
- const meta = getMonomerMetadata(atoms, bonds, capGroups, capGroupIdxMap);
1106
- const monomerGraph = { atoms: atoms, bonds: bonds, meta: meta };
1107
- adjustPeptideMonomerGraph(monomerGraph);
1108
- const molfile = convertMolGraphToMolfileV3K(monomerGraph);
1109
- return molfile;
1110
- }
1111
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG8tYXRvbWljLWxldmVsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidG8tYXRvbWljLWxldmVsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLHlGQUF5RjtBQUN6RixPQUFPLEtBQUssSUFBSSxNQUFNLG1CQUFtQixDQUFDO0FBQzFDLE9BQU8sS0FBSyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDdEMsT0FBTyxFQUFjLGdCQUFnQixFQUFzRCxNQUFNLFNBQVMsQ0FBQztBQUMzRyxPQUFPLEVBQVcsV0FBVyxFQUErQixNQUFNLGlCQUFpQixDQUFDO0FBRXBGLE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLHNCQUFzQixDQUFDO0FBR3ZELHNDQUFzQztBQUN0QyxNQUFNLGFBQWEsR0FBRyxDQUFDLENBQUM7QUFDeEIsTUFBTSxZQUFZLEdBQUcsUUFBUSxDQUFDO0FBQzlCLE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQztBQUV6Qix3REFBd0Q7QUFDeEQsTUFBTSxnQkFBZ0IsR0FBRyxFQUFFLENBQUM7QUFDNUIsTUFBTSxhQUFhLEdBQUcsQ0FBQyxDQUFDO0FBQ3hCLE1BQU0scUJBQXFCLEdBQUcsc0NBQXNDLENBQUM7QUFDckUsTUFBTSxzQkFBc0IsR0FBRywyQ0FBMkMsQ0FBQztBQUMzRSxNQUFNLG9CQUFvQixHQUFHLHFCQUFxQixDQUFDO0FBQ25ELE1BQU0sa0JBQWtCLEdBQUcsbUJBQW1CLENBQUM7QUFDL0MsTUFBTSxxQkFBcUIsR0FBRyxnQkFBZ0IsQ0FBQztBQUMvQyxNQUFNLHNCQUFzQixHQUFHLFVBQVUsQ0FBQztBQUMxQyxNQUFNLG9CQUFvQixHQUFHLHFCQUFxQixDQUFDO0FBQ25ELE1BQU0sa0JBQWtCLEdBQUcsbUJBQW1CLENBQUM7QUFDL0MsTUFBTSxvQkFBb0IsR0FBRyxxQkFBcUIsQ0FBQztBQUNuRCxNQUFNLGtCQUFrQixHQUFHLG1CQUFtQixDQUFDO0FBQy9DLE1BQU0sZUFBZSxHQUFHLE9BQU8s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Q0w7QUFDSCxDQUFDO0FBRUQsV0FBVztBQUNYLFNBQVMsU0FBUyxDQUFDLFFBQWtCLEVBQUUsV0FBOEI7SUFDbkUsSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1FBQ25DLFFBQVEsQ0FBQyxJQUFJLENBQUMsYUFBYSxHQUFHO1lBQzVCLGFBQWEsQ0FDWCxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQzdDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUNyRDtZQUNELGFBQWEsQ0FDWCxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQzdDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUNyRDtTQUNGLENBQUM7S0FDSDtJQUVELElBQUksV0FBVyxzQ0FBMEIsSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1FBQzVFLFFBQVEsQ0FBQyxJQUFJLENBQUMsV0FBVyxHQUFHO1lBQzFCLGFBQWEsQ0FDWCxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQzdDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUNyRDtZQUNELGFBQWEsQ0FDWCxRQUFR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QUFLLENBQUMsRUFBRTtRQUNsQixLQUFLLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7S0FDNUM7U0FBTTtRQUNMLE1BQU0sR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDbEIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM1QixLQUFLLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUM7S0FDNUQ7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRCxtRUFBbUU7QUFDbkUsU0FBUyxlQUFlLENBQUMsQ0FBUyxFQUFFLENBQVM7SUFDM0MsT0FBTyxlQUFlLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBQzdDLENBQUM7QUFFRCxvREFBb0Q7QUFDcEQsU0FBUyxtQkFBbUIsQ0FBQyxLQUFZLEVBQUUsS0FBYTtJQUN0RCxJQUFJLEtBQUssS0FBSyxDQUFDLEVBQUU7UUFDZixNQUFNLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ2xCLE1BQU0sQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFFbEIsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM1QixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTVCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxF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dCBsaW5lcyB0byBtYXRjaCBleHRlcm5hbCBtb2R1bGVzIGluIHdlYnBhY2sgY29uZmlndXJhdGlvbiAqL1xuaW1wb3J0ICogYXMgZ3JvayBmcm9tICdkYXRhZ3Jvay1hcGkvZ3Jvayc7XG5pbXBvcnQgKiBhcyBERyBmcm9tICdkYXRhZ3Jvay1hcGkvZGcnO1xuaW1wb3J0IHtIRUxNX0ZJRUxEUywgSEVMTV9DT1JFX0ZJRUxEUywgSEVMTV9QT0xZTUVSX1RZUEUsIEhFTE1fTU9OT01FUl9UWVBFLCBSR1JPVVBfRklFTERTfSBmcm9tICcuL2NvbnN0JztcbmltcG9ydCB7QUxQSEFCRVQsIGdldFNwbGl0dGVyLCBOT1RBVElPTiwgU3BsaXR0ZXJGdW5jLCBUQUdTfSBmcm9tICcuL21hY3JvbW9sZWN1bGUnO1xuaW1wb3J0IHtVbml0c0hhbmRsZXJ9IGZyb20gJy4vdW5pdHMtaGFuZGxlcic7XG5pbXBvcnQge05vdGF0aW9uQ29udmVydGVyfSBmcm9tICcuL25vdGF0aW9uLWNvbnZlcnRlcic7XG5pbXBvcnQge01vbm9tZXJ9IGZyb20gJy4uL3R5cGVzJztcblxuLy8gY29uc3RhbnRzIGZvciBwYXJzaW5nIG1vbGZpbGUgVjIwMDBcbmNvbnN0IFYyS19SR1BfU0hJRlQgPSA4O1xuY29uc3QgVjJLX1JHUF9MSU5FID0gJ00gIFJHUCc7XG5jb25zdCBWMktfQV9MSU5FID0gJ0EgICc7XG5cbi8vIGNvbnN0YW50cyBmb3IgcGFyc2luZy9yZWNvbnN0cnVjdGlvbiBvZiBtb2xmaWxlIFYzMDAwXG5jb25zdCBWM0tfQ09VTlRTX1NISUZUID0gMTQ7XG5jb25zdCBWM0tfSURYX1NISUZUID0gNztcbmNvbnN0IFYzS19IRUFERVJfRklSU1RfTElORSA9ICdcXG5EYXRhZ3JvayBtYWNyb21vbGVjdWxlIGhhbmRsZXJcXG5cXG4nO1xuY29uc3QgVjNLX0hFQURFUl9TRUNPTkRfTElORSA9ICcgIDAgIDAgIDAgIDAgIDAgIDAgICAgICAgICAgICA5OTkgVjMwMDBcXG4nO1xuY29uc3QgVjNLX0JFR0lOX0NUQUJfQkxPQ0sgPSAnTSAgVjMwIEJFR0lOIENUQUJcXG4nO1xuY29uc3QgVjNLX0VORF9DVEFCX0JMT0NLID0gJ00gIFYzMCBFTkQgQ1RBQlxcbic7XG5jb25zdCBWM0tfQkVHSU5fQ09VTlRTX0xJTkUgPSAnTSAgVjMwIENPVU5UUyAnO1xuY29uc3QgVjNLX0NPVU5UU19MSU5FX0VORElORyA9ICcgMCAwIDBcXG4nO1xuY29uc3QgVjNLX0JFR0lOX0FUT01fQkxPQ0sgPSAnTSAgVjMwIEJFR0lOIEFUT01cXG4nO1xuY29uc3QgVjNLX0VORF9BVE9NX0JMT0NLID0gJ00gIFYzMCBFTkQgQVRPTVxcbic7XG5jb25zdCBWM0tfQkVHSU5fQk9ORF9CTE9DSyA9ICdNICBWMzAgQkVHSU4gQk9ORFxcbic7XG5jb25zdCBWM0tfRU5EX0JPTkRfQkxPQ0sgPSAnTSAgVjMwIEVORCBCT05EXFxuJztcbmNvbnN0IFYzS19CT05EX0NPTkZJRyA9ICcgQ0ZHPSc7XG5jb25zdCBWM0tfQkVHSU5fREFUQV9MSU5FID0gJ00gIFYzMCAnO1xuY29uc3QgVjNLX0VORCA9ICdNICBFTkRcXG4nO1xuXG5jb25zdCBQUkVDSVNJT05fRkFDVE9SID0gMTBfMDAwOyAvLyBIRUxNQ29yZUxpYnJhcnkgaGFzIDQgc2lnbmlmaWNhbnQgZGlnaXRzIGFmdGVyIGRlY2ltYWwgcG9pbnQgaW4gYXRvbSBjb29yZGluYXRlc1xuXG4vLyBzeW1ib2xzIGZvciB0aGUgY29ycmVzcG9uZGluZyBtb25vbWVycyBpbiBIRUxNIGxpYnJhcnlcbmNvbnN0IERFT1hZUklCT1NFID0gJ2QnO1xuY29uc3QgUklCT1NFID0gJ3InO1xuY29uc3QgUEhPU1BIQVRFID0gJ3AnO1xuXG5jb25zdCBPWFlHRU4gPSAnTyc7XG5jb25zdCBIWURST0dFTiA9ICdIJztcblxuLyogU3RvcmVzIG5lY2Vzc2FyeSBkYXRhIGFib3V0IGF0b21zIG9mIGEgbW9ub21lciBwYXJzZWQgZnJvbSBNb2xmaWxlICovXG50eXBlIEF0b21zID0ge1xuICAvKiBlbGVtZW50IHN5bWJvbHMgZm9yIG1vbm9tZXIncyBhdG9tcyAqL1xuICBhdG9tVHlwZXM6IHN0cmluZ1tdLFxuICAvKiBDYXJ0ZXNpYW4gY29vcmRpYW50ZXMgb2YgbW9ub21lcidzIGF0b21zICovXG4gIHg6IG51bWJlcltdLCAvLyB0b2RvOiBjb252ZXJ0IHRvIEZsb2F0MzJcbiAgeTogbnVtYmVyW10sXG4gIC8qIFYzSyBhdG9tIGxpbmUgbWF5IGNvbnRhaW4ga2V5d29yZCBhcmdzICovXG4gIGt3YXJnczogc3RyaW5nW10sXG59XG5cbi8qIFN0b3JlcyBuZWNlc3NhcnkgZGF0YSBhYm91dCBib25kcyBvZiBhIG1vbm9tZXIgcGFyc2VkIGZyb20gTW9sZmlsZSAqL1xudHlwZSBCb25kcyA9IHtcbiAgLyogYm9uZCB0eXBlcyBmb3IgYWxsIGxpbmVzIG9mIE1vbGZpbGUgYm9uZCBibG9jayAqL1xuICBib25kVHlwZXM6IG51bWJlcltdLCAvLyB0b2RvOiBjb252ZXJ0IHRvIEluZDMyXG4gIC8qIEluZGljZXMgb2YgYWxsIGF0b20gcGFpcnMsIGluZGV4aW5nIHN0YXJ0aW5nIGZyb20gMSAgKi9cbiAgYXRvbVBhaXJzOiBudW1iZXJbXVtdLFxuICAvKiBJZiBhIGJvbmQgaGFzIENGRz0uLi4ga2V5d29yZCBhcmd1bWVudCwgaXQgaXMgcGFyc2VkIGFuZCBzb3RyZWQgYXMgYVxuICAgKiB2YWx1ZSBvZiB0aGUgbWFwLCB3aXRoIHRoZSBrZXkgYmVpbmcgdGhlIGJvbmQncyBpbmRleCAgKi9cbiAgYm9uZENvbmZpZ3VyYXRpb246IE1hcDxudW1iZXIsIG51bWJlcj4sXG4gIC8qIFYzSyBib25kIGxpbmUgbWF5IGNvbnRhaW4ga2V5d29yZCBhcmdzICovXG4gIGt3YXJnczogTWFwPG51bWJlciwgc3RyaW5nPixcbn1cblxuLyogTWV0YWRhdGEgYXNzb2NpYXRlZCB3aXRoIHRoZSBtb25vbWVyIG5lY2Vzc2FyeSB0byByZXN0b3JlIHRoZSByZXN1bHRpbmdcbiAqIG1vbGZpbGUgICovXG50eXBlIE1vbm9tZXJNZXRhZGF0YSA9IHtcbiAgLyogdGVybWluYWwgbm9kZXM6IDAtdGggY29ycmVzcG9uZHMgdG8gdGhlIFwibGVmdG1vc3RcIiBvbmUsIDFzdCwgdG8gdGhlIFwicmlnaHRtb3N0XCIsXG4gICAqIGUuZy4gTi10ZXJtaW51cyBhbmQgQy10ZXJtaW51cyBpbiBwZXB0aWRlcyAqL1xuICB0ZXJtaW5hbE5vZGVzOiBudW1iZXJbXSxcbiAgLyogci1ncm91cCBub2RlczogMC10aCBjb3JyZXNwb25kcyB0byB0aGUgXCJsZWZ0bW9zdFwiIG9uZSwgMXN0LCB0byB0aGUgXCJyaWdodG1vc3RcIiAqL1xuICByTm9kZXM6IG51bWJlcltdLFxuICAvKiBzaGlmdCBmcm9tIHRoZSBvcmlnaW4gdG8gdGhlIG5leHQgYmFja2JvbmUsIG51bGwgZm9yIGJyYW5jaCBtb25vbWVycyAqL1xuICBiYWNrYm9uZVNoaWZ0OiBudW1iZXJbXSB8IG51bGwsXG4gIC8qIHNoaWZ0IGZyb20gdGhlIG9yaWdpbiB0byB0aGUgbmV4dCBicmFuY2gsIG51bGwgZm9yIGJyYW5jaCBtb25vbWVycyAqL1xuICBicmFuY2hTaGlmdDogbnVtYmVyW10gfCBudWxsXG59XG5cbnR5cGUgTW9sR3JhcGggPSB7XG4gIGF0b21zOiBBdG9tcyxcbiAgYm9uZHM6IEJvbmRzLFxuICBtZXRhOiBNb25vbWVyTWV0YWRhdGEsXG59XG5cbi8qIEhlbHBlciBzdHJ1Y3R1cmUgd3JhcHBpbmcgY29tbW9uIGFyZ3VtZW50cyB0byBzZXZlcmFsIGZ1bmN0aW9ucyAqL1xudHlwZSBMb29wVmFyaWFibGVzID0ge1xuICBpOiBudW1iZXIsXG4gIG5vZGVTaGlmdDogbnVtYmVyLFxuICBib25kU2hpZnQ6IG51bWJlcixcbiAgYmFja2JvbmVQb3NpdGlvblNoaWZ0OiBudW1iZXJbXSxcbiAgYmFja2JvbmVBdHRhY2hOb2RlOiBudW1iZXI7IC8vIG5vZGUgdG8gd2hpY2ggdGhlIG5leHQgYmFja2JvbmUgaXMgYXR0YWNoZWRcbiAgYnJhbmNoUG9zaXRpb25TaGlmdDogbnVtYmVyW10sXG4gIGJyYW5jaEF0dGFjaE5vZGU6IG51bWJlcixcbiAgZmxpcEZhY3RvcjogbnVtYmVyLFxuICAvLyB0b2RvOiBzaG91bGQgd2UgY29uc2lkZXIgcmVwcmVzZW50YXRpb25zIG90aGVyIHRoYW4gcGxhbmFyP1xufVxuXG4vKiBIZWxwZXIgc3RydWN0dXJlIHdyYXBwaW5nIGNvbW1vbiBhcmd1bWVudHMgdG8gc2V2ZXJhbCBmdW5jdGlvbnMgKi9cbnR5cGUgTG9vcENvbnN0YW50cyA9IHtcbiAgc3VnYXI6IE1vbEdyYXBoIHwgbnVsbCxcbiAgcGhvc3BoYXRlOiBNb2xHcmFwaCB8IG51bGwsXG4gIHNlcUxlbmd0aDogbnVtYmVyLFxuICBhdG9tQ291bnQ6IG51bWJlcixcbiAgYm9uZENvdW50OiBudW1iZXIsXG59XG5cbi8vIHRvZG86IHZlcmlmeSB0aGF0IGFsbCBmdW5jdGlvbnMgaGF2ZSByZXR1cm4gdHlwZXNcblxuLyogQ29udmVydCBNYWNyb21vbGVjdWxlIGNvbHVtbiBpbnRvIE1vbGVjdWxlIGNvbHVtbiBzdG9yaW5nIG1vbGZpbGUgVjMwMDAgd2l0aCB0aGUgaGVscCBvZiBhIG1vbm9tZXIgbGlicmFyeSAgKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBfdG9BdG9taWNMZXZlbChcbiAgZGY6IERHLkRhdGFGcmFtZSwgbWFjcm9Nb2xDb2w6IERHLkNvbHVtbjxzdHJpbmc+LCBtb25vbWVyc0xpYkxpc3Q6IGFueVtdXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKERHLkZ1bmMuZmluZCh7cGFja2FnZTogJ0NoZW0nLCBuYW1lOiAnZ2V0UmRLaXRNb2R1bGUnfSkubGVuZ3RoID09PSAwKSB7XG4gICAgZ3Jvay5zaGVsbC53YXJuaW5nKCdUcmFuc2Zvcm1hdGlvbiB0byBhdG9taWMgbGV2ZWwgcmVxdWlyZXMgcGFja2FnZSBcIkNoZW1cIiBpbnN0YWxsZWQuJyk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKG1hY3JvTW9sQ29sLnNlbVR5cGUgIT09IERHLlNFTVRZUEUuTUFDUk9NT0xFQ1VMRSkge1xuICAgIGdyb2suc2hlbGwud2FybmluZyhcbiAgICAgIGBPbmx5IHRoZSAke0RHLlNFTVRZUEUuTUFDUk9NT0xFQ1VMRX0gY29sdW1ucyBjYW4gYmUgY29udmVydGVkIHRvIGF0b21pY1xuICAgICAgbGV2ZWwsIHRoZSBjaG9zZW4gY29sdW1uIGhhcyBzZW1UeXBlICR7bWFjcm9Nb2xDb2wuc2VtVHlwZX1gXG4gICAgKTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBjb252ZXJ0ICdoZWxtJyB0byAnc2VwYXJhdG9yJyB1bml0c1xuICBpZiAobWFjcm9Nb2xDb2wuZ2V0VGFnKERHLlRBR1MuVU5JVFMpID09PSBOT1RBVElPTi5IRUxNKSB7XG4gICAgY29uc3QgY29udmVydGVyID0gbmV3IE5vdGF0aW9uQ29udmVydGVyKG1hY3JvTW9sQ29sKTtcbiAgICBjb25zdCBzZXBhcmF0b3IgPSAnLyc7XG4gICAgbWFjcm9Nb2xDb2wgPSBjb252ZXJ0ZXIuY29udmVydChOT1RBVElPTi5TRVBBUkFUT1IsIHNlcGFyYXRvcik7XG4gIH1cblxuICBjb25zdCBhbHBoYWJldCA9IG1hY3JvTW9sQ29sLmdldFRhZyhUQUdTLmFscGhhYmV0KTtcblxuICAvLyBkZXRlcm1pbmUgdGhlIHBvbHltZXIgdHlwZSBhY2NvcmRpbmcgdG8gSEVMTSBzcGVjaWZpY2F0aW9uc1xuICBsZXQgcG9seW1lclR5cGU7XG4gIC8vIHRvZG86IGFuIGV4Y2VwdGlvbiBmcm9tIGRhcnQgY29tZXMgYmVmb3JlIHRoaXMgY2hlY2sgaWYgdGhlIGFscGhhYmV0IGlzIFVOXG4gIGlmIChhbHBoYWJldCA9PT0gQUxQSEFCRVQuUFQpIHtcbiAgICBwb2x5bWVyVHlwZSA9IEhFTE1fUE9MWU1FUl9UWVBFLlBFUFRJREU7XG4gIH0gZWxzZSBpZiAoYWxwaGFiZXQgPT09IEFMUEhBQkVULlJOQSB8fCBhbHBoYWJldCA9PT0gQUxQSEFCRVQuRE5BKSB7XG4gICAgcG9seW1lclR5cGUgPSBIRUxNX1BPTFlNRVJfVFlQRS5STkE7XG4gIH0gZWxzZSB7XG4gICAgZ3Jvay5zaGVsbC53YXJuaW5nKFxuICAgICAgYE9ubHkgUFQsIEROQSBhbmQgUk5BIGFscGhhYmV0cyBhcmUgc3VwcG9ydGVkLCB3aGlsZSB0aGUgc2VsZWN0ZWQgY29sdW1uIGhhcyAke3BvbHltZXJUeXBlfSBhbHBoYWJldGBcbiAgICApO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IG1vbm9tZXJTZXF1ZW5jZXNBcnJheTogc3RyaW5nW11bXSA9IGdldE1vbm9tZXJTZXF1ZW5jZXNBcnJheShtYWNyb01vbENvbCk7XG4gIC8vIHRvZG86IGNvbnNpZGVyIHNlcGFyYXRlbHkgYmFja2JvbmUsIHRlcm1pbmFsLCBicmFuY2ggbW9ub21lciB0eXBlc1xuICBjb25zdCBtb25vbWVyc0RpY3QgPSBhd2FpdCBnZXRNb25vbWVyc0RpY3QobW9ub21lclNlcXVlbmNlc0FycmF5LCBtb25vbWVyc0xpYkxpc3QsIHBvbHltZXJUeXBlLCBhbHBoYWJldCk7XG4gIGNvbnN0IGNvbHVtbkxlbmd0aCA9IG1hY3JvTW9sQ29sLmxlbmd0aDtcbiAgY29uc3QgcmVjb25zdHJ1Y3RlZDogc3RyaW5nW10gPSBuZXcgQXJyYXkoY29sdW1uTGVuZ3RoKTtcbiAgZm9yIChsZXQgcm93ID0gMDsgcm93IDwgY29sdW1uTGVuZ3RoOyArK3Jvdykge1xuICAgIGNvbnN0IG1vbm9tZXJTZXEgPSBtb25vbWVyU2VxdWVuY2VzQXJyYXlbcm93XTtcbiAgICByZWNvbnN0cnVjdGVkW3Jvd10gPSBtb25vbWVyU2VxVG9Nb2xmaWxlKG1vbm9tZXJTZXEsIG1vbm9tZXJzRGljdCwgYWxwaGFiZXQsIHBvbHltZXJUeXBlKTtcbiAgICBjb25zb2xlLmxvZyhyZWNvbnN0cnVjdGVkW3Jvd10pO1xuICB9XG5cbiAgLy8gZXhjbHVkZSBuYW1lIGNvbGxpc2lvbnNcbiAgY29uc3QgbmFtZSA9ICdtb2xmaWxlKCcgKyBtYWNyb01vbENvbC5uYW1lICsgJyknO1xuICBjb25zdCBuZXdDb2xOYW1lID0gZGYuY29sdW1ucy5nZXRVbnVzZWROYW1lKG5hbWUpO1xuICBjb25zdCBuZXdDb2wgPSBERy5Db2x1bW4uZnJvbVN0cmluZ3MobmV3Q29sTmFtZSwgcmVjb25zdHJ1Y3RlZCk7XG5cbiAgbmV3Q29sLnNlbVR5cGUgPSBERy5TRU1UWVBFLk1PTEVDVUxFO1xuICBuZXdDb2wuc2V0VGFnKERHLlRBR1MuVU5JVFMsIERHLlVOSVRTLk1vbGVjdWxlLk1PTEJMT0NLKTtcbiAgZGYuY29sdW1ucy5hZGQobmV3Q29sLCB0cnVlKTtcbiAgYXdhaXQgZ3Jvay5kYXRhLmRldGVjdFNlbWFudGljVHlwZXMoZGYpO1xufVxuXG4vKiBHZXQgYSBtYXBwaW5nIG9mIHBlcHRpZGUgc3ltYm9scyB0byBIRUxNIG1vbm9tZXIgbGlicmFyeSBvYmplY3RzIHdpdGhcbiAqIHNlbGVjdHRlZCBmaWVsZHMgICovXG5mdW5jdGlvbiBnZXRGb3JtYXR0ZWRNb25vbWVyTGliKFxuICBtb25vbWVyc0xpYkxpc3Q6IGFueVtdLCBwb2x5bWVyVHlwZTogSEVMTV9QT0xZTUVSX1RZUEUsIGFscGhhYmV0OiBBTFBIQUJFVFxuKTogTWFwPHN0cmluZywgYW55PiB7XG4gIGNvbnN0IG1hcCA9IG5ldyBNYXA8c3RyaW5nLCBhbnk+KCk7XG4gIG1vbm9tZXJzTGliTGlzdC5mb3JFYWNoKFxuICAgIChpdCkgPT4ge1xuICAgICAgaWYgKGl0W0hFTE1fRklFTERTLlBPTFlNRVJfVFlQRV0gPT09IHBvbHltZXJUeXBlKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBwb2x5bWVyVHlwZSA9PT0gSEVMTV9QT0xZTUVSX1RZUEUuUk5BICYmXG4gICAgICAgICAgKGl0W0hFTE1fRklFTERTLk1PTk9NRVJfVFlQRV0gPT09IEhFTE1fTU9OT01FUl9UWVBFLkJSQU5DSCB8fFxuICAgICAgICAgICAgYWxwaGFiZXQgPT09IEFMUEhBQkVULkROQSAmJiBpdFtIRUxNX0ZJRUxEUy5TWU1CT0xdID09PSBERU9YWVJJQk9TRSB8fFxuICAgICAgICAgICAgYWxwaGFiZXQgPT09IEFMUEhBQkVULlJOQSAmJiBpdFtIRUxNX0ZJRUxEUy5TWU1CT0xdID09PSBSSUJPU0UgfHxcbiAgICAgICAgICAgIGl0W0hFTE1fRklFTERTLlNZTUJPTF0gPT09IFBIT1NQSEFURSkgfHxcbiAgICAgICAgICBwb2x5bWVyVHlwZSA9PT0gSEVMTV9QT0xZTUVSX1RZUEUuUEVQVElERSAmJlxuICAgICAgICAgIGl0W0hFTE1fRklFTERTLk1PTk9NRVJfVFlQRV0gIT09IEhFTE1fTU9OT01FUl9UWVBFLkJSQU5DSFxuICAgICAgICApIHtcbiAgICAgICAgICBjb25zdCBtb25vbWVyT2JqZWN0OiB7IFtrZXk6IHN0cmluZ106IGFueSB9ID0ge307XG4gICAgICAgICAgSEVMTV9DT1JFX0ZJRUxEUy5mb3JFYWNoKChmaWVsZCkgPT4ge1xuICAgICAgICAgICAgbW9ub21lck9iamVjdFtmaWVsZF0gPSBpdFtmaWVsZF07XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgbWFwLnNldChpdFtIRUxNX0ZJRUxEUy5TWU1CT0xdLCBtb25vbWVyT2JqZWN0KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICByZXR1cm4gbWFwO1xufVxuXG4vKiBHZXQgamFnZ2VkIGFycmF5IG9mIG1vbm9tZXIgc3ltYm9scyBmb3IgdGhlIGRhdGFmcmFtZSAgKi9cbmZ1bmN0aW9uIGdldE1vbm9tZXJTZXF1ZW5jZXNBcnJheShtYWNyb01vbENvbDogREcuQ29sdW1uPHN0cmluZz4pOiBzdHJpbmdbXVtdIHtcbiAgY29uc3QgY29sdW1uTGVuZ3RoID0gbWFjcm9Nb2xDb2wubGVuZ3RoO1xuICBjb25zdCByZXN1bHQ6IHN0cmluZ1tdW10gPSBuZXcgQXJyYXkoY29sdW1uTGVuZ3RoKTtcblxuICAvLyBzcGxpdCB0aGUgc3RyaW5nIGludG8gbW9ub21lcnNcbiAgY29uc3QgY29sVW5pdHMgPSBtYWNyb01vbENvbC5nZXRUYWcoREcuVEFHUy5VTklUUyk7XG4gIGNvbnN0IHNlcGFyYXRvciA9IG1hY3JvTW9sQ29sLmdldFRhZyhUQUdTLnNlcGFyYXRvcik7XG4gIGNvbnN0IHNwbGl0dGVyRnVuYzogU3BsaXR0ZXJGdW5jID0gZ2V0U3BsaXR0ZXIoY29sVW5pdHMsIHNlcGFyYXRvcik7XG5cbiAgZm9yIChsZXQgcm93ID0gMDsgcm93IDwgY29sdW1uTGVuZ3RoOyArK3Jvdykge1xuICAgIGNvbnN0IG1hY3JvTW9sZWN1bGUgPSBtYWNyb01vbENvbC5nZXQocm93KTtcbiAgICAvLyB0b2RvOiBoYW5kbGUgdGhlIGV4Y2VwdGlvbiBjYXNlIHdoZW4gbWFjcm9Nb2xlY3VsZSBpcyBudWxsXG4gICAgcmVzdWx0W3Jvd10gPSBtYWNyb01vbGVjdWxlID8gc3BsaXR0ZXJGdW5jKG1hY3JvTW9sZWN1bGUpIDogW107XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuLyogR2V0IGEgbWFwcGluZyBvZiBtb25vbWVyIHN5bWJvbHMgdG8gTW9sR3JhcGggb2JqZWN0cyAqL1xuYXN5bmMgZnVuY3Rpb24gZ2V0TW9ub21lcnNEaWN0KFxuICBtb25vbWVyU2VxdWVuY2VzQXJyYXk6IHN0cmluZ1tdW10sIG1vbm9tZXJzTGliTGlzdDogYW55W10sIHBvbHltZXJUeXBlOiBIRUxNX1BPTFlNRVJfVFlQRSwgYWxwaGFiZXQ6IEFMUEhBQkVUXG4pOiBQcm9taXNlPE1hcDxzdHJpbmcsIE1vbEdyYXBoPj4ge1xuICAvLyB0b2RvOiBleGNlcHRpb24gLSBubyBnYXBzLCBubyBlbXB0eSBzdHJpbmcgbW9ub21lcnNcbiAgY29uc3QgZm9ybWF0dGVkTW9ub21lckxpYiA9IGdldEZvcm1hdHRlZE1vbm9tZXJMaWIobW9ub21lcnNMaWJMaXN0LCBwb2x5bWVyVHlwZSwgYWxwaGFiZXQpO1xuICBjb25zdCBtb25vbWVyc0RpY3QgPSBuZXcgTWFwPHN0cmluZywgTW9sR3JhcGg+KCk7XG5cbiAgY29uc3QgbW9kdWxlUmRraXQgPSBhd2FpdCBncm9rLmZ1bmN0aW9ucy5jYWxsKCdDaGVtOmdldFJkS2l0TW9kdWxlJyk7XG5cbiAgLy8gYWRkIGRlb3h5cmlib3NlL3JpYm9zZSBhbmQgcGhvc3BoYXRlIGZvciBudWNsZW90aWRlIHNlcXVlbmNlc1xuICBpZiAocG9seW1lclR5cGUgPT09IEhFTE1fUE9MWU1FUl9UWVBFLlJOQSkge1xuICAgIGNvbnN0IHN5bWJvbHMgPSAoYWxwaGFiZXQgPT09IEFMUEhBQkVULlJOQSkgP1xuICAgICAgW1JJQk9TRSwgUEhPU1BIQVRFXSA6IFtERU9YWVJJQk9TRSwgUEhPU1BIQVRFXTtcbiAgICBmb3IgKGNvbnN0IHN5bSBvZiBzeW1ib2xzKVxuICAgICAgdXBkYXRlTW9ub21lcnNEaWN0KG1vbm9tZXJzRGljdCwgc3ltLCBmb3JtYXR0ZWRNb25vbWVyTGliLCBtb2R1bGVSZGtpdCwgcG9seW1lclR5cGUpO1xuICB9XG5cbiAgZm9yIChsZXQgcm93ID0gMDsgcm93IDwgbW9ub21lclNlcXVlbmNlc0FycmF5Lmxlbmd0aDsgKytyb3cpIHtcbiAgICBjb25zdCBtb25vbWVyU2VxOiBzdHJpbmdbXSA9IG1vbm9tZXJTZXF1ZW5jZXNBcnJheVtyb3ddO1xuICAgIGZvciAoY29uc3Qgc3ltIG9mIG1vbm9tZXJTZXEpXG4gICAgICB1cGRhdGVNb25vbWVyc0RpY3QobW9ub21lcnNEaWN0LCBzeW0sIGZvcm1hdHRlZE1vbm9tZXJMaWIsIG1vZHVsZVJka2l0LCBwb2x5bWVyVHlwZSk7XG4gIH1cbiAgLy8gY29uc29sZS5sb2cobW9ub21lcnNEaWN0KTtcblxuICByZXR1cm4gbW9ub21lcnNEaWN0O1xufVxuXG4vKiBBZGRzIE1vbEdyYXBoIG9iamVjdCBmb3IgJ3N5bScgdG8gdGhlIG1vbm9tZXJzIGRpY3Qgd2hlbiBuZWNlc3NhcnkgICovXG5mdW5jdGlvbiB1cGRhdGVNb25vbWVyc0RpY3QoXG4gIG1vbm9tZXJzRGljdDogTWFwPHN0cmluZywgTW9sR3JhcGg+LCBzeW06IHN0cmluZyxcbiAgZm9ybWF0dGVkTW9ub21lckxpYjogTWFwPHN0cmluZywgYW55PiwgbW9kdWxlUmRraXQ6IGFueSwgcG9seW1lclR5cGU6IEhFTE1fUE9MWU1FUl9UWVBFXG4pOiB2b2lkIHtcbiAgaWYgKCFtb25vbWVyc0RpY3QuaGFzKHN5bSkpIHtcbiAgICBjb25zdCBtb25vbWVyRGF0YTogTW9sR3JhcGggfCBudWxsID0gZ2V0TW9sR3JhcGgoc3ltLCBmb3JtYXR0ZWRNb25vbWVyTGliLCBtb2R1bGVSZGtpdCwgcG9seW1lclR5cGUpO1xuICAgIGlmIChtb25vbWVyRGF0YSlcbiAgICAgIG1vbm9tZXJzRGljdC5zZXQoc3ltLCBtb25vbWVyRGF0YSk7XG4gICAgZWxzZVxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBNb25vbWVyIHdpdGggc3ltYm9sICcke3N5bX0nIGlzIGFic2VudCB0aGUgbW9ub21lciBsaWJyYXJ5YCk7XG4gICAgLy8gdG9kbzogaGFuZGxlIGV4Y2VwdGlvblxuICB9XG59XG5cbi8qIENvbnN0cnVjdCB0aGUgTW9sR3JhcGggb2JqZWN0IGZvciBzcGVjaWZpZWQgbW9ub21lclN5bWJvbDogdGhlIGFzc29jaWF0ZWRcbiAqIGdyYXBoIGlzIGFkanVzdGVkIGluIFhZIHBsYW5lIGFuZCBmaWxsZWQgd2l0aCBkZWZhdWx0IFItZ3JvdXBzICovXG5mdW5jdGlvbiBnZXRNb2xHcmFwaChcbiAgbW9ub21lclN5bWJvbDogc3RyaW5nLCBmb3JtYXR0ZWRNb25vbWVyTGliOiBNYXA8c3RyaW5nLCBhbnk+LFxuICBtb2R1bGVSZGtpdDogYW55LCBwb2x5bWVyVHlwZTogSEVMTV9QT0xZTUVSX1RZUEUgLy8gdG9kbzogc3BlY2lmeSB0eXBlIGZvciBtb2R1bGVSZGtpdFxuKTogTW9sR3JhcGggfCBudWxsIHtcbiAgaWYgKCFmb3JtYXR0ZWRNb25vbWVyTGliLmhhcyhtb25vbWVyU3ltYm9sKSkge1xuICAgIHJldHVybiBudWxsO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IGxpYk9iamVjdCA9IGZvcm1hdHRlZE1vbm9tZXJMaWIuZ2V0KG1vbm9tZXJTeW1ib2wpO1xuICAgIGNvbnN0IGNhcEdyb3VwcyA9IHBhcnNlQ2FwR3JvdXBzKGxpYk9iamVjdFtIRUxNX0ZJRUxEUy5SR1JPVVBTXSk7XG4gICAgY29uc3QgY2FwR3JvdXBJZHhNYXAgPSBwYXJzZUNhcEdyb3VwSWR4TWFwKGxpYk9iamVjdFtIRUxNX0ZJRUxEUy5NT0xGSUxFXSk7XG4gICAgY29uc3QgbW9sZmlsZVYzSyA9IGNvbnZlcnRNb2xmaWxlVG9WM0socmVtb3ZlUkdyb3VwTGluZXMobGliT2JqZWN0W0hFTE1fRklFTERTLk1PTEZJTEVdKSwgbW9kdWxlUmRraXQpO1xuICAgIGNvbnN0IGNvdW50cyA9IHBhcnNlQXRvbUFuZEJvbmRDb3VudHMobW9sZmlsZVYzSyk7XG5cbiAgICBjb25zdCBhdG9tcyA9IHBhcnNlQXRvbUJsb2NrKG1vbGZpbGVWM0ssIGNvdW50cy5hdG9tQ291bnQpO1xuICAgIGNvbnN0IGJvbmRzID0gcGFyc2VCb25kQmxvY2sobW9sZmlsZVYzSywgY291bnRzLmJvbmRDb3VudCk7XG4gICAgY29uc3QgbWV0YSA9IGdldE1vbm9tZXJNZXRhZGF0YShhdG9tcywgYm9uZHMsIGNhcEdyb3VwcywgY2FwR3JvdXBJZHhNYXApO1xuXG4gICAgY29uc3QgbW9ub21lckdyYXBoOiBNb2xHcmFwaCA9IHthdG9tczogYXRvbXMsIGJvbmRzOiBib25kcywgbWV0YTogbWV0YX07XG5cbiAgICBpZiAocG9seW1lclR5cGUgPT09IEhFTE1fUE9MWU1FUl9UWVBFLlBFUFRJREUpIHtcbiAgICAgIGFkanVzdFBlcHRpZGVNb25vbWVyR3JhcGgobW9ub21lckdyYXBoKTtcbiAgICB9IGVsc2UgeyAvLyBudWNsZW90aWRlc1xuICAgICAgaWYgKG1vbm9tZXJTeW1ib2wgPT09IFJJQk9TRSB8fCBtb25vbWVyU3ltYm9sID09PSBERU9YWVJJQk9TRSlcbiAgICAgICAgYWRqdXN0U3VnYXJNb25vbWVyR3JhcGgobW9ub21lckdyYXBoKTtcbiAgICAgIGVsc2UgaWYgKG1vbm9tZXJTeW1ib2wgPT09IFBIT1NQSEFURSlcbiAgICAgICAgYWRqdXN0UGhvc3BoYXRlTW9ub21lckdyYXBoKG1vbm9tZXJHcmFwaCk7XG4gICAgICBlbHNlXG4gICAgICAgIGFkanVzdEJhc2VNb25vbWVyR3JhcGgobW9ub21lckdyYXBoKTtcbiAgICB9XG5cbiAgICAvLyByZW1vdmUgdGhlICdyaWdodG1vc3QnIGNoYWluLWV4dGVuZGluZyByLWdyb3VwIG5vZGUgaW4gdGhlIGJhY2tib25lXG4gICAgaWYgKHBvbHltZXJUeXBlID09PSBIRUxNX1BPTFlNRVJfVFlQRS5QRVBUSURFKSB7XG4gICAgICBzZXRTaGlmdHMobW9ub21lckdyYXBoLCBwb2x5bWVyVHlwZSk7XG4gICAgICByZW1vdmVOb2RlQW5kQm9uZHMobW9ub21lckdyYXBoLCBtb25vbWVyR3JhcGgubWV0YS5yTm9kZXNbMV0pO1xuICAgIH0gZWxzZSB7IC8vIG51Y2xlb3RpZGVzXG4gICAgICBpZiAobW9ub21lclN5bWJvbCA9PT0gUklCT1NFIHx8IG1vbm9tZXJTeW1ib2wgPT09IERFT1hZUklCT1NFKSB7XG4gICAgICAgIC8vIHJlbW92ZSBSMlxuICAgICAgICByZW1vdmVOb2RlQW5kQm9uZHMobW9ub21lckdyYXBoLCBtb25vbWVyR3JhcGgubWV0YS5yTm9kZXNbMV0pO1xuICAgICAgICAvLyBzZXQgdGVybWluYWxOb2RlMiAob3h5Z2VuKSBhcyBuZXcgUjJcbiAgICAgICAgbW9ub21lckdyYXBoLm1ldGEuck5vZGVzWzFdID0gbW9ub21lckdyYXBoLm1ldGEudGVybWluYWxOb2Rlc1sxXTtcbiAgICAgICAgc2V0VGVybWluYWxOb2Rlcyhtb25vbWVyR3JhcGguYm9uZHMsIG1vbm9tZXJHcmFwaC5tZXRhKTsgLy8gc2V0IHRlcm1pbmFsIG5vZGVzIGFuZXdcbiAgICAgICAgc2V0U2hpZnRzKG1vbm9tZXJHcmFwaCwgcG9seW1lclR5cGUpO1xuICAgICAgICAvLyByZW1vdmUgJ25ldycgUjIgKG94eWdlbilcbiAgICAgICAgcmVtb3ZlTm9kZUFuZEJvbmRzKG1vbm9tZXJHcmFwaCwgbW9ub21lckdyYXBoLm1ldGEuck5vZGVzWzFdKTtcbiAgICAgICAgLy8gcmVtb3ZlIFIxXG4gICAgICAgIHJlbW92ZU5vZGVBbmRCb25kcyhtb25vbWVyR3JhcGgsIG1vbm9tZXJHcmFwaC5tZXRhLnJOb2Rlc1swXSk7XG4gICAgICAgIC8vIHJlbW92ZSB0aGUgYnJhbmNoaW5nIHItZ3JvdXBcbiAgICAgICAgcmVtb3ZlTm9kZUFuZEJvbmRzKG1vbm9tZXJHcmFwaCwgbW9ub21lckdyYXBoLm1ldGEuck5vZGVzWzJdKTtcbiAgICAgIH0gZWxzZSBpZiAobW9ub21lclN5bWJvbCA9PT0gUEhPU1BIQVRFKSB7XG4gICAgICAgIG1vbm9tZXJHcmFwaC5tZXRhLnRlcm1pbmFsTm9kZXNbMF0gPSBtb25vbWVyR3JhcGgubWV0YS5yTm9kZXNbMF07XG4gICAgICAgIHNoaWZ0Q29vcmRpbmF0ZXMoXG4gICAgICAgICAgbW9ub21lckdyYXBoLFxuICAgICAgICAgIC1tb25vbWVyR3JhcGguYXRvbXMueFttb25vbWVyR3JhcGgubWV0YS50ZXJtaW5hbE5vZGVzWzBdIC0gMV0sXG4gICAgICAgICAgLW1vbm9tZXJHcmFwaC5hdG9tcy55W21vbm9tZXJHcmFwaC5tZXRhLnRlcm1pbmFsTm9kZXNbMF0gLSAxXVxuICAgICAgICApO1xuICAgICAgICBzZXRTaGlmdHMobW9ub21lckdyYXBoLCBwb2x5bWVyVHlwZSk7XG4gICAgICAgIHJlbW92ZU5vZGVBbmRCb25kcyhtb25vbWVyR3JhcGgsIG1vbm9tZXJHcmFwaC5tZXRhLnJOb2Rlc1sxXSk7XG4gICAgICB9IGVsc2UgeyAvLyBudWNsZW9iYXNlc1xuICAgICAgICByZW1vdmVOb2RlQW5kQm9uZHMobW9ub21lckdyYXBoLCBtb25vbWVyR3JhcGgubWV0YS5yTm9kZXNbMF0pO1xuICAgICAgfVxuICAgIH1cbiAgICByZW1vdmVIeWRyb2dlbihtb25vbWVyR3JhcGgpO1xuXG4gICAgcmV0dXJuIG1vbm9tZXJHcmFwaDtcbiAgfVxufVxuXG4vLyB0b2RvOiBkb2NcbmZ1bmN0aW9uIGdldE1vbm9tZXJNZXRhZGF0YShcbiAgYXRvbXM6IEF0b21zLCBib25kczogQm9uZHMsIGNhcEdyb3Vwczogc3RyaW5nW10sIGNhcEdyb3VwSWR4TWFwOiBNYXA8bnVtYmVyLCBudW1iZXI+XG4pOiBNb25vbWVyTWV0YWRhdGEge1xuICBjb25zdCBtZXRhOiBNb25vbWVyTWV0YWRhdGEgPSB7XG4gICAgYmFja2JvbmVTaGlmdDogbnVsbCxcbiAgICBicmFuY2hTaGlmdDogbnVsbCxcbiAgICB0ZXJtaW5hbE5vZGVzOiBbXSxcbiAgICByTm9kZXM6IFtdLFxuICB9O1xuXG4gIHN1YnN0aXR1dGVDYXBHcm91cHMoYXRvbXMsIGNhcEdyb3VwcywgY2FwR3JvdXBJZHhNYXApO1xuICBzZXRSTm9kZXMoY2FwR3JvdXBJZHhNYXAsIG1ldGEpO1xuICBzZXRUZXJtaW5hbE5vZGVzKGJvbmRzLCBtZXRhKTtcbiAgcmV0dXJuIG1ldGE7XG59XG5cbi8qIFBhcnNlIGVsZW1lbnQgc3ltYm9scyBmb3IgUi1ncm91cHMgZnJvbSB0aGUgSEVMTSBtb25vbWVyIGxpYnJhcnkgUi1ncm91cHNcbiAqIGZpZWxkICAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQ2FwR3JvdXBzKHJHcm91cE9iakxpc3Q6IGFueVtdKTogc3RyaW5nW10ge1xuICAvLyBzcGVjaWZpY2FsbHkgZm9yIEhFTE1Db3JlTGlicmFyeVxuICAvLyBjb25zaWRlcmVkIG9ubHkgbW9ub2F0b21pYyByZ3JvdXBzXG4gIC8vIHN1cHBvc2luZyB0aGF0IGVsZW1lbnRzIGluIHJHcm91cE9iakxpc3QgYXJlIHNvcnRlZCB3LnIudC4gdGhlIHJncm91cHMgaWR4XG4gIC8vIHRvZG86IHBvc3NpYmxlIGdlbmVyYWxpemF0aW9uc1xuICBjb25zdCBjYXBHcm91cHNBcnJheTogc3RyaW5nW10gPSBbXTtcbiAgZm9yIChjb25zdCBvYmogb2Ygckdyb3VwT2JqTGlzdCkge1xuICAgIGxldCBjYXBHcm91cDogc3RyaW5nID0gb2JqW1JHUk9VUF9GSUVMRFMuQ0FQX0dST1VQX1NNSUxFU107XG5cbiAgICAvLyBpbiBzb21lIGNhc2VzIHRoZSBzbWlsZXMgZmllbGQgaXMgd3JpdHRlbiB3aXRoIHVwcGVyY2FzZVxuICAgIGlmICghY2FwR3JvdXApXG4gICAgICBjYXBHcm91cCA9IG9ialtSR1JPVVBfRklFTERTLkNBUF9HUk9VUF9TTUlMRVNfVVBQRVJDQVNFXTtcbiAgICAvLyB0b2RvOiB2ZXJpZnkgdGhhdCB0aGVyZSBhcmUgbm8gbXVsdGktZWxlbWVudCBjYXAgZ3JvdXBzLCBvciBjb25zaWRlciBob3cgdG9cbiAgICAvLyB0cmFuc2Zvcm0gdGhlbVxuICAgIGNhcEdyb3VwID0gY2FwR3JvdXAucmVwbGFjZSgvKFxcW3xcXF18XFwqfDp8XFxkKS9nLCAnJyk7XG4gICAgaWYgKGNhcEdyb3VwLmxlbmd0aCA+IDEpIC8vIHRvZG86IGNoZWNrIGlmIHN1Y2ggY2FzZXMgYXJlIHBvc3NpYmxlLCByZW1vdmUgaWYgbm90XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0RlZmF1bHQgY2FwIGdyb3VwIGhhcyBsZW5ndGggbW9yZSB0aGFuIG9uZScpO1xuICAgIGNhcEdyb3Vwc0FycmF5LnB1c2goY2FwR3JvdXApO1xuICB9XG4gIHJldHVybiBjYXBHcm91cHNBcnJheTtcbn1cblxuLyogU3Vic3RpdHV0ZSB0aGUgY2FwIGdyb3VwIGVsZW1lbnRzIGluc3RlYWQgb2YgUiMgKi9cbmZ1bmN0aW9uIHN1YnN0aXR1dGVDYXBHcm91cHMoXG4gIGF0b21zOiBBdG9tcywgY2FwR3JvdXBzOiBzdHJpbmdbXSwgY2FwR3JvdXBJZHhNYXA6IE1hcDxudW1iZXIsIG51bWJlcj5cbik6IHZvaWQge1xuICBmb3IgKGNvbnN0IFtub2RlLCBjYXBJZHhdIG9mIGNhcEdyb3VwSWR4TWFwKVxuICAgIGF0b21zLmF0b21UeXBlc1tub2RlIC0gMV0gPSBjYXBHcm91cHNbY2FwSWR4IC0gMV07IC8vIC0xIGJlY2F1c2UgbW9sZmlsZSBpbmRleGluZyBzdGFydHMgZnJvbSAxXG59XG5cbi8vdG9kbzogZG9jXG5mdW5jdGlvbiBzZXRSTm9kZXMoY2FwR3JvdXBJZHhNYXA6IE1hcDxudW1iZXIsIG51bWJlcj4sIG1ldGE6IE1vbm9tZXJNZXRhZGF0YSk6IHZvaWQge1xuICBtZXRhLnJOb2RlcyA9IEFycmF5LmZyb20oY2FwR3JvdXBJZHhNYXAua2V5cygpKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBtZXRhLnJOb2Rlcy5sZW5ndGg7IGkrKykge1xuICAgIGZvciAoY29uc3QgaiBvZiBbMSwgMl0pIHsgLy8gMSBhbmQgMiBieSBkZWYuIGNvcnJlc3BvbmQgdG8gJ2xlZnQvcmlnaHRtb3N0JyByLW5vZGVzXG4gICAgICAvLyBzd2FwIHRoZSB2YWx1ZXMgaWYgbmVjZXNzYXJ5LCBzbyB0aGF0IHRoZSBcImxlZnRtb3N0XCIgci1ub2RlIGlzIGF0IDAsXG4gICAgICAvLyBhbmQgdGhlICdyaWdodG1vc3QnLCBhdCAxXG4gICAgICBpZiAoY2FwR3JvdXBJZHhNYXAuZ2V0KG1ldGEuck5vZGVzW2ldKSA9PT0gaikge1xuICAgICAgICBjb25zdCB0bXAgPSBtZXRhLnJOb2Rlc1tqIC0gMV07XG4gICAgICAgIG1ldGEuck5vZGVzW2ogLSAxXSA9IG1ldGEuck5vZGVzW2ldO1xuICAgICAgICBtZXRhLnJOb2Rlc1tpXSA9IHRtcDtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuLy90b2RvOiBkb2NcbmZ1bmN0aW9uIHNldFRlcm1pbmFsTm9kZXMoYm9uZHM6IEJvbmRzLCBtZXRhOiBNb25vbWVyTWV0YWRhdGEpOiB2b2lkIHtcbiAgY29uc3Qgck5vZGVzID0gbWV0YS5yTm9kZXM7XG4gIG1ldGEudGVybWluYWxOb2RlcyA9IG5ldyBBcnJheTxudW1iZXI+KHJOb2Rlcy5sZW5ndGgpLmZpbGwoMCk7XG4gIGNvbnN0IHRlcm1pbmFsTm9kZXMgPSBtZXRhLnRlcm1pbmFsTm9kZXM7XG4gIGNvbnN0IGF0b21QYWlycyA9IGJvbmRzLmF0b21QYWlycztcbiAgbGV0IGkgPSAwO1xuICBsZXQgaiA9IDA7XG4gIHdoaWxlICgoaSA8IGF0b21QYWlycy5sZW5ndGgpICYmIGogPCB0ZXJtaW5hbE5vZGVzLmxlbmd0aCkge1xuICAgIC8vIHJOb2RlcyBhcnJheSBpcyBzb3J0ZWQgc28gdGhhdCBpdHMgMHRoIGFuZCAxc3QgZWxlbWVudHMgKGlmIGJvdGhcbiAgICAvLyBwcmVzZW50KSBjb3JyZXNwb25kIHRvIHRoZSBjaGFpbiBleHRlbmRpbmcgKGkuZS4gbm90IGJyYW5jaGluZykgci1ncm91cHNcbiAgICBmb3IgKGxldCBrID0gMDsgayA8IHRlcm1pbmFsTm9kZXMubGVuZ3RoOyArK2spIHtcbiAgICAgIGZvciAobGV0IGwgPSAwOyBsIDwgMjsgKytsKSB7XG4gICAgICAgIGlmIChhdG9tUGFpcnNbaV1bbF0gPT09IHJOb2Rlc1trXSkge1xuICAgICAgICAgIHRlcm1pbmFsTm9kZXNba10gPSBhdG9tUGFpcnNbaV1bKGwgKyAxKSAlIDJdO1xuICAgICAgICAgIGlmIChyTm9kZXMubGVuZ3RoID4gMikge1xuICAgICAgICAgIH1cbiAgICAgICAgICArK2o7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgKytpO1xuICB9XG59XG5cbi8vdG9kbzogZG9jXG5mdW5jdGlvbiBzZXRTaGlmdHMobW9sR3JhcGg6IE1vbEdyYXBoLCBwb2x5bWVyVHlwZTogSEVMTV9QT0xZTUVSX1RZUEUpOiB2b2lkIHtcbiAgaWYgKG1vbEdyYXBoLm1ldGEuck5vZGVzLmxlbmd0aCA+IDEpIHtcbiAgICBtb2xHcmFwaC5tZXRhLmJhY2tib25lU2hpZnQgPSBbXG4gICAgICBrZWVwUHJlY2lzaW9uKFxuICAgICAgICBtb2xHcmFwaC5hdG9tcy54W21vbEdyYXBoLm1ldGEuck5vZGVzWzFdIC0gMV0gLVxuICAgICAgICBtb2xHcmFwaC5hdG9tcy54W21vbEdyYXBoLm1ldGEudGVybWluYWxOb2Rlc1swXSAtIDFdXG4gICAgICApLFxuICAgICAga2VlcFByZWNpc2lvbihcbiAgICAgICAgbW9sR3JhcGguYXRvbXMueVttb2xHcmFwaC5tZXRhLnJOb2Rlc1sxXSAtIDFdIC1cbiAgICAgICAgbW9sR3JhcGguYXRvbXMueVttb2xHcmFwaC5tZXRhLnRlcm1pbmFsTm9kZXNbMF0gLSAxXVxuICAgICAgKSxcbiAgICBdO1xuICB9XG5cbiAgaWYgKHBvbHltZXJUeXBlID09PSBIRUxNX1BPTFlNRVJfVFlQRS5STkEgJiYgbW9sR3JhcGgubWV0YS5yTm9kZXMubGVuZ3RoID4gMikge1xuICAgIG1vbEdyYXBoLm1ldGEuYnJhbmNoU2hpZnQgPSBbXG4gICAgICBrZWVwUHJlY2lzaW9uKFxuICAgICAgICBtb2xHcmFwaC5hdG9tcy54W21vbEdyYXBoLm1ldGEuck5vZGVzWzJdIC0gMV0gLVxuICAgICAgICBtb2xHcmFwaC5hdG9tcy54W21vbEdyYXBoLm1ldGEudGVybWluYWxOb2Rlc1swXSAtIDFdXG4gICAgICApLFxuICAgICAga2VlcFByZWNpc2lvbihcbiAgICAgICAgbW9sR3JhcGguYXRvbXMueVttb2xHcmFwaC5tZXRhLnJOb2Rlc1syXSAtIDFdIC1cbiAgICAgICAgbW9sR3JhcGguYXRvbXMueVttb2xHcmFwaC5tZXRhLnRlcm1pbmFsTm9kZXNbMF0gLSAxXVxuICAgICAgKSxcbiAgICBdO1xuICB9XG59XG5cbi8qIEhlbHBlciBmdW5jdGlvbiBuZWNlc3NhcnkgdG8gYnVpbGQgYSBjb3JyZWN0IFYzMDAwIG1vbGZpbGUgb3V0IG9mIFYyMDAwIHdpdGhcbiAqIHNwZWNpZmllZCByLWdyb3VwcyovXG5mdW5jdGlvbiByZW1vdmVSR3JvdXBMaW5lcyhtb2xmaWxlVjJLOiBzdHJpbmcpOiBzdHJpbmcge1xuICBsZXQgYmVnaW4gPSBtb2xmaWxlVjJLLmluZGV4T2YoVjJLX0FfTElORSwgMCk7XG4gIGlmIChiZWdpbiA9PT0gLTEpXG4gICAgYmVnaW4gPSBtb2xmaWxlVjJLLmluZGV4T2YoVjJLX1JHUF9MSU5FKTtcbiAgY29uc3QgZW5kID0gbW9sZmlsZVYySy5pbmRleE9mKFYzS19FTkQsIGJlZ2luKTtcbiAgcmV0dXJuIG1vbGZpbGVWMksuc3Vic3RyaW5nKDAsIGJlZ2luKSArIG1vbGZpbGVWMksuc3Vic3RyaW5nKGVuZCk7XG59XG5cbi8qIFYyMDAwIHRvIFYzMDAwIGNvbnZlcnRlciAgKi9cbmZ1bmN0aW9uIGNvbnZlcnRNb2xmaWxlVG9WM0sobW9sZmlsZVYySzogc3RyaW5nLCBtb2R1bGVSZGtpdDogYW55KTogc3RyaW5nIHtcbiAgLy8gdG9kbzogdHlwZSBvZiBtb2R1bGVSZGtpdFxuICAvLyB0b2RvOiBjb25zaWRlciB0aGUgdXNlIG9mIHN0YW5kYXJkIENoZW0gY29udmVydGVyIChyZWxpZXMgb24gY3JlYXRpb24gb2YgbW9kdWxlUmRraXQgb24gZWFjaCBpdGVyYXRpb24sIHRob3VnaClcbiAgY29uc3QgbW9sT2JqID0gbW9kdWxlUmRraXQuZ2V0X21vbChtb2xmaWxlVjJLKTtcbiAgY29uc3QgbW9sZmlsZVYzSyA9IG1vbE9iai5nZXRfdjNLbW9sYmxvY2soKTtcbiAgbW9sT2JqLmRlbGV0ZSgpO1xuICByZXR1cm4gbW9sZmlsZVYzSztcbn1cblxuLyogUGFyc2UgVjMwMDAgYm9uZCBibG9jayBhbmQgY29uc3RydWN0IHRoZSBCb25kcyBvYmplY3QgKi9cbmZ1bmN0aW9uIHBhcnNlQm9uZEJsb2NrKG1vbGZpbGVWM0s6IHN0cmluZywgYm9uZENvdW50OiBudW1iZXIpOiBCb25kcyB7XG4gIC8vIHRvZG86IGNvbnNpZGVyIHRoZSBjYXNlIHdoZW4gdGhlcmUgaXMgbm8gc2ltcGxlIGxlZnRtb3N0L3JpZ2h0bW9zdCBjaG9pY2VcbiAgLy8gdG9kbzogY29uc2lkZXIgdGhlIGNhc2Ugd2hlbiB0aGVyZSBhcmUgbXVsdGlwbGUgY29uc2VxdWVudCBNICBSR1AgbGluZXMsXG4gIC8vIGxpa2UgaW4gSEVMTUNvcmVMaWJyYXJ5IG51Y2xlb3RpZGVzXG5cbiAgY29uc3QgYm9uZFR5cGVzOiBudW1iZXJbXSA9IG5ldyBBcnJheShib25kQ291bnQpO1xuICBjb25zdCBhdG9tUGFpcnM6IG51bWJlcltdW10gPSBuZXcgQXJyYXkoYm9uZENvdW50KTtcbiAgY29uc3QgYm9uZENvbmZpZ3VyYXRpb24gPSBuZXcgTWFwPG51bWJlciwgbnVtYmVyPigpO1xuICBjb25zdCBrd2FyZ3MgPSBuZXcgTWFwPG51bWJlciwgc3RyaW5nPigpO1xuXG4gIGxldCBiZWdpbiA9IG1vbGZpbGVWM0suaW5kZXhPZihWM0tfQkVHSU5fQk9ORF9CTE9DSyk7XG4gIGJlZ2luID0gbW9sZmlsZVYzSy5pbmRleE9mKCdcXG4nLCBiZWdpbik7XG4gIGxldCBlbmQgPSBiZWdpbjtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBib25kQ291bnQ7ICsraSkge1xuICAgIC8vIHBhcnNlIGJvbmQgdHlwZSBhbmQgYXRvbSBwYWlyXG4gICAgY29uc3QgcGFyc2VkVmFsdWVzOiBudW1iZXJbXSA9IG5ldyBBcnJheSgzKTtcbiAgICBiZWdpbiA9IG1vbGZpbGVWM0suaW5kZXhPZihWM0tfQkVHSU5fREFUQV9MSU5FLCBlbmQpICsgVjNLX0lEWF9TSElGVDtcbiAgICBlbmQgPSBtb2xmaWxlVjNLLmluZGV4T2YoJyAnLCBiZWdpbik7XG4gICAgZm9yIChsZXQgayA9IDA7IGsgPCAzOyArK2spIHtcbiAgICAgIGJlZ2luID0gZW5kICsgMTtcbiAgICAgIGVuZCA9IE1hdGgubWluKG1vbGZpbGVWM0suaW5kZXhPZignXFxuJywgYmVnaW4pLCBtb2xmaWxlVjNLLmluZGV4T2YoJyAnLCBiZWdpbikpO1xuICAgICAgcGFyc2VkVmFsdWVzW2tdID0gcGFyc2VJbnQobW9sZmlsZVYzSy5zbGljZShiZWdpbiwgZW5kKSk7XG4gICAgfVxuICAgIGJvbmRUeXBlc1tpXSA9IHBhcnNlZFZhbHVlc1swXTtcbiAgICBhdG9tUGFpcnNbaV0gPSBwYXJzZWRWYWx1ZXMuc2xpY2UoMSk7XG5cbiAgICAvLyBwYXJzZSBrZXl3b3JkIGFyZ3VtZW50c1xuICAgIGNvbnN0IGVuZE9mTGluZSA9IG1vbGZpbGVWM0suaW5kZXhPZignXFxuJywgYmVnaW4pO1xuICAgIGxldCBsaW5lUmVtYWluZGVyID0gbW9sZmlsZVYzSy5zbGljZShlbmQsIGVuZE9mTGluZSk7XG4gICAgbGV0IGJlZ2luQ2ZnID0gbGluZVJlbWFpbmRlci5pbmRleE9mKFYzS19CT05EX0NPTkZJRyk7XG4gICAgaWYgKGJlZ2luQ2ZnICE9PSAtMSkge1xuICAgICAgYmVnaW5DZmcgPSBsaW5lUmVtYWluZGVyLmluZGV4T2YoJz0nLCBiZWdpbkNmZykgKyAxO1xuICAgICAgbGV0IGVuZENmZyA9IGxpbmVSZW1haW5kZXIuaW5kZXhPZignICcsIGJlZ2luQ2ZnKTtcbiAgICAgIGlmIChlbmRDZmcgPT09IC0xKVxuICAgICAgICBlbmRDZmcgPSBsaW5lUmVtYWluZGVyLmxlbmd0aDtcbiAgICAgIGNvbnN0IGJvbmRDb25maWcgPSBwYXJzZUludChsaW5lUmVtYWluZGVyLnNsaWNlKGJlZ2luQ2ZnLCBlbmRDZmcpKTtcbiAgICAgIGJvbmRDb25maWd1cmF0aW9uLnNldChpLCBib25kQ29uZmlnKTtcbiAgICAgIGNvbnN0IHJlbW92ZWRTdWJzdHJpbmcgPSBWM0tfQk9ORF9DT05GSUcgKyBib25kQ29uZmlnLnRvU3RyaW5nKCk7XG4gICAgICBsaW5lUmVtYWluZGVyID0gbGluZVJlbWFpbmRlci5yZXBsYWNlKHJlbW92ZWRTdWJzdHJpbmcsICcnKTtcbiAgICB9XG4gICAgaWYgKCFsaW5lUmVtYWluZGVyKVxuICAgICAga3dhcmdzLnNldChpLCBsaW5lUmVtYWluZGVyKTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgYm9uZFR5cGVzOiBib25kVHlwZXMsXG4gICAgYXRvbVBhaXJzOiBhdG9tUGFpcnMsXG4gICAgYm9uZENvbmZpZ3VyYXRpb246IGJvbmRDb25maWd1cmF0aW9uLFxuICAgIGt3YXJnczoga3dhcmdzLFxuICB9O1xufVxuXG4vKiBDb25zdHJ1Y3RzIG1hcHBpbmcgb2Ygci1ncm91cCBub2RlcyB0byBkZWZhdWx0IGNhcEdyb3VwcywgYWxsIG51bWVyYXRpb24gc3RhcnRpbmcgZnJvbSAxLlxuICogQWNjb3JkaW5nIHRvIGh0dHBzOi8vcHVicy5hY3Mub3JnL2RvaS8xMC4xMDIxL2NpMzAwMTkyNSwgUjEgYW5kIFIyIGFyZSB0aGUgY2hhaW4gZXh0ZW5kaW5nIGF0dGFjaG1lbnQgcG9pbnRzLFxuICogd2hpbGUgUjMgaXMgdGhlIGJyYW5jaGluZyBhdHRhY2htZW50IHBvaW50LiAqL1xuZnVuY3Rpb24gcGFyc2VDYXBHcm91cElkeE1hcChtb2xmaWxlVjJLOiBzdHJpbmcpOiBNYXA8bnVtYmVyLCBudW1iZXI+IHtcbiAgY29uc3QgY2FwR3JvdXBJZHhNYXAgPSBuZXcgTWFwPG51bWJlciwgbnVtYmVyPigpO1xuXG4gIC8vIHBhcnNlIEEtbGluZXMgKFJOQSlcbiAgbGV0IGJlZ2luID0gbW9sZmlsZVYySy5pbmRleE9mKFYyS19BX0xJTkUsIDApO1xuICBsZXQgZW5kID0gYmVnaW47XG4gIHdoaWxlIChiZWdpbiAhPT0gLTEpIHtcbiAgICAvLyBwYXJzZSB0aGUgck5vZGUgdG8gd2hpY2ggdGhlIGNhcCBncm91cCBpcyBhdHRhY2hlZFxuICAgIGVuZCA9IG1vbGZpbGVWMksuaW5kZXhPZignXFxuJywgYmVnaW4pO1xuICAgIGNvbnN0IHJOb2RlID0gcGFyc2VJbnQobW9sZmlsZVYySy5zdWJzdHJpbmcoYmVnaW4sIGVuZCkucmVwbGFjZSgvXkFcXHMrLywgJycpKTtcblxuICAgIC8vIHBhcnNlIHRoZSBjYXBHcm91cCBpbmRleFxuICAgIGJlZ2luID0gbW9sZmlsZVYySy5pbmRleE9mKCdSJywgZW5kKTtcbiAgICBlbmQgPSBtb2xmaWxlVjJLLmluZGV4T2YoJ1xcbicsIGJlZ2luKTtcbiAgICBjb25zdCBjYXBHcm91cCA9IHBhcnNlSW50KG1vbGZpbGVWMksuc3Vic3RyaW5nKGJlZ2luLCBlbmQpLnJlcGxhY2UoL15SLywgJycpKTtcbiAgICBjYXBHcm91cElkeE1hcC5zZXQock5vZGUsIGNhcEdyb3VwKTtcblxuICAgIGJlZ2luID0gbW9sZmlsZVYySy5pbmRleE9mKFYyS19BX0xJTkUsIGVuZCk7XG4gIH1cblxuICAvLyBwYXJzZSBSR1AgbGluZXMgKG1heSBiZSBtb3JlIHRoYW4gb25lIGluIFJOQSBtb25vbWVycylcbiAgYmVnaW4gPSBtb2xmaWxlVjJLLmluZGV4T2YoVjJLX1JHUF9MSU5FLCAwKTtcbiAgZW5kID0gbW9sZmlsZVYySy5pbmRleE9mKCdcXG4nLCBiZWdpbik7XG4gIHdoaWxlIChiZWdpbiAhPT0gLTEpIHtcbiAgICBiZWdpbiArPSBWMktfUkdQX1NISUZUO1xuICAgIGVuZCA9IG1vbGZpbGVWMksuaW5kZXhPZignXFxuJywgYmVnaW4pO1xuICAgIGNvbnN0IHJncFN0cmluZ1BhcnNlZCA9IG1vbGZpbGVWMksuc3Vic3RyaW5nKGJlZ2luLCBlbmQpXG4gICAgICAucmVwbGFjZUFsbCgvXFxzKy9nLCAnICcpXG4gICAgICAuc3BsaXQoJyAnKTtcbiAgICBjb25zdCByZ3BJbmRpY2VzQXJyYXkgPSByZ3BTdHJpbmdQYXJzZWQubWFwKChlbCkgPT4gcGFyc2VJbnQoZWwpKVxuICAgICAgLnNsaWNlKDEpOyAvLyBzbGljZSBmcm9tIDEgYmVjYXVzZSB0aGUgMXN0IHZhbHVlIGlzIHRoZSBudW1iZXIgb2YgcGFpcnMgaW4gdGhlIGxpbmVcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJncEluZGljZXNBcnJheS5sZW5ndGg7IGkgKz0gMikge1xuICAgICAgLy8gbm90aWNlOiB0aGVyZSBtYXkgYmUgY29uZmxpY3RpbmcgY2FwIGdyb3VwIGRlZmluaXRpb25zLCBsaWtlIDMtTy1NZXRoeWxyaWJvc2UgKDIsNSBjb25uZWN0aXZpdHkpXG4gICAgICAvLyAodGhlIGxhc3QgbW9ub21lciBpbiBIRUxNQ29yZUxpYnJhcnkpXG4gICAgICAvLyB0aGVyZSB0aGUgaW5kaWNlcyBvZiBjYXAgZ3JvdXBzIGFyZSBzZWxmLWNvbnRyYWRpY3RvcnlcbiAgICAgIC8vIHRvZG86IGNsYXJpZnkgd2h5IHN1Y2ggc2l0dWF0aW9ucyBvY2N1ciBpbiBwcmluY2lwbGVcbiAgICAgIGlmIChjYXBHcm91cElkeE1hcC5oYXMocmdwSW5kaWNlc0FycmF5W2ldKSAmJiBjYXBHcm91cElkeE1hcC5nZXQocmdwSW5kaWNlc0FycmF5W2ldKSAhPT0gcmdwSW5kaWNlc0FycmF5W2kgKyAxXSlcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGByLWdyb3VwIGluZGV4ICR7cmdwSW5kaWNlc0FycmF5W2ldfSBoYXMgYWxyZWFkeSBiZWVuIGFkZGVkIHdpdGggYSBkaWZmZXJlbnQgdmFsdWVgKTtcbiAgICAgIGVsc2VcbiAgICAgICAgY2FwR3JvdXBJZHhNYXAuc2V0KHJncEluZGljZXNBcnJheVtpXSwgcmdwSW5kaWNlc0FycmF5W2kgKyAxXSk7XG4gICAgfVxuXG4gICAgYmVnaW4gPSBtb2xmaWxlVjJLLmluZGV4T2YoVjJLX1JHUF9MSU5FLCBlbmQpO1xuICB9XG5cbiAgcmV0dXJuIGNhcEdyb3VwSWR4TWFwO1xufVxuXG5mdW5jdGlvbiBwYXJzZUF0b21BbmRCb25kQ291bnRzKG1vbGZpbGVWM0s6IHN0cmluZyk6IHsgYXRvbUNvdW50OiBudW1iZXIsIGJvbmRDb3VudDogbnVtYmVyIH0ge1xuICBtb2xmaWxlVjNLID0gbW9sZmlsZVYzSy5yZXBsYWNlQWxsKCdcXHInLCAnJyk7IC8vIHRvIGhhbmRsZSBvbGQgYW5kIG5ldyBzZGYgc3RhbmRhcmRzXG5cbiAgLy8gcGFyc2UgYXRvbSBjb3VudFxuICBsZXQgYmVnaW4gPSBtb2xmaWxlVjNLLmluZGV4T2YoVjNLX0JFR0lOX0NPVU5UU19MSU5FKSArIFYzS19DT1VOVFNfU0hJRlQ7XG4gIGxldCBlbmQgPSBtb2xmaWxlVjNLLmluZGV4T2YoJyAnLCBiZWdpbik7XG4gIGNvbnN0IG51bU9mQXRvbXMgPSBwYXJzZUludChtb2xmaWxlVjNLLnN1YnN0cmluZyhiZWdpbiwgZW5kKSk7XG5cbiAgLy8gcGFyc2UgYm9uZCBjb3VudFxuICBiZWdpbiA9IGVuZCArIDE7XG4gIGVuZCA9IG1vbGZpbGVWM0suaW5kZXhPZignICcsIGJlZ2luKTtcbiAgY29uc3QgbnVtT2ZCb25kcyA9IHBhcnNlSW50KG1vbGZpbGVWM0suc3Vic3RyaW5nKGJlZ2luLCBlbmQpKTtcblxuICByZXR1cm4ge2F0b21Db3VudDogbnVtT2ZBdG9tcywgYm9uZENvdW50OiBudW1PZkJvbmRzfTtcbn1cblxuLyogUGFyc2UgVjMwMDAgYXRvbSBibG9jayBhbmQgcmV0dXJuIEF0b21zIG9iamVjdC4gTk9USUNFOiBvbmx5IGF0b21UeXBlcywgeCwgeVxuICogYW5kIGt3YXJncyBmaWVsZHMgYXJlIHNldCBpbiB0aGUgcmV0dXJuIHZhbHVlLCB3aXRoIG90aGVyIGZpZWxkcyBkdW1teSAqL1xuZnVuY3Rpb24gcGFyc2VBdG9tQmxvY2sobW9sZmlsZVYzSzogc3RyaW5nLCBhdG9tQ291bnQ6IG51bWJlcik6IEF0b21zIHtcbiAgY29uc3QgYXRvbVR5cGVzOiBzdHJpbmdbXSA9IG5ldyBBcnJheShhdG9tQ291bnQpO1xuICBjb25zdCB4OiBudW1iZXJbXSA9IG5ldyBBcnJheShhdG9tQ291bnQpO1xuICBjb25zdCB5OiBudW1iZXJbXSA9IG5ldyBBcnJheShhdG9tQ291bnQpO1xuICBjb25zdCBrd2FyZ3M6IHN0cmluZ1tdID0gbmV3IEFycmF5KGF0b21Db3VudCk7XG5cbiAgbGV0IGJlZ2luID0gbW9sZmlsZVYzSy5pbmRleE9mKFYzS19CRUdJTl9BVE9NX0JMT0NLKTsgLy8gVjMwMDAgYXRvbXMgYmxvY2tcbiAgYmVnaW4gPSBtb2xmaWxlVjNLLmluZGV4T2YoJ1xcbicsIGJlZ2luKTtcbiAgbGV0IGVuZCA9IGJlZ2luO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXRvbUNvdW50OyBpKyspIHtcbiAgICBiZWdpbiA9IG1vbGZpbGVWM0suaW5kZXhPZihWM0tfQkVHSU5fREFUQV9MSU5FLCBiZWdpbikgKyBWM0tfSURYX1NISUZUO1xuICAgIGVuZCA9IG1vbGZpbGVWM0suaW5kZXhPZignICcsIGJlZ2luKTsgLy8gc2tpcCB0aGUgaWR4IHJvd1xuXG4gICAgLy8gcGFyc2UgYXRvbSB0eXBlXG4gICAgYmVnaW4gPSBlbmQgKyAxO1xuICAgIGVuZCA9IG1vbGZpbGVWM0suaW5kZXhPZignICcsIGJlZ2luKTtcbiAgICBhdG9tVHlwZXNbaV0gPSBtb2xmaWxlVjNLLnN1YnN0cmluZyhiZWdpbiwgZW5kKTtcblxuICAgIC8vIHBhcnNlIFggYW5kIFkgY29vcmRpbmF0ZXMgb2YgdGhlIGF0b21cbiAgICBjb25zdCBjb29yZGluYXRlOiBudW1iZXJbXSA9IG5ldyBBcnJheSgyKTtcbiAgICBmb3IgKGxldCBrID0gMDsgayA8IDI7ICsraykge1xuICAgICAgYmVnaW4gPSBlbmQgKyAxO1xuICAgICAgZW5kID0gbW9sZmlsZVYzSy5pbmRleE9mKCcgJywgYmVnaW4pO1xuICAgICAgY29vcmRpbmF0ZVtrXSA9IHBhcnNlRmxvYXQobW9sZmlsZVYzSy5zdWJzdHJpbmcoYmVnaW4sIGVuZCkpO1xuICAgIH1cbiAgICB4W2ldID0gY29vcmRpbmF0ZVswXTtcbiAgICB5W2ldID0gY29vcmRpbmF0ZVsxXTtcblxuICAgIC8vIHBhcnNlIHRoZSByZW1haW5pbmcgcG9zc2libGUga2V5d29yZCBhcmd1bWVudHNcbiAgICBiZWdpbiA9IGVuZDtcbiAgICBlbmQgPSBtb2xmaWxlVjNLLmluZGV4T2YoJ1xcbicsIGJlZ2luKSArIDE7XG4gICAga3dhcmdzW2ldID0gbW9sZmlsZVYzSy5zbGljZShiZWdpbiwgZW5kKTtcblxuICAgIGJlZ2luID0gZW5kO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBhdG9tVHlwZXM6IGF0b21UeXBlcyxcbiAgICB4OiB4LFxuICAgIHk6IHksXG4gICAga3dhcmdzOiBrd2FyZ3MsXG4gIH07XG59XG5cbi8qIFJlbW92ZSBoeWRyb2dlbiBub2RlcyAqL1xuZnVuY3Rpb24gcmVtb3ZlSHlkcm9nZW4obW9ub21lckdyYXBoOiBNb2xHcmFwaCk6IHZvaWQge1xuICBsZXQgaSA9IDA7XG4gIHdoaWxlIChpIDwgbW9ub21lckdyYXBoLmF0b21zLmF0b21UeXBlcy5sZW5ndGgpIHtcbiAgICBpZiAobW9ub21lckdyYXBoLmF0b21zLmF0b21UeXBlc1tpXSA9PT0gSFlEUk9HRU4pIHtcbiAgICAgIHJlbW92ZU5vZGVBbmRCb25kcyhtb25vbWVyR3JhcGgsIGkgKyAxKTsgLy8gaSArIDEgYmVjYXVzZSBtb2xmaWxlIG5vZGUgaW5kZXhpbmcgc3RhcnRzIGZyb20gMVxuICAgICAgLS1pO1xuICAgICAgLy8gbW9ub21lckdyYXBoLmF0b21zLmF0b21UeXBlc1tpXSA9ICdMaSc7XG4gICAgfVxuICAgICsraTtcbiAgfVxufVxuXG4vKiBSZW1vdmUgbm9kZSAncmVtb3ZlZE5vZGUnIGFuZCB0aGUgYXNzb2NpYXRlZCBib25kcy4gTm90aWNlLCBudW1lcmF0aW9uIG9mXG4gKiBub2RlcyBpbiBtb2xmaWxlcyBzdGFydHMgZnJvbSAxLCBub3QgMCAqL1xuZnVuY3Rpb24gcmVtb3ZlTm9kZUFuZEJvbmRzKG1vbm9tZXJHcmFwaDogTW9sR3JhcGgsIHJlbW92ZWROb2RlPzogbnVtYmVyKTogdm9pZCB7XG4gIGlmICh0eXBlb2YgcmVtb3ZlZE5vZGUgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgY29uc3QgcmVtb3ZlZE5vZGVJZHggPSByZW1vdmVkTm9kZSAtIDE7XG4gICAgY29uc3QgYXRvbXMgPSBtb25vbWVyR3JhcGguYXRvbXM7XG4gICAgY29uc3QgYm9uZHMgPSBtb25vbWVyR3JhcGguYm9uZHM7XG4gICAgY29uc3QgbWV0YSA9IG1vbm9tZXJHcmFwaC5tZXRhO1xuXG4gICAgLy8gcmVtb3ZlIHRoZSBub2RlIGZyb20gYXRvbXNcbiAgICBhdG9tcy5hdG9tVHlwZXMuc3BsaWNlKHJlbW92ZWROb2RlSWR4LCAxKTtcbiAgICBhdG9tcy54LnNwbGljZShyZW1vdmVkTm9kZUlkeCwgMSk7XG4gICAgYXRvbXMueS5zcGxpY2UocmVtb3ZlZE5vZGVJZHgsIDEpO1xuICAgIGF0b21zLmt3YXJncy5zcGxpY2UocmVtb3ZlZE5vZGVJZHgsIDEpO1xuXG4gICAgLy8gdXBkYXRlIHRoZSB2YWx1ZXMgb2YgdGVybWluYWwgYW5kIHItZ3JvdXAgbm9kZXMgaWYgbmVjZXNzYXJ5XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtZXRhLnRlcm1pbmFsTm9kZXMubGVuZ3RoOyArK2kpIHtcbiAgICAgIGlmIChtZXRhLnRlcm1pbmFsTm9kZXNbaV0gPiByZW1vdmVkTm9kZSlcbiAgICAgICAgLS1tZXRhLnRlcm1pbmFsTm9kZXNbaV07XG4gICAgICBlbHNlIGlmIChtZXRhLnRlcm1pbmFsTm9kZXNbaV0gPT09IHJlbW92ZWROb2RlKVxuICAgICAgICBtZXRhLnRlcm1pbmFsTm9kZXNbaV0gPSAtMTsgLy8gc2VudGluZWwgdG8gbWFyayB0aGUgdmFsdWUgYXMgcmVtb3ZlZFxuICAgIH1cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1ldGEuck5vZGVzLmxlbmd0aDsgKytpKSB7XG4gICAgICBpZiAobWV0YS5yTm9kZXNbaV0gPiByZW1vdmVkTm9kZSlcbiAgICAgICAgLS1tZXRhLnJOb2Rlc1tpXTtcbiAgICAgIGVsc2UgaWYgKG1ldGEuck5vZGVzW2ldID09PSByZW1vdmVkTm9kZSlcbiAgICAgICAgbWV0YS5yTm9kZXNbaV0gPSAtMTsgLy8gc2VudGluZWwgdG8gbWFyayB0aGUgdmFsdWUgYXMgcmVtb3ZlZFxuICAgIH1cblxuICAgIC8vIHVwZGF0ZSBpbmRpY2VzIG9mIGF0b21zIGluIGJvbmRzXG4gICAgbGV0IGkgPSAwO1xuICAgIHdoaWxlIChpIDwgYm9uZHMuYXRvbVBhaXJzLmxlbmd0aCkge1xuICAgICAgY29uc3QgZmlyc3RBdG9tID0gYm9uZHMuYXRvbVBhaXJzW2ldWzBdO1xuICAgICAgY29uc3Qgc2Vjb25kQXRvbSA9IGJvbmRzLmF0b21QYWlyc1tpXVsxXTtcbiAgICAgIGlmIChmaXJzdEF0b20gPT09IHJlbW92ZWROb2RlIHx8IHNlY29uZEF0b20gPT09IHJlbW92ZWROb2RlKSB7XG4gICAgICAgIGJvbmRzLmF0b21QYWlycy5zcGxpY2UoaSwgMSk7XG4gICAgICAgIGJvbmRzLmJvbmRUeXBlcy5zcGxpY2UoaSwgMSk7XG4gICAgICAgIGlmIChib25kcy5ib25kQ29uZmlndXJhdGlvbi5oYXMoaSkpXG4gICAgICAgICAgYm9uZHMuYm9uZENvbmZpZ3VyYXRpb24uZGVsZXRlKGkpO1xuICAgICAgICBpZiAoYm9uZHMua3dhcmdzLmhhcyhpKSlcbiAgICAgICAgICBib25kcy5rd2FyZ3MuZGVsZXRlKGkpO1xuICAgICAgICAtLWk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBib25kcy5hdG9tUGFpcnNbaV1bMF0gPSAoZmlyc3RBdG9tID4gcmVtb3ZlZE5vZGUpID8gZmlyc3RBdG9tIC0gMSA6IGZpcnN0QXRvbTtcbiAgICAgICAgYm9uZHMuYXRvbVBhaXJzW2ldWzFdID0gKHNlY29uZEF0b20gPiByZW1vdmVkTm9kZSkgPyBzZWNvbmRBdG9tIC0gMSA6IHNlY29uZEF0b207XG4gICAgICB9XG4gICAgICArK2k7XG4gICAgfVxuXG4gICAgLy8gdXBkYXRlIGJvbmRDb25maWd1cmF0aW9uIGFuZCBrd2FyZ3Mga2V5c1xuICAgIGxldCBrZXlzID0gQXJyYXkuZnJvbShib25kcy5ib25kQ29uZmlndXJhdGlvbi5rZXlzKCkpO1xuICAgIGtleXMuZm9yRWFjaCgoa2V5KSA9PiB7XG4gICAgICBpZiAoYm9uZHMuYm9uZENvbmZpZ3VyYXRpb24uaGFzKGtleSkgJiYga2V5ID4gcmVtb3ZlZE5vZGVJZHgpIHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSBib25kcy5ib25kQ29uZmlndXJhdGlvbi5nZXQoa2V5KSE7XG4gICAgICAgIGJvbmRzLmJvbmRDb25maWd1cmF0aW9uLmRlbGV0ZShrZXkpO1xuICAgICAgICBib25kcy5ib25kQ29uZmlndXJhdGlvbi5zZXQoa2V5IC0gMSwgdmFsdWUpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIGtleXMgPSBBcnJheS5mcm9tKGJvbmRzLmt3YXJncy5rZXlzKCkpO1xuICAgIGtleXMuZm9yRWFjaCgoa2V5KSA9PiB7XG4gICAgICBpZiAoYm9uZHMua3dhcmdzLmhhcyhrZXkpICYmIGtleSA+IHJlbW92ZWROb2RlSWR4KSB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gYm9uZHMua3dhcmdzLmdldChrZXkpITtcbiAgICAgICAgYm9uZHMua3dhcmdzLmRlbGV0ZShrZXkpO1xuICAgICAgICBib25kcy5rd2FyZ3Muc2V0KGtleSAtIDEsIHZhbHVlKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxufVxuXG4vLyB0b2RvOiByZXdyaXRlIGRlc2NyaXB0aW9uXG4vKiBBZGp1c3QgdGhlIChwZXB0aWRlKSBtb25vbWVyIGdyYXBoIHNvIHRoYXQgaXQgaGFzIHN0YW5kYXJkIGZvcm0gICovXG5mdW5jdGlvbiBhZGp1c3RQZXB0aWRlTW9ub21lckdyYXBoKG1vbm9tZXI6IE1vbEdyYXBoKTogdm9pZCB7XG4gIGNvbnN0IG5vZGVPbmVJZHggPSBtb25vbWVyLm1ldGEudGVybWluYWxOb2Rlc1swXSAtIDE7IC8vIG5vZGUgaW5kZXhpbmcgaW4gbW9sZmlsZXMgc3RhcnRzIGZyb20gMVxuICBjb25zdCBub2RlVHdvSWR4ID0gbW9ub21lci5tZXRhLnJOb2Rlc1swXSAtIDE7XG4gIGNvbnN0IHggPSBtb25vbWVyLmF0b21zLng7XG4gIGNvbnN0IHkgPSBtb25vbWVyLmF0b21zLnk7XG5cbiAgLy8gcGxhY2Ugbm9kZU9uZSBhdCBvcmlnaW5cbiAgc2hpZnRDb29yZGluYXRlcyhtb25vbWVyLCAteFtub2RlT25lSWR4XSwgLXlbbm9kZU9uZUlkeF0pO1xuXG4gIC8vIGFuZ2xlIGlzIG1lYXN1cmVkIGJldHdlZW4gT1kgYW5kIHRoZSByb3RhdGVkIG5vZGVcbiAgY29uc3QgYW5nbGUgPSBmaW5kQW5nbGVXaXRoT1koeFtub2RlVHdvSWR4XSwgeVtub2RlVHdvSWR4XSk7XG5cbiAgLy8gcm90YXRlIHRoZSBjZW50ZXJlZCBncmFwaCwgc28gdGhhdCAnbm9kZVR3bycgZW5kcyB1cCBvbiB0aGUgcG9zaXRpdmUgcmF5IG9mIE9ZXG4gIHJvdGF0ZUNlbnRlcmVkR3JhcGgobW9ub21lci5hdG9tcywgLWFuZ2xlKTtcblxuICBpZiAoeFttb25vbWVyLm1ldGEuck5vZGVzWzFdIC0gMV0gPCAwKVxuICAgIGZsaXBNb25vbWVyQXJvdW5kT1kobW9ub21lcik7XG5cbiAgY29uc3QgZG91YmxlQm9uZGVkT3h5Z2VuID0gZmluZERvdWJsZUJvbmRlZENhcmJvbnlsT3h5Z2VuKG1vbm9tZXIpO1xuXG4gIC8vIGZsaXAgY2FyYm94eWwgYW5kIFIgaWYgbmVjZXNzYXJ5XG4gIGZsaXBDYXJib3h5bEFuZFJhZGljYWwobW9ub21lciwgZG91YmxlQm9uZGVkT3h5Z2VuKTtcblxuICAvLyBmbGlwIGh5ZHJveHlsIGdyb3VwIHdpdGggZG91YmxlLWJvdW5kIE8gaW5zaWRlIGNhcmJveHlsIGdyb3VwIGlmIG5lY2Vzc2FyeVxuICBmbGlwSHlkcm94aWxHcm91cChtb25vbWVyLCBkb3VibGVCb25kZWRPeHlnZW4pO1xufVxuXG5mdW5jdGlvbiBhZGp1c3RQaG9zcGhhdGVNb25vbWVyR3JhcGgobW9ub21lcjogTW9sR3JhcGgpOiB2b2lkIHtcbiAgY29uc3Qgbm9kZU9uZUlkeCA9IG1vbm9tZXIubWV0YS50ZXJtaW5hbE5vZGVzWzBdIC0gMTsgLy8gbm9kZSBpbmRleGluZyBpbiBtb2xmaWxlcyBzdGFydHMgZnJvbSAxXG4gIGNvbnN0IG5vZGVUd29JZHggPSBtb25vbWVyLm1ldGEuck5vZGVzWzBdIC0gMTtcbiAgY29uc3QgeCA9IG1vbm9tZXIuYXRvbXMueDtcbiAgY29uc3QgeSA9IG1vbm9tZXIuYXRvbXMueTtcblxuICAvLyBwbGFjZSBub2RlT25lIGF0IG9yaWdpblxuICBzaGlmdENvb3JkaW5hdGVzKG1vbm9tZXIsIC14W25vZGVPbmVJZHhdLCAteVtub2RlT25lSWR4XSk7XG5cbiAgLy8gLy8gYW5nbGUgaXMgbWVhc3VyZWQgYmV0d2VlbiBPWSBhbmQgdGhlIHJvdGF0ZWQgbm9kZVxuICAvLyBjb25zdCBhbmdsZSA9IGZpbmRBbmdsZVdpdGhPWSh4W25vZGVUd29JZHhdLCB5W25vZGVUd29JZHhdKTtcblxuICAvLyAvLyByb3RhdGUgdGhlIGNlbnRlcmVkIGdyYXBoLCBzbyB0aGF0ICdub2RlVHdvJyBlbmRzIHVwIG9uIHRoZSBwb3NpdGl2ZSByYXkgb2YgT1lcbiAgLy8gcm90YXRlQ2VudGVyZWRHcmFwaChtb25vbWVyLmF0b21zLCAtYW5nbGUpO1xuXG4gIC8vIGlmICh4W21vbm9tZXIubWV0YS5yTm9kZXNbMV0gLSAxXSA8IDApXG4gIC8vICAgZmxpcE1vbm9tZXJBcm91bmRPWShtb25vbWVyKTtcblxuICAvLyBjb25zdCBkb3VibGVCb25kZWRPeHlnZW4gPSBmaW5kRG91YmxlQm9uZGVkQ2FyYm9ueWxPeHlnZW4obW9ub21lcik7XG5cbiAgLy8gLy8gZmxpcCBjYXJib3h5bCBhbmQgUiBpZiBuZWNlc3NhcnlcbiAgLy8gZmxpcENhcmJveHlsQW5kUmFkaWNhbChtb25vbWVyLCBkb3VibGVCb25kZWRPeHlnZW4pO1xuXG4gIC8vIC8vIGZsaXAgaHlkcm94eWwgZ3JvdXAgd2l0aCBkb3VibGUtYm91bmQgTyBpbnNpZGUgY2FyYm94eWwgZ3JvdXAgaWYgbmVjZXNzYXJ5XG4gIC8vIGZsaXBIeWRyb3hpbEdyb3VwKG1vbm9tZXIsIGRvdWJsZUJvbmRlZE94eWdlbik7XG59XG5cbmZ1bmN0aW9uIGFkanVzdFN1Z2FyTW9ub21lckdyYXBoKG1vbm9tZXI6IE1vbEdyYXBoKTogdm9pZCB7XG4gIGNvbnN0IG5vZGVPbmVJZHggPSBtb25vbWVyLm1ldGEudGVybWluYWxOb2Rlc1swXSAtIDE7IC8vIG5vZGUgaW5kZXhpbmcgaW4gbW9sZmlsZXMgc3RhcnRzIGZyb20gMVxuICBjb25zdCBub2RlVHdvSWR4ID0gbW9ub21lci5tZXRhLnJOb2Rlc1swXSAtIDE7XG4gIGNvbnN0IHggPSBtb25vbWVyLmF0b21zLng7XG4gIGNvbnN0IHkgPSBtb25vbWVyLmF0b21zLnk7XG5cbiAgLy8gcGxhY2Ugbm9kZU9uZSBhdCBvcmlnaW5cbiAgc2hpZnRDb29yZGluYXRlcyhtb25vbWVyLCAteFtub2RlT25lSWR4XSwgLXlbbm9kZU9uZUlkeF0pO1xuXG4gIC8vIC8vIGFuZ2xlIGlzIG1lYXN1cmVkIGJldHdlZW4gT1kgYW5kIHRoZSByb3RhdGVkIG5vZGVcbiAgLy8gY29uc3QgYW5nbGUgPSBmaW5kQW5nbGVXaXRoT1koeFtub2RlVHdvSWR4XSwgeVtub2RlVHdvSWR4XSk7XG5cbiAgLy8gLy8gcm90YXRlIHRoZSBjZW50ZXJlZCBncmFwaCwgc28gdGhhdCAnbm9kZVR3bycgZW5kcyB1cCBvbiB0aGUgcG9zaXRpdmUgcmF5IG9mIE9ZXG4gIC8vIHJvdGF0ZUNlbnRlcmVkR3JhcGgobW9ub21lci5hdG9tcywgLWFuZ2xlKTtcblxuICAvLyBpZiAoeFttb25vbWVyLm1ldGEuck5vZGVzWzFdIC0gMV0gPCAwKVxuICAvLyAgIGZsaXBNb25vbWVyQXJvdW5kT1kobW9ub21lcik7XG5cbiAgLy8gY29uc3QgZG91YmxlQm9uZGVkT3h5Z2VuID0gZmluZERvdWJsZUJvbmRlZENhcmJvbnlsT3h5Z2VuKG1vbm9tZXIpO1xuXG4gIC8vIC8vIGZsaXAgY2FyYm94eWwgYW5kIFIgaWYgbmVjZXNzYXJ5XG4gIC8vIGZsaXBDYXJib3h5bEFuZFJhZGljYWwobW9ub21lciwgZG91YmxlQm9uZGVkT3h5Z2VuKTtcblxuICAvLyAvLyBmbGlwIGh5ZHJveHlsIGdyb3VwIHdpdGggZG91YmxlLWJvdW5kIE8gaW5zaWRlIGNhcmJveHlsIGdyb3VwIGlmIG5lY2Vzc2FyeVxuICAvLyBmbGlwSHlkcm94aWxHcm91cChtb25vbWVyLCBkb3VibGVCb25kZWRPeHlnZW4pO1xufVxuXG5mdW5jdGlvbiBhZGp1c3RCYXNlTW9ub21lckdyYXBoKG1vbm9tZXI6IE1vbEdyYXBoKTogdm9pZCB7XG4gIGNvbnN0IG5vZGVPbmVJZHggPSBtb25vbWVyLm1ldGEudGVybWluYWxOb2Rlc1swXSAtIDE7IC8vIG5vZGUgaW5kZXhpbmcgaW4gbW9sZmlsZXMgc3RhcnRzIGZyb20gMVxuICBjb25zdCBub2RlVHdvSWR4ID0gbW9ub21lci5tZXRhLnJOb2Rlc1swXSAtIDE7XG4gIGNvbnN0IHggPSBtb25vbWVyLmF0b21zLng7XG4gIGNvbnN0IHkgPSBtb25vbWVyLmF0b21zLnk7XG5cbiAgLy8gcGxhY2Ugbm9kZU9uZSBhdCBvcmlnaW5cbiAgc2hpZnRDb29yZGluYXRlcyhtb25vbWVyLCAteFtub2RlT25lSWR4XSwgLXlbbm9kZU9uZUlkeF0pO1xuXG4gIC8vIC8vIGFuZ2xlIGlzIG1lYXN1cmVkIGJldHdlZW4gT1kgYW5kIHRoZSByb3RhdGVkIG5vZGVcbiAgLy8gY29uc3QgYW5nbGUgPSBmaW5kQW5nbGVXaXRoT1koeFtub2RlVHdvSWR4XSwgeVtub2RlVHdvSWR4XSk7XG5cbiAgLy8gLy8gcm90YXRlIHRoZSBjZW50ZXJlZCBncmFwaCwgc28gdGhhdCAnbm9kZVR3bycgZW5kcyB1cCBvbiB0aGUgcG9zaXRpdmUgcmF5IG9mIE9ZXG4gIC8vIHJvdGF0ZUNlbnRlcmVkR3JhcGgobW9ub21lci5hdG9tcywgLWFuZ2xlKTtcblxuICAvLyBpZiAoeFttb25vbWVyLm1ldGEuck5vZGVzWzFdIC0gMV0gPCAwKVxuICAvLyAgIGZsaXBNb25vbWVyQXJvdW5kT1kobW9ub21lcik7XG5cbiAgLy8gY29uc3QgZG91YmxlQm9uZGVkT3h5Z2VuID0gZmluZERvdWJsZUJvbmRlZENhcmJvbnlsT3h5Z2VuKG1vbm9tZXIpO1xuXG4gIC8vIC8vIGZsaXAgY2FyYm94eWwgYW5kIFIgaWYgbmVjZXNzYXJ5XG4gIC8vIGZsaXBDYXJib3h5bEFuZFJhZGljYWwobW9ub21lciwgZG91YmxlQm9uZGVkT3h5Z2VuKTtcblxuICAvLyAvLyBmbGlwIGh5ZHJveHlsIGdyb3VwIHdpdGggZG91YmxlLWJvdW5kIE8gaW5zaWRlIGNhcmJveHlsIGdyb3VwIGlmIG5lY2Vzc2FyeVxuICAvLyBmbGlwSHlkcm94aWxHcm91cChtb25vbWVyLCBkb3VibGVCb25kZWRPeHlnZW4pO1xufVxuXG4vKiBGbGlwIGNhcmJveHlsIGdyb3VwIHdpdGggdGhlIHJhZGljYWwgaW4gYSBwZXB0aWRlIG1vbm9tZXIgaW4gY2FzZSB0aGVcbiAqIGNhcmJveHlsIGdyb3VwIGlzIGluIHRoZSBsb3dlciBoYWxmLXBsYW5lICovXG5mdW5jdGlvbiBmbGlwQ2FyYm94eWxBbmRSYWRpY2FsKG1vbm9tZXI6IE1vbEdyYXBoLCBkb3VibGVCb25kZWRPeHlnZW46IG51bWJlcik6IHZvaWQge1xuICAvLyB2ZXJpZnkgdGhhdCB0aGUgY2FyYm94eWwgZ3JvdXAgaXMgaW4gdGhlIGxvd2VyIGhhbGYtcGxhbmVcbiAgaWYgKG1vbm9tZXIuYXRvbXMueVttb25vbWVyLm1ldGEuck5vZGVzWzFdIC0gMV0gPCAwICYmXG4gICAgbW9ub21lci5hdG9tcy55W2RvdWJsZUJvbmRlZE94eWdlbiAtIDFdIDwgMCkge1xuICAgIGZsaXBNb25vbWVyQXJvdW5kT1gobW9ub21lcik7XG5cbiAgICByb3RhdGVDZW50ZXJlZEdyYXBoKG1vbm9tZXIuYXRvbXMsXG4gICAgICAtZmluZEFuZ2xlV2l0aE9YKFxuICAgICAgICBtb25vbWVyLmF0b21zLnhbbW9ub21lci5tZXRhLnRlcm1pbmFsTm9kZXNbMV0gLSAxXSxcbiAgICAgICAgbW9ub21lci5hdG9tcy55W21vbm9tZXIubWV0YS50ZXJtaW5hbE5vZGVzWzFdIC0gMV1cbiAgICAgIClcbiAgICApO1xuICB9XG59XG5cbi8qIEZpbmRzIGFuZ2xlIGJldHdlZW4gT1kgYW5kIHRoZSByYXkgam9pbmluZyBvcmlnaW4gd2l0aCAoeCwgeSkgKi9cbmZ1bmN0aW9uIGZpbmRBbmdsZVdpdGhPWSh4OiBudW1iZXIsIHk6IG51bWJlcik6IG51bWJlciB7XG4gIGxldCBhbmdsZTtcbiAgaWYgKHggPT09IDApIHtcbiAgICBhbmdsZSA9IHkgPiAwID8gMCA6IE1hdGguUEk7XG4gIH0gZWxzZSBpZiAoeSA9PT0gMCkge1xuICAgIGFuZ2xlID0geCA+IDAgPyAtTWF0aC5QSSAvIDIgOiBNYXRoLlBJIC8gMjtcbiAgfSBlbHNlIHtcbiAgICBjb25zdCB0YW4gPSB5IC8geDtcbiAgICBjb25zdCBhdGFuID0gTWF0aC5hdGFuKHRhbik7XG4gICAgYW5nbGUgPSAoeCA8IDApID8gTWF0aC5QSSAvIDIgKyBhdGFuIDogLU1hdGguUEkgLyAyICsgYXRhbjtcbiAgfVxuICByZXR1cm4gYW5nbGU7XG59XG5cbi8qIEZpbmRzIGFuZ2xlIGJldHdlZW4gT1ggYW5kIHRoZSByYXkgam9pbmluZyBvcmlnaW4gd2l0aCAoeCwgeSkgKi9cbmZ1bmN0aW9uIGZpbmRBbmdsZVdpdGhPWCh4OiBudW1iZXIsIHk6IG51bWJlcik6IG51bWJlciB7XG4gIHJldHVybiBmaW5kQW5nbGVXaXRoT1koeCwgeSkgKyBNYXRoLlBJIC8gMjtcbn1cblxuLyogIFJvdGF0ZSB0aGUgZ3JhcGggYXJvdW5kIHRoZSBvcmlnaW4gYnkgJ2FuZ2xlJyAqL1xuZnVuY3Rpb24gcm90YXRlQ2VudGVyZWRHcmFwaChhdG9tczogQXRvbXMsIGFuZ2xlOiBudW1iZXIpOiB2b2lkIHtcbiAgaWYgKGFuZ2xlICE9PSAwKSB7XG4gICAgY29uc3QgeCA9IGF0b21zLng7XG4gICAgY29uc3QgeSA9IGF0b21zLnk7XG5cbiAgICBjb25zdCBjb3MgPSBNYXRoLmNvcyhhbmdsZSk7XG4gICAgY29uc3Qgc2luID0gTWF0aC5zaW4oYW5nbGUpO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB4Lmxlbmd0aDsgKytpKSB7XG4gICAgICBjb25zdCB0bXAgPSB4W2ldO1xuICAgICAgeFtpXSA9IGtlZXBQcmVjaXNpb24odG1wICogY29zIC0geVtpXSAqIHNpbik7XG4gICAgICB5W2ldID0ga2VlcFByZWNpc2lvbih0bXAgKiBzaW4gKyB5W2ldICogY29zKTtcbiAgICB9XG4gIH1cbn1cblxuLyogRmxpcCBtb25vbWVyIGdyYXBoIGFyb3VuZCBPWCBheGlzIHByZXNlcnZpbmcgc3RlcmVvbWV0cnkgKi9cbmZ1bmN0aW9uIGZsaXBNb25vbWVyQXJvdW5kT1gobW9ub21lcjogTW9sR3JhcGgpOiB2b2lkIHtcbiAgZmxpcE1vbEdyYXBoKG1vbm9tZXIsIHRydWUpO1xufVxuXG4vKiBGbGlwIG1vbm9tZXIgZ3JhcGggYXJvdW5kIE9ZIGF4aXMgcHJlc2VydmluZyBzdGVyZW9tZXRyeSAqL1xuZnVuY3Rpb24gZmxpcE1vbm9tZXJBcm91bmRPWShtb25vbWVyOiBNb2xHcmFwaCk6IHZvaWQge1xuICBmbGlwTW9sR3JhcGgobW9ub21lciwgZmFsc2UpO1xufVxuXG4vKiBGbGlwIGdyYXBoIGFyb3VuZCBhIHNwZWNpZmllZCBheGlzOiAndHJ1ZScgY29ycmVzcG9uZHMgdG8gT1gsICdmYWxzZScgdG8gT1kgKi9cbmZ1bmN0aW9uIGZsaXBNb2xHcmFwaChtb2xHcmFwaDogTW9sR3JhcGgsIGF4aXM6IGJvb2xlYW4pOiB2b2lkIHtcbiAgaWYgKGF4aXMpIHsgLy8gZmxpcHBpbmcgYXJvdW5kIE9YXG4gICAgY29uc3QgeSA9IG1vbEdyYXBoLmF0b21zLnk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB5Lmxlbmd0aDsgaSsrKVxuICAgICAgeVtpXSA9IC15W2ldO1xuICB9IGVsc2UgeyAvLyBmbGlwcGluZyBhcm91bmQgT1lcbiAgICBjb25zdCB4ID0gbW9sR3JhcGguYXRvbXMueDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHgubGVuZ3RoOyBpKyspXG4gICAgICB4W2ldID0gLXhbaV07XG4gIH1cblxuICAvLyBwcmVzZXJ2ZSB0aGUgc3RlcmVvbWV0cnlcbiAgY29uc3Qgb3JpZW50YXRpb24gPSBtb2xHcmFwaC5ib25kcy5ib25kQ29uZmlndXJhdGlvbjtcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2Ygb3JpZW50YXRpb24pIHtcbiAgICBjb25zdCBuZXdWYWx1ZSA9IHZhbHVlID09PSAxID8gMyA6IDE7XG4gICAgb3JpZW50YXRpb24uc2V0KGtleSwgbmV3VmFsdWUpO1xuICB9XG59XG5cbi8qIEZsaXBzIGRvdWJsZS1ib25kZWQgJ08nIGluIGNhcmJvbnlsIGdyb3VwIHdpdGggJ09IJyBpbiBvcmRlciBmb3IgdGhlIG1vbm9tZXJzXG4gKiB0byBoYXZlIHN0YW5kYXJkIHJlcHJlc2VudGF0aW9uIHNpbXBsaWZ5aW5nIHRoZWlyIGNvbmNhdGVuYXRpb24uIFRoZVxuICogbW9ub21lciBtdXN0IGFscmVhZHkgYmUgYWRqdXN0ZWQgd2l0aCBhZGp1c3RQZXB0aWRlTW9ub21lckdyYXBoIGluIG9yZGVyIGZvciB0aGlzIGZ1bmN0aW9uIHRvIGJlIGltcGxlbWVudGVkICAqL1xuZnVuY3Rpb24gZmxpcEh5ZHJveGlsR3JvdXAobW9ub21lcjogTW9sR3JhcGgsIGRvdWJsZUJvbmRlZE94eWdlbjogbnVtYmVyKTogdm9pZCB7XG4gIGNvbnN0IHggPSBtb25vbWVyLmF0b21zLng7XG4gIC8vIC0xIGJlbG93IGJlY2F1c2UgaW5kZXhpbmcgb2Ygbm9kZXMgaW4gbW9sZmlsZXMgc3RhcnRzIGZyb20gMSwgdW5saWtlIGFycmF5c1xuICBpZiAoeFttb25vbWVyLm1ldGEuck5vZGVzWzFdIC0gMV0gPiB4W2RvdWJsZUJvbmRlZE94eWdlbiAtIDFdKVxuICAgIHN3YXBOb2Rlcyhtb25vbWVyLCBkb3VibGVCb25kZWRPeHlnZW4sIG1vbm9tZXIubWV0YS5yTm9kZXNbMV0pO1xufVxuXG4vKiBEZXRlcm1pbmUgdGhlIG51bWJlciBvZiBub2RlIChzdGFydGluZyBmcm9tIDEpIGNvcnJlc3BvbmRpbmcgdG8gdGhlXG4gKiBkb3VibGUtYm9uZGVkIG94eWdlbiBvZiB0aGUgY2FyYm9ueWwgZ3JvdXAgICovXG5mdW5jdGlvbiBmaW5kRG91YmxlQm9uZGVkQ2FyYm9ueWxPeHlnZW4obW9ub21lcjogTW9sR3JhcGgpOiBudW1iZXIge1xuICBjb25zdCBib25kc01hcCA9IGNvbnN0cnVjdEJvbmRzTWFwKG1vbm9tZXIpO1xuICBsZXQgZG91YmxlQm9uZGVkT3h5Z2VuID0gMDtcbiAgbGV0IGkgPSAwO1xuICAvLyBpdGVyYXRlIG92ZXIgdGhlIG5vZGVzIGJvbmRlZCB0byB0aGUgY2FyYm9uIGFuZCBmaW5kIHRoZSBkb3VibGUgb25lXG4gIHdoaWxlIChkb3VibGVCb25kZWRPeHlnZW4gPT09IDApIHtcbiAgICBjb25zdCBub2RlID0gYm9uZHNNYXAuZ2V0KG1vbm9tZXIubWV0YS50ZXJtaW5hbE5vZGVzWzFdKSFbaV07XG4gICAgaWYgKG1vbm9tZXIuYXRvbXMuYXRvbVR5cGVzW25vZGUgLSAxXSA9PT0gT1hZR0VOICYmIG5vZGUgIT09IG1vbm9tZXIubWV0YS5yTm9kZXNbMV0pXG4gICAgICBkb3VibGVCb25kZWRPeHlnZW4gPSBub2RlO1xuICAgIGkrKztcbiAgfVxuICByZXR1cm4gZG91YmxlQm9uZGVkT3h5Z2VuO1xufVxuXG4vKiBTd2FwIHRoZSBDYXJ0ZXNpYW4gY29vcmRpbmF0ZXMgb2YgdGhlIHR3byBzcGVjaWZpZWQgbm9kZXMgaW4gTW9sR3JhcGggICovXG5mdW5jdGlvbiBzd2FwTm9kZXMobW9ub21lcjogTW9sR3JhcGgsIG5vZGVPbmU6IG51bWJlciwgbm9kZVR3bzogbnVtYmVyKTogdm9pZCB7XG4gIGNvbnN0IG5vZGVPbmVJZHggPSBub2RlT25lIC0gMTtcbiAgY29uc3Qgbm9kZVR3b0lkeCA9IG5vZGVUd28gLSAxO1xuICBjb25zdCB4ID0gbW9ub21lci5hdG9tcy54O1xuICBjb25zdCB5ID0gbW9ub21lci5hdG9tcy55O1xuICBjb25zdCB0bXBYID0geFtub2RlT25lSWR4XTtcbiAgY29uc3QgdG1wWSA9IHlbbm9kZU9uZUlkeF07XG4gIHhbbm9kZU9uZUlkeF0gPSB4W25vZGVUd29JZHhdO1xuICB5W25vZGVPbmVJZHhdID0geVtub2RlVHdvSWR4XTtcbiAgeFtub2RlVHdvSWR4XSA9IHRtcFg7XG4gIHlbbm9kZVR3b0lkeF0gPSB0bXBZO1xufVxuXG4vLyB0b2RvOiBkb2NcbmZ1bmN0aW9uIGNvbnN0cnVjdEJvbmRzTWFwKG1vbm9tZXI6IE1vbEdyYXBoKTogTWFwPG51bWJlciwgQXJyYXk8bnVtYmVyPj4ge1xuICBjb25zdCBtYXAgPSBuZXcgTWFwPG51bWJlciwgQXJyYXk8bnVtYmVyPj4oKTtcbiAgZm9yIChjb25zdCBhdG9tUGFpcnMgb2YgbW9ub21lci5ib25kcy5hdG9tUGFpcnMpIHtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IDI7IGkrKykge1xuICAgICAgY29uc3Qga2V5ID0gYXRvbVBhaXJzW2ldO1xuICAgICAgY29uc3QgdmFsdWUgPSBhdG9tUGFpcnNbKGkgKyAxKSAlIDJdO1xuICAgICAgaWYgKG1hcC5oYXMoa2V5KSlcbiAgICAgICAgbWFwLmdldChrZXkpPy5wdXNoKHZhbHVlKTtcbiAgICAgIGVsc2VcbiAgICAgICAgbWFwLnNldChrZXksIG5ldyBBcnJheTxudW1iZXI+KDEpLmZpbGwodmFsdWUpKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG1hcDtcbn1cblxuLyogU2hpZnQgbW9sR3JhcGggaW4gdGhlIFhPWSBwbGFuZSAgKi9cbmZ1bmN0aW9uIHNoaWZ0Q29vcmRpbmF0ZXMobW9sR3JhcGg6IE1vbEdyYXBoLCB4U2hpZnQ6IG51bWJlciwgeVNoaWZ0PzogbnVtYmVyKTogdm9pZCB7XG4gIGNvbnN0IHggPSBtb2xHcmFwaC5hdG9tcy54O1xuICBjb25zdCB5ID0gbW9sR3JhcGguYXRvbXMueTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB4Lmxlbmd0aDsgKytpKSB7XG4gICAgeFtpXSA9IGtlZXBQcmVjaXNpb24oeFtpXSArIHhTaGlmdCk7XG4gICAgaWYgKHR5cGVvZiB5U2hpZnQgIT09ICd1bmRlZmluZWQnKVxuICAgICAgeVtpXSA9IGtlZXBQcmVjaXNpb24oeVtpXSArIHlTaGlmdCk7XG4gIH1cbn1cblxuLyogVHJhbnNsYXRlIGEgc2VxdWVuY2Ugb2YgbW9ub21lciBzeW1ib2xzIGludG8gTW9sZmlsZSBWMzAwMCAqL1xuZnVuY3Rpb24gbW9ub21lclNlcVRvTW9sZmlsZShcbiAgbW9ub21lclNlcTogc3RyaW5nW10sIG1vbm9tZXJzRGljdDogTWFwPHN0cmluZywgTW9sR3JhcGg+LCBhbHBoYWJldDogQUxQSEFCRVQsIHBvbHltZXJUeXBlOiBIRUxNX1BPTFlNRVJfVFlQRVxuKTogc3RyaW5nIHtcbiAgLy8gdG9kbzogaGFuZGxlIHRoZSBjYXNlIHdoZW4gdGhlIHBvbHltZXIgaXMgZW1wdHlcbiAgaWYgKG1vbm9tZXJTZXEubGVuZ3RoID09PSAwKVxuICAgIHRocm93IG5ldyBFcnJvcignbW9ub21lclNlcSBpcyBlbXB0eScpO1xuXG4gIC8vIGRlZmluZSBhdG9tIGFuZCBib25kIGNvdW50cywgdGFraW5nIGludG8gYWNjb3VudCB0aGUgYm9uZCB0eXBlXG4gIGNvbnN0IHthdG9tQ291bnQsIGJvbmRDb3VudH0gPSBnZXRSZXN1bHRpbmdBdG9tQm9uZENvdW50cyhtb25vbWVyU2VxLCBtb25vbWVyc0RpY3QsIGFscGhhYmV0LCBwb2x5bWVyVHlwZSk7XG5cbiAgLy8gY3JlYXRlIGFycmF5cyB0byBzdG9yZSBsaW5lcyBvZiB0aGUgcmVzdWx0aW5nIG1vbGZpbGVcbiAgY29uc3QgbW9sZmlsZUF0b21CbG9jayA9IG5ldyBBcnJheTxzdHJpbmc+KGF0b21Db3VudCk7XG4gIGNvbnN0IG1vbGZpbGVCb25kQmxvY2sgPSBuZXcgQXJyYXk8c3RyaW5nPihib25kQ291bnQpO1xuXG4gIGxldCBhZGRNb25vbWVyVG9Nb2xibG9jaztcbiAgbGV0IGNhcE1vbGJsb2NrO1xuICBsZXQgbm9kZVNoaWZ0SW5pdFZhbHVlO1xuICBsZXQgYm9uZFNoaWZ0SW5pdFZhbHVlO1xuICBsZXQgc3VnYXIgPSBudWxsO1xuICBsZXQgcGhvc3BoYXRlID0gbnVsbDtcblxuICBpZiAocG9seW1lclR5cGUgPT09IEhFTE1fUE9MWU1FUl9UWVBFLlBFUFRJREUpIHtcbiAgICBhZGRNb25vbWVyVG9Nb2xibG9jayA9IGFkZEFtaW5vQWNpZFRvTW9sYmxvY2s7XG4gICAgY2FwTW9sYmxvY2sgPSBjYXBQZXB0aWRlTW9sYmxvY2s7XG4gICAgbm9kZVNoaWZ0SW5pdFZhbHVlID0gYm9uZFNoaWZ0SW5pdFZhbHVlID0gMDtcbiAgfSBlbHNlIHsgLy8gbnVjbGVvdGlkZXNcbiAgICBhZGRNb25vbWVyVG9Nb2xibG9jayA9IGFkZE51Y2xlb3RpZGVUb01vbGJsb2NrO1xuICAgIGNhcE1vbGJsb2NrID0gY2FwUGVwdGlkZU1vbGJsb2NrOyAvLyB0b2RvOiBjbGVhbnVwICYgcmVmYWN0b3JcbiAgICBub2RlU2hpZnRJbml0VmFsdWUgPSAwO1xuICAgIGJvbmRTaGlmdEluaXRWYWx1ZSA9IDA7XG4gICAgc3VnYXIgPSAoYWxwaGFiZXQgPT09IEFMUEhBQkVULkROQSkgPyBtb25vbWVyc0RpY3QuZ2V0KERFT1hZUklCT1NFKSA6IG1vbm9tZXJzRGljdC5nZXQoUklCT1NFKTtcbiAgICBwaG9zcGhhdGUgPSBtb25vbWVyc0RpY3QuZ2V0KFBIT1NQSEFURSk7XG4gIH1cblxuICBjb25zdCB2OiBMb29wVmFyaWFibGVzID0ge1xuICAgIGk6IDAsXG4gICAgbm9kZVNoaWZ0OiBub2RlU2hpZnRJbml0VmFsdWUsXG4gICAgYm9uZFNoaWZ0OiBib25kU2hpZnRJbml0VmFsdWUsXG4gICAgYmFja2JvbmVQb3NpdGlvblNoaWZ0OiBuZXcgQXJyYXk8bnVtYmVyPigyKS5maWxsKDApLFxuICAgIGJyYW5jaFBvc2l0aW9uU2hpZnQ6IG5ldyBBcnJheTxudW1iZXI+KDIpLmZpbGwoMCksXG4gICAgYmFja2JvbmVBdHRhY2hOb2RlOiAwLFxuICAgIGJyYW5jaEF0dGFjaE5vZGU6IDAsXG4gICAgZmxpcEZhY3RvcjogMSxcbiAgfTtcblxuICBjb25zdCBDOiBMb29wQ29uc3RhbnRzID0ge1xuICAgIHN1Z2FyOiBzdWdhciEsXG4gICAgcGhvc3BoYXRlOiBwaG9zcGhhdGUhLFxuICAgIHNlcUxlbmd0aDogbW9ub21lclNlcS5sZW5ndGgsXG4gICAgYXRvbUNvdW50OiBhdG9tQ291bnQsXG4gICAgYm9uZENvdW50OiBib25kQ291bnQsXG4gIH07XG5cbiAgZm9yICh2LmkgPSAwOyB2LmkgPCBDLnNlcUxlbmd0aDsgKyt2LmkpIHtcbiAgICBjb25zdCBtb25vbWVyID0gbW9ub21lcnNEaWN0LmdldChtb25vbWVyU2VxW3YuaV0pITtcbiAgICBhZGRNb25vbWVyVG9Nb2xibG9jayhtb25vbWVyLCBtb2xmaWxlQXRvbUJsb2NrLCBtb2xmaWxlQm9uZEJsb2NrLCB2LCBDKTtcbiAgfVxuXG4gIGNhcE1vbGJsb2NrKG1vbGZpbGVBdG9tQmxvY2ssIG1vbGZpbGVCb25kQmxvY2ssIHYsIEMpO1xuXG4gIGNvbnN0IG1vbGZpbGVDb3VudHNMaW5lID0gVjNLX0JFR0lOX0NPVU5UU19MSU5FICsgYXRvbUNvdW50ICsgJyAnICsgYm9uZENvdW50ICsgVjNLX0NPVU5UU19MSU5FX0VORElORztcblxuICAvLyB0b2RvOiBvcHRpbWl6ZSBjb25jYXRlbmF0aW9uIHVzaW5nIEFsZXhhbmRlcidzIGhpbnRcbiAgY29uc3QgbW9sZmlsZVBhcnRzID0gW1xuICAgIFYzS19IRUFERVJfRklSU1RfTElORSxcbiAgICBWM0tfSEVBREVSX1NFQ09ORF9MSU5FLFxuICAgIFYzS19CRUdJTl9DVEFCX0JMT0NLLFxuICAgIG1vbGZpbGVDb3VudHNMaW5lLFxuICAgIFYzS19CRUdJTl9BVE9NX0JMT0NLLFxuICAgIG1vbGZpbGVBdG9tQmxvY2suam9pbignJyksXG4gICAgVjNLX0VORF9BVE9NX0JMT0NLLFxuICAgIFYzS19CRUdJTl9CT05EX0JMT0NLLFxuICAgIG1vbGZpbGVCb25kQmxvY2suam9pbignJyksXG4gICAgVjNLX0VORF9CT05EX0JMT0NLLFxuICAgIFYzS19FTkRfQ1RBQl9CTE9DSyxcbiAgICBWM0tfRU5ELFxuICBdO1xuXG4gIHJldHVybiBtb2xmaWxlUGFydHMuam9pbignJyk7XG59XG5cbi8vIHRvZG86IGRvY1xuZnVuY3Rpb24gY2FwUGVwdGlkZU1vbGJsb2NrKFxuICBtb2xmaWxlQXRvbUJsb2NrOiBzdHJpbmdbXSwgbW9sZmlsZUJvbmRCbG9jazogc3RyaW5nW10sXG4gIHY6IExvb3BWYXJpYWJsZXMsIEM6IExvb3BDb25zdGFudHNcbik6IHZvaWQge1xuICAvLyBhZGQgdGVybWluYWwgb3h5Z2VuXG4gIGNvbnN0IGF0b21JZHggPSB2Lm5vZGVTaGlmdCArIDE7XG4gIG1vbGZpbGVBdG9tQmxvY2tbQy5hdG9tQ291bnRdID0gVjNLX0JFR0lOX0RBVEFfTElORSArIGF0b21JZHggKyAnICcgK1xuICAgIE9YWUdFTiArICcgJyArIGtlZXBQcmVjaXNpb24odi5iYWNrYm9uZVBvc2l0aW9uU2hpZnRbMF0pICsgJyAnICtcbiAgICB2LmZsaXBGYWN0b3IgKiBrZWVwUHJlY2lzaW9uKHYuYmFja2JvbmVQb3NpdGlvblNoaWZ0WzFdKSArICcgJyArICcwLjAwMDAwMCAwJyArICdcXG4nO1xuXG4gIC8vIGFkZCB0ZXJtaW5hbCBib25kXG4gIGNvbnN0IGZpcnN0QXRvbSA9IHYuYmFja2JvbmVBdHRhY2hOb2RlO1xuICBjb25zdCBzZWNvbmRBdG9tID0gYXRvbUlkeDtcbiAgbW9sZmlsZUJvbmRCbG9ja1tDLmJvbmRDb3VudF0gPSBWM0tfQkVHSU5fREFUQV9MSU5FICsgdi5ib25kU2hpZnQgKyAnICcgK1xuICAgIDEgKyAnICcgKyBmaXJzdEF0b20gKyAnICcgKyBzZWNvbmRBdG9tICsgJ1xcbic7XG59XG5cbi8vIHRvZG86IGRvY1xuZnVuY3Rpb24gYWRkQW1pbm9BY2lkVG9Nb2xibG9jayhtb25vbWVyOiBNb2xHcmFwaCwgbW9sZmlsZUF0b21CbG9jazogc3RyaW5nW10sXG4gIG1vbGZpbGVCb25kQmxvY2s6IHN0cmluZ1tdLCB2OiBMb29wVmFyaWFibGVzLCBDOiBMb29wQ29uc3RhbnRzXG4pOiB2b2lkIHtcbiAgdi5mbGlwRmFjdG9yID0gKC0xKSAqKiAodi5pICUgMik7IC8vIHRvIGZsaXAgZXZlcnkgZXZlbiBtb25vbWVyIG92ZXIgT1hcbiAgYWRkQmFja2JvbmVNb25vbWVyVG9Nb2xibG9jayhtb25vbWVyLCBtb2xmaWxlQXRvbUJsb2NrLCBtb2xmaWxlQm9uZEJsb2NrLCB2LCBDKTtcbn1cblxuZnVuY3Rpb24gYWRkQmFja2JvbmVNb25vbWVyVG9Nb2xibG9jayhcbiAgbW9ub21lcjogTW9sR3JhcGgsIG1vbGZpbGVBdG9tQmxvY2s6IHN0cmluZ1tdLCBtb2xmaWxlQm9uZEJsb2NrOiBzdHJpbmdbXSwgdjogTG9vcFZhcmlhYmxlcywgQzogTG9vcENvbnN0YW50c1xuKTogdm9pZCB7XG4gIC8vIHRvZG86IHJlbW92ZSB0aGVzZSBjb21tZW50cyB0byB0aGUgZG9jc3RyaW5ncyBvZiB0aGUgY29yci4gZnVuY3Rpb25zXG4gIC8vIGNvbnN0cnVuY3QgdGhlIGxpbmVzIG9mIFYzSyBtb2xmaWxlIGF0b20gYmxvY2tcbiAgZmlsbEF0b21MaW5lcyhtb25vbWVyLCBtb2xmaWxlQXRvbUJsb2NrLCB2KTtcblxuICAvLyBjb25zdHJ1Y3QgdGhlIGxpbmVzIG9mIFYzSyBtb2xmaWxlIGJvbmQgYmxvY2tcbiAgZmlsbEJvbmRMaW5lcyhtb25vbWVyLCBtb2xmaWxlQm9uZEJsb2NrLCB2KTtcblxuICAvLyBwZXB0aWRlIGJvbmRcbiAgZmlsbENoYWluRXh0ZW5kaW5nQm9uZChtb25vbWVyLCBtb2xmaWxlQm9uZEJsb2NrLCB2KTtcblxuICAvLyB1cGRhdGUgYnJhbmNoIHZhcmlhYmxlcyBpZiBuZWNlc3NhcnlcbiAgaWYgKG1vbm9tZXIubWV0YS5icmFuY2hTaGlmdCAhPT0gbnVsbCAmJiBtb25vbWVyLm1ldGEudGVybWluYWxOb2Rlcy5sZW5ndGggPiAyKVxuICAgIHVwZGF0ZUJyYW5jaFZhcmlhYmxlcyhtb25vbWVyLCB2KTtcblxuICAvLyB1cGRhdGUgbG9vcCB2YXJpYWJsZXNcbiAgdXBkYXRlQ2hhaW5FeHRlbmRpbmdWYXJpYWJsZXMobW9ub21lciwgdiwgQyk7XG59XG5cbi8vIHRvZG86IGRvY1xuZnVuY3Rpb24gYWRkTnVjbGVvdGlkZVRvTW9sYmxvY2soXG4gIG51Y2xlb2Jhc2U6IE1vbEdyYXBoLCBtb2xmaWxlQXRvbUJsb2NrOiBzdHJpbmdbXSwgbW9sZmlsZUJvbmRCbG9jazogc3RyaW5nW10sIHY6IExvb3BWYXJpYWJsZXMsIEM6IExvb3BDb25zdGFudHNcbik6IHZvaWQge1xuICAvLyBjb25zdHJ1bmN0IHRoZSBsaW5lcyBvZiBWM0sgbW9sZmlsZSBhdG9tIGJsb2NrIGNvcnJlc3BvbmRpbmcgdG8gcGhvc3BoYXRlXG4gIC8vIGFuZCBzdWdhclxuICBmb3IgKGNvbnN0IG1vbm9tZXIgb2YgW0MucGhvc3BoYXRlLCBDLnN1Z2FyXSlcbiAgICBhZGRCYWNrYm9uZU1vbm9tZXJUb01vbGJsb2NrKG1vbm9tZXIhLCBtb2xmaWxlQXRvbUJsb2NrLCBtb2xmaWxlQm9uZEJsb2NrLCB2LCBDKTtcblxuICBhZGRCcmFuY2hNb25vbWVyVG9Nb2xibG9jayhudWNsZW9iYXNlLCBtb2xmaWxlQXRvbUJsb2NrLCBtb2xmaWxlQm9uZEJsb2NrLCB2LCBDKTtcbn1cblxuZnVuY3Rpb24gYWRkQnJhbmNoTW9ub21lclRvTW9sYmxvY2soXG4gIG1vbm9tZXI6IE1vbEdyYXBoLCBtb2xmaWxlQXRvbUJsb2NrOiBzdHJpbmdbXSwgbW9sZmlsZUJvbmRCbG9jazogc3RyaW5nW10sIHY6IExvb3BWYXJpYWJsZXMsIEM6IExvb3BDb25zdGFudHNcbik6IHZvaWQge1xuICBmaWxsQnJhbmNoQXRvbUxpbmVzKG1vbm9tZXIsIG1vbGZpbGVBdG9tQmxvY2ssIHYpO1xuICBmaWxsQm9uZExpbmVzKG1vbm9tZXIsIG1vbGZpbGVCb25kQmxvY2ssIHYpO1xuICBmaWxsQmFja2JvbmVUb0JyYW5jaEJvbmQobW9ub21lciwgbW9sZmlsZUJvbmRCbG9jaywgdik7XG5cbiAgLy8gQy1OIGJvbmRcbiAgY29uc3QgYm9uZElkeCA9IHYuYm9uZFNoaWZ0O1xuICBjb25zdCBmaXJzdEF0b20gPSB2LmJyYW5jaEF0dGFjaE5vZGU7XG4gIGNvbnN0IHNlY29uZEF0b20gPSBtb25vbWVyLm1ldGEudGVybWluYWxOb2Rlc1swXSArIHYubm9kZVNoaWZ0O1xuICBtb2xmaWxlQm9uZEJsb2NrW2JvbmRJZHggLSAxXSA9IFYzS19CRUdJTl9EQVRBX0xJTkUgKyBib25kSWR4ICsgJyAnICtcbiAgICAxICsgJyAnICsgZmlyc3RBdG9tICsgJyAnICsgc2Vjb25kQXRvbSArICdcXG4nO1xuXG4gIC8vIHVwZGF0ZSBsb29wIHZhcmlhYmxlc1xuICB2LmJvbmRTaGlmdCArPSBtb25vbWVyLmJvbmRzLmF0b21QYWlycy5sZW5ndGggKyAxO1xuICB2Lm5vZGVTaGlmdCArPSBtb25vbWVyLmF0b21zLmF0b21UeXBlcy5sZW5ndGg7XG59XG5cbmZ1bmN0aW9uIHVwZGF0ZUNoYWluRXh0ZW5kaW5nVmFyaWFibGVzKG1vbm9tZXI6IE1vbEdyYXBoLCB2OiBMb29wVmFyaWFibGVzLCBDOiBMb29wQ29uc3RhbnRzKTogdm9pZCB7XG4gIHYuYmFja2JvbmVBdHRhY2hOb2RlID0gdi5ub2RlU2hpZnQgKyBtb25vbWVyLm1ldGEudGVybWluYWxOb2Rlc1sxXTtcbiAgdi5ib25kU2hpZnQgKz0gbW9ub21lci5ib25kcy5hdG9tUGFpcnMubGVuZ3RoICsgMTtcblxuICB2Lm5vZGVTaGlmdCArPSBtb25vbWVyLmF0b21zLmF0b21UeXBlcy5sZW5ndGg7XG4gIHYuYmFja2JvbmVQb3NpdGlvblNoaWZ0WzBdICs9IG1vbm9tZXIubWV0YS5iYWNrYm9uZVNoaWZ0IVswXTsgLy8gdG9kbzogbm9uLW51bGwgY2hlY2tcbiAgdi5iYWNrYm9uZVBvc2l0aW9uU2hpZnRbMV0gKz0gdi5mbGlwRmFjdG9yICogbW9ub21lci5tZXRhLmJhY2tib25lU2hpZnQhWzFdO1xufVxuXG5mdW5jdGlvbiB1cGRhdGVCcmFuY2hWYXJpYWJsZXMobW9ub21lcjogTW9sR3JhcGgsIHY6IExvb3BWYXJpYWJsZXMpIHtcbiAgdi5icmFuY2hBdHRhY2hOb2RlID0gdi5ub2RlU2hpZnQgKyBtb25vbWVyLm1ldGEudGVybWluYWxOb2Rlc1syXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCAyOyArK2kpXG4gICAgdi5icmFuY2hQb3NpdGlvblNoaWZ0W2ldID0gdi5iYWNrYm9uZVBvc2l0aW9uU2hpZnRbaV0gKyBtb25vbWVyLm1ldGEuYnJhbmNoU2hpZnQhW2ldO1xufVxuXG5mdW5jdGlvbiBmaWxsQXRvbUxpbmVzKG1vbm9tZXI6IE1vbEdyYXBoLCBtb2xmaWxlQXRvbUJsb2NrOiBzdHJpbmdbXSwgdjogTG9vcFZhcmlhYmxlcyk6IHZvaWQge1xuICBmb3IgKGxldCBqID0gMDsgaiA8IG1vbm9tZXIuYXRvbXMuYXRvbVR5cGVzLmxlbmd0aDsgKytqKSB7XG4gICAgY29uc3QgYXRvbUlkeCA9IHYubm9kZVNoaWZ0ICsgaiArIDE7XG4gICAgbW9sZmlsZUF0b21CbG9ja1t2Lm5vZGVTaGlmdCArIGpdID0gVjNLX0JFR0lOX0RBVEFfTElORSArIGF0b21JZHggKyAnICcgK1xuICAgICAgbW9ub21lci5hdG9tcy5hdG9tVHlwZXNbal0gKyAnICcgK1xuICAgICAga2VlcFByZWNpc2lvbih2LmJhY2tib25lUG9zaXRpb25TaGlmdFswXSArIG1vbm9tZXIuYXRvbXMueFtqXSkgKyAnICcgK1xuICAgICAga2VlcFByZWNpc2lvbih2LmJhY2tib25lUG9zaXRpb25TaGlmdFsxXSArIHYuZmxpcEZhY3RvciAqIG1vbm9tZXIuYXRvbXMueVtqXSkgK1xuICAgICAgJyAnICsgbW9ub21lci5hdG9tcy5rd2FyZ3Nbal07XG4gIH1cbn1cblxuLy8gdG9kbzogcmVtb3ZlIGFzIHF1aWNrZml4XG5mdW5jdGlvbiBmaWxsQnJhbmNoQXRvbUxpbmVzKG1vbm9tZXI6IE1vbEdyYXBoLCBtb2xmaWxlQXRvbUJsb2NrOiBzdHJpbmdbXSwgdjogTG9vcFZhcmlhYmxlcyk6IHZvaWQge1xuICBmb3IgKGxldCBqID0gMDsgaiA8IG1vbm9tZXIuYXRvbXMuYXRvbVR5cGVzLmxlbmd0aDsgKytqKSB7XG4gICAgY29uc3QgYXRvbUlkeCA9IHYubm9kZVNoaWZ0ICsgaiArIDE7XG4gICAgbW9sZmlsZUF0b21CbG9ja1t2Lm5vZGVTaGlmdCArIGpdID0gVjNLX0JFR0lOX0RBVEFfTElORSArIGF0b21JZHggKyAnICcgK1xuICAgICAgbW9ub21lci5hdG9tcy5hdG9tVHlwZXNbal0gKyAnICcgK1xuICAgICAga2VlcFByZWNpc2lvbih2LmJyYW5jaFBvc2l0aW9uU2hpZnRbMF0gKyBtb25vbWVyLmF0b21zLnhbal0pICsgJyAnICtcbiAgICAgIGtlZXBQcmVjaXNpb24odi5icmFuY2hQb3NpdGlvblNoaWZ0WzFdICsgdi5mbGlwRmFjdG9yICogbW9ub21lci5hdG9tcy55W2pdKSArXG4gICAgICAnICcgKyBtb25vbWVyLmF0b21zLmt3YXJnc1tqXTtcbiAgfVxufVxuXG5mdW5jdGlvbiBmaWxsQm9uZExpbmVzKG1vbm9tZXI6IE1vbEdyYXBoLCBtb2xmaWxlQm9uZEJsb2NrOiBzdHJpbmdbXSwgdjogTG9vcFZhcmlhYmxlcyk6IHZvaWQge1xuICAvLyBjb25zdHJ1Y3QgdGhlIGxpbmVzIG9mIFYzSyBtb2xmaWxlIGJvbmQgYmxvY2tcbiAgZm9yIChsZXQgaiA9IDA7IGogPCBtb25vbWVyLmJvbmRzLmF0b21QYWlycy5sZW5ndGg7ICsraikge1xuICAgIGNvbnN0IGJvbmRJZHggPSB2LmJvbmRTaGlmdCArIGogKyAxO1xuICAgIGNvbnN0IGZpcnN0QXRvbSA9IG1vbm9tZXIuYm9uZHMuYXRvbVBhaXJzW2pdWzBdICsgdi5ub2RlU2hpZnQ7XG4gICAgY29uc3Qgc2Vjb25kQXRvbSA9IG1vbm9tZXIuYm9uZHMuYXRvbVBhaXJzW2pdWzFdICsgdi5ub2RlU2hpZnQ7XG4gICAgbGV0IGJvbmRDZmcgPSAnJztcbiAgICBpZiAobW9ub21lci5ib25kcy5ib25kQ29uZmlndXJhdGlvbi5oYXMoaikpIHtcbiAgICAgIC8vIGZsaXAgb3JpZW50YXRpb24gd2hlbiBuZWNlc3NhcnlcbiAgICAgIGxldCBvcmllbnRhdGlvbiA9IG1vbm9tZXIuYm9uZHMuYm9uZENvbmZpZ3VyYXRpb24uZ2V0KGopO1xuICAgICAgaWYgKHYuZmxpcEZhY3RvciA8IDApXG4gICAgICAgIG9yaWVudGF0aW9uID0gKG9yaWVudGF0aW9uID09PSAxKSA/IDMgOiAxO1xuICAgICAgYm9uZENmZyA9ICcgQ0ZHPScgKyBvcmllbnRhdGlvbjtcbiAgICB9XG4gICAgY29uc3Qga3dhcmdzID0gbW9ub21lci5ib25kcy5rd2FyZ3MuaGFzKGopID9cbiAgICAgICcgJyArIG1vbm9tZXIuYm9uZHMua3dhcmdzLmdldChqKSA6ICcnO1xuICAgIG1vbGZpbGVCb25kQmxvY2tbdi5ib25kU2hpZnQgKyBqXSA9IFYzS19CRUdJTl9EQVRBX0xJTkUgKyBib25kSWR4ICsgJyAnICtcbiAgICAgIG1vbm9tZXIuYm9uZHMuYm9uZFR5cGVzW2pdICsgJyAnICtcbiAgICAgIGZpcnN0QXRvbSArICcgJyArIHNlY29uZEF0b20gKyBib25kQ2ZnICsga3dhcmdzICsgJ1xcbic7XG4gIH1cbn1cblxuZnVuY3Rpb24gZmlsbENoYWluRXh0ZW5kaW5nQm9uZChtb25vbWVyOiBNb2xHcmFwaCwgbW9sZmlsZUJvbmRCbG9jazogc3RyaW5nW10sIHY6IExvb3BWYXJpYWJsZXMpOiB2b2lkIHtcbiAgaWYgKHYuYmFja2JvbmVBdHRhY2hOb2RlICE9PSAwKSB7XG4gICAgY29uc3QgYm9uZElkeCA9IHYuYm9uZFNoaWZ0O1xuICAgIGNvbnN0IGZpcnN0QXRvbSA9IHYuYmFja2JvbmVBdHRhY2hOb2RlO1xuICAgIGNvbnN0IHNlY29uZEF0b20gPSBtb25vbWVyLm1ldGEudGVybWluYWxOb2Rlc1swXSArIHYubm9kZVNoaWZ0O1xuICAgIG1vbGZpbGVCb25kQmxvY2tbdi5ib25kU2hpZnQgLSAxXSA9IFYzS19CRUdJTl9EQVRBX0xJTkUgKyBib25kSWR4ICsgJyAnICtcbiAgICAgIDEgKyAnICcgKyBmaXJzdEF0b20gKyAnICcgKyBzZWNvbmRBdG9tICsgJ1xcbic7XG4gIH1cbn1cblxuLy8gdG9kbzogcmVtb3ZlXG5mdW5jdGlvbiBmaWxsQmFja2JvbmVUb0JyYW5jaEJvbmQoYnJhbmNoTW9ub21lcjogTW9sR3JhcGgsIG1vbGZpbGVCb25kQmxvY2s6IHN0cmluZ1tdLCB2OiBMb29wVmFyaWFibGVzKTogdm9pZCB7XG4gIGNvbnN0IGJvbmRJZHggPSB2LmJvbmRTaGlmdDtcbiAgY29uc3QgZmlyc3RBdG9tID0gdi5icmFuY2hBdHRhY2hOb2RlO1xuICBjb25zdCBzZWNvbmRBdG9tID0gYnJhbmNoTW9ub21lci5tZXRhLnRlcm1pbmFsTm9kZXNbMF0gKyB2Lm5vZGVTaGlmdDtcbiAgbW9sZmlsZUJvbmRCbG9ja1tib25kSWR4IC0gMV0gPSBWM0tfQkVHSU5fREFUQV9MSU5FICsgYm9uZElkeCArICcgJyArXG4gICAgMSArICcgJyArIGZpcnN0QXRvbSArICcgJyArIHNlY29uZEF0b20gKyAnXFxuJztcbn1cblxuLyogQ29tcHV0ZSB0aGUgYXRvbS9ib25kIGNvdW50cyBmb3IgdGhlIHJlc3VsdGluZyBtb2xmaWxlLCBkZXBlbmRpbmcgb24gdGhlXG4gKiB0eXBlIG9mIHBvbHltZXIgKHBlcHRpZGUvbnVjbGVvdGlkZSkgKi9cbmZ1bmN0aW9uIGdldFJlc3VsdGluZ0F0b21Cb25kQ291bnRzKFxuICBtb25vbWVyU2VxOiBzdHJpbmdbXSwgbW9ub21lcnNEaWN0OiBNYXA8c3RyaW5nLCBNb2xHcmFwaD4sXG4gIGFscGhhYmV0OiBBTFBIQUJFVCwgcG9seW1lclR5cGU6IEhFTE1fUE9MWU1FUl9UWVBFXG4pOiB7IGF0b21Db3VudDogbnVtYmVyLCBib25kQ291bnQ6IG51bWJlciB9IHtcbiAgbGV0IGF0b21Db3VudCA9IDA7XG4gIGxldCBib25kQ291bnQgPSAwO1xuXG4gIC8vIHN1bSB1cCBhbGwgdGhlIGF0b21zL25vZGVzIHByb3ZpZGVkIGJ5IHRoZSBzZXF1ZW5jZVxuICBmb3IgKGNvbnN0IG1vbm9tZXJTeW1ib2wgb2YgbW9ub21lclNlcSkge1xuICAgIGNvbnN0IG1vbm9tZXIgPSBtb25vbWVyc0RpY3QuZ2V0KG1vbm9tZXJTeW1ib2wpITtcbiAgICBhdG9tQ291bnQgKz0gbW9ub21lci5hdG9tcy54Lmxlbmd0aDtcbiAgICBib25kQ291bnQgKz0gbW9ub21lci5ib25kcy5ib25kVHlwZXMubGVuZ3RoO1xuICB9XG5cbiAgLy8gYWRkIGV4dHJhIHZhbHVlcyBkZXBlbmRpbmcgb24gdGhlIHBvbHltZXIgdHlwZVxuICBpZiAocG9seW1lclR5cGUgPT09IEhFTE1fUE9MWU1FUl9UWVBFLlBFUFRJREUpIHtcbiAgICAvLyBhZGQgdGhlIHJpZ2h0bW9zdC90ZXJtaW5hdGluZyBjYXAgZ3JvdXAgJ09IJyAoaS5lLiAnTycpXG4gICAgYXRvbUNvdW50ICs9IDE7XG4gICAgLy8gYWRkIGNoYWluLWV4dGVuZGluZyBib25kcyAoQy1OSCBwZXIgZWFjaCBtb25vbWVyIHBhaXIgYW5kIHRlcm1pbmFsIEMtT0gpXG4gICAgYm9uZENvdW50ICs9IG1vbm9tZXJTZXEubGVuZ3RoO1xuICB9IGVsc2UgeyAvLyBudWNsZW90aWRlc1xuICAgIGNvbnN0IHN1Z2FyID0gKGFscGhhYmV0ID09PSBBTFBIQUJFVC5ETkEpID9cbiAgICAgIG1vbm9tZXJzRGljdC5nZXQoREVPWFlSSUJPU0UpISA6IG1vbm9tZXJzRGljdC5nZXQoUklCT1NFKSE7XG4gICAgY29uc3QgcGhvc3BoYXRlID0gbW9ub21lcnNEaWN0LmdldChQSE9TUEhBVEUpITtcblxuICAgIC8vIGFkZCBwaG9zcGhhdGUgYW5kIHN1Z2FyIHBlciBlYWNoIG51Y2xlb2Jhc2Ugc3ltYm9sXG4gICAgYXRvbUNvdW50ICs9IG1vbm9tZXJTZXEubGVuZ3RoICogKHBob3NwaGF0ZS5hdG9tcy54Lmxlbmd0aCArIHN1Z2FyLmF0b21zLngubGVuZ3RoKTtcbiAgICAvLyBhZGQgdGhlIGxlZnRtb3N0IGNhcCBncm91cCAnT0gnIChpLmUuICdPJykgdG8gdGhlIGZpcnN0IHBob3NwaGF0ZVxuICAgIGF0b21Db3VudCArPSAxO1xuXG4gICAgLy8gYWRkIGJvbmRzIGZyb20gcGhvc3BoYXRlIGFuZCBzdWdhclxuICAgIGJvbmRDb3VudCArPSBtb25vbWVyU2VxLmxlbmd0aCAqIChwaG9zcGhhdGUuYm9uZHMuYm9uZFR5cGVzLmxlbmd0aCArIHN1Z2FyLmJvbmRzLmJvbmRUeXBlcy5sZW5ndGgpO1xuXG4gICAgLy8gYWRkIGNoYWluLWV4dGVuZGluZyBhbmQgYnJhbmNoIGJvbmRzIChPLVAsIEMtTyBhbmQgQy1OIHBlciBlYWNoIG51Y2xlb3RpZGUpXG4gICAgYm9uZENvdW50ICs9IG1vbm9tZXJTZXEubGVuZ3RoICogMztcbiAgfVxuXG4gIHJldHVybiB7YXRvbUNvdW50LCBib25kQ291bnR9O1xufVxuXG4vKiBLZWVwIHByZWNpc2lvbiB1cG9uIGZsb2F0aW5nIHBvaW50IG9wZXJhdGlvbnMgb3ZlciBhdG9tIGNvb3JkaW5hdGVzICovXG5mdW5jdGlvbiBrZWVwUHJlY2lzaW9uKHg6IG51bWJlcikge1xuICByZXR1cm4gTWF0aC5yb3VuZChQUkVDSVNJT05fRkFDVE9SICogeCkgLyBQUkVDSVNJT05fRkFDVE9SO1xufVxuXG5mdW5jdGlvbiBjb252ZXJ0TW9sR3JhcGhUb01vbGZpbGVWM0sobW9sR3JhcGg6IE1vbEdyYXBoKTogc3RyaW5nIHtcbiAgLy8gY291bnRzIGxpbmVcbiAgY29uc3QgYXRvbVR5cGUgPSBtb2xHcmFwaC5hdG9tcy5hdG9tVHlwZXM7XG4gIGNvbnN0IHggPSBtb2xHcmFwaC5hdG9tcy54O1xuICBjb25zdCB5ID0gbW9sR3JhcGguYXRvbXMueTtcbiAgY29uc3QgYXRvbUt3YXJncyA9IG1vbEdyYXBoLmF0b21zLmt3YXJncztcbiAgY29uc3QgYm9uZFR5cGUgPSBtb2xHcmFwaC5ib25kcy5ib25kVHlwZXM7XG4gIGNvbnN0IGF0b21QYWlyID0gbW9sR3JhcGguYm9uZHMuYXRvbVBhaXJzO1xuICBjb25zdCBib25kS3dhcmdzID0gbW9sR3JhcGguYm9uZHMua3dhcmdzO1xuICBjb25zdCBib25kQ29uZmlnID0gbW9sR3JhcGguYm9uZHMuYm9uZENvbmZpZ3VyYXRpb247XG4gIGNvbnN0IGF0b21Db3VudCA9IGF0b21UeXBlLmxlbmd0aDtcbiAgY29uc3QgYm9uZENvdW50ID0gbW9sR3JhcGguYm9uZHMuYm9uZFR5cGVzLmxlbmd0aDtcblxuICAvLyB0b2RvIHJld3JpdGUgdXNpbmcgY29uc3RhbnRzXG4gIGNvbnN0IG1vbGZpbGVDb3VudHNMaW5lID0gVjNLX0JFR0lOX0NPVU5UU19MSU5FICsgYXRvbUNvdW50ICsgJyAnICsgYm9uZENvdW50ICsgVjNLX0NPVU5UU19MSU5FX0VORElORztcblxuICAvLyBhdG9tIGJsb2NrXG4gIGxldCBtb2xmaWxlQXRvbUJsb2NrID0gJyc7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXRvbUNvdW50OyArK2kpIHtcbiAgICBjb25zdCBhdG9tSWR4ID0gaSArIDE7XG4gICAgY29uc3QgY29vcmRpbmF0ZSA9IFt4W2ldLnRvU3RyaW5nKCksIHlbaV0udG9TdHJpbmcoKV07XG5cbiAgICAvLyBmb3JtYXQgY29vcmRpbmF0ZXMgc28gdGhhdCB0aGV5IGhhdmUgNiBkaWdpdHMgYWZ0ZXIgZGVjaW1hbCBwb2ludFxuICAgIC8vIGZvciAobGV0IGsgPSAwOyBrIDwgMjsgKytrKSB7XG4gICAgLy8gICBjb25zdCBmb3JtYXR0ZWQgPSBjb29yZGluYXRlW2tdLnRvU3RyaW5nKCkuc3BsaXQoJy4nKTtcbiAgICAvLyAgIGlmIChmb3JtYXR0ZWQubGVuZ3RoID09PSAxKVxuICAgIC8vICAgICBmb3JtYXR0ZWQucHVzaCgnMCcpO1xuICAgIC8vICAgZm9ybWF0dGVkWzFdID0gZm9ybWF0dGVkWzFdLnBhZEVuZChWM0tfQVRPTV9DT09SRElOQVRFX1BSRUNJU0lPTiwgJzAnKTtcbiAgICAvLyAgIGNvb3JkaW5hdGVba10gPSBmb3JtYXR0ZWQuam9pbignLicpO1xuICAgIC8vIH1cblxuICAgIGNvbnN0IGF0b21MaW5lID0gVjNLX0JFR0lOX0RBVEFfTElORSArIGF0b21JZHggKyAnICcgKyBhdG9tVHlwZVtpXSArICcgJyArXG4gICAgICBjb29yZGluYXRlWzBdICsgJyAnICsgY29vcmRpbmF0ZVsxXSArICcgJyArIGF0b21Ld2FyZ3NbaV07XG4gICAgbW9sZmlsZUF0b21CbG9jayArPSBhdG9tTGluZTtcbiAgfVxuXG4gIC8vIGJvbmQgYmxvY2tcbiAgbGV0IG1vbGZpbGVCb25kQmxvY2sgPSAnJztcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBib25kQ291bnQ7ICsraSkge1xuICAgIGNvbnN0IGJvbmRJZHggPSBpICsgMTtcbiAgICBjb25zdCBmaXJzdEF0b20gPSBhdG9tUGFpcltpXVswXTtcbiAgICBjb25zdCBzZWNvbmRBdG9tID0gYXRvbVBhaXJbaV1bMV07XG4gICAgY29uc3Qga3dhcmdzID0gYm9uZEt3YXJncy5oYXMoaSkgPyAnICcgKyBib25kS3dhcmdzLmdldChpKSA6ICcnO1xuICAgIGNvbnN0IGJvbmRDZmcgPSBib25kQ29uZmlnLmhhcyhpKSA/ICcgQ0ZHPScgKyBib25kQ29uZmlnLmdldChpKSA6ICcnO1xuICAgIGNvbnN0IGJvbmRMaW5lID0gVjNLX0JFR0lOX0RBVEFfTElORSArIGJvbmRJZHggKyAnICcgKyBib25kVHlwZVtpXSArICcgJyArXG4gICAgICBmaXJzdEF0b20gKyAnICcgKyBzZWNvbmRBdG9tICsgYm9uZENmZyArIGt3YXJncyArICdcXG4nO1xuICAgIG1vbGZpbGVCb25kQmxvY2sgKz0gYm9uZExpbmU7XG4gIH1cblxuICBjb25zdCBtb2xmaWxlUGFydHMgPSBbXG4gICAgVjNLX0hFQURFUl9GSVJTVF9MSU5FLFxuICAgIFYzS19IRUFERVJfU0VDT05EX0xJTkUsXG4gICAgVjNLX0JFR0lOX0NUQUJfQkxPQ0ssXG4gICAgbW9sZmlsZUNvdW50c0xpbmUsXG4gICAgVjNLX0JFR0lOX0FUT01fQkxPQ0ssXG4gICAgbW9sZmlsZUF0b21CbG9jayxcbiAgICBWM0tfRU5EX0FUT01fQkxPQ0ssXG4gICAgVjNLX0JFR0lOX0JPTkRfQkxPQ0ssXG4gICAgbW9sZmlsZUJvbmRCbG9jayxcbiAgICBWM0tfRU5EX0JPTkRfQkxPQ0ssXG4gICAgVjNLX0VORF9DVEFCX0JMT0NLLFxuICAgIFYzS19FTkQsXG4gIF07XG4gIGNvbnN0IHJlc3VsdGluZ01vbGZpbGUgPSBtb2xmaWxlUGFydHMuam9pbignJyk7XG4gIC8vIGNvbnNvbGUubG9nKHJlc3VsdGluZ01vbGZpbGUpO1xuXG4gIHJldHVybiByZXN1bHRpbmdNb2xmaWxlO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0U3ltYm9sVG9DYXBwZWRNb2xmaWxlTWFwKG1vbm9tZXJzTGliTGlzdDogYW55W10pOiBQcm9taXNlPE1hcDxzdHJpbmcsIHN0cmluZz4gfCB1bmRlZmluZWQ+IHtcbiAgaWYgKERHLkZ1bmMuZmluZCh7cGFja2FnZTogJ0NoZW0nLCBuYW1lOiAnZ2V0UmRLaXRNb2R1bGUnfSkubGVuZ3RoID09PSAwKSB7XG4gICAgZ3Jvay5zaGVsbC53YXJuaW5nKCdUcmFuc2Zvcm1hdGlvbiB0byBhdG9taWMgbGV2ZWwgcmVxdWlyZXMgcGFja2FnZSBcIkNoZW1cIiBpbnN0YWxsZWQuJyk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3Qgc3ltYm9sVG9DYXBwZWRNb2xmaWxlTWFwID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTtcbiAgY29uc3QgbW9kdWxlUmRraXQgPSBhd2FpdCBncm9rLmZ1bmN0aW9ucy5jYWxsKCdDaGVtOmdldFJkS2l0TW9kdWxlJyk7XG5cbiAgZm9yIChjb25zdCBtb25vbWVyTGliT2JqZWN0IG9mIG1vbm9tZXJzTGliTGlzdCkge1xuICAgIGNvbnN0IG1vbm9tZXJTeW1ib2wgPSBtb25vbWVyTGliT2JqZWN0W0hFTE1fRklFTERTLlNZTUJPTF07XG4gICAgY29uc3QgY2FwR3JvdXBzID0gcGFyc2VDYXBHcm91cHMobW9ub21lckxpYk9iamVjdFtIRUxNX0ZJRUxEUy5SR1JPVVBTXSk7XG4gICAgY29uc3QgY2FwR3JvdXBJZHhNYXAgPSBwYXJzZUNhcEdyb3VwSWR4TWFwKG1vbm9tZXJMaWJPYmplY3RbSEVMTV9GSUVMRFMuTU9MRklMRV0pO1xuXG4gICAgY29uc3QgbW9sZmlsZVYzSyA9IGNvbnZlcnRNb2xmaWxlVG9WM0socmVtb3ZlUkdyb3VwTGluZXMobW9ub21lckxpYk9iamVjdFtIRUxNX0ZJRUxEUy5NT0xGSUxFXSksIG1vZHVsZVJka2l0KTtcbiAgICBjb25zdCBjb3VudHMgPSBwYXJzZUF0b21BbmRCb25kQ291bnRzKG1vbGZpbGVWM0spO1xuXG4gICAgY29uc3QgYXRvbXMgPSBwYXJzZUF0b21CbG9jayhtb2xmaWxlVjNLLCBjb3VudHMuYXRvbUNvdW50KTtcbiAgICBjb25zdCBib25kcyA9IHBhcnNlQm9uZEJsb2NrKG1vbGZpbGVWM0ssIGNvdW50cy5ib25kQ291bnQpO1xuICAgIGNvbnN0IG1ldGEgPSBnZXRNb25vbWVyTWV0YWRhdGEoYXRvbXMsIGJvbmRzLCBjYXBHcm91cHMsIGNhcEdyb3VwSWR4TWFwKTtcblxuICAgIGNvbnN0IG1vbm9tZXJHcmFwaDogTW9sR3JhcGggPSB7YXRvbXM6IGF0b21zLCBib25kczogYm9uZHMsIG1ldGE6IG1ldGF9O1xuXG4gICAgcmVtb3ZlSHlkcm9nZW4obW9ub21lckdyYXBoKTtcblxuICAgIGNvbnN0IG1vbGZpbGUgPSBjb252ZXJ0TW9sR3JhcGhUb01vbGZpbGVWM0sobW9ub21lckdyYXBoKTtcbiAgICBzeW1ib2xUb0NhcHBlZE1vbGZpbGVNYXAuc2V0KG1vbm9tZXJTeW1ib2wsIG1vbGZpbGUpO1xuICB9XG4gIHJldHVybiBzeW1ib2xUb0NhcHBlZE1vbGZpbGVNYXA7XG59XG5cbi8qIEdldCB0aGUgVjNLIG1vbGZpbGUgY29ycmVzcG9uZGluZyB0byB0aGUgY2FwcGVkIE1vbm9tZXIgKGRlZmF1bHQgY2FwIGdyb3VwcykgICovXG5leHBvcnQgZnVuY3Rpb24gY2FwUGVwdGlkZU1vbm9tZXIobW9ub21lcjogTW9ub21lcik6IHN0cmluZyB7XG4gIGNvbnN0IGZ1bmNMaXN0OiBERy5GdW5jW10gPSBERy5GdW5jLmZpbmQoe3BhY2thZ2U6ICdDaGVtJywgbmFtZTogJ2dldFJkS2l0TW9kdWxlJ30pO1xuICBjb25zdCBtb2R1bGVSZGtpdCA9IGZ1bmNMaXN0WzBdLmFwcGx5KCk7XG4gIFxuICBjb25zdCBjYXBHcm91cHMgPSBwYXJzZUNhcEdyb3Vwcyhtb25vbWVyW0hFTE1fRklFTERTLlJHUk9VUFNdKTtcbiAgY29uc3QgY2FwR3JvdXBJZHhNYXAgPSBwYXJzZUNhcEdyb3VwSWR4TWFwKG1vbm9tZXJbSEVMTV9GSUVMRFMuTU9MRklMRV0pO1xuICBjb25zdCBtb2xmaWxlVjNLID0gY29udmVydE1vbGZpbGVUb1YzSyhyZW1vdmVSR3JvdXBMaW5lcyhtb25vbWVyW0hFTE1fRklFTERTLk1PTEZJTEVdKSwgbW9kdWxlUmRraXQpO1xuICBjb25zdCBjb3VudHMgPSBwYXJzZUF0b21BbmRCb25kQ291bnRzKG1vbGZpbGVWM0spO1xuXG4gIGNvbnN0IGF0b21zID0gcGFyc2VBdG9tQmxvY2sobW9sZmlsZVYzSywgY291bnRzLmF0b21Db3VudCk7XG4gIGNvbnN0IGJvbmRzID0gcGFyc2VCb25kQmxvY2sobW9sZmlsZVYzSywgY291bnRzLmJvbmRDb3VudCk7XG4gIGNvbnN0IG1ldGEgPSBnZXRNb25vbWVyTWV0YWRhdGEoYXRvbXMsIGJvbmRzLCBjYXBHcm91cHMsIGNhcEdyb3VwSWR4TWFwKTtcblxuICBjb25zdCBtb25vbWVyR3JhcGg6IE1vbEdyYXBoID0ge2F0b21zOiBhdG9tcywgYm9uZHM6IGJvbmRzLCBtZXRhOiBtZXRhfTtcblxuICBhZGp1c3RQZXB0aWRlTW9ub21lckdyYXBoKG1vbm9tZXJHcmFwaCk7XG5cbiAgY29uc3QgbW9sZmlsZSA9IGNvbnZlcnRNb2xHcmFwaFRvTW9sZmlsZVYzSyhtb25vbWVyR3JhcGgpO1xuICByZXR1cm4gbW9sZmlsZTtcbn1cbiJdfQ==