@gmod/bbi 1.0.30 → 1.0.31

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/dist/bbi.js CHANGED
@@ -1,455 +1,324 @@
1
1
  "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
-
5
- Object.defineProperty(exports, "__esModule", {
6
- value: true
7
- });
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (_) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __importDefault = (this && this.__importDefault) || function (mod) {
50
+ return (mod && mod.__esModule) ? mod : { "default": mod };
51
+ };
52
+ Object.defineProperty(exports, "__esModule", { value: true });
8
53
  exports.BBI = void 0;
9
-
10
- var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
11
-
12
- var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
13
-
14
- var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
15
-
16
- var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
17
-
18
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
19
-
20
- var _binaryParser = require("@gmod/binary-parser");
21
-
22
- var _genericFilehandle = require("generic-filehandle");
23
-
24
- var _rxjs = require("rxjs");
25
-
26
- var _operators = require("rxjs/operators");
27
-
28
- var _abortablePromiseCache = _interopRequireDefault(require("abortable-promise-cache"));
29
-
30
- var _quickLru = _interopRequireDefault(require("quick-lru"));
31
-
32
- var _blockView = require("./blockView");
33
-
34
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
35
-
36
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
37
-
54
+ var binary_parser_1 = require("@gmod/binary-parser");
55
+ var generic_filehandle_1 = require("generic-filehandle");
56
+ var rxjs_1 = require("rxjs");
57
+ var operators_1 = require("rxjs/operators");
58
+ var abortable_promise_cache_1 = __importDefault(require("abortable-promise-cache"));
59
+ var quick_lru_1 = __importDefault(require("quick-lru"));
60
+ var blockView_1 = require("./blockView");
38
61
  var BIG_WIG_MAGIC = -2003829722;
39
62
  var BIG_BED_MAGIC = -2021002517;
40
-
41
63
  /* get the compiled parsers for different sections of the bigwig file
42
64
  *
43
65
  * @param isBE - is big endian, typically false
44
66
  * @return an object with compiled parsers
45
67
  */
46
68
  function getParsers(isBE) {
47
- var le = isBE ? 'big' : 'little';
48
- var headerParser = new _binaryParser.Parser().endianess(le).int32('magic').uint16('version').uint16('numZoomLevels').uint64('chromTreeOffset').uint64('unzoomedDataOffset').uint64('unzoomedIndexOffset').uint16('fieldCount').uint16('definedFieldCount').uint64('asOffset') // autoSql offset, used in bigbed
49
- .uint64('totalSummaryOffset').uint32('uncompressBufSize').uint64('extHeaderOffset') // name index offset, used in bigbed
50
- .array('zoomLevels', {
51
- length: 'numZoomLevels',
52
- type: new _binaryParser.Parser().uint32('reductionLevel').uint32('reserved').uint64('dataOffset').uint64('indexOffset')
53
- });
54
- var totalSummaryParser = new _binaryParser.Parser().endianess(le).uint64('basesCovered').double('scoreMin').double('scoreMax').double('scoreSum').double('scoreSumSquares');
55
- var chromTreeParser = new _binaryParser.Parser().endianess(le).uint32('magic').uint32('blockSize').uint32('keySize').uint32('valSize').uint64('itemCount');
56
- var isLeafNode = new _binaryParser.Parser().endianess(le).uint8('isLeafNode').skip(1).uint16('cnt');
57
- return {
58
- chromTreeParser: chromTreeParser,
59
- totalSummaryParser: totalSummaryParser,
60
- headerParser: headerParser,
61
- isLeafNode: isLeafNode
62
- };
69
+ var le = isBE ? 'big' : 'little';
70
+ var headerParser = new binary_parser_1.Parser()
71
+ .endianess(le)
72
+ .int32('magic')
73
+ .uint16('version')
74
+ .uint16('numZoomLevels')
75
+ .uint64('chromTreeOffset')
76
+ .uint64('unzoomedDataOffset')
77
+ .uint64('unzoomedIndexOffset')
78
+ .uint16('fieldCount')
79
+ .uint16('definedFieldCount')
80
+ .uint64('asOffset') // autoSql offset, used in bigbed
81
+ .uint64('totalSummaryOffset')
82
+ .uint32('uncompressBufSize')
83
+ .uint64('extHeaderOffset') // name index offset, used in bigbed
84
+ .array('zoomLevels', {
85
+ length: 'numZoomLevels',
86
+ type: new binary_parser_1.Parser()
87
+ .uint32('reductionLevel')
88
+ .uint32('reserved')
89
+ .uint64('dataOffset')
90
+ .uint64('indexOffset'),
91
+ });
92
+ var totalSummaryParser = new binary_parser_1.Parser()
93
+ .endianess(le)
94
+ .uint64('basesCovered')
95
+ .double('scoreMin')
96
+ .double('scoreMax')
97
+ .double('scoreSum')
98
+ .double('scoreSumSquares');
99
+ var chromTreeParser = new binary_parser_1.Parser()
100
+ .endianess(le)
101
+ .uint32('magic')
102
+ .uint32('blockSize')
103
+ .uint32('keySize')
104
+ .uint32('valSize')
105
+ .uint64('itemCount');
106
+ var isLeafNode = new binary_parser_1.Parser()
107
+ .endianess(le)
108
+ .uint8('isLeafNode')
109
+ .skip(1)
110
+ .uint16('cnt');
111
+ return {
112
+ chromTreeParser: chromTreeParser,
113
+ totalSummaryParser: totalSummaryParser,
114
+ headerParser: headerParser,
115
+ isLeafNode: isLeafNode,
116
+ };
63
117
  }
