sliftutils 1.7.71 → 1.7.73

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.
Files changed (62) hide show
  1. package/index.d.ts +506 -257
  2. package/misc/https/dist/hostServer.ts.cache +5 -2
  3. package/package.json +1 -1
  4. package/spec.txt +10 -0
  5. package/storage/ArchivesDisk.d.ts +4 -13
  6. package/storage/ArchivesDisk.ts +6 -4
  7. package/storage/IArchives.d.ts +15 -10
  8. package/storage/IArchives.ts +19 -6
  9. package/storage/backblaze.d.ts +3 -9
  10. package/storage/backblaze.ts +22 -19
  11. package/storage/dist/ArchivesDisk.ts.cache +5 -2
  12. package/storage/dist/IArchives.ts.cache +17 -3
  13. package/storage/dist/backblaze.ts.cache +35 -26
  14. package/storage/remoteStorage/ArchivesRemote.d.ts +5 -9
  15. package/storage/remoteStorage/ArchivesRemote.ts +25 -20
  16. package/storage/remoteStorage/ArchivesUrl.d.ts +3 -9
  17. package/storage/remoteStorage/ArchivesUrl.ts +7 -5
  18. package/storage/remoteStorage/accessPage.tsx +4 -4
  19. package/storage/remoteStorage/accessStats.d.ts +2 -0
  20. package/storage/remoteStorage/accessStats.ts +32 -0
  21. package/storage/remoteStorage/blobStore.d.ts +193 -88
  22. package/storage/remoteStorage/blobStore.ts +535 -400
  23. package/storage/remoteStorage/bucketDisk.d.ts +18 -0
  24. package/storage/remoteStorage/bucketDisk.ts +66 -0
  25. package/storage/remoteStorage/createArchives.d.ts +4 -10
  26. package/storage/remoteStorage/createArchives.ts +103 -62
  27. package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +28 -19
  28. package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +7 -4
  29. package/storage/remoteStorage/dist/accessPage.tsx.cache +6 -6
  30. package/storage/remoteStorage/dist/accessStats.ts.cache +38 -3
  31. package/storage/remoteStorage/dist/blobStore.ts.cache +516 -374
  32. package/storage/remoteStorage/dist/bucketDisk.ts.cache +72 -0
  33. package/storage/remoteStorage/dist/createArchives.ts.cache +114 -57
  34. package/storage/remoteStorage/dist/intermediateSources.ts.cache +12 -12
  35. package/storage/remoteStorage/dist/remoteConfig.ts.cache +18 -2
  36. package/storage/remoteStorage/dist/serverConfig.ts.cache +116 -0
  37. package/storage/remoteStorage/dist/sourceWrapper.ts.cache +6 -5
  38. package/storage/remoteStorage/dist/sourcesList.ts.cache +5 -2
  39. package/storage/remoteStorage/dist/storageController.ts.cache +223 -190
  40. package/storage/remoteStorage/dist/storageServer.ts.cache +9 -9
  41. package/storage/remoteStorage/dist/storageServerState.ts.cache +329 -566
  42. package/storage/remoteStorage/dist/storePlan.ts.cache +149 -0
  43. package/storage/remoteStorage/dist/validation.ts.cache +40 -0
  44. package/storage/remoteStorage/grantAccessCli.ts +1 -1
  45. package/storage/remoteStorage/intermediateSources.d.ts +3 -5
  46. package/storage/remoteStorage/intermediateSources.ts +14 -16
  47. package/storage/remoteStorage/remoteConfig.d.ts +2 -2
  48. package/storage/remoteStorage/remoteConfig.ts +19 -3
  49. package/storage/remoteStorage/serverConfig.d.ts +27 -0
  50. package/storage/remoteStorage/serverConfig.ts +109 -0
  51. package/storage/remoteStorage/sourceWrapper.d.ts +3 -3
  52. package/storage/remoteStorage/sourceWrapper.ts +7 -6
  53. package/storage/remoteStorage/sourcesList.ts +3 -0
  54. package/storage/remoteStorage/storageController.d.ts +118 -36
  55. package/storage/remoteStorage/storageController.ts +166 -168
  56. package/storage/remoteStorage/storageServer.ts +1 -1
  57. package/storage/remoteStorage/storageServerState.d.ts +52 -63
  58. package/storage/remoteStorage/storageServerState.ts +340 -584
  59. package/storage/remoteStorage/storePlan.d.ts +34 -0
  60. package/storage/remoteStorage/storePlan.ts +166 -0
  61. package/storage/remoteStorage/validation.d.ts +4 -0
  62. package/storage/remoteStorage/validation.ts +31 -0
