velocious 1.0.474 → 1.0.475

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +7 -2
  2. package/build/configuration-types.js +38 -1
  3. package/build/configuration.js +41 -1
  4. package/build/database/drivers/base.js +51 -3
  5. package/build/database/drivers/mysql/index.js +74 -7
  6. package/build/database/drivers/sqlite/connection-sql-js.js +16 -5
  7. package/build/database/drivers/sqlite/index.web.js +29 -15
  8. package/build/database/drivers/sqlite/web-persistence.js +521 -0
  9. package/build/environment-handlers/node/cli/commands/generate/frontend-models.js +63 -0
  10. package/build/frontend-model-controller.js +127 -4
  11. package/build/frontend-model-resource/base-resource.js +5 -1
  12. package/build/frontend-models/base.js +146 -2
  13. package/build/frontend-models/query.js +3 -3
  14. package/build/frontend-models/resource-definition.js +304 -2
  15. package/build/routes/hooks/frontend-model-command-route-hook.js +8 -0
  16. package/build/src/configuration-types.d.ts +113 -2
  17. package/build/src/configuration-types.d.ts.map +1 -1
  18. package/build/src/configuration-types.js +35 -2
  19. package/build/src/configuration.d.ts +18 -1
  20. package/build/src/configuration.d.ts.map +1 -1
  21. package/build/src/configuration.js +37 -2
  22. package/build/src/database/drivers/base.d.ts +30 -0
  23. package/build/src/database/drivers/base.d.ts.map +1 -1
  24. package/build/src/database/drivers/base.js +47 -4
  25. package/build/src/database/drivers/mysql/index.d.ts +32 -3
  26. package/build/src/database/drivers/mysql/index.d.ts.map +1 -1
  27. package/build/src/database/drivers/mysql/index.js +65 -7
  28. package/build/src/database/drivers/sqlite/connection-sql-js.d.ts +8 -1
  29. package/build/src/database/drivers/sqlite/connection-sql-js.d.ts.map +1 -1
  30. package/build/src/database/drivers/sqlite/connection-sql-js.js +15 -6
  31. package/build/src/database/drivers/sqlite/index.web.d.ts +5 -5
  32. package/build/src/database/drivers/sqlite/index.web.d.ts.map +1 -1
  33. package/build/src/database/drivers/sqlite/index.web.js +27 -13
  34. package/build/src/database/drivers/sqlite/web-persistence.d.ts +77 -0
  35. package/build/src/database/drivers/sqlite/web-persistence.d.ts.map +1 -0
  36. package/build/src/database/drivers/sqlite/web-persistence.js +464 -0
  37. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts +30 -0
  38. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.d.ts.map +1 -1
  39. package/build/src/environment-handlers/node/cli/commands/generate/frontend-models.js +53 -1
  40. package/build/src/frontend-model-controller.d.ts +34 -0
  41. package/build/src/frontend-model-controller.d.ts.map +1 -1
  42. package/build/src/frontend-model-controller.js +113 -5
  43. package/build/src/frontend-model-resource/base-resource.d.ts +4 -2
  44. package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
  45. package/build/src/frontend-model-resource/base-resource.js +7 -2
  46. package/build/src/frontend-models/base.d.ts +29 -0
  47. package/build/src/frontend-models/base.d.ts.map +1 -1
  48. package/build/src/frontend-models/base.js +131 -3
  49. package/build/src/frontend-models/query.js +4 -4
  50. package/build/src/frontend-models/resource-definition.d.ts +6 -0
  51. package/build/src/frontend-models/resource-definition.d.ts.map +1 -1
  52. package/build/src/frontend-models/resource-definition.js +272 -3
  53. package/build/src/routes/hooks/frontend-model-command-route-hook.d.ts.map +1 -1
  54. package/build/src/routes/hooks/frontend-model-command-route-hook.js +8 -1
  55. package/build/src/sync/device-identity.d.ts +240 -0
  56. package/build/src/sync/device-identity.d.ts.map +1 -0
  57. package/build/src/sync/device-identity.js +454 -0
  58. package/build/src/sync/local-mutation-log.d.ts +212 -0
  59. package/build/src/sync/local-mutation-log.d.ts.map +1 -0
  60. package/build/src/sync/local-mutation-log.js +404 -0
  61. package/build/src/sync/offline-grant.d.ts +157 -0
  62. package/build/src/sync/offline-grant.d.ts.map +1 -0
  63. package/build/src/sync/offline-grant.js +292 -0
  64. package/build/sync/device-identity.js +503 -0
  65. package/build/sync/local-mutation-log.js +448 -0
  66. package/build/sync/offline-grant.js +327 -0
  67. package/build/tsconfig.tsbuildinfo +1 -1
  68. package/package.json +3 -3
  69. package/src/configuration-types.js +38 -1
  70. package/src/configuration.js +41 -1
  71. package/src/database/drivers/base.js +51 -3
  72. package/src/database/drivers/mysql/index.js +74 -7
  73. package/src/database/drivers/sqlite/connection-sql-js.js +16 -5
  74. package/src/database/drivers/sqlite/index.web.js +29 -15
  75. package/src/database/drivers/sqlite/web-persistence.js +521 -0
  76. package/src/environment-handlers/node/cli/commands/generate/frontend-models.js +63 -0
  77. package/src/frontend-model-controller.js +127 -4
  78. package/src/frontend-model-resource/base-resource.js +5 -1
  79. package/src/frontend-models/base.js +146 -2
  80. package/src/frontend-models/query.js +3 -3
  81. package/src/frontend-models/resource-definition.js +304 -2
  82. package/src/routes/hooks/frontend-model-command-route-hook.js +8 -0
  83. package/src/sync/device-identity.js +503 -0
  84. package/src/sync/local-mutation-log.js +448 -0
  85. package/src/sync/offline-grant.js +327 -0
