@gmod/tabix 1.4.5 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,380 +1,259 @@
1
1
  "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
4
-
5
- var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");
6
-
7
- _Object$defineProperty(exports, "__esModule", {
8
- value: true
9
- });
10
-
11
- exports.default = void 0;
12
-
13
- var _parseInt2 = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/parse-int"));
14
-
15
- var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
16
-
17
- var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
18
-
19
- var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
20
-
21
- var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
22
-
23
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
24
-
25
- var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
26
-
27
- var _abortablePromiseCache = _interopRequireDefault(require("abortable-promise-cache"));
28
-
29
- var _quickLru = _interopRequireDefault(require("quick-lru"));
30
-
31
- var _genericFilehandle = require("generic-filehandle");
32
-
33
- var _bgzfFilehandle = require("@gmod/bgzf-filehandle");
34
-
35
- var _util = require("./util");
36
-
37
- var _tbi = _interopRequireDefault(require("./tbi"));
38
-
39
- var _csi = _interopRequireDefault(require("./csi"));
40
-
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (_) try {
18
+ 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;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ var abortable_promise_cache_1 = __importDefault(require("abortable-promise-cache"));
43
+ var quick_lru_1 = __importDefault(require("quick-lru"));
44
+ var generic_filehandle_1 = require("generic-filehandle");
45
+ var bgzf_filehandle_1 = require("@gmod/bgzf-filehandle");
46
+ var util_1 = require("./util");
47
+ var tbi_1 = __importDefault(require("./tbi"));
48
+ var csi_1 = __importDefault(require("./csi"));
41
49
  function timeout(time) {
42
- return new _promise.default(function (resolve) {
43
- setTimeout(resolve, time);
44
- });
50
+ return new Promise(function (resolve) {
51
+ setTimeout(resolve, time);
52
+ });
45
53
  }
46
-
47
- var TabixIndexedFile = /*#__PURE__*/function () {
48
- /**
49
- * @param {object} args
50
- * @param {string} [args.path]
51
- * @param {filehandle} [args.filehandle]
52
- * @param {string} [args.tbiPath]
53
- * @param {filehandle} [args.tbiFilehandle]
54
- * @param {string} [args.csiPath]
55
- * @param {filehandle} [args.csiFilehandle]
56
- * @param {number} [args.chunkSizeLimit] maximum number of bytes to fetch in a single `getLines` call.
57
- * default 2MiB
58
- * @param {number} [args.yieldLimit] maximum number of lines to parse without yielding.
59
- * this avoids having a large read prevent any other work getting done on the thread. default 300 lines.
60
- * @param {function} [args.renameRefSeqs] optional function with sig `string => string` to transform
61
- * reference sequence names for the purpose of indexing and querying. note that the data that is returned is
62
- * not altered, just the names of the reference sequences that are used for querying.
63
- * @param {number} [args.chunkCacheSize] maximum size in bytes of the chunk cache. default 5MB
64
- * @param {number} [args.blockCacheSize] maximum size in bytes of the block cache. default 5MB
65
- */
66
- function TabixIndexedFile(_ref) {
67
- var path = _ref.path,
68
- filehandle = _ref.filehandle,
69
- tbiPath = _ref.tbiPath,
70
- tbiFilehandle = _ref.tbiFilehandle,
71
- csiPath = _ref.csiPath,
72
- csiFilehandle = _ref.csiFilehandle,
73
- _ref$chunkSizeLimit = _ref.chunkSizeLimit,
74
- chunkSizeLimit = _ref$chunkSizeLimit === void 0 ? 2000000 : _ref$chunkSizeLimit,
75
- _ref$yieldLimit = _ref.yieldLimit,
76
- yieldLimit = _ref$yieldLimit === void 0 ? 300 : _ref$yieldLimit,
77
- _ref$renameRefSeqs = _ref.renameRefSeqs,
78
- renameRefSeqs = _ref$renameRefSeqs === void 0 ? function (n) {
79
- return n;
80
- } : _ref$renameRefSeqs,
81
- _ref$chunkCacheSize = _ref.chunkCacheSize,
82
- chunkCacheSize = _ref$chunkCacheSize === void 0 ? 5 * Math.pow(2, 20) : _ref$chunkCacheSize;
83
- (0, _classCallCheck2.default)(this, TabixIndexedFile);
84
- (0, _defineProperty2.default)(this, "filehandle", void 0);
85
- (0, _defineProperty2.default)(this, "index", void 0);
86
- (0, _defineProperty2.default)(this, "chunkSizeLimit", void 0);
87
- (0, _defineProperty2.default)(this, "renameRefSeq", void 0);
88
- (0, _defineProperty2.default)(this, "yieldLimit", void 0);
89
- (0, _defineProperty2.default)(this, "chunkCache", void 0);
90
- if (filehandle) this.filehandle = filehandle;else if (path) this.filehandle = new _genericFilehandle.LocalFile(path);else throw new TypeError('must provide either filehandle or path');
91
- if (tbiFilehandle) this.index = new _tbi.default({
92
- filehandle: tbiFilehandle,
93
- renameRefSeqs: renameRefSeqs
94
- });else if (csiFilehandle) this.index = new _csi.default({
95
- filehandle: csiFilehandle,
96
- renameRefSeqs: renameRefSeqs
97
- });else if (tbiPath) this.index = new _tbi.default({
98
- filehandle: new _genericFilehandle.LocalFile(tbiPath),
99
- renameRefSeqs: renameRefSeqs
100
- });else if (csiPath) this.index = new _csi.default({
101
- filehandle: new _genericFilehandle.LocalFile(csiPath),
102
- renameRefSeqs: renameRefSeqs
103
- });else if (path) {
104
- this.index = new _tbi.default({
105
- filehandle: new _genericFilehandle.LocalFile("".concat(path, ".tbi")),
106
- renameRefSeqs: renameRefSeqs
107
- });
108
- } else {
109
- throw new TypeError('must provide one of tbiFilehandle, tbiPath, csiFilehandle, or csiPath');
54
+ var TabixIndexedFile = /** @class */ (function () {
55
+ /**
56
+ * @param {object} args
57
+ * @param {string} [args.path]
58
+ * @param {filehandle} [args.filehandle]
59
+ * @param {string} [args.tbiPath]
60
+ * @param {filehandle} [args.tbiFilehandle]
61
+ * @param {string} [args.csiPath]
62
+ * @param {filehandle} [args.csiFilehandle]
63
+ * @param {chunkSizeLimit} default 50MiB
64
+ * @param {function} [args.renameRefSeqs] optional function with sig `string => string` to transform
65
+ * reference sequence names for the purpose of indexing and querying. note that the data that is returned is
66
+ * not altered, just the names of the reference sequences that are used for querying.
67
+ * @param {number} [args.chunkCacheSize] maximum size in bytes of the chunk cache. default 5MB
68
+ * @param {number} [args.blockCacheSize] maximum size in bytes of the block cache. default 5MB
69
+ */
70
+ function TabixIndexedFile(_a) {
71
+ var path = _a.path, filehandle = _a.filehandle, tbiPath = _a.tbiPath, tbiFilehandle = _a.tbiFilehandle, csiPath = _a.csiPath, csiFilehandle = _a.csiFilehandle, _b = _a.chunkSizeLimit, chunkSizeLimit = _b === void 0 ? 50000000 : _b, _c = _a.renameRefSeqs, renameRefSeqs = _c === void 0 ? function (n) { return n; } : _c, _d = _a.chunkCacheSize, chunkCacheSize = _d === void 0 ? 5 * Math.pow(2, 20) : _d;
72
+ if (filehandle) {
73
+ this.filehandle = filehandle;
74
+ }
75
+ else if (path) {
76
+ this.filehandle = new generic_filehandle_1.LocalFile(path);
77
+ }
78
+ else {
79
+ throw new TypeError('must provide either filehandle or path');
80
+ }
81
+ if (tbiFilehandle) {
82
+ this.index = new tbi_1.default({
83
+ filehandle: tbiFilehandle,
84
+ renameRefSeqs: renameRefSeqs,
85
+ });
86
+ }
87
+ else if (csiFilehandle) {
88
+ this.index = new csi_1.default({
89
+ filehandle: csiFilehandle,
90
+ renameRefSeqs: renameRefSeqs,
91
+ });
92
+ }
93
+ else if (tbiPath) {
94
+ this.index = new tbi_1.default({
95
+ filehandle: new generic_filehandle_1.LocalFile(tbiPath),
96
+ renameRefSeqs: renameRefSeqs,
97
+ });
98
+ }
99
+ else if (csiPath) {
100
+ this.index = new csi_1.default({
101
+ filehandle: new generic_filehandle_1.LocalFile(csiPath),
102
+ renameRefSeqs: renameRefSeqs,
103
+ });
104
+ }
105
+ else if (path) {
106
+ this.index = new tbi_1.default({
107
+ filehandle: new generic_filehandle_1.LocalFile("".concat(path, ".tbi")),
108
+ renameRefSeqs: renameRefSeqs,
109
+ });
110
+ }
111
+ else {
112
+ throw new TypeError('must provide one of tbiFilehandle, tbiPath, csiFilehandle, or csiPath');
113
+ }
114
+ this.chunkSizeLimit = chunkSizeLimit;
115
+ this.renameRefSeq = renameRefSeqs;
116
+ this.chunkCache = new abortable_promise_cache_1.default({
117
+ cache: new quick_lru_1.default({
118
+ maxSize: Math.floor(chunkCacheSize / (1 << 16)),
119
+ }),
120
+ fill: this.readChunk.bind(this),
121
+ });
110
122
  }
111
- this.chunkSizeLimit = chunkSizeLimit;
112
- this.yieldLimit = yieldLimit;
113
- this.renameRefSeq = renameRefSeqs;
114
- this.chunkCache = new _abortablePromiseCache.default({
115
- cache: new _quickLru.default({
116
- maxSize: Math.floor(chunkCacheSize / (1 << 16))
117
- }),
118
- fill: this.readChunk.bind(this)
119
- });
120
- }
121
- /**
122
- * @param {string} refName name of the reference sequence
123
- * @param {number} start start of the region (in 0-based half-open coordinates)
124
- * @param {number} end end of the region (in 0-based half-open coordinates)
125
- * @param {function|object} lineCallback callback called for each line in the region. can also pass a object param containing obj.lineCallback, obj.signal, etc
126
- * @returns {Promise} resolved when the whole read is finished, rejected on error
127
- */
128
-
129
-
130
- (0, _createClass2.default)(TabixIndexedFile, [{
131
- key: "getLines",
132
- value: function () {
133
- var _getLines = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(refName, start, end, opts) {
134
- var signal, options, callback, metadata, chunks, i, size, linesSinceLastYield, chunkNum, previousStartCoordinate, c, _yield$this$chunkCach, buffer, cpositions, dpositions, lines, blockStart, pos, _i, line, _this$checkLine, startCoordinate, overlaps;
135
-
136
- return _regenerator.default.wrap(function _callee$(_context) {
137
- while (1) {
138
- switch (_context.prev = _context.next) {
139
- case 0:
140
- options = {};
141
-
142
- if (!(typeof opts === 'undefined')) {
143
- _context.next = 3;
144
- break;
145
- }
146
-
147
- throw new TypeError('line callback must be provided');
148
-
149
- case 3:
150
- if (typeof opts === 'function') callback = opts;else {
151
- options = opts;
152
- callback = opts.lineCallback;
153
- }
154
-
155
- if (!(refName === undefined)) {
156
- _context.next = 6;
157
- break;
158
- }
159
-
160
- throw new TypeError('must provide a reference sequence name');
161
-
162
- case 6:
163
- if (callback) {
164
- _context.next = 8;
165
- break;
166
- }
167
-
168
- throw new TypeError('line callback must be provided');
169
-
170
- case 8:
171
- _context.next = 10;
172
- return this.index.getMetadata(options);
173
-
174
- case 10:
175
- metadata = _context.sent;
176
- (0, _util.checkAbortSignal)(signal);
177
-
178
- if (!start) {
179
- start = 0;
180
- }
181
-
182
- if (!end) {
183
- end = metadata.maxRefLength;
184
- }
185
-
186
- if (start <= end) {
187
- _context.next = 16;
188
- break;
189
- }
190
-
191
- throw new TypeError('invalid start and end coordinates. start must be less than or equal to end');
192
-
193
- case 16:
194
- if (!(start === end)) {
195
- _context.next = 18;
196
- break;
197
- }
198
-
199
- return _context.abrupt("return");
200
-
201
- case 18:
202
- _context.next = 20;
203
- return this.index.blocksForRange(refName, start, end, options);
204
-
205
- case 20:
206
- chunks = _context.sent;
207
- (0, _util.checkAbortSignal)(signal); // check the chunks for any that are over the size limit. if
208
- // any are, don't fetch any of them
209
-
210
- i = 0;
211
-
212
- case 23:
213
- if (!(i < chunks.length)) {
214
- _context.next = 30;
215
- break;
216
- }
217
-
218
- size = chunks[i].fetchedSize();
219
-
220
- if (!(size > this.chunkSizeLimit)) {
221
- _context.next = 27;
222
- break;
223
- }
224
-
225
- throw new Error("Too much data. Chunk size ".concat(size.toLocaleString(), " bytes exceeds chunkSizeLimit of ").concat(this.chunkSizeLimit.toLocaleString(), "."));
226
-
227
- case 27:
228
- i += 1;
229
- _context.next = 23;
230
- break;
231
-
232
- case 30:
233
- // now go through each chunk and parse and filter the lines out of it
234
- linesSinceLastYield = 0;
235
- chunkNum = 0;
236
-
237
- case 32:
238
- if (!(chunkNum < chunks.length)) {
239
- _context.next = 73;
240
- break;
241
- }
242
-
243
- previousStartCoordinate = void 0;
244
- c = chunks[chunkNum];
245
- _context.next = 37;
246
- return this.chunkCache.get(c.toString(), c, signal);
247
-
248
- case 37:
249
- _yield$this$chunkCach = _context.sent;
250
- buffer = _yield$this$chunkCach.buffer;
251
- cpositions = _yield$this$chunkCach.cpositions;
252
- dpositions = _yield$this$chunkCach.dpositions;
253
- lines = buffer.toString().split('\n');
254
- lines.pop();
255
- (0, _util.checkAbortSignal)(signal);
256
- blockStart = c.minv.dataPosition;
257
- pos = void 0;
258
- _i = 0;
259
-
260
- case 47:
261
- if (!(_i < lines.length)) {
262
- _context.next = 70;
263
- break;
264
- }
265
-
266
- line = lines[_i];
267
-
268
- for (pos = 0; blockStart >= dpositions[pos]; pos += 1) {
269
- ;
270
- } // filter the line for whether it is within the requested range
271
-
272
-
273
- _this$checkLine = this.checkLine(metadata, refName, start, end, line), startCoordinate = _this$checkLine.startCoordinate, overlaps = _this$checkLine.overlaps; // do a small check just to make sure that the lines are really sorted by start coordinate
274
-
275
- if (!(previousStartCoordinate !== undefined && startCoordinate !== undefined && previousStartCoordinate > startCoordinate)) {
276
- _context.next = 53;
277
- break;
278
- }
279
-
280
- throw new Error("Lines not sorted by start coordinate (".concat(previousStartCoordinate, " > ").concat(startCoordinate, "), this file is not usable with Tabix."));
281
-
282
- case 53:
283
- previousStartCoordinate = startCoordinate;
284
-
285
- if (!overlaps) {
286
- _context.next = 58;
287
- break;
288
- }
289
-
290
- callback(line.trim(), // cpositions[pos] refers to actual file offset of a bgzip block boundaries
291
- //
292
- // we multiply by (1 <<8) in order to make sure each block has a "unique"
293
- // address space so that data in that block could never overlap
294
- //
295
- // then the blockStart-dpositions is an uncompressed file offset from
296
- // that bgzip block boundary, and since the cpositions are multiplied by
297
- // (1 << 8) these uncompressed offsets get a unique space
298
- cpositions[pos] * (1 << 8) + (blockStart - dpositions[pos]));
299
- _context.next = 60;
300
- break;
301
-
302
- case 58:
303
- if (!(startCoordinate !== undefined && startCoordinate >= end)) {
304
- _context.next = 60;
305
- break;
306
- }
307
-
308
- return _context.abrupt("return");
309
-
310
- case 60:
311
- blockStart += line.length + 1; // yield if we have emitted beyond the yield limit
312
-
313
- linesSinceLastYield += 1;
314
-
315
- if (!(linesSinceLastYield >= this.yieldLimit)) {
316
- _context.next = 67;
317
- break;
123
+ /**
124
+ * @param {string} refName name of the reference sequence
125
+ * @param {number} start start of the region (in 0-based half-open coordinates)
126
+ * @param {number} end end of the region (in 0-based half-open coordinates)
127
+ * @param {function|object} lineCallback callback called for each line in the region. can also pass a object param containing obj.lineCallback, obj.signal, etc
128
+ * @returns {Promise} resolved when the whole read is finished, rejected on error
129
+ */
130
+ TabixIndexedFile.prototype.getLines = function (refName, start, end, opts) {
131
+ return __awaiter(this, void 0, void 0, function () {
132
+ var signal, options, callback, metadata, chunks, i, size, last, chunkNum, previousStartCoordinate, c, _a, buffer, cpositions, dpositions, lines, blockStart, pos, i, line, _b, startCoordinate, overlaps;
133
+ return __generator(this, function (_c) {
134
+ switch (_c.label) {
135
+ case 0:
136
+ options = {};
137
+ if (typeof opts === 'undefined') {
138
+ throw new TypeError('line callback must be provided');
139
+ }
140
+ if (typeof opts === 'function') {
141
+ callback = opts;
142
+ }
143
+ else {
144
+ options = opts;
145
+ callback = opts.lineCallback;
146
+ }
147
+ if (refName === undefined) {
148
+ throw new TypeError('must provide a reference sequence name');
149
+ }
150
+ if (!callback) {
151
+ throw new TypeError('line callback must be provided');
152
+ }
153
+ return [4 /*yield*/, this.index.getMetadata(options)];
154
+ case 1:
155
+ metadata = _c.sent();
156
+ (0, util_1.checkAbortSignal)(signal);
157
+ if (!start) {
158
+ start = 0;
159
+ }
160
+ if (!end) {
161
+ end = metadata.maxRefLength;
162
+ }
163
+ if (!(start <= end)) {
164
+ throw new TypeError('invalid start and end coordinates. start must be less than or equal to end');
165
+ }
166
+ if (start === end) {
167
+ return [2 /*return*/];
168
+ }
169
+ return [4 /*yield*/, this.index.blocksForRange(refName, start, end, options)];
170
+ case 2:
171
+ chunks = _c.sent();
172
+ (0, util_1.checkAbortSignal)(signal);
173
+ // check the chunks for any that are over the size limit. if
174
+ // any are, don't fetch any of them
175
+ for (i = 0; i < chunks.length; i += 1) {
176
+ size = chunks[i].fetchedSize();
177
+ if (size > this.chunkSizeLimit) {
178
+ throw new Error("Too much data. Chunk size ".concat(size.toLocaleString(), " bytes exceeds chunkSizeLimit of ").concat(this.chunkSizeLimit.toLocaleString(), "."));
179
+ }
180
+ }
181
+ last = Date.now();
182
+ chunkNum = 0;
183
+ _c.label = 3;
184
+ case 3:
185
+ if (!(chunkNum < chunks.length)) return [3 /*break*/, 9];
186
+ previousStartCoordinate = void 0;
187
+ c = chunks[chunkNum];
188
+ return [4 /*yield*/, this.chunkCache.get(c.toString(), c, signal)];
189
+ case 4:
190
+ _a = _c.sent(), buffer = _a.buffer, cpositions = _a.cpositions, dpositions = _a.dpositions;
191
+ lines = (typeof TextDecoder !== 'undefined'
192
+ ? new TextDecoder('utf-8').decode(buffer)
193
+ : buffer.toString()).split('\n');
194
+ lines.pop();
195
+ (0, util_1.checkAbortSignal)(signal);
196
+ blockStart = c.minv.dataPosition;
197
+ pos = void 0;
198
+ i = 0;
199
+ _c.label = 5;
200
+ case 5:
201
+ if (!(i < lines.length)) return [3 /*break*/, 8];
202
+ line = lines[i];
203
+ for (pos = 0; blockStart >= dpositions[pos]; pos += 1) { }
204
+ _b = this.checkLine(metadata, refName, start, end, line), startCoordinate = _b.startCoordinate, overlaps = _b.overlaps;
205
+ // do a small check just to make sure that the lines are really sorted by start coordinate
206
+ if (previousStartCoordinate !== undefined &&
207
+ startCoordinate !== undefined &&
208
+ previousStartCoordinate > startCoordinate) {
209
+ throw new Error("Lines not sorted by start coordinate (".concat(previousStartCoordinate, " > ").concat(startCoordinate, "), this file is not usable with Tabix."));
210
+ }
211
+ previousStartCoordinate = startCoordinate;
212
+ if (overlaps) {
213
+ callback(line.trim(),
214
+ // cpositions[pos] refers to actual file offset of a bgzip block boundaries
215
+ //
216
+ // we multiply by (1 <<8) in order to make sure each block has a "unique"
217
+ // address space so that data in that block could never overlap
218
+ //
219
+ // then the blockStart-dpositions is an uncompressed file offset from
220
+ // that bgzip block boundary, and since the cpositions are multiplied by
221
+ // (1 << 8) these uncompressed offsets get a unique space
222
+ cpositions[pos] * (1 << 8) + (blockStart - dpositions[pos]));
223
+ }
224
+ else if (startCoordinate !== undefined && startCoordinate >= end) {
225
+ // the lines were overlapping the region, but now have stopped, so
226
+ // we must be at the end of the relevant data and we can stop
227
+ // processing data now
228
+ return [2 /*return*/];
229
+ }
230
+ blockStart += line.length + 1;
231
+ if (!(last - Date.now() > 500)) return [3 /*break*/, 7];
232
+ last = Date.now();
233
+ (0, util_1.checkAbortSignal)(signal);
234
+ return [4 /*yield*/, timeout(1)];
235
+ case 6:
236
+ _c.sent();
237
+ _c.label = 7;
238
+ case 7:
239
+ i += 1;
240
+ return [3 /*break*/, 5];
241
+ case 8:
242
+ chunkNum += 1;
243
+ return [3 /*break*/, 3];
244
+ case 9: return [2 /*return*/];
318
245
  }
319
-
320
- _context.next = 65;
321
- return timeout(1);
322
-
323
- case 65:
324
- (0, _util.checkAbortSignal)(signal);
325
- linesSinceLastYield = 0;
326
-
327
- case 67:
328
- _i += 1;
329
- _context.next = 47;
330
- break;
331
-
332
- case 70:
333
- chunkNum += 1;
334
- _context.next = 32;
335
- break;
336
-
337
- case 73:
338
- case "end":
339
- return _context.stop();
340
- }
341
- }
342
- }, _callee, this);
343
- }));
344
-
345
- function getLines(_x, _x2, _x3, _x4) {
346
- return _getLines.apply(this, arguments);
347
- }
348
-
349
- return getLines;
350
- }()
351
- }, {
352
- key: "getMetadata",
353
- value: function () {
354
- var _getMetadata = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
355
- var opts,
356
- _args2 = arguments;
357
- return _regenerator.default.wrap(function _callee2$(_context2) {
358
- while (1) {
359
- switch (_context2.prev = _context2.next) {
360
- case 0:
361
- opts = _args2.length > 0 && _args2[0] !== undefined ? _args2[0] : {};
362
- return _context2.abrupt("return", this.index.getMetadata(opts));
363
-
364
- case 2:
365
- case "end":
366
- return _context2.stop();
367
- }
368
- }
369
- }, _callee2, this);
370
- }));
371
-
372
- function getMetadata() {
373
- return _getMetadata.apply(this, arguments);
374
- }
375
-
376
- return getMetadata;
377
- }()
246
+ });
247
+ });
248
+ };
249
+ TabixIndexedFile.prototype.getMetadata = function (opts) {
250
+ if (opts === void 0) { opts = {}; }
251
+ return __awaiter(this, void 0, void 0, function () {
252
+ return __generator(this, function (_a) {
253
+ return [2 /*return*/, this.index.getMetadata(opts)];
254
+ });
255
+ });
256
+ };
378
257
  /**
379
258
  * get a buffer containing the "header" region of
380
259
  * the file, which are the bytes up to the first
@@ -382,156 +261,78 @@ var TabixIndexedFile = /*#__PURE__*/function () {
382
261
  *
383
262
  * @returns {Promise} for a buffer
384
263
  */
385
-
386
- }, {
387
- key: "getHeaderBuffer",
388
- value: function () {
389
- var _getHeaderBuffer = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
390
- var opts,
391
- _yield$this$getMetada,
392
- firstDataLine,
393
- metaChar,
394
- maxBlockSize,
395
- maxFetch,
396
- bytes,
397
- lastNewline,
398
- newlineByte,
399
- metaByte,
400
- i,
401
- _args3 = arguments;
402
-
403
- return _regenerator.default.wrap(function _callee3$(_context3) {
404
- while (1) {
405
- switch (_context3.prev = _context3.next) {
406
- case 0:
407
- opts = _args3.length > 0 && _args3[0] !== undefined ? _args3[0] : {};
408
- _context3.next = 3;
409
- return this.getMetadata(opts);
410
-
411
- case 3:
412
- _yield$this$getMetada = _context3.sent;
413
- firstDataLine = _yield$this$getMetada.firstDataLine;
414
- metaChar = _yield$this$getMetada.metaChar;
415
- maxBlockSize = _yield$this$getMetada.maxBlockSize;
416
- (0, _util.checkAbortSignal)(opts.signal);
417
- maxFetch = firstDataLine && firstDataLine.blockPosition ? firstDataLine.blockPosition + maxBlockSize : maxBlockSize; // TODO: what if we don't have a firstDataLine, and the header
418
- // actually takes up more than one block? this case is not covered here
419
-
420
- _context3.next = 11;
421
- return this._readRegion(0, maxFetch, opts);
422
-
423
- case 11:
424
- bytes = _context3.sent;
425
- (0, _util.checkAbortSignal)(opts.signal);
426
- _context3.prev = 13;
427
- _context3.next = 16;
428
- return (0, _bgzfFilehandle.unzip)(bytes);
429
-
430
- case 16:
431
- bytes = _context3.sent;
432
- _context3.next = 23;
433
- break;
434
-
435
- case 19:
436
- _context3.prev = 19;
437
- _context3.t0 = _context3["catch"](13);
438
- console.error(_context3.t0);
439
- throw new Error("error decompressing block ".concat(_context3.t0.code, " at 0 (length ").concat(maxFetch, ") ").concat(_context3.t0));
440
-
441
- case 23:
442
- if (!metaChar) {
443
- _context3.next = 36;
444
- break;
445
- }
446
-
447
- // trim backward from the end
448
- lastNewline = -1;
449
- newlineByte = '\n'.charCodeAt(0);
450
- metaByte = metaChar.charCodeAt(0);
451
- i = 0;
452
-
453
- case 28:
454
- if (!(i < bytes.length)) {
455
- _context3.next = 35;
456
- break;
457
- }
458
-
459
- if (!(i === lastNewline + 1 && bytes[i] !== metaByte)) {
460
- _context3.next = 31;
461
- break;
264
+ TabixIndexedFile.prototype.getHeaderBuffer = function (opts) {
265
+ if (opts === void 0) { opts = {}; }
266
+ return __awaiter(this, void 0, void 0, function () {
267
+ var _a, firstDataLine, metaChar, maxBlockSize, maxFetch, bytes, e_1, lastNewline, newlineByte, metaByte, i;
268
+ return __generator(this, function (_b) {
269
+ switch (_b.label) {
270
+ case 0: return [4 /*yield*/, this.getMetadata(opts)];
271
+ case 1:
272
+ _a = _b.sent(), firstDataLine = _a.firstDataLine, metaChar = _a.metaChar, maxBlockSize = _a.maxBlockSize;
273
+ (0, util_1.checkAbortSignal)(opts.signal);
274
+ maxFetch = firstDataLine && firstDataLine.blockPosition
275
+ ? firstDataLine.blockPosition + maxBlockSize
276
+ : maxBlockSize;
277
+ return [4 /*yield*/, this._readRegion(0, maxFetch, opts)];
278
+ case 2:
279
+ bytes = _b.sent();
280
+ (0, util_1.checkAbortSignal)(opts.signal);
281
+ _b.label = 3;
282
+ case 3:
283
+ _b.trys.push([3, 5, , 6]);
284
+ return [4 /*yield*/, (0, bgzf_filehandle_1.unzip)(bytes)];
285
+ case 4:
286
+ bytes = _b.sent();
287
+ return [3 /*break*/, 6];
288
+ case 5:
289
+ e_1 = _b.sent();
290
+ console.error(e_1);
291
+ throw new Error(
292
+ //@ts-ignore
293
+ "error decompressing block ".concat(e_1.code, " at 0 (length ").concat(maxFetch, ") ").concat(e_1));
294
+ case 6:
295
+ // trim off lines after the last non-meta line
296
+ if (metaChar) {
297
+ lastNewline = -1;
298
+ newlineByte = '\n'.charCodeAt(0);
299
+ metaByte = metaChar.charCodeAt(0);
300
+ for (i = 0; i < bytes.length; i += 1) {
301
+ if (i === lastNewline + 1 && bytes[i] !== metaByte) {
302
+ break;
303
+ }
304
+ if (bytes[i] === newlineByte) {
305
+ lastNewline = i;
306
+ }
307
+ }
308
+ bytes = bytes.slice(0, lastNewline + 1);
309
+ }
310
+ return [2 /*return*/, bytes];
462
311
  }
463
-
464
- return _context3.abrupt("break", 35);
465
-
466
- case 31:
467
- if (bytes[i] === newlineByte) lastNewline = i;
468
-
469
- case 32:
470
- i += 1;
471
- _context3.next = 28;
472
- break;
473
-
474
- case 35:
475
- bytes = bytes.slice(0, lastNewline + 1);
476
-
477
- case 36:
478
- return _context3.abrupt("return", bytes);
479
-
480
- case 37:
481
- case "end":
482
- return _context3.stop();
483
- }
484
- }
485
- }, _callee3, this, [[13, 19]]);
486
- }));
487
-
488
- function getHeaderBuffer() {
489
- return _getHeaderBuffer.apply(this, arguments);
490
- }
491
-
492
- return getHeaderBuffer;
493
- }()
312
+ });
313
+ });
314
+ };
494
315
  /**
495
316
  * get a string containing the "header" region of the
496
317
  * file, is the portion up to the first non-meta line
497
318
  *
498
319
  * @returns {Promise} for a string
499
320
  */
500
-
501
- }, {
502
- key: "getHeader",
503
- value: function () {
504
- var _getHeader = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4() {
505
- var opts,
506
- bytes,
507
- _args4 = arguments;
508
- return _regenerator.default.wrap(function _callee4$(_context4) {
509
- while (1) {
510
- switch (_context4.prev = _context4.next) {
511
- case 0:
512
- opts = _args4.length > 0 && _args4[0] !== undefined ? _args4[0] : {};
513
- _context4.next = 3;
514
- return this.getHeaderBuffer(opts);
515
-
516
- case 3:
517
- bytes = _context4.sent;
518
- (0, _util.checkAbortSignal)(opts.signal);
519
- return _context4.abrupt("return", bytes.toString('utf8'));
520
-
521
- case 6:
522
- case "end":
523
- return _context4.stop();
524
- }
525
- }
526
- }, _callee4, this);
527
- }));
528
-
529
- function getHeader() {
530
- return _getHeader.apply(this, arguments);
531
- }
532
-
533
- return getHeader;
534
- }()
321
+ TabixIndexedFile.prototype.getHeader = function (opts) {
322
+ if (opts === void 0) { opts = {}; }
323
+ return __awaiter(this, void 0, void 0, function () {
324
+ var bytes;
325
+ return __generator(this, function (_a) {
326
+ switch (_a.label) {
327
+ case 0: return [4 /*yield*/, this.getHeaderBuffer(opts)];
328
+ case 1:
329
+ bytes = _a.sent();
330
+ (0, util_1.checkAbortSignal)(opts.signal);
331
+ return [2 /*return*/, bytes.toString('utf8')];
332
+ }
333
+ });
334
+ });
335
+ };
535
336
  /**
536
337
  * get an array of reference sequence names, in the order in which
537
338
  * they occur in the file.
@@ -540,40 +341,20 @@ var TabixIndexedFile = /*#__PURE__*/function () {
540
341
  *
541
342
  * @returns {Promise} for an array of string sequence names
542
343
  */
543
-
544
- }, {
545
- key: "getReferenceSequenceNames",
546
- value: function () {
547
- var _getReferenceSequenceNames = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5() {
548
- var opts,
549
- metadata,
550
- _args5 = arguments;
551
- return _regenerator.default.wrap(function _callee5$(_context5) {
552
- while (1) {
553
- switch (_context5.prev = _context5.next) {
554
- case 0:
555
- opts = _args5.length > 0 && _args5[0] !== undefined ? _args5[0] : {};
556
- _context5.next = 3;
557
- return this.getMetadata(opts);
558
-
559
- case 3:
560
- metadata = _context5.sent;
561
- return _context5.abrupt("return", metadata.refIdToName);
562
-
563
- case 5:
564
- case "end":
565
- return _context5.stop();
566
- }
567
- }
568
- }, _callee5, this);
569
- }));
570
-
571
- function getReferenceSequenceNames() {
572
- return _getReferenceSequenceNames.apply(this, arguments);
573
- }
574
-
575
- return getReferenceSequenceNames;
576
- }()
344
+ TabixIndexedFile.prototype.getReferenceSequenceNames = function (opts) {
345
+ if (opts === void 0) { opts = {}; }
346
+ return __awaiter(this, void 0, void 0, function () {
347
+ var metadata;
348
+ return __generator(this, function (_a) {
349
+ switch (_a.label) {
350
+ case 0: return [4 /*yield*/, this.getMetadata(opts)];
351
+ case 1:
352
+ metadata = _a.sent();
353
+ return [2 /*return*/, metadata.refIdToName];
354
+ }
355
+ });
356
+ });
357
+ };
577
358
  /**
578
359
  * @param {object} metadata metadata object from the parsed index,
579
360
  * containing columnNumbers, metaChar, and format
@@ -584,251 +365,165 @@ var TabixIndexedFile = /*#__PURE__*/function () {
584
365
  * @returns {object} like `{startCoordinate, overlaps}`. overlaps is boolean,
585
366
  * true if line is a data line that overlaps the given region
586
367
  */
587
-
588
- }, {
589
- key: "checkLine",
590
- value: function checkLine(_ref2, regionRefName, regionStart, regionEnd, line) {
591
- var columnNumbers = _ref2.columnNumbers,
592
- metaChar = _ref2.metaChar,
593
- coordinateType = _ref2.coordinateType,
594
- format = _ref2.format;
595
-
596
- // skip meta lines
597
- if (line.charAt(0) === metaChar) {
598
- return {
599
- overlaps: false
600
- };
601
- } // check ref/start/end using column metadata from index
602
-
603
-
604
- var ref = columnNumbers.ref,
605
- start = columnNumbers.start,
606
- end = columnNumbers.end;
607
- if (!ref) ref = 0;
608
- if (!start) start = 0;
609
- if (!end) end = 0;
610
- if (format === 'VCF') end = 8;
611
- var maxColumn = Math.max(ref, start, end); // this code is kind of complex, but it is fairly fast.
612
- // basically, we want to avoid doing a split, because if the lines are really long
613
- // that could lead to us allocating a bunch of extra memory, which is slow
614
-
615
- var currentColumnNumber = 1; // cols are numbered starting at 1 in the index metadata
616
-
617
- var currentColumnStart = 0;
618
- var refSeq = '';
619
- var startCoordinate = -Infinity;
620
-
621
- for (var i = 0; i < line.length + 1; i += 1) {
622
- if (line[i] === '\t' || i === line.length) {
623
- if (currentColumnNumber === ref) {
624
- if (this.renameRefSeq(line.slice(currentColumnStart, i)) !== regionRefName) {
625
- return {
626
- overlaps: false
627
- };
628
- }
629
- } else if (currentColumnNumber === start) {
630
- startCoordinate = (0, _parseInt2.default)(line.slice(currentColumnStart, i), 10); // we convert to 0-based-half-open
631
-
632
- if (coordinateType === '1-based-closed') {
633
- startCoordinate -= 1;
634
- }
635
-
636
- if (startCoordinate >= regionEnd) {
637
- return {
638
- startCoordinate: startCoordinate,
639
- overlaps: false
640
- };
641
- }
642
-
643
- if (end === 0 || end === start) {
644
- // if we have no end, we assume the feature is 1 bp long
645
- if (startCoordinate + 1 <= regionStart) {
646
- return {
647
- startCoordinate: startCoordinate,
648
- overlaps: false
649
- };
650
- }
651
- }
652
- } else if (format === 'VCF' && currentColumnNumber === 4) {
653
- refSeq = line.slice(currentColumnStart, i);
654
- } else if (currentColumnNumber === end) {
655
- var endCoordinate = void 0; // this will never match if there is no end column
656
-
657
- if (format === 'VCF') {
658
- endCoordinate = this._getVcfEnd(startCoordinate, refSeq, line.slice(currentColumnStart, i));
659
- } else {
660
- endCoordinate = (0, _parseInt2.default)(line.slice(currentColumnStart, i), 10);
368
+ TabixIndexedFile.prototype.checkLine = function (_a, regionRefName, regionStart, regionEnd, line) {
369
+ var columnNumbers = _a.columnNumbers, metaChar = _a.metaChar, coordinateType = _a.coordinateType, format = _a.format;
370
+ // skip meta lines
371
+ if (line.charAt(0) === metaChar) {
372
+ return { overlaps: false };
373
+ }
374
+ // check ref/start/end using column metadata from index
375
+ var ref = columnNumbers.ref, start = columnNumbers.start, end = columnNumbers.end;
376
+ if (!ref) {
377
+ ref = 0;
378
+ }
379
+ if (!start) {
380
+ start = 0;
381
+ }
382
+ if (!end) {
383
+ end = 0;
384
+ }
385
+ if (format === 'VCF') {
386
+ end = 8;
387
+ }
388
+ var maxColumn = Math.max(ref, start, end);
389
+ // this code is kind of complex, but it is fairly fast.
390
+ // basically, we want to avoid doing a split, because if the lines are really long
391
+ // that could lead to us allocating a bunch of extra memory, which is slow
392
+ var currentColumnNumber = 1; // cols are numbered starting at 1 in the index metadata
393
+ var currentColumnStart = 0;
394
+ var refSeq = '';
395
+ var startCoordinate = -Infinity;
396
+ for (var i = 0; i < line.length + 1; i += 1) {
397
+ if (line[i] === '\t' || i === line.length) {
398
+ if (currentColumnNumber === ref) {
399
+ if (this.renameRefSeq(line.slice(currentColumnStart, i)) !==
400
+ regionRefName) {
401
+ return { overlaps: false };
402
+ }
403
+ }
404
+ else if (currentColumnNumber === start) {
405
+ startCoordinate = parseInt(line.slice(currentColumnStart, i), 10);
406
+ // we convert to 0-based-half-open
407
+ if (coordinateType === '1-based-closed') {
408
+ startCoordinate -= 1;
409
+ }
410
+ if (startCoordinate >= regionEnd) {
411
+ return { startCoordinate: startCoordinate, overlaps: false };
412
+ }
413
+ if (end === 0 || end === start) {
414
+ // if we have no end, we assume the feature is 1 bp long
415
+ if (startCoordinate + 1 <= regionStart) {
416
+ return { startCoordinate: startCoordinate, overlaps: false };
417
+ }
418
+ }
419
+ }
420
+ else if (format === 'VCF' && currentColumnNumber === 4) {
421
+ refSeq = line.slice(currentColumnStart, i);
422
+ }
423
+ else if (currentColumnNumber === end) {
424
+ var endCoordinate
425
+ // this will never match if there is no end column
426
+ = void 0;
427
+ // this will never match if there is no end column
428
+ if (format === 'VCF') {
429
+ endCoordinate = this._getVcfEnd(startCoordinate, refSeq, line.slice(currentColumnStart, i));
430
+ }
431
+ else {
432
+ endCoordinate = parseInt(line.slice(currentColumnStart, i), 10);
433
+ }
434
+ if (endCoordinate <= regionStart) {
435
+ return { overlaps: false };
436
+ }
437
+ }
438
+ currentColumnStart = i + 1;
439
+ currentColumnNumber += 1;
440
+ if (currentColumnNumber > maxColumn) {
441
+ break;
442
+ }
661
443
  }
662
-
663
- if (endCoordinate <= regionStart) {
664
- return {
665
- overlaps: false
666
- };
444
+ }
445
+ return { startCoordinate: startCoordinate, overlaps: true };
446
+ };
447
+ TabixIndexedFile.prototype._getVcfEnd = function (startCoordinate, refSeq, info) {
448
+ var endCoordinate = startCoordinate + refSeq.length;
449
+ // ignore TRA features as they specify CHR2 and END
450
+ // as being on a different chromosome
451
+ // if CHR2 is on the same chromosome, still ignore it
452
+ // because there should be another pairwise feature
453
+ // at the end of this one
454
+ var isTRA = info.indexOf('SVTYPE=TRA') !== -1;
455
+ if (info[0] !== '.' && !isTRA) {
456
+ var prevChar = ';';
457
+ for (var j = 0; j < info.length; j += 1) {
458
+ if (prevChar === ';' && info.slice(j, j + 4) === 'END=') {
459
+ var valueEnd = info.indexOf(';', j);
460
+ if (valueEnd === -1) {
461
+ valueEnd = info.length;
462
+ }
463
+ endCoordinate = parseInt(info.slice(j + 4, valueEnd), 10);
464
+ break;
465
+ }
466
+ prevChar = info[j];
667
467
  }
668
- }
669
-
670
- currentColumnStart = i + 1;
671
- currentColumnNumber += 1;
672
-
673
- if (currentColumnNumber > maxColumn) {
674
- break;
675
- }
676
468
  }
677
- }
678
-
679
- return {
680
- startCoordinate: startCoordinate,
681
- overlaps: true
682
- };
683
- }
684
- }, {
685
- key: "_getVcfEnd",
686
- value: function _getVcfEnd(startCoordinate, refSeq, info) {
687
- var endCoordinate = startCoordinate + refSeq.length; // ignore TRA features as they specify CHR2 and END
688
- // as being on a different chromosome
689
- // if CHR2 is on the same chromosome, still ignore it
690
- // because there should be another pairwise feature
691
- // at the end of this one
692
-
693
- var isTRA = info.indexOf('SVTYPE=TRA') !== -1;
694
-
695
- if (info[0] !== '.' && !isTRA) {
696
- var prevChar = ';';
697
-
698
- for (var j = 0; j < info.length; j += 1) {
699
- if (prevChar === ';' && info.slice(j, j + 4) === 'END=') {
700
- var valueEnd = info.indexOf(';', j);
701
- if (valueEnd === -1) valueEnd = info.length;
702
- endCoordinate = (0, _parseInt2.default)(info.slice(j + 4, valueEnd), 10);
703
- break;
704
- }
705
-
706
- prevChar = info[j];
469
+ else if (isTRA) {
470
+ return startCoordinate + 1;
707
471
  }
708
- } else if (isTRA) {
709
- return startCoordinate + 1;
710
- }
711
-
712
- return endCoordinate;
713
- }
472
+ return endCoordinate;
473
+ };
714
474
  /**
715
475
  * return the approximate number of data lines in the given reference sequence
716
476
  * @param {string} refSeq reference sequence name
717
477
  * @returns {Promise} for number of data lines present on that reference sequence
718
478
  */
719
-
720
- }, {
721
- key: "lineCount",
722
- value: function () {
723
- var _lineCount = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee6(refName) {
724
- var opts,
725
- _args6 = arguments;
726
- return _regenerator.default.wrap(function _callee6$(_context6) {
727
- while (1) {
728
- switch (_context6.prev = _context6.next) {
729
- case 0:
730
- opts = _args6.length > 1 && _args6[1] !== undefined ? _args6[1] : {};
731
- return _context6.abrupt("return", this.index.lineCount(refName, opts));
732
-
733
- case 2:
734
- case "end":
735
- return _context6.stop();
736
- }
737
- }
738
- }, _callee6, this);
739
- }));
740
-
741
- function lineCount(_x5) {
742
- return _lineCount.apply(this, arguments);
743
- }
744
-
745
- return lineCount;
746
- }()
747
- }, {
748
- key: "_readRegion",
749
- value: function () {
750
- var _readRegion2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee7(position, compressedSize) {
751
- var opts,
752
- _yield$this$filehandl,
753
- buffer,
754
- _args7 = arguments;
755
-
756
- return _regenerator.default.wrap(function _callee7$(_context7) {
757
- while (1) {
758
- switch (_context7.prev = _context7.next) {
759
- case 0:
760
- opts = _args7.length > 2 && _args7[2] !== undefined ? _args7[2] : {};
761
- _context7.next = 3;
762
- return this.filehandle.read(Buffer.alloc(compressedSize), 0, compressedSize, position, opts);
763
-
764
- case 3:
765
- _yield$this$filehandl = _context7.sent;
766
- buffer = _yield$this$filehandl.buffer;
767
- return _context7.abrupt("return", buffer);
768
-
769
- case 6:
770
- case "end":
771
- return _context7.stop();
772
- }
773
- }
774
- }, _callee7, this);
775
- }));
776
-
777
- function _readRegion(_x6, _x7) {
778
- return _readRegion2.apply(this, arguments);
779
- }
780
-
781
- return _readRegion;
782
- }()
479
+ TabixIndexedFile.prototype.lineCount = function (refName, opts) {
480
+ if (opts === void 0) { opts = {}; }
481
+ return __awaiter(this, void 0, void 0, function () {
482
+ return __generator(this, function (_a) {
483
+ return [2 /*return*/, this.index.lineCount(refName, opts)];
484
+ });
485
+ });
486
+ };
487
+ TabixIndexedFile.prototype._readRegion = function (position, compressedSize, opts) {
488
+ if (opts === void 0) { opts = {}; }
489
+ return __awaiter(this, void 0, void 0, function () {
490
+ var _a, bytesRead, buffer;
491
+ return __generator(this, function (_b) {
492
+ switch (_b.label) {
493
+ case 0: return [4 /*yield*/, this.filehandle.read(Buffer.alloc(compressedSize), 0, compressedSize, position, opts)];
494
+ case 1:
495
+ _a = _b.sent(), bytesRead = _a.bytesRead, buffer = _a.buffer;
496
+ return [2 /*return*/, bytesRead < compressedSize ? buffer.slice(0, bytesRead) : buffer];
497
+ }
498
+ });
499
+ });
500
+ };
783
501
  /**
784
502
  * read and uncompress the data in a chunk (composed of one or more
785
503
  * contiguous bgzip blocks) of the file
786
504
  * @param {Chunk} chunk
787
505
  * @returns {Promise} for a string chunk of the file
788
506
  */
789
-
790
- }, {
791
- key: "readChunk",
792
- value: function () {
793
- var _readChunk = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee8(chunk) {
794
- var opts,
795
- compressedData,
796
- _args8 = arguments;
797
- return _regenerator.default.wrap(function _callee8$(_context8) {
798
- while (1) {
799
- switch (_context8.prev = _context8.next) {
800
- case 0:
801
- opts = _args8.length > 1 && _args8[1] !== undefined ? _args8[1] : {};
802
- _context8.next = 3;
803
- return this._readRegion(chunk.minv.blockPosition, chunk.fetchedSize(), opts);
804
-
805
- case 3:
806
- compressedData = _context8.sent;
807
- _context8.prev = 4;
808
- return _context8.abrupt("return", (0, _bgzfFilehandle.unzipChunkSlice)(compressedData, chunk));
809
-
810
- case 8:
811
- _context8.prev = 8;
812
- _context8.t0 = _context8["catch"](4);
813
- throw new Error("error decompressing chunk ".concat(chunk.toString(), " ").concat(_context8.t0));
814
-
815
- case 11:
816
- case "end":
817
- return _context8.stop();
818
- }
819
- }
820
- }, _callee8, this, [[4, 8]]);
821
- }));
822
-
823
- function readChunk(_x8) {
824
- return _readChunk.apply(this, arguments);
825
- }
826
-
827
- return readChunk;
828
- }()
829
- }]);
830
- return TabixIndexedFile;
831
- }();
832
-
507
+ TabixIndexedFile.prototype.readChunk = function (chunk, opts) {
508
+ if (opts === void 0) { opts = {}; }
509
+ return __awaiter(this, void 0, void 0, function () {
510
+ var compressedData;
511
+ return __generator(this, function (_a) {
512
+ switch (_a.label) {
513
+ case 0: return [4 /*yield*/, this._readRegion(chunk.minv.blockPosition, chunk.fetchedSize(), opts)];
514
+ case 1:
515
+ compressedData = _a.sent();
516
+ try {
517
+ return [2 /*return*/, (0, bgzf_filehandle_1.unzipChunkSlice)(compressedData, chunk)];
518
+ }
519
+ catch (e) {
520
+ throw new Error("error decompressing chunk ".concat(chunk.toString(), " ").concat(e));
521
+ }
522
+ return [2 /*return*/];
523
+ }
524
+ });
525
+ });
526
+ };
527
+ return TabixIndexedFile;
528
+ }());
833
529
  exports.default = TabixIndexedFile;
834
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy90YWJpeEluZGV4ZWRGaWxlLnRzIl0sIm5hbWVzIjpbInRpbWVvdXQiLCJ0aW1lIiwicmVzb2x2ZSIsInNldFRpbWVvdXQiLCJUYWJpeEluZGV4ZWRGaWxlIiwicGF0aCIsImZpbGVoYW5kbGUiLCJ0YmlQYXRoIiwidGJpRmlsZWhhbmRsZSIsImNzaVBhdGgiLCJjc2lGaWxlaGFuZGxlIiwiY2h1bmtTaXplTGltaXQiLCJ5aWVsZExpbWl0IiwicmVuYW1lUmVmU2VxcyIsIm4iLCJjaHVua0NhY2hlU2l6ZSIsIkxvY2FsRmlsZSIsIlR5cGVFcnJvciIsImluZGV4IiwiVEJJIiwiQ1NJIiwicmVuYW1lUmVmU2VxIiwiY2h1bmtDYWNoZSIsIkFib3J0YWJsZVByb21pc2VDYWNoZSIsImNhY2hlIiwiTFJVIiwibWF4U2l6ZSIsIk1hdGgiLCJmbG9vciIsImZpbGwiLCJyZWFkQ2h1bmsiLCJiaW5kIiwicmVmTmFtZSIsInN0YXJ0IiwiZW5kIiwib3B0cyIsIm9wdGlvbnMiLCJjYWxsYmFjayIsImxpbmVDYWxsYmFjayIsInVuZGVmaW5lZCIsImdldE1ldGFkYXRhIiwibWV0YWRhdGEiLCJzaWduYWwiLCJtYXhSZWZMZW5ndGgiLCJibG9ja3NGb3JSYW5nZSIsImNodW5rcyIsImkiLCJsZW5ndGgiLCJzaXplIiwiZmV0Y2hlZFNpemUiLCJFcnJvciIsInRvTG9jYWxlU3RyaW5nIiwibGluZXNTaW5jZUxhc3RZaWVsZCIsImNodW5rTnVtIiwicHJldmlvdXNTdGFydENvb3JkaW5hdGUiLCJjIiwiZ2V0IiwidG9TdHJpbmciLCJidWZmZXIiLCJjcG9zaXRpb25zIiwiZHBvc2l0aW9ucyIsImxpbmVzIiwic3BsaXQiLCJwb3AiLCJibG9ja1N0YXJ0IiwibWludiIsImRhdGFQb3NpdGlvbiIsInBvcyIsImxpbmUiLCJjaGVja0xpbmUiLCJzdGFydENvb3JkaW5hdGUiLCJvdmVybGFwcyIsInRyaW0iLCJmaXJzdERhdGFMaW5lIiwibWV0YUNoYXIiLCJtYXhCbG9ja1NpemUiLCJtYXhGZXRjaCIsImJsb2NrUG9zaXRpb24iLCJfcmVhZFJlZ2lvbiIsImJ5dGVzIiwiY29uc29sZSIsImVycm9yIiwiY29kZSIsImxhc3ROZXdsaW5lIiwibmV3bGluZUJ5dGUiLCJjaGFyQ29kZUF0IiwibWV0YUJ5dGUiLCJzbGljZSIsImdldEhlYWRlckJ1ZmZlciIsInJlZklkVG9OYW1lIiwicmVnaW9uUmVmTmFtZSIsInJlZ2lvblN0YXJ0IiwicmVnaW9uRW5kIiwiY29sdW1uTnVtYmVycyIsImNvb3JkaW5hdGVUeXBlIiwiZm9ybWF0IiwiY2hhckF0IiwicmVmIiwibWF4Q29sdW1uIiwibWF4IiwiY3VycmVudENvbHVtbk51bWJlciIsImN1cnJlbnRDb2x1bW5TdGFydCIsInJlZlNlcSIsIkluZmluaXR5IiwiZW5kQ29vcmRpbmF0ZSIsIl9nZXRWY2ZFbmQiLCJpbmZvIiwiaXNUUkEiLCJpbmRleE9mIiwicHJldkNoYXIiLCJqIiwidmFsdWVFbmQiLCJsaW5lQ291bnQiLCJwb3NpdGlvbiIsImNvbXByZXNzZWRTaXplIiwicmVhZCIsIkJ1ZmZlciIsImFsbG9jIiwiY2h1bmsiLCJjb21wcmVzc2VkRGF0YSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQTs7QUFHQTs7QUFDQTs7QUFFQSxTQUFTQSxPQUFULENBQWlCQyxJQUFqQixFQUErQjtBQUM3QixTQUFPLHFCQUFZLFVBQUFDLE9BQU8sRUFBSTtBQUM1QkMsSUFBQUEsVUFBVSxDQUFDRCxPQUFELEVBQVVELElBQVYsQ0FBVjtBQUNELEdBRk0sQ0FBUDtBQUdEOztJQUVvQkcsZ0I7QUFPbkI7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQWtCQSxrQ0FzQkc7QUFBQSxRQXJCREMsSUFxQkMsUUFyQkRBLElBcUJDO0FBQUEsUUFwQkRDLFVBb0JDLFFBcEJEQSxVQW9CQztBQUFBLFFBbkJEQyxPQW1CQyxRQW5CREEsT0FtQkM7QUFBQSxRQWxCREMsYUFrQkMsUUFs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QUFDREYsVUFBQUEsUUFBUSxHQUFHSCxJQUFJLENBQUNJLENBQUQsQ0FBZjtBQUNEO0FBQ0YsT0FYRCxNQVdPLElBQUlILEtBQUosRUFBVztBQUNoQixlQUFPckMsZUFBZSxHQUFHLENBQXpCO0FBQ0Q7O0FBQ0QsYUFBT2tDLGFBQVA7QUFDRDtBQUVEOzs7Ozs7Ozs7aUhBS2dCeEUsTzs7Ozs7OztBQUFpQkcsZ0JBQUFBLEksOERBQWdCLEU7a0RBQ3hDLEtBQUtqQixLQUFMLENBQVc4RixTQUFYLENBQXFCaEYsT0FBckIsRUFBOEJHLElBQTlCLEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7bUhBSVA4RSxRLEVBQ0FDLGM7Ozs7Ozs7Ozs7QUFDQS9FLGdCQUFBQSxJLDhEQUFnQixFOzt1QkFFUyxLQUFLN0IsVUFBTCxDQUFnQjZHLElBQWhCLENBQ3ZCQyxNQUFNLENBQUNDLEtBQVAsQ0FBYUgsY0FBYixDQUR1QixFQUV2QixDQUZ1QixFQUd2QkEsY0FIdUIsRUFJdkJELFFBSnVCLEVBS3ZCOUUsSUFMdUIsQzs7OztBQUFqQnVCLGdCQUFBQSxNLHlCQUFBQSxNO2tEQVFEQSxNOzs7Ozs7Ozs7Ozs7Ozs7O0FBR1Q7Ozs7Ozs7Ozs7aUhBTWdCNEQsSzs7Ozs7Ozs7QUFBY25GLGdCQUFBQSxJLDhEQUFnQixFOzt1QkFJZixLQUFLMkMsV0FBTCxDQUMzQndDLEtBQUssQ0FBQ3JELElBQU4sQ0FBV1ksYUFEZ0IsRUFFM0J5QyxLQUFLLENBQUNyRSxXQUFOLEVBRjJCLEVBRzNCZCxJQUgyQixDOzs7QUFBdkJvRixnQkFBQUEsYzs7a0RBTUcscUNBQWdCQSxjQUFoQixFQUFnQ0QsS0FBaEMsQzs7Ozs7c0JBRUQsSUFBSXBFLEtBQUoscUNBQXVDb0UsS0FBSyxDQUFDN0QsUUFBTixFQUF2Qyw0QiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBBYm9ydGFibGVQcm9taXNlQ2FjaGUgZnJvbSAnYWJvcnRhYmxlLXByb21pc2UtY2FjaGUnXG5pbXBvcnQgTFJVIGZyb20gJ3F1aWNrLWxydSdcbmltcG9ydCB7IEdlbmVyaWNGaWxlaGFuZGxlLCBMb2NhbEZpbGUgfSBmcm9tICdnZW5lcmljLWZpbGVoYW5kbGUnXG5pbXBvcnQgeyB1bnppcCwgdW56aXBDaHVua1NsaWNlIH0gZnJvbSAnQGdtb2QvYmd6Zi1maWxlaGFuZGxlJ1xuXG5pbXBvcnQgeyBjaGVja0Fib3J0U2lnbmFsIH0gZnJvbSAnLi91dGlsJ1xuaW1wb3J0IEluZGV4RmlsZSwgeyBPcHRpb25zIH0gZnJvbSAnLi9pbmRleEZpbGUnXG5pbXBvcnQgQ2h1bmsgZnJvbSAnLi9jaHVuaydcbmltcG9ydCBUQkkgZnJvbSAnLi90YmknXG5pbXBvcnQgQ1NJIGZyb20gJy4vY3NpJ1xuXG5mdW5jdGlvbiB0aW1lb3V0KHRpbWU6IG51bWJlcikge1xuICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgc2V0VGltZW91dChyZXNvbHZlLCB0aW1lKVxuICB9KVxufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUYWJpeEluZGV4ZWRGaWxlIHtcbiAgcHJpdmF0ZSBmaWxlaGFuZGxlOiBHZW5lcmljRmlsZWhhbmRsZVxuICBwcml2YXRlIGluZGV4OiBJbmRleEZpbGVcbiAgcHJpdmF0ZSBjaHVua1NpemVMaW1pdDogbnVtYmVyXG4gIHByaXZhdGUgcmVuYW1lUmVmU2VxOiAobjogc3RyaW5nKSA9PiBzdHJpbmdcbiAgcHJpdmF0ZSB5aWVsZExpbWl0OiBudW1iZXJcbiAgcHJpdmF0ZSBjaHVua0NhY2hlOiBhbnlcbiAgLyoqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy5wYXRoXVxuICAgKiBAcGFyYW0ge2ZpbGVoYW5kbGV9IFthcmdzLmZpbGVoYW5kbGVdXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy50YmlQYXRoXVxuICAgKiBAcGFyYW0ge2ZpbGVoYW5kbGV9IFthcmdzLnRiaUZpbGVoYW5kbGVdXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy5jc2lQYXRoXVxuICAgKiBAcGFyYW0ge2ZpbGVoYW5kbGV9IFthcmdzLmNzaUZpbGVoYW5kbGVdXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJncy5jaHVua1NpemVMaW1pdF0gbWF4aW11bSBudW1iZXIgb2YgYnl0ZXMgdG8gZmV0Y2ggaW4gYSBzaW5nbGUgYGdldExpbmVzYCBjYWxsLlxuICAgKiBkZWZhdWx0IDJNaUJcbiAgICogQHBhcmFtIHtudW1iZXJ9IFthcmdzLnlpZWxkTGltaXRdIG1heGltdW0gbnVtYmVyIG9mIGxpbmVzIHRvIHBhcnNlIHdpdGhvdXQgeWllbGRpbmcuXG4gICAqIHRoaXMgYXZvaWRzIGhhdmluZyBhIGxhcmdlIHJlYWQgcHJldmVudCBhbnkgb3RoZXIgd29yayBnZXR0aW5nIGRvbmUgb24gdGhlIHRocmVhZC4gIGRlZmF1bHQgMzAwIGxpbmVzLlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBbYXJncy5yZW5hbWVSZWZTZXFzXSBvcHRpb25hbCBmdW5jdGlvbiB3aXRoIHNpZyBgc3RyaW5nID0+IHN0cmluZ2AgdG8gdHJhbnNmb3JtXG4gICAqIHJlZmVyZW5jZSBzZXF1ZW5jZSBuYW1lcyBmb3IgdGhlIHB1cnBvc2Ugb2YgaW5kZXhpbmcgYW5kIHF1ZXJ5aW5nLiBub3RlIHRoYXQgdGhlIGRhdGEgdGhhdCBpcyByZXR1cm5lZCBpc1xuICAgKiBub3QgYWx0ZXJlZCwganVzdCB0aGUgbmFtZXMgb2YgdGhlIHJlZmVyZW5jZSBzZXF1ZW5jZXMgdGhhdCBhcmUgdXNlZCBmb3IgcXVlcnlpbmcuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJncy5jaHVua0NhY2hlU2l6ZV0gbWF4aW11bSBzaXplIGluIGJ5dGVzIG9mIHRoZSBjaHVuayBjYWNoZS4gZGVmYXVsdCA1TUJcbiAgICogQHBhcmFtIHtudW1iZXJ9IFthcmdzLmJsb2NrQ2FjaGVTaXplXSBtYXhpbXVtIHNpemUgaW4gYnl0ZXMgb2YgdGhlIGJsb2NrIGNhY2hlLiBkZWZhdWx0IDVNQlxuICAgKi9cbiAgY29uc3RydWN0b3Ioe1xuICAgIHBhdGgsXG4gICAgZmlsZWhhbmRsZSxcbiAgICB0YmlQYXRoLFxuICAgIHRiaUZpbGVoYW5kbGUsXG4gICAgY3NpUGF0aCxcbiAgICBjc2lGaWxlaGFuZGxlLFxuICAgIGNodW5rU2l6ZUxpbWl0ID0gMjAwMDAwMCxcbiAgICB5aWVsZExpbWl0ID0gMzAwLFxuICAgIHJlbmFtZVJlZlNlcXMgPSBuID0+IG4sXG4gICAgY2h1bmtDYWNoZVNpemUgPSA1ICogMiAqKiAyMCxcbiAgfToge1xuICAgIHBhdGg/OiBzdHJpbmdcbiAgICBmaWxlaGFuZGxlPzogR2VuZXJpY0ZpbGVoYW5kbGVcbiAgICB0YmlQYXRoPzogc3RyaW5nXG4gICAgdGJpRmlsZWhhbmRsZT86IEdlbmVyaWNGaWxlaGFuZGxlXG4gICAgY3NpUGF0aD86IHN0cmluZ1xuICAgIGNzaUZpbGVoYW5kbGU/OiBHZW5lcmljRmlsZWhhbmRsZVxuICAgIGNodW5rU2l6ZUxpbWl0PzogbnVtYmVyXG4gICAgeWllbGRMaW1pdD86IG51bWJlclxuICAgIHJlbmFtZVJlZlNlcXM/OiAobjogc3RyaW5nKSA9PiBzdHJpbmdcbiAgICBjaHVua0NhY2hlU2l6ZT86IG51bWJlclxuICB9KSB7XG4gICAgaWYgKGZpbGVoYW5kbGUpIHRoaXMuZmlsZWhhbmRsZSA9IGZpbGVoYW5kbGVcbiAgICBlbHNlIGlmIChwYXRoKSB0aGlzLmZpbGVoYW5kbGUgPSBuZXcgTG9jYWxGaWxlKHBhdGgpXG4gICAgZWxzZSB0aHJvdyBuZXcgVHlwZUVycm9yKCdtdXN0IHByb3ZpZGUgZWl0aGVyIGZpbGVoYW5kbGUgb3IgcGF0aCcpXG5cbiAgICBpZiAodGJpRmlsZWhhbmRsZSlcbiAgICAgIHRoaXMuaW5kZXggPSBuZXcgVEJJKHtcbiAgICAgICAgZmlsZWhhbmRsZTogdGJpRmlsZWhhbmRsZSxcbiAgICAgICAgcmVuYW1lUmVmU2VxcyxcbiAgICAgIH0pXG4gICAgZWxzZSBpZiAoY3NpRmlsZWhhbmRsZSlcbiAgICAgIHRoaXMuaW5kZXggPSBuZXcgQ1NJKHtcbiAgICAgICAgZmlsZWhhbmRsZTogY3NpRmlsZWhhbmRsZSxcbiAgICAgICAgcmVuYW1lUmVmU2VxcyxcbiAgICAgIH0pXG4gICAgZWxzZSBpZiAodGJpUGF0aClcbiAgICAgIHRoaXMuaW5kZXggPSBuZXcgVEJJKHtcbiAgICAgICAgZmlsZWhhbmRsZTogbmV3IExvY2FsRmlsZSh0YmlQYXRoKSxcbiAgICAgICAgcmVuYW1lUmVmU2VxcyxcbiAgICAgIH0pXG4gICAgZWxzZSBpZiAoY3NpUGF0aClcbiAgICAgIHRoaXMuaW5kZXggPSBuZXcgQ1NJKHtcbiAgICAgICAgZmlsZWhhbmRsZTogbmV3IExvY2FsRmlsZShjc2lQYXRoKSxcbiAgICAgICAgcmVuYW1lUmVmU2VxcyxcbiAgICAgIH0pXG4gICAgZWxzZSBpZiAocGF0aCkge1xuICAgICAgdGhpcy5pbmRleCA9IG5ldyBUQkkoe1xuICAgICAgICBmaWxlaGFuZGxlOiBuZXcgTG9jYWxGaWxlKGAke3BhdGh9LnRiaWApLFxuICAgICAgICByZW5hbWVSZWZTZXFzLFxuICAgICAgfSlcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcbiAgICAgICAgJ211c3QgcHJvdmlkZSBvbmUgb2YgdGJpRmlsZWhhbmRsZSwgdGJpUGF0aCwgY3NpRmlsZWhhbmRsZSwgb3IgY3NpUGF0aCcsXG4gICAgICApXG4gICAgfVxuXG4gICAgdGhpcy5jaHVua1NpemVMaW1pdCA9IGNodW5rU2l6ZUxpbWl0XG4gICAgdGhpcy55aWVsZExpbWl0ID0geWllbGRMaW1pdFxuICAgIHRoaXMucmVuYW1lUmVmU2VxID0gcmVuYW1lUmVmU2Vxc1xuICAgIHRoaXMuY2h1bmtDYWNoZSA9IG5ldyBBYm9ydGFibGVQcm9taXNlQ2FjaGUoe1xuICAgICAgY2FjaGU6IG5ldyBMUlUoe1xuICAgICAgICBtYXhTaXplOiBNYXRoLmZsb29yKGNodW5rQ2FjaGVTaXplIC8gKDEgPDwgMTYpKSxcbiAgICAgIH0pLFxuXG4gICAgICBmaWxsOiB0aGlzLnJlYWRDaHVuay5iaW5kKHRoaXMpLFxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlZk5hbWUgbmFtZSBvZiB0aGUgcmVmZXJlbmNlIHNlcXVlbmNlXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdGFydCBzdGFydCBvZiB0aGUgcmVnaW9uIChpbiAwLWJhc2VkIGhhbGYtb3BlbiBjb29yZGluYXRlcylcbiAgICogQHBhcmFtIHtudW1iZXJ9IGVuZCBlbmQgb2YgdGhlIHJlZ2lvbiAoaW4gMC1iYXNlZCBoYWxmLW9wZW4gY29vcmRpbmF0ZXMpXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb258b2JqZWN0fSBsaW5lQ2FsbGJhY2sgY2FsbGJhY2sgY2FsbGVkIGZvciBlYWNoIGxpbmUgaW4gdGhlIHJlZ2lvbi4gY2FuIGFsc28gcGFzcyBhIG9iamVjdCBwYXJhbSBjb250YWluaW5nIG9iai5saW5lQ2FsbGJhY2ssIG9iai5zaWduYWwsIGV0Y1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcmVzb2x2ZWQgd2hlbiB0aGUgd2hvbGUgcmVhZCBpcyBmaW5pc2hlZCwgcmVqZWN0ZWQgb24gZXJyb3JcbiAgICovXG4gIGFzeW5jIGdldExpbmVzKFxuICAgIHJlZk5hbWU6IHN0cmluZyxcbiAgICBzdGFydDogbnVtYmVyLFxuICAgIGVuZDogbnVtYmVyLFxuICAgIG9wdHM6IHsgc2lnbmFsPzogQWJvcnRTaWduYWw7IGxpbmVDYWxsYmFjazogRnVuY3Rpb24gfSB8IEZ1bmN0aW9uLFxuICApIHtcbiAgICBsZXQgc2lnbmFsOiBBYm9ydFNpZ25hbCB8IHVuZGVmaW5lZFxuICAgIGxldCBvcHRpb25zOiBPcHRpb25zID0ge31cbiAgICBsZXQgY2FsbGJhY2s6IEZ1bmN0aW9uXG4gICAgaWYgKHR5cGVvZiBvcHRzID09PSAndW5kZWZpbmVkJylcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ2xpbmUgY2FsbGJhY2sgbXVzdCBiZSBwcm92aWRlZCcpXG4gICAgaWYgKHR5cGVvZiBvcHRzID09PSAnZnVuY3Rpb24nKSBjYWxsYmFjayA9IG9wdHNcbiAgICBlbHNlIHtcbiAgICAgIG9wdGlvbnMgPSBvcHRzXG4gICAgICBjYWxsYmFjayA9IG9wdHMubGluZUNhbGxiYWNrXG4gICAgfVxuICAgIGlmIChyZWZOYW1lID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ211c3QgcHJvdmlkZSBhIHJlZmVyZW5jZSBzZXF1ZW5jZSBuYW1lJylcbiAgICB9XG4gICAgaWYgKCFjYWxsYmFjaykge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignbGluZSBjYWxsYmFjayBtdXN0IGJlIHByb3ZpZGVkJylcbiAgICB9XG5cbiAgICBjb25zdCBtZXRhZGF0YSA9IGF3YWl0IHRoaXMuaW5kZXguZ2V0TWV0YWRhdGEob3B0aW9ucylcbiAgICBjaGVja0Fib3J0U2lnbmFsKHNpZ25hbClcbiAgICBpZiAoIXN0YXJ0KSB7XG4gICAgICBzdGFydCA9IDBcbiAgICB9XG4gICAgaWYgKCFlbmQpIHtcbiAgICAgIGVuZCA9IG1ldGFkYXRhLm1heFJlZkxlbmd0aFxuICAgIH1cbiAgICBpZiAoIShzdGFydCA8PSBlbmQpKVxuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcbiAgICAgICAgJ2ludmFsaWQgc3RhcnQgYW5kIGVuZCBjb29yZGluYXRlcy4gc3RhcnQgbXVzdCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gZW5kJyxcbiAgICAgIClcbiAgICBpZiAoc3RhcnQgPT09IGVuZCkgcmV0dXJuXG5cbiAgICBjb25zdCBjaHVua3MgPSBhd2FpdCB0aGlzLmluZGV4LmJsb2Nrc0ZvclJhbmdlKHJlZk5hbWUsIHN0YXJ0LCBlbmQsIG9wdGlvbnMpXG4gICAgY2hlY2tBYm9ydFNpZ25hbChzaWduYWwpXG5cbiAgICAvLyBjaGVjayB0aGUgY2h1bmtzIGZvciBhbnkgdGhhdCBhcmUgb3ZlciB0aGUgc2l6ZSBsaW1pdC4gIGlmXG4gICAgLy8gYW55IGFyZSwgZG9uJ3QgZmV0Y2ggYW55IG9mIHRoZW1cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNodW5rcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgY29uc3Qgc2l6ZSA9IGNodW5rc1tpXS5mZXRjaGVkU2l6ZSgpXG4gICAgICBpZiAoc2l6ZSA+IHRoaXMuY2h1bmtTaXplTGltaXQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGBUb28gbXVjaCBkYXRhLiBDaHVuayBzaXplICR7c2l6ZS50b0xvY2FsZVN0cmluZygpfSBieXRlcyBleGNlZWRzIGNodW5rU2l6ZUxpbWl0IG9mICR7dGhpcy5jaHVua1NpemVMaW1pdC50b0xvY2FsZVN0cmluZygpfS5gLFxuICAgICAgICApXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gbm93IGdvIHRocm91Z2ggZWFjaCBjaHVuayBhbmQgcGFyc2UgYW5kIGZpbHRlciB0aGUgbGluZXMgb3V0IG9mIGl0XG4gICAgbGV0IGxpbmVzU2luY2VMYXN0WWllbGQgPSAwXG4gICAgZm9yIChsZXQgY2h1bmtOdW0gPSAwOyBjaHVua051bSA8IGNodW5rcy5sZW5ndGg7IGNodW5rTnVtICs9IDEpIHtcbiAgICAgIGxldCBwcmV2aW91c1N0YXJ0Q29vcmRpbmF0ZTogbnVtYmVyIHwgdW5kZWZpbmVkXG4gICAgICBjb25zdCBjID0gY2h1bmtzW2NodW5rTnVtXVxuICAgICAgY29uc3QgeyBidWZmZXIsIGNwb3NpdGlvbnMsIGRwb3NpdGlvbnMgfSA9IGF3YWl0IHRoaXMuY2h1bmtDYWNoZS5nZXQoXG4gICAgICAgIGMudG9TdHJpbmcoKSxcbiAgICAgICAgYyxcbiAgICAgICAgc2lnbmFsLFxuICAgICAgKVxuICAgICAgY29uc3QgbGluZXMgPSBidWZmZXIudG9TdHJpbmcoKS5zcGxpdCgnXFxuJylcbiAgICAgIGxpbmVzLnBvcCgpXG4gICAgICBjaGVja0Fib3J0U2lnbmFsKHNpZ25hbClcbiAgICAgIGxldCBibG9ja1N0YXJ0ID0gYy5taW52LmRhdGFQb3NpdGlvblxuICAgICAgbGV0IHBvc1xuXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgICAgIGNvbnN0IGxpbmUgPSBsaW5lc1tpXVxuXG4gICAgICAgIGZvciAocG9zID0gMDsgYmxvY2tTdGFydCA+PSBkcG9zaXRpb25zW3Bvc107IHBvcyArPSAxKTtcblxuICAgICAgICAvLyBmaWx0ZXIgdGhlIGxpbmUgZm9yIHdoZXRoZXIgaXQgaXMgd2l0aGluIHRoZSByZXF1ZXN0ZWQgcmFuZ2VcbiAgICAgICAgY29uc3QgeyBzdGFydENvb3JkaW5hdGUsIG92ZXJsYXBzIH0gPSB0aGlzLmNoZWNrTGluZShcbiAgICAgICAgICBtZXRhZGF0YSxcbiAgICAgICAgICByZWZOYW1lLFxuICAgICAgICAgIHN0YXJ0LFxuICAgICAgICAgIGVuZCxcbiAgICAgICAgICBsaW5lLFxuICAgICAgICApXG5cbiAgICAgICAgLy8gZG8gYSBzbWFsbCBjaGVjayBqdXN0IHRvIG1ha2Ugc3VyZSB0aGF0IHRoZSBsaW5lcyBhcmUgcmVhbGx5IHNvcnRlZCBieSBzdGFydCBjb29yZGluYXRlXG4gICAgICAgIGlmIChcbiAgICAgICAgICBwcmV2aW91c1N0YXJ0Q29vcmRpbmF0ZSAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICAgc3RhcnRDb29yZGluYXRlICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICBwcmV2aW91c1N0YXJ0Q29vcmRpbmF0ZSA+IHN0YXJ0Q29vcmRpbmF0ZVxuICAgICAgICApXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYExpbmVzIG5vdCBzb3J0ZWQgYnkgc3RhcnQgY29vcmRpbmF0ZSAoJHtwcmV2aW91c1N0YXJ0Q29vcmRpbmF0ZX0gPiAke3N0YXJ0Q29vcmRpbmF0ZX0pLCB0aGlzIGZpbGUgaXMgbm90IHVzYWJsZSB3aXRoIFRhYml4LmAsXG4gICAgICAgICAgKVxuICAgICAgICBwcmV2aW91c1N0YXJ0Q29vcmRpbmF0ZSA9IHN0YXJ0Q29vcmRpbmF0ZVxuXG4gICAgICAgIGlmIChvdmVybGFwcykge1xuICAgICAgICAgIGNhbGxiYWNrKFxuICAgICAgICAgICAgbGluZS50cmltKCksXG4gICAgICAgICAgICAvLyBjcG9zaXRpb25zW3Bvc10gcmVmZXJzIHRvIGFjdHVhbCBmaWxlIG9mZnNldCBvZiBhIGJnemlwIGJsb2NrIGJvdW5kYXJpZXNcbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyB3ZSBtdWx0aXBseSBieSAoMSA8PDgpIGluIG9yZGVyIHRvIG1ha2Ugc3VyZSBlYWNoIGJsb2NrIGhhcyBhIFwidW5pcXVlXCJcbiAgICAgICAgICAgIC8vIGFkZHJlc3Mgc3BhY2Ugc28gdGhhdCBkYXRhIGluIHRoYXQgYmxvY2sgY291bGQgbmV2ZXIgb3ZlcmxhcFxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIHRoZW4gdGhlIGJsb2NrU3RhcnQtZHBvc2l0aW9ucyBpcyBhbiB1bmNvbXByZXNzZWQgZmlsZSBvZmZzZXQgZnJvbVxuICAgICAgICAgICAgLy8gdGhhdCBiZ3ppcCBibG9jayBib3VuZGFyeSwgYW5kIHNpbmNlIHRoZSBjcG9zaXRpb25zIGFyZSBtdWx0aXBsaWVkIGJ5XG4gICAgICAgICAgICAvLyAoMSA8PCA4KSB0aGVzZSB1bmNvbXByZXNzZWQgb2Zmc2V0cyBnZXQgYSB1bmlxdWUgc3BhY2VcbiAgICAgICAgICAgIGNwb3NpdGlvbnNbcG9zXSAqICgxIDw8IDgpICsgKGJsb2NrU3RhcnQgLSBkcG9zaXRpb25zW3Bvc10pLFxuICAgICAgICAgIClcbiAgICAgICAgfSBlbHNlIGlmIChzdGFydENvb3JkaW5hdGUgIT09IHVuZGVmaW5lZCAmJiBzdGFydENvb3JkaW5hdGUgPj0gZW5kKSB7XG4gICAgICAgICAgLy8gdGhlIGxpbmVzIHdlcmUgb3ZlcmxhcHBpbmcgdGhlIHJlZ2lvbiwgYnV0IG5vdyBoYXZlIHN0b3BwZWQsIHNvXG4gICAgICAgICAgLy8gd2UgbXVzdCBiZSBhdCB0aGUgZW5kIG9mIHRoZSByZWxldmFudCBkYXRhIGFuZCB3ZSBjYW4gc3RvcFxuICAgICAgICAgIC8vIHByb2Nlc3NpbmcgZGF0YSBub3dcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBibG9ja1N0YXJ0ICs9IGxpbmUubGVuZ3RoICsgMVxuXG4gICAgICAgIC8vIHlpZWxkIGlmIHdlIGhhdmUgZW1pdHRlZCBiZXlvbmQgdGhlIHlpZWxkIGxpbWl0XG4gICAgICAgIGxpbmVzU2luY2VMYXN0WWllbGQgKz0gMVxuICAgICAgICBpZiAobGluZXNTaW5jZUxhc3RZaWVsZCA+PSB0aGlzLnlpZWxkTGltaXQpIHtcbiAgICAgICAgICBhd2FpdCB0aW1lb3V0KDEpXG4gICAgICAgICAgY2hlY2tBYm9ydFNpZ25hbChzaWduYWwpXG4gICAgICAgICAgbGluZXNTaW5jZUxhc3RZaWVsZCA9IDBcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGdldE1ldGFkYXRhKG9wdHM6IE9wdGlvbnMgPSB7fSkge1xuICAgIHJldHVybiB0aGlzLmluZGV4LmdldE1ldGFkYXRhKG9wdHMpXG4gIH1cblxuICAvKipcbiAgICogZ2V0IGEgYnVmZmVyIGNvbnRhaW5pbmcgdGhlIFwiaGVhZGVyXCIgcmVnaW9uIG9mXG4gICAqIHRoZSBmaWxlLCB3aGljaCBhcmUgdGhlIGJ5dGVzIHVwIHRvIHRoZSBmaXJzdFxuICAgKiBub24tbWV0YSBsaW5lXG4gICAqXG4gICAqIEByZXR1cm5zIHtQcm9taXNlfSBmb3IgYSBidWZmZXJcbiAgICovXG4gIGFzeW5jIGdldEhlYWRlckJ1ZmZlcihvcHRzOiBPcHRpb25zID0ge30pIHtcbiAgICBjb25zdCB7IGZpcnN0RGF0YUxpbmUsIG1ldGFDaGFyLCBtYXhCbG9ja1NpemUgfSA9IGF3YWl0IHRoaXMuZ2V0TWV0YWRhdGEoXG4gICAgICBvcHRzLFxuICAgIClcbiAgICBjaGVja0Fib3J0U2lnbmFsKG9wdHMuc2lnbmFsKVxuICAgIGNvbnN0IG1heEZldGNoID1cbiAgICAgIGZpcnN0RGF0YUxpbmUgJiYgZmlyc3REYXRhTGluZS5ibG9ja1Bvc2l0aW9uXG4gICAgICAgID8gZmlyc3REYXRhTGluZS5ibG9ja1Bvc2l0aW9uICsgbWF4QmxvY2tTaXplXG4gICAgICAgIDogbWF4QmxvY2tTaXplXG4gICAgLy8gVE9ETzogd2hhdCBpZiB3ZSBkb24ndCBoYXZlIGEgZmlyc3REYXRhTGluZSwgYW5kIHRoZSBoZWFkZXJcbiAgICAvLyBhY3R1YWxseSB0YWtlcyB1cCBtb3JlIHRoYW4gb25lIGJsb2NrPyB0aGlzIGNhc2UgaXMgbm90IGNvdmVyZWQgaGVyZVxuXG4gICAgbGV0IGJ5dGVzID0gYXdhaXQgdGhpcy5fcmVhZFJlZ2lvbigwLCBtYXhGZXRjaCwgb3B0cylcbiAgICBjaGVja0Fib3J0U2lnbmFsKG9wdHMuc2lnbmFsKVxuICAgIHRyeSB7XG4gICAgICBieXRlcyA9IGF3YWl0IHVuemlwKGJ5dGVzKVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoZSlcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYGVycm9yIGRlY29tcHJlc3NpbmcgYmxvY2sgJHtlLmNvZGV9IGF0IDAgKGxlbmd0aCAke21heEZldGNofSkgJHtlfWAsXG4gICAgICApXG4gICAgfVxuXG4gICAgLy8gdHJpbSBvZmYgbGluZXMgYWZ0ZXIgdGhlIGxhc3Qgbm9uLW1ldGEgbGluZVxuICAgIGlmIChtZXRhQ2hhcikge1xuICAgICAgLy8gdHJpbSBiYWNrd2FyZCBmcm9tIHRoZSBlbmRcbiAgICAgIGxldCBsYXN0TmV3bGluZSA9IC0xXG4gICAgICBjb25zdCBuZXdsaW5lQnl0ZSA9ICdcXG4nLmNoYXJDb2RlQXQoMClcbiAgICAgIGNvbnN0IG1ldGFCeXRlID0gbWV0YUNoYXIuY2hhckNvZGVBdCgwKVxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBieXRlcy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICBpZiAoaSA9PT0gbGFzdE5ld2xpbmUgKyAxICYmIGJ5dGVzW2ldICE9PSBtZXRhQnl0ZSkgYnJlYWtcbiAgICAgICAgaWYgKGJ5dGVzW2ldID09PSBuZXdsaW5lQnl0ZSkgbGFzdE5ld2xpbmUgPSBpXG4gICAgICB9XG4gICAgICBieXRlcyA9IGJ5dGVzLnNsaWNlKDAsIGxhc3ROZXdsaW5lICsgMSlcbiAgICB9XG4gICAgcmV0dXJuIGJ5dGVzXG4gIH1cblxuICAvKipcbiAgICogZ2V0IGEgc3RyaW5nIGNvbnRhaW5pbmcgdGhlIFwiaGVhZGVyXCIgcmVnaW9uIG9mIHRoZVxuICAgKiBmaWxlLCBpcyB0aGUgcG9ydGlvbiB1cCB0byB0aGUgZmlyc3Qgbm9uLW1ldGEgbGluZVxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gZm9yIGEgc3RyaW5nXG4gICAqL1xuICBhc3luYyBnZXRIZWFkZXIob3B0czogT3B0aW9ucyA9IHt9KSB7XG4gICAgY29uc3QgYnl0ZXMgPSBhd2FpdCB0aGlzLmdldEhlYWRlckJ1ZmZlcihvcHRzKVxuICAgIGNoZWNrQWJvcnRTaWduYWwob3B0cy5zaWduYWwpXG4gICAgcmV0dXJuIGJ5dGVzLnRvU3RyaW5nKCd1dGY4JylcbiAgfVxuXG4gIC8qKlxuICAgKiBnZXQgYW4gYXJyYXkgb2YgcmVmZXJlbmNlIHNlcXVlbmNlIG5hbWVzLCBpbiB0aGUgb3JkZXIgaW4gd2hpY2hcbiAgICogdGhleSBvY2N1ciBpbiB0aGUgZmlsZS5cbiAgICpcbiAgICogcmVmZXJlbmNlIHNlcXVlbmNlIHJlbmFtaW5nIGlzIG5vdCBhcHBsaWVkIHRvIHRoZXNlIG5hbWVzLlxuICAgKlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gZm9yIGFuIGFycmF5IG9mIHN0cmluZyBzZXF1ZW5jZSBuYW1lc1xuICAgKi9cbiAgYXN5bmMgZ2V0UmVmZXJlbmNlU2VxdWVuY2VOYW1lcyhvcHRzOiBPcHRpb25zID0ge30pIHtcbiAgICBjb25zdCBtZXRhZGF0YSA9IGF3YWl0IHRoaXMuZ2V0TWV0YWRhdGEob3B0cylcbiAgICByZXR1cm4gbWV0YWRhdGEucmVmSWRUb05hbWVcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge29iamVjdH0gbWV0YWRhdGEgbWV0YWRhdGEgb2JqZWN0IGZyb20gdGhlIHBhcnNlZCBpbmRleCxcbiAgICogY29udGFpbmluZyBjb2x1bW5OdW1iZXJzLCBtZXRhQ2hhciwgYW5kIGZvcm1hdFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVnaW9uUmVmTmFtZVxuICAgKiBAcGFyYW0ge251bWJlcn0gcmVnaW9uU3RhcnQgcmVnaW9uIHN0YXJ0IGNvb3JkaW5hdGUgKDAtYmFzZWQtaGFsZi1vcGVuKVxuICAgKiBAcGFyYW0ge251bWJlcn0gcmVnaW9uRW5kIHJlZ2lvbiBlbmQgY29vcmRpbmF0ZSAoMC1iYXNlZC1oYWxmLW9wZW4pXG4gICAqIEBwYXJhbSB7YXJyYXlbc3RyaW5nXX0gbGluZVxuICAgKiBAcmV0dXJucyB7b2JqZWN0fSBsaWtlIGB7c3RhcnRDb29yZGluYXRlLCBvdmVybGFwc31gLiBvdmVybGFwcyBpcyBib29sZWFuLFxuICAgKiB0cnVlIGlmIGxpbmUgaXMgYSBkYXRhIGxpbmUgdGhhdCBvdmVybGFwcyB0aGUgZ2l2ZW4gcmVnaW9uXG4gICAqL1xuICBjaGVja0xpbmUoXG4gICAge1xuICAgICAgY29sdW1uTnVtYmVycyxcbiAgICAgIG1ldGFDaGFyLFxuICAgICAgY29vcmRpbmF0ZVR5cGUsXG4gICAgICBmb3JtYXQsXG4gICAgfToge1xuICAgICAgY29sdW1uTnVtYmVyczogeyByZWY6IG51bWJlcjsgc3RhcnQ6IG51bWJlcjsgZW5kOiBudW1iZXIgfVxuICAgICAgbWV0YUNoYXI6IHN0cmluZ1xuICAgICAgY29vcmRpbmF0ZVR5cGU6IHN0cmluZ1xuICAgICAgZm9ybWF0OiBzdHJpbmdcbiAgICB9LFxuICAgIHJlZ2lvblJlZk5hbWU6IHN0cmluZyxcbiAgICByZWdpb25TdGFydDogbnVtYmVyLFxuICAgIHJlZ2lvbkVuZDogbnVtYmVyLFxuICAgIGxpbmU6IHN0cmluZyxcbiAgKSB7XG4gICAgLy8gc2tpcCBtZXRhIGxpbmVzXG4gICAgaWYgKGxpbmUuY2hhckF0KDApID09PSBtZXRhQ2hhcikge1xuICAgICAgcmV0dXJuIHsgb3ZlcmxhcHM6IGZhbHNlIH1cbiAgICB9XG5cbiAgICAvLyBjaGVjayByZWYvc3RhcnQvZW5kIHVzaW5nIGNvbHVtbiBtZXRhZGF0YSBmcm9tIGluZGV4XG4gICAgbGV0IHsgcmVmLCBzdGFydCwgZW5kIH0gPSBjb2x1bW5OdW1iZXJzXG4gICAgaWYgKCFyZWYpIHJlZiA9IDBcbiAgICBpZiAoIXN0YXJ0KSBzdGFydCA9IDBcbiAgICBpZiAoIWVuZCkgZW5kID0gMFxuICAgIGlmIChmb3JtYXQgPT09ICdWQ0YnKSBlbmQgPSA4XG4gICAgY29uc3QgbWF4Q29sdW1uID0gTWF0aC5tYXgocmVmLCBzdGFydCwgZW5kKVxuXG4gICAgLy8gdGhpcyBjb2RlIGlzIGtpbmQgb2YgY29tcGxleCwgYnV0IGl0IGlzIGZhaXJseSBmYXN0LlxuICAgIC8vIGJhc2ljYWxseSwgd2Ugd2FudCB0byBhdm9pZCBkb2luZyBhIHNwbGl0LCBiZWNhdXNlIGlmIHRoZSBsaW5lcyBhcmUgcmVhbGx5IGxvbmdcbiAgICAvLyB0aGF0IGNvdWxkIGxlYWQgdG8gdXMgYWxsb2NhdGluZyBhIGJ1bmNoIG9mIGV4dHJhIG1lbW9yeSwgd2hpY2ggaXMgc2xvd1xuXG4gICAgbGV0IGN1cnJlbnRDb2x1bW5OdW1iZXIgPSAxIC8vIGNvbHMgYXJlIG51bWJlcmVkIHN0YXJ0aW5nIGF0IDEgaW4gdGhlIGluZGV4IG1ldGFkYXRhXG4gICAgbGV0IGN1cnJlbnRDb2x1bW5TdGFydCA9IDBcbiAgICBsZXQgcmVmU2VxID0gJydcbiAgICBsZXQgc3RhcnRDb29yZGluYXRlID0gLUluZmluaXR5XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaW5lLmxlbmd0aCArIDE7IGkgKz0gMSkge1xuICAgICAgaWYgKGxpbmVbaV0gPT09ICdcXHQnIHx8IGkgPT09IGxpbmUubGVuZ3RoKSB7XG4gICAgICAgIGlmIChjdXJyZW50Q29sdW1uTnVtYmVyID09PSByZWYpIHtcbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICB0aGlzLnJlbmFtZVJlZlNlcShsaW5lLnNsaWNlKGN1cnJlbnRDb2x1bW5TdGFydCwgaSkpICE9PVxuICAgICAgICAgICAgcmVnaW9uUmVmTmFtZVxuICAgICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuIHsgb3ZlcmxhcHM6IGZhbHNlIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoY3VycmVudENvbHVtbk51bWJlciA9PT0gc3RhcnQpIHtcbiAgICAgICAgICBzdGFydENvb3JkaW5hdGUgPSBwYXJzZUludChsaW5lLnNsaWNlKGN1cnJlbnRDb2x1bW5TdGFydCwgaSksIDEwKVxuICAgICAgICAgIC8vIHdlIGNvbnZlcnQgdG8gMC1iYXNlZC1oYWxmLW9wZW5cbiAgICAgICAgICBpZiAoY29vcmRpbmF0ZVR5cGUgPT09ICcxLWJhc2VkLWNsb3NlZCcpIHtcbiAgICAgICAgICAgIHN0YXJ0Q29vcmRpbmF0ZSAtPSAxXG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChzdGFydENvb3JkaW5hdGUgPj0gcmVnaW9uRW5kKSB7XG4gICAgICAgICAgICByZXR1cm4geyBzdGFydENvb3JkaW5hdGUsIG92ZXJsYXBzOiBmYWxzZSB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChlbmQgPT09IDAgfHwgZW5kID09PSBzdGFydCkge1xuICAgICAgICAgICAgLy8gaWYgd2UgaGF2ZSBubyBlbmQsIHdlIGFzc3VtZSB0aGUgZmVhdHVyZSBpcyAxIGJwIGxvbmdcbiAgICAgICAgICAgIGlmIChzdGFydENvb3JkaW5hdGUgKyAxIDw9IHJlZ2lvblN0YXJ0KSB7XG4gICAgICAgICAgICAgIHJldHVybiB7IHN0YXJ0Q29vcmRpbmF0ZSwgb3ZlcmxhcHM6IGZhbHNlIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZm9ybWF0ID09PSAnVkNGJyAmJiBjdXJyZW50Q29sdW1uTnVtYmVyID09PSA0KSB7XG4gICAgICAgICAgcmVmU2VxID0gbGluZS5zbGljZShjdXJyZW50Q29sdW1uU3RhcnQsIGkpXG4gICAgICAgIH0gZWxzZSBpZiAoY3VycmVudENvbHVtbk51bWJlciA9PT0gZW5kKSB7XG4gICAgICAgICAgbGV0IGVuZENvb3JkaW5hdGVcbiAgICAgICAgICAvLyB0aGlzIHdpbGwgbmV2ZXIgbWF0Y2ggaWYgdGhlcmUgaXMgbm8gZW5kIGNvbHVtblxuICAgICAgICAgIGlmIChmb3JtYXQgPT09ICdWQ0YnKSB7XG4gICAgICAgICAgICBlbmRDb29yZGluYXRlID0gdGhpcy5fZ2V0VmNmRW5kKFxuICAgICAgICAgICAgICBzdGFydENvb3JkaW5hdGUsXG4gICAgICAgICAgICAgIHJlZlNlcSxcbiAgICAgICAgICAgICAgbGluZS5zbGljZShjdXJyZW50Q29sdW1uU3RhcnQsIGkpLFxuICAgICAgICAgICAgKVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBlbmRDb29yZGluYXRlID0gcGFyc2VJbnQobGluZS5zbGljZShjdXJyZW50Q29sdW1uU3RhcnQsIGkpLCAxMClcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGVuZENvb3JkaW5hdGUgPD0gcmVnaW9uU3RhcnQpIHtcbiAgICAgICAgICAgIHJldHVybiB7IG92ZXJsYXBzOiBmYWxzZSB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGN1cnJlbnRDb2x1bW5TdGFydCA9IGkgKyAxXG4gICAgICAgIGN1cnJlbnRDb2x1bW5OdW1iZXIgKz0gMVxuICAgICAgICBpZiAoY3VycmVudENvbHVtbk51bWJlciA+IG1heENvbHVtbikge1xuICAgICAgICAgIGJyZWFrXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHsgc3RhcnRDb29yZGluYXRlLCBvdmVybGFwczogdHJ1ZSB9XG4gIH1cblxuICBfZ2V0VmNmRW5kKHN0YXJ0Q29vcmRpbmF0ZTogbnVtYmVyLCByZWZTZXE6IHN0cmluZywgaW5mbzogYW55KSB7XG4gICAgbGV0IGVuZENvb3JkaW5hdGUgPSBzdGFydENvb3JkaW5hdGUgKyByZWZTZXEubGVuZ3RoXG4gICAgLy8gaWdub3JlIFRSQSBmZWF0dXJlcyBhcyB0aGV5IHNwZWNpZnkgQ0hSMiBhbmQgRU5EXG4gICAgLy8gYXMgYmVpbmcgb24gYSBkaWZmZXJlbnQgY2hyb21vc29tZVxuICAgIC8vIGlmIENIUjIgaXMgb24gdGhlIHNhbWUgY2hyb21vc29tZSwgc3RpbGwgaWdub3JlIGl0XG4gICAgLy8gYmVjYXVzZSB0aGVyZSBzaG91bGQgYmUgYW5vdGhlciBwYWlyd2lzZSBmZWF0dXJlXG4gICAgLy8gYXQgdGhlIGVuZCBvZiB0aGlzIG9uZVxuICAgIGNvbnN0IGlzVFJBID0gaW5mby5pbmRleE9mKCdTVlRZUEU9VFJBJykgIT09IC0xXG4gICAgaWYgKGluZm9bMF0gIT09ICcuJyAmJiAhaXNUUkEpIHtcbiAgICAgIGxldCBwcmV2Q2hhciA9ICc7J1xuICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCBpbmZvLmxlbmd0aDsgaiArPSAxKSB7XG4gICAgICAgIGlmIChwcmV2Q2hhciA9PT0gJzsnICYmIGluZm8uc2xpY2UoaiwgaiArIDQpID09PSAnRU5EPScpIHtcbiAgICAgICAgICBsZXQgdmFsdWVFbmQgPSBpbmZvLmluZGV4T2YoJzsnLCBqKVxuICAgICAgICAgIGlmICh2YWx1ZUVuZCA9PT0gLTEpIHZhbHVlRW5kID0gaW5mby5sZW5ndGhcbiAgICAgICAgICBlbmRDb29yZGluYXRlID0gcGFyc2VJbnQoaW5mby5zbGljZShqICsgNCwgdmFsdWVFbmQpLCAxMClcbiAgICAgICAgICBicmVha1xuICAgICAgICB9XG4gICAgICAgIHByZXZDaGFyID0gaW5mb1tqXVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoaXNUUkEpIHtcbiAgICAgIHJldHVybiBzdGFydENvb3JkaW5hdGUgKyAxXG4gICAgfVxuICAgIHJldHVybiBlbmRDb29yZGluYXRlXG4gIH1cblxuICAvKipcbiAgICogcmV0dXJuIHRoZSBhcHByb3hpbWF0ZSBudW1iZXIgb2YgZGF0YSBsaW5lcyBpbiB0aGUgZ2l2ZW4gcmVmZXJlbmNlIHNlcXVlbmNlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWZTZXEgcmVmZXJlbmNlIHNlcXVlbmNlIG5hbWVcbiAgICogQHJldHVybnMge1Byb21pc2V9IGZvciBudW1iZXIgb2YgZGF0YSBsaW5lcyBwcmVzZW50IG9uIHRoYXQgcmVmZXJlbmNlIHNlcXVlbmNlXG4gICAqL1xuICBhc3luYyBsaW5lQ291bnQocmVmTmFtZTogc3RyaW5nLCBvcHRzOiBPcHRpb25zID0ge30pIHtcbiAgICByZXR1cm4gdGhpcy5pbmRleC5saW5lQ291bnQocmVmTmFtZSwgb3B0cylcbiAgfVxuXG4gIGFzeW5jIF9yZWFkUmVnaW9uKFxuICAgIHBvc2l0aW9uOiBudW1iZXIsXG4gICAgY29tcHJlc3NlZFNpemU6IG51bWJlcixcbiAgICBvcHRzOiBPcHRpb25zID0ge30sXG4gICkge1xuICAgIGNvbnN0IHsgYnVmZmVyIH0gPSBhd2FpdCB0aGlzLmZpbGVoYW5kbGUucmVhZChcbiAgICAgIEJ1ZmZlci5hbGxvYyhjb21wcmVzc2VkU2l6ZSksXG4gICAgICAwLFxuICAgICAgY29tcHJlc3NlZFNpemUsXG4gICAgICBwb3NpdGlvbixcbiAgICAgIG9wdHMsXG4gICAgKVxuXG4gICAgcmV0dXJuIGJ1ZmZlclxuICB9XG5cbiAgLyoqXG4gICAqIHJlYWQgYW5kIHVuY29tcHJlc3MgdGhlIGRhdGEgaW4gYSBjaHVuayAoY29tcG9zZWQgb2Ygb25lIG9yIG1vcmVcbiAgICogY29udGlndW91cyBiZ3ppcCBibG9ja3MpIG9mIHRoZSBmaWxlXG4gICAqIEBwYXJhbSB7Q2h1bmt9IGNodW5rXG4gICAqIEByZXR1cm5zIHtQcm9taXNlfSBmb3IgYSBzdHJpbmcgY2h1bmsgb2YgdGhlIGZpbGVcbiAgICovXG4gIGFzeW5jIHJlYWRDaHVuayhjaHVuazogQ2h1bmssIG9wdHM6IE9wdGlvbnMgPSB7fSkge1xuICAgIC8vIGZldGNoIHRoZSB1bmNvbXByZXNzZWQgZGF0YSwgdW5jb21wcmVzcyBjYXJlZnVsbHkgYSBibG9jayBhdCBhIHRpbWUsXG4gICAgLy8gYW5kIHN0b3Agd2hlbiBkb25lXG5cbiAgICBjb25zdCBjb21wcmVzc2VkRGF0YSA9IGF3YWl0IHRoaXMuX3JlYWRSZWdpb24oXG4gICAgICBjaHVuay5taW52LmJsb2NrUG9zaXRpb24sXG4gICAgICBjaHVuay5mZXRjaGVkU2l6ZSgpLFxuICAgICAgb3B0cyxcbiAgICApXG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiB1bnppcENodW5rU2xpY2UoY29tcHJlc3NlZERhdGEsIGNodW5rKVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgZXJyb3IgZGVjb21wcmVzc2luZyBjaHVuayAke2NodW5rLnRvU3RyaW5nKCl9ICR7ZX1gKVxuICAgIH1cbiAgfVxufVxuIl19