sliftutils 1.7.12 → 1.7.14

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 (53) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/index.d.ts +95 -39
  3. package/misc/dist/yaml.ts.cache +2 -2
  4. package/misc/dist/yamlBase.ts.cache +2 -2
  5. package/misc/https/hostServer.d.ts +7 -0
  6. package/misc/https/hostServer.ts +89 -20
  7. package/misc/openrouter.ts +17 -14
  8. package/package.json +2 -2
  9. package/storage/ArchivesDisk.d.ts +1 -1
  10. package/storage/ArchivesDisk.ts +2 -1
  11. package/storage/IArchives.d.ts +5 -1
  12. package/storage/IArchives.ts +5 -1
  13. package/storage/backblaze.d.ts +1 -1
  14. package/storage/backblaze.ts +9 -6
  15. package/storage/dist/embeddingFormats.ts.cache +2 -2
  16. package/storage/proxydatabase/dist/Database.ts.cache +2 -2
  17. package/storage/proxydatabase/dist/ivfEmbeddingDatabase.ts.cache +123 -61
  18. package/storage/proxydatabase/dist/transactionSet.ts.cache +16 -4
  19. package/storage/remoteStorage/ArchivesRemote.d.ts +1 -1
  20. package/storage/remoteStorage/ArchivesRemote.ts +2 -1
  21. package/storage/remoteStorage/ArchivesUrl.d.ts +1 -1
  22. package/storage/remoteStorage/ArchivesUrl.ts +13 -9
  23. package/storage/remoteStorage/blobStore.d.ts +6 -2
  24. package/storage/remoteStorage/blobStore.ts +46 -6
  25. package/storage/remoteStorage/createArchives.d.ts +26 -11
  26. package/storage/remoteStorage/createArchives.ts +104 -28
  27. package/storage/remoteStorage/deployTakeover.d.ts +24 -0
  28. package/storage/remoteStorage/deployTakeover.ts +373 -0
  29. package/storage/remoteStorage/dist/ArchivesUrl.ts.cache +16 -11
  30. package/storage/remoteStorage/dist/blobStore.ts.cache +39 -4
  31. package/storage/remoteStorage/dist/createArchives.ts.cache +91 -9
  32. package/storage/remoteStorage/dist/deployTakeover.ts.cache +371 -0
  33. package/storage/remoteStorage/dist/remoteConfig.ts.cache +9 -3
  34. package/storage/remoteStorage/dist/sourceWrapper.ts.cache +3 -3
  35. package/storage/remoteStorage/dist/storageController.ts.cache +11 -12
  36. package/storage/remoteStorage/dist/storageServerState.ts.cache +120 -19
  37. package/storage/remoteStorage/remoteConfig.d.ts +1 -0
  38. package/storage/remoteStorage/remoteConfig.ts +6 -0
  39. package/storage/remoteStorage/storageController.d.ts +2 -0
  40. package/storage/remoteStorage/storageController.ts +9 -9
  41. package/storage/remoteStorage/storageServer.ts +14 -1
  42. package/storage/remoteStorage/storageServerState.d.ts +16 -1
  43. package/storage/remoteStorage/storageServerState.ts +118 -16
  44. package/yarn.lock +4 -4
  45. package/storage/dist/faceFramesData.ts.cache +0 -55
  46. package/storage/embeddingBench.d.ts +0 -1
  47. package/storage/embeddingBench.ts +0 -152
  48. package/storage/faceFramesData.d.ts +0 -1
  49. package/storage/faceFramesData.ts +0 -49
  50. package/storage/faceFramesServer.d.ts +0 -1
  51. package/storage/faceFramesServer.ts +0 -56
  52. package/storage/proxydatabase/ivfDbCheck.d.ts +0 -1
  53. package/storage/proxydatabase/ivfDbCheck.ts +0 -85
@@ -6,7 +6,8 @@
6
6
  "Bash(echo \"---EXIT:$?---\")",
7
7
  "Bash(yarn publish *)",
8
8
  "Bash(git push *)",
9
- "Bash(yarn type *)"
9
+ "Bash(yarn type *)",
10
+ "Bash(git rm *)"
10
11
  ]
11
12
  }
12
13
  }
