sliftutils 1.7.64 → 1.7.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +51 -7
- package/package.json +1 -1
- package/storage/IArchives.d.ts +11 -1
- package/storage/IArchives.ts +11 -6
- package/storage/dist/IArchives.ts.cache +6 -6
- package/storage/remoteStorage/ArchivesRemote.ts +2 -2
- package/storage/remoteStorage/blobStore.d.ts +18 -0
- package/storage/remoteStorage/blobStore.ts +40 -7
- package/storage/remoteStorage/createArchives.d.ts +17 -4
- package/storage/remoteStorage/createArchives.ts +121 -80
- package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +4 -4
- package/storage/remoteStorage/dist/blobStore.ts.cache +39 -9
- package/storage/remoteStorage/dist/createArchives.ts.cache +119 -78
- package/storage/remoteStorage/dist/sourceWrapper.ts.cache +3 -4
- package/storage/remoteStorage/dist/storageController.ts.cache +8 -5
- package/storage/remoteStorage/dist/storageServerState.ts.cache +35 -6
- package/storage/remoteStorage/sourceWrapper.ts +2 -3
- package/storage/remoteStorage/storageController.d.ts +2 -2
- package/storage/remoteStorage/storageController.ts +6 -3
- package/storage/remoteStorage/storageServerState.d.ts +3 -0
- package/storage/remoteStorage/storageServerState.ts +31 -4
- package/test.ts +48 -38
- package/treeSummary.ts +127 -0
package/index.d.ts
CHANGED
|
@@ -2146,6 +2146,8 @@ declare module "sliftutils/storage/IArchives" {
|
|
|
2146
2146
|
};
|
|
2147
2147
|
/** Read ONLY from the primary source - the one writes would target - instead of falling back across the redundant sources. Use this when you want your reads and writes to be somewhat atomic: there will still be issues with the round trip, but without it you could talk to a completely different node and get a much older value. Most reads aren't followed by a write though, so for most cases it's better to get a value than to have to wait (or even throw) when the primary node is not available. */
|
|
2148
2148
|
noFallbacks?: boolean;
|
|
2149
|
+
/** 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. */
|
|
2150
|
+
internal?: boolean;
|
|
2149
2151
|
};
|
|
2150
2152
|
export type ChangesAfterConfig = {
|
|
2151
2153
|
time: number;
|
|
@@ -2158,6 +2160,8 @@ declare module "sliftutils/storage/IArchives" {
|
|
|
2158
2160
|
forceSetImmutable?: boolean;
|
|
2159
2161
|
/** 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. */
|
|
2160
2162
|
noChecks?: boolean;
|
|
2163
|
+
/** 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. */
|
|
2164
|
+
internal?: boolean;
|
|
2161
2165
|
};
|
|
2162
2166
|
export type ArchiveFileInfo = {
|
|
2163
2167
|
path: string;
|
|
@@ -2212,6 +2216,7 @@ declare module "sliftutils/storage/IArchives" {
|
|
|
2212
2216
|
writeTime?: number;
|
|
2213
2217
|
forceSetImmutable?: boolean;
|
|
2214
2218
|
noChecks?: boolean;
|
|
2219
|
+
internal?: boolean;
|
|
2215
2220
|
}): Promise<{
|
|
2216
2221
|
writeTime: number;
|
|
2217
2222
|
size: number;
|
|
@@ -2242,12 +2247,17 @@ declare module "sliftutils/storage/IArchives" {
|
|
|
2242
2247
|
* throws instead of degrading to a stale copy).
|
|
2243
2248
|
*/
|
|
2244
2249
|
get(fileName: string, config?: GetConfig): Promise<Buffer | undefined>;
|
|
2245
|
-
/** See get for the fallback semantics (and when to pass noFallbacks). url is the config URL of the source that
|
|
2250
|
+
/** See get for the fallback semantics (and when to pass noFallbacks). url is the config URL of the source that answered - the authority the data (or the "does not exist") came from. Multi-source implementations (ArchivesChain) ALWAYS return an object: when the value doesn't exist there is still a server saying it doesn't exist, so they return { url } alone rather than undefined. Single-source backends return undefined for absent (they ARE the authority). */
|
|
2246
2251
|
get2(fileName: string, config?: GetConfig): Promise<{
|
|
2247
2252
|
data: Buffer;
|
|
2248
2253
|
writeTime: number;
|
|
2249
2254
|
size: number;
|
|
2250
2255
|
url?: string;
|
|
2256
|
+
} | {
|
|
2257
|
+
data?: undefined;
|
|
2258
|
+
writeTime?: undefined;
|
|
2259
|
+
size?: undefined;
|
|
2260
|
+
url: string;
|
|
2251
2261
|
} | undefined>;
|
|
2252
2262
|
/**
|
|
2253
2263
|
* lastModified stamps the write with that last-write time instead of now. If it is OLDER than
|
|
@@ -2996,6 +3006,14 @@ declare module "sliftutils/storage/remoteStorage/blobStore" {
|
|
|
2996
3006
|
writeTime: number;
|
|
2997
3007
|
size: number;
|
|
2998
3008
|
} | undefined>;
|
|
3009
|
+
getInternal2?(fileName: string, config?: GetConfig): Promise<{
|
|
3010
|
+
data: Buffer;
|
|
3011
|
+
writeTime: number;
|
|
3012
|
+
size: number;
|
|
3013
|
+
} | undefined>;
|
|
3014
|
+
setInternal?(fileName: string, data: Buffer, config: {
|
|
3015
|
+
lastModified: number;
|
|
3016
|
+
}): Promise<void>;
|
|
2999
3017
|
set(fileName: string, data: Buffer, config?: WriteConfig): Promise<string>;
|
|
3000
3018
|
del(fileName: string, config?: WriteConfig): Promise<void>;
|
|
3001
3019
|
getInfo(fileName: string): Promise<{
|
|
@@ -3135,6 +3153,16 @@ declare module "sliftutils/storage/remoteStorage/blobStore" {
|
|
|
3135
3153
|
writeTime: number;
|
|
3136
3154
|
size: number;
|
|
3137
3155
|
} | undefined>;
|
|
3156
|
+
/** Internal (store-to-store) read: purely the local disk, completely short-circuiting the index and holder resolution - the caller is another store, and chasing OUR remote holders while answering it is how infinite get loops between stores form. No window or route checks: if the bytes are on our disk, the caller may have them. Note fast writes still sitting in the overlay are invisible here; the caller re-finds them after our flush. */
|
|
3157
|
+
getInternal2(key: string, config?: GetConfig): Promise<{
|
|
3158
|
+
data: Buffer;
|
|
3159
|
+
writeTime: number;
|
|
3160
|
+
size: number;
|
|
3161
|
+
} | undefined>;
|
|
3162
|
+
/** Internal (store-to-store) write: the local disk plus our index, with NO downstream fan-out - the pushing store owns propagation, and fanning its pushes back out is how write loops between stores form. Window/route acceptance is the caller's (writeBucketFile's) job; only-take-latest still applies here. */
|
|
3163
|
+
setInternal(key: string, data: Buffer, config: {
|
|
3164
|
+
lastModified: number;
|
|
3165
|
+
}): Promise<void>;
|
|
3138
3166
|
private cacheRead;
|
|
3139
3167
|
set(key: string, data: Buffer, config?: WriteConfig): Promise<string>;
|
|
3140
3168
|
del(key: string, config?: WriteConfig): Promise<void>;
|
|
@@ -3210,7 +3238,9 @@ declare module "sliftutils/storage/remoteStorage/createArchives" {
|
|
|
3210
3238
|
private recheckAvailability;
|
|
3211
3239
|
private recheckAvailabilityNow;
|
|
3212
3240
|
private run;
|
|
3213
|
-
private
|
|
3241
|
+
private runPrimary;
|
|
3242
|
+
/** Races call against a size-based deadline. Uploads know their size upfront; gets are given SMART_TIMEOUT_PROBE to produce anything, and only then is the file's info fetched (from the same source, itself time-limited) to size the deadline - measured from the call's start, so a source that was slow before the probe doesn't get the full allowance again. Timed-out calls keep running in the background (they cannot be cancelled) but their eventual result is ignored. */
|
|
3243
|
+
private applySmartTimeout;
|
|
3214
3244
|
private lastConfigRefresh;
|
|
3215
3245
|
private prepareWrongTargetRetry;
|
|
3216
3246
|
private request;
|
|
@@ -3226,13 +3256,24 @@ declare module "sliftutils/storage/remoteStorage/createArchives" {
|
|
|
3226
3256
|
writeTime: number;
|
|
3227
3257
|
size: number;
|
|
3228
3258
|
url: string;
|
|
3229
|
-
} |
|
|
3259
|
+
} | {
|
|
3260
|
+
data?: undefined;
|
|
3261
|
+
writeTime?: undefined;
|
|
3262
|
+
size?: undefined;
|
|
3263
|
+
url: string;
|
|
3264
|
+
}>;
|
|
3265
|
+
/** Always resolves with a url - the authority that answered. A value that doesn't exist is still an answer FROM a server, so it comes back as { url } with no data (never plain undefined); errors from every source throw instead. */
|
|
3230
3266
|
get2(fileName: string, config?: GetConfig): Promise<{
|
|
3231
3267
|
data: Buffer;
|
|
3232
3268
|
writeTime: number;
|
|
3233
3269
|
size: number;
|
|
3234
3270
|
url: string;
|
|
3235
|
-
} |
|
|
3271
|
+
} | {
|
|
3272
|
+
data?: undefined;
|
|
3273
|
+
writeTime?: undefined;
|
|
3274
|
+
size?: undefined;
|
|
3275
|
+
url: string;
|
|
3276
|
+
}>;
|
|
3236
3277
|
getInfo(fileName: string): Promise<{
|
|
3237
3278
|
writeTime: number;
|
|
3238
3279
|
size: number;
|
|
@@ -3265,7 +3306,7 @@ declare module "sliftutils/storage/remoteStorage/createArchives" {
|
|
|
3265
3306
|
getNextData(): Promise<Buffer | undefined>;
|
|
3266
3307
|
}): Promise<void>;
|
|
3267
3308
|
getURL(path: string): Promise<string>;
|
|
3268
|
-
/** Every URL that could serve this path: public sources matching both the path's route and the current valid window. The first is the write node's (first matching source in config order, see
|
|
3309
|
+
/** Every URL that could serve this path: public sources matching both the path's route and the current valid window. The first is the write node's (first matching source in config order, see runPrimary - the one guaranteed current); the rest are ranked fastest-first by measured latency. Empty when none qualify. */
|
|
3269
3310
|
getURLs(path: string): Promise<string[]>;
|
|
3270
3311
|
/** getURLs, but after the one await (initialization) the returned function is synchronous: everything underneath - route hashing, window checks, latencies, URL building - is synchronous, and the closure always reads the newest adopted config, so it stays correct across config refreshes. */
|
|
3271
3312
|
getGetURLs(): Promise<(path: string) => string[]>;
|
|
@@ -3554,12 +3595,12 @@ declare module "sliftutils/storage/remoteStorage/storageController" {
|
|
|
3554
3595
|
get2: (account: string, bucketName: string, path: string, range?: {
|
|
3555
3596
|
start: number;
|
|
3556
3597
|
end: number;
|
|
3557
|
-
}) => Promise<{
|
|
3598
|
+
}, internal?: boolean) => Promise<{
|
|
3558
3599
|
data: Buffer;
|
|
3559
3600
|
writeTime: number;
|
|
3560
3601
|
size: number;
|
|
3561
3602
|
} | undefined>;
|
|
3562
|
-
set: (account: string, bucketName: string, path: string, data: Buffer, lastModified?: number, forceSetImmutable?: boolean) => Promise<void>;
|
|
3603
|
+
set: (account: string, bucketName: string, path: string, data: Buffer, lastModified?: number, forceSetImmutable?: boolean, internal?: boolean) => Promise<void>;
|
|
3563
3604
|
del: (account: string, bucketName: string, path: string) => Promise<void>;
|
|
3564
3605
|
getInfo: (account: string, bucketName: string, path: string) => Promise<{
|
|
3565
3606
|
writeTime: number;
|
|
@@ -3664,6 +3705,8 @@ declare module "sliftutils/storage/remoteStorage/storageServerState" {
|
|
|
3664
3705
|
};
|
|
3665
3706
|
export declare function addExtraListenPort(port: number): void;
|
|
3666
3707
|
export declare function removeExtraListenPort(port: number): void;
|
|
3708
|
+
/** Whether address:port is this server process. The ONE self test - findSelfIndexes, createApiArchives, and SourceWrapper all consult it, so "is this me" cannot disagree between the routing plan and connection building: a URL that is us on an extra listen port must never become a network client to ourselves, which is how infinite self-request loops form. */
|
|
3709
|
+
export declare function isOwnAddress(address: string, port: number): boolean;
|
|
3667
3710
|
/** A cached IArchives for a persisted source identity: a routing URL (hosted/backblaze) or a disk folder path - the form BlobStore's sources list stores. Configuration (valid windows, routes) decides WHEN a source should be used; for reading bytes the index says a source holds, the URL alone is enough - even for sources no longer in any config. */
|
|
3668
3711
|
export declare function resolveSourceArchives(url: string): IArchives;
|
|
3669
3712
|
/** Our role in a bucket's routing config, summarized across ALL currently-valid self entries. Stored instead of a single representative HostedConfig, so nothing can accidentally use one entry's route or flags where the union is required - the standard config has the same URL twice: a routed write-shard entry plus an unrouted read-everything entry. */
|
|
@@ -3681,6 +3724,7 @@ declare module "sliftutils/storage/remoteStorage/storageServerState" {
|
|
|
3681
3724
|
export declare function writeBucketFile(account: string, bucketName: string, filePath: string, data: Buffer, config?: {
|
|
3682
3725
|
lastModified?: number;
|
|
3683
3726
|
forceSetImmutable?: boolean;
|
|
3727
|
+
internal?: boolean;
|
|
3684
3728
|
}): Promise<void>;
|
|
3685
3729
|
export declare function getBucketConfig(bucket: LoadedBucket): ArchivesConfig;
|
|
3686
3730
|
/** Which buckets this process currently has loaded - what a deploy successor asks its predecessor for, so it activates exactly the buckets that are actually in use. */
|
package/package.json
CHANGED
package/storage/IArchives.d.ts
CHANGED
|
@@ -55,6 +55,8 @@ export type GetConfig = {
|
|
|
55
55
|
};
|
|
56
56
|
/** Read ONLY from the primary source - the one writes would target - instead of falling back across the redundant sources. Use this when you want your reads and writes to be somewhat atomic: there will still be issues with the round trip, but without it you could talk to a completely different node and get a much older value. Most reads aren't followed by a write though, so for most cases it's better to get a value than to have to wait (or even throw) when the primary node is not available. */
|
|
57
57
|
noFallbacks?: boolean;
|
|
58
|
+
/** 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
|
+
internal?: boolean;
|
|
58
60
|
};
|
|
59
61
|
export type ChangesAfterConfig = {
|
|
60
62
|
time: number;
|
|
@@ -67,6 +69,8 @@ export type SetConfig = {
|
|
|
67
69
|
forceSetImmutable?: boolean;
|
|
68
70
|
/** 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. */
|
|
69
71
|
noChecks?: boolean;
|
|
72
|
+
/** 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. */
|
|
73
|
+
internal?: boolean;
|
|
70
74
|
};
|
|
71
75
|
export type ArchiveFileInfo = {
|
|
72
76
|
path: string;
|
|
@@ -121,6 +125,7 @@ export declare function copyArchiveFile(config: {
|
|
|
121
125
|
writeTime?: number;
|
|
122
126
|
forceSetImmutable?: boolean;
|
|
123
127
|
noChecks?: boolean;
|
|
128
|
+
internal?: boolean;
|
|
124
129
|
}): Promise<{
|
|
125
130
|
writeTime: number;
|
|
126
131
|
size: number;
|
|
@@ -151,12 +156,17 @@ export interface IArchives {
|
|
|
151
156
|
* throws instead of degrading to a stale copy).
|
|
152
157
|
*/
|
|
153
158
|
get(fileName: string, config?: GetConfig): Promise<Buffer | undefined>;
|
|
154
|
-
/** See get for the fallback semantics (and when to pass noFallbacks). url is the config URL of the source that
|
|
159
|
+
/** See get for the fallback semantics (and when to pass noFallbacks). url is the config URL of the source that answered - the authority the data (or the "does not exist") came from. Multi-source implementations (ArchivesChain) ALWAYS return an object: when the value doesn't exist there is still a server saying it doesn't exist, so they return { url } alone rather than undefined. Single-source backends return undefined for absent (they ARE the authority). */
|
|
155
160
|
get2(fileName: string, config?: GetConfig): Promise<{
|
|
156
161
|
data: Buffer;
|
|
157
162
|
writeTime: number;
|
|
158
163
|
size: number;
|
|
159
164
|
url?: string;
|
|
165
|
+
} | {
|
|
166
|
+
data?: undefined;
|
|
167
|
+
writeTime?: undefined;
|
|
168
|
+
size?: undefined;
|
|
169
|
+
url: string;
|
|
160
170
|
} | undefined>;
|
|
161
171
|
/**
|
|
162
172
|
* lastModified stamps the write with that last-write time instead of now. If it is OLDER than
|
package/storage/IArchives.ts
CHANGED
|
@@ -90,6 +90,8 @@ export type GetConfig = {
|
|
|
90
90
|
range?: { start: number; end: number };
|
|
91
91
|
/** Read ONLY from the primary source - the one writes would target - instead of falling back across the redundant sources. Use this when you want your reads and writes to be somewhat atomic: there will still be issues with the round trip, but without it you could talk to a completely different node and get a much older value. Most reads aren't followed by a write though, so for most cases it's better to get a value than to have to wait (or even throw) when the primary node is not available. */
|
|
92
92
|
noFallbacks?: boolean;
|
|
93
|
+
/** 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
|
+
internal?: boolean;
|
|
93
95
|
};
|
|
94
96
|
|
|
95
97
|
export type ChangesAfterConfig = {
|
|
@@ -104,6 +106,8 @@ export type SetConfig = {
|
|
|
104
106
|
forceSetImmutable?: boolean;
|
|
105
107
|
/** 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. */
|
|
106
108
|
noChecks?: boolean;
|
|
109
|
+
/** 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. */
|
|
110
|
+
internal?: boolean;
|
|
107
111
|
};
|
|
108
112
|
|
|
109
113
|
// createTime is a misnomer kept for compatibility — it is really the LAST-WRITE time, same as getInfo's writeTime. Neither Backblaze nor our remote storage tracks a distinct creation date: each write stamps a fresh timestamp on the current version, so both fields are just "when the bytes served by get() were most recently written".
|
|
@@ -182,6 +186,7 @@ export async function copyArchiveFile(config: {
|
|
|
182
186
|
writeTime?: number;
|
|
183
187
|
forceSetImmutable?: boolean;
|
|
184
188
|
noChecks?: boolean;
|
|
189
|
+
internal?: boolean;
|
|
185
190
|
}): Promise<{ writeTime: number; size: number } | undefined> {
|
|
186
191
|
let { from, to, path } = config;
|
|
187
192
|
let size = config.size;
|
|
@@ -193,9 +198,9 @@ export async function copyArchiveFile(config: {
|
|
|
193
198
|
writeTime = info.writeTime;
|
|
194
199
|
}
|
|
195
200
|
if (size <= LARGE_COPY_THRESHOLD) {
|
|
196
|
-
let result = await from.get2(path);
|
|
197
|
-
if (!result) return undefined;
|
|
198
|
-
await to.set(path, result.data, { lastModified: result.writeTime, forceSetImmutable: config.forceSetImmutable, noChecks: config.noChecks });
|
|
201
|
+
let result = await from.get2(path, { internal: config.internal });
|
|
202
|
+
if (!result || !result.data) return undefined;
|
|
203
|
+
await to.set(path, result.data, { lastModified: result.writeTime, forceSetImmutable: config.forceSetImmutable, noChecks: config.noChecks, internal: config.internal });
|
|
199
204
|
return { writeTime: result.writeTime, size: result.data.length };
|
|
200
205
|
}
|
|
201
206
|
// Consts so the closure keeps the narrowed types
|
|
@@ -208,7 +213,7 @@ export async function copyArchiveFile(config: {
|
|
|
208
213
|
getNextData: async () => {
|
|
209
214
|
if (offset >= totalSize) return undefined;
|
|
210
215
|
let end = Math.min(offset + LARGE_COPY_CHUNK, totalSize);
|
|
211
|
-
let data = await from.get(path, { range: { start: offset, end } });
|
|
216
|
+
let data = await from.get(path, { range: { start: offset, end }, internal: config.internal });
|
|
212
217
|
if (!data || !data.length) {
|
|
213
218
|
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)`);
|
|
214
219
|
}
|
|
@@ -248,8 +253,8 @@ export interface IArchives {
|
|
|
248
253
|
* throws instead of degrading to a stale copy).
|
|
249
254
|
*/
|
|
250
255
|
get(fileName: string, config?: GetConfig): Promise<Buffer | undefined>;
|
|
251
|
-
/** See get for the fallback semantics (and when to pass noFallbacks). url is the config URL of the source that
|
|
252
|
-
get2(fileName: string, config?: GetConfig): Promise<{ data: Buffer; writeTime: number; size: number; url?: string } | undefined>;
|
|
256
|
+
/** See get for the fallback semantics (and when to pass noFallbacks). url is the config URL of the source that answered - the authority the data (or the "does not exist") came from. Multi-source implementations (ArchivesChain) ALWAYS return an object: when the value doesn't exist there is still a server saying it doesn't exist, so they return { url } alone rather than undefined. Single-source backends return undefined for absent (they ARE the authority). */
|
|
257
|
+
get2(fileName: string, config?: GetConfig): Promise<{ data: Buffer; writeTime: number; size: number; url?: string } | { data?: undefined; writeTime?: undefined; size?: undefined; url: string } | undefined>;
|
|
253
258
|
/**
|
|
254
259
|
* lastModified stamps the write with that last-write time instead of now. If it is OLDER than
|
|
255
260
|
* the file's current last-write time the write no-ops (so delayed / synchronized writes can
|
|
@@ -44,10 +44,10 @@ async function copyArchiveFile(config) {
|
|
|
44
44
|
writeTime = info.writeTime;
|
|
45
45
|
}
|
|
46
46
|
if (size <= LARGE_COPY_THRESHOLD) {
|
|
47
|
-
let result = await from.get2(path);
|
|
48
|
-
if (!result)
|
|
47
|
+
let result = await from.get2(path, { internal: config.internal });
|
|
48
|
+
if (!result || !result.data)
|
|
49
49
|
return undefined;
|
|
50
|
-
await to.set(path, result.data, { lastModified: result.writeTime, forceSetImmutable: config.forceSetImmutable, noChecks: config.noChecks });
|
|
50
|
+
await to.set(path, result.data, { lastModified: result.writeTime, forceSetImmutable: config.forceSetImmutable, noChecks: config.noChecks, internal: config.internal });
|
|
51
51
|
return { writeTime: result.writeTime, size: result.data.length };
|
|
52
52
|
}
|
|
53
53
|
// Consts so the closure keeps the narrowed types
|
|
@@ -61,7 +61,7 @@ async function copyArchiveFile(config) {
|
|
|
61
61
|
if (offset >= totalSize)
|
|
62
62
|
return undefined;
|
|
63
63
|
let end = Math.min(offset + LARGE_COPY_CHUNK, totalSize);
|
|
64
|
-
let data = await from.get(path, { range: { start: offset, end } });
|
|
64
|
+
let data = await from.get(path, { range: { start: offset, end }, internal: config.internal });
|
|
65
65
|
if (!data || !data.length) {
|
|
66
66
|
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)`);
|
|
67
67
|
}
|
|
@@ -72,5 +72,5 @@ async function copyArchiveFile(config) {
|
|
|
72
72
|
return { writeTime: finalWriteTime, size: totalSize };
|
|
73
73
|
}
|
|
74
74
|
exports.copyArchiveFile = copyArchiveFile;
|
|
75
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSUFyY2hpdmVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiSUFyY2hpdmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSx3S0FBd0s7OztBQUV4SyxzSkFBc0o7QUFDekksUUFBQSx3QkFBd0IsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUV2RCx5TEFBeUw7QUFDNUssUUFBQSxvQkFBb0IsR0FBRyxLQUFLLEdBQUcsSUFBSSxDQUFDO0FBQ2pELFNBQWdCLHVCQUF1QixDQUFDLFlBQW9CO0lBQ3hELElBQUksR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxnQ0FBd0IsQ0FBQztJQUNoRCxJQUFJLFlBQVksR0FBRyxHQUFHLEVBQUUsQ0FBQztRQUNyQixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxZQUFZLE1BQU0sR0FBRyxxQkFBcUIsQ0FBQyxDQUFDO0lBQzFHLENBQUM7QUFDTCxDQUFDO0FBTEQsMERBS0M7QUF1RVksUUFBQSxpQkFBaUIsR0FBcUIsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7QUF3RWhGLHdYQUF3WDtBQUMzVyxRQUFBLDBCQUEwQixHQUFHLDRDQUE0QyxDQUFDO0FBRXZGLDhMQUE4TDtBQUNqTCxRQUFBLG1CQUFtQixHQUFHLHFDQUFxQyxDQUFDO0FBRTVELFFBQUEsVUFBVSxHQUFxQixDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUVuRCwyUkFBMlI7QUFDOVEsUUFBQSxjQUFjLEdBQUcsNkNBQTZDLENBQUM7QUFDNUUsb0xBQW9MO0FBQ3BMLDhKQUE4SjtBQUM5SixTQUFnQixtQkFBbUIsQ0FBQyxXQUF5QztJQUN6RSxJQUFJLENBQUMsV0FBVztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQzlCLE9BQU8sV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztBQUN2QyxDQUFDO0FBSEQsa0RBR0M7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QUM7QUEzQ0QsMENBMkNDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gVGhlIGltcG9ydGFudCBvcGVyYXRpb25zIG9mIGFuIGFyY2hpdmUgYnVja2V0IChleHRyYWN0ZWQgZnJvbSBBcmNoaXZlc0JhY2tibGF6ZSksIHNvIG90aGVyIGJhY2tlbmRzIChlLmcuIG91ciBvd24gcmVtb3RlIHN0b3JhZ2Ugc2VydmVyKSBjYW4gYmUgdXNlZCBpbnRlcmNoYW5nZWFibHkuXG5cbi8vIEEgd3JpdGUgbWF5IG5vdCBiZSBzdGFtcGVkIG1vcmUgdGhhbiB0aGlzIGZhciBpbiB0aGUgZnV0dXJlLCBvciBjbG9jayBza2V3IGJldHdlZW4gbWFjaGluZXMgd291bGQgbGV0IGEgYmFkIHRpbWVzdGFtcCBibG9jayB3cml0ZXMgZm9yIGEgbG9uZyB0aW1lLlxuZXhwb3J0IGNvbnN0IE1BWF9MQVNUX01PRElGSUVEX0ZVVFVSRSA9IDE1ICogNjAgKiAxMDAwO1xuXG4vLyBIb3cgbG9uZyBicm93c2VycyBtYXkgY2FjaGUgZmlsZXMgZnJvbSBpbW11dGFibGUgYnVja2V0cyAodGhlIENhY2hlLUNvbnRyb2wgbWF4LWFnZSksIHNoYXJlZCBieSBldmVyeSBob3N0aW5nIHBhdGggKGJhY2tibGF6ZSBidWNrZXQgc2V0dGluZ3MgYW5kIG91ciBvd24gc3RvcmFnZSBzZXJ2ZXIncyBIVFRQIHJvdXRlKVxuZXhwb3J0IGNvbnN0IElNTVVUQUJMRV9DQUNIRV9USU1FID0gODY0MDAgKiAxMDAwO1xuZXhwb3J0IGZ1bmN0aW9uIGFzc2VydFZhbGlkTGFzdE1vZGlmaWVkKGxhc3RNb2RpZmllZDogbnVtYmVyKTogdm9pZCB7XG4gICAgbGV0IG1heCA9IERhdGUubm93KCkgKyBNQVhfTEFTVF9NT0RJRklFRF9GVVRVUkU7XG4gICAgaWYgKGxhc3RNb2RpZmllZCA+IG1heCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGxhc3RNb2RpZmllZCBpcyB0b28gZmFyIGluIHRoZSBmdXR1cmU6ICR7bGFzdE1vZGlmaWVkfSA+ICR7bWF4fSAobm93ICsgMTUgbWludXRlcylgKTtcbiAgICB9XG59XG5cblxuZXhwb3J0IHR5cGUgUmVtb3RlQ29uZmlnID0ge1xuICAgIC8vIE5PVEU6IFZlcnNpb24gaXMgdXNlZCB3aGVuIHVwZGF0aW5nIHRoZSBjb25maWd1cmF0aW9uLiBUaGUgbmV3ZXIgdmVyc2lvbiBpcyBhbHdheXMgdGFrZW4uIEEgbWlzc2luZyB2ZXJzaW9uIGNvdW50cyBhcyB2ZXJzaW9uIC0xLlxuICAgIHZlcnNpb24/OiBudW1iZXI7XG4gICAgc291cmNlczogUmVtb3RlQ29uZmlnQmFzZVtdO1xufTtcblxuLyoqXG4gICAgc3RyaW5nIGFyZ3VtZW50cyB3aWxsIGJlIGEgdXJsLCBsb29raW5nIGxpa2U6XG4gICAgICAgIGh0dHBzOi8vc3RvcmFnZTIudmlkZ3JpZHdlYi5jb206NDQ0NS9maWxlL2V4YW1wbGVhY2NvdW50L2V4YW1wbGVidWNrZXQvc3RvcmFnZS9zdG9yYWdlcm91dGluZy5qc29uXG4gICAgICAgIGh0dHBzOi8vZjAwMi5iYWNrYmxhemViMi5jb20vZmlsZS9xdWVyeXN1YnRlc3QtY29tLXB1YmxpYy1pbW11dGFibGUvc3RvcmFnZS9zdG9yYWdlcm91dGluZy5qc29uXG4gICAgICAgIC0gVGhlc2UgbWFwIHRvIHsgdXJsIH0sIHdpdGggdGhlIHR5cGUgaW5mZXJyZWQgZnJvbSB0aGUgdXJsXG4gICAgICAgIC0gSG9zdGVkIHVybHMgYXJlIC9maWxlLzxhY2NvdW50Pi88YnVja2V0TmFtZT4vLi4uLCBiYWNrYmxhemUgdXJscyBhcmUgL2ZpbGUvPGJ1Y2tldE5hbWU+Ly4uLlxuXG4gICAgTk9URTogSWYgd2UgZG8gbm90IGhhdmUgcmlnaHQgYWNjZXNzIHRvIHRoZXNlLCB0aGVuIGl0IGJlY29tZXMgYSByZWFkLW9ubHkgSUFyY2hpdmVzLCB3aGVyZSB3ZSBzb2xlbHkgcmVhZCB1c2luZyB0aGUgdXJsIGZvcm0gKHdoaWNoIG1pZ2h0IHRocm93IGR1ZSB0byBub3QgaGF2aW5nIGFjY2VzcyBhcyB3ZWxsKS4gVU5MRVNTIE91ciBjb25maWd1cmF0aW9uIGV4cGxpY2l0bHkgaGFzIHB1YmxpYzogZmFsc2UsIGluIHdoaWNoIGNhc2UsIHdlIGRvbid0IGV2ZW4gaGl0IHRoZSBVUkwgYW5kIHdlIHRocm93IG9uIGFjY2Vzcy5cblxuICAgIE5PVEU6IElmIHdlJ3JlIGluIHRoZSBicm93c2VyLCB3ZSBzaG91bGQgYWxsb3cgZG93bmxvYWRpbmcgdGhlIGZpbGVzIHZpYSB0aGUgVVJMIGZvcm0gKGlmIGl0J3MgYSBwdWJsaWMgYnVja2V0KSwgaG93ZXZlciwgd2Ugd29uJ3QgYWxsb3cgd3JpdGluZywgYmVjYXVzZSB0aGVpciBzZXJ2ZXJzIGRvIG5vdCBhbGxvdyBzZWN1cmUgYnJvd3NlciB3cml0ZXMuXG4qL1xuZXhwb3J0IHR5cGUgUmVtb3RlQ29uZmlnQmFzZSA9IHN0cmluZyB8IEhvc3RlZENvbmZpZyB8IEJhY2tibGF6ZUNvbmZpZztcblxuZXhwb3J0IHR5cGUgQ29tbW9uQ29uZmlnID0ge1xuICAgIC8qKiBCeSBkZWZhdWx0IGEgc2VydmVyIGhvc3RpbmcgdGhpcyBidWNrZXQgZWFnZXJseSBjb3BpZXMgdGhpcyBzb3VyY2UncyBmdWxsIGNvbnRlbnRzIG9udG8gaXRzIG93biBkaXNrIChvbiB0b3Agb2YgdGhlIGxhenkgcmVhZC10aHJvdWdoIGNhY2hpbmcpLiBTZXQgdGhpcyB0byBiZSBhIGZyb250IGVuZCBmb3IgYSB2ZXJ5IGxhcmdlIGRhdGFiYXNlIHdpdGhvdXQgY29weWluZyB0aGUgZnVsbCBkYXRhYmFzZSAtIHJlYWRzIHN0aWxsIGRvd24tY2FjaGUgaW5kaXZpZHVhbCBmaWxlcyBvbiBkZW1hbmQuICovXG4gICAgbm9GdWxsU3luYz86IGJvb2xlYW47XG4gICAgLyoqIEJ5dGVzIG9mIHJlYWQtY2FjaGUgdGhpcyBzZXJ2ZXIncyBkaXNrIG1heSBob2xkOyBsZWFzdC1yZWNlbnRseS11c2VkIGZpbGVzIGFyZSBkZWxldGVkIGZyb20gZGlzayB0byBzdGF5IHVuZGVyIGl0IChvbmx5IGV2ZXIgd2hlbiBhbm90aGVyIHNvdXJjZSB2ZXJpZmlhYmx5IGhvbGRzIHRoZSBmaWxlIC0gdGhlIG9ubHkgY29weSBpcyBuZXZlciBkZWxldGVkKS4gUmVxdWlyZXMgbm9GdWxsU3luYyAoYSBmdWxsIGNvcHkgY2FuJ3QgYmUgYm91bmRlZCkuICovXG4gICAgcmVhZGVyRGlza0xpbWl0PzogbnVtYmVyO1xuICAgIC8qKiBUaGUgd3JpdGUgdGltZXMgKFtzdGFydE1zLCBlbmRNc10pIHRoaXMgc291cmNlIGlzIHZhbGlkIGZvciAoc2VlIEFyY2hpdmVzU291cmNlLnZhbGlkV2luZG93IGZvciB0aGUgc3luY2hyb25pemF0aW9uIHNlbWFudGljcykuIFJlcXVpcmVkIG9uIG9iamVjdCBjb25maWdzOiBjb25maWd1cmF0aW9uIGNoYW5nZXMgbXVzdCBiZSBTQ0hFRFVMRUQgKGEgbmV3IHNvdXJjZSBiZWNvbWVzIHZhbGlkIGF0IGEgZnV0dXJlIHRpbWUgd2hpbGUgdGhlIG9sZCBvbmUncyB3aW5kb3cgZW5kcyksIG5vdCBmbGlwcGVkIGluc3RhbnRseS4gUGxhaW4gVVJMLXN0cmluZyBzb3VyY2VzIGRlZmF1bHQgdG8gRlVMTF9WQUxJRF9XSU5ET1cgLSBvbmNlIHlvdSdyZSB3cml0aW5nIG9iamVjdCBjb25maWdzLCB5b3UncmUgZG9pbmcgc29tZXRoaW5nIGNvbXBsaWNhdGVkIGVub3VnaCB0byB0aGluayBhYm91dCB3aGVuIHRoaW5ncyBjaGFuZ2UuICovXG4gICAgdmFsaWRXaW5kb3c6IFtudW1iZXIsIG51bWJlcl07XG4gICAgLyoqIFNoYXJkaW5nOiB0aGUgZnJhY3Rpb24gb2YgdGhlIGtleSBzcGFjZSB0aGlzIHNvdXJjZSBoYW5kbGVzLCBhcyBbc3RhcnQsIGVuZCkgb3ZlciBbMCwgMSkgKGtleXMgYXJlIHJvdXRlZCBieSBnZXRSb3V0ZSBpbiByZW1vdGVDb25maWcudHMpLiBEZWZhdWx0cyB0byBGVUxMX1JPVVRFICh1bnNoYXJkZWQpLiBBdCBldmVyeSBwb2ludCBpbiB0aW1lIHRoZSBzb3VyY2VzJyByb3V0ZXMgbXVzdCBmdWxseSBjb3ZlciBbMCwgMSksIG9yIHNvbWUga2V5cyBjb3VsZCBuZXZlciBiZSByZWFkLiAqL1xuICAgIHJvdXRlPzogW251bWJlciwgbnVtYmVyXTtcbiAgICAvKiogU2V0IG9uIGVudHJpZXMgaW5qZWN0ZWQgaW50byB0aGUgaW4tbWVtb3J5IGNvbmZpZyBieSBhbiBvdmVybGF5IChhIGRlcGxveSBzd2l0Y2hvdmVyJ3MgYWx0ZXJuYXRlLXBvcnQgd2luZG93KS4gTmV2ZXIgd3JpdHRlbiB0byBkaXNrOiByZXNvbHZlSW50ZXJtZWRpYXRlU291cmNlcyBzdHJpcHMgdGhlc2UgYW5kIHJlam9pbnMgdGhlIHdpbmRvd3MgYXJvdW5kIHRoZW0sIHdoaWNoIGlzIGFsc28gaG93IGEgY2xpZW50IHRlbGxzIHdoZXRoZXIgYW4gdXBkYXRlIGlzIGEgcmVhbCBjb25maWd1cmF0aW9uIGNoYW5nZSBvciBqdXN0IGFuIG92ZXJsYXkuICovXG4gICAgaW50ZXJtZWRpYXRlPzogYm9vbGVhbjtcbn07XG5cbmV4cG9ydCB0eXBlIEhvc3RlZENvbmZpZyA9IENvbW1vbkNvbmZpZyAmIHtcbiAgICB0eXBlOiBcInJlbW90ZVwiO1xuXG4gICAgLy8gRXg6IGh0dHBzOi8vOTktMjUwLTEyNC05MS5xdWVyeXN1YnRlc3QuY29tOjUyMzMvZmlsZS9yb290L3VuaXF1ZWJ1Y2tldG5hbWUvc3RvcmFnZS9zdG9yYWdlcm91dGluZy5qc29uXG4gICAgLy8gTk9URTogVGhlIGFjY291bnQgYW5kIGJ1Y2tldCBuYW1lIGFyZSBvYnRhaW5lZCBmcm9tIHRoZSBVUkwuXG4gICAgdXJsOiBzdHJpbmc7XG5cbiAgICAvLyBOT1RFOiBBdXRoZW50aWNhdGlvbiBpcyBoYW5kbGVkIGJ5IGNlcnQudHMsIHZpYSBoYXZpbmcgeW91ciBtYWNoaW5lIHRydXN0ZWQgdG8gYWNjZXNzIHRoaXMgYWNjb3VudC4gXG5cbiAgICBwdWJsaWM/OiBib29sZWFuO1xuICAgIC8vIEZhc3QgbW9kZTogdGhlIHNlcnZlciBhY2tub3dsZWRnZXMgd3JpdGVzIG9uY2UgdGhleSBhcmUgaW4gbWVtb3J5LCBmbHVzaGluZyB0byBkaXNrIGFmdGVyIHdyaXRlRGVsYXkgKGRlZmF1bHQgNSBtaW51dGVzKSBhbmQgY29hbGVzY2luZyB3cml0ZXMgdG8gdGhlIHNhbWUgZmlsZS4gQSBzZXJ2ZXIgY3Jhc2ggbG9zZXMgd3JpdGVzIHRoYXQgaGF2ZW4ndCBmbHVzaGVkIHlldC5cbiAgICBmYXN0PzogYm9vbGVhbjtcbiAgICB3cml0ZURlbGF5PzogbnVtYmVyO1xuICAgIC8vIFRoZSBidWNrZXQgaXMgc2VydmVkIHN0cmFpZ2h0IGZyb20gdGhlIHNlcnZlcidzIGRpc2ssIHdpdGggbm8gaW5kZXgg4oCUIHNvIG5vIGZhc3Qgd3JpdGVzLCBubyBnZXRTeW5jU3RhdHVzLCBhbmQgZ2V0Q2hhbmdlc0FmdGVyMiBmYWxscyBiYWNrIHRvIGEgZnVsbCBsaXN0aW5nLlxuICAgIHJhd0Rpc2s/OiBib29sZWFuO1xuICAgIC8vIFdyaXRlcyB0byBwYXRocyB0aGF0IGFscmVhZHkgZXhpc3QgYXJlIGRpc2FsbG93ZWQgKGRlbGV0ZXMgc3RpbGwgd29yaykuXG4gICAgaW1tdXRhYmxlPzogYm9vbGVhbjtcbn07XG5cbmV4cG9ydCB0eXBlIEJhY2tibGF6ZUNvbmZpZyA9IENvbW1vbkNvbmZpZyAmIHtcbiAgICB0eXBlOiBcImJhY2tibGF6ZVwiO1xuICAgIC8vIEV4OiBodHRwczovL2YwMDIuYmFja2JsYXplYjIuY29tL2ZpbGUvcXVlcnlzdWJ0ZXN0LWNvbS1wdWJsaWMtaW1tdXRhYmxlL3N0b3JhZ2Uvc3RvcmFnZXJvdXRpbmcuanNvblxuICAgIC8vIE5PVEU6IFRoZSBidWNrZXQgbmFtZSBpcyBvYnRhaW5lZCBmcm9tIHRoZSBVUkwuXG4gICAgdXJsOiBzdHJpbmc7XG4gICAgLy8gUHVibGljIGJ1Y2tldHMgYXJlIHNlcnZlZCBvdmVyIHBsYWluIEhUVFBTIEdFVHMgKGdldFVSTCkuIFByaXZhdGUgYnVja2V0cyBhcmUgQVBJLWFjY2VzcyBvbmx5LlxuICAgIHB1YmxpYz86IGJvb2xlYW47XG4gICAgLy8gTk9URTogVGhpcyBpc24ndCBlbmZvcmNlZCBvbiB0aGUgYmFja2JsYXplIGxldmVsLCBzbyB0aGlzIGlzIGp1c3QgYSBjbGllbnQtc2lkZSBndWFyYW50ZWUuIFRoaXMgY2FuIGNoYW5nZSBob3cgd2UgY2FjaGUgZmlsZXMuXG4gICAgLy8gIC0gQmFja2JsYXplIGRvZXMgc3VwcG9ydCBpbW11dGFiaWxpdHkuIEhvd2V2ZXIsIGFwcGFyZW50bHksIG9uY2Ugd2UgZW5hYmxlIGl0IG9uIGEgYnVja2V0LCB3ZSBjYW4ndCBkaXNhYmxlIGl0LCB3aGljaCBpcyByZWFsbHkgYmFkLCBhcyBpdCBtZWFucyBpZiBvdXIgY29kZSBjb3VsZCBldmVyIGVuYWJsZSBpdCBhbmQgd2UgYWNjaWRlbnRhbGx5IGVuYWJsZSBpdCBvbiBhbiBpbXBvcnRhbnQgYnVja2V0LCB3ZSBlc3NlbnRpYWxseSBqdXN0IGJyaWNrZWQgdGhhdCBidWNrZXQuIFNvIHdlIHNob3VsZCBuZXZlciB3cml0ZSBhbnkgY29kZSB0aGF0IGV2ZXIgdHJpZXMgdG8gdXNlIGJhY2tibGF6ZSB0byBtYWtlIHRoaW5ncyBpbW11dGFibGUuIFxuICAgIGltbXV0YWJsZT86IGJvb2xlYW47XG4gICAgLy8gQ09SUyBvcmlnaW5zIGFsbG93ZWQgdG8gY29uc3VtZSB0aGUgYnVja2V0J3MgZmlsZXMgaW4gYSBicm93c2VyLiBOb3QgYSBzZWN1cml0eSBib3VuZGFyeSAoYWNjZXNzIGlzIGdhdGVkIGJ5IHRoZSBBUEkga2V5IC8gc2lnbmVkIFVSTHMsIG5laXRoZXIgb2Ygd2hpY2ggcmlkZXMgaW4gY29va2llcykgLSBpdCBvbmx5IGNvbnRyb2xzIHdoaWNoIHNpdGVzJyBpbi1wYWdlIEphdmFTY3JpcHQgY2FuIHJlYWQgcmVzcG9uc2VzLiBEZWZhdWx0cyB0byBhbnkgSFRUUFMgb3JpZ2luLlxuICAgIGFsbG93ZWRPcmlnaW5zPzogc3RyaW5nW107XG5cbiAgICAvLyBOT1RFOiBXZSB3aWxsIGFjY2VzcyB0aGUgYXBpIGtleSBmcm9tIGdldFNlY3JldCwgc2VlIGJhY2tibGF6ZS50cyBmb3IgdGhlIHNwZWNpZmljIGtleXMuXG59O1xuXG5cbmV4cG9ydCBjb25zdCBGVUxMX1ZBTElEX1dJTkRPVzogW251bWJlciwgbnVtYmVyXSA9IFswLCBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUl07XG5cblxuXG5cbmV4cG9ydCB0eXBlIEdldENvbmZpZyA9IHtcbiAgICByYW5nZT86IHsgc3RhcnQ6IG51bWJlcjsgZW5kOiBudW1iZXIgfTtcbiAgICAvKiogUmVhZCBPTkxZIGZyb20gdGhlIHByaW1hcnkgc291cmNlIC0gdGhlIG9uZSB3cml0ZXMgd291bGQgdGFyZ2V0IC0gaW5zdGVhZCBvZiBmYWxsaW5nIGJhY2sgYWNyb3NzIHRoZSByZWR1bmRhbnQgc291cmNlcy4gVXNlIHRoaXMgd2hlbiB5b3Ugd2FudCB5b3VyIHJlYWRzIGFuZCB3cml0ZXMgdG8gYmUgc29tZXdoYXQgYXRvbWljOiB0aGVyZSB3aWxsIHN0aWxsIGJlIGlzc3VlcyB3aXRoIHRoZSByb3VuZCB0cmlwLCBidXQgd2l0aG91dCBpdCB5b3UgY291bGQgdGFsayB0byBhIGNvbXBsZXRlbHkgZGlmZmVyZW50IG5vZGUgYW5kIGdldCBhIG11Y2ggb2xkZXIgdmFsdWUuIE1vc3QgcmVhZHMgYXJlbid0IGZvbGxvd2VkIGJ5IGEgd3JpdGUgdGhvdWdoLCBzbyBmb3IgbW9zdCBjYXNlcyBpdCdzIGJldHRlciB0byBnZXQgYSB2YWx1ZSB0aGFuIHRvIGhhdmUgdG8gd2FpdCAob3IgZXZlbiB0aHJvdykgd2hlbiB0aGUgcHJpbWFyeSBub2RlIGlzIG5vdCBhdmFpbGFibGUuICovXG4gICAgbm9GYWxsYmFja3M/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IHR5cGUgQ2hhbmdlc0FmdGVyQ29uZmlnID0ge1xuICAgIHRpbWU6IG51bWJlcjtcbiAgICAvKiogT25seSBrZXlzIHJvdXRpbmcgaW50byBvbmUgb2YgdGhlc2UgW3N0YXJ0LCBlbmQpIHJhbmdlcy4gT25seSBzY2FubmluZyBwYXNzZXMgdGhpcyAtIGl0IGxldHMgYSBzdG9yZSBzeW5jaW5nIGEgcGFydGlhbCBzaGFyZCBhc2sgZm9yIGp1c3QgaXRzIHNsaWNlLiAqL1xuICAgIHJvdXRlcz86IFtudW1iZXIsIG51bWJlcl1bXTtcbn07XG5cbmV4cG9ydCB0eXBlIFNldENvbmZpZyA9IHtcbiAgICBsYXN0TW9kaWZpZWQ/OiBudW1iZXI7XG4gICAgLyoqIE1ha2VzIHRoZSB3cml0ZSBhY2NlcHRhYmxlIG9uIGltbXV0YWJsZSB0YXJnZXRzOiBhbiBleGlzdGluZyBwYXRoIGlzIHNpbXBseSBrZXB0IChpbW11dGFiaWxpdHkgd2lucyAtIG5vdGhpbmcgaXMgb3ZlcndyaXR0ZW4pIGluc3RlYWQgb2YgdGhlIHdyaXRlIHRocm93aW5nLiBSZXF1aXJlcyBsYXN0TW9kaWZpZWQuIFN5bmNocm9uaXphdGlvbiBNVVNUIHBhc3MgdGhpcyBvbiBldmVyeSBwdXNoIC0gYSBwbGFpbiBzZXQgdGhyb3dzIG9uIGltbXV0YWJsZSB0YXJnZXRzLCB3aGljaCB3b3VsZCBhYm9ydCByZWNvbmNpbGlhdGlvbiB3aGVuZXZlciBvbmUgc291cmNlIGluIGEgY2hhaW4gaXMgaW1tdXRhYmxlLiAqL1xuICAgIGZvcmNlU2V0SW1tdXRhYmxlPzogYm9vbGVhbjtcbiAgICAvKiogU2tpcHMgdGhlIHRhcmdldC1zaWRlIHNhZmV0eSByZWFkcyBhcm91bmQgdGhlIHdyaXRlIChiYWNrYmxhemU6IHRoZSBwcmUtd3JpdGUgZ2V0SW5mbyBjb21wYXJpc29uIGFuZCB0aGUgcG9zdC11cGxvYWQgZXhpc3RlbmNlIHBvbGwpLiBGb3Igd3JpdGVycyB3aG9zZSBvd24gYm9va2tlZXBpbmcgYWxyZWFkeSBkZWNpZGVzIHdoYXQgdG8gd3JpdGUgYW5kIG9yZGVycyBpdCBieSB3cml0ZSB0aW1lIChCbG9iU3RvcmUncyBpbmRleC1kcml2ZW4gd3JpdGVzIGFuZCBzeW5jaHJvbml6YXRpb24pLCB0aG9zZSByZWFkcyBhcmUgcHVyZSBleHRyYSBBUEkgY2FsbHMgLSBidXQgdGhlIGRlZmF1bHQgc3RheXMgY2hlY2tlZCwgYmVjYXVzZSBvdGhlciB1c2VycyBvZiB0aGUgcmF3IGJhY2tlbmRzIHJlbHkgb24gdGhlIGNoZWNrcy4gKi9cbiAgICBub0NoZWNrcz86IGJvb2xlYW47XG59O1xuXG4vLyBjcmVhdGVUaW1lIGlzIGEgbWlzbm9tZXIga2VwdCBmb3IgY29tcGF0aWJpbGl0eSDigJQgaXQgaXMgcmVhbGx5IHRoZSBMQVNULVdSSVRFIHRpbWUsIHNhbWUgYXMgZ2V0SW5mbydzIHdyaXRlVGltZS4gTmVpdGhlciBCYWNrYmxhemUgbm9yIG91ciByZW1vdGUgc3RvcmFnZSB0cmFja3MgYSBkaXN0aW5jdCBjcmVhdGlvbiBkYXRlOiBlYWNoIHdyaXRlIHN0YW1wcyBhIGZyZXNoIHRpbWVzdGFtcCBvbiB0aGUgY3VycmVudCB2ZXJzaW9uLCBzbyBib3RoIGZpZWxkcyBhcmUganVzdCBcIndoZW4gdGhlIGJ5dGVzIHNlcnZlZCBieSBnZXQoKSB3ZXJlIG1vc3QgcmVjZW50bHkgd3JpdHRlblwiLlxuZXhwb3J0IHR5cGUgQXJjaGl2ZUZpbGVJbmZvID0geyBwYXRoOiBzdHJpbmc7IGNyZWF0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH07XG5cbi8vIEFuIGluLXByb2dyZXNzIGJhY2tncm91bmQgc3luY2hyb25pemF0aW9uIHRhc2sgKHNlZSBBcmNoaXZlc0NvbmZpZy5zeW5jaW5nKVxuZXhwb3J0IHR5cGUgU3luY0FjdGl2aXR5ID0ge1xuICAgIC8vIEEgbWV0YWRhdGEgc2NhbiBpcyBhIHNpbmdsZSBsaXN0aW5nIGNhbGwsIHNvIGl0IGhhcyBubyBpbmNyZW1lbnRhbCBwcm9ncmVzcyAtIGp1c3QgdGhhdCBpdCdzIHJ1bm5pbmcgYW5kIHNpbmNlIHdoZW4uIEEgZnVsbCBzeW5jIGtub3dzIGl0cyBleGFjdCBmaWxlL2J5dGUgcHJvZ3Jlc3MuXG4gICAgdHlwZTogXCJtZXRhZGF0YVNjYW5cIiB8IFwiZnVsbFN5bmNcIjtcbiAgICBzb3VyY2VEZWJ1Z05hbWU6IHN0cmluZztcbiAgICBzdGFydFRpbWU6IG51bWJlcjtcbiAgICBkb25lRmlsZXM/OiBudW1iZXI7XG4gICAgdG90YWxGaWxlcz86IG51bWJlcjtcbiAgICBkb25lQnl0ZXM/OiBudW1iZXI7XG4gICAgdG90YWxCeXRlcz86IG51bWJlcjtcbn07XG5cbmV4cG9ydCB0eXBlIEFyY2hpdmVzQ29uZmlnID0ge1xuICAgIC8vIFdoZXRoZXIgZ2V0Q2hhbmdlc0FmdGVyMiBpcyBuYXRpdmVseSBpbmRleC1iYWNrZWQgKGZhc3QgY2hhbmdlIHBvbGxpbmc7IGV2ZXJ5IGJhY2tlbmQgc3RpbGwgc2VydmVzIGl0LCBidXQgdGhlIG90aGVycyBlbXVsYXRlIGl0IHdpdGggYSBmdWxsIGxpc3RpbmcpXG4gICAgc3VwcG9ydHNDaGFuZ2VzQWZ0ZXI/OiBib29sZWFuO1xuICAgIC8vIFRoZSBidWNrZXQncyBmdWxsIHJvdXRpbmcgY29uZmlnIChST1VUSU5HX0ZJTEUpLiBBYnNlbnQgZm9yIHNvdXJjZXMgdGhhdCBkb24ndCBoYXZlIG9uZSAoYSBiYXJlIGRpc2sgc291cmNlLCBvciBhIGJ1Y2tldCB0aGF0IGRvZXNuJ3QgZXhpc3QgeWV0KS5cbiAgICByZW1vdGVDb25maWc/OiBSZW1vdGVDb25maWc7XG4gICAgLy8gTGl2ZSBpbmRleCB0b3RhbHMgKHRvbWJzdG9uZXMgZXhjbHVkZWQpLCBrZXB0IHVwIHRvIGRhdGUgaW4gbWVtb3J5IG9uIGV2ZXJ5IG11dGF0aW9uIGFuZCByZWNvbXB1dGVkIG9uIGxvYWQgLSBzbyBhbnkgZHJpZnQgaGVhbHMgb24gcmVzdGFydFxuICAgIGluZGV4PzogeyBmaWxlQ291bnQ6IG51bWJlcjsgYnl0ZUNvdW50OiBudW1iZXIgfTtcbiAgICAvLyBUaGUgc2FtZSB0b3RhbHMgYnJva2VuIGRvd24gYnkgd2hpY2ggc291cmNlIGN1cnJlbnRseSBob2xkcyBlYWNoIGZpbGUncyBieXRlcyAodGhlIGZpcnN0IGVudHJ5IGlzIHRoZSBzZXJ2ZXIncyBvd24gZGlzaylcbiAgICBpbmRleFNvdXJjZXM/OiB7IGRlYnVnTmFtZTogc3RyaW5nOyBmaWxlQ291bnQ6IG51bWJlcjsgYnl0ZUNvdW50OiBudW1iZXIgfVtdO1xuICAgIC8vIFRoZSBzZXJ2ZXIncyBjb25maWd1cmVkIHJlYWRlckRpc2tMaW1pdCwgd2hlbiBpdCBydW5zIGFzIGEgYm91bmRlZCByZWFkIGNhY2hlXG4gICAgcmVhZGVyRGlza0xpbWl0PzogbnVtYmVyO1xuICAgIC8vIEJhY2tncm91bmQgc3luY2hyb25pemF0aW9uIGN1cnJlbnRseSBpbiBwcm9ncmVzcyAoZW1wdHkgd2hlbiBpZGxlKVxuICAgIHN5bmNpbmc/OiBTeW5jQWN0aXZpdHlbXTtcbn07XG5cbi8vIEEgc3luY2hyb25pemF0aW9uIHNvdXJjZSBvZiBhIEJsb2JTdG9yZSAod2hpY2ggc3luY2hyb25pemVzIGFuIGluZGV4ICsgbG9jYWwgY2FjaGUgZnJvbSB0aGVtKVxuZXhwb3J0IHR5cGUgQXJjaGl2ZXNTb3VyY2UgPSB7XG4gICAgc291cmNlOiBJQXJjaGl2ZXM7XG4gICAgLyoqIFRoZSBwZXJzaXN0ZW50IGlkZW50aXR5IG9mIHRoZSBlbmRwb2ludDogaXRzIHJvdXRpbmcgVVJMIChob3N0ZWQvYmFja2JsYXplKSwgb3IgdGhlIGRpc2sgZm9sZGVyIHBhdGggZm9yIHRoZSBiYXNlIGRpc2sgc291cmNlLiBUaGUgc3RvcmUgcGVyc2lzdHMgdGhpcyAodmlhIGl0cyBhcHBlbmQtb25seSBzb3VyY2VzIGxpc3QpIGFzIEluZGV4RW50cnkuc291cmNlc0xpc3RJbmRleCwgc28gaXQgbXVzdCBtZWFuIHRoZSBzYW1lIGVuZHBvaW50IGZvcmV2ZXIuICovXG4gICAgdXJsOiBzdHJpbmc7XG4gICAgLy8gRnJvbSB0aGUgc291cmNlJ3MgQ29tbW9uQ29uZmlnLiBUaGUgd2luZG93IHJvdXRlcyBXUklURVM6IG9uY2UgaXRzIGVuZCBpcyBwYXN0IChzZWUgd2luZG93QWNjZXB0c1dyaXRlcykgdGhlIHNvdXJjZSBzdG9wcyByZWNlaXZpbmcgd3JpdGVzIGVudGlyZWx5IC0gaXQganVzdCBzdG9wcyBncm93aW5nLiBJdCBkb2VzIE5PVCBmaWx0ZXIgc2Nhbm5pbmc6IGEgc2NhbiBpcyB1cyBhc2tpbmcgdGhlIHNvdXJjZSB3aGF0IGl0IGFscmVhZHkgaG9sZHMsIGFuZCBleGlzdGluZyB2YWx1ZXMgc3luY2hyb25pemUgcmVnYXJkbGVzcyBvZiB0aGVpciB3cml0ZSB0aW1lcyAodGhlIHNhbWUgcmVhc29uaW5nIHRoYXQgbGV0cyBzeW5jaHJvbml6YXRpb24gaWdub3JlIHRoZSBpbW11dGFibGUgZmxhZykuXG4gICAgdmFsaWRXaW5kb3c6IFtudW1iZXIsIG51bWJlcl07XG4gICAgLy8gRnJvbSB0aGUgc291cmNlJ3MgQ29tbW9uQ29uZmlnIChpbnRlcnNlY3RlZCB3aXRoIHRoZSBvd25pbmcgc3RvcmUncyBvd24gcm91dGUpOiBvbmx5IGtleXMgcm91dGluZyBpbnRvIFtzdGFydCwgZW5kKSBhcmUgYWNjZXB0ZWQgZnJvbSB0aGlzIHNvdXJjZSdzIHNjYW5zIGFuZCBzZW50IHRvIGl0IGluIHdyaXRlcy9yZWNvbmNpbGlhdGlvbi4gVGhlIHJvdXRpbmcgZmlsZSBpcyBleGVtcHQgLSBjb25maWcgZmxvd3MgZXZlcnl3aGVyZS4gQWJzZW50ID0gYWxsIGtleXMuXG4gICAgcm91dGU/OiBbbnVtYmVyLCBudW1iZXJdO1xuICAgIC8vIEZyb20gdGhlIHNvdXJjZSdzIENvbW1vbkNvbmZpZzsgc2VlIHRoZXJlLlxuICAgIG5vRnVsbFN5bmM/OiBib29sZWFuO1xuICAgIC8vIEZyb20gdGhlIHNvdXJjZSdzIENvbW1vbkNvbmZpZzogYSBkZXBsb3kgc3dpdGNob3ZlcidzIHRlbXBvcmFyeSBhbHRlcm5hdGUtcG9ydCBlbnRyeS4gT25jZSBpdHMgd2luZG93IGlzIHBhc3QsIHRoZSBwb3J0IGl0IHBvaW50cyBhdCBpcyBnb25lIGZvciBnb29kIC0gc28gaXQgaXMgbmV2ZXIgc2Nhbm5lZCB0aGVuLCBhbmQgc2NhbiBmYWlsdXJlcyBhcmUgbmV2ZXIgcmV0cmllZC5cbiAgICBpbnRlcm1lZGlhdGU/OiBib29sZWFuO1xuICAgIC8vIFN0YWJsZSBpZGVudGl0eSBvZiB0aGUgdW5kZXJseWluZyBlbmRwb2ludCAoaXRzIGNvbmZpZyB3aXRoIHdpbmRvd3Mvcm91dGVzIHN0cmlwcGVkKSAtIGhvdyBCbG9iU3RvcmUudXBkYXRlU291cmNlcyByZWNvZ25pemVzIGEgc291cmNlIGFjcm9zcyBjb25maWcgY2hhbmdlcyBzbyBpdCBjYW4gdXBkYXRlIGl0IGluIHBsYWNlIGluc3RlYWQgb2YgcmVtb3ZpbmcgYW5kIHJlLWFkZGluZyBpdFxuICAgIGlkZW50aXR5Pzogc3RyaW5nO1xufTtcblxuLy8gRXJyb3IgbWFya2VyIGEgc2VydmVyIGluY2x1ZGVzIHdoZW4gYSBmcmVzaGx5LXN0YW1wZWQgd3JpdGUgcmVhY2hlcyBpdCBvdXRzaWRlIGl0cyB2YWxpZCB3aW5kb3dzICh0aGUgY2xpZW50IHJlc29sdmVkIGl0cyB0YXJnZXQsIHRoZW4gdGltZSBjcm9zc2VkIGEgd2luZG93IGJvdW5kYXJ5IGJlZm9yZSB0aGUgd3JpdGUgbGFuZGVkKS4gQ2xpZW50cyBkZXRlY3QgdGhpcyBtYXJrZXIgYW5kIHJlLXJlc29sdmUgdGhlIGN1cnJlbnRseS12YWxpZCBzb3VyY2UsIHJldHJ5aW5nIE9OQ0UgLSBib3VuZGFyaWVzIGFyZSBmYXIgYXBhcnQsIHNvIGhpdHRpbmcgaXQgdHdpY2UgaW4gb25lIGF0dGVtcHQgbWVhbnMgc29tZXRoaW5nIGlzIGFjdHVhbGx5IHdyb25nLlxuZXhwb3J0IGNvbnN0IFNUT1JBR0VfV1JPTkdfVkFMSURfV0lORE9XID0gXCJSRU1PVEVfU1RPUkFHRV9XUk9OR19WQUxJRF9XSU5ET1dfYTdjMWYwNGVcIjtcblxuLy8gRXJyb3IgbWFya2VyIGEgc2VydmVyIGluY2x1ZGVzIHdoZW4gYSBmcmVzaGx5LXN0YW1wZWQgd3JpdGUncyBrZXkgcm91dGVzIG91dHNpZGUgdGhlIHNoYXJkcyB0aGlzIHNlcnZlciBoYW5kbGVzICh0aGUgY2xpZW50J3MgY29uZmlnIGRpc2FncmVlcyB3aXRoIHRoZSBzZXJ2ZXIncyAtIGNsaWVudHMgcmUtcmVzb2x2ZSBvbmNlKVxuZXhwb3J0IGNvbnN0IFNUT1JBR0VfV1JPTkdfUk9VVEUgPSBcIlJFTU9URV9TVE9SQUdFX1dST05HX1JPVVRFX2M5NGQyZTE3XCI7XG5cbmV4cG9ydCBjb25zdCBGVUxMX1JPVVRFOiBbbnVtYmVyLCBudW1iZXJdID0gWzAsIDFdO1xuXG4vLyBBIGtleSBjb250YWluaW5nIHRoaXMgc2VudGluZWwgZG9lc24ndCBoYXZlIGEgZml4ZWQgc2hhcmQ6IHNldFZhcmlhYmxlU2hhcmQgcGlja3MgdGhlIChsb3dlc3QgbGF0ZW5jeSwgdXApIHdyaXRlIHNoYXJkLCBhcHBlbmRzIFwiXzx2YWx1ZSBpbiB0aGUgc2hhcmQncyByb3V0ZT5cIiBkaXJlY3RseSBhZnRlciB0aGUgc2VudGluZWwsIGFuZCByZXR1cm5zIHRoZSBtYXRlcmlhbGl6ZWQga2V5LiBnZXRSb3V0ZSB0cmVhdHMgdGhhdCBzdWZmaXggYXMgYSBjb21wbGV0ZSByb3V0ZSBvdmVycmlkZS5cbmV4cG9ydCBjb25zdCBWQVJJQUJMRV9TSEFSRCA9IFwiVkFSSUFCTEVfU0hBUkRfZjAyMzRqZmFoMDhmZ3loZmd5c3NkZHM4M25tcFwiO1xuLy8gTm8gZ3JhY2UgcGFzdCB0aGUgZW5kOiBhIHdpbmRvdyBib3VuZGFyeSBpcyBhIGhhcmQgaGFuZG9mZiAoY2xpZW50cyByZXRyeSBhIHJlamVjdGVkIHdyaXRlIGFnYWluc3QgdGhlIG5ld2x5LXZhbGlkIHNvdXJjZSwgc28gbGVuaWVuY3kgaGVyZSB3b3VsZCBvbmx5IGRlc3luY2hyb25pemUgdGhlIGhhbmRvZmYpXG4vLyAgLSBXcml0aW5nIHRvIG9sZGVyIHZhbGlkIHN0YXRlIHdpbmRvd3MgaXMgZmluZSwgdGhvdWdoLiBXZSBuZWVkIHRoaXMgdG8gaW5nZXN0IHRoZSBvbGQgZGF0YSB3aGVuIHdlJ3JlIHN5bmNocm9uaXppbmcgbm9kZXMgdG8gZ2V0IHRoZW0gdXAgdG8gZGF0ZSBhbnl3YXkuIFxuZXhwb3J0IGZ1bmN0aW9uIHdpbmRvd0FjY2VwdHNXcml0ZXModmFsaWRXaW5kb3c6IFtudW1iZXIsIG51bWJlcl0gfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgICBpZiAoIXZhbGlkV2luZG93KSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gdmFsaWRXaW5kb3dbMV0gPiBEYXRlLm5vdygpO1xufVxuXG5jb25zdCBMQVJHRV9DT1BZX1RIUkVTSE9MRCA9IDY0ICogMTAyNCAqIDEwMjQ7XG5jb25zdCBMQVJHRV9DT1BZX0NIVU5LID0gMzIgKiAxMDI0ICogMTAyNDtcblxuLyoqIENvcGllcyBvbmUgZmlsZSBiZXR3ZWVuIHR3byBhcmNoaXZlcy4gU21hbGwgZmlsZXMgZ28gYXMgYSBzaW5nbGUgZ2V0MitzZXQ7IHBhc3QgTEFSR0VfQ09QWV9USFJFU0hPTEQgdGhlIGNvcHkgc3RyZWFtcyB0aHJvdWdoIHNldExhcmdlRmlsZSBpbiBMQVJHRV9DT1BZX0NIVU5LIHJhbmdlZCByZWFkcywgc28gdGhlIHdob2xlIGZpbGUgaXMgbmV2ZXIgaW4gbWVtb3J5LiBzaXplL3dyaXRlVGltZSB1c3VhbGx5IGNvbWUgZnJvbSB0aGUgY2FsbGVyJ3MgbWV0YWRhdGEgc2Nhbjsgd2hlbiBlaXRoZXIgaXMgb21pdHRlZCwgZ2V0SW5mbyBmaWxscyB0aGVtIGluLiBSZXR1cm5zIHRoZSBjb3BpZWQgZmlsZSdzIGluZm8sIG9yIHVuZGVmaW5lZCB3aGVuIHRoZSBzb3VyY2UgZG9lc24ndCBoYXZlIHRoZSBmaWxlLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvcHlBcmNoaXZlRmlsZShjb25maWc6IHtcbiAgICBmcm9tOiBJQXJjaGl2ZXM7XG4gICAgdG86IElBcmNoaXZlcztcbiAgICBwYXRoOiBzdHJpbmc7XG4gICAgc2l6ZT86IG51bWJlcjtcbiAgICB3cml0ZVRpbWU/OiBudW1iZXI7XG4gICAgZm9yY2VTZXRJbW11dGFibGU/OiBib29sZWFuO1xuICAgIG5vQ2hlY2tzPzogYm9vbGVhbjtcbn0pOiBQcm9taXNlPHsgd3JpdGVUaW1lOiBudW1iZXI7IHNpemU6IG51bWJlciB9IHwgdW5kZWZpbmVkPiB7XG4gICAgbGV0IHsgZnJvbSwgdG8sIHBhdGggfSA9IGNvbmZpZztcbiAgICBsZXQgc2l6ZSA9IGNvbmZpZy5zaXplO1xuICAgIGxldCB3cml0ZVRpbWUgPSBjb25maWcud3JpdGVUaW1lO1xuICAgIGlmIChzaXplID09PSB1bmRlZmluZWQgfHwgd3JpdGVUaW1lID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbGV0IGluZm8gPSBhd2FpdCBmcm9tLmdldEluZm8ocGF0aCk7XG4gICAgICAgIGlmICghaW5mbykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgc2l6ZSA9IGluZm8uc2l6ZTtcbiAgICAgICAgd3JpdGVUaW1lID0gaW5mby53cml0ZVRpbWU7XG4gICAgfVxuICAgIGlmIChzaXplIDw9IExBUkdFX0NPUFlfVEhSRVNIT0xEKSB7XG4gICAgICAgIGxldCByZXN1bHQgPSBhd2FpdCBmcm9tLmdldDIocGF0aCk7XG4gICAgICAgIGlmICghcmVzdWx0KSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICBhd2FpdCB0by5zZXQocGF0aCwgcmVzdWx0LmRhdGEsIHsgbGFzdE1vZGlmaWVkOiByZXN1bHQud3JpdGVUaW1lLCBmb3JjZVNldEltbXV0YWJsZTogY29uZmlnLmZvcmNlU2V0SW1tdXRhYmxlLCBub0NoZWNrczogY29uZmlnLm5vQ2hlY2tzIH0pO1xuICAgICAgICByZXR1cm4geyB3cml0ZVRpbWU6IHJlc3VsdC53cml0ZVRpbWUsIHNpemU6IHJlc3VsdC5kYXRhLmxlbmd0aCB9O1xuICAgIH1cbiAgICAvLyBDb25zdHMgc28gdGhlIGNsb3N1cmUga2VlcHMgdGhlIG5hcnJvd2VkIHR5cGVzXG4gICAgY29uc3QgdG90YWxTaXplID0gc2l6ZTtcbiAgICBjb25zdCBmaW5hbFdyaXRlVGltZSA9IHdyaXRlVGltZTtcbiAgICBsZXQgb2Zmc2V0ID0gMDtcbiAgICBhd2FpdCB0by5zZXRMYXJnZUZpbGUoe1xuICAgICAgICBwYXRoLFxuICAgICAgICBsYXN0TW9kaWZpZWQ6IGZpbmFsV3JpdGVUaW1lLFxuICAgICAgICBnZXROZXh0RGF0YTogYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKG9mZnNldCA+PSB0b3RhbFNpemUpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICBsZXQgZW5kID0gTWF0aC5taW4ob2Zmc2V0ICsgTEFSR0VfQ09QWV9DSFVOSywgdG90YWxTaXplKTtcbiAgICAgICAgICAgIGxldCBkYXRhID0gYXdhaXQgZnJvbS5nZXQocGF0aCwgeyByYW5nZTogeyBzdGFydDogb2Zmc2V0LCBlbmQgfSB9KTtcbiAgICAgICAgICAgIGlmICghZGF0YSB8fCAhZGF0YS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFJhbmdlZCByZWFkIG9mICR7SlNPTi5zdHJpbmdpZnkocGF0aCl9IGZyb20gJHtmcm9tLmdldERlYnVnTmFtZSgpfSByZXR1cm5lZCAke2RhdGEgJiYgZGF0YS5sZW5ndGggfHwgXCJub3RoaW5nXCJ9IGF0ICR7b2Zmc2V0fS0ke2VuZH0gKGV4cGVjdGVkICR7ZW5kIC0gb2Zmc2V0fSBieXRlcyBvZiBhICR7dG90YWxTaXplfSBieXRlIGZpbGUgLSBpdCBjaGFuZ2VkIG9yIHZhbmlzaGVkIG1pZC1jb3B5KWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgb2Zmc2V0ICs9IGRhdGEubGVuZ3RoO1xuICAgICAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgICAgIH0sXG4gICAgfSk7XG4gICAgcmV0dXJuIHsgd3JpdGVUaW1lOiBmaW5hbFdyaXRlVGltZSwgc2l6ZTogdG90YWxTaXplIH07XG59XG5cbmV4cG9ydCB0eXBlIEFyY2hpdmVzU3luY1NvdXJjZVN0YXR1cyA9IHtcbiAgICBkZWJ1Z05hbWU6IHN0cmluZztcbiAgICB2YWxpZFdpbmRvdzogW251bWJlciwgbnVtYmVyXTtcbiAgICByb3V0ZT86IFtudW1iZXIsIG51bWJlcl07XG4gICAgbm9GdWxsU3luYz86IGJvb2xlYW47XG4gICAgc3VwcG9ydHNDaGFuZ2VzQWZ0ZXI6IGJvb2xlYW47XG4gICAgaW5pdGlhbFNjYW5Db21wbGV0ZTogYm9vbGVhbjtcbiAgICAvLyBGaWxlcyBzZWVuIGluIHRoaXMgc291cmNlJ3Mgc2NhbnMgLyBjaGFuZ2UgcG9sbHMgc28gZmFyXG4gICAgc2Nhbm5lZENvdW50OiBudW1iZXI7XG59O1xuZXhwb3J0IHR5cGUgQXJjaGl2ZXNTeW5jU3RhdHVzID0ge1xuICAgIGFsbFNjYW5zQ29tcGxldGU6IGJvb2xlYW47XG4gICAgLy8gTnVtYmVyIG9mIGZpbGVzIGluIHRoZSBpbmRleFxuICAgIGluZGV4U2l6ZTogbnVtYmVyO1xuICAgIHNvdXJjZXM6IEFyY2hpdmVzU3luY1NvdXJjZVN0YXR1c1tdO1xufTtcblxuZXhwb3J0IGludGVyZmFjZSBJQXJjaGl2ZXMge1xuICAgIGdldERlYnVnTmFtZSgpOiBzdHJpbmc7XG4gICAgLyoqIFdoZXRoZXIgd3JpdGVzIHdvdWxkIGJlIGFjY2VwdGVkIChjcmVkZW50aWFscyBleGlzdCwgdGhlIGFjY291bnQgdHJ1c3RzIHRoaXMgbWFjaGluZSwgZXRjKS4gQ2hlY2tlZCB3aXRob3V0IHdyaXRpbmcgYW55dGhpbmcuICovXG4gICAgaGFzV3JpdGVBY2Nlc3MoKTogUHJvbWlzZTxib29sZWFuPjtcbiAgICAvKipcbiAgICAgKiBSZWFkcyBhdXRvbWF0aWNhbGx5IGZhbGwgYmFjayBhY3Jvc3MgdGhlIHJlZHVuZGFudCBzb3VyY2VzIHVubGVzcyBjb25maWcubm9GYWxsYmFja3MgaXMgc2V0LlxuICAgICAqIEEgZmFsbGJhY2sgY29weSBjYW4gbGFnIHRoZSB3cml0ZSB0YXJnZXQsIHNvIGEgY2FsbGVyIHJlYWRpbmcgc3RhdGUgaW4gb3JkZXIgdG8gbXV0YXRlIGl0XG4gICAgICogKGUuZy4geCsrKSwgd2hlcmUgYWN0aW5nIG9uIHByZXZpb3VzIHN0YXRlIHdvdWxkIGNhdXNlIGJpZyBpc3N1ZXMsIHNob3VsZCBwYXNzIG5vRmFsbGJhY2tzIC1cbiAgICAgKiBhbmQgdHJ5L2NhdGNoIHRoZSByZWFkLCBoYW5kbGluZyB0aGUgY2F0Y2ggY2FzZSAoYSBkb3duIHByaW1hcnkgaXMgcmV0cmllZCBmb3IgYSB3aGlsZSwgdGhlblxuICAgICAqIHRocm93cyBpbnN0ZWFkIG9mIGRlZ3JhZGluZyB0byBhIHN0YWxlIGNvcHkpLlxuICAgICAqL1xuICAgIGdldChmaWxlTmFtZTogc3RyaW5nLCBjb25maWc/OiBHZXRDb25maWcpOiBQcm9taXNlPEJ1ZmZlciB8IHVuZGVmaW5lZD47XG4gICAgLyoqIFNlZSBnZXQgZm9yIHRoZSBmYWxsYmFjayBzZW1hbnRpY3MgKGFuZCB3aGVuIHRvIHBhc3Mgbm9GYWxsYmFja3MpLiB1cmwgaXMgdGhlIGNvbmZpZyBVUkwgb2YgdGhlIHNvdXJjZSB0aGF0IHNlcnZlZCB0aGUgdmFsdWUgLSBzZXQgYnkgbXVsdGktc291cmNlIGltcGxlbWVudGF0aW9ucyAoQXJjaGl2ZXNDaGFpbiksIGFic2VudCBmcm9tIHNpbmdsZS1zb3VyY2UgYmFja2VuZHMuICovXG4gICAgZ2V0MihmaWxlTmFtZTogc3RyaW5nLCBjb25maWc/OiBHZXRDb25maWcpOiBQcm9taXNlPHsgZGF0YTogQnVmZmVyOyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyOyB1cmw/OiBzdHJpbmcgfSB8IHVuZGVmaW5lZD47XG4gICAgLyoqXG4gICAgICogbGFzdE1vZGlmaWVkIHN0YW1wcyB0aGUgd3JpdGUgd2l0aCB0aGF0IGxhc3Qtd3JpdGUgdGltZSBpbnN0ZWFkIG9mIG5vdy4gSWYgaXQgaXMgT0xERVIgdGhhblxuICAgICAqIHRoZSBmaWxlJ3MgY3VycmVudCBsYXN0LXdyaXRlIHRpbWUgdGhlIHdyaXRlIG5vLW9wcyAoc28gZGVsYXllZCAvIHN5bmNocm9uaXplZCB3cml0ZXMgY2FuXG4gICAgICogbmV2ZXIgY2xvYmJlciBuZXdlciBkYXRhKS4gVGltZXMgbW9yZSB0aGFuIDE1IG1pbnV0ZXMgaW4gdGhlIGZ1dHVyZSBhcmUgcmVqZWN0ZWQuXG4gICAgICpcbiAgICAgKiBSZXR1cm5zIHRoZSBmdWxsIGtleSBhY3R1YWxseSB3cml0dGVuIC0gaWRlbnRpY2FsIHRvIGZpbGVOYW1lLCBFWENFUFQgZm9yIGtleXMgY29udGFpbmluZ1xuICAgICAqIFZBUklBQkxFX1NIQVJELCB3aGVyZSB0aGUgc2hhcmQgdmFsdWUgaXMgbWF0ZXJpYWxpemVkIGludG8gdGhlIGtleSAocGlja2VkIGJ5IHNoYXJkIGxhdGVuY3ksXG4gICAgICogc2VlIEFyY2hpdmVzQ2hhaW4pIGFuZCB0aGUgY2FsbGVyIG5lZWRzIHRoZSByZXR1cm5lZCBrZXkgdG8gZXZlciByZWFkIHRoZSB2YWx1ZSBiYWNrLlxuICAgICAqL1xuICAgIHNldChmaWxlTmFtZTogc3RyaW5nLCBkYXRhOiBCdWZmZXIsIGNvbmZpZz86IFNldENvbmZpZyk6IFByb21pc2U8c3RyaW5nPjtcbiAgICBkZWwoZmlsZU5hbWU6IHN0cmluZyk6IFByb21pc2U8dm9pZD47XG4gICAgLyoqIFN0cmVhbXMgYSBmaWxlIHRvbyBsYXJnZSB0byBob2xkIGluIG1lbW9yeS4gZ2V0TmV4dERhdGEgcmV0dXJucyB1bmRlZmluZWQgd2hlbiBkb25lLiBsYXN0TW9kaWZpZWQgc3RhbXBzIHRoZSBmaW5pc2hlZCBmaWxlIGxpa2Ugc2V0J3MgKHN5bmNocm9uaXplZCBjb3BpZXMgbmVlZCBpdCB0byBrZWVwIHdyaXRlIG9yZGVyaW5nKTsgYmFja2VuZHMgdGhhdCBzdGFtcCB0aGVpciBvd24gdGltZXMgKGJhY2tibGF6ZSkgYWNjZXB0IGFuZCBpZ25vcmUgaXQuICovXG4gICAgc2V0TGFyZ2VGaWxlKGNvbmZpZzogeyBwYXRoOiBzdHJpbmc7IGxhc3RNb2RpZmllZD86IG51bWJlcjsgZ2V0TmV4dERhdGEoKTogUHJvbWlzZTxCdWZmZXIgfCB1bmRlZmluZWQ+IH0pOiBQcm9taXNlPHZvaWQ+O1xuICAgIC8qKiB3cml0ZVRpbWUgaXMgdGhlIGxhc3Qtd3JpdGUgdGltZSDigJQgc2VlIEFyY2hpdmVGaWxlSW5mby5jcmVhdGVUaW1lLCB3aGljaCBpcyB0aGUgc2FtZSB2YWx1ZS4gdXJsIGFzIGluIGdldDIuICovXG4gICAgZ2V0SW5mbyhmaWxlTmFtZTogc3RyaW5nKTogUHJvbWlzZTx7IHdyaXRlVGltZTogbnVtYmVyOyBzaXplOiBudW1iZXI7IHVybD86IHN0cmluZyB9IHwgdW5kZWZpbmVkPjtcbiAgICBmaW5kKHByZWZpeDogc3RyaW5nLCBjb25maWc/OiB7IHNoYWxsb3c/OiBib29sZWFuOyB0eXBlOiBcImZpbGVzXCIgfCBcImZvbGRlcnNcIiB9KTogUHJvbWlzZTxzdHJpbmdbXT47XG4gICAgZmluZEluZm8ocHJlZml4OiBzdHJpbmcsIGNvbmZpZz86IHsgc2hhbGxvdz86IGJvb2xlYW47IHR5cGU6IFwiZmlsZXNcIiB8IFwiZm9sZGVyc1wiIH0pOiBQcm9taXNlPEFyY2hpdmVGaWxlSW5mb1tdPjtcbiAgICAvKiogT25seSB3b3JrcyBmb3IgcHVibGljIGJ1Y2tldHMgKHByaXZhdGUgYnVja2V0cyBhcmUgQVBJLWFjY2VzcyBvbmx5KS4gKi9cbiAgICBnZXRVUkwocGF0aDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+O1xuICAgIC8qKiBUaGUgYnVja2V0J3MgY29uZmlndXJhdGlvbiwgd2hpY2ggdGVsbHMgd2hldGhlciB0aGUgb3B0aW9uYWwgZnVuY3Rpb25zIGFyZSBzdXBwb3J0ZWQuICovXG4gICAgZ2V0Q29uZmlnKCk6IFByb21pc2U8QXJjaGl2ZXNDb25maWc+O1xuICAgIC8qKlxuICAgICAqIEFsbCBmaWxlcyBjaGFuZ2VkIGFmdGVyIGNvbmZpZy50aW1lLCBvcHRpb25hbGx5IHJlc3RyaWN0ZWQgdG8ga2V5cyByb3V0aW5nIGludG8gb25lIG9mXG4gICAgICogY29uZmlnLnJvdXRlcyAodXNlZCBieSBzY2FubmluZywgc28gcGFydGlhbGx5LW92ZXJsYXBwaW5nIHNoYXJkcyBvbmx5IHJlY2VpdmUgdGhlaXIgc2xpY2UpLlxuICAgICAqIFdoZW4gZ2V0Q29uZmlnKCkuc3VwcG9ydHNDaGFuZ2VzQWZ0ZXIsIHRoaXMgaXMgYmFja2VkIGJ5IGFuIGluZGV4IChmYXN0LCBhbmQgZGVsZXRpb25zIEFSRVxuICAgICAqIHJlcG9ydGVkLCBhcyBzaXplLTAgdG9tYnN0b25lIGVudHJpZXMpLiBFdmVyeSBvdGhlciBiYWNrZW5kIGVtdWxhdGVzIGl0OiBhIGZ1bGwgZmluZEluZm9cbiAgICAgKiBsaXN0aW5nIGZpbHRlcmVkIGluIG1lbW9yeSAtIGNvcnJlY3QsIGJ1dCBubyBjaGVhcGVyIHRoYW4gdGhlIGxpc3RpbmcgaXRzZWxmLlxuICAgICAqL1xuICAgIGdldENoYW5nZXNBZnRlcjIoY29uZmlnOiBDaGFuZ2VzQWZ0ZXJDb25maWcpOiBQcm9taXNlPEFyY2hpdmVGaWxlSW5mb1tdPjtcbiAgICAvKiogU3luY2hyb25pemF0aW9uIGludHJvc3BlY3Rpb24sIGZvciBiYWNrZW5kcyB0aGF0IHN5bmNocm9uaXplIGZyb20gc291cmNlcyAoc2VlIEJsb2JTdG9yZSkuICovXG4gICAgZ2V0U3luY1N0YXR1cz8oKTogUHJvbWlzZTxBcmNoaXZlc1N5bmNTdGF0dXM+O1xufVxuIl19
|
|
76
|
-
/* _JS_SOURCE_HASH = "
|
|
75
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSUFyY2hpdmVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiSUFyY2hpdmVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSx3S0FBd0s7OztBQUV4SyxzSkFBc0o7QUFDekksUUFBQSx3QkFBd0IsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUV2RCx5TEFBeUw7QUFDNUssUUFBQSxvQkFBb0IsR0FBRyxLQUFLLEdBQUcsSUFBSSxDQUFDO0FBQ2pELFNBQWdCLHVCQUF1QixDQUFDLFlBQW9CO0lBQ3hELElBQUksR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxnQ0FBd0IsQ0FBQztJQUNoRCxJQUFJLFlBQVksR0FBRyxHQUFHLEVBQUUsQ0FBQztRQUNyQixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxZQUFZLE1BQU0sR0FBRyxxQkFBcUIsQ0FBQyxDQUFDO0lBQzFHLENBQUM7QUFDTCxDQUFDO0FBTEQsMERBS0M7QUF1RVksUUFBQSxpQkFBaUIsR0FBcUIsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7QUE0RWhGLHdYQUF3WDtBQUMzVyxRQUFBLDBCQUEwQixHQUFHLDRDQUE0QyxDQUFDO0FBRXZGLDhMQUE4TDtBQUNqTCxRQUFBLG1CQUFtQixHQUFHLHFDQUFxQyxDQUFDO0FBRTVELFFBQUEsVUFBVSxHQUFxQixDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUVuRCwyUkFBMlI7QUFDOVEsUUFBQSxjQUFjLEdBQUcsNkNBQTZDLENBQUM7QUFDNUUsb0xBQW9MO0FBQ3BMLDhKQUE4SjtBQUM5SixTQUFnQixtQkFBbUIsQ0FBQyxXQUF5QztJQUN6RSxJQUFJLENBQUMsV0FBVztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQzlCLE9BQU8sV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztBQUN2QyxDQUFDO0FBSEQsa0RBR0M7QUFFRCxNQUFNLG9CQUFvQixHQUFHLEVBQUUsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBQzlDLE1BQU0sZ0JBQWdCLEdBQUcsRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFFMUMseVpBQXlaO0FBQ2xaLEtBQUssVUFBVSxlQUFlLENBQUMsTUFTckM7SUFDRyxJQUFJLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsR0FBRyxNQUFNLENBQUM7SUFDaEMsSUFBSSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQztJQUN2QixJQUFJLFNBQVMsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDO0lBQ2pDLElBQUksSUFBSSxLQUFLLFNBQVMsSUFBSSxTQUFTLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDaEQsSUFBSSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3BDLElBQUksQ0FBQyxJQUFJO1lBQUUsT0FBTyxTQUFTLENBQUM7UUFDNUIsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUM7UUFDakIsU0FBUyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7SUFDL0IsQ0FBQztJQUNELElBQUksSUFBSSxJQUFJLG9CQUFvQixFQUFFLENBQUM7UUFDL0IsSUFBSSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUNsRSxJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUk7WUFBRSxPQUFPLFNBQVMsQ0FBQztRQUM5QyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLEVBQUUsRUFBRSxZQUFZLEVBQUUsTUFBTSxDQUFDLFNBQVMsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLENBQUMsaUJBQWlCLEVBQUUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZLLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUNyRSxDQUFDO0lBQ0QsaURBQWlEO0lBQ2pELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQztJQUN2QixNQUFNLGNBQWMsR0FBRyxTQUFTLENBQUM7SUFDakMsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQ2YsTUFBTSxFQUFFLENBQUMsWUFBWSxDQUFDO1FBQ2xCLElBQUk7UUFDSixZQUFZLEVBQUUsY0FBYztRQUM1QixXQUFXLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDcEIsSUFBSSxNQUFNLElBQUksU0FBUztnQkFBRSxPQUFPLFNBQVMsQ0FBQztZQUMxQyxJQUFJLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxnQkFBZ0IsRUFBRSxTQUFTLENBQUMsQ0FBQztZQUN6RCxJQUFJLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7WUFDOUYsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDeEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsU0FBUyxJQUFJLENBQUMsWUFBWSxFQUFFLGFBQWEsSUFBSSxJQUFJLElBQUksQ0FBQyxNQUFNLElBQUksU0FBUyxPQUFPLE1BQU0sSUFBSSxHQUFHLGNBQWMsR0FBRyxHQUFHLE1BQU0sZUFBZSxTQUFTLCtDQUErQyxDQUFDLENBQUM7WUFDMVAsQ0FBQztZQUNELE1BQU0sSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDO1lBQ3RCLE9BQU8sSUFBSSxDQUFDO1FBQ2hCLENBQUM7S0FDSixDQUFDLENBQUM7SUFDSCxPQUFPLEVBQUUsU0FBUyxFQUFFLGNBQWMsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7QUFDMUQsQ0FBQztBQTVDRCwwQ0E0Q0MiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBUaGUgaW1wb3J0YW50IG9wZXJhdGlvbnMgb2YgYW4gYXJjaGl2ZSBidWNrZXQgKGV4dHJhY3RlZCBmcm9tIEFyY2hpdmVzQmFja2JsYXplKSwgc28gb3RoZXIgYmFja2VuZHMgKGUuZy4gb3VyIG93biByZW1vdGUgc3RvcmFnZSBzZXJ2ZXIpIGNhbiBiZSB1c2VkIGludGVyY2hhbmdlYWJseS5cblxuLy8gQSB3cml0ZSBtYXkgbm90IGJlIHN0YW1wZWQgbW9yZSB0aGFuIHRoaXMgZmFyIGluIHRoZSBmdXR1cmUsIG9yIGNsb2NrIHNrZXcgYmV0d2VlbiBtYWNoaW5lcyB3b3VsZCBsZXQgYSBiYWQgdGltZXN0YW1wIGJsb2NrIHdyaXRlcyBmb3IgYSBsb25nIHRpbWUuXG5leHBvcnQgY29uc3QgTUFYX0xBU1RfTU9ESUZJRURfRlVUVVJFID0gMTUgKiA2MCAqIDEwMDA7XG5cbi8vIEhvdyBsb25nIGJyb3dzZXJzIG1heSBjYWNoZSBmaWxlcyBmcm9tIGltbXV0YWJsZSBidWNrZXRzICh0aGUgQ2FjaGUtQ29udHJvbCBtYXgtYWdlKSwgc2hhcmVkIGJ5IGV2ZXJ5IGhvc3RpbmcgcGF0aCAoYmFja2JsYXplIGJ1Y2tldCBzZXR0aW5ncyBhbmQgb3VyIG93biBzdG9yYWdlIHNlcnZlcidzIEhUVFAgcm91dGUpXG5leHBvcnQgY29uc3QgSU1NVVRBQkxFX0NBQ0hFX1RJTUUgPSA4NjQwMCAqIDEwMDA7XG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0VmFsaWRMYXN0TW9kaWZpZWQobGFzdE1vZGlmaWVkOiBudW1iZXIpOiB2b2lkIHtcbiAgICBsZXQgbWF4ID0gRGF0ZS5ub3coKSArIE1BWF9MQVNUX01PRElGSUVEX0ZVVFVSRTtcbiAgICBpZiAobGFzdE1vZGlmaWVkID4gbWF4KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgbGFzdE1vZGlmaWVkIGlzIHRvbyBmYXIgaW4gdGhlIGZ1dHVyZTogJHtsYXN0TW9kaWZpZWR9ID4gJHttYXh9IChub3cgKyAxNSBtaW51dGVzKWApO1xuICAgIH1cbn1cblxuXG5leHBvcnQgdHlwZSBSZW1vdGVDb25maWcgPSB7XG4gICAgLy8gTk9URTogVmVyc2lvbiBpcyB1c2VkIHdoZW4gdXBkYXRpbmcgdGhlIGNvbmZpZ3VyYXRpb24uIFRoZSBuZXdlciB2ZXJzaW9uIGlzIGFsd2F5cyB0YWtlbi4gQSBtaXNzaW5nIHZlcnNpb24gY291bnRzIGFzIHZlcnNpb24gLTEuXG4gICAgdmVyc2lvbj86IG51bWJlcjtcbiAgICBzb3VyY2VzOiBSZW1vdGVDb25maWdCYXNlW107XG59O1xuXG4vKipcbiAgICBzdHJpbmcgYXJndW1lbnRzIHdpbGwgYmUgYSB1cmwsIGxvb2tpbmcgbGlrZTpcbiAgICAgICAgaHR0cHM6Ly9zdG9yYWdlMi52aWRncmlkd2ViLmNvbTo0NDQ1L2ZpbGUvZXhhbXBsZWFjY291bnQvZXhhbXBsZWJ1Y2tldC9zdG9yYWdlL3N0b3JhZ2Vyb3V0aW5nLmpzb25cbiAgICAgICAgaHR0cHM6Ly9mMDAyLmJhY2tibGF6ZWIyLmNvbS9maWxlL3F1ZXJ5c3VidGVzdC1jb20tcHVibGljLWltbXV0YWJsZS9zdG9yYWdlL3N0b3JhZ2Vyb3V0aW5nLmpzb25cbiAgICAgICAgLSBUaGVzZSBtYXAgdG8geyB1cmwgfSwgd2l0aCB0aGUgdHlwZSBpbmZlcnJlZCBmcm9tIHRoZSB1cmxcbiAgICAgICAgLSBIb3N0ZWQgdXJscyBhcmUgL2ZpbGUvPGFjY291bnQ+LzxidWNrZXROYW1lPi8uLi4sIGJhY2tibGF6ZSB1cmxzIGFyZSAvZmlsZS88YnVja2V0TmFtZT4vLi4uXG5cbiAgICBOT1RFOiBJZiB3ZSBkbyBub3QgaGF2ZSByaWdodCBhY2Nlc3MgdG8gdGhlc2UsIHRoZW4gaXQgYmVjb21lcyBhIHJlYWQtb25seSBJQXJjaGl2ZXMsIHdoZXJlIHdlIHNvbGVseSByZWFkIHVzaW5nIHRoZSB1cmwgZm9ybSAod2hpY2ggbWlnaHQgdGhyb3cgZHVlIHRvIG5vdCBoYXZpbmcgYWNjZXNzIGFzIHdlbGwpLiBVTkxFU1MgT3VyIGNvbmZpZ3VyYXRpb24gZXhwbGljaXRseSBoYXMgcHVibGljOiBmYWxzZSwgaW4gd2hpY2ggY2FzZSwgd2UgZG9uJ3QgZXZlbiBoaXQgdGhlIFVSTCBhbmQgd2UgdGhyb3cgb24gYWNjZXNzLlxuXG4gICAgTk9URTogSWYgd2UncmUgaW4gdGhlIGJyb3dzZXIsIHdlIHNob3VsZCBhbGxvdyBkb3dubG9hZGluZyB0aGUgZmlsZXMgdmlhIHRoZSBVUkwgZm9ybSAoaWYgaXQncyBhIHB1YmxpYyBidWNrZXQpLCBob3dldmVyLCB3ZSB3b24ndCBhbGxvdyB3cml0aW5nLCBiZWNhdXNlIHRoZWlyIHNlcnZlcnMgZG8gbm90IGFsbG93IHNlY3VyZSBicm93c2VyIHdyaXRlcy5cbiovXG5leHBvcnQgdHlwZSBSZW1vdGVDb25maWdCYXNlID0gc3RyaW5nIHwgSG9zdGVkQ29uZmlnIHwgQmFja2JsYXplQ29uZmlnO1xuXG5leHBvcnQgdHlwZSBDb21tb25Db25maWcgPSB7XG4gICAgLyoqIEJ5IGRlZmF1bHQgYSBzZXJ2ZXIgaG9zdGluZyB0aGlzIGJ1Y2tldCBlYWdlcmx5IGNvcGllcyB0aGlzIHNvdXJjZSdzIGZ1bGwgY29udGVudHMgb250byBpdHMgb3duIGRpc2sgKG9uIHRvcCBvZiB0aGUgbGF6eSByZWFkLXRocm91Z2ggY2FjaGluZykuIFNldCB0aGlzIHRvIGJlIGEgZnJvbnQgZW5kIGZvciBhIHZlcnkgbGFyZ2UgZGF0YWJhc2Ugd2l0aG91dCBjb3B5aW5nIHRoZSBmdWxsIGRhdGFiYXNlIC0gcmVhZHMgc3RpbGwgZG93bi1jYWNoZSBpbmRpdmlkdWFsIGZpbGVzIG9uIGRlbWFuZC4gKi9cbiAgICBub0Z1bGxTeW5jPzogYm9vbGVhbjtcbiAgICAvKiogQnl0ZXMgb2YgcmVhZC1jYWNoZSB0aGlzIHNlcnZlcidzIGRpc2sgbWF5IGhvbGQ7IGxlYXN0LXJlY2VudGx5LXVzZWQgZmlsZXMgYXJlIGRlbGV0ZWQgZnJvbSBkaXNrIHRvIHN0YXkgdW5kZXIgaXQgKG9ubHkgZXZlciB3aGVuIGFub3RoZXIgc291cmNlIHZlcmlmaWFibHkgaG9sZHMgdGhlIGZpbGUgLSB0aGUgb25seSBjb3B5IGlzIG5ldmVyIGRlbGV0ZWQpLiBSZXF1aXJlcyBub0Z1bGxTeW5jIChhIGZ1bGwgY29weSBjYW4ndCBiZSBib3VuZGVkKS4gKi9cbiAgICByZWFkZXJEaXNrTGltaXQ/OiBudW1iZXI7XG4gICAgLyoqIFRoZSB3cml0ZSB0aW1lcyAoW3N0YXJ0TXMsIGVuZE1zXSkgdGhpcyBzb3VyY2UgaXMgdmFsaWQgZm9yIChzZWUgQXJjaGl2ZXNTb3VyY2UudmFsaWRXaW5kb3cgZm9yIHRoZSBzeW5jaHJvbml6YXRpb24gc2VtYW50aWNzKS4gUmVxdWlyZWQgb24gb2JqZWN0IGNvbmZpZ3M6IGNvbmZpZ3VyYXRpb24gY2hhbmdlcyBtdXN0IGJlIFNDSEVEVUxFRCAoYSBuZXcgc291cmNlIGJlY29tZXMgdmFsaWQgYXQgYSBmdXR1cmUgdGltZSB3aGlsZSB0aGUgb2xkIG9uZSdzIHdpbmRvdyBlbmRzKSwgbm90IGZsaXBwZWQgaW5zdGFudGx5LiBQbGFpbiBVUkwtc3RyaW5nIHNvdXJjZXMgZGVmYXVsdCB0byBGVUxMX1ZBTElEX1dJTkRPVyAtIG9uY2UgeW91J3JlIHdyaXRpbmcgb2JqZWN0IGNvbmZpZ3MsIHlvdSdyZSBkb2luZyBzb21ldGhpbmcgY29tcGxpY2F0ZWQgZW5vdWdoIHRvIHRoaW5rIGFib3V0IHdoZW4gdGhpbmdzIGNoYW5nZS4gKi9cbiAgICB2YWxpZFdpbmRvdzogW251bWJlciwgbnVtYmVyXTtcbiAgICAvKiogU2hhcmRpbmc6IHRoZSBmcmFjdGlvbiBvZiB0aGUga2V5IHNwYWNlIHRoaXMgc291cmNlIGhhbmRsZXMsIGFzIFtzdGFydCwgZW5kKSBvdmVyIFswLCAxKSAoa2V5cyBhcmUgcm91dGVkIGJ5IGdldFJvdXRlIGluIHJlbW90ZUNvbmZpZy50cykuIERlZmF1bHRzIHRvIEZVTExfUk9VVEUgKHVuc2hhcmRlZCkuIEF0IGV2ZXJ5IHBvaW50IGluIHRpbWUgdGhlIHNvdXJjZXMnIHJvdXRlcyBtdXN0IGZ1bGx5IGNvdmVyIFswLCAxKSwgb3Igc29tZSBrZXlzIGNvdWxkIG5ldmVyIGJlIHJlYWQuICovXG4gICAgcm91dGU/OiBbbnVtYmVyLCBudW1iZXJdO1xuICAgIC8qKiBTZXQgb24gZW50cmllcyBpbmplY3RlZCBpbnRvIHRoZSBpbi1tZW1vcnkgY29uZmlnIGJ5IGFuIG92ZXJsYXkgKGEgZGVwbG95IHN3aXRjaG92ZXIncyBhbHRlcm5hdGUtcG9ydCB3aW5kb3cpLiBOZXZlciB3cml0dGVuIHRvIGRpc2s6IHJlc29sdmVJbnRlcm1lZGlhdGVTb3VyY2VzIHN0cmlwcyB0aGVzZSBhbmQgcmVqb2lucyB0aGUgd2luZG93cyBhcm91bmQgdGhlbSwgd2hpY2ggaXMgYWxzbyBob3cgYSBjbGllbnQgdGVsbHMgd2hldGhlciBhbiB1cGRhdGUgaXMgYSByZWFsIGNvbmZpZ3VyYXRpb24gY2hhbmdlIG9yIGp1c3QgYW4gb3ZlcmxheS4gKi9cbiAgICBpbnRlcm1lZGlhdGU/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IHR5cGUgSG9zdGVkQ29uZmlnID0gQ29tbW9uQ29uZmlnICYge1xuICAgIHR5cGU6IFwicmVtb3RlXCI7XG5cbiAgICAvLyBFeDogaHR0cHM6Ly85OS0yNTAtMTI0LTkxLnF1ZXJ5c3VidGVzdC5jb206NTIzMy9maWxlL3Jvb3QvdW5pcXVlYnVja2V0bmFtZS9zdG9yYWdlL3N0b3JhZ2Vyb3V0aW5nLmpzb25cbiAgICAvLyBOT1RFOiBUaGUgYWNjb3VudCBhbmQgYnVja2V0IG5hbWUgYXJlIG9idGFpbmVkIGZyb20gdGhlIFVSTC5cbiAgICB1cmw6IHN0cmluZztcblxuICAgIC8vIE5PVEU6IEF1dGhlbnRpY2F0aW9uIGlzIGhhbmRsZWQgYnkgY2VydC50cywgdmlhIGhhdmluZyB5b3VyIG1hY2hpbmUgdHJ1c3RlZCB0byBhY2Nlc3MgdGhpcyBhY2NvdW50LiBcblxuICAgIHB1YmxpYz86IGJvb2xlYW47XG4gICAgLy8gRmFzdCBtb2RlOiB0aGUgc2VydmVyIGFja25vd2xlZGdlcyB3cml0ZXMgb25jZSB0aGV5IGFyZSBpbiBtZW1vcnksIGZsdXNoaW5nIHRvIGRpc2sgYWZ0ZXIgd3JpdGVEZWxheSAoZGVmYXVsdCA1IG1pbnV0ZXMpIGFuZCBjb2FsZXNjaW5nIHdyaXRlcyB0byB0aGUgc2FtZSBmaWxlLiBBIHNlcnZlciBjcmFzaCBsb3NlcyB3cml0ZXMgdGhhdCBoYXZlbid0IGZsdXNoZWQgeWV0LlxuICAgIGZhc3Q/OiBib29sZWFuO1xuICAgIHdyaXRlRGVsYXk/OiBudW1iZXI7XG4gICAgLy8gVGhlIGJ1Y2tldCBpcyBzZXJ2ZWQgc3RyYWlnaHQgZnJvbSB0aGUgc2VydmVyJ3MgZGlzaywgd2l0aCBubyBpbmRleCDigJQgc28gbm8gZmFzdCB3cml0ZXMsIG5vIGdldFN5bmNTdGF0dXMsIGFuZCBnZXRDaGFuZ2VzQWZ0ZXIyIGZhbGxzIGJhY2sgdG8gYSBmdWxsIGxpc3RpbmcuXG4gICAgcmF3RGlzaz86IGJvb2xlYW47XG4gICAgLy8gV3JpdGVzIHRvIHBhdGhzIHRoYXQgYWxyZWFkeSBleGlzdCBhcmUgZGlzYWxsb3dlZCAoZGVsZXRlcyBzdGlsbCB3b3JrKS5cbiAgICBpbW11dGFibGU/OiBib29sZWFuO1xufTtcblxuZXhwb3J0IHR5cGUgQmFja2JsYXplQ29uZmlnID0gQ29tbW9uQ29uZmlnICYge1xuICAgIHR5cGU6IFwiYmFja2JsYXplXCI7XG4gICAgLy8gRXg6IGh0dHBzOi8vZjAwMi5iYWNrYmxhemViMi5jb20vZmlsZS9xdWVyeXN1YnRlc3QtY29tLXB1YmxpYy1pbW11dGFibGUvc3RvcmFnZS9zdG9yYWdlcm91dGluZy5qc29uXG4gICAgLy8gTk9URTogVGhlIGJ1Y2tldCBuYW1lIGlzIG9idGFpbmVkIGZyb20gdGhlIFVSTC5cbiAgICB1cmw6IHN0cmluZztcbiAgICAvLyBQdWJsaWMgYnVja2V0cyBhcmUgc2VydmVkIG92ZXIgcGxhaW4gSFRUUFMgR0VUcyAoZ2V0VVJMKS4gUHJpdmF0ZSBidWNrZXRzIGFyZSBBUEktYWNjZXNzIG9ubHkuXG4gICAgcHVibGljPzogYm9vbGVhbjtcbiAgICAvLyBOT1RFOiBUaGlzIGlzbid0IGVuZm9yY2VkIG9uIHRoZSBiYWNrYmxhemUgbGV2ZWwsIHNvIHRoaXMgaXMganVzdCBhIGNsaWVudC1zaWRlIGd1YXJhbnRlZS4gVGhpcyBjYW4gY2hhbmdlIGhvdyB3ZSBjYWNoZSBmaWxlcy5cbiAgICAvLyAgLSBCYWNrYmxhemUgZG9lcyBzdXBwb3J0IGltbXV0YWJpbGl0eS4gSG93ZXZlciwgYXBwYXJlbnRseSwgb25jZSB3ZSBlbmFibGUgaXQgb24gYSBidWNrZXQsIHdlIGNhbid0IGRpc2FibGUgaXQsIHdoaWNoIGlzIHJlYWxseSBiYWQsIGFzIGl0IG1lYW5zIGlmIG91ciBjb2RlIGNvdWxkIGV2ZXIgZW5hYmxlIGl0IGFuZCB3ZSBhY2NpZGVudGFsbHkgZW5hYmxlIGl0IG9uIGFuIGltcG9ydGFudCBidWNrZXQsIHdlIGVzc2VudGlhbGx5IGp1c3QgYnJpY2tlZCB0aGF0IGJ1Y2tldC4gU28gd2Ugc2hvdWxkIG5ldmVyIHdyaXRlIGFueSBjb2RlIHRoYXQgZXZlciB0cmllcyB0byB1c2UgYmFja2JsYXplIHRvIG1ha2UgdGhpbmdzIGltbXV0YWJsZS4gXG4gICAgaW1tdXRhYmxlPzogYm9vbGVhbjtcbiAgICAvLyBDT1JTIG9yaWdpbnMgYWxsb3dlZCB0byBjb25zdW1lIHRoZSBidWNrZXQncyBmaWxlcyBpbiBhIGJyb3dzZXIuIE5vdCBhIHNlY3VyaXR5IGJvdW5kYXJ5IChhY2Nlc3MgaXMgZ2F0ZWQgYnkgdGhlIEFQSSBrZXkgLyBzaWduZWQgVVJMcywgbmVpdGhlciBvZiB3aGljaCByaWRlcyBpbiBjb29raWVzKSAtIGl0IG9ubHkgY29udHJvbHMgd2hpY2ggc2l0ZXMnIGluLXBhZ2UgSmF2YVNjcmlwdCBjYW4gcmVhZCByZXNwb25zZXMuIERlZmF1bHRzIHRvIGFueSBIVFRQUyBvcmlnaW4uXG4gICAgYWxsb3dlZE9yaWdpbnM/OiBzdHJpbmdbXTtcblxuICAgIC8vIE5PVEU6IFdlIHdpbGwgYWNjZXNzIHRoZSBhcGkga2V5IGZyb20gZ2V0U2VjcmV0LCBzZWUgYmFja2JsYXplLnRzIGZvciB0aGUgc3BlY2lmaWMga2V5cy5cbn07XG5cblxuZXhwb3J0IGNvbnN0IEZVTExfVkFMSURfV0lORE9XOiBbbnVtYmVyLCBudW1iZXJdID0gWzAsIE51bWJlci5NQVhfU0FGRV9JTlRFR0VSXTtcblxuXG5cblxuZXhwb3J0IHR5cGUgR2V0Q29uZmlnID0ge1xuICAgIHJhbmdlPzogeyBzdGFydDogbnVtYmVyOyBlbmQ6IG51bWJlciB9O1xuICAgIC8qKiBSZWFkIE9OTFkgZnJvbSB0aGUgcHJpbWFyeSBzb3VyY2UgLSB0aGUgb25lIHdyaXRlcyB3b3VsZCB0YXJnZXQgLSBpbnN0ZWFkIG9mIGZhbGxpbmcgYmFjayBhY3Jvc3MgdGhlIHJlZHVuZGFudCBzb3VyY2VzLiBVc2UgdGhpcyB3aGVuIHlvdSB3YW50IHlvdXIgcmVhZHMgYW5kIHdyaXRlcyB0byBiZSBzb21ld2hhdCBhdG9taWM6IHRoZXJlIHdpbGwgc3RpbGwgYmUgaXNzdWVzIHdpdGggdGhlIHJvdW5kIHRyaXAsIGJ1dCB3aXRob3V0IGl0IHlvdSBjb3VsZCB0YWxrIHRvIGEgY29tcGxldGVseSBkaWZmZXJlbnQgbm9kZSBhbmQgZ2V0IGEgbXVjaCBvbGRlciB2YWx1ZS4gTW9zdCByZWFkcyBhcmVuJ3QgZm9sbG93ZWQgYnkgYSB3cml0ZSB0aG91Z2gsIHNvIGZvciBtb3N0IGNhc2VzIGl0J3MgYmV0dGVyIHRvIGdldCBhIHZhbHVlIHRoYW4gdG8gaGF2ZSB0byB3YWl0IChvciBldmVuIHRocm93KSB3aGVuIHRoZSBwcmltYXJ5IG5vZGUgaXMgbm90IGF2YWlsYWJsZS4gKi9cbiAgICBub0ZhbGxiYWNrcz86IGJvb2xlYW47XG4gICAgLyoqIFN0b3JlLXRvLXN0b3JlIGNhbGw6IHRoZSBzZXJ2aW5nIG5vZGUgYW5zd2VycyBwdXJlbHkgZnJvbSBpdHMgb3duIGRpc2ssIGNvbXBsZXRlbHkgc2hvcnQtY2lyY3VpdGluZyBpdHMgaW5kZXggaG9sZGVycyAtIGNoYXNpbmcgaXRzIG93biByZW1vdGUgaG9sZGVycyB3aGlsZSBhbnN3ZXJpbmcgYW5vdGhlciBzdG9yZSBpcyBob3cgaW5maW5pdGUgZ2V0IGxvb3BzIGJldHdlZW4gc3RvcmVzIGZvcm0gKEEgYXNrcyBCLCBCJ3MgaW5kZXggcG9pbnRzIGJhY2sgYXQgQSwgLi4uKS4gTm8gd2luZG93IG9yIHJvdXRlIGNoZWNrcyBvbiByZWFkczogaWYgdGhlIGJ5dGVzIGFyZSBvbiBpdHMgZGlzaywgdGhlIGNhbGxlciBtYXkgaGF2ZSB0aGVtLiAqL1xuICAgIGludGVybmFsPzogYm9vbGVhbjtcbn07XG5cbmV4cG9ydCB0eXBlIENoYW5nZXNBZnRlckNvbmZpZyA9IHtcbiAgICB0aW1lOiBudW1iZXI7XG4gICAgLyoqIE9ubHkga2V5cyByb3V0aW5nIGludG8gb25lIG9mIHRoZXNlIFtzdGFydCwgZW5kKSByYW5nZXMuIE9ubHkgc2Nhbm5pbmcgcGFzc2VzIHRoaXMgLSBpdCBsZXRzIGEgc3RvcmUgc3luY2luZyBhIHBhcnRpYWwgc2hhcmQgYXNrIGZvciBqdXN0IGl0cyBzbGljZS4gKi9cbiAgICByb3V0ZXM/OiBbbnVtYmVyLCBudW1iZXJdW107XG59O1xuXG5leHBvcnQgdHlwZSBTZXRDb25maWcgPSB7XG4gICAgbGFzdE1vZGlmaWVkPzogbnVtYmVyO1xuICAgIC8qKiBNYWtlcyB0aGUgd3JpdGUgYWNjZXB0YWJsZSBvbiBpbW11dGFibGUgdGFyZ2V0czogYW4gZXhpc3RpbmcgcGF0aCBpcyBzaW1wbHkga2VwdCAoaW1tdXRhYmlsaXR5IHdpbnMgLSBub3RoaW5nIGlzIG92ZXJ3cml0dGVuKSBpbnN0ZWFkIG9mIHRoZSB3cml0ZSB0aHJvd2luZy4gUmVxdWlyZXMgbGFzdE1vZGlmaWVkLiBTeW5jaHJvbml6YXRpb24gTVVTVCBwYXNzIHRoaXMgb24gZXZlcnkgcHVzaCAtIGEgcGxhaW4gc2V0IHRocm93cyBvbiBpbW11dGFibGUgdGFyZ2V0cywgd2hpY2ggd291bGQgYWJvcnQgcmVjb25jaWxpYXRpb24gd2hlbmV2ZXIgb25lIHNvdXJjZSBpbiBhIGNoYWluIGlzIGltbXV0YWJsZS4gKi9cbiAgICBmb3JjZVNldEltbXV0YWJsZT86IGJvb2xlYW47XG4gICAgLyoqIFNraXBzIHRoZSB0YXJnZXQtc2lkZSBzYWZldHkgcmVhZHMgYXJvdW5kIHRoZSB3cml0ZSAoYmFja2JsYXplOiB0aGUgcHJlLXdyaXRlIGdldEluZm8gY29tcGFyaXNvbiBhbmQgdGhlIHBvc3QtdXBsb2FkIGV4aXN0ZW5jZSBwb2xsKS4gRm9yIHdyaXRlcnMgd2hvc2Ugb3duIGJvb2trZWVwaW5nIGFscmVhZHkgZGVjaWRlcyB3aGF0IHRvIHdyaXRlIGFuZCBvcmRlcnMgaXQgYnkgd3JpdGUgdGltZSAoQmxvYlN0b3JlJ3MgaW5kZXgtZHJpdmVuIHdyaXRlcyBhbmQgc3luY2hyb25pemF0aW9uKSwgdGhvc2UgcmVhZHMgYXJlIHB1cmUgZXh0cmEgQVBJIGNhbGxzIC0gYnV0IHRoZSBkZWZhdWx0IHN0YXlzIGNoZWNrZWQsIGJlY2F1c2Ugb3RoZXIgdXNlcnMgb2YgdGhlIHJhdyBiYWNrZW5kcyByZWx5IG9uIHRoZSBjaGVja3MuICovXG4gICAgbm9DaGVja3M/OiBib29sZWFuO1xuICAgIC8qKiBTdG9yZS10by1zdG9yZSBwdXNoOiB0aGUgcmVjZWl2aW5nIG5vZGUgd3JpdGVzIHB1cmVseSB0byBpdHMgb3duIGRpc2sgYW5kIGluZGV4LCB3aXRoIE5PIGRvd25zdHJlYW0gZmFuLW91dCAodGhlIHB1c2hpbmcgc3RvcmUgb3ducyBwcm9wYWdhdGlvbiAtIGZhbm5pbmcgaXRzIHB1c2hlcyBiYWNrIG91dCBpcyBob3cgd3JpdGUgbG9vcHMgYmV0d2VlbiBzdG9yZXMgZm9ybSkuIFdpbmRvdyBhbmQgcm91dGUgQVJFIHN0aWxsIGNoZWNrZWQ6IHRoZSBzdGFtcCBtdXN0IGZhbGwgaW5zaWRlIG9uZSBvZiB0aGUgcmVjZWl2ZXIncyBjb25maWd1cmVkIHdpbmRvd3MgYW5kIHJvdXRlcywgc28gYSBjb25mdXNlZCBwZWVyIGNhbm5vdCBzdHVmZiBkYXRhIG9udG8gYSBub2RlIHRoYXQgd2FzIG5ldmVyIG1lYW50IHRvIGhvbGQgaXQuIFJlcXVpcmVzIGxhc3RNb2RpZmllZC4gKi9cbiAgICBpbnRlcm5hbD86IGJvb2xlYW47XG59O1xuXG4vLyBjcmVhdGVUaW1lIGlzIGEgbWlzbm9tZXIga2VwdCBmb3IgY29tcGF0aWJpbGl0eSDigJQgaXQgaXMgcmVhbGx5IHRoZSBMQVNULVdSSVRFIHRpbWUsIHNhbWUgYXMgZ2V0SW5mbydzIHdyaXRlVGltZS4gTmVpdGhlciBCYWNrYmxhemUgbm9yIG91ciByZW1vdGUgc3RvcmFnZSB0cmFja3MgYSBkaXN0aW5jdCBjcmVhdGlvbiBkYXRlOiBlYWNoIHdyaXRlIHN0YW1wcyBhIGZyZXNoIHRpbWVzdGFtcCBvbiB0aGUgY3VycmVudCB2ZXJzaW9uLCBzbyBib3RoIGZpZWxkcyBhcmUganVzdCBcIndoZW4gdGhlIGJ5dGVzIHNlcnZlZCBieSBnZXQoKSB3ZXJlIG1vc3QgcmVjZW50bHkgd3JpdHRlblwiLlxuZXhwb3J0IHR5cGUgQXJjaGl2ZUZpbGVJbmZvID0geyBwYXRoOiBzdHJpbmc7IGNyZWF0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyIH07XG5cbi8vIEFuIGluLXByb2dyZXNzIGJhY2tncm91bmQgc3luY2hyb25pemF0aW9uIHRhc2sgKHNlZSBBcmNoaXZlc0NvbmZpZy5zeW5jaW5nKVxuZXhwb3J0IHR5cGUgU3luY0FjdGl2aXR5ID0ge1xuICAgIC8vIEEgbWV0YWRhdGEgc2NhbiBpcyBhIHNpbmdsZSBsaXN0aW5nIGNhbGwsIHNvIGl0IGhhcyBubyBpbmNyZW1lbnRhbCBwcm9ncmVzcyAtIGp1c3QgdGhhdCBpdCdzIHJ1bm5pbmcgYW5kIHNpbmNlIHdoZW4uIEEgZnVsbCBzeW5jIGtub3dzIGl0cyBleGFjdCBmaWxlL2J5dGUgcHJvZ3Jlc3MuXG4gICAgdHlwZTogXCJtZXRhZGF0YVNjYW5cIiB8IFwiZnVsbFN5bmNcIjtcbiAgICBzb3VyY2VEZWJ1Z05hbWU6IHN0cmluZztcbiAgICBzdGFydFRpbWU6IG51bWJlcjtcbiAgICBkb25lRmlsZXM/OiBudW1iZXI7XG4gICAgdG90YWxGaWxlcz86IG51bWJlcjtcbiAgICBkb25lQnl0ZXM/OiBudW1iZXI7XG4gICAgdG90YWxCeXRlcz86IG51bWJlcjtcbn07XG5cbmV4cG9ydCB0eXBlIEFyY2hpdmVzQ29uZmlnID0ge1xuICAgIC8vIFdoZXRoZXIgZ2V0Q2hhbmdlc0FmdGVyMiBpcyBuYXRpdmVseSBpbmRleC1iYWNrZWQgKGZhc3QgY2hhbmdlIHBvbGxpbmc7IGV2ZXJ5IGJhY2tlbmQgc3RpbGwgc2VydmVzIGl0LCBidXQgdGhlIG90aGVycyBlbXVsYXRlIGl0IHdpdGggYSBmdWxsIGxpc3RpbmcpXG4gICAgc3VwcG9ydHNDaGFuZ2VzQWZ0ZXI/OiBib29sZWFuO1xuICAgIC8vIFRoZSBidWNrZXQncyBmdWxsIHJvdXRpbmcgY29uZmlnIChST1VUSU5HX0ZJTEUpLiBBYnNlbnQgZm9yIHNvdXJjZXMgdGhhdCBkb24ndCBoYXZlIG9uZSAoYSBiYXJlIGRpc2sgc291cmNlLCBvciBhIGJ1Y2tldCB0aGF0IGRvZXNuJ3QgZXhpc3QgeWV0KS5cbiAgICByZW1vdGVDb25maWc/OiBSZW1vdGVDb25maWc7XG4gICAgLy8gTGl2ZSBpbmRleCB0b3RhbHMgKHRvbWJzdG9uZXMgZXhjbHVkZWQpLCBrZXB0IHVwIHRvIGRhdGUgaW4gbWVtb3J5IG9uIGV2ZXJ5IG11dGF0aW9uIGFuZCByZWNvbXB1dGVkIG9uIGxvYWQgLSBzbyBhbnkgZHJpZnQgaGVhbHMgb24gcmVzdGFydFxuICAgIGluZGV4PzogeyBmaWxlQ291bnQ6IG51bWJlcjsgYnl0ZUNvdW50OiBudW1iZXIgfTtcbiAgICAvLyBUaGUgc2FtZSB0b3RhbHMgYnJva2VuIGRvd24gYnkgd2hpY2ggc291cmNlIGN1cnJlbnRseSBob2xkcyBlYWNoIGZpbGUncyBieXRlcyAodGhlIGZpcnN0IGVudHJ5IGlzIHRoZSBzZXJ2ZXIncyBvd24gZGlzaylcbiAgICBpbmRleFNvdXJjZXM/OiB7IGRlYnVnTmFtZTogc3RyaW5nOyBmaWxlQ291bnQ6IG51bWJlcjsgYnl0ZUNvdW50OiBudW1iZXIgfVtdO1xuICAgIC8vIFRoZSBzZXJ2ZXIncyBjb25maWd1cmVkIHJlYWRlckRpc2tMaW1pdCwgd2hlbiBpdCBydW5zIGFzIGEgYm91bmRlZCByZWFkIGNhY2hlXG4gICAgcmVhZGVyRGlza0xpbWl0PzogbnVtYmVyO1xuICAgIC8vIEJhY2tncm91bmQgc3luY2hyb25pemF0aW9uIGN1cnJlbnRseSBpbiBwcm9ncmVzcyAoZW1wdHkgd2hlbiBpZGxlKVxuICAgIHN5bmNpbmc/OiBTeW5jQWN0aXZpdHlbXTtcbn07XG5cbi8vIEEgc3luY2hyb25pemF0aW9uIHNvdXJjZSBvZiBhIEJsb2JTdG9yZSAod2hpY2ggc3luY2hyb25pemVzIGFuIGluZGV4ICsgbG9jYWwgY2FjaGUgZnJvbSB0aGVtKVxuZXhwb3J0IHR5cGUgQXJjaGl2ZXNTb3VyY2UgPSB7XG4gICAgc291cmNlOiBJQXJjaGl2ZXM7XG4gICAgLyoqIFRoZSBwZXJzaXN0ZW50IGlkZW50aXR5IG9mIHRoZSBlbmRwb2ludDogaXRzIHJvdXRpbmcgVVJMIChob3N0ZWQvYmFja2JsYXplKSwgb3IgdGhlIGRpc2sgZm9sZGVyIHBhdGggZm9yIHRoZSBiYXNlIGRpc2sgc291cmNlLiBUaGUgc3RvcmUgcGVyc2lzdHMgdGhpcyAodmlhIGl0cyBhcHBlbmQtb25seSBzb3VyY2VzIGxpc3QpIGFzIEluZGV4RW50cnkuc291cmNlc0xpc3RJbmRleCwgc28gaXQgbXVzdCBtZWFuIHRoZSBzYW1lIGVuZHBvaW50IGZvcmV2ZXIuICovXG4gICAgdXJsOiBzdHJpbmc7XG4gICAgLy8gRnJvbSB0aGUgc291cmNlJ3MgQ29tbW9uQ29uZmlnLiBUaGUgd2luZG93IHJvdXRlcyBXUklURVM6IG9uY2UgaXRzIGVuZCBpcyBwYXN0IChzZWUgd2luZG93QWNjZXB0c1dyaXRlcykgdGhlIHNvdXJjZSBzdG9wcyByZWNlaXZpbmcgd3JpdGVzIGVudGlyZWx5IC0gaXQganVzdCBzdG9wcyBncm93aW5nLiBJdCBkb2VzIE5PVCBmaWx0ZXIgc2Nhbm5pbmc6IGEgc2NhbiBpcyB1cyBhc2tpbmcgdGhlIHNvdXJjZSB3aGF0IGl0IGFscmVhZHkgaG9sZHMsIGFuZCBleGlzdGluZyB2YWx1ZXMgc3luY2hyb25pemUgcmVnYXJkbGVzcyBvZiB0aGVpciB3cml0ZSB0aW1lcyAodGhlIHNhbWUgcmVhc29uaW5nIHRoYXQgbGV0cyBzeW5jaHJvbml6YXRpb24gaWdub3JlIHRoZSBpbW11dGFibGUgZmxhZykuXG4gICAgdmFsaWRXaW5kb3c6IFtudW1iZXIsIG51bWJlcl07XG4gICAgLy8gRnJvbSB0aGUgc291cmNlJ3MgQ29tbW9uQ29uZmlnIChpbnRlcnNlY3RlZCB3aXRoIHRoZSBvd25pbmcgc3RvcmUncyBvd24gcm91dGUpOiBvbmx5IGtleXMgcm91dGluZyBpbnRvIFtzdGFydCwgZW5kKSBhcmUgYWNjZXB0ZWQgZnJvbSB0aGlzIHNvdXJjZSdzIHNjYW5zIGFuZCBzZW50IHRvIGl0IGluIHdyaXRlcy9yZWNvbmNpbGlhdGlvbi4gVGhlIHJvdXRpbmcgZmlsZSBpcyBleGVtcHQgLSBjb25maWcgZmxvd3MgZXZlcnl3aGVyZS4gQWJzZW50ID0gYWxsIGtleXMuXG4gICAgcm91dGU/OiBbbnVtYmVyLCBudW1iZXJdO1xuICAgIC8vIEZyb20gdGhlIHNvdXJjZSdzIENvbW1vbkNvbmZpZzsgc2VlIHRoZXJlLlxuICAgIG5vRnVsbFN5bmM/OiBib29sZWFuO1xuICAgIC8vIEZyb20gdGhlIHNvdXJjZSdzIENvbW1vbkNvbmZpZzogYSBkZXBsb3kgc3dpdGNob3ZlcidzIHRlbXBvcmFyeSBhbHRlcm5hdGUtcG9ydCBlbnRyeS4gT25jZSBpdHMgd2luZG93IGlzIHBhc3QsIHRoZSBwb3J0IGl0IHBvaW50cyBhdCBpcyBnb25lIGZvciBnb29kIC0gc28gaXQgaXMgbmV2ZXIgc2Nhbm5lZCB0aGVuLCBhbmQgc2NhbiBmYWlsdXJlcyBhcmUgbmV2ZXIgcmV0cmllZC5cbiAgICBpbnRlcm1lZGlhdGU/OiBib29sZWFuO1xuICAgIC8vIFN0YWJsZSBpZGVudGl0eSBvZiB0aGUgdW5kZXJseWluZyBlbmRwb2ludCAoaXRzIGNvbmZpZyB3aXRoIHdpbmRvd3Mvcm91dGVzIHN0cmlwcGVkKSAtIGhvdyBCbG9iU3RvcmUudXBkYXRlU291cmNlcyByZWNvZ25pemVzIGEgc291cmNlIGFjcm9zcyBjb25maWcgY2hhbmdlcyBzbyBpdCBjYW4gdXBkYXRlIGl0IGluIHBsYWNlIGluc3RlYWQgb2YgcmVtb3ZpbmcgYW5kIHJlLWFkZGluZyBpdFxuICAgIGlkZW50aXR5Pzogc3RyaW5nO1xufTtcblxuLy8gRXJyb3IgbWFya2VyIGEgc2VydmVyIGluY2x1ZGVzIHdoZW4gYSBmcmVzaGx5LXN0YW1wZWQgd3JpdGUgcmVhY2hlcyBpdCBvdXRzaWRlIGl0cyB2YWxpZCB3aW5kb3dzICh0aGUgY2xpZW50IHJlc29sdmVkIGl0cyB0YXJnZXQsIHRoZW4gdGltZSBjcm9zc2VkIGEgd2luZG93IGJvdW5kYXJ5IGJlZm9yZSB0aGUgd3JpdGUgbGFuZGVkKS4gQ2xpZW50cyBkZXRlY3QgdGhpcyBtYXJrZXIgYW5kIHJlLXJlc29sdmUgdGhlIGN1cnJlbnRseS12YWxpZCBzb3VyY2UsIHJldHJ5aW5nIE9OQ0UgLSBib3VuZGFyaWVzIGFyZSBmYXIgYXBhcnQsIHNvIGhpdHRpbmcgaXQgdHdpY2UgaW4gb25lIGF0dGVtcHQgbWVhbnMgc29tZXRoaW5nIGlzIGFjdHVhbGx5IHdyb25nLlxuZXhwb3J0IGNvbnN0IFNUT1JBR0VfV1JPTkdfVkFMSURfV0lORE9XID0gXCJSRU1PVEVfU1RPUkFHRV9XUk9OR19WQUxJRF9XSU5ET1dfYTdjMWYwNGVcIjtcblxuLy8gRXJyb3IgbWFya2VyIGEgc2VydmVyIGluY2x1ZGVzIHdoZW4gYSBmcmVzaGx5LXN0YW1wZWQgd3JpdGUncyBrZXkgcm91dGVzIG91dHNpZGUgdGhlIHNoYXJkcyB0aGlzIHNlcnZlciBoYW5kbGVzICh0aGUgY2xpZW50J3MgY29uZmlnIGRpc2FncmVlcyB3aXRoIHRoZSBzZXJ2ZXIncyAtIGNsaWVudHMgcmUtcmVzb2x2ZSBvbmNlKVxuZXhwb3J0IGNvbnN0IFNUT1JBR0VfV1JPTkdfUk9VVEUgPSBcIlJFTU9URV9TVE9SQUdFX1dST05HX1JPVVRFX2M5NGQyZTE3XCI7XG5cbmV4cG9ydCBjb25zdCBGVUxMX1JPVVRFOiBbbnVtYmVyLCBudW1iZXJdID0gWzAsIDFdO1xuXG4vLyBBIGtleSBjb250YWluaW5nIHRoaXMgc2VudGluZWwgZG9lc24ndCBoYXZlIGEgZml4ZWQgc2hhcmQ6IHNldFZhcmlhYmxlU2hhcmQgcGlja3MgdGhlIChsb3dlc3QgbGF0ZW5jeSwgdXApIHdyaXRlIHNoYXJkLCBhcHBlbmRzIFwiXzx2YWx1ZSBpbiB0aGUgc2hhcmQncyByb3V0ZT5cIiBkaXJlY3RseSBhZnRlciB0aGUgc2VudGluZWwsIGFuZCByZXR1cm5zIHRoZSBtYXRlcmlhbGl6ZWQga2V5LiBnZXRSb3V0ZSB0cmVhdHMgdGhhdCBzdWZmaXggYXMgYSBjb21wbGV0ZSByb3V0ZSBvdmVycmlkZS5cbmV4cG9ydCBjb25zdCBWQVJJQUJMRV9TSEFSRCA9IFwiVkFSSUFCTEVfU0hBUkRfZjAyMzRqZmFoMDhmZ3loZmd5c3NkZHM4M25tcFwiO1xuLy8gTm8gZ3JhY2UgcGFzdCB0aGUgZW5kOiBhIHdpbmRvdyBib3VuZGFyeSBpcyBhIGhhcmQgaGFuZG9mZiAoY2xpZW50cyByZXRyeSBhIHJlamVjdGVkIHdyaXRlIGFnYWluc3QgdGhlIG5ld2x5LXZhbGlkIHNvdXJjZSwgc28gbGVuaWVuY3kgaGVyZSB3b3VsZCBvbmx5IGRlc3luY2hyb25pemUgdGhlIGhhbmRvZmYpXG4vLyAgLSBXcml0aW5nIHRvIG9sZGVyIHZhbGlkIHN0YXRlIHdpbmRvd3MgaXMgZmluZSwgdGhvdWdoLiBXZSBuZWVkIHRoaXMgdG8gaW5nZXN0IHRoZSBvbGQgZGF0YSB3aGVuIHdlJ3JlIHN5bmNocm9uaXppbmcgbm9kZXMgdG8gZ2V0IHRoZW0gdXAgdG8gZGF0ZSBhbnl3YXkuIFxuZXhwb3J0IGZ1bmN0aW9uIHdpbmRvd0FjY2VwdHNXcml0ZXModmFsaWRXaW5kb3c6IFtudW1iZXIsIG51bWJlcl0gfCB1bmRlZmluZWQpOiBib29sZWFuIHtcbiAgICBpZiAoIXZhbGlkV2luZG93KSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gdmFsaWRXaW5kb3dbMV0gPiBEYXRlLm5vdygpO1xufVxuXG5jb25zdCBMQVJHRV9DT1BZX1RIUkVTSE9MRCA9IDY0ICogMTAyNCAqIDEwMjQ7XG5jb25zdCBMQVJHRV9DT1BZX0NIVU5LID0gMzIgKiAxMDI0ICogMTAyNDtcblxuLyoqIENvcGllcyBvbmUgZmlsZSBiZXR3ZWVuIHR3byBhcmNoaXZlcy4gU21hbGwgZmlsZXMgZ28gYXMgYSBzaW5nbGUgZ2V0MitzZXQ7IHBhc3QgTEFSR0VfQ09QWV9USFJFU0hPTEQgdGhlIGNvcHkgc3RyZWFtcyB0aHJvdWdoIHNldExhcmdlRmlsZSBpbiBMQVJHRV9DT1BZX0NIVU5LIHJhbmdlZCByZWFkcywgc28gdGhlIHdob2xlIGZpbGUgaXMgbmV2ZXIgaW4gbWVtb3J5LiBzaXplL3dyaXRlVGltZSB1c3VhbGx5IGNvbWUgZnJvbSB0aGUgY2FsbGVyJ3MgbWV0YWRhdGEgc2Nhbjsgd2hlbiBlaXRoZXIgaXMgb21pdHRlZCwgZ2V0SW5mbyBmaWxscyB0aGVtIGluLiBSZXR1cm5zIHRoZSBjb3BpZWQgZmlsZSdzIGluZm8sIG9yIHVuZGVmaW5lZCB3aGVuIHRoZSBzb3VyY2UgZG9lc24ndCBoYXZlIHRoZSBmaWxlLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvcHlBcmNoaXZlRmlsZShjb25maWc6IHtcbiAgICBmcm9tOiBJQXJjaGl2ZXM7XG4gICAgdG86IElBcmNoaXZlcztcbiAgICBwYXRoOiBzdHJpbmc7XG4gICAgc2l6ZT86IG51bWJlcjtcbiAgICB3cml0ZVRpbWU/OiBudW1iZXI7XG4gICAgZm9yY2VTZXRJbW11dGFibGU/OiBib29sZWFuO1xuICAgIG5vQ2hlY2tzPzogYm9vbGVhbjtcbiAgICBpbnRlcm5hbD86IGJvb2xlYW47XG59KTogUHJvbWlzZTx7IHdyaXRlVGltZTogbnVtYmVyOyBzaXplOiBudW1iZXIgfSB8IHVuZGVmaW5lZD4ge1xuICAgIGxldCB7IGZyb20sIHRvLCBwYXRoIH0gPSBjb25maWc7XG4gICAgbGV0IHNpemUgPSBjb25maWcuc2l6ZTtcbiAgICBsZXQgd3JpdGVUaW1lID0gY29uZmlnLndyaXRlVGltZTtcbiAgICBpZiAoc2l6ZSA9PT0gdW5kZWZpbmVkIHx8IHdyaXRlVGltZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGxldCBpbmZvID0gYXdhaXQgZnJvbS5nZXRJbmZvKHBhdGgpO1xuICAgICAgICBpZiAoIWluZm8pIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIHNpemUgPSBpbmZvLnNpemU7XG4gICAgICAgIHdyaXRlVGltZSA9IGluZm8ud3JpdGVUaW1lO1xuICAgIH1cbiAgICBpZiAoc2l6ZSA8PSBMQVJHRV9DT1BZX1RIUkVTSE9MRCkge1xuICAgICAgICBsZXQgcmVzdWx0ID0gYXdhaXQgZnJvbS5nZXQyKHBhdGgsIHsgaW50ZXJuYWw6IGNvbmZpZy5pbnRlcm5hbCB9KTtcbiAgICAgICAgaWYgKCFyZXN1bHQgfHwgIXJlc3VsdC5kYXRhKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICBhd2FpdCB0by5zZXQocGF0aCwgcmVzdWx0LmRhdGEsIHsgbGFzdE1vZGlmaWVkOiByZXN1bHQud3JpdGVUaW1lLCBmb3JjZVNldEltbXV0YWJsZTogY29uZmlnLmZvcmNlU2V0SW1tdXRhYmxlLCBub0NoZWNrczogY29uZmlnLm5vQ2hlY2tzLCBpbnRlcm5hbDogY29uZmlnLmludGVybmFsIH0pO1xuICAgICAgICByZXR1cm4geyB3cml0ZVRpbWU6IHJlc3VsdC53cml0ZVRpbWUsIHNpemU6IHJlc3VsdC5kYXRhLmxlbmd0aCB9O1xuICAgIH1cbiAgICAvLyBDb25zdHMgc28gdGhlIGNsb3N1cmUga2VlcHMgdGhlIG5hcnJvd2VkIHR5cGVzXG4gICAgY29uc3QgdG90YWxTaXplID0gc2l6ZTtcbiAgICBjb25zdCBmaW5hbFdyaXRlVGltZSA9IHdyaXRlVGltZTtcbiAgICBsZXQgb2Zmc2V0ID0gMDtcbiAgICBhd2FpdCB0by5zZXRMYXJnZUZpbGUoe1xuICAgICAgICBwYXRoLFxuICAgICAgICBsYXN0TW9kaWZpZWQ6IGZpbmFsV3JpdGVUaW1lLFxuICAgICAgICBnZXROZXh0RGF0YTogYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKG9mZnNldCA+PSB0b3RhbFNpemUpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICBsZXQgZW5kID0gTWF0aC5taW4ob2Zmc2V0ICsgTEFSR0VfQ09QWV9DSFVOSywgdG90YWxTaXplKTtcbiAgICAgICAgICAgIGxldCBkYXRhID0gYXdhaXQgZnJvbS5nZXQocGF0aCwgeyByYW5nZTogeyBzdGFydDogb2Zmc2V0LCBlbmQgfSwgaW50ZXJuYWw6IGNvbmZpZy5pbnRlcm5hbCB9KTtcbiAgICAgICAgICAgIGlmICghZGF0YSB8fCAhZGF0YS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFJhbmdlZCByZWFkIG9mICR7SlNPTi5zdHJpbmdpZnkocGF0aCl9IGZyb20gJHtmcm9tLmdldERlYnVnTmFtZSgpfSByZXR1cm5lZCAke2RhdGEgJiYgZGF0YS5sZW5ndGggfHwgXCJub3RoaW5nXCJ9IGF0ICR7b2Zmc2V0fS0ke2VuZH0gKGV4cGVjdGVkICR7ZW5kIC0gb2Zmc2V0fSBieXRlcyBvZiBhICR7dG90YWxTaXplfSBieXRlIGZpbGUgLSBpdCBjaGFuZ2VkIG9yIHZhbmlzaGVkIG1pZC1jb3B5KWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgb2Zmc2V0ICs9IGRhdGEubGVuZ3RoO1xuICAgICAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgICAgIH0sXG4gICAgfSk7XG4gICAgcmV0dXJuIHsgd3JpdGVUaW1lOiBmaW5hbFdyaXRlVGltZSwgc2l6ZTogdG90YWxTaXplIH07XG59XG5cbmV4cG9ydCB0eXBlIEFyY2hpdmVzU3luY1NvdXJjZVN0YXR1cyA9IHtcbiAgICBkZWJ1Z05hbWU6IHN0cmluZztcbiAgICB2YWxpZFdpbmRvdzogW251bWJlciwgbnVtYmVyXTtcbiAgICByb3V0ZT86IFtudW1iZXIsIG51bWJlcl07XG4gICAgbm9GdWxsU3luYz86IGJvb2xlYW47XG4gICAgc3VwcG9ydHNDaGFuZ2VzQWZ0ZXI6IGJvb2xlYW47XG4gICAgaW5pdGlhbFNjYW5Db21wbGV0ZTogYm9vbGVhbjtcbiAgICAvLyBGaWxlcyBzZWVuIGluIHRoaXMgc291cmNlJ3Mgc2NhbnMgLyBjaGFuZ2UgcG9sbHMgc28gZmFyXG4gICAgc2Nhbm5lZENvdW50OiBudW1iZXI7XG59O1xuZXhwb3J0IHR5cGUgQXJjaGl2ZXNTeW5jU3RhdHVzID0ge1xuICAgIGFsbFNjYW5zQ29tcGxldGU6IGJvb2xlYW47XG4gICAgLy8gTnVtYmVyIG9mIGZpbGVzIGluIHRoZSBpbmRleFxuICAgIGluZGV4U2l6ZTogbnVtYmVyO1xuICAgIHNvdXJjZXM6IEFyY2hpdmVzU3luY1NvdXJjZVN0YXR1c1tdO1xufTtcblxuZXhwb3J0IGludGVyZmFjZSBJQXJjaGl2ZXMge1xuICAgIGdldERlYnVnTmFtZSgpOiBzdHJpbmc7XG4gICAgLyoqIFdoZXRoZXIgd3JpdGVzIHdvdWxkIGJlIGFjY2VwdGVkIChjcmVkZW50aWFscyBleGlzdCwgdGhlIGFjY291bnQgdHJ1c3RzIHRoaXMgbWFjaGluZSwgZXRjKS4gQ2hlY2tlZCB3aXRob3V0IHdyaXRpbmcgYW55dGhpbmcuICovXG4gICAgaGFzV3JpdGVBY2Nlc3MoKTogUHJvbWlzZTxib29sZWFuPjtcbiAgICAvKipcbiAgICAgKiBSZWFkcyBhdXRvbWF0aWNhbGx5IGZhbGwgYmFjayBhY3Jvc3MgdGhlIHJlZHVuZGFudCBzb3VyY2VzIHVubGVzcyBjb25maWcubm9GYWxsYmFja3MgaXMgc2V0LlxuICAgICAqIEEgZmFsbGJhY2sgY29weSBjYW4gbGFnIHRoZSB3cml0ZSB0YXJnZXQsIHNvIGEgY2FsbGVyIHJlYWRpbmcgc3RhdGUgaW4gb3JkZXIgdG8gbXV0YXRlIGl0XG4gICAgICogKGUuZy4geCsrKSwgd2hlcmUgYWN0aW5nIG9uIHByZXZpb3VzIHN0YXRlIHdvdWxkIGNhdXNlIGJpZyBpc3N1ZXMsIHNob3VsZCBwYXNzIG5vRmFsbGJhY2tzIC1cbiAgICAgKiBhbmQgdHJ5L2NhdGNoIHRoZSByZWFkLCBoYW5kbGluZyB0aGUgY2F0Y2ggY2FzZSAoYSBkb3duIHByaW1hcnkgaXMgcmV0cmllZCBmb3IgYSB3aGlsZSwgdGhlblxuICAgICAqIHRocm93cyBpbnN0ZWFkIG9mIGRlZ3JhZGluZyB0byBhIHN0YWxlIGNvcHkpLlxuICAgICAqL1xuICAgIGdldChmaWxlTmFtZTogc3RyaW5nLCBjb25maWc/OiBHZXRDb25maWcpOiBQcm9taXNlPEJ1ZmZlciB8IHVuZGVmaW5lZD47XG4gICAgLyoqIFNlZSBnZXQgZm9yIHRoZSBmYWxsYmFjayBzZW1hbnRpY3MgKGFuZCB3aGVuIHRvIHBhc3Mgbm9GYWxsYmFja3MpLiB1cmwgaXMgdGhlIGNvbmZpZyBVUkwgb2YgdGhlIHNvdXJjZSB0aGF0IGFuc3dlcmVkIC0gdGhlIGF1dGhvcml0eSB0aGUgZGF0YSAob3IgdGhlIFwiZG9lcyBub3QgZXhpc3RcIikgY2FtZSBmcm9tLiBNdWx0aS1zb3VyY2UgaW1wbGVtZW50YXRpb25zIChBcmNoaXZlc0NoYWluKSBBTFdBWVMgcmV0dXJuIGFuIG9iamVjdDogd2hlbiB0aGUgdmFsdWUgZG9lc24ndCBleGlzdCB0aGVyZSBpcyBzdGlsbCBhIHNlcnZlciBzYXlpbmcgaXQgZG9lc24ndCBleGlzdCwgc28gdGhleSByZXR1cm4geyB1cmwgfSBhbG9uZSByYXRoZXIgdGhhbiB1bmRlZmluZWQuIFNpbmdsZS1zb3VyY2UgYmFja2VuZHMgcmV0dXJuIHVuZGVmaW5lZCBmb3IgYWJzZW50ICh0aGV5IEFSRSB0aGUgYXV0aG9yaXR5KS4gKi9cbiAgICBnZXQyKGZpbGVOYW1lOiBzdHJpbmcsIGNvbmZpZz86IEdldENvbmZpZyk6IFByb21pc2U8eyBkYXRhOiBCdWZmZXI7IHdyaXRlVGltZTogbnVtYmVyOyBzaXplOiBudW1iZXI7IHVybD86IHN0cmluZyB9IHwgeyBkYXRhPzogdW5kZWZpbmVkOyB3cml0ZVRpbWU/OiB1bmRlZmluZWQ7IHNpemU/OiB1bmRlZmluZWQ7IHVybDogc3RyaW5nIH0gfCB1bmRlZmluZWQ+O1xuICAgIC8qKlxuICAgICAqIGxhc3RNb2RpZmllZCBzdGFtcHMgdGhlIHdyaXRlIHdpdGggdGhhdCBsYXN0LXdyaXRlIHRpbWUgaW5zdGVhZCBvZiBub3cuIElmIGl0IGlzIE9MREVSIHRoYW5cbiAgICAgKiB0aGUgZmlsZSdzIGN1cnJlbnQgbGFzdC13cml0ZSB0aW1lIHRoZSB3cml0ZSBuby1vcHMgKHNvIGRlbGF5ZWQgLyBzeW5jaHJvbml6ZWQgd3JpdGVzIGNhblxuICAgICAqIG5ldmVyIGNsb2JiZXIgbmV3ZXIgZGF0YSkuIFRpbWVzIG1vcmUgdGhhbiAxNSBtaW51dGVzIGluIHRoZSBmdXR1cmUgYXJlIHJlamVjdGVkLlxuICAgICAqXG4gICAgICogUmV0dXJucyB0aGUgZnVsbCBrZXkgYWN0dWFsbHkgd3JpdHRlbiAtIGlkZW50aWNhbCB0byBmaWxlTmFtZSwgRVhDRVBUIGZvciBrZXlzIGNvbnRhaW5pbmdcbiAgICAgKiBWQVJJQUJMRV9TSEFSRCwgd2hlcmUgdGhlIHNoYXJkIHZhbHVlIGlzIG1hdGVyaWFsaXplZCBpbnRvIHRoZSBrZXkgKHBpY2tlZCBieSBzaGFyZCBsYXRlbmN5LFxuICAgICAqIHNlZSBBcmNoaXZlc0NoYWluKSBhbmQgdGhlIGNhbGxlciBuZWVkcyB0aGUgcmV0dXJuZWQga2V5IHRvIGV2ZXIgcmVhZCB0aGUgdmFsdWUgYmFjay5cbiAgICAgKi9cbiAgICBzZXQoZmlsZU5hbWU6IHN0cmluZywgZGF0YTogQnVmZmVyLCBjb25maWc/OiBTZXRDb25maWcpOiBQcm9taXNlPHN0cmluZz47XG4gICAgZGVsKGZpbGVOYW1lOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+O1xuICAgIC8qKiBTdHJlYW1zIGEgZmlsZSB0b28gbGFyZ2UgdG8gaG9sZCBpbiBtZW1vcnkuIGdldE5leHREYXRhIHJldHVybnMgdW5kZWZpbmVkIHdoZW4gZG9uZS4gbGFzdE1vZGlmaWVkIHN0YW1wcyB0aGUgZmluaXNoZWQgZmlsZSBsaWtlIHNldCdzIChzeW5jaHJvbml6ZWQgY29waWVzIG5lZWQgaXQgdG8ga2VlcCB3cml0ZSBvcmRlcmluZyk7IGJhY2tlbmRzIHRoYXQgc3RhbXAgdGhlaXIgb3duIHRpbWVzIChiYWNrYmxhemUpIGFjY2VwdCBhbmQgaWdub3JlIGl0LiAqL1xuICAgIHNldExhcmdlRmlsZShjb25maWc6IHsgcGF0aDogc3RyaW5nOyBsYXN0TW9kaWZpZWQ/OiBudW1iZXI7IGdldE5leHREYXRhKCk6IFByb21pc2U8QnVmZmVyIHwgdW5kZWZpbmVkPiB9KTogUHJvbWlzZTx2b2lkPjtcbiAgICAvKiogd3JpdGVUaW1lIGlzIHRoZSBsYXN0LXdyaXRlIHRpbWUg4oCUIHNlZSBBcmNoaXZlRmlsZUluZm8uY3JlYXRlVGltZSwgd2hpY2ggaXMgdGhlIHNhbWUgdmFsdWUuIHVybCBhcyBpbiBnZXQyLiAqL1xuICAgIGdldEluZm8oZmlsZU5hbWU6IHN0cmluZyk6IFByb21pc2U8eyB3cml0ZVRpbWU6IG51bWJlcjsgc2l6ZTogbnVtYmVyOyB1cmw/OiBzdHJpbmcgfSB8IHVuZGVmaW5lZD47XG4gICAgZmluZChwcmVmaXg6IHN0cmluZywgY29uZmlnPzogeyBzaGFsbG93PzogYm9vbGVhbjsgdHlwZTogXCJmaWxlc1wiIHwgXCJmb2xkZXJzXCIgfSk6IFByb21pc2U8c3RyaW5nW10+O1xuICAgIGZpbmRJbmZvKHByZWZpeDogc3RyaW5nLCBjb25maWc/OiB7IHNoYWxsb3c/OiBib29sZWFuOyB0eXBlOiBcImZpbGVzXCIgfCBcImZvbGRlcnNcIiB9KTogUHJvbWlzZTxBcmNoaXZlRmlsZUluZm9bXT47XG4gICAgLyoqIE9ubHkgd29ya3MgZm9yIHB1YmxpYyBidWNrZXRzIChwcml2YXRlIGJ1Y2tldHMgYXJlIEFQSS1hY2Nlc3Mgb25seSkuICovXG4gICAgZ2V0VVJMKHBhdGg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPjtcbiAgICAvKiogVGhlIGJ1Y2tldCdzIGNvbmZpZ3VyYXRpb24sIHdoaWNoIHRlbGxzIHdoZXRoZXIgdGhlIG9wdGlvbmFsIGZ1bmN0aW9ucyBhcmUgc3VwcG9ydGVkLiAqL1xuICAgIGdldENvbmZpZygpOiBQcm9taXNlPEFyY2hpdmVzQ29uZmlnPjtcbiAgICAvKipcbiAgICAgKiBBbGwgZmlsZXMgY2hhbmdlZCBhZnRlciBjb25maWcudGltZSwgb3B0aW9uYWxseSByZXN0cmljdGVkIHRvIGtleXMgcm91dGluZyBpbnRvIG9uZSBvZlxuICAgICAqIGNvbmZpZy5yb3V0ZXMgKHVzZWQgYnkgc2Nhbm5pbmcsIHNvIHBhcnRpYWxseS1vdmVybGFwcGluZyBzaGFyZHMgb25seSByZWNlaXZlIHRoZWlyIHNsaWNlKS5cbiAgICAgKiBXaGVuIGdldENvbmZpZygpLnN1cHBvcnRzQ2hhbmdlc0FmdGVyLCB0aGlzIGlzIGJhY2tlZCBieSBhbiBpbmRleCAoZmFzdCwgYW5kIGRlbGV0aW9ucyBBUkVcbiAgICAgKiByZXBvcnRlZCwgYXMgc2l6ZS0wIHRvbWJzdG9uZSBlbnRyaWVzKS4gRXZlcnkgb3RoZXIgYmFja2VuZCBlbXVsYXRlcyBpdDogYSBmdWxsIGZpbmRJbmZvXG4gICAgICogbGlzdGluZyBmaWx0ZXJlZCBpbiBtZW1vcnkgLSBjb3JyZWN0LCBidXQgbm8gY2hlYXBlciB0aGFuIHRoZSBsaXN0aW5nIGl0c2VsZi5cbiAgICAgKi9cbiAgICBnZXRDaGFuZ2VzQWZ0ZXIyKGNvbmZpZzogQ2hhbmdlc0FmdGVyQ29uZmlnKTogUHJvbWlzZTxBcmNoaXZlRmlsZUluZm9bXT47XG4gICAgLyoqIFN5bmNocm9uaXphdGlvbiBpbnRyb3NwZWN0aW9uLCBmb3IgYmFja2VuZHMgdGhhdCBzeW5jaHJvbml6ZSBmcm9tIHNvdXJjZXMgKHNlZSBCbG9iU3RvcmUpLiAqL1xuICAgIGdldFN5bmNTdGF0dXM/KCk6IFByb21pc2U8QXJjaGl2ZXNTeW5jU3RhdHVzPjtcbn1cbiJdfQ==
|
|
76
|
+
/* _JS_SOURCE_HASH = "93fef80ba5ae920152449386acb644322188cb57f60511c218b0b3fd1cba1131"; */
|
|
@@ -142,11 +142,11 @@ export class ArchivesRemote implements IArchives {
|
|
|
142
142
|
return result && result.data || undefined;
|
|
143
143
|
}
|
|
144
144
|
public async get2(fileName: string, config?: GetConfig): Promise<{ data: Buffer; writeTime: number; size: number } | undefined> {
|
|
145
|
-
let result = await this.call(() => this.controller.get2(this.account, this.bucketName, fileName, config?.range));
|
|
145
|
+
let result = await this.call(() => this.controller.get2(this.account, this.bucketName, fileName, config?.range, config?.internal));
|
|
146
146
|
return result && { data: Buffer.from(result.data), writeTime: result.writeTime, size: result.size } || undefined;
|
|
147
147
|
}
|
|
148
148
|
public async set(fileName: string, data: Buffer, config?: SetConfig): Promise<string> {
|
|
149
|
-
await this.call(() => this.controller.set(this.account, this.bucketName, fileName, data, config?.lastModified, config?.forceSetImmutable));
|
|
149
|
+
await this.call(() => this.controller.set(this.account, this.bucketName, fileName, data, config?.lastModified, config?.forceSetImmutable, config?.internal));
|
|
150
150
|
return fileName;
|
|
151
151
|
}
|
|
152
152
|
public async del(fileName: string): Promise<void> {
|
|
@@ -15,6 +15,14 @@ export type IBucketStore = {
|
|
|
15
15
|
writeTime: number;
|
|
16
16
|
size: number;
|
|
17
17
|
} | undefined>;
|
|
18
|
+
getInternal2?(fileName: string, config?: GetConfig): Promise<{
|
|
19
|
+
data: Buffer;
|
|
20
|
+
writeTime: number;
|
|
21
|
+
size: number;
|
|
22
|
+
} | undefined>;
|
|
23
|
+
setInternal?(fileName: string, data: Buffer, config: {
|
|
24
|
+
lastModified: number;
|
|
25
|
+
}): Promise<void>;
|
|
18
26
|
set(fileName: string, data: Buffer, config?: WriteConfig): Promise<string>;
|
|
19
27
|
del(fileName: string, config?: WriteConfig): Promise<void>;
|
|
20
28
|
getInfo(fileName: string): Promise<{
|
|
@@ -154,6 +162,16 @@ export declare class BlobStore implements IBucketStore {
|
|
|
154
162
|
writeTime: number;
|
|
155
163
|
size: number;
|
|
156
164
|
} | undefined>;
|
|
165
|
+
/** Internal (store-to-store) read: purely the local disk, completely short-circuiting the index and holder resolution - the caller is another store, and chasing OUR remote holders while answering it is how infinite get loops between stores form. No window or route checks: if the bytes are on our disk, the caller may have them. Note fast writes still sitting in the overlay are invisible here; the caller re-finds them after our flush. */
|
|
166
|
+
getInternal2(key: string, config?: GetConfig): Promise<{
|
|
167
|
+
data: Buffer;
|
|
168
|
+
writeTime: number;
|
|
169
|
+
size: number;
|
|
170
|
+
} | undefined>;
|
|
171
|
+
/** Internal (store-to-store) write: the local disk plus our index, with NO downstream fan-out - the pushing store owns propagation, and fanning its pushes back out is how write loops between stores form. Window/route acceptance is the caller's (writeBucketFile's) job; only-take-latest still applies here. */
|
|
172
|
+
setInternal(key: string, data: Buffer, config: {
|
|
173
|
+
lastModified: number;
|
|
174
|
+
}): Promise<void>;
|
|
157
175
|
private cacheRead;
|
|
158
176
|
set(key: string, data: Buffer, config?: WriteConfig): Promise<string>;
|
|
159
177
|
del(key: string, config?: WriteConfig): Promise<void>;
|
|
@@ -58,6 +58,9 @@ export type WriteConfig = {
|
|
|
58
58
|
export type IBucketStore = {
|
|
59
59
|
get(fileName: string, config?: GetConfig): Promise<Buffer | undefined>;
|
|
60
60
|
get2(fileName: string, config?: GetConfig): Promise<{ data: Buffer; writeTime: number; size: number } | undefined>;
|
|
61
|
+
// Internal (store-to-store) forms; see GetConfig.internal / SetConfig.internal. Absent on rawDisk stores, where the normal forms already ARE the disk.
|
|
62
|
+
getInternal2?(fileName: string, config?: GetConfig): Promise<{ data: Buffer; writeTime: number; size: number } | undefined>;
|
|
63
|
+
setInternal?(fileName: string, data: Buffer, config: { lastModified: number }): Promise<void>;
|
|
61
64
|
set(fileName: string, data: Buffer, config?: WriteConfig): Promise<string>;
|
|
62
65
|
del(fileName: string, config?: WriteConfig): Promise<void>;
|
|
63
66
|
getInfo(fileName: string): Promise<{ writeTime: number; size: number } | undefined>;
|
|
@@ -443,7 +446,7 @@ export class BlobStore implements IBucketStore {
|
|
|
443
446
|
tally.tombstone++;
|
|
444
447
|
continue;
|
|
445
448
|
}
|
|
446
|
-
let copied = await copyArchiveFile({ from: source, to: this.sources[0].source, path: file.path, size: file.size, writeTime: file.createTime, forceSetImmutable: true, noChecks: true });
|
|
449
|
+
let copied = await copyArchiveFile({ from: source, to: this.sources[0].source, path: file.path, size: file.size, writeTime: file.createTime, forceSetImmutable: true, noChecks: true, internal: true });
|
|
447
450
|
if (!copied) continue;
|
|
448
451
|
if (copied.size === 0) {
|
|
449
452
|
this.setIndexEntry(file.path, { writeTime: copied.writeTime, size: 0, sourcesListIndex: this.sourcesListIndexOfSlot(0) });
|
|
@@ -673,14 +676,14 @@ export class BlobStore implements IBucketStore {
|
|
|
673
676
|
if (entry.size === 0) {
|
|
674
677
|
// A deletion only needs pushing while the source still holds an older copy
|
|
675
678
|
if (theirTime === undefined) continue;
|
|
676
|
-
await source.set(key, Buffer.alloc(0), { lastModified: entry.writeTime, forceSetImmutable: true, noChecks: true });
|
|
679
|
+
await source.set(key, Buffer.alloc(0), { lastModified: entry.writeTime, forceSetImmutable: true, noChecks: true, internal: true });
|
|
677
680
|
pushed++;
|
|
678
681
|
consecutiveFailures = 0;
|
|
679
682
|
continue;
|
|
680
683
|
}
|
|
681
684
|
let holder = await this.getEntryHolder(entry);
|
|
682
685
|
if (!holder) continue;
|
|
683
|
-
let copied = await copyArchiveFile({ from: holder, to: source, path: key, size: entry.size, writeTime: entry.writeTime, forceSetImmutable: true, noChecks: true });
|
|
686
|
+
let copied = await copyArchiveFile({ from: holder, to: source, path: key, size: entry.size, writeTime: entry.writeTime, forceSetImmutable: true, noChecks: true, internal: true });
|
|
684
687
|
if (!copied) continue;
|
|
685
688
|
pushed++;
|
|
686
689
|
consecutiveFailures = 0;
|
|
@@ -794,7 +797,7 @@ export class BlobStore implements IBucketStore {
|
|
|
794
797
|
let index = nextIndex++;
|
|
795
798
|
if (index >= pending.length) return;
|
|
796
799
|
let { key, entry } = pending[index];
|
|
797
|
-
let copied = await copyArchiveFile({ from: source, to: this.sources[0].source, path: key, size: entry.size, writeTime: entry.writeTime, forceSetImmutable: true, noChecks: true });
|
|
800
|
+
let copied = await copyArchiveFile({ from: source, to: this.sources[0].source, path: key, size: entry.size, writeTime: entry.writeTime, forceSetImmutable: true, noChecks: true, internal: true });
|
|
798
801
|
if (copied) {
|
|
799
802
|
// Only move the entry's source if it wasn't changed while we copied
|
|
800
803
|
if (this.mem.get(key) === entry) {
|
|
@@ -888,7 +891,10 @@ export class BlobStore implements IBucketStore {
|
|
|
888
891
|
let holderError: Error | undefined;
|
|
889
892
|
if (holderArchives) {
|
|
890
893
|
try {
|
|
891
|
-
|
|
894
|
+
let answer = await holderArchives.get2(key, { range, internal: true });
|
|
895
|
+
if (answer && answer.data) {
|
|
896
|
+
result = { data: answer.data, writeTime: answer.writeTime, size: answer.size };
|
|
897
|
+
}
|
|
892
898
|
} catch (e) {
|
|
893
899
|
holderError = e as Error;
|
|
894
900
|
}
|
|
@@ -911,7 +917,10 @@ export class BlobStore implements IBucketStore {
|
|
|
911
917
|
if (i === holderSlot || !this.isLive(i)) continue;
|
|
912
918
|
let fallback: { data: Buffer; writeTime: number; size: number } | undefined;
|
|
913
919
|
try {
|
|
914
|
-
|
|
920
|
+
let answer = await this.sources[i].source.get2(key, { internal: true });
|
|
921
|
+
if (answer && answer.data) {
|
|
922
|
+
fallback = { data: answer.data, writeTime: answer.writeTime, size: answer.size };
|
|
923
|
+
}
|
|
915
924
|
} catch {
|
|
916
925
|
continue;
|
|
917
926
|
}
|
|
@@ -929,6 +938,30 @@ export class BlobStore implements IBucketStore {
|
|
|
929
938
|
return undefined;
|
|
930
939
|
}
|
|
931
940
|
|
|
941
|
+
/** Internal (store-to-store) read: purely the local disk, completely short-circuiting the index and holder resolution - the caller is another store, and chasing OUR remote holders while answering it is how infinite get loops between stores form. No window or route checks: if the bytes are on our disk, the caller may have them. Note fast writes still sitting in the overlay are invisible here; the caller re-finds them after our flush. */
|
|
942
|
+
public async getInternal2(key: string, config?: GetConfig): Promise<{ data: Buffer; writeTime: number; size: number } | undefined> {
|
|
943
|
+
await this.init();
|
|
944
|
+
let result = await this.getDiskSource().disk.get2(key, { range: config?.range });
|
|
945
|
+
return result && result.data && { data: result.data, writeTime: result.writeTime, size: result.size } || undefined;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/** Internal (store-to-store) write: the local disk plus our index, with NO downstream fan-out - the pushing store owns propagation, and fanning its pushes back out is how write loops between stores form. Window/route acceptance is the caller's (writeBucketFile's) job; only-take-latest still applies here. */
|
|
949
|
+
public async setInternal(key: string, data: Buffer, config: { lastModified: number }): Promise<void> {
|
|
950
|
+
await this.init();
|
|
951
|
+
assertValidLastModified(config.lastModified);
|
|
952
|
+
let overlayEntry = this.overlay.get(key);
|
|
953
|
+
let entry = this.mem.get(key);
|
|
954
|
+
let currentTime = overlayEntry && overlayEntry.t || entry && entry.writeTime || 0;
|
|
955
|
+
if (config.lastModified < currentTime) return;
|
|
956
|
+
if (data.length === 0) {
|
|
957
|
+
// A tombstone stores nothing on our own source - the index entry alone records it
|
|
958
|
+
await this.sources[0].source.del(key);
|
|
959
|
+
} else {
|
|
960
|
+
await this.sources[0].source.set(key, data, { lastModified: config.lastModified, forceSetImmutable: true, noChecks: true });
|
|
961
|
+
}
|
|
962
|
+
this.setIndexEntry(key, { writeTime: config.lastModified, size: data.length, sourcesListIndex: this.sourcesListIndexOfSlot(0) });
|
|
963
|
+
}
|
|
964
|
+
|
|
932
965
|
// The read's bytes came from a remote source, so write them onto our own base source (the local disk), which becomes the entry's new holder - reads only pay the remote fetch once
|
|
933
966
|
private async cacheRead(key: string, result: { data: Buffer; writeTime: number }): Promise<void> {
|
|
934
967
|
await this.sources[0].source.set(key, result.data, { lastModified: result.writeTime, forceSetImmutable: true, noChecks: true });
|
|
@@ -1007,7 +1040,7 @@ export class BlobStore implements IBucketStore {
|
|
|
1007
1040
|
for (let i of writable) {
|
|
1008
1041
|
if (!routeContains(this.sources[i].route, route)) continue;
|
|
1009
1042
|
// Downstream sources receive tombstones as actual empty writes, so their listings show the deletion (size 0) and other stores scan it in as a tombstone
|
|
1010
|
-
void this.sources[i].source.set(key, data, { lastModified: writeTime, forceSetImmutable: true, noChecks: true }).catch((e: Error) => {
|
|
1043
|
+
void this.sources[i].source.set(key, data, { lastModified: writeTime, forceSetImmutable: true, noChecks: true, internal: true }).catch((e: Error) => {
|
|
1011
1044
|
console.error(`Background write of ${key} to sync source ${this.sources[i].source.getDebugName()} failed: ${e.stack ?? e}`);
|
|
1012
1045
|
});
|
|
1013
1046
|
}
|