@@ -0,0 +1,454 @@
1
+ // @ts-check
2
+ const ECDSA_P256_SHA256_ALGORITHM = "ECDSA-P256-SHA256";
3
+ const ECDSA_P256_SHA256_SIGNATURE_PREFIX = "ecdsa-p256-sha256-";
4
+ /**
5
+ * JSON Web Key used by the sync signing helpers.
6
+ * @typedef {JsonWebKey} SyncJsonWebKey
7
+ */
8
+ /**
9
+ * Backend-signed device certificate payload.
10
+ * @typedef {object} DeviceCertificatePayload
11
+ * @property {string} actorDeviceId - Device id allowed to sign mutations.
12
+ * @property {string} actorUserId - User id represented by the device.
13
+ * @property {string} certificateId - Certificate id.
14
+ * @property {SyncJsonWebKey} devicePublicKey - Device public key peers/backends use to verify mutations.
15
+ * @property {string} expiresAt - ISO timestamp after which the certificate is invalid.
16
+ * @property {string} issuedAt - ISO timestamp when the backend issued the certificate.
17
+ */
18
+ /**
19
+ * Backend-signed device certificate envelope.
20
+ * @typedef {object} DeviceCertificate
21
+ * @property {"ECDSA-P256-SHA256"} algorithm - Signature algorithm.
22
+ * @property {DeviceCertificatePayload} certificate - Certificate payload.
23
+ * @property {string} signature - Backend signature over the certificate payload.
24
+ */
25
+ /**
26
+ * Sync mutation payload signed by a device.
27
+ * @typedef {object} SyncMutation
28
+ * @property {string} actorDeviceId - Device that signed the mutation.
29
+ * @property {string} actorUserId - User represented by the signing device.
30
+ * @property {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} [attributes] - Model attributes for CRUD mutations.
31
+ * @property {string | number | null} [baseVersion] - Base server/client version.
32
+ * @property {string} clientMutationId - Device-local idempotency id.
33
+ * @property {string} [command] - Domain command name for command mutations.
34
+ * @property {string} model - Sync model/resource name.
35
+ * @property {string} occurredAt - ISO timestamp when the mutation occurred.
36
+ * @property {string} offlineGrantId - Offline grant id authorizing the mutation.
37
+ * @property {string} operation - CRUD operation or command operation.
38
+ * @property {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} [payload] - Domain command payload.
39
+ * @property {string} policyHash - Sync policy hash the mutation was checked against.
40
+ */
41
+ /**
42
+ * Device-signed mutation envelope.
43
+ * @typedef {object} SignedSyncMutation
44
+ * @property {"ECDSA-P256-SHA256"} algorithm - Signature algorithm.
45
+ * @property {DeviceCertificate} deviceCertificate - Backend-signed device certificate.
46
+ * @property {SyncMutation} mutation - Mutation payload.
47
+ * @property {string} signature - Device signature over the mutation envelope.
48
+ */
49
+ /**
50
+ * Generates an ECDSA P-256 keypair exported as JWKs.
51
+ * @returns {Promise<{privateKey: SyncJsonWebKey, publicKey: SyncJsonWebKey}>} - Exported keypair.
52
+ */
53
+ export async function generateSyncSigningKeyPair() {
54
+ const keyPair = await cryptoSubtle().generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]);
55
+ return {
56
+ privateKey: await cryptoSubtle().exportKey("jwk", keyPair.privateKey),
57
+ publicKey: await cryptoSubtle().exportKey("jwk", keyPair.publicKey)
58
+ };
59
+ }
60
+ /**
61
+ * Creates a backend-signed device certificate.
62
+ * @param {object} args - Arguments.
63
+ * @param {SyncJsonWebKey} args.backendPrivateKey - Backend private signing key.
64
+ * @param {DeviceCertificatePayload} args.certificate - Certificate payload.
65
+ * @returns {Promise<DeviceCertificate>} - Signed certificate.
66
+ */
67
+ export async function createDeviceCertificate({ backendPrivateKey, certificate }) {
68
+ const normalizedCertificate = normalizeDeviceCertificatePayload(certificate);
69
+ return {
70
+ algorithm: ECDSA_P256_SHA256_ALGORITHM,
71
+ certificate: normalizedCertificate,
72
+ signature: await signStableJson({
73
+ privateKey: backendPrivateKey,
74
+ value: deviceCertificateSignatureValue(normalizedCertificate)
75
+ })
76
+ };
77
+ }
78
+ /**
79
+ * Verifies a backend-signed device certificate.
80
+ * @param {object} args - Arguments.
81
+ * @param {SyncJsonWebKey} args.backendPublicKey - Backend public key.
82
+ * @param {DeviceCertificate} args.certificate - Signed certificate.
83
+ * @param {Date} [args.now] - Verification time. Defaults to current time.
84
+ * @returns {Promise<DeviceCertificatePayload>} - Verified certificate payload.
85
+ */
86
+ export async function verifyDeviceCertificate({ backendPublicKey, certificate, now = new Date() }) {
87
+ const normalizedCertificate = normalizeDeviceCertificate(certificate);
88
+ const verified = await verifyStableJsonSignature({
89
+ publicKey: backendPublicKey,
90
+ signature: normalizedCertificate.signature,
91
+ value: deviceCertificateSignatureValue(normalizedCertificate.certificate)
92
+ });
93
+ if (!verified)
94
+ throw new Error("Device certificate signature did not match");
95
+ assertNotExpired({ expiresAt: normalizedCertificate.certificate.expiresAt, label: "Device certificate", now });
96
+ return normalizedCertificate.certificate;
97
+ }
98
+ /**
99
+ * Creates a device-signed mutation envelope.
100
+ * @param {object} args - Arguments.
101
+ * @param {DeviceCertificate} args.deviceCertificate - Backend-signed device certificate.
102
+ * @param {SyncJsonWebKey} args.devicePrivateKey - Device private signing key.
103
+ * @param {SyncMutation} args.mutation - Mutation payload.
104
+ * @returns {Promise<SignedSyncMutation>} - Signed mutation.
105
+ */
106
+ export async function createSignedMutation({ deviceCertificate, devicePrivateKey, mutation }) {
107
+ const normalizedDeviceCertificate = normalizeDeviceCertificate(deviceCertificate);
108
+ const normalizedMutation = normalizeSyncMutation(mutation);
109
+ assertMutationMatchesCertificate({ certificate: normalizedDeviceCertificate.certificate, mutation: normalizedMutation });
110
+ return {
111
+ algorithm: ECDSA_P256_SHA256_ALGORITHM,
112
+ deviceCertificate: normalizedDeviceCertificate,
113
+ mutation: normalizedMutation,
114
+ signature: await signStableJson({
115
+ privateKey: devicePrivateKey,
116
+ value: signedMutationSignatureValue({
117
+ deviceCertificate: normalizedDeviceCertificate,
118
+ mutation: normalizedMutation
119
+ })
120
+ })
121
+ };
122
+ }
123
+ /**
124
+ * Verifies a signed sync mutation and its device certificate.
125
+ * @param {object} args - Arguments.
126
+ * @param {SyncJsonWebKey} args.backendPublicKey - Backend public key used to verify the device certificate.
127
+ * @param {Date} [args.now] - Verification time. Defaults to current time.
128
+ * @param {SignedSyncMutation} args.signedMutation - Signed mutation envelope.
129
+ * @returns {Promise<SyncMutation>} - Verified mutation payload.
130
+ */
131
+ export async function verifySignedMutation({ backendPublicKey, now = new Date(), signedMutation }) {
132
+ const normalizedSignedMutation = normalizeSignedSyncMutation(signedMutation);
133
+ const certificatePayload = await verifyDeviceCertificate({
134
+ backendPublicKey,
135
+ certificate: normalizedSignedMutation.deviceCertificate,
136
+ now
137
+ });
138
+ assertMutationMatchesCertificate({ certificate: certificatePayload, mutation: normalizedSignedMutation.mutation });
139
+ const verified = await verifyStableJsonSignature({
140
+ publicKey: certificatePayload.devicePublicKey,
141
+ signature: normalizedSignedMutation.signature,
142
+ value: signedMutationSignatureValue({
143
+ deviceCertificate: normalizedSignedMutation.deviceCertificate,
144
+ mutation: normalizedSignedMutation.mutation
145
+ })
146
+ });
147
+ if (!verified)
148
+ throw new Error("Sync mutation signature did not match");
149
+ return normalizedSignedMutation.mutation;
150
+ }
151
+ /**
152
+ * Returns the replay/idempotency key for a signed mutation.
153
+ * @param {{mutation: {actorDeviceId?: unknown, actorUserId?: unknown, clientMutationId?: unknown}}} signedMutation - Signed mutation-like object.
154
+ * @returns {string} - Idempotency key.
155
+ */
156
+ export function mutationIdempotencyKey(signedMutation) {
157
+ const mutation = signedMutation.mutation;
158
+ return [
159
+ requiredString(mutation.actorUserId, "actorUserId"),
160
+ requiredString(mutation.actorDeviceId, "actorDeviceId"),
161
+ requiredString(mutation.clientMutationId, "clientMutationId")
162
+ ].join(":");
163
+ }
164
+ /**
165
+ * Builds the stable value signed by backend device certificates.
166
+ * @param {DeviceCertificatePayload} certificate - Certificate payload.
167
+ * @returns {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} - Stable signature value.
168
+ */
169
+ function deviceCertificateSignatureValue(certificate) {
170
+ return {
171
+ algorithm: ECDSA_P256_SHA256_ALGORITHM,
172
+ certificate: /** @type {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} */ (deterministicJsonObject({ label: "certificate", value: certificate }))
173
+ };
174
+ }
175
+ /**
176
+ * Builds the stable value signed by sync mutations.
177
+ * @param {object} args - Arguments.
178
+ * @param {DeviceCertificate} args.deviceCertificate - Device certificate.
179
+ * @param {SyncMutation} args.mutation - Mutation payload.
180
+ * @returns {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} - Stable signature value.
181
+ */
182
+ function signedMutationSignatureValue({ deviceCertificate, mutation }) {
183
+ return {
184
+ algorithm: ECDSA_P256_SHA256_ALGORITHM,
185
+ deviceCertificate: /** @type {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} */ (deterministicJsonObject({ label: "deviceCertificate", value: deviceCertificate })),
186
+ mutation: /** @type {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} */ (deterministicJsonObject({ label: "mutation", value: mutation }))
187
+ };
188
+ }
189
+ /**
190
+ * Signs a deterministic JSON value with ECDSA P-256/SHA-256.
191
+ * @param {object} args - Arguments.
192
+ * @param {SyncJsonWebKey} args.privateKey - Private JWK.
193
+ * @param {unknown} args.value - Value to sign.
194
+ * @returns {Promise<string>} - Prefixed base64url signature.
195
+ */
196
+ async function signStableJson({ privateKey, value }) {
197
+ const key = await cryptoSubtle().importKey("jwk", privateKey, { name: "ECDSA", namedCurve: "P-256" }, false, ["sign"]);
198
+ const signature = await cryptoSubtle().sign({ hash: "SHA-256", name: "ECDSA" }, key, /** @type {BufferSource} */ (utf8(stableJsonStringify(value))));
199
+ return `${ECDSA_P256_SHA256_SIGNATURE_PREFIX}${base64UrlEncode(new Uint8Array(signature))}`;
200
+ }
201
+ /**
202
+ * Verifies a deterministic JSON value with ECDSA P-256/SHA-256.
203
+ * @param {object} args - Arguments.
204
+ * @param {SyncJsonWebKey} args.publicKey - Public JWK.
205
+ * @param {string} args.signature - Prefixed base64url signature.
206
+ * @param {unknown} args.value - Value to verify.
207
+ * @returns {Promise<boolean>} - Whether the signature matches.
208
+ */
209
+ async function verifyStableJsonSignature({ publicKey, signature, value }) {
210
+ const key = await cryptoSubtle().importKey("jwk", publicKey, { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"]);
211
+ const signatureBytes = base64UrlDecode(signatureWithoutPrefix(signature));
212
+ return await cryptoSubtle().verify({ hash: "SHA-256", name: "ECDSA" }, key, /** @type {BufferSource} */ (signatureBytes), /** @type {BufferSource} */ (utf8(stableJsonStringify(value))));
213
+ }
214
+ /**
215
+ * Normalizes a signed device certificate envelope.
216
+ * @param {DeviceCertificate} certificate - Signed certificate.
217
+ * @returns {DeviceCertificate} - Normalized certificate.
218
+ */
219
+ function normalizeDeviceCertificate(certificate) {
220
+ if (!certificate || typeof certificate !== "object" || Array.isArray(certificate))
221
+ throw new Error("Expected device certificate object");
222
+ if (certificate.algorithm !== ECDSA_P256_SHA256_ALGORITHM)
223
+ throw new Error(`Unsupported device certificate algorithm '${String(certificate.algorithm)}'`);
224
+ return {
225
+ algorithm: certificate.algorithm,
226
+ certificate: normalizeDeviceCertificatePayload(certificate.certificate),
227
+ signature: normalizeSignature(certificate.signature, "device certificate signature")
228
+ };
229
+ }
230
+ /**
231
+ * Normalizes a device certificate payload.
232
+ * @param {DeviceCertificatePayload} certificate - Certificate payload.
233
+ * @returns {DeviceCertificatePayload} - Normalized certificate payload.
234
+ */
235
+ function normalizeDeviceCertificatePayload(certificate) {
236
+ if (!certificate || typeof certificate !== "object" || Array.isArray(certificate))
237
+ throw new Error("Expected device certificate payload object");
238
+ return {
239
+ actorDeviceId: requiredString(certificate.actorDeviceId, "actorDeviceId"),
240
+ actorUserId: requiredString(certificate.actorUserId, "actorUserId"),
241
+ certificateId: requiredString(certificate.certificateId, "certificateId"),
242
+ devicePublicKey: normalizeJwk(certificate.devicePublicKey, "devicePublicKey"),
243
+ expiresAt: isoDateString(new Date(requiredString(certificate.expiresAt, "expiresAt")), "expiresAt"),
244
+ issuedAt: isoDateString(new Date(requiredString(certificate.issuedAt, "issuedAt")), "issuedAt")
245
+ };
246
+ }
247
+ /**
248
+ * Normalizes a signed sync mutation envelope.
249
+ * @param {SignedSyncMutation} signedMutation - Signed mutation.
250
+ * @returns {SignedSyncMutation} - Normalized signed mutation.
251
+ */
252
+ function normalizeSignedSyncMutation(signedMutation) {
253
+ if (!signedMutation || typeof signedMutation !== "object" || Array.isArray(signedMutation))
254
+ throw new Error("Expected signed sync mutation object");
255
+ if (signedMutation.algorithm !== ECDSA_P256_SHA256_ALGORITHM)
256
+ throw new Error(`Unsupported sync mutation algorithm '${String(signedMutation.algorithm)}'`);
257
+ return {
258
+ algorithm: signedMutation.algorithm,
259
+ deviceCertificate: normalizeDeviceCertificate(signedMutation.deviceCertificate),
260
+ mutation: normalizeSyncMutation(signedMutation.mutation),
261
+ signature: normalizeSignature(signedMutation.signature, "sync mutation signature")
262
+ };
263
+ }
264
+ /**
265
+ * Normalizes a sync mutation payload.
266
+ * @param {SyncMutation} mutation - Mutation payload.
267
+ * @returns {SyncMutation} - Normalized mutation payload.
268
+ */
269
+ function normalizeSyncMutation(mutation) {
270
+ if (!mutation || typeof mutation !== "object" || Array.isArray(mutation))
271
+ throw new Error("Expected sync mutation object");
272
+ /** @type {SyncMutation} */
273
+ const normalized = {
274
+ actorDeviceId: requiredString(mutation.actorDeviceId, "actorDeviceId"),
275
+ actorUserId: requiredString(mutation.actorUserId, "actorUserId"),
276
+ clientMutationId: requiredString(mutation.clientMutationId, "clientMutationId"),
277
+ model: requiredString(mutation.model, "model"),
278
+ occurredAt: isoDateString(new Date(requiredString(mutation.occurredAt, "occurredAt")), "occurredAt"),
279
+ offlineGrantId: requiredString(mutation.offlineGrantId, "offlineGrantId"),
280
+ operation: requiredString(mutation.operation, "operation"),
281
+ policyHash: requiredString(mutation.policyHash, "policyHash")
282
+ };
283
+ if (mutation.attributes !== undefined)
284
+ normalized.attributes = deterministicJsonObject({ label: "attributes", value: mutation.attributes });
285
+ if (mutation.baseVersion !== undefined)
286
+ normalized.baseVersion = /** @type {string | number | null} */ (deterministicJson({ label: "baseVersion", value: mutation.baseVersion }));
287
+ if (mutation.command !== undefined)
288
+ normalized.command = requiredString(mutation.command, "command");
289
+ if (mutation.payload !== undefined)
290
+ normalized.payload = deterministicJsonObject({ label: "payload", value: mutation.payload });
291
+ return normalized;
292
+ }
293
+ /**
294
+ * Asserts that mutation actor fields match the certificate actor.
295
+ * @param {object} args - Arguments.
296
+ * @param {DeviceCertificatePayload} args.certificate - Device certificate payload.
297
+ * @param {SyncMutation} args.mutation - Mutation payload.
298
+ * @returns {void} - No return value.
299
+ */
300
+ function assertMutationMatchesCertificate({ certificate, mutation }) {
301
+ if (mutation.actorDeviceId !== certificate.actorDeviceId || mutation.actorUserId !== certificate.actorUserId) {
302
+ throw new Error("Sync mutation actor does not match device certificate");
303
+ }
304
+ }
305
+ /**
306
+ * Asserts a timestamp is not expired.
307
+ * @param {object} args - Arguments.
308
+ * @param {string} args.expiresAt - Expiry timestamp.
309
+ * @param {string} args.label - Error label.
310
+ * @param {Date} args.now - Verification time.
311
+ * @returns {void} - No return value.
312
+ */
313
+ function assertNotExpired({ expiresAt, label, now }) {
314
+ if (Number.isNaN(now.getTime()))
315
+ throw new Error("Invalid sync verification time");
316
+ if (new Date(expiresAt).getTime() <= now.getTime())
317
+ throw new Error(`${label} expired`);
318
+ }
319
+ /**
320
+ * Normalizes a JSON Web Key object.
321
+ * @param {SyncJsonWebKey} key - JWK.
322
+ * @param {string} label - Key label.
323
+ * @returns {SyncJsonWebKey} - Normalized JWK.
324
+ */
325
+ function normalizeJwk(key, label) {
326
+ const normalized = deterministicJsonObject({ label, value: key });
327
+ return /** @type {SyncJsonWebKey} */ (normalized);
328
+ }
329
+ /**
330
+ * Normalizes a prefixed signature string.
331
+ * @param {unknown} signature - Signature value.
332
+ * @param {string} label - Error label.
333
+ * @returns {string} - Signature string.
334
+ */
335
+ function normalizeSignature(signature, label) {
336
+ if (typeof signature !== "string" || !signature.startsWith(ECDSA_P256_SHA256_SIGNATURE_PREFIX))
337
+ throw new Error(`Expected ${label}`);
338
+ return signature;
339
+ }
340
+ /**
341
+ * Removes the signature prefix.
342
+ * @param {string} signature - Prefixed signature.
343
+ * @returns {string} - Base64url signature body.
344
+ */
345
+ function signatureWithoutPrefix(signature) {
346
+ return signature.slice(ECDSA_P256_SHA256_SIGNATURE_PREFIX.length);
347
+ }
348
+ /**
349
+ * Requires a non-empty string field.
350
+ * @param {unknown} value - Value.
351
+ * @param {string} name - Field name.
352
+ * @returns {string} - String value.
353
+ */
354
+ function requiredString(value, name) {
355
+ if (typeof value !== "string" || value.length < 1)
356
+ throw new Error(`Expected sync ${name}`);
357
+ return value;
358
+ }
359
+ /**
360
+ * Normalizes a Date to an ISO timestamp.
361
+ * @param {Date} date - Date value.
362
+ * @param {string} label - Field label.
363
+ * @returns {string} - ISO timestamp.
364
+ */
365
+ function isoDateString(date, label) {
366
+ if (Number.isNaN(date.getTime()))
367
+ throw new Error(`Invalid sync ${label}`);
368
+ return date.toISOString();
369
+ }
370
+ /**
371
+ * Returns encoded UTF-8 bytes for a string.
372
+ * @param {string} value - String value.
373
+ * @returns {Uint8Array} - UTF-8 bytes.
374
+ */
375
+ function utf8(value) {
376
+ return new TextEncoder().encode(value);
377
+ }
378
+ /**
379
+ * Returns WebCrypto subtle API.
380
+ * @returns {SubtleCrypto} - SubtleCrypto implementation.
381
+ */
382
+ function cryptoSubtle() {
383
+ if (!globalThis.crypto?.subtle)
384
+ throw new Error("WebCrypto subtle API is required for sync signing");
385
+ return globalThis.crypto.subtle;
386
+ }
387
+ /**
388
+ * Base64url-encodes bytes.
389
+ * @param {Uint8Array} bytes - Bytes.
390
+ * @returns {string} - Base64url string.
391
+ */
392
+ function base64UrlEncode(bytes) {
393
+ let binary = "";
394
+ for (const byte of bytes)
395
+ binary += String.fromCharCode(byte);
396
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
397
+ }
398
+ /**
399
+ * Base64url-decodes bytes.
400
+ * @param {string} value - Base64url string.
401
+ * @returns {Uint8Array} - Bytes.
402
+ */
403
+ function base64UrlDecode(value) {
404
+ const base64 = value.replaceAll("-", "+").replaceAll("_", "/").padEnd(Math.ceil(value.length / 4) * 4, "=");
405
+ const binary = atob(base64);
406
+ return Uint8Array.from(binary, (char) => char.charCodeAt(0));
407
+ }
408
+ /**
409
+ * Stable JSON stringifier with sorted object keys.
410
+ * @param {unknown} value - Value.
411
+ * @returns {string} - JSON string.
412
+ */
413
+ function stableJsonStringify(value) {
414
+ return JSON.stringify(deterministicJson({ label: "root", value }));
415
+ }
416
+ /**
417
+ * Normalizes a value as a JSON object.
418
+ * @param {object} args - Arguments.
419
+ * @param {string} args.label - Diagnostic label.
420
+ * @param {unknown} args.value - Value.
421
+ * @returns {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} - JSON object.
422
+ */
423
+ function deterministicJsonObject({ label, value }) {
424
+ const normalized = deterministicJson({ label, value });
425
+ if (!normalized || typeof normalized !== "object" || Array.isArray(normalized))
426
+ throw new Error(`Expected sync ${label} object`);
427
+ return /** @type {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} */ (normalized);
428
+ }
429
+ /**
430
+ * Normalizes deterministic JSON with sorted object keys.
431
+ * @param {object} args - Arguments.
432
+ * @param {string} args.label - Diagnostic label.
433
+ * @param {unknown} args.value - Value.
434
+ * @returns {import("../configuration-types.js").FrontendModelSyncJsonValue} - Normalized JSON value.
435
+ */
436
+ function deterministicJson({ label, value }) {
437
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean")
438
+ return value;
439
+ if (Array.isArray(value))
440
+ return value.map((entry, index) => deterministicJson({ label: `${label}/${index}`, value: entry }));
441
+ if (value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
442
+ /** @type {Record<string, import("../configuration-types.js").FrontendModelSyncJsonValue>} */
443
+ const normalized = {};
444
+ for (const key of Object.keys(value).sort()) {
445
+ const childValue = /** @type {Record<string, unknown>} */ (value)[key];
446
+ if (childValue === undefined)
447
+ continue;
448
+ normalized[key] = deterministicJson({ label: `${label}/${key}`, value: childValue });
449
+ }
450
+ return normalized;
451
+ }
452
+ throw new Error(`Sync ${label} must be deterministic JSON`);
453
+ }
454
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV2aWNlLWlkZW50aXR5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3N5bmMvZGV2aWNlLWlkZW50aXR5LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixNQUFNLDJCQUEyQixHQUFHLG1CQUFtQixDQUFBO0FBQ3ZELE1BQU0sa0NBQWtDLEdBQUcsb0JBQW9CLENBQUE7QUFFL0Q7OztHQUdHO0FBRUg7Ozs7Ozs7OztHQVNHO0FBRUg7Ozs7OztHQU1HO0FBRUg7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUg7Ozs7Ozs7R0FPRztBQUVIOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsMEJBQTBCO0lBQzlDLE1BQU0sT0FBTyxHQUFHLE1BQU0sWUFBWSxFQUFFLENBQUMsV0FBVyxDQUM5QyxFQUFDLElBQUksRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBQyxFQUNwQyxJQUFJLEVBQ0osQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQ25CLENBQUE7SUFFRCxPQUFPO1FBQ0wsVUFBVSxFQUFFLE1BQU0sWUFBWSxFQUFFLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsVUFBVSxDQUFDO1FBQ3JFLFNBQVMsRUFBRSxNQUFNLFlBQVksRUFBRSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLFNBQVMsQ0FBQztLQUNwRSxDQUFBO0FBQ0gsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsdUJBQXVCLENBQUMsRUFBQyxpQkFBaUIsRUFBRSxXQUFXLEVBQUM7SUFDNUUsTUFBTSxxQkFBcUIsR0FBRyxpQ0FBaUMsQ0FBQyxXQUFXLENBQUMsQ0FBQTtJQUU1RSxPQUFPO1FBQ0wsU0FBUyxFQUFFLDJCQUEyQjtRQUN0QyxXQUFXLEVBQUUscUJBQXFCO1FBQ2xDLFNBQVMsRUFBRSxNQUFNLGNBQWMsQ0FBQztZQUM5QixVQUFVLEVB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QU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQztZQUM1QyxNQUFNLFVBQVUsR0FBRyxzQ0FBc0MsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBRXRFLElBQUksVUFBVSxLQUFLLFNBQVM7Z0JBQUUsU0FBUTtZQUN0QyxVQUFVLENBQUMsR0FBRyxDQUFDLEdBQUcsaUJBQWlCLENBQUMsRUFBQyxLQUFLLEVBQUUsR0FBRyxLQUFLLElBQUksR0FBRyxFQUFFLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBQyxDQUFDLENBQUE7UUFDcEYsQ0FBQztRQUVELE9BQU8sVUFBVSxDQUFBO0lBQ25CLENBQUM7SUFFRCxNQUFNLElBQUksS0FBSyxDQUFDLFFBQVEsS0FBSyw2QkFBNkIsQ0FBQyxDQUFBO0FBQzdELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuY29uc3QgRUNEU0FfUDI1Nl9TSEEyNTZfQUxHT1JJVEhNID0gXCJFQ0RTQS1QMjU2LVNIQTI1NlwiXG5jb25zdCBFQ0RTQV9QMjU2X1NIQTI1Nl9TSUdOQVRVUkVfUFJFRklYID0gXCJlY2RzYS1wMjU2LXNoYTI1Ni1cIlxuXG4vKipcbiAqIEpTT04gV2ViIEtleSB1c2VkIGJ5IHRoZSBzeW5jIHNpZ25pbmcgaGVscGVycy5cbiAqIEB0eXBlZGVmIHtKc29uV2ViS2V5fSBTeW5jSnNvbldlYktleVxuICovXG5cbi8qKlxuICogQmFja2VuZC1zaWduZWQgZGV2aWNlIGNlcnRpZmljYXRlIHBheWxvYWQuXG4gKiBAdHlwZWRlZiB7b2JqZWN0fSBEZXZpY2VDZXJ0aWZpY2F0ZVBheWxvYWRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBhY3RvckRldmljZUlkIC0gRGV2aWNlIGlkIGFsbG93ZWQgdG8gc2lnbiBtdXRhdGlvbnMuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gYWN0b3JVc2VySWQgLSBVc2VyIGlkIHJlcHJlc2VudGVkIGJ5IHRoZSBkZXZpY2UuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gY2VydGlmaWNhdGVJZCAtIENlcnRpZmljYXRlIGlkLlxuICogQHByb3BlcnR5IHtTeW5jSnNvbldlYktleX0gZGV2aWNlUHVibGljS2V5IC0gRGV2aWNlIHB1YmxpYyBrZXkgcGVlcnMvYmFja2VuZHMgdXNlIHRvIHZlcmlmeSBtdXRhdGlvbnMuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gZXhwaXJlc0F0IC0gSVNPIHRpbWVzdGFtcCBhZnRlciB3aGljaCB0aGUgY2VydGlmaWNhdGUgaXMgaW52YWxpZC5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBpc3N1ZWRBdCAtIElTTyB0aW1lc3RhbXAgd2hlbiB0aGUgYmFja2VuZCBpc3N1ZWQgdGhlIGNlcnRpZmljYXRlLlxuICovXG5cbi8qKlxuICogQmFja2VuZC1zaWduZWQgZGV2aWNlIGNlcnRpZmljYXRlIGVudmVsb3BlLlxuICogQHR5cGVkZWYge29iamVjdH0gRGV2aWNlQ2VydGlmaWNhdGVcbiAqIEBwcm9wZXJ0eSB7XCJFQ0RTQS1QMjU2LVNIQTI1NlwifSBhbGdvcml0aG0gLSBTaWduYXR1cmUgYWxnb3JpdGhtLlxuICogQHByb3BlcnR5IHtEZXZpY2VDZXJ0aWZpY2F0ZVBheWxvYWR9IGNlcnRpZmljYXRlIC0gQ2VydGlmaWNhdGUgcGF5bG9hZC5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBzaWduYXR1cmUgLSBCYWNrZW5kIHNpZ25hdHVyZSBvdmVyIHRoZSBjZXJ0aWZpY2F0ZSBwYXlsb2FkLlxuICovXG5cbi8qKlxuICogU3luYyBtdXRhdGlvbiBwYXlsb2FkIHNpZ25lZCBieSBhIGRldmljZS5cbiAqIEB0eXBlZGVmIHtvYmplY3R9IFN5bmNNdXRhdGlvblxuICogQHByb3BlcnR5IHtzdHJpbmd9IGFjdG9yRGV2aWNlSWQgLSBEZXZpY2UgdGhhdCBzaWduZWQgdGhlIG11dGF0aW9uLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGFjdG9yVXNlcklkIC0gVXNlciByZXByZXNlbnRlZCBieSB0aGUgc2lnbmluZyBkZXZpY2UuXG4gKiBAcHJvcGVydHkge1JlY29yZDxzdHJpbmcsIGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuRnJvbnRlbmRNb2RlbFN5bmNKc29uVmFsdWU+fSBbYXR0cmlidXRlc10gLSBNb2RlbCBhdHRyaWJ1dGVzIGZvciBDUlVEIG11dGF0aW9ucy5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nIHwgbnVtYmVyIHwgbnVsbH0gW2Jhc2VWZXJzaW9uXSAtIEJhc2Ugc2VydmVyL2NsaWVudCB2ZXJzaW9uLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGNsaWVudE11dGF0aW9uSWQgLSBEZXZpY2UtbG9jYWwgaWRlbXBvdGVuY3kgaWQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gW2NvbW1hbmRdIC0gRG9tYWluIGNvbW1hbmQgbmFtZSBmb3IgY29tbWFuZCBtdXRhdGlvbnMuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gbW9kZWwgLSBTeW5jIG1vZGVsL3Jlc291cmNlIG5hbWUuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gb2NjdXJyZWRBdCAtIElTTyB0aW1lc3RhbXAgd2hlbiB0aGUgbXV0YXRpb24gb2NjdXJyZWQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gb2ZmbGluZUdyYW50SWQgLSBPZmZsaW5lIGdyYW50IGlkIGF1dGhvcml6aW5nIHRoZSBtdXRhdGlvbi5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBvcGVyYXRpb24gLSBDUlVEIG9wZXJhdGlvbiBvciBjb21tYW5kIG9wZXJhdGlvbi5cbiAqIEBwcm9wZXJ0eSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59IFtwYXlsb2FkXSAtIERvbWFpbiBjb21tYW5kIHBheWxvYWQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gcG9saWN5SGFzaCAtIFN5bmMgcG9saWN5IGhhc2ggdGhlIG11dGF0aW9uIHdhcyBjaGVja2VkIGFnYWluc3QuXG4gKi9cblxuLyoqXG4gKiBEZXZpY2Utc2lnbmVkIG11dGF0aW9uIGVudmVsb3BlLlxuICogQHR5cGVkZWYge29iamVjdH0gU2lnbmVkU3luY011dGF0aW9uXG4gKiBAcHJvcGVydHkge1wiRUNEU0EtUDI1Ni1TSEEyNTZcIn0gYWxnb3JpdGhtIC0gU2lnbmF0dXJlIGFsZ29yaXRobS5cbiAqIEBwcm9wZXJ0eSB7RGV2aWNlQ2VydGlmaWNhdGV9IGRldmljZUNlcnRpZmljYXRlIC0gQmFja2VuZC1zaWduZWQgZGV2aWNlIGNlcnRpZmljYXRlLlxuICogQHByb3BlcnR5IHtTeW5jTXV0YXRpb259IG11dGF0aW9uIC0gTXV0YXRpb24gcGF5bG9hZC5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBzaWduYXR1cmUgLSBEZXZpY2Ugc2lnbmF0dXJlIG92ZXIgdGhlIG11dGF0aW9uIGVudmVsb3BlLlxuICovXG5cbi8qKlxuICogR2VuZXJhdGVzIGFuIEVDRFNBIFAtMjU2IGtleXBhaXIgZXhwb3J0ZWQgYXMgSldLcy5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHtwcml2YXRlS2V5OiBTeW5jSnNvbldlYktleSwgcHVibGljS2V5OiBTeW5jSnNvbldlYktleX0+fSAtIEV4cG9ydGVkIGtleXBhaXIuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZW5lcmF0ZVN5bmNTaWduaW5nS2V5UGFpcigpIHtcbiAgY29uc3Qga2V5UGFpciA9IGF3YWl0IGNyeXB0b1N1YnRsZSgpLmdlbmVyYXRlS2V5KFxuICAgIHtuYW1lOiBcIkVDRFNBXCIsIG5hbWVkQ3VydmU6IFwiUC0yNTZcIn0sXG4gICAgdHJ1ZSxcbiAgICBbXCJzaWduXCIsIFwidmVyaWZ5XCJdXG4gIClcblxuICByZXR1cm4ge1xuICAgIHByaXZhdGVLZXk6IGF3YWl0IGNyeXB0b1N1YnRsZSgpLmV4cG9ydEtleShcImp3a1wiLCBrZXlQYWlyLnByaXZhdGVLZXkpLFxuICAgIHB1YmxpY0tleTogYXdhaXQgY3J5cHRvU3VidGxlKCkuZXhwb3J0S2V5KFwiandrXCIsIGtleVBhaXIucHVibGljS2V5KVxuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIGJhY2tlbmQtc2lnbmVkIGRldmljZSBjZXJ0aWZpY2F0ZS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtTeW5jSnNvbldlYktleX0gYXJncy5iYWNrZW5kUHJpdmF0ZUtleSAtIEJhY2tlbmQgcHJpdmF0ZSBzaWduaW5nIGtleS5cbiAqIEBwYXJhbSB7RGV2aWNlQ2VydGlmaWNhdGVQYXlsb2FkfSBhcmdzLmNlcnRpZmljYXRlIC0gQ2VydGlmaWNhdGUgcGF5bG9hZC5cbiAqIEByZXR1cm5zIHtQcm9taXNlPERldmljZUNlcnRpZmljYXRlPn0gLSBTaWduZWQgY2VydGlmaWNhdGUuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVEZXZpY2VDZXJ0aWZpY2F0ZSh7YmFja2VuZFByaXZhdGVLZXksIGNlcnRpZmljYXRlfSkge1xuICBjb25zdCBub3JtYWxpemVkQ2VydGlmaWNhdGUgPSBub3JtYWxpemVEZXZpY2VDZXJ0aWZpY2F0ZVBheWxvYWQoY2VydGlmaWNhdGUpXG5cbiAgcmV0dXJuIHtcbiAgICBhbGdvcml0aG06IEVDRFNBX1AyNTZfU0hBMjU2X0FMR09SSVRITSxcbiAgICBjZXJ0aWZpY2F0ZTogbm9ybWFsaXplZENlcnRpZmljYXRlLFxuICAgIHNpZ25hdHVyZTogYXdhaXQgc2lnblN0YWJsZUpzb24oe1xuICAgICAgcHJpdmF0ZUtleTogYmFja2VuZFByaXZhdGVLZXksXG4gICAgICB2YWx1ZTogZGV2aWNlQ2VydGlmaWNhdGVTaWduYXR1cmVWYWx1ZShub3JtYWxpemVkQ2VydGlmaWNhdGUpXG4gICAgfSlcbiAgfVxufVxuXG4vKipcbiAqIFZlcmlmaWVzIGEgYmFja2VuZC1zaWduZWQgZGV2aWNlIGNlcnRpZmljYXRlLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBBcmd1bWVudHMuXG4gKiBAcGFyYW0ge1N5bmNKc29uV2ViS2V5fSBhcmdzLmJhY2tlbmRQdWJsaWNLZXkgLSBCYWNrZW5kIHB1YmxpYyBrZXkuXG4gKiBAcGFyYW0ge0RldmljZUNlcnRpZmljYXRlfSBhcmdzLmNlcnRpZmljYXRlIC0gU2lnbmVkIGNlcnRpZmljYXRlLlxuICogQHBhcmFtIHtEYXRlfSBbYXJncy5ub3ddIC0gVmVyaWZpY2F0aW9uIHRpbWUuIERlZmF1bHRzIHRvIGN1cnJlbnQgdGltZS5cbiAqIEByZXR1cm5zIHtQcm9taXNlPERldmljZUNlcnRpZmljYXRlUGF5bG9hZD59IC0gVmVyaWZpZWQgY2VydGlmaWNhdGUgcGF5bG9hZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHZlcmlmeURldmljZUNlcnRpZmljYXRlKHtiYWNrZW5kUHVibGljS2V5LCBjZXJ0aWZpY2F0ZSwgbm93ID0gbmV3IERhdGUoKX0pIHtcbiAgY29uc3Qgbm9ybWFsaXplZENlcnRpZmljYXRlID0gbm9ybWFsaXplRGV2aWNlQ2VydGlmaWNhdGUoY2VydGlmaWNhdGUpXG4gIGNvbnN0IHZlcmlmaWVkID0gYXdhaXQgdmVyaWZ5U3RhYmxlSnNvblNpZ25hdHVyZSh7XG4gICAgcHVibGljS2V5OiBiYWNrZW5kUHVibGljS2V5LFxuICAgIHNpZ25hdHVyZTogbm9ybWFsaXplZENlcnRpZmljYXRlLnNpZ25hdHVyZSxcbiAgICB2YWx1ZTogZGV2aWNlQ2VydGlmaWNhdGVTaWduYXR1cmVWYWx1ZShub3JtYWxpemVkQ2VydGlmaWNhdGUuY2VydGlmaWNhdGUpXG4gIH0pXG5cbiAgaWYgKCF2ZXJpZmllZCkgdGhyb3cgbmV3IEVycm9yKFwiRGV2aWNlIGNlcnRpZmljYXRlIHNpZ25hdHVyZSBkaWQgbm90IG1hdGNoXCIpXG4gIGFzc2VydE5vdEV4cGlyZWQoe2V4cGlyZXNBdDogbm9ybWFsaXplZENlcnRpZmljYXRlLmNlcnRpZmljYXRlLmV4cGlyZXNBdCwgbGFiZWw6IFwiRGV2aWNlIGNlcnRpZmljYXRlXCIsIG5vd30pXG5cbiAgcmV0dXJuIG5vcm1hbGl6ZWRDZXJ0aWZpY2F0ZS5jZXJ0aWZpY2F0ZVxufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBkZXZpY2Utc2lnbmVkIG11dGF0aW9uIGVudmVsb3BlLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBBcmd1bWVudHMuXG4gKiBAcGFyYW0ge0RldmljZUNlcnRpZmljYXRlfSBhcmdzLmRldmljZUNlcnRpZmljYXRlIC0gQmFja2VuZC1zaWduZWQgZGV2aWNlIGNlcnRpZmljYXRlLlxuICogQHBhcmFtIHtTeW5jSnNvbldlYktleX0gYXJncy5kZXZpY2VQcml2YXRlS2V5IC0gRGV2aWNlIHByaXZhdGUgc2lnbmluZyBrZXkuXG4gKiBAcGFyYW0ge1N5bmNNdXRhdGlvbn0gYXJncy5tdXRhdGlvbiAtIE11dGF0aW9uIHBheWxvYWQuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxTaWduZWRTeW5jTXV0YXRpb24+fSAtIFNpZ25lZCBtdXRhdGlvbi5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZVNpZ25lZE11dGF0aW9uKHtkZXZpY2VDZXJ0aWZpY2F0ZSwgZGV2aWNlUHJpdmF0ZUtleSwgbXV0YXRpb259KSB7XG4gIGNvbnN0IG5vcm1hbGl6ZWREZXZpY2VDZXJ0aWZpY2F0ZSA9IG5vcm1hbGl6ZURldmljZUNlcnRpZmljYXRlKGRldmljZUNlcnRpZmljYXRlKVxuICBjb25zdCBub3JtYWxpemVkTXV0YXRpb24gPSBub3JtYWxpemVTeW5jTXV0YXRpb24obXV0YXRpb24pXG5cbiAgYXNzZXJ0TXV0YXRpb25NYXRjaGVzQ2VydGlmaWNhdGUoe2NlcnRpZmljYXRlOiBub3JtYWxpemVkRGV2aWNlQ2VydGlmaWNhdGUuY2VydGlmaWNhdGUsIG11dGF0aW9uOiBub3JtYWxpemVkTXV0YXRpb259KVxuXG4gIHJldHVybiB7XG4gICAgYWxnb3JpdGhtOiBFQ0RTQV9QMjU2X1NIQTI1Nl9BTEdPUklUSE0sXG4gICAgZGV2aWNlQ2VydGlmaWNhdGU6IG5vcm1hbGl6ZWREZXZpY2VDZXJ0aWZpY2F0ZSxcbiAgICBtdXRhdGlvbjogbm9ybWFsaXplZE11dGF0aW9uLFxuICAgIHNpZ25hdHVyZTogYXdhaXQgc2lnblN0YWJsZUpzb24oe1xuICAgICAgcHJpdmF0ZUtleTogZGV2aWNlUHJpdmF0ZUtleSxcbiAgICAgIHZhbHVlOiBzaWduZWRNdXRhdGlvblNpZ25hdHVyZVZhbHVlKHtcbiAgICAgICAgZGV2aWNlQ2VydGlmaWNhdGU6IG5vcm1hbGl6ZWREZXZpY2VDZXJ0aWZpY2F0ZSxcbiAgICAgICAgbXV0YXRpb246IG5vcm1hbGl6ZWRNdXRhdGlvblxuICAgICAgfSlcbiAgICB9KVxuICB9XG59XG5cbi8qKlxuICogVmVyaWZpZXMgYSBzaWduZWQgc3luYyBtdXRhdGlvbiBhbmQgaXRzIGRldmljZSBjZXJ0aWZpY2F0ZS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtTeW5jSnNvbldlYktleX0gYXJncy5iYWNrZW5kUHVibGljS2V5IC0gQmFja2VuZCBwdWJsaWMga2V5IHVzZWQgdG8gdmVyaWZ5IHRoZSBkZXZpY2UgY2VydGlmaWNhdGUuXG4gKiBAcGFyYW0ge0RhdGV9IFthcmdzLm5vd10gLSBWZXJpZmljYXRpb24gdGltZS4gRGVmYXVsdHMgdG8gY3VycmVudCB0aW1lLlxuICogQHBhcmFtIHtTaWduZWRTeW5jTXV0YXRpb259IGFyZ3Muc2lnbmVkTXV0YXRpb24gLSBTaWduZWQgbXV0YXRpb24gZW52ZWxvcGUuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxTeW5jTXV0YXRpb24+fSAtIFZlcmlmaWVkIG11dGF0aW9uIHBheWxvYWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB2ZXJpZnlTaWduZWRNdXRhdGlvbih7YmFja2VuZFB1YmxpY0tleSwgbm93ID0gbmV3IERhdGUoKSwgc2lnbmVkTXV0YXRpb259KSB7XG4gIGNvbnN0IG5vcm1hbGl6ZWRTaWduZWRNdXRhdGlvbiA9IG5vcm1hbGl6ZVNpZ25lZFN5bmNNdXRhdGlvbihzaWduZWRNdXRhdGlvbilcbiAgY29uc3QgY2VydGlmaWNhdGVQYXlsb2FkID0gYXdhaXQgdmVyaWZ5RGV2aWNlQ2VydGlmaWNhdGUoe1xuICAgIGJhY2tlbmRQdWJsaWNLZXksXG4gICAgY2VydGlmaWNhdGU6IG5vcm1hbGl6ZWRTaWduZWRNdXRhdGlvbi5kZXZpY2VDZXJ0aWZpY2F0ZSxcbiAgICBub3dcbiAgfSlcblxuICBhc3NlcnRNdXRhdGlvbk1hdGNoZXNDZXJ0aWZpY2F0ZSh7Y2VydGlmaWNhdGU6IGNlcnRpZmljYXRlUGF5bG9hZCwgbXV0YXRpb246IG5vcm1hbGl6ZWRTaWduZWRNdXRhdGlvbi5tdXRhdGlvbn0pXG5cbiAgY29uc3QgdmVyaWZpZWQgPSBhd2FpdCB2ZXJpZnlTdGFibGVKc29uU2lnbmF0dXJlKHtcbiAgICBwdWJsaWNLZXk6IGNlcnRpZmljYXRlUGF5bG9hZC5kZXZpY2VQdWJsaWNLZXksXG4gICAgc2lnbmF0dXJlOiBub3JtYWxpemVkU2lnbmVkTXV0YXRpb24uc2lnbmF0dXJlLFxuICAgIHZhbHVlOiBzaWduZWRNdXRhdGlvblNpZ25hdHVyZVZhbHVlKHtcbiAgICAgIGRldmljZUNlcnRpZmljYXRlOiBub3JtYWxpemVkU2lnbmVkTXV0YXRpb24uZGV2aWNlQ2VydGlmaWNhdGUsXG4gICAgICBtdXRhdGlvbjogbm9ybWFsaXplZFNpZ25lZE11dGF0aW9uLm11dGF0aW9uXG4gICAgfSlcbiAgfSlcblxuICBpZiAoIXZlcmlmaWVkKSB0aHJvdyBuZXcgRXJyb3IoXCJTeW5jIG11dGF0aW9uIHNpZ25hdHVyZSBkaWQgbm90IG1hdGNoXCIpXG5cbiAgcmV0dXJuIG5vcm1hbGl6ZWRTaWduZWRNdXRhdGlvbi5tdXRhdGlvblxufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIHJlcGxheS9pZGVtcG90ZW5jeSBrZXkgZm9yIGEgc2lnbmVkIG11dGF0aW9uLlxuICogQHBhcmFtIHt7bXV0YXRpb246IHthY3RvckRldmljZUlkPzogdW5rbm93biwgYWN0b3JVc2VySWQ/OiB1bmtub3duLCBjbGllbnRNdXRhdGlvbklkPzogdW5rbm93bn19fSBzaWduZWRNdXRhdGlvbiAtIFNpZ25lZCBtdXRhdGlvbi1saWtlIG9iamVjdC5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gSWRlbXBvdGVuY3kga2V5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gbXV0YXRpb25JZGVtcG90ZW5jeUtleShzaWduZWRNdXRhdGlvbikge1xuICBjb25zdCBtdXRhdGlvbiA9IHNpZ25lZE11dGF0aW9uLm11dGF0aW9uXG5cbiAgcmV0dXJuIFtcbiAgICByZXF1aXJlZFN0cmluZyhtdXRhdGlvbi5hY3RvclVzZXJJZCwgXCJhY3RvclVzZXJJZFwiKSxcbiAgICByZXF1aXJlZFN0cmluZyhtdXRhdGlvbi5hY3RvckRldmljZUlkLCBcImFjdG9yRGV2aWNlSWRcIiksXG4gICAgcmVxdWlyZWRTdHJpbmcobXV0YXRpb24uY2xpZW50TXV0YXRpb25JZCwgXCJjbGllbnRNdXRhdGlvbklkXCIpXG4gIF0uam9pbihcIjpcIilcbn1cblxuLyoqXG4gKiBCdWlsZHMgdGhlIHN0YWJsZSB2YWx1ZSBzaWduZWQgYnkgYmFja2VuZCBkZXZpY2UgY2VydGlmaWNhdGVzLlxuICogQHBhcmFtIHtEZXZpY2VDZXJ0aWZpY2F0ZVBheWxvYWR9IGNlcnRpZmljYXRlIC0gQ2VydGlmaWNhdGUgcGF5bG9hZC5cbiAqIEByZXR1cm5zIHtSZWNvcmQ8c3RyaW5nLCBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkZyb250ZW5kTW9kZWxTeW5jSnNvblZhbHVlPn0gLSBTdGFibGUgc2lnbmF0dXJlIHZhbHVlLlxuICovXG5mdW5jdGlvbiBkZXZpY2VDZXJ0aWZpY2F0ZVNpZ25hdHVyZVZhbHVlKGNlcnRpZmljYXRlKSB7XG4gIHJldHVybiB7XG4gICAgYWxnb3JpdGhtOiBFQ0RTQV9QMjU2X1NIQTI1Nl9BTEdPUklUSE0sXG4gICAgY2VydGlmaWNhdGU6IC8qKiBAdHlwZSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59ICovIChkZXRlcm1pbmlzdGljSnNvbk9iamVjdCh7bGFiZWw6IFwiY2VydGlmaWNhdGVcIiwgdmFsdWU6IGNlcnRpZmljYXRlfSkpXG4gIH1cbn1cblxuLyoqXG4gKiBCdWlsZHMgdGhlIHN0YWJsZSB2YWx1ZSBzaWduZWQgYnkgc3luYyBtdXRhdGlvbnMuXG4gKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIEFyZ3VtZW50cy5cbiAqIEBwYXJhbSB7RGV2aWNlQ2VydGlmaWNhdGV9IGFyZ3MuZGV2aWNlQ2VydGlmaWNhdGUgLSBEZXZpY2UgY2VydGlmaWNhdGUuXG4gKiBAcGFyYW0ge1N5bmNNdXRhdGlvbn0gYXJncy5tdXRhdGlvbiAtIE11dGF0aW9uIHBheWxvYWQuXG4gKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59IC0gU3RhYmxlIHNpZ25hdHVyZSB2YWx1ZS5cbiAqL1xuZnVuY3Rpb24gc2lnbmVkTXV0YXRpb25TaWduYXR1cmVWYWx1ZSh7ZGV2aWNlQ2VydGlmaWNhdGUsIG11dGF0aW9ufSkge1xuICByZXR1cm4ge1xuICAgIGFsZ29yaXRobTogRUNEU0FfUDI1Nl9TSEEyNTZfQUxHT1JJVEhNLFxuICAgIGRldmljZUNlcnRpZmljYXRlOiAvKiogQHR5cGUge1JlY29yZDxzdHJpbmcsIGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuRnJvbnRlbmRNb2RlbFN5bmNKc29uVmFsdWU+fSAqLyAoZGV0ZXJtaW5pc3RpY0pzb25PYmplY3Qoe2xhYmVsOiBcImRldmljZUNlcnRpZmljYXRlXCIsIHZhbHVlOiBkZXZpY2VDZXJ0aWZpY2F0ZX0pKSxcbiAgICBtdXRhdGlvbjogLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkZyb250ZW5kTW9kZWxTeW5jSnNvblZhbHVlPn0gKi8gKGRldGVybWluaXN0aWNKc29uT2JqZWN0KHtsYWJlbDogXCJtdXRhdGlvblwiLCB2YWx1ZTogbXV0YXRpb259KSlcbiAgfVxufVxuXG4vKipcbiAqIFNpZ25zIGEgZGV0ZXJtaW5pc3RpYyBKU09OIHZhbHVlIHdpdGggRUNEU0EgUC0yNTYvU0hBLTI1Ni5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtTeW5jSnNvbldlYktleX0gYXJncy5wcml2YXRlS2V5IC0gUHJpdmF0ZSBKV0suXG4gKiBAcGFyYW0ge3Vua25vd259IGFyZ3MudmFsdWUgLSBWYWx1ZSB0byBzaWduLlxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gLSBQcmVmaXhlZCBiYXNlNjR1cmwgc2lnbmF0dXJlLlxuICovXG5hc3luYyBmdW5jdGlvbiBzaWduU3RhYmxlSnNvbih7cHJpdmF0ZUtleSwgdmFsdWV9KSB7XG4gIGNvbnN0IGtleSA9IGF3YWl0IGNyeXB0b1N1YnRsZSgpLmltcG9ydEtleShcImp3a1wiLCBwcml2YXRlS2V5LCB7bmFtZTogXCJFQ0RTQVwiLCBuYW1lZEN1cnZlOiBcIlAtMjU2XCJ9LCBmYWxzZSwgW1wic2lnblwiXSlcbiAgY29uc3Qgc2lnbmF0dXJlID0gYXdhaXQgY3J5cHRvU3VidGxlKCkuc2lnbih7aGFzaDogXCJTSEEtMjU2XCIsIG5hbWU6IFwiRUNEU0FcIn0sIGtleSwgLyoqIEB0eXBlIHtCdWZmZXJTb3VyY2V9ICovICh1dGY4KHN0YWJsZUpzb25TdHJpbmdpZnkodmFsdWUpKSkpXG5cbiAgcmV0dXJuIGAke0VDRFNBX1AyNTZfU0hBMjU2X1NJR05BVFVSRV9QUkVGSVh9JHtiYXNlNjRVcmxFbmNvZGUobmV3IFVpbnQ4QXJyYXkoc2lnbmF0dXJlKSl9YFxufVxuXG4vKipcbiAqIFZlcmlmaWVzIGEgZGV0ZXJtaW5pc3RpYyBKU09OIHZhbHVlIHdpdGggRUNEU0EgUC0yNTYvU0hBLTI1Ni5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtTeW5jSnNvbldlYktleX0gYXJncy5wdWJsaWNLZXkgLSBQdWJsaWMgSldLLlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muc2lnbmF0dXJlIC0gUHJlZml4ZWQgYmFzZTY0dXJsIHNpZ25hdHVyZS5cbiAqIEBwYXJhbSB7dW5rbm93bn0gYXJncy52YWx1ZSAtIFZhbHVlIHRvIHZlcmlmeS5cbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSAtIFdoZXRoZXIgdGhlIHNpZ25hdHVyZSBtYXRjaGVzLlxuICovXG5hc3luYyBmdW5jdGlvbiB2ZXJpZnlTdGFibGVKc29uU2lnbmF0dXJlKHtwdWJsaWNLZXksIHNpZ25hdHVyZSwgdmFsdWV9KSB7XG4gIGNvbnN0IGtleSA9IGF3YWl0IGNyeXB0b1N1YnRsZSgpLmltcG9ydEtleShcImp3a1wiLCBwdWJsaWNLZXksIHtuYW1lOiBcIkVDRFNBXCIsIG5hbWVkQ3VydmU6IFwiUC0yNTZcIn0sIGZhbHNlLCBbXCJ2ZXJpZnlcIl0pXG4gIGNvbnN0IHNpZ25hdHVyZUJ5dGVzID0gYmFzZTY0VXJsRGVjb2RlKHNpZ25hdHVyZVdpdGhvdXRQcmVmaXgoc2lnbmF0dXJlKSlcblxuICByZXR1cm4gYXdhaXQgY3J5cHRvU3VidGxlKCkudmVyaWZ5KHtoYXNoOiBcIlNIQS0yNTZcIiwgbmFtZTogXCJFQ0RTQVwifSwga2V5LCAvKiogQHR5cGUge0J1ZmZlclNvdXJjZX0gKi8gKHNpZ25hdHVyZUJ5dGVzKSwgLyoqIEB0eXBlIHtCdWZmZXJTb3VyY2V9ICovICh1dGY4KHN0YWJsZUpzb25TdHJpbmdpZnkodmFsdWUpKSkpXG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBhIHNpZ25lZCBkZXZpY2UgY2VydGlmaWNhdGUgZW52ZWxvcGUuXG4gKiBAcGFyYW0ge0RldmljZUNlcnRpZmljYXRlfSBjZXJ0aWZpY2F0ZSAtIFNpZ25lZCBjZXJ0aWZpY2F0ZS5cbiAqIEByZXR1cm5zIHtEZXZpY2VDZXJ0aWZpY2F0ZX0gLSBOb3JtYWxpemVkIGNlcnRpZmljYXRlLlxuICovXG5mdW5jdGlvbiBub3JtYWxpemVEZXZpY2VDZXJ0aWZpY2F0ZShjZXJ0aWZpY2F0ZSkge1xuICBpZiAoIWNlcnRpZmljYXRlIHx8IHR5cGVvZiBjZXJ0aWZpY2F0ZSAhPT0gXCJvYmplY3RcIiB8fCBBcnJheS5pc0FycmF5KGNlcnRpZmljYXRlKSkgdGhyb3cgbmV3IEVycm9yKFwiRXhwZWN0ZWQgZGV2aWNlIGNlcnRpZmljYXRlIG9iamVjdFwiKVxuICBpZiAoY2VydGlmaWNhdGUuYWxnb3JpdGhtICE9PSBFQ0RTQV9QMjU2X1NIQTI1Nl9BTEdPUklUSE0pIHRocm93IG5ldyBFcnJvcihgVW5zdXBwb3J0ZWQgZGV2aWNlIGNlcnRpZmljYXRlIGFsZ29yaXRobSAnJHtTdHJpbmcoY2VydGlmaWNhdGUuYWxnb3JpdGhtKX0nYClcblxuICByZXR1cm4ge1xuICAgIGFsZ29yaXRobTogY2VydGlmaWNhdGUuYWxnb3JpdGhtLFxuICAgIGNlcnRpZmljYXRlOiBub3JtYWxpemVEZXZpY2VDZXJ0aWZpY2F0ZVBheWxvYWQoY2VydGlmaWNhdGUuY2VydGlmaWNhdGUpLFxuICAgIHNpZ25hdHVyZTogbm9ybWFsaXplU2lnbmF0dXJlKGNlcnRpZmljYXRlLnNpZ25hdHVyZSwgXCJkZXZpY2UgY2VydGlmaWNhdGUgc2lnbmF0dXJlXCIpXG4gIH1cbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGEgZGV2aWNlIGNlcnRpZmljYXRlIHBheWxvYWQuXG4gKiBAcGFyYW0ge0RldmljZUNlcnRpZmljYXRlUGF5bG9hZH0gY2VydGlmaWNhdGUgLSBDZXJ0aWZpY2F0ZSBwYXlsb2FkLlxuICogQHJldHVybnMge0RldmljZUNlcnRpZmljYXRlUGF5bG9hZH0gLSBOb3JtYWxpemVkIGNlcnRpZmljYXRlIHBheWxvYWQuXG4gKi9cbmZ1bmN0aW9uIG5vcm1hbGl6ZURldmljZUNlcnRpZmljYXRlUGF5bG9hZChjZXJ0aWZpY2F0ZSkge1xuICBpZiAoIWNlcnRpZmljYXRlIHx8IHR5cGVvZiBjZXJ0aWZpY2F0ZSAhPT0gXCJvYmplY3RcIiB8fCBBcnJheS5pc0FycmF5KGNlcnRpZmljYXRlKSkgdGhyb3cgbmV3IEVycm9yKFwiRXhwZWN0ZWQgZGV2aWNlIGNlcnRpZmljYXRlIHBheWxvYWQgb2JqZWN0XCIpXG5cbiAgcmV0dXJuIHtcbiAgICBhY3RvckRldmljZUlkOiByZXF1aXJlZFN0cmluZyhjZXJ0aWZpY2F0ZS5hY3RvckRldmljZUlkLCBcImFjdG9yRGV2aWNlSWRcIiksXG4gICAgYWN0b3JVc2VySWQ6IHJlcXVpcmVkU3RyaW5nKGNlcnRpZmljYXRlLmFjdG9yVXNlcklkLCBcImFjdG9yVXNlcklkXCIpLFxuICAgIGNlcnRpZmljYXRlSWQ6IHJlcXVpcmVkU3RyaW5nKGNlcnRpZmljYXRlLmNlcnRpZmljYXRlSWQsIFwiY2VydGlmaWNhdGVJZFwiKSxcbiAgICBkZXZpY2VQdWJsaWNLZXk6IG5vcm1hbGl6ZUp3ayhjZXJ0aWZpY2F0ZS5kZXZpY2VQdWJsaWNLZXksIFwiZGV2aWNlUHVibGljS2V5XCIpLFxuICAgIGV4cGlyZXNBdDogaXNvRGF0ZVN0cmluZyhuZXcgRGF0ZShyZXF1aXJlZFN0cmluZyhjZXJ0aWZpY2F0ZS5leHBpcmVzQXQsIFwiZXhwaXJlc0F0XCIpKSwgXCJleHBpcmVzQXRcIiksXG4gICAgaXNzdWVkQXQ6IGlzb0RhdGVTdHJpbmcobmV3IERhdGUocmVxdWlyZWRTdHJpbmcoY2VydGlmaWNhdGUuaXNzdWVkQXQsIFwiaXNzdWVkQXRcIikpLCBcImlzc3VlZEF0XCIpXG4gIH1cbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGEgc2lnbmVkIHN5bmMgbXV0YXRpb24gZW52ZWxvcGUuXG4gKiBAcGFyYW0ge1NpZ25lZFN5bmNNdXRhdGlvbn0gc2lnbmVkTXV0YXRpb24gLSBTaWduZWQgbXV0YXRpb24uXG4gKiBAcmV0dXJucyB7U2lnbmVkU3luY011dGF0aW9ufSAtIE5vcm1hbGl6ZWQgc2lnbmVkIG11dGF0aW9uLlxuICovXG5mdW5jdGlvbiBub3JtYWxpemVTaWduZWRTeW5jTXV0YXRpb24oc2lnbmVkTXV0YXRpb24pIHtcbiAgaWYgKCFzaWduZWRNdXRhdGlvbiB8fCB0eXBlb2Ygc2lnbmVkTXV0YXRpb24gIT09IFwib2JqZWN0XCIgfHwgQXJyYXkuaXNBcnJheShzaWduZWRNdXRhdGlvbikpIHRocm93IG5ldyBFcnJvcihcIkV4cGVjdGVkIHNpZ25lZCBzeW5jIG11dGF0aW9uIG9iamVjdFwiKVxuICBpZiAoc2lnbmVkTXV0YXRpb24uYWxnb3JpdGhtICE9PSBFQ0RTQV9QMjU2X1NIQTI1Nl9BTEdPUklUSE0pIHRocm93IG5ldyBFcnJvcihgVW5zdXBwb3J0ZWQgc3luYyBtdXRhdGlvbiBhbGdvcml0aG0gJyR7U3RyaW5nKHNpZ25lZE11dGF0aW9uLmFsZ29yaXRobSl9J2ApXG5cbiAgcmV0dXJuIHtcbiAgICBhbGdvcml0aG06IHNpZ25lZE11dGF0aW9uLmFsZ29yaXRobSxcbiAgICBkZXZpY2VDZXJ0aWZpY2F0ZTogbm9ybWFsaXplRGV2aWNlQ2VydGlmaWNhdGUoc2lnbmVkTXV0YXRpb24uZGV2aWNlQ2VydGlmaWNhdGUpLFxuICAgIG11dGF0aW9uOiBub3JtYWxpemVTeW5jTXV0YXRpb24oc2lnbmVkTXV0YXRpb24ubXV0YXRpb24pLFxuICAgIHNpZ25hdHVyZTogbm9ybWFsaXplU2lnbmF0dXJlKHNpZ25lZE11dGF0aW9uLnNpZ25hdHVyZSwgXCJzeW5jIG11dGF0aW9uIHNpZ25hdHVyZVwiKVxuICB9XG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBhIHN5bmMgbXV0YXRpb24gcGF5bG9hZC5cbiAqIEBwYXJhbSB7U3luY011dGF0aW9ufSBtdXRhdGlvbiAtIE11dGF0aW9uIHBheWxvYWQuXG4gKiBAcmV0dXJucyB7U3luY011dGF0aW9ufSAtIE5vcm1hbGl6ZWQgbXV0YXRpb24gcGF5bG9hZC5cbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplU3luY011dGF0aW9uKG11dGF0aW9uKSB7XG4gIGlmICghbXV0YXRpb24gfHwgdHlwZW9mIG11dGF0aW9uICE9PSBcIm9iamVjdFwiIHx8IEFycmF5LmlzQXJyYXkobXV0YXRpb24pKSB0aHJvdyBuZXcgRXJyb3IoXCJFeHBlY3RlZCBzeW5jIG11dGF0aW9uIG9iamVjdFwiKVxuXG4gIC8qKiBAdHlwZSB7U3luY011dGF0aW9ufSAqL1xuICBjb25zdCBub3JtYWxpemVkID0ge1xuICAgIGFjdG9yRGV2aWNlSWQ6IHJlcXVpcmVkU3RyaW5nKG11dGF0aW9uLmFjdG9yRGV2aWNlSWQsIFwiYWN0b3JEZXZpY2VJZFwiKSxcbiAgICBhY3RvclVzZXJJZDogcmVxdWlyZWRTdHJpbmcobXV0YXRpb24uYWN0b3JVc2VySWQsIFwiYWN0b3JVc2VySWRcIiksXG4gICAgY2xpZW50TXV0YXRpb25JZDogcmVxdWlyZWRTdHJpbmcobXV0YXRpb24uY2xpZW50TXV0YXRpb25JZCwgXCJjbGllbnRNdXRhdGlvbklkXCIpLFxuICAgIG1vZGVsOiByZXF1aXJlZFN0cmluZyhtdXRhdGlvbi5tb2RlbCwgXCJtb2RlbFwiKSxcbiAgICBvY2N1cnJlZEF0OiBpc29EYXRlU3RyaW5nKG5ldyBEYXRlKHJlcXVpcmVkU3RyaW5nKG11dGF0aW9uLm9jY3VycmVkQXQsIFwib2NjdXJyZWRBdFwiKSksIFwib2NjdXJyZWRBdFwiKSxcbiAgICBvZmZsaW5lR3JhbnRJZDogcmVxdWlyZWRTdHJpbmcobXV0YXRpb24ub2ZmbGluZUdyYW50SWQsIFwib2ZmbGluZUdyYW50SWRcIiksXG4gICAgb3BlcmF0aW9uOiByZXF1aXJlZFN0cmluZyhtdXRhdGlvbi5vcGVyYXRpb24sIFwib3BlcmF0aW9uXCIpLFxuICAgIHBvbGljeUhhc2g6IHJlcXVpcmVkU3RyaW5nKG11dGF0aW9uLnBvbGljeUhhc2gsIFwicG9saWN5SGFzaFwiKVxuICB9XG5cbiAgaWYgKG11dGF0aW9uLmF0dHJpYnV0ZXMgIT09IHVuZGVmaW5lZCkgbm9ybWFsaXplZC5hdHRyaWJ1dGVzID0gZGV0ZXJtaW5pc3RpY0pzb25PYmplY3Qoe2xhYmVsOiBcImF0dHJpYnV0ZXNcIiwgdmFsdWU6IG11dGF0aW9uLmF0dHJpYnV0ZXN9KVxuICBpZiAobXV0YXRpb24uYmFzZVZlcnNpb24gIT09IHVuZGVmaW5lZCkgbm9ybWFsaXplZC5iYXNlVmVyc2lvbiA9IC8qKiBAdHlwZSB7c3RyaW5nIHwgbnVtYmVyIHwgbnVsbH0gKi8gKGRldGVybWluaXN0aWNKc29uKHtsYWJlbDogXCJiYXNlVmVyc2lvblwiLCB2YWx1ZTogbXV0YXRpb24uYmFzZVZlcnNpb259KSlcbiAgaWYgKG11dGF0aW9uLmNvbW1hbmQgIT09IHVuZGVmaW5lZCkgbm9ybWFsaXplZC5jb21tYW5kID0gcmVxdWlyZWRTdHJpbmcobXV0YXRpb24uY29tbWFuZCwgXCJjb21tYW5kXCIpXG4gIGlmIChtdXRhdGlvbi5wYXlsb2FkICE9PSB1bmRlZmluZWQpIG5vcm1hbGl6ZWQucGF5bG9hZCA9IGRldGVybWluaXN0aWNKc29uT2JqZWN0KHtsYWJlbDogXCJwYXlsb2FkXCIsIHZhbHVlOiBtdXRhdGlvbi5wYXlsb2FkfSlcblxuICByZXR1cm4gbm9ybWFsaXplZFxufVxuXG4vKipcbiAqIEFzc2VydHMgdGhhdCBtdXRhdGlvbiBhY3RvciBmaWVsZHMgbWF0Y2ggdGhlIGNlcnRpZmljYXRlIGFjdG9yLlxuICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBBcmd1bWVudHMuXG4gKiBAcGFyYW0ge0RldmljZUNlcnRpZmljYXRlUGF5bG9hZH0gYXJncy5jZXJ0aWZpY2F0ZSAtIERldmljZSBjZXJ0aWZpY2F0ZSBwYXlsb2FkLlxuICogQHBhcmFtIHtTeW5jTXV0YXRpb259IGFyZ3MubXV0YXRpb24gLSBNdXRhdGlvbiBwYXlsb2FkLlxuICogQHJldHVybnMge3ZvaWR9IC0gTm8gcmV0dXJuIHZhbHVlLlxuICovXG5mdW5jdGlvbiBhc3NlcnRNdXRhdGlvbk1hdGNoZXNDZXJ0aWZpY2F0ZSh7Y2VydGlmaWNhdGUsIG11dGF0aW9ufSkge1xuICBpZiAobXV0YXRpb24uYWN0b3JEZXZpY2VJZCAhPT0gY2VydGlmaWNhdGUuYWN0b3JEZXZpY2VJZCB8fCBtdXRhdGlvbi5hY3RvclVzZXJJZCAhPT0gY2VydGlmaWNhdGUuYWN0b3JVc2VySWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJTeW5jIG11dGF0aW9uIGFjdG9yIGRvZXMgbm90IG1hdGNoIGRldmljZSBjZXJ0aWZpY2F0ZVwiKVxuICB9XG59XG5cbi8qKlxuICogQXNzZXJ0cyBhIHRpbWVzdGFtcCBpcyBub3QgZXhwaXJlZC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MuZXhwaXJlc0F0IC0gRXhwaXJ5IHRpbWVzdGFtcC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmxhYmVsIC0gRXJyb3IgbGFiZWwuXG4gKiBAcGFyYW0ge0RhdGV9IGFyZ3Mubm93IC0gVmVyaWZpY2F0aW9uIHRpbWUuXG4gKiBAcmV0dXJucyB7dm9pZH0gLSBObyByZXR1cm4gdmFsdWUuXG4gKi9cbmZ1bmN0aW9uIGFzc2VydE5vdEV4cGlyZWQoe2V4cGlyZXNBdCwgbGFiZWwsIG5vd30pIHtcbiAgaWYgKE51bWJlci5pc05hTihub3cuZ2V0VGltZSgpKSkgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBzeW5jIHZlcmlmaWNhdGlvbiB0aW1lXCIpXG4gIGlmIChuZXcgRGF0ZShleHBpcmVzQXQpLmdldFRpbWUoKSA8PSBub3cuZ2V0VGltZSgpKSB0aHJvdyBuZXcgRXJyb3IoYCR7bGFiZWx9IGV4cGlyZWRgKVxufVxuXG4vKipcbiAqIE5vcm1hbGl6ZXMgYSBKU09OIFdlYiBLZXkgb2JqZWN0LlxuICogQHBhcmFtIHtTeW5jSnNvbldlYktleX0ga2V5IC0gSldLLlxuICogQHBhcmFtIHtzdHJpbmd9IGxhYmVsIC0gS2V5IGxhYmVsLlxuICogQHJldHVybnMge1N5bmNKc29uV2ViS2V5fSAtIE5vcm1hbGl6ZWQgSldLLlxuICovXG5mdW5jdGlvbiBub3JtYWxpemVKd2soa2V5LCBsYWJlbCkge1xuICBjb25zdCBub3JtYWxpemVkID0gZGV0ZXJtaW5pc3RpY0pzb25PYmplY3Qoe2xhYmVsLCB2YWx1ZToga2V5fSlcblxuICByZXR1cm4gLyoqIEB0eXBlIHtTeW5jSnNvbldlYktleX0gKi8gKG5vcm1hbGl6ZWQpXG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBhIHByZWZpeGVkIHNpZ25hdHVyZSBzdHJpbmcuXG4gKiBAcGFyYW0ge3Vua25vd259IHNpZ25hdHVyZSAtIFNpZ25hdHVyZSB2YWx1ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBsYWJlbCAtIEVycm9yIGxhYmVsLlxuICogQHJldHVybnMge3N0cmluZ30gLSBTaWduYXR1cmUgc3RyaW5nLlxuICovXG5mdW5jdGlvbiBub3JtYWxpemVTaWduYXR1cmUoc2lnbmF0dXJlLCBsYWJlbCkge1xuICBpZiAodHlwZW9mIHNpZ25hdHVyZSAhPT0gXCJzdHJpbmdcIiB8fCAhc2lnbmF0dXJlLnN0YXJ0c1dpdGgoRUNEU0FfUDI1Nl9TSEEyNTZfU0lHTkFUVVJFX1BSRUZJWCkpIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgJHtsYWJlbH1gKVxuXG4gIHJldHVybiBzaWduYXR1cmVcbn1cblxuLyoqXG4gKiBSZW1vdmVzIHRoZSBzaWduYXR1cmUgcHJlZml4LlxuICogQHBhcmFtIHtzdHJpbmd9IHNpZ25hdHVyZSAtIFByZWZpeGVkIHNpZ25hdHVyZS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gQmFzZTY0dXJsIHNpZ25hdHVyZSBib2R5LlxuICovXG5mdW5jdGlvbiBzaWduYXR1cmVXaXRob3V0UHJlZml4KHNpZ25hdHVyZSkge1xuICByZXR1cm4gc2lnbmF0dXJlLnNsaWNlKEVDRFNBX1AyNTZfU0hBMjU2X1NJR05BVFVSRV9QUkVGSVgubGVuZ3RoKVxufVxuXG4vKipcbiAqIFJlcXVpcmVzIGEgbm9uLWVtcHR5IHN0cmluZyBmaWVsZC5cbiAqIEBwYXJhbSB7dW5rbm93bn0gdmFsdWUgLSBWYWx1ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIC0gRmllbGQgbmFtZS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gU3RyaW5nIHZhbHVlLlxuICovXG5mdW5jdGlvbiByZXF1aXJlZFN0cmluZyh2YWx1ZSwgbmFtZSkge1xuICBpZiAodHlwZW9mIHZhbHVlICE9PSBcInN0cmluZ1wiIHx8IHZhbHVlLmxlbmd0aCA8IDEpIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgc3luYyAke25hbWV9YClcblxuICByZXR1cm4gdmFsdWVcbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGEgRGF0ZSB0byBhbiBJU08gdGltZXN0YW1wLlxuICogQHBhcmFtIHtEYXRlfSBkYXRlIC0gRGF0ZSB2YWx1ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBsYWJlbCAtIEZpZWxkIGxhYmVsLlxuICogQHJldHVybnMge3N0cmluZ30gLSBJU08gdGltZXN0YW1wLlxuICovXG5mdW5jdGlvbiBpc29EYXRlU3RyaW5nKGRhdGUsIGxhYmVsKSB7XG4gIGlmIChOdW1iZXIuaXNOYU4oZGF0ZS5nZXRUaW1lKCkpKSB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc3luYyAke2xhYmVsfWApXG5cbiAgcmV0dXJuIGRhdGUudG9JU09TdHJpbmcoKVxufVxuXG4vKipcbiAqIFJldHVybnMgZW5jb2RlZCBVVEYtOCBieXRlcyBmb3IgYSBzdHJpbmcuXG4gKiBAcGFyYW0ge3N0cmluZ30gdmFsdWUgLSBTdHJpbmcgdmFsdWUuXG4gKiBAcmV0dXJucyB7VWludDhBcnJheX0gLSBVVEYtOCBieXRlcy5cbiAqL1xuZnVuY3Rpb24gdXRmOCh2YWx1ZSkge1xuICByZXR1cm4gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKHZhbHVlKVxufVxuXG4vKipcbiAqIFJldHVybnMgV2ViQ3J5cHRvIHN1YnRsZSBBUEkuXG4gKiBAcmV0dXJucyB7U3VidGxlQ3J5cHRvfSAtIFN1YnRsZUNyeXB0byBpbXBsZW1lbnRhdGlvbi5cbiAqL1xuZnVuY3Rpb24gY3J5cHRvU3VidGxlKCkge1xuICBpZiAoIWdsb2JhbFRoaXMuY3J5cHRvPy5zdWJ0bGUpIHRocm93IG5ldyBFcnJvcihcIldlYkNyeXB0byBzdWJ0bGUgQVBJIGlzIHJlcXVpcmVkIGZvciBzeW5jIHNpZ25pbmdcIilcblxuICByZXR1cm4gZ2xvYmFsVGhpcy5jcnlwdG8uc3VidGxlXG59XG5cbi8qKlxuICogQmFzZTY0dXJsLWVuY29kZXMgYnl0ZXMuXG4gKiBAcGFyYW0ge1VpbnQ4QXJyYXl9IGJ5dGVzIC0gQnl0ZXMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIEJhc2U2NHVybCBzdHJpbmcuXG4gKi9cbmZ1bmN0aW9uIGJhc2U2NFVybEVuY29kZShieXRlcykge1xuICBsZXQgYmluYXJ5ID0gXCJcIlxuXG4gIGZvciAoY29uc3QgYnl0ZSBvZiBieXRlcykgYmluYXJ5ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnl0ZSlcblxuICByZXR1cm4gYnRvYShiaW5hcnkpLnJlcGxhY2VBbGwoXCIrXCIsIFwiLVwiKS5yZXBsYWNlQWxsKFwiL1wiLCBcIl9cIikucmVwbGFjZUFsbChcIj1cIiwgXCJcIilcbn1cblxuLyoqXG4gKiBCYXNlNjR1cmwtZGVjb2RlcyBieXRlcy5cbiAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIEJhc2U2NHVybCBzdHJpbmcuXG4gKiBAcmV0dXJucyB7VWludDhBcnJheX0gLSBCeXRlcy5cbiAqL1xuZnVuY3Rpb24gYmFzZTY0VXJsRGVjb2RlKHZhbHVlKSB7XG4gIGNvbnN0IGJhc2U2NCA9IHZhbHVlLnJlcGxhY2VBbGwoXCItXCIsIFwiK1wiKS5yZXBsYWNlQWxsKFwiX1wiLCBcIi9cIikucGFkRW5kKE1hdGguY2VpbCh2YWx1ZS5sZW5ndGggLyA0KSAqIDQsIFwiPVwiKVxuICBjb25zdCBiaW5hcnkgPSBhdG9iKGJhc2U2NClcblxuICByZXR1cm4gVWludDhBcnJheS5mcm9tKGJpbmFyeSwgKGNoYXIpID0+IGNoYXIuY2hhckNvZGVBdCgwKSlcbn1cblxuLyoqXG4gKiBTdGFibGUgSlNPTiBzdHJpbmdpZmllciB3aXRoIHNvcnRlZCBvYmplY3Qga2V5cy5cbiAqIEBwYXJhbSB7dW5rbm93bn0gdmFsdWUgLSBWYWx1ZS5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gSlNPTiBzdHJpbmcuXG4gKi9cbmZ1bmN0aW9uIHN0YWJsZUpzb25TdHJpbmdpZnkodmFsdWUpIHtcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGRldGVybWluaXN0aWNKc29uKHtsYWJlbDogXCJyb290XCIsIHZhbHVlfSkpXG59XG5cbi8qKlxuICogTm9ybWFsaXplcyBhIHZhbHVlIGFzIGEgSlNPTiBvYmplY3QuXG4gKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIEFyZ3VtZW50cy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmxhYmVsIC0gRGlhZ25vc3RpYyBsYWJlbC5cbiAqIEBwYXJhbSB7dW5rbm93bn0gYXJncy52YWx1ZSAtIFZhbHVlLlxuICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsIGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuRnJvbnRlbmRNb2RlbFN5bmNKc29uVmFsdWU+fSAtIEpTT04gb2JqZWN0LlxuICovXG5mdW5jdGlvbiBkZXRlcm1pbmlzdGljSnNvbk9iamVjdCh7bGFiZWwsIHZhbHVlfSkge1xuICBjb25zdCBub3JtYWxpemVkID0gZGV0ZXJtaW5pc3RpY0pzb24oe2xhYmVsLCB2YWx1ZX0pXG5cbiAgaWYgKCFub3JtYWxpemVkIHx8IHR5cGVvZiBub3JtYWxpemVkICE9PSBcIm9iamVjdFwiIHx8IEFycmF5LmlzQXJyYXkobm9ybWFsaXplZCkpIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgc3luYyAke2xhYmVsfSBvYmplY3RgKVxuXG4gIHJldHVybiAvKiogQHR5cGUge1JlY29yZDxzdHJpbmcsIGltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24tdHlwZXMuanNcIikuRnJvbnRlbmRNb2RlbFN5bmNKc29uVmFsdWU+fSAqLyAobm9ybWFsaXplZClcbn1cblxuLyoqXG4gKiBOb3JtYWxpemVzIGRldGVybWluaXN0aWMgSlNPTiB3aXRoIHNvcnRlZCBvYmplY3Qga2V5cy5cbiAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQXJndW1lbnRzLlxuICogQHBhcmFtIHtzdHJpbmd9IGFyZ3MubGFiZWwgLSBEaWFnbm9zdGljIGxhYmVsLlxuICogQHBhcmFtIHt1bmtub3dufSBhcmdzLnZhbHVlIC0gVmFsdWUuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZX0gLSBOb3JtYWxpemVkIEpTT04gdmFsdWUuXG4gKi9cbmZ1bmN0aW9uIGRldGVybWluaXN0aWNKc29uKHtsYWJlbCwgdmFsdWV9KSB7XG4gIGlmICh2YWx1ZSA9PT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgfHwgdHlwZW9mIHZhbHVlID09PSBcIm51bWJlclwiIHx8IHR5cGVvZiB2YWx1ZSA9PT0gXCJib29sZWFuXCIpIHJldHVybiB2YWx1ZVxuXG4gIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkgcmV0dXJuIHZhbHVlLm1hcCgoZW50cnksIGluZGV4KSA9PiBkZXRlcm1pbmlzdGljSnNvbih7bGFiZWw6IGAke2xhYmVsfS8ke2luZGV4fWAsIHZhbHVlOiBlbnRyeX0pKVxuXG4gIGlmICh2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIgJiYgT2JqZWN0LmdldFByb3RvdHlwZU9mKHZhbHVlKSA9PT0gT2JqZWN0LnByb3RvdHlwZSkge1xuICAgIC8qKiBAdHlwZSB7UmVjb3JkPHN0cmluZywgaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5Gcm9udGVuZE1vZGVsU3luY0pzb25WYWx1ZT59ICovXG4gICAgY29uc3Qgbm9ybWFsaXplZCA9IHt9XG5cbiAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyh2YWx1ZSkuc29ydCgpKSB7XG4gICAgICBjb25zdCBjaGlsZFZhbHVlID0gLyoqIEB0eXBlIHtSZWNvcmQ8c3RyaW5nLCB1bmtub3duPn0gKi8gKHZhbHVlKVtrZXldXG5cbiAgICAgIGlmIChjaGlsZFZhbHVlID09PSB1bmRlZmluZWQpIGNvbnRpbnVlXG4gICAgICBub3JtYWxpemVkW2tleV0gPSBkZXRlcm1pbmlzdGljSnNvbih7bGFiZWw6IGAke2xhYmVsfS8ke2tleX1gLCB2YWx1ZTogY2hpbGRWYWx1ZX0pXG4gICAgfVxuXG4gICAgcmV0dXJuIG5vcm1hbGl6ZWRcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcihgU3luYyAke2xhYmVsfSBtdXN0IGJlIGRldGVybWluaXN0aWMgSlNPTmApXG59XG4iXX0=