@pipeline-builder/pipeline-data 4.1.46 → 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.
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9zdGdyZXMtY29ubmVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhYmFzZS9wb3N0Z3Jlcy1jb25uZWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFFLFlBQVksRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ25GLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsSUFBSSxFQUFtQixNQUFNLElBQUksQ0FBQztBQUMzQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDN0MsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFOUQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0FBRXhDLHFEQUFxRDtBQUNyRCxNQUFNLFFBQVEsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsQ0FBQztBQUV4RDs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FBQyxRQUFtQztJQUM5RCxJQUFJLFFBQVEsS0FBSyxTQUFTO1FBQUUsT0FBTyxRQUFRLENBQUM7SUFFNUMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLENBQUM7SUFDaEQsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsV0FBVyxFQUFFLENBQUM7SUFFckQsSUFBSSxPQUFnQixDQUFDO0lBQ3JCLElBQUksS0FBSyxLQUFLLE1BQU0sSUFBSSxLQUFLLEtBQUssR0FBRztRQUFFLE9BQU8sR0FBRyxJQUFJLENBQUM7U0FDakQsSUFBSSxLQUFLLEtBQUssT0FBTyxJQUFJLEtBQUssS0FBSyxHQUFHO1FBQUUsT0FBTyxHQUFHLEtBQUssQ0FBQztTQUN4RCxJQUFJLE9BQU87UUFBRSxPQUFPLEdBQUcsT0FBTyxLQUFLLFNBQVMsQ0FBQzs7UUFDN0MsT0FBTyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLFlBQVksQ0FBQztJQUVyRCxJQUFJLENBQUMsT0FBTztRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQzNCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxPQUFPLENBQUMsNEJBQTRCLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQztBQUM5RSxDQUFDO0FBRUQsU0FBUyxpQkFBaUI7SUFDeEIsaUZBQWlGO0lBQ2pGLDBEQUEwRDtJQUMxRCxNQUFNLGVBQWUsR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQzFDLE1BQU0sa0JBQWtCLEdBQUcsUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztJQUVwRCxPQUFPO1FBQ0wsSUFBSSxFQUFFLE1BQU0sQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDO1FBQ25DLElBQUksRUFBRSxNQUFNLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQztRQUM3QixRQUFRLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRSxrQkFBa0IsQ0FBQztRQUNoRCxJQUFJLEVBQUUsTUFBTSxDQUFDLFNBQVMsRUFBRSxVQUFVLENBQUM7UUFDbkMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEtBQUssWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxHQUFHLE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFZLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNySyxXQUFXLEVBQUUsTUFBTSxDQUFDLHVCQUF1QixFQUFFLGVBQWUsQ0FBQztRQUM3RCxpQkFBaUIsRUFBRSxNQUFNLENBQUMsNkJBQTZCLEVBQUUsa0JBQWtCLENBQUM7UUFDNUUsdUJBQXVCLEVBQUUsTUFBTSxDQUFDLG1DQUFtQyxFQUFFLElBQUksQ0FBQztLQUMzRSxDQUFDO0FBQ0osQ0FBQztBQStCRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUNILE1BQU0sT0FBTyxVQUFVO0lBQ2IsTUFBTSxDQUFDLFFBQVEsR0FBc0IsSUFBSSxDQUFDO0lBRWxEOztPQUVHO0lBQ2EsRUFBRSxDQUE2QjtJQUU5QixJQUFJLENBQU87SUFDWCxPQUFPLENBQThCO0lBQ3JDLGFBQWEsQ0FBMEI7SUFDaEQsY0FBYyxHQUFHLEtBQUssQ0FBQztJQUUvQjs7Ozs7O09BTUc7SUFDSCxZQUFvQixPQUFPLEdBQXNCLEVBQUU7UUFDakQsSUFBSSxDQUFDLE9BQU8sR0FBRztZQUNiLGFBQWEsRUFBRSxPQUFPLENBQUMsYUFBYSxJQUFJLElBQUk7WUFDNUMsZUFBZSxFQUFFLE9BQU8sQ0FBQyxlQUFlLElBQUksSUFBSTtZQUNoRCxVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVUsSUFBSSxNQUFNLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQ3pFLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVSxJQUFJLE1BQU0sQ0FBQyxtQkFBbUIsRUFBRSxJQUFJLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUM7WUFDL0UseUVBQXlFO1lBQ3pFLHdFQUF3RTtZQUN4RSxnREFBZ0Q7WUFDaEQsR0FBRyxFQUFFLFlBQVksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDO1NBQy9CLENBQUM7UUFFRiw0QkFBNEI7UUFDNUIsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLHVCQUF1QixDQUFDO1lBQy9DLFVBQVUsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVU7WUFDbkMsWUFBWSxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVTtTQUN0QyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUM7WUFDSCxNQUFNLE1BQU0sR0FBRyxpQkFBaUIsRUFBRSxDQUFDO1lBRW5DLE1BQU0sVUFBVSxHQUFlO2dCQUM3QixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7Z0JBQ2pCLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSTtnQkFDakIsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRO2dCQUN6QixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUk7Z0JBQ2pCLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUTtnQkFDekIsR0FBRyxFQUFFLE1BQU0sQ0FBQyxXQUFXO2dCQUN2QixpQkFBaUIsRUFBRSxNQUFNLENBQUMsaUJBQWlCO2dCQUMzQyx1QkFBdUIsRUFBRSxNQUFNLENBQUMsdUJBQXVCO2dCQUN2RCxHQUFHLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHO2dCQUNyQixlQUFlLEVBQUUsSUFBSTthQUN0QixDQUFDO1lBRUYsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUNqQyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztZQUUxQixJQUFJLENBQUMsRUFBRSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztZQUV6QyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUM7Z0JBQy9CLE1BQU0sQ0FBQyxJQUFJLENBQUMsOENBQThDLENBQUMsQ0FBQztnQkFDNUQsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ3ZDLENBQUM7UUFDSCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsMkNBQTJDLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDakUsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1FBQ3BELENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ksTUFBTSxDQUFDLFdBQVcsQ0FBQyxPQUEyQjtRQUNuRCxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3pCLFVBQVUsQ0FBQyxRQUFRLEdBQUcsSUFBSSxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDaEQsQ0FBQztRQUNELE9BQU8sVUFBVSxDQUFDLFFBQVEsQ0FBQztJQUM3QixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxNQUFNLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxhQUFhLEdBQVksSUFBSTtRQUNyRCxJQUFJLFVBQVUsQ0FBQyxRQUFRLElBQUksYUFBYSxFQUFFLENBQUM7WUFDekMsTUFBTSxVQUFVLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ3BDLENBQUM7UUFDRCxVQUFVLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztJQUM3QixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLEtBQUssQ0FBQyxjQUFjO1FBQ3pCLElBQUksQ0FBQztZQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUN6QywyRUFBMkU7WUFDM0UseUVBQXlFO1lBQ3pFLHNDQUFzQztZQUN0QyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxNQUFNLEdBQUcsTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUM5QyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUM7b0JBQy9CLE1BQU0sQ0FBQyxJQUFJLENBQUMscUNBQXFDLENBQUMsQ0FBQztnQkFDckQsQ0FBQztnQkFDRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztZQUNoQyxDQUFDO29CQUFTLENBQUM7Z0JBQ1QsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ25CLENBQUM7UUFDSCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsa0NBQWtDLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDeEQsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxRQUFRO1FBQ2IsT0FBTztZQUNMLFVBQVUsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVU7WUFDaEMsU0FBUyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUztZQUM5QixZQUFZLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZO1NBQ3JDLENBQUM7SUFDSixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ksS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFPLEdBQVcsTUFBTSxDQUFDLHFCQUFxQixFQUFFLElBQUksQ0FBQztRQUN0RSxJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN4QixNQUFNLENBQUMsSUFBSSxDQUFDLHFDQUFxQyxDQUFDLENBQUM7WUFDbkQsT0FBTztRQUNULENBQUM7UUFFRCxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQztRQUUzQixJQUFJLENBQUM7WUFDSCxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUM7Z0JBQy9CLE1BQU0sQ0FBQyxJQUFJLENBQUMscUNBQXFDLENBQUMsQ0FBQztnQkFDbkQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUM5QixNQUFNLENBQUMsSUFBSSxDQUFDLHVCQUF1QixLQUFLLENBQUMsVUFBVSxXQUFXLEtBQUssQ0FBQyxTQUFTLGNBQWMsS0FBSyxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUM7WUFDbkgsQ0FBQztZQUVELHNDQUFzQztZQUN0QyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ3JDLE1BQU0sY0FBYyxHQUFHLElBQUksT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxFQUFFLENBQy9DLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsMEJBQTBCLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUN6RSxDQUFDO1lBRUYsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsWUFBWSxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUM7WUFFbkQsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUMvQixNQUFNLENBQUMsSUFBSSxDQUFDLHlDQUF5QyxDQUFDLENBQUM7WUFDekQsQ0FBQztRQUNILENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxDQUFDLEtBQUssQ0FBQyxvQ0FBb0MsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMxRCxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7Z0JBQVMsQ0FBQztZQUNULElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFDO1FBQzlCLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLFNBQVM7UUFDZCxPQUFPLElBQUksQ0FBQyxjQUFjLENBQUM7SUFDN0IsQ0FBQztJQUVEOztPQUVHO0lBQ0ssa0JBQWtCO1FBQ3hCLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFO1lBQzVCLE1BQU0sQ0FBQyxLQUFLLENBQUMsa0NBQWtDLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFFdEQsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLGVBQWUsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQy9GLEtBQUssSUFBSSxDQUFDLGFBQWEsQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUU7b0JBQ2pHLE1BQU0sQ0FBQyxLQUFLLENBQUMseUJBQXlCLEVBQUUsUUFBUSxDQUFDLENBQUM7Z0JBQ3BELENBQUMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsU0FBUyxFQUFFLEdBQUcsRUFBRTtZQUMzQixJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsaUNBQWlDO1lBRTdELElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQztnQkFDL0IsTUFBTSxDQUFDLEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxDQUFDO1lBQ3RELENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUU7WUFDMUIsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUMvQixNQUFNLENBQUMsS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUM7WUFDM0MsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0ssbUJBQW1CLENBQUMsTUFBa0I7UUFDNUMsTUFBTSxDQUFDLElBQUksQ0FBQyx5QkFBeUIsRUFBRTtZQUNyQyxJQUFJLEVBQUUsR0FBRyxNQUFNLENBQUMsSUFBSSxJQUFJLE1BQU0sQ0FBQyxJQUFJLEVBQUU7WUFDckMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRO1lBQ3pCLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSTtZQUNqQixXQUFXLEVBQUUsTUFBTSxDQUFDLEdBQUc7WUFDdkIsYUFBYSxFQUFFLE1BQU0sQ0FBQyxpQkFBaUI7WUFDdkMsbUJBQW1CLEVBQUUsTUFBTSxDQUFDLHVCQUF1QjtZQUNuRCxHQUFHLEVBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxVQUFVO1NBQ3pDLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBRUgsNkRBQTZEO0FBQzdELElBQUksV0FBVyxHQUFzQyxJQUFJLENBQUM7QUFFMUQ7OztHQUdHO0FBQ0gsU0FBUyxhQUFhO0lBQ3BCLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNqQixXQUFXLEdBQUcsVUFBVSxDQUFDLFdBQVcsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUM1QyxDQUFDO0lBQ0QsT0FBTyxXQUFXLENBQUM7QUFDckIsQ0FBQztBQUVEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sRUFBRSxHQUFHLElBQUksS0FBSyxDQUFDLEVBQWdDLEVBQUU7SUFDNUQsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFxQjtRQUMxQixNQUFNLFFBQVEsR0FBRyxhQUFhLEVBQUUsQ0FBQztRQUNqQyxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsSUFBNkIsQ0FBQyxDQUFDO1FBQ3RELDBEQUEwRDtRQUMxRCxJQUFJLE9BQU8sS0FBSyxLQUFLLFVBQVUsRUFBRSxDQUFDO1lBQ2hDLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUM5QixDQUFDO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0NBQ0YsQ0FBQyxDQUFDO0FBRUg7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFNLFVBQVUsYUFBYTtJQUMzQixPQUFPLFVBQVUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztBQUNsQyxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsZUFBZTtJQUNuQyxNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDNUMsTUFBTSxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDekIsV0FBVyxHQUFHLElBQUksQ0FBQyxDQUFDLHNCQUFzQjtBQUM1QyxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGNBQWM7SUFDbEMsTUFBTSxVQUFVLEdBQUcsVUFBVSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzVDLE9BQU8sVUFBVSxDQUFDLGNBQWMsRUFBRSxDQUFDO0FBQ3JDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyLCBlbnZCb29sLCBlbnZJbnQsIGVudlN0ciB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IGRyaXp6bGUgfSBmcm9tICdkcml6emxlLW9ybS9ub2RlLXBvc3RncmVzJztcbmltcG9ydCB7IFBvb2wsIHR5cGUgUG9vbENvbmZpZyB9IGZyb20gJ3BnJztcbmltcG9ydCB7IHNjaGVtYSB9IGZyb20gJy4vZHJpenpsZS1zY2hlbWEuanMnO1xuaW1wb3J0IHsgQ29ubmVjdGlvblJldHJ5U3RyYXRlZ3kgfSBmcm9tICcuL3JldHJ5LXN0cmF0ZWd5LmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdkYXRhYmFzZScpO1xuXG4vKiogRGV0ZWN0IExhbWJkYSBlbnZpcm9ubWVudCBmb3IgcG9vbC1zaXplIHR1bmluZyAqL1xuY29uc3QgaXNMYW1iZGEgPSAhIXByb2Nlc3MuZW52LkFXU19MQU1CREFfRlVOQ1RJT05fTkFNRTtcblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBwZyBUTFMvU1NMIGNvbmZpZyBmcm9tIGFuIGV4cGxpY2l0IG9wdGlvbiBvciB0aGUgZW52aXJvbm1lbnQsXG4gKiBmb2xsb3dpbmcgdGhlIHNhbWUgZW52LXR1bmFibGUgcGF0dGVybiBhcyB0aGUgcG9vbCBzaXppbmcgYWJvdmUuXG4gKlxuICogUHJlY2VkZW5jZTpcbiAqICAgMS4gQW4gZXhwbGljaXQgYG9wdGlvbnMuc3NsYCAoY29uc3RydWN0b3IgYXJnKSBhbHdheXMgd2lucyDigJQgaW5jbHVkaW5nIGFuXG4gKiAgICAgIGV4cGxpY2l0IGBmYWxzZWAgdG8gZm9yY2UgcGxhaW50ZXh0LlxuICogICAyLiBgREJfU1NMYCAoYHRydWVgL2AxYCBvbiwgYGZhbHNlYC9gMGAgb2ZmKSBvciBQb3N0Z3Jlcycgc3RhbmRhcmRcbiAqICAgICAgYFBHU1NMTU9ERWAgKGBkaXNhYmxlYCA9IG9mZiwgYW55IG90aGVyIG1vZGUgPSBvbikuXG4gKiAgIDMuIERlZmF1bHQ6IE9OIGluIHByb2R1Y3Rpb24gKFJEUyBjb25uZWN0aW9ucyBtdXN0IGJlIGVuY3J5cHRlZCBpbiB0cmFuc2l0KSxcbiAqICAgICAgT0ZGIGV2ZXJ5d2hlcmUgZWxzZSBzbyBhIGxvY2FsIFBvc3RncmVzIHdpdGhvdXQgVExTIGtlZXBzIHdvcmtpbmcuXG4gKlxuICogV2hlbiBlbmFibGVkLCBgcmVqZWN0VW5hdXRob3JpemVkYCBmb2xsb3dzIGBEQl9TU0xfUkVKRUNUX1VOQVVUSE9SSVpFRGBcbiAqIChkZWZhdWx0IGBmYWxzZWApOiBBV1MgUkRTIHByZXNlbnRzIGEgY2VydCBzaWduZWQgYnkgdGhlIFJEUyBDQSwgd2hpY2ggaXMgbm90XG4gKiBpbiBOb2RlJ3MgZGVmYXVsdCB0cnVzdCBzdG9yZSB1bmxlc3MgdGhlIENBIGJ1bmRsZSBpcyBtb3VudGVkLCBzbyBjZXJ0aWZpY2F0ZVxuICogVkVSSUZJQ0FUSU9OIGlzIG9wdC1pbiB0byBhdm9pZCBicmVha2luZyBhIHN0b2NrIFJEUyBkZXBsb3kg4oCUIHRoZSBjaGFubmVsIGlzXG4gKiBzdGlsbCBFTkNSWVBURUQuIFNldCBgREJfU1NMX1JFSkVDVF9VTkFVVEhPUklaRUQ9dHJ1ZWAgb25jZSB0aGUgUkRTIENBIGJ1bmRsZVxuICogaXMgd2lyZWQgdG8gZ2V0IGZ1bGwgdmVyaWZpY2F0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U3NsQ29uZmlnKGV4cGxpY2l0PzogQ29ubmVjdGlvbk9wdGlvbnNbJ3NzbCddKTogYm9vbGVhbiB8IHsgcmVqZWN0VW5hdXRob3JpemVkOiBib29sZWFuIH0ge1xuICBpZiAoZXhwbGljaXQgIT09IHVuZGVmaW5lZCkgcmV0dXJuIGV4cGxpY2l0O1xuXG4gIGNvbnN0IGRiU3NsID0gcHJvY2Vzcy5lbnYuREJfU1NMPy50b0xvd2VyQ2FzZSgpO1xuICBjb25zdCBzc2xNb2RlID0gcHJvY2Vzcy5lbnYuUEdTU0xNT0RFPy50b0xvd2VyQ2FzZSgpO1xuXG4gIGxldCBlbmFibGVkOiBib29sZWFuO1xuICBpZiAoZGJTc2wgPT09ICd0cnVlJyB8fCBkYlNzbCA9PT0gJzEnKSBlbmFibGVkID0gdHJ1ZTtcbiAgZWxzZSBpZiAoZGJTc2wgPT09ICdmYWxzZScgfHwgZGJTc2wgPT09ICcwJykgZW5hYmxlZCA9IGZhbHNlO1xuICBlbHNlIGlmIChzc2xNb2RlKSBlbmFibGVkID0gc3NsTW9kZSAhPT0gJ2Rpc2FibGUnO1xuICBlbHNlIGVuYWJsZWQgPSBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ3Byb2R1Y3Rpb24nO1xuXG4gIGlmICghZW5hYmxlZCkgcmV0dXJuIGZhbHNlO1xuICByZXR1cm4geyByZWplY3RVbmF1dGhvcml6ZWQ6IGVudkJvb2woJ0RCX1NTTF9SRUpFQ1RfVU5BVVRIT1JJWkVEJywgZmFsc2UpIH07XG59XG5cbmZ1bmN0aW9uIGdldERhdGFiYXNlQ29uZmlnKCkge1xuICAvLyBMYW1iZGE6IHNtYWxsIHBvb2wgKGVhY2ggaW52b2NhdGlvbiBpcyBzaG9ydC1saXZlZCwgbWFueSBjb25jdXJyZW50IGluc3RhbmNlcylcbiAgLy8gRUNTL2xvbmctcnVubmluZzogbGFyZ2VyIHBvb2wgZm9yIHN1c3RhaW5lZCBjb25jdXJyZW5jeVxuICBjb25zdCBkZWZhdWx0UG9vbFNpemUgPSBpc0xhbWJkYSA/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