@glimmer/runtime
Version:
Minimal runtime needed to render Glimmer templates
371 lines (300 loc) • 36.3 kB
JavaScript
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==