64
-
65
- var BBI = /*#__PURE__*/function () {
66
- (0, _createClass2.default)(BBI, [{
67
- key: "getHeader",
68
-
69
- /* fetch and parse header information from a bigwig or bigbed file
70
- * @param abortSignal - abort the operation, can be null
71
- * @return a Header object
72
- */
73
- value: function getHeader() {
74
- var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
75
- var options = 'aborted' in opts ? {
76
- signal: opts
77
- } : opts;
78
- return this.headerCache.get(JSON.stringify(options), options, options.signal);
79
- }
118
+ var BBI = /** @class */ (function () {
80
119
  /*
81
120
  * @param filehandle - a filehandle from generic-filehandle or implementing something similar to the node10 fs.promises API
82
121
  * @param path - a Local file path as a string
83
122
  * @param url - a URL string
84
123
  * @param renameRefSeqs - an optional method to rename the internal reference sequences using a mapping function
85
124
  */
86
-
87
- }]);
88
-
89
- function BBI() {
90
- var _this = this;
91
-
92
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
93
- (0, _classCallCheck2.default)(this, BBI);
94
- (0, _defineProperty2.default)(this, "bbi", void 0);
95
- (0, _defineProperty2.default)(this, "headerCache", new _abortablePromiseCache.default({
96
- cache: new _quickLru.default({
97
- maxSize: 1
98
- }),
99
- fill: function () {
100
- var _fill = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(params, signal) {
101
- return _regenerator.default.wrap(function _callee$(_context) {
102
- while (1) {
103
- switch (_context.prev = _context.next) {
104
- case 0:
105
- return _context.abrupt("return", _this._getHeader(_objectSpread(_objectSpread({}, params), {}, {
106
- signal: signal
107
- })));
108
-
109
- case 1:
110
- case "end":
111
- return _context.stop();
112
- }
113
- }
114
- }, _callee);
115
- }));
116
-
117
- function fill(_x, _x2) {
118
- return _fill.apply(this, arguments);
125
+ function BBI(options) {
126
+ var _this = this;
127
+ if (options === void 0) { options = {}; }
128
+ this.headerCache = new abortable_promise_cache_1.default({
129
+ cache: new quick_lru_1.default({ maxSize: 1 }),
130
+ fill: function (params, signal) { return __awaiter(_this, void 0, void 0, function () {
131
+ return __generator(this, function (_a) {
132
+ return [2 /*return*/, this._getHeader(__assign(__assign({}, params), { signal: signal }))];
133
+ });
134
+ }); },
135
+ });
136
+ var filehandle = options.filehandle, renameRefSeqs = options.renameRefSeqs, path = options.path, url = options.url;
137
+ this.renameRefSeqs = renameRefSeqs || (function (s) { return s; });
138
+ if (filehandle) {
139
+ this.bbi = filehandle;
140
+ }
141
+ else if (url) {
142
+ this.bbi = new generic_filehandle_1.RemoteFile(url);
143
+ }
144
+ else if (path) {
145
+ this.bbi = new generic_filehandle_1.LocalFile(path);
146
+ }
147
+ else {
148
+ throw new Error('no file given');
119
149
  }
120
-
121
- return fill;
122
- }()
123
- }));
124
- (0, _defineProperty2.default)(this, "renameRefSeqs", void 0);
125
- var filehandle = options.filehandle,
126
- renameRefSeqs = options.renameRefSeqs,
127
- path = options.path,
128
- url = options.url;
129
-
130
- this.renameRefSeqs = renameRefSeqs || function (s) {
131
- return s;
132
- };
133
-
134
- if (filehandle) {
135
- this.bbi = filehandle;
136
- } else if (url) {
137
- this.bbi = new _genericFilehandle.RemoteFile(url);
138
- } else if (path) {
139
- this.bbi = new _genericFilehandle.LocalFile(path);
140
- } else {
141
- throw new Error('no file given');
142
150
  }
143
- }
144
-
145
- (0, _createClass2.default)(BBI, [{
146
- key: "_getHeader",
147
- value: function () {
148
- var _getHeader2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(opts) {
149
- var header, chroms;
150
- return _regenerator.default.wrap(function _callee2$(_context2) {
151
- while (1) {
152
- switch (_context2.prev = _context2.next) {
153
- case 0:
154
- _context2.next = 2;
155
- return this._getMainHeader(opts);
156
-
157
- case 2:
158
- header = _context2.sent;
159
- _context2.next = 5;
160
- return this._readChromTree(header, opts);
161
-
162
- case 5:
163
- chroms = _context2.sent;
164
- return _context2.abrupt("return", _objectSpread(_objectSpread({}, header), chroms));
165
-
166
- case 7:
167
- case "end":
168
- return _context2.stop();
169
- }
170
- }
171
- }, _callee2, this);
172
- }));
173
-
174
- function _getHeader(_x3) {
175
- return _getHeader2.apply(this, arguments);
176
- }
177
-
178
- return _getHeader;
179
- }()
180
- }, {
181
- key: "_getMainHeader",
182
- value: function () {
183
- var _getMainHeader2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(opts) {
184
- var requestSize,
185
- _yield$this$bbi$read,
186
- buffer,
187
- isBigEndian,
188
- ret,
189
- header,
190
- tail,
191
- _args3 = arguments;
192
-
193
- return _regenerator.default.wrap(function _callee3$(_context3) {
194
- while (1) {
195
- switch (_context3.prev = _context3.next) {
196
- case 0:
197
- requestSize = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : 2000;
198
- _context3.next = 3;
199
- return this.bbi.read(Buffer.alloc(requestSize), 0, requestSize, 0, opts);
200
-
201
- case 3:
202
- _yield$this$bbi$read = _context3.sent;
203
- buffer = _yield$this$bbi$read.buffer;
204
- isBigEndian = this._isBigEndian(buffer);
205
- ret = getParsers(isBigEndian);
206
- header = ret.headerParser.parse(buffer).result;
207
- header.fileType = header.magic === BIG_BED_MAGIC ? 'bigbed' : 'bigwig';
208
-
209
- if (!(header.asOffset > requestSize || header.totalSummaryOffset > requestSize)) {
210
- _context3.next = 11;
211
- break;
212
- }
213
-
214
- return _context3.abrupt("return", this._getMainHeader(opts, requestSize * 2));
215
-
216
- case 11:
217
- if (header.asOffset) {
218
- header.autoSql = buffer.slice(header.asOffset, buffer.indexOf(0, header.asOffset)).toString('utf8');
219
- }
220
-
221
- if (!(header.totalSummaryOffset > requestSize)) {
222
- _context3.next = 14;
223
- break;
224
- }
225
-
226
- return _context3.abrupt("return", this._getMainHeader(opts, requestSize * 2));
227
-
228
- case 14:
229
- if (header.totalSummaryOffset) {
230
- tail = buffer.slice(header.totalSummaryOffset);
231
- header.totalSummary = ret.totalSummaryParser.parse(tail).result;
151
+ /* fetch and parse header information from a bigwig or bigbed file
152
+ * @param abortSignal - abort the operation, can be null
153
+ * @return a Header object
154
+ */
155
+ BBI.prototype.getHeader = function (opts) {
156
+ if (opts === void 0) { opts = {}; }
157
+ var options = 'aborted' in opts ? { signal: opts } : opts;
158
+ return this.headerCache.get(JSON.stringify(options), options, options.signal);
159
+ };
160
+ BBI.prototype._getHeader = function (opts) {
161
+ return __awaiter(this, void 0, void 0, function () {
162
+ var header, chroms;
163
+ return __generator(this, function (_a) {
164
+ switch (_a.label) {
165
+ case 0: return [4 /*yield*/, this._getMainHeader(opts)];
166
+ case 1:
167
+ header = _a.sent();
168
+ return [4 /*yield*/, this._readChromTree(header, opts)];
169
+ case 2:
170
+ chroms = _a.sent();
171
+ return [2 /*return*/, __assign(__assign({}, header), chroms)];
232
172
  }
233
-
234
- return _context3.abrupt("return", _objectSpread(_objectSpread({}, header), {}, {
235
- isBigEndian: isBigEndian
236
- }));
237
-
238
- case 16:
239
- case "end":
240
- return _context3.stop();
241
- }
242
- }
243
- }, _callee3, this);
244
- }));
245
-
246
- function _getMainHeader(_x4) {
247
- return _getMainHeader2.apply(this, arguments);
248
- }
249
-
250
- return _getMainHeader;
251
- }()
252
- }, {
253
- key: "_isBigEndian",
254
- value: function _isBigEndian(buffer) {
255
- var ret = buffer.readInt32LE(0);
256
-
257
- if (ret === BIG_WIG_MAGIC || ret === BIG_BED_MAGIC) {
258
- return false;
259
- }
260
-
261
- ret = buffer.readInt32BE(0);
262
-
263
- if (ret === BIG_WIG_MAGIC || ret === BIG_BED_MAGIC) {
264
- return true;
265
- }
266
-
267
- throw new Error('not a BigWig/BigBed file');
268
- } // todo: add progress if long running
269
-
270
- }, {
271
- key: "_readChromTree",
272
- value: function () {
273
- var _readChromTree2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5(header, opts) {
274
- var _this2 = this;
275
-
276
- var isBE, le, refsByNumber, refsByName, chromTreeOffset, unzoomedDataOffset, _yield$this$bbi$read2, data, p, keySize, leafNodeParser, nonleafNodeParser, rootNodeOffset, bptReadNode;
277
-
278
- return _regenerator.default.wrap(function _callee5$(_context5) {
279
- while (1) {
280
- switch (_context5.prev = _context5.next) {
281
- case 0:
282
- isBE = header.isBigEndian;
283
- le = isBE ? 'big' : 'little';
284
- refsByNumber = [];
285
- refsByName = {};
286
- chromTreeOffset = header.chromTreeOffset;
287
- unzoomedDataOffset = header.unzoomedDataOffset;
288
-
289
- while (unzoomedDataOffset % 4 !== 0) {
290
- unzoomedDataOffset += 1;
173
+ });
174
+ });
175
+ };
176
+ BBI.prototype._getMainHeader = function (opts, requestSize) {
177
+ if (requestSize === void 0) { requestSize = 2000; }
178
+ return __awaiter(this, void 0, void 0, function () {
179
+ var buffer, isBigEndian, ret, header, tail;
180
+ return __generator(this, function (_a) {
181
+ switch (_a.label) {
182
+ case 0: return [4 /*yield*/, this.bbi.read(Buffer.alloc(requestSize), 0, requestSize, 0, opts)];
183
+ case 1:
184
+ buffer = (_a.sent()).buffer;
185
+ isBigEndian = this._isBigEndian(buffer);
186
+ ret = getParsers(isBigEndian);
187
+ header = ret.headerParser.parse(buffer).result;
188
+ header.fileType = header.magic === BIG_BED_MAGIC ? 'bigbed' : 'bigwig';
189
+ if (header.asOffset > requestSize ||
190
+ header.totalSummaryOffset > requestSize) {
191
+ return [2 /*return*/, this._getMainHeader(opts, requestSize * 2)];
192
+ }
193
+ if (header.asOffset) {
194
+ header.autoSql = buffer
195
+ .slice(header.asOffset, buffer.indexOf(0, header.asOffset))
196
+ .toString('utf8');
197
+ }
198
+ if (header.totalSummaryOffset > requestSize) {
199
+ return [2 /*return*/, this._getMainHeader(opts, requestSize * 2)];
200
+ }
201
+ if (header.totalSummaryOffset) {
202
+ tail = buffer.slice(header.totalSummaryOffset);
203
+ header.totalSummary = ret.totalSummaryParser.parse(tail).result;
204
+ }
205
+ return [2 /*return*/, __assign(__assign({}, header), { isBigEndian: isBigEndian })];
291
206
  }
292
-
293
- _context5.next = 9;
294
- return this.bbi.read(Buffer.alloc(unzoomedDataOffset - chromTreeOffset), 0, unzoomedDataOffset - chromTreeOffset, chromTreeOffset, opts);
295
-
296
- case 9:
297
- _yield$this$bbi$read2 = _context5.sent;
298
- data = _yield$this$bbi$read2.buffer;
299
- p = getParsers(isBE);
300
- keySize = p.chromTreeParser.parse(data).result.keySize;
301
- leafNodeParser = new _binaryParser.Parser().endianess(le).string('key', {
302
- stripNull: true,
303
- length: keySize
304
- }).uint32('refId').uint32('refSize');
305
- nonleafNodeParser = new _binaryParser.Parser().endianess(le).skip(keySize).uint64('childOffset');
306
- rootNodeOffset = 32;
307
-
308
- bptReadNode = /*#__PURE__*/function () {
309
- var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(currentOffset) {
310
- var offset, ret, _ret$result, isLeafNode, cnt, n, leafRet, _leafRet$result, _key, refId, refSize, refRec, nextNodes, _n, nonleafRet, childOffset;
311
-
312
- return _regenerator.default.wrap(function _callee4$(_context4) {
313
- while (1) {
314
- switch (_context4.prev = _context4.next) {
315
- case 0:
316
- offset = currentOffset;
317
-
318
- if (!(offset >= data.length)) {
319
- _context4.next = 3;
320
- break;
321
- }
322
-
323
- throw new Error('reading beyond end of buffer');
324
-
325
- case 3:
326
- ret = p.isLeafNode.parse(data.slice(offset));
327
- _ret$result = ret.result, isLeafNode = _ret$result.isLeafNode, cnt = _ret$result.cnt;
328
- offset += ret.offset;
329
-
330
- if (!isLeafNode) {
331
- _context4.next = 10;
332
- break;
333
- }
334
-
335
- for (n = 0; n < cnt; n += 1) {
336
- leafRet = leafNodeParser.parse(data.slice(offset));
337
- offset += leafRet.offset;
338
- _leafRet$result = leafRet.result, _key = _leafRet$result.key, refId = _leafRet$result.refId, refSize = _leafRet$result.refSize;
339
- refRec = {
340
- name: _key,
341
- id: refId,
342
- length: refSize
343
- };
344
- refsByName[_this2.renameRefSeqs(_key)] = refId;
345
- refsByNumber[refId] = refRec;
346
- }
347
-
348
- _context4.next = 14;
349
- break;
350
-
351
- case 10:
352
- // parse index node
353
- nextNodes = [];
354
-
355
- for (_n = 0; _n < cnt; _n += 1) {
356
- nonleafRet = nonleafNodeParser.parse(data.slice(offset));
357
- childOffset = nonleafRet.result.childOffset;
358
- offset += nonleafRet.offset;
359
- childOffset -= chromTreeOffset;
360
- nextNodes.push(bptReadNode(childOffset));
361
- }
362
-
363
- _context4.next = 14;
364
- return Promise.all(nextNodes);
365
-
366
- case 14:
367
- case "end":
368
- return _context4.stop();
207
+ });
208
+ });
209
+ };
210
+ BBI.prototype._isBigEndian = function (buffer) {
211
+ var ret = buffer.readInt32LE(0);
212
+ if (ret === BIG_WIG_MAGIC || ret === BIG_BED_MAGIC) {
213
+ return false;
214
+ }
215
+ ret = buffer.readInt32BE(0);
216
+ if (ret === BIG_WIG_MAGIC || ret === BIG_BED_MAGIC) {
217
+ return true;
218
+ }
219
+ throw new Error('not a BigWig/BigBed file');
220
+ };
221
+ // todo: add progress if long running
222
+ BBI.prototype._readChromTree = function (header, opts) {
223
+ return __awaiter(this, void 0, void 0, function () {
224
+ var isBE, le, refsByNumber, refsByName, chromTreeOffset, unzoomedDataOffset, data, p, keySize, leafNodeParser, nonleafNodeParser, rootNodeOffset, bptReadNode;
225
+ var _this = this;
226
+ return __generator(this, function (_a) {
227
+ switch (_a.label) {
228
+ case 0:
229
+ isBE = header.isBigEndian;
230
+ le = isBE ? 'big' : 'little';
231
+ refsByNumber = [];
232
+ refsByName = {};
233
+ chromTreeOffset = header.chromTreeOffset;
234
+ unzoomedDataOffset = header.unzoomedDataOffset;
235
+ while (unzoomedDataOffset % 4 !== 0) {
236
+ unzoomedDataOffset += 1;
369
237
  }
370
- }
371
- }, _callee4);
372
- }));
373
-
374
- return function bptReadNode(_x7) {
375
- return _ref.apply(this, arguments);
376
- };
377
- }();
378
-
379
- _context5.next = 19;
380
- return bptReadNode(rootNodeOffset);
381
-
382
- case 19:
383
- return _context5.abrupt("return", {
384
- refsByName: refsByName,
385
- refsByNumber: refsByNumber
386
- });
387
-
388
- case 20:
389
- case "end":
390
- return _context5.stop();
391
- }
392
- }
393
- }, _callee5, this);
394
- }));
395
-
396
- function _readChromTree(_x5, _x6) {
397
- return _readChromTree2.apply(this, arguments);
398
- }
399
-
400
- return _readChromTree;
401
- }()
238
+ return [4 /*yield*/, this.bbi.read(Buffer.alloc(unzoomedDataOffset - chromTreeOffset), 0, unzoomedDataOffset - chromTreeOffset, chromTreeOffset, opts)];
239
+ case 1:
240
+ data = (_a.sent()).buffer;
241
+ p = getParsers(isBE);
242
+ keySize = p.chromTreeParser.parse(data).result.keySize;
243
+ leafNodeParser = new binary_parser_1.Parser()
244
+ .endianess(le)
245
+ .string('key', { stripNull: true, length: keySize })
246
+ .uint32('refId')
247
+ .uint32('refSize');
248
+ nonleafNodeParser = new binary_parser_1.Parser()
249
+ .endianess(le)
250
+ .skip(keySize)
251
+ .uint64('childOffset');
252
+ rootNodeOffset = 32;
253
+ bptReadNode = function (currentOffset) { return __awaiter(_this, void 0, void 0, function () {
254
+ var offset, ret, _a, isLeafNode, cnt, n, leafRet, _b, key, refId, refSize, refRec, nextNodes, n, nonleafRet, childOffset;
255
+ return __generator(this, function (_c) {
256
+ switch (_c.label) {
257
+ case 0:
258
+ offset = currentOffset;
259
+ if (offset >= data.length) {
260
+ throw new Error('reading beyond end of buffer');
261
+ }
262
+ ret = p.isLeafNode.parse(data.slice(offset));
263
+ _a = ret.result, isLeafNode = _a.isLeafNode, cnt = _a.cnt;
264
+ offset += ret.offset;
265
+ if (!isLeafNode) return [3 /*break*/, 1];
266
+ for (n = 0; n < cnt; n += 1) {
267
+ leafRet = leafNodeParser.parse(data.slice(offset));
268
+ offset += leafRet.offset;
269
+ _b = leafRet.result, key = _b.key, refId = _b.refId, refSize = _b.refSize;
270
+ refRec = { name: key, id: refId, length: refSize };
271
+ refsByName[this.renameRefSeqs(key)] = refId;
272
+ refsByNumber[refId] = refRec;
273
+ }
274
+ return [3 /*break*/, 3];
275
+ case 1:
276
+ nextNodes = [];
277
+ for (n = 0; n < cnt; n += 1) {
278
+ nonleafRet = nonleafNodeParser.parse(data.slice(offset));
279
+ childOffset = nonleafRet.result.childOffset;
280
+ offset += nonleafRet.offset;
281
+ childOffset -= chromTreeOffset;
282
+ nextNodes.push(bptReadNode(childOffset));
283
+ }
284
+ return [4 /*yield*/, Promise.all(nextNodes)];
285
+ case 2:
286
+ _c.sent();
287
+ _c.label = 3;
288
+ case 3: return [2 /*return*/];
289
+ }
290
+ });
291
+ }); };
292
+ return [4 /*yield*/, bptReadNode(rootNodeOffset)];
293
+ case 2:
294
+ _a.sent();
295
+ return [2 /*return*/, {
296
+ refsByName: refsByName,
297
+ refsByNumber: refsByNumber,
298
+ }];
299
+ }
300
+ });
301
+ });
302
+ };
402
303
  /*
403
304
  * fetches the "unzoomed" view of the bigwig data. this is the default for bigbed
404
305
  * @param abortSignal - a signal to optionally abort this operation
405
306
  */
406
-
407
- }, {
408
- key: "getUnzoomedView",
409
- value: function () {
410
- var _getUnzoomedView = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee6(opts) {
411
- var _yield$this$getHeader, unzoomedIndexOffset, zoomLevels, refsByName, uncompressBufSize, isBigEndian, fileType, nzl, cirLen;
412
-
413
- return _regenerator.default.wrap(function _callee6$(_context6) {
414
- while (1) {
415
- switch (_context6.prev = _context6.next) {
416
- case 0:
417
- _context6.next = 2;
418
- return this.getHeader(opts);
419
-
420
- case 2:
421
- _yield$this$getHeader = _context6.sent;
422
- unzoomedIndexOffset = _yield$this$getHeader.unzoomedIndexOffset;
423
- zoomLevels = _yield$this$getHeader.zoomLevels;
424
- refsByName = _yield$this$getHeader.refsByName;
425
- uncompressBufSize = _yield$this$getHeader.uncompressBufSize;
426
- isBigEndian = _yield$this$getHeader.isBigEndian;
427
- fileType = _yield$this$getHeader.fileType;
428
- nzl = zoomLevels[0];
429
- cirLen = nzl ? nzl.dataOffset - unzoomedIndexOffset : 4000;
430
- return _context6.abrupt("return", new _blockView.BlockView(this.bbi, refsByName, unzoomedIndexOffset, cirLen, isBigEndian, uncompressBufSize > 0, fileType));
431
-
432
- case 12:
433
- case "end":
434
- return _context6.stop();
435
- }
436
- }
437
- }, _callee6, this);
438
- }));
439
-
440
- function getUnzoomedView(_x8) {
441
- return _getUnzoomedView.apply(this, arguments);
442
- }
443
-
444
- return getUnzoomedView;
445
- }()
446
- /*
447
- * abstract method - get the view for a given scale
448
- */
449
-
450
- }, {
451
- key: "getFeatureStream",
452
-
307
+ BBI.prototype.getUnzoomedView = function (opts) {
308
+ return __awaiter(this, void 0, void 0, function () {
309
+ var _a, unzoomedIndexOffset, zoomLevels, refsByName, uncompressBufSize, isBigEndian, fileType, nzl, cirLen;
310
+ return __generator(this, function (_b) {
311
+ switch (_b.label) {
312
+ case 0: return [4 /*yield*/, this.getHeader(opts)];
313
+ case 1:
314
+ _a = _b.sent(), unzoomedIndexOffset = _a.unzoomedIndexOffset, zoomLevels = _a.zoomLevels, refsByName = _a.refsByName, uncompressBufSize = _a.uncompressBufSize, isBigEndian = _a.isBigEndian, fileType = _a.fileType;
315
+ nzl = zoomLevels[0];
316
+ cirLen = nzl ? nzl.dataOffset - unzoomedIndexOffset : 4000;
317
+ return [2 /*return*/, new blockView_1.BlockView(this.bbi, refsByName, unzoomedIndexOffset, cirLen, isBigEndian, uncompressBufSize > 0, fileType)];
318
+ }
319
+ });
320
+ });
321
+ };
453
322
  /**
454
323
  * Gets features from a BigWig file
455
324
  *
@@ -458,132 +327,65 @@ var BBI = /*#__PURE__*/function () {
458
327
  * @param end - The end of a region
459
328
  * @param opts - An object containing basesPerSpan (e.g. pixels per basepair) or scale used to infer the zoomLevel to use
460
329
  */
461
- value: function () {
462
- var _getFeatureStream = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee7(refName, start, end) {
463
- var opts,
464
- chrName,
465
- view,
466
- _args7 = arguments;
467
- return _regenerator.default.wrap(function _callee7$(_context7) {
468
- while (1) {
469
- switch (_context7.prev = _context7.next) {
470
- case 0:
471
- opts = _args7.length > 3 && _args7[3] !== undefined ? _args7[3] : {
472
- scale: 1
473
- };
474
- _context7.next = 3;
475
- return this.getHeader(opts);
476
-
477
- case 3:
478
- chrName = this.renameRefSeqs(refName);
479
-
480
- if (!opts.basesPerSpan) {
481
- _context7.next = 10;
482
- break;
483
- }
484
-
485
- _context7.next = 7;
486
- return this.getView(1 / opts.basesPerSpan, opts);
487
-
488
- case 7:
489
- view = _context7.sent;
490
- _context7.next = 19;
491
- break;
492
-
493
- case 10:
494
- if (!opts.scale) {
495
- _context7.next = 16;
496
- break;
330
+ BBI.prototype.getFeatureStream = function (refName, start, end, opts) {
331
+ if (opts === void 0) { opts = {
332
+ scale: 1,
333
+ }; }
334
+ return __awaiter(this, void 0, void 0, function () {
335
+ var chrName, view;
336
+ return __generator(this, function (_a) {
337
+ switch (_a.label) {
338
+ case 0: return [4 /*yield*/, this.getHeader(opts)];
339
+ case 1:
340
+ _a.sent();
341
+ chrName = this.renameRefSeqs(refName);
342
+ if (!opts.basesPerSpan) return [3 /*break*/, 3];
343
+ return [4 /*yield*/, this.getView(1 / opts.basesPerSpan, opts)];
344
+ case 2:
345
+ view = _a.sent();
346
+ return [3 /*break*/, 7];
347
+ case 3:
348
+ if (!opts.scale) return [3 /*break*/, 5];
349
+ return [4 /*yield*/, this.getView(opts.scale, opts)];
350
+ case 4:
351
+ view = _a.sent();
352
+ return [3 /*break*/, 7];
353
+ case 5: return [4 /*yield*/, this.getView(1, opts)];
354
+ case 6:
355
+ view = _a.sent();
356
+ _a.label = 7;
357
+ case 7:
358
+ if (!view) {
359
+ throw new Error('unable to get block view for data');
360
+ }
361
+ return [2 /*return*/, new rxjs_1.Observable(function (observer) {
362
+ view.readWigData(chrName, start, end, observer, opts);
363
+ })];
497
364
  }
498
-
499
- _context7.next = 13;
500
- return this.getView(opts.scale, opts);
501
-
502
- case 13:
503
- view = _context7.sent;
504
- _context7.next = 19;
505
- break;
506
-
507
- case 16:
508
- _context7.next = 18;
509
- return this.getView(1, opts);
510
-
511
- case 18:
512
- view = _context7.sent;
513
-
514
- case 19:
515
- if (view) {
516
- _context7.next = 21;
517
- break;
365
+ });
366
+ });
367
+ };
368
+ BBI.prototype.getFeatures = function (refName, start, end, opts) {
369
+ if (opts === void 0) { opts = {
370
+ scale: 1,
371
+ }; }
372
+ return __awaiter(this, void 0, void 0, function () {
373
+ var ob, ret;
374
+ return __generator(this, function (_a) {
375
+ switch (_a.label) {
376
+ case 0: return [4 /*yield*/, this.getFeatureStream(refName, start, end, opts)];
377
+ case 1:
378
+ ob = _a.sent();
379
+ return [4 /*yield*/, ob
380
+ .pipe((0, operators_1.reduce)(function (acc, curr) { return acc.concat(curr); }))
381
+ .toPromise()];
382
+ case 2:
383
+ ret = _a.sent();
384
+ return [2 /*return*/, ret || []];
518
385
  }
519
-
520
- throw new Error('unable to get block view for data');
521
-
522
- case 21:
523
- return _context7.abrupt("return", new _rxjs.Observable(function (observer) {
524
- view.readWigData(chrName, start, end, observer, opts);
525
- }));
526
-
527
- case 22:
528
- case "end":
529
- return _context7.stop();
530
- }
531
- }
532
- }, _callee7, this);
533
- }));
534
-
535
- function getFeatureStream(_x9, _x10, _x11) {
536
- return _getFeatureStream.apply(this, arguments);
537
- }
538
-
539
- return getFeatureStream;
540
- }()
541
- }, {
542
- key: "getFeatures",
543
- value: function () {
544
- var _getFeatures = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee8(refName, start, end) {
545
- var opts,
546
- ob,
547
- ret,
548
- _args8 = arguments;
549
- return _regenerator.default.wrap(function _callee8$(_context8) {
550
- while (1) {
551
- switch (_context8.prev = _context8.next) {
552
- case 0:
553
- opts = _args8.length > 3 && _args8[3] !== undefined ? _args8[3] : {
554
- scale: 1
555
- };
556
- _context8.next = 3;
557
- return this.getFeatureStream(refName, start, end, opts);
558
-
559
- case 3:
560
- ob = _context8.sent;
561
- _context8.next = 6;
562
- return ob.pipe((0, _operators.reduce)(function (acc, curr) {
563
- return acc.concat(curr);
564
- })).toPromise();
565
-
566
- case 6:
567
- ret = _context8.sent;
568
- return _context8.abrupt("return", ret || []);
569
-
570
- case 8:
571
- case "end":
572
- return _context8.stop();
573
- }
574
- }
575
- }, _callee8, this);
576
- }));
577
-
578
- function getFeatures(_x12, _x13, _x14) {
579
- return _getFeatures.apply(this, arguments);
580
- }
581
-
582
- return getFeatures;
583
- }()
584
- }]);
585
- return BBI;
586
- }();
587
-
386
+ });
387
+ });
388
+ };
389
+ return BBI;
390
+ }());
588
391
  exports.BBI = BBI;
