@pipeline-builder/pipeline-data 4.1.45 → 4.1.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/reporting/analytics-queries.js +43 -15
- package/lib/database/index.d.ts +2 -0
- package/lib/database/index.js +5 -1
- package/lib/database/postgres-connection.js +8 -1
- package/lib/database/read-connection.d.ts +19 -0
- package/lib/database/read-connection.js +122 -0
- package/lib/database/read-lag.d.ts +31 -0
- package/lib/database/read-lag.js +202 -0
- package/lib/database/tenancy.d.ts +102 -1
- package/lib/database/tenancy.js +101 -3
- package/lib/testing/exports.json +10 -0
- package/package.json +3 -3
|
@@ -378,6 +378,13 @@ export async function closeConnection() {
|
|
|
378
378
|
const connection = Connection.getInstance();
|
|
379
379
|
await connection.close();
|
|
380
380
|
_dbInstance = null; // Reset lazy instance
|
|
381
|
+
// Close the read-replica pool too. A half-closed process keeps server
|
|
382
|
+
// connections open on the standby and its replication slot busy, which on the
|
|
383
|
+
// primary means retained WAL — the failure mode that fills the data volume.
|
|
384
|
+
// Imported lazily so this module does not depend on the read connection at
|
|
385
|
+
// load time (it has no replica on most deploys).
|
|
386
|
+
const { closeReadConnection } = await import('./read-connection.js');
|
|
387
|
+
await closeReadConnection();
|
|
381
388
|
}
|
|
382
389
|
/**
|
|
383
390
|
* Tests the database connection
|
|
@@ -400,4 +407,4 @@ export async function testConnection() {
|
|
|
400
407
|
const connection = Connection.getInstance();
|
|
401
408
|
return connection.testConnection();
|
|
402
409
|
}
|
|
403
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9zdGdyZXMtY29ubmVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhYmFzZS9wb3N0Z3Jlcy1jb25uZWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLFlBQVksRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ25GLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsSUFBSSxFQUFtQixNQUFNLElBQUksQ0FBQztBQUMzQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDN0MsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFOUQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0FBRXhDLHFEQUFxRDtBQUNyRCxNQUFNLFFBQVEsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsQ0FBQztBQUV4RDs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FBQyxRQUFtQztJQUM5RCxJQUFJLFFBQVEsS0FBSyxTQUFTO1FBQUUsT0FBTyxRQUFRLENBQUM7SUFFNUMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLENBQUM7SUFDaEQsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsV0FBVyxFQUFFLENBQUM7SUFFckQsSUFBSSxPQUFnQixDQUFDO0lBQ3JCLElBQUksS0FBSyxLQUFLLE1BQU0sSUFBSSxLQUFLLEtBQUssR0FBRztRQUFFLE9BQU8sR0FBRyxJQUFJLENBQUM7U0FDakQsSUFBSSxLQUFLLEtBQUssT0FBTyxJQUFJLEtBQUss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LFdBQVcsRUFBRSxDQUFDO0lBQzVDLE9BQU8sVUFBVSxDQUFDLGNBQWMsRUFBRSxDQUFDO0FBQ3JDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyLCBlbnZCb29sLCBlbnZJbnQsIGVudlN0ciB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IGRyaXp6bGUgfSBmcm9tICdkcml6emxlLW9ybS9ub2RlLXBvc3RncmVzJztcbmltcG9ydCB7IFBvb2wsIHR5cGUgUG9vbENvbmZpZyB9IGZyb20gJ3BnJztcbmltcG9ydCB7IHNjaGVtYSB9IGZyb20gJy4vZHJpenpsZS1zY2hlbWEuanMnO1xuaW1wb3J0IHsgQ29ubmVjdGlvblJldHJ5U3RyYXRlZ3kgfSBmcm9tICcuL3JldHJ5LXN0cmF0ZWd5LmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdkYXRhYmFzZScpO1xuXG4vKiogRGV0ZWN0IExhbWJkYSBlbnZpcm9ubWVudCBmb3IgcG9vbC1zaXplIHR1bmluZyAqL1xuY29uc3QgaXNMYW1iZGEgPSAhIXByb2Nlc3MuZW52LkFXU19MQU1CREFfRlVOQ1RJT05fTkFNRTtcblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBwZyBUTFMvU1NMIGNvbmZpZyBmcm9tIGFuIGV4cGxpY2l0IG9wdGlvbiBvciB0aGUgZW52aXJvbm1lbnQsXG4gKiBmb2xsb3dpbmcgdGhlIHNhbWUgZW52LXR1bmFibGUgcGF0dGVybiBhcyB0aGUgcG9vbCBzaXppbmcgYWJvdmUuXG4gKlxuICogUHJlY2VkZW5jZTpcbiAqICAgMS4gQW4gZXhwbGljaXQgYG9wdGlvbnMuc3NsYCAoY29uc3RydWN0b3IgYXJnKSBhbHdheXMgd2lucyDigJQgaW5jbHVkaW5nIGFuXG4gKiAgICAgIGV4cGxpY2l0IGBmYWxzZWAgdG8gZm9yY2UgcGxhaW50ZXh0LlxuICogICAyLiBgREJfU1NMYCAoYHRydWVgL2AxYCBvbiwgYGZhbHNlYC9gMGAgb2ZmKSBvciBQb3N0Z3Jlcycgc3RhbmRhcmRcbiAqICAgICAgYFBHU1NMTU9ERWAgKGBkaXNhYmxlYCA9IG9mZiwgYW55IG90aGVyIG1vZGUgPSBvbikuXG4gKiAgIDMuIERlZmF1bHQ6IE9OIGluIHByb2R1Y3Rpb24gKFJEUyBjb25uZWN0aW9ucyBtdXN0IGJlIGVuY3J5cHRlZCBpbiB0cmFuc2l0KSxcbiAqICAgICAgT0ZGIGV2ZXJ5d2hlcmUgZWxzZSBzbyBhIGxvY2FsIFBvc3RncmVzIHdpdGhvdXQgVExTIGtlZXBzIHdvcmtpbmcuXG4gKlxuICogV2hlbiBlbmFibGVkLCBgcmVqZWN0VW5hdXRob3JpemVkYCBmb2xsb3dzIGBEQl9TU0xfUkVKRUNUX1VOQVVUSE9SSVpFRGBcbiAqIChkZWZhdWx0IGBmYWxzZWApOiBBV1MgUkRTIHByZXNlbnRzIGEgY2VydCBzaWduZWQgYnkgdGhlIFJEUyBDQSwgd2hpY2ggaXMgbm90XG4gKiBpbiBOb2RlJ3MgZGVmYXVsdCB0cnVzdCBzdG9yZSB1bmxlc3MgdGhlIENBIGJ1bmRsZSBpcyBtb3VudGVkLCBzbyBjZXJ0aWZpY2F0ZVxuICogVkVSSUZJQ0FUSU9OIGlzIG9wdC1pbiB0byBhdm9pZCBicmVha2luZyBhIHN0b2NrIFJEUyBkZXBsb3kg4oCUIHRoZSBjaGFubmVsIGlzXG4gKiBzdGlsbCBFTkNSWVBURUQuIFNldCBgREJfU1NMX1JFSkVDVF9VTkFVVEhPUklaRUQ9dHJ1ZWAgb25jZSB0aGUgUkRTIENBIGJ1bmRsZVxuICogaXMgd2lyZWQgdG8gZ2V0IGZ1bGwgdmVyaWZpY2F0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U3NsQ29uZmlnKGV4cGxpY2l0PzogQ29ubmVjdGlvbk9wdGlvbnNbJ3NzbCddKTogYm9vbGVhbiB8IHsgcmVqZWN0VW5hdXRob3JpemVkOiBib29sZWFuIH0ge1xuICBpZiAoZXhwbGljaXQgIT09IHVuZGVmaW5lZCkgcmV0dXJuIGV4cGxpY2l0O1xuXG4gIGNvbnN0IGRiU3NsID0gcHJvY2Vzcy5lbnYuREJfU1NMPy50b0xvd2VyQ2FzZSgpO1xuICBjb25zdCBzc2xNb2RlID0gcHJvY2Vzcy5lbnYuUEdTU0xNT0RFPy50b0xvd2VyQ2FzZSgpO1xuXG4gIGxldCBlbmFibGVkOiBib29sZWFuO1xuICBpZiAoZGJTc2wgPT09ICd0cnVlJyB8fCBkYlNzbCA9PT0gJzEnKSBlbmFibGVkID0gdHJ1ZTtcbiAgZWxzZSBpZiAoZGJTc2wgPT09ICdmYWxzZScgfHwgZGJTc2wgPT09ICcwJykgZW5hYmxlZCA9IGZhbHNlO1xuICBlbHNlIGlmIChzc2xNb2RlKSBlbmFibGVkID0gc3NsTW9kZSAhPT0gJ2Rpc2FibGUnO1xuICBlbHNlIGVuYWJsZWQgPSBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ3Byb2R1Y3Rpb24nO1xuXG4gIGlmICghZW5hYmxlZCkgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4geyByZWplY3RVbmF1dGhvcml6ZWQ6IGVudkJvb2woJ0RCX1NTTF9SRUpFQ1RfVU5BVVRIT1JJWkVEJywgZmFsc2UpIH07XG59XG5cbmZ1bmN0aW9uIGdldERhdGFiYXNlQ29uZmlnKCkge1xuICAvLyBMYW1iZGE6IHNtYWxsIHBvb2wgKGVhY2ggaW52b2NhdGlvbiBpcyBzaG9ydC1saXZlZCwgbWFueSBjb25jdXJyZW50IGluc3RhbmNlcylcbiAgLy8gRUNTL2xvbmctcnVubmluZzogbGFyZ2VyIHBvb2wgZm9yIHN1c3RhaW5lZCBjb25jdXJyZW5jeVxuICBjb25zdCBkZWZhdWx0UG9vbFNpemUgPSBpc0xhbWJkYSA/IDIgOiAyMDtcbiAgY29uc3QgZGVmYXVsdElkbGVUaW1lb3V0ID0gaXNMYW1iZGEgPyAxMDAwMCA6IDMwMDAwO1xuXG4gIHJldHVybiB7XG4gICAgaG9zdDogZW52U3RyKCdEQl9IT1NUJywgJ3Bvc3RncmVzJyksXG4gICAgcG9ydDogZW52SW50KCdEQl9QT1JUJywgNTQzMiksXG4gICAgZGF0YWJhc2U6IGVudlN0cignREFUQUJBU0UnLCAncGlwZWxpbmVfYnVpbGRlcicpLFxuICAgIHVzZXI6IGVudlN0cignREJfVVNFUicsICdwb3N0Z3JlcycpLFxuICAgIHBhc3N3b3JkOiBwcm9jZXNzLmVudi5EQl9QQVNTV09SRCB8fCAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdwcm9kdWN0aW9uJyA/ICgoKSA9PiB7IHRocm93IG5ldyBFcnJvcignREJfUEFTU1dPUkQgaXMgcmVxdWlyZWQgaW4gcHJvZHVjdGlvbicpOyB9KSgpIGFzIHN0cmluZyA6ICcnKSxcbiAgICBtYXhQb29sU2l6ZTogZW52SW50KCdEUklaWkxFX01BWF9QT09MX1NJWkUnLCBkZWZhdWx0UG9vbFNpemUpLFxuICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBlbnZJbnQoJ0RSSVpaTEVfSURMRV9USU1FT1VUX01JTExJUycsIGRlZmF1bHRJZGxlVGltZW91dCksXG4gICAgY29ubmVjdGlvblRpbWVvdXRNaWxsaXM6IGVudkludCgnRFJJWlpMRV9DT05ORUNUSU9OX1RJTUVPVVRfTUlMTElTJywgNTAwMCksXG4gIH07XG59XG5cbi8qKlxuICogRGF0YWJhc2UgY29ubmVjdGlvbiBzdGF0aXN0aWNzIGZvciBtb25pdG9yaW5nXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29ubmVjdGlvblN0YXRzIHtcbiAgdG90YWxDb3VudDogbnVtYmVyO1xuICBpZGxlQ291bnQ6IG51bWJlcjtcbiAgd2FpdGluZ0NvdW50OiBudW1iZXI7XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgY29uZmlndXJpbmcgdGhlIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb25uZWN0aW9uT3B0aW9ucyB7XG4gIC8qKiBXaGV0aGVyIHRvIGVuYWJsZSBjb25uZWN0aW9uIGxvZ2dpbmcgKi9cbiAgZW5hYmxlTG9nZ2luZz86IGJvb2xlYW47XG5cbiAgLyoqIFdoZXRoZXIgdG8gYXV0b21hdGljYWxseSByZXRyeSBmYWlsZWQgY29ubmVjdGlvbnMgKi9cbiAgZW5hYmxlQXV0b1JldHJ5PzogYm9vbGVhbjtcblxuICAvKiogTWF4aW11bSBudW1iZXIgb2YgY29ubmVjdGlvbiByZXRyeSBhdHRlbXB0cyAqL1xuICBtYXhSZXRyaWVzPzogbnVtYmVyO1xuXG4gIC8qKiBEZWxheSBiZXR3ZWVuIHJldHJ5IGF0dGVtcHRzIGluIG1pbGxpc2Vjb25kcyAqL1xuICByZXRyeURlbGF5PzogbnVtYmVyO1xuXG4gIC8qKiBTU0wgY29uZmlndXJhdGlvbiAqL1xuICBzc2w/OiBib29sZWFuIHwgeyByZWplY3RVbmF1dGhvcml6ZWQ6IGJvb2xlYW4gfTtcbn1cblxuLyoqXG4gKiBTaW5nbGV0b24gZGF0YWJhc2UgY29ubmVjdGlvbiBjbGFzcy5cbiAqIE1hbmFnZXMgUG9zdGdyZVNRTCBjb25uZWN0aW9uIHBvb2xpbmcgYW5kIERyaXp6bGUgT1JNIGluc3RhbmNlLlxuICpcbiAqIEZlYXR1cmVzOlxuICogLSBTaW5nbGV0b24gcGF0dGVybiBmb3Igc2luZ2xlIGNvbm5lY3Rpb24gcG9vbFxuICogLSBBdXRvbWF0aWMgY29ubmVjdGlvbiByZXRyeSB3aXRoIGJhY2tvZmZcbiAqIC0gQ29ubmVjdGlvbiBoZWFsdGggbW9uaXRvcmluZ1xuICogLSBHcmFjZWZ1bCBzaHV0ZG93biBoYW5kbGluZ1xuICogLSBDb21wcmVoZW5zaXZlIGVycm9yIGhhbmRsaW5nXG4gKiAtIENvbm5lY3Rpb24gc3RhdGlzdGljcyB0cmFja2luZ1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBDb25uZWN0aW9uIH0gZnJvbSAnLi9jb25uZWN0aW9uJztcbiAqXG4gKiBjb25zdCBjb25uZWN0aW9uID0gQ29ubmVjdGlvbi5nZXRJbnN0YW5jZSgpO1xuICogY29uc3QgcGx1Z2lucyA9IGF3YWl0IGNvbm5lY3Rpb24uZGIuc2VsZWN0KCkuZnJvbShzY2hlbWEucGx1Z2luKTtcbiAqXG4gKiAvLyBEdXJpbmcgc2h1dGRvd25cbiAqIGF3YWl0IGNvbm5lY3Rpb24uY2xvc2UoKTtcbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgQ29ubmVjdGlvbiB7XG4gIHByaXZhdGUgc3RhdGljIGluc3RhbmNlOiBDb25uZWN0aW9uIHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqXG4gICAqIERyaXp6bGUgT1JNIGRhdGFiYXNlIGluc3RhbmNlIHdpdGggc2NoZW1hXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZGI6IFJldHVyblR5cGU8dHlwZW9mIGRyaXp6bGU+O1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgcG9vbDogUG9vbDtcbiAgcHJpdmF0ZSByZWFkb25seSBvcHRpb25zOiBSZXF1aXJlZDxDb25uZWN0aW9uT3B0aW9ucz47XG4gIHByaXZhdGUgcmVhZG9ubHkgcmV0cnlTdHJhdGVneTogQ29ubmVjdGlvblJldHJ5U3RyYXRlZ3k7XG4gIHByaXZhdGUgaXNTaHV0dGluZ0Rvd24gPSBmYWxzZTtcblxuICAvKipcbiAgICogUHJpdmF0ZSBjb25zdHJ1Y3RvciB0byBlbmZvcmNlIHNpbmdsZXRvbiBwYXR0ZXJuLlxuICAgKiBJbml0aWFsaXplcyBQb3N0Z3JlU1FMIGNvbm5lY3Rpb24gcG9vbCBhbmQgRHJpenpsZSBPUk0gaW5zdGFuY2UuXG4gICAqXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gT3B0aW9uYWwgY29uZmlndXJhdGlvbiBmb3IgdGhlIGNvbm5lY3Rpb25cbiAgICogQHRocm93cyB7RXJyb3J9IElmIGRhdGFiYXNlIGluaXRpYWxpemF0aW9uIGZhaWxzIGFmdGVyIGFsbCByZXRyaWVzXG4gICAqL1xuICBwcml2YXRlIGNvbnN0cnVjdG9yKG9wdGlvbnM6IENvbm5lY3Rpb25PcHRpb25zID0ge30pIHtcbiAgICB0aGlzLm9wdGlvbnMgPSB7XG4gICAgICBlbmFibGVMb2dnaW5nOiBvcHRpb25zLmVuYWJsZUxvZ2dpbmcgPz8gdHJ1ZSxcbiAgICAgIGVuYWJsZUF1dG9SZXRyeTogb3B0aW9ucy5lbmFibGVBdXRvUmV0cnkgPz8gdHJ1ZSxcbiAgICAgIG1heFJldHJpZXM6IG9wdGlvbnMubWF4UmV0cmllcyA/PyBlbnZJbnQoJ0RCX01BWF9SRVRSSUVTJywgMywgeyBtaW46IDAgfSksXG4gICAgICByZXRyeURlbGF5OiBvcHRpb25zLnJldHJ5RGVsYXkgPz8gZW52SW50KCdEQl9SRVRSWV9ERUxBWV9NUycsIDEwMDAsIHsgbWluOiAwIH0pLFxuICAgICAgLy8gRW52LWRyaXZlbiBUTFM6IG9uLWJ5LWRlZmF1bHQgaW4gcHJvZHVjdGlvbiwgZW52LWVuYWJsZWFibGUgZWxzZXdoZXJlLlxuICAgICAgLy8gZ2V0SW5zdGFuY2UoKSBpcyBub3JtYWxseSBjYWxsZWQgd2l0aCBubyBvcHRpb25zLCBzbyB0aGlzIGlzIHRoZSBvbmx5XG4gICAgICAvLyBwbGFjZSBwcm9kdWN0aW9uIFJEUyBjb25uZWN0aW9ucyBwaWNrIHVwIFNTTC5cbiAgICAgIHNzbDogZ2V0U3NsQ29uZmlnKG9wdGlvbnMuc3NsKSxcbiAgICB9O1xuXG4gICAgLy8gSW5pdGlhbGl6ZSByZXRyeSBzdHJhdGVneVxuICAgIHRoaXMucmV0cnlTdHJhdGVneSA9IG5ldyBDb25uZWN0aW9uUmV0cnlTdHJhdGVneSh7XG4gICAgICBtYXhSZXRyaWVzOiB0aGlzLm9wdGlvbnMubWF4UmV0cmllcyxcbiAgICAgIHJldHJ5RGVsYXlNczogdGhpcy5vcHRpb25zLnJldHJ5RGVsYXksXG4gICAgfSk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgY29uZmlnID0gZ2V0RGF0YWJhc2VDb25maWcoKTtcblxuICAgICAgY29uc3QgcG9vbENvbmZpZzogUG9vbENvbmZpZyA9IHtcbiAgICAgICAgaG9zdDogY29uZmlnLmhvc3QsXG4gICAgICAgIHBvcnQ6IGNvbmZpZy5wb3J0LFxuICAgICAgICBkYXRhYmFzZTogY29uZmlnLmRhdGFiYXNlLFxuICAgICAgICB1c2VyOiBjb25maWcudXNlcixcbiAgICAgICAgcGFzc3dvcmQ6IGNvbmZpZy5wYXNzd29yZCxcbiAgICAgICAgbWF4OiBjb25maWcubWF4UG9vbFNpemUsXG4gICAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBjb25maWcuaWRsZVRpbWVvdXRNaWxsaXMsXG4gICAgICAgIGNvbm5lY3Rpb25UaW1lb3V0TWlsbGlzOiBjb25maWcuY29ubmVjdGlvblRpbWVvdXRNaWxsaXMsXG4gICAgICAgIHNzbDogdGhpcy5vcHRpb25zLnNzbCxcbiAgICAgICAgYWxsb3dFeGl0T25JZGxlOiB0cnVlLFxuICAgICAgfTtcblxuICAgICAgdGhpcy5wb29sID0gbmV3IFBvb2wocG9vbENvbmZpZyk7XG4gICAgICB0aGlzLnNldHVwRXZlbnRIYW5kbGVycygpO1xuXG4gICAgICB0aGlzLmRiID0gZHJpenpsZSh0aGlzLnBvb2wsIHsgc2NoZW1hIH0pO1xuXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmVuYWJsZUxvZ2dpbmcpIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oJ0RhdGFiYXNlIGNvbm5lY3Rpb24gaW5pdGlhbGl6ZWQgc3VjY2Vzc2Z1bGx5Jyk7XG4gICAgICAgIHRoaXMubG9nQ29ubmVjdGlvbkNvbmZpZyhwb29sQ29uZmlnKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gaW5pdGlhbGl6ZSBkYXRhYmFzZSBjb25uZWN0aW9uOicsIGVycm9yKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRGF0YWJhc2UgaW5pdGlhbGl6YXRpb24gZmFpbGVkJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIHNpbmdsZXRvbiBpbnN0YW5jZSBvZiB0aGUgQ29ubmVjdGlvbiBjbGFzcy5cbiAgICogQ3JlYXRlcyBhIG5ldyBpbnN0YW5jZSBpZiBvbmUgZG9lc24ndCBleGlzdC5cbiAgICpcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcHRpb25hbCBjb25maWd1cmF0aW9uIChvbmx5IHVzZWQgb24gZmlyc3QgY2FsbClcbiAgICogQHJldHVybnMgVGhlIHNpbmdsZXRvbiBDb25uZWN0aW9uIGluc3RhbmNlXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGdldEluc3RhbmNlKG9wdGlvbnM/OiBDb25uZWN0aW9uT3B0aW9ucyk6IENvbm5lY3Rpb24ge1xuICAgIGlmICghQ29ubmVjdGlvbi5pbnN0YW5jZSkge1xuICAgICAgQ29ubmVjdGlvbi5pbnN0YW5jZSA9IG5ldyBDb25uZWN0aW9uKG9wdGlvbnMpO1xuICAgIH1cbiAgICByZXR1cm4gQ29ubmVjdGlvbi5pbnN0YW5jZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNldHMgdGhlIHNpbmdsZXRvbiBpbnN0YW5jZS5cbiAgICogVXNlZnVsIGZvciB0ZXN0aW5nIG9yIHJlY29uZmlndXJpbmcgdGhlIGNvbm5lY3Rpb24uXG4gICAqXG4gICAqIEBwYXJhbSBjbG9zZUV4aXN0aW5nIC0gV2hldGhlciB0byBjbG9zZSBleGlzdGluZyBjb25uZWN0aW9uIGJlZm9yZSByZXNldFxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBhc3luYyByZXNldChjbG9zZUV4aXN0aW5nOiBib29sZWFuID0gdHJ1ZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmIChDb25uZWN0aW9uLmluc3RhbmNlICYmIGNsb3NlRXhpc3RpbmcpIHtcbiAgICAgIGF3YWl0IENvbm5lY3Rpb24uaW5zdGFuY2UuY2xvc2UoKTtcbiAgICB9XG4gICAgQ29ubmVjdGlvbi5pbnN0YW5jZSA9IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogVGVzdHMgdGhlIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiAgICpcbiAgICogQHJldHVybnMgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgaWYgY29ubmVjdGlvbiBpcyBoZWFsdGh5XG4gICAqL1xuICBwdWJsaWMgYXN5bmMgdGVzdENvbm5lY3Rpb24oKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGNsaWVudCA9IGF3YWl0IHRoaXMucG9vbC5jb25uZWN0KCk7XG4gICAgICAvLyBSZWxlYXNlIGV2ZW4gaWYgdGhlIHByb2JlIHF1ZXJ5IHRocm93cyDigJQgb3RoZXJ3aXNlIGEgZmxha3kgREIgKHRoZSBleGFjdFxuICAgICAgLy8gY2FzZSB0aGlzIGNoZWNrIGV4aXN0cyBmb3IpIGxlYWtzIGEgcG9vbGVkIGNsaWVudCBlYWNoIGZhaWx1cmUgYW5kIGNhblxuICAgICAgLy8gZXhoYXVzdCB0aGUgcG9vbCBvbiB0aGUgcmV0cnkgcGF0aC5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGNsaWVudC5xdWVyeSgnU0VMRUNUIDEnKTtcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5lbmFibGVMb2dnaW5nKSB7XG4gICAgICAgICAgbG9nZ2VyLmluZm8oJ0RhdGFiYXNlIGNvbm5lY3Rpb24gdGVzdCBzdWNjZXNzZnVsJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdC5yb3dzLmxlbmd0aCA+IDA7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBjbGllbnQucmVsZWFzZSgpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0RhdGFiYXNlIGNvbm5lY3Rpb24gdGVzdCBmYWlsZWQ6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGNvbm5lY3Rpb24gcG9vbCBzdGF0aXN0aWNzXG4gICAqXG4gICAqIEByZXR1cm5zIEN1cnJlbnQgY29ubmVjdGlvbiBwb29sIHN0YXRpc3RpY3NcbiAgICovXG4gIHB1YmxpYyBnZXRTdGF0cygpOiBDb25uZWN0aW9uU3RhdHMge1xuICAgIHJldHVybiB7XG4gICAgICB0b3RhbENvdW50OiB0aGlzLnBvb2wudG90YWxDb3VudCxcbiAgICAgIGlkbGVDb3VudDogdGhpcy5wb29sLmlkbGVDb3VudCxcbiAgICAgIHdhaXRpbmdDb3VudDogdGhpcy5wb29sLndhaXRpbmdDb3VudCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENsb3NlcyB0aGUgZGF0YWJhc2UgY29ubmVjdGlvbiBwb29sIGdyYWNlZnVsbHkuXG4gICAqIFNob3VsZCBiZSBjYWxsZWQgZHVyaW5nIGFwcGxpY2F0aW9uIHNodXRkb3duLlxuICAgKlxuICAgKiBAcGFyYW0gdGltZW91dCAtIE1heGltdW0gdGltZSB0byB3YWl0IGZvciBjb25uZWN0aW9ucyB0byBjbG9zZSAobXMpXG4gICAqIEByZXR1cm5zIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHBvb2wgaXMgY2xvc2VkXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgY2xvc2UodGltZW91dDogbnVtYmVyID0gZW52SW50KCdEQl9DTE9TRV9USU1FT1VUX01TJywgNTAwMCkpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5pc1NodXR0aW5nRG93bikge1xuICAgICAgbG9nZ2VyLndhcm4oJ0Nvbm5lY3Rpb24gaXMgYWxyZWFkeSBzaHV0dGluZyBkb3duJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5pc1NodXR0aW5nRG93biA9IHRydWU7XG5cbiAgICB0cnkge1xuICAgICAgaWYgKHRoaXMub3B0aW9ucy5lbmFibGVMb2dnaW5nKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKCdDbG9zaW5nIGRhdGFiYXNlIGNvbm5lY3Rpb24gcG9vbC4uLicpO1xuICAgICAgICBjb25zdCBzdGF0cyA9IHRoaXMuZ2V0U3RhdHMoKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oYFBvb2wgc3RhdHMgLSBUb3RhbDogJHtzdGF0cy50b3RhbENvdW50fSwgSWRsZTogJHtzdGF0cy5pZGxlQ291bnR9LCBXYWl0aW5nOiAke3N0YXRzLndhaXRpbmdDb3VudH1gKTtcbiAgICAgIH1cblxuICAgICAgLy8gU2V0IGEgdGltZW91dCBmb3IgZ3JhY2VmdWwgc2h1dGRvd25cbiAgICAgIGNvbnN0IGNsb3NlUHJvbWlzZSA9IHRoaXMucG9vbC5lbmQoKTtcbiAgICAgIGNvbnN0IHRpbWVvdXRQcm9taXNlID0gbmV3IFByb21pc2UoKF8sIHJlamVjdCkgPT5cbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiByZWplY3QobmV3IEVycm9yKCdDb25uZWN0aW9uIGNsb3NlIHRpbWVvdXQnKSksIHRpbWVvdXQpLFxuICAgICAgKTtcblxuICAgICAgYXdhaXQgUHJvbWlzZS5yYWNlKFtjbG9zZVByb21pc2UsIHRpbWVvdXRQcm9taXNlXSk7XG5cbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuZW5hYmxlTG9nZ2luZykge1xuICAgICAgICBsb2dnZXIuaW5mbygnRGF0YWJhc2UgY29ubmVjdGlvbiBjbG9zZWQgc3VjY2Vzc2Z1bGx5Jyk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcignRXJyb3IgY2xvc2luZyBkYXRhYmFzZSBjb25uZWN0aW9uOicsIGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLmlzU2h1dHRpbmdEb3duID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgY29ubmVjdGlvbiBpcyBzaHV0dGluZyBkb3duXG4gICAqXG4gICAqIEByZXR1cm5zIHRydWUgaWYgY29ubmVjdGlvbiBpcyBpbiBzaHV0ZG93biBzdGF0ZVxuICAgKi9cbiAgcHVibGljIGlzQ2xvc2luZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc1NodXR0aW5nRG93bjtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHVwIGV2ZW50IGhhbmRsZXJzIGZvciB0aGUgY29ubmVjdGlvbiBwb29sXG4gICAqL1xuICBwcml2YXRlIHNldHVwRXZlbnRIYW5kbGVycygpOiB2b2lkIHtcbiAgICB0aGlzLnBvb2wub24oJ2Vycm9yJywgKGVycikgPT4ge1xuICAgICAgbG9nZ2VyLmVycm9yKCdVbmV4cGVjdGVkIGVycm9yIG9uIGlkbGUgY2xpZW50OicsIGVycik7XG5cbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuZW5hYmxlQXV0b1JldHJ5ICYmIHRoaXMucmV0cnlTdHJhdGVneS5nZXRBdHRlbXB0cygpIDwgdGhpcy5vcHRpb25zLm1heFJldHJpZXMpIHtcbiAgICAgICAgdm9pZCB0aGlzLnJldHJ5U3RyYXRlZ3kuaGFuZGxlQ29ubmVjdGlvbkVycm9yKGVyciwgKCkgPT4gdGhpcy50ZXN0Q29ubmVjdGlvbigpKS5jYXRjaCgocmV0cnlFcnIpID0+IHtcbiAgICAgICAgICBsb2dnZXIuZXJyb3IoJ0Nvbm5lY3Rpb24gcmV0cnkgZXJyb3I6JywgcmV0cnlFcnIpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMucG9vbC5vbignY29ubmVjdCcsICgpID0+IHtcbiAgICAgIHRoaXMucmV0cnlTdHJhdGVneS5yZXNldCgpOyAvLyBSZXNldCBvbiBzdWNjZXNzZnVsIGNvbm5lY3Rpb25cblxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5lbmFibGVMb2dnaW5nKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnTmV3IGRhdGFiYXNlIGNvbm5lY3Rpb24gZXN0YWJsaXNoZWQnKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRoaXMucG9vbC5vbigncmVtb3ZlJywgKCkgPT4ge1xuICAgICAgaWYgKHRoaXMub3B0aW9ucy5lbmFibGVMb2dnaW5nKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnQ2xpZW50IHJlbW92ZWQgZnJvbSBwb29sJyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogTG9ncyBjb25uZWN0aW9uIGNvbmZpZ3VyYXRpb24gKHNhbml0aXplZClcbiAgICovXG4gIHByaXZhdGUgbG9nQ29ubmVjdGlvbkNvbmZpZyhjb25maWc6IFBvb2xDb25maWcpOiB2b2lkIHtcbiAgICBsb2dnZXIuaW5mbygnRGF0YWJhc2UgQ29uZmlndXJhdGlvbjonLCB7XG4gICAgICBob3N0OiBgJHtjb25maWcuaG9zdH06JHtjb25maWcucG9ydH1gLFxuICAgICAgZGF0YWJhc2U6IGNvbmZpZy5kYXRhYmFzZSxcbiAgICAgIHVzZXI6IGNvbmZpZy51c2VyLFxuICAgICAgbWF4UG9vbFNpemU6IGNvbmZpZy5tYXgsXG4gICAgICBpZGxlVGltZW91dE1zOiBjb25maWcuaWRsZVRpbWVvdXRNaWxsaXMsXG4gICAgICBjb25uZWN0aW9uVGltZW91dE1zOiBjb25maWcuY29ubmVjdGlvblRpbWVvdXRNaWxsaXMsXG4gICAgICBzc2w6IGNvbmZpZy5zc2wgPyAnZW5hYmxlZCcgOiAnZGlzYWJsZWQnLFxuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogU2luZ2xldG9uIGRhdGFiYXNlIGluc3RhbmNlIGZvciB1c2UgdGhyb3VnaG91dCB0aGUgYXBwbGljYXRpb24uXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IGRiIH0gZnJvbSAnLi9jb25uZWN0aW9uJztcbiAqXG4gKiAvLyBTZWxlY3QgcXVlcmllc1xuICogY29uc3QgcGx1Z2lucyA9IGF3YWl0IGRiLnNlbGVjdCgpLmZyb20oc2NoZW1hLnBsdWdpbik7XG4gKlxuICogLy8gSW5zZXJ0IHF1ZXJpZXNcbiAqIGF3YWl0IGRiLmluc2VydChzY2hlbWEucGx1Z2luKS52YWx1ZXMoeyBuYW1lOiAnbXktcGx1Z2luJyB9KTtcbiAqXG4gKiAvLyBUcmFuc2FjdGlvbnNcbiAqIGF3YWl0IGRiLnRyYW5zYWN0aW9uKGFzeW5jICh0eCkgPT4ge1xuICogICBhd2FpdCB0eC5pbnNlcnQoc2NoZW1hLnBsdWdpbikudmFsdWVzKHsgLi4uIH0pO1xuICogICBhd2FpdCB0eC51cGRhdGUoc2NoZW1hLnBsdWdpbikuc2V0KHsgLi4uIH0pO1xuICogfSk7XG4gKiBgYGBcbiAqL1xuXG4vLyBMYXp5IGluaXRpYWxpemF0aW9uIHRvIGF2b2lkIHJhY2UgY29uZGl0aW9uIG9uIG1vZHVsZSBsb2FkXG5sZXQgX2RiSW5zdGFuY2U6IFJldHVyblR5cGU8dHlwZW9mIGRyaXp6bGU+IHwgbnVsbCA9IG51bGw7XG5cbi8qKlxuICogR2V0IHRoZSBkYXRhYmFzZSBpbnN0YW5jZSB3aXRoIGxhenkgaW5pdGlhbGl6YXRpb25cbiAqIFRoaXMgYXZvaWRzIHRoZSByYWNlIGNvbmRpdGlvbiB3aGVyZSB0aGUgbW9kdWxlIGlzIGxvYWRlZCBiZWZvcmUgZW52aXJvbm1lbnQgaXMgY29uZmlndXJlZFxuICovXG5mdW5jdGlvbiBnZXREYkluc3RhbmNlKCk6IFJldHVyblR5cGU8dHlwZW9mIGRyaXp6bGU+IHtcbiAgaWYgKCFfZGJJbnN0YW5jZSkge1xuICAgIF9kYkluc3RhbmNlID0gQ29ubmVjdGlvbi5nZXRJbnN0YW5jZSgpLmRiO1xuICB9XG4gIHJldHVybiBfZGJJbnN0YW5jZTtcbn1cblxuLyoqXG4gKiBQcm94eS1iYXNlZCBsYXp5IGRhdGFiYXNlIGluc3RhbmNlXG4gKiBUaGUgYWN0dWFsIGNvbm5lY3Rpb24gaXMgb25seSBjcmVhdGVkIHdoZW4gZmlyc3QgYWNjZXNzZWRcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgZGIgfSBmcm9tICcuL2Nvbm5lY3Rpb24nO1xuICpcbiAqIC8vIENvbm5lY3Rpb24gaXMgY3JlYXRlZCBoZXJlIG9uIGZpcnN0IHVzZSwgbm90IG9uIGltcG9ydFxuICogY29uc3QgcGx1Z2lucyA9IGF3YWl0IGRiLnNlbGVjdCgpLmZyb20oc2NoZW1hLnBsdWdpbik7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNvbnN0IGRiID0gbmV3IFByb3h5KHt9IGFzIFJldHVyblR5cGU8dHlwZW9mIGRyaXp6bGU+LCB7XG4gIGdldChfLCBwcm9wOiBzdHJpbmcgfCBzeW1ib2wpIHtcbiAgICBjb25zdCBpbnN0YW5jZSA9IGdldERiSW5zdGFuY2UoKTtcbiAgICBjb25zdCB2YWx1ZSA9IGluc3RhbmNlW3Byb3AgYXMga2V5b2YgdHlwZW9mIGluc3RhbmNlXTtcbiAgICAvLyBCaW5kIG1ldGhvZHMgdG8gdGhlIGluc3RhbmNlIHRvIHByZXNlcnZlICd0aGlzJyBjb250ZXh0XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgcmV0dXJuIHZhbHVlLmJpbmQoaW5zdGFuY2UpO1xuICAgIH1cbiAgICByZXR1cm4gdmFsdWU7XG4gIH0sXG59KTtcblxuLyoqXG4gKiBHZXRzIHRoZSBDb25uZWN0aW9uIGluc3RhbmNlIGZvciBhZHZhbmNlZCBvcGVyYXRpb25zXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IGdldENvbm5lY3Rpb24gfSBmcm9tICcuL2Nvbm5lY3Rpb24nO1xuICpcbiAqIGNvbnN0IGNvbm5lY3Rpb24gPSBnZXRDb25uZWN0aW9uKCk7XG4gKiBjb25zdCBzdGF0cyA9IGNvbm5lY3Rpb24uZ2V0U3RhdHMoKTtcbiAqIGNvbnNvbGUubG9nKGBBY3RpdmUgY29ubmVjdGlvbnM6ICR7c3RhdHMudG90YWxDb3VudH1gKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q29ubmVjdGlvbigpOiBDb25uZWN0aW9uIHtcbiAgcmV0dXJuIENvbm5lY3Rpb24uZ2V0SW5zdGFuY2UoKTtcbn1cblxuLyoqXG4gKiBDbG9zZXMgdGhlIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiAqIFNob3VsZCBiZSBjYWxsZWQgZHVyaW5nIGFwcGxpY2F0aW9uIHNodXRkb3duXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IGNsb3NlQ29ubmVjdGlvbiB9IGZyb20gJy4vY29ubmVjdGlvbic7XG4gKlxuICogcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jICgpID0+IHtcbiAqICAgYXdhaXQgY2xvc2VDb25uZWN0aW9uKCk7XG4gKiAgIHByb2Nlc3MuZXhpdCgwKTtcbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZUNvbm5lY3Rpb24oKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGNvbm5lY3Rpb24gPSBDb25uZWN0aW9uLmdldEluc3RhbmNlKCk7XG4gIGF3YWl0IGNvbm5lY3Rpb24uY2xvc2UoKTtcbiAgX2RiSW5zdGFuY2UgPSBudWxsOyAvLyBSZXNldCBsYXp5IGluc3RhbmNlXG59XG5cbi8qKlxuICogVGVzdHMgdGhlIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiAqXG4gKiBAcmV0dXJucyBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiBjb25uZWN0aW9uIGlzIGhlYWx0aHlcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgdGVzdENvbm5lY3Rpb24gfSBmcm9tICcuL2Nvbm5lY3Rpb24nO1xuICpcbiAqIGlmIChhd2FpdCB0ZXN0Q29ubmVjdGlvbigpKSB7XG4gKiAgIGNvbnNvbGUubG9nKCdEYXRhYmFzZSBpcyByZWFkeScpO1xuICogfSBlbHNlIHtcbiAqICAgY29uc29sZS5lcnJvcignRGF0YWJhc2UgY29ubmVjdGlvbiBmYWlsZWQnKTtcbiAqICAgcHJvY2Vzcy5leGl0KDEpO1xuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB0ZXN0Q29ubmVjdGlvbigpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgY29uc3QgY29ubmVjdGlvbiA9IENvbm5lY3Rpb24uZ2V0SW5zdGFuY2UoKTtcbiAgcmV0dXJuIGNvbm5lY3Rpb24udGVzdENvbm5lY3Rpb24oKTtcbn1cbiJdfQ==
|
|
410
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9zdGdyZXMtY29ubmVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhYmFzZS9wb3N0Z3Jlcy1jb25uZWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLFlBQVksRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ25GLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsSUFBSSxFQUFtQixNQUFNLElBQUksQ0FBQztBQUMzQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDN0MsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFOUQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0FBRXhDLHFEQUFxRDtBQUNyRCxNQUFNLFFBQVEsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsQ0FBQztBQUV4RDs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FBQyxRQUFtQztJQUM5RCxJQUFJLFFBQVEsS0FBSyxTQUFTO1FBQUUsT0FBTyxRQUFRLENBQUM7SUFFNUMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLENBQUM7SUFDaEQsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsV0FBVyxFQUFFLENBQUM7SUFFckQsSUFBSSxPQUFnQixDQUFDO0lBQ3JCLElBQUksS0FBSyxLQUFLLE1BQU0sSUFBSSxLQUFLLEtBQUssR0FBRztRQUFFLE9BQU8sR0FBRyxJQUFJLENBQUM7U0FDakQsSUFBSSxLQUFLLEtBQUssT0FBTyxJQUFJLEtBQUss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LE1BQU0sTUFBTSxDQUFDLHNCQUFzQixDQUFDLENBQUM7SUFDckUsTUFBTSxtQkFBbUIsRUFBRSxDQUFDO0FBQzlCLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsY0FBYztJQUNsQyxNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDNUMsT0FBTyxVQUFVLENBQUMsY0FBYyxFQUFFLENBQUM7QUFDckMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIsIGVudkJvb2wsIGVudkludCwgZW52U3RyIH0gZnJvbSAnQHBpcGVsaW5lLWJ1aWxkZXIvYXBpLWNvcmUnO1xuaW1wb3J0IHsgZHJpenpsZSB9IGZyb20gJ2RyaXp6bGUtb3JtL25vZGUtcG9zdGdyZXMnO1xuaW1wb3J0IHsgUG9vbCwgdHlwZSBQb29sQ29uZmlnIH0gZnJvbSAncGcnO1xuaW1wb3J0IHsgc2NoZW1hIH0gZnJvbSAnLi9kcml6emxlLXNjaGVtYS5qcyc7XG5pbXBvcnQgeyBDb25uZWN0aW9uUmV0cnlTdHJhdGVneSB9IGZyb20gJy4vcmV0cnktc3RyYXRlZ3kuanMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2RhdGFiYXNlJyk7XG5cbi8qKiBEZXRlY3QgTGFtYmRhIGVudmlyb25tZW50IGZvciBwb29sLXNpemUgdHVuaW5nICovXG5jb25zdCBpc0xhbWJkYSA9ICEhcHJvY2Vzcy5lbnYuQVdTX0xBTUJEQV9GVU5DVElPTl9OQU1FO1xuXG4vKipcbiAqIFJlc29sdmUgdGhlIHBnIFRMUy9TU0wgY29uZmlnIGZyb20gYW4gZXhwbGljaXQgb3B0aW9uIG9yIHRoZSBlbnZpcm9ubWVudCxcbiAqIGZvbGxvd2luZyB0aGUgc2FtZSBlbnYtdHVuYWJsZSBwYXR0ZXJuIGFzIHRoZSBwb29sIHNpemluZyBhYm92ZS5cbiAqXG4gKiBQcmVjZWRlbmNlOlxuICogICAxLiBBbiBleHBsaWNpdCBgb3B0aW9ucy5zc2xgIChjb25zdHJ1Y3RvciBhcmcpIGFsd2F5cyB3aW5zIOKAlCBpbmNsdWRpbmcgYW5cbiAqICAgICAgZXhwbGljaXQgYGZhbHNlYCB0byBmb3JjZSBwbGFpbnRleHQuXG4gKiAgIDIuIGBEQl9TU0xgIChgdHJ1ZWAvYDFgIG9uLCBgZmFsc2VgL2AwYCBvZmYpIG9yIFBvc3RncmVzJyBzdGFuZGFyZFxuICogICAgICBgUEdTU0xNT0RFYCAoYGRpc2FibGVgID0gb2ZmLCBhbnkgb3RoZXIgbW9kZSA9IG9uKS5cbiAqICAgMy4gRGVmYXVsdDogT04gaW4gcHJvZHVjdGlvbiAoUkRTIGNvbm5lY3Rpb25zIG11c3QgYmUgZW5jcnlwdGVkIGluIHRyYW5zaXQpLFxuICogICAgICBPRkYgZXZlcnl3aGVyZSBlbHNlIHNvIGEgbG9jYWwgUG9zdGdyZXMgd2l0aG91dCBUTFMga2VlcHMgd29ya2luZy5cbiAqXG4gKiBXaGVuIGVuYWJsZWQsIGByZWplY3RVbmF1dGhvcml6ZWRgIGZvbGxvd3MgYERCX1NTTF9SRUpFQ1RfVU5BVVRIT1JJWkVEYFxuICogKGRlZmF1bHQgYGZhbHNlYCk6IEFXUyBSRFMgcHJlc2VudHMgYSBjZXJ0IHNpZ25lZCBieSB0aGUgUkRTIENBLCB3aGljaCBpcyBub3RcbiAqIGluIE5vZGUncyBkZWZhdWx0IHRydXN0IHN0b3JlIHVubGVzcyB0aGUgQ0EgYnVuZGxlIGlzIG1vdW50ZWQsIHNvIGNlcnRpZmljYXRlXG4gKiBWRVJJRklDQVRJT04gaXMgb3B0LWluIHRvIGF2b2lkIGJyZWFraW5nIGEgc3RvY2sgUkRTIGRlcGxveSDigJQgdGhlIGNoYW5uZWwgaXNcbiAqIHN0aWxsIEVOQ1JZUFRFRC4gU2V0IGBEQl9TU0xfUkVKRUNUX1VOQVVUSE9SSVpFRD10cnVlYCBvbmNlIHRoZSBSRFMgQ0EgYnVuZGxlXG4gKiBpcyB3aXJlZCB0byBnZXQgZnVsbCB2ZXJpZmljYXRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTc2xDb25maWcoZXhwbGljaXQ/OiBDb25uZWN0aW9uT3B0aW9uc1snc3NsJ10pOiBib29sZWFuIHwgeyByZWplY3RVbmF1dGhvcml6ZWQ6IGJvb2xlYW4gfSB7XG4gIGlmIChleHBsaWNpdCAhPT0gdW5kZWZpbmVkKSByZXR1cm4gZXhwbGljaXQ7XG5cbiAgY29uc3QgZGJTc2wgPSBwcm9jZXNzLmVudi5EQl9TU0w/LnRvTG93ZXJDYXNlKCk7XG4gIGNvbnN0IHNzbE1vZGUgPSBwcm9jZXNzLmVudi5QR1NTTE1PREU/LnRvTG93ZXJDYXNlKCk7XG5cbiAgbGV0IGVuYWJsZWQ6IGJvb2xlYW47XG4gIGlmIChkYlNzbCA9PT0gJ3RydWUnIHx8IGRiU3NsID09PSAnMScpIGVuYWJsZWQgPSB0cnVlO1xuICBlbHNlIGlmIChkYlNzbCA9PT0gJ2ZhbHNlJyB8fCBkYlNzbCA9PT0gJzAnKSBlbmFibGVkID0gZmFsc2U7XG4gIGVsc2UgaWYgKHNzbE1vZGUpIGVuYWJsZWQgPSBzc2xNb2RlICE9PSAnZGlzYWJsZSc7XG4gIGVsc2UgZW5hYmxlZCA9IHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSAncHJvZHVjdGlvbic7XG5cbiAgaWYgKCFlbmFibGVkKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiB7IHJlamVjdFVuYXV0aG9yaXplZDogZW52Qm9vbCgnREJfU1NMX1JFSkVDVF9VTkFVVEhPUklaRUQnLCBmYWxzZSkgfTtcbn1cblxuZnVuY3Rpb24gZ2V0RGF0YWJhc2VDb25maWcoKSB7XG4gIC8vIExhbWJkYTogc21hbGwgcG9vbCAoZWFjaCBpbnZvY2F0aW9uIGlzIHNob3J0LWxpdmVkLCBtYW55IGNvbmN1cnJlbnQgaW5zdGFuY2VzKVxuICAvLyBFQ1MvbG9uZy1ydW5uaW5nOiBsYXJnZXIgcG9vbCBmb3Igc3VzdGFpbmVkIGNvbmN1cnJlbmN5XG4gIGNvbnN0IGRlZmF1bHRQb29sU2l6ZSA9IGlzTGFtYmRhID8gMiA6IDIwO1xuICBjb25zdCBkZWZhdWx0SWRsZVRpbWVvdXQgPSBpc0xhbWJkYSA/IDEwMDAwIDogMzAwMDA7XG5cbiAgcmV0dXJuIHtcbiAgICBob3N0OiBlbnZTdHIoJ0RCX0hPU1QnLCAncG9zdGdyZXMnKSxcbiAgICBwb3J0OiBlbnZJbnQoJ0RCX1BPUlQnLCA1NDMyKSxcbiAgICBkYXRhYmFzZTogZW52U3RyKCdEQVRBQkFTRScsICdwaXBlbGluZV9idWlsZGVyJyksXG4gICAgdXNlcjogZW52U3RyKCdEQl9VU0VSJywgJ3Bvc3RncmVzJyksXG4gICAgcGFzc3dvcmQ6IHByb2Nlc3MuZW52LkRCX1BBU1NXT1JEIHx8IChwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ3Byb2R1Y3Rpb24nID8gKCgpID0+IHsgdGhyb3cgbmV3IEVycm9yKCdEQl9QQVNTV09SRCBpcyByZXF1aXJlZCBpbiBwcm9kdWN0aW9uJyk7IH0pKCkgYXMgc3RyaW5nIDogJycpLFxuICAgIG1heFBvb2xTaXplOiBlbnZJbnQoJ0RSSVpaTEVfTUFYX1BPT0xfU0laRScsIGRlZmF1bHRQb29sU2l6ZSksXG4gICAgaWRsZVRpbWVvdXRNaWxsaXM6IGVudkludCgnRFJJWlpMRV9JRExFX1RJTUVPVVRfTUlMTElTJywgZGVmYXVsdElkbGVUaW1lb3V0KSxcbiAgICBjb25uZWN0aW9uVGltZW91dE1pbGxpczogZW52SW50KCdEUklaWkxFX0NPTk5FQ1RJT05fVElNRU9VVF9NSUxMSVMnLCA1MDAwKSxcbiAgfTtcbn1cblxuLyoqXG4gKiBEYXRhYmFzZSBjb25uZWN0aW9uIHN0YXRpc3RpY3MgZm9yIG1vbml0b3JpbmdcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb25uZWN0aW9uU3RhdHMge1xuICB0b3RhbENvdW50OiBudW1iZXI7XG4gIGlkbGVDb3VudDogbnVtYmVyO1xuICB3YWl0aW5nQ291bnQ6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciBjb25maWd1cmluZyB0aGUgZGF0YWJhc2UgY29ubmVjdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbm5lY3Rpb25PcHRpb25zIHtcbiAgLyoqIFdoZXRoZXIgdG8gZW5hYmxlIGNvbm5lY3Rpb24gbG9nZ2luZyAqL1xuICBlbmFibGVMb2dnaW5nPzogYm9vbGVhbjtcblxuICAvKiogV2hldGhlciB0byBhdXRvbWF0aWNhbGx5IHJldHJ5IGZhaWxlZCBjb25uZWN0aW9ucyAqL1xuICBlbmFibGVBdXRvUmV0cnk/OiBib29sZWFuO1xuXG4gIC8qKiBNYXhpbXVtIG51bWJlciBvZiBjb25uZWN0aW9uIHJldHJ5IGF0dGVtcHRzICovXG4gIG1heFJldHJpZXM/OiBudW1iZXI7XG5cbiAgLyoqIERlbGF5IGJldHdlZW4gcmV0cnkgYXR0ZW1wdHMgaW4gbWlsbGlzZWNvbmRzICovXG4gIHJldHJ5RGVsYXk/OiBudW1iZXI7XG5cbiAgLyoqIFNTTCBjb25maWd1cmF0aW9uICovXG4gIHNzbD86IGJvb2xlYW4gfCB7IHJlamVjdFVuYXV0aG9yaXplZDogYm9vbGVhbiB9O1xufVxuXG4vKipcbiAqIFNpbmdsZXRvbiBkYXRhYmFzZSBjb25uZWN0aW9uIGNsYXNzLlxuICogTWFuYWdlcyBQb3N0Z3JlU1FMIGNvbm5lY3Rpb24gcG9vbGluZyBhbmQgRHJpenpsZSBPUk0gaW5zdGFuY2UuXG4gKlxuICogRmVhdHVyZXM6XG4gKiAtIFNpbmdsZXRvbiBwYXR0ZXJuIGZvciBzaW5nbGUgY29ubmVjdGlvbiBwb29sXG4gKiAtIEF1dG9tYXRpYyBjb25uZWN0aW9uIHJldHJ5IHdpdGggYmFja29mZlxuICogLSBDb25uZWN0aW9uIGhlYWx0aCBtb25pdG9yaW5nXG4gKiAtIEdyYWNlZnVsIHNodXRkb3duIGhhbmRsaW5nXG4gKiAtIENvbXByZWhlbnNpdmUgZXJyb3IgaGFuZGxpbmdcbiAqIC0gQ29ubmVjdGlvbiBzdGF0aXN0aWNzIHRyYWNraW5nXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IENvbm5lY3Rpb24gfSBmcm9tICcuL2Nvbm5lY3Rpb24nO1xuICpcbiAqIGNvbnN0IGNvbm5lY3Rpb24gPSBDb25uZWN0aW9uLmdldEluc3RhbmNlKCk7XG4gKiBjb25zdCBwbHVnaW5zID0gYXdhaXQgY29ubmVjdGlvbi5kYi5zZWxlY3QoKS5mcm9tKHNjaGVtYS5wbHVnaW4pO1xuICpcbiAqIC8vIER1cmluZyBzaHV0ZG93blxuICogYXdhaXQgY29ubmVjdGlvbi5jbG9zZSgpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBDb25uZWN0aW9uIHtcbiAgcHJpdmF0ZSBzdGF0aWMgaW5zdGFuY2U6IENvbm5lY3Rpb24gfCBudWxsID0gbnVsbDtcblxuICAvKipcbiAgICogRHJpenpsZSBPUk0gZGF0YWJhc2UgaW5zdGFuY2Ugd2l0aCBzY2hlbWFcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBkYjogUmV0dXJuVHlwZTx0eXBlb2YgZHJpenpsZT47XG5cbiAgcHJpdmF0ZSByZWFkb25seSBwb29sOiBQb29sO1xuICBwcml2YXRlIHJlYWRvbmx5IG9wdGlvbnM6IFJlcXVpcmVkPENvbm5lY3Rpb25PcHRpb25zPjtcbiAgcHJpdmF0ZSByZWFkb25seSByZXRyeVN0cmF0ZWd5OiBDb25uZWN0aW9uUmV0cnlTdHJhdGVneTtcbiAgcHJpdmF0ZSBpc1NodXR0aW5nRG93biA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBQcml2YXRlIGNvbnN0cnVjdG9yIHRvIGVuZm9yY2Ugc2luZ2xldG9uIHBhdHRlcm4uXG4gICAqIEluaXRpYWxpemVzIFBvc3RncmVTUUwgY29ubmVjdGlvbiBwb29sIGFuZCBEcml6emxlIE9STSBpbnN0YW5jZS5cbiAgICpcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcHRpb25hbCBjb25maWd1cmF0aW9uIGZvciB0aGUgY29ubmVjdGlvblxuICAgKiBAdGhyb3dzIHtFcnJvcn0gSWYgZGF0YWJhc2UgaW5pdGlhbGl6YXRpb24gZmFpbHMgYWZ0ZXIgYWxsIHJldHJpZXNcbiAgICovXG4gIHByaXZhdGUgY29uc3RydWN0b3Iob3B0aW9uczogQ29ubmVjdGlvbk9wdGlvbnMgPSB7fSkge1xuICAgIHRoaXMub3B0aW9ucyA9IHtcbiAgICAgIGVuYWJsZUxvZ2dpbmc6IG9wdGlvbnMuZW5hYmxlTG9nZ2luZyA/PyB0cnVlLFxuICAgICAgZW5hYmxlQXV0b1JldHJ5OiBvcHRpb25zLmVuYWJsZUF1dG9SZXRyeSA/PyB0cnVlLFxuICAgICAgbWF4UmV0cmllczogb3B0aW9ucy5tYXhSZXRyaWVzID8/IGVudkludCgnREJfTUFYX1JFVFJJRVMnLCAzLCB7IG1pbjogMCB9KSxcbiAgICAgIHJldHJ5RGVsYXk6IG9wdGlvbnMucmV0cnlEZWxheSA/PyBlbnZJbnQoJ0RCX1JFVFJZX0RFTEFZX01TJywgMTAwMCwgeyBtaW46IDAgfSksXG4gICAgICAvLyBFbnYtZHJpdmVuIFRMUzogb24tYnktZGVmYXVsdCBpbiBwcm9kdWN0aW9uLCBlbnYtZW5hYmxlYWJsZSBlbHNld2hlcmUuXG4gICAgICAvLyBnZXRJbnN0YW5jZSgpIGlzIG5vcm1hbGx5IGNhbGxlZCB3aXRoIG5vIG9wdGlvbnMsIHNvIHRoaXMgaXMgdGhlIG9ubHlcbiAgICAgIC8vIHBsYWNlIHByb2R1Y3Rpb24gUkRTIGNvbm5lY3Rpb25zIHBpY2sgdXAgU1NMLlxuICAgICAgc3NsOiBnZXRTc2xDb25maWcob3B0aW9ucy5zc2wpLFxuICAgIH07XG5cbiAgICAvLyBJbml0aWFsaXplIHJldHJ5IHN0cmF0ZWd5XG4gICAgdGhpcy5yZXRyeVN0cmF0ZWd5ID0gbmV3IENvbm5lY3Rpb25SZXRyeVN0cmF0ZWd5KHtcbiAgICAgIG1heFJldHJpZXM6IHRoaXMub3B0aW9ucy5tYXhSZXRyaWVzLFxuICAgICAgcmV0cnlEZWxheU1zOiB0aGlzLm9wdGlvbnMucmV0cnlEZWxheSxcbiAgICB9KTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb25maWcgPSBnZXREYXRhYmFzZUNvbmZpZygpO1xuXG4gICAgICBjb25zdCBwb29sQ29uZmlnOiBQb29sQ29uZmlnID0ge1xuICAgICAgICBob3N0OiBjb25maWcuaG9zdCxcbiAgICAgICAgcG9ydDogY29uZmlnLnBvcnQsXG4gICAgICAgIGRhdGFiYXNlOiBjb25maWcuZGF0YWJhc2UsXG4gICAgICAgIHVzZXI6IGNvbmZpZy51c2VyLFxuICAgICAgICBwYXNzd29yZDogY29uZmlnLnBhc3N3b3JkLFxuICAgICAgICBtYXg6IGNvbmZpZy5tYXhQb29sU2l6ZSxcbiAgICAgICAgaWRsZVRpbWVvdXRNaWxsaXM6IGNvbmZpZy5pZGxlVGltZW91dE1pbGxpcyxcbiAgICAgICAgY29ubmVjdGlvblRpbWVvdXRNaWxsaXM6IGNvbmZpZy5jb25uZWN0aW9uVGltZW91dE1pbGxpcyxcbiAgICAgICAgc3NsOiB0aGlzLm9wdGlvbnMuc3NsLFxuICAgICAgICBhbGxvd0V4aXRPbklkbGU6IHRydWUsXG4gICAgICB9O1xuXG4gICAgICB0aGlzLnBvb2wgPSBuZXcgUG9vbChwb29sQ29uZmlnKTtcbiAgICAgIHRoaXMuc2V0dXBFdmVudEhhbmRsZXJzKCk7XG5cbiAgICAgIHRoaXMuZGIgPSBkcml6emxlKHRoaXMucG9vbCwgeyBzY2hlbWEgfSk7XG5cbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuZW5hYmxlTG9nZ2luZykge1xuICAgICAgICBsb2dnZXIuaW5mbygnRGF0YWJhc2UgY29ubmVjdGlvbiBpbml0aWFsaXplZCBzdWNjZXNzZnVsbHknKTtcbiAgICAgICAgdGhpcy5sb2dDb25uZWN0aW9uQ29uZmlnKHBvb2xDb25maWcpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0ZhaWxlZCB0byBpbml0aWFsaXplIGRhdGFiYXNlIGNvbm5lY3Rpb246JywgZXJyb3IpO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdEYXRhYmFzZSBpbml0aWFsaXphdGlvbiBmYWlsZWQnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgc2luZ2xldG9uIGluc3RhbmNlIG9mIHRoZSBDb25uZWN0aW9uIGNsYXNzLlxuICAgKiBDcmVhdGVzIGEgbmV3IGluc3RhbmNlIGlmIG9uZSBkb2Vzbid0IGV4aXN0LlxuICAgKlxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gKG9ubHkgdXNlZCBvbiBmaXJzdCBjYWxsKVxuICAgKiBAcmV0dXJucyBUaGUgc2luZ2xldG9uIENvbm5lY3Rpb24gaW5zdGFuY2VcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZ2V0SW5zdGFuY2Uob3B0aW9ucz86IENvbm5lY3Rpb25PcHRpb25zKTogQ29ubmVjdGlvbiB7XG4gICAgaWYgKCFDb25uZWN0aW9uLmluc3RhbmNlKSB7XG4gICAgICBDb25uZWN0aW9uLmluc3RhbmNlID0gbmV3IENvbm5lY3Rpb24ob3B0aW9ucyk7XG4gICAgfVxuICAgIHJldHVybiBDb25uZWN0aW9uLmluc3RhbmNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc2V0cyB0aGUgc2luZ2xldG9uIGluc3RhbmNlLlxuICAgKiBVc2VmdWwgZm9yIHRlc3Rpbmcgb3IgcmVjb25maWd1cmluZyB0aGUgY29ubmVjdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIGNsb3NlRXhpc3RpbmcgLSBXaGV0aGVyIHRvIGNsb3NlIGV4aXN0aW5nIGNvbm5lY3Rpb24gYmVmb3JlIHJlc2V0XG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGFzeW5jIHJlc2V0KGNsb3NlRXhpc3Rpbmc6IGJvb2xlYW4gPSB0cnVlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKENvbm5lY3Rpb24uaW5zdGFuY2UgJiYgY2xvc2VFeGlzdGluZykge1xuICAgICAgYXdhaXQgQ29ubmVjdGlvbi5pbnN0YW5jZS5jbG9zZSgpO1xuICAgIH1cbiAgICBDb25uZWN0aW9uLmluc3RhbmNlID0gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBUZXN0cyB0aGUgZGF0YWJhc2UgY29ubmVjdGlvblxuICAgKlxuICAgKiBAcmV0dXJucyBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiBjb25uZWN0aW9uIGlzIGhlYWx0aHlcbiAgICovXG4gIHB1YmxpYyBhc3luYyB0ZXN0Q29ubmVjdGlvbigpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgY2xpZW50ID0gYXdhaXQgdGhpcy5wb29sLmNvbm5lY3QoKTtcbiAgICAgIC8vIFJlbGVhc2UgZXZlbiBpZiB0aGUgcHJvYmUgcXVlcnkgdGhyb3dzIOKAlCBvdGhlcndpc2UgYSBmbGFreSBEQiAodGhlIGV4YWN0XG4gICAgICAvLyBjYXNlIHRoaXMgY2hlY2sgZXhpc3RzIGZvcikgbGVha3MgYSBwb29sZWQgY2xpZW50IGVhY2ggZmFpbHVyZSBhbmQgY2FuXG4gICAgICAvLyBleGhhdXN0IHRoZSBwb29sIG9uIHRoZSByZXRyeSBwYXRoLlxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY2xpZW50LnF1ZXJ5KCdTRUxFQ1QgMScpO1xuICAgICAgICBpZiAodGhpcy5vcHRpb25zLmVuYWJsZUxvZ2dpbmcpIHtcbiAgICAgICAgICBsb2dnZXIuaW5mbygnRGF0YWJhc2UgY29ubmVjdGlvbiB0ZXN0IHN1Y2Nlc3NmdWwnKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0LnJvd3MubGVuZ3RoID4gMDtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGNsaWVudC5yZWxlYXNlKCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcignRGF0YWJhc2UgY29ubmVjdGlvbiB0ZXN0IGZhaWxlZDonLCBlcnJvcik7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgY29ubmVjdGlvbiBwb29sIHN0YXRpc3RpY3NcbiAgICpcbiAgICogQHJldHVybnMgQ3VycmVudCBjb25uZWN0aW9uIHBvb2wgc3RhdGlzdGljc1xuICAgKi9cbiAgcHVibGljIGdldFN0YXRzKCk6IENvbm5lY3Rpb25TdGF0cyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRvdGFsQ291bnQ6IHRoaXMucG9vbC50b3RhbENvdW50LFxuICAgICAgaWRsZUNvdW50OiB0aGlzLnBvb2wuaWRsZUNvdW50LFxuICAgICAgd2FpdGluZ0NvdW50OiB0aGlzLnBvb2wud2FpdGluZ0NvdW50LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ2xvc2VzIHRoZSBkYXRhYmFzZSBjb25uZWN0aW9uIHBvb2wgZ3JhY2VmdWxseS5cbiAgICogU2hvdWxkIGJlIGNhbGxlZCBkdXJpbmcgYXBwbGljYXRpb24gc2h1dGRvd24uXG4gICAqXG4gICAqIEBwYXJhbSB0aW1lb3V0IC0gTWF4aW11bSB0aW1lIHRvIHdhaXQgZm9yIGNvbm5lY3Rpb25zIHRvIGNsb3NlIChtcylcbiAgICogQHJldHVybnMgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gcG9vbCBpcyBjbG9zZWRcbiAgICovXG4gIHB1YmxpYyBhc3luYyBjbG9zZSh0aW1lb3V0OiBudW1iZXIgPSBlbnZJbnQoJ0RCX0NMT1NFX1RJTUVPVVRfTVMnLCA1MDAwKSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmlzU2h1dHRpbmdEb3duKSB7XG4gICAgICBsb2dnZXIud2FybignQ29ubmVjdGlvbiBpcyBhbHJlYWR5IHNodXR0aW5nIGRvd24nKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmlzU2h1dHRpbmdEb3duID0gdHJ1ZTtcblxuICAgIHRyeSB7XG4gICAgICBpZiAodGhpcy5vcHRpb25zLmVuYWJsZUxvZ2dpbmcpIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oJ0Nsb3NpbmcgZGF0YWJhc2UgY29ubmVjdGlvbiBwb29sLi4uJyk7XG4gICAgICAgIGNvbnN0IHN0YXRzID0gdGhpcy5nZXRTdGF0cygpO1xuICAgICAgICBsb2dnZXIuaW5mbyhgUG9vbCBzdGF0cyAtIFRvdGFsOiAke3N0YXRzLnRvdGFsQ291bnR9LCBJZGxlOiAke3N0YXRzLmlkbGVDb3VudH0sIFdhaXRpbmc6ICR7c3RhdHMud2FpdGluZ0NvdW50fWApO1xuICAgICAgfVxuXG4gICAgICAvLyBTZXQgYSB0aW1lb3V0IGZvciBncmFjZWZ1bCBzaHV0ZG93blxuICAgICAgY29uc3QgY2xvc2VQcm9taXNlID0gdGhpcy5wb29sLmVuZCgpO1xuICAgICAgY29uc3QgdGltZW91dFByb21pc2UgPSBuZXcgUHJvbWlzZSgoXywgcmVqZWN0KSA9PlxuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHJlamVjdChuZXcgRXJyb3IoJ0Nvbm5lY3Rpb24gY2xvc2UgdGltZW91dCcpKSwgdGltZW91dCksXG4gICAgICApO1xuXG4gICAgICBhd2FpdCBQcm9taXNlLnJhY2UoW2Nsb3NlUHJvbWlzZSwgdGltZW91dFByb21pc2VdKTtcblxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5lbmFibGVMb2dnaW5nKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKCdEYXRhYmFzZSBjb25uZWN0aW9uIGNsb3NlZCBzdWNjZXNzZnVsbHknKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdFcnJvciBjbG9zaW5nIGRhdGFiYXNlIGNvbm5lY3Rpb246JywgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuaXNTaHV0dGluZ0Rvd24gPSBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBjb25uZWN0aW9uIGlzIHNodXR0aW5nIGRvd25cbiAgICpcbiAgICogQHJldHVybnMgdHJ1ZSBpZiBjb25uZWN0aW9uIGlzIGluIHNodXRkb3duIHN0YXRlXG4gICAqL1xuICBwdWJsaWMgaXNDbG9zaW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzU2h1dHRpbmdEb3duO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldHMgdXAgZXZlbnQgaGFuZGxlcnMgZm9yIHRoZSBjb25uZWN0aW9uIHBvb2xcbiAgICovXG4gIHByaXZhdGUgc2V0dXBFdmVudEhhbmRsZXJzKCk6IHZvaWQge1xuICAgIHRoaXMucG9vbC5vbignZXJyb3InLCAoZXJyKSA9PiB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ1VuZXhwZWN0ZWQgZXJyb3Igb24gaWRsZSBjbGllbnQ6JywgZXJyKTtcblxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5lbmFibGVBdXRvUmV0cnkgJiYgdGhpcy5yZXRyeVN0cmF0ZWd5LmdldEF0dGVtcHRzKCkgPCB0aGlzLm9wdGlvbnMubWF4UmV0cmllcykge1xuICAgICAgICB2b2lkIHRoaXMucmV0cnlTdHJhdGVneS5oYW5kbGVDb25uZWN0aW9uRXJyb3IoZXJyLCAoKSA9PiB0aGlzLnRlc3RDb25uZWN0aW9uKCkpLmNhdGNoKChyZXRyeUVycikgPT4ge1xuICAgICAgICAgIGxvZ2dlci5lcnJvcignQ29ubmVjdGlvbiByZXRyeSBlcnJvcjonLCByZXRyeUVycik7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5wb29sLm9uKCdjb25uZWN0JywgKCkgPT4ge1xuICAgICAgdGhpcy5yZXRyeVN0cmF0ZWd5LnJlc2V0KCk7IC8vIFJlc2V0IG9uIHN1Y2Nlc3NmdWwgY29ubmVjdGlvblxuXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmVuYWJsZUxvZ2dpbmcpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdOZXcgZGF0YWJhc2UgY29ubmVjdGlvbiBlc3RhYmxpc2hlZCcpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5wb29sLm9uKCdyZW1vdmUnLCAoKSA9PiB7XG4gICAgICBpZiAodGhpcy5vcHRpb25zLmVuYWJsZUxvZ2dpbmcpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdDbGllbnQgcmVtb3ZlZCBmcm9tIHBvb2wnKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBMb2dzIGNvbm5lY3Rpb24gY29uZmlndXJhdGlvbiAoc2FuaXRpemVkKVxuICAgKi9cbiAgcHJpdmF0ZSBsb2dDb25uZWN0aW9uQ29uZmlnKGNvbmZpZzogUG9vbENvbmZpZyk6IHZvaWQge1xuICAgIGxvZ2dlci5pbmZvKCdEYXRhYmFzZSBDb25maWd1cmF0aW9uOicsIHtcbiAgICAgIGhvc3Q6IGAke2NvbmZpZy5ob3N0fToke2NvbmZpZy5wb3J0fWAsXG4gICAgICBkYXRhYmFzZTogY29uZmlnLmRhdGFiYXNlLFxuICAgICAgdXNlcjogY29uZmlnLnVzZXIsXG4gICAgICBtYXhQb29sU2l6ZTogY29uZmlnLm1heCxcbiAgICAgIGlkbGVUaW1lb3V0TXM6IGNvbmZpZy5pZGxlVGltZW91dE1pbGxpcyxcbiAgICAgIGNvbm5lY3Rpb25UaW1lb3V0TXM6IGNvbmZpZy5jb25uZWN0aW9uVGltZW91dE1pbGxpcyxcbiAgICAgIHNzbDogY29uZmlnLnNzbCA/ICdlbmFibGVkJyA6ICdkaXNhYmxlZCcsXG4gICAgfSk7XG4gIH1cbn1cblxuLyoqXG4gKiBTaW5nbGV0b24gZGF0YWJhc2UgaW5zdGFuY2UgZm9yIHVzZSB0aHJvdWdob3V0IHRoZSBhcHBsaWNhdGlvbi5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgZGIgfSBmcm9tICcuL2Nvbm5lY3Rpb24nO1xuICpcbiAqIC8vIFNlbGVjdCBxdWVyaWVzXG4gKiBjb25zdCBwbHVnaW5zID0gYXdhaXQgZGIuc2VsZWN0KCkuZnJvbShzY2hlbWEucGx1Z2luKTtcbiAqXG4gKiAvLyBJbnNlcnQgcXVlcmllc1xuICogYXdhaXQgZGIuaW5zZXJ0KHNjaGVtYS5wbHVnaW4pLnZhbHVlcyh7IG5hbWU6ICdteS1wbHVnaW4nIH0pO1xuICpcbiAqIC8vIFRyYW5zYWN0aW9uc1xuICogYXdhaXQgZGIudHJhbnNhY3Rpb24oYXN5bmMgKHR4KSA9PiB7XG4gKiAgIGF3YWl0IHR4Lmluc2VydChzY2hlbWEucGx1Z2luKS52YWx1ZXMoeyAuLi4gfSk7XG4gKiAgIGF3YWl0IHR4LnVwZGF0ZShzY2hlbWEucGx1Z2luKS5zZXQoeyAuLi4gfSk7XG4gKiB9KTtcbiAqIGBgYFxuICovXG5cbi8vIExhenkgaW5pdGlhbGl6YXRpb24gdG8gYXZvaWQgcmFjZSBjb25kaXRpb24gb24gbW9kdWxlIGxvYWRcbmxldCBfZGJJbnN0YW5jZTogUmV0dXJuVHlwZTx0eXBlb2YgZHJpenpsZT4gfCBudWxsID0gbnVsbDtcblxuLyoqXG4gKiBHZXQgdGhlIGRhdGFiYXNlIGluc3RhbmNlIHdpdGggbGF6eSBpbml0aWFsaXphdGlvblxuICogVGhpcyBhdm9pZHMgdGhlIHJhY2UgY29uZGl0aW9uIHdoZXJlIHRoZSBtb2R1bGUgaXMgbG9hZGVkIGJlZm9yZSBlbnZpcm9ubWVudCBpcyBjb25maWd1cmVkXG4gKi9cbmZ1bmN0aW9uIGdldERiSW5zdGFuY2UoKTogUmV0dXJuVHlwZTx0eXBlb2YgZHJpenpsZT4ge1xuICBpZiAoIV9kYkluc3RhbmNlKSB7XG4gICAgX2RiSW5zdGFuY2UgPSBDb25uZWN0aW9uLmdldEluc3RhbmNlKCkuZGI7XG4gIH1cbiAgcmV0dXJuIF9kYkluc3RhbmNlO1xufVxuXG4vKipcbiAqIFByb3h5LWJhc2VkIGxhenkgZGF0YWJhc2UgaW5zdGFuY2VcbiAqIFRoZSBhY3R1YWwgY29ubmVjdGlvbiBpcyBvbmx5IGNyZWF0ZWQgd2hlbiBmaXJzdCBhY2Nlc3NlZFxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBkYiB9IGZyb20gJy4vY29ubmVjdGlvbic7XG4gKlxuICogLy8gQ29ubmVjdGlvbiBpcyBjcmVhdGVkIGhlcmUgb24gZmlyc3QgdXNlLCBub3Qgb24gaW1wb3J0XG4gKiBjb25zdCBwbHVnaW5zID0gYXdhaXQgZGIuc2VsZWN0KCkuZnJvbShzY2hlbWEucGx1Z2luKTtcbiAqIGBgYFxuICovXG5leHBvcnQgY29uc3QgZGIgPSBuZXcgUHJveHkoe30gYXMgUmV0dXJuVHlwZTx0eXBlb2YgZHJpenpsZT4sIHtcbiAgZ2V0KF8sIHByb3A6IHN0cmluZyB8IHN5bWJvbCkge1xuICAgIGNvbnN0IGluc3RhbmNlID0gZ2V0RGJJbnN0YW5jZSgpO1xuICAgIGNvbnN0IHZhbHVlID0gaW5zdGFuY2VbcHJvcCBhcyBrZXlvZiB0eXBlb2YgaW5zdGFuY2VdO1xuICAgIC8vIEJpbmQgbWV0aG9kcyB0byB0aGUgaW5zdGFuY2UgdG8gcHJlc2VydmUgJ3RoaXMnIGNvbnRleHRcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gdmFsdWUuYmluZChpbnN0YW5jZSk7XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbiAgfSxcbn0pO1xuXG4vKipcbiAqIEdldHMgdGhlIENvbm5lY3Rpb24gaW5zdGFuY2UgZm9yIGFkdmFuY2VkIG9wZXJhdGlvbnNcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgZ2V0Q29ubmVjdGlvbiB9IGZyb20gJy4vY29ubmVjdGlvbic7XG4gKlxuICogY29uc3QgY29ubmVjdGlvbiA9IGdldENvbm5lY3Rpb24oKTtcbiAqIGNvbnN0IHN0YXRzID0gY29ubmVjdGlvbi5nZXRTdGF0cygpO1xuICogY29uc29sZS5sb2coYEFjdGl2ZSBjb25uZWN0aW9uczogJHtzdGF0cy50b3RhbENvdW50fWApO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRDb25uZWN0aW9uKCk6IENvbm5lY3Rpb24ge1xuICByZXR1cm4gQ29ubmVjdGlvbi5nZXRJbnN0YW5jZSgpO1xufVxuXG4vKipcbiAqIENsb3NlcyB0aGUgZGF0YWJhc2UgY29ubmVjdGlvblxuICogU2hvdWxkIGJlIGNhbGxlZCBkdXJpbmcgYXBwbGljYXRpb24gc2h1dGRvd25cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgY2xvc2VDb25uZWN0aW9uIH0gZnJvbSAnLi9jb25uZWN0aW9uJztcbiAqXG4gKiBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKCkgPT4ge1xuICogICBhd2FpdCBjbG9zZUNvbm5lY3Rpb24oKTtcbiAqICAgcHJvY2Vzcy5leGl0KDApO1xuICogfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlQ29ubmVjdGlvbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgY29ubmVjdGlvbiA9IENvbm5lY3Rpb24uZ2V0SW5zdGFuY2UoKTtcbiAgYXdhaXQgY29ubmVjdGlvbi5jbG9zZSgpO1xuICBfZGJJbnN0YW5jZSA9IG51bGw7IC8vIFJlc2V0IGxhenkgaW5zdGFuY2VcbiAgLy8gQ2xvc2UgdGhlIHJlYWQtcmVwbGljYSBwb29sIHRvby4gQSBoYWxmLWNsb3NlZCBwcm9jZXNzIGtlZXBzIHNlcnZlclxuICAvLyBjb25uZWN0aW9ucyBvcGVuIG9uIHRoZSBzdGFuZGJ5IGFuZCBpdHMgcmVwbGljYXRpb24gc2xvdCBidXN5LCB3aGljaCBvbiB0aGVcbiAgLy8gcHJpbWFyeSBtZWFucyByZXRhaW5lZCBXQUwg4oCUIHRoZSBmYWlsdXJlIG1vZGUgdGhhdCBmaWxscyB0aGUgZGF0YSB2b2x1bWUuXG4gIC8vIEltcG9ydGVkIGxhemlseSBzbyB0aGlzIG1vZHVsZSBkb2VzIG5vdCBkZXBlbmQgb24gdGhlIHJlYWQgY29ubmVjdGlvbiBhdFxuICAvLyBsb2FkIHRpbWUgKGl0IGhhcyBubyByZXBsaWNhIG9uIG1vc3QgZGVwbG95cykuXG4gIGNvbnN0IHsgY2xvc2VSZWFkQ29ubmVjdGlvbiB9ID0gYXdhaXQgaW1wb3J0KCcuL3JlYWQtY29ubmVjdGlvbi5qcycpO1xuICBhd2FpdCBjbG9zZVJlYWRDb25uZWN0aW9uKCk7XG59XG5cbi8qKlxuICogVGVzdHMgdGhlIGRhdGFiYXNlIGNvbm5lY3Rpb25cbiAqXG4gKiBAcmV0dXJucyBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiBjb25uZWN0aW9uIGlzIGhlYWx0aHlcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgdGVzdENvbm5lY3Rpb24gfSBmcm9tICcuL2Nvbm5lY3Rpb24nO1xuICpcbiAqIGlmIChhd2FpdCB0ZXN0Q29ubmVjdGlvbigpKSB7XG4gKiAgIGNvbnNvbGUubG9nKCdEYXRhYmFzZSBpcyByZWFkeScpO1xuICogfSBlbHNlIHtcbiAqICAgY29uc29sZS5lcnJvcignRGF0YWJhc2UgY29ubmVjdGlvbiBmYWlsZWQnKTtcbiAqICAgcHJvY2Vzcy5leGl0KDEpO1xuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB0ZXN0Q29ubmVjdGlvbigpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgY29uc3QgY29ubmVjdGlvbiA9IENvbm5lY3Rpb24uZ2V0SW5zdGFuY2UoKTtcbiAgcmV0dXJuIGNvbm5lY3Rpb24udGVzdENvbm5lY3Rpb24oKTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
2
|
+
import { Pool } from 'pg';
|
|
3
|
+
/**
|
|
4
|
+
* The replica pool, or null when no replica is configured.
|
|
5
|
+
*
|
|
6
|
+
* Lazily created so importing this module costs nothing on a deploy that has no
|
|
7
|
+
* replica — which, until Phase 1 lands, is all of them.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getReadPool(): Pool | null;
|
|
10
|
+
/** The replica's drizzle instance, or null when no replica is configured. */
|
|
11
|
+
export declare function getReadDb(): ReturnType<typeof drizzle> | null;
|
|
12
|
+
/**
|
|
13
|
+
* Close the replica pool. Called from `closeConnection()` so a shutdown closes
|
|
14
|
+
* BOTH pools — a half-closed process holds server connections open on the
|
|
15
|
+
* standby and keeps its replication slot busy.
|
|
16
|
+
*/
|
|
17
|
+
export declare function closeReadConnection(): Promise<void>;
|
|
18
|
+
/** Test seam: forget the memoized pool without closing it. */
|
|
19
|
+
export declare function resetReadConnectionForTests(): void;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* The read-replica connection — a second pool pointed at a streaming standby.
|
|
5
|
+
*
|
|
6
|
+
* Shaped after {@link ./public-reader.ts}: a separate, smaller pool that
|
|
7
|
+
* connects like every other client (through pgbouncer), rather than a second
|
|
8
|
+
* target bolted onto the primary pool. As with the public reader, what selects
|
|
9
|
+
* the backend is the pgbouncer DATABASE name — `pipeline_builder_read`, whose
|
|
10
|
+
* `[databases]` entry points at the `postgres-read` Service — not the host.
|
|
11
|
+
* `DB_READ_HOST` is pgbouncer on every target, exactly like `DB_HOST`. It carries the SAME application role and
|
|
12
|
+
* the SAME RLS policies — a physical standby replicates `pg_authid` and every
|
|
13
|
+
* policy — so `withTenantTxRead` sets the identical GUCs here that
|
|
14
|
+
* `withTenantTx` sets on the primary.
|
|
15
|
+
*
|
|
16
|
+
* NOT CONFIGURED IS THE NORMAL STATE UNTIL A REPLICA EXISTS. With `DB_READ_HOST`
|
|
17
|
+
* unset, {@link getReadPool} returns null and every caller falls back to the
|
|
18
|
+
* primary. That is what lets this module ship before any infrastructure does,
|
|
19
|
+
* and it is also the degraded path the kill switch and (later) the lag circuit
|
|
20
|
+
* fall back to — so it has to keep working and be tested deliberately, not only
|
|
21
|
+
* exercised by accident on a laptop.
|
|
22
|
+
*
|
|
23
|
+
* WHY A SEPARATE MODULE rather than a flag on `Connection`: a global whose
|
|
24
|
+
* target can change is how a write reaches a standby. `Connection` stays the
|
|
25
|
+
* primary, unconditionally, and callers that want a replica have to ask for one
|
|
26
|
+
* by name.
|
|
27
|
+
*/
|
|
28
|
+
import { createLogger, envInt, envStr, isReadReplicaConfigured } from '@pipeline-builder/api-core';
|
|
29
|
+
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
30
|
+
import { Pool } from 'pg';
|
|
31
|
+
import { schema } from './drizzle-schema.js';
|
|
32
|
+
import { getSslConfig } from './postgres-connection.js';
|
|
33
|
+
const logger = createLogger('database-read');
|
|
34
|
+
let pool = null;
|
|
35
|
+
let readDb = null;
|
|
36
|
+
/** Set once so a misconfigured deploy does not log on every query. */
|
|
37
|
+
let warned = false;
|
|
38
|
+
/**
|
|
39
|
+
* The replica pool, or null when no replica is configured.
|
|
40
|
+
*
|
|
41
|
+
* Lazily created so importing this module costs nothing on a deploy that has no
|
|
42
|
+
* replica — which, until Phase 1 lands, is all of them.
|
|
43
|
+
*/
|
|
44
|
+
export function getReadPool() {
|
|
45
|
+
if (!isReadReplicaConfigured())
|
|
46
|
+
return null;
|
|
47
|
+
if (pool)
|
|
48
|
+
return pool;
|
|
49
|
+
const host = envStr('DB_READ_HOST', '');
|
|
50
|
+
const config = {
|
|
51
|
+
host,
|
|
52
|
+
port: envInt('DB_READ_PORT', envInt('DB_PORT', 5432)),
|
|
53
|
+
// A DIFFERENT pgbouncer database than the write path, and that is the whole
|
|
54
|
+
// point: reads go to `pipeline_builder_read`, whose `[databases]` entry
|
|
55
|
+
// names `host=postgres-read` — the Service in front of the standbys. The
|
|
56
|
+
// primary's pool (`pipeline_builder`) names `host=postgres`.
|
|
57
|
+
//
|
|
58
|
+
// So the thing that decides whether a read reaches a replica is the
|
|
59
|
+
// DATABASE NAME, not the host: DB_READ_HOST is pgbouncer on every target,
|
|
60
|
+
// the same pooler the write path uses. Defaulting this to `DATABASE` would
|
|
61
|
+
// send every "read" straight back to the primary's pool through a second
|
|
62
|
+
// connection pool — all of the complexity, none of the offload, and no
|
|
63
|
+
// error anywhere to say so.
|
|
64
|
+
database: envStr('DB_READ_DATABASE', 'pipeline_builder_read'),
|
|
65
|
+
// The SAME application role as the primary. A standby replicates the role
|
|
66
|
+
// catalog, so a second credential would be a second thing to rotate for no
|
|
67
|
+
// benefit — and a role that existed only on the replica would vanish the
|
|
68
|
+
// moment the standby was re-seeded from a base backup.
|
|
69
|
+
user: envStr('DB_USER', 'postgres'),
|
|
70
|
+
password: process.env.DB_PASSWORD ?? '',
|
|
71
|
+
// Deliberately smaller than the primary's. Read traffic must not be able to
|
|
72
|
+
// exhaust connections the write path needs, and the replica has its own
|
|
73
|
+
// max_connections budget which is NOT the primary's.
|
|
74
|
+
max: envInt('DB_READ_MAX_POOL_SIZE', 10),
|
|
75
|
+
idleTimeoutMillis: envInt('DRIZZLE_IDLE_TIMEOUT_MILLIS', 30_000),
|
|
76
|
+
connectionTimeoutMillis: envInt('DRIZZLE_CONNECTION_TIMEOUT_MILLIS', 5000),
|
|
77
|
+
ssl: getSslConfig(),
|
|
78
|
+
allowExitOnIdle: true,
|
|
79
|
+
};
|
|
80
|
+
pool = new Pool(config);
|
|
81
|
+
pool.on('error', (err) => {
|
|
82
|
+
// Never throw from here: an idle-client error on the REPLICA must not take
|
|
83
|
+
// the process down, because every read can be served by the primary.
|
|
84
|
+
logger.error('Read-replica pool error (reads fall back to the primary)', err);
|
|
85
|
+
});
|
|
86
|
+
readDb = drizzle(pool, { schema });
|
|
87
|
+
logger.info('Read-replica connection initialized', { host, max: config.max });
|
|
88
|
+
return pool;
|
|
89
|
+
}
|
|
90
|
+
/** The replica's drizzle instance, or null when no replica is configured. */
|
|
91
|
+
export function getReadDb() {
|
|
92
|
+
if (!getReadPool()) {
|
|
93
|
+
if (!warned && envStr('DB_READ_HOST', '').trim().length > 0) {
|
|
94
|
+
warned = true;
|
|
95
|
+
logger.info('Read replica is configured but disabled (DB_READ_ENABLED=false); reads use the primary');
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return readDb;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Close the replica pool. Called from `closeConnection()` so a shutdown closes
|
|
103
|
+
* BOTH pools — a half-closed process holds server connections open on the
|
|
104
|
+
* standby and keeps its replication slot busy.
|
|
105
|
+
*/
|
|
106
|
+
export async function closeReadConnection() {
|
|
107
|
+
if (!pool)
|
|
108
|
+
return;
|
|
109
|
+
const p = pool;
|
|
110
|
+
pool = null;
|
|
111
|
+
readDb = null;
|
|
112
|
+
warned = false;
|
|
113
|
+
await p.end();
|
|
114
|
+
logger.info('Read-replica connection closed');
|
|
115
|
+
}
|
|
116
|
+
/** Test seam: forget the memoized pool without closing it. */
|
|
117
|
+
export function resetReadConnectionForTests() {
|
|
118
|
+
pool = null;
|
|
119
|
+
readDb = null;
|
|
120
|
+
warned = false;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVhZC1jb25uZWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2RhdGFiYXNlL3JlYWQtY29ubmVjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F3Qkc7QUFFSCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNuRyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDcEQsT0FBTyxFQUFFLElBQUksRUFBbUIsTUFBTSxJQUFJLENBQUM7QUFFM0MsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUV4RCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsZUFBZSxDQUFDLENBQUM7QUFFN0MsSUFBSSxJQUFJLEdBQWdCLElBQUksQ0FBQztBQUM3QixJQUFJLE1BQU0sR0FBc0MsSUFBSSxDQUFDO0FBQ3JELHNFQUFzRTtBQUN0RSxJQUFJLE1BQU0sR0FBRyxLQUFLLENBQUM7QUFFbkI7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsV0FBVztJQUN6QixJQUFJLENBQUMsdUJBQXVCLEVBQUU7UUFBRSxPQUFPLElBQUksQ0FBQztJQUM1QyxJQUFJLElBQUk7UUFBRSxPQUFPLElBQUksQ0FBQztJQUV0QixNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsY0FBYyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3hDLE1BQU0sTUFBTSxHQUFlO1FBQ3pCLElBQUk7UUFDSixJQUFJLEVBQUUsTUFBTSxDQUFDLGNBQWMsRUFBRSxNQUFNLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ3JELDRFQUE0RTtRQUM1RSx3RUFBd0U7UUFDeEUseUVBQXlFO1FBQ3pFLDZEQUE2RDtRQUM3RCxFQUFFO1FBQ0Ysb0VBQW9FO1FBQ3BFLDBFQUEwRTtRQUMxRSwyRUFBMkU7UUFDM0UseUVBQXlFO1FBQ3pFLHVFQUF1RTtRQUN2RSw0QkFBNEI7UUFDNUIsUUFBUSxFQUFFLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRSx1QkFBdUIsQ0FBQztRQUM3RCwwRUFBMEU7UUFDMUUsMkVBQTJFO1FBQzNFLHlFQUF5RTtRQUN6RSx1REFBdUQ7UUFDdkQsSUFBSSxFQUFFLE1BQU0sQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDO1FBQ25DLFFBQVEsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsSUFBSSxFQUFFO1FBQ3ZDLDRFQUE0RTtRQUM1RSx3RUFBd0U7UUFDeEUscURBQXFEO1FBQ3JELEdBQUcsRUFBRSxNQUFNLENBQUMsdUJBQXVCLEVBQUUsRUFBRSxDQUFDO1FBQ3hDLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyw2QkFBNkIsRUFBRSxNQUFNLENBQUM7UUFDaEUsdUJBQXVCLEVBQUUsTUFBTSxDQUFDLG1DQUFtQyxFQUFFLElBQUksQ0FBQztRQUMxRSxHQUFHLEVBQUUsWUFBWSxFQUFFO1FBQ25CLGVBQWUsRUFBRSxJQUFJO0tBQ3RCLENBQUM7SUFFRixJQUFJLEdBQUcsSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDeEIsSUFBSSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRTtRQUN2QiwyRUFBMkU7UUFDM0UscUVBQXFFO1FBQ3JFLE1BQU0sQ0FBQyxLQUFLLENBQUMsMERBQTBELEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDaEYsQ0FBQyxDQUFDLENBQUM7SUFDSCxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFFbkMsTUFBTSxDQUFDLElBQUksQ0FBQyxxQ0FBcUMsRUFBRSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDOUUsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQsNkVBQTZFO0FBQzdFLE1BQU0sVUFBVSxTQUFTO0lBQ3ZCLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO1FBQ25CLElBQUksQ0FBQyxNQUFNLElBQUksTUFBTSxDQUFDLGNBQWMsRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDNUQsTUFBTSxHQUFHLElBQUksQ0FBQztZQUNkLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0ZBQXdGLENBQUMsQ0FBQztRQUN4RyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQ0QsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLG1CQUFtQjtJQUN2QyxJQUFJLENBQUMsSUFBSTtRQUFFLE9BQU87SUFDbEIsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDO0lBQ2YsSUFBSSxHQUFHLElBQUksQ0FBQztJQUNaLE1BQU0sR0FBRyxJQUFJLENBQUM7SUFDZCxNQUFNLEdBQUcsS0FBSyxDQUFDO0lBQ2YsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUM7SUFDZCxNQUFNLENBQUMsSUFBSSxDQUFDLGdDQUFnQyxDQUFDLENBQUM7QUFDaEQsQ0FBQztBQUVELDhEQUE4RDtBQUM5RCxNQUFNLFVBQVUsMkJBQTJCO0lBQ3pDLElBQUksR0FBRyxJQUFJLENBQUM7SUFDWixNQUFNLEdBQUcsSUFBSSxDQUFDO0lBQ2QsTUFBTSxHQUFHLEtBQUssQ0FBQztBQUNqQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogVGhlIHJlYWQtcmVwbGljYSBjb25uZWN0aW9uIOKAlCBhIHNlY29uZCBwb29sIHBvaW50ZWQgYXQgYSBzdHJlYW1pbmcgc3RhbmRieS5cbiAqXG4gKiBTaGFwZWQgYWZ0ZXIge0BsaW5rIC4vcHVibGljLXJlYWRlci50c306IGEgc2VwYXJhdGUsIHNtYWxsZXIgcG9vbCB0aGF0XG4gKiBjb25uZWN0cyBsaWtlIGV2ZXJ5IG90aGVyIGNsaWVudCAodGhyb3VnaCBwZ2JvdW5jZXIpLCByYXRoZXIgdGhhbiBhIHNlY29uZFxuICogdGFyZ2V0IGJvbHRlZCBvbnRvIHRoZSBwcmltYXJ5IHBvb2wuIEFzIHdpdGggdGhlIHB1YmxpYyByZWFkZXIsIHdoYXQgc2VsZWN0c1xuICogdGhlIGJhY2tlbmQgaXMgdGhlIHBnYm91bmNlciBEQVRBQkFTRSBuYW1lIOKAlCBgcGlwZWxpbmVfYnVpbGRlcl9yZWFkYCwgd2hvc2VcbiAqIGBbZGF0YWJhc2VzXWAgZW50cnkgcG9pbnRzIGF0IHRoZSBgcG9zdGdyZXMtcmVhZGAgU2VydmljZSDigJQgbm90IHRoZSBob3N0LlxuICogYERCX1JFQURfSE9TVGAgaXMgcGdib3VuY2VyIG9uIGV2ZXJ5IHRhcmdldCwgZXhhY3RseSBsaWtlIGBEQl9IT1NUYC4gSXQgY2FycmllcyB0aGUgU0FNRSBhcHBsaWNhdGlvbiByb2xlIGFuZFxuICogdGhlIFNBTUUgUkxTIHBvbGljaWVzIOKAlCBhIHBoeXNpY2FsIHN0YW5kYnkgcmVwbGljYXRlcyBgcGdfYXV0aGlkYCBhbmQgZXZlcnlcbiAqIHBvbGljeSDigJQgc28gYHdpdGhUZW5hbnRUeFJlYWRgIHNldHMgdGhlIGlkZW50aWNhbCBHVUNzIGhlcmUgdGhhdFxuICogYHdpdGhUZW5hbnRUeGAgc2V0cyBvbiB0aGUgcHJpbWFyeS5cbiAqXG4gKiBOT1QgQ09ORklHVVJFRCBJUyBUSEUgTk9STUFMIFNUQVRFIFVOVElMIEEgUkVQTElDQSBFWElTVFMuIFdpdGggYERCX1JFQURfSE9TVGBcbiAqIHVuc2V0LCB7QGxpbmsgZ2V0UmVhZFBvb2x9IHJldHVybnMgbnVsbCBhbmQgZXZlcnkgY2FsbGVyIGZhbGxzIGJhY2sgdG8gdGhlXG4gKiBwcmltYXJ5LiBUaGF0IGlzIHdoYXQgbGV0cyB0aGlzIG1vZHVsZSBzaGlwIGJlZm9yZSBhbnkgaW5mcmFzdHJ1Y3R1cmUgZG9lcyxcbiAqIGFuZCBpdCBpcyBhbHNvIHRoZSBkZWdyYWRlZCBwYXRoIHRoZSBraWxsIHN3aXRjaCBhbmQgKGxhdGVyKSB0aGUgbGFnIGNpcmN1aXRcbiAqIGZhbGwgYmFjayB0byDigJQgc28gaXQgaGFzIHRvIGtlZXAgd29ya2luZyBhbmQgYmUgdGVzdGVkIGRlbGliZXJhdGVseSwgbm90IG9ubHlcbiAqIGV4ZXJjaXNlZCBieSBhY2NpZGVudCBvbiBhIGxhcHRvcC5cbiAqXG4gKiBXSFkgQSBTRVBBUkFURSBNT0RVTEUgcmF0aGVyIHRoYW4gYSBmbGFnIG9uIGBDb25uZWN0aW9uYDogYSBnbG9iYWwgd2hvc2VcbiAqIHRhcmdldCBjYW4gY2hhbmdlIGlzIGhvdyBhIHdyaXRlIHJlYWNoZXMgYSBzdGFuZGJ5LiBgQ29ubmVjdGlvbmAgc3RheXMgdGhlXG4gKiBwcmltYXJ5LCB1bmNvbmRpdGlvbmFsbHksIGFuZCBjYWxsZXJzIHRoYXQgd2FudCBhIHJlcGxpY2EgaGF2ZSB0byBhc2sgZm9yIG9uZVxuICogYnkgbmFtZS5cbiAqL1xuXG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIsIGVudkludCwgZW52U3RyLCBpc1JlYWRSZXBsaWNhQ29uZmlndXJlZCB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IGRyaXp6bGUgfSBmcm9tICdkcml6emxlLW9ybS9ub2RlLXBvc3RncmVzJztcbmltcG9ydCB7IFBvb2wsIHR5cGUgUG9vbENvbmZpZyB9IGZyb20gJ3BnJztcblxuaW1wb3J0IHsgc2NoZW1hIH0gZnJvbSAnLi9kcml6emxlLXNjaGVtYS5qcyc7XG5pbXBvcnQgeyBnZXRTc2xDb25maWcgfSBmcm9tICcuL3Bvc3RncmVzLWNvbm5lY3Rpb24uanMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2RhdGFiYXNlLXJlYWQnKTtcblxubGV0IHBvb2w6IFBvb2wgfCBudWxsID0gbnVsbDtcbmxldCByZWFkRGI6IFJldHVyblR5cGU8dHlwZW9mIGRyaXp6bGU+IHwgbnVsbCA9IG51bGw7XG4vKiogU2V0IG9uY2Ugc28gYSBtaXNjb25maWd1cmVkIGRlcGxveSBkb2VzIG5vdCBsb2cgb24gZXZlcnkgcXVlcnkuICovXG5sZXQgd2FybmVkID0gZmFsc2U7XG5cbi8qKlxuICogVGhlIHJlcGxpY2EgcG9vbCwgb3IgbnVsbCB3aGVuIG5vIHJlcGxpY2EgaXMgY29uZmlndXJlZC5cbiAqXG4gKiBMYXppbHkgY3JlYXRlZCBzbyBpbXBvcnRpbmcgdGhpcyBtb2R1bGUgY29zdHMgbm90aGluZyBvbiBhIGRlcGxveSB0aGF0IGhhcyBub1xuICogcmVwbGljYSDigJQgd2hpY2gsIHVudGlsIFBoYXNlIDEgbGFuZHMsIGlzIGFsbCBvZiB0aGVtLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UmVhZFBvb2woKTogUG9vbCB8IG51bGwge1xuICBpZiAoIWlzUmVhZFJlcGxpY2FDb25maWd1cmVkKCkpIHJldHVybiBudWxsO1xuICBpZiAocG9vbCkgcmV0dXJuIHBvb2w7XG5cbiAgY29uc3QgaG9zdCA9IGVudlN0cignREJfUkVBRF9IT1NUJywgJycpO1xuICBjb25zdCBjb25maWc6IFBvb2xDb25maWcgPSB7XG4gICAgaG9zdCxcbiAgICBwb3J0OiBlbnZJbnQoJ0RCX1JFQURfUE9SVCcsIGVudkludCgnREJfUE9SVCcsIDU0MzIpKSxcbiAgICAvLyBBIERJRkZFUkVOVCBwZ2JvdW5jZXIgZGF0YWJhc2UgdGhhbiB0aGUgd3JpdGUgcGF0aCwgYW5kIHRoYXQgaXMgdGhlIHdob2xlXG4gICAgLy8gcG9pbnQ6IHJlYWRzIGdvIHRvIGBwaXBlbGluZV9idWlsZGVyX3JlYWRgLCB3aG9zZSBgW2RhdGFiYXNlc11gIGVudHJ5XG4gICAgLy8gbmFtZXMgYGhvc3Q9cG9zdGdyZXMtcmVhZGAg4oCUIHRoZSBTZXJ2aWNlIGluIGZyb250IG9mIHRoZSBzdGFuZGJ5cy4gVGhlXG4gICAgLy8gcHJpbWFyeSdzIHBvb2wgKGBwaXBlbGluZV9idWlsZGVyYCkgbmFtZXMgYGhvc3Q9cG9zdGdyZXNgLlxuICAgIC8vXG4gICAgLy8gU28gdGhlIHRoaW5nIHRoYXQgZGVjaWRlcyB3aGV0aGVyIGEgcmVhZCByZWFjaGVzIGEgcmVwbGljYSBpcyB0aGVcbiAgICAvLyBEQVRBQkFTRSBOQU1FLCBub3QgdGhlIGhvc3Q6IERCX1JFQURfSE9TVCBpcyBwZ2JvdW5jZXIgb24gZXZlcnkgdGFyZ2V0LFxuICAgIC8vIHRoZSBzYW1lIHBvb2xlciB0aGUgd3JpdGUgcGF0aCB1c2VzLiBEZWZhdWx0aW5nIHRoaXMgdG8gYERBVEFCQVNFYCB3b3VsZFxuICAgIC8vIHNlbmQgZXZlcnkgXCJyZWFkXCIgc3RyYWlnaHQgYmFjayB0byB0aGUgcHJpbWFyeSdzIHBvb2wgdGhyb3VnaCBhIHNlY29uZFxuICAgIC8vIGNvbm5lY3Rpb24gcG9vbCDigJQgYWxsIG9mIHRoZSBjb21wbGV4aXR5LCBub25lIG9mIHRoZSBvZmZsb2FkLCBhbmQgbm9cbiAgICAvLyBlcnJvciBhbnl3aGVyZSB0byBzYXkgc28uXG4gICAgZGF0YWJhc2U6IGVudlN0cignREJfUkVBRF9EQVRBQkFTRScsICdwaXBlbGluZV9idWlsZGVyX3JlYWQnKSxcbiAgICAvLyBUaGUgU0FNRSBhcHBsaWNhdGlvbiByb2xlIGFzIHRoZSBwcmltYXJ5LiBBIHN0YW5kYnkgcmVwbGljYXRlcyB0aGUgcm9sZVxuICAgIC8vIGNhdGFsb2csIHNvIGEgc2Vjb25kIGNyZWRlbnRpYWwgd291bGQgYmUgYSBzZWNvbmQgdGhpbmcgdG8gcm90YXRlIGZvciBub1xuICAgIC8vIGJlbmVmaXQg4oCUIGFuZCBhIHJvbGUgdGhhdCBleGlzdGVkIG9ubHkgb24gdGhlIHJlcGxpY2Egd291bGQgdmFuaXNoIHRoZVxuICAgIC8vIG1vbWVudCB0aGUgc3RhbmRieSB3YXMgcmUtc2VlZGVkIGZyb20gYSBiYXNlIGJhY2t1cC5cbiAgICB1c2VyOiBlbnZTdHIoJ0RCX1VTRVInLCAncG9zdGdyZXMnKSxcbiAgICBwYXNzd29yZDogcHJvY2Vzcy5lbnYuREJfUEFTU1dPUkQgPz8gJycsXG4gICAgLy8gRGVsaWJlcmF0ZWx5IHNtYWxsZXIgdGhhbiB0aGUgcHJpbWFyeSdzLiBSZWFkIHRyYWZmaWMgbXVzdCBub3QgYmUgYWJsZSB0b1xuICAgIC8vIGV4aGF1c3QgY29ubmVjdGlvbnMgdGhlIHdyaXRlIHBhdGggbmVlZHMsIGFuZCB0aGUgcmVwbGljYSBoYXMgaXRzIG93blxuICAgIC8vIG1heF9jb25uZWN0aW9ucyBidWRnZXQgd2hpY2ggaXMgTk9UIHRoZSBwcmltYXJ5J3MuXG4gICAgbWF4OiBlbnZJbnQoJ0RCX1JFQURfTUFYX1BPT0xfU0laRScsIDEwKSxcbiAgICBpZGxlVGltZW91dE1pbGxpczogZW52SW50KCdEUklaWkxFX0lETEVfVElNRU9VVF9NSUxMSVMnLCAzMF8wMDApLFxuICAgIGNvbm5lY3Rpb25UaW1lb3V0TWlsbGlzOiBlbnZJbnQoJ0RSSVpaTEVfQ09OTkVDVElPTl9USU1FT1VUX01JTExJUycsIDUwMDApLFxuICAgIHNzbDogZ2V0U3NsQ29uZmlnKCksXG4gICAgYWxsb3dFeGl0T25JZGxlOiB0cnVlLFxuICB9O1xuXG4gIHBvb2wgPSBuZXcgUG9vbChjb25maWcpO1xuICBwb29sLm9uKCdlcnJvcicsIChlcnIpID0+IHtcbiAgICAvLyBOZXZlciB0aHJvdyBmcm9tIGhlcmU6IGFuIGlkbGUtY2xpZW50IGVycm9yIG9uIHRoZSBSRVBMSUNBIG11c3Qgbm90IHRha2VcbiAgICAvLyB0aGUgcHJvY2VzcyBkb3duLCBiZWNhdXNlIGV2ZXJ5IHJlYWQgY2FuIGJlIHNlcnZlZCBieSB0aGUgcHJpbWFyeS5cbiAgICBsb2dnZXIuZXJyb3IoJ1JlYWQtcmVwbGljYSBwb29sIGVycm9yIChyZWFkcyBmYWxsIGJhY2sgdG8gdGhlIHByaW1hcnkpJywgZXJyKTtcbiAgfSk7XG4gIHJlYWREYiA9IGRyaXp6bGUocG9vbCwgeyBzY2hlbWEgfSk7XG5cbiAgbG9nZ2VyLmluZm8oJ1JlYWQtcmVwbGljYSBjb25uZWN0aW9uIGluaXRpYWxpemVkJywgeyBob3N0LCBtYXg6IGNvbmZpZy5tYXggfSk7XG4gIHJldHVybiBwb29sO1xufVxuXG4vKiogVGhlIHJlcGxpY2EncyBkcml6emxlIGluc3RhbmNlLCBvciBudWxsIHdoZW4gbm8gcmVwbGljYSBpcyBjb25maWd1cmVkLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFJlYWREYigpOiBSZXR1cm5UeXBlPHR5cGVvZiBkcml6emxlPiB8IG51bGwge1xuICBpZiAoIWdldFJlYWRQb29sKCkpIHtcbiAgICBpZiAoIXdhcm5lZCAmJiBlbnZTdHIoJ0RCX1JFQURfSE9TVCcsICcnKS50cmltKCkubGVuZ3RoID4gMCkge1xuICAgICAgd2FybmVkID0gdHJ1ZTtcbiAgICAgIGxvZ2dlci5pbmZvKCdSZWFkIHJlcGxpY2EgaXMgY29uZmlndXJlZCBidXQgZGlzYWJsZWQgKERCX1JFQURfRU5BQkxFRD1mYWxzZSk7IHJlYWRzIHVzZSB0aGUgcHJpbWFyeScpO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICByZXR1cm4gcmVhZERiO1xufVxuXG4vKipcbiAqIENsb3NlIHRoZSByZXBsaWNhIHBvb2wuIENhbGxlZCBmcm9tIGBjbG9zZUNvbm5lY3Rpb24oKWAgc28gYSBzaHV0ZG93biBjbG9zZXNcbiAqIEJPVEggcG9vbHMg4oCUIGEgaGFsZi1jbG9zZWQgcHJvY2VzcyBob2xkcyBzZXJ2ZXIgY29ubmVjdGlvbnMgb3BlbiBvbiB0aGVcbiAqIHN0YW5kYnkgYW5kIGtlZXBzIGl0cyByZXBsaWNhdGlvbiBzbG90IGJ1c3kuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZVJlYWRDb25uZWN0aW9uKCk6IFByb21pc2U8dm9pZD4ge1xuICBpZiAoIXBvb2wpIHJldHVybjtcbiAgY29uc3QgcCA9IHBvb2w7XG4gIHBvb2wgPSBudWxsO1xuICByZWFkRGIgPSBudWxsO1xuICB3YXJuZWQgPSBmYWxzZTtcbiAgYXdhaXQgcC5lbmQoKTtcbiAgbG9nZ2VyLmluZm8oJ1JlYWQtcmVwbGljYSBjb25uZWN0aW9uIGNsb3NlZCcpO1xufVxuXG4vKiogVGVzdCBzZWFtOiBmb3JnZXQgdGhlIG1lbW9pemVkIHBvb2wgd2l0aG91dCBjbG9zaW5nIGl0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc2V0UmVhZENvbm5lY3Rpb25Gb3JUZXN0cygpOiB2b2lkIHtcbiAgcG9vbCA9IG51bGw7XG4gIHJlYWREYiA9IG51bGw7XG4gIHdhcm5lZCA9IGZhbHNlO1xufVxuIl19
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Pool } from 'pg';
|
|
2
|
+
export type LagVerdict =
|
|
3
|
+
/** No sample yet, or the last one is stale/failed. Reads use the primary. */
|
|
4
|
+
'unknown'
|
|
5
|
+
/** Replay lag is within the threshold. */
|
|
6
|
+
| 'ok'
|
|
7
|
+
/** Replay lag is beyond the threshold. Reads use the primary. */
|
|
8
|
+
| 'lagging';
|
|
9
|
+
/**
|
|
10
|
+
* The circuit's current state, read synchronously by the routing decision.
|
|
11
|
+
*
|
|
12
|
+
* Returns `unknown` rather than throwing or guessing when there is nothing
|
|
13
|
+
* trustworthy to report, and every caller treats `unknown` as "use the
|
|
14
|
+
* primary".
|
|
15
|
+
*/
|
|
16
|
+
export declare function lagVerdict(now?: number): LagVerdict;
|
|
17
|
+
/**
|
|
18
|
+
* Refresh the sample if it is due. Fire-and-forget: never throws, never
|
|
19
|
+
* returns a rejected promise, and resolves as soon as a sample is not needed.
|
|
20
|
+
*
|
|
21
|
+
* `pg_is_in_recovery() = false` means this pool is pointed at a PRIMARY, which
|
|
22
|
+
* is a misconfiguration worth surfacing rather than a lag of zero — but it is
|
|
23
|
+
* reported as lag 0 anyway, because the alternative is refusing to serve reads
|
|
24
|
+
* from a server that is, in fact, able to serve them correctly. The warning is
|
|
25
|
+
* logged once per transition instead.
|
|
26
|
+
*/
|
|
27
|
+
export declare function maybeSampleLag(pool: Pool): Promise<void>;
|
|
28
|
+
/** Test seam: forget the cached sample and failure state. */
|
|
29
|
+
export declare function resetLagStateForTests(): void;
|
|
30
|
+
/** Test seam: install a sample directly, without a database. */
|
|
31
|
+
export declare function setLagSampleForTests(lagSeconds: number, atMs?: number): void;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* The read-replica lag circuit.
|
|
5
|
+
*
|
|
6
|
+
* A standby that has fallen behind does not fail reads — it answers them with
|
|
7
|
+
* old data, confidently and quickly. That is the whole hazard of read-splitting
|
|
8
|
+
* and the reason this module gates the feature: `DB_READ_HOST` must not be
|
|
9
|
+
* configured on any target until this exists.
|
|
10
|
+
*
|
|
11
|
+
* SHAPE: a cached sample, not a per-query check. Asking the standby how far
|
|
12
|
+
* behind it is costs a round-trip, so doing it per read would spend most of the
|
|
13
|
+
* benefit on the measurement. Instead a sample is refreshed at most every
|
|
14
|
+
* `DB_READ_LAG_SAMPLE_MS` in the background, and the routing decision reads the
|
|
15
|
+
* cache synchronously.
|
|
16
|
+
*
|
|
17
|
+
* FAIL CLOSED, THREE WAYS. An unknown lag is treated as unacceptable, so:
|
|
18
|
+
* - before the first sample completes, reads go to the primary;
|
|
19
|
+
* - if the sample query errors, reads go to the primary;
|
|
20
|
+
* - if the cached sample has gone STALE — the sampler stopped running, the
|
|
21
|
+
* pool is wedged — reads go to the primary.
|
|
22
|
+
* The last one matters most: a cache that merely stops updating would otherwise
|
|
23
|
+
* freeze the circuit in whatever state it was last in, which for a healthy
|
|
24
|
+
* reading means "keep using a replica nobody is checking any more".
|
|
25
|
+
*
|
|
26
|
+
* WHY NOT A TIMER: pipeline-data has no scheduler and no leader lock, and a
|
|
27
|
+
* `setInterval` in a library keeps the event loop alive and leaks across tests.
|
|
28
|
+
* Sampling is kicked off opportunistically from the read path instead
|
|
29
|
+
* (fire-and-forget, debounced), so a process that never reads never samples —
|
|
30
|
+
* which is correct, and costs nothing.
|
|
31
|
+
*/
|
|
32
|
+
import { createLogger, emitGauge, envInt } from '@pipeline-builder/api-core';
|
|
33
|
+
const logger = createLogger('database-read-lag');
|
|
34
|
+
/**
|
|
35
|
+
* How far behind a standby may be and still serve reads.
|
|
36
|
+
*
|
|
37
|
+
* Five seconds is a deliberately loose default: this circuit exists to catch a
|
|
38
|
+
* standby that is BROKEN or badly behind, not to provide read-your-writes.
|
|
39
|
+
* Read-after-write is handled separately and exactly, by the write watermark in
|
|
40
|
+
* `tenancy.ts` — a lag threshold cannot do that job at any value, because a
|
|
41
|
+
* replica 200ms behind still has not replayed a commit from 100ms ago.
|
|
42
|
+
* Confusing the two is how a lag threshold ends up tuned to a number that
|
|
43
|
+
* neither protects correctness nor permits any offload.
|
|
44
|
+
*/
|
|
45
|
+
const maxLagSeconds = () => envInt('DB_READ_MAX_LAG_SECONDS', 5);
|
|
46
|
+
const sampleIntervalMs = () => envInt('DB_READ_LAG_SAMPLE_MS', 5000);
|
|
47
|
+
/**
|
|
48
|
+
* How long one sample may take before it is abandoned.
|
|
49
|
+
*
|
|
50
|
+
* THIS IS NOT A PERFORMANCE KNOB, it is what makes the sampler recoverable.
|
|
51
|
+
* Nothing else bounds a running query on this pool — `connectionTimeoutMillis`
|
|
52
|
+
* bounds ACQUIRING a connection and `idleTimeoutMillis` evicts idle ones;
|
|
53
|
+
* neither touches a query already executing. So a wedged connection left
|
|
54
|
+
* `inFlight` true forever, the `finally` never ran, every later call returned
|
|
55
|
+
* at the guard, and no further sample was taken FOR THE LIFE OF THE PROCESS.
|
|
56
|
+
* The cached reading then went stale, the verdict became `unknown`, and every
|
|
57
|
+
* read fell back to the primary permanently — safe, but unrecoverable without
|
|
58
|
+
* a restart, and visible only as PostgresReadCircuitOpen 30 minutes later.
|
|
59
|
+
*/
|
|
60
|
+
const sampleTimeoutMs = () => envInt('DB_READ_LAG_SAMPLE_TIMEOUT_MS', 5000);
|
|
61
|
+
/**
|
|
62
|
+
* Race a query against a timer so the caller always regains control.
|
|
63
|
+
*
|
|
64
|
+
* The abandoned query is left to the pool — Postgres keeps running it, and the
|
|
65
|
+
* pool's own idle handling reclaims the connection. That is deliberate: the
|
|
66
|
+
* alternative is cancelling server-side, which needs a second connection and a
|
|
67
|
+
* PID, and this is a 1-row read whose cost is bounded anyway. What matters is
|
|
68
|
+
* that `inFlight` is released, so the next read retries.
|
|
69
|
+
*
|
|
70
|
+
* `clearTimeout` in `finally` is not tidiness: an un-cleared timer keeps the
|
|
71
|
+
* Node event loop alive, which hangs a test run and, in a short-lived process,
|
|
72
|
+
* delays exit.
|
|
73
|
+
*/
|
|
74
|
+
async function withTimeout(work, ms, what) {
|
|
75
|
+
let timer;
|
|
76
|
+
try {
|
|
77
|
+
return await Promise.race([
|
|
78
|
+
work,
|
|
79
|
+
new Promise((_resolve, reject) => {
|
|
80
|
+
timer = setTimeout(() => reject(new Error(`${what} timed out after ${ms}ms`)), ms);
|
|
81
|
+
timer.unref?.();
|
|
82
|
+
}),
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
if (timer)
|
|
87
|
+
clearTimeout(timer);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** A sample older than this many intervals is treated as no sample at all. */
|
|
91
|
+
const STALE_INTERVALS = 3;
|
|
92
|
+
let sample = null;
|
|
93
|
+
let inFlight = false;
|
|
94
|
+
let consecutiveFailures = 0;
|
|
95
|
+
/**
|
|
96
|
+
* The circuit's current state, read synchronously by the routing decision.
|
|
97
|
+
*
|
|
98
|
+
* Returns `unknown` rather than throwing or guessing when there is nothing
|
|
99
|
+
* trustworthy to report, and every caller treats `unknown` as "use the
|
|
100
|
+
* primary".
|
|
101
|
+
*/
|
|
102
|
+
export function lagVerdict(now = Date.now()) {
|
|
103
|
+
if (!sample)
|
|
104
|
+
return 'unknown';
|
|
105
|
+
if (now - sample.atMs > sampleIntervalMs() * STALE_INTERVALS)
|
|
106
|
+
return 'unknown';
|
|
107
|
+
return sample.lagSeconds > maxLagSeconds() ? 'lagging' : 'ok';
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The lag query, and the one subtlety in this whole module.
|
|
111
|
+
*
|
|
112
|
+
* `now() - pg_last_xact_replay_timestamp()` is the usual lag expression and it
|
|
113
|
+
* is WRONG ON ITS OWN: that timestamp is the commit time of the last replayed
|
|
114
|
+
* transaction, so on an idle primary it simply gets older and older. A standby
|
|
115
|
+
* that is perfectly caught up on a quiet system would report minutes of "lag"
|
|
116
|
+
* and this circuit would send every read back to the primary — permanently,
|
|
117
|
+
* and most visibly at night when nothing is happening.
|
|
118
|
+
*
|
|
119
|
+
* The guard is the LSN comparison first: when everything received has been
|
|
120
|
+
* replayed, the standby is current by definition, whatever the clock says.
|
|
121
|
+
* Only when there is unreplayed WAL does the timestamp mean anything.
|
|
122
|
+
*/
|
|
123
|
+
const LAG_SQL = `
|
|
124
|
+
SELECT CASE
|
|
125
|
+
WHEN NOT pg_is_in_recovery() THEN 0
|
|
126
|
+
WHEN pg_last_wal_receive_lsn() IS NULL THEN NULL
|
|
127
|
+
WHEN pg_last_wal_receive_lsn() = pg_last_wal_replay_lsn() THEN 0
|
|
128
|
+
ELSE GREATEST(0, EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp())))
|
|
129
|
+
END AS lag_seconds
|
|
130
|
+
`;
|
|
131
|
+
/**
|
|
132
|
+
* Refresh the sample if it is due. Fire-and-forget: never throws, never
|
|
133
|
+
* returns a rejected promise, and resolves as soon as a sample is not needed.
|
|
134
|
+
*
|
|
135
|
+
* `pg_is_in_recovery() = false` means this pool is pointed at a PRIMARY, which
|
|
136
|
+
* is a misconfiguration worth surfacing rather than a lag of zero — but it is
|
|
137
|
+
* reported as lag 0 anyway, because the alternative is refusing to serve reads
|
|
138
|
+
* from a server that is, in fact, able to serve them correctly. The warning is
|
|
139
|
+
* logged once per transition instead.
|
|
140
|
+
*/
|
|
141
|
+
export async function maybeSampleLag(pool) {
|
|
142
|
+
const now = Date.now();
|
|
143
|
+
if (inFlight)
|
|
144
|
+
return;
|
|
145
|
+
if (sample && now - sample.atMs < sampleIntervalMs())
|
|
146
|
+
return;
|
|
147
|
+
inFlight = true;
|
|
148
|
+
try {
|
|
149
|
+
const res = await withTimeout(pool.query(LAG_SQL), sampleTimeoutMs(), 'read-replica lag sample');
|
|
150
|
+
const raw = res.rows[0]?.lag_seconds;
|
|
151
|
+
if (raw === null || raw === undefined) {
|
|
152
|
+
// A standby that has never received WAL. Not an error, but not a usable
|
|
153
|
+
// reading either — it must not be recorded as "caught up".
|
|
154
|
+
recordFailure('no WAL received yet');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const lagSeconds = Number(raw);
|
|
158
|
+
if (!Number.isFinite(lagSeconds)) {
|
|
159
|
+
recordFailure(`non-numeric lag value: ${String(raw)}`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (consecutiveFailures > 0) {
|
|
163
|
+
logger.info('Read-replica lag sampling recovered', { afterFailures: consecutiveFailures, lagSeconds });
|
|
164
|
+
consecutiveFailures = 0;
|
|
165
|
+
}
|
|
166
|
+
sample = { lagSeconds, atMs: Date.now() };
|
|
167
|
+
emitGauge('postgres_replica_lag_seconds', {}, lagSeconds);
|
|
168
|
+
emitGauge('postgres_read_circuit_open', {}, lagVerdict() === 'ok' ? 0 : 1);
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
recordFailure(err instanceof Error ? err.message : String(err));
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
inFlight = false;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function recordFailure(reason) {
|
|
178
|
+
consecutiveFailures += 1;
|
|
179
|
+
// Discard the previous sample rather than keeping a stale "ok": a sampler
|
|
180
|
+
// that cannot reach the standby is exactly when reads must not go there.
|
|
181
|
+
sample = null;
|
|
182
|
+
emitGauge('postgres_read_circuit_open', {}, 1);
|
|
183
|
+
// Log the first failure and then back off, so an unreachable standby does not
|
|
184
|
+
// produce a line per read.
|
|
185
|
+
if (consecutiveFailures === 1 || consecutiveFailures % 100 === 0) {
|
|
186
|
+
logger.warn('Read-replica lag sample failed; reads fall back to the primary', {
|
|
187
|
+
reason,
|
|
188
|
+
consecutiveFailures,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/** Test seam: forget the cached sample and failure state. */
|
|
193
|
+
export function resetLagStateForTests() {
|
|
194
|
+
sample = null;
|
|
195
|
+
inFlight = false;
|
|
196
|
+
consecutiveFailures = 0;
|
|
197
|
+
}
|
|
198
|
+
/** Test seam: install a sample directly, without a database. */
|
|
199
|
+
export function setLagSampleForTests(lagSeconds, atMs = Date.now()) {
|
|
200
|
+
sample = { lagSeconds, atMs };
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVhZC1sYWcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGF0YWJhc2UvcmVhZC1sYWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTRCRztBQUVILE9BQU8sRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRzdFLE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0FBRWpEOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLGFBQWEsR0FBRyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMseUJBQXlCLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDakUsTUFBTSxnQkFBZ0IsR0FBRyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsdUJBQXVCLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFDckU7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsTUFBTSxlQUFlLEdBQUcsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLCtCQUErQixFQUFFLElBQUksQ0FBQyxDQUFDO0FBRTVFOzs7Ozs7Ozs7Ozs7R0FZRztBQUNILEtBQUssVUFBVSxXQUFXLENBQUksSUFBZ0IsRUFBRSxFQUFVLEVBQUUsSUFBWTtJQUN0RSxJQUFJLEtBQWdELENBQUM7SUFDckQsSUFBSSxDQUFDO1FBQ0gsT0FBTyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUM7WUFDeEIsSUFBSTtZQUNKLElBQUksT0FBTyxDQUFRLENBQUMsUUFBUSxFQUFFLE1BQU0sRUFBRSxFQUFFO2dCQUN0QyxLQUFLLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxHQUFHLElBQUksb0JBQW9CLEVBQUUsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztnQkFDbkYsS0FBSyxDQUFD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QUMsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDbEUsQ0FBQztZQUFTLENBQUM7UUFDVCxRQUFRLEdBQUcsS0FBSyxDQUFDO0lBQ25CLENBQUM7QUFDSCxDQUFDO0FBRUQsU0FBUyxhQUFhLENBQUMsTUFBYztJQUNuQyxtQkFBbUIsSUFBSSxDQUFDLENBQUM7SUFDekIsMEVBQTBFO0lBQzFFLHlFQUF5RTtJQUN6RSxNQUFNLEdBQUcsSUFBSSxDQUFDO0lBQ2QsU0FBUyxDQUFDLDRCQUE0QixFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUMvQyw4RUFBOEU7SUFDOUUsMkJBQTJCO0lBQzNCLElBQUksbUJBQW1CLEtBQUssQ0FBQyxJQUFJLG1CQUFtQixHQUFHLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUNqRSxNQUFNLENBQUMsSUFBSSxDQUFDLGdFQUFnRSxFQUFFO1lBQzVFLE1BQU07WUFDTixtQkFBbUI7U0FDcEIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztBQUNILENBQUM7QUFFRCw2REFBNkQ7QUFDN0QsTUFBTSxVQUFVLHFCQUFxQjtJQUNuQyxNQUFNLEdBQUcsSUFBSSxDQUFDO0lBQ2QsUUFBUSxHQUFHLEtBQUssQ0FBQztJQUNqQixtQkFBbUIsR0FBRyxDQUFDLENBQUM7QUFDMUIsQ0FBQztBQUVELGdFQUFnRTtBQUNoRSxNQUFNLFVBQVUsb0JBQW9CLENBQUMsVUFBa0IsRUFBRSxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRTtJQUN4RSxNQUFNLEdBQUcsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLENBQUM7QUFDaEMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIFRoZSByZWFkLXJlcGxpY2EgbGFnIGNpcmN1aXQuXG4gKlxuICogQSBzdGFuZGJ5IHRoYXQgaGFzIGZhbGxlbiBiZWhpbmQgZG9lcyBub3QgZmFpbCByZWFkcyDigJQgaXQgYW5zd2VycyB0aGVtIHdpdGhcbiAqIG9sZCBkYXRhLCBjb25maWRlbnRseSBhbmQgcXVpY2tseS4gVGhhdCBpcyB0aGUgd2hvbGUgaGF6YXJkIG9mIHJlYWQtc3BsaXR0aW5nXG4gKiBhbmQgdGhlIHJlYXNvbiB0aGlzIG1vZHVsZSBnYXRlcyB0aGUgZmVhdHVyZTogYERCX1JFQURfSE9TVGAgbXVzdCBub3QgYmVcbiAqIGNvbmZpZ3VyZWQgb24gYW55IHRhcmdldCB1bnRpbCB0aGlzIGV4aXN0cy5cbiAqXG4gKiBTSEFQRTogYSBjYWNoZWQgc2FtcGxlLCBub3QgYSBwZXItcXVlcnkgY2hlY2suIEFza2luZyB0aGUgc3RhbmRieSBob3cgZmFyXG4gKiBiZWhpbmQgaXQgaXMgY29zdHMgYSByb3VuZC10cmlwLCBzbyBkb2luZyBpdCBwZXIgcmVhZCB3b3VsZCBzcGVuZCBtb3N0IG9mIHRoZVxuICogYmVuZWZpdCBvbiB0aGUgbWVhc3VyZW1lbnQuIEluc3RlYWQgYSBzYW1wbGUgaXMgcmVmcmVzaGVkIGF0IG1vc3QgZXZlcnlcbiAqIGBEQl9SRUFEX0xBR19TQU1QTEVfTVNgIGluIHRoZSBiYWNrZ3JvdW5kLCBhbmQgdGhlIHJvdXRpbmcgZGVjaXNpb24gcmVhZHMgdGhlXG4gKiBjYWNoZSBzeW5jaHJvbm91c2x5LlxuICpcbiAqIEZBSUwgQ0xPU0VELCBUSFJFRSBXQVlTLiBBbiB1bmtub3duIGxhZyBpcyB0cmVhdGVkIGFzIHVuYWNjZXB0YWJsZSwgc286XG4gKiAgIC0gYmVmb3JlIHRoZSBmaXJzdCBzYW1wbGUgY29tcGxldGVzLCByZWFkcyBnbyB0byB0aGUgcHJpbWFyeTtcbiAqICAgLSBpZiB0aGUgc2FtcGxlIHF1ZXJ5IGVycm9ycywgcmVhZHMgZ28gdG8gdGhlIHByaW1hcnk7XG4gKiAgIC0gaWYgdGhlIGNhY2hlZCBzYW1wbGUgaGFzIGdvbmUgU1RBTEUg4oCUIHRoZSBzYW1wbGVyIHN0b3BwZWQgcnVubmluZywgdGhlXG4gKiAgICAgcG9vbCBpcyB3ZWRnZWQg4oCUIHJlYWRzIGdvIHRvIHRoZSBwcmltYXJ5LlxuICogVGhlIGxhc3Qgb25lIG1hdHRlcnMgbW9zdDogYSBjYWNoZSB0aGF0IG1lcmVseSBzdG9wcyB1cGRhdGluZyB3b3VsZCBvdGhlcndpc2VcbiAqIGZyZWV6ZSB0aGUgY2lyY3VpdCBpbiB3aGF0ZXZlciBzdGF0ZSBpdCB3YXMgbGFzdCBpbiwgd2hpY2ggZm9yIGEgaGVhbHRoeVxuICogcmVhZGluZyBtZWFucyBcImtlZXAgdXNpbmcgYSByZXBsaWNhIG5vYm9keSBpcyBjaGVja2luZyBhbnkgbW9yZVwiLlxuICpcbiAqIFdIWSBOT1QgQSBUSU1FUjogcGlwZWxpbmUtZGF0YSBoYXMgbm8gc2NoZWR1bGVyIGFuZCBubyBsZWFkZXIgbG9jaywgYW5kIGFcbiAqIGBzZXRJbnRlcnZhbGAgaW4gYSBsaWJyYXJ5IGtlZXBzIHRoZSBldmVudCBsb29wIGFsaXZlIGFuZCBsZWFrcyBhY3Jvc3MgdGVzdHMuXG4gKiBTYW1wbGluZyBpcyBraWNrZWQgb2ZmIG9wcG9ydHVuaXN0aWNhbGx5IGZyb20gdGhlIHJlYWQgcGF0aCBpbnN0ZWFkXG4gKiAoZmlyZS1hbmQtZm9yZ2V0LCBkZWJvdW5jZWQpLCBzbyBhIHByb2Nlc3MgdGhhdCBuZXZlciByZWFkcyBuZXZlciBzYW1wbGVzIOKAlFxuICogd2hpY2ggaXMgY29ycmVjdCwgYW5kIGNvc3RzIG5vdGhpbmcuXG4gKi9cblxuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyLCBlbWl0R2F1Z2UsIGVudkludCB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB0eXBlIHsgUG9vbCB9IGZyb20gJ3BnJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdkYXRhYmFzZS1yZWFkLWxhZycpO1xuXG4vKipcbiAqIEhvdyBmYXIgYmVoaW5kIGEgc3RhbmRieSBtYXkgYmUgYW5kIHN0aWxsIHNlcnZlIHJlYWRzLlxuICpcbiAqIEZpdmUgc2Vjb25kcyBpcyBhIGRlbGliZXJhdGVseSBsb29zZSBkZWZhdWx0OiB0aGlzIGNpcmN1aXQgZXhpc3RzIHRvIGNhdGNoIGFcbiAqIHN0YW5kYnkgdGhhdCBpcyBCUk9LRU4gb3IgYmFkbHkgYmVoaW5kLCBub3QgdG8gcHJvdmlkZSByZWFkLXlvdXItd3JpdGVzLlxuICogUmVhZC1hZnRlci13cml0ZSBpcyBoYW5kbGVkIHNlcGFyYXRlbHkgYW5kIGV4YWN0bHksIGJ5IHRoZSB3cml0ZSB3YXRlcm1hcmsgaW5cbiAqIGB0ZW5hbmN5LnRzYCDigJQgYSBsYWcgdGhyZXNob2xkIGNhbm5vdCBkbyB0aGF0IGpvYiBhdCBhbnkgdmFsdWUsIGJlY2F1c2UgYVxuICogcmVwbGljYSAyMDBtcyBiZWhpbmQgc3RpbGwgaGFzIG5vdCByZXBsYXllZCBhIGNvbW1pdCBmcm9tIDEwMG1zIGFnby5cbiAqIENvbmZ1c2luZyB0aGUgdHdvIGlzIGhvdyBhIGxhZyB0aHJlc2hvbGQgZW5kcyB1cCB0dW5lZCB0byBhIG51bWJlciB0aGF0XG4gKiBuZWl0aGVyIHByb3RlY3RzIGNvcnJlY3RuZXNzIG5vciBwZXJtaXRzIGFueSBvZmZsb2FkLlxuICovXG5jb25zdCBtYXhMYWdTZWNvbmRzID0gKCkgPT4gZW52SW50KCdEQl9SRUFEX01BWF9MQUdfU0VDT05EUycsIDUpO1xuY29uc3Qgc2FtcGxlSW50ZXJ2YWxNcyA9ICgpID0+IGVudkludCgnREJfUkVBRF9MQUdfU0FNUExFX01TJywgNTAwMCk7XG4vKipcbiAqIEhvdyBsb25nIG9uZSBzYW1wbGUgbWF5IHRha2UgYmVmb3JlIGl0IGlzIGFiYW5kb25lZC5cbiAqXG4gKiBUSElTIElTIE5PVCBBIFBFUkZPUk1BTkNFIEtOT0IsIGl0IGlzIHdoYXQgbWFrZXMgdGhlIHNhbXBsZXIgcmVjb3ZlcmFibGUuXG4gKiBOb3RoaW5nIGVsc2UgYm91bmRzIGEgcnVubmluZyBxdWVyeSBvbiB0aGlzIHBvb2wg4oCUIGBjb25uZWN0aW9uVGltZW91dE1pbGxpc2BcbiAqIGJvdW5kcyBBQ1FVSVJJTkcgYSBjb25uZWN0aW9uIGFuZCBgaWRsZVRpbWVvdXRNaWxsaXNgIGV2aWN0cyBpZGxlIG9uZXM7XG4gKiBuZWl0aGVyIHRvdWNoZXMgYSBxdWVyeSBhbHJlYWR5IGV4ZWN1dGluZy4gU28gYSB3ZWRnZWQgY29ubmVjdGlvbiBsZWZ0XG4gKiBgaW5GbGlnaHRgIHRydWUgZm9yZXZlciwgdGhlIGBmaW5hbGx5YCBuZXZlciByYW4sIGV2ZXJ5IGxhdGVyIGNhbGwgcmV0dXJuZWRcbiAqIGF0IHRoZSBndWFyZCwgYW5kIG5vIGZ1cnRoZXIgc2FtcGxlIHdhcyB0YWtlbiBGT1IgVEhFIExJRkUgT0YgVEhFIFBST0NFU1MuXG4gKiBUaGUgY2FjaGVkIHJlYWRpbmcgdGhlbiB3ZW50IHN0YWxlLCB0aGUgdmVyZGljdCBiZWNhbWUgYHVua25vd25gLCBhbmQgZXZlcnlcbiAqIHJlYWQgZmVsbCBiYWNrIHRvIHRoZSBwcmltYXJ5IHBlcm1hbmVudGx5IOKAlCBzYWZlLCBidXQgdW5yZWNvdmVyYWJsZSB3aXRob3V0XG4gKiBhIHJlc3RhcnQsIGFuZCB2aXNpYmxlIG9ubHkgYXMgUG9zdGdyZXNSZWFkQ2lyY3VpdE9wZW4gMzAgbWludXRlcyBsYXRlci5cbiAqL1xuY29uc3Qgc2FtcGxlVGltZW91dE1zID0gKCkgPT4gZW52SW50KCdEQl9SRUFEX0xBR19TQU1QTEVfVElNRU9VVF9NUycsIDUwMDApO1xuXG4vKipcbiAqIFJhY2UgYSBxdWVyeSBhZ2FpbnN0IGEgdGltZXIgc28gdGhlIGNhbGxlciBhbHdheXMgcmVnYWlucyBjb250cm9sLlxuICpcbiAqIFRoZSBhYmFuZG9uZWQgcXVlcnkgaXMgbGVmdCB0byB0aGUgcG9vbCDigJQgUG9zdGdyZXMga2VlcHMgcnVubmluZyBpdCwgYW5kIHRoZVxuICogcG9vbCdzIG93biBpZGxlIGhhbmRsaW5nIHJlY2xhaW1zIHRoZSBjb25uZWN0aW9uLiBUaGF0IGlzIGRlbGliZXJhdGU6IHRoZVxuICogYWx0ZXJuYXRpdmUgaXMgY2FuY2VsbGluZyBzZXJ2ZXItc2lkZSwgd2hpY2ggbmVlZHMgYSBzZWNvbmQgY29ubmVjdGlvbiBhbmQgYVxuICogUElELCBhbmQgdGhpcyBpcyBhIDEtcm93IHJlYWQgd2hvc2UgY29zdCBpcyBib3VuZGVkIGFueXdheS4gV2hhdCBtYXR0ZXJzIGlzXG4gKiB0aGF0IGBpbkZsaWdodGAgaXMgcmVsZWFzZWQsIHNvIHRoZSBuZXh0IHJlYWQgcmV0cmllcy5cbiAqXG4gKiBgY2xlYXJUaW1lb3V0YCBpbiBgZmluYWxseWAgaXMgbm90IHRpZGluZXNzOiBhbiB1bi1jbGVhcmVkIHRpbWVyIGtlZXBzIHRoZVxuICogTm9kZSBldmVudCBsb29wIGFsaXZlLCB3aGljaCBoYW5ncyBhIHRlc3QgcnVuIGFuZCwgaW4gYSBzaG9ydC1saXZlZCBwcm9jZXNzLFxuICogZGVsYXlzIGV4aXQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHdpdGhUaW1lb3V0PFQ+KHdvcms6IFByb21pc2U8VD4sIG1zOiBudW1iZXIsIHdoYXQ6IHN0cmluZyk6IFByb21pc2U8VD4ge1xuICBsZXQgdGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgdW5kZWZpbmVkO1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBQcm9taXNlLnJhY2UoW1xuICAgICAgd29yayxcbiAgICAgIG5ldyBQcm9taXNlPG5ldmVyPigoX3Jlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4gcmVqZWN0KG5ldyBFcnJvcihgJHt3aGF0fSB0aW1lZCBvdXQgYWZ0ZXIgJHttc31tc2ApKSwgbXMpO1xuICAgICAgICB0aW1lci51bnJlZj8uKCk7XG4gICAgICB9KSxcbiAgICBdKTtcbiAgfSBmaW5hbGx5IHtcbiAgICBpZiAodGltZXIpIGNsZWFyVGltZW91dCh0aW1lcik7XG4gIH1cbn1cblxuLyoqIEEgc2FtcGxlIG9sZGVyIHRoYW4gdGhpcyBtYW55IGludGVydmFscyBpcyB0cmVhdGVkIGFzIG5vIHNhbXBsZSBhdCBhbGwuICovXG5jb25zdCBTVEFMRV9JTlRFUlZBTFMgPSAzO1xuXG5pbnRlcmZhY2UgU2FtcGxlIHtcbiAgbGFnU2Vjb25kczogbnVtYmVyO1xuICBhdE1zOiBudW1iZXI7XG59XG5cbmxldCBzYW1wbGU6IFNhbXBsZSB8IG51bGwgPSBudWxsO1xubGV0IGluRmxpZ2h0ID0gZmFsc2U7XG5sZXQgY29uc2VjdXRpdmVGYWlsdXJlcyA9IDA7XG5cbmV4cG9ydCB0eXBlIExhZ1ZlcmRpY3QgPVxuICAvKiogTm8gc2FtcGxlIHlldCwgb3IgdGhlIGxhc3Qgb25lIGlzIHN0YWxlL2ZhaWxlZC4gUmVhZHMgdXNlIHRoZSBwcmltYXJ5LiAqL1xuICB8ICd1bmtub3duJ1xuICAvKiogUmVwbGF5IGxhZyBpcyB3aXRoaW4gdGhlIHRocmVzaG9sZC4gKi9cbiAgfCAnb2snXG4gIC8qKiBSZXBsYXkgbGFnIGlzIGJleW9uZCB0aGUgdGhyZXNob2xkLiBSZWFkcyB1c2UgdGhlIHByaW1hcnkuICovXG4gIHwgJ2xhZ2dpbmcnO1xuXG4vKipcbiAqIFRoZSBjaXJjdWl0J3MgY3VycmVudCBzdGF0ZSwgcmVhZCBzeW5jaHJvbm91c2x5IGJ5IHRoZSByb3V0aW5nIGRlY2lzaW9uLlxuICpcbiAqIFJldHVybnMgYHVua25vd25gIHJhdGhlciB0aGFuIHRocm93aW5nIG9yIGd1ZXNzaW5nIHdoZW4gdGhlcmUgaXMgbm90aGluZ1xuICogdHJ1c3R3b3J0aHkgdG8gcmVwb3J0LCBhbmQgZXZlcnkgY2FsbGVyIHRyZWF0cyBgdW5rbm93bmAgYXMgXCJ1c2UgdGhlXG4gKiBwcmltYXJ5XCIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsYWdWZXJkaWN0KG5vdyA9IERhdGUubm93KCkpOiBMYWdWZXJkaWN0IHtcbiAgaWYgKCFzYW1wbGUpIHJldHVybiAndW5rbm93bic7XG4gIGlmIChub3cgLSBzYW1wbGUuYXRNcyA+IHNhbXBsZUludGVydmFsTXMoKSAqIFNUQUxFX0lOVEVSVkFMUykgcmV0dXJuICd1bmtub3duJztcbiAgcmV0dXJuIHNhbXBsZS5sYWdTZWNvbmRzID4gbWF4TGFnU2Vjb25kcygpID8gJ2xhZ2dpbmcnIDogJ29rJztcbn1cblxuLyoqXG4gKiBUaGUgbGFnIHF1ZXJ5LCBhbmQgdGhlIG9uZSBzdWJ0bGV0eSBpbiB0aGlzIHdob2xlIG1vZHVsZS5cbiAqXG4gKiBgbm93KCkgLSBwZ19sYXN0X3hhY3RfcmVwbGF5X3RpbWVzdGFtcCgpYCBpcyB0aGUgdXN1YWwgbGFnIGV4cHJlc3Npb24gYW5kIGl0XG4gKiBpcyBXUk9ORyBPTiBJVFMgT1dOOiB0aGF0IHRpbWVzdGFtcCBpcyB0aGUgY29tbWl0IHRpbWUgb2YgdGhlIGxhc3QgcmVwbGF5ZWRcbiAqIHRyYW5zYWN0aW9uLCBzbyBvbiBhbiBpZGxlIHByaW1hcnkgaXQgc2ltcGx5IGdldHMgb2xkZXIgYW5kIG9sZGVyLiBBIHN0YW5kYnlcbiAqIHRoYXQgaXMgcGVyZmVjdGx5IGNhdWdodCB1cCBvbiBhIHF1aWV0IHN5c3RlbSB3b3VsZCByZXBvcnQgbWludXRlcyBvZiBcImxhZ1wiXG4gKiBhbmQgdGhpcyBjaXJjdWl0IHdvdWxkIHNlbmQgZXZlcnkgcmVhZCBiYWNrIHRvIHRoZSBwcmltYXJ5IOKAlCBwZXJtYW5lbnRseSxcbiAqIGFuZCBtb3N0IHZpc2libHkgYXQgbmlnaHQgd2hlbiBub3RoaW5nIGlzIGhhcHBlbmluZy5cbiAqXG4gKiBUaGUgZ3VhcmQgaXMgdGhlIExTTiBjb21wYXJpc29uIGZpcnN0OiB3aGVuIGV2ZXJ5dGhpbmcgcmVjZWl2ZWQgaGFzIGJlZW5cbiAqIHJlcGxheWVkLCB0aGUgc3RhbmRieSBpcyBjdXJyZW50IGJ5IGRlZmluaXRpb24sIHdoYXRldmVyIHRoZSBjbG9jayBzYXlzLlxuICogT25seSB3aGVuIHRoZXJlIGlzIHVucmVwbGF5ZWQgV0FMIGRvZXMgdGhlIHRpbWVzdGFtcCBtZWFuIGFueXRoaW5nLlxuICovXG5jb25zdCBMQUdfU1FMID0gYFxuICBTRUxFQ1QgQ0FTRVxuICAgIFdIRU4gTk9UIHBnX2lzX2luX3JlY292ZXJ5KCkgVEhFTiAwXG4gICAgV0hFTiBwZ19sYXN0X3dhbF9yZWNlaXZlX2xzbigpIElTIE5VTEwgVEhFTiBOVUxMXG4gICAgV0hFTiBwZ19sYXN0X3dhbF9yZWNlaXZlX2xzbigpID0gcGdfbGFzdF93YWxfcmVwbGF5X2xzbigpIFRIRU4gMFxuICAgIEVMU0UgR1JFQVRFU1QoMCwgRVhUUkFDVChFUE9DSCBGUk9NIChub3coKSAtIHBnX2xhc3RfeGFjdF9yZXBsYXlfdGltZXN0YW1wKCkpKSlcbiAgRU5EIEFTIGxhZ19zZWNvbmRzXG5gO1xuXG4vKipcbiAqIFJlZnJlc2ggdGhlIHNhbXBsZSBpZiBpdCBpcyBkdWUuIEZpcmUtYW5kLWZvcmdldDogbmV2ZXIgdGhyb3dzLCBuZXZlclxuICogcmV0dXJucyBhIHJlamVjdGVkIHByb21pc2UsIGFuZCByZXNvbHZlcyBhcyBzb29uIGFzIGEgc2FtcGxlIGlzIG5vdCBuZWVkZWQuXG4gKlxuICogYHBnX2lzX2luX3JlY292ZXJ5KCkgPSBmYWxzZWAgbWVhbnMgdGhpcyBwb29sIGlzIHBvaW50ZWQgYXQgYSBQUklNQVJZLCB3aGljaFxuICogaXMgYSBtaXNjb25maWd1cmF0aW9uIHdvcnRoIHN1cmZhY2luZyByYXRoZXIgdGhhbiBhIGxhZyBvZiB6ZXJvIOKAlCBidXQgaXQgaXNcbiAqIHJlcG9ydGVkIGFzIGxhZyAwIGFueXdheSwgYmVjYXVzZSB0aGUgYWx0ZXJuYXRpdmUgaXMgcmVmdXNpbmcgdG8gc2VydmUgcmVhZHNcbiAqIGZyb20gYSBzZXJ2ZXIgdGhhdCBpcywgaW4gZmFjdCwgYWJsZSB0byBzZXJ2ZSB0aGVtIGNvcnJlY3RseS4gVGhlIHdhcm5pbmcgaXNcbiAqIGxvZ2dlZCBvbmNlIHBlciB0cmFuc2l0aW9uIGluc3RlYWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBtYXliZVNhbXBsZUxhZyhwb29sOiBQb29sKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gIGlmIChpbkZsaWdodCkgcmV0dXJuO1xuICBpZiAoc2FtcGxlICYmIG5vdyAtIHNhbXBsZS5hdE1zIDwgc2FtcGxlSW50ZXJ2YWxNcygpKSByZXR1cm47XG4gIGluRmxpZ2h0ID0gdHJ1ZTtcbiAgdHJ5IHtcbiAgICBjb25zdCByZXMgPSBhd2FpdCB3aXRoVGltZW91dChcbiAgICAgIHBvb2wucXVlcnk8eyBsYWdfc2Vjb25kczogc3RyaW5nIHwgbnVtYmVyIHwgbnVsbCB9PihMQUdfU1FMKSxcbiAgICAgIHNhbXBsZVRpbWVvdXRNcygpLFxuICAgICAgJ3JlYWQtcmVwbGljYSBsYWcgc2FtcGxlJyxcbiAgICApO1xuICAgIGNvbnN0IHJhdyA9IHJlcy5yb3dzWzBdPy5sYWdfc2Vjb25kcztcbiAgICBpZiAocmF3ID09PSBudWxsIHx8IHJhdyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAvLyBBIHN0YW5kYnkgdGhhdCBoYXMgbmV2ZXIgcmVjZWl2ZWQgV0FMLiBOb3QgYW4gZXJyb3IsIGJ1dCBub3QgYSB1c2FibGVcbiAgICAgIC8vIHJlYWRpbmcgZWl0aGVyIOKAlCBpdCBtdXN0IG5vdCBiZSByZWNvcmRlZCBhcyBcImNhdWdodCB1cFwiLlxuICAgICAgcmVjb3JkRmFpbHVyZSgnbm8gV0FMIHJlY2VpdmVkIHlldCcpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBsYWdTZWNvbmRzID0gTnVtYmVyKHJhdyk7XG4gICAgaWYgKCFOdW1iZXIuaXNGaW5pdGUobGFnU2Vjb25kcykpIHtcbiAgICAgIHJlY29yZEZhaWx1cmUoYG5vbi1udW1lcmljIGxhZyB2YWx1ZTogJHtTdHJpbmcocmF3KX1gKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKGNvbnNlY3V0aXZlRmFpbHVyZXMgPiAwKSB7XG4gICAgICBsb2dnZXIuaW5mbygnUmVhZC1yZXBsaWNhIGxhZyBzYW1wbGluZyByZWNvdmVyZWQnLCB7IGFmdGVyRmFpbHVyZXM6IGNvbnNlY3V0aXZlRmFpbHVyZXMsIGxhZ1NlY29uZHMgfSk7XG4gICAgICBjb25zZWN1dGl2ZUZhaWx1cmVzID0gMDtcbiAgICB9XG4gICAgc2FtcGxlID0geyBsYWdTZWNvbmRzLCBhdE1zOiBEYXRlLm5vdygpIH07XG4gICAgZW1pdEdhdWdlKCdwb3N0Z3Jlc19yZXBsaWNhX2xhZ19zZWNvbmRzJywge30sIGxhZ1NlY29uZHMpO1xuICAgIGVtaXRHYXVnZSgncG9zdGdyZXNfcmVhZF9jaXJjdWl0X29wZW4nLCB7fSwgbGFnVmVyZGljdCgpID09PSAnb2snID8gMCA6IDEpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICByZWNvcmRGYWlsdXJlKGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKSk7XG4gIH0gZmluYWxseSB7XG4gICAgaW5GbGlnaHQgPSBmYWxzZTtcbiAgfVxufVxuXG5mdW5jdGlvbiByZWNvcmRGYWlsdXJlKHJlYXNvbjogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnNlY3V0aXZlRmFpbHVyZXMgKz0gMTtcbiAgLy8gRGlzY2FyZCB0aGUgcHJldmlvdXMgc2FtcGxlIHJhdGhlciB0aGFuIGtlZXBpbmcgYSBzdGFsZSBcIm9rXCI6IGEgc2FtcGxlclxuICAvLyB0aGF0IGNhbm5vdCByZWFjaCB0aGUgc3RhbmRieSBpcyBleGFjdGx5IHdoZW4gcmVhZHMgbXVzdCBub3QgZ28gdGhlcmUuXG4gIHNhbXBsZSA9IG51bGw7XG4gIGVtaXRHYXVnZSgncG9zdGdyZXNfcmVhZF9jaXJjdWl0X29wZW4nLCB7fSwgMSk7XG4gIC8vIExvZyB0aGUgZmlyc3QgZmFpbHVyZSBhbmQgdGhlbiBiYWNrIG9mZiwgc28gYW4gdW5yZWFjaGFibGUgc3RhbmRieSBkb2VzIG5vdFxuICAvLyBwcm9kdWNlIGEgbGluZSBwZXIgcmVhZC5cbiAgaWYgKGNvbnNlY3V0aXZlRmFpbHVyZXMgPT09IDEgfHwgY29uc2VjdXRpdmVGYWlsdXJlcyAlIDEwMCA9PT0gMCkge1xuICAgIGxvZ2dlci53YXJuKCdSZWFkLXJlcGxpY2EgbGFnIHNhbXBsZSBmYWlsZWQ7IHJlYWRzIGZhbGwgYmFjayB0byB0aGUgcHJpbWFyeScsIHtcbiAgICAgIHJlYXNvbixcbiAgICAgIGNvbnNlY3V0aXZlRmFpbHVyZXMsXG4gICAgfSk7XG4gIH1cbn1cblxuLyoqIFRlc3Qgc2VhbTogZm9yZ2V0IHRoZSBjYWNoZWQgc2FtcGxlIGFuZCBmYWlsdXJlIHN0YXRlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc2V0TGFnU3RhdGVGb3JUZXN0cygpOiB2b2lkIHtcbiAgc2FtcGxlID0gbnVsbDtcbiAgaW5GbGlnaHQgPSBmYWxzZTtcbiAgY29uc2VjdXRpdmVGYWlsdXJlcyA9IDA7XG59XG5cbi8qKiBUZXN0IHNlYW06IGluc3RhbGwgYSBzYW1wbGUgZGlyZWN0bHksIHdpdGhvdXQgYSBkYXRhYmFzZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZXRMYWdTYW1wbGVGb3JUZXN0cyhsYWdTZWNvbmRzOiBudW1iZXIsIGF0TXMgPSBEYXRlLm5vdygpKTogdm9pZCB7XG4gIHNhbXBsZSA9IHsgbGFnU2Vjb25kcywgYXRNcyB9O1xufVxuIl19
|