UNPKG

mix-async-generator

Version:

``` npm i mix-async-generator ```

225 lines 28.9 kB
import { Evt } from "evt"; import { safePromiseThen, PromiseOut } from "@bfchain/util-extends-promise"; import { FastQuene } from "./FastQuene"; const DONE = Promise.resolve({ step: { value: undefined, done: true }, }); export class MixAsyncGenerator { constructor() { this._allGenList = new FastQuene(); /**正在执行中的任务,等待返回后就从这个集合中移除 */ this._runnings = new Map(); /**候补队列 */ this._benchGen = new FastQuene(); /**自由队列 */ this._freeGen = new FastQuene(); this._genWaitter = new FastQuene(); // private _traceCount = 0; this._freeResult = new FastQuene(); this._benchResult = new FastQuene(); this._resultWaiter = new FastQuene(); this.onError = new Evt(); } join(runner, opts) { let bench = false; let jumpGun; let name = `gen-${this._allGenList.size + 1}`; if (opts !== undefined) { opts.name !== undefined && (name = opts.name); opts.bench !== undefined && (bench = opts.bench); jumpGun = opts.jumpGun; } if (jumpGun === undefined) { jumpGun = bench ? 1 : 1; /**非惰性元素至少抢跑1步 */ } if (bench === false && jumpGun < 1) { throw new RangeError("when runner no in bench, jump gun should not be 0"); } return this._join({ runner, name, bench, jumpGun, currentStep: undefined, inQueueSteps: 0, }); } _join(gen) { this._allGenList.push(gen); /// 否则保存到惰性列表中,需要时再使用 if (gen.bench) { this._benchGen.push(gen); } /// 如果是非惰性的,那么直接启动迭代 else { this._handleGen(gen); } return gen; } remove(gen) { if (this._allGenList.remove(gen)) { /// 如果全部归空了,那么将其余在等待中的都关闭掉 if (this._allGenList.size === 0) { do { const waiter = this._resultWaiter.shift(); if (waiter === undefined) { break; } waiter.resolve(DONE); } while (true); } return true; } return false; } _enqueueGen(gen) { // 是否有在等待中的 const waiter = this._genWaitter.shift(); if (waiter) { waiter.resolve(gen); } /// 如果是惰性元素,那么回到惰性队列 else if (gen.bench) { this._benchGen.push(gen); } /// 如果是非惰性元素,那么回到自由队列 else { this._freeGen.push(gen); } } async _dequeueGen() { // 获取一个可用的迭代器 const gen = this._freeGen.shift() || this._benchGen.shift() || (await this._genWaitter.push(new PromiseOut()).promise); this._handleGen(gen); } _handleGen(gen) { const item = gen.runner.next(); this._runnings.set(item, gen); // 如果完成,则回到自由队列 safePromiseThen(item, (value) => { this._runnings.delete(item); // 缓存当前结果 gen.currentStep = value; /// 如果已经完结了,那么直接移除掉了 if (value.done) { this.remove(gen); /// 如果没有任何在执行中的元素,就需要继续从队列中读取出来执行,否则外面的Promise就永远无法resolve if (this._runnings.size === 0) { this._dequeueGen(); } } /// 否则回到队列中继续提供下一个迭代 else { // 传递到结果队列中 this._enqueueResult({ from: gen, step: value }); /// 如果可以偷跑,那么继续执行 if (gen.inQueueSteps < gen.jumpGun) { this._handleGen(gen); } else { // 回到空闲队列中 this._enqueueGen(gen); } } }, (reason) => { this._runnings.delete(item); // 如果已经出错,那么直接移除 this.remove(gen); // 向外传递错误 this.onError.post({ from: gen, reason }); }); } /**入列 * 这个函数与_handleGen是紧密关联的,是_handleGen的一部分 */ _enqueueResult(result) { /// 是否有在等待中的 const waiter = this._resultWaiter.shift(); if (waiter !== undefined) { /** * 因为本就是要直接返回的,所以这里直接将步数减去 * * Waiter模式不需要修改inQueueSteps,因为是预约的,直接返回 */ waiter.resolve(result); } else { result.from.bench ? this._benchResult.push(result) : this._freeResult.push(result); result.from.inQueueSteps += 1; } } /**出列 */ _dequeueResult() { /// 再从结果队列中读取 const resultWithFrom1 = this._freeResult.shift(); if (resultWithFrom1 !== undefined) { const gen = resultWithFrom1.from; gen.inQueueSteps -= 1; if (this._freeGen.remove(gen)) { this._handleGen(gen); } return resultWithFrom1; } const resultWithFrom2 = this._benchResult.shift(); if (resultWithFrom2 !== undefined) { const gen = resultWithFrom2.from; gen.inQueueSteps -= 1; if (this._benchGen.remove(gen)) { this._handleGen(gen); } /** * @TODO 使用了候补元素,那么就要对元素尽快进行补充 */ return resultWithFrom2; } // 否则排队进行等待,Waiter模式不需要修改inQueueSteps,因为是预约的,直接返回 const resultPromise = this._resultWaiter.push(new PromiseOut()).promise; /// 必要时,让选手出列 if ( // 如果没有任何一个在运行中的任务:那么立刻执行 this._runnings.size === 0 || // 如果自由队列为空,但是候补队列有存在的:那么也立刻执行 (this._freeGen.size === 0 && this._benchGen.size !== 0)) { this._dequeueGen(); } // console.log(++this._traceCount); // if (this._traceCount === 2) { // debugger; // } return resultPromise; } next() { if (this.isDone) { return DONE; } return this._dequeueResult(); } get isDone() { return ( /* _allGenList为空也就意味着_running为空 */ this._allGenList.size === 0 && this._freeResult.size === 0 && this._benchResult.size === 0); } async *toAsyncIterator() { while (true) { const result = await this.next(); if (result.step.done) { return; } yield result.step.value; } } async toPromise() { while (true) { const result = await this.next(); if (result.step.done) { return; } } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWl4QXN5bmNHZW5lcmF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvTWl4QXN5bmNHZW5lcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUMxQixPQUFPLEVBQUUsZUFBZSxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzVFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUF1Q3hDLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUM7SUFDM0IsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsSUFBYSxFQUFFO0NBQ2hELENBQUMsQ0FBQztBQUVILE1BQU0sT0FBTyxpQkFBaUI7SUFBOUI7UUFHVSxnQkFBVyxHQUFHLElBQUksU0FBUyxFQUE0QixDQUFDO1FBZ0ZoRSw2QkFBNkI7UUFDckIsY0FBUyxHQUFHLElBQUksR0FBRyxFQUd4QixDQUFDO1FBNENKLFVBQVU7UUFDRixjQUFTLEdBQUcsSUFBSSxTQUFTLEVBQWtDLENBQUM7UUFDcEUsVUFBVTtRQUNGLGFBQVEsR0FBRyxJQUFJLFNBQVMsRUFBbUMsQ0FBQztRQUM1RCxnQkFBVyxHQUFHLElBQUksU0FBUyxFQUF3QyxDQUFDO1FBb0U1RSwyQkFBMkI7UUFDbkIsZ0JBQVcsR0FBRyxJQUFJLFNBQVMsRUFFaEMsQ0FBQztRQUNJLGlCQUFZLEdBQUcsSUFBSSxTQUFTLEVBRWpDLENBQUM7UUFDSSxrQkFBYSxHQUFHLElBQUksU0FBUyxFQUVsQyxDQUFDO1FBQ0ssWUFBTyxHQUFHLElBQUksR0FBRyxFQUE4QixDQUFDO0lBK0IzRCxDQUFDO0lBaFBDLElBQUksQ0FDRixNQUF3QyxFQUN4QyxJQUEyRDtRQUUzRCxJQUFJLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbEIsSUFBSSxPQUEyQixDQUFDO1FBQ2hDLElBQUks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QyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksS0FBSyxDQUFDO1lBQzlELElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxLQUFLLENBQUM7WUFDM0IsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLEtBQUssQ0FBQyxDQUM3QixDQUFDO0lBQ0osQ0FBQztJQUNELEtBQUssQ0FBQyxDQUFDLGVBQWU7UUFDcEIsT0FBTyxJQUFJLEVBQUU7WUFDWCxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNqQyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFO2dCQUNwQixPQUFPO2FBQ1I7WUFDRCxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDO1NBQ3pCO0lBQ0gsQ0FBQztJQUNELEtBQUssQ0FBQyxTQUFTO1FBQ2IsT0FBTyxJQUFJLEVBQUU7WUFDWCxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNqQyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFO2dCQUNwQixPQUFPO2FBQ1I7U0FDRjtJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEV2dCB9IGZyb20gXCJldnRcIjtcclxuaW1wb3J0IHsgc2FmZVByb21pc2VUaGVuLCBQcm9taXNlT3V0IH0gZnJvbSBcIkBiZmNoYWluL3V0aWwtZXh0ZW5kcy1wcm9taXNlXCI7XHJcbmltcG9ydCB7IEZhc3RRdWVuZSB9IGZyb20gXCIuL0Zhc3RRdWVuZVwiO1xyXG5cclxuZXhwb3J0IGRlY2xhcmUgbmFtZXNwYWNlIE1peEFzeW5jR2VuZXJhdG9yIHtcclxuICB0eXBlIEFHPE5leHRPdXQgPSB1bmtub3duLCBSZXR1cm4gPSB1bmtub3duLCBOZXh0SW4gPSB1bmtub3duPiA9IFtcclxuICAgIE5leHRPdXQsXHJcbiAgICBSZXR1cm4sXHJcbiAgICBOZXh0SW5cclxuICBdO1xyXG4gIHR5cGUgR2VuPFQgZXh0ZW5kcyBBRywgQiBleHRlbmRzIGJvb2xlYW4gPSBib29sZWFuPiA9IHtcclxuICAgIG5hbWU6IHN0cmluZztcclxuICAgIHJ1bm5lcjogQXN5bmNHZW5lcmF0b3I8VFswXSwgVFsxXSwgVFsyXT47XHJcbiAgICAvKirmm7/ooaXlhYPntKAv5oOw5oCn5YWD57SgXHJcbiAgICAgKiDmhI/lkbPnnYDlj6rmnInliLDkuI3lvpfkuI3nlKjnmoTml7blgJnmiY3kvJrljrvkvb/nlKhcclxuICAgICAqL1xyXG4gICAgYmVuY2g6IEI7XHJcbiAgICAvKirlvZPliY3nmoTmraXkvJAgKi9cclxuICAgIGN1cnJlbnRTdGVwOiBJdGVyYXRvclJlc3VsdDxUWzBdLCBUWzFdPiB8IHVuZGVmaW5lZDtcclxuICAgIC8qKuWBt+i3keeahOatpeaVsO+8jOm7mOiupOaYrzBcclxuICAgICAqIOWBt+i3keaEj+WRs+edgOWug+Wni+e7iOS8muWKquWKm+aPkOS+m2p1bXBHdW7kuKpyZXN1bHRcclxuICAgICAqIOabv+ihpeWFg+e0oOS5n+WPr+S7peWBt+i3ke+8jOS9huWPquaciei9ruWIsOWug+S4iuWcuuaJjeiDveWBt+i3kVxyXG4gICAgICovXHJcbiAgICBqdW1wR3VuOiBudW1iZXI7XHJcbiAgICAvKirnvJPlrZjlnKjpmJ/liJfkuK3nmoTmraXkvJDmlbAgKi9cclxuICAgIGluUXVldWVTdGVwczogbnVtYmVyO1xyXG4gIH07XHJcbiAgdHlwZSBSZXN1bHQ8VCBleHRlbmRzIEFHPiA9IHtcclxuICAgIHN0ZXA6IEl0ZXJhdG9yUmVzdWx0PFRbMF0sIFRbMV0+O1xyXG4gICAgZnJvbT86IEdlbjxUPjtcclxuICB9O1xyXG4gIHR5cGUgUmVzdWx0V2l0aEZyb208VCBleHRlbmRzIEFHLCBCIGV4dGVuZHMgYm9vbGVhbiA9IGJvb2xlYW4+ID0ge1xyXG4gICAgc3RlcDogSXRlcmF0b3JSZXN1bHQ8VFswXSwgVFsxXT47XHJcbiAgICBmcm9tOiBHZW48VCwgQj47XHJcbiAgfTtcclxuICB0eXBlIEVycm9yPFQgZXh0ZW5kcyBBRz4gPSB7XHJcbiAgICBmcm9tOiBHZW48VD47XHJcbiAgICByZWFzb246IHVua25vd247XHJcbiAgfTtcclxufVxyXG5cclxuY29uc3QgRE9ORSA9IFByb21pc2UucmVzb2x2ZSh7XHJcbiAgc3RlcDogeyB2YWx1ZTogdW5kZWZpbmVkLCBkb25lOiB0cnVlIGFzIGNvbnN0IH0sXHJcbn0pO1xyXG5cclxuZXhwb3J0IGNsYXNzIE1peEFzeW5jR2VuZXJhdG9yPFxyXG4gIFQgZXh0ZW5kcyBNaXhBc3luY0dlbmVyYXRvci5BRyA9IE1peEFzeW5jR2VuZXJhdG9yLkFHXHJcbj4ge1xyXG4gIHByaXZhdGUgX2FsbEdlbkxpc3QgPSBuZXcgRmFzdFF1ZW5lPE1peEFzeW5jR2VuZXJhdG9yLkdlbjxUPj4oKTtcclxuICBqb2luKFxyXG4gICAgcnVubmVyOiBBc3luY0dlbmVyYXRvcjxUWzBdLCBUWzFdLCBUWzJdPixcclxuICAgIG9wdHM/OiB7IG5hbWU/OiBzdHJpbmc7IGJlbmNoPzogYm9vbGVhbjsganVtcEd1bj86IG51bWJlciB9XHJcbiAgKSB7XHJcbiAgICBsZXQgYmVuY2ggPSBmYWxzZTtcclxuICAgIGxldCBqdW1wR3VuOiBudW1iZXIgfCB1bmRlZmluZWQ7XHJcbiAgICBsZXQgbmFtZSA9IGBnZW4tJHt0aGlzLl9hbGxHZW5MaXN0LnNpemUgKyAxfWA7XHJcbiAgICBpZiAob3B0cyAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgIG9wdHMubmFtZSAhPT0gdW5kZWZpbmVkICYmIChuYW1lID0gb3B0cy5uYW1lKTtcclxuICAgICAgb3B0cy5iZW5jaCAhPT0gdW5kZWZpbmVkICYmIChiZW5jaCA9IG9wdHMuYmVuY2gpO1xyXG4gICAgICBqdW1wR3VuID0gb3B0cy5qdW1wR3VuO1xyXG4gICAgfVxyXG4gICAgaWYgKGp1bXBHdW4gPT09IHVuZGVmaW5lZCkge1xyXG4gICAgICBqdW1wR3VuID0gYmVuY2ggPyAxIDogMTsgLyoq6Z2e5oOw5oCn5YWD57Sg6Iez5bCR5oqi6LeRMeatpSAqL1xyXG4gICAgfVxyXG4gICAgaWYgKGJlbmNoID09PSBmYWxzZSAmJiBqdW1wR3VuIDwgMSkge1xyXG4gICAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcihcIndoZW4gcnVubmVyIG5vIGluIGJlbmNoLCBqdW1wIGd1biBzaG91bGQgbm90IGJlIDBcIik7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXMuX2pvaW4oe1xyXG4gICAgICBydW5uZXIsXHJcbiAgICAgIG5hbWUsXHJcbiAgICAgIGJlbmNoLFxyXG4gICAgICBqdW1wR3VuLFxyXG4gICAgICBjdXJyZW50U3RlcDogdW5kZWZpbmVkLFxyXG4gICAgICBpblF1ZXVlU3RlcHM6IDAsXHJcbiAgICB9KTtcclxuICB9XHJcbiAgcHJpdmF0ZSBfam9pbihnZW46IE1peEFzeW5jR2VuZXJhdG9yLkdlbjxUPikge1xyXG4gICAgdGhpcy5fYWxsR2VuTGlzdC5wdXNoKGdlbik7XHJcbiAgICAvLy8g5ZCm5YiZ5L+d5a2Y5Yiw5oOw5oCn5YiX6KGo5Lit77yM6ZyA6KaB5pe25YaN5L2/55SoXHJcbiAgICBpZiAoZ2VuLmJlbmNoKSB7XHJcbiAgICAgIHRoaXMuX2JlbmNoR2VuLnB1c2goZ2VuIGFzIE1peEFzeW5jR2VuZXJhdG9yLkdlbjxULCB0cnVlPik7XHJcbiAgICB9XHJcbiAgICAvLy8g5aaC5p6c5piv6Z2e5oOw5oCn55qE77yM6YKj5LmI55u05o6l5ZCv5Yqo6L+t5LujXHJcbiAgICBlbHNlIHtcclxuICAgICAgdGhpcy5faGFuZGxlR2VuKGdlbik7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gZ2VuO1xyXG4gIH1cclxuICByZW1vdmUoZ2VuOiBNaXhBc3luY0dlbmVyYXRvci5HZW48VD4pIHtcclxuICAgIGlmICh0aGlzLl9hbGxHZW5MaXN0LnJlbW92ZShnZW4pKSB7XHJcbiAgICAgIC8vLyDlpoLmnpzlhajpg6jlvZLnqbrkuobvvIzpgqPkuYjlsIblhbbkvZnlnKjnrYnlvoXkuK3nmoTpg73lhbPpl63mjolcclxuICAgICAgaWYgKHRoaXMuX2FsbEdlbkxpc3Quc2l6ZSA9PT0gMCkge1xyXG4gICAgICAgIGRvIHtcclxuICAgICAgICAgIGNvbnN0IHdhaXRlciA9IHRoaXMuX3Jlc3VsdFdhaXRlci5zaGlmdCgpO1xyXG4gICAgICAgICAgaWYgKHdhaXRlciA9PT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgd2FpdGVyLnJlc29sdmUoRE9ORSk7XHJcbiAgICAgICAgfSB3aGlsZSAodHJ1ZSk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG4gIHByaXZhdGUgX2VucXVldWVHZW4oZ2VuOiBNaXhBc3luY0dlbmVyYXRvci5HZW48VD4pIHtcclxuICAgIC8vIOaYr+WQpuacieWcqOetieW+heS4reeahFxyXG4gICAgY29uc3Qgd2FpdGVyID0gdGhpcy5fZ2VuV2FpdHRlci5zaGlmdCgpO1xyXG4gICAgaWYgKHdhaXRlcikge1xyXG4gICAgICB3YWl0ZXIucmVzb2x2ZShnZW4pO1xyXG4gICAgfVxyXG4gICAgLy8vIOWmguaenOaYr+aDsOaAp+WFg+e0oO+8jOmCo+S5iOWbnuWIsOaDsOaAp+mYn+WIl1xyXG4gICAgZWxzZSBpZiAoZ2VuLmJlbmNoKSB7XHJcbiAgICAgIHRoaXMuX2JlbmNoR2VuLnB1c2goZ2VuIGFzIE1peEFzeW5jR2VuZXJhdG9yLkdlbjxULCB0cnVlPik7XHJcbiAgICB9XHJcbiAgICAvLy8g5aaC5p6c5piv6Z2e5oOw5oCn5YWD57Sg77yM6YKj5LmI5Zue5Yiw6Ieq55Sx6Zif5YiXXHJcbiAgICBlbHNlIHtcclxuICAgICAgdGhpcy5fZnJlZUdlbi5wdXNoKGdlbiBhcyBNaXhBc3luY0dlbmVyYXRvci5HZW48VCwgZmFsc2U+KTtcclxuICAgIH1cclxuICB9XHJcbiAgcHJpdmF0ZSBhc3luYyBfZGVxdWV1ZUdlbigpIHtcclxuICAgIC8vIOiOt+WPluS4gOS4quWPr+eUqOeahOi/reS7o+WZqFxyXG4gICAgY29uc3QgZ2VuID1cclxuICAgICAgdGhpcy5fZnJlZUdlbi5zaGlmdCgpIHx8XHJcbiAgICAgIHRoaXMuX2JlbmNoR2VuLnNoaWZ0KCkgfHxcclxuICAgICAgKGF3YWl0IHRoaXMuX2dlbldhaXR0ZXIucHVzaChuZXcgUHJvbWlzZU91dCgpKS5wcm9taXNlKTtcclxuICAgIHRoaXMuX2hhbmRsZUdlbihnZW4pO1xyXG4gIH1cclxuICAvKirmraPlnKjmiafooYzkuK3nmoTku7vliqHvvIznrYnlvoXov5Tlm57lkI7lsLHku47ov5nkuKrpm4blkIjkuK3np7vpmaQgKi9cclxuICBwcml2YXRlIF9ydW5uaW5ncyA9IG5ldyBNYXA8XHJcbiAgICBQcm9taXNlPEl0ZXJhdG9yUmVzdWx0PFRbMF0sIFRbMV0+PixcclxuICAgIE1peEFzeW5jR2VuZXJhdG9yLkdlbjxUPlxyXG4gID4oKTtcclxuICBwcml2YXRlIF9oYW5kbGVHZW4oZ2VuOiBNaXhBc3luY0dlbmVyYXRvci5HZW48VD4pIHtcclxuICAgIGNvbnN0IGl0ZW0gPSBnZW4ucnVubmVyLm5leHQoKTtcclxuICAgIHRoaXMuX3J1bm5pbmdzLnNldChpdGVtLCBnZW4pO1xyXG4gICAgLy8g5aaC5p6c5a6M5oiQ77yM5YiZ5Zue5Yiw6Ieq55Sx6Zif5YiXXHJcbiAgICBzYWZlUHJvbWlzZVRoZW4oXHJcbiAgICAgIGl0ZW0sXHJcbiAgICAgICh2YWx1ZSkgPT4ge1xyXG4gICAgICAgIHRoaXMuX3J1bm5pbmdzLmRlbGV0ZShpdGVtKTtcclxuICAgICAgICAvLyDnvJPlrZjlvZPliY3nu5PmnpxcclxuICAgICAgICBnZW4uY3VycmVudFN0ZXAgPSB2YWx1ZTtcclxuICAgICAgICAvLy8g5aaC5p6c5bey57uP5a6M57uT5LqG77yM6YKj5LmI55u05o6l56e76Zmk5o6J5LqGXHJcbiAgICAgICAgaWYgKHZhbHVlLmRvbmUpIHtcclxuICAgICAgICAgIHRoaXMucmVtb3ZlKGdlbik7XHJcblxyXG4gICAgICAgICAgLy8vIOWmguaenOayoeacieS7u+S9leWcqOaJp+ihjOS4reeahOWFg+e0oO+8jOWwsemcgOimgee7p+e7reS7jumYn+WIl+S4reivu+WPluWHuuadpeaJp+ihjO+8jOWQpuWImeWklumdoueahFByb21pc2XlsLHmsLjov5zml6Dms5VyZXNvbHZlXHJcbiAgICAgICAgICBpZiAodGhpcy5fcnVubmluZ3Muc2l6ZSA9PT0gMCkge1xyXG4gICAgICAgICAgICB0aGlzLl9kZXF1ZXVlR2VuKCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8vLyDlkKbliJnlm57liLDpmJ/liJfkuK3nu6fnu63mj5DkvpvkuIvkuIDkuKrov63ku6NcclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgIC8vIOS8oOmAkuWIsOe7k+aenOmYn+WIl+S4rVxyXG4gICAgICAgICAgdGhpcy5fZW5xdWV1ZVJlc3VsdCh7IGZyb206IGdlbiwgc3RlcDogdmFsdWUgfSk7XHJcblxyXG4gICAgICAgICAgLy8vIOWmguaenOWPr+S7peWBt+i3ke+8jOmCo+S5iOe7p+e7reaJp+ihjFxyXG4gICAgICAgICAgaWYgKGdlbi5pblF1ZXVlU3RlcHMgPCBnZW4uanVtcEd1bikge1xyXG4gICAgICAgICAgICB0aGlzLl9oYW5kbGVHZW4oZ2VuKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIC8vIOWbnuWIsOepuumXsumYn+WIl+S4rVxyXG4gICAgICAgICAgICB0aGlzLl9lbnF1ZXVlR2VuKGdlbik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICAocmVhc29uOiB1bmtub3duKSA9PiB7XHJcbiAgICAgICAgdGhpcy5fcnVubmluZ3MuZGVsZXRlKGl0ZW0pO1xyXG4gICAgICAgIC8vIOWmguaenOW3sue7j+WHuumUme+8jOmCo+S5iOebtOaOpeenu+mZpFxyXG4gICAgICAgIHRoaXMucmVtb3ZlKGdlbik7XHJcbiAgICAgICAgLy8g5ZCR5aSW5Lyg6YCS6ZSZ6K+vXHJcbiAgICAgICAgdGhpcy5vbkVycm9yLnBvc3QoeyBmcm9tOiBnZW4sIHJlYXNvbiB9KTtcclxuICAgICAgfVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8qKuWAmeihpemYn+WIlyAqL1xyXG4gIHByaXZhdGUgX2JlbmNoR2VuID0gbmV3IEZhc3RRdWVuZTxNaXhBc3luY0dlbmVyYXRvci5HZW48VCwgdHJ1ZT4+KCk7XHJcbiAgLyoq6Ieq55Sx6Zif5YiXICovXHJcbiAgcHJpdmF0ZSBfZnJlZUdlbiA9IG5ldyBGYXN0UXVlbmU8TWl4QXN5bmNHZW5lcmF0b3IuR2VuPFQsIGZhbHNlPj4oKTtcclxuICBwcml2YXRlIF9nZW5XYWl0dGVyID0gbmV3IEZhc3RRdWVuZTxQcm9taXNlT3V0PE1peEFzeW5jR2VuZXJhdG9yLkdlbjxUPj4+KCk7XHJcbiAgLyoq5YWl5YiXXHJcbiAgICog6L+Z5Liq5Ye95pWw5LiOX2hhbmRsZUdlbuaYr+e0p+WvhuWFs+iBlOeahO+8jOaYr19oYW5kbGVHZW7nmoTkuIDpg6jliIZcclxuICAgKi9cclxuICBwcml2YXRlIF9lbnF1ZXVlUmVzdWx0KHJlc3VsdDogTWl4QXN5bmNHZW5lcmF0b3IuUmVzdWx0V2l0aEZyb208VD4pIHtcclxuICAgIC8vLyDmmK/lkKbmnInlnKjnrYnlvoXkuK3nmoRcclxuICAgIGNvbnN0IHdhaXRlciA9IHRoaXMuX3Jlc3VsdFdhaXRlci5zaGlmdCgpO1xyXG4gICAgaWYgKHdhaXRlciAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgIC8qKlxyXG4gICAgICAgKiDlm6DkuLrmnKzlsLHmmK/opoHnm7TmjqXov5Tlm57nmoTvvIzmiYDku6Xov5nph4znm7TmjqXlsIbmraXmlbDlh4/ljrtcclxuICAgICAgICpcclxuICAgICAgICogV2FpdGVy5qih5byP5LiN6ZyA6KaB5L+u5pS5aW5RdWV1ZVN0ZXBz77yM5Zug5Li65piv6aKE57qm55qE77yM55u05o6l6L+U5ZueXHJcbiAgICAgICAqL1xyXG4gICAgICB3YWl0ZXIucmVzb2x2ZShyZXN1bHQpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmVzdWx0LmZyb20uYmVuY2hcclxuICAgICAgICA/IHRoaXMuX2JlbmNoUmVzdWx0LnB1c2goXHJcbiAgICAgICAgICAgIHJlc3VsdCBhcyBNaXhBc3luY0dlbmVyYXRvci5SZXN1bHRXaXRoRnJvbTxULCB0cnVlPlxyXG4gICAgICAgICAgKVxyXG4gICAgICAgIDogdGhpcy5fZnJlZVJlc3VsdC5wdXNoKFxyXG4gICAgICAgICAgICByZXN1bHQgYXMgTWl4QXN5bmNHZW5lcmF0b3IuUmVzdWx0V2l0aEZyb208VCwgZmFsc2U+XHJcbiAgICAgICAgICApO1xyXG4gICAgICByZXN1bHQuZnJvbS5pblF1ZXVlU3RlcHMgKz0gMTtcclxuICAgIH1cclxuICB9XHJcbiAgLyoq5Ye65YiXICovXHJcbiAgcHJpdmF0ZSBfZGVxdWV1ZVJlc3VsdCgpIHtcclxuICAgIC8vLyDlho3ku47nu5PmnpzpmJ/liJfkuK3or7vlj5ZcclxuICAgIGNvbnN0IHJlc3VsdFdpdGhGcm9tMSA9IHRoaXMuX2ZyZWVSZXN1bHQuc2hpZnQoKTtcclxuICAgIGlmIChyZXN1bHRXaXRoRnJvbTEgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICBjb25zdCBnZW4gPSByZXN1bHRXaXRoRnJvbTEuZnJvbTtcclxuICAgICAgZ2VuLmluUXVldWVTdGVwcyAtPSAxO1xyXG4gICAgICBpZiAodGhpcy5fZnJlZUdlbi5yZW1vdmUoZ2VuKSkge1xyXG4gICAgICAgIHRoaXMuX2hhbmRsZUdlbihnZW4pO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiByZXN1bHRXaXRoRnJvbTE7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgcmVzdWx0V2l0aEZyb20yID0gdGhpcy5fYmVuY2hSZXN1bHQuc2hpZnQoKTtcclxuICAgIGlmIChyZXN1bHRXaXRoRnJvbTIgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICBjb25zdCBnZW4gPSByZXN1bHRXaXRoRnJvbTIuZnJvbTtcclxuICAgICAgZ2VuLmluUXVldWVTdGVwcyAtPSAxO1xyXG4gICAgICBpZiAodGhpcy5fYmVuY2hHZW4ucmVtb3ZlKGdlbikpIHtcclxuICAgICAgICB0aGlzLl9oYW5kbGVHZW4oZ2VuKTtcclxuICAgICAgfVxyXG4gICAgICAvKipcclxuICAgICAgICogQFRPRE8g5L2/55So5LqG5YCZ6KGl5YWD57Sg77yM6YKj5LmI5bCx6KaB5a+55YWD57Sg5bC95b+r6L+b6KGM6KGl5YWFXHJcbiAgICAgICAqL1xyXG4gICAgICByZXR1cm4gcmVzdWx0V2l0aEZyb20yO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIOWQpuWImeaOkumYn+i/m+ihjOetieW+he+8jFdhaXRlcuaooeW8j+S4jemcgOimgeS/ruaUuWluUXVldWVTdGVwc++8jOWboOS4uuaYr+mihOe6pueahO+8jOebtOaOpei/lOWbnlxyXG4gICAgY29uc3QgcmVzdWx0UHJvbWlzZSA9IHRoaXMuX3Jlc3VsdFdhaXRlci5wdXNoKG5ldyBQcm9taXNlT3V0KCkpLnByb21pc2U7XHJcbiAgICAvLy8g5b+F6KaB5pe277yM6K6p6YCJ5omL5Ye65YiXXHJcbiAgICBpZiAoXHJcbiAgICAgIC8vIOWmguaenOayoeacieS7u+S9leS4gOS4quWcqOi/kOihjOS4reeahOS7u+WKoe+8mumCo+S5iOeri+WIu+aJp+ihjFxyXG4gICAgICB0aGlzLl9ydW5uaW5ncy5zaXplID09PSAwIHx8XHJcbiAgICAgIC8vIOWmguaenOiHqueUsemYn+WIl+S4uuepuu+8jOS9huaYr+WAmeihpemYn+WIl+acieWtmOWcqOeahO+8mumCo+S5iOS5n+eri+WIu+aJp+ihjFxyXG4gICAgICAodGhpcy5fZnJlZUdlbi5zaXplID09PSAwICYmIHRoaXMuX2JlbmNoR2VuLnNpemUgIT09IDApXHJcbiAgICApIHtcclxuICAgICAgdGhpcy5fZGVxdWV1ZUdlbigpO1xyXG4gICAgfVxyXG4gICAgLy8gY29uc29sZS5sb2coKyt0aGlzLl90cmFjZUNvdW50KTtcclxuICAgIC8vIGlmICh0aGlzLl90cmFjZUNvdW50ID09PSAyKSB7XHJcbiAgICAvLyAgIGRlYnVnZ2VyO1xyXG4gICAgLy8gfVxyXG4gICAgcmV0dXJuIHJlc3VsdFByb21pc2U7XHJcbiAgfVxyXG4gIC8vIHByaXZhdGUgX3RyYWNlQ291bnQgPSAwO1xyXG4gIHByaXZhdGUgX2ZyZWVSZXN1bHQgPSBuZXcgRmFzdFF1ZW5lPFxyXG4gICAgTWl4QXN5bmNHZW5lcmF0b3IuUmVzdWx0V2l0aEZyb208VCwgZmFsc2U+XHJcbiAgPigpO1xyXG4gIHByaXZhdGUgX2JlbmNoUmVzdWx0ID0gbmV3IEZhc3RRdWVuZTxcclxuICAgIE1peEFzeW5jR2VuZXJhdG9yLlJlc3VsdFdpdGhGcm9tPFQsIHRydWU+XHJcbiAgPigpO1xyXG4gIHByaXZhdGUgX3Jlc3VsdFdhaXRlciA9IG5ldyBGYXN0UXVlbmU8XHJcbiAgICBQcm9taXNlT3V0PE1peEFzeW5jR2VuZXJhdG9yLlJlc3VsdDxUPj5cclxuICA+KCk7XHJcbiAgcmVhZG9ubHkgb25FcnJvciA9IG5ldyBFdnQ8TWl4QXN5bmNHZW5lcmF0b3IuRXJyb3I8VD4+KCk7XHJcbiAgbmV4dCgpIHtcclxuICAgIGlmICh0aGlzLmlzRG9uZSkge1xyXG4gICAgICByZXR1cm4gRE9ORSBhcyBQcm9taXNlPE1peEFzeW5jR2VuZXJhdG9yLlJlc3VsdDxUPj47XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcy5fZGVxdWV1ZVJlc3VsdCgpO1xyXG4gIH1cclxuICBnZXQgaXNEb25lKCkge1xyXG4gICAgcmV0dXJuIChcclxuICAgICAgLyogX2FsbEdlbkxpc3TkuLrnqbrkuZ/lsLHmhI/lkbPnnYBfcnVubmluZ+S4uuepuiAqLyB0aGlzLl9hbGxHZW5MaXN0LnNpemUgPT09IDAgJiZcclxuICAgICAgdGhpcy5fZnJlZVJlc3VsdC5zaXplID09PSAwICYmXHJcbiAgICAgIHRoaXMuX2JlbmNoUmVzdWx0LnNpemUgPT09IDBcclxuICAgICk7XHJcbiAgfVxyXG4gIGFzeW5jICp0b0FzeW5jSXRlcmF0b3IoKSB7XHJcbiAgICB3aGlsZSAodHJ1ZSkge1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLm5leHQoKTtcclxuICAgICAgaWYgKHJlc3VsdC5zdGVwLmRvbmUpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuICAgICAgeWllbGQgcmVzdWx0LnN0ZXAudmFsdWU7XHJcbiAgICB9XHJcbiAgfVxyXG4gIGFzeW5jIHRvUHJvbWlzZSgpIHtcclxuICAgIHdoaWxlICh0cnVlKSB7XHJcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMubmV4dCgpO1xyXG4gICAgICBpZiAocmVzdWx0LnN0ZXAuZG9uZSkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iXX0=