UNPKG

aws-cdk

Version:

CDK Toolkit, the command line tool for CDK apps

173 lines 18.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RWLock = void 0; const fs_1 = require("fs"); const path = require("path"); /** * A single-writer/multi-reader lock on a directory * * It uses marker files with PIDs in them as a locking marker; the PIDs will be * checked for liveness, so that if the process exits without cleaning up the * files the lock is implicitly released. * * This class is not 100% race safe, but in practice it should be a lot * better than the 0 protection we have today. */ class RWLock { constructor(directory) { this.directory = directory; this.readCounter = 0; this.pidString = `${process.pid}`; this.writerFile = path.join(this.directory, 'synth.lock'); } /** * Acquire a writer lock. * * No other readers or writers must exist for the given directory. */ async acquireWrite() { await this.assertNoOtherWriters(); const readers = await this.currentReaders(); if (readers.length > 0) { throw new Error(`Other CLIs (PID=${readers}) are currently reading from ${this.directory}. Invoke the CLI in sequence, or use '--output' to synth into different directories.`); } await writeFileAtomic(this.writerFile, this.pidString); return { release: async () => { await deleteFile(this.writerFile); }, convertToReaderLock: async () => { // Acquire the read lock before releasing the write lock. Slightly less // chance of racing! const ret = await this.doAcquireRead(); await deleteFile(this.writerFile); return ret; }, }; } /** * Acquire a read lock * * Will fail if there are any writers. */ async acquireRead() { await this.assertNoOtherWriters(); return this.doAcquireRead(); } /** * Obtains the name fo a (new) `readerFile` to use. This includes a counter so * that if multiple threads of the same PID attempt to concurrently acquire * the same lock, they're guaranteed to use a different reader file name (only * one thread will ever execute JS code at once, guaranteeing the readCounter * is incremented "atomically" from the point of view of this PID.). */ readerFile() { return path.join(this.directory, `read.${this.pidString}.${++this.readCounter}.lock`); } /** * Do the actual acquiring of a read lock. */ async doAcquireRead() { const readerFile = this.readerFile(); await writeFileAtomic(readerFile, this.pidString); return { release: async () => { await deleteFile(readerFile); }, }; } async assertNoOtherWriters() { const writer = await this.currentWriter(); if (writer) { throw new Error(`Another CLI (PID=${writer}) is currently synthing to ${this.directory}. Invoke the CLI in sequence, or use '--output' to synth into different directories.`); } } /** * Check the current writer (if any) */ async currentWriter() { const contents = await readFileIfExists(this.writerFile); if (!contents) { return undefined; } const pid = parseInt(contents, 10); if (!processExists(pid)) { // Do cleanup of a stray file now await deleteFile(this.writerFile); return undefined; } return pid; } /** * Check the current readers (if any) */ async currentReaders() { const re = /^read\.([^.]+)\.[^.]+\.lock$/; const ret = new Array(); let children; try { children = await fs_1.promises.readdir(this.directory, { encoding: 'utf-8' }); } catch (e) { // Can't be locked if the directory doesn't exist if (e.code === 'ENOENT') { return []; } throw e; } for (const fname of children) { const m = fname.match(re); if (m) { const pid = parseInt(m[1], 10); if (processExists(pid)) { ret.push(pid); } else { // Do cleanup of a stray file now await deleteFile(path.join(this.directory, fname)); } } } return ret; } } exports.RWLock = RWLock; async function readFileIfExists(filename) { try { return await fs_1.promises.readFile(filename, { encoding: 'utf-8' }); } catch (e) { if (e.code === 'ENOENT') { return undefined; } throw e; } } let tmpCounter = 0; async function writeFileAtomic(filename, contents) { await fs_1.promises.mkdir(path.dirname(filename), { recursive: true }); const tmpFile = `${filename}.${process.pid}_${++tmpCounter}`; await fs_1.promises.writeFile(tmpFile, contents, { encoding: 'utf-8' }); await fs_1.promises.rename(tmpFile, filename); } async function deleteFile(filename) { try { await fs_1.promises.unlink(filename); } catch (e) { if (e.code === 'ENOENT') { return; } throw e; } } function processExists(pid) { try { process.kill(pid, 0); return true; } catch (e) { return false; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicndsb2NrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicndsb2NrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDJCQUFvQztBQUNwQyw2QkFBNkI7QUFFN0I7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBYSxNQUFNO0lBS2pCLFlBQTRCLFNBQWlCO1FBQWpCLGNBQVMsR0FBVCxTQUFTLENBQVE7UUFGckMsZ0JBQVcsR0FBRyxDQUFDLENBQUM7UUFHdEIsSUFBSSxDQUFDLFNBQVMsR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUVsQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxZQUFZLENBQUMsQ0FBQztJQUM1RCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLEtBQUssQ0FBQyxZQUFZO1FBQ3ZCLE1BQU0sSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7UUFFbEMsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDNUMsSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtZQUN0QixNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixPQUFPLGdDQUFnQyxJQUFJLENBQUMsU0FBUyxzRkFBc0YsQ0FBQyxDQUFDO1NBQ2pMO1FBRUQsTUFBTSxlQUFlLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFdkQsT0FBTztZQUNMLE9BQU8sRUFBRSxLQUFLLElBQUksRUFBRTtnQkFDbEIsTUFBTSxVQUFVLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ3BDLENBQUM7WUFDRCxtQkFBbUIsRUFBRSxLQUFLLElBQUksRUFBRTtnQkFDOUIsdUVBQXVFO2dCQUN2RSxvQkFBb0I7Z0JBQ3BCLE1BQU0sR0FBRyxHQUFHLE1BQU0sSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO2dC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TyxDQUFNLEVBQUU7UUFDZixJQUFJLENBQUMsQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFO1lBQ3ZCLE9BQU87U0FDUjtRQUNELE1BQU0sQ0FBQyxDQUFDO0tBQ1Q7QUFDSCxDQUFDO0FBRUQsU0FBUyxhQUFhLENBQUMsR0FBVztJQUNoQyxJQUFJO1FBQ0YsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDckIsT0FBTyxJQUFJLENBQUM7S0FDYjtJQUFDLE9BQU8sQ0FBQyxFQUFFO1FBQ1YsT0FBTyxLQUFLLENBQUM7S0FDZDtBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBwcm9taXNlcyBhcyBmcyB9IGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5cbi8qKlxuICogQSBzaW5nbGUtd3JpdGVyL211bHRpLXJlYWRlciBsb2NrIG9uIGEgZGlyZWN0b3J5XG4gKlxuICogSXQgdXNlcyBtYXJrZXIgZmlsZXMgd2l0aCBQSURzIGluIHRoZW0gYXMgYSBsb2NraW5nIG1hcmtlcjsgdGhlIFBJRHMgd2lsbCBiZVxuICogY2hlY2tlZCBmb3IgbGl2ZW5lc3MsIHNvIHRoYXQgaWYgdGhlIHByb2Nlc3MgZXhpdHMgd2l0aG91dCBjbGVhbmluZyB1cCB0aGVcbiAqIGZpbGVzIHRoZSBsb2NrIGlzIGltcGxpY2l0bHkgcmVsZWFzZWQuXG4gKlxuICogVGhpcyBjbGFzcyBpcyBub3QgMTAwJSByYWNlIHNhZmUsIGJ1dCBpbiBwcmFjdGljZSBpdCBzaG91bGQgYmUgYSBsb3RcbiAqIGJldHRlciB0aGFuIHRoZSAwIHByb3RlY3Rpb24gd2UgaGF2ZSB0b2RheS5cbiAqL1xuZXhwb3J0IGNsYXNzIFJXTG9jayB7XG4gIHByaXZhdGUgcmVhZG9ubHkgcGlkU3RyaW5nOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgd3JpdGVyRmlsZTogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRDb3VudGVyID0gMDtcblxuICBjb25zdHJ1Y3RvcihwdWJsaWMgcmVhZG9ubHkgZGlyZWN0b3J5OiBzdHJpbmcpIHtcbiAgICB0aGlzLnBpZFN0cmluZyA9IGAke3Byb2Nlc3MucGlkfWA7XG5cbiAgICB0aGlzLndyaXRlckZpbGUgPSBwYXRoLmpvaW4odGhpcy5kaXJlY3RvcnksICdzeW50aC5sb2NrJyk7XG4gIH1cblxuICAvKipcbiAgICogQWNxdWlyZSBhIHdyaXRlciBsb2NrLlxuICAgKlxuICAgKiBObyBvdGhlciByZWFkZXJzIG9yIHdyaXRlcnMgbXVzdCBleGlzdCBmb3IgdGhlIGdpdmVuIGRpcmVjdG9yeS5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBhY3F1aXJlV3JpdGUoKTogUHJvbWlzZTxJV3JpdGVyTG9jaz4ge1xuICAgIGF3YWl0IHRoaXMuYXNzZXJ0Tm9PdGhlcldyaXRlcnMoKTtcblxuICAgIGNvbnN0IHJlYWRlcnMgPSBhd2FpdCB0aGlzLmN1cnJlbnRSZWFkZXJzKCk7XG4gICAgaWYgKHJlYWRlcnMubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBPdGhlciBDTElzIChQSUQ9JHtyZWFkZXJzfSkgYXJlIGN1cnJlbnRseSByZWFkaW5nIGZyb20gJHt0aGlzLmRpcmVjdG9yeX0uIEludm9rZSB0aGUgQ0xJIGluIHNlcXVlbmNlLCBvciB1c2UgJy0tb3V0cHV0JyB0byBzeW50aCBpbnRvIGRpZmZlcmVudCBkaXJlY3Rvcmllcy5gKTtcbiAgICB9XG5cbiAgICBhd2FpdCB3cml0ZUZpbGVBdG9taWModGhpcy53cml0ZXJGaWxlLCB0aGlzLnBpZFN0cmluZyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgcmVsZWFzZTogYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCBkZWxldGVGaWxlKHRoaXMud3JpdGVyRmlsZSk7XG4gICAgICB9LFxuICAgICAgY29udmVydFRvUmVhZGVyTG9jazogYXN5bmMgKCkgPT4ge1xuICAgICAgICAvLyBBY3F1aXJlIHRoZSByZWFkIGxvY2sgYmVmb3JlIHJlbGVhc2luZyB0aGUgd3JpdGUgbG9jay4gU2xpZ2h0bHkgbGVzc1xuICAgICAgICAvLyBjaGFuY2Ugb2YgcmFjaW5nIVxuICAgICAgICBjb25zdCByZXQgPSBhd2FpdCB0aGlzLmRvQWNxdWlyZVJlYWQoKTtcbiAgICAgICAgYXdhaXQgZGVsZXRlRmlsZSh0aGlzLndyaXRlckZpbGUpO1xuICAgICAgICByZXR1cm4gcmV0O1xuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEFjcXVpcmUgYSByZWFkIGxvY2tcbiAgICpcbiAgICogV2lsbCBmYWlsIGlmIHRoZXJlIGFyZSBhbnkgd3JpdGVycy5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBhY3F1aXJlUmVhZCgpOiBQcm9taXNlPElMb2NrPiB7XG4gICAgYXdhaXQgdGhpcy5hc3NlcnROb090aGVyV3JpdGVycygpO1xuICAgIHJldHVybiB0aGlzLmRvQWNxdWlyZVJlYWQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnRhaW5zIHRoZSBuYW1lIGZvIGEgKG5ldykgYHJlYWRlckZpbGVgIHRvIHVzZS4gVGhpcyBpbmNsdWRlcyBhIGNvdW50ZXIgc29cbiAgICogdGhhdCBpZiBtdWx0aXBsZSB0aHJlYWRzIG9mIHRoZSBzYW1lIFBJRCBhdHRlbXB0IHRvIGNvbmN1cnJlbnRseSBhY3F1aXJlXG4gICAqIHRoZSBzYW1lIGxvY2ssIHRoZXkncmUgZ3VhcmFudGVlZCB0byB1c2UgYSBkaWZmZXJlbnQgcmVhZGVyIGZpbGUgbmFtZSAob25seVxuICAgKiBvbmUgdGhyZWFkIHdpbGwgZXZlciBleGVjdXRlIEpTIGNvZGUgYXQgb25jZSwgZ3VhcmFudGVlaW5nIHRoZSByZWFkQ291bnRlclxuICAgKiBpcyBpbmNyZW1lbnRlZCBcImF0b21pY2FsbHlcIiBmcm9tIHRoZSBwb2ludCBvZiB2aWV3IG9mIHRoaXMgUElELikuXG4gICAqL1xuICBwcml2YXRlIHJlYWRlckZpbGUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gcGF0aC5qb2luKHRoaXMuZGlyZWN0b3J5LCBgcmVhZC4ke3RoaXMucGlkU3RyaW5nfS4keysrdGhpcy5yZWFkQ291bnRlcn0ubG9ja2ApO1xuICB9XG5cbiAgLyoqXG4gICAqIERvIHRoZSBhY3R1YWwgYWNxdWlyaW5nIG9mIGEgcmVhZCBsb2NrLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBkb0FjcXVpcmVSZWFkKCk6IFByb21pc2U8SUxvY2s+IHtcbiAgICBjb25zdCByZWFkZXJGaWxlID0gdGhpcy5yZWFkZXJGaWxlKCk7XG4gICAgYXdhaXQgd3JpdGVGaWxlQXRvbWljKHJlYWRlckZpbGUsIHRoaXMucGlkU3RyaW5nKTtcbiAgICByZXR1cm4ge1xuICAgICAgcmVsZWFzZTogYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCBkZWxldGVGaWxlKHJlYWRlckZpbGUpO1xuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBhc3NlcnROb090aGVyV3JpdGVycygpIHtcbiAgICBjb25zdCB3cml0ZXIgPSBhd2FpdCB0aGlzLmN1cnJlbnRXcml0ZXIoKTtcbiAgICBpZiAod3JpdGVyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEFub3RoZXIgQ0xJIChQSUQ9JHt3cml0ZXJ9KSBpcyBjdXJyZW50bHkgc3ludGhpbmcgdG8gJHt0aGlzLmRpcmVjdG9yeX0uIEludm9rZSB0aGUgQ0xJIGluIHNlcXVlbmNlLCBvciB1c2UgJy0tb3V0cHV0JyB0byBzeW50aCBpbnRvIGRpZmZlcmVudCBkaXJlY3Rvcmllcy5gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgdGhlIGN1cnJlbnQgd3JpdGVyIChpZiBhbnkpXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGN1cnJlbnRXcml0ZXIoKTogUHJvbWlzZTxudW1iZXIgfCB1bmRlZmluZWQ+IHtcbiAgICBjb25zdCBjb250ZW50cyA9IGF3YWl0IHJlYWRGaWxlSWZFeGlzdHModGhpcy53cml0ZXJGaWxlKTtcbiAgICBpZiAoIWNvbnRlbnRzKSB7IHJldHVybiB1bmRlZmluZWQ7IH1cblxuICAgIGNvbnN0IHBpZCA9IHBhcnNlSW50KGNvbnRlbnRzLCAxMCk7XG4gICAgaWYgKCFwcm9jZXNzRXhpc3RzKHBpZCkpIHtcbiAgICAgIC8vIERvIGNsZWFudXAgb2YgYSBzdHJheSBmaWxlIG5vd1xuICAgICAgYXdhaXQgZGVsZXRlRmlsZSh0aGlzLndyaXRlckZpbGUpO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICByZXR1cm4gcGlkO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIHRoZSBjdXJyZW50IHJlYWRlcnMgKGlmIGFueSlcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY3VycmVudFJlYWRlcnMoKTogUHJvbWlzZTxudW1iZXJbXT4ge1xuICAgIGNvbnN0IHJlID0gL15yZWFkXFwuKFteLl0rKVxcLlteLl0rXFwubG9jayQvO1xuICAgIGNvbnN0IHJldCA9IG5ldyBBcnJheTxudW1iZXI+KCk7XG5cbiAgICBsZXQgY2hpbGRyZW47XG4gICAgdHJ5IHtcbiAgICAgIGNoaWxkcmVuID0gYXdhaXQgZnMucmVhZGRpcih0aGlzLmRpcmVjdG9yeSwgeyBlbmNvZGluZzogJ3V0Zi04JyB9KTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIC8vIENhbid0IGJlIGxvY2tlZCBpZiB0aGUgZGlyZWN0b3J5IGRvZXNuJ3QgZXhpc3RcbiAgICAgIGlmIChlLmNvZGUgPT09ICdFTk9FTlQnKSB7IHJldHVybiBbXTsgfVxuICAgICAgdGhyb3cgZTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGZuYW1lIG9mIGNoaWxkcmVuKSB7XG4gICAgICBjb25zdCBtID0gZm5hbWUubWF0Y2gocmUpO1xuICAgICAgaWYgKG0pIHtcbiAgICAgICAgY29uc3QgcGlkID0gcGFyc2VJbnQobVsxXSwgMTApO1xuICAgICAgICBpZiAocHJvY2Vzc0V4aXN0cyhwaWQpKSB7XG4gICAgICAgICAgcmV0LnB1c2gocGlkKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBEbyBjbGVhbnVwIG9mIGEgc3RyYXkgZmlsZSBub3dcbiAgICAgICAgICBhd2FpdCBkZWxldGVGaWxlKHBhdGguam9pbih0aGlzLmRpcmVjdG9yeSwgZm5hbWUpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmV0O1xuICB9XG59XG5cbi8qKlxuICogQW4gYWNxdWlyZWQgbG9ja1xuICovXG5leHBvcnQgaW50ZXJmYWNlIElMb2NrIHtcbiAgcmVsZWFzZSgpOiBQcm9taXNlPHZvaWQ+O1xufVxuXG4vKipcbiAqIEFuIGFjcXVpcmVkIHdyaXRlciBsb2NrXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSVdyaXRlckxvY2sgZXh0ZW5kcyBJTG9jayB7XG4gIC8qKlxuICAgKiBDb252ZXJ0IHRoZSB3cml0ZXIgbG9jayB0byBhIHJlYWRlciBsb2NrXG4gICAqL1xuICBjb252ZXJ0VG9SZWFkZXJMb2NrKCk6IFByb21pc2U8SUxvY2s+O1xufVxuXG5hc3luYyBmdW5jdGlvbiByZWFkRmlsZUlmRXhpc3RzKGZpbGVuYW1lOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBmcy5yZWFkRmlsZShmaWxlbmFtZSwgeyBlbmNvZGluZzogJ3V0Zi04JyB9KTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgaWYgKGUuY29kZSA9PT0gJ0VOT0VOVCcpIHsgcmV0dXJuIHVuZGVmaW5lZDsgfVxuICAgIHRocm93IGU7XG4gIH1cbn1cblxubGV0IHRtcENvdW50ZXIgPSAwO1xuYXN5bmMgZnVuY3Rpb24gd3JpdGVGaWxlQXRvbWljKGZpbGVuYW1lOiBzdHJpbmcsIGNvbnRlbnRzOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgZnMubWtkaXIocGF0aC5kaXJuYW1lKGZpbGVuYW1lKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gIGNvbnN0IHRtcEZpbGUgPSBgJHtmaWxlbmFtZX0uJHtwcm9jZXNzLnBpZH1fJHsrK3RtcENvdW50ZXJ9YDtcbiAgYXdhaXQgZnMud3JpdGVGaWxlKHRtcEZpbGUsIGNvbnRlbnRzLCB7IGVuY29kaW5nOiAndXRmLTgnIH0pO1xuICBhd2FpdCBmcy5yZW5hbWUodG1wRmlsZSwgZmlsZW5hbWUpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBkZWxldGVGaWxlKGZpbGVuYW1lOiBzdHJpbmcpIHtcbiAgdHJ5IHtcbiAgICBhd2FpdCBmcy51bmxpbmsoZmlsZW5hbWUpO1xuICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICBpZiAoZS5jb2RlID09PSAnRU5PRU5UJykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aHJvdyBlO1xuICB9XG59XG5cbmZ1bmN0aW9uIHByb2Nlc3NFeGlzdHMocGlkOiBudW1iZXIpIHtcbiAgdHJ5IHtcbiAgICBwcm9jZXNzLmtpbGwocGlkLCAwKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuIl19