@angular/core
Version:
Angular - the core framework
171 lines • 25.3 kB
JavaScript
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { createWatch } from '@angular/core/primitives/signals';
import { ChangeDetectorRef } from '../../change_detection';
import { assertInInjectionContext } from '../../di/contextual';
import { InjectionToken } from '../../di/injection_token';
import { Injector } from '../../di/injector';
import { inject } from '../../di/injector_compatibility';
import { ɵɵdefineInjectable } from '../../di/interface/defs';
import { ErrorHandler } from '../../error_handler';
import { DestroyRef } from '../../linker/destroy_ref';
import { FLAGS, EFFECTS_TO_SCHEDULE } from '../interfaces/view';
import { assertNotInReactiveContext } from './asserts';
/**
* Not public API, which guarantees `EffectScheduler` only ever comes from the application root
* injector.
*/
export const APP_EFFECT_SCHEDULER = new InjectionToken('', {
providedIn: 'root',
factory: () => inject(EffectScheduler),
});
/**
* A scheduler which manages the execution of effects.
*/
export class EffectScheduler {
/** @nocollapse */
static { this.ɵprov = ɵɵdefineInjectable({
token: EffectScheduler,
providedIn: 'root',
factory: () => new ZoneAwareEffectScheduler(),
}); }
}
/**
* A wrapper around `ZoneAwareQueueingScheduler` that schedules flushing via the microtask queue
* when.
*/
export class ZoneAwareEffectScheduler {
constructor() {
this.hasQueuedFlush = false;
this.queuedEffectCount = 0;
this.queues = new Map();
}
scheduleEffect(handle) {
this.enqueue(handle);
if (!this.hasQueuedFlush) {
queueMicrotask(() => this.flush());
// Leave `hasQueuedFlush` as `true` so we don't queue another microtask if more effects are
// scheduled during flushing. We are guaranteed to empty the whole queue during flush.
this.hasQueuedFlush = false;
}
}
enqueue(handle) {
const zone = handle.creationZone;
if (!this.queues.has(zone)) {
this.queues.set(zone, new Set());
}
const queue = this.queues.get(zone);
if (queue.has(handle)) {
return;
}
this.queuedEffectCount++;
queue.add(handle);
}
/**
* Run all scheduled effects.
*
* Execution order of effects within the same zone is guaranteed to be FIFO, but there is no
* ordering guarantee between effects scheduled in different zones.
*/
flush() {
while (this.queuedEffectCount > 0) {
for (const [zone, queue] of this.queues) {
// `zone` here must be defined.
if (zone === null) {
this.flushQueue(queue);
}
else {
zone.run(() => this.flushQueue(queue));
}
}
}
}
flushQueue(queue) {
for (const handle of queue) {
queue.delete(handle);
this.queuedEffectCount--;
// TODO: what happens if this throws an error?
handle.run();
}
}
}
/**
* Core reactive node for an Angular effect.
*
* `EffectHandle` combines the reactive graph's `Watch` base node for effects with the framework's
* scheduling abstraction (`EffectScheduler`) as well as automatic cleanup via `DestroyRef` if
* available/requested.
*/
class EffectHandle {
constructor(scheduler, effectFn, creationZone, destroyRef, injector, allowSignalWrites) {
this.scheduler = scheduler;
this.effectFn = effectFn;
this.creationZone = creationZone;
this.injector = injector;
this.watcher = createWatch((onCleanup) => this.runEffect(onCleanup), () => this.schedule(), allowSignalWrites);
this.unregisterOnDestroy = destroyRef?.onDestroy(() => this.destroy());
}
runEffect(onCleanup) {
try {
this.effectFn(onCleanup);
}
catch (err) {
// Inject the `ErrorHandler` here in order to avoid circular DI error
// if the effect is used inside of a custom `ErrorHandler`.
const errorHandler = this.injector.get(ErrorHandler, null, { optional: true });
errorHandler?.handleError(err);
}
}
run() {
this.watcher.run();
}
schedule() {
this.scheduler.scheduleEffect(this);
}
destroy() {
this.watcher.destroy();
this.unregisterOnDestroy?.();
// Note: if the effect is currently scheduled, it's not un-scheduled, and so the scheduler will
// retain a reference to it. Attempting to execute it will be a no-op.
}
}
/**
* Create a global `Effect` for the given reactive function.
*
* @developerPreview
*/
export function effect(effectFn, options) {
ngDevMode &&
assertNotInReactiveContext(effect, 'Call `effect` outside of a reactive context. For example, schedule the ' +
'effect inside the component constructor.');
!options?.injector && assertInInjectionContext(effect);
const injector = options?.injector ?? inject(Injector);
const destroyRef = options?.manualCleanup !== true ? injector.get(DestroyRef) : null;
const handle = new EffectHandle(injector.get(APP_EFFECT_SCHEDULER), effectFn, (typeof Zone === 'undefined') ? null : Zone.current, destroyRef, injector, options?.allowSignalWrites ?? false);
// Effects need to be marked dirty manually to trigger their initial run. The timing of this
// marking matters, because the effects may read signals that track component inputs, which are
// only available after those components have had their first update pass.
//
// We inject `ChangeDetectorRef` optionally, to determine whether this effect is being created in
// the context of a component or not. If it is, then we check whether the component has already
// run its update pass, and defer the effect's initial scheduling until the update pass if it
// hasn't already run.
const cdr = injector.get(ChangeDetectorRef, null, { optional: true });
if (!cdr || !(cdr._lView[FLAGS] & 8 /* LViewFlags.FirstLViewPass */)) {
// This effect is either not running in a view injector, or the view has already
// undergone its first change detection pass, which is necessary for any required inputs to be
// set.
handle.watcher.notify();
}
else {
// Delay the initialization of the effect until the view is fully initialized.
(cdr._lView[EFFECTS_TO_SCHEDULE] ??= []).push(handle.watcher.notify);
}
return handle;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWZmZWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvY29yZS9zcmMvcmVuZGVyMy9yZWFjdGl2aXR5L2VmZmVjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUMsV0FBVyxFQUFnQyxNQUFNLGtDQUFrQyxDQUFDO0FBRTVGLE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLHdCQUF3QixDQUFDO0FBQ3pELE9BQU8sRUFBQyx3QkFBd0IsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBQzdELE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSwwQkFBMEIsQ0FBQztBQUN4RCxPQUFPLEVBQUMsUUFBUSxFQUFDLE1BQU0sbUJBQW1CLENBQUM7QUFDM0MsT0FBTyxFQUFDLE1BQU0sRUFBQyxNQUFNLGlDQUFpQyxDQUFDO0FBQ3ZELE9BQU8sRUFBQyxrQkFBa0IsRUFBQyxNQUFNLHlCQUF5QixDQUFDO0FBQzNELE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQUVqRCxPQUFPLEVBQUMsVUFBVSxFQUFDLE1BQU0sMEJBQTBCLENBQUM7QUFDcEQsT0FBTyxFQUFDLEtBQUssRUFBYyxtQkFBbUIsRUFBQyxNQUFNLG9CQUFvQixDQUFDO0FBRTFFLE9BQU8sRUFBQywwQkFBMEIsRUFBQyxNQUFNLFdBQVcsQ0FBQztBQXdCckQ7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxjQUFjLENBQUMsRUFBRSxFQUFFO0lBQ3pELFVBQVUsRUFBRSxNQUFNO0lBQ2xCLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDO0NBQ3ZDLENBQUMsQ0FBQztBQUVIOztHQUVHO0FBQ0gsTUFBTSxPQUFnQixlQUFlO0lBYW5DLGtCQUFrQjthQUNYLFVBQUssR0FBNkIsa0JBQWtCLENBQUM7UUFDMUQs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Q0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN2RSxDQUFDO0lBRUQsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge2NyZWF0ZVdhdGNoLCBXYXRjaCwgV2F0Y2hDbGVhbnVwUmVnaXN0ZXJGbn0gZnJvbSAnQGFuZ3VsYXIvY29yZS9wcmltaXRpdmVzL3NpZ25hbHMnO1xuXG5pbXBvcnQge0NoYW5nZURldGVjdG9yUmVmfSBmcm9tICcuLi8uLi9jaGFuZ2VfZGV0ZWN0aW9uJztcbmltcG9ydCB7YXNzZXJ0SW5JbmplY3Rpb25Db250ZXh0fSBmcm9tICcuLi8uLi9kaS9jb250ZXh0dWFsJztcbmltcG9ydCB7SW5qZWN0aW9uVG9rZW59IGZyb20gJy4uLy4uL2RpL2luamVjdGlvbl90b2tlbic7XG5pbXBvcnQge0luamVjdG9yfSBmcm9tICcuLi8uLi9kaS9pbmplY3Rvcic7XG5pbXBvcnQge2luamVjdH0gZnJvbSAnLi4vLi4vZGkvaW5qZWN0b3JfY29tcGF0aWJpbGl0eSc7XG5pbXBvcnQge8m1ybVkZWZpbmVJbmplY3RhYmxlfSBmcm9tICcuLi8uLi9kaS9pbnRlcmZhY2UvZGVmcyc7XG5pbXBvcnQge0Vycm9ySGFuZGxlcn0gZnJvbSAnLi4vLi4vZXJyb3JfaGFuZGxlcic7XG5pbXBvcnQgdHlwZSB7Vmlld1JlZn0gZnJvbSAnLi4vdmlld19yZWYnO1xuaW1wb3J0IHtEZXN0cm95UmVmfSBmcm9tICcuLi8uLi9saW5rZXIvZGVzdHJveV9yZWYnO1xuaW1wb3J0IHtGTEFHUywgTFZpZXdGbGFncywgRUZGRUNUU19UT19TQ0hFRFVMRX0gZnJvbSAnLi4vaW50ZXJmYWNlcy92aWV3JztcblxuaW1wb3J0IHthc3NlcnROb3RJblJlYWN0aXZlQ29udGV4dH0gZnJvbSAnLi9hc3NlcnRzJztcblxuXG4vKipcbiAqIEFuIGVmZmVjdCBjYW4sIG9wdGlvbmFsbHksIHJlZ2lzdGVyIGEgY2xlYW51cCBmdW5jdGlvbi4gSWYgcmVnaXN0ZXJlZCwgdGhlIGNsZWFudXAgaXMgZXhlY3V0ZWRcbiAqIGJlZm9yZSB0aGUgbmV4dCBlZmZlY3QgcnVuLiBUaGUgY2xlYW51cCBmdW5jdGlvbiBtYWtlcyBpdCBwb3NzaWJsZSB0byBcImNhbmNlbFwiIGFueSB3b3JrIHRoYXQgdGhlXG4gKiBwcmV2aW91cyBlZmZlY3QgcnVuIG1pZ2h0IGhhdmUgc3RhcnRlZC5cbiAqXG4gKiBAZGV2ZWxvcGVyUHJldmlld1xuICovXG5leHBvcnQgdHlwZSBFZmZlY3RDbGVhbnVwRm4gPSAoKSA9PiB2b2lkO1xuXG4vKipcbiAqIEEgY2FsbGJhY2sgcGFzc2VkIHRvIHRoZSBlZmZlY3QgZnVuY3Rpb24gdGhhdCBtYWtlcyBpdCBwb3NzaWJsZSB0byByZWdpc3RlciBjbGVhbnVwIGxvZ2ljLlxuICpcbiAqIEBkZXZlbG9wZXJQcmV2aWV3XG4gKi9cbmV4cG9ydCB0eXBlIEVmZmVjdENsZWFudXBSZWdpc3RlckZuID0gKGNsZWFudXBGbjogRWZmZWN0Q2xlYW51cEZuKSA9PiB2b2lkO1xuXG5leHBvcnQgaW50ZXJmYWNlIFNjaGVkdWxhYmxlRWZmZWN0IHtcbiAgcnVuKCk6IHZvaWQ7XG4gIGNyZWF0aW9uWm9uZTogdW5rbm93bjtcbn1cblxuLyoqXG4gKiBOb3QgcHVibGljIEFQSSwgd2hpY2ggZ3VhcmFudGVlcyBgRWZmZWN0U2NoZWR1bGVyYCBvbmx5IGV2ZXIgY29tZXMgZnJvbSB0aGUgYXBwbGljYXRpb24gcm9vdFxuICogaW5qZWN0b3IuXG4gKi9cbmV4cG9ydCBjb25zdCBBUFBfRUZGRUNUX1NDSEVEVUxFUiA9IG5ldyBJbmplY3Rpb25Ub2tlbignJywge1xuICBwcm92aWRlZEluOiAncm9vdCcsXG4gIGZhY3Rvcnk6ICgpID0+IGluamVjdChFZmZlY3RTY2hlZHVsZXIpLFxufSk7XG5cbi8qKlxuICogQSBzY2hlZHVsZXIgd2hpY2ggbWFuYWdlcyB0aGUgZXhlY3V0aW9uIG9mIGVmZmVjdHMuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBFZmZlY3RTY2hlZHVsZXIge1xuICAvKipcbiAgICogU2NoZWR1bGUgdGhlIGdpdmVuIGVmZmVjdCB0byBiZSBleGVjdXRlZCBhdCBhIGxhdGVyIHRpbWUuXG4gICAqXG4gICAqIEl0IGlzIGFuIGVycm9yIHRvIGF0dGVtcHQgdG8gZXhlY3V0ZSBhbnkgZWZmZWN0cyBzeW5jaHJvbm91c2x5IGR1cmluZyBhIHNjaGVkdWxpbmcgb3BlcmF0aW9uLlxuICAgKi9cbiAgYWJzdHJhY3Qgc2NoZWR1bGVFZmZlY3QoZTogU2NoZWR1bGFibGVFZmZlY3QpOiB2b2lkO1xuXG4gIC8qKlxuICAgKiBSdW4gYW55IHNjaGVkdWxlZCBlZmZlY3RzLlxuICAgKi9cbiAgYWJzdHJhY3QgZmx1c2goKTogdm9pZDtcblxuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIMm1cHJvdiA9IC8qKiBAcHVyZU9yQnJlYWtNeUNvZGUgKi8gybXJtWRlZmluZUluamVjdGFibGUoe1xuICAgIHRva2VuOiBFZmZlY3RTY2hlZHVsZXIsXG4gICAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxuICAgIGZhY3Rvcnk6ICgpID0+IG5ldyBab25lQXdhcmVFZmZlY3RTY2hlZHVsZXIoKSxcbiAgfSk7XG59XG5cbi8qKlxuICogQSB3cmFwcGVyIGFyb3VuZCBgWm9uZUF3YXJlUXVldWVpbmdTY2hlZHVsZXJgIHRoYXQgc2NoZWR1bGVzIGZsdXNoaW5nIHZpYSB0aGUgbWljcm90YXNrIHF1ZXVlXG4gKiB3aGVuLlxuICovXG5leHBvcnQgY2xhc3MgWm9uZUF3YXJlRWZmZWN0U2NoZWR1bGVyIGltcGxlbWVudHMgRWZmZWN0U2NoZWR1bGVyIHtcbiAgcHJpdmF0ZSBoYXNRdWV1ZWRGbHVzaCA9IGZhbHNlO1xuICBwcml2YXRlIHF1ZXVlZEVmZmVjdENvdW50ID0gMDtcbiAgcHJpdmF0ZSBxdWV1ZXMgPSBuZXcgTWFwPFpvbmV8bnVsbCwgU2V0PFNjaGVkdWxhYmxlRWZmZWN0Pj4oKTtcblxuICBzY2hlZHVsZUVmZmVjdChoYW5kbGU6IFNjaGVkdWxhYmxlRWZmZWN0KTogdm9pZCB7XG4gICAgdGhpcy5lbnF1ZXVlKGhhbmRsZSk7XG5cbiAgICBpZiAoIXRoaXMuaGFzUXVldWVkRmx1c2gpIHtcbiAgICAgIHF1ZXVlTWljcm90YXNrKCgpID0+IHRoaXMuZmx1c2goKSk7XG4gICAgICAvLyBMZWF2ZSBgaGFzUXVldWVkRmx1c2hgIGFzIGB0cnVlYCBzbyB3ZSBkb24ndCBxdWV1ZSBhbm90aGVyIG1pY3JvdGFzayBpZiBtb3JlIGVmZmVjdHMgYXJlXG4gICAgICAvLyBzY2hlZHVsZWQgZHVyaW5nIGZsdXNoaW5nLiBXZSBhcmUgZ3VhcmFudGVlZCB0byBlbXB0eSB0aGUgd2hvbGUgcXVldWUgZHVyaW5nIGZsdXNoLlxuICAgICAgdGhpcy5oYXNRdWV1ZWRGbHVzaCA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZW5xdWV1ZShoYW5kbGU6IFNjaGVkdWxhYmxlRWZmZWN0KTogdm9pZCB7XG4gICAgY29uc3Qgem9uZSA9IGhhbmRsZS5jcmVhdGlvblpvbmUgYXMgWm9uZSB8IG51bGw7XG4gICAgaWYgKCF0aGlzLnF1ZXVlcy5oYXMoem9uZSkpIHtcbiAgICAgIHRoaXMucXVldWVzLnNldCh6b25lLCBuZXcgU2V0KCkpO1xuICAgIH1cblxuICAgIGNvbnN0IHF1ZXVlID0gdGhpcy5xdWV1ZXMuZ2V0KHpvbmUpITtcbiAgICBpZiAocXVldWUuaGFzKGhhbmRsZSkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5xdWV1ZWRFZmZlY3RDb3VudCsrO1xuICAgIHF1ZXVlLmFkZChoYW5kbGUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1biBhbGwgc2NoZWR1bGVkIGVmZmVjdHMuXG4gICAqXG4gICAqIEV4ZWN1dGlvbiBvcmRlciBvZiBlZmZlY3RzIHdpdGhpbiB0aGUgc2FtZSB6b25lIGlzIGd1YXJhbnRlZWQgdG8gYmUgRklGTywgYnV0IHRoZXJlIGlzIG5vXG4gICAqIG9yZGVyaW5nIGd1YXJhbnRlZSBiZXR3ZWVuIGVmZmVjdHMgc2NoZWR1bGVkIGluIGRpZmZlcmVudCB6b25lcy5cbiAgICovXG4gIGZsdXNoKCk6IHZvaWQge1xuICAgIHdoaWxlICh0aGlzLnF1ZXVlZEVmZmVjdENvdW50ID4gMCkge1xuICAgICAgZm9yIChjb25zdCBbem9uZSwgcXVldWVdIG9mIHRoaXMucXVldWVzKSB7XG4gICAgICAgIC8vIGB6b25lYCBoZXJlIG11c3QgYmUgZGVmaW5lZC5cbiAgICAgICAgaWYgKHpvbmUgPT09IG51bGwpIHtcbiAgICAgICAgICB0aGlzLmZsdXNoUXVldWUocXVldWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHpvbmUucnVuKCgpID0+IHRoaXMuZmx1c2hRdWV1ZShxdWV1ZSkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBmbHVzaFF1ZXVlKHF1ZXVlOiBTZXQ8U2NoZWR1bGFibGVFZmZlY3Q+KTogdm9pZCB7XG4gICAgZm9yIChjb25zdCBoYW5kbGUgb2YgcXVldWUpIHtcbiAgICAgIHF1ZXVlLmRlbGV0ZShoYW5kbGUpO1xuICAgICAgdGhpcy5xdWV1ZWRFZmZlY3RDb3VudC0tO1xuXG4gICAgICAvLyBUT0RPOiB3aGF0IGhhcHBlbnMgaWYgdGhpcyB0aHJvd3MgYW4gZXJyb3I/XG4gICAgICBoYW5kbGUucnVuKCk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogQ29yZSByZWFjdGl2ZSBub2RlIGZvciBhbiBBbmd1bGFyIGVmZmVjdC5cbiAqXG4gKiBgRWZmZWN0SGFuZGxlYCBjb21iaW5lcyB0aGUgcmVhY3RpdmUgZ3JhcGgncyBgV2F0Y2hgIGJhc2Ugbm9kZSBmb3IgZWZmZWN0cyB3aXRoIHRoZSBmcmFtZXdvcmsnc1xuICogc2NoZWR1bGluZyBhYnN0cmFjdGlvbiAoYEVmZmVjdFNjaGVkdWxlcmApIGFzIHdlbGwgYXMgYXV0b21hdGljIGNsZWFudXAgdmlhIGBEZXN0cm95UmVmYCBpZlxuICogYXZhaWxhYmxlL3JlcXVlc3RlZC5cbiAqL1xuY2xhc3MgRWZmZWN0SGFuZGxlIGltcGxlbWVudHMgRWZmZWN0UmVmLCBTY2hlZHVsYWJsZUVmZmVjdCB7XG4gIHVucmVnaXN0ZXJPbkRlc3Ryb3k6ICgoKSA9PiB2b2lkKXx1bmRlZmluZWQ7XG4gIHJlYWRvbmx5IHdhdGNoZXI6IFdhdGNoO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgICAgcHJpdmF0ZSBzY2hlZHVsZXI6IEVmZmVjdFNjaGVkdWxlcixcbiAgICAgIHByaXZhdGUgZWZmZWN0Rm46IChvbkNsZWFudXA6IEVmZmVjdENsZWFudXBSZWdpc3RlckZuKSA9PiB2b2lkLFxuICAgICAgcHVibGljIGNyZWF0aW9uWm9uZTogWm9uZXxudWxsLCBkZXN0cm95UmVmOiBEZXN0cm95UmVmfG51bGwsIHByaXZhdGUgaW5qZWN0b3I6IEluamVjdG9yLFxuICAgICAgYWxsb3dTaWduYWxXcml0ZXM6IGJvb2xlYW4pIHtcbiAgICB0aGlzLndhdGNoZXIgPSBjcmVhdGVXYXRjaChcbiAgICAgICAgKG9uQ2xlYW51cCkgPT4gdGhpcy5ydW5FZmZlY3Qob25DbGVhbnVwKSwgKCkgPT4gdGhpcy5zY2hlZHVsZSgpLCBhbGxvd1NpZ25hbFdyaXRlcyk7XG4gICAgdGhpcy51bnJlZ2lzdGVyT25EZXN0cm95ID0gZGVzdHJveVJlZj8ub25EZXN0cm95KCgpID0+IHRoaXMuZGVzdHJveSgpKTtcbiAgfVxuXG4gIHByaXZhdGUgcnVuRWZmZWN0KG9uQ2xlYW51cDogV2F0Y2hDbGVhbnVwUmVnaXN0ZXJGbik6IHZvaWQge1xuICAgIHRyeSB7XG4gICAgICB0aGlzLmVmZmVjdEZuKG9uQ2xlYW51cCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBJbmplY3QgdGhlIGBFcnJvckhhbmRsZXJgIGhlcmUgaW4gb3JkZXIgdG8gYXZvaWQgY2lyY3VsYXIgREkgZXJyb3JcbiAgICAgIC8vIGlmIHRoZSBlZmZlY3QgaXMgdXNlZCBpbnNpZGUgb2YgYSBjdXN0b20gYEVycm9ySGFuZGxlcmAuXG4gICAgICBjb25zdCBlcnJvckhhbmRsZXIgPSB0aGlzLmluamVjdG9yLmdldChFcnJvckhhbmRsZXIsIG51bGwsIHtvcHRpb25hbDogdHJ1ZX0pO1xuICAgICAgZXJyb3JIYW5kbGVyPy5oYW5kbGVFcnJvcihlcnIpO1xuICAgIH1cbiAgfVxuXG4gIHJ1bigpOiB2b2lkIHtcbiAgICB0aGlzLndhdGNoZXIucnVuKCk7XG4gIH1cblxuICBwcml2YXRlIHNjaGVkdWxlKCk6IHZvaWQge1xuICAgIHRoaXMuc2NoZWR1bGVyLnNjaGVkdWxlRWZmZWN0KHRoaXMpO1xuICB9XG5cbiAgZGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLndhdGNoZXIuZGVzdHJveSgpO1xuICAgIHRoaXMudW5yZWdpc3Rlck9uRGVzdHJveT8uKCk7XG5cbiAgICAvLyBOb3RlOiBpZiB0aGUgZWZmZWN0IGlzIGN1cnJlbnRseSBzY2hlZHVsZWQsIGl0J3Mgbm90IHVuLXNjaGVkdWxlZCwgYW5kIHNvIHRoZSBzY2hlZHVsZXIgd2lsbFxuICAgIC8vIHJldGFpbiBhIHJlZmVyZW5jZSB0byBpdC4gQXR0ZW1wdGluZyB0byBleGVjdXRlIGl0IHdpbGwgYmUgYSBuby1vcC5cbiAgfVxufVxuXG4vKipcbiAqIEEgZ2xvYmFsIHJlYWN0aXZlIGVmZmVjdCwgd2hpY2ggY2FuIGJlIG1hbnVhbGx5IGRlc3Ryb3llZC5cbiAqXG4gKiBAZGV2ZWxvcGVyUHJldmlld1xuICovXG5leHBvcnQgaW50ZXJmYWNlIEVmZmVjdFJlZiB7XG4gIC8qKlxuICAgKiBTaHV0IGRvd24gdGhlIGVmZmVjdCwgcmVtb3ZpbmcgaXQgZnJvbSBhbnkgdXBjb21pbmcgc2NoZWR1bGVkIGV4ZWN1dGlvbnMuXG4gICAqL1xuICBkZXN0cm95KCk6IHZvaWQ7XG59XG5cbi8qKlxuICogT3B0aW9ucyBwYXNzZWQgdG8gdGhlIGBlZmZlY3RgIGZ1bmN0aW9uLlxuICpcbiAqIEBkZXZlbG9wZXJQcmV2aWV3XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ3JlYXRlRWZmZWN0T3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgYEluamVjdG9yYCBpbiB3aGljaCB0byBjcmVhdGUgdGhlIGVmZmVjdC5cbiAgICpcbiAgICogSWYgdGhpcyBpcyBub3QgcHJvdmlkZWQsIHRoZSBjdXJyZW50IFtpbmplY3Rpb24gY29udGV4dF0oZ3VpZGUvZGVwZW5kZW5jeS1pbmplY3Rpb24tY29udGV4dClcbiAgICogd2lsbCBiZSB1c2VkIGluc3RlYWQgKHZpYSBgaW5qZWN0YCkuXG4gICAqL1xuICBpbmplY3Rvcj86IEluamVjdG9yO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBgZWZmZWN0YCBzaG91bGQgcmVxdWlyZSBtYW51YWwgY2xlYW51cC5cbiAgICpcbiAgICogSWYgdGhpcyBpcyBgZmFsc2VgICh0aGUgZGVmYXVsdCkgdGhlIGVmZmVjdCB3aWxsIGF1dG9tYXRpY2FsbHkgcmVnaXN0ZXIgaXRzZWxmIHRvIGJlIGNsZWFuZWQgdXBcbiAgICogd2l0aCB0aGUgY3VycmVudCBgRGVzdHJveVJlZmAuXG4gICAqL1xuICBtYW51YWxDbGVhbnVwPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgYGVmZmVjdGAgc2hvdWxkIGFsbG93IHdyaXRpbmcgdG8gc2lnbmFscy5cbiAgICpcbiAgICogVXNpbmcgZWZmZWN0cyB0byBzeW5jaHJvbml6ZSBkYXRhIGJ5IHdyaXRpbmcgdG8gc2lnbmFscyBjYW4gbGVhZCB0byBjb25mdXNpbmcgYW5kIHBvdGVudGlhbGx5XG4gICAqIGluY29ycmVjdCBiZWhhdmlvciwgYW5kIHNob3VsZCBiZSBlbmFibGVkIG9ubHkgd2hlbiBuZWNlc3NhcnkuXG4gICAqL1xuICBhbGxvd1NpZ25hbFdyaXRlcz86IGJvb2xlYW47XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgZ2xvYmFsIGBFZmZlY3RgIGZvciB0aGUgZ2l2ZW4gcmVhY3RpdmUgZnVuY3Rpb24uXG4gKlxuICogQGRldmVsb3BlclByZXZpZXdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVmZmVjdChcbiAgICBlZmZlY3RGbjogKG9uQ2xlYW51cDogRWZmZWN0Q2xlYW51cFJlZ2lzdGVyRm4pID0+IHZvaWQsXG4gICAgb3B0aW9ucz86IENyZWF0ZUVmZmVjdE9wdGlvbnMpOiBFZmZlY3RSZWYge1xuICBuZ0Rldk1vZGUgJiZcbiAgICAgIGFzc2VydE5vdEluUmVhY3RpdmVDb250ZXh0KFxuICAgICAgICAgIGVmZmVjdCxcbiAgICAgICAgICAnQ2FsbCBgZWZmZWN0YCBvdXRzaWRlIG9mIGEgcmVhY3RpdmUgY29udGV4dC4gRm9yIGV4YW1wbGUsIHNjaGVkdWxlIHRoZSAnICtcbiAgICAgICAgICAgICAgJ2VmZmVjdCBpbnNpZGUgdGhlIGNvbXBvbmVudCBjb25zdHJ1Y3Rvci4nKTtcblxuICAhb3B0aW9ucz8uaW5qZWN0b3IgJiYgYXNzZXJ0SW5JbmplY3Rpb25Db250ZXh0KGVmZmVjdCk7XG4gIGNvbnN0IGluamVjdG9yID0gb3B0aW9ucz8uaW5qZWN0b3IgPz8gaW5qZWN0KEluamVjdG9yKTtcbiAgY29uc3QgZGVzdHJveVJlZiA9IG9wdGlvbnM/Lm1hbnVhbENsZWFudXAgIT09IHRydWUgPyBpbmplY3Rvci5nZXQoRGVzdHJveVJlZikgOiBudWxsO1xuXG4gIGNvbnN0IGhhbmRsZSA9IG5ldyBFZmZlY3RIYW5kbGUoXG4gICAgICBpbmplY3Rvci5nZXQoQVBQX0VGRkVDVF9TQ0hFRFVMRVIpLCBlZmZlY3RGbixcbiAgICAgICh0eXBlb2YgWm9uZSA9PT0gJ3VuZGVmaW5lZCcpID8gbnVsbCA6IFpvbmUuY3VycmVudCwgZGVzdHJveVJlZiwgaW5qZWN0b3IsXG4gICAgICBvcHRpb25zPy5hbGxvd1NpZ25hbFdyaXRlcyA/PyBmYWxzZSk7XG5cbiAgLy8gRWZmZWN0cyBuZWVkIHRvIGJlIG1hcmtlZCBkaXJ0eSBtYW51YWxseSB0byB0cmlnZ2VyIHRoZWlyIGluaXRpYWwgcnVuLiBUaGUgdGltaW5nIG9mIHRoaXNcbiAgLy8gbWFya2luZyBtYXR0ZXJzLCBiZWNhdXNlIHRoZSBlZmZlY3RzIG1heSByZWFkIHNpZ25hbHMgdGhhdCB0cmFjayBjb21wb25lbnQgaW5wdXRzLCB3aGljaCBhcmVcbiAgLy8gb25seSBhdmFpbGFibGUgYWZ0ZXIgdGhvc2UgY29tcG9uZW50cyBoYXZlIGhhZCB0aGVpciBmaXJzdCB1cGRhdGUgcGFzcy5cbiAgLy9cbiAgLy8gV2UgaW5qZWN0IGBDaGFuZ2VEZXRlY3RvclJlZmAgb3B0aW9uYWxseSwgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhpcyBlZmZlY3QgaXMgYmVpbmcgY3JlYXRlZCBpblxuICAvLyB0aGUgY29udGV4dCBvZiBhIGNvbXBvbmVudCBvciBub3QuIElmIGl0IGlzLCB0aGVuIHdlIGNoZWNrIHdoZXRoZXIgdGhlIGNvbXBvbmVudCBoYXMgYWxyZWFkeVxuICAvLyBydW4gaXRzIHVwZGF0ZSBwYXNzLCBhbmQgZGVmZXIgdGhlIGVmZmVjdCdzIGluaXRpYWwgc2NoZWR1bGluZyB1bnRpbCB0aGUgdXBkYXRlIHBhc3MgaWYgaXRcbiAgLy8gaGFzbid0IGFscmVhZHkgcnVuLlxuICBjb25zdCBjZHIgPSBpbmplY3Rvci5nZXQoQ2hhbmdlRGV0ZWN0b3JSZWYsIG51bGwsIHtvcHRpb25hbDogdHJ1ZX0pIGFzIFZpZXdSZWY8dW5rbm93bj58IG51bGw7XG4gIGlmICghY2RyIHx8ICEoY2RyLl9sVmlld1tGTEFHU10gJiBMVmlld0ZsYWdzLkZpcnN0TFZpZXdQYXNzKSkge1xuICAgIC8vIFRoaXMgZWZmZWN0IGlzIGVpdGhlciBub3QgcnVubmluZyBpbiBhIHZpZXcgaW5qZWN0b3IsIG9yIHRoZSB2aWV3IGhhcyBhbHJlYWR5XG4gICAgLy8gdW5kZXJnb25lIGl0cyBmaXJzdCBjaGFuZ2UgZGV0ZWN0aW9uIHBhc3MsIHdoaWNoIGlzIG5lY2Vzc2FyeSBmb3IgYW55IHJlcXVpcmVkIGlucHV0cyB0byBiZVxuICAgIC8vIHNldC5cbiAgICBoYW5kbGUud2F0Y2hlci5ub3RpZnkoKTtcbiAgfSBlbHNlIHtcbiAgICAvLyBEZWxheSB0aGUgaW5pdGlhbGl6YXRpb24gb2YgdGhlIGVmZmVjdCB1bnRpbCB0aGUgdmlldyBpcyBmdWxseSBpbml0aWFsaXplZC5cbiAgICAoY2RyLl9sVmlld1tFRkZFQ1RTX1RPX1NDSEVEVUxFXSA/Pz0gW10pLnB1c2goaGFuZGxlLndhdGNoZXIubm90aWZ5KTtcbiAgfVxuXG4gIHJldHVybiBoYW5kbGU7XG59XG4iXX0=