UNPKG

@angular/core

Version:

Angular - the core framework

91 lines 19.1 kB
/** * @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 { assertInInjectionContext, assertNotInReactiveContext, computed, DestroyRef, inject, signal, ɵRuntimeError } from '@angular/core'; /** * Get the current value of an `Observable` as a reactive `Signal`. * * `toSignal` returns a `Signal` which provides synchronous reactive access to values produced * by the given `Observable`, by subscribing to that `Observable`. The returned `Signal` will always * have the most recent value emitted by the subscription, and will throw an error if the * `Observable` errors. * * With `requireSync` set to `true`, `toSignal` will assert that the `Observable` produces a value * immediately upon subscription. No `initialValue` is needed in this case, and the returned signal * does not include an `undefined` type. * * By default, the subscription will be automatically cleaned up when the current [injection * context](/guide/dependency-injection-context) is destroyed. For example, when `toObservable` is * called during the construction of a component, the subscription will be cleaned up when the * component is destroyed. If an injection context is not available, an explicit `Injector` can be * passed instead. * * If the subscription should persist until the `Observable` itself completes, the `manualCleanup` * option can be specified instead, which disables the automatic subscription teardown. No injection * context is needed in this configuration as well. * * @developerPreview */ export function toSignal(source, options) { ngDevMode && assertNotInReactiveContext(toSignal, 'Invoking `toSignal` causes new subscriptions every time. ' + 'Consider moving `toSignal` outside of the reactive context and read the signal value where needed.'); const requiresCleanup = !options?.manualCleanup; requiresCleanup && !options?.injector && assertInInjectionContext(toSignal); const cleanupRef = requiresCleanup ? options?.injector?.get(DestroyRef) ?? inject(DestroyRef) : null; // Note: T is the Observable value type, and U is the initial value type. They don't have to be // the same - the returned signal gives values of type `T`. let state; if (options?.requireSync) { // Initially the signal is in a `NoValue` state. state = signal({ kind: 0 /* StateKind.NoValue */ }); } else { // If an initial value was passed, use it. Otherwise, use `undefined` as the initial value. state = signal({ kind: 1 /* StateKind.Value */, value: options?.initialValue }); } // Note: This code cannot run inside a reactive context (see assertion above). If we'd support // this, we would subscribe to the observable outside of the current reactive context, avoiding // that side-effect signal reads/writes are attribute to the current consumer. The current // consumer only needs to be notified when the `state` signal changes through the observable // subscription. Additional context (related to async pipe): // https://github.com/angular/angular/pull/50522. const sub = source.subscribe({ next: value => state.set({ kind: 1 /* StateKind.Value */, value }), error: error => { if (options?.rejectErrors) { // Kick the error back to RxJS. It will be caught and rethrown in a macrotask, which causes // the error to end up as an uncaught exception. throw error; } state.set({ kind: 2 /* StateKind.Error */, error }); }, // Completion of the Observable is meaningless to the signal. Signals don't have a concept of // "complete". }); if (ngDevMode && options?.requireSync && state().kind === 0 /* StateKind.NoValue */) { throw new ɵRuntimeError(601 /* ɵRuntimeErrorCode.REQUIRE_SYNC_WITHOUT_SYNC_EMIT */, '`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.'); } // Unsubscribe when the current context is destroyed, if requested. cleanupRef?.onDestroy(sub.unsubscribe.bind(sub)); // The actual returned signal is a `computed` of the `State` signal, which maps the various states // to either values or errors. return computed(() => { const current = state(); switch (current.kind) { case 1 /* StateKind.Value */: return current.value; case 2 /* StateKind.Error */: throw current.error; case 0 /* StateKind.NoValue */: // This shouldn't really happen because the error is thrown on creation. // TODO(alxhub): use a RuntimeError when we finalize the error semantics throw new ɵRuntimeError(601 /* ɵRuntimeErrorCode.REQUIRE_SYNC_WITHOUT_SYNC_EMIT */, '`toSignal()` called with `requireSync` but `Observable` did not emit synchronously.'); } }); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9fc2lnbmFsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvY29yZS9yeGpzLWludGVyb3Avc3JjL3RvX3NpZ25hbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUMsd0JBQXdCLEVBQUUsMEJBQTBCLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQVksTUFBTSxFQUEwQixhQUFhLEVBQW9CLE1BQU0sZUFBZSxDQUFDO0FBeUU3TDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F1Qkc7QUFDSCxNQUFNLFVBQVUsUUFBUSxDQUNwQixNQUFxQyxFQUNyQyxPQUE0QztJQUM5QyxTQUFTO1FBQ0wsMEJBQTBCLENBQ3RCLFFBQVEsRUFDUiwyREFBMkQ7WUFDdkQsb0dBQW9HLENBQUMsQ0FBQztJQUVsSCxNQUFNLGVBQWUsR0FBRyxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUM7SUFDaEQsZUFBZSxJQUFJLENBQUMsT0FBTyxFQUFFLFFBQVEsSUFBSSx3QkFBd0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM1RSxNQUFNLFVBQVUsR0FDWixlQUFlLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsR0FBRyxDQUFDLFVBQVUsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBRXRGLCtGQUErRjtJQUMvRiwyREFBMkQ7SUFDM0QsSUFBSSxLQUFpQyxDQUFDO0lBQ3RDLElBQUksT0FBTyxFQUFFLFdBQVcsRUFBRSxDQUFDO1FBQ3pCLGdEQUFnRDtRQUNoRCxLQUFLLEdBQUcsTUFBTSxDQUFDLEVBQUMsSUFBSSwyQkFBbUIsRUFBQyxDQUFDLENBQUM7SUFDNUMsQ0FBQztTQUFNLENBQUM7UUFDTiwyRkFBMkY7UUFDM0YsS0FBSyxHQUFHLE1BQU0sQ0FBYSxFQUFDLElBQUkseUJBQWlCLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxZQUFpQixFQUFDLENBQUMsQ0FBQztJQUN6RixDQUFDO0lBRUQsOEZBQThGO0lBQzlGLCtGQUErRjtJQUMvRiwwRkFBMEY7SUFDMUYsNEZBQTRGO0lBQzVGLDREQUE0RDtJQUM1RCxpREFBaUQ7SUFDakQsTUFBTSxHQUFHLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQztRQUMzQixJQUFJLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUMsSUFBSSx5QkFBaUIsRUFBRSxLQUFLLEVBQUMsQ0FBQztRQUN4RCxLQUFLLEVBQUUsS0FBSyxDQUFDLEVBQUU7WUFDYixJQUFJLE9BQU8sRUFBRSxZQUFZLEVBQUUsQ0FBQztnQkFDMUIsMkZBQTJGO2dCQUMzRixnREFBZ0Q7Z0JBQ2hELE1BQU0sS0FBSyxDQUFDO1lBQ2QsQ0FBQztZQUNELEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBQyxJQUFJLHlCQUFpQixFQUFFLEtBQUssRUFBQyxDQUFDLENBQUM7UUFDNUMsQ0FBQztRQUNELDZGQUE2RjtRQUM3RixjQUFjO0tBQ2YsQ0FBQyxDQUFDO0lBRUgsSUFBSSxTQUFTLElBQUksT0FBTyxFQUFFLFdBQVcsSUFBSSxLQUFLLEVBQUUsQ0FBQyxJQUFJLDhCQUFzQixFQUFFLENBQUM7UUFDNUUsTUFBTSxJQUFJLGFBQWEsNkRBRW5CLHFGQUFxRixDQUFDLENBQUM7SUFDN0YsQ0FBQztJQUVELG1FQUFtRTtJQUNuRSxVQUFVLEVBQUUsU0FBUyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFFakQsa0dBQWtHO0lBQ2xHLDhCQUE4QjtJQUM5QixPQUFPLFFBQVEsQ0FBQyxHQUFHLEVBQUU7UUFDbkIsTUFBTSxPQUFPLEdBQUcsS0FBSyxFQUFFLENBQUM7UUFDeEIsUUFBUSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDckI7Z0JBQ0UsT0FBTyxPQUFPLENBQUMsS0FBSyxDQUFDO1lBQ3ZCO2dCQUNFLE1BQU0sT0FBTyxDQUFDLEtBQUssQ0FBQztZQUN0QjtnQkFDRSx3RUFBd0U7Z0JBQ3hFLHdFQUF3RTtnQkFDeEUsTUFBTSxJQUFJLGFBQWEsNkRBRW5CLHFGQUFxRixDQUFDLENBQUM7UUFDL0YsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge2Fzc2VydEluSW5qZWN0aW9uQ29udGV4dCwgYXNzZXJ0Tm90SW5SZWFjdGl2ZUNvbnRleHQsIGNvbXB1dGVkLCBEZXN0cm95UmVmLCBpbmplY3QsIEluamVjdG9yLCBzaWduYWwsIFNpZ25hbCwgV3JpdGFibGVTaWduYWwsIMm1UnVudGltZUVycm9yLCDJtVJ1bnRpbWVFcnJvckNvZGV9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtPYnNlcnZhYmxlLCBTdWJzY3JpYmFibGV9IGZyb20gJ3J4anMnO1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGB0b1NpZ25hbGAuXG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRvU2lnbmFsT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBJbml0aWFsIHZhbHVlIGZvciB0aGUgc2lnbmFsIHByb2R1Y2VkIGJ5IGB0b1NpZ25hbGAuXG4gICAqXG4gICAqIFRoaXMgd2lsbCBiZSB0aGUgdmFsdWUgb2YgdGhlIHNpZ25hbCB1bnRpbCB0aGUgb2JzZXJ2YWJsZSBlbWl0cyBpdHMgZmlyc3QgdmFsdWUuXG4gICAqL1xuICBpbml0aWFsVmFsdWU/OiB1bmtub3duO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIHJlcXVpcmUgdGhhdCB0aGUgb2JzZXJ2YWJsZSBlbWl0cyBzeW5jaHJvbm91c2x5IHdoZW4gYHRvU2lnbmFsYCBzdWJzY3JpYmVzLlxuICAgKlxuICAgKiBJZiB0aGlzIGlzIGB0cnVlYCwgYHRvU2lnbmFsYCB3aWxsIGFzc2VydCB0aGF0IHRoZSBvYnNlcnZhYmxlIHByb2R1Y2VzIGEgdmFsdWUgaW1tZWRpYXRlbHkgdXBvblxuICAgKiBzdWJzY3JpcHRpb24uIFNldHRpbmcgdGhpcyBvcHRpb24gcmVtb3ZlcyB0aGUgbmVlZCB0byBlaXRoZXIgZGVhbCB3aXRoIGB1bmRlZmluZWRgIGluIHRoZVxuICAgKiBzaWduYWwgdHlwZSBvciBwcm92aWRlIGFuIGBpbml0aWFsVmFsdWVgLCBhdCB0aGUgY29zdCBvZiBhIHJ1bnRpbWUgZXJyb3IgaWYgdGhpcyByZXF1aXJlbWVudCBpc1xuICAgKiBub3QgbWV0LlxuICAgKi9cbiAgcmVxdWlyZVN5bmM/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBgSW5qZWN0b3JgIHdoaWNoIHdpbGwgcHJvdmlkZSB0aGUgYERlc3Ryb3lSZWZgIHVzZWQgdG8gY2xlYW4gdXAgdGhlIE9ic2VydmFibGUgc3Vic2NyaXB0aW9uLlxuICAgKlxuICAgKiBJZiB0aGlzIGlzIG5vdCBwcm92aWRlZCwgYSBgRGVzdHJveVJlZmAgd2lsbCBiZSByZXRyaWV2ZWQgZnJvbSB0aGUgY3VycmVudCBbaW5qZWN0aW9uXG4gICAqIGNvbnRleHRdKC9ndWlkZS9kZXBlbmRlbmN5LWluamVjdGlvbi1jb250ZXh0KSwgdW5sZXNzIG1hbnVhbCBjbGVhbnVwIGlzIHJlcXVlc3RlZC5cbiAgICovXG4gIGluamVjdG9yPzogSW5qZWN0b3I7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHN1YnNjcmlwdGlvbiBzaG91bGQgYmUgYXV0b21hdGljYWxseSBjbGVhbmVkIHVwICh2aWEgYERlc3Ryb3lSZWZgKSB3aGVuXG4gICAqIGB0b09ic2VydmFibGVgJ3MgY3JlYXRpb24gY29udGV4dCBpcyBkZXN0cm95ZWQuXG4gICAqXG4gICAqIElmIG1hbnVhbCBjbGVhbnVwIGlzIGVuYWJsZWQsIHRoZW4gYERlc3Ryb3lSZWZgIGlzIG5vdCB1c2VkLCBhbmQgdGhlIHN1YnNjcmlwdGlvbiB3aWxsIHBlcnNpc3RcbiAgICogdW50aWwgdGhlIGBPYnNlcnZhYmxlYCBpdHNlbGYgY29tcGxldGVzLlxuICAgKi9cbiAgbWFudWFsQ2xlYW51cD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgYHRvU2lnbmFsYCBzaG91bGQgdGhyb3cgZXJyb3JzIGZyb20gdGhlIE9ic2VydmFibGUgZXJyb3IgY2hhbm5lbCBiYWNrIHRvIFJ4SlMsIHdoZXJlXG4gICAqIHRoZXknbGwgYmUgcHJvY2Vzc2VkIGFzIHVuY2F1Z2h0IGV4Y2VwdGlvbnMuXG4gICAqXG4gICAqIEluIHByYWN0aWNlLCB0aGlzIG1lYW5zIHRoYXQgdGhlIHNpZ25hbCByZXR1cm5lZCBieSBgdG9TaWduYWxgIHdpbGwga2VlcCByZXR1cm5pbmcgdGhlIGxhc3RcbiAgICogZ29vZCB2YWx1ZSBmb3JldmVyLCBhcyBPYnNlcnZhYmxlcyB3aGljaCBlcnJvciBwcm9kdWNlIG5vIGZ1cnRoZXIgdmFsdWVzLiBUaGlzIG9wdGlvbiBlbXVsYXRlc1xuICAgKiB0aGUgYmVoYXZpb3Igb2YgdGhlIGBhc3luY2AgcGlwZS5cbiAgICovXG4gIHJlamVjdEVycm9ycz86IGJvb2xlYW47XG59XG5cbi8vIEJhc2UgY2FzZTogbm8gb3B0aW9ucyAtPiBgdW5kZWZpbmVkYCBpbiB0aGUgcmVzdWx0IHR5cGUuXG5leHBvcnQgZnVuY3Rpb24gdG9TaWduYWw8VD4oc291cmNlOiBPYnNlcnZhYmxlPFQ+fFN1YnNjcmliYWJsZTxUPik6IFNpZ25hbDxUfHVuZGVmaW5lZD47XG4vLyBPcHRpb25zIHdpdGggYHVuZGVmaW5lZGAgaW5pdGlhbCB2YWx1ZSBhbmQgbm8gYHJlcXVpcmVkU3luY2AgLT4gYHVuZGVmaW5lZGAuXG5leHBvcnQgZnVuY3Rpb24gdG9TaWduYWw8VD4oXG4gICAgc291cmNlOiBPYnNlcnZhYmxlPFQ+fFN1YnNjcmliYWJsZTxUPixcbiAgICBvcHRpb25zOiBUb1NpZ25hbE9wdGlvbnMme2luaXRpYWxWYWx1ZT86IHVuZGVmaW5lZCwgcmVxdWlyZVN5bmM/OiBmYWxzZX0pOiBTaWduYWw8VHx1bmRlZmluZWQ+O1xuLy8gT3B0aW9ucyB3aXRoIGBudWxsYCBpbml0aWFsIHZhbHVlIC0+IGBudWxsYC5cbmV4cG9ydCBmdW5jdGlvbiB0b1NpZ25hbDxUPihcbiAgICBzb3VyY2U6IE9ic2VydmFibGU8VD58U3Vic2NyaWJhYmxlPFQ+LFxuICAgIG9wdGlvbnM6IFRvU2lnbmFsT3B0aW9ucyZ7aW5pdGlhbFZhbHVlPzogbnVsbCwgcmVxdWlyZVN5bmM/OiBmYWxzZX0pOiBTaWduYWw8VHxudWxsPjtcbi8vIE9wdGlvbnMgd2l0aCBgdW5kZWZpbmVkYCBpbml0aWFsIHZhbHVlIGFuZCBgcmVxdWlyZWRTeW5jYCAtPiBzdHJpY3QgcmVzdWx0IHR5cGUuXG5leHBvcnQgZnVuY3Rpb24gdG9TaWduYWw8VD4oXG4gICAgc291cmNlOiBPYnNlcnZhYmxlPFQ+fFN1YnNjcmliYWJsZTxUPixcbiAgICBvcHRpb25zOiBUb1NpZ25hbE9wdGlvbnMme2luaXRpYWxWYWx1ZT86IHVuZGVmaW5lZCwgcmVxdWlyZVN5bmM6IHRydWV9KTogU2lnbmFsPFQ+O1xuLy8gT3B0aW9ucyB3aXRoIGEgbW9yZSBzcGVjaWZpYyBpbml0aWFsIHZhbHVlIHR5cGUuXG5leHBvcnQgZnVuY3Rpb24gdG9TaWduYWw8VCwgY29uc3QgVSBleHRlbmRzIFQ+KFxuICAgIHNvdXJjZTogT2JzZXJ2YWJsZTxUPnxTdWJzY3JpYmFibGU8VD4sXG4gICAgb3B0aW9uczogVG9TaWduYWxPcHRpb25zJntpbml0aWFsVmFsdWU6IFUsIHJlcXVpcmVTeW5jPzogZmFsc2V9KTogU2lnbmFsPFR8VT47XG5cbi8qKlxuICogR2V0IHRoZSBjdXJyZW50IHZhbHVlIG9mIGFuIGBPYnNlcnZhYmxlYCBhcyBhIHJlYWN0aXZlIGBTaWduYWxgLlxuICpcbiAqIGB0b1NpZ25hbGAgcmV0dXJucyBhIGBTaWduYWxgIHdoaWNoIHByb3ZpZGVzIHN5bmNocm9ub3VzIHJlYWN0aXZlIGFjY2VzcyB0byB2YWx1ZXMgcHJvZHVjZWRcbiAqIGJ5IHRoZSBnaXZlbiBgT2JzZXJ2YWJsZWAsIGJ5IHN1YnNjcmliaW5nIHRvIHRoYXQgYE9ic2VydmFibGVgLiBUaGUgcmV0dXJuZWQgYFNpZ25hbGAgd2lsbCBhbHdheXNcbiAqIGhhdmUgdGhlIG1vc3QgcmVjZW50IHZhbHVlIGVtaXR0ZWQgYnkgdGhlIHN1YnNjcmlwdGlvbiwgYW5kIHdpbGwgdGhyb3cgYW4gZXJyb3IgaWYgdGhlXG4gKiBgT2JzZXJ2YWJsZWAgZXJyb3JzLlxuICpcbiAqIFdpdGggYHJlcXVpcmVTeW5jYCBzZXQgdG8gYHRydWVgLCBgdG9TaWduYWxgIHdpbGwgYXNzZXJ0IHRoYXQgdGhlIGBPYnNlcnZhYmxlYCBwcm9kdWNlcyBhIHZhbHVlXG4gKiBpbW1lZGlhdGVseSB1cG9uIHN1YnNjcmlwdGlvbi4gTm8gYGluaXRpYWxWYWx1ZWAgaXMgbmVlZGVkIGluIHRoaXMgY2FzZSwgYW5kIHRoZSByZXR1cm5lZCBzaWduYWxcbiAqIGRvZXMgbm90IGluY2x1ZGUgYW4gYHVuZGVmaW5lZGAgdHlwZS5cbiAqXG4gKiBCeSBkZWZhdWx0LCB0aGUgc3Vic2NyaXB0aW9uIHdpbGwgYmUgYXV0b21hdGljYWxseSBjbGVhbmVkIHVwIHdoZW4gdGhlIGN1cnJlbnQgW2luamVjdGlvblxuICogY29udGV4dF0oL2d1aWRlL2RlcGVuZGVuY3ktaW5qZWN0aW9uLWNvbnRleHQpIGlzIGRlc3Ryb3llZC4gRm9yIGV4YW1wbGUsIHdoZW4gYHRvT2JzZXJ2YWJsZWAgaXNcbiAqIGNhbGxlZCBkdXJpbmcgdGhlIGNvbnN0cnVjdGlvbiBvZiBhIGNvbXBvbmVudCwgdGhlIHN1YnNjcmlwdGlvbiB3aWxsIGJlIGNsZWFuZWQgdXAgd2hlbiB0aGVcbiAqIGNvbXBvbmVudCBpcyBkZXN0cm95ZWQuIElmIGFuIGluamVjdGlvbiBjb250ZXh0IGlzIG5vdCBhdmFpbGFibGUsIGFuIGV4cGxpY2l0IGBJbmplY3RvcmAgY2FuIGJlXG4gKiBwYXNzZWQgaW5zdGVhZC5cbiAqXG4gKiBJZiB0aGUgc3Vic2NyaXB0aW9uIHNob3VsZCBwZXJzaXN0IHVudGlsIHRoZSBgT2JzZXJ2YWJsZWAgaXRzZWxmIGNvbXBsZXRlcywgdGhlIGBtYW51YWxDbGVhbnVwYFxuICogb3B0aW9uIGNhbiBiZSBzcGVjaWZpZWQgaW5zdGVhZCwgd2hpY2ggZGlzYWJsZXMgdGhlIGF1dG9tYXRpYyBzdWJzY3JpcHRpb24gdGVhcmRvd24uIE5vIGluamVjdGlvblxuICogY29udGV4dCBpcyBuZWVkZWQgaW4gdGhpcyBjb25maWd1cmF0aW9uIGFzIHdlbGwuXG4gKlxuICogQGRldmVsb3BlclByZXZpZXdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvU2lnbmFsPFQsIFUgPSB1bmRlZmluZWQ+KFxuICAgIHNvdXJjZTogT2JzZXJ2YWJsZTxUPnxTdWJzY3JpYmFibGU8VD4sXG4gICAgb3B0aW9ucz86IFRvU2lnbmFsT3B0aW9ucyZ7aW5pdGlhbFZhbHVlPzogVX0pOiBTaWduYWw8VHxVPiB7XG4gIG5nRGV2TW9kZSAmJlxuICAgICAgYXNzZXJ0Tm90SW5SZWFjdGl2ZUNvbnRleHQoXG4gICAgICAgICAgdG9TaWduYWwsXG4gICAgICAgICAgJ0ludm9raW5nIGB0b1NpZ25hbGAgY2F1c2VzIG5ldyBzdWJzY3JpcHRpb25zIGV2ZXJ5IHRpbWUuICcgK1xuICAgICAgICAgICAgICAnQ29uc2lkZXIgbW92aW5nIGB0b1NpZ25hbGAgb3V0c2lkZSBvZiB0aGUgcmVhY3RpdmUgY29udGV4dCBhbmQgcmVhZCB0aGUgc2lnbmFsIHZhbHVlIHdoZXJlIG5lZWRlZC4nKTtcblxuICBjb25zdCByZXF1aXJlc0NsZWFudXAgPSAhb3B0aW9ucz8ubWFudWFsQ2xlYW51cDtcbiAgcmVxdWlyZXNDbGVhbnVwICYmICFvcHRpb25zPy5pbmplY3RvciAmJiBhc3NlcnRJbkluamVjdGlvbkNvbnRleHQodG9TaWduYWwpO1xuICBjb25zdCBjbGVhbnVwUmVmID1cbiAgICAgIHJlcXVpcmVzQ2xlYW51cCA/IG9wdGlvbnM/LmluamVjdG9yPy5nZXQoRGVzdHJveVJlZikgPz8gaW5qZWN0KERlc3Ryb3lSZWYpIDogbnVsbDtcblxuICAvLyBOb3RlOiBUIGlzIHRoZSBPYnNlcnZhYmxlIHZhbHVlIHR5cGUsIGFuZCBVIGlzIHRoZSBpbml0aWFsIHZhbHVlIHR5cGUuIFRoZXkgZG9uJ3QgaGF2ZSB0byBiZVxuICAvLyB0aGUgc2FtZSAtIHRoZSByZXR1cm5lZCBzaWduYWwgZ2l2ZXMgdmFsdWVzIG9mIHR5cGUgYFRgLlxuICBsZXQgc3RhdGU6IFdyaXRhYmxlU2lnbmFsPFN0YXRlPFR8VT4+O1xuICBpZiAob3B0aW9ucz8ucmVxdWlyZVN5bmMpIHtcbiAgICAvLyBJbml0aWFsbHkgdGhlIHNpZ25hbCBpcyBpbiBhIGBOb1ZhbHVlYCBzdGF0ZS5cbiAgICBzdGF0ZSA9IHNpZ25hbCh7a2luZDogU3RhdGVLaW5kLk5vVmFsdWV9KTtcbiAgfSBlbHNlIHtcbiAgICAvLyBJZiBhbiBpbml0aWFsIHZhbHVlIHdhcyBwYXNzZWQsIHVzZSBpdC4gT3RoZXJ3aXNlLCB1c2UgYHVuZGVmaW5lZGAgYXMgdGhlIGluaXRpYWwgdmFsdWUuXG4gICAgc3RhdGUgPSBzaWduYWw8U3RhdGU8VHxVPj4oe2tpbmQ6IFN0YXRlS2luZC5WYWx1ZSwgdmFsdWU6IG9wdGlvbnM/LmluaXRpYWxWYWx1ZSBhcyBVfSk7XG4gIH1cblxuICAvLyBOb3RlOiBUaGlzIGNvZGUgY2Fubm90IHJ1biBpbnNpZGUgYSByZWFjdGl2ZSBjb250ZXh0IChzZWUgYXNzZXJ0aW9uIGFib3ZlKS4gSWYgd2UnZCBzdXBwb3J0XG4gIC8vIHRoaXMsIHdlIHdvdWxkIHN1YnNjcmliZSB0byB0aGUgb2JzZXJ2YWJsZSBvdXRzaWRlIG9mIHRoZSBjdXJyZW50IHJlYWN0aXZlIGNvbnRleHQsIGF2b2lkaW5nXG4gIC8vIHRoYXQgc2lkZS1lZmZlY3Qgc2lnbmFsIHJlYWRzL3dyaXRlcyBhcmUgYXR0cmlidXRlIHRvIHRoZSBjdXJyZW50IGNvbnN1bWVyLiBUaGUgY3VycmVudFxuICAvLyBjb25zdW1lciBvbmx5IG5lZWRzIHRvIGJlIG5vdGlmaWVkIHdoZW4gdGhlIGBzdGF0ZWAgc2lnbmFsIGNoYW5nZXMgdGhyb3VnaCB0aGUgb2JzZXJ2YWJsZVxuICAvLyBzdWJzY3JpcHRpb24uIEFkZGl0aW9uYWwgY29udGV4dCAocmVsYXRlZCB0byBhc3luYyBwaXBlKTpcbiAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2FuZ3VsYXIvYW5ndWxhci9wdWxsLzUwNTIyLlxuICBjb25zdCBzdWIgPSBzb3VyY2Uuc3Vic2NyaWJlKHtcbiAgICBuZXh0OiB2YWx1ZSA9PiBzdGF0ZS5zZXQoe2tpbmQ6IFN0YXRlS2luZC5WYWx1ZSwgdmFsdWV9KSxcbiAgICBlcnJvcjogZXJyb3IgPT4ge1xuICAgICAgaWYgKG9wdGlvbnM/LnJlamVjdEVycm9ycykge1xuICAgICAgICAvLyBLaWNrIHRoZSBlcnJvciBiYWNrIHRvIFJ4SlMuIEl0IHdpbGwgYmUgY2F1Z2h0IGFuZCByZXRocm93biBpbiBhIG1hY3JvdGFzaywgd2hpY2ggY2F1c2VzXG4gICAgICAgIC8vIHRoZSBlcnJvciB0byBlbmQgdXAgYXMgYW4gdW5jYXVnaHQgZXhjZXB0aW9uLlxuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cbiAgICAgIHN0YXRlLnNldCh7a2luZDogU3RhdGVLaW5kLkVycm9yLCBlcnJvcn0pO1xuICAgIH0sXG4gICAgLy8gQ29tcGxldGlvbiBvZiB0aGUgT2JzZXJ2YWJsZSBpcyBtZWFuaW5nbGVzcyB0byB0aGUgc2lnbmFsLiBTaWduYWxzIGRvbid0IGhhdmUgYSBjb25jZXB0IG9mXG4gICAgLy8gXCJjb21wbGV0ZVwiLlxuICB9KTtcblxuICBpZiAobmdEZXZNb2RlICYmIG9wdGlvbnM/LnJlcXVpcmVTeW5jICYmIHN0YXRlKCkua2luZCA9PT0gU3RhdGVLaW5kLk5vVmFsdWUpIHtcbiAgICB0aHJvdyBuZXcgybVSdW50aW1lRXJyb3IoXG4gICAgICAgIMm1UnVudGltZUVycm9yQ29kZS5SRVFVSVJFX1NZTkNfV0lUSE9VVF9TWU5DX0VNSVQsXG4gICAgICAgICdgdG9TaWduYWwoKWAgY2FsbGVkIHdpdGggYHJlcXVpcmVTeW5jYCBidXQgYE9ic2VydmFibGVgIGRpZCBub3QgZW1pdCBzeW5jaHJvbm91c2x5LicpO1xuICB9XG5cbiAgLy8gVW5zdWJzY3JpYmUgd2hlbiB0aGUgY3VycmVudCBjb250ZXh0IGlzIGRlc3Ryb3llZCwgaWYgcmVxdWVzdGVkLlxuICBjbGVhbnVwUmVmPy5vbkRlc3Ryb3koc3ViLnVuc3Vic2NyaWJlLmJpbmQoc3ViKSk7XG5cbiAgLy8gVGhlIGFjdHVhbCByZXR1cm5lZCBzaWduYWwgaXMgYSBgY29tcHV0ZWRgIG9mIHRoZSBgU3RhdGVgIHNpZ25hbCwgd2hpY2ggbWFwcyB0aGUgdmFyaW91cyBzdGF0ZXNcbiAgLy8gdG8gZWl0aGVyIHZhbHVlcyBvciBlcnJvcnMuXG4gIHJldHVybiBjb21wdXRlZCgoKSA9PiB7XG4gICAgY29uc3QgY3VycmVudCA9IHN0YXRlKCk7XG4gICAgc3dpdGNoIChjdXJyZW50LmtpbmQpIHtcbiAgICAgIGNhc2UgU3RhdGVLaW5kLlZhbHVlOlxuICAgICAgICByZXR1cm4gY3VycmVudC52YWx1ZTtcbiAgICAgIGNhc2UgU3RhdGVLaW5kLkVycm9yOlxuICAgICAgICB0aHJvdyBjdXJyZW50LmVycm9yO1xuICAgICAgY2FzZSBTdGF0ZUtpbmQuTm9WYWx1ZTpcbiAgICAgICAgLy8gVGhpcyBzaG91bGRuJ3QgcmVhbGx5IGhhcHBlbiBiZWNhdXNlIHRoZSBlcnJvciBpcyB0aHJvd24gb24gY3JlYXRpb24uXG4gICAgICAgIC8vIFRPRE8oYWx4aHViKTogdXNlIGEgUnVudGltZUVycm9yIHdoZW4gd2UgZmluYWxpemUgdGhlIGVycm9yIHNlbWFudGljc1xuICAgICAgICB0aHJvdyBuZXcgybVSdW50aW1lRXJyb3IoXG4gICAgICAgICAgICDJtVJ1bnRpbWVFcnJvckNvZGUuUkVRVUlSRV9TWU5DX1dJVEhPVVRfU1lOQ19FTUlULFxuICAgICAgICAgICAgJ2B0b1NpZ25hbCgpYCBjYWxsZWQgd2l0aCBgcmVxdWlyZVN5bmNgIGJ1dCBgT2JzZXJ2YWJsZWAgZGlkIG5vdCBlbWl0IHN5bmNocm9ub3VzbHkuJyk7XG4gICAgfVxuICB9KTtcbn1cblxuY29uc3QgZW51bSBTdGF0ZUtpbmQge1xuICBOb1ZhbHVlLFxuICBWYWx1ZSxcbiAgRXJyb3IsXG59XG5cbmludGVyZmFjZSBOb1ZhbHVlU3RhdGUge1xuICBraW5kOiBTdGF0ZUtpbmQuTm9WYWx1ZTtcbn1cblxuaW50ZXJmYWNlIFZhbHVlU3RhdGU8VD4ge1xuICBraW5kOiBTdGF0ZUtpbmQuVmFsdWU7XG4gIHZhbHVlOiBUO1xufVxuXG5pbnRlcmZhY2UgRXJyb3JTdGF0ZSB7XG4gIGtpbmQ6IFN0YXRlS2luZC5FcnJvcjtcbiAgZXJyb3I6IHVua25vd247XG59XG5cbnR5cGUgU3RhdGU8VD4gPSBOb1ZhbHVlU3RhdGV8VmFsdWVTdGF0ZTxUPnxFcnJvclN0YXRlO1xuIl19