UNPKG

@angular/core

Version:

Angular - the core framework

312 lines • 46.5 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 */ /** * The currently active consumer `ReactiveNode`, if running code in a reactive context. * * Change this via `setActiveConsumer`. */ let activeConsumer = null; let inNotificationPhase = false; /** * Global epoch counter. Incremented whenever a source signal is set. */ let epoch = 1; /** * Symbol used to tell `Signal`s apart from other functions. * * This can be used to auto-unwrap signals in various cases, or to auto-wrap non-signal values. */ export const SIGNAL = /* @__PURE__ */ Symbol('SIGNAL'); export function setActiveConsumer(consumer) { const prev = activeConsumer; activeConsumer = consumer; return prev; } export function getActiveConsumer() { return activeConsumer; } export function isInNotificationPhase() { return inNotificationPhase; } export function isReactive(value) { return value[SIGNAL] !== undefined; } export const REACTIVE_NODE = { version: 0, lastCleanEpoch: 0, dirty: false, producerNode: undefined, producerLastReadVersion: undefined, producerIndexOfThis: undefined, nextProducerIndex: 0, liveConsumerNode: undefined, liveConsumerIndexOfThis: undefined, consumerAllowSignalWrites: false, consumerIsAlwaysLive: false, producerMustRecompute: () => false, producerRecomputeValue: () => { }, consumerMarkedDirty: () => { }, consumerOnSignalRead: () => { }, }; /** * Called by implementations when a producer's signal is read. */ export function producerAccessed(node) { if (inNotificationPhase) { throw new Error(typeof ngDevMode !== 'undefined' && ngDevMode ? `Assertion error: signal read during notification phase` : ''); } if (activeConsumer === null) { // Accessed outside of a reactive context, so nothing to record. return; } activeConsumer.consumerOnSignalRead(node); // This producer is the `idx`th dependency of `activeConsumer`. const idx = activeConsumer.nextProducerIndex++; assertConsumerNode(activeConsumer); if (idx < activeConsumer.producerNode.length && activeConsumer.producerNode[idx] !== node) { // There's been a change in producers since the last execution of `activeConsumer`. // `activeConsumer.producerNode[idx]` holds a stale dependency which will be be removed and // replaced with `this`. // // If `activeConsumer` isn't live, then this is a no-op, since we can replace the producer in // `activeConsumer.producerNode` directly. However, if `activeConsumer` is live, then we need // to remove it from the stale producer's `liveConsumer`s. if (consumerIsLive(activeConsumer)) { const staleProducer = activeConsumer.producerNode[idx]; producerRemoveLiveConsumerAtIndex(staleProducer, activeConsumer.producerIndexOfThis[idx]); // At this point, the only record of `staleProducer` is the reference at // `activeConsumer.producerNode[idx]` which will be overwritten below. } } if (activeConsumer.producerNode[idx] !== node) { // We're a new dependency of the consumer (at `idx`). activeConsumer.producerNode[idx] = node; // If the active consumer is live, then add it as a live consumer. If not, then use 0 as a // placeholder value. activeConsumer.producerIndexOfThis[idx] = consumerIsLive(activeConsumer) ? producerAddLiveConsumer(node, activeConsumer, idx) : 0; } activeConsumer.producerLastReadVersion[idx] = node.version; } /** * Increment the global epoch counter. * * Called by source producers (that is, not computeds) whenever their values change. */ export function producerIncrementEpoch() { epoch++; } /** * Ensure this producer's `version` is up-to-date. */ export function producerUpdateValueVersion(node) { if (consumerIsLive(node) && !node.dirty) { // A live consumer will be marked dirty by producers, so a clean state means that its version // is guaranteed to be up-to-date. return; } if (!node.dirty && node.lastCleanEpoch === epoch) { // Even non-live consumers can skip polling if they previously found themselves to be clean at // the current epoch, since their dependencies could not possibly have changed (such a change // would've increased the epoch). return; } if (!node.producerMustRecompute(node) && !consumerPollProducersForChange(node)) { // None of our producers report a change since the last time they were read, so no // recomputation of our value is necessary, and we can consider ourselves clean. node.dirty = false; node.lastCleanEpoch = epoch; return; } node.producerRecomputeValue(node); // After recomputing the value, we're no longer dirty. node.dirty = false; node.lastCleanEpoch = epoch; } /** * Propagate a dirty notification to live consumers of this producer. */ export function producerNotifyConsumers(node) { if (node.liveConsumerNode === undefined) { return; } // Prevent signal reads when we're updating the graph const prev = inNotificationPhase; inNotificationPhase = true; try { for (const consumer of node.liveConsumerNode) { if (!consumer.dirty) { consumerMarkDirty(consumer); } } } finally { inNotificationPhase = prev; } } /** * Whether this `ReactiveNode` in its producer capacity is currently allowed to initiate updates, * based on the current consumer context. */ export function producerUpdatesAllowed() { return activeConsumer?.consumerAllowSignalWrites !== false; } export function consumerMarkDirty(node) { node.dirty = true; producerNotifyConsumers(node); node.consumerMarkedDirty?.(node); } /** * Prepare this consumer to run a computation in its reactive context. * * Must be called by subclasses which represent reactive computations, before those computations * begin. */ export function consumerBeforeComputation(node) { node && (node.nextProducerIndex = 0); return setActiveConsumer(node); } /** * Finalize this consumer's state after a reactive computation has run. * * Must be called by subclasses which represent reactive computations, after those computations * have finished. */ export function consumerAfterComputation(node, prevConsumer) { setActiveConsumer(prevConsumer); if (!node || node.producerNode === undefined || node.producerIndexOfThis === undefined || node.producerLastReadVersion === undefined) { return; } if (consumerIsLive(node)) { // For live consumers, we need to remove the producer -> consumer edge for any stale producers // which weren't dependencies after the recomputation. for (let i = node.nextProducerIndex; i < node.producerNode.length; i++) { producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]); } } // Truncate the producer tracking arrays. // Perf note: this is essentially truncating the length to `node.nextProducerIndex`, but // benchmarking has shown that individual pop operations are faster. while (node.producerNode.length > node.nextProducerIndex) { node.producerNode.pop(); node.producerLastReadVersion.pop(); node.producerIndexOfThis.pop(); } } /** * Determine whether this consumer has any dependencies which have changed since the last time * they were read. */ export function consumerPollProducersForChange(node) { assertConsumerNode(node); // Poll producers for change. for (let i = 0; i < node.producerNode.length; i++) { const producer = node.producerNode[i]; const seenVersion = node.producerLastReadVersion[i]; // First check the versions. A mismatch means that the producer's value is known to have // changed since the last time we read it. if (seenVersion !== producer.version) { return true; } // The producer's version is the same as the last time we read it, but it might itself be // stale. Force the producer to recompute its version (calculating a new value if necessary). producerUpdateValueVersion(producer); // Now when we do this check, `producer.version` is guaranteed to be up to date, so if the // versions still match then it has not changed since the last time we read it. if (seenVersion !== producer.version) { return true; } } return false; } /** * Disconnect this consumer from the graph. */ export function consumerDestroy(node) { assertConsumerNode(node); if (consumerIsLive(node)) { // Drop all connections from the graph to this node. for (let i = 0; i < node.producerNode.length; i++) { producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]); } } // Truncate all the arrays to drop all connection from this node to the graph. node.producerNode.length = node.producerLastReadVersion.length = node.producerIndexOfThis.length = 0; if (node.liveConsumerNode) { node.liveConsumerNode.length = node.liveConsumerIndexOfThis.length = 0; } } /** * Add `consumer` as a live consumer of this node. * * Note that this operation is potentially transitive. If this node becomes live, then it becomes * a live consumer of all of its current producers. */ function producerAddLiveConsumer(node, consumer, indexOfThis) { assertProducerNode(node); assertConsumerNode(node); if (node.liveConsumerNode.length === 0) { // When going from 0 to 1 live consumers, we become a live consumer to our producers. for (let i = 0; i < node.producerNode.length; i++) { node.producerIndexOfThis[i] = producerAddLiveConsumer(node.producerNode[i], node, i); } } node.liveConsumerIndexOfThis.push(indexOfThis); return node.liveConsumerNode.push(consumer) - 1; } /** * Remove the live consumer at `idx`. */ function producerRemoveLiveConsumerAtIndex(node, idx) { assertProducerNode(node); assertConsumerNode(node); if (typeof ngDevMode !== 'undefined' && ngDevMode && idx >= node.liveConsumerNode.length) { throw new Error(`Assertion error: active consumer index ${idx} is out of bounds of ${node.liveConsumerNode.length} consumers)`); } if (node.liveConsumerNode.length === 1) { // When removing the last live consumer, we will no longer be live. We need to remove // ourselves from our producers' tracking (which may cause consumer-producers to lose // liveness as well). for (let i = 0; i < node.producerNode.length; i++) { producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]); } } // Move the last value of `liveConsumers` into `idx`. Note that if there's only a single // live consumer, this is a no-op. const lastIdx = node.liveConsumerNode.length - 1; node.liveConsumerNode[idx] = node.liveConsumerNode[lastIdx]; node.liveConsumerIndexOfThis[idx] = node.liveConsumerIndexOfThis[lastIdx]; // Truncate the array. node.liveConsumerNode.length--; node.liveConsumerIndexOfThis.length--; // If the index is still valid, then we need to fix the index pointer from the producer to this // consumer, and update it from `lastIdx` to `idx` (accounting for the move above). if (idx < node.liveConsumerNode.length) { const idxProducer = node.liveConsumerIndexOfThis[idx]; const consumer = node.liveConsumerNode[idx]; assertConsumerNode(consumer); consumer.producerIndexOfThis[idxProducer] = idx; } } function consumerIsLive(node) { return node.consumerIsAlwaysLive || (node?.liveConsumerNode?.length ?? 0) > 0; } function assertConsumerNode(node) { node.producerNode ??= []; node.producerIndexOfThis ??= []; node.producerLastReadVersion ??= []; } function assertProducerNode(node) { node.liveConsumerNode ??= []; node.liveConsumerIndexOfThis ??= []; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JhcGguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb3JlL3ByaW1pdGl2ZXMvc2lnbmFscy9zcmMvZ3JhcGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBT0g7Ozs7R0FJRztBQUNILElBQUksY0FBYyxHQUFzQixJQUFJLENBQUM7QUFDN0MsSUFBSSxtQkFBbUIsR0FBRyxLQUFLLENBQUM7QUFJaEM7O0dBRUc7QUFDSCxJQUFJLEtBQUssR0FBWSxDQUFZLENBQUM7QUFFbEM7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLE1BQU0sR0FBRyxlQUFlLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRXZELE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxRQUEyQjtJQUMzRCxNQUFNLElBQUksR0FBRyxjQUFjLENBQUM7SUFDNUIsY0FBYyxHQUFHLFFBQVEsQ0FBQztJQUMxQixPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFFRCxNQUFNLFVBQVUsaUJBQWlCO0lBQy9CLE9BQU8sY0FBYyxDQUFDO0FBQ3hCLENBQUM7QUFFRCxNQUFNLFVBQVUscUJBQXFCO0lBQ25DLE9BQU8sbUJBQW1CLENBQUM7QUFDN0IsQ0FBQztBQU1ELE1BQU0sVUFBVSxVQUFVLENBQUMsS0FBYztJQUN2QyxPQUFRLEtBQTJCLENBQUMsTUFBTSxDQUFDLEtBQUssU0FBUyxDQUFDO0FBQzVELENBQUM7QUFFRCxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQWlCO0lBQ3pDLE9BQU8sRUFBRSxDQUFZO0lBQ3JCLGNBQWMsRUFBRSxDQUFZO0lBQzVCLEtBQUssRUFBRSxLQUFLO0lBQ1osWUFBWSxFQUFFLFNBQVM7SUFDdkIsdUJBQXVCLEVBQUUsU0FBUztJQUNsQyxtQkFBbUIsRUFBRSxTQUFTO0lBQzlCLGlCQUFpQixFQUFFLENBQUM7SUFDcEIsZ0JBQWdCLEVBQUUsU0FBUztJQUMzQix1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b2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbi8vIFJlcXVpcmVkIGFzIHRoZSBzaWduYWxzIGxpYnJhcnkgaXMgaW4gYSBzZXBhcmF0ZSBwYWNrYWdlLCBzbyB3ZSBuZWVkIHRvIGV4cGxpY2l0bHkgZW5zdXJlIHRoZVxuLy8gZ2xvYmFsIGBuZ0Rldk1vZGVgIHR5cGUgaXMgZGVmaW5lZC5cbmRlY2xhcmUgY29uc3QgbmdEZXZNb2RlOiBib29sZWFufHVuZGVmaW5lZDtcblxuXG4vKipcbiAqIFRoZSBjdXJyZW50bHkgYWN0aXZlIGNvbnN1bWVyIGBSZWFjdGl2ZU5vZGVgLCBpZiBydW5uaW5nIGNvZGUgaW4gYSByZWFjdGl2ZSBjb250ZXh0LlxuICpcbiAqIENoYW5nZSB0aGlzIHZpYSBgc2V0QWN0aXZlQ29uc3VtZXJgLlxuICovXG5sZXQgYWN0aXZlQ29uc3VtZXI6IFJlYWN0aXZlTm9kZXxudWxsID0gbnVsbDtcbmxldCBpbk5vdGlmaWNhdGlvblBoYXNlID0gZmFsc2U7XG5cbnR5cGUgVmVyc2lvbiA9IG51bWJlciZ7X19icmFuZDogJ1ZlcnNpb24nfTtcblxuLyoqXG4gKiBHbG9iYWwgZXBvY2ggY291bnRlci4gSW5jcmVtZW50ZWQgd2hlbmV2ZXIgYSBzb3VyY2Ugc2lnbmFsIGlzIHNldC5cbiAqL1xubGV0IGVwb2NoOiBWZXJzaW9uID0gMSBhcyBWZXJzaW9uO1xuXG4vKipcbiAqIFN5bWJvbCB1c2VkIHRvIHRlbGwgYFNpZ25hbGBzIGFwYXJ0IGZyb20gb3RoZXIgZnVuY3Rpb25zLlxuICpcbiAqIFRoaXMgY2FuIGJlIHVzZWQgdG8gYXV0by11bndyYXAgc2lnbmFscyBpbiB2YXJpb3VzIGNhc2VzLCBvciB0byBhdXRvLXdyYXAgbm9uLXNpZ25hbCB2YWx1ZXMuXG4gKi9cbmV4cG9ydCBjb25zdCBTSUdOQUwgPSAvKiBAX19QVVJFX18gKi8gU3ltYm9sKCdTSUdOQUwnKTtcblxuZXhwb3J0IGZ1bmN0aW9uIHNldEFjdGl2ZUNvbnN1bWVyKGNvbnN1bWVyOiBSZWFjdGl2ZU5vZGV8bnVsbCk6IFJlYWN0aXZlTm9kZXxudWxsIHtcbiAgY29uc3QgcHJldiA9IGFjdGl2ZUNvbnN1bWVyO1xuICBhY3RpdmVDb25zdW1lciA9IGNvbnN1bWVyO1xuICByZXR1cm4gcHJldjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEFjdGl2ZUNvbnN1bWVyKCk6IFJlYWN0aXZlTm9kZXxudWxsIHtcbiAgcmV0dXJuIGFjdGl2ZUNvbnN1bWVyO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNJbk5vdGlmaWNhdGlvblBoYXNlKCk6IGJvb2xlYW4ge1xuICByZXR1cm4gaW5Ob3RpZmljYXRpb25QaGFzZTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZWFjdGl2ZSB7XG4gIFtTSUdOQUxdOiBSZWFjdGl2ZU5vZGU7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1JlYWN0aXZlKHZhbHVlOiB1bmtub3duKTogdmFsdWUgaXMgUmVhY3RpdmUge1xuICByZXR1cm4gKHZhbHVlIGFzIFBhcnRpYWw8UmVhY3RpdmU+KVtTSUdOQUxdICE9PSB1bmRlZmluZWQ7XG59XG5cbmV4cG9ydCBjb25zdCBSRUFDVElWRV9OT0RFOiBSZWFjdGl2ZU5vZGUgPSB7XG4gIHZlcnNpb246IDAgYXMgVmVyc2lvbixcbiAgbGFzdENsZWFuRXBvY2g6IDAgYXMgVmVyc2lvbixcbiAgZGlydHk6IGZhbHNlLFxuICBwcm9kdWNlck5vZGU6IHVuZGVmaW5lZCxcbiAgcHJvZHVjZXJMYXN0UmVhZFZlcnNpb246IHVuZGVmaW5lZCxcbiAgcHJvZHVjZXJJbmRleE9mVGhpczogdW5kZWZpbmVkLFxuICBuZXh0UHJvZHVjZXJJbmRleDogMCxcbiAgbGl2ZUNvbnN1bWVyTm9kZTogdW5kZWZpbmVkLFxuICBsaXZlQ29uc3VtZXJJbmRleE9mVGhpczogdW5kZWZpbmVkLFxuICBjb25zdW1lckFsbG93U2lnbmFsV3JpdGVzOiBmYWxzZSxcbiAgY29uc3VtZXJJc0Fsd2F5c0xpdmU6IGZhbHNlLFxuICBwcm9kdWNlck11c3RSZWNvbXB1dGU6ICgpID0+IGZhbHNlLFxuICBwcm9kdWNlclJlY29tcHV0ZVZhbHVlOiAoKSA9PiB7fSxcbiAgY29uc3VtZXJNYXJrZWREaXJ0eTogKCkgPT4ge30sXG4gIGNvbnN1bWVyT25TaWduYWxSZWFkOiAoKSA9PiB7fSxcbn07XG5cbi8qKlxuICogQSBwcm9kdWNlciBhbmQvb3IgY29uc3VtZXIgd2hpY2ggcGFydGljaXBhdGVzIGluIHRoZSByZWFjdGl2ZSBncmFwaC5cbiAqXG4gKiBQcm9kdWNlciBgUmVhY3RpdmVOb2RlYHMgd2hpY2ggYXJlIGFjY2Vzc2VkIHdoZW4gYSBjb25zdW1lciBgUmVhY3RpdmVOb2RlYCBpcyB0aGVcbiAqIGBhY3RpdmVDb25zdW1lcmAgYXJlIHRyYWNrZWQgYXMgZGVwZW5kZW5jaWVzIG9mIHRoYXQgY29uc3VtZXIuXG4gKlxuICogQ2VydGFpbiBjb25zdW1lcnMgYXJlIGFsc28gdHJhY2tlZCBhcyBcImxpdmVcIiBjb25zdW1lcnMgYW5kIGNyZWF0ZSBlZGdlcyBpbiB0aGUgb3RoZXIgZGlyZWN0aW9uLFxuICogZnJvbSBwcm9kdWNlciB0byBjb25zdW1lci4gVGhlc2UgZWRnZXMgYXJlIHVzZWQgdG8gcHJvcGFnYXRlIGNoYW5nZSBub3RpZmljYXRpb25zIHdoZW4gYVxuICogcHJvZHVjZXIncyB2YWx1ZSBpcyB1cGRhdGVkLlxuICpcbiAqIEEgYFJlYWN0aXZlTm9kZWAgbWF5IGJlIGJvdGggYSBwcm9kdWNlciBhbmQgY29uc3VtZXIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVhY3RpdmVOb2RlIHtcbiAgLyoqXG4gICAqIFZlcnNpb24gb2YgdGhlIHZhbHVlIHRoYXQgdGhpcyBub2RlIHByb2R1Y2VzLlxuICAgKlxuICAgKiBUaGlzIGlzIGluY3JlbWVudGVkIHdoZW5ldmVyIGEgbmV3IHZhbHVlIGlzIHByb2R1Y2VkIGJ5IHRoaXMgbm9kZSB3aGljaCBpcyBub3QgZXF1YWwgdG8gdGhlXG4gICAqIHByZXZpb3VzIHZhbHVlIChieSB3aGF0ZXZlciBkZWZpbml0aW9uIG9mIGVxdWFsaXR5IGlzIGluIHVzZSkuXG4gICAqL1xuICB2ZXJzaW9uOiBWZXJzaW9uO1xuXG4gIC8qKlxuICAgKiBFcG9jaCBhdCB3aGljaCB0aGlzIG5vZGUgaXMgdmVyaWZpZWQgdG8gYmUgY2xlYW4uXG4gICAqXG4gICAqIFRoaXMgYWxsb3dzIHNraXBwaW5nIG9mIHNvbWUgcG9sbGluZyBvcGVyYXRpb25zIGluIHRoZSBjYXNlIHdoZXJlIG5vIHNpZ25hbHMgaGF2ZSBiZWVuIHNldFxuICAgKiBzaW5jZSB0aGlzIG5vZGUgd2FzIGxhc3QgcmVhZC5cbiAgICovXG4gIGxhc3RDbGVhbkVwb2NoOiBWZXJzaW9uO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoaXMgbm9kZSAoaW4gaXRzIGNvbnN1bWVyIGNhcGFjaXR5KSBpcyBkaXJ0eS5cbiAgICpcbiAgICogT25seSBsaXZlIGNvbnN1bWVycyBiZWNvbWUgZGlydHksIHdoZW4gcmVjZWl2aW5nIGEgY2hhbmdlIG5vdGlmaWNhdGlvbiBmcm9tIGEgZGVwZW5kZW5jeVxuICAgKiBwcm9kdWNlci5cbiAgICovXG4gIGRpcnR5OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBQcm9kdWNlcnMgd2hpY2ggYXJlIGRlcGVuZGVuY2llcyBvZiB0aGlzIGNvbnN1bWVyLlxuICAgKlxuICAgKiBVc2VzIHRoZSBzYW1lIGluZGljZXMgYXMgdGhlIGBwcm9kdWNlckxhc3RSZWFkVmVyc2lvbmAgYW5kIGBwcm9kdWNlckluZGV4T2ZUaGlzYCBhcnJheXMuXG4gICAqL1xuICBwcm9kdWNlck5vZGU6IFJlYWN0aXZlTm9kZVtdfHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogYFZlcnNpb25gIG9mIHRoZSB2YWx1ZSBsYXN0IHJlYWQgYnkgYSBnaXZlbiBwcm9kdWNlci5cbiAgICpcbiAgICogVXNlcyB0aGUgc2FtZSBpbmRpY2VzIGFzIHRoZSBgcHJvZHVjZXJOb2RlYCBhbmQgYHByb2R1Y2VySW5kZXhPZlRoaXNgIGFycmF5cy5cbiAgICovXG4gIHByb2R1Y2VyTGFzdFJlYWRWZXJzaW9uOiBWZXJzaW9uW118dW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBJbmRleCBvZiBgdGhpc2AgKGNvbnN1bWVyKSBpbiBlYWNoIHByb2R1Y2VyJ3MgYGxpdmVDb25zdW1lcnNgIGFycmF5LlxuICAgKlxuICAgKiBUaGlzIHZhbHVlIGlzIG9ubHkgbWVhbmluZ2Z1bCBpZiB0aGlzIG5vZGUgaXMgbGl2ZSAoYGxpdmVDb25zdW1lcnMubGVuZ3RoID4gMGApLiBPdGhlcndpc2VcbiAgICogdGhlc2UgaW5kaWNlcyBhcmUgc3RhbGUuXG4gICAqXG4gICAqIFVzZXMgdGhlIHNhbWUgaW5kaWNlcyBhcyB0aGUgYHByb2R1Y2VyTm9kZWAgYW5kIGBwcm9kdWNlckxhc3RSZWFkVmVyc2lvbmAgYXJyYXlzLlxuICAgKi9cbiAgcHJvZHVjZXJJbmRleE9mVGhpczogbnVtYmVyW118dW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBJbmRleCBpbnRvIHRoZSBwcm9kdWNlciBhcnJheXMgdGhhdCB0aGUgbmV4dCBkZXBlbmRlbmN5IG9mIHRoaXMgbm9kZSBhcyBhIGNvbnN1bWVyIHdpbGwgdXNlLlxuICAgKlxuICAgKiBUaGlzIGluZGV4IGlzIHplcm9lZCBiZWZvcmUgdGhpcyBub2RlIGFzIGEgY29uc3VtZXIgYmVnaW5zIGV4ZWN1dGluZy4gV2hlbiBhIHByb2R1Y2VyIGlzIHJlYWQsXG4gICAqIGl0IGdldHMgaW5zZXJ0ZWQgaW50byB0aGUgcHJvZHVjZXJzIGFycmF5cyBhdCB0aGlzIGluZGV4LiBUaGVyZSBtYXkgYmUgYW4gZXhpc3RpbmcgZGVwZW5kZW5jeVxuICAgKiBpbiB0aGlzIGxvY2F0aW9uIHdoaWNoIG1heSBvciBtYXkgbm90IG1hdGNoIHRoZSBpbmNvbWluZyBwcm9kdWNlciwgZGVwZW5kaW5nIG9uIHdoZXRoZXIgdGhlXG4gICAqIHNhbWUgcHJvZHVjZXJzIHdlcmUgcmVhZCBpbiB0aGUgc2FtZSBvcmRlciBhcyB0aGUgbGFzdCBjb21wdXRhdGlvbi5cbiAgICovXG4gIG5leHRQcm9kdWNlckluZGV4OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEFycmF5IG9mIGNvbnN1bWVycyBvZiB0aGlzIHByb2R1Y2VyIHRoYXQgYXJlIFwibGl2ZVwiICh0aGV5IHJlcXVpcmUgcHVzaCBub3RpZmljYXRpb25zKS5cbiAgICpcbiAgICogYGxpdmVDb25zdW1lck5vZGUubGVuZ3RoYCBpcyBlZmZlY3RpdmVseSBvdXIgcmVmZXJlbmNlIGNvdW50IGZvciB0aGlzIG5vZGUuXG4gICAqL1xuICBsaXZlQ29uc3VtZXJOb2RlOiBSZWFjdGl2ZU5vZGVbXXx1bmRlZmluZWQ7XG5cbiAgLyoqXG4gICAqIEluZGV4IG9mIGB0aGlzYCAocHJvZHVjZXIpIGluIGVhY2ggY29uc3VtZXIncyBgcHJvZHVjZXJOb2RlYCBhcnJheS5cbiAgICpcbiAgICogVXNlcyB0aGUgc2FtZSBpbmRpY2VzIGFzIHRoZSBgbGl2ZUNvbnN1bWVyTm9kZWAgYXJyYXkuXG4gICAqL1xuICBsaXZlQ29uc3VtZXJJbmRleE9mVGhpczogbnVtYmVyW118dW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHdyaXRlcyB0byBzaWduYWxzIGFyZSBhbGxvd2VkIHdoZW4gdGhpcyBjb25zdW1lciBpcyB0aGUgYGFjdGl2ZUNvbnN1bWVyYC5cbiAgICpcbiAgICogVGhpcyBpcyB1c2VkIHRvIGVuZm9yY2UgZ3VhcmRyYWlscyBzdWNoIGFzIHByZXZlbnRpbmcgd3JpdGVzIHRvIHdyaXRhYmxlIHNpZ25hbHMgaW4gdGhlXG4gICAqIGNvbXB1dGF0aW9uIGZ1bmN0aW9uIG9mIGNvbXB1dGVkIHNpZ25hbHMsIHdoaWNoIGlzIHN1cHBvc2VkIHRvIGJlIHB1cmUuXG4gICAqL1xuICBjb25zdW1lckFsbG93U2lnbmFsV3JpdGVzOiBib29sZWFuO1xuXG4gIHJlYWRvbmx5IGNvbnN1bWVySXNBbHdheXNMaXZlOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBUcmFja3Mgd2hldGhlciBwcm9kdWNlcnMgbmVlZCB0byByZWNvbXB1dGUgdGhlaXIgdmFsdWUgaW5kZXBlbmRlbnRseSBvZiB0aGUgcmVhY3RpdmUgZ3JhcGggKGZvclxuICAgKiBleGFtcGxlLCBpZiBubyBpbml0aWFsIHZhbHVlIGhhcyBiZWVuIGNvbXB1dGVkKS5cbiAgICovXG4gIHByb2R1Y2VyTXVzdFJlY29tcHV0ZShub2RlOiB1bmtub3duKTogYm9vbGVhbjtcbiAgcHJvZHVjZXJSZWNvbXB1dGVWYWx1ZShub2RlOiB1bmtub3duKTogdm9pZDtcbiAgY29uc3VtZXJNYXJrZWREaXJ0eShub2RlOiB1bmtub3duKTogdm9pZDtcblxuICAvKipcbiAgICogQ2FsbGVkIHdoZW4gYSBzaWduYWwgaXMgcmVhZCB3aXRoaW4gdGhpcyBjb25zdW1lci5cbiAgICovXG4gIGNvbnN1bWVyT25TaWduYWxSZWFkKG5vZGU6IHVua25vd24pOiB2b2lkO1xufVxuXG5pbnRlcmZhY2UgQ29uc3VtZXJOb2RlIGV4dGVuZHMgUmVhY3RpdmVOb2RlIHtcbiAgcHJvZHVjZXJOb2RlOiBOb25OdWxsYWJsZTxSZWFjdGl2ZU5vZGVbJ3Byb2R1Y2VyTm9kZSddPjtcbiAgcHJvZHVjZXJJbmRleE9mVGhpczogTm9uTnVsbGFibGU8UmVhY3RpdmVOb2RlWydwcm9kdWNlckluZGV4T2ZUaGlzJ10+O1xuICBwcm9kdWNlckxhc3RSZWFkVmVyc2lvbjogTm9uTnVsbGFibGU8UmVhY3RpdmVOb2RlWydwcm9kdWNlckxhc3RSZWFkVmVyc2lvbiddPjtcbn1cblxuaW50ZXJmYWNlIFByb2R1Y2VyTm9kZSBleHRlbmRzIFJlYWN0aXZlTm9kZSB7XG4gIGxpdmVDb25zdW1lck5vZGU6IE5vbk51bGxhYmxlPFJlYWN0aXZlTm9kZVsnbGl2ZUNvbnN1bWVyTm9kZSddPjtcbiAgbGl2ZUNvbnN1bWVySW5kZXhPZlRoaXM6IE5vbk51bGxhYmxlPFJlYWN0aXZlTm9kZVsnbGl2ZUNvbnN1bWVySW5kZXhPZlRoaXMnXT47XG59XG5cbi8qKlxuICogQ2FsbGVkIGJ5IGltcGxlbWVudGF0aW9ucyB3aGVuIGEgcHJvZHVjZXIncyBzaWduYWwgaXMgcmVhZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByb2R1Y2VyQWNjZXNzZWQobm9kZTogUmVhY3RpdmVOb2RlKTogdm9pZCB7XG4gIGlmIChpbk5vdGlmaWNhdGlvblBoYXNlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICB0eXBlb2YgbmdEZXZNb2RlICE9PSAndW5kZWZpbmVkJyAmJiBuZ0Rldk1vZGUgP1xuICAgICAgICAgICAgYEFzc2VydGlvbiBlcnJvcjogc2lnbmFsIHJlYWQgZHVyaW5nIG5vdGlmaWNhdGlvbiBwaGFzZWAgOlxuICAgICAgICAgICAgJycpO1xuICB9XG5cbiAgaWYgKGFjdGl2ZUNvbnN1bWVyID09PSBudWxsKSB7XG4gICAgLy8gQWNjZXNzZWQgb3V0c2lkZSBvZiBhIHJlYWN0aXZlIGNvbnRleHQsIHNvIG5vdGhpbmcgdG8gcmVjb3JkLlxuICAgIHJldHVybjtcbiAgfVxuXG4gIGFjdGl2ZUNvbnN1bWVyLmNvbnN1bWVyT25TaWduYWxSZWFkKG5vZGUpO1xuXG4gIC8vIFRoaXMgcHJvZHVjZXIgaXMgdGhlIGBpZHhgdGggZGVwZW5kZW5jeSBvZiBgYWN0aXZlQ29uc3VtZXJgLlxuICBjb25zdCBpZHggPSBhY3RpdmVDb25zdW1lci5uZXh0UHJvZHVjZXJJbmRleCsrO1xuXG4gIGFzc2VydENvbnN1bWVyTm9kZShhY3RpdmVDb25zdW1lcik7XG5cbiAgaWYgKGlkeCA8IGFjdGl2ZUNvbnN1bWVyLnByb2R1Y2VyTm9kZS5sZW5ndGggJiYgYWN0aXZlQ29uc3VtZXIucHJvZHVjZXJOb2RlW2lkeF0gIT09IG5vZGUpIHtcbiAgICAvLyBUaGVyZSdzIGJlZW4gYSBjaGFuZ2UgaW4gcHJvZHVjZXJzIHNpbmNlIHRoZSBsYXN0IGV4ZWN1dGlvbiBvZiBgYWN0aXZlQ29uc3VtZXJgLlxuICAgIC8vIGBhY3RpdmVDb25zdW1lci5wcm9kdWNlck5vZGVbaWR4XWAgaG9sZHMgYSBzdGFsZSBkZXBlbmRlbmN5IHdoaWNoIHdpbGwgYmUgYmUgcmVtb3ZlZCBhbmRcbiAgICAvLyByZXBsYWNlZCB3aXRoIGB0aGlzYC5cbiAgICAvL1xuICAgIC8vIElmIGBhY3RpdmVDb25zdW1lcmAgaXNuJ3QgbGl2ZSwgdGhlbiB0aGlzIGlzIGEgbm8tb3AsIHNpbmNlIHdlIGNhbiByZXBsYWNlIHRoZSBwcm9kdWNlciBpblxuICAgIC8vIGBhY3RpdmVDb25zdW1lci5wcm9kdWNlck5vZGVgIGRpcmVjdGx5LiBIb3dldmVyLCBpZiBgYWN0aXZlQ29uc3VtZXJgIGlzIGxpdmUsIHRoZW4gd2UgbmVlZFxuICAgIC8vIHRvIHJlbW92ZSBpdCBmcm9tIHRoZSBzdGFsZSBwcm9kdWNlcidzIGBsaXZlQ29uc3VtZXJgcy5cbiAgICBpZiAoY29uc3VtZXJJc0xpdmUoYWN0aXZlQ29uc3VtZXIpKSB7XG4gICAgICBjb25zdCBzdGFsZVByb2R1Y2VyID0gYWN0aXZlQ29uc3VtZXIucHJvZHVjZXJOb2RlW2lkeF07XG4gICAgICBwcm9kdWNlclJlbW92ZUxpdmVDb25zdW1lckF0SW5kZXgoc3RhbGVQcm9kdWNlciwgYWN0aXZlQ29uc3VtZXIucHJvZHVjZXJJbmRleE9mVGhpc1tpZHhdKTtcblxuICAgICAgLy8gQXQgdGhpcyBwb2ludCwgdGhlIG9ubHkgcmVjb3JkIG9mIGBzdGFsZVByb2R1Y2VyYCBpcyB0aGUgcmVmZXJlbmNlIGF0XG4gICAgICAvLyBgYWN0aXZlQ29uc3VtZXIucHJvZHVjZXJOb2RlW2lkeF1gIHdoaWNoIHdpbGwgYmUgb3ZlcndyaXR0ZW4gYmVsb3cuXG4gICAgfVxuICB9XG5cbiAgaWYgKGFjdGl2ZUNvbnN1bWVyLnByb2R1Y2VyTm9kZVtpZHhdICE9PSBub2RlKSB7XG4gICAgLy8gV2UncmUgYSBuZXcgZGVwZW5kZW5jeSBvZiB0aGUgY29uc3VtZXIgKGF0IGBpZHhgKS5cbiAgICBhY3RpdmVDb25zdW1lci5wcm9kdWNlck5vZGVbaWR4XSA9IG5vZGU7XG5cbiAgICAvLyBJZiB0aGUgYWN0aXZlIGNvbnN1bWVyIGlzIGxpdmUsIHRoZW4gYWRkIGl0IGFzIGEgbGl2ZSBjb25zdW1lci4gSWYgbm90LCB0aGVuIHVzZSAwIGFzIGFcbiAgICAvLyBwbGFjZWhvbGRlciB2YWx1ZS5cbiAgICBhY3RpdmVDb25zdW1lci5wcm9kdWNlckluZGV4T2ZUaGlzW2lkeF0gPVxuICAgICAgICBjb25zdW1lcklzTGl2ZShhY3RpdmVDb25zdW1lcikgPyBwcm9kdWNlckFkZExpdmVDb25zdW1lcihub2RlLCBhY3RpdmVDb25zdW1lciwgaWR4KSA6IDA7XG4gIH1cbiAgYWN0aXZlQ29uc3VtZXIucHJvZHVjZXJMYXN0UmVhZFZlcnNpb25baWR4XSA9IG5vZGUudmVyc2lvbjtcbn1cblxuLyoqXG4gKiBJbmNyZW1lbnQgdGhlIGdsb2JhbCBlcG9jaCBjb3VudGVyLlxuICpcbiAqIENhbGxlZCBieSBzb3VyY2UgcHJvZHVjZXJzICh0aGF0IGlzLCBub3QgY29tcHV0ZWRzKSB3aGVuZXZlciB0aGVpciB2YWx1ZXMgY2hhbmdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJvZHVjZXJJbmNyZW1lbnRFcG9jaCgpOiB2b2lkIHtcbiAgZXBvY2grKztcbn1cblxuLyoqXG4gKiBFbnN1cmUgdGhpcyBwcm9kdWNlcidzIGB2ZXJzaW9uYCBpcyB1cC10by1kYXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJvZHVjZXJVcGRhdGVWYWx1ZVZlcnNpb24obm9kZTogUmVhY3RpdmVOb2RlKTogdm9pZCB7XG4gIGlmIChjb25zdW1lcklzTGl2ZShub2RlKSAmJiAhbm9kZS5kaXJ0eSkge1xuICAgIC8vIEEgbGl2ZSBjb25zdW1lciB3aWxsIGJlIG1hcmtlZCBkaXJ0eSBieSBwcm9kdWNlcnMsIHNvIGEgY2xlYW4gc3RhdGUgbWVhbnMgdGhhdCBpdHMgdmVyc2lvblxuICAgIC8vIGlzIGd1YXJhbnRlZWQgdG8gYmUgdXAtdG8tZGF0ZS5cbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoIW5vZGUuZGlydHkgJiYgbm9kZS5sYXN0Q2xlYW5FcG9jaCA9PT0gZXBvY2gpIHtcbiAgICAvLyBFdmVuIG5vbi1saXZlIGNvbnN1bWVycyBjYW4gc2tpcCBwb2xsaW5nIGlmIHRoZXkgcHJldmlvdXNseSBmb3VuZCB0aGVtc2VsdmVzIHRvIGJlIGNsZWFuIGF0XG4gICAgLy8gdGhlIGN1cnJlbnQgZXBvY2gsIHNpbmNlIHRoZWlyIGRlcGVuZGVuY2llcyBjb3VsZCBub3QgcG9zc2libHkgaGF2ZSBjaGFuZ2VkIChzdWNoIGEgY2hhbmdlXG4gICAgLy8gd291bGQndmUgaW5jcmVhc2VkIHRoZSBlcG9jaCkuXG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKCFub2RlLnByb2R1Y2VyTXVzdFJlY29tcHV0ZShub2RlKSAmJiAhY29uc3VtZXJQb2xsUHJvZHVjZXJzRm9yQ2hhbmdlKG5vZGUpKSB7XG4gICAgLy8gTm9uZSBvZiBvdXIgcHJvZHVjZXJzIHJlcG9ydCBhIGNoYW5nZSBzaW5jZSB0aGUgbGFzdCB0aW1lIHRoZXkgd2VyZSByZWFkLCBzbyBub1xuICAgIC8vIHJlY29tcHV0YXRpb24gb2Ygb3VyIHZhbHVlIGlzIG5lY2Vzc2FyeSwgYW5kIHdlIGNhbiBjb25zaWRlciBvdXJzZWx2ZXMgY2xlYW4uXG4gICAgbm9kZS5kaXJ0eSA9IGZhbHNlO1xuICAgIG5vZGUubGFzdENsZWFuRXBvY2ggPSBlcG9jaDtcbiAgICByZXR1cm47XG4gIH1cblxuICBub2RlLnByb2R1Y2VyUmVjb21wdXRlVmFsdWUobm9kZSk7XG5cbiAgLy8gQWZ0ZXIgcmVjb21wdXRpbmcgdGhlIHZhbHVlLCB3ZSdyZSBubyBsb25nZXIgZGlydHkuXG4gIG5vZGUuZGlydHkgPSBmYWxzZTtcbiAgbm9kZS5sYXN0Q2xlYW5FcG9jaCA9IGVwb2NoO1xufVxuXG4vKipcbiAqIFByb3BhZ2F0ZSBhIGRpcnR5IG5vdGlmaWNhdGlvbiB0byBsaXZlIGNvbnN1bWVycyBvZiB0aGlzIHByb2R1Y2VyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJvZHVjZXJOb3RpZnlDb25zdW1lcnMobm9kZTogUmVhY3RpdmVOb2RlKTogdm9pZCB7XG4gIGlmIChub2RlLmxpdmVDb25zdW1lck5vZGUgPT09IHVuZGVmaW5lZCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIFByZXZlbnQgc2lnbmFsIHJlYWRzIHdoZW4gd2UncmUgdXBkYXRpbmcgdGhlIGdyYXBoXG4gIGNvbnN0IHByZXYgPSBpbk5vdGlmaWNhdGlvblBoYXNlO1xuICBpbk5vdGlmaWNhdGlvblBoYXNlID0gdHJ1ZTtcbiAgdHJ5IHtcbiAgICBmb3IgKGNvbnN0IGNvbnN1bWVyIG9mIG5vZGUubGl2ZUNvbnN1bWVyTm9kZSkge1xuICAgICAgaWYgKCFjb25zdW1lci5kaXJ0eSkge1xuICAgICAgICBjb25zdW1lck1hcmtEaXJ0eShjb25zdW1lcik7XG4gICAgICB9XG4gICAgfVxuICB9IGZpbmFsbHkge1xuICAgIGluTm90aWZpY2F0aW9uUGhhc2UgPSBwcmV2O1xuICB9XG59XG5cbi8qKlxuICogV2hldGhlciB0aGlzIGBSZWFjdGl2ZU5vZGVgIGluIGl0cyBwcm9kdWNlciBjYXBhY2l0eSBpcyBjdXJyZW50bHkgYWxsb3dlZCB0byBpbml0aWF0ZSB1cGRhdGVzLFxuICogYmFzZWQgb24gdGhlIGN1cnJlbnQgY29uc3VtZXIgY29udGV4dC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByb2R1Y2VyVXBkYXRlc0FsbG93ZWQoKTogYm9vbGVhbiB7XG4gIHJldHVybiBhY3RpdmVDb25zdW1lcj8uY29uc3VtZXJBbGxvd1NpZ25hbFdyaXRlcyAhPT0gZmFsc2U7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjb25zdW1lck1hcmtEaXJ0eShub2RlOiBSZWFjdGl2ZU5vZGUpOiB2b2lkIHtcbiAgbm9kZS5kaXJ0eSA9IHRydWU7XG4gIHByb2R1Y2VyTm90aWZ5Q29uc3VtZXJzKG5vZGUpO1xuICBub2RlLmNvbnN1bWVyTWFya2VkRGlydHk/Lihub2RlKTtcbn1cblxuLyoqXG4gKiBQcmVwYXJlIHRoaXMgY29uc3VtZXIgdG8gcnVuIGEgY29tcHV0YXRpb24gaW4gaXRzIHJlYWN0aXZlIGNvbnRleHQuXG4gKlxuICogTXVzdCBiZSBjYWxsZWQgYnkgc3ViY2xhc3NlcyB3aGljaCByZXByZXNlbnQgcmVhY3RpdmUgY29tcHV0YXRpb25zLCBiZWZvcmUgdGhvc2UgY29tcHV0YXRpb25zXG4gKiBiZWdpbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbnN1bWVyQmVmb3JlQ29tcHV0YXRpb24obm9kZTogUmVhY3RpdmVOb2RlfG51bGwpOiBSZWFjdGl2ZU5vZGV8bnVsbCB7XG4gIG5vZGUgJiYgKG5vZGUubmV4dFByb2R1Y2VySW5kZXggPSAwKTtcbiAgcmV0dXJuIHNldEFjdGl2ZUNvbnN1bWVyKG5vZGUpO1xufVxuXG4vKipcbiAqIEZpbmFsaXplIHRoaXMgY29uc3VtZXIncyBzdGF0ZSBhZnRlciBhIHJlYWN0aXZlIGNvbXB1dGF0aW9uIGhhcyBydW4uXG4gKlxuICogTXVzdCBiZSBjYWxsZWQgYnkgc3ViY2xhc3NlcyB3aGljaCByZXByZXNlbnQgcmVhY3RpdmUgY29tcHV0YXRpb25zLCBhZnRlciB0aG9zZSBjb21wdXRhdGlvbnNcbiAqIGhhdmUgZmluaXNoZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb25zdW1lckFmdGVyQ29tcHV0YXRpb24oXG4gICAgbm9kZTogUmVhY3RpdmVOb2RlfG51bGwsIHByZXZDb25zdW1lcjogUmVhY3RpdmVOb2RlfG51bGwpOiB2b2lkIHtcbiAgc2V0QWN0aXZlQ29uc3VtZXIocHJldkNvbnN1bWVyKTtcblxuICBpZiAoIW5vZGUgfHwgbm9kZS5wcm9kdWNlck5vZGUgPT09IHVuZGVmaW5lZCB8fCBub2RlLnByb2R1Y2VySW5kZXhPZlRoaXMgPT09IHVuZGVmaW5lZCB8fFxuICAgICAgbm9kZS5wcm9kdWNlckxhc3RSZWFkVmVyc2lvbiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKGNvbnN1bWVySXNMaXZlKG5vZGUpKSB7XG4gICAgLy8gRm9yIGxpdmUgY29uc3VtZXJzLCB3ZSBuZWVkIHRvIHJlbW92ZSB0aGUgcHJvZHVjZXIgLT4gY29uc3VtZXIgZWRnZSBmb3IgYW55IHN0YWxlIHByb2R1Y2Vyc1xuICAgIC8vIHdoaWNoIHdlcmVuJ3QgZGVwZW5kZW5jaWVzIGFmdGVyIHRoZSByZWNvbXB1dGF0aW9uLlxuICAgIGZvciAobGV0IGkgPSBub2RlLm5leHRQcm9kdWNlckluZGV4OyBpIDwgbm9kZS5wcm9kdWNlck5vZGUubGVuZ3RoOyBpKyspIHtcbiAgICAgIHByb2R1Y2VyUmVtb3ZlTGl2ZUNvbnN1bWVyQXRJbmRleChub2RlLnByb2R1Y2VyTm9kZVtpXSwgbm9kZS5wcm9kdWNlckluZGV4T2ZUaGlzW2ldKTtcbiAgICB9XG4gIH1cblxuICAvLyBUcnVuY2F0ZSB0aGUgcHJvZHVjZXIgdHJhY2tpbmcgYXJyYXlzLlxuICAvLyBQZXJmIG5vdGU6IHRoaXMgaXMgZXNzZW50aWFsbHkgdHJ1bmNhdGluZyB0aGUgbGVuZ3RoIHRvIGBub2RlLm5leHRQcm9kdWNlckluZGV4YCwgYnV0XG4gIC8vIGJlbmNobWFya2luZyBoYXMgc2hvd24gdGhhdCBpbmRpdmlkdWFsIHBvcCBvcGVyYXRpb25zIGFyZSBmYXN0ZXIuXG4gIHdoaWxlIChub2RlLnByb2R1Y2VyTm9kZS5sZW5ndGggPiBub2RlLm5leHRQcm9kdWNlckluZGV4KSB7XG4gICAgbm9kZS5wcm9kdWNlck5vZGUucG9wKCk7XG4gICAgbm9kZS5wcm9kdWNlckxhc3RSZWFkVmVyc2lvbi5wb3AoKTtcbiAgICBub2RlLnByb2R1Y2VySW5kZXhPZlRoaXMucG9wKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBEZXRlcm1pbmUgd2hldGhlciB0aGlzIGNvbnN1bWVyIGhhcyBhbnkgZGVwZW5kZW5jaWVzIHdoaWNoIGhhdmUgY2hhbmdlZCBzaW5jZSB0aGUgbGFzdCB0aW1lXG4gKiB0aGV5IHdlcmUgcmVhZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbnN1bWVyUG9sbFByb2R1Y2Vyc0ZvckNoYW5nZShub2RlOiBSZWFjdGl2ZU5vZGUpOiBib29sZWFuIHtcbiAgYXNzZXJ0Q29uc3VtZXJOb2RlKG5vZGUpO1xuXG4gIC8vIFBvbGwgcHJvZHVjZXJzIGZvciBjaGFuZ2UuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbm9kZS5wcm9kdWNlck5vZGUubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBwcm9kdWNlciA9IG5vZGUucHJvZHVjZXJOb2RlW2ldO1xuICAgIGNvbnN0IHNlZW5WZXJzaW9uID0gbm9kZS5wcm9kdWNlckxhc3RSZWFkVmVyc2lvbltpXTtcblxuICAgIC8vIEZpcnN0IGNoZWNrIHRoZSB2ZXJzaW9ucy4gQSBtaXNtYXRjaCBtZWFucyB0aGF0IHRoZSBwcm9kdWNlcidzIHZhbHVlIGlzIGtub3duIHRvIGhhdmVcbiAgICAvLyBjaGFuZ2VkIHNpbmNlIHRoZSBsYXN0IHRpbWUgd2UgcmVhZCBpdC5cbiAgICBpZiAoc2VlblZlcnNpb24gIT09IHByb2R1Y2VyLnZlcnNpb24pIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8vIFRoZSBwcm9kdWNlcidzIHZlcnNpb24gaXMgdGhlIHNhbWUgYXMgdGhlIGxhc3QgdGltZSB3ZSByZWFkIGl0LCBidXQgaXQgbWlnaHQgaXRzZWxmIGJlXG4gICAgLy8gc3RhbGUuIEZvcmNlIHRoZSBwcm9kdWNlciB0byByZWNvbXB1dGUgaXRzIHZlcnNpb24gKGNhbGN1bGF0aW5nIGEgbmV3IHZhbHVlIGlmIG5lY2Vzc2FyeSkuXG4gICAgcHJvZHVjZXJVcGRhdGVWYWx1ZVZlcnNpb24ocHJvZHVjZXIpO1xuXG4gICAgLy8gTm93IHdoZW4gd2UgZG8gdGhpcyBjaGVjaywgYHByb2R1Y2VyLnZlcnNpb25gIGlzIGd1YXJhbnRlZWQgdG8gYmUgdXAgdG8gZGF0ZSwgc28gaWYgdGhlXG4gICAgLy8gdmVyc2lvbnMgc3RpbGwgbWF0Y2ggdGhlbiBpdCBoYXMgbm90IGNoYW5nZWQgc2luY2UgdGhlIGxhc3QgdGltZSB3ZSByZWFkIGl0LlxuICAgIGlmIChzZWVuVmVyc2lvbiAhPT0gcHJvZHVjZXIudmVyc2lvbikge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG4vKipcbiAqIERpc2Nvbm5lY3QgdGhpcyBjb25zdW1lciBmcm9tIHRoZSBncmFwaC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbnN1bWVyRGVzdHJveShub2RlOiBSZWFjdGl2ZU5vZGUpOiB2b2lkIHtcbiAgYXNzZXJ0Q29uc3VtZXJOb2RlKG5vZGUpO1xuICBpZiAoY29uc3VtZXJJc0xpdmUobm9kZSkpIHtcbiAgICAvLyBEcm9wIGFsbCBjb25uZWN0aW9ucyBmcm9tIHRoZSBncmFwaCB0byB0aGlzIG5vZGUuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBub2RlLnByb2R1Y2VyTm9kZS5sZW5ndGg7IGkrKykge1xuICAgICAgcHJvZHVjZXJSZW1vdmVMaXZlQ29uc3VtZXJBdEluZGV4KG5vZGUucHJvZHVjZXJOb2RlW2ldLCBub2RlLnByb2R1Y2VySW5kZXhPZlRoaXNbaV0pO1xuICAgIH1cbiAgfVxuXG4gIC8vIFRydW5jYXRlIGFsbCB0aGUgYXJyYXlzIHRvIGRyb3AgYWxsIGNvbm5lY3Rpb24gZnJvbSB0aGlzIG5vZGUgdG8gdGhlIGdyYXBoLlxuICBub2RlLnByb2R1Y2VyTm9kZS5sZW5ndGggPSBub2RlLnByb2R1Y2VyTGFzdFJlYWRWZXJzaW9uLmxlbmd0aCA9IG5vZGUucHJvZHVjZXJJbmRleE9mVGhpcy5sZW5ndGggPVxuICAgICAgMDtcbiAgaWYgKG5vZGUubGl2ZUNvbnN1bWVyTm9kZSkge1xuICAgIG5vZGUubGl2ZUNvbnN1bWVyTm9kZS5sZW5ndGggPSBub2RlLmxpdmVDb25zdW1lckluZGV4T2ZUaGlzIS5sZW5ndGggPSAwO1xuICB9XG59XG5cbi8qKlxuICogQWRkIGBjb25zdW1lcmAgYXMgYSBsaXZlIGNvbnN1bWVyIG9mIHRoaXMgbm9kZS5cbiAqXG4gKiBOb3RlIHRoYXQgdGhpcyBvcGVyYXRpb24gaXMgcG90ZW50aWFsbHkgdHJhbnNpdGl2ZS4gSWYgdGhpcyBub2RlIGJlY29tZXMgbGl2ZSwgdGhlbiBpdCBiZWNvbWVzXG4gKiBhIGxpdmUgY29uc3VtZXIgb2YgYWxsIG9mIGl0cyBjdXJyZW50IHByb2R1Y2Vycy5cbiAqL1xuZnVuY3Rpb24gcHJvZHVjZXJBZGRMaXZlQ29uc3VtZXIoXG4gICAgbm9kZTogUmVhY3RpdmVOb2RlLCBjb25zdW1lcjogUmVhY3RpdmVOb2RlLCBpbmRleE9mVGhpczogbnVtYmVyKTogbnVtYmVyIHtcbiAgYXNzZXJ0UHJvZHVjZXJOb2RlKG5vZGUpO1xuICBhc3NlcnRDb25zdW1lck5vZGUobm9kZSk7XG4gIGlmIChub2RlLmxpdmVDb25zdW1lck5vZGUubGVuZ3RoID09PSAwKSB7XG4gICAgLy8gV2hlbiBnb2luZyBmcm9tIDAgdG8gMSBsaXZlIGNvbnN1bWVycywgd2UgYmVjb21lIGEgbGl2ZSBjb25zdW1lciB0byBvdXIgcHJvZHVjZXJzLlxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbm9kZS5wcm9kdWNlck5vZGUubGVuZ3RoOyBpKyspIHtcbiAgICAgIG5vZGUucHJvZHVjZXJJbmRleE9mVGhpc1tpXSA9IHByb2R1Y2VyQWRkTGl2ZUNvbnN1bWVyKG5vZGUucHJvZHVjZXJOb2RlW2ldLCBub2RlLCBpKTtcbiAgICB9XG4gIH1cbiAgbm9kZS5saXZlQ29uc3VtZXJJbmRleE9mVGhpcy5wdXNoKGluZGV4T2ZUaGlzKTtcbiAgcmV0dXJuIG5vZGUubGl2ZUNvbnN1bWVyTm9kZS5wdXNoKGNvbnN1bWVyKSAtIDE7XG59XG5cbi8qKlxuICogUmVtb3ZlIHRoZSBsaXZlIGNvbnN1bWVyIGF0IGBpZHhgLlxuICovXG5mdW5jdGlvbiBwcm9kdWNlclJlbW92ZUxpdmVDb25zdW1lckF0SW5kZXgobm9kZTogUmVhY3RpdmVOb2RlLCBpZHg6IG51bWJlcik6IHZvaWQge1xuICBhc3NlcnRQcm9kdWNlck5vZGUobm9kZSk7XG4gIGFzc2VydENvbnN1bWVyTm9kZShub2RlKTtcblxuICBpZiAodHlwZW9mIG5nRGV2TW9kZSAhPT0gJ3VuZGVmaW5lZCcgJiYgbmdEZXZNb2RlICYmIGlkeCA+PSBub2RlLmxpdmVDb25zdW1lck5vZGUubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBBc3NlcnRpb24gZXJyb3I6IGFjdGl2ZSBjb25zdW1lciBpbmRleCAke2lkeH0gaXMgb3V0IG9mIGJvdW5kcyBvZiAke1xuICAgICAgICBub2RlLmxpdmVDb25zdW1lck5vZGUubGVuZ3RofSBjb25zdW1lcnMpYCk7XG4gIH1cblxuICBpZiAobm9kZS5saXZlQ29uc3VtZXJOb2RlLmxlbmd0aCA9PT0gMSkge1xuICAgIC8vIFdoZW4gcmVtb3ZpbmcgdGhlIGxhc3QgbGl2ZSBjb25zdW1lciwgd2Ugd2lsbCBubyBsb25nZXIgYmUgbGl2ZS4gV2UgbmVlZCB0byByZW1vdmVcbiAgICAvLyBvdXJzZWx2ZXMgZnJvbSBvdXIgcHJvZHVjZXJzJyB0cmFja2luZyAod2hpY2ggbWF5IGNhdXNlIGNvbnN1bWVyLXByb2R1Y2VycyB0byBsb3NlXG4gICAgLy8gbGl2ZW5lc3MgYXMgd2VsbCkuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBub2RlLnByb2R1Y2VyTm9kZS5sZW5ndGg7IGkrKykge1xuICAgICAgcHJvZHVjZXJSZW1vdmVMaXZlQ29uc3VtZXJBdEluZGV4KG5vZGUucHJvZHVjZXJOb2RlW2ldLCBub2RlLnByb2R1Y2VySW5kZXhPZlRoaXNbaV0pO1xuICAgIH1cbiAgfVxuXG4gIC8vIE1vdmUgdGhlIGxhc3QgdmFsdWUgb2YgYGxpdmVDb25zdW1lcnNgIGludG8gYGlkeGAuIE5vdGUgdGhhdCBpZiB0aGVyZSdzIG9ubHkgYSBzaW5nbGVcbiAgLy8gbGl2ZSBjb25zdW1lciwgdGhpcyBpcyBhIG5vLW9wLlxuICBjb25zdCBsYXN0SWR4ID0gbm9kZS5saXZlQ29uc3VtZXJOb2RlLmxlbmd0aCAtIDE7XG4gIG5vZGUubGl2ZUNvbnN1bWVyTm9kZVtpZHhdID0gbm9kZS5saXZlQ29uc3VtZXJOb2RlW2xhc3RJZHhdO1xuICBub2RlLmxpdmVDb25zdW1lckluZGV4T2ZUaGlzW2lkeF0gPSBub2RlLmxpdmVDb25zdW1lckluZGV4T2ZUaGlzW2xhc3RJZHhdO1xuXG4gIC8vIFRydW5jYXRlIHRoZSBhcnJheS5cbiAgbm9kZS5saXZlQ29uc3VtZXJOb2RlLmxlbmd0aC0tO1xuICBub2RlLmxpdmVDb25zdW1lckluZGV4T2ZUaGlzLmxlbmd0aC0tO1xuXG4gIC8vIElmIHRoZSBpbmRleCBpcyBzdGlsbCB2YWxpZCwgdGhlbiB3ZSBuZWVkIHRvIGZpeCB0aGUgaW5kZXggcG9pbnRlciBmcm9tIHRoZSBwcm9kdWNlciB0byB0aGlzXG4gIC8vIGNvbnN1bWVyLCBhbmQgdXBkYXRlIGl0IGZyb20gYGxhc3RJZHhgIHRvIGBpZHhgIChhY2NvdW50aW5nIGZvciB0aGUgbW92ZSBhYm92ZSkuXG4gIGlmIChpZHggPCBub2RlLmxpdmVDb25zdW1lck5vZGUubGVuZ3RoKSB7XG4gICAgY29uc3QgaWR4UHJvZHVjZXIgPSBub2RlLmxpdmVDb25zdW1lckluZGV4T2ZUaGlzW2lkeF07XG4gICAgY29uc3QgY29uc3VtZXIgPSBub2RlLmxpdmVDb25zdW1lck5vZGVbaWR4XTtcbiAgICBhc3NlcnRDb25zdW1lck5vZGUoY29uc3VtZXIpO1xuICAgIGNvbnN1bWVyLnByb2R1Y2VySW5kZXhPZlRoaXNbaWR4UHJvZHVjZXJdID0gaWR4O1xuICB9XG59XG5cbmZ1bmN0aW9uIGNvbnN1bWVySXNMaXZlKG5vZGU6IFJlYWN0aXZlTm9kZSk6IGJvb2xlYW4ge1xuICByZXR1cm4gbm9kZS5jb25zdW1lcklzQWx3YXlzTGl2ZSB8fCAobm9kZT8ubGl2ZUNvbnN1bWVyTm9kZT8ubGVuZ3RoID8/IDApID4gMDtcbn1cblxuXG5mdW5jdGlvbiBhc3NlcnRDb25zdW1lck5vZGUobm9kZTogUmVhY3RpdmVOb2RlKTogYXNzZXJ0cyBub2RlIGlzIENvbnN1bWVyTm9kZSB7XG4gIG5vZGUucHJvZHVjZXJOb2RlID8/PSBbXTtcbiAgbm9kZS5wcm9kdWNlckluZGV4T2ZUaGlzID8/PSBbXTtcbiAgbm9kZS5wcm9kdWNlckxhc3RSZWFkVmVyc2lvbiA/Pz0gW107XG59XG5cbmZ1bmN0aW9uIGFzc2VydFByb2R1Y2VyTm9kZShub2RlOiBSZWFjdGl2ZU5vZGUpOiBhc3NlcnRzIG5vZGUgaXMgUHJvZHVjZXJOb2RlIHtcbiAgbm9kZS5saXZlQ29uc3VtZXJOb2RlID8/PSBbXTtcbiAgbm9kZS5saXZlQ29uc3VtZXJJbmRleE9mVGhpcyA/Pz0gW107XG59XG4iXX0=