UNPKG

@data-client/core

Version:

Async State Management without the Management. REST, GraphQL, SSE, Websockets, Fetch

150 lines (141 loc) 21.9 kB
import DefaultConnectionListener from './DefaultConnectionListener.js'; /** * PollingSubscription keeps a given resource updated by * dispatching a fetch at a rate equal to the minimum update * interval requested. * * @see https://dataclient.io/docs/api/PollingSubscription */ export default class PollingSubscription { constructor(action, controller, connectionListener) { this.frequencyHistogram = new Map(); /** What happens when browser goes offline */ this.offlineListener = () => { // this clears existing listeners, so no need to clear offline listener this.cleanup(); this.connectionListener.addOnlineListener(this.onlineListener); }; /** What happens when browser comes online */ this.onlineListener = () => { this.connectionListener.removeOnlineListener(this.onlineListener); const now = Date.now(); this.startId = setTimeout(() => { if (this.startId) { delete this.startId; this.update(); this.run(); } else if (process.env.NODE_ENV !== 'production') { console.warn(`Poll setTimeout for ${this.key} still running, but timeoutId deleted`); } }, Math.max(0, this.lastFetchTime() - now + this.frequency)); this.connectionListener.addOfflineListener(this.offlineListener); }; if (action.endpoint.pollFrequency === undefined) throw new Error('frequency needed for polling subscription'); this.endpoint = action.endpoint; this.frequency = action.endpoint.pollFrequency; this.args = action.args; this.key = action.key; this.frequencyHistogram.set(this.frequency, 1); this.controller = controller; this.connectionListener = connectionListener || new DefaultConnectionListener(); // Kickstart running since this is initialized after the online notif is sent if (this.connectionListener.isOnline()) { this.onlineListener(); } else { this.offlineListener(); } } /** Subscribe to a frequency */ add(frequency) { if (frequency === undefined) return; if (this.frequencyHistogram.has(frequency)) { this.frequencyHistogram.set(frequency, this.frequencyHistogram.get(frequency) + 1); } else { this.frequencyHistogram.set(frequency, 1); // new min so restart service if (frequency < this.frequency) { this.frequency = frequency; this.run(); } } } /** Unsubscribe from a frequency */ remove(frequency) { if (frequency === undefined) return false; if (this.frequencyHistogram.has(frequency)) { this.frequencyHistogram.set(frequency, this.frequencyHistogram.get(frequency) - 1); if (this.frequencyHistogram.get(frequency) < 1) { this.frequencyHistogram.delete(frequency); // nothing subscribed to this anymore...it is invalid if (this.frequencyHistogram.size === 0) { this.cleanup(); return true; } // this was the min, so find the next size if (frequency <= this.frequency) { this.frequency = Math.min(...this.frequencyHistogram.keys()); this.run(); } } } /* istanbul ignore next */else if (process.env.NODE_ENV !== 'production') { console.error(`Mismatched remove: ${frequency} is not subscribed for ${this.key}`); } return false; } /** Cleanup means clearing out background interval. */ cleanup() { if (this.intervalId) { clearInterval(this.intervalId); delete this.intervalId; } if (this.lastIntervalId) { clearInterval(this.lastIntervalId); delete this.lastIntervalId; } if (this.startId) { clearTimeout(this.startId); delete this.startId; } this.connectionListener.removeOnlineListener(this.onlineListener); this.connectionListener.removeOfflineListener(this.offlineListener); } /** Trigger request for latest resource */ update() { const sup = this.endpoint; const endpoint = function endpoint(...args) { return sup.call(this, ...args); }; Object.assign(endpoint, this.endpoint); endpoint.dataExpiryLength = this.frequency / 2; endpoint.errorExpiryLength = this.frequency / 10; endpoint.errorPolicy = () => 'soft'; endpoint.key = () => this.key; // stop any errors here from bubbling this.controller.fetch(endpoint, ...this.args).catch(() => null); } /** Run polling process with current frequency * * Will clean up old poll interval on next run */ run() { if (this.startId) return; if (this.intervalId) this.lastIntervalId = this.intervalId; this.intervalId = setInterval(() => { // since we don't know how long into the last poll it was before resetting // we wait til the next fetch to clear old intervals if (this.lastIntervalId) { clearInterval(this.lastIntervalId); delete this.lastIntervalId; } if (this.intervalId) this.update();else if (process.env.NODE_ENV !== 'production') { console.warn(`Poll intervalId for ${this.key} still running, but intervalId deleted`); } }, this.frequency); } /** Last fetch time */ lastFetchTime() { var _this$controller$getS, _this$controller$getS2; return (_this$controller$getS = (_this$controller$getS2 = this.controller.getState().meta[this.key]) == null ? void 0 : _this$controller$getS2.date) != null ? _this$controller$getS : 0; } } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJEZWZhdWx0Q29ubmVjdGlvbkxpc3RlbmVyIiwiUG9sbGluZ1N1YnNjcmlwdGlvbiIsImNvbnN0cnVjdG9yIiwiYWN0aW9uIiwiY29udHJvbGxlciIsImNvbm5lY3Rpb25MaXN0ZW5lciIsImZyZXF1ZW5jeUhpc3RvZ3JhbSIsIk1hcCIsIm9mZmxpbmVMaXN0ZW5lciIsImNsZWFudXAiLCJhZGRPbmxpbmVMaXN0ZW5lciIsIm9ubGluZUxpc3RlbmVyIiwicmVtb3ZlT25saW5lTGlzdGVuZXIiLCJub3ciLCJEYXRlIiwic3RhcnRJZCIsInNldFRpbWVvdXQiLCJ1cGRhdGUiLCJydW4iLCJwcm9jZXNzIiwiZW52IiwiTk9ERV9FTlYiLCJjb25zb2xlIiwid2FybiIsImtleSIsIk1hdGgiLCJtYXgiLCJsYXN0RmV0Y2hUaW1lIiwiZnJlcXVlbmN5IiwiYWRkT2ZmbGluZUxpc3RlbmVyIiwiZW5kcG9pbnQiLCJwb2xsRnJlcXVlbmN5IiwidW5kZWZpbmVkIiwiRXJyb3IiLCJhcmdzIiwic2V0IiwiaXNPbmxpbmUiLCJhZGQiLCJoYXMiLCJnZXQiLCJyZW1vdmUiLCJkZWxldGUiLCJzaXplIiwibWluIiwia2V5cyIsImVycm9yIiwiaW50ZXJ2YWxJZCIsImNsZWFySW50ZXJ2YWwiLCJsYXN0SW50ZXJ2YWxJZCIsImNsZWFyVGltZW91dCIsInJlbW92ZU9mZmxpbmVMaXN0ZW5lciIsInN1cCIsImNhbGwiLCJPYmplY3QiLCJhc3NpZ24iLCJkYXRhRXhwaXJ5TGVuZ3RoIiwiZXJyb3JFeHBpcnlMZW5ndGgiLCJlcnJvclBvbGljeSIsImZldGNoIiwiY2F0Y2giLCJzZXRJbnRlcnZhbCIsIl90aGlzJGNvbnRyb2xsZXIkZ2V0UyIsIl90aGlzJGNvbnRyb2xsZXIkZ2V0UzIiLCJnZXRTdGF0ZSIsIm1ldGEiLCJkYXRlIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL21hbmFnZXIvUG9sbGluZ1N1YnNjcmlwdGlvbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IEVuZHBvaW50SW50ZXJmYWNlIH0gZnJvbSAnQGRhdGEtY2xpZW50L25vcm1hbGl6cic7XG5cbmltcG9ydCBDb25uZWN0aW9uTGlzdGVuZXIgZnJvbSAnLi9Db25uZWN0aW9uTGlzdGVuZXIuanMnO1xuaW1wb3J0IERlZmF1bHRDb25uZWN0aW9uTGlzdGVuZXIgZnJvbSAnLi9EZWZhdWx0Q29ubmVjdGlvbkxpc3RlbmVyLmpzJztcbmltcG9ydCB0eXBlIHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAnLi9TdWJzY3JpcHRpb25NYW5hZ2VyLmpzJztcbmltcG9ydCB0eXBlIENvbnRyb2xsZXIgZnJvbSAnLi4vY29udHJvbGxlci9Db250cm9sbGVyLmpzJztcbmltcG9ydCB0eXBlIHsgU3Vic2NyaWJlQWN0aW9uIH0gZnJvbSAnLi4vdHlwZXMuanMnO1xuXG4vKipcbiAqIFBvbGxpbmdTdWJzY3JpcHRpb24ga2VlcHMgYSBnaXZlbiByZXNvdXJjZSB1cGRhdGVkIGJ5XG4gKiBkaXNwYXRjaGluZyBhIGZldGNoIGF0IGEgcmF0ZSBlcXVhbCB0byB0aGUgbWluaW11bSB1cGRhdGVcbiAqIGludGVydmFsIHJlcXVlc3RlZC5cbiAqXG4gKiBAc2VlIGh0dHBzOi8vZGF0YWNsaWVudC5pby9kb2NzL2FwaS9Qb2xsaW5nU3Vic2NyaXB0aW9uXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFBvbGxpbmdTdWJzY3JpcHRpb24gaW1wbGVtZW50cyBTdWJzY3JpcHRpb24ge1xuICBkZWNsYXJlIHByb3RlY3RlZCByZWFkb25seSBlbmRwb2ludDogRW5kcG9pbnRJbnRlcmZhY2U7XG4gIGRlY2xhcmUgcHJvdGVjdGVkIHJlYWRvbmx5IGFyZ3M6IHJlYWRvbmx5IGFueVtdO1xuICBkZWNsYXJlIHByb3RlY3RlZCByZWFkb25seSBrZXk6IHN0cmluZztcbiAgZGVjbGFyZSBwcm90ZWN0ZWQgZnJlcXVlbmN5OiBudW1iZXI7XG4gIHByb3RlY3RlZCBmcmVxdWVuY3lIaXN0b2dyYW06IE1hcDxudW1iZXIsIG51bWJlcj4gPSBuZXcgTWFwKCk7XG4gIGRlY2xhcmUgcHJvdGVjdGVkIGNvbnRyb2xsZXI6IENvbnRyb2xsZXI7XG4gIGRlY2xhcmUgcHJvdGVjdGVkIGludGVydmFsSWQ/OiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRJbnRlcnZhbD47XG4gIGRlY2xhcmUgcHJvdGVjdGVkIGxhc3RJbnRlcnZhbElkPzogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0SW50ZXJ2YWw+O1xuICBkZWNsYXJlIHByb3RlY3RlZCBzdGFydElkPzogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD47XG4gIGRlY2xhcmUgcHJpdmF0ZSBjb25uZWN0aW9uTGlzdGVuZXI6IENvbm5lY3Rpb25MaXN0ZW5lcjtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBhY3Rpb246IE9taXQ8U3Vic2NyaWJlQWN0aW9uLCAndHlwZSc+LFxuICAgIGNvbnRyb2xsZXI6IENvbnRyb2xsZXIsXG4gICAgY29ubmVjdGlvbkxpc3RlbmVyPzogQ29ubmVjdGlvbkxpc3RlbmVyLFxuICApIHtcbiAgICBpZiAoYWN0aW9uLmVuZHBvaW50LnBvbGxGcmVxdWVuY3kgPT09IHVuZGVmaW5lZClcbiAgICAgIHRocm93IG5ldyBFcnJvcignZnJlcXVlbmN5IG5lZWRlZCBmb3IgcG9sbGluZyBzdWJzY3JpcHRpb24nKTtcbiAgICB0aGlzLmVuZHBvaW50ID0gYWN0aW9uLmVuZHBvaW50O1xuICAgIHRoaXMuZnJlcXVlbmN5ID0gYWN0aW9uLmVuZHBvaW50LnBvbGxGcmVxdWVuY3k7XG4gICAgdGhpcy5hcmdzID0gYWN0aW9uLmFyZ3M7XG4gICAgdGhpcy5rZXkgPSBhY3Rpb24ua2V5O1xuICAgIHRoaXMuZnJlcXVlbmN5SGlzdG9ncmFtLnNldCh0aGlzLmZyZXF1ZW5jeSwgMSk7XG4gICAgdGhpcy5jb250cm9sbGVyID0gY29udHJvbGxlcjtcbiAgICB0aGlzLmNvbm5lY3Rpb25MaXN0ZW5lciA9XG4gICAgICBjb25uZWN0aW9uTGlzdGVuZXIgfHwgbmV3IERlZmF1bHRDb25uZWN0aW9uTGlzdGVuZXIoKTtcblxuICAgIC8vIEtpY2tzdGFydCBydW5uaW5nIHNpbmNlIHRoaXMgaXMgaW5pdGlhbGl6ZWQgYWZ0ZXIgdGhlIG9ubGluZSBub3RpZiBpcyBzZW50XG4gICAgaWYgKHRoaXMuY29ubmVjdGlvbkxpc3RlbmVyLmlzT25saW5lKCkpIHtcbiAgICAgIHRoaXMub25saW5lTGlzdGVuZXIoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5vZmZsaW5lTGlzdGVuZXIoKTtcbiAgICB9XG4gIH1cblxuICAvKiogU3Vic2NyaWJlIHRvIGEgZnJlcXVlbmN5ICovXG4gIGFkZChmcmVxdWVuY3k/OiBudW1iZXIpIHtcbiAgICBpZiAoZnJlcXVlbmN5ID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICBpZiAodGhpcy5mcmVxdWVuY3lIaXN0b2dyYW0uaGFzKGZyZXF1ZW5jeSkpIHtcbiAgICAgIHRoaXMuZnJlcXVlbmN5SGlzdG9ncmFtLnNldChcbiAgICAgICAgZnJlcXVlbmN5LFxuICAgICAgICAodGhpcy5mcmVxdWVuY3lIaXN0b2dyYW0uZ2V0KGZyZXF1ZW5jeSkgYXMgbnVtYmVyKSArIDEsXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmZyZXF1ZW5jeUhpc3RvZ3JhbS5zZXQoZnJlcXVlbmN5LCAxKTtcblxuICAgICAgLy8gbmV3IG1pbiBzbyByZXN0YXJ0IHNlcnZpY2VcbiAgICAgIGlmIChmcmVxdWVuY3kgPCB0aGlzLmZyZXF1ZW5jeSkge1xuICAgICAgICB0aGlzLmZyZXF1ZW5jeSA9IGZyZXF1ZW5jeTtcbiAgICAgICAgdGhpcy5ydW4oKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKiogVW5zdWJzY3JpYmUgZnJvbSBhIGZyZXF1ZW5jeSAqL1xuICByZW1vdmUoZnJlcXVlbmN5PzogbnVtYmVyKSB7XG4gICAgaWYgKGZyZXF1ZW5jeSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKHRoaXMuZnJlcXVlbmN5SGlzdG9ncmFtLmhhcyhmcmVxdWVuY3kpKSB7XG4gICAgICB0aGlzLmZyZXF1ZW5jeUhpc3RvZ3JhbS5zZXQoXG4gICAgICAgIGZyZXF1ZW5jeSxcbiAgICAgICAgKHRoaXMuZnJlcXVlbmN5SGlzdG9ncmFtLmdldChmcmVxdWVuY3kpIGFzIG51bWJlcikgLSAxLFxuICAgICAgKTtcbiAgICAgIGlmICgodGhpcy5mcmVxdWVuY3lIaXN0b2dyYW0uZ2V0KGZyZXF1ZW5jeSkgYXMgbnVtYmVyKSA8IDEpIHtcbiAgICAgICAgdGhpcy5mcmVxdWVuY3lIaXN0b2dyYW0uZGVsZXRlKGZyZXF1ZW5jeSk7XG5cbiAgICAgICAgLy8gbm90aGluZyBzdWJzY3JpYmVkIHRvIHRoaXMgYW55bW9yZS4uLml0IGlzIGludmFsaWRcbiAgICAgICAgaWYgKHRoaXMuZnJlcXVlbmN5SGlzdG9ncmFtLnNpemUgPT09IDApIHtcbiAgICAgICAgICB0aGlzLmNsZWFudXAoKTtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHRoaXMgd2FzIHRoZSBtaW4sIHNvIGZpbmQgdGhlIG5leHQgc2l6ZVxuICAgICAgICBpZiAoZnJlcXVlbmN5IDw9IHRoaXMuZnJlcXVlbmN5KSB7XG4gICAgICAgICAgdGhpcy5mcmVxdWVuY3kgPSBNYXRoLm1pbiguLi50aGlzLmZyZXF1ZW5jeUhpc3RvZ3JhbS5rZXlzKCkpO1xuICAgICAgICAgIHRoaXMucnVuKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovIGVsc2UgaWYgKFxuICAgICAgcHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJ1xuICAgICkge1xuICAgICAgY29uc29sZS5lcnJvcihcbiAgICAgICAgYE1pc21hdGNoZWQgcmVtb3ZlOiAke2ZyZXF1ZW5jeX0gaXMgbm90IHN1YnNjcmliZWQgZm9yICR7dGhpcy5rZXl9YCxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKiBDbGVhbnVwIG1lYW5zIGNsZWFyaW5nIG91dCBiYWNrZ3JvdW5kIGludGVydmFsLiAqL1xuICBjbGVhbnVwKCkge1xuICAgIGlmICh0aGlzLmludGVydmFsSWQpIHtcbiAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5pbnRlcnZhbElkKTtcbiAgICAgIGRlbGV0ZSB0aGlzLmludGVydmFsSWQ7XG4gICAgfVxuICAgIGlmICh0aGlzLmxhc3RJbnRlcnZhbElkKSB7XG4gICAgICBjbGVhckludGVydmFsKHRoaXMubGFzdEludGVydmFsSWQpO1xuICAgICAgZGVsZXRlIHRoaXMubGFzdEludGVydmFsSWQ7XG4gICAgfVxuICAgIGlmICh0aGlzLnN0YXJ0SWQpIHtcbiAgICAgIGNsZWFyVGltZW91dCh0aGlzLnN0YXJ0SWQpO1xuICAgICAgZGVsZXRlIHRoaXMuc3RhcnRJZDtcbiAgICB9XG4gICAgdGhpcy5jb25uZWN0aW9uTGlzdGVuZXIucmVtb3ZlT25saW5lTGlzdGVuZXIodGhpcy5vbmxpbmVMaXN0ZW5lcik7XG4gICAgdGhpcy5jb25uZWN0aW9uTGlzdGVuZXIucmVtb3ZlT2ZmbGluZUxpc3RlbmVyKHRoaXMub2ZmbGluZUxpc3RlbmVyKTtcbiAgfVxuXG4gIC8qKiBUcmlnZ2VyIHJlcXVlc3QgZm9yIGxhdGVzdCByZXNvdXJjZSAqL1xuICBwcm90ZWN0ZWQgdXBkYXRlKCkge1xuICAgIGNvbnN0IHN1cCA9IHRoaXMuZW5kcG9pbnQ7XG4gICAgY29uc3QgZW5kcG9pbnQgPSBmdW5jdGlvbiAodGhpczogYW55LCAuLi5hcmdzOiBhbnlbXSkge1xuICAgICAgcmV0dXJuIHN1cC5jYWxsKHRoaXMsIC4uLmFyZ3MpO1xuICAgIH07XG4gICAgT2JqZWN0LmFzc2lnbihlbmRwb2ludCwgdGhpcy5lbmRwb2ludCk7XG4gICAgZW5kcG9pbnQuZGF0YUV4cGlyeUxlbmd0aCA9IHRoaXMuZnJlcXVlbmN5IC8gMjtcbiAgICBlbmRwb2ludC5lcnJvckV4cGlyeUxlbmd0aCA9IHRoaXMuZnJlcXVlbmN5IC8gMTA7XG4gICAgZW5kcG9pbnQuZXJyb3JQb2xpY3kgPSAoKSA9PiAnc29mdCcgYXMgY29uc3Q7XG4gICAgZW5kcG9pbnQua2V5ID0gKCkgPT4gdGhpcy5rZXk7XG4gICAgLy8gc3RvcCBhbnkgZXJyb3JzIGhlcmUgZnJvbSBidWJibGluZ1xuICAgIHRoaXMuY29udHJvbGxlci5mZXRjaChlbmRwb2ludCwgLi4udGhpcy5hcmdzKS5jYXRjaCgoKSA9PiBudWxsKTtcbiAgfVxuXG4gIC8qKiBXaGF0IGhhcHBlbnMgd2hlbiBicm93c2VyIGdvZXMgb2ZmbGluZSAqL1xuICBwcm90ZWN0ZWQgb2ZmbGluZUxpc3RlbmVyID0gKCkgPT4ge1xuICAgIC8vIHRoaXMgY2xlYXJzIGV4aXN0aW5nIGxpc3RlbmVycywgc28gbm8gbmVlZCB0byBjbGVhciBvZmZsaW5lIGxpc3RlbmVyXG4gICAgdGhpcy5jbGVhbnVwKCk7XG4gICAgdGhpcy5jb25uZWN0aW9uTGlzdGVuZXIuYWRkT25saW5lTGlzdGVuZXIodGhpcy5vbmxpbmVMaXN0ZW5lcik7XG4gIH07XG5cbiAgLyoqIFdoYXQgaGFwcGVucyB3aGVuIGJyb3dzZXIgY29tZXMgb25saW5lICovXG4gIHByb3RlY3RlZCBvbmxpbmVMaXN0ZW5lciA9ICgpID0+IHtcbiAgICB0aGlzLmNvbm5lY3Rpb25MaXN0ZW5lci5yZW1vdmVPbmxpbmVMaXN0ZW5lcih0aGlzLm9ubGluZUxpc3RlbmVyKTtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIHRoaXMuc3RhcnRJZCA9IHNldFRpbWVvdXQoXG4gICAgICAoKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLnN0YXJ0SWQpIHtcbiAgICAgICAgICBkZWxldGUgdGhpcy5zdGFydElkO1xuICAgICAgICAgIHRoaXMudXBkYXRlKCk7XG4gICAgICAgICAgdGhpcy5ydW4oKTtcbiAgICAgICAgfSBlbHNlIGlmIChwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Byb2R1Y3Rpb24nKSB7XG4gICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgYFBvbGwgc2V0VGltZW91dCBmb3IgJHt0aGlzLmtleX0gc3RpbGwgcnVubmluZywgYnV0IHRpbWVvdXRJZCBkZWxldGVkYCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgTWF0aC5tYXgoMCwgdGhpcy5sYXN0RmV0Y2hUaW1lKCkgLSBub3cgKyB0aGlzLmZyZXF1ZW5jeSksXG4gICAgKTtcbiAgICB0aGlzLmNvbm5lY3Rpb25MaXN0ZW5lci5hZGRPZmZsaW5lTGlzdGVuZXIodGhpcy5vZmZsaW5lTGlzdGVuZXIpO1xuICB9O1xuXG4gIC8qKiBSdW4gcG9sbGluZyBwcm9jZXNzIHdpdGggY3VycmVudCBmcmVxdWVuY3lcbiAgICpcbiAgICogV2lsbCBjbGVhbiB1cCBvbGQgcG9sbCBpbnRlcnZhbCBvbiBuZXh0IHJ1blxuICAgKi9cbiAgcHJvdGVjdGVkIHJ1bigpIHtcbiAgICBpZiAodGhpcy5zdGFydElkKSByZXR1cm47XG4gICAgaWYgKHRoaXMuaW50ZXJ2YWxJZCkgdGhpcy5sYXN0SW50ZXJ2YWxJZCA9IHRoaXMuaW50ZXJ2YWxJZDtcbiAgICB0aGlzLmludGVydmFsSWQgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAvLyBzaW5jZSB3ZSBkb24ndCBrbm93IGhvdyBsb25nIGludG8gdGhlIGxhc3QgcG9sbCBpdCB3YXMgYmVmb3JlIHJlc2V0dGluZ1xuICAgICAgLy8gd2Ugd2FpdCB0aWwgdGhlIG5leHQgZmV0Y2ggdG8gY2xlYXIgb2xkIGludGVydmFsc1xuICAgICAgaWYgKHRoaXMubGFzdEludGVydmFsSWQpIHtcbiAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmxhc3RJbnRlcnZhbElkKTtcbiAgICAgICAgZGVsZXRlIHRoaXMubGFzdEludGVydmFsSWQ7XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5pbnRlcnZhbElkKSB0aGlzLnVwZGF0ZSgpO1xuICAgICAgZWxzZSBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgIT09ICdwcm9kdWN0aW9uJykge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgYFBvbGwgaW50ZXJ2YWxJZCBmb3IgJHt0aGlzLmtleX0gc3RpbGwgcnVubmluZywgYnV0IGludGVydmFsSWQgZGVsZXRlZGAsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSwgdGhpcy5mcmVxdWVuY3kpO1xuICB9XG5cbiAgLyoqIExhc3QgZmV0Y2ggdGltZSAqL1xuICBwcm90ZWN0ZWQgbGFzdEZldGNoVGltZSgpIHtcbiAgICByZXR1cm4gdGhpcy5jb250cm9sbGVyLmdldFN0YXRlKCkubWV0YVt0aGlzLmtleV0/LmRhdGUgPz8gMDtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiQUFHQSxPQUFPQSx5QkFBeUIsTUFBTSxnQ0FBZ0M7QUFLdEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLE1BQU1DLG1CQUFtQixDQUF5QjtFQVkvREMsV0FBV0EsQ0FDVEMsTUFBcUMsRUFDckNDLFVBQXNCLEVBQ3RCQyxrQkFBdUMsRUFDdkM7SUFBQSxLQVhRQyxrQkFBa0IsR0FBd0IsSUFBSUMsR0FBRyxDQUFDLENBQUM7SUFvSDdEO0lBQUEsS0FDVUMsZUFBZSxHQUFHLE1BQU07TUFDaEM7TUFDQSxJQUFJLENBQUNDLE9BQU8sQ0FBQyxDQUFDO01BQ2QsSUFBSSxDQUFDSixrQkFBa0IsQ0FBQ0ssaUJBQWlCLENBQUMsSUFBSSxDQUFDQyxjQUFjLENBQUM7SUFDaEUsQ0FBQztJQUVEO0lBQUEsS0FDVUEsY0FBYyxHQUFHLE1BQU07TUFDL0IsSUFBSSxDQUFDTixrQkFBa0IsQ0FBQ08sb0JBQW9CLENBQUMsSUFBSSxDQUFDRCxjQUFjLENBQUM7TUFDakUsTUFBTUUsR0FBRyxHQUFHQyxJQUFJLENBQUNELEdBQUcsQ0FBQyxDQUFDO01BQ3RCLElBQUksQ0FBQ0UsT0FBTyxHQUFHQyxVQUFVLENBQ3ZCLE1BQU07UUFDSixJQUFJLElBQUksQ0FBQ0QsT0FBTyxFQUFFO1VBQ2hCLE9BQU8sSUFB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