UNPKG

@glimmer/runtime

Version:

Minimal runtime needed to render Glimmer templates

371 lines (300 loc) 36.3 kB
import { registerDestructor } from '@glimmer/destroyable'; import { DEBUG } from '@glimmer/env'; import { setInternalModifierManager } from '@glimmer/manager'; import { valueForRef } from '@glimmer/reference'; import { reifyNamed } from '@glimmer/runtime'; import { createUpdatableTag } from '@glimmer/validator'; import { buildUntouchableThis } from '@glimmer/util'; const untouchableContext = buildUntouchableThis('`on` modifier'); /* Internet Explorer 11 does not support `once` and also does not support passing `eventOptions`. In some situations it then throws a weird script error, like: ``` Could not complete the operation due to error 80020101 ``` This flag determines, whether `{ once: true }` and thus also event options in general are supported. */ const SUPPORTS_EVENT_OPTIONS = (() => { try { const div = document.createElement('div'); let counter = 0; div.addEventListener('click', () => counter++, { once: true }); let event; if (typeof Event === 'function') { event = new Event('click'); } else { event = document.createEvent('Event'); event.initEvent('click', true, true); } div.dispatchEvent(event); div.dispatchEvent(event); return counter === 1; } catch (error) { return false; } })(); export class OnModifierState { constructor(element, args) { this.tag = createUpdatableTag(); this.shouldUpdate = true; this.element = element; this.args = args; } updateFromArgs() { let { args } = this; let { once, passive, capture } = reifyNamed(args.named); if (once !== this.once) { this.once = once; this.shouldUpdate = true; } if (passive !== this.passive) { this.passive = passive; this.shouldUpdate = true; } if (capture !== this.capture) { this.capture = capture; this.shouldUpdate = true; } let options; // we want to handle both `true` and `false` because both have a meaning: // https://bugs.chromium.org/p/chromium/issues/detail?id=770208 if (once !== undefined || passive !== undefined || capture !== undefined) { options = this.options = { once, passive, capture }; } else { this.options = undefined; } if (DEBUG && (args.positional[0] === undefined || typeof valueForRef(args.positional[0]) !== 'string')) { throw new Error('You must pass a valid DOM event name as the first argument to the `on` modifier'); } let eventName = valueForRef(args.positional[0]); if (eventName !== this.eventName) { this.eventName = eventName; this.shouldUpdate = true; } let userProvidedCallbackReference = args.positional[1]; if (DEBUG) { if (args.positional[1] === undefined) { throw new Error(`You must pass a function as the second argument to the \`on\` modifier.`); } let value = valueForRef(userProvidedCallbackReference); if (typeof value !== 'function') { throw new Error(`You must pass a function as the second argument to the \`on\` modifier; you passed ${value === null ? 'null' : typeof value}. While rendering:\n\n${userProvidedCallbackReference.debugLabel}`); } } let userProvidedCallback = valueForRef(userProvidedCallbackReference); if (userProvidedCallback !== this.userProvidedCallback) { this.userProvidedCallback = userProvidedCallback; this.shouldUpdate = true; } if (DEBUG && args.positional.length !== 2) { throw new Error(`You can only pass two positional arguments (event name and callback) to the \`on\` modifier, but you provided ${args.positional.length}. Consider using the \`fn\` helper to provide additional arguments to the \`on\` callback.`); } let needsCustomCallback = SUPPORTS_EVENT_OPTIONS === false && once || /* needs manual once implementation */ DEBUG && passive; /* needs passive enforcement */ if (this.shouldUpdate) { if (needsCustomCallback) { let callback = this.callback = function (event) { if (DEBUG && passive) { event.preventDefault = () => { throw new Error(`You marked this listener as 'passive', meaning that you must not call 'event.preventDefault()': \n\n${userProvidedCallback}`); }; } if (!SUPPORTS_EVENT_OPTIONS && once) { removeEventListener(this, eventName, callback, options); } return userProvidedCallback.call(untouchableContext, event); }; } else if (DEBUG) { // prevent the callback from being bound to the element this.callback = userProvidedCallback.bind(untouchableContext); } else { this.callback = userProvidedCallback; } } } } let adds = 0; let removes = 0; function removeEventListener(element, eventName, callback, options) { removes++; if (SUPPORTS_EVENT_OPTIONS) { // when options are supported, use them across the board element.removeEventListener(eventName, callback, options); } else if (options !== undefined && options.capture) { // used only in the following case: // // `{ once: true | false, passive: true | false, capture: true } // // `once` is handled via a custom callback that removes after first // invocation so we only care about capture here as a boolean element.removeEventListener(eventName, callback, true); } else { // used only in the following cases: // // * where there is no options // * `{ once: true | false, passive: true | false, capture: false } element.removeEventListener(eventName, callback); } } function addEventListener(element, eventName, callback, options) { adds++; if (SUPPORTS_EVENT_OPTIONS) { // when options are supported, use them across the board element.addEventListener(eventName, callback, options); } else if (options !== undefined && options.capture) { // used only in the following case: // // `{ once: true | false, passive: true | false, capture: true } // // `once` is handled via a custom callback that removes after first // invocation so we only care about capture here as a boolean element.addEventListener(eventName, callback, true); } else { // used only in the following cases: // // * where there is no options // * `{ once: true | false, passive: true | false, capture: false } element.addEventListener(eventName, callback); } } /** The `{{on}}` modifier lets you easily add event listeners (it uses [EventTarget.addEventListener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) internally). For example, if you'd like to run a function on your component when a `<button>` in the components template is clicked you might do something like: ```app/components/like-post.hbs <button {{on 'click' this.saveLike}}>Like this post!</button> ``` ```app/components/like-post.js import Component from '@glimmer/component'; import { action } from '@ember/object'; export default class LikePostComponent extends Component { saveLike = () => { // someone likes your post! // better send a request off to your server... } } ``` ### Arguments `{{on}}` accepts two positional arguments, and a few named arguments. The positional arguments are: - `event` -- the name to use when calling `addEventListener` - `callback` -- the function to be passed to `addEventListener` The named arguments are: - capture -- a `true` value indicates that events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree. - once -- indicates that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked. - passive -- if `true`, indicates that the function specified by listener will never call preventDefault(). If a passive listener does call preventDefault(), the user agent will do nothing other than generate a console warning. See [Improving scrolling performance with passive listeners](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Improving_scrolling_performance_with_passive_listeners) to learn more. The callback function passed to `{{on}}` will receive any arguments that are passed to the event handler. Most commonly this would be the `event` itself. If you would like to pass additional arguments to the function you should use the `{{fn}}` helper. For example, in our example case above if you'd like to pass in the post that was being liked when the button is clicked you could do something like: ```app/components/like-post.hbs <button {{on 'click' (fn this.saveLike @post)}}>Like this post!</button> ``` In this case, the `saveLike` function will receive two arguments: the click event and the value of `@post`. ### Function Context In the example above, we used an arrow function to ensure that `likePost` is properly bound to the `items-list`, but let's explore what happens if we left out the arrow function: ```app/components/like-post.js import Component from '@glimmer/component'; export default class LikePostComponent extends Component { saveLike() { // ...snip... } } ``` In this example, when the button is clicked `saveLike` will be invoked, it will **not** have access to the component instance. In other words, it will have no `this` context, so please make sure your functions are bound (via an arrow function or other means) before passing into `on`! @method on @public */ class OnModifierManager { constructor() { this.SUPPORTS_EVENT_OPTIONS = SUPPORTS_EVENT_OPTIONS; } getDebugName() { return 'on'; } get counters() { return { adds, removes }; } create(_owner, element, _state, args) { return new OnModifierState(element, args); } getTag(state) { if (state === null) { return null; } return state.tag; } install(state) { if (state === null) { return; } state.updateFromArgs(); let { element, eventName, callback, options } = state; addEventListener(element, eventName, callback, options); registerDestructor(state, () => removeEventListener(element, eventName, callback, options)); state.shouldUpdate = false; } update(state) { if (state === null) { return; } // stash prior state for el.removeEventListener let { element, eventName, callback, options } = state; state.updateFromArgs(); if (!state.shouldUpdate) { return; } // use prior state values for removal removeEventListener(element, eventName, callback, options); // read updated values from the state object addEventListener(state.element, state.eventName, state.callback, state.options); state.shouldUpdate = false; } getDestroyable(state) { return state; } } export default setInternalModifierManager(new OnModifierManager(), {}); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL0BnbGltbWVyL3J1bnRpbWUvbGliL21vZGlmaWVycy9vbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxTQUFTLGtCQUFULFFBQW1DLHNCQUFuQztBQUNBLFNBQVMsS0FBVCxRQUFzQixjQUF0QjtBQUVBLFNBQVMsMEJBQVQsUUFBMkMsa0JBQTNDO0FBQ0EsU0FBUyxXQUFULFFBQTRCLG9CQUE1QjtBQUNBLFNBQVMsVUFBVCxRQUEyQixrQkFBM0I7QUFDQSxTQUFTLGtCQUFULFFBQWlELG9CQUFqRDtBQUVBLFNBQVMsb0JBQVQsUUFBcUMsZUFBckM7QUFFQSxNQUFNLGtCQUFrQixHQUFHLG9CQUFvQixDQUFDLGVBQUQsQ0FBL0M7QUFFQTs7Ozs7Ozs7Ozs7OztBQVlBLE1BQU0sc0JBQXNCLEdBQUcsQ0FBQyxNQUFLO0FBQ25DLE1BQUk7QUFDRixVQUFNLEdBQUcsR0FBRyxRQUFRLENBQUMsYUFBVCxDQUF1QixLQUF2QixDQUFaO0FBQ0EsUUFBSSxPQUFPLEdBQUcsQ0FBZDtBQUNBLElBQUEsR0FBRyxDQUFDLGdCQUFKLENBQXFCLE9BQXJCLEVBQThCLE1BQU0sT0FBTyxFQUEzQyxFQUErQztBQUFFLE1BQUEsSUFBSSxFQUFFO0FBQVIsS0FBL0M7QUFFQSxRQUFJLEtBQUo7O0FBQ0EsUUFBSSxPQUFPLEtBQVAsS0FBaUIsVUFBckIsRUFBaUM7QUFDL0IsTUFBQSxLQUFLLEdBQUcsSUFBSSxLQUFKLENBQVUsT0FBVixDQUFSO0FBQ0QsS0FGRCxNQUVPO0FBQ0wsTUFBQSxLQUFLLEdBQUcsUUFBUSxDQUFDLFdBQVQsQ0FBcUIsT0FBckIsQ0FBUjtBQUNBLE1BQUEsS0FBSyxDQUFDLFNBQU4sQ0FBZ0IsT0FBaEIsRUFBeUIsSUFBekIsRUFBK0IsSUFBL0I7QUFDRDs7QUFFRCxJQUFBLEdBQUcsQ0FBQyxhQUFKLENBQWtCLEtBQWxCO0FBQ0EsSUFBQSxHQUFHLENBQUMsYUFBSixDQUFrQixLQUFsQjtBQUVB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SSxLQUFLLEtBQUssSUFBZCxFQUFvQjtBQUNsQjtBQUNELEtBSGlDLENBS2xDOzs7QUFDQSxRQUFJO0FBQUUsTUFBQSxPQUFGO0FBQVcsTUFBQSxTQUFYO0FBQXNCLE1BQUEsUUFBdEI7QUFBZ0MsTUFBQTtBQUFoQyxRQUE0QyxLQUFoRDtBQUVBLElBQUEsS0FBSyxDQUFDLGNBQU47O0FBRUEsUUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFYLEVBQXlCO0FBQ3ZCO0FBQ0QsS0FaaUMsQ0FjbEM7OztBQUNBLElBQUEsbUJBQW1CLENBQUMsT0FBRCxFQUFVLFNBQVYsRUFBcUIsUUFBckIsRUFBK0IsT0FBL0IsQ0FBbkIsQ0Fma0MsQ0FpQmxDOztBQUNBLElBQUEsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLE9BQVAsRUFBZ0IsS0FBSyxDQUFDLFNBQXRCLEVBQWlDLEtBQUssQ0FBQyxRQUF2QyxFQUFpRCxLQUFLLENBQUMsT0FBdkQsQ0FBaEI7QUFFQSxJQUFBLEtBQUssQ0FBQyxZQUFOLEdBQXFCLEtBQXJCO0FBQ0Q7O0FBRUQsRUFBQSxjQUFjLENBQUMsS0FBRCxFQUE4QjtBQUMxQyxXQUFPLEtBQVA7QUFDRDs7QUFyRW9COztBQXdFdkIsZUFBZSwwQkFBMEIsQ0FBQyxJQUFJLGlCQUFKLEVBQUQsRUFBMEIsRUFBMUIsQ0FBekMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyByZWdpc3RlckRlc3RydWN0b3IgfSBmcm9tICdAZ2xpbW1lci9kZXN0cm95YWJsZSc7XG5pbXBvcnQgeyBERUJVRyB9IGZyb20gJ0BnbGltbWVyL2Vudic7XG5pbXBvcnQgeyBDYXB0dXJlZEFyZ3VtZW50cywgSW50ZXJuYWxNb2RpZmllck1hbmFnZXIsIE93bmVyIH0gZnJvbSAnQGdsaW1tZXIvaW50ZXJmYWNlcyc7XG5pbXBvcnQgeyBzZXRJbnRlcm5hbE1vZGlmaWVyTWFuYWdlciB9IGZyb20gJ0BnbGltbWVyL21hbmFnZXInO1xuaW1wb3J0IHsgdmFsdWVGb3JSZWYgfSBmcm9tICdAZ2xpbW1lci9yZWZlcmVuY2UnO1xuaW1wb3J0IHsgcmVpZnlOYW1lZCB9IGZyb20gJ0BnbGltbWVyL3J1bnRpbWUnO1xuaW1wb3J0IHsgY3JlYXRlVXBkYXRhYmxlVGFnLCBVcGRhdGFibGVUYWcgfSBmcm9tICdAZ2xpbW1lci92YWxpZGF0b3InO1xuaW1wb3J0IHsgU2ltcGxlRWxlbWVudCB9IGZyb20gJ0BzaW1wbGUtZG9tL2ludGVyZmFjZSc7XG5pbXBvcnQgeyBidWlsZFVudG91Y2hhYmxlVGhpcyB9IGZyb20gJ0BnbGltbWVyL3V0aWwnO1xuXG5jb25zdCB1bnRvdWNoYWJsZUNvbnRleHQgPSBidWlsZFVudG91Y2hhYmxlVGhpcygnYG9uYCBtb2RpZmllcicpO1xuXG4vKlxuICBJbnRlcm5ldCBFeHBsb3JlciAxMSBkb2VzIG5vdCBzdXBwb3J0IGBvbmNlYCBhbmQgYWxzbyBkb2VzIG5vdCBzdXBwb3J0XG4gIHBhc3NpbmcgYGV2ZW50T3B0aW9uc2AuIEluIHNvbWUgc2l0dWF0aW9ucyBpdCB0aGVuIHRocm93cyBhIHdlaXJkIHNjcmlwdFxuICBlcnJvciwgbGlrZTpcblxuICBgYGBcbiAgQ291bGQgbm90IGNvbXBsZXRlIHRoZSBvcGVyYXRpb24gZHVlIHRvIGVycm9yIDgwMDIwMTAxXG4gIGBgYFxuXG4gIFRoaXMgZmxhZyBkZXRlcm1pbmVzLCB3aGV0aGVyIGB7IG9uY2U6IHRydWUgfWAgYW5kIHRodXMgYWxzbyBldmVudCBvcHRpb25zIGluXG4gIGdlbmVyYWwgYXJlIHN1cHBvcnRlZC5cbiovXG5jb25zdCBTVVBQT1JUU19FVkVOVF9PUFRJT05TID0gKCgpID0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCBkaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBsZXQgY291bnRlciA9IDA7XG4gICAgZGl2LmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKCkgPT4gY291bnRlcisrLCB7IG9uY2U6IHRydWUgfSk7XG5cbiAgICBsZXQgZXZlbnQ7XG4gICAgaWYgKHR5cGVvZiBFdmVudCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgZXZlbnQgPSBuZXcgRXZlbnQoJ2NsaWNrJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGV2ZW50ID0gZG9jdW1lbnQuY3JlYXRlRXZlbnQoJ0V2ZW50Jyk7XG4gICAgICBldmVudC5pbml0RXZlbnQoJ2NsaWNrJywgdHJ1ZSwgdHJ1ZSk7XG4gICAgfVxuXG4gICAgZGl2LmRpc3BhdGNoRXZlbnQoZXZlbnQpO1xuICAgIGRpdi5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcblxuICAgIHJldHVybiBjb3VudGVyID09PSAxO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufSkoKTtcblxuZXhwb3J0IGNsYXNzIE9uTW9kaWZpZXJTdGF0ZSB7XG4gIHB1YmxpYyB0YWcgPSBjcmVhdGVVcGRhdGFibGVUYWcoKTtcbiAgcHVibGljIGVsZW1lbnQ6IEVsZW1lbnQ7XG4gIHB1YmxpYyBhcmdzOiBDYXB0dXJlZEFyZ3VtZW50cztcbiAgcHVibGljIGV2ZW50TmFtZSE6IHN0cmluZztcbiAgcHVibGljIGNhbGxiYWNrITogRXZlbnRMaXN0ZW5lcjtcbiAgcHJpdmF0ZSB1c2VyUHJvdmlkZWRDYWxsYmFjayE6IEV2ZW50TGlzdGVuZXI7XG4gIHB1YmxpYyBvbmNlPzogYm9vbGVhbjtcbiAgcHVibGljIHBhc3NpdmU/OiBib29sZWFuO1xuICBwdWJsaWMgY2FwdHVyZT86IGJvb2xlYW47XG4gIHB1YmxpYyBvcHRpb25zPzogQWRkRXZlbnRMaXN0ZW5lck9wdGlvbnM7XG4gIHB1YmxpYyBzaG91bGRVcGRhdGUgPSB0cnVlO1xuXG4gIGNvbnN0cnVjdG9yKGVsZW1lbnQ6IEVsZW1lbnQsIGFyZ3M6IENhcHR1cmVkQXJndW1lbnRzKSB7XG4gICAgdGhpcy5lbGVtZW50ID0gZWxlbWVudDtcbiAgICB0aGlzLmFyZ3MgPSBhcmdzO1xuICB9XG5cbiAgdXBkYXRlRnJvbUFyZ3MoKTogdm9pZCB7XG4gICAgbGV0IHsgYXJncyB9ID0gdGhpcztcblxuICAgIGxldCB7IG9uY2UsIHBhc3NpdmUsIGNhcHR1cmUgfTogQWRkRXZlbnRMaXN0ZW5lck9wdGlvbnMgPSByZWlmeU5hbWVkKGFyZ3MubmFtZWQpO1xuICAgIGlmIChvbmNlICE9PSB0aGlzLm9uY2UpIHtcbiAgICAgIHRoaXMub25jZSA9IG9uY2U7XG4gICAgICB0aGlzLnNob3VsZFVwZGF0ZSA9IHRydWU7XG4gICAgfVxuXG4gICAgaWYgKHBhc3NpdmUgIT09IHRoaXMucGFzc2l2ZSkge1xuICAgICAgdGhpcy5wYXNzaXZlID0gcGFzc2l2ZTtcbiAgICAgIHRoaXMuc2hvdWxkVXBkYXRlID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBpZiAoY2FwdHVyZSAhPT0gdGhpcy5jYXB0dXJlKSB7XG4gICAgICB0aGlzLmNhcHR1cmUgPSBjYXB0dXJlO1xuICAgICAgdGhpcy5zaG91bGRVcGRhdGUgPSB0cnVlO1xuICAgIH1cblxuICAgIGxldCBvcHRpb25zOiBBZGRFdmVudExpc3RlbmVyT3B0aW9ucztcbiAgICAvLyB3ZSB3YW50IHRvIGhhbmRsZSBib3RoIGB0cnVlYCBhbmQgYGZhbHNlYCBiZWNhdXNlIGJvdGggaGF2ZSBhIG1lYW5pbmc6XG4gICAgLy8gaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL2Nocm9taXVtL2lzc3Vlcy9kZXRhaWw/aWQ9NzcwMjA4XG4gICAgaWYgKG9uY2UgIT09IHVuZGVmaW5lZCB8fCBwYXNzaXZlICE9PSB1bmRlZmluZWQgfHwgY2FwdHVyZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBvcHRpb25zID0gdGhpcy5vcHRpb25zID0geyBvbmNlLCBwYXNzaXZlLCBjYXB0dXJlIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMub3B0aW9ucyA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBERUJVRyAmJlxuICAgICAgKGFyZ3MucG9zaXRpb25hbFswXSA9PT0gdW5kZWZpbmVkIHx8IHR5cGVvZiB2YWx1ZUZvclJlZihhcmdzLnBvc2l0aW9uYWxbMF0pICE9PSAnc3RyaW5nJylcbiAgICApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ1lvdSBtdXN0IHBhc3MgYSB2YWxpZCBET00gZXZlbnQgbmFtZSBhcyB0aGUgZmlyc3QgYXJndW1lbnQgdG8gdGhlIGBvbmAgbW9kaWZpZXInXG4gICAgICApO1xuICAgIH1cblxuICAgIGxldCBldmVudE5hbWUgPSB2YWx1ZUZvclJlZihhcmdzLnBvc2l0aW9uYWxbMF0pIGFzIHN0cmluZztcbiAgICBpZiAoZXZlbnROYW1lICE9PSB0aGlzLmV2ZW50TmFtZSkge1xuICAgICAgdGhpcy5ldmVudE5hbWUgPSBldmVudE5hbWU7XG4gICAgICB0aGlzLnNob3VsZFVwZGF0ZSA9IHRydWU7XG4gICAgfVxuXG4gICAgbGV0IHVzZXJQcm92aWRlZENhbGxiYWNrUmVmZXJlbmNlID0gYXJncy5wb3NpdGlvbmFsWzFdO1xuXG4gICAgaWYgKERFQlVHKSB7XG4gICAgICBpZiAoYXJncy5wb3NpdGlvbmFsWzFdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBZb3UgbXVzdCBwYXNzIGEgZnVuY3Rpb24gYXMgdGhlIHNlY29uZCBhcmd1bWVudCB0byB0aGUgXFxgb25cXGAgbW9kaWZpZXIuYCk7XG4gICAgICB9XG5cbiAgICAgIGxldCB2YWx1ZSA9IHZhbHVlRm9yUmVmKHVzZXJQcm92aWRlZENhbGxiYWNrUmVmZXJlbmNlKTtcblxuICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYFlvdSBtdXN0IHBhc3MgYSBmdW5jdGlvbiBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IHRvIHRoZSBcXGBvblxcYCBtb2RpZmllcjsgeW91IHBhc3NlZCAke1xuICAgICAgICAgICAgdmFsdWUgPT09IG51bGwgPyAnbnVsbCcgOiB0eXBlb2YgdmFsdWVcbiAgICAgICAgICB9LiBXaGlsZSByZW5kZXJpbmc6XFxuXFxuJHt1c2VyUHJvdmlkZWRDYWxsYmFja1JlZmVyZW5jZS5kZWJ1Z0xhYmVsfWBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgdXNlclByb3ZpZGVkQ2FsbGJhY2sgPSB2YWx1ZUZvclJlZih1c2VyUHJvdmlkZWRDYWxsYmFja1JlZmVyZW5jZSkgYXMgRXZlbnRMaXN0ZW5lcjtcbiAgICBpZiAodXNlclByb3ZpZGVkQ2FsbGJhY2sgIT09IHRoaXMudXNlclByb3ZpZGVkQ2FsbGJhY2spIHtcbiAgICAgIHRoaXMudXNlclByb3ZpZGVkQ2FsbGJhY2sgPSB1c2VyUHJvdmlkZWRDYWxsYmFjaztcbiAgICAgIHRoaXMuc2hvdWxkVXBkYXRlID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBpZiAoREVCVUcgJiYgYXJncy5wb3NpdGlvbmFsLmxlbmd0aCAhPT0gMikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgWW91IGNhbiBvbmx5IHBhc3MgdHdvIHBvc2l0aW9uYWwgYXJndW1lbnRzIChldmVudCBuYW1lIGFuZCBjYWxsYmFjaykgdG8gdGhlIFxcYG9uXFxgIG1vZGlmaWVyLCBidXQgeW91IHByb3ZpZGVkICR7YXJncy5wb3NpdGlvbmFsLmxlbmd0aH0uIENvbnNpZGVyIHVzaW5nIHRoZSBcXGBmblxcYCBoZWxwZXIgdG8gcHJvdmlkZSBhZGRpdGlvbmFsIGFyZ3VtZW50cyB0byB0aGUgXFxgb25cXGAgY2FsbGJhY2suYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBsZXQgbmVlZHNDdXN0b21DYWxsYmFjayA9XG4gICAgICAoU1VQUE9SVFNfRVZFTlRfT1BUSU9OUyA9PT0gZmFsc2UgJiYgb25jZSkgLyogbmVlZHMgbWFudWFsIG9uY2UgaW1wbGVtZW50YXRpb24gKi8gfHxcbiAgICAgIChERUJVRyAmJiBwYXNzaXZlKTsgLyogbmVlZHMgcGFzc2l2ZSBlbmZvcmNlbWVudCAqL1xuXG4gICAgaWYgKHRoaXMuc2hvdWxkVXBkYXRlKSB7XG4gICAgICBpZiAobmVlZHNDdXN0b21DYWxsYmFjaykge1xuICAgICAgICBsZXQgY2FsbGJhY2sgPSAodGhpcy5jYWxsYmFjayA9IGZ1bmN0aW9uICh0aGlzOiBFbGVtZW50LCBldmVudCkge1xuICAgICAgICAgIGlmIChERUJVRyAmJiBwYXNzaXZlKSB7XG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCA9ICgpID0+IHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgIGBZb3UgbWFya2VkIHRoaXMgbGlzdGVuZXIgYXMgJ3Bhc3NpdmUnLCBtZWFuaW5nIHRoYXQgeW91IG11c3Qgbm90IGNhbGwgJ2V2ZW50LnByZXZlbnREZWZhdWx0KCknOiBcXG5cXG4ke3VzZXJQcm92aWRlZENhbGxiYWNrfWBcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKCFTVVBQT1JUU19FVkVOVF9PUFRJT05TICYmIG9uY2UpIHtcbiAgICAgICAgICAgIHJlbW92ZUV2ZW50TGlzdGVuZXIodGhpcywgZXZlbnROYW1lLCBjYWxsYmFjaywgb3B0aW9ucyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB1c2VyUHJvdmlkZWRDYWxsYmFjay5jYWxsKHVudG91Y2hhYmxlQ29udGV4dCwgZXZlbnQpO1xuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoREVCVUcpIHtcbiAgICAgICAgLy8gcHJldmVudCB0aGUgY2FsbGJhY2sgZnJvbSBiZWluZyBib3VuZCB0byB0aGUgZWxlbWVudFxuICAgICAgICB0aGlzLmNhbGxiYWNrID0gdXNlclByb3ZpZGVkQ2FsbGJhY2suYmluZCh1bnRvdWNoYWJsZUNvbnRleHQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5jYWxsYmFjayA9IHVzZXJQcm92aWRlZENhbGxiYWNrO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5sZXQgYWRkcyA9IDA7XG5sZXQgcmVtb3ZlcyA9IDA7XG5cbmZ1bmN0aW9uIHJlbW92ZUV2ZW50TGlzdGVuZXIoXG4gIGVsZW1lbnQ6IEVsZW1lbnQsXG4gIGV2ZW50TmFtZTogc3RyaW5nLFxuICBjYWxsYmFjazogRXZlbnRMaXN0ZW5lcixcbiAgb3B0aW9ucz86IEFkZEV2ZW50TGlzdGVuZXJPcHRpb25zXG4pOiB2b2lkIHtcbiAgcmVtb3ZlcysrO1xuXG4gIGlmIChTVVBQT1JUU19FVkVOVF9PUFRJT05TKSB7XG4gICAgLy8gd2hlbiBvcHRpb25zIGFyZSBzdXBwb3J0ZWQsIHVzZSB0aGVtIGFjcm9zcyB0aGUgYm9hcmRcbiAgICBlbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCBjYWxsYmFjaywgb3B0aW9ucyk7XG4gIH0gZWxzZSBpZiAob3B0aW9ucyAhPT0gdW5kZWZpbmVkICYmIG9wdGlvbnMuY2FwdHVyZSkge1xuICAgIC8vIHVzZWQgb25seSBpbiB0aGUgZm9sbG93aW5nIGNhc2U6XG4gICAgLy9cbiAgICAvLyBgeyBvbmNlOiB0cnVlIHwgZmFsc2UsIHBhc3NpdmU6IHRydWUgfCBmYWxzZSwgY2FwdHVyZTogdHJ1ZSB9XG4gICAgLy9cbiAgICAvLyBgb25jZWAgaXMgaGFuZGxlZCB2aWEgYSBjdXN0b20gY2FsbGJhY2sgdGhhdCByZW1vdmVzIGFmdGVyIGZpcnN0XG4gICAgLy8gaW52b2NhdGlvbiBzbyB3ZSBvbmx5IGNhcmUgYWJvdXQgY2FwdHVyZSBoZXJlIGFzIGEgYm9vbGVhblxuICAgIGVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsIGNhbGxiYWNrLCB0cnVlKTtcbiAgfSBlbHNlIHtcbiAgICAvLyB1c2VkIG9ubHkgaW4gdGhlIGZvbGxvd2luZyBjYXNlczpcbiAgICAvL1xuICAgIC8vICogd2hlcmUgdGhlcmUgaXMgbm8gb3B0aW9uc1xuICAgIC8vICogYHsgb25jZTogdHJ1ZSB8IGZhbHNlLCBwYXNzaXZlOiB0cnVlIHwgZmFsc2UsIGNhcHR1cmU6IGZhbHNlIH1cbiAgICBlbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCBjYWxsYmFjayk7XG4gIH1cbn1cblxuZnVuY3Rpb24gYWRkRXZlbnRMaXN0ZW5lcihcbiAgZWxlbWVudDogRWxlbWVudCxcbiAgZXZlbnROYW1lOiBzdHJpbmcsXG4gIGNhbGxiYWNrOiBFdmVudExpc3RlbmVyLFxuICBvcHRpb25zPzogQWRkRXZlbnRMaXN0ZW5lck9wdGlvbnNcbik6IHZvaWQge1xuICBhZGRzKys7XG5cbiAgaWYgKFNVUFBPUlRTX0VWRU5UX09QVElPTlMpIHtcbiAgICAvLyB3aGVuIG9wdGlvbnMgYXJlIHN1cHBvcnRlZCwgdXNlIHRoZW0gYWNyb3NzIHRoZSBib2FyZFxuICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsIGNhbGxiYWNrLCBvcHRpb25zKTtcbiAgfSBlbHNlIGlmIChvcHRpb25zICE9PSB1bmRlZmluZWQgJiYgb3B0aW9ucy5jYXB0dXJlKSB7XG4gICAgLy8gdXNlZCBvbmx5IGluIHRoZSBmb2xsb3dpbmcgY2FzZTpcbiAgICAvL1xuICAgIC8vIGB7IG9uY2U6IHRydWUgfCBmYWxzZSwgcGFzc2l2ZTogdHJ1ZSB8IGZhbHNlLCBjYXB0dXJlOiB0cnVlIH1cbiAgICAvL1xuICAgIC8vIGBvbmNlYCBpcyBoYW5kbGVkIHZpYSBhIGN1c3RvbSBjYWxsYmFjayB0aGF0IHJlbW92ZXMgYWZ0ZXIgZmlyc3RcbiAgICAvLyBpbnZvY2F0aW9uIHNvIHdlIG9ubHkgY2FyZSBhYm91dCBjYXB0dXJlIGhlcmUgYXMgYSBib29sZWFuXG4gICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgY2FsbGJhY2ssIHRydWUpO1xuICB9IGVsc2Uge1xuICAgIC8vIHVzZWQgb25seSBpbiB0aGUgZm9sbG93aW5nIGNhc2VzOlxuICAgIC8vXG4gICAgLy8gKiB3aGVyZSB0aGVyZSBpcyBubyBvcHRpb25zXG4gICAgLy8gKiBgeyBvbmNlOiB0cnVlIHwgZmFsc2UsIHBhc3NpdmU6IHRydWUgfCBmYWxzZSwgY2FwdHVyZTogZmFsc2UgfVxuICAgIGVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsIGNhbGxiYWNrKTtcbiAgfVxufVxuXG4vKipcbiAgVGhlIGB7e29ufX1gIG1vZGlmaWVyIGxldHMgeW91IGVhc2lseSBhZGQgZXZlbnQgbGlzdGVuZXJzIChpdCB1c2VzXG4gIFtFdmVudFRhcmdldC5hZGRFdmVudExpc3RlbmVyXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvRXZlbnRUYXJnZXQvYWRkRXZlbnRMaXN0ZW5lcilcbiAgaW50ZXJuYWxseSkuXG5cbiAgRm9yIGV4YW1wbGUsIGlmIHlvdSdkIGxpa2UgdG8gcnVuIGEgZnVuY3Rpb24gb24geW91ciBjb21wb25lbnQgd2hlbiBhIGA8YnV0dG9uPmBcbiAgaW4gdGhlIGNvbXBvbmVudHMgdGVtcGxhdGUgaXMgY2xpY2tlZCB5b3UgbWlnaHQgZG8gc29tZXRoaW5nIGxpa2U6XG5cbiAgYGBgYXBwL2NvbXBvbmVudHMvbGlrZS1wb3N0Lmhic1xuICA8YnV0dG9uIHt7b24gJ2NsaWNrJyB0aGlzLnNhdmVMaWtlfX0+TGlrZSB0aGlzIHBvc3QhPC9idXR0b24+XG4gIGBgYFxuXG4gIGBgYGFwcC9jb21wb25lbnRzL2xpa2UtcG9zdC5qc1xuICBpbXBvcnQgQ29tcG9uZW50IGZyb20gJ0BnbGltbWVyL2NvbXBvbmVudCc7XG4gIGltcG9ydCB7IGFjdGlvbiB9IGZyb20gJ0BlbWJlci9vYmplY3QnO1xuXG4gIGV4cG9ydCBkZWZhdWx0IGNsYXNzIExpa2VQb3N0Q29tcG9uZW50IGV4dGVuZHMgQ29tcG9uZW50IHtcbiAgICBzYXZlTGlrZSA9ICgpID0+IHtcbiAgICAgIC8vIHNvbWVvbmUgbGlrZXMgeW91ciBwb3N0IVxuICAgICAgLy8gYmV0dGVyIHNlbmQgYSByZXF1ZXN0IG9mZiB0byB5b3VyIHNlcnZlci4uLlxuICAgIH1cbiAgfVxuICBgYGBcblxuICAjIyMgQXJndW1lbnRzXG5cbiAgYHt7b259fWAgYWNjZXB0cyB0d28gcG9zaXRpb25hbCBhcmd1bWVudHMsIGFuZCBhIGZldyBuYW1lZCBhcmd1bWVudHMuXG5cbiAgVGhlIHBvc2l0aW9uYWwgYXJndW1lbnRzIGFyZTpcblxuICAtIGBldmVudGAgLS0gdGhlIG5hbWUgdG8gdXNlIHdoZW4gY2FsbGluZyBgYWRkRXZlbnRMaXN0ZW5lcmBcbiAgLSBgY2FsbGJhY2tgIC0tIHRoZSBmdW5jdGlvbiB0byBiZSBwYXNzZWQgdG8gYGFkZEV2ZW50TGlzdGVuZXJgXG5cbiAgVGhlIG5hbWVkIGFyZ3VtZW50cyBhcmU6XG5cbiAgLSBjYXB0dXJlIC0tIGEgYHRydWVgIHZhbHVlIGluZGljYXRlcyB0aGF0IGV2ZW50cyBvZiB0aGlzIHR5cGUgd2lsbCBiZSBkaXNwYXRjaGVkXG4gICAgdG8gdGhlIHJlZ2lzdGVyZWQgbGlzdGVuZXIgYmVmb3JlIGJlaW5nIGRpc3BhdGNoZWQgdG8gYW55IEV2ZW50VGFyZ2V0IGJlbmVhdGggaXRcbiAgICBpbiB0aGUgRE9NIHRyZWUuXG4gIC0gb25jZSAtLSBpbmRpY2F0ZXMgdGhhdCB0aGUgbGlzdGVuZXIgc2hvdWxkIGJlIGludm9rZWQgYXQgbW9zdCBvbmNlIGFmdGVyIGJlaW5nXG4gICAgYWRkZWQuIElmIHRydWUsIHRoZSBsaXN0ZW5lciB3b3VsZCBiZSBhdXRvbWF0aWNhbGx5IHJlbW92ZWQgd2hlbiBpbnZva2VkLlxuICAtIHBhc3NpdmUgLS0gaWYgYHRydWVgLCBpbmRpY2F0ZXMgdGhhdCB0aGUgZnVuY3Rpb24gc3BlY2lmaWVkIGJ5IGxpc3RlbmVyIHdpbGwgbmV2ZXJcbiAgICBjYWxsIHByZXZlbnREZWZhdWx0KCkuIElmIGEgcGFzc2l2ZSBsaXN0ZW5lciBkb2VzIGNhbGwgcHJldmVudERlZmF1bHQoKSwgdGhlIHVzZXJcbiAgICBhZ2VudCB3aWxsIGRvIG5vdGhpbmcgb3RoZXIgdGhhbiBnZW5lcmF0ZSBhIGNvbnNvbGUgd2FybmluZy4gU2VlXG4gICAgW0ltcHJvdmluZyBzY3JvbGxpbmcgcGVyZm9ybWFuY2Ugd2l0aCBwYXNzaXZlIGxpc3RlbmVyc10oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0V2ZW50VGFyZ2V0L2FkZEV2ZW50TGlzdGVuZXIjSW1wcm92aW5nX3Njcm9sbGluZ19wZXJmb3JtYW5jZV93aXRoX3Bhc3NpdmVfbGlzdGVuZXJzKVxuICAgIHRvIGxlYXJuIG1vcmUuXG5cbiAgVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHBhc3NlZCB0byBge3tvbn19YCB3aWxsIHJlY2VpdmUgYW55IGFyZ3VtZW50cyB0aGF0IGFyZSBwYXNzZWRcbiAgdG8gdGhlIGV2ZW50IGhhbmRsZXIuIE1vc3QgY29tbW9ubHkgdGhpcyB3b3VsZCBiZSB0aGUgYGV2ZW50YCBpdHNlbGYuXG5cbiAgSWYgeW91IHdvdWxkIGxpa2UgdG8gcGFzcyBhZGRpdGlvbmFsIGFyZ3VtZW50cyB0byB0aGUgZnVuY3Rpb24geW91IHNob3VsZCB1c2VcbiAgdGhlIGB7e2ZufX1gIGhlbHBlci5cblxuICBGb3IgZXhhbXBsZSwgaW4gb3VyIGV4YW1wbGUgY2FzZSBhYm92ZSBpZiB5b3UnZCBsaWtlIHRvIHBhc3MgaW4gdGhlIHBvc3QgdGhhdFxuICB3YXMgYmVpbmcgbGlrZWQgd2hlbiB0aGUgYnV0dG9uIGlzIGNsaWNrZWQgeW91IGNvdWxkIGRvIHNvbWV0aGluZyBsaWtlOlxuXG4gIGBgYGFwcC9jb21wb25lbnRzL2xpa2UtcG9zdC5oYnNcbiAgPGJ1dHRvbiB7e29uICdjbGljaycgKGZuIHRoaXMuc2F2ZUxpa2UgQHBvc3QpfX0+TGlrZSB0aGlzIHBvc3QhPC9idXR0b24+XG4gIGBgYFxuXG4gIEluIHRoaXMgY2FzZSwgdGhlIGBzYXZlTGlrZWAgZnVuY3Rpb24gd2lsbCByZWNlaXZlIHR3byBhcmd1bWVudHM6IHRoZSBjbGljayBldmVudFxuICBhbmQgdGhlIHZhbHVlIG9mIGBAcG9zdGAuXG5cbiAgIyMjIEZ1bmN0aW9uIENvbnRleHRcblxuICBJbiB0aGUgZXhhbXBsZSBhYm92ZSwgd2UgdXNlZCBhbiBhcnJvdyBmdW5jdGlvbiB0byBlbnN1cmUgdGhhdCBgbGlrZVBvc3RgIGlzXG4gIHByb3Blcmx5IGJvdW5kIHRvIHRoZSBgaXRlbXMtbGlzdGAsIGJ1dCBsZXQncyBleHBsb3JlIHdoYXQgaGFwcGVucyBpZiB3ZVxuICBsZWZ0IG91dCB0aGUgYXJyb3cgZnVuY3Rpb246XG5cbiAgYGBgYXBwL2NvbXBvbmVudHMvbGlrZS1wb3N0LmpzXG4gIGltcG9ydCBDb21wb25lbnQgZnJvbSAnQGdsaW1tZXIvY29tcG9uZW50JztcblxuICBleHBvcnQgZGVmYXVsdCBjbGFzcyBMaWtlUG9zdENvbXBvbmVudCBleHRlbmRzIENvbXBvbmVudCB7XG4gICAgc2F2ZUxpa2UoKSB7XG4gICAgICAvLyAuLi5zbmlwLi4uXG4gICAgfVxuICB9XG4gIGBgYFxuXG4gIEluIHRoaXMgZXhhbXBsZSwgd2hlbiB0aGUgYnV0dG9uIGlzIGNsaWNrZWQgYHNhdmVMaWtlYCB3aWxsIGJlIGludm9rZWQsXG4gIGl0IHdpbGwgKipub3QqKiBoYXZlIGFjY2VzcyB0byB0aGUgY29tcG9uZW50IGluc3RhbmNlLiBJbiBvdGhlclxuICB3b3JkcywgaXQgd2lsbCBoYXZlIG5vIGB0aGlzYCBjb250ZXh0LCBzbyBwbGVhc2UgbWFrZSBzdXJlIHlvdXIgZnVuY3Rpb25zXG4gIGFyZSBib3VuZCAodmlhIGFuIGFycm93IGZ1bmN0aW9uIG9yIG90aGVyIG1lYW5zKSBiZWZvcmUgcGFzc2luZyBpbnRvIGBvbmAhXG5cbiAgQG1ldGhvZCBvblxuICBAcHVibGljXG4qL1xuY2xhc3MgT25Nb2RpZmllck1hbmFnZXIgaW1wbGVtZW50cyBJbnRlcm5hbE1vZGlmaWVyTWFuYWdlcjxPbk1vZGlmaWVyU3RhdGUgfCBudWxsLCBvYmplY3Q+IHtcbiAgcHVibGljIFNVUFBPUlRTX0VWRU5UX09QVElPTlM6IGJvb2xlYW4gPSBTVVBQT1JUU19FVkVOVF9PUFRJT05TO1xuXG4gIGdldERlYnVnTmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiAnb24nO1xuICB9XG5cbiAgZ2V0IGNvdW50ZXJzKCk6IHsgYWRkczogbnVtYmVyOyByZW1vdmVzOiBudW1iZXIgfSB7XG4gICAgcmV0dXJuIHsgYWRkcywgcmVtb3ZlcyB9O1xuICB9XG5cbiAgY3JlYXRlKFxuICAgIF9vd25lcjogT3duZXIsXG4gICAgZWxlbWVudDogU2ltcGxlRWxlbWVudCB8IEVsZW1lbnQsXG4gICAgX3N0YXRlOiBvYmplY3QsXG4gICAgYXJnczogQ2FwdHVyZWRBcmd1bWVudHNcbiAgKTogT25Nb2RpZmllclN0YXRlIHwgbnVsbCB7XG4gICAgcmV0dXJuIG5ldyBPbk1vZGlmaWVyU3RhdGUoZWxlbWVudCBhcyBFbGVtZW50LCBhcmdzKTtcbiAgfVxuXG4gIGdldFRhZyhzdGF0ZTogT25Nb2RpZmllclN0YXRlIHwgbnVsbCk6IFVwZGF0YWJsZVRhZyB8IG51bGwge1xuICAgIGlmIChzdGF0ZSA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgcmV0dXJuIHN0YXRlLnRhZztcbiAgfVxuXG4gIGluc3RhbGwoc3RhdGU6IE9uTW9kaWZpZXJTdGF0ZSB8IG51bGwpOiB2b2lkIHtcbiAgICBpZiAoc3RhdGUgPT09IG51bGwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBzdGF0ZS51cGRhdGVGcm9tQXJncygpO1xuXG4gICAgbGV0IHsgZWxlbWVudCwgZXZlbnROYW1lLCBjYWxsYmFjaywgb3B0aW9ucyB9ID0gc3RhdGU7XG5cbiAgICBhZGRFdmVudExpc3RlbmVyKGVsZW1lbnQsIGV2ZW50TmFtZSwgY2FsbGJhY2ssIG9wdGlvbnMpO1xuXG4gICAgcmVnaXN0ZXJEZXN0cnVjdG9yKHN0YXRlLCAoKSA9PiByZW1vdmVFdmVudExpc3RlbmVyKGVsZW1lbnQsIGV2ZW50TmFtZSwgY2FsbGJhY2ssIG9wdGlvbnMpKTtcblxuICAgIHN0YXRlLnNob3VsZFVwZGF0ZSA9IGZhbHNlO1xuICB9XG5cbiAgdXBkYXRlKHN0YXRlOiBPbk1vZGlmaWVyU3RhdGUgfCBudWxsKTogdm9pZCB7XG4gICAgaWYgKHN0YXRlID09PSBudWxsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gc3Rhc2ggcHJpb3Igc3RhdGUgZm9yIGVsLnJlbW92ZUV2ZW50TGlzdGVuZXJcbiAgICBsZXQgeyBlbGVtZW50LCBldmVudE5hbWUsIGNhbGxiYWNrLCBvcHRpb25zIH0gPSBzdGF0ZTtcblxuICAgIHN0YXRlLnVwZGF0ZUZyb21BcmdzKCk7XG5cbiAgICBpZiAoIXN0YXRlLnNob3VsZFVwZGF0ZSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHVzZSBwcmlvciBzdGF0ZSB2YWx1ZXMgZm9yIHJlbW92YWxcbiAgICByZW1vdmVFdmVudExpc3RlbmVyKGVsZW1lbnQsIGV2ZW50TmFtZSwgY2FsbGJhY2ssIG9wdGlvbnMpO1xuXG4gICAgLy8gcmVhZCB1cGRhdGVkIHZhbHVlcyBmcm9tIHRoZSBzdGF0ZSBvYmplY3RcbiAgICBhZGRFdmVudExpc3RlbmVyKHN0YXRlLmVsZW1lbnQsIHN0YXRlLmV2ZW50TmFtZSwgc3RhdGUuY2FsbGJhY2ssIHN0YXRlLm9wdGlvbnMpO1xuXG4gICAgc3RhdGUuc2hvdWxkVXBkYXRlID0gZmFsc2U7XG4gIH1cblxuICBnZXREZXN0cm95YWJsZShzdGF0ZTogT25Nb2RpZmllclN0YXRlIHwgbnVsbCk6IE9uTW9kaWZpZXJTdGF0ZSB8IG51bGwge1xuICAgIHJldHVybiBzdGF0ZTtcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBzZXRJbnRlcm5hbE1vZGlmaWVyTWFuYWdlcihuZXcgT25Nb2RpZmllck1hbmFnZXIoKSwge30pO1xuIl0sInNvdXJjZVJvb3QiOiIifQ==