589
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9iYmkudHMiXSwibmFtZXMiOlsiQklHX1dJR19NQUdJQyIsIkJJR19CRURfTUFHSUMiLCJnZXRQYXJzZXJzIiwiaXNCRSIsImxlIiwiaGVhZGVyUGFyc2VyIiwiUGFyc2VyIiwiZW5kaWFuZXNzIiwiaW50MzIiLCJ1aW50MTYiLCJ1aW50NjQiLCJ1aW50MzIiLCJhcnJheSIsImxlbmd0aCIsInR5cGUiLCJ0b3RhbFN1bW1hcnlQYXJzZXIiLCJkb3VibGUiLCJjaHJvbVRyZWVQYXJzZXIiLCJpc0xlYWZOb2RlIiwidWludDgiLCJza2lwIiwiQkJJIiwib3B0cyIsIm9wdGlvbnMiLCJzaWduYWwiLCJoZWFkZXJDYWNoZSIsImdldCIsIkpTT04iLCJzdHJpbmdpZnkiLCJBYm9ydGFibGVQcm9taXNlQ2FjaGUiLCJjYWNoZSIsIlF1aWNrTFJVIiwibWF4U2l6ZSIsImZpbGwiLCJwYXJhbXMiLCJfZ2V0SGVhZGVyIiwiZmlsZWhhbmRsZSIsInJlbmFtZVJlZlNlcXMiLCJwYXRoIiwidXJsIiwicyIsImJiaSIsIlJlbW90ZUZpbGUiLCJMb2NhbEZpbGUiLCJFcnJvciIsIl9nZXRNYWluSGVhZGVyIiwiaGVhZGVyIiwiX3JlYWRDaHJvbVRyZWUiLCJjaHJvbXMiLCJyZXF1ZXN0U2l6ZSIsInJlYWQiLCJCdWZmZXIiLCJhbGxvYyIsImJ1ZmZlciIsImlzQmlnRW5kaWFuIiwiX2lzQmlnRW5kaWFuIiwicmV0IiwicGFyc2UiLCJyZXN1bHQiLCJmaWxlVHlwZSIsIm1hZ2ljIiwiYXNPZmZzZXQiLCJ0b3RhbFN1bW1hcnlPZmZzZXQiLCJhdXRvU3FsIiwic2xpY2UiLCJpbmRleE9mIiwidG9TdHJpbmciLCJ0YWlsIiwidG90YWxTdW1tYXJ5IiwicmVhZEludDMyTEUiLCJyZWFkSW50MzJCRSIsInJlZnNCeU51bWJlciIsInJlZnNCeU5hbWUiLCJjaHJvbVRyZWVPZmZzZXQiLCJ1bnpvb21lZERhdGFPZmZzZXQiLCJkYXRhIiwicCIsImtleVNpemUiLCJsZWFmTm9kZVBhcnNlciIsInN0cmluZyIsInN0cmlwTnVsbCIsIm5vbmxlYWZOb2RlUGFyc2VyIiwicm9vdE5vZGVPZmZzZXQiLCJicHRSZWFkTm9kZSIsImN1cnJlbnRPZmZzZXQiLCJvZmZzZXQiLCJjbnQiLCJuIiwibGVhZlJldCIsImtleSIsInJlZklkIiwicmVmU2l6ZSIsInJlZlJlYyIsIm5hbWUiLCJpZCIsIm5leHROb2RlcyIsIm5vbmxlYWZSZXQiLCJjaGlsZE9mZnNldCIsInB1c2giLCJQcm9taXNlIiwiYWxsIiwiZ2V0SGVhZGVyIiwidW56b29tZWRJbmRleE9mZnNldCIsInpvb21MZXZlbHMiLCJ1bmNvbXByZXNzQnVmU2l6ZSIsIm56bCIsImNpckxlbiIsImRhdGFPZmZzZXQiLCJCbG9ja1ZpZXciLCJyZWZOYW1lIiwic3RhcnQiLCJlbmQiLCJzY2FsZSIsImNock5hbWUiLCJiYXNlc1BlclNwYW4iLCJnZXRWaWV3IiwidmlldyIsIk9ic2VydmFibGUiLCJvYnNlcnZlciIsInJlYWRXaWdEYXRhIiwiZ2V0RmVhdHVyZVN0cmVhbSIsIm9iIiwicGlwZSIsImFjYyIsImN1cnIiLCJjb25jYXQiLCJ0b1Byb21pc2UiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7Ozs7O0FBRUEsSUFBTUEsYUFBYSxHQUFHLENBQUMsVUFBdkI7QUFDQSxJQUFNQyxhQUFhLEdBQUcsQ0FBQyxVQUF2Qjs7QUF5Q0E7Ozs7O0FBS0EsU0FBU0MsVUFBVCxDQUFvQkMsSUFBcEIsRUFBd0M7QUFDdEMsTUFBTUMsRUFBRSxHQUFHRCxJQUFJLEdBQUcsS0FBSCxHQUFXLFFBQTFCO0FBQ0EsTUFBTUUsWUFBWSxHQUFHLElBQUlDLG9CQUFKLEdBQ2xCQyxTQURrQixDQUNSSCxFQURRLEVBRWxCSSxLQUZrQixDQUVaLE9BRlksRUFHbEJDLE1BSGtCLENBR1gsU0FIVyxFQUlsQkEsTUFKa0IsQ0FJWCxlQUpXLEVBS2xCQyxNQUxrQixDQUtY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WyJpbXBvcnQgeyBQYXJzZXIgfSBmcm9tICdAZ21vZC9iaW5hcnktcGFyc2VyJ1xuaW1wb3J0IHsgTG9jYWxGaWxlLCBSZW1vdGVGaWxlLCBHZW5lcmljRmlsZWhhbmRsZSB9IGZyb20gJ2dlbmVyaWMtZmlsZWhhbmRsZSdcbmltcG9ydCB7IE9ic2VydmFibGUsIE9ic2VydmVyIH0gZnJvbSAncnhqcydcbmltcG9ydCB7IHJlZHVjZSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJ1xuaW1wb3J0IEFib3J0YWJsZVByb21pc2VDYWNoZSBmcm9tICdhYm9ydGFibGUtcHJvbWlzZS1jYWNoZSdcbmltcG9ydCBRdWlja0xSVSBmcm9tICdxdWljay1scnUnXG5pbXBvcnQgeyBCbG9ja1ZpZXcgfSBmcm9tICcuL2Jsb2NrVmlldydcblxuY29uc3QgQklHX1dJR19NQUdJQyA9IC0yMDAzODI5NzIyXG5jb25zdCBCSUdfQkVEX01BR0lDID0gLTIwMjEwMDI1MTdcblxuZXhwb3J0IGludGVyZmFjZSBGZWF0dXJlIHtcbiAgc3RhcnQ6IG51bWJlclxuICBlbmQ6IG51bWJlclxuICBzY29yZTogbnVtYmVyXG4gIHJlc3Q/OiBzdHJpbmcgLy8gZm9yIGJpZ2JlZCBsaW5lXG4gIG1pblNjb3JlPzogbnVtYmVyIC8vIGZvciBzdW1tYXJ5IGxpbmVcbiAgbWF4U2NvcmU/OiBudW1iZXIgLy8gZm9yIHN1bW1hcnkgbGluZVxuICBzdW1tYXJ5PzogYm9vbGVhbiAvLyBpcyBzdW1tYXJ5IGxpbmVcbiAgdW5pcXVlSWQ/OiBzdHJpbmcgLy8gZm9yIGJpZ2JlZCBjb250YWlucyB1bmlxdWVJZCBjYWxjdWxhdGVkIGZyb20gZmlsZSBvZmZzZXRcbiAgZmllbGQ/OiBudW1iZXIgLy8gdXNlZCBpbiBiaWdiZWQgc2VhcmNoaW5nXG59XG5pbnRlcmZhY2UgU3RhdGlzdGljcyB7XG4gIHNjb3JlU3VtOiBudW1iZXJcbiAgYmFzZXNDb3ZlcmVkOiBudW1iZXJcbiAgc2NvcmVTdW1TcXVhcmVzOiBudW1iZXJcbn1cblxuaW50ZXJmYWNlIFJlZkluZm8ge1xuICBuYW1lOiBzdHJpbmdcbiAgaWQ6IG51bWJlclxuICBsZW5ndGg6IG51bWJlclxufVxuZXhwb3J0IGludGVyZmFjZSBIZWFkZXIge1xuICBhdXRvU3FsOiBzdHJpbmdcbiAgdG90YWxTdW1tYXJ5OiBTdGF0aXN0aWNzXG4gIHpvb21MZXZlbHM6IGFueVxuICB1bnpvb21lZEluZGV4T2Zmc2V0OiBudW1iZXJcbiAgdW56b29tZWREYXRhT2Zmc2V0OiBudW1iZXJcbiAgZGVmaW5lZEZpZWxkQ291bnQ6IG51bWJlclxuICB1bmNvbXByZXNzQnVmU2l6ZTogbnVtYmVyXG4gIGNocm9tVHJlZU9mZnNldDogbnVtYmVyXG4gIGZpbGVTaXplOiBudW1iZXJcbiAgZXh0SGVhZGVyT2Zmc2V0OiBudW1iZXJcbiAgaXNCaWdFbmRpYW46IGJvb2xlYW5cbiAgZmlsZVR5cGU6IHN0cmluZ1xuICByZWZzQnlOYW1lOiB7IFtrZXk6IHN0cmluZ106IG51bWJlciB9XG4gIHJlZnNCeU51bWJlcjogeyBba2V5OiBudW1iZXJdOiBSZWZJbmZvIH1cbn1cblxuLyogZ2V0IHRoZSBjb21waWxlZCBwYXJzZXJzIGZvciBkaWZmZXJlbnQgc2VjdGlvbnMgb2YgdGhlIGJpZ3dpZyBmaWxlXG4gKlxuICogQHBhcmFtIGlzQkUgLSBpcyBiaWcgZW5kaWFuLCB0eXBpY2FsbHkgZmFsc2VcbiAqIEByZXR1cm4gYW4gb2JqZWN0IHdpdGggY29tcGlsZWQgcGFyc2Vyc1xuICovXG5mdW5jdGlvbiBnZXRQYXJzZXJzKGlzQkU6IGJvb2xlYW4pOiBhbnkge1xuICBjb25zdCBsZSA9IGlzQkUgPyAnYmlnJyA6ICdsaXR0bGUnXG4gIGNvbnN0IGhlYWRlclBhcnNlciA9IG5ldyBQYXJzZXIoKVxuICAgIC5lbmRpYW5lc3MobGUpXG4gICAgLmludDMyKCdtYWdpYycpXG4gICAgLnVpbnQxNigndmVyc2lvbicpXG4gICAgLnVpbnQxNignbnVtWm9vbUxldmVscycpXG4gICAgLnVpbnQ2NCgnY2hyb21UcmVlT2Zmc2V0JylcbiAgICAudWludDY0KCd1bnpvb21lZERhdGFPZmZzZXQnKVxuICAgIC51aW50NjQoJ3Vuem9vbWVkSW5kZXhPZmZzZXQnKVxuICAgIC51aW50MTYoJ2ZpZWxkQ291bnQnKVxuICAgIC51aW50MTYoJ2RlZmluZWRGaWVsZENvdW50JylcbiAgICAudWludDY0KCdhc09mZnNldCcpIC8vIGF1dG9TcWwgb2Zmc2V0LCB1c2VkIGluIGJpZ2JlZFxuICAgIC51aW50NjQoJ3RvdGFsU3VtbWFyeU9mZnNldCcpXG4gICAgLnVpbnQzMigndW5jb21wcmVzc0J1ZlNpemUnKVxuICAgIC51aW50NjQoJ2V4dEhlYWRlck9mZnNldCcpIC8vIG5hbWUgaW5kZXggb2Zmc2V0LCB1c2VkIGluIGJpZ2JlZFxuICAgIC5hcnJheSgnem9vbUxldmVscycsIHtcbiAgICAgIGxlbmd0aDogJ251bVpvb21MZXZlbHMnLFxuICAgICAgdHlwZTogbmV3IFBhcnNlcigpXG4gICAgICAgIC51aW50MzIoJ3JlZHVjdGlvbkxldmVsJylcbiAgICAgICAgLnVpbnQzMigncmVzZXJ2ZWQnKVxuICAgICAgICAudWludDY0KCdkYXRhT2Zmc2V0JylcbiAgICAgICAgLnVpbnQ2NCgnaW5kZXhPZmZzZXQnKSxcbiAgICB9KVxuXG4gIGNvbnN0IHRvdGFsU3VtbWFyeVBhcnNlciA9IG5ldyBQYXJzZXIoKVxuICAgIC5lbmRpYW5lc3MobGUpXG4gICAgLnVpbnQ2NCgnYmFzZXNDb3ZlcmVkJylcbiAgICAuZG91YmxlKCdzY29yZU1pbicpXG4gICAgLmRvdWJsZSgnc2NvcmVNYXgnKVxuICAgIC5kb3VibGUoJ3Njb3JlU3VtJylcbiAgICAuZG91YmxlKCdzY29yZVN1bVNxdWFyZXMnKVxuXG4gIGNvbnN0IGNocm9tVHJlZVBhcnNlciA9IG5ldyBQYXJzZXIoKVxuICAgIC5lbmRpYW5lc3MobGUpXG4gICAgLnVpbnQzMignbWFnaWMnKVxuICAgIC51aW50MzIoJ2Jsb2NrU2l6ZScpXG4gICAgLnVpbnQzMigna2V5U2l6ZScpXG4gICAgLnVpbnQzMigndmFsU2l6ZScpXG4gICAgLnVpbnQ2NCgnaXRlbUNvdW50JylcblxuICBjb25zdCBpc0xlYWZOb2RlID0gbmV3IFBhcnNlcigpXG4gICAgLmVuZGlhbmVzcyhsZSlcbiAgICAudWludDgoJ2lzTGVhZk5vZGUnKVxuICAgIC5za2lwKDEpXG4gICAgLnVpbnQxNignY250JylcblxuICByZXR1cm4ge1xuICAgIGNocm9tVHJlZVBhcnNlcixcbiAgICB0b3RhbFN1bW1hcnlQYXJzZXIsXG4gICAgaGVhZGVyUGFyc2VyLFxuICAgIGlzTGVhZk5vZGUsXG4gIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXF1ZXN0T3B0aW9ucyB7XG4gIHNpZ25hbD86IEFib3J0U2lnbmFsXG4gIGhlYWRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+XG4gIFtrZXk6IHN0cmluZ106IHVua25vd25cbn1cblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEJCSSB7XG4gIHByb3RlY3RlZCBiYmk6IEdlbmVyaWNGaWxlaGFuZGxlXG5cbiAgcHJvdGVjdGVkIGhlYWRlckNhY2hlID0gbmV3IEFib3J0YWJsZVByb21pc2VDYWNoZSh7XG4gICAgY2FjaGU6IG5ldyBRdWlja0xSVSh7IG1heFNpemU6IDEgfSksXG4gICAgZmlsbDogYXN5bmMgKHBhcmFtczogYW55LCBzaWduYWw/OiBBYm9ydFNpZ25hbCkgPT4ge1xuICAgICAgcmV0dXJuIHRoaXMuX2dldEhlYWRlcih7IC4uLnBhcmFtcywgc2lnbmFsIH0pXG4gICAgfSxcbiAgfSlcblxuICBwcm90ZWN0ZWQgcmVuYW1lUmVmU2VxczogKGE6IHN0cmluZykgPT4gc3RyaW5nXG5cbiAgLyogZmV0Y2ggYW5kIHBhcnNlIGhlYWRlciBpbmZvcm1hdGlvbiBmcm9tIGEgYmlnd2lnIG9yIGJpZ2JlZCBmaWxlXG4gICAqIEBwYXJhbSBhYm9ydFNpZ25hbCAtIGFib3J0IHRoZSBvcGVyYXRpb24sIGNhbiBiZSBudWxsXG4gICAqIEByZXR1cm4gYSBIZWFkZXIgb2JqZWN0XG4gICAqL1xuICBwdWJsaWMgZ2V0SGVhZGVyKG9wdHM6IFJlcXVlc3RPcHRpb25zIHwgQWJvcnRTaWduYWwgPSB7fSkge1xuICAgIGNvbnN0IG9wdGlvbnMgPSAnYWJvcnRlZCcgaW4gb3B0cyA/IHsgc2lnbmFsOiBvcHRzIH0gOiBvcHRzXG4gICAgcmV0dXJuIHRoaXMuaGVhZGVyQ2FjaGUuZ2V0KEpTT04uc3RyaW5naWZ5KG9wdGlvbnMpLCBvcHRpb25zLCBvcHRpb25zLnNpZ25hbClcbiAgfVxuXG4gIC8qXG4gICAqIEBwYXJhbSBmaWxlaGFuZGxlIC0gYSBmaWxlaGFuZGxlIGZyb20gZ2VuZXJpYy1maWxlaGFuZGxlIG9yIGltcGxlbWVudGluZyBzb21ldGhpbmcgc2ltaWxhciB0byB0aGUgbm9kZTEwIGZzLnByb21pc2VzIEFQSVxuICAgKiBAcGFyYW0gcGF0aCAtIGEgTG9jYWwgZmlsZSBwYXRoIGFzIGEgc3RyaW5nXG4gICAqIEBwYXJhbSB1cmwgLSBhIFVSTCBzdHJpbmdcbiAgICogQHBhcmFtIHJlbmFtZVJlZlNlcXMgLSBhbiBvcHRpb25hbCBtZXRob2QgdG8gcmVuYW1lIHRoZSBpbnRlcm5hbCByZWZlcmVuY2Ugc2VxdWVuY2VzIHVzaW5nIGEgbWFwcGluZyBmdW5jdGlvblxuICAgKi9cbiAgcHVibGljIGNvbnN0cnVjdG9yKFxuICAgIG9wdGlvbnM6IHtcbiAgICAgIGZpbGVoYW5kbGU/OiBHZW5lcmljRmlsZWhhbmRsZVxuICAgICAgcGF0aD86IHN0cmluZ1xuICAgICAgdXJsPzogc3RyaW5nXG4gICAgICByZW5hbWVSZWZTZXFzPzogKGE6IHN0cmluZykgPT4gc3RyaW5nXG4gICAgfSA9IHt9LFxuICApIHtcbiAgICBjb25zdCB7IGZpbGVoYW5kbGUsIHJlbmFtZVJlZlNlcXMsIHBhdGgsIHVybCB9ID0gb3B0aW9uc1xuICAgIHRoaXMucmVuYW1lUmVmU2VxcyA9IHJlbmFtZVJlZlNlcXMgfHwgKChzOiBzdHJpbmcpOiBzdHJpbmcgPT4gcylcbiAgICBpZiAoZmlsZWhhbmRsZSkge1xuICAgICAgdGhpcy5iYmkgPSBmaWxlaGFuZGxlXG4gICAgfSBlbHNlIGlmICh1cmwpIHtcbiAgICAgIHRoaXMuYmJpID0gbmV3IFJlbW90ZUZpbGUodXJsKVxuICAgIH0gZWxzZSBpZiAocGF0aCkge1xuICAgICAgdGhpcy5iYmkgPSBuZXcgTG9jYWxGaWxlKHBhdGgpXG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbm8gZmlsZSBnaXZlbicpXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBfZ2V0SGVhZGVyKG9wdHM6IFJlcXVlc3RPcHRpb25zKSB7XG4gICAgY29uc3QgaGVhZGVyID0gYXdhaXQgdGhpcy5fZ2V0TWFpbkhlYWRlcihvcHRzKVxuICAgIGNvbnN0IGNocm9tcyA9IGF3YWl0IHRoaXMuX3JlYWRDaHJvbVRyZWUoaGVhZGVyLCBvcHRzKVxuICAgIHJldHVybiB7IC4uLmhlYWRlciwgLi4uY2hyb21zIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgX2dldE1haW5IZWFkZXIob3B0czogUmVxdWVzdE9wdGlvbnMsIHJlcXVlc3RTaXplID0gMjAwMCk6IFByb21pc2U8SGVhZGVyPiB7XG4gICAgY29uc3QgeyBidWZmZXIgfSA9IGF3YWl0IHRoaXMuYmJpLnJlYWQoQnVmZmVyLmFsbG9jKHJlcXVlc3RTaXplKSwgMCwgcmVxdWVzdFNpemUsIDAsIG9wdHMpXG4gICAgY29uc3QgaXNCaWdFbmRpYW4gPSB0aGlzLl9pc0JpZ0VuZGlhbihidWZmZXIpXG4gICAgY29uc3QgcmV0ID0gZ2V0UGFyc2Vycyhpc0JpZ0VuZGlhbilcbiAgICBjb25zdCBoZWFkZXIgPSByZXQuaGVhZGVyUGFyc2VyLnBhcnNlKGJ1ZmZlcikucmVzdWx0XG4gICAgaGVhZGVyLmZpbGVUeXBlID0gaGVhZGVyLm1hZ2ljID09PSBCSUdfQkVEX01BR0lDID8gJ2JpZ2JlZCcgOiAnYmlnd2lnJ1xuICAgIGlmIChoZWFkZXIuYXNPZmZzZXQgPiByZXF1ZXN0U2l6ZSB8fCBoZWFkZXIudG90YWxTdW1tYXJ5T2Zmc2V0ID4gcmVxdWVzdFNpemUpIHtcbiAgICAgIHJldHVybiB0aGlzLl9nZXRNYWluSGVhZGVyKG9wdHMsIHJlcXVlc3RTaXplICogMilcbiAgICB9XG4gICAgaWYgKGhlYWRlci5hc09mZnNldCkge1xuICAgICAgaGVhZGVyLmF1dG9TcWwgPSBidWZmZXJcbiAgICAgICAgLnNsaWNlKGhlYWRlci5hc09mZnNldCwgYnVmZmVyLmluZGV4T2YoMCwgaGVhZGVyLmFzT2Zmc2V0KSlcbiAgICAgICAgLnRvU3RyaW5nKCd1dGY4JylcbiAgICB9XG4gICAgaWYgKGhlYWRlci50b3RhbFN1bW1hcnlPZmZzZXQgPiByZXF1ZXN0U2l6ZSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2dldE1haW5IZWFkZXIob3B0cywgcmVxdWVzdFNpemUgKiAyKVxuICAgIH1cbiAgICBpZiAoaGVhZGVyLnRvdGFsU3VtbWFyeU9mZnNldCkge1xuICAgICAgY29uc3QgdGFpbCA9IGJ1ZmZlci5zbGljZShoZWFkZXIudG90YWxTdW1tYXJ5T2Zmc2V0KVxuICAgICAgaGVhZGVyLnRvdGFsU3VtbWFyeSA9IHJldC50b3RhbFN1bW1hcnlQYXJzZXIucGFyc2UodGFpbCkucmVzdWx0XG4gICAgfVxuICAgIHJldHVybiB7IC4uLmhlYWRlciwgaXNCaWdFbmRpYW4gfVxuICB9XG5cbiAgcHJpdmF0ZSBfaXNCaWdFbmRpYW4oYnVmZmVyOiBCdWZmZXIpOiBib29sZWFuIHtcbiAgICBsZXQgcmV0ID0gYnVmZmVyLnJlYWRJbnQzMkxFKDApXG4gICAgaWYgKHJldCA9PT0gQklHX1dJR19NQUdJQyB8fCByZXQgPT09IEJJR19CRURfTUFHSUMpIHtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cbiAgICByZXQgPSBidWZmZXIucmVhZEludDMyQkUoMClcbiAgICBpZiAocmV0ID09PSBCSUdfV0lHX01BR0lDIHx8IHJldCA9PT0gQklHX0JFRF9NQUdJQykge1xuICAgICAgcmV0dXJuIHRydWVcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKCdub3QgYSBCaWdXaWcvQmlnQmVkIGZpbGUnKVxuICB9XG5cbiAgLy8gdG9kbzogYWRkIHByb2dyZXNzIGlmIGxvbmcgcnVubmluZ1xuICBwcml2YXRlIGFzeW5jIF9yZWFkQ2hyb21UcmVlKGhlYWRlcjogSGVhZGVyLCBvcHRzOiB7IHNpZ25hbD86IEFib3J0U2lnbmFsIH0pIHtcbiAgICBjb25zdCBpc0JFID0gaGVhZGVyLmlzQmlnRW5kaWFuXG4gICAgY29uc3QgbGUgPSBpc0JFID8gJ2JpZycgOiAnbGl0dGxlJ1xuICAgIGNvbnN0IHJlZnNCeU51bWJlcjogeyBba2V5OiBudW1iZXJdOiB7IG5hbWU6IHN0cmluZzsgaWQ6IG51bWJlcjsgbGVuZ3RoOiBudW1iZXIgfSB9ID0gW11cbiAgICBjb25zdCByZWZzQnlOYW1lOiB7IFtrZXk6IHN0cmluZ106IG51bWJlciB9ID0ge31cbiAgICBjb25zdCB7IGNocm9tVHJlZU9mZnNldCB9ID0gaGVhZGVyXG4gICAgbGV0IHsgdW56b29tZWREYXRhT2Zmc2V0IH0gPSBoZWFkZXJcblxuICAgIHdoaWxlICh1bnpvb21lZERhdGFPZmZzZXQgJSA0ICE9PSAwKSB7XG4gICAgICB1bnpvb21lZERhdGFPZmZzZXQgKz0gMVxuICAgIH1cblxuICAgIGNvbnN0IHsgYnVmZmVyOiBkYXRhIH0gPSBhd2FpdCB0aGlzLmJiaS5yZWFkKFxuICAgICAgQnVmZmVyLmFsbG9jKHVuem9vbWVkRGF0YU9mZnNldCAtIGNocm9tVHJlZU9mZnNldCksXG4gICAgICAwLFxuICAgICAgdW56b29tZWREYXRhT2Zmc2V0IC0gY2hyb21UcmVlT2Zmc2V0LFxuICAgICAgY2hyb21UcmVlT2Zmc2V0LFxuICAgICAgb3B0cyxcbiAgICApXG5cbiAgICBjb25zdCBwID0gZ2V0UGFyc2Vycyhpc0JFKVxuICAgIGNvbnN0IHsga2V5U2l6ZSB9ID0gcC5jaHJvbVRyZWVQYXJzZXIucGFyc2UoZGF0YSkucmVzdWx0XG4gICAgY29uc3QgbGVhZk5vZGVQYXJzZXIgPSBuZXcgUGFyc2VyKClcbiAgICAgIC5lbmRpYW5lc3MobGUpXG4gICAgICAuc3RyaW5nKCdrZXknLCB7IHN0cmlwTnVsbDogdHJ1ZSwgbGVuZ3RoOiBrZXlTaXplIH0pXG4gICAgICAudWludDMyKCdyZWZJZCcpXG4gICAgICAudWludDMyKCdyZWZTaXplJylcbiAgICBjb25zdCBub25sZWFmTm9kZVBhcnNlciA9IG5ldyBQYXJzZXIoKVxuICAgICAgLmVuZGlhbmVzcyhsZSlcbiAgICAgIC5za2lwKGtleVNpemUpXG4gICAgICAudWludDY0KCdjaGlsZE9mZnNldCcpXG4gICAgY29uc3Qgcm9vdE5vZGVPZmZzZXQgPSAzMlxuICAgIGNvbnN0IGJwdFJlYWROb2RlID0gYXN5bmMgKGN1cnJlbnRPZmZzZXQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgbGV0IG9mZnNldCA9IGN1cnJlbnRPZmZzZXRcbiAgICAgIGlmIChvZmZzZXQgPj0gZGF0YS5sZW5ndGgpIHRocm93IG5ldyBFcnJvcigncmVhZGluZyBiZXlvbmQgZW5kIG9mIGJ1ZmZlcicpXG4gICAgICBjb25zdCByZXQgPSBwLmlzTGVhZk5vZGUucGFyc2UoZGF0YS5zbGljZShvZmZzZXQpKVxuICAgICAgY29uc3QgeyBpc0xlYWZOb2RlLCBjbnQgfSA9IHJldC5yZXN1bHRcbiAgICAgIG9mZnNldCArPSByZXQub2Zmc2V0XG4gICAgICBpZiAoaXNMZWFmTm9kZSkge1xuICAgICAgICBmb3IgKGxldCBuID0gMDsgbiA8IGNudDsgbiArPSAxKSB7XG4gICAgICAgICAgY29uc3QgbGVhZlJldCA9IGxlYWZOb2RlUGFyc2VyLnBhcnNlKGRhdGEuc2xpY2Uob2Zmc2V0KSlcbiAgICAgICAgICBvZmZzZXQgKz0gbGVhZlJldC5vZmZzZXRcbiAgICAgICAgICBjb25zdCB7IGtleSwgcmVmSWQsIHJlZlNpemUgfSA9IGxlYWZSZXQucmVzdWx0XG4gICAgICAgICAgY29uc3QgcmVmUmVjID0geyBuYW1lOiBrZXksIGlkOiByZWZJZCwgbGVuZ3RoOiByZWZTaXplIH1cbiAgICAgICAgICByZWZzQnlOYW1lW3RoaXMucmVuYW1lUmVmU2VxcyhrZXkpXSA9IHJlZklkXG4gICAgICAgICAgcmVmc0J5TnVtYmVyW3JlZklkXSA9IHJlZlJlY1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBwYXJzZSBpbmRleCBub2RlXG4gICAgICAgIGNvbnN0IG5leHROb2RlcyA9IFtdXG4gICAgICAgIGZvciAobGV0IG4gPSAwOyBuIDwgY250OyBuICs9IDEpIHtcbiAgICAgICAgICBjb25zdCBub25sZWFmUmV0ID0gbm9ubGVhZk5vZGVQYXJzZXIucGFyc2UoZGF0YS5zbGljZShvZmZzZXQpKVxuICAgICAgICAgIGxldCB7IGNoaWxkT2Zmc2V0IH0gPSBub25sZWFmUmV0LnJlc3VsdFxuICAgICAgICAgIG9mZnNldCArPSBub25sZWFmUmV0Lm9mZnNldFxuICAgICAgICAgIGNoaWxkT2Zmc2V0IC09IGNocm9tVHJlZU9mZnNldFxuICAgICAgICAgIG5leHROb2Rlcy5wdXNoKGJwdFJlYWROb2RlKGNoaWxkT2Zmc2V0KSlcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChuZXh0Tm9kZXMpXG4gICAgICB9XG4gICAgfVxuICAgIGF3YWl0IGJwdFJlYWROb2RlKHJvb3ROb2RlT2Zmc2V0KVxuICAgIHJldHVybiB7XG4gICAgICByZWZzQnlOYW1lLFxuICAgICAgcmVmc0J5TnVtYmVyLFxuICAgIH1cbiAgfVxuXG4gIC8qXG4gICAqIGZldGNoZXMgdGhlIFwidW56b29tZWRcIiB2aWV3IG9mIHRoZSBiaWd3aWcgZGF0YS4gdGhpcyBpcyB0aGUgZGVmYXVsdCBmb3IgYmlnYmVkXG4gICAqIEBwYXJhbSBhYm9ydFNpZ25hbCAtIGEgc2lnbmFsIHRvIG9wdGlvbmFsbHkgYWJvcnQgdGhpcyBvcGVyYXRpb25cbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBnZXRVbnpvb21lZFZpZXcob3B0czogUmVxdWVzdE9wdGlvbnMpOiBQcm9taXNlPEJsb2NrVmlldz4ge1xuICAgIGNvbnN0IHtcbiAgICAgIHVuem9vbWVkSW5kZXhPZmZzZXQsXG4gICAgICB6b29tTGV2ZWxzLFxuICAgICAgcmVmc0J5TmFtZSxcbiAgICAgIHVuY29tcHJlc3NCdWZTaXplLFxuICAgICAgaXNCaWdFbmRpYW4sXG4gICAgICBmaWxlVHlwZSxcbiAgICB9ID0gYXdhaXQgdGhpcy5nZXRIZWFkZXIob3B0cylcbiAgICBjb25zdCBuemwgPSB6b29tTGV2ZWxzWzBdXG4gICAgY29uc3QgY2lyTGVuID0gbnpsID8gbnpsLmRhdGFPZmZzZXQgLSB1bnpvb21lZEluZGV4T2Zmc2V0IDogNDAwMFxuICAgIHJldHVybiBuZXcgQmxvY2tWaWV3KFxuICAgICAgdGhpcy5iYmksXG4gICAgICByZWZzQnlOYW1lLFxuICAgICAgdW56b29tZWRJbmRleE9mZnNldCxcbiAgICAgIGNpckxlbixcbiAgICAgIGlzQmlnRW5kaWFuLFxuICAgICAgdW5jb21wcmVzc0J1ZlNpemUgPiAwLFxuICAgICAgZmlsZVR5cGUsXG4gICAgKVxuICB9XG5cbiAgLypcbiAgICogYWJzdHJhY3QgbWV0aG9kIC0gZ2V0IHRoZSB2aWV3IGZvciBhIGdpdmVuIHNjYWxlXG4gICAqL1xuICBwcm90ZWN0ZWQgYWJzdHJhY3QgYXN5bmMgZ2V0VmlldyhzY2FsZTogbnVtYmVyLCBvcHRzOiBSZXF1ZXN0T3B0aW9ucyk6IFByb21pc2U8QmxvY2tWaWV3PlxuXG4gIC8qKlxuICAgKiBHZXRzIGZlYXR1cmVzIGZyb20gYSBCaWdXaWcgZmlsZVxuICAgKlxuICAgKiBAcGFyYW0gcmVmTmFtZSAtIFRoZSBjaHJvbW9zb21lIG5hbWVcbiAgICogQHBhcmFtIHN0YXJ0IC0gVGhlIHN0YXJ0IG9mIGEgcmVnaW9uXG4gICAqIEBwYXJhbSBlbmQgLSBUaGUgZW5kIG9mIGEgcmVnaW9uXG4gICAqIEBwYXJhbSBvcHRzIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgYmFzZXNQZXJTcGFuIChlLmcuIHBpeGVscyBwZXIgYmFzZXBhaXIpIG9yIHNjYWxlIHVzZWQgdG8gaW5mZXIgdGhlIHpvb21MZXZlbCB0byB1c2VcbiAgICovXG4gIHB1YmxpYyBhc3luYyBnZXRGZWF0dXJlU3RyZWFtKFxuICAgIHJlZk5hbWU6IHN0cmluZyxcbiAgICBzdGFydDogbnVtYmVyLFxuICAgIGVuZDogbnVtYmVyLFxuICAgIG9wdHM6IFJlcXVlc3RPcHRpb25zICYgeyBzY2FsZT86IG51bWJlcjsgYmFzZXNQZXJTcGFuPzogbnVtYmVyIH0gPSB7IHNjYWxlOiAxIH0sXG4gICk6IFByb21pc2U8T2JzZXJ2YWJsZTxGZWF0dXJlW10+PiB7XG4gICAgYXdhaXQgdGhpcy5nZXRIZWFkZXIob3B0cylcbiAgICBjb25zdCBjaHJOYW1lID0gdGhpcy5yZW5hbWVSZWZTZXFzKHJlZk5hbWUpXG4gICAgbGV0IHZpZXc6IEJsb2NrVmlld1xuXG4gICAgaWYgKG9wdHMuYmFzZXNQZXJTcGFuKSB7XG4gICAgICB2aWV3ID0gYXdhaXQgdGhpcy5nZXRWaWV3KDEgLyBvcHRzLmJhc2VzUGVyU3Bhbiwgb3B0cylcbiAgICB9IGVsc2UgaWYgKG9wdHMuc2NhbGUpIHtcbiAgICAgIHZpZXcgPSBhd2FpdCB0aGlzLmdldFZpZXcob3B0cy5zY2FsZSwgb3B0cylcbiAgICB9IGVsc2Uge1xuICAgICAgdmlldyA9IGF3YWl0IHRoaXMuZ2V0VmlldygxLCBvcHRzKVxuICAgIH1cblxuICAgIGlmICghdmlldykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCd1bmFibGUgdG8gZ2V0IGJsb2NrIHZpZXcgZm9yIGRhdGEnKVxuICAgIH1cbiAgICByZXR1cm4gbmV3IE9ic2VydmFibGUoKG9ic2VydmVyOiBPYnNlcnZlcjxGZWF0dXJlW10+KTogdm9pZCA9PiB7XG4gICAgICB2aWV3LnJlYWRXaWdEYXRhKGNock5hbWUsIHN0YXJ0LCBlbmQsIG9ic2VydmVyLCBvcHRzKVxuICAgIH0pXG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZ2V0RmVhdHVyZXMoXG4gICAgcmVmTmFtZTogc3RyaW5nLFxuICAgIHN0YXJ0OiBudW1iZXIsXG4gICAgZW5kOiBudW1iZXIsXG4gICAgb3B0czogUmVxdWVzdE9wdGlvbnMgJiB7IHNjYWxlPzogbnVtYmVyOyBiYXNlc1BlclNwYW4/OiBudW1iZXIgfSA9IHsgc2NhbGU6IDEgfSxcbiAgKTogUHJvbWlzZTxGZWF0dXJlW10+IHtcbiAgICBjb25zdCBvYiA9IGF3YWl0IHRoaXMuZ2V0RmVhdHVyZVN0cmVhbShyZWZOYW1lLCBzdGFydCwgZW5kLCBvcHRzKVxuXG4gICAgY29uc3QgcmV0ID0gYXdhaXQgb2IucGlwZShyZWR1Y2UoKGFjYywgY3VycikgPT4gYWNjLmNvbmNhdChjdXJyKSkpLnRvUHJvbWlzZSgpXG4gICAgcmV0dXJuIHJldCB8fCBbXVxuICB9XG59XG4iXX0=