UNPKG

projen

Version:

CDK for software projects

252 lines • 30.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FutureComponent = exports.Component = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const constructs_1 = require("constructs"); const constructs_2 = require("./util/constructs"); const autoIds = new WeakMap(); const componentId = (scope) => { const nextId = (autoIds.get(scope) ?? 0) + 1; autoIds.set(scope, nextId); return `AutoId${nextId}`; }; /** * Represents a project component. * @param project * @param id Unique id of the component. If not provided, an unstable AutoId is generated. */ class Component extends constructs_1.Construct { static [JSII_RTTI_SYMBOL_1] = { fqn: "projen.Component", version: "0.103.12" }; /** * Test whether the given construct is a component. */ static isComponent(x) { return (0, constructs_2.isComponent)(x); } project; constructor(scope, id) { super(scope, id || `${new.target.name}#${componentId(scope)}`); (0, constructs_2.tagAsComponent)(this); this.node.addMetadata("type", "component"); this.node.addMetadata("construct", new.target.name); this.project = (0, constructs_2.findClosestProject)(scope, new.target.name); } /** * Called before synthesis. */ preSynthesize() { } /** * Synthesizes files to the project output directory. */ synthesize() { } /** * Called after synthesis. Order is *not* guaranteed. */ postSynthesize() { } /** * Called once, right after `synthesize()`, only when the project is created for the first time. * * It does not run on later `projen` invocations. It only fires for `projen new` (or `Projects.createProject`). * Use it for deterministic, one-off file generation. Order across components is not guaranteed. * * @param initProject Details about how the project was created, e.g. its type and the original CLI args. */ projectCreation(initProject) { initProject; } /** * Called once, right after `postSynthesize()`, only when the project is created for the first time. * * It does not run on later `projen` invocations. It only fires for `projen new` (or `Projects.createProject`). * It is also skipped when post-synthesis steps are disabled, e.g. `--no-post` or `PROJEN_DISABLE_POST`. * Use it for one-off setup that can be turned off by the user, like running a task to give the user immediate * feedback on their new project. Order across components is not guaranteed. * * @param initProject Details about how the project was created, e.g. its type and the original CLI args. */ postProjectCreation(initProject) { initProject; } } exports.Component = Component; /** * Internal flag key read by the detached-guard proxy. A symbol so it never * collides with a real (string-keyed) member and is always readable through the * guard (symbol access is never blocked). */ const FUTURE_ATTACHED = Symbol.for("projen.future.attached"); /** * The members a detached future component is allowed to expose. Reading anything * else before attach throws. (`copy` is the copyable capability method a * copyable subclass adds, per the `recreate()` convention.) */ const DETACHED_ALLOWLIST = new Set([ "attach", "tryAttach", "attached", "copy", "constructor", "toString", ]); /** * Wrap a freshly constructed {@link FutureComponent} in a guard proxy. * * Two jobs: * * 1. Block use before attach. While detached, any property read outside * {@link DETACHED_ALLOWLIST} (and outside symbol keys, which always pass so * `instanceof`, jsii and inspection keep working) throws instead of silently * returning shadow-tree state. * 2. "Drop" itself on attach. Once attached, the guard is a transparent * pass-through: a single boolean check, then `Reflect`. Every method it * returns is bound to the *real* target, so the moment you call one method * the work continues on the bare object with no further proxy traps. * * Only `get` is guarded. `set` is intentionally left open so a subclass * constructor can assign its own fields (e.g. `this.options = options`). */ function guardDetached(target) { const boundCache = new Map(); const handler = { get(t, prop) { // never present as a thenable, or `await futureComponent` would hang/throw if (prop === "then") { return undefined; } const attached = t[FUTURE_ATTACHED] === true; const allowed = attached || typeof prop !== "string" || DETACHED_ALLOWLIST.has(prop); if (!allowed) { const name = t.newTargetName ?? t.constructor.name; throw new Error(`Cannot access '${String(prop)}' on ${name}: a future component is ` + `not usable until it is attached. Call attach(scope) first, or pass ` + `it to a Project which attaches it for you.`); } // bind functions to the *real* target so that, once invoked, all internal // `this` access happens on the bare object with no proxy involvement. const value = Reflect.get(t, prop, t); if (typeof value === "function") { let bound = boundCache.get(prop); if (!bound) { bound = value.bind(t); boundCache.set(prop, bound); } return bound; } return value; }, }; return new Proxy(target, handler); } /** * A {@link Component} that is created *detached* from any project and attached * to one later via {@link FutureComponent.attach}. * * Like a regular component, but constructed without a project. It improves on a * naive deferred component in three ways: * * - Use-before-attach is an error, not a silent footgun. The constructor hands * the caller a guard proxy; touching `project`, `node`, `synthesize()` or any * subclass feature before `attach()` throws. * - No global shadow-tree leak. Each instance gets its own throwaway shadow * root, so detached components never share an id counter and the root becomes * garbage once the component is reparented on attach. * - `attach()` returns the unwrapped component, so callers can opt out of the * proxy entirely. * * The constructor takes no arguments (`super()`). A subclass that needs options * captures them itself, reading the local parameter inside its constructor - NOT * `this.options`, which the guard blocks until attach. * * ```ts * class Worker extends FutureComponent { * private readonly options: WorkerOptions; * constructor(options: WorkerOptions = {}) { * super(); * this.options = options; // set: allowed * } * protected init() { * // this.project is available here * } * } * * const w = new Worker({ retries: 3 }); * // w.project; // throws: not attached yet * const real = w.attach(project); // reparents, runs init(), returns the bare instance * ``` */ class FutureComponent extends Component { static [JSII_RTTI_SYMBOL_1] = { fqn: "projen.FutureComponent", version: "0.103.12" }; newTargetName; attachedState = false; constructor() { // Each future component gets its OWN shadow root. Unlike a single global // shadow tree, detached components never collide on an id counter, and the // root is collected once we reparent on attach(). const shadow = new constructs_1.RootConstruct(); (0, constructs_2.tagAsProject)(shadow); super(shadow); this.newTargetName = new.target.name; // Hand the caller a guarded proxy. `this` here is still the bare object; // returning it makes the proxy the instance seen by `new`. Because the base // constructor returns an object, subclass constructors transparently adopt // the proxy as their `this` too. return guardDetached(this); } /** * Whether `attach()` has been called. A convenience for tests/introspection; * prefer `tryAttach()` over reading this and branching. */ get attached() { return this.attachedState; } /** * Project-dependent setup. Runs once, from `attach()`, when `this.project` is * finally available. */ init() { } /** * Attach the component to a scope. Only now does it become usable. * * Returns the real, unwrapped component (not the proxy). A component may be * attached exactly once; attaching an already-attached component throws (copy * it first to attach a variant elsewhere). Use `tryAttach()` if you don't care * whether it has already been attached. */ attach(scope, id) { if (this.attachedState) { throw new Error(`${this.newTargetName} is already attached to '${this.project.node.path}'. ` + `Use \`tryAttach\` or \`copy\` it to attach a variant.`); } // constructs has no public reparent, so build a fresh node on the real // scope. The per-instance shadow root and its original node become an // unreachable island and are collected. this.node = new constructs_1.Node(this, scope, id ?? componentId(scope)); // The component already carries the component tag (set by the base // constructor, which is idempotent against the same object); re-add the // metadata to the new node and resolve the real project. this.node.addMetadata("type", "component"); this.node.addMetadata("construct", this.newTargetName); this.project = (0, constructs_2.findClosestProject)(scope, this.newTargetName); this.attachedState = true; // Flip the guard into transparent pass-through for any proxy handles the // caller still holds. Symbol key, so the guard can always read it. this[FUTURE_ATTACHED] = true; // project is now available, run project-dependent setup this.init(); // hand back the bare object so the caller can drop the proxy entirely return this; } /** * Attach the component if it isn't already, without caring *where*. * * Unlike `attach()`, never throws on an already-attached component: if attached * anywhere at all, the existing instance is returned and `scope` is ignored. * Use `attach()` when attaching to a specific scope is part of your contract * and a pre-existing attachment elsewhere would be a bug. */ tryAttach(scope, id) { return this.attachedState ? this : this.attach(scope, id); } } exports.FutureComponent = FutureComponent; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQ0EsMkNBQTREO0FBRTVELGtEQUsyQjtBQUUzQixNQUFNLE9BQU8sR0FBRyxJQUFJLE9BQU8sRUFBc0IsQ0FBQztBQUNsRCxNQUFNLFdBQVcsR0FBRyxDQUFDLEtBQWlCLEVBQUUsRUFBRTtJQUN4QyxNQUFNLE1BQU0sR0FBRyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzdDLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQzNCLE9BQU8sU0FBUyxNQUFNLEVBQUUsQ0FBQztBQUMzQixDQUFDLENBQUM7QUFFRjs7OztHQUlHO0FBQ0gsTUFBYSxTQUFVLFNBQVEsc0JBQVM7O0lBQ3RDOztPQUVHO0lBQ0ksTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFNO1FBQzlCLE9BQU8sSUFBQSx3QkFBVyxFQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLENBQUM7SUFFZSxPQUFPLENBQVU7SUFFakMsWUFBWSxLQUFpQixFQUFFLEVBQVc7UUFDeEMsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLElBQUksR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksSUFBSSxXQUFXLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQy9ELElBQUEsMkJBQWMsRUFBQyxJQUFJLENBQUMsQ0FBQztRQUNyQixJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDM0MsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsV0FBVyxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFcEQsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFBLCtC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Q0FDbkIsQ0FBQztRQUVGLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDO1FBQzFCLHlFQUF5RTtRQUN6RSxtRUFBbUU7UUFDbEUsSUFBWSxDQUFDLGVBQWUsQ0FBQyxHQUFHLElBQUksQ0FBQztRQUV0Qyx3REFBd0Q7UUFDeEQsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBRVosc0VBQXNFO1FBQ3RFLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSSxTQUFTLENBQUMsS0FBaUIsRUFBRSxFQUFXO1FBQzdDLE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztJQUM1RCxDQUFDOztBQTNGSCwwQ0E0RkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IElDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IHsgQ29uc3RydWN0LCBOb2RlLCBSb290Q29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB0eXBlIHsgSW5pdFByb2plY3QsIFByb2plY3QgfSBmcm9tIFwiLi9wcm9qZWN0XCI7XG5pbXBvcnQge1xuICBpc0NvbXBvbmVudCxcbiAgZmluZENsb3Nlc3RQcm9qZWN0LFxuICB0YWdBc0NvbXBvbmVudCxcbiAgdGFnQXNQcm9qZWN0LFxufSBmcm9tIFwiLi91dGlsL2NvbnN0cnVjdHNcIjtcblxuY29uc3QgYXV0b0lkcyA9IG5ldyBXZWFrTWFwPElDb25zdHJ1Y3QsIG51bWJlcj4oKTtcbmNvbnN0IGNvbXBvbmVudElkID0gKHNjb3BlOiBJQ29uc3RydWN0KSA9PiB7XG4gIGNvbnN0IG5leHRJZCA9IChhdXRvSWRzLmdldChzY29wZSkgPz8gMCkgKyAxO1xuICBhdXRvSWRzLnNldChzY29wZSwgbmV4dElkKTtcbiAgcmV0dXJuIGBBdXRvSWQke25leHRJZH1gO1xufTtcblxuLyoqXG4gKiBSZXByZXNlbnRzIGEgcHJvamVjdCBjb21wb25lbnQuXG4gKiBAcGFyYW0gcHJvamVjdFxuICogQHBhcmFtIGlkIFVuaXF1ZSBpZCBvZiB0aGUgY29tcG9uZW50LiBJZiBub3QgcHJvdmlkZWQsIGFuIHVuc3RhYmxlIEF1dG9JZCBpcyBnZW5lcmF0ZWQuXG4gKi9cbmV4cG9ydCBjbGFzcyBDb21wb25lbnQgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICAvKipcbiAgICogVGVzdCB3aGV0aGVyIHRoZSBnaXZlbiBjb25zdHJ1Y3QgaXMgYSBjb21wb25lbnQuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGlzQ29tcG9uZW50KHg6IGFueSk6IHggaXMgQ29tcG9uZW50IHtcbiAgICByZXR1cm4gaXNDb21wb25lbnQoeCk7XG4gIH1cblxuICBwdWJsaWMgcmVhZG9ubHkgcHJvamVjdDogUHJvamVjdDtcblxuICBjb25zdHJ1Y3RvcihzY29wZTogSUNvbnN0cnVjdCwgaWQ/OiBzdHJpbmcpIHtcbiAgICBzdXBlcihzY29wZSwgaWQgfHwgYCR7bmV3LnRhcmdldC5uYW1lfSMke2NvbXBvbmVudElkKHNjb3BlKX1gKTtcbiAgICB0YWdBc0NvbXBvbmVudCh0aGlzKTtcbiAgICB0aGlzLm5vZGUuYWRkTWV0YWRhdGEoXCJ0eXBlXCIsIFwiY29tcG9uZW50XCIpO1xuICAgIHRoaXMubm9kZS5hZGRNZXRhZGF0YShcImNvbnN0cnVjdFwiLCBuZXcudGFyZ2V0Lm5hbWUpO1xuXG4gICAgdGhpcy5wcm9qZWN0ID0gZmluZENsb3Nlc3RQcm9qZWN0KHNjb3BlLCBuZXcudGFyZ2V0Lm5hbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGxlZCBiZWZvcmUgc3ludGhlc2lzLlxuICAgKi9cbiAgcHVibGljIHByZVN5bnRoZXNpemUoKSB7fVxuXG4gIC8qKlxuICAgKiBTeW50aGVzaXplcyBmaWxlcyB0byB0aGUgcHJvamVjdCBvdXRwdXQgZGlyZWN0b3J5LlxuICAgKi9cbiAgcHVibGljIHN5bnRoZXNpemUoKSB7fVxuXG4gIC8qKlxuICAgKiBDYWxsZWQgYWZ0ZXIgc3ludGhlc2lzLiBPcmRlciBpcyAqbm90KiBndWFyYW50ZWVkLlxuICAgKi9cbiAgcHVibGljIHBvc3RTeW50aGVzaXplKCkge31cblxuICAvKipcbiAgICogQ2FsbGVkIG9uY2UsIHJpZ2h0IGFmdGVyIGBzeW50aGVzaXplKClgLCBvbmx5IHdoZW4gdGhlIHByb2plY3QgaXMgY3JlYXRlZCBmb3IgdGhlIGZpcnN0IHRpbWUuXG4gICAqXG4gICAqIEl0IGRvZXMgbm90IHJ1biBvbiBsYXRlciBgcHJvamVuYCBpbnZvY2F0aW9ucy4gSXQgb25seSBmaXJlcyBmb3IgYHByb2plbiBuZXdgIChvciBgUHJvamVjdHMuY3JlYXRlUHJvamVjdGApLlxuICAgKiBVc2UgaXQgZm9yIGRldGVybWluaXN0aWMsIG9uZS1vZmYgZmlsZSBnZW5lcmF0aW9uLiBPcmRlciBhY3Jvc3MgY29tcG9uZW50cyBpcyBub3QgZ3VhcmFudGVlZC5cbiAgICpcbiAgICogQHBhcmFtIGluaXRQcm9qZWN0IERldGFpbHMgYWJvdXQgaG93IHRoZSBwcm9qZWN0IHdhcyBjcmVhdGVkLCBlLmcuIGl0cyB0eXBlIGFuZCB0aGUgb3JpZ2luYWwgQ0xJIGFyZ3MuXG4gICAqL1xuICBwdWJsaWMgcHJvamVjdENyZWF0aW9uKGluaXRQcm9qZWN0OiBJbml0UHJvamVjdCkge1xuICAgIGluaXRQcm9qZWN0O1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGxlZCBvbmNlLCByaWdodCBhZnRlciBgcG9zdFN5bnRoZXNpemUoKWAsIG9ubHkgd2hlbiB0aGUgcHJvamVjdCBpcyBjcmVhdGVkIGZvciB0aGUgZmlyc3QgdGltZS5cbiAgICpcbiAgICogSXQgZG9lcyBub3QgcnVuIG9uIGxhdGVyIGBwcm9qZW5gIGludm9jYXRpb25zLiBJdCBvbmx5IGZpcmVzIGZvciBgcHJvamVuIG5ld2AgKG9yIGBQcm9qZWN0cy5jcmVhdGVQcm9qZWN0YCkuXG4gICAqIEl0IGlzIGFsc28gc2tpcHBlZCB3aGVuIHBvc3Qtc3ludGhlc2lzIHN0ZXBzIGFyZSBkaXNhYmxlZCwgZS5nLiBgLS1uby1wb3N0YCBvciBgUFJPSkVOX0RJU0FCTEVfUE9TVGAuXG4gICAqIFVzZSBpdCBmb3Igb25lLW9mZiBzZXR1cCB0aGF0IGNhbiBiZSB0dXJuZWQgb2ZmIGJ5IHRoZSB1c2VyLCBsaWtlIHJ1bm5pbmcgYSB0YXNrIHRvIGdpdmUgdGhlIHVzZXIgaW1tZWRpYXRlXG4gICAqIGZlZWRiYWNrIG9uIHRoZWlyIG5ldyBwcm9qZWN0LiBPcmRlciBhY3Jvc3MgY29tcG9uZW50cyBpcyBub3QgZ3VhcmFudGVlZC5cbiAgICpcbiAgICogQHBhcmFtIGluaXRQcm9qZWN0IERldGFpbHMgYWJvdXQgaG93IHRoZSBwcm9qZWN0IHdhcyBjcmVhdGVkLCBlLmcuIGl0cyB0eXBlIGFuZCB0aGUgb3JpZ2luYWwgQ0xJIGFyZ3MuXG4gICAqL1xuICBwdWJsaWMgcG9zdFByb2plY3RDcmVhdGlvbihpbml0UHJvamVjdDogSW5pdFByb2plY3QpIHtcbiAgICBpbml0UHJvamVjdDtcbiAgfVxufVxuXG4vKipcbiAqIEludGVybmFsIGZsYWcga2V5IHJlYWQgYnkgdGhlIGRldGFjaGVkLWd1YXJkIHByb3h5LiBBIHN5bWJvbCBzbyBpdCBuZXZlclxuICogY29sbGlkZXMgd2l0aCBhIHJlYWwgKHN0cmluZy1rZXllZCkgbWVtYmVyIGFuZCBpcyBhbHdheXMgcmVhZGFibGUgdGhyb3VnaCB0aGVcbiAqIGd1YXJkIChzeW1ib2wgYWNjZXNzIGlzIG5ldmVyIGJsb2NrZWQpLlxuICovXG5jb25zdCBGVVRVUkVfQVRUQUNIRUQgPSBTeW1ib2wuZm9yKFwicHJvamVuLmZ1dHVyZS5hdHRhY2hlZFwiKTtcblxuLyoqXG4gKiBUaGUgbWVtYmVycyBhIGRldGFjaGVkIGZ1dHVyZSBjb21wb25lbnQgaXMgYWxsb3dlZCB0byBleHBvc2UuIFJlYWRpbmcgYW55dGhpbmdcbiAqIGVsc2UgYmVmb3JlIGF0dGFjaCB0aHJvd3MuIChgY29weWAgaXMgdGhlIGNvcHlhYmxlIGNhcGFiaWxpdHkgbWV0aG9kIGFcbiAqIGNvcHlhYmxlIHN1YmNsYXNzIGFkZHMsIHBlciB0aGUgYHJlY3JlYXRlKClgIGNvbnZlbnRpb24uKVxuICovXG5jb25zdCBERVRBQ0hFRF9BTExPV0xJU1QgPSBuZXcgU2V0PFByb3BlcnR5S2V5PihbXG4gIFwiYXR0YWNoXCIsXG4gIFwidHJ5QXR0YWNoXCIsXG4gIFwiYXR0YWNoZWRcIixcbiAgXCJjb3B5XCIsXG4gIFwiY29uc3RydWN0b3JcIixcbiAgXCJ0b1N0cmluZ1wiLFxuXSk7XG5cbi8qKlxuICogV3JhcCBhIGZyZXNobHkgY29uc3RydWN0ZWQge0BsaW5rIEZ1dHVyZUNvbXBvbmVudH0gaW4gYSBndWFyZCBwcm94eS5cbiAqXG4gKiBUd28gam9iczpcbiAqXG4gKiAxLiBCbG9jayB1c2UgYmVmb3JlIGF0dGFjaC4gV2hpbGUgZGV0YWNoZWQsIGFueSBwcm9wZXJ0eSByZWFkIG91dHNpZGVcbiAqICAgIHtAbGluayBERVRBQ0hFRF9BTExPV0xJU1R9IChhbmQgb3V0c2lkZSBzeW1ib2wga2V5cywgd2hpY2ggYWx3YXlzIHBhc3Mgc29cbiAqICAgIGBpbnN0YW5jZW9mYCwganNpaSBhbmQgaW5zcGVjdGlvbiBrZWVwIHdvcmtpbmcpIHRocm93cyBpbnN0ZWFkIG9mIHNpbGVudGx5XG4gKiAgICByZXR1cm5pbmcgc2hhZG93LXRyZWUgc3RhdGUuXG4gKiAyLiBcIkRyb3BcIiBpdHNlbGYgb24gYXR0YWNoLiBPbmNlIGF0dGFjaGVkLCB0aGUgZ3VhcmQgaXMgYSB0cmFuc3BhcmVudFxuICogICAgcGFzcy10aHJvdWdoOiBhIHNpbmdsZSBib29sZWFuIGNoZWNrLCB0aGVuIGBSZWZsZWN0YC4gRXZlcnkgbWV0aG9kIGl0XG4gKiAgICByZXR1cm5zIGlzIGJvdW5kIHRvIHRoZSAqcmVhbCogdGFyZ2V0LCBzbyB0aGUgbW9tZW50IHlvdSBjYWxsIG9uZSBtZXRob2RcbiAqICAgIHRoZSB3b3JrIGNvbnRpbnVlcyBvbiB0aGUgYmFyZSBvYmplY3Qgd2l0aCBubyBmdXJ0aGVyIHByb3h5IHRyYXBzLlxuICpcbiAqIE9ubHkgYGdldGAgaXMgZ3VhcmRlZC4gYHNldGAgaXMgaW50ZW50aW9uYWxseSBsZWZ0IG9wZW4gc28gYSBzdWJjbGFzc1xuICogY29uc3RydWN0b3IgY2FuIGFzc2lnbiBpdHMgb3duIGZpZWxkcyAoZS5nLiBgdGhpcy5vcHRpb25zID0gb3B0aW9uc2ApLlxuICovXG5mdW5jdGlvbiBndWFyZERldGFjaGVkPFQgZXh0ZW5kcyBvYmplY3Q+KHRhcmdldDogVCk6IFQge1xuICBjb25zdCBib3VuZENhY2hlID0gbmV3IE1hcDxQcm9wZXJ0eUtleSwgKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnk+KCk7XG4gIGNvbnN0IGhhbmRsZXI6IFByb3h5SGFuZGxlcjxUPiA9IHtcbiAgICBnZXQodCwgcHJvcCkge1xuICAgICAgLy8gbmV2ZXIgcHJlc2VudCBhcyBhIHRoZW5hYmxlLCBvciBgYXdhaXQgZnV0dXJlQ29tcG9uZW50YCB3b3VsZCBoYW5nL3Rocm93XG4gICAgICBpZiAocHJvcCA9PT0gXCJ0aGVuXCIpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIH1cblxuICAgICAgY29uc3QgYXR0YWNoZWQgPSAodCBhcyBhbnkpW0ZVVFVSRV9BVFRBQ0hFRF0gPT09IHRydWU7XG4gICAgICBjb25zdCBhbGxvd2VkID1cbiAgICAgICAgYXR0YWNoZWQgfHwgdHlwZW9mIHByb3AgIT09IFwic3RyaW5nXCIgfHwgREVUQUNIRURfQUxMT1dMSVNULmhhcyhwcm9wKTtcblxuICAgICAgaWYgKCFhbGxvd2VkKSB7XG4gICAgICAgIGNvbnN0IG5hbWUgPSAodCBhcyBhbnkpLm5ld1RhcmdldE5hbWUgPz8gdC5jb25zdHJ1Y3Rvci5uYW1lO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYENhbm5vdCBhY2Nlc3MgJyR7U3RyaW5nKHByb3ApfScgb24gJHtuYW1lfTogYSBmdXR1cmUgY29tcG9uZW50IGlzIGAgK1xuICAgICAgICAgICAgYG5vdCB1c2FibGUgdW50aWwgaXQgaXMgYXR0YWNoZWQuIENhbGwgYXR0YWNoKHNjb3BlKSBmaXJzdCwgb3IgcGFzcyBgICtcbiAgICAgICAgICAgIGBpdCB0byBhIFByb2plY3Qgd2hpY2ggYXR0YWNoZXMgaXQgZm9yIHlvdS5gLFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBiaW5kIGZ1bmN0aW9ucyB0byB0aGUgKnJlYWwqIHRhcmdldCBzbyB0aGF0LCBvbmNlIGludm9rZWQsIGFsbCBpbnRlcm5hbFxuICAgICAgLy8gYHRoaXNgIGFjY2VzcyBoYXBwZW5zIG9uIHRoZSBiYXJlIG9iamVjdCB3aXRoIG5vIHByb3h5IGludm9sdmVtZW50LlxuICAgICAgY29uc3QgdmFsdWUgPSBSZWZsZWN0LmdldCh0LCBwcm9wLCB0KTtcbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICBsZXQgYm91bmQgPSBib3VuZENhY2hlLmdldChwcm9wKTtcbiAgICAgICAgaWYgKCFib3VuZCkge1xuICAgICAgICAgIGJvdW5kID0gKHZhbHVlIGFzICguLi5hcmdzOiBhbnlbXSkgPT4gYW55KS5iaW5kKHQpO1xuICAgICAgICAgIGJvdW5kQ2FjaGUuc2V0KHByb3AsIGJvdW5kKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYm91bmQ7XG4gICAgICB9XG4gICAgICByZXR1cm4gdmFsdWU7XG4gICAgfSxcbiAgfTtcbiAgcmV0dXJuIG5ldyBQcm94eSh0YXJnZXQsIGhhbmRsZXIpO1xufVxuXG4vKipcbiAqIE1ha2UgYSBzcGVjaWZpYyBwcm9wZXJ0eSB3cml0YWJsZSBhZ2Fpbi5cbiAqL1xudHlwZSBXcml0ZWFibGVQcm9wPFQsIEsgZXh0ZW5kcyBrZXlvZiBUPiA9IE9taXQ8VCwgSz4gJiB7XG4gIC1yZWFkb25seSBbUCBpbiBLXTogVFtQXTtcbn07XG5cbi8qKlxuICogQSB7QGxpbmsgQ29tcG9uZW50fSB0aGF0IGlzIGNyZWF0ZWQgKmRldGFjaGVkKiBmcm9tIGFueSBwcm9qZWN0IGFuZCBhdHRhY2hlZFxuICogdG8gb25lIGxhdGVyIHZpYSB7QGxpbmsgRnV0dXJlQ29tcG9uZW50LmF0dGFjaH0uXG4gKlxuICogTGlrZSBhIHJlZ3VsYXIgY29tcG9uZW50LCBidXQgY29uc3RydWN0ZWQgd2l0aG91dCBhIHByb2plY3QuIEl0IGltcHJvdmVzIG9uIGFcbiAqIG5haXZlIGRlZmVycmVkIGNvbXBvbmVudCBpbiB0aHJlZSB3YXlzOlxuICpcbiAqIC0gVXNlLWJlZm9yZS1hdHRhY2ggaXMgYW4gZXJyb3IsIG5vdCBhIHNpbGVudCBmb290Z3VuLiBUaGUgY29uc3RydWN0b3IgaGFuZHNcbiAqICAgdGhlIGNhbGxlciBhIGd1YXJkIHByb3h5OyB0b3VjaGluZyBgcHJvamVjdGAsIGBub2RlYCwgYHN5bnRoZXNpemUoKWAgb3IgYW55XG4gKiAgIHN1YmNsYXNzIGZlYXR1cmUgYmVmb3JlIGBhdHRhY2goKWAgdGhyb3dzLlxuICogLSBObyBnbG9iYWwgc2hhZG93LXRyZWUgbGVhay4gRWFjaCBpbnN0YW5jZSBnZXRzIGl0cyBvd24gdGhyb3dhd2F5IHNoYWRvd1xuICogICByb290LCBzbyBkZXRhY2hlZCBjb21wb25lbnRzIG5ldmVyIHNoYXJlIGFuIGlkIGNvdW50ZXIgYW5kIHRoZSByb290IGJlY29tZXNcbiAqICAgZ2FyYmFnZSBvbmNlIHRoZSBjb21wb25lbnQgaXMgcmVwYXJlbnRlZCBvbiBhdHRhY2guXG4gKiAtIGBhdHRhY2goKWAgcmV0dXJucyB0aGUgdW53cmFwcGVkIGNvbXBvbmVudCwgc28gY2FsbGVycyBjYW4gb3B0IG91dCBvZiB0aGVcbiAqICAgcHJveHkgZW50aXJlbHkuXG4gKlxuICogVGhlIGNvbnN0cnVjdG9yIHRha2VzIG5vIGFyZ3VtZW50cyAoYHN1cGVyKClgKS4gQSBzdWJjbGFzcyB0aGF0IG5lZWRzIG9wdGlvbnNcbiAqIGNhcHR1cmVzIHRoZW0gaXRzZWxmLCByZWFkaW5nIHRoZSBsb2NhbCBwYXJhbWV0ZXIgaW5zaWRlIGl0cyBjb25zdHJ1Y3RvciAtIE5PVFxuICogYHRoaXMub3B0aW9uc2AsIHdoaWNoIHRoZSBndWFyZCBibG9ja3MgdW50aWwgYXR0YWNoLlxuICpcbiAqIGBgYHRzXG4gKiBjbGFzcyBXb3JrZXIgZXh0ZW5kcyBGdXR1cmVDb21wb25lbnQge1xuICogICBwcml2YXRlIHJlYWRvbmx5IG9wdGlvbnM6IFdvcmtlck9wdGlvbnM7XG4gKiAgIGNvbnN0cnVjdG9yKG9wdGlvbnM6IFdvcmtlck9wdGlvbnMgPSB7fSkge1xuICogICAgIHN1cGVyKCk7XG4gKiAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9uczsgLy8gc2V0OiBhbGxvd2VkXG4gKiAgIH1cbiAqICAgcHJvdGVjdGVkIGluaXQoKSB7XG4gKiAgICAgLy8gdGhpcy5wcm9qZWN0IGlzIGF2YWlsYWJsZSBoZXJlXG4gKiAgIH1cbiAqIH1cbiAqXG4gKiBjb25zdCB3ID0gbmV3IFdvcmtlcih7IHJldHJpZXM6IDMgfSk7XG4gKiAvLyB3LnByb2plY3Q7ICAgICAgICAgICAgICAgICAgLy8gdGhyb3dzOiBub3QgYXR0YWNoZWQgeWV0XG4gKiBjb25zdCByZWFsID0gdy5hdHRhY2gocHJvamVjdCk7IC8vIHJlcGFyZW50cywgcnVucyBpbml0KCksIHJldHVybnMgdGhlIGJhcmUgaW5zdGFuY2VcbiAqIGBgYFxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgRnV0dXJlQ29tcG9uZW50IGV4dGVuZHMgQ29tcG9uZW50IHtcbiAgcHJpdmF0ZSByZWFkb25seSBuZXdUYXJnZXROYW1lOiBzdHJpbmc7XG4gIHByaXZhdGUgYXR0YWNoZWRTdGF0ZSA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIC8vIEVhY2ggZnV0dXJlIGNvbXBvbmVudCBnZXRzIGl0cyBPV04gc2hhZG93IHJvb3QuIFVubGlrZSBhIHNpbmdsZSBnbG9iYWxcbiAgICAvLyBzaGFkb3cgdHJlZSwgZGV0YWNoZWQgY29tcG9uZW50cyBuZXZlciBjb2xsaWRlIG9uIGFuIGlkIGNvdW50ZXIsIGFuZCB0aGVcbiAgICAvLyByb290IGlzIGNvbGxlY3RlZCBvbmNlIHdlIHJlcGFyZW50IG9uIGF0dGFjaCgpLlxuICAgIGNvbnN0IHNoYWRvdyA9IG5ldyBSb290Q29uc3RydWN0KCk7XG4gICAgdGFnQXNQcm9qZWN0KHNoYWRvdyk7XG4gICAgc3VwZXIoc2hhZG93KTtcblxuICAgIHRoaXMubmV3VGFyZ2V0TmFtZSA9IG5ldy50YXJnZXQubmFtZTtcblxuICAgIC8vIEhhbmQgdGhlIGNhbGxlciBhIGd1YXJkZWQgcHJveHkuIGB0aGlzYCBoZXJlIGlzIHN0aWxsIHRoZSBiYXJlIG9iamVjdDtcbiAgICAvLyByZXR1cm5pbmcgaXQgbWFrZXMgdGhlIHByb3h5IHRoZSBpbnN0YW5jZSBzZWVuIGJ5IGBuZXdgLiBCZWNhdXNlIHRoZSBiYXNlXG4gICAgLy8gY29uc3RydWN0b3IgcmV0dXJucyBhbiBvYmplY3QsIHN1YmNsYXNzIGNvbnN0cnVjdG9ycyB0cmFuc3BhcmVudGx5IGFkb3B0XG4gICAgLy8gdGhlIHByb3h5IGFzIHRoZWlyIGB0aGlzYCB0b28uXG4gICAgcmV0dXJuIGd1YXJkRGV0YWNoZWQodGhpcyk7XG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciBgYXR0YWNoKClgIGhhcyBiZWVuIGNhbGxlZC4gQSBjb252ZW5pZW5jZSBmb3IgdGVzdHMvaW50cm9zcGVjdGlvbjtcbiAgICogcHJlZmVyIGB0cnlBdHRhY2goKWAgb3ZlciByZWFkaW5nIHRoaXMgYW5kIGJyYW5jaGluZy5cbiAgICovXG4gIHB1YmxpYyBnZXQgYXR0YWNoZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuYXR0YWNoZWRTdGF0ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcm9qZWN0LWRlcGVuZGVudCBzZXR1cC4gUnVucyBvbmNlLCBmcm9tIGBhdHRhY2goKWAsIHdoZW4gYHRoaXMucHJvamVjdGAgaXNcbiAgICogZmluYWxseSBhdmFpbGFibGUuXG4gICAqL1xuICBwcm90ZWN0ZWQgaW5pdCgpOiB2b2lkIHt9XG5cbiAgLyoqXG4gICAqIEF0dGFjaCB0aGUgY29tcG9uZW50IHRvIGEgc2NvcGUuIE9ubHkgbm93IGRvZXMgaXQgYmVjb21lIHVzYWJsZS5cbiAgICpcbiAgICogUmV0dXJucyB0aGUgcmVhbCwgdW53cmFwcGVkIGNvbXBvbmVudCAobm90IHRoZSBwcm94eSkuIEEgY29tcG9uZW50IG1heSBiZVxuICAgKiBhdHRhY2hlZCBleGFjdGx5IG9uY2U7IGF0dGFjaGluZyBhbiBhbHJlYWR5LWF0dGFjaGVkIGNvbXBvbmVudCB0aHJvd3MgKGNvcHlcbiAgICogaXQgZmlyc3QgdG8gYXR0YWNoIGEgdmFyaWFudCBlbHNld2hlcmUpLiBVc2UgYHRyeUF0dGFjaCgpYCBpZiB5b3UgZG9uJ3QgY2FyZVxuICAgKiB3aGV0aGVyIGl0IGhhcyBhbHJlYWR5IGJlZW4gYXR0YWNoZWQuXG4gICAqL1xuICBwdWJsaWMgYXR0YWNoKHNjb3BlOiBJQ29uc3RydWN0LCBpZD86IHN0cmluZykge1xuICAgIGlmICh0aGlzLmF0dGFjaGVkU3RhdGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYCR7dGhpcy5uZXdUYXJnZXROYW1lfSBpcyBhbHJlYWR5IGF0dGFjaGVkIHRvICcke3RoaXMucHJvamVjdC5ub2RlLnBhdGh9Jy4gYCArXG4gICAgICAgICAgYFVzZSBcXGB0cnlBdHRhY2hcXGAgb3IgXFxgY29weVxcYCBpdCB0byBhdHRhY2ggYSB2YXJpYW50LmAsXG4gICAgICApO1xuICAgIH1cbiAgICAvLyBjb25zdHJ1Y3RzIGhhcyBubyBwdWJsaWMgcmVwYXJlbnQsIHNvIGJ1aWxkIGEgZnJlc2ggbm9kZSBvbiB0aGUgcmVhbFxuICAgIC8vIHNjb3BlLiBUaGUgcGVyLWluc3RhbmNlIHNoYWRvdyByb290IGFuZCBpdHMgb3JpZ2luYWwgbm9kZSBiZWNvbWUgYW5cbiAgICAvLyB1bnJlYWNoYWJsZSBpc2xhbmQgYW5kIGFyZSBjb2xsZWN0ZWQuXG4gICAgKHRoaXMgYXMgV3JpdGVhYmxlUHJvcDx0aGlzLCBcIm5vZGVcIj4pLm5vZGUgPSBuZXcgTm9kZShcbiAgICAgIHRoaXMsXG4gICAgICBzY29wZSxcbiAgICAgIGlkID8/IGNvbXBvbmVudElkKHNjb3BlKSxcbiAgICApO1xuXG4gICAgLy8gVGhlIGNvbXBvbmVudCBhbHJlYWR5IGNhcnJpZXMgdGhlIGNvbXBvbmVudCB0YWcgKHNldCBieSB0aGUgYmFzZVxuICAgIC8vIGNvbnN0cnVjdG9yLCB3aGljaCBpcyBpZGVtcG90ZW50IGFnYWluc3QgdGhlIHNhbWUgb2JqZWN0KTsgcmUtYWRkIHRoZVxuICAgIC8vIG1ldGFkYXRhIHRvIHRoZSBuZXcgbm9kZSBhbmQgcmVzb2x2ZSB0aGUgcmVhbCBwcm9qZWN0LlxuICAgIHRoaXMubm9kZS5hZGRNZXRhZGF0YShcInR5cGVcIiwgXCJjb21wb25lbnRcIik7XG4gICAgdGhpcy5ub2RlLmFkZE1ldGFkYXRhKFwiY29uc3RydWN0XCIsIHRoaXMubmV3VGFyZ2V0TmFtZSk7XG4gICAgKHRoaXMgYXMgV3JpdGVhYmxlUHJvcDx0aGlzLCBcInByb2plY3RcIj4pLnByb2plY3QgPSBmaW5kQ2xvc2VzdFByb2plY3QoXG4gICAgICBzY29wZSxcbiAgICAgIHRoaXMubmV3VGFyZ2V0TmFtZSxcbiAgICApO1xuXG4gICAgdGhpcy5hdHRhY2hlZFN0YXRlID0gdHJ1ZTtcbiAgICAvLyBGbGlwIHRoZSBndWFyZCBpbnRvIHRyYW5zcGFyZW50IHBhc3MtdGhyb3VnaCBmb3IgYW55IHByb3h5IGhhbmRsZXMgdGhlXG4gICAgLy8gY2FsbGVyIHN0aWxsIGhvbGRzLiBTeW1ib2wga2V5LCBzbyB0aGUgZ3VhcmQgY2FuIGFsd2F5cyByZWFkIGl0LlxuICAgICh0aGlzIGFzIGFueSlbRlVUVVJFX0FUVEFDSEVEXSA9IHRydWU7XG5cbiAgICAvLyBwcm9qZWN0IGlzIG5vdyBhdmFpbGFibGUsIHJ1biBwcm9qZWN0LWRlcGVuZGVudCBzZXR1cFxuICAgIHRoaXMuaW5pdCgpO1xuXG4gICAgLy8gaGFuZCBiYWNrIHRoZSBiYXJlIG9iamVjdCBzbyB0aGUgY2FsbGVyIGNhbiBkcm9wIHRoZSBwcm94eSBlbnRpcmVseVxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEF0dGFjaCB0aGUgY29tcG9uZW50IGlmIGl0IGlzbid0IGFscmVhZHksIHdpdGhvdXQgY2FyaW5nICp3aGVyZSouXG4gICAqXG4gICAqIFVubGlrZSBgYXR0YWNoKClgLCBuZXZlciB0aHJvd3Mgb24gYW4gYWxyZWFkeS1hdHRhY2hlZCBjb21wb25lbnQ6IGlmIGF0dGFjaGVkXG4gICAqIGFueXdoZXJlIGF0IGFsbCwgdGhlIGV4aXN0aW5nIGluc3RhbmNlIGlzIHJldHVybmVkIGFuZCBgc2NvcGVgIGlzIGlnbm9yZWQuXG4gICAqIFVzZSBgYXR0YWNoKClgIHdoZW4gYXR0YWNoaW5nIHRvIGEgc3BlY2lmaWMgc2NvcGUgaXMgcGFydCBvZiB5b3VyIGNvbnRyYWN0XG4gICAqIGFuZCBhIHByZS1leGlzdGluZyBhdHRhY2htZW50IGVsc2V3aGVyZSB3b3VsZCBiZSBhIGJ1Zy5cbiAgICovXG4gIHB1YmxpYyB0cnlBdHRhY2goc2NvcGU6IElDb25zdHJ1Y3QsIGlkPzogc3RyaW5nKSB7XG4gICAgcmV0dXJuIHRoaXMuYXR0YWNoZWRTdGF0ZSA/IHRoaXMgOiB0aGlzLmF0dGFjaChzY29wZSwgaWQpO1xuICB9XG59XG4iXX0=