package/index.d.ts CHANGED
@@ -223,6 +223,13 @@ declare module "sliftutils/misc/https/hostServer" {
223
223
  setDNSRecord?: boolean;
224
224
  publicIp?: string;
225
225
  allowHostnames?: string[];
226
+ /** Deploy takeover: when the port is busy (the previous version still holds it), mount on a random alternate port instead, and keep trying to take the real port - once it frees, a raw TCP relay on the real port forwards to our listener (SocketFunction can only mount once per process). Only pass this when a deploy timeline actually exists; without it a busy port is a real misconfiguration and must throw. */
227
+ portFallback?: {
228
+ /** Delay until the next main-port acquisition attempt (tightened around the predecessor's scheduled death) */
229
+ getAcquireDelay: () => number;
230
+ /** Reports every port we become reachable on (the alternate at mount, the main port once relayed) */
231
+ onListening: (port: number, isMainPort: boolean) => void;
232
+ };
226
233
  };
227
234
  /** Hosts a SocketFunction server on a real domain, with an automatically created and renewed Let's Encrypt HTTPS certificate (cached in the home folder, shared between processes on the machine). Expose your controllers (and any RequireController setup) before calling this. Returns the mounted nodeId. */
228
235
  export declare function hostServer(config: HostServerConfig): Promise<string>;
@@ -872,7 +879,7 @@ declare module "sliftutils/storage/ArchivesDisk" {
872
879
  private filePath;
873
880
  set(key: string, data: Buffer, config?: {
874
881
  lastModified?: number;
875
- }): Promise<void>;
882
+ }): Promise<string>;
876
883
  del(key: string): Promise<void>;