@@ -87,6 +87,9 @@ async function runMainPortAcquireLoop(domain, mainPort, servingPort, fallback) {
87
87
  let acquired = await new Promise(resolve => {
88
88
  let relay = net_1.default.createServer(client => {
89
89
  let upstream = net_1.default.connect({ host: "127.0.0.1", port: servingPort });
90
+ // Without this every relayed request pays the ~40ms delayed-ACK timer: a call is a small write (often a header then a body), Nagle holds the second write until the first is acknowledged, and the peer has nothing to piggyback the ACK on. Measured as 43ms per call through the relay versus 1ms direct.
91
+ client.setNoDelay(true);
92
+ upstream.setNoDelay(true);
90
93
  client.pipe(upstream);
91
94
  upstream.pipe(client);
92
95
  let cleanup = () => {
@@ -172,5 +175,5 @@ async function runCertRenewalLoop(domain, onNewCert) {
172
175
  }
173
176
  }
174
177
  }
175
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaG9zdFNlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImhvc3RTZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsNENBQW9CO0FBQ3BCLDRDQUFvQjtBQUNwQiw4Q0FBc0I7QUFDdEIsbUVBQWdFO0FBQ2hFLDZEQUFrRTtBQUNsRSxtREFBd0Q7QUFDeEQsMkRBQXFEO0FBQ3JELCtEQUErRDtBQUMvRCxpRUFBOEQ7QUFDOUQsd0VBQW1FO0FBQ25FLG1DQUE0RTtBQUM1RSw2Q0FBc0U7QUFDdEUsK0JBQWtDO0FBRWxDLHlUQUF5VDtBQUN6VCxNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLG1CQUFtQixHQUFHLG1CQUFZLEdBQUcsRUFBRSxDQUFDO0FBRTlDLGlHQUFpRztBQUNqRyxNQUFNLGNBQWMsR0FBRyxtQkFBbUIsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxtQkFBbUIsR0FBRyxtQkFBbUIsQ0FBQyxDQUFDO0FBdUJ6RyxpVEFBaVQ7QUFDMVMsS0FBSyxVQUFVLFVBQVUsQ0FBQyxNQUF3Qjs7SUFDckQsSUFBSSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxNQUFNLENBQUM7SUFDOUIsZ0dBQWdHO0lBQ2hHLElBQUksVUFBVSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3ZELE1BQU0sSUFBQSxzQkFBYyxFQUFDLFVBQVUsQ0FBQyxDQUFDO0lBRWpDLElBQUksTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3RCLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxRQUFRLElBQUksTUFBTSxJQUFBLDBCQUFhLEdBQUUsQ0FBQztRQUNsRCxNQUFNLElBQUEsZUFBUyxFQUFDLEdB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QUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDcEcsT0FBTyxFQUFFLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDcEQsQ0FBQztBQXhCRCw4Q0F3QkM7QUFFRCxLQUFLLFVBQVUsa0JBQWtCLENBQUMsTUFBYyxFQUFFLFNBQTJEOztJQUN6RyxJQUFJLFFBQVEsR0FBRyxNQUFBLGdCQUFnQixDQUFDLE1BQU0sQ0FBQywwQ0FBRSxJQUFJLENBQUM7SUFDOUMsT0FBTyxJQUFJLEVBQUUsQ0FBQztRQUNWLE1BQU0sSUFBQSxnQkFBSyxFQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDakMsSUFBSSxDQUFDO1lBQ0QsSUFBSSxPQUFPLEdBQUcsTUFBTSxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUM5QyxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQzVCLFFBQVEsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDO2dCQUN4QixPQUFPLENBQUMsR0FBRyxDQUFDLElBQUEsbUJBQU8sRUFBQyxrQkFBa0IsTUFBTSxzQ0FBc0MsQ0FBQyxDQUFDLENBQUM7Z0JBQ3JGLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN2QixDQUFDO1FBQ0wsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDVCxPQUFPLENBQUMsS0FBSyxDQUFDLHdDQUF3QyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUN2RSxDQUFDO0lBQ0wsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgb3MgZnJvbSBcIm9zXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzXCI7XG5pbXBvcnQgbmV0IGZyb20gXCJuZXRcIjtcbmltcG9ydCB7IFNvY2tldEZ1bmN0aW9uIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9Tb2NrZXRGdW5jdGlvblwiO1xuaW1wb3J0IHsgZ2V0Tm9kZUlkTG9jYXRpb24gfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9ub2RlQ2FjaGVcIjtcbmltcG9ydCB7IHRpbWVJbk1pbnV0ZSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL21pc2NcIjtcbmltcG9ydCB7IGRlbGF5IH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvYmF0Y2hpbmdcIjtcbmltcG9ydCB7IGdldEV4dGVybmFsSVAgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9uZXR3b3JraW5nXCI7XG5pbXBvcnQgeyBmb3J3YXJkUG9ydCB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL2ZvcndhcmRQb3J0XCI7XG5pbXBvcnQgeyBtYWdlbnRhIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvZm9ybWF0dGluZy9sb2dDb2xvcnNcIjtcbmltcG9ydCB7IGdldE93bk1hY2hpbmVJZCwgZ2V0VGhyZWFkS2V5Q2VydCwgbG9hZElkZW50aXR5Q0EgfSBmcm9tIFwiLi9jZXJ0c1wiO1xuaW1wb3J0IHsgZ2VuZXJhdGVDZXJ0LCBnZXRBY2NvdW50S2V5LCBwYXJzZUNlcnQgfSBmcm9tIFwiLi9odHRwc0NlcnRzXCI7XG5pbXBvcnQgeyBzZXRSZWNvcmQgfSBmcm9tIFwiLi9kbnNcIjtcblxuLy8gUmVuZXcgc29tZXdoZXJlIHJhbmRvbWx5IGJldHdlZW4gNDAlIGFuZCA2MCUgb2YgdGhlIHdheSB0aHJvdWdoIHRoZSBjZXJ0IGxpZmV0aW1lLiBUaGUgcmFuZG9tIHRocmVzaG9sZCBzdGFnZ2VycyBwYXJhbGxlbCBwcm9jZXNzZXMgb24gdGhlIHNhbWUgbWFjaGluZSwgc28gdXN1YWxseSBvbmUgcHJvY2VzcyByZW5ld3MgZWFybHksIGFuZCB0aGUgb3RoZXJzIHNlZSB0aGUgcmVuZXdlZCBjZXJ0IG9uIGRpc2sgKHdlIHJlLXJlYWQgdGhlIGRpc2sgYmVmb3JlIGV2ZXJ5IHJlbmV3YWwgY2hlY2spIGFuZCBuZXZlciByZW5ldyB0aGVtc2VsdmVzLlxuY29uc3QgUkVORVdfVEhSRVNIT0xEX01JTiA9IDAuNDtcbmNvbnN0IFJFTkVXX1RIUkVTSE9MRF9NQVggPSAwLjY7XG5jb25zdCBDRVJUX0NIRUNLX0lOVEVSVkFMID0gdGltZUluTWludXRlICogMTU7XG5cbi8vIE9uZSB0aHJlc2hvbGQgcGVyIHByb2Nlc3MsIHNvIGEgcHJvY2VzcyBpcyBjb25zaXN0ZW50bHkgZWFybHkgb3IgbGF0ZSByZWxhdGl2ZSB0byBpdHMgc2libGluZ3NcbmNvbnN0IHJlbmV3VGhyZXNob2xkID0gUkVORVdfVEhSRVNIT0xEX01JTiArIE1hdGgucmFuZG9tKCkgKiAoUkVORVdfVEhSRVNIT0xEX01BWCAtIFJFTkVXX1RIUkVTSE9MRF9NSU4pO1xuXG5leHBvcnQgdHlwZSBIb3N0U2VydmVyQ29uZmlnID0ge1xuICAgIC8qKiBGdWxsIGRvbWFpbiB0byBob3N0IG9uIChlLmcuIFwidGVzdHNpdGUuZXhhbXBsZS5jb21cIikuIFRoZSBIVFRQUyBjZXJ0IGlzIGNyZWF0ZWQgZm9yIHRoaXMgZG9tYWluIGFuZCAqLmRvbWFpbiwgc28gdXNpbmcgYSBzdWJkb21haW4gbmV2ZXIgdG91Y2hlcyB0aGUgcm9vdCBkb21haW4gKGJleW9uZCBpdHMgX2FjbWUtY2hhbGxlbmdlIFRYVCByZWNvcmQpLiAqL1xuICAgIGRvbWFpbjogc3RyaW5nO1xuICAgIHBvcnQ6IG51bWJlcjtcblxuICAgIC8vIFRPRE86IEV2ZW50dWFsbHkgd2Ugc2hvdWxkIHN1cHBvcnQgcnVubmluZyB3aXRob3V0IENsb3VkZmxhcmUgQVBJIHRva2Vucy4gSXQncyBhbm5veWluZyB0aG91Z2ggYXMgdGhlIHVzZXIgd2lsbCBoYXZlIHRvIGNyZWF0ZSBhIHNlbGYtc2lnbmVkIGNlcnRpZmljYXRlIGFuZCB0aGVuIHRoZXknbGwgaGF2ZSB0byBnbyB0aHJvdWdoIGFuZCB0cnVzdCBpdCBldmVyeXdoZXJlLCBhbmQgYSBsb3Qgb2YgdGhlIHN0dWZmIGlzIHRyYW5zcGFyZW50LCBhbmQgc28gaXQnbGwgaGF2ZSB0byBiZSBub24tdHJhbnNwYXJlbnQsIGdldHRpbmcgdGhlIHVzZXIgdG8gZ28gdG8gdGhlIHBhZ2UgdGhhdCBvd25zIHRoZSBkb21haW4gYW5kIHRydXN0IGl0IGZyb20gdGhlcmUuIEl0J3MgbXVjaCBiZXR0ZXIganVzdCBtYWtlIGEgQ2xvdWRmbGFyZSBhY2NvdW50LiBZb3UgY2FuIGJ1eSBhIGRvbWFpbiBmb3IgJDE1IGEgeWVhciwgYW5kIHRoZW4geW91IGNhbiB1c2UgaXQgZm9yIEdpdEh1YiBwYWdlcyB0byBob3N0IHlvdXIgb3duIHNpdGUgYW5kIGRvIGFsbCBraW5kcyBvZiB0aGluZ3MganVzdCBsaWtlIGFueSBvdGhlciByZWFsIHNpdGUuXG4gICAgLyoqIENyZWF0ZXMgYW4gdW5wcm94aWVkIEEgcmVjb3JkIHBvaW50aW5nIGRvbWFpbiBhdCB0aGlzIG1hY2hpbmUgKHB1YmxpY0lwLCBvciBvdXIgZGV0ZWN0ZWQgZXh0ZXJuYWwgSVApICovXG4gICAgc2V0RE5TUmVjb3JkPzogYm9vbGVhbjtcbiAgICBwdWJsaWNJcD86IHN0cmluZztcbiAgICBhbGxvd0hvc3RuYW1lcz86IHN0cmluZ1tdO1xuICAgIC8qKiBXaGVuIHRoZSBwb3J0IGlzIGJ1c3kgKGUuZy4gdGhlIHByZXZpb3VzIGRlcGxveSBzdGlsbCBob2xkcyBpdCksIG1vdW50IG9uIGFuIGFsdGVybmF0ZSBwb3J0IGluc3RlYWQgKHRoZSBzb2NrZXQgc2VydmVyJ3MgYnVpbHQtaW4gZnJlZS1wb3J0IHNjYW4pLCBhbmQga2VlcCB0cnlpbmcgdG8gdGFrZSB0aGUgcmVhbCBwb3J0IC0gb25jZSBpdCBmcmVlcywgYSByYXcgVENQIHJlbGF5IG9uIHRoZSByZWFsIHBvcnQgZm9yd2FyZHMgdG8gb3VyIGxpc3RlbmVyIChTb2NrZXRGdW5jdGlvbiBjYW4gb25seSBtb3VudCBvbmNlIHBlciBwcm9jZXNzKS4gKi9cbiAgICBwb3J0RmFsbGJhY2s/OiB7XG4gICAgICAgIC8qKiBEZWxheSB1bnRpbCB0aGUgbmV4dCBtYWluLXBvcnQgYWNxdWlzaXRpb24gYXR0ZW1wdCAodGlnaHRlbmVkIGFyb3VuZCB0aGUgcHJlZGVjZXNzb3IncyBzY2hlZHVsZWQgZGVhdGgpICovXG4gICAgICAgIGdldEFjcXVpcmVEZWxheTogKCkgPT4gbnVtYmVyO1xuICAgICAgICAvKiogQ2FsbGVkIHdoZW4gdGhlIG1haW4gcG9ydCB0dXJuZWQgb3V0IHRvIGJlIGJ1c3ksIGJlZm9yZSB3ZSBhY3QgYXMgaXRzIHN1Y2Nlc3NvciBpbiBhbnkgd2F5LiBUaHJvd2luZyBhYm9ydHMgc3RhcnR1cCAtIGEgYnVzeSBwb3J0IHdpdGggbm8gZGVwbG95IGluIHByb2dyZXNzIG1lYW5zIHNvbWV0aGluZyBlbHNlIGhvbGRzIGl0LCB3aGljaCBpcyBub3QgYSBzdGF0ZSB0byBrZWVwIHJ1bm5pbmcgaW4uICovXG4gICAgICAgIG9uUG9ydEluVXNlPzogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgICAgICAgLyoqIFJlcG9ydHMgZXZlcnkgcG9ydCB3ZSBiZWNvbWUgcmVhY2hhYmxlIG9uICh0aGUgYWx0ZXJuYXRlIGF0IG1vdW50LCB0aGUgbWFpbiBwb3J0IG9uY2UgcmVsYXllZCkgKi9cbiAgICAgICAgb25MaXN0ZW5pbmc6IChwb3J0OiBudW1iZXIsIGlzTWFpblBvcnQ6IGJvb2xlYW4pID0+IHZvaWQ7XG4gICAgfTtcbn07XG5cbi8qKiBIb3N0cyBhIFNvY2tldEZ1bmN0aW9uIHNlcnZlciBvbiBhIHJlYWwgZG9tYWluLCB3aXRoIGFuIGF1dG9tYXRpY2FsbHkgY3JlYXRlZCBhbmQgcmVuZXdlZCBMZXQncyBFbmNyeXB0IEhUVFBTIGNlcnRpZmljYXRlIChjYWNoZWQgaW4gdGhlIGhvbWUgZm9sZGVyLCBzaGFyZWQgYmV0d2VlbiBwcm9jZXNzZXMgb24gdGhlIG1hY2hpbmUpLiBFeHBvc2UgeW91ciBjb250cm9sbGVycyAoYW5kIGFueSBSZXF1aXJlQ29udHJvbGxlciBzZXR1cCkgYmVmb3JlIGNhbGxpbmcgdGhpcy4gUmV0dXJucyB0aGUgbW91bnRlZCBub2RlSWQuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaG9zdFNlcnZlcihjb25maWc6IEhvc3RTZXJ2ZXJDb25maWcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGxldCB7IGRvbWFpbiwgcG9ydCB9ID0gY29uZmlnO1xuICAgIC8vIFRoZSBpZGVudGl0eSBDQSBhbHdheXMgbGl2ZXMgb24gdGhlIHJvb3QgZG9tYWluIChub2RlSWRzIGFyZSB0aHJlYWRIYXNoLm1hY2hpbmVIYXNoLnJvb3QudGxkKVxuICAgIGxldCByb290RG9tYWluID0gZG9tYWluLnNwbGl0KFwiLlwiKS5zbGljZSgtMikuam9pbihcIi5cIik7XG4gICAgYXdhaXQgbG9hZElkZW50aXR5Q0Eocm9vdERvbWFpbik7XG5cbiAgICBpZiAoY29uZmlnLnNldEROU1JlY29yZCkge1xuICAgICAgICBsZXQgaXAgPSBjb25maWcucHVibGljSXAgfHwgYXdhaXQgZ2V0RXh0ZXJuYWxJUCgpO1xuICAgICAgICBhd2FpdCBzZXRSZWNvcmQoXCJBXCIsIGRvbWFpbiwgaXApO1xuICAgIH1cblxuICAgIGxldCBrZXlDZXJ0ID0gYXdhaXQgZ2V0RnJlc2hIVFRQU0NlcnQoZG9tYWluKTtcbiAgICBsZXQgY2VydExpc3RlbmVyczogKCh2YWx1ZTogeyBrZXk6IHN0cmluZzsgY2VydDogc3RyaW5nIH0pID0+IHZvaWQpW10gPSBbXTtcbiAgICB2b2lkIHJ1bkNlcnRSZW5ld2FsTG9vcChkb21haW4sIG5ld0tleUNlcnQgPT4ge1xuICAgICAgICBrZXlDZXJ0ID0gbmV3S2V5Q2VydDtcbiAgICAgICAgZm9yIChsZXQgbGlzdGVuZXIgb2YgY2VydExpc3RlbmVycykge1xuICAgICAgICAgICAgbGlzdGVuZXIobmV3S2V5Q2VydCk7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIFdpdGggcG9ydEZhbGxiYWNrLCBhIGJ1c3kgcG9ydCBpcyBub3QgYW4gZXJyb3I6IHRoZSB1bmRlcmx5aW5nIHNlcnZlciBzY2FucyBmb3IgYSBmcmVlIHBvcnQgaW5zdGVhZCAodXNlQXZhaWxhYmxlUG9ydElmUG9ydEluVXNlKSwgYW5kIHRoZSBub2RlSWQgdGVsbHMgdXMgd2hpY2ggcG9ydCB3ZSBhY3R1YWxseSBnb3RcbiAgICBsZXQgbm9kZUlkID0gYXdhaXQgU29ja2V0RnVuY3Rpb24ubW91bnQoe1xuICAgICAgICBwdWJsaWM6IHRydWUsXG4gICAgICAgIGF1dG9Gb3J3YXJkUG9ydDogdHJ1ZSxcbiAgICAgICAgcG9ydCxcbiAgICAgICAgdXNlQXZhaWxhYmxlUG9ydElmUG9ydEluVXNlOiAhIWNvbmZpZy5wb3J0RmFsbGJhY2ssXG4gICAgICAgIC4uLmdldFRocmVhZEtleUNlcnQocm9vdERvbWFpbiksXG4gICAgICAgIFNOSUNlcnRzOiB7XG4gICAgICAgICAgICBbZG9tYWluXTogY2FsbGJhY2sgPT4ge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGtleUNlcnQpO1xuICAgICAgICAgICAgICAgIGNlcnRMaXN0ZW5lcnMucHVzaChjYWxsYmFjayk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgW2dldE93bk1hY2hpbmVJZChyb290RG9tYWluKSArIFwiLlwiICsgcm9vdERvbWFpbl06IGFzeW5jIGNhbGxiYWNrID0+IHtcbiAgICAgICAgICAgICAgICBsZXQgdGhyZWFkQ2VydCA9IGF3YWl0IGdldFRocmVhZEtleUNlcnQocm9vdERvbWFpbik7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soe1xuICAgICAgICAgICAgICAgICAgICBrZXk6IHRocmVhZENlcnQua2V5LFxuICAgICAgICAgICAgICAgICAgICBjZXJ0OiB0aHJlYWRDZXJ0LmNlcnQsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgW1wiMTI3LTAtMC0xLlwiICsgcm9vdERvbWFpbl06IGFzeW5jIGNhbGxiYWNrID0+IHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhrZXlDZXJ0KTtcbiAgICAgICAgICAgICAgICBjZXJ0TGlzdGVuZXJzLnB1c2goY2FsbGJhY2spO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgYWxsb3dIb3N0bmFtZXM6IGNvbmZpZy5hbGxvd0hvc3RuYW1lcyxcbiAgICB9KTtcbiAgICBsZXQgc2VydmluZ1BvcnQgPSBnZXROb2RlSWRMb2NhdGlvbihub2RlSWQpPy5wb3J0IHx8IHBvcnQ7XG4gICAgbGV0IGZhbGxiYWNrID0gY29uZmlnLnBvcnRGYWxsYmFjaztcbiAgICBpZiAoZmFsbGJhY2sgJiYgc2VydmluZ1BvcnQgIT09IHBvcnQpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGBQb3J0ICR7cG9ydH0gaXMgaW4gdXNlIChwcmVzdW1hYmx5IGJ5IG91ciBwcmVkZWNlc3Nvcik7IHNlcnZpbmcgb24gYWx0ZXJuYXRlIHBvcnQgJHtzZXJ2aW5nUG9ydH0gdW50aWwgaXQgZnJlZXNgKTtcbiAgICAgICAgYXdhaXQgZmFsbGJhY2sub25Qb3J0SW5Vc2U/LigpO1xuICAgICAgICB2b2lkIHJ1bk1haW5Qb3J0QWNxdWlyZUxvb3AoZG9tYWluLCBwb3J0LCBzZXJ2aW5nUG9ydCwgZmFsbGJhY2spO1xuICAgIH1cbiAgICBmYWxsYmFjaz8ub25MaXN0ZW5pbmcoc2VydmluZ1BvcnQsIHNlcnZpbmdQb3J0ID09PSBwb3J0KTtcbiAgICBjb25zb2xlLmxvZyhtYWdlbnRhKGBIb3N0aW5nIGh0dHBzOi8vJHtkb21haW59OiR7c2VydmluZ1BvcnR9IChub2RlSWQgJHtub2RlSWR9KWApKTtcbiAgICByZXR1cm4gbm9kZUlkO1xufVxuXG4vLyBTb2NrZXRGdW5jdGlvbiBjYW4gb25seSBtb3VudCBvbmNlIHBlciBwcm9jZXNzLCBzbyBcInRha2luZyBvdmVyXCIgdGhlIG1haW4gcG9ydCBpcyBhIHJhdyBUQ1AgcmVsYXkgZm9yd2FyZGluZyB0byBvdXIgcmVhbCBsaXN0ZW5lciAtIFRMUy9TTkkgcGFzc2VzIHN0cmFpZ2h0IHRocm91Z2gsIGFuZCBjbGllbnRzIGFkZHJlc3Mgc2VydmVycyBieSBpcCBkb21haW4gKHdpbGRjYXJkIG5lZ290aWF0aW9uKSwgc28gdGhlIGV4dHJhIGhvcCBpcyBpbnZpc2libGUuXG5hc3luYyBmdW5jdGlvbiBydW5NYWluUG9ydEFjcXVpcmVMb29wKGRvbWFpbjogc3RyaW5nLCBtYWluUG9ydDogbnVtYmVyLCBzZXJ2aW5nUG9ydDogbnVtYmVyLCBmYWxsYmFjazogTm9uTnVsbGFibGU8SG9zdFNlcnZlckNvbmZpZ1tcInBvcnRGYWxsYmFja1wiXT4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICBhd2FpdCBkZWxheShmYWxsYmFjay5nZXRBY3F1aXJlRGVsYXkoKSk7XG4gICAgICAgIGxldCBhY3F1aXJlZCA9IGF3YWl0IG5ldyBQcm9taXNlPGJvb2xlYW4+KHJlc29sdmUgPT4ge1xuICAgICAgICAgICAgbGV0IHJlbGF5ID0gbmV0LmNyZWF0ZVNlcnZlcihjbGllbnQgPT4ge1xuICAgICAgICAgICAgICAgIGxldCB1cHN0cmVhbSA9IG5ldC5jb25uZWN0KHsgaG9zdDogXCIxMjcuMC4wLjFcIiwgcG9ydDogc2VydmluZ1BvcnQgfSk7XG4gICAgICAgICAgICAgICAgY2xpZW50LnBpcGUodXBzdHJlYW0pO1xuICAgICAgICAgICAgICAgIHVwc3RyZWFtLnBpcGUoY2xpZW50KTtcbiAgICAgICAgICAgICAgICBsZXQgY2xlYW51cCA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY2xpZW50LmRlc3Ryb3koKTtcbiAgICAgICAgICAgICAgICAgICAgdXBzdHJlYW0uZGVzdHJveSgpO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgY2xpZW50Lm9uKFwiZXJyb3JcIiwgY2xlYW51cCk7XG4gICAgICAgICAgICAgICAgdXBzdHJlYW0ub24oXCJlcnJvclwiLCBjbGVhbnVwKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgcmVsYXkub25jZShcImVycm9yXCIsICgpID0+IHJlc29sdmUoZmFsc2UpKTtcbiAgICAgICAgICAgIHJlbGF5Lmxpc3RlbihtYWluUG9ydCwgKCkgPT4gcmVzb2x2ZSh0cnVlKSk7XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoYWNxdWlyZWQpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKG1hZ2VudGEoYEFjcXVpcmVkIG1haW4gcG9ydCAke21haW5Qb3J0fSBmb3IgaHR0cHM6Ly8ke2RvbWFpbn0gKHJlbGF5aW5nIHRvIG91ciBsaXN0ZW5lciBvbiAke3NlcnZpbmdQb3J0fSlgKSk7XG4gICAgICAgICAgICAvLyBUaGUgbW91bnQgb25seSBmb3J3YXJkZWQgT1VSIHNlcnZpbmcgcG9ydDsgdGhlIG1haW4gcG9ydCBuZWVkcyBpdHMgb3duIG1hcHBpbmcgKHRoZSBwcmVkZWNlc3NvcidzIG1hcHBpbmcgcG9pbnRlZCBhdCB0aGUgc2FtZSBtYWNoaW5lK3BvcnQsIGJ1dCBkaWVzIHdpdGggaXQpXG4gICAgICAgICAgICBhd2FpdCBmb3J3YXJkUG9ydCh7IGV4dGVybmFsUG9ydDogbWFpblBvcnQsIGludGVybmFsUG9ydDogbWFpblBvcnQgfSk7XG4gICAgICAgICAgICBmYWxsYmFjay5vbkxpc3RlbmluZyhtYWluUG9ydCwgdHJ1ZSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmZ1bmN0aW9uIGdldENlcnREaXNrUGF0aChkb21haW46IHN0cmluZykge1xuICAgIHJldHVybiBvcy5ob21lZGlyKCkgKyBgL2h0dHBzY2VydF8ke2RvbWFpbn0uanNvbmA7XG59XG5mdW5jdGlvbiByZWFkQ2VydEZyb21EaXNrKGRvbWFpbjogc3RyaW5nKTogeyBrZXk6IHN0cmluZzsgY2VydDogc3RyaW5nIH0gfCB1bmRlZmluZWQge1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKGZzLnJlYWRGaWxlU3luYyhnZXRDZXJ0RGlza1BhdGgoZG9tYWluKSwgXCJ1dGY4XCIpKSBhcyB7IGtleTogc3RyaW5nOyBjZXJ0OiBzdHJpbmcgfTtcbiAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG59XG5mdW5jdGlvbiBnZXRSZW5ld1RpbWUoY2VydFBlbTogc3RyaW5nLCB0aHJlc2hvbGQ6IG51bWJlcikge1xuICAgIGxldCBjZXJ0T2JqID0gcGFyc2VDZXJ0KGNlcnRQZW0pO1xuICAgIGxldCBzdGFydCA9ICtuZXcgRGF0ZShjZXJ0T2JqLnZhbGlkaXR5Lm5vdEJlZm9yZSk7XG4gICAgbGV0IGVuZCA9ICtuZXcgRGF0ZShjZXJ0T2JqLnZhbGlkaXR5Lm5vdEFmdGVyKTtcbiAgICByZXR1cm4gc3RhcnQgKyAoZW5kIC0gc3RhcnQpICogdGhyZXNob2xkO1xufVxuXG4vKiogUmV0dXJucyB0aGUgY2FjaGVkIEhUVFBTIGNlcnQgZm9yIHRoZSBkb21haW4sIGNyZWF0aW5nL3JlbmV3aW5nIGl0IGZpcnN0IGlmIGl0IGlzIHBhc3QgdGhpcyBwcm9jZXNzJ3MgcmVuZXdhbCB0aHJlc2hvbGQuIFJlYWRzIHRoZSBkaXNrIGNhY2hlIG9uIGV2ZXJ5IGNhbGwsIHNvIGEgcmVuZXdhbCBkb25lIGJ5IGEgcGFyYWxsZWwgcHJvY2VzcyBpcyBwaWNrZWQgdXAgaW5zdGVhZCBvZiByZW5ld2luZyBhZ2Fpbi4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRGcmVzaEhUVFBTQ2VydChkb21haW46IHN0cmluZyk6IFByb21pc2U8eyBrZXk6IHN0cmluZzsgY2VydDogc3RyaW5nIH0+IHtcbiAgICBsZXQga2V5Q2VydCA9IHJlYWRDZXJ0RnJvbURpc2soZG9tYWluKTtcbiAgICBpZiAoa2V5Q2VydCAmJiBnZXRSZW5ld1RpbWUoa2V5Q2VydC5jZXJ0LCByZW5ld1RocmVzaG9sZCkgPiBEYXRlLm5vdygpKSB7XG4gICAgICAgIHJldHVybiBrZXlDZXJ0O1xuICAgIH1cbiAgICBpZiAoa2V5Q2VydCkge1xuICAgICAgICBjb25zb2xlLmxvZyhtYWdlbnRhKGBIVFRQUyBjZXJ0IGZvciAke2RvbWFpbn0gaXMgcGFzdCAkeyhyZW5ld1RocmVzaG9sZCAqIDEwMCkudG9GaXhlZCgwKX0lIG9mIGl0cyBsaWZldGltZSwgcmVuZXdpbmdgKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5sb2cobWFnZW50YShgTm8gSFRUUFMgY2VydCBvbiBkaXNrIGZvciAke2RvbWFpbn0sIGNyZWF0aW5nIG9uZWApKTtcbiAgICB9XG4gICAgbGV0IGFjY291bnRLZXkgPSBhd2FpdCBnZXRBY2NvdW50S2V5KGRvbWFpbik7XG4gICAgdHJ5IHtcbiAgICAgICAga2V5Q2VydCA9IGF3YWl0IGdlbmVyYXRlQ2VydCh7IGFjY291bnRLZXksIGRvbWFpbiwgYWx0RG9tYWluczogW1wiKi5cIiArIGRvbWFpbl0gfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBpZiAoU3RyaW5nKGUpLmluY2x1ZGVzKFwiYXV0aG9yaXphdGlvbiBtdXN0IGJlIHBlbmRpbmdcIikpIHtcbiAgICAgICAgICAgIC8vIEFub3RoZXIgcHJvY2VzcyBpcyBtaWQtcmVuZXdhbC4gV2FpdCBmb3IgaXQgdG8gZmluaXNoLCB0aGVuIHJlLWNoZWNrIHRoZSBkaXNrLlxuICAgICAgICAgICAgY29uc29sZS5sb2coYENlcnRpZmljYXRlIGF1dGhvcml6YXRpb24gaXMgcGVuZGluZyBpbiBhbm90aGVyIHByb2Nlc3MsIHdhaXRpbmcgMiBtaW51dGVzYCk7XG4gICAgICAgICAgICBhd2FpdCBkZWxheSh0aW1lSW5NaW51dGUgKiAyKTtcbiAgICAgICAgICAgIHJldHVybiBhd2FpdCBnZXRGcmVzaEhUVFBTQ2VydChkb21haW4pO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IGU7XG4gICAgfVxuICAgIGZzLndyaXRlRmlsZVN5bmMoZ2V0Q2VydERpc2tQYXRoKGRvbWFpbiksIEpTT04uc3RyaW5naWZ5KHsga2V5OiBrZXlDZXJ0LmtleSwgY2VydDoga2V5Q2VydC5jZXJ0IH0pKTtcbiAgICByZXR1cm4geyBrZXk6IGtleUNlcnQua2V5LCBjZXJ0OiBrZXlDZXJ0LmNlcnQgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcnVuQ2VydFJlbmV3YWxMb29wKGRvbWFpbjogc3RyaW5nLCBvbk5ld0NlcnQ6IChrZXlDZXJ0OiB7IGtleTogc3RyaW5nOyBjZXJ0OiBzdHJpbmcgfSkgPT4gdm9pZCkge1xuICAgIGxldCBsYXN0Q2VydCA9IHJlYWRDZXJ0RnJvbURpc2soZG9tYWluKT8uY2VydDtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICBhd2FpdCBkZWxheShDRVJUX0NIRUNLX0lOVEVSVkFMKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGxldCBrZXlDZXJ0ID0gYXdhaXQgZ2V0RnJlc2hIVFRQU0NlcnQoZG9tYWluKTtcbiAgICAgICAgICAgIGlmIChrZXlDZXJ0LmNlcnQgIT09IGxhc3RDZXJ0KSB7XG4gICAgICAgICAgICAgICAgbGFzdENlcnQgPSBrZXlDZXJ0LmNlcnQ7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2cobWFnZW50YShgSFRUUFMgY2VydCBmb3IgJHtkb21haW59IHVwZGF0ZWQsIGFwcGx5aW5nIHRvIHJ1bm5pbmcgc2VydmVyYCkpO1xuICAgICAgICAgICAgICAgIG9uTmV3Q2VydChrZXlDZXJ0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihgRmFpbGVkIHRvIGNoZWNrL3JlbmV3IEhUVFBTIGNlcnQgZm9yICR7ZG9tYWlufWAsIGUpO1xuICAgICAgICB9XG4gICAgfVxufVxuIl19
176
- /* _JS_SOURCE_HASH = "73d4e7d18e033dcf8b735e9c48f18a2196de2a0377f4f0bb984b76ea3c86a2b6"; */
178
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaG9zdFNlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImhvc3RTZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsNENBQW9CO0FBQ3BCLDRDQUFvQjtBQUNwQiw4Q0FBc0I7QUFDdEIsbUVBQWdFO0FBQ2hFLDZEQUFrRTtBQUNsRSxtREFBd0Q7QUFDeEQsMkRBQXFEO0FBQ3JELCtEQUErRDtBQUMvRCxpRUFBOEQ7QUFDOUQsd0VBQW1FO0FBQ25FLG1DQUE0RTtBQUM1RSw2Q0FBc0U7QUFDdEUsK0JBQWtDO0FBRWxDLHlUQUF5VDtBQUN6VCxNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLG1CQUFtQixHQUFHLEdBQUcsQ0FBQztBQUNoQyxNQUFNLG1CQUFtQixHQUFHLG1CQUFZLEdBQUcsRUFBRSxDQUFDO0FBRTlDLGlHQUFpRztBQUNqRyxNQUFNLGNBQWMsR0FBRyxtQkFBbUIsR0FBRyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxtQkFBbUIsR0FBRyxtQkFBbUIsQ0FBQyxDQUFDO0FBdUJ6RyxpVEFBaVQ7QUFDMVMsS0FBSyxVQUFVLFVBQVUsQ0FBQyxNQUF3Qjs7SUFDckQsSUFBSSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxNQUFNLENBQUM7SUFDOUIsZ0dBQWdHO0lBQ2hHLElBQUksVUFBVSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3ZELE1BQU0sSUFBQSxzQkFBYyxFQUFDLFVBQVUsQ0FBQyxDQUFDO0lBRWpDLElBQUksTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3RCLElBQUksRUFBRSxHQUFHLE1BQU0sQ0FBQyxRQUFRLElBQUksTUFBTSxJQUFBLDBCQUFhLEdBQUUsQ0FBQztRQUNsRCxNQUFNLElBQUEsZUFBUyxFQUFDLEdB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bmltcG9ydCBmcyBmcm9tIFwiZnNcIjtcbmltcG9ydCBuZXQgZnJvbSBcIm5ldFwiO1xuaW1wb3J0IHsgU29ja2V0RnVuY3Rpb24gfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL1NvY2tldEZ1bmN0aW9uXCI7XG5pbXBvcnQgeyBnZXROb2RlSWRMb2NhdGlvbiB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL25vZGVDYWNoZVwiO1xuaW1wb3J0IHsgdGltZUluTWludXRlIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvbWlzY1wiO1xuaW1wb3J0IHsgZGVsYXkgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9iYXRjaGluZ1wiO1xuaW1wb3J0IHsgZ2V0RXh0ZXJuYWxJUCB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL25ldHdvcmtpbmdcIjtcbmltcG9ydCB7IGZvcndhcmRQb3J0IH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvZm9yd2FyZFBvcnRcIjtcbmltcG9ydCB7IG1hZ2VudGEgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9mb3JtYXR0aW5nL2xvZ0NvbG9yc1wiO1xuaW1wb3J0IHsgZ2V0T3duTWFjaGluZUlkLCBnZXRUaHJlYWRLZXlDZXJ0LCBsb2FkSWRlbnRpdHlDQSB9IGZyb20gXCIuL2NlcnRzXCI7XG5pbXBvcnQgeyBnZW5lcmF0ZUNlcnQsIGdldEFjY291bnRLZXksIHBhcnNlQ2VydCB9IGZyb20gXCIuL2h0dHBzQ2VydHNcIjtcbmltcG9ydCB7IHNldFJlY29yZCB9IGZyb20gXCIuL2Ruc1wiO1xuXG4vLyBSZW5ldyBzb21ld2hlcmUgcmFuZG9tbHkgYmV0d2VlbiA0MCUgYW5kIDYwJSBvZiB0aGUgd2F5IHRocm91Z2ggdGhlIGNlcnQgbGlmZXRpbWUuIFRoZSByYW5kb20gdGhyZXNob2xkIHN0YWdnZXJzIHBhcmFsbGVsIHByb2Nlc3NlcyBvbiB0aGUgc2FtZSBtYWNoaW5lLCBzbyB1c3VhbGx5IG9uZSBwcm9jZXNzIHJlbmV3cyBlYXJseSwgYW5kIHRoZSBvdGhlcnMgc2VlIHRoZSByZW5ld2VkIGNlcnQgb24gZGlzayAod2UgcmUtcmVhZCB0aGUgZGlzayBiZWZvcmUgZXZlcnkgcmVuZXdhbCBjaGVjaykgYW5kIG5ldmVyIHJlbmV3IHRoZW1zZWx2ZXMuXG5jb25zdCBSRU5FV19USFJFU0hPTERfTUlOID0gMC40O1xuY29uc3QgUkVORVdfVEhSRVNIT0xEX01BWCA9IDAuNjtcbmNvbnN0IENFUlRfQ0hFQ0tfSU5URVJWQUwgPSB0aW1lSW5NaW51dGUgKiAxNTtcblxuLy8gT25lIHRocmVzaG9sZCBwZXIgcHJvY2Vzcywgc28gYSBwcm9jZXNzIGlzIGNvbnNpc3RlbnRseSBlYXJseSBvciBsYXRlIHJlbGF0aXZlIHRvIGl0cyBzaWJsaW5nc1xuY29uc3QgcmVuZXdUaHJlc2hvbGQgPSBSRU5FV19USFJFU0hPTERfTUlOICsgTWF0aC5yYW5kb20oKSAqIChSRU5FV19USFJFU0hPTERfTUFYIC0gUkVORVdfVEhSRVNIT0xEX01JTik7XG5cbmV4cG9ydCB0eXBlIEhvc3RTZXJ2ZXJDb25maWcgPSB7XG4gICAgLyoqIEZ1bGwgZG9tYWluIHRvIGhvc3Qgb24gKGUuZy4gXCJ0ZXN0c2l0ZS5leGFtcGxlLmNvbVwiKS4gVGhlIEhUVFBTIGNlcnQgaXMgY3JlYXRlZCBmb3IgdGhpcyBkb21haW4gYW5kICouZG9tYWluLCBzbyB1c2luZyBhIHN1YmRvbWFpbiBuZXZlciB0b3VjaGVzIHRoZSByb290IGRvbWFpbiAoYmV5b25kIGl0cyBfYWNtZS1jaGFsbGVuZ2UgVFhUIHJlY29yZCkuICovXG4gICAgZG9tYWluOiBzdHJpbmc7XG4gICAgcG9ydDogbnVtYmVyO1xuXG4gICAgLy8gVE9ETzogRXZlbnR1YWxseSB3ZSBzaG91bGQgc3VwcG9ydCBydW5uaW5nIHdpdGhvdXQgQ2xvdWRmbGFyZSBBUEkgdG9rZW5zLiBJdCdzIGFubm95aW5nIHRob3VnaCBhcyB0aGUgdXNlciB3aWxsIGhhdmUgdG8gY3JlYXRlIGEgc2VsZi1zaWduZWQgY2VydGlmaWNhdGUgYW5kIHRoZW4gdGhleSdsbCBoYXZlIHRvIGdvIHRocm91Z2ggYW5kIHRydXN0IGl0IGV2ZXJ5d2hlcmUsIGFuZCBhIGxvdCBvZiB0aGUgc3R1ZmYgaXMgdHJhbnNwYXJlbnQsIGFuZCBzbyBpdCdsbCBoYXZlIHRvIGJlIG5vbi10cmFuc3BhcmVudCwgZ2V0dGluZyB0aGUgdXNlciB0byBnbyB0byB0aGUgcGFnZSB0aGF0IG93bnMgdGhlIGRvbWFpbiBhbmQgdHJ1c3QgaXQgZnJvbSB0aGVyZS4gSXQncyBtdWNoIGJldHRlciBqdXN0IG1ha2UgYSBDbG91ZGZsYXJlIGFjY291bnQuIFlvdSBjYW4gYnV5IGEgZG9tYWluIGZvciAkMTUgYSB5ZWFyLCBhbmQgdGhlbiB5b3UgY2FuIHVzZSBpdCBmb3IgR2l0SHViIHBhZ2VzIHRvIGhvc3QgeW91ciBvd24gc2l0ZSBhbmQgZG8gYWxsIGtpbmRzIG9mIHRoaW5ncyBqdXN0IGxpa2UgYW55IG90aGVyIHJlYWwgc2l0ZS5cbiAgICAvKiogQ3JlYXRlcyBhbiB1bnByb3hpZWQgQSByZWNvcmQgcG9pbnRpbmcgZG9tYWluIGF0IHRoaXMgbWFjaGluZSAocHVibGljSXAsIG9yIG91ciBkZXRlY3RlZCBleHRlcm5hbCBJUCkgKi9cbiAgICBzZXRETlNSZWNvcmQ/OiBib29sZWFuO1xuICAgIHB1YmxpY0lwPzogc3RyaW5nO1xuICAgIGFsbG93SG9zdG5hbWVzPzogc3RyaW5nW107XG4gICAgLyoqIFdoZW4gdGhlIHBvcnQgaXMgYnVzeSAoZS5nLiB0aGUgcHJldmlvdXMgZGVwbG95IHN0aWxsIGhvbGRzIGl0KSwgbW91bnQgb24gYW4gYWx0ZXJuYXRlIHBvcnQgaW5zdGVhZCAodGhlIHNvY2tldCBzZXJ2ZXIncyBidWlsdC1pbiBmcmVlLXBvcnQgc2NhbiksIGFuZCBrZWVwIHRyeWluZyB0byB0YWtlIHRoZSByZWFsIHBvcnQgLSBvbmNlIGl0IGZyZWVzLCBhIHJhdyBUQ1AgcmVsYXkgb24gdGhlIHJlYWwgcG9ydCBmb3J3YXJkcyB0byBvdXIgbGlzdGVuZXIgKFNvY2tldEZ1bmN0aW9uIGNhbiBvbmx5IG1vdW50IG9uY2UgcGVyIHByb2Nlc3MpLiAqL1xuICAgIHBvcnRGYWxsYmFjaz86IHtcbiAgICAgICAgLyoqIERlbGF5IHVudGlsIHRoZSBuZXh0IG1haW4tcG9ydCBhY3F1aXNpdGlvbiBhdHRlbXB0ICh0aWdodGVuZWQgYXJvdW5kIHRoZSBwcmVkZWNlc3NvcidzIHNjaGVkdWxlZCBkZWF0aCkgKi9cbiAgICAgICAgZ2V0QWNxdWlyZURlbGF5OiAoKSA9PiBudW1iZXI7XG4gICAgICAgIC8qKiBDYWxsZWQgd2hlbiB0aGUgbWFpbiBwb3J0IHR1cm5lZCBvdXQgdG8gYmUgYnVzeSwgYmVmb3JlIHdlIGFjdCBhcyBpdHMgc3VjY2Vzc29yIGluIGFueSB3YXkuIFRocm93aW5nIGFib3J0cyBzdGFydHVwIC0gYSBidXN5IHBvcnQgd2l0aCBubyBkZXBsb3kgaW4gcHJvZ3Jlc3MgbWVhbnMgc29tZXRoaW5nIGVsc2UgaG9sZHMgaXQsIHdoaWNoIGlzIG5vdCBhIHN0YXRlIHRvIGtlZXAgcnVubmluZyBpbi4gKi9cbiAgICAgICAgb25Qb3J0SW5Vc2U/OiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xuICAgICAgICAvKiogUmVwb3J0cyBldmVyeSBwb3J0IHdlIGJlY29tZSByZWFjaGFibGUgb24gKHRoZSBhbHRlcm5hdGUgYXQgbW91bnQsIHRoZSBtYWluIHBvcnQgb25jZSByZWxheWVkKSAqL1xuICAgICAgICBvbkxpc3RlbmluZzogKHBvcnQ6IG51bWJlciwgaXNNYWluUG9ydDogYm9vbGVhbikgPT4gdm9pZDtcbiAgICB9O1xufTtcblxuLyoqIEhvc3RzIGEgU29ja2V0RnVuY3Rpb24gc2VydmVyIG9uIGEgcmVhbCBkb21haW4sIHdpdGggYW4gYXV0b21hdGljYWxseSBjcmVhdGVkIGFuZCByZW5ld2VkIExldCdzIEVuY3J5cHQgSFRUUFMgY2VydGlmaWNhdGUgKGNhY2hlZCBpbiB0aGUgaG9tZSBmb2xkZXIsIHNoYXJlZCBiZXR3ZWVuIHByb2Nlc3NlcyBvbiB0aGUgbWFjaGluZSkuIEV4cG9zZSB5b3VyIGNvbnRyb2xsZXJzIChhbmQgYW55IFJlcXVpcmVDb250cm9sbGVyIHNldHVwKSBiZWZvcmUgY2FsbGluZyB0aGlzLiBSZXR1cm5zIHRoZSBtb3VudGVkIG5vZGVJZC4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBob3N0U2VydmVyKGNvbmZpZzogSG9zdFNlcnZlckNvbmZpZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgbGV0IHsgZG9tYWluLCBwb3J0IH0gPSBjb25maWc7XG4gICAgLy8gVGhlIGlkZW50aXR5IENBIGFsd2F5cyBsaXZlcyBvbiB0aGUgcm9vdCBkb21haW4gKG5vZGVJZHMgYXJlIHRocmVhZEhhc2gubWFjaGluZUhhc2gucm9vdC50bGQpXG4gICAgbGV0IHJvb3REb21haW4gPSBkb21haW4uc3BsaXQoXCIuXCIpLnNsaWNlKC0yKS5qb2luKFwiLlwiKTtcbiAgICBhd2FpdCBsb2FkSWRlbnRpdHlDQShyb290RG9tYWluKTtcblxuICAgIGlmIChjb25maWcuc2V0RE5TUmVjb3JkKSB7XG4gICAgICAgIGxldCBpcCA9IGNvbmZpZy5wdWJsaWNJcCB8fCBhd2FpdCBnZXRFeHRlcm5hbElQKCk7XG4gICAgICAgIGF3YWl0IHNldFJlY29yZChcIkFcIiwgZG9tYWluLCBpcCk7XG4gICAgfVxuXG4gICAgbGV0IGtleUNlcnQgPSBhd2FpdCBnZXRGcmVzaEhUVFBTQ2VydChkb21haW4pO1xuICAgIGxldCBjZXJ0TGlzdGVuZXJzOiAoKHZhbHVlOiB7IGtleTogc3RyaW5nOyBjZXJ0OiBzdHJpbmcgfSkgPT4gdm9pZClbXSA9IFtdO1xuICAgIHZvaWQgcnVuQ2VydFJlbmV3YWxMb29wKGRvbWFpbiwgbmV3S2V5Q2VydCA9PiB7XG4gICAgICAgIGtleUNlcnQgPSBuZXdLZXlDZXJ0O1xuICAgICAgICBmb3IgKGxldCBsaXN0ZW5lciBvZiBjZXJ0TGlzdGVuZXJzKSB7XG4gICAgICAgICAgICBsaXN0ZW5lcihuZXdLZXlDZXJ0KTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gV2l0aCBwb3J0RmFsbGJhY2ssIGEgYnVzeSBwb3J0IGlzIG5vdCBhbiBlcnJvcjogdGhlIHVuZGVybHlpbmcgc2VydmVyIHNjYW5zIGZvciBhIGZyZWUgcG9ydCBpbnN0ZWFkICh1c2VBdmFpbGFibGVQb3J0SWZQb3J0SW5Vc2UpLCBhbmQgdGhlIG5vZGVJZCB0ZWxscyB1cyB3aGljaCBwb3J0IHdlIGFjdHVhbGx5IGdvdFxuICAgIGxldCBub2RlSWQgPSBhd2FpdCBTb2NrZXRGdW5jdGlvbi5tb3VudCh7XG4gICAgICAgIHB1YmxpYzogdHJ1ZSxcbiAgICAgICAgYXV0b0ZvcndhcmRQb3J0OiB0cnVlLFxuICAgICAgICBwb3J0LFxuICAgICAgICB1c2VBdmFpbGFibGVQb3J0SWZQb3J0SW5Vc2U6ICEhY29uZmlnLnBvcnRGYWxsYmFjayxcbiAgICAgICAgLi4uZ2V0VGhyZWFkS2V5Q2VydChyb290RG9tYWluKSxcbiAgICAgICAgU05JQ2VydHM6IHtcbiAgICAgICAgICAgIFtkb21haW5dOiBjYWxsYmFjayA9PiB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soa2V5Q2VydCk7XG4gICAgICAgICAgICAgICAgY2VydExpc3RlbmVycy5wdXNoKGNhbGxiYWNrKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBbZ2V0T3duTWFjaGluZUlkKHJvb3REb21haW4pICsgXCIuXCIgKyByb290RG9tYWluXTogYXN5bmMgY2FsbGJhY2sgPT4ge1xuICAgICAgICAgICAgICAgIGxldCB0aHJlYWRDZXJ0ID0gYXdhaXQgZ2V0VGhyZWFkS2V5Q2VydChyb290RG9tYWluKTtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayh7XG4gICAgICAgICAgICAgICAgICAgIGtleTogdGhyZWFkQ2VydC5rZXksXG4gICAgICAgICAgICAgICAgICAgIGNlcnQ6IHRocmVhZENlcnQuY2VydCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBbXCIxMjctMC0wLTEuXCIgKyByb290RG9tYWluXTogYXN5bmMgY2FsbGJhY2sgPT4ge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGtleUNlcnQpO1xuICAgICAgICAgICAgICAgIGNlcnRMaXN0ZW5lcnMucHVzaChjYWxsYmFjayk7XG4gICAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBhbGxvd0hvc3RuYW1lczogY29uZmlnLmFsbG93SG9zdG5hbWVzLFxuICAgIH0pO1xuICAgIGxldCBzZXJ2aW5nUG9ydCA9IGdldE5vZGVJZExvY2F0aW9uKG5vZGVJZCk/LnBvcnQgfHwgcG9ydDtcbiAgICBsZXQgZmFsbGJhY2sgPSBjb25maWcucG9ydEZhbGxiYWNrO1xuICAgIGlmIChmYWxsYmFjayAmJiBzZXJ2aW5nUG9ydCAhPT0gcG9ydCkge1xuICAgICAgICBjb25zb2xlLndhcm4oYFBvcnQgJHtwb3J0fSBpcyBpbiB1c2UgKHByZXN1bWFibHkgYnkgb3VyIHByZWRlY2Vzc29yKTsgc2VydmluZyBvbiBhbHRlcm5hdGUgcG9ydCAke3NlcnZpbmdQb3J0fSB1bnRpbCBpdCBmcmVlc2ApO1xuICAgICAgICBhd2FpdCBmYWxsYmFjay5vblBvcnRJblVzZT8uKCk7XG4gICAgICAgIHZvaWQgcnVuTWFpblBvcnRBY3F1aXJlTG9vcChkb21haW4sIHBvcnQsIHNlcnZpbmdQb3J0LCBmYWxsYmFjayk7XG4gICAgfVxuICAgIGZhbGxiYWNrPy5vbkxpc3RlbmluZyhzZXJ2aW5nUG9ydCwgc2VydmluZ1BvcnQgPT09IHBvcnQpO1xuICAgIGNvbnNvbGUubG9nKG1hZ2VudGEoYEhvc3RpbmcgaHR0cHM6Ly8ke2RvbWFpbn06JHtzZXJ2aW5nUG9ydH0gKG5vZGVJZCAke25vZGVJZH0pYCkpO1xuICAgIHJldHVybiBub2RlSWQ7XG59XG5cbi8vIFNvY2tldEZ1bmN0aW9uIGNhbiBvbmx5IG1vdW50IG9uY2UgcGVyIHByb2Nlc3MsIHNvIFwidGFraW5nIG92ZXJcIiB0aGUgbWFpbiBwb3J0IGlzIGEgcmF3IFRDUCByZWxheSBmb3J3YXJkaW5nIHRvIG91ciByZWFsIGxpc3RlbmVyIC0gVExTL1NOSSBwYXNzZXMgc3RyYWlnaHQgdGhyb3VnaCwgYW5kIGNsaWVudHMgYWRkcmVzcyBzZXJ2ZXJzIGJ5IGlwIGRvbWFpbiAod2lsZGNhcmQgbmVnb3RpYXRpb24pLCBzbyB0aGUgZXh0cmEgaG9wIGlzIGludmlzaWJsZS5cbmFzeW5jIGZ1bmN0aW9uIHJ1bk1haW5Qb3J0QWNxdWlyZUxvb3AoZG9tYWluOiBzdHJpbmcsIG1haW5Qb3J0OiBudW1iZXIsIHNlcnZpbmdQb3J0OiBudW1iZXIsIGZhbGxiYWNrOiBOb25OdWxsYWJsZTxIb3N0U2VydmVyQ29uZmlnW1wicG9ydEZhbGxiYWNrXCJdPik6IFByb21pc2U8dm9pZD4ge1xuICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIGF3YWl0IGRlbGF5KGZhbGxiYWNrLmdldEFjcXVpcmVEZWxheSgpKTtcbiAgICAgICAgbGV0IGFjcXVpcmVkID0gYXdhaXQgbmV3IFByb21pc2U8Ym9vbGVhbj4ocmVzb2x2ZSA9PiB7XG4gICAgICAgICAgICBsZXQgcmVsYXkgPSBuZXQuY3JlYXRlU2VydmVyKGNsaWVudCA9PiB7XG4gICAgICAgICAgICAgICAgbGV0IHVwc3RyZWFtID0gbmV0LmNvbm5lY3QoeyBob3N0OiBcIjEyNy4wLjAuMVwiLCBwb3J0OiBzZXJ2aW5nUG9ydCB9KTtcbiAgICAgICAgICAgICAgICAvLyBXaXRob3V0IHRoaXMgZXZlcnkgcmVsYXllZCByZXF1ZXN0IHBheXMgdGhlIH40MG1zIGRlbGF5ZWQtQUNLIHRpbWVyOiBhIGNhbGwgaXMgYSBzbWFsbCB3cml0ZSAob2Z0ZW4gYSBoZWFkZXIgdGhlbiBhIGJvZHkpLCBOYWdsZSBob2xkcyB0aGUgc2Vjb25kIHdyaXRlIHVudGlsIHRoZSBmaXJzdCBpcyBhY2tub3dsZWRnZWQsIGFuZCB0aGUgcGVlciBoYXMgbm90aGluZyB0byBwaWdneWJhY2sgdGhlIEFDSyBvbi4gTWVhc3VyZWQgYXMgNDNtcyBwZXIgY2FsbCB0aHJvdWdoIHRoZSByZWxheSB2ZXJzdXMgMW1zIGRpcmVjdC5cbiAgICAgICAgICAgICAgICBjbGllbnQuc2V0Tm9EZWxheSh0cnVlKTtcbiAgICAgICAgICAgICAgICB1cHN0cmVhbS5zZXROb0RlbGF5KHRydWUpO1xuICAgICAgICAgICAgICAgIGNsaWVudC5waXBlKHVwc3RyZWFtKTtcbiAgICAgICAgICAgICAgICB1cHN0cmVhbS5waXBlKGNsaWVudCk7XG4gICAgICAgICAgICAgICAgbGV0IGNsZWFudXAgPSAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNsaWVudC5kZXN0cm95KCk7XG4gICAgICAgICAgICAgICAgICAgIHVwc3RyZWFtLmRlc3Ryb3koKTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGNsaWVudC5vbihcImVycm9yXCIsIGNsZWFudXApO1xuICAgICAgICAgICAgICAgIHVwc3RyZWFtLm9uKFwiZXJyb3JcIiwgY2xlYW51cCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJlbGF5Lm9uY2UoXCJlcnJvclwiLCAoKSA9PiByZXNvbHZlKGZhbHNlKSk7XG4gICAgICAgICAgICByZWxheS5saXN0ZW4obWFpblBvcnQsICgpID0+IHJlc29sdmUodHJ1ZSkpO1xuICAgICAgICB9KTtcbiAgICAgICAgaWYgKGFjcXVpcmVkKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhtYWdlbnRhKGBBY3F1aXJlZCBtYWluIHBvcnQgJHttYWluUG9ydH0gZm9yIGh0dHBzOi8vJHtkb21haW59IChyZWxheWluZyB0byBvdXIgbGlzdGVuZXIgb24gJHtzZXJ2aW5nUG9ydH0pYCkpO1xuICAgICAgICAgICAgLy8gVGhlIG1vdW50IG9ubHkgZm9yd2FyZGVkIE9VUiBzZXJ2aW5nIHBvcnQ7IHRoZSBtYWluIHBvcnQgbmVlZHMgaXRzIG93biBtYXBwaW5nICh0aGUgcHJlZGVjZXNzb3IncyBtYXBwaW5nIHBvaW50ZWQgYXQgdGhlIHNhbWUgbWFjaGluZStwb3J0LCBidXQgZGllcyB3aXRoIGl0KVxuICAgICAgICAgICAgYXdhaXQgZm9yd2FyZFBvcnQoeyBleHRlcm5hbFBvcnQ6IG1haW5Qb3J0LCBpbnRlcm5hbFBvcnQ6IG1haW5Qb3J0IH0pO1xuICAgICAgICAgICAgZmFsbGJhY2sub25MaXN0ZW5pbmcobWFpblBvcnQsIHRydWUpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5mdW5jdGlvbiBnZXRDZXJ0RGlza1BhdGgoZG9tYWluOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gb3MuaG9tZWRpcigpICsgYC9odHRwc2NlcnRfJHtkb21haW59Lmpzb25gO1xufVxuZnVuY3Rpb24gcmVhZENlcnRGcm9tRGlzayhkb21haW46IHN0cmluZyk6IHsga2V5OiBzdHJpbmc7IGNlcnQ6IHN0cmluZyB9IHwgdW5kZWZpbmVkIHtcbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShmcy5yZWFkRmlsZVN5bmMoZ2V0Q2VydERpc2tQYXRoKGRvbWFpbiksIFwidXRmOFwiKSkgYXMgeyBrZXk6IHN0cmluZzsgY2VydDogc3RyaW5nIH07XG4gICAgfSBjYXRjaCB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxufVxuZnVuY3Rpb24gZ2V0UmVuZXdUaW1lKGNlcnRQZW06IHN0cmluZywgdGhyZXNob2xkOiBudW1iZXIpIHtcbiAgICBsZXQgY2VydE9iaiA9IHBhcnNlQ2VydChjZXJ0UGVtKTtcbiAgICBsZXQgc3RhcnQgPSArbmV3IERhdGUoY2VydE9iai52YWxpZGl0eS5ub3RCZWZvcmUpO1xuICAgIGxldCBlbmQgPSArbmV3IERhdGUoY2VydE9iai52YWxpZGl0eS5ub3RBZnRlcik7XG4gICAgcmV0dXJuIHN0YXJ0ICsgKGVuZCAtIHN0YXJ0KSAqIHRocmVzaG9sZDtcbn1cblxuLyoqIFJldHVybnMgdGhlIGNhY2hlZCBIVFRQUyBjZXJ0IGZvciB0aGUgZG9tYWluLCBjcmVhdGluZy9yZW5ld2luZyBpdCBmaXJzdCBpZiBpdCBpcyBwYXN0IHRoaXMgcHJvY2VzcydzIHJlbmV3YWwgdGhyZXNob2xkLiBSZWFkcyB0aGUgZGlzayBjYWNoZSBvbiBldmVyeSBjYWxsLCBzbyBhIHJlbmV3YWwgZG9uZSBieSBhIHBhcmFsbGVsIHByb2Nlc3MgaXMgcGlja2VkIHVwIGluc3RlYWQgb2YgcmVuZXdpbmcgYWdhaW4uICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0RnJlc2hIVFRQU0NlcnQoZG9tYWluOiBzdHJpbmcpOiBQcm9taXNlPHsga2V5OiBzdHJpbmc7IGNlcnQ6IHN0cmluZyB9PiB7XG4gICAgbGV0IGtleUNlcnQgPSByZWFkQ2VydEZyb21EaXNrKGRvbWFpbik7XG4gICAgaWYgKGtleUNlcnQgJiYgZ2V0UmVuZXdUaW1lKGtleUNlcnQuY2VydCwgcmVuZXdUaHJlc2hvbGQpID4gRGF0ZS5ub3coKSkge1xuICAgICAgICByZXR1cm4ga2V5Q2VydDtcbiAgICB9XG4gICAgaWYgKGtleUNlcnQpIHtcbiAgICAgICAgY29uc29sZS5sb2cobWFnZW50YShgSFRUUFMgY2VydCBmb3IgJHtkb21haW59IGlzIHBhc3QgJHsocmVuZXdUaHJlc2hvbGQgKiAxMDApLnRvRml4ZWQoMCl9JSBvZiBpdHMgbGlmZXRpbWUsIHJlbmV3aW5nYCkpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUubG9nKG1hZ2VudGEoYE5vIEhUVFBTIGNlcnQgb24gZGlzayBmb3IgJHtkb21haW59LCBjcmVhdGluZyBvbmVgKSk7XG4gICAgfVxuICAgIGxldCBhY2NvdW50S2V5ID0gYXdhaXQgZ2V0QWNjb3VudEtleShkb21haW4pO1xuICAgIHRyeSB7XG4gICAgICAgIGtleUNlcnQgPSBhd2FpdCBnZW5lcmF0ZUNlcnQoeyBhY2NvdW50S2V5LCBkb21haW4sIGFsdERvbWFpbnM6IFtcIiouXCIgKyBkb21haW5dIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKFN0cmluZyhlKS5pbmNsdWRlcyhcImF1dGhvcml6YXRpb24gbXVzdCBiZSBwZW5kaW5nXCIpKSB7XG4gICAgICAgICAgICAvLyBBbm90aGVyIHByb2Nlc3MgaXMgbWlkLXJlbmV3YWwuIFdhaXQgZm9yIGl0IHRvIGZpbmlzaCwgdGhlbiByZS1jaGVjayB0aGUgZGlzay5cbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBDZXJ0aWZpY2F0ZSBhdXRob3JpemF0aW9uIGlzIHBlbmRpbmcgaW4gYW5vdGhlciBwcm9jZXNzLCB3YWl0aW5nIDIgbWludXRlc2ApO1xuICAgICAgICAgICAgYXdhaXQgZGVsYXkodGltZUluTWludXRlICogMik7XG4gICAgICAgICAgICByZXR1cm4gYXdhaXQgZ2V0RnJlc2hIVFRQU0NlcnQoZG9tYWluKTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBlO1xuICAgIH1cbiAgICBmcy53cml0ZUZpbGVTeW5jKGdldENlcnREaXNrUGF0aChkb21haW4pLCBKU09OLnN0cmluZ2lmeSh7IGtleToga2V5Q2VydC5rZXksIGNlcnQ6IGtleUNlcnQuY2VydCB9KSk7XG4gICAgcmV0dXJuIHsga2V5OiBrZXlDZXJ0LmtleSwgY2VydDoga2V5Q2VydC5jZXJ0IH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJ1bkNlcnRSZW5ld2FsTG9vcChkb21haW46IHN0cmluZywgb25OZXdDZXJ0OiAoa2V5Q2VydDogeyBrZXk6IHN0cmluZzsgY2VydDogc3RyaW5nIH0pID0+IHZvaWQpIHtcbiAgICBsZXQgbGFzdENlcnQgPSByZWFkQ2VydEZyb21EaXNrKGRvbWFpbik/LmNlcnQ7XG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgYXdhaXQgZGVsYXkoQ0VSVF9DSEVDS19JTlRFUlZBTCk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQga2V5Q2VydCA9IGF3YWl0IGdldEZyZXNoSFRUUFNDZXJ0KGRvbWFpbik7XG4gICAgICAgICAgICBpZiAoa2V5Q2VydC5jZXJ0ICE9PSBsYXN0Q2VydCkge1xuICAgICAgICAgICAgICAgIGxhc3RDZXJ0ID0ga2V5Q2VydC5jZXJ0O1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKG1hZ2VudGEoYEhUVFBTIGNlcnQgZm9yICR7ZG9tYWlufSB1cGRhdGVkLCBhcHBseWluZyB0byBydW5uaW5nIHNlcnZlcmApKTtcbiAgICAgICAgICAgICAgICBvbk5ld0NlcnQoa2V5Q2VydCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEZhaWxlZCB0byBjaGVjay9yZW5ldyBIVFRQUyBjZXJ0IGZvciAke2RvbWFpbn1gLCBlKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiJdfQ==
179
+ /* _JS_SOURCE_HASH = "9baf70af1a68cebffec3371ab785502f6622d22b98fd99a3e0deb3d517091896"; */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sliftutils",
3
- "version": "1.7.71",
3
+ "version": "1.7.73",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "files": [
package/spec.txt CHANGED
@@ -1,3 +1,13 @@
1
+ Refactor
2
+
3
+ createArchives => storageController => storageServerState => BlobStore
4
+
5
+ So create Archives has to decide who we're going to talk to, and then Storage Controller, it just acts like adds security and stuff. and then it gets into load it bucket, and then load it bucket. It then decides what back-end store we're talking to, and the back-end store, it might talk to multiple sources.
6
+ So there's which server we're going to talk to, which bucket on the server it maps to once we get there, and then there's which back-end stores that we talk to. So I guess it's fine.
7
+
8
+
9
+
10
+
1
11
  TODO: Use wildcard certificates, and then expose urls which match up to the shard fraction, to 2 decimal places:
2
12
  storageshard01.domain.com
3
13
  storageshard26.domain.com
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
- import { IArchives, ArchiveFileInfo, ArchivesConfig, ChangesAfterConfig, DelConfig, GetConfig, GetInfoConfig, SetConfig } from "./IArchives";
3
+ import { IArchives, ArchiveFileInfo, ArchivesConfig, ChangesAfterConfig, DelConfig, FindConfig, GetConfig, GetInfoConfig, SetConfig } from "./IArchives";
4
4
  export declare class ArchivesDisk implements IArchives {
5
5
  private folder;
6
6
  constructor(folder: string);
@@ -31,14 +31,8 @@ export declare class ArchivesDisk implements IArchives {
31
31
  writeTime: number;
32
32
  size: number;
33
33
  } | undefined>;
34
- find(prefix: string, config?: {
35
- shallow?: boolean;
36
- type: "files" | "folders";
37
- }): Promise<string[]>;
38
- findInfo(prefix: string, config?: {
39
- shallow?: boolean;
40
- type?: "files" | "folders";
41
- }): Promise<ArchiveFileInfo[]>;
34
+ find(prefix: string, config?: FindConfig): Promise<string[]>;
35
+ findInfo(prefix: string, config?: FindConfig): Promise<ArchiveFileInfo[]>;
42
36
  private collectFiles;
43
37
  setLargeFile(config: {
44
38
  path: string;
@@ -51,7 +45,4 @@ export declare class ArchivesDisk implements IArchives {
51
45
  cancelLargeUpload(id: string): Promise<void>;
52
46
  getURL(path: string): Promise<string>;
53
47
  }
54
- export declare function applyFindInfoShape(files: ArchiveFileInfo[], prefix: string, config?: {
55
- shallow?: boolean;
56
- type?: "files" | "folders";
57
- }): ArchiveFileInfo[];
48
+ export declare function applyFindInfoShape(files: ArchiveFileInfo[], prefix: string, config?: FindConfig): ArchiveFileInfo[];
@@ -3,7 +3,7 @@ import path from "path";
3
3
  import { lazy } from "socket-function/src/caching";
4
4
  import { runInfinitePoll } from "socket-function/src/batching";
5
5
  import { sort, binarySearchBasic } from "socket-function/src/misc";
6
- import { IArchives, ArchiveFileInfo, ArchivesConfig, ChangesAfterConfig, DelConfig, GetConfig, GetInfoConfig, SetConfig, assertValidLastModified } from "./IArchives";
6
+ import { IArchives, ArchiveFileInfo, ArchivesConfig, ChangesAfterConfig, DelConfig, FindConfig, GetConfig, GetInfoConfig, SetConfig, assertValidLastModified } from "./IArchives";
7
7
  import { filterChanges } from "./remoteStorage/remoteConfig";
8
8
 
9
9
  // The base file-system IArchives: storage is one-to-one with the file system, every key is exactly one real file under <folder>/files, so the file system itself is the index. File handles are cached and reused, and closed once idle (see FileHandleCache). All operations on a file run in serial, so they can't collide with each other or with handle closing. Used as the disk synchronization source of BlobStore (see remoteStorage/blobStore.ts).
@@ -210,6 +210,8 @@ export class ArchivesDisk implements IArchives {
210
210
  }
211
211
  let stats = await handle.stat();
212
212
  let size = stats.size;
213
+ // A size-0 file is a tombstone (an empty file IS a missing file) - absent, unless the caller asked for tombstones. Ranged reads of a REAL file can still legitimately return no bytes (range past EOF, below).
214
+ if (!size && !config?.includeTombstones) return undefined;
213
215
  let start = range && Math.min(range.start, size) || 0;
214
216
  let end = range && Math.min(range.end, size) || size;
215
217
  if (end <= start) return { data: Buffer.alloc(0), writeTime: stats.mtimeMs, size };
@@ -233,11 +235,11 @@ export class ArchivesDisk implements IArchives {
233
235
  });
234
236
  }
235
237
 
236
- public async find(prefix: string, config?: { shallow?: boolean; type: "files" | "folders" }): Promise<string[]> {
238
+ public async find(prefix: string, config?: FindConfig): Promise<string[]> {
237
239
  return (await this.findInfo(prefix, config)).map(x => x.path);
238
240
  }
239
241
 
240
- public async findInfo(prefix: string, config?: { shallow?: boolean; type?: "files" | "folders" }): Promise<ArchiveFileInfo[]> {
242
+ public async findInfo(prefix: string, config?: FindConfig): Promise<ArchiveFileInfo[]> {
241
243
  await this.init();
242
244
  let infos = new Map<string, ArchiveFileInfo>();
243
245
  await this.collectFiles("", prefix, infos);
@@ -362,7 +364,7 @@ async function statOrUndefined(filePath: string): Promise<fs.Stats | undefined>
362
364
  }
363
365
 
364
366
  // The folders/shallow post-processing shared by findInfo implementations that list flat files (used by ArchivesDisk on the raw disk walk, and by BlobStore on its index).
365
- export function applyFindInfoShape(files: ArchiveFileInfo[], prefix: string, config?: { shallow?: boolean; type?: "files" | "folders" }): ArchiveFileInfo[] {
367
+ export function applyFindInfoShape(files: ArchiveFileInfo[], prefix: string, config?: FindConfig): ArchiveFileInfo[] {
366
368
  if (config?.type === "folders") {
367
369
  let folders = new Map<string, ArchiveFileInfo>();
368
370
  for (let file of files) {
@@ -18,7 +18,9 @@ export type RemoteConfig = {
18
18
 
19
19
  NOTE: If we're in the browser, we should allow downloading the files via the URL form (if it's a public bucket), however, we won't allow writing, because their servers do not allow secure browser writes.
20
20
  */
21
- export type RemoteConfigBase = string | HostedConfig | BackblazeConfig;
21
+ export type RemoteConfigBase = string | SourceConfig;
22
+ /** One configured source in a routing config: a hosted (our storage server) or backblaze entry. Requests carry the exact SourceConfig they selected, and the server matches it against its own entries to pick the backing store. */
23
+ export type SourceConfig = HostedConfig | BackblazeConfig;
22
24
  export type CommonConfig = {
23
25
  /** By default a server hosting this bucket eagerly copies this source's full contents onto its own disk (on top of the lazy read-through caching). Set this to be a front end for a very large database without copying the full database - reads still down-cache individual files on demand. */
24
26
  noFullSync?: boolean;
@@ -57,6 +59,14 @@ export type GetConfig = {
57
59
  noFallbacks?: boolean;
58
60
  /** Store-to-store call: the serving node answers purely from its own disk, completely short-circuiting its index holders - chasing its own remote holders while answering another store is how infinite get loops between stores form (A asks B, B's index points back at A, ...). No window or route checks on reads: if the bytes are on its disk, the caller may have them. */
59
61
  internal?: boolean;
62
+ /** Also return size-0 results (tombstones - an empty file IS a missing file) instead of treating them as absent. Off by default, matching getInfo's flag of the same name. Synchronization passes this so a DELETED file (with its write time) is distinguishable from a file that never existed. */
63
+ includeTombstones?: boolean;
64
+ };
65
+ export type FindConfig = {
66
+ shallow?: boolean;
67
+ type?: "files" | "folders";
68
+ /** Listings normally come ONLY from the authoritative sources (the same nodes writes go to - read-your-writes). With fallbacks, a failing shard's routes are covered by the next source holding them (e.g. a wide read replica) instead of the call failing - high availability at the cost of possibly missing just-written data. Single-source archives ignore the flag. */
69
+ fallbacks?: boolean;
60
70
  };
61
71
  export type DelConfig = {
62
72
  /** Stamps the deletion (its tombstone) with this write time instead of now. Synchronization passes the ORIGINAL deletion time, so deletion ordering survives propagation exactly like any other write's ordering. */
@@ -79,7 +89,7 @@ export type SetConfig = {
79
89
  lastModified?: number;
80
90
  /** Makes the write acceptable on immutable targets: an existing path is simply kept (immutability wins - nothing is overwritten) instead of the write throwing. Requires lastModified. Synchronization MUST pass this on every push - a plain set throws on immutable targets, which would abort reconciliation whenever one source in a chain is immutable. */
81
91
  forceSetImmutable?: boolean;
82
- /** Skips the target-side safety reads around the write (backblaze: the pre-write getInfo comparison and the post-upload existence poll). For writers whose own bookkeeping already decides what to write and orders it by write time (BlobStore's index-driven writes and synchronization), those reads are pure extra API calls - but the default stays checked, because other users of the raw backends rely on the checks. */
92
+ /** Skips REDUNDANT target-side safety reads around the write (backblaze: the post-upload existence poll). It does NOT skip checks that are the target's only ordering guard: backblaze's pre-write comparison stays, because b2 has no server of ours enforcing only-take-the-latest - without it a stale push lands over a newer value or tombstone and b2's self-stamped upload time launders it into the newest copy in the system (global resurrection). Hosted targets re-check server-side, so their client-side shortcuts are safe. */
83
93
  noChecks?: boolean;
84
94
  /** Store-to-store push: the receiving node writes purely to its own disk and index, with NO downstream fan-out (the pushing store owns propagation - fanning its pushes back out is how write loops between stores form). Window and route ARE still checked: the stamp must fall inside one of the receiver's configured windows and routes, so a confused peer cannot stuff data onto a node that was never meant to hold it. Requires lastModified. */
85
95
  internal?: boolean;
@@ -141,6 +151,7 @@ export declare function copyArchiveFile(config: {
141
151
  forceSetImmutable?: boolean;
142
152
  noChecks?: boolean;
143
153
  internal?: boolean;
154
+ noFallbacks?: boolean;
144
155
  }): Promise<{
145
156
  writeTime: number;
146
157
  size: number;
@@ -218,15 +229,9 @@ export interface IArchives {
218
229
  * their empty files - that is how scans learn of deletions - but nothing built on the index
219
230
  * ever surfaces them.
220
231
  */
221
- find(prefix: string, config?: {
222
- shallow?: boolean;
223
- type: "files" | "folders";
224
- }): Promise<string[]>;
232
+ find(prefix: string, config?: FindConfig): Promise<string[]>;
225
233
  /** See find for the empty-file (tombstone) rule. */
226
- findInfo(prefix: string, config?: {
227
- shallow?: boolean;
228
- type: "files" | "folders";
229
- }): Promise<ArchiveFileInfo[]>;
234
+ findInfo(prefix: string, config?: FindConfig): Promise<ArchiveFileInfo[]>;
230
235
  /** Only works for public buckets (private buckets are API-access only). */
231
236
  getURL(path: string): Promise<string>;
232
237
  /** The bucket's configuration, which tells whether the optional functions are supported. */
@@ -30,7 +30,10 @@ export type RemoteConfig = {
30
30
 
31
31
  NOTE: If we're in the browser, we should allow downloading the files via the URL form (if it's a public bucket), however, we won't allow writing, because their servers do not allow secure browser writes.
32
32
  */
33
- export type RemoteConfigBase = string | HostedConfig | BackblazeConfig;
33
+ export type RemoteConfigBase = string | SourceConfig;
34
+
35
+ /** One configured source in a routing config: a hosted (our storage server) or backblaze entry. Requests carry the exact SourceConfig they selected, and the server matches it against its own entries to pick the backing store. */
36
+ export type SourceConfig = HostedConfig | BackblazeConfig;
34
37
 
35
38
  export type CommonConfig = {
36
39
  /** By default a server hosting this bucket eagerly copies this source's full contents onto its own disk (on top of the lazy read-through caching). Set this to be a front end for a very large database without copying the full database - reads still down-cache individual files on demand. */
@@ -92,6 +95,15 @@ export type GetConfig = {
92
95
  noFallbacks?: boolean;
93
96
  /** Store-to-store call: the serving node answers purely from its own disk, completely short-circuiting its index holders - chasing its own remote holders while answering another store is how infinite get loops between stores form (A asks B, B's index points back at A, ...). No window or route checks on reads: if the bytes are on its disk, the caller may have them. */
94
97
  internal?: boolean;
98
+ /** Also return size-0 results (tombstones - an empty file IS a missing file) instead of treating them as absent. Off by default, matching getInfo's flag of the same name. Synchronization passes this so a DELETED file (with its write time) is distinguishable from a file that never existed. */
99
+ includeTombstones?: boolean;
100
+ };
101
+
102
+ export type FindConfig = {
103
+ shallow?: boolean;
104
+ type?: "files" | "folders";
105
+ /** Listings normally come ONLY from the authoritative sources (the same nodes writes go to - read-your-writes). With fallbacks, a failing shard's routes are covered by the next source holding them (e.g. a wide read replica) instead of the call failing - high availability at the cost of possibly missing just-written data. Single-source archives ignore the flag. */
106
+ fallbacks?: boolean;
95
107
  };
96
108
 
97
109
  export type DelConfig = {
@@ -118,7 +130,7 @@ export type SetConfig = {
118
130
  lastModified?: number;
119
131
  /** Makes the write acceptable on immutable targets: an existing path is simply kept (immutability wins - nothing is overwritten) instead of the write throwing. Requires lastModified. Synchronization MUST pass this on every push - a plain set throws on immutable targets, which would abort reconciliation whenever one source in a chain is immutable. */
120
132
  forceSetImmutable?: boolean;
121
- /** Skips the target-side safety reads around the write (backblaze: the pre-write getInfo comparison and the post-upload existence poll). For writers whose own bookkeeping already decides what to write and orders it by write time (BlobStore's index-driven writes and synchronization), those reads are pure extra API calls - but the default stays checked, because other users of the raw backends rely on the checks. */
133
+ /** Skips REDUNDANT target-side safety reads around the write (backblaze: the post-upload existence poll). It does NOT skip checks that are the target's only ordering guard: backblaze's pre-write comparison stays, because b2 has no server of ours enforcing only-take-the-latest - without it a stale push lands over a newer value or tombstone and b2's self-stamped upload time launders it into the newest copy in the system (global resurrection). Hosted targets re-check server-side, so their client-side shortcuts are safe. */
122
134
  noChecks?: boolean;
123
135
  /** Store-to-store push: the receiving node writes purely to its own disk and index, with NO downstream fan-out (the pushing store owns propagation - fanning its pushes back out is how write loops between stores form). Window and route ARE still checked: the stamp must fall inside one of the receiver's configured windows and routes, so a confused peer cannot stuff data onto a node that was never meant to hold it. Requires lastModified. */
124
136
  internal?: boolean;
@@ -215,6 +227,7 @@ export async function copyArchiveFile(config: {
215
227
  forceSetImmutable?: boolean;
216
228
  noChecks?: boolean;
217
229
  internal?: boolean;
230
+ noFallbacks?: boolean;
218
231
  }): Promise<{ writeTime: number; size: number } | undefined> {
219
232
  let { from, to, path } = config;
220
233
  let size = config.size;
@@ -226,7 +239,7 @@ export async function copyArchiveFile(config: {
226
239
  writeTime = info.writeTime;
227
240
  }
228
241
  if (size <= LARGE_COPY_THRESHOLD) {
229
- let result = await from.get2(path, { internal: config.internal });
242
+ let result = await from.get2(path, { internal: config.internal, noFallbacks: config.noFallbacks });
230
243
  // Empty counts as absent, never as content to copy: an empty file IS a deletion, set refuses empty buffers, and deletions travel through their own path (del / scan tombstones)
231
244
  if (!result || !result.data || !result.data.length) return undefined;
232
245
  await to.set(path, result.data, { lastModified: result.writeTime, forceSetImmutable: config.forceSetImmutable, noChecks: config.noChecks, internal: config.internal });
@@ -242,7 +255,7 @@ export async function copyArchiveFile(config: {
242
255
  getNextData: async () => {
243
256
  if (offset >= totalSize) return undefined;
244
257
  let end = Math.min(offset + LARGE_COPY_CHUNK, totalSize);
245
- let data = await from.get(path, { range: { start: offset, end }, internal: config.internal });
258
+ let data = await from.get(path, { range: { start: offset, end }, internal: config.internal, noFallbacks: config.noFallbacks });
246
259
  if (!data || !data.length) {
247
260
  throw new Error(`Ranged read of ${JSON.stringify(path)} from ${from.getDebugName()} returned ${data && data.length || "nothing"} at ${offset}-${end} (expected ${end - offset} bytes of a ${totalSize} byte file - it changed or vanished mid-copy)`);
248
261
  }
@@ -312,9 +325,9 @@ export interface IArchives {
312
325
  * their empty files - that is how scans learn of deletions - but nothing built on the index
313
326
  * ever surfaces them.
314
327
  */
315
- find(prefix: string, config?: { shallow?: boolean; type: "files" | "folders" }): Promise<string[]>;
328
+ find(prefix: string, config?: FindConfig): Promise<string[]>;
316
329
  /** See find for the empty-file (tombstone) rule. */
317
- findInfo(prefix: string, config?: { shallow?: boolean; type: "files" | "folders" }): Promise<ArchiveFileInfo[]>;
330
+ findInfo(prefix: string, config?: FindConfig): Promise<ArchiveFileInfo[]>;
318
331
  /** Only works for public buckets (private buckets are API-access only). */
319
332
  getURL(path: string): Promise<string>;
320
333
  /** The bucket's configuration, which tells whether the optional functions are supported. */
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
- import { IArchives, ArchivesConfig, ChangesAfterConfig, ArchiveFileInfo, DelConfig, GetConfig, GetInfoConfig, SetConfig } from "./IArchives";
3
+ import { IArchives, ArchivesConfig, ChangesAfterConfig, ArchiveFileInfo, DelConfig, FindConfig, GetConfig, GetInfoConfig, SetConfig } from "./IArchives";
4
4
  export declare class ArchivesBackblaze implements IArchives {
5
5
  private config;
6
6
  constructor(config: {
@@ -39,15 +39,9 @@ export declare class ArchivesBackblaze implements IArchives {
39
39
  writeTime: number;
40
40
  size: number;
41
41
  } | undefined>;
42
- find(prefix: string, config?: {
43
- shallow?: boolean;
44
- type: "files" | "folders";
45
- }): Promise<string[]>;
42
+ find(prefix: string, config?: FindConfig): Promise<string[]>;
46
43
  getChangesAfter2(config: ChangesAfterConfig): Promise<ArchiveFileInfo[]>;
47
- findInfo(prefix: string, config?: {
48
- shallow?: boolean;
49
- type: "files" | "folders";
50
- }): Promise<{
44
+ findInfo(prefix: string, config?: FindConfig): Promise<{
51
45
  path: string;
52
46
  createTime: number;
53
47
  size: number;
@@ -9,7 +9,7 @@ import debugbreak from "debugbreak";
9
9
  import dns from "dns";
10
10
  import { getSecret } from "../misc/getSecret";
11
11
  import { httpsRequest, HttpsResponseInfo } from "socket-function/src/https";
12
- import { IArchives, ArchivesConfig, ChangesAfterConfig, ArchiveFileInfo, DelConfig, GetConfig, GetInfoConfig, SetConfig, assertValidLastModified, bufferChunkStream, IMMUTABLE_CACHE_TIME } from "./IArchives";
12
+ import { IArchives, ArchivesConfig, ChangesAfterConfig, ArchiveFileInfo, DelConfig, FindConfig, GetConfig, GetInfoConfig, SetConfig, assertValidLastModified, bufferChunkStream, IMMUTABLE_CACHE_TIME } from "./IArchives";
13
13
  import { filterChanges } from "./remoteStorage/remoteConfig";
14
14
 
15
15
  type BackblazeCreds = {
@@ -639,12 +639,12 @@ export class ArchivesBackblaze implements IArchives {
639
639
  setTimeout(downloadPoll, 5000);
640
640
  };
641
641
  setTimeout(downloadPoll, 5000);
642
- let result = await this.apiRetryLogic(`get ${fileName}`, async (api): Promise<{ data: Buffer; writeTime: number; size: number }> => {
642
+ let result = await this.apiRetryLogic(`get ${fileName}`, async (api): Promise<{ data: Buffer; writeTime: number; size: number } | undefined> => {
643
643
  let range = config?.range;
644
644
  if (range) {
645
- // The clamp needs the file's size (and gives us its metadata for free)
646
- let fileInfo = await this.getInfo(fileName);
647
- if (!fileInfo) throw new Error(`File ${fileName} not found`);
645
+ // The clamp needs the file's size (and gives us its metadata for free). The tombstone flag forwards: without it a deleted file's info is hidden, so the ranged read reports absent too.
646
+ let fileInfo = await this.getInfo(fileName, { includeTombstones: config?.includeTombstones });
647
+ if (!fileInfo) return undefined;
648
648
  let rangeStart = range.start;
649
649
  let rangeEnd = Math.min(range.end, fileInfo.size);
650
650
  // NOTE: I think if we request nothing, it confuses Backblaze and ends up giving us the entire file.
@@ -666,9 +666,15 @@ export class ArchivesBackblaze implements IArchives {
666
666
  fileName,
667
667
  outResponse: response,
668
668
  });
669
+ // Backblaze stores this system's deletions as REAL empty files (its hide would make them invisible to scans), so an empty download IS a tombstone - absent, unless the caller asked to see tombstones
670
+ if (!data.length && !config?.includeTombstones) {
671
+ this.log(`backblaze file is a tombstone (deleted) ${fileName}`);
672
+ return undefined;
673
+ }
669
674
  let meta = parseFileMetadataHeaders(response);
670
675
  return { data, writeTime: meta.uploadTimestamp, size: data.length };
671
676
  });
677
+ if (!result) return undefined;
672
678
  let timeStr = formatTime(Date.now() - time);
673
679
  let rateStr = formatNumber(result.data.length / (Date.now() - time) * 1000) + "B/s";
674
680
  this.log(`backblaze download (${formatNumber(result.data.length)}B${config?.range && `, ${formatNumber(config.range.start)} - ${formatNumber(config.range.end)}` || ""}) in ${timeStr} (${rateStr}, ${fileName})`);
@@ -713,14 +719,12 @@ export class ArchivesBackblaze implements IArchives {
713
719
  }
714
720
  if (config?.lastModified) {
715
721
  assertValidLastModified(config.lastModified);
716
- if (!config.noChecks) {
717
- // includeTombstones: a deletion pushed to b2 is a real size-0 file, and it must still win the older-write comparison - or an older-stamped write would resurrect the deleted file
718
- let existing = await this.getInfo(fileName, { includeTombstones: true });
719
- // An older write never overwrites a newer one (see IArchives.set). B2 stamps its own upload time, so the exact lastModified is not preserved on the stored file.
720
- if (existing && config.lastModified < existing.writeTime) return fileName;
721
- // Immutability wins: a synchronization push never overwrites an existing path on an immutable bucket (see SetConfig.forceSetImmutable)
722
- if (existing && config.forceSetImmutable && this.config.immutable) return fileName;
723
- }
722
+ // This comparison deliberately IGNORES noChecks: backblaze has no server of ours to enforce only-take-the-latest (unlike hosted targets, where the receiving store re-checks), so this comparison IS the ordering guard. Skipping it lets a stale push land over a newer value or tombstone - and because b2 stamps its own upload times, the stale data then becomes the newest-timestamped copy in the whole system, resurrecting globally through everyone's scans. includeTombstones: a deletion on b2 is a real size-0 file and must win this comparison too.
723
+ let existing = await this.getInfo(fileName, { includeTombstones: true });
724
+ // An older write never overwrites a newer one (see IArchives.set). B2 stamps its own upload time, so the exact lastModified is not preserved on the stored file.
725
+ if (existing && config.lastModified < existing.writeTime) return fileName;
726
+ // Immutability wins: a synchronization push never overwrites an existing path on an immutable bucket (see SetConfig.forceSetImmutable)
727
+ if (existing && config.forceSetImmutable && this.config.immutable) return fileName;
724
728
  }
725
729
  // Big buffers stream through the large-file API: a failed part retries alone instead of restarting the whole upload. The threshold MUST stay at two full chunks - below that setLargeFile falls back to plain set, which would recurse right back here.
726
730
  if (data.length >= LARGE_FILE_MIN_CHUNK_SIZE * 2) {
@@ -750,10 +754,9 @@ export class ArchivesBackblaze implements IArchives {
750
754
  public async del(fileName: string, config?: DelConfig): Promise<void> {
751
755
  if (config?.lastModified) {
752
756
  // A synchronized deletion: b2's hide removes the file from listings entirely, so peers scanning the bucket could never learn of it. Instead the tombstone is stored as a REAL empty file (an empty file IS a missing file), which listings show and scans ingest as a deletion. (b2 stamps its own upload time, so the exact deletion time is not preserved here - same as every b2 write.)
753
- if (!config.noChecks) {
754
- let existing = await this.getInfo(fileName, { includeTombstones: true });
755
- if (existing && config.lastModified < existing.writeTime) return;
756
- }
757
+ // The comparison ignores noChecks for the same reason as in set: on b2 it IS the ordering guard
758
+ let existing = await this.getInfo(fileName, { includeTombstones: true });
759
+ if (existing && config.lastModified < existing.writeTime) return;
757
760
  this.log(`backblaze tombstone upload ${fileName}`);
758
761
  await this.apiRetryLogic(`del ${fileName}`, async (api) => {
759
762
  await api.uploadFile({ bucketId: this.bucketId, fileName, data: Buffer.alloc(0) });
@@ -929,7 +932,7 @@ export class ArchivesBackblaze implements IArchives {
929
932
  }
930
933
 
931
934
  // For example findFileNames("ips/")
932
- public async find(prefix: string, config?: { shallow?: boolean; type: "files" | "folders" }): Promise<string[]> {
935
+ public async find(prefix: string, config?: FindConfig): Promise<string[]> {
933
936
  let result = await this.findInfo(prefix, config);
934
937
  return result.map(x => x.path);
935
938
  }
@@ -938,7 +941,7 @@ export class ArchivesBackblaze implements IArchives {
938
941
  return filterChanges(await this.findInfo(""), config);
939
942
  }
940
943
 
941
- public async findInfo(prefix: string, config?: { shallow?: boolean; type: "files" | "folders" }): Promise<{ path: string; createTime: number; size: number; }[]> {
944
+ public async findInfo(prefix: string, config?: FindConfig): Promise<{ path: string; createTime: number; size: number; }[]> {
942
945
  return await this.apiRetryLogic(`findInfo ${prefix}`, async (api) => {
943
946
  if (!config?.shallow && config?.type === "folders") {
944
947
  let allFiles = await this.findInfo(prefix);