@datagrok-libraries/bio 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
/** enum type to simplify setting "user-friendly" notation if necessary */
|
|
3
|
+
export declare const enum NOTATION {
|
|
4
|
+
FASTA = "FASTA",
|
|
5
|
+
SEPARATOR = "SEPARATOR",
|
|
6
|
+
HELM = "HELM"
|
|
7
|
+
}
|
|
8
|
+
/** Class for handling conversion of notation systems in Macromolecule columns */
|
|
9
|
+
export declare class NotationConverter {
|
|
10
|
+
private _sourceColumn;
|
|
11
|
+
private _sourceUnits;
|
|
12
|
+
private _sourceNotation;
|
|
13
|
+
private _defaultGapSymbol;
|
|
14
|
+
private _defaultGapSymbolsDict;
|
|
15
|
+
private get sourceUnits();
|
|
16
|
+
private get sourceColumn();
|
|
17
|
+
get sourceNotation(): NOTATION;
|
|
18
|
+
get defaultGapSymbol(): string;
|
|
19
|
+
get separator(): string;
|
|
20
|
+
isFasta(): boolean;
|
|
21
|
+
isSeparator(): boolean;
|
|
22
|
+
isHelm(): boolean;
|
|
23
|
+
toFasta(targetNotation: NOTATION): boolean;
|
|
24
|
+
toSeparator(targetNotation: NOTATION): boolean;
|
|
25
|
+
toHelm(targetNotation: NOTATION): boolean;
|
|
26
|
+
isRna(): boolean;
|
|
27
|
+
isDna(): boolean;
|
|
28
|
+
isPeptide(): boolean;
|
|
29
|
+
/** Associate notation types with the corresponding units */
|
|
30
|
+
/**
|
|
31
|
+
* @return {NOTATION} Notation associated with the units type
|
|
32
|
+
*/
|
|
33
|
+
private getSourceNotation;
|
|
34
|
+
/**
|
|
35
|
+
* Create a new empty column of the specified notation type and the same
|
|
36
|
+
* length as sourceColumn
|
|
37
|
+
*
|
|
38
|
+
* @param {NOTATION} targetNotation
|
|
39
|
+
* @return {DG.Column}
|
|
40
|
+
*/
|
|
41
|
+
private getNewColumn;
|
|
42
|
+
/**
|
|
43
|
+
* Convert a Macromolecule column from FASTA to SEPARATOR notation
|
|
44
|
+
*
|
|
45
|
+
* @param {string} separator A specific separator to be used
|
|
46
|
+
* @param {string} gapSymbol Gap symbol in FASTA, '-' by default
|
|
47
|
+
* @return {DG.Column} A new column in SEPARATOR notation
|
|
48
|
+
*/
|
|
49
|
+
private convertFastaToSeparator;
|
|
50
|
+
private convertToHelm;
|
|
51
|
+
private handleSeparatorItemForFasta;
|
|
52
|
+
private convertSeparatorToFasta;
|
|
53
|
+
private convertHelmToFasta;
|
|
54
|
+
private convertHelmToSeparator;
|
|
55
|
+
/** Dispatcher method for notation conversion
|
|
56
|
+
*
|
|
57
|
+
* @param {NOTATION} targetNotation Notation we want to convert to
|
|
58
|
+
* @param {string | null} tgtSeparator Possible separator
|
|
59
|
+
* @return {DG.Column} Converted column
|
|
60
|
+
*/
|
|
61
|
+
convert(targetNotation: NOTATION, tgtSeparator?: string | null): DG.Column;
|
|
62
|
+
constructor(col: DG.Column);
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=notation-converter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notation-converter.d.ts","sourceRoot":"","sources":["notation-converter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAGtC,0EAA0E;AAC1E,0BAAkB,QAAQ;IACxB,KAAK,UAAU;IACf,SAAS,cAAc;IACvB,IAAI,SAAS;CACd;AAED,iFAAiF;AACjF,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAW;IAClC,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,sBAAsB,CAI5B;IAEF,OAAO,KAAK,WAAW,GAAwC;IAE/D,OAAO,KAAK,YAAY,GAA4C;IAEpE,IAAW,cAAc,IAAI,QAAQ,CAAiC;IAEtE,IAAW,gBAAgB,IAAI,MAAM,CAAmC;IAExE,IAAW,SAAS,IAAI,MAAM,CAM7B;IAEM,OAAO,IAAI,OAAO;IAElB,WAAW,IAAI,OAAO;IAEtB,MAAM,IAAI,OAAO;IAEjB,OAAO,CAAC,cAAc,EAAE,QAAQ,GAAG,OAAO;IAE1C,WAAW,CAAC,cAAc,EAAE,QAAQ,GAAG,OAAO;IAE9C,MAAM,CAAC,cAAc,EAAE,QAAQ,GAAG,OAAO;IAEzC,KAAK,IAAI,OAAO;IAEhB,KAAK,IAAI,OAAO;IAEhB,SAAS,IAAI,OAAO;IAE3B,4DAA4D;IAC5D;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;IAyBpB;;;;;;OAMG;IACH,OAAO,CAAC,uBAAuB;IAkB/B,OAAO,CAAC,aAAa;IA0CrB,OAAO,CAAC,2BAA2B;IAmBnC,OAAO,CAAC,uBAAuB;IA2C/B,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,sBAAsB;IAK9B;;;;;OAKG;IACI,OAAO,CAAC,cAAc,EAAE,QAAQ,EAAE,YAAY,GAAE,MAAM,GAAG,IAAW,GAAG,EAAE,CAAC,MAAM;gBAmBpE,GAAG,EAAE,EAAE,CAAC,MAAM;CAYlC"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
import { WebLogo } from '../viewers/web-logo';
|
|
3
|
+
/** Class for handling conversion of notation systems in Macromolecule columns */
|
|
4
|
+
export class NotationConverter {
|
|
5
|
+
constructor(col) {
|
|
6
|
+
this._defaultGapSymbolsDict = {
|
|
7
|
+
helm: '*',
|
|
8
|
+
separator: '',
|
|
9
|
+
fasta: '-',
|
|
10
|
+
};
|
|
11
|
+
this._sourceColumn = col;
|
|
12
|
+
const units = this._sourceColumn.tags[DG.TAGS.UNITS];
|
|
13
|
+
if (units !== null)
|
|
14
|
+
this._sourceUnits = units;
|
|
15
|
+
else
|
|
16
|
+
throw new Error('Units are not specified in column');
|
|
17
|
+
this._sourceNotation = this.getSourceNotation();
|
|
18
|
+
this._defaultGapSymbol = (this.isFasta()) ? this._defaultGapSymbolsDict.fasta :
|
|
19
|
+
(this.isHelm()) ? this._defaultGapSymbolsDict.helm :
|
|
20
|
+
this._defaultGapSymbolsDict.separator;
|
|
21
|
+
}
|
|
22
|
+
get sourceUnits() { return this._sourceUnits; }
|
|
23
|
+
get sourceColumn() { return this._sourceColumn; }
|
|
24
|
+
get sourceNotation() { return this._sourceNotation; }
|
|
25
|
+
get defaultGapSymbol() { return this._defaultGapSymbol; }
|
|
26
|
+
get separator() {
|
|
27
|
+
const separator = this.sourceColumn.getTag('separator');
|
|
28
|
+
if (separator !== null)
|
|
29
|
+
return separator;
|
|
30
|
+
else
|
|
31
|
+
throw new Error('Separator not set');
|
|
32
|
+
}
|
|
33
|
+
isFasta() { return this.sourceNotation === "FASTA" /* NOTATION.FASTA */; }
|
|
34
|
+
isSeparator() { return this.sourceNotation === "SEPARATOR" /* NOTATION.SEPARATOR */; }
|
|
35
|
+
isHelm() { return this.sourceNotation === "HELM" /* NOTATION.HELM */; }
|
|
36
|
+
toFasta(targetNotation) { return targetNotation === "FASTA" /* NOTATION.FASTA */; }
|
|
37
|
+
toSeparator(targetNotation) { return targetNotation === "SEPARATOR" /* NOTATION.SEPARATOR */; }
|
|
38
|
+
toHelm(targetNotation) { return targetNotation === "HELM" /* NOTATION.HELM */; }
|
|
39
|
+
isRna() { return this.sourceUnits.toLowerCase().endsWith('rna'); }
|
|
40
|
+
isDna() { return this.sourceUnits.toLowerCase().endsWith('dna'); }
|
|
41
|
+
isPeptide() { return this.sourceUnits.toLowerCase().endsWith('pt'); }
|
|
42
|
+
/** Associate notation types with the corresponding units */
|
|
43
|
+
/**
|
|
44
|
+
* @return {NOTATION} Notation associated with the units type
|
|
45
|
+
*/
|
|
46
|
+
getSourceNotation() {
|
|
47
|
+
if (this.sourceUnits.toLowerCase().startsWith('fasta'))
|
|
48
|
+
return "FASTA" /* NOTATION.FASTA */;
|
|
49
|
+
else if (this.sourceUnits.toLowerCase().startsWith('separator'))
|
|
50
|
+
return "SEPARATOR" /* NOTATION.SEPARATOR */;
|
|
51
|
+
else if (this.sourceUnits.toLowerCase().startsWith('helm'))
|
|
52
|
+
return "HELM" /* NOTATION.HELM */;
|
|
53
|
+
else
|
|
54
|
+
throw new Error('The column has units that do not correspond to any notation');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create a new empty column of the specified notation type and the same
|
|
58
|
+
* length as sourceColumn
|
|
59
|
+
*
|
|
60
|
+
* @param {NOTATION} targetNotation
|
|
61
|
+
* @return {DG.Column}
|
|
62
|
+
*/
|
|
63
|
+
getNewColumn(targetNotation) {
|
|
64
|
+
const col = this.sourceColumn;
|
|
65
|
+
const len = col.length;
|
|
66
|
+
const name = targetNotation + '(' + col.name + ')';
|
|
67
|
+
const newColName = col.dataFrame.columns.getUnusedName(name);
|
|
68
|
+
// dummy code
|
|
69
|
+
const newColumn = DG.Column.fromList('string', newColName, new Array(len).fill(''));
|
|
70
|
+
newColumn.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
71
|
+
newColumn.setTag(DG.TAGS.UNITS, this.sourceUnits.replace(this.sourceNotation.toLowerCase().toString(), targetNotation.toLowerCase().toString()));
|
|
72
|
+
// TODO: specify cell renderers for all cases
|
|
73
|
+
if (this.toFasta(targetNotation)) {
|
|
74
|
+
newColumn.setTag(DG.TAGS.CELL_RENDERER,
|
|
75
|
+
// TODO: replace by the enumeration value
|
|
76
|
+
'Macromolecule');
|
|
77
|
+
}
|
|
78
|
+
return newColumn;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Convert a Macromolecule column from FASTA to SEPARATOR notation
|
|
82
|
+
*
|
|
83
|
+
* @param {string} separator A specific separator to be used
|
|
84
|
+
* @param {string} gapSymbol Gap symbol in FASTA, '-' by default
|
|
85
|
+
* @return {DG.Column} A new column in SEPARATOR notation
|
|
86
|
+
*/
|
|
87
|
+
convertFastaToSeparator(separator, gapSymbol = '-') {
|
|
88
|
+
// a function splitting FASTA sequence into an array of monomers:
|
|
89
|
+
const splitterAsFasta = WebLogo.splitterAsFasta;
|
|
90
|
+
const newColumn = this.getNewColumn("SEPARATOR" /* NOTATION.SEPARATOR */);
|
|
91
|
+
// assign the values to the newly created empty column
|
|
92
|
+
newColumn.init((idx) => {
|
|
93
|
+
const fastaPolymer = this.sourceColumn.get(idx);
|
|
94
|
+
const fastaMonomersArray = splitterAsFasta(fastaPolymer);
|
|
95
|
+
for (let i = 0; i < fastaMonomersArray.length; i++) {
|
|
96
|
+
if (fastaMonomersArray[i] === gapSymbol)
|
|
97
|
+
fastaMonomersArray[i] = '';
|
|
98
|
+
}
|
|
99
|
+
return fastaMonomersArray.join(separator);
|
|
100
|
+
});
|
|
101
|
+
return newColumn;
|
|
102
|
+
}
|
|
103
|
+
convertToHelm(sourceGapSymbol = null) {
|
|
104
|
+
if (sourceGapSymbol === null)
|
|
105
|
+
sourceGapSymbol = this.defaultGapSymbol;
|
|
106
|
+
// A function splitting a sequence into an array of monomers according to
|
|
107
|
+
// its notation
|
|
108
|
+
const splitter = WebLogo.getSplitterForColumn(this.sourceColumn);
|
|
109
|
+
const prefix = (this.isDna()) ? 'DNA1{' :
|
|
110
|
+
(this.isRna()) ? 'RNA1{' :
|
|
111
|
+
(this.isPeptide()) ? 'PEPTIDE1{' :
|
|
112
|
+
'Unknown'; // this case should be handled as exceptional
|
|
113
|
+
if (prefix === 'Unknown')
|
|
114
|
+
throw new Error('Neither peptide, nor nucleotide');
|
|
115
|
+
const postfix = '}$$$';
|
|
116
|
+
const leftWrapper = (this.isDna()) ? 'D(' :
|
|
117
|
+
(this.isRna()) ? 'R(' : ''; // no wrapper for peptides
|
|
118
|
+
const rightWrapper = (this.isDna() || this.isRna()) ? ')P' : ''; // no wrapper for peptides
|
|
119
|
+
const newColumn = this.getNewColumn("HELM" /* NOTATION.HELM */);
|
|
120
|
+
// assign the values to the empty column
|
|
121
|
+
newColumn.init((idx) => {
|
|
122
|
+
const sourcePolymer = this.sourceColumn.get(idx);
|
|
123
|
+
const sourceMonomersArray = splitter(sourcePolymer);
|
|
124
|
+
const helmArray = [prefix];
|
|
125
|
+
let firstIteration = true;
|
|
126
|
+
for (let i = 0; i < sourceMonomersArray.length; i++) {
|
|
127
|
+
const dot = firstIteration ? '' : '.';
|
|
128
|
+
let token = sourceMonomersArray[i];
|
|
129
|
+
if (token === sourceGapSymbol)
|
|
130
|
+
token = this._defaultGapSymbolsDict.helm;
|
|
131
|
+
const item = [dot, leftWrapper, token, rightWrapper];
|
|
132
|
+
helmArray.push(item.join(''));
|
|
133
|
+
firstIteration = false;
|
|
134
|
+
}
|
|
135
|
+
helmArray.push(postfix);
|
|
136
|
+
return helmArray.join('');
|
|
137
|
+
});
|
|
138
|
+
return newColumn;
|
|
139
|
+
}
|
|
140
|
+
handleSeparatorItemForFasta(idx, separatorItemsArray, separator, gapSymbol, fastaMonomersArray) {
|
|
141
|
+
const item = separatorItemsArray[idx];
|
|
142
|
+
if (item.length > 1) {
|
|
143
|
+
// the case of a multi-character monomer
|
|
144
|
+
const monomer = '[' + item + ']';
|
|
145
|
+
fastaMonomersArray.push(monomer);
|
|
146
|
+
}
|
|
147
|
+
if (item === separator) {
|
|
148
|
+
if (idx !== 0 && separatorItemsArray[idx - 1] === separator)
|
|
149
|
+
fastaMonomersArray.push(gapSymbol);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
convertSeparatorToFasta(separator = null, gapSymbol = '-') {
|
|
153
|
+
// TODO: implementation
|
|
154
|
+
// * similarly to fasta2separator, divide string into monomers
|
|
155
|
+
// * adjacent separators is a gap (symbol to be specified)
|
|
156
|
+
// * the monomers MUST be single-character onles, otherwise forbid
|
|
157
|
+
// * NO, they can be multi-characters
|
|
158
|
+
// conversion
|
|
159
|
+
// * consider automatic determining the separator
|
|
160
|
+
if (separator === null)
|
|
161
|
+
separator = this.separator;
|
|
162
|
+
// a function splitting FASTA sequence into an array of monomers
|
|
163
|
+
//const splitterAsSeparator = WebLogo.getSplitterWithSeparator(separator);
|
|
164
|
+
const splitter = WebLogo.getSplitterForColumn(this.sourceColumn);
|
|
165
|
+
const newColumn = this.getNewColumn("FASTA" /* NOTATION.FASTA */);
|
|
166
|
+
// assign the values to the empty column
|
|
167
|
+
newColumn.init((idx) => {
|
|
168
|
+
const separatorPolymer = this.sourceColumn.get(idx);
|
|
169
|
+
// items can be monomers or separators
|
|
170
|
+
const separatorItemsArray = splitter(separatorPolymer);
|
|
171
|
+
const fastaMonomersArray = [];
|
|
172
|
+
for (let i = 0; i < separatorItemsArray.length; i++) {
|
|
173
|
+
const item = separatorItemsArray[i];
|
|
174
|
+
if (item.length === 0) {
|
|
175
|
+
fastaMonomersArray.push(gapSymbol);
|
|
176
|
+
}
|
|
177
|
+
else if (item.length > 1) {
|
|
178
|
+
// the case of a multi-character monomer
|
|
179
|
+
const monomer = '[' + item + ']';
|
|
180
|
+
fastaMonomersArray.push(monomer);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
fastaMonomersArray.push(item);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return fastaMonomersArray.join('');
|
|
187
|
+
});
|
|
188
|
+
return newColumn;
|
|
189
|
+
}
|
|
190
|
+
convertHelmToFasta() {
|
|
191
|
+
// TODO: implementation
|
|
192
|
+
return this.getNewColumn("FASTA" /* NOTATION.FASTA */);
|
|
193
|
+
}
|
|
194
|
+
convertHelmToSeparator() {
|
|
195
|
+
// TODO: implementatioreturn this.getNewColumn();
|
|
196
|
+
return this.getNewColumn("SEPARATOR" /* NOTATION.SEPARATOR */);
|
|
197
|
+
}
|
|
198
|
+
/** Dispatcher method for notation conversion
|
|
199
|
+
*
|
|
200
|
+
* @param {NOTATION} targetNotation Notation we want to convert to
|
|
201
|
+
* @param {string | null} tgtSeparator Possible separator
|
|
202
|
+
* @return {DG.Column} Converted column
|
|
203
|
+
*/
|
|
204
|
+
convert(targetNotation, tgtSeparator = null) {
|
|
205
|
+
// possible exceptions
|
|
206
|
+
if (this.sourceNotation === targetNotation)
|
|
207
|
+
throw new Error('Target notation is invalid');
|
|
208
|
+
if (this.toSeparator(targetNotation) && tgtSeparator === null)
|
|
209
|
+
throw new Error('Target separator is not specified');
|
|
210
|
+
if (this.isFasta() && this.toSeparator(targetNotation) && tgtSeparator !== null)
|
|
211
|
+
return this.convertFastaToSeparator(tgtSeparator);
|
|
212
|
+
else if ((this.isFasta() || this.isSeparator()) && this.toHelm(targetNotation))
|
|
213
|
+
return this.convertToHelm();
|
|
214
|
+
else if (this.isSeparator() && this.toFasta(targetNotation))
|
|
215
|
+
return this.convertSeparatorToFasta(tgtSeparator);
|
|
216
|
+
else if (this.isHelm() && this.toFasta(targetNotation))
|
|
217
|
+
return this.convertHelmToFasta();
|
|
218
|
+
else
|
|
219
|
+
return this.convertHelmToSeparator();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90YXRpb24tY29udmVydGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibm90YXRpb24tY29udmVydGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDdEMsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBUzVDLGlGQUFpRjtBQUNqRixNQUFNLE9BQU8saUJBQWlCO0lBZ1E1QixZQUFtQixHQUFjO1FBM1B6QiwyQkFBc0IsR0FBRztZQUMvQixJQUFJLEVBQUUsR0FBRztZQUNULFNBQVMsRUFBRSxFQUFFO1lBQ2IsS0FBSyxFQUFFLEdBQUc7U0FDWCxDQUFDO1FBd1BBLElBQUksQ0FBQyxhQUFhLEdBQUcsR0FBRyxDQUFDO1FBQ3pCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDckQsSUFBSSxLQUFLLEtBQUssSUFBSTtZQUNoQixJQUFJLENBQUMsWUFBWSxHQUFHLEtBQUssQ0FBQzs7WUFFMUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQ0FBbUMsQ0FBQyxDQUFDO1FBQ3ZELElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFDaEQsSUFBSSxDQUFDLGlCQUFpQixHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUM3RSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2xELElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxTQUFTLENBQUM7SUFDNUMsQ0FBQztJQWhRRCxJQUFZLFdBQVcsS0FBYSxPQUFPLElB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Qyw0QkFBNEIsQ0FBQyxDQUFDO1FBQ2hELElBQUksSUFBSSxDQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUMsSUFBSSxZQUFZLEtBQUssSUFBSTtZQUMzRCxNQUFNLElBQUksS0FBSyxDQUFDLG1DQUFtQyxDQUFDLENBQUM7UUFFdkQsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLElBQUksSUFBSSxDQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUMsSUFBSSxZQUFZLEtBQUssSUFBSTtZQUM3RSxPQUFPLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxZQUFZLENBQUMsQ0FBQzthQUMvQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDO1lBQzVFLE9BQU8sSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO2FBQ3pCLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDO1lBQ3pELE9BQU8sSUFBSSxDQUFDLHVCQUF1QixDQUFDLFlBQWEsQ0FBQyxDQUFDO2FBQ2hELElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDO1lBQ3BELE9BQU8sSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7O1lBRWpDLE9BQU8sSUFBSSxDQUFDLHNCQUFzQixFQUFFLENBQUM7SUFDekMsQ0FBQztDQWNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgREcgZnJvbSAnZGF0YWdyb2stYXBpL2RnJztcbmltcG9ydCB7V2ViTG9nb30gZnJvbSAnLi4vdmlld2Vycy93ZWItbG9nbyc7XG5cbi8qKiBlbnVtIHR5cGUgdG8gc2ltcGxpZnkgc2V0dGluZyBcInVzZXItZnJpZW5kbHlcIiBub3RhdGlvbiBpZiBuZWNlc3NhcnkgKi9cbmV4cG9ydCBjb25zdCBlbnVtIE5PVEFUSU9OIHtcbiAgRkFTVEEgPSAnRkFTVEEnLFxuICBTRVBBUkFUT1IgPSAnU0VQQVJBVE9SJyxcbiAgSEVMTSA9ICdIRUxNJ1xufVxuXG4vKiogQ2xhc3MgZm9yIGhhbmRsaW5nIGNvbnZlcnNpb24gb2Ygbm90YXRpb24gc3lzdGVtcyBpbiBNYWNyb21vbGVjdWxlIGNvbHVtbnMgKi9cbmV4cG9ydCBjbGFzcyBOb3RhdGlvbkNvbnZlcnRlciB7XG4gIHByaXZhdGUgX3NvdXJjZUNvbHVtbjogREcuQ29sdW1uOyAvLyB0aGUgY29sdW1uIHRvIGJlIGNvbnZlcnRlZFxuICBwcml2YXRlIF9zb3VyY2VVbml0czogc3RyaW5nOyAvLyB1bml0cywgb2YgdGhlIGZvcm0gZmFzdGE6U0VROk5ULCBldGMuXG4gIHByaXZhdGUgX3NvdXJjZU5vdGF0aW9uOiBOT1RBVElPTjsgLy8gY3VycmVudCBub3RhdGlvbiAod2l0aG91dCA6U0VROk5ULCBldGMuKVxuICBwcml2YXRlIF9kZWZhdWx0R2FwU3ltYm9sOiBzdHJpbmc7XG4gIHByaXZhdGUgX2RlZmF1bHRHYXBTeW1ib2xzRGljdCA9IHtcbiAgICBoZWxtOiAnKicsXG4gICAgc2VwYXJhdG9yOiAnJyxcbiAgICBmYXN0YTogJy0nLFxuICB9O1xuXG4gIHByaXZhdGUgZ2V0IHNvdXJjZVVuaXRzKCk6IHN0cmluZyB7IHJldHVybiB0aGlzLl9zb3VyY2VVbml0czsgfVxuXG4gIHByaXZhdGUgZ2V0IHNvdXJjZUNvbHVtbigpOiBERy5Db2x1bW4geyByZXR1cm4gdGhpcy5fc291cmNlQ29sdW1uOyB9XG5cbiAgcHVibGljIGdldCBzb3VyY2VOb3RhdGlvbigpOiBOT1RBVElPTiB7IHJldHVybiB0aGlzLl9zb3VyY2VOb3RhdGlvbjsgfVxuXG4gIHB1YmxpYyBnZXQgZGVmYXVsdEdhcFN5bWJvbCgpOiBzdHJpbmcgeyByZXR1cm4gdGhpcy5fZGVmYXVsdEdhcFN5bWJvbDsgfVxuXG4gIHB1YmxpYyBnZXQgc2VwYXJhdG9yKCk6IHN0cmluZyB7XG4gICAgY29uc3Qgc2VwYXJhdG9yID0gdGhpcy5zb3VyY2VDb2x1bW4uZ2V0VGFnKCdzZXBhcmF0b3InKTtcbiAgICBpZiAoc2VwYXJhdG9yICE9PSBudWxsKVxuICAgICAgcmV0dXJuIHNlcGFyYXRvcjtcbiAgICBlbHNlXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NlcGFyYXRvciBub3Qgc2V0Jyk7XG4gIH1cblxuICBwdWJsaWMgaXNGYXN0YSgpOiBib29sZWFuIHsgcmV0dXJuIHRoaXMuc291cmNlTm90YXRpb24gPT09IE5PVEFUSU9OLkZBU1RBOyB9XG5cbiAgcHVibGljIGlzU2VwYXJhdG9yKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5zb3VyY2VOb3RhdGlvbiA9PT0gTk9UQVRJT04uU0VQQVJBVE9SOyB9XG5cbiAgcHVibGljIGlzSGVsbSgpOiBib29sZWFuIHsgcmV0dXJuIHRoaXMuc291cmNlTm90YXRpb24gPT09IE5PVEFUSU9OLkhFTE07IH1cblxuICBwdWJsaWMgdG9GYXN0YSh0YXJnZXROb3RhdGlvbjogTk9UQVRJT04pOiBib29sZWFuIHsgcmV0dXJuIHRhcmdldE5vdGF0aW9uID09PSBOT1RBVElPTi5GQVNUQTsgfVxuXG4gIHB1YmxpYyB0b1NlcGFyYXRvcih0YXJnZXROb3RhdGlvbjogTk9UQVRJT04pOiBib29sZWFuIHsgcmV0dXJuIHRhcmdldE5vdGF0aW9uID09PSBOT1RBVElPTi5TRVBBUkFUT1I7IH1cblxuICBwdWJsaWMgdG9IZWxtKHRhcmdldE5vdGF0aW9uOiBOT1RBVElPTik6IGJvb2xlYW4geyByZXR1cm4gdGFyZ2V0Tm90YXRpb24gPT09IE5PVEFUSU9OLkhFTE07IH1cblxuICBwdWJsaWMgaXNSbmEoKTogYm9vbGVhbiB7IHJldHVybiB0aGlzLnNvdXJjZVVuaXRzLnRvTG93ZXJDYXNlKCkuZW5kc1dpdGgoJ3JuYScpOyB9XG5cbiAgcHVibGljIGlzRG5hKCk6IGJvb2xlYW4geyByZXR1cm4gdGhpcy5zb3VyY2VVbml0cy50b0xvd2VyQ2FzZSgpLmVuZHNXaXRoKCdkbmEnKTsgfVxuXG4gIHB1YmxpYyBpc1BlcHRpZGUoKTogYm9vbGVhbiB7IHJldHVybiB0aGlzLnNvdXJjZVVuaXRzLnRvTG93ZXJDYXNlKCkuZW5kc1dpdGgoJ3B0Jyk7IH1cblxuICAvKiogQXNzb2NpYXRlIG5vdGF0aW9uIHR5cGVzIHdpdGggdGhlIGNvcnJlc3BvbmRpbmcgdW5pdHMgKi9cbiAgLyoqXG4gICAqIEByZXR1cm4ge05PVEFUSU9OfSAgICAgTm90YXRpb24gYXNzb2NpYXRlZCB3aXRoIHRoZSB1bml0cyB0eXBlXG4gICAqL1xuICBwcml2YXRlIGdldFNvdXJjZU5vdGF0aW9uKCk6IE5PVEFUSU9OIHtcbiAgICBpZiAodGhpcy5zb3VyY2VVbml0cy50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoJ2Zhc3RhJykpXG4gICAgICByZXR1cm4gTk9UQVRJT04uRkFTVEE7XG4gICAgZWxzZSBpZiAodGhpcy5zb3VyY2VVbml0cy50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoJ3NlcGFyYXRvcicpKVxuICAgICAgcmV0dXJuIE5PVEFUSU9OLlNFUEFSQVRPUjtcbiAgICBlbHNlIGlmICh0aGlzLnNvdXJjZVVuaXRzLnRvTG93ZXJDYXNlKCkuc3RhcnRzV2l0aCgnaGVsbScpKVxuICAgICAgcmV0dXJuIE5PVEFUSU9OLkhFTE07XG4gICAgZWxzZVxuICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGUgY29sdW1uIGhhcyB1bml0cyB0aGF0IGRvIG5vdCBjb3JyZXNwb25kIHRvIGFueSBub3RhdGlvbicpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIG5ldyBlbXB0eSBjb2x1bW4gb2YgdGhlIHNwZWNpZmllZCBub3RhdGlvbiB0eXBlIGFuZCB0aGUgc2FtZVxuICAgKiBsZW5ndGggYXMgc291cmNlQ29sdW1uXG4gICAqXG4gICAqIEBwYXJhbSB7Tk9UQVRJT059IHRhcmdldE5vdGF0aW9uXG4gICAqIEByZXR1cm4ge0RHLkNvbHVtbn1cbiAgICovXG4gIHByaXZhdGUgZ2V0TmV3Q29sdW1uKHRhcmdldE5vdGF0aW9uOiBOT1RBVElPTik6IERHLkNvbHVtbiB7XG4gICAgY29uc3QgY29sID0gdGhpcy5zb3VyY2VDb2x1bW47XG4gICAgY29uc3QgbGVuID0gY29sLmxlbmd0aDtcbiAgICBjb25zdCBuYW1lID0gdGFyZ2V0Tm90YXRpb24gKyAnKCcgKyBjb2wubmFtZSArICcpJztcbiAgICBjb25zdCBuZXdDb2xOYW1lID0gY29sLmRhdGFGcmFtZS5jb2x1bW5zLmdldFVudXNlZE5hbWUobmFtZSk7XG4gICAgLy8gZHVtbXkgY29kZVxuICAgIGNvbnN0IG5ld0NvbHVtbiA9IERHLkNvbHVtbi5mcm9tTGlzdCgnc3RyaW5nJywgbmV3Q29sTmFtZSwgbmV3IEFycmF5KGxlbikuZmlsbCgnJykpO1xuICAgIG5ld0NvbHVtbi5zZW1UeXBlID0gREcuU0VNVFlQRS5NQUNST01PTEVDVUxFO1xuICAgIG5ld0NvbHVtbi5zZXRUYWcoXG4gICAgICBERy5UQUdTLlVOSVRTLFxuICAgICAgdGhpcy5zb3VyY2VVbml0cy5yZXBsYWNlKFxuICAgICAgICB0aGlzLnNvdXJjZU5vdGF0aW9uLnRvTG93ZXJDYXNlKCkudG9TdHJpbmcoKSxcbiAgICAgICAgdGFyZ2V0Tm90YXRpb24udG9Mb3dlckNhc2UoKS50b1N0cmluZygpXG4gICAgICApXG4gICAgKTtcbiAgICAvLyBUT0RPOiBzcGVjaWZ5IGNlbGwgcmVuZGVyZXJzIGZvciBhbGwgY2FzZXNcbiAgICBpZiAodGhpcy50b0Zhc3RhKHRhcmdldE5vdGF0aW9uKSkge1xuICAgICAgbmV3Q29sdW1uLnNldFRhZyhcbiAgICAgICAgREcuVEFHUy5DRUxMX1JFTkRFUkVSLFxuICAgICAgICAvLyBUT0RPOiByZXBsYWNlIGJ5IHRoZSBlbnVtZXJhdGlvbiB2YWx1ZVxuICAgICAgICAnTWFjcm9tb2xlY3VsZScpO1xuICAgIH1cbiAgICByZXR1cm4gbmV3Q29sdW1uO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYSBNYWNyb21vbGVjdWxlIGNvbHVtbiBmcm9tIEZBU1RBIHRvIFNFUEFSQVRPUiBub3RhdGlvblxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gc2VwYXJhdG9yICBBIHNwZWNpZmljIHNlcGFyYXRvciB0byBiZSB1c2VkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBnYXBTeW1ib2wgIEdhcCBzeW1ib2wgaW4gRkFTVEEsICctJyBieSBkZWZhdWx0XG4gICAqIEByZXR1cm4ge0RHLkNvbHVtbn0gICAgICAgIEEgbmV3IGNvbHVtbiBpbiBTRVBBUkFUT1Igbm90YXRpb25cbiAgICovXG4gIHByaXZhdGUgY29udmVydEZhc3RhVG9TZXBhcmF0b3Ioc2VwYXJhdG9yOiBzdHJpbmcsIGdhcFN5bWJvbDogc3RyaW5nID0gJy0nKTogREcuQ29sdW1uIHtcbiAgICAvLyBhIGZ1bmN0aW9uIHNwbGl0dGluZyBGQVNUQSBzZXF1ZW5jZSBpbnRvIGFuIGFycmF5IG9mIG1vbm9tZXJzOlxuICAgIGNvbnN0IHNwbGl0dGVyQXNGYXN0YSA9IFdlYkxvZ28uc3BsaXR0ZXJBc0Zhc3RhO1xuXG4gICAgY29uc3QgbmV3Q29sdW1uID0gdGhpcy5nZXROZXdDb2x1bW4oTk9UQVRJT04uU0VQQVJBVE9SKTtcbiAgICAvLyBhc3NpZ24gdGhlIHZhbHVlcyB0byB0aGUgbmV3bHkgY3JlYXRlZCBlbXB0eSBjb2x1bW5cbiAgICBuZXdDb2x1bW4uaW5pdCgoaWR4OiBudW1iZXIpID0+IHtcbiAgICAgIGNvbnN0IGZhc3RhUG9seW1lciA9IHRoaXMuc291cmNlQ29sdW1uLmdldChpZHgpO1xuICAgICAgY29uc3QgZmFzdGFNb25vbWVyc0FycmF5ID0gc3BsaXR0ZXJBc0Zhc3RhKGZhc3RhUG9seW1lcik7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGZhc3RhTW9ub21lcnNBcnJheS5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAoZmFzdGFNb25vbWVyc0FycmF5W2ldID09PSBnYXBTeW1ib2wpXG4gICAgICAgICAgZmFzdGFNb25vbWVyc0FycmF5W2ldID0gJyc7XG4gICAgICB9XG4gICAgICByZXR1cm4gZmFzdGFNb25vbWVyc0FycmF5LmpvaW4oc2VwYXJhdG9yKTtcbiAgICB9KTtcbiAgICByZXR1cm4gbmV3Q29sdW1uO1xuICB9XG5cbiAgcHJpdmF0ZSBjb252ZXJ0VG9IZWxtKHNvdXJjZUdhcFN5bWJvbDogc3RyaW5nIHwgbnVsbCA9IG51bGwpIHtcbiAgICBpZiAoc291cmNlR2FwU3ltYm9sID09PSBudWxsKVxuICAgICAgc291cmNlR2FwU3ltYm9sID0gdGhpcy5kZWZhdWx0R2FwU3ltYm9sO1xuICAgIC8vIEEgZnVuY3Rpb24gc3BsaXR0aW5nIGEgc2VxdWVuY2UgaW50byBhbiBhcnJheSBvZiBtb25vbWVycyBhY2NvcmRpbmcgdG9cbiAgICAvLyBpdHMgbm90YXRpb25cbiAgICBjb25zdCBzcGxpdHRlciA9IFdlYkxvZ28uZ2V0U3BsaXR0ZXJGb3JDb2x1bW4odGhpcy5zb3VyY2VDb2x1bW4pO1xuXG4gICAgY29uc3QgcHJlZml4ID0gKHRoaXMuaXNEbmEoKSkgPyAnRE5BMXsnIDpcbiAgICAgICh0aGlzLmlzUm5hKCkpID8gJ1JOQTF7JyA6XG4gICAgICAgICh0aGlzLmlzUGVwdGlkZSgpKSA/ICdQRVBUSURFMXsnIDpcbiAgICAgICAgICAnVW5rbm93bic7IC8vIHRoaXMgY2FzZSBzaG91bGQgYmUgaGFuZGxlZCBhcyBleGNlcHRpb25hbFxuXG4gICAgaWYgKHByZWZpeCA9PT0gJ1Vua25vd24nKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKCdOZWl0aGVyIHBlcHRpZGUsIG5vciBudWNsZW90aWRlJyk7XG5cbiAgICBjb25zdCBwb3N0Zml4ID0gJ30kJCQnO1xuICAgIGNvbnN0IGxlZnRXcmFwcGVyID0gKHRoaXMuaXNEbmEoKSkgPyAnRCgnIDpcbiAgICAgICh0aGlzLmlzUm5hKCkpID8gJ1IoJyA6ICcnOyAvLyBubyB3cmFwcGVyIGZvciBwZXB0aWRlc1xuICAgIGNvbnN0IHJpZ2h0V3JhcHBlciA9ICh0aGlzLmlzRG5hKCkgfHwgdGhpcy5pc1JuYSgpKSA/ICcpUCcgOiAnJzsgLy8gbm8gd3JhcHBlciBmb3IgcGVwdGlkZXNcblxuICAgIGNvbnN0IG5ld0NvbHVtbiA9IHRoaXMuZ2V0TmV3Q29sdW1uKE5PVEFUSU9OLkhFTE0pO1xuICAgIC8vIGFzc2lnbiB0aGUgdmFsdWVzIHRvIHRoZSBlbXB0eSBjb2x1bW5cbiAgICBuZXdDb2x1bW4uaW5pdCgoaWR4OiBudW1iZXIpID0+IHtcbiAgICAgIGNvbnN0IHNvdXJjZVBvbHltZXIgPSB0aGlzLnNvdXJjZUNvbHVtbi5nZXQoaWR4KTtcbiAgICAgIGNvbnN0IHNvdXJjZU1vbm9tZXJzQXJyYXkgPSBzcGxpdHRlcihzb3VyY2VQb2x5bWVyKTtcbiAgICAgIGNvbnN0IGhlbG1BcnJheSA9IFtwcmVmaXhdO1xuICAgICAgbGV0IGZpcnN0SXRlcmF0aW9uID0gdHJ1ZTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc291cmNlTW9ub21lcnNBcnJheS5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zdCBkb3QgPSBmaXJzdEl0ZXJhdGlvbiA/ICcnIDogJy4nO1xuICAgICAgICBsZXQgdG9rZW4gPSBzb3VyY2VNb25vbWVyc0FycmF5W2ldO1xuICAgICAgICBpZiAodG9rZW4gPT09IHNvdXJjZUdhcFN5bWJvbClcbiAgICAgICAgICB0b2tlbiA9IHRoaXMuX2RlZmF1bHRHYXBTeW1ib2xzRGljdC5oZWxtO1xuICAgICAgICBjb25zdCBpdGVtID0gW2RvdCwgbGVmdFdyYXBwZXIsIHRva2VuLCByaWdodFdyYXBwZXJdO1xuICAgICAgICBoZWxtQXJyYXkucHVzaChpdGVtLmpvaW4oJycpKTtcbiAgICAgICAgZmlyc3RJdGVyYXRpb24gPSBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGhlbG1BcnJheS5wdXNoKHBvc3RmaXgpO1xuICAgICAgcmV0dXJuIGhlbG1BcnJheS5qb2luKCcnKTtcbiAgICB9KTtcbiAgICByZXR1cm4gbmV3Q29sdW1uO1xuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVTZXBhcmF0b3JJdGVtRm9yRmFzdGEoXG4gICAgaWR4OiBudW1iZXIsXG4gICAgc2VwYXJhdG9ySXRlbXNBcnJheTogc3RyaW5nW10sXG4gICAgc2VwYXJhdG9yOiBzdHJpbmcsXG4gICAgZ2FwU3ltYm9sOiBzdHJpbmcsXG4gICAgZmFzdGFNb25vbWVyc0FycmF5OiBzdHJpbmdbXVxuICApOiB2b2lkIHtcbiAgICBjb25zdCBpdGVtID0gc2VwYXJhdG9ySXRlbXNBcnJheVtpZHhdO1xuICAgIGlmIChpdGVtLmxlbmd0aCA+IDEpIHtcbiAgICAgIC8vIHRoZSBjYXNlIG9mIGEgbXVsdGktY2hhcmFjdGVyIG1vbm9tZXJcbiAgICAgIGNvbnN0IG1vbm9tZXIgPSAnWycgKyBpdGVtICsgJ10nO1xuICAgICAgZmFzdGFNb25vbWVyc0FycmF5LnB1c2gobW9ub21lcik7XG4gICAgfVxuICAgIGlmIChpdGVtID09PSBzZXBhcmF0b3IpIHtcbiAgICAgIGlmIChpZHggIT09IDAgJiYgc2VwYXJhdG9ySXRlbXNBcnJheVtpZHggLSAxXSA9PT0gc2VwYXJhdG9yKVxuICAgICAgICBmYXN0YU1vbm9tZXJzQXJyYXkucHVzaChnYXBTeW1ib2wpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY29udmVydFNlcGFyYXRvclRvRmFzdGEoXG4gICAgc2VwYXJhdG9yOiBzdHJpbmcgfCBudWxsID0gbnVsbCxcbiAgICBnYXBTeW1ib2w6IHN0cmluZyA9ICctJ1xuICApOiBERy5Db2x1bW4ge1xuICAgIC8vIFRPRE86IGltcGxlbWVudGF0aW9uXG4gICAgLy8gKiBzaW1pbGFybHkgdG8gZmFzdGEyc2VwYXJhdG9yLCBkaXZpZGUgc3RyaW5nIGludG8gbW9ub21lcnNcbiAgICAvLyAqIGFkamFjZW50IHNlcGFyYXRvcnMgaXMgYSBnYXAgKHN5bWJvbCB0byBiZSBzcGVjaWZpZWQpXG4gICAgLy8gKiB0aGUgbW9ub21lcnMgTVVTVCBiZSBzaW5nbGUtY2hhcmFjdGVyIG9ubGVzLCBvdGhlcndpc2UgZm9yYmlkXG4gICAgLy8gKiBOTywgdGhleSBjYW4gYmUgbXVsdGktY2hhcmFjdGVyc1xuICAgIC8vIGNvbnZlcnNpb25cbiAgICAvLyAqIGNvbnNpZGVyIGF1dG9tYXRpYyBkZXRlcm1pbmluZyB0aGUgc2VwYXJhdG9yXG5cbiAgICBpZiAoc2VwYXJhdG9yID09PSBudWxsKVxuICAgICAgc2VwYXJhdG9yID0gdGhpcy5zZXBhcmF0b3I7XG5cbiAgICAvLyBhIGZ1bmN0aW9uIHNwbGl0dGluZyBGQVNUQSBzZXF1ZW5jZSBpbnRvIGFuIGFycmF5IG9mIG1vbm9tZXJzXG4gICAgLy9jb25zdCBzcGxpdHRlckFzU2VwYXJhdG9yID0gV2ViTG9nby5nZXRTcGxpdHRlcldpdGhTZXBhcmF0b3Ioc2VwYXJhdG9yKTtcbiAgICBjb25zdCBzcGxpdHRlciA9IFdlYkxvZ28uZ2V0U3BsaXR0ZXJGb3JDb2x1bW4odGhpcy5zb3VyY2VDb2x1bW4pO1xuXG4gICAgY29uc3QgbmV3Q29sdW1uID0gdGhpcy5nZXROZXdDb2x1bW4oTk9UQVRJT04uRkFTVEEpO1xuICAgIC8vIGFzc2lnbiB0aGUgdmFsdWVzIHRvIHRoZSBlbXB0eSBjb2x1bW5cbiAgICBuZXdDb2x1bW4uaW5pdCgoaWR4OiBudW1iZXIpID0+IHtcbiAgICAgIGNvbnN0IHNlcGFyYXRvclBvbHltZXIgPSB0aGlzLnNvdXJjZUNvbHVtbi5nZXQoaWR4KTtcbiAgICAgIC8vIGl0ZW1zIGNhbiBiZSBtb25vbWVycyBvciBzZXBhcmF0b3JzXG4gICAgICBjb25zdCBzZXBhcmF0b3JJdGVtc0FycmF5ID0gc3BsaXR0ZXIoc2VwYXJhdG9yUG9seW1lcik7XG4gICAgICBjb25zdCBmYXN0YU1vbm9tZXJzQXJyYXk6IHN0cmluZ1tdID0gW107XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNlcGFyYXRvckl0ZW1zQXJyYXkubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgY29uc3QgaXRlbSA9IHNlcGFyYXRvckl0ZW1zQXJyYXlbaV07XG4gICAgICAgIGlmIChpdGVtLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIGZhc3RhTW9ub21lcnNBcnJheS5wdXNoKGdhcFN5bWJvbCk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXRlbS5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgLy8gdGhlIGNhc2Ugb2YgYSBtdWx0aS1jaGFyYWN0ZXIgbW9ub21lclxuICAgICAgICAgIGNvbnN0IG1vbm9tZXIgPSAnWycgKyBpdGVtICsgJ10nO1xuICAgICAgICAgIGZhc3RhTW9ub21lcnNBcnJheS5wdXNoKG1vbm9tZXIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGZhc3RhTW9ub21lcnNBcnJheS5wdXNoKGl0ZW0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gZmFzdGFNb25vbWVyc0FycmF5LmpvaW4oJycpO1xuICAgIH0pO1xuICAgIHJldHVybiBuZXdDb2x1bW47XG4gIH1cblxuICBwcml2YXRlIGNvbnZlcnRIZWxtVG9GYXN0YSgpOiBERy5Db2x1bW4ge1xuICAgIC8vIFRPRE86IGltcGxlbWVudGF0aW9uXG4gICAgcmV0dXJuIHRoaXMuZ2V0TmV3Q29sdW1uKE5PVEFUSU9OLkZBU1RBKTtcbiAgfVxuXG4gIHByaXZhdGUgY29udmVydEhlbG1Ub1NlcGFyYXRvcigpOiBERy5Db2x1bW4ge1xuICAgIC8vIFRPRE86IGltcGxlbWVudGF0aW9yZXR1cm4gdGhpcy5nZXROZXdDb2x1bW4oKTtcbiAgICByZXR1cm4gdGhpcy5nZXROZXdDb2x1bW4oTk9UQVRJT04uU0VQQVJBVE9SKTtcbiAgfVxuXG4gIC8qKiBEaXNwYXRjaGVyIG1ldGhvZCBmb3Igbm90YXRpb24gY29udmVyc2lvblxuICAgKlxuICAgKiBAcGFyYW0ge05PVEFUSU9OfSB0YXJnZXROb3RhdGlvbiAgIE5vdGF0aW9uIHdlIHdhbnQgdG8gY29udmVydCB0b1xuICAgKiBAcGFyYW0ge3N0cmluZyB8IG51bGx9IHRndFNlcGFyYXRvciAgIFBvc3NpYmxlIHNlcGFyYXRvclxuICAgKiBAcmV0dXJuIHtERy5Db2x1bW59ICAgICAgICAgICAgICAgIENvbnZlcnRlZCBjb2x1bW5cbiAgICovXG4gIHB1YmxpYyBjb252ZXJ0KHRhcmdldE5vdGF0aW9uOiBOT1RBVElPTiwgdGd0U2VwYXJhdG9yOiBzdHJpbmcgfCBudWxsID0gbnVsbCk6IERHLkNvbHVtbiB7XG4gICAgLy8gcG9zc2libGUgZXhjZXB0aW9uc1xuICAgIGlmICh0aGlzLnNvdXJjZU5vdGF0aW9uID09PSB0YXJnZXROb3RhdGlvbilcbiAgICAgIHRocm93IG5ldyBFcnJvcignVGFyZ2V0IG5vdGF0aW9uIGlzIGludmFsaWQnKTtcbiAgICBpZiAodGhpcy50b1NlcGFyYXRvcih0YXJnZXROb3RhdGlvbikgJiYgdGd0U2VwYXJhdG9yID09PSBudWxsKVxuICAgICAgdGhyb3cgbmV3IEVycm9yKCdUYXJnZXQgc2VwYXJhdG9yIGlzIG5vdCBzcGVjaWZpZWQnKTtcblxuICAgIGlmICh0aGlzLmlzRmFzdGEoKSAmJiB0aGlzLnRvU2VwYXJhdG9yKHRhcmdldE5vdGF0aW9uKSAmJiB0Z3RTZXBhcmF0b3IgIT09IG51bGwpXG4gICAgICByZXR1cm4gdGhpcy5jb252ZXJ0RmFzdGFUb1NlcGFyYXRvcih0Z3RTZXBhcmF0b3IpO1xuICAgIGVsc2UgaWYgKCh0aGlzLmlzRmFzdGEoKSB8fCB0aGlzLmlzU2VwYXJhdG9yKCkpICYmIHRoaXMudG9IZWxtKHRhcmdldE5vdGF0aW9uKSlcbiAgICAgIHJldHVybiB0aGlzLmNvbnZlcnRUb0hlbG0oKTtcbiAgICBlbHNlIGlmICh0aGlzLmlzU2VwYXJhdG9yKCkgJiYgdGhpcy50b0Zhc3RhKHRhcmdldE5vdGF0aW9uKSlcbiAgICAgIHJldHVybiB0aGlzLmNvbnZlcnRTZXBhcmF0b3JUb0Zhc3RhKHRndFNlcGFyYXRvciEpO1xuICAgIGVsc2UgaWYgKHRoaXMuaXNIZWxtKCkgJiYgdGhpcy50b0Zhc3RhKHRhcmdldE5vdGF0aW9uKSlcbiAgICAgIHJldHVybiB0aGlzLmNvbnZlcnRIZWxtVG9GYXN0YSgpO1xuICAgIGVsc2VcbiAgICAgIHJldHVybiB0aGlzLmNvbnZlcnRIZWxtVG9TZXBhcmF0b3IoKTtcbiAgfVxuXG4gIHB1YmxpYyBjb25zdHJ1Y3Rvcihjb2w6IERHLkNvbHVtbikge1xuICAgIHRoaXMuX3NvdXJjZUNvbHVtbiA9IGNvbDtcbiAgICBjb25zdCB1bml0cyA9IHRoaXMuX3NvdXJjZUNvbHVtbi50YWdzW0RHLlRBR1MuVU5JVFNdO1xuICAgIGlmICh1bml0cyAhPT0gbnVsbClcbiAgICAgIHRoaXMuX3NvdXJjZVVuaXRzID0gdW5pdHM7XG4gICAgZWxzZVxuICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbml0cyBhcmUgbm90IHNwZWNpZmllZCBpbiBjb2x1bW4nKTtcbiAgICB0aGlzLl9zb3VyY2VOb3RhdGlvbiA9IHRoaXMuZ2V0U291cmNlTm90YXRpb24oKTtcbiAgICB0aGlzLl9kZWZhdWx0R2FwU3ltYm9sID0gKHRoaXMuaXNGYXN0YSgpKSA/IHRoaXMuX2RlZmF1bHRHYXBTeW1ib2xzRGljdC5mYXN0YSA6XG4gICAgICAodGhpcy5pc0hlbG0oKSkgPyB0aGlzLl9kZWZhdWx0R2FwU3ltYm9sc0RpY3QuaGVsbSA6XG4gICAgICAgIHRoaXMuX2RlZmF1bHRHYXBTeW1ib2xzRGljdC5zZXBhcmF0b3I7XG4gIH1cbn1cbiJdfQ==
|