877
884
  get(key: string, config?: {
878
885
  range?: {
@@ -2222,10 +2229,14 @@ declare module "sliftutils/storage/IArchives" {
2222
2229
  * lastModified stamps the write with that last-write time instead of now. If it is OLDER than
2223
2230
  * the file's current last-write time the write no-ops (so delayed / synchronized writes can
2224
2231
  * never clobber newer data). Times more than 15 minutes in the future are rejected.
2232
+ *
2233
+ * Returns the full key actually written - identical to fileName, EXCEPT for keys containing
2234
+ * VARIABLE_SHARD, where the shard value is materialized into the key (picked by shard latency,
2235
+ * see ArchivesChain) and the caller needs the returned key to ever read the value back.
2225
2236
  */
2226
2237
  set(fileName: string, data: Buffer, config?: {
2227
2238
  lastModified?: number;
2228
- }): Promise<void>;
2239
+ }): Promise<string>;
2229
2240
  del(fileName: string): Promise<void>;
2230
2241
  /** Streams a file too large to hold in memory. getNextData returns undefined when done. */
2231
2242
  setLargeFile(config: {
@@ -2557,7 +2568,7 @@ declare module "sliftutils/storage/backblaze" {
2557
2568
  hasWriteAccess(): Promise<boolean>;
2558
2569
  set(fileName: string, data: Buffer, config?: {
2559
2570
  lastModified?: number;
2560
- }): Promise<void>;
2571
+ }): Promise<string>;
2561
2572
  del(fileName: string): Promise<void>;
2562
2573
  setLargeFile(config: {
2563
2574
  path: string;
@@ -2642,11 +2653,6 @@ declare module "sliftutils/storage/backblaze" {
2642
2653
 
2643
2654
  }
2644
2655
 
2645
- declare module "sliftutils/storage/embeddingBench" {
2646
- export {};
2647
-
2648
- }
2649
-
2650
2656
  declare module "sliftutils/storage/embeddingFormats" {
2651
2657
  export type EmbeddingFormat = "q8g8_2048" | "q8_g16_2048" | "q8_g16_1024" | "float32";
2652
2658
  export declare const EMBEDDING_FORMATS: EmbeddingFormat[];
@@ -2683,16 +2689,6 @@ declare module "sliftutils/storage/embeddingFormats" {
2683
2689
 
2684
2690
  }
2685
2691
 
2686
- declare module "sliftutils/storage/faceFramesData" {
2687
- export declare function ensureFaceData(fileName: string, byteLength: number): Promise<string>;
2688
-
2689
- }
2690
-
2691
- declare module "sliftutils/storage/faceFramesServer" {
2692
- export {};
2693
-
2694
- }
2695
-
2696
2692
  declare module "sliftutils/storage/fileSystemPointer" {
2697
2693
  export type FileSystemPointer = string;
2698
2694
  export declare function storeFileSystemPointer(config: {
@@ -2736,11 +2732,6 @@ declare module "sliftutils/storage/proxydatabase/inMemoryDatabase" {
2736
2732
 
2737
2733
  }
2738
2734
 
2739
- declare module "sliftutils/storage/proxydatabase/ivfDbCheck" {
2740
- export {};
2741
-
2742
- }
2743
-
2744
2735
  declare module "sliftutils/storage/proxydatabase/ivfEmbeddingDatabase" {
2745
2736
  import { Database } from "./Database";
2746
2737
  import { TransactionSetStore } from "./transactionSet";
@@ -2909,7 +2900,7 @@ declare module "sliftutils/storage/remoteStorage/ArchivesRemote" {
2909
2900
  } | undefined>;
2910
2901
  set(fileName: string, data: Buffer, config?: {
2911
2902
  lastModified?: number;
2912
- }): Promise<void>;
2903
+ }): Promise<string>;
2913
2904
  del(fileName: string): Promise<void>;
2914
2905
  getInfo(fileName: string): Promise<{
2915
2906
  writeTime: number;
@@ -2966,7 +2957,7 @@ declare module "sliftutils/storage/remoteStorage/ArchivesUrl" {
2966
2957
  } | undefined>;
2967
2958
  set(fileName: string, data: Buffer, config?: {
2968
2959
  lastModified?: number;
2969
- }): Promise<void>;
2960
+ }): Promise<string>;
2970
2961
  del(fileName: string): Promise<void>;
2971
2962
  setLargeFile(config: {
2972
2963
  path: string;
@@ -3019,7 +3010,7 @@ declare module "sliftutils/storage/remoteStorage/blobStore" {
3019
3010
  writeTime: number;
3020
3011
  size: number;
3021
3012
  } | undefined>;
3022
- set(fileName: string, data: Buffer, config?: WriteConfig): Promise<void>;
3013
+ set(fileName: string, data: Buffer, config?: WriteConfig): Promise<string>;
3023
3014
  del(fileName: string, config?: WriteConfig): Promise<void>;
3024
3015
  getInfo(fileName: string): Promise<{
3025
3016
  writeTime: number;
@@ -3065,6 +3056,7 @@ declare module "sliftutils/storage/remoteStorage/blobStore" {
3065
3056
  constructor(folder: string, sources: ArchivesSource[], config?: {
3066
3057
  onIndexChanged?: ((key: string) => void) | undefined;
3067
3058
  readerDiskLimit?: number | undefined;
3059
+ getFlushDeadline?: (() => number | undefined) | undefined;
3068
3060
  } | undefined);
3069
3061
  private stopped;
3070
3062
  private index;
@@ -3087,6 +3079,9 @@ declare module "sliftutils/storage/remoteStorage/blobStore" {
3087
3079
  private countEntry;
3088
3080
  private setIndexEntry;
3089
3081
  private deleteIndexEntry;
3082
+ /** Rescans our own disk's metadata into the index - used around deploy switchovers, where the
3083
+ * other process wrote files to the shared folder that our index hasn't seen. */
3084
+ rescanBase(): Promise<void>;
3090
3085
  /** The cheap always-current totals plus any in-progress background synchronization. */
3091
3086
  getSyncProgress(): {
3092
3087
  index: {
@@ -3139,7 +3134,7 @@ declare module "sliftutils/storage/remoteStorage/blobStore" {
3139
3134
  size: number;
3140
3135
  } | undefined>;
3141
3136
  private cacheRead;
3142
- set(key: string, data: Buffer, config?: WriteConfig): Promise<void>;
3137
+ set(key: string, data: Buffer, config?: WriteConfig): Promise<string>;
3143
3138
  del(key: string, config?: WriteConfig): Promise<void>;
3144
3139
  private getWritableSources;
3145
3140
  private writeToSources;
@@ -3175,6 +3170,7 @@ declare module "sliftutils/storage/remoteStorage/createArchives" {
3175
3170
  /// <reference types="node" />
3176
3171
  /// <reference types="node" />
3177
3172
  import { IArchives, RemoteConfig, RemoteConfigBase, HostedConfig, BackblazeConfig, ArchiveFileInfo, ArchivesConfig, ArchivesSyncStatus } from "../IArchives";
3173
+ import { ServerBucketInfo } from "./storageServerState";
3178
3174
  export declare function createApiArchives(source: HostedConfig | BackblazeConfig): IArchives;
3179
3175
  export declare class ArchivesChain implements IArchives {
3180
3176
  private configured;
@@ -3190,9 +3186,14 @@ declare module "sliftutils/storage/remoteStorage/createArchives" {
3190
3186
  private init;
3191
3187
  private buildSources;
3192
3188
  private startConfigPoll;
3189
+ private configRefreshInFlight;
3190
+ private refreshActiveConfig;
3191
+ private fetchLatestConfig;
3193
3192
  private checkForNewConfig;
3194
3193
  private run;
3195
3194
  private runWrite;
3195
+ private lastConfigRefresh;
3196
+ private prepareWrongTargetRetry;
3196
3197
  private request;
3197
3198
  waitingForAccess(): Promise<{
3198
3199
  link: string;
@@ -3235,20 +3236,14 @@ declare module "sliftutils/storage/remoteStorage/createArchives" {
3235
3236
  /** True only when EVERY write-receiving source would accept our writes (partial write access
3236
3237
  * desynchronizes sources, so it counts as no access). */
3237
3238
  hasWriteAccess(): Promise<boolean>;
3238
- private assertNotBareVariableShard;
3239
+ /** Returns the full key written. Plain keys come back unchanged; keys containing VARIABLE_SHARD
3240
+ * are automatically materialized (a shard value is picked and embedded, see setVariableShard)
3241
+ * and the caller needs the returned key to ever read the value back. */
3239
3242
  set(fileName: string, data: Buffer, config?: {
3240
3243
  lastModified?: number;
3241
- }): Promise<void>;
3242
- del(fileName: string): Promise<void>;
3243
- /** Writes a key containing the VARIABLE_SHARD sentinel: picks the lowest-latency up write
3244
- * shard, materializes the key with a random value inside that shard's route, writes it, and
3245
- * returns the FULL key actually written (the caller needs it to ever read the value back).
3246
- * Unlike normal writes this CAN move to another shard when the preferred one is down (error +
3247
- * socket down, same rule as reads) - each shard receives a different key, so write
3248
- * consistency is preserved. */
3249
- setVariableShard(key: string, data: Buffer, config?: {
3250
- lastModified?: number;
3251
3244
  }): Promise<string>;
3245
+ del(fileName: string): Promise<void>;
3246
+ private setVariableShard;
3252
3247
  setLargeFile(config: {
3253
3248
  path: string;
3254
3249
  getNextData(): Promise<Buffer | undefined>;
@@ -3257,6 +3252,49 @@ declare module "sliftutils/storage/remoteStorage/createArchives" {
3257
3252
  dispose(): void;
3258
3253
  }
3259
3254
  export declare function createArchives(config: RemoteConfig | RemoteConfigBase): ArchivesChain;
3255
+ /** Every bucket an account has on one storage server - active and inactive - with each bucket's
3256
+ * configuration. One authenticated call (the normal trust system applies): no ArchivesChain, no
3257
+ * synchronization, and inactive buckets on the server stay inactive. Any URL addressing the
3258
+ * server works (a bucket routing URL, or just https://host:port). */
3259
+ export declare function listServerBuckets(config: {
3260
+ url: string;
3261
+ account: string;
3262
+ }): Promise<ServerBucketInfo[]>;
3263
+ /** Live info for one bucket given its routing URL (getConfig: routing config, index totals, disk
3264
+ * limit, in-progress synchronization). One authenticated call to that server - a light, safe
3265
+ * alternative to instantiating an ArchivesChain, which would start synchronization machinery. */
3266
+ export declare function getBucketInfo(config: {
3267
+ url: string;
3268
+ accountName?: string;
3269
+ }): Promise<ArchivesConfig>;
3270
+
3271
+ }
3272
+
3273
+ declare module "sliftutils/storage/remoteStorage/deployTakeover" {
3274
+ import { RemoteConfig } from "../IArchives";
3275
+ export type TakeoverEvent = "remapChanged" | "diskScan";
3276
+ /** Starts the takeover machinery. Returns whether a deploy timeline exists - when it doesn't,
3277
+ * everything here stays inert (and the caller must NOT fall back to alternate ports, since a busy
3278
+ * port then means a real misconfiguration, not a deploy). */
3279
+ export declare function initDeployTakeover(config: {
3280
+ domain: string;
3281
+ mainPort: number;
3282
+ storageFolder: string;
3283
+ }): Promise<boolean>;
3284
+ /** Called when we had to listen on an alternate port (the main port was still held by our
3285
+ * predecessor): registers it so the predecessor can route the middle overlap window to us. */
3286
+ export declare function registerAltPort(port: number): Promise<void>;
3287
+ export declare function onTakeoverEvent(listener: (event: TakeoverEvent) => void): void;
3288
+ /** The interpretation overlay: splits every source pointing at our domain+main port so the middle
3289
+ * of the deploy overlap points at the alternate port. Pure, in-memory only - the stored routing
3290
+ * config is never modified, and this must never be applied to data that gets persisted. */
3291
+ export declare function applyDeployRemap(routing: RemoteConfig): RemoteConfig;
3292
+ /** For the dying process: fast-write flush delays must never extend past this time, and after it
3293
+ * fast writes flush immediately - so nothing is left in memory when the write window transfers. */
3294
+ export declare function getFlushDeadline(): number | undefined;
3295
+ /** How long to wait between main-port acquisition attempts: tight around the predecessor's
3296
+ * scheduled death (when the port actually frees), relaxed otherwise. */
3297
+ export declare function getMainPortAcquireDelay(): number;
3260
3298
 
3261
3299
  }
3262
3300
 
@@ -3291,6 +3329,7 @@ declare module "sliftutils/storage/remoteStorage/remoteConfig" {
3291
3329
  export declare function parseBackblazeUrl(url: string): {
3292
3330
  bucketName: string;
3293
3331
  };
3332
+ export declare function replaceHostedUrlPort(url: string, port: number): string;
3294
3333
  export declare function normalizeSource(source: RemoteConfigBase): HostedConfig | BackblazeConfig;
3295
3334
  export declare function normalizeRemoteConfig(config: RemoteConfig | RemoteConfigBase): RemoteConfig;
3296
3335
  export declare function parseRoutingData(data: Buffer): RemoteConfig;
@@ -3347,6 +3386,7 @@ declare module "sliftutils/storage/remoteStorage/storageController" {
3347
3386
  /// <reference types="node" />
3348
3387
  /// <reference types="node" />
3349
3388
  import { ArchiveFileInfo, ArchivesConfig, ArchivesSyncStatus } from "../IArchives";
3389
+ import { ServerBucketInfo } from "./storageServerState";
3350
3390
  export declare const REMOTE_STORAGE_CLASS_GUID = "RemoteStorageController-b7e42a91";
3351
3391
  export declare const STORAGE_AUTH_PURPOSE = "remoteStorage-auth-1";
3352
3392
  export declare const STORAGE_NOT_AUTHENTICATED = "REMOTE_STORAGE_NOT_AUTHENTICATED_cf2f7b1e";
@@ -3417,6 +3457,7 @@ declare module "sliftutils/storage/remoteStorage/storageController" {
3417
3457
  }) => Promise<ArchiveFileInfo[]>;
3418
3458
  getChangesAfter: (account: string, bucketName: string, time: number) => Promise<ArchiveFileInfo[]>;
3419
3459
  getArchivesConfig: (account: string, bucketName: string) => Promise<ArchivesConfig>;
3460
+ listBuckets: (account: string) => Promise<ServerBucketInfo[]>;
3420
3461
  getIndexInfo: (account: string, bucketName: string) => Promise<{
3421
3462
  fileCount: number;
3422
3463
  byteCount: number;
@@ -3459,7 +3500,7 @@ declare module "sliftutils/storage/remoteStorage/storageServerState" {
3459
3500
  /// <reference types="node" />
3460
3501
  /// <reference types="node" />
3461
3502
  import { IBucketStore } from "./blobStore";
3462
- import { RemoteConfig, HostedConfig, IArchives } from "../IArchives";
3503
+ import { RemoteConfig, HostedConfig, IArchives, ArchivesConfig } from "../IArchives";
3463
3504
  import type { IStorage } from "../IStorage";
3464
3505
  import type { AccessRequest, TrustRecord } from "./storageController";
3465
3506
  export type StorageServerConfig = {
@@ -3492,11 +3533,26 @@ declare module "sliftutils/storage/remoteStorage/storageServerState" {
3492
3533
  self: HostedConfig | undefined;
3493
3534
  store: IBucketStore;
3494
3535
  };
3536
+ export declare function addExtraListenPort(port: number): void;
3495
3537
  export declare function getLoadedBucket(account: string, bucketName: string): Promise<LoadedBucket | undefined>;
3496
3538
  export declare function assertMutable(bucket: LoadedBucket, filePath: string, writeTime: number): Promise<void>;
3497
3539
  export declare function writeBucketFile(account: string, bucketName: string, filePath: string, data: Buffer, config?: {
3498
3540
  lastModified?: number;
3499
3541
  }): Promise<void>;
3542
+ export declare function getBucketConfig(bucket: LoadedBucket): ArchivesConfig;
3543
+ export declare function rebuildAllLoadedBuckets(): Promise<void>;
3544
+ export declare function rescanAllLoadedBucketDisks(): Promise<void>;
3545
+ export type ServerBucketInfo = {
3546
+ bucketName: string;
3547
+ active: boolean;
3548
+ config?: ArchivesConfig;
3549
+ error?: string;
3550
+ };
3551
+ /** Every bucket the account has on this server, active or not, each with its configuration.
3552
+ * Inactive buckets are inspected straight from disk WITHOUT loading them - loading would start
3553
+ * their synchronization, and old invalid buckets must stay inert (their parse error is reported
3554
+ * instead). */
3555
+ export declare function listAccountBuckets(account: string): Promise<ServerBucketInfo[]>;
3500
3556
  export declare function deleteBucketFile(account: string, bucketName: string, filePath: string): Promise<void>;
3501
3557
  export declare function getLocalArchives(account: string, bucketName: string): IArchives;
3502
3558
 
@@ -1,4 +1,4 @@
1
- "use strict";
1
+ "use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
2
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
3
  if (k2 === undefined) k2 = k;
4
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -42,4 +42,4 @@ function stringifyYAML(value) {
42
42
  }
43
43
  exports.stringifyYAML = stringifyYAML;
44
44
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieWFtbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInlhbWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxpREFBbUM7QUFFbkMsU0FBZ0IsU0FBUyxDQUFDLElBQVk7SUFDbEMsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNuQixJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztRQUM3QixJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDL0MsQ0FBQztJQUNELElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3ZCLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUMvQyxDQUFDO0lBQ0QsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNuQixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDNUIsQ0FBQztBQVZELDhCQVVDO0FBRUQsU0FBZ0IsYUFBYSxDQUFDLEtBQWM7SUFDeEMsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQ2pDLENBQUM7QUFGRCxzQ0FFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIHlhbWwgZnJvbSBcIi4veWFtbEJhc2VcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlWUFNTCh0ZXh0OiBzdHJpbmcpOiB1bmtub3duIHtcbiAgICB0ZXh0ID0gdGV4dC50cmltKCk7XG4gICAgaWYgKHRleHQuc3RhcnRzV2l0aChcImBgYHlhbWxcIikpIHtcbiAgICAgICAgdGV4dCA9IHRleHQuc2xpY2UoXCJgYGB5YW1sXCIubGVuZ3RoKS50cmltKCk7XG4gICAgfVxuICAgIGlmICh0ZXh0LmVuZHNXaXRoKFwiYGBgXCIpKSB7XG4gICAgICAgIHRleHQgPSB0ZXh0LnNsaWNlKDAsIC1cImBgYFwiLmxlbmd0aCkudHJpbSgpO1xuICAgIH1cbiAgICB0ZXh0ID0gdGV4dC50cmltKCk7XG4gICAgcmV0dXJuIHlhbWwucGFyc2UodGV4dCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzdHJpbmdpZnlZQU1MKHZhbHVlOiB1bmtub3duKTogc3RyaW5nIHtcbiAgICByZXR1cm4geWFtbC5zdHJpbmdpZnkodmFsdWUpO1xufVxuXG4iXX0=
45
- /* _JS_SOURCE_HASH = "842295d9e84e235d67bbc8cd2064350a75ff84df4b6d53be8b5c7822a03528fa"; */
45
+ /* _JS_SOURCE_HASH = "6ff947dda36cc08bf827c5dfd19667e64240e3d31c748dbe0ea2852b297ed804"; */