@dbx-tools/databricks 0.6.9 → 0.6.10

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/README.md CHANGED
@@ -10,12 +10,50 @@ Key features:
10
10
 
11
11
  - Workspace URL and numeric workspace id resolution from AppKit context,
12
12
  Databricks SDK config, env, and config files.
13
+ - `DatabricksFileSystem` (`FileSystem` over workspace files, UC volumes, and DBFS)
14
+ with intelligent roots: `/Workspace/...`, `/Volumes/...` (also `/Volume/...` and
15
+ `catalog.schema.volume`), `~` → `/Workspace/Users/<userName>`, and `/dbfs/...`.
16
+ - `tryGetWorkspaceClient` / `getWorkspaceClient` / `getCurrentUserName` for client
17
+ and home-path resolution.
13
18
  - Cloud provider/region detection by resolving workspace hosts against public
14
19
  AWS, Azure, and GCP IP feeds.
15
20
  - In-process and on-disk caching for cloud IP range feeds.
16
21
  - DNS A/AAAA lookup helpers for Databricks and adjacent service hosts.
17
22
  - Memoized outbound public-IP discovery for setup and diagnostics.
18
23
 
24
+ ## Databricks filesystem
25
+
26
+ ```ts
27
+ import { DatabricksFileSystem } from "@dbx-tools/databricks";
28
+
29
+ // Unity Catalog volume via three-part id
30
+ const volume = new DatabricksFileSystem({ root: "main.default.assets" });
31
+ await volume.writeFile("notes/hello.txt", "hi");
32
+
33
+ // Workspace home (resolves ~ via currentUser.me / AppKit userName)
34
+ const home = await DatabricksFileSystem.create({ root: "~" });
35
+ const entries = await home.readdir(".");
36
+ ```
37
+
38
+ Roots are normalized before use:
39
+
40
+ | Input | Normalized root | API |
41
+ | ----------------------------------------------------------- | --------------------------------- | --------- |
42
+ | `catalog.schema.volume` | `/Volumes/catalog/schema/volume` | UC Files |
43
+ | `/Volume/...` | `/Volumes/...` | UC Files |
44
+ | `~` / `~/...` | `/Workspace/Users/<userName>/...` | Workspace |
45
+ | `/Workspace/...`, `/Users/...`, `/Repos/...`, `/Shared/...` | unchanged (POSIX) | Workspace |
46
+ | `/dbfs/...` | unchanged (POSIX) | DBFS |
47
+
48
+ `~` expansion uses `getCurrentUserName()` (AppKit context `userName`, else
49
+ `currentUser.me()` via `tryGetWorkspaceClient` / `getWorkspaceClient`). Prefer
50
+ `DatabricksFileSystem.create({ root: "~" })` when the username is not known up
51
+ front.
52
+
53
+ Built on `@dbx-tools/shared-fs` `BaseFileSystem`, so portable behavior (parents,
54
+ recursion, encoding, error mapping) is shared with `LocalFileSystem` /
55
+ `MemoryFileSystem`.
56
+
19
57
  ## Resolve Workspace Identity
20
58
 
21
59
  ```ts
@@ -61,7 +99,8 @@ short-lived reuse.
61
99
 
62
100
  ## Modules
63
101
 
64
- - `workspace` - workspace URL and numeric id resolution.
102
+ - `databricks-fs` / `databricks-path` - rooted `FileSystem` over workspace / volumes / DBFS.
103
+ - `workspace` - workspace URL/id, `tryGetWorkspaceClient` / `getWorkspaceClient`, and current username.
65
104
  - `cloud` - provider/region detection from public cloud IP ranges.
66
105
  - `net` - DNS A/AAAA resolution and outbound public-IP discovery.
67
106
 
package/index.ts CHANGED
@@ -3,9 +3,14 @@
3
3
  // Hand edits are overwritten on the next watch; this file is read-only.
4
4
 
5
5
  export * as cloud from "./src/cloud.ts";
6
+ export * as databricksFS from "./src/databricks-fs.ts";
7
+ export * as databricksPath from "./src/databricks-path.ts";
6
8
  export * as net from "./src/net.ts";
7
9
  export * as workspace from "./src/workspace.ts";
8
- export { RANGE_CACHE_TTL_MS, CloudProvider, resolveCloudLocation, loadProviderRanges } from "./src/cloud.ts";
10
+ export { RANGE_CACHE_TTL_MS, CloudProvider } from "./src/cloud.ts";
9
11
  export type { CloudLocation } from "./src/cloud.ts";
10
- export { getPublicIp, resolveHostIps } from "./src/net.ts";
11
- export { getWorkspaceUrl, getWorkspaceId } from "./src/workspace.ts";
12
+ export { DatabricksFileSystem } from "./src/databricks-fs.ts";
13
+ export type { DatabricksFileSystemOptions } from "./src/databricks-fs.ts";
14
+ export { isHomeRelativePath } from "./src/databricks-path.ts";
15
+ export type { DatabricksFilesBackend, NormalizeDatabricksRootOptions, ResolveDatabricksRootOptions } from "./src/databricks-path.ts";
16
+ export { getPublicIp } from "./src/net.ts";
package/lib/index.d.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  export * as cloud from "./src/cloud.ts";
2
+ export * as databricksFS from "./src/databricks-fs.ts";
3
+ export * as databricksPath from "./src/databricks-path.ts";
2
4
  export * as net from "./src/net.ts";
3
5
  export * as workspace from "./src/workspace.ts";
4
- export { RANGE_CACHE_TTL_MS, CloudProvider, resolveCloudLocation, loadProviderRanges } from "./src/cloud.ts";
6
+ export { RANGE_CACHE_TTL_MS, CloudProvider } from "./src/cloud.ts";
5
7
  export type { CloudLocation } from "./src/cloud.ts";
6
- export { getPublicIp, resolveHostIps } from "./src/net.ts";
7
- export { getWorkspaceUrl, getWorkspaceId } from "./src/workspace.ts";
8
+ export { DatabricksFileSystem } from "./src/databricks-fs.ts";
9
+ export type { DatabricksFileSystemOptions } from "./src/databricks-fs.ts";
10
+ export { isHomeRelativePath } from "./src/databricks-path.ts";
11
+ export type { DatabricksFilesBackend, NormalizeDatabricksRootOptions, ResolveDatabricksRootOptions } from "./src/databricks-path.ts";
12
+ export { getPublicIp } from "./src/net.ts";
package/lib/index.js CHANGED
@@ -2,9 +2,12 @@
2
2
  // Regenerated from the exporting modules in ./src.
3
3
  // Hand edits are overwritten on the next watch; this file is read-only.
4
4
  export * as cloud from "./src/cloud.js";
5
+ export * as databricksFS from "./src/databricks-fs.js";
6
+ export * as databricksPath from "./src/databricks-path.js";
5
7
  export * as net from "./src/net.js";
6
8
  export * as workspace from "./src/workspace.js";
7
- export { RANGE_CACHE_TTL_MS, CloudProvider, resolveCloudLocation, loadProviderRanges } from "./src/cloud.js";
8
- export { getPublicIp, resolveHostIps } from "./src/net.js";
9
- export { getWorkspaceUrl, getWorkspaceId } from "./src/workspace.js";
10
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssS0FBSyxNQUFNLGdCQUFnQixDQUFDO0FBQ3hDLE9BQU8sS0FBSyxHQUFHLE1BQU0sY0FBYyxDQUFDO0FBQ3BDLE9BQU8sS0FBSyxTQUFTLE1BQU0sb0JBQW9CLENBQUM7QUFDaEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLGFBQWEsRUFBRSxvQkFBb0IsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTdHLE9BQU8sRUFBRSxXQUFXLEVBQUUsY0FBYyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzNELE9BQU8sRUFBRSxlQUFlLEVBQUUsY0FBYyxFQUFFLE1BQU0sb0JBQW9CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBHRU5FUkFURUQgYnkgcHJvamVuIHdhdGNoIC0gRE8gTk9UIEVESVQuXG4vLyBSZWdlbmVyYXRlZCBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlcyBpbiAuL3NyYy5cbi8vIEhhbmQgZWRpdHMgYXJlIG92ZXJ3cml0dGVuIG9uIHRoZSBuZXh0IHdhdGNoOyB0aGlzIGZpbGUgaXMgcmVhZC1vbmx5LlxuXG5leHBvcnQgKiBhcyBjbG91ZCBmcm9tIFwiLi9zcmMvY2xvdWQudHNcIjtcbmV4cG9ydCAqIGFzIG5ldCBmcm9tIFwiLi9zcmMvbmV0LnRzXCI7XG5leHBvcnQgKiBhcyB3b3Jrc3BhY2UgZnJvbSBcIi4vc3JjL3dvcmtzcGFjZS50c1wiO1xuZXhwb3J0IHsgUkFOR0VfQ0FDSEVfVFRMX01TLCBDbG91ZFByb3ZpZGVyLCByZXNvbHZlQ2xvdWRMb2NhdGlvbiwgbG9hZFByb3ZpZGVyUmFuZ2VzIH0gZnJvbSBcIi4vc3JjL2Nsb3VkLnRzXCI7XG5leHBvcnQgdHlwZSB7IENsb3VkTG9jYXRpb24gfSBmcm9tIFwiLi9zcmMvY2xvdWQudHNcIjtcbmV4cG9ydCB7IGdldFB1YmxpY0lwLCByZXNvbHZlSG9zdElwcyB9IGZyb20gXCIuL3NyYy9uZXQudHNcIjtcbmV4cG9ydCB7IGdldFdvcmtzcGFjZVVybCwgZ2V0V29ya3NwYWNlSWQgfSBmcm9tIFwiLi9zcmMvd29ya3NwYWNlLnRzXCI7XG4iXX0=
9
+ export { RANGE_CACHE_TTL_MS, CloudProvider } from "./src/cloud.js";
10
+ export { DatabricksFileSystem } from "./src/databricks-fs.js";
11
+ export { isHomeRelativePath } from "./src/databricks-path.js";
12
+ export { getPublicIp } from "./src/net.js";
13
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwyQ0FBMkM7QUFDM0MsbURBQW1EO0FBQ25ELHdFQUF3RTtBQUV4RSxPQUFPLEtBQUssS0FBSyxNQUFNLGdCQUFnQixDQUFDO0FBQ3hDLE9BQU8sS0FBSyxZQUFZLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxLQUFLLGNBQWMsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEtBQUssR0FBRyxNQUFNLGNBQWMsQ0FBQztBQUNwQyxPQUFPLEtBQUssU0FBUyxNQUFNLG9CQUFvQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxhQUFhLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVuRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUU5RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUU5RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sY0FBYyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gR0VORVJBVEVEIGJ5IHByb2plbiB3YXRjaCAtIERPIE5PVCBFRElULlxuLy8gUmVnZW5lcmF0ZWQgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZXMgaW4gLi9zcmMuXG4vLyBIYW5kIGVkaXRzIGFyZSBvdmVyd3JpdHRlbiBvbiB0aGUgbmV4dCB3YXRjaDsgdGhpcyBmaWxlIGlzIHJlYWQtb25seS5cblxuZXhwb3J0ICogYXMgY2xvdWQgZnJvbSBcIi4vc3JjL2Nsb3VkLnRzXCI7XG5leHBvcnQgKiBhcyBkYXRhYnJpY2tzRlMgZnJvbSBcIi4vc3JjL2RhdGFicmlja3MtZnMudHNcIjtcbmV4cG9ydCAqIGFzIGRhdGFicmlja3NQYXRoIGZyb20gXCIuL3NyYy9kYXRhYnJpY2tzLXBhdGgudHNcIjtcbmV4cG9ydCAqIGFzIG5ldCBmcm9tIFwiLi9zcmMvbmV0LnRzXCI7XG5leHBvcnQgKiBhcyB3b3Jrc3BhY2UgZnJvbSBcIi4vc3JjL3dvcmtzcGFjZS50c1wiO1xuZXhwb3J0IHsgUkFOR0VfQ0FDSEVfVFRMX01TLCBDbG91ZFByb3ZpZGVyIH0gZnJvbSBcIi4vc3JjL2Nsb3VkLnRzXCI7XG5leHBvcnQgdHlwZSB7IENsb3VkTG9jYXRpb24gfSBmcm9tIFwiLi9zcmMvY2xvdWQudHNcIjtcbmV4cG9ydCB7IERhdGFicmlja3NGaWxlU3lzdGVtIH0gZnJvbSBcIi4vc3JjL2RhdGFicmlja3MtZnMudHNcIjtcbmV4cG9ydCB0eXBlIHsgRGF0YWJyaWNrc0ZpbGVTeXN0ZW1PcHRpb25zIH0gZnJvbSBcIi4vc3JjL2RhdGFicmlja3MtZnMudHNcIjtcbmV4cG9ydCB7IGlzSG9tZVJlbGF0aXZlUGF0aCB9IGZyb20gXCIuL3NyYy9kYXRhYnJpY2tzLXBhdGgudHNcIjtcbmV4cG9ydCB0eXBlIHsgRGF0YWJyaWNrc0ZpbGVzQmFja2VuZCwgTm9ybWFsaXplRGF0YWJyaWNrc1Jvb3RPcHRpb25zLCBSZXNvbHZlRGF0YWJyaWNrc1Jvb3RPcHRpb25zIH0gZnJvbSBcIi4vc3JjL2RhdGFicmlja3MtcGF0aC50c1wiO1xuZXhwb3J0IHsgZ2V0UHVibGljSXAgfSBmcm9tIFwiLi9zcmMvbmV0LnRzXCI7XG4iXX0=
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Databricks {@link FileSystem} backed by {@link WorkspaceClient}.
3
+ *
4
+ * Extends {@link BaseFileSystem}. Routes I/O by absolute path:
5
+ * - `/Workspace`, `/Users`, `/Repos`, `/Shared` → workspace objects API
6
+ * - `/Volumes/...` (or `catalog.schema.volume` roots) → Unity Catalog Files API
7
+ * - `/dbfs/...` → DBFS API
8
+ *
9
+ * Every primitive picks its API through {@link DatabricksFileSystem.dispatch}
10
+ * rather than re-branching by hand, and error normalization is inherited from
11
+ * {@link BaseFileSystem}, so a primitive here is just the SDK call.
12
+ *
13
+ * @module
14
+ */
15
+ import { WorkspaceClient } from "@databricks/sdk-experimental";
16
+ import { BaseFileSystem, type CopyOptions, type FileEntry, type FileStat, type WriteFileOptions } from "@dbx-tools/shared-fs";
17
+ /** Options for {@link DatabricksFileSystem}. */
18
+ export interface DatabricksFileSystemOptions {
19
+ /** Unique identifier. Defaults to a stable hash of the normalized root. */
20
+ id?: string;
21
+ /**
22
+ * Filesystem root. Accepts:
23
+ * - `/Volumes/catalog/schema/volume` (also `/Volume/...`)
24
+ * - `catalog.schema.volume`
25
+ * - `~` / `~/...` → `/Workspace/Users/<userName>/...` (needs {@link userName},
26
+ * or use {@link DatabricksFileSystem.create})
27
+ * - `/Workspace/...`, `/Users/...`, `/Repos/...`, `/Shared/...`
28
+ * - `/dbfs/...`
29
+ */
30
+ root: string;
31
+ /**
32
+ * Username for expanding `~`. When omitted and {@link root} is home-relative,
33
+ * prefer {@link DatabricksFileSystem.create} which resolves it via
34
+ * `getCurrentUserName`.
35
+ */
36
+ userName?: string;
37
+ /**
38
+ * Databricks workspace client. Defaults to `tryGetWorkspaceClient()`, otherwise
39
+ * a default {@link WorkspaceClient} from env / profile auth.
40
+ */
41
+ client?: WorkspaceClient;
42
+ /** Block all write operations. Defaults to false. */
43
+ readOnly?: boolean;
44
+ /**
45
+ * Create {@link root} (and parents) during init. Defaults to false (volume
46
+ * and workspace roots are usually provisioned out of band).
47
+ */
48
+ createRoot?: boolean;
49
+ }
50
+ /**
51
+ * {@link FileSystem} implementation over Databricks workspace files, UC
52
+ * volumes, and DBFS.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * const fs = new DatabricksFileSystem({ root: "main.default.assets" });
57
+ * await fs.writeFile("notes/hello.txt", "hi");
58
+ *
59
+ * const home = await DatabricksFileSystem.create({ root: "~" });
60
+ * const listing = await home.readdir(".");
61
+ * ```
62
+ */
63
+ export declare class DatabricksFileSystem extends BaseFileSystem<"databricks"> {
64
+ private client;
65
+ private readonly clientOption;
66
+ constructor(options: DatabricksFileSystemOptions);
67
+ /**
68
+ * Construct a {@link DatabricksFileSystem}, resolving `~` roots via the
69
+ * workspace current user when needed.
70
+ */
71
+ static create(options: DatabricksFileSystemOptions): Promise<DatabricksFileSystem>;
72
+ protected onInit(): Promise<void>;
73
+ /** Run the handler for `absolutePath`'s Databricks API with the live client. */
74
+ private dispatch;
75
+ protected createRootDirectory(): Promise<void>;
76
+ protected readBytesAt(resolvedPath: string): Promise<Uint8Array>;
77
+ protected writeBytesAt(resolvedPath: string, content: Uint8Array, options: Required<WriteFileOptions>): Promise<void>;
78
+ protected deleteFileAt(resolvedPath: string): Promise<void>;
79
+ protected createDirectoryAt(resolvedPath: string): Promise<void>;
80
+ protected removeDirectoryAt(resolvedPath: string): Promise<void>;
81
+ protected listDirectoryAt(resolvedPath: string): Promise<FileEntry[]>;
82
+ protected statAt(resolvedPath: string): Promise<Omit<FileStat, "path">>;
83
+ protected tryMoveFileAt(sourcePath: string, destinationPath: string, _options: Required<CopyOptions>): Promise<boolean>;
84
+ /**
85
+ * UC `createDirectory` is single-level, so walk the path creating each level
86
+ * below the volume itself. A level that already exists is not an error.
87
+ */
88
+ private createVolumeDirectories;
89
+ /** Stat a UC path: file metadata first, then a directory probe. */
90
+ private statVolumePath;
91
+ private readDbfsFile;
92
+ private writeDbfsFile;
93
+ }
@@ -0,0 +1,330 @@
1
+ /**
2
+ * Databricks {@link FileSystem} backed by {@link WorkspaceClient}.
3
+ *
4
+ * Extends {@link BaseFileSystem}. Routes I/O by absolute path:
5
+ * - `/Workspace`, `/Users`, `/Repos`, `/Shared` → workspace objects API
6
+ * - `/Volumes/...` (or `catalog.schema.volume` roots) → Unity Catalog Files API
7
+ * - `/dbfs/...` → DBFS API
8
+ *
9
+ * Every primitive picks its API through {@link DatabricksFileSystem.dispatch}
10
+ * rather than re-branching by hand, and error normalization is inherited from
11
+ * {@link BaseFileSystem}, so a primitive here is just the SDK call.
12
+ *
13
+ * @module
14
+ */
15
+ import { hash } from "@dbx-tools/shared-core";
16
+ import { BaseFileSystem, baseFS, FileSystemError, posixPath, } from "@dbx-tools/shared-fs";
17
+ import { isHomeRelativePath, normalizeDatabricksRoot, resolveDatabricksFilesBackend, resolveDatabricksRoot, } from "./databricks-path.js";
18
+ import { getWorkspaceClient } from "./workspace.js";
19
+ const DBFS_READ_CHUNK_BYTES = 1024 * 1024;
20
+ const DBFS_PUT_MAX_BYTES = 1024 * 1024;
21
+ /** Segments in `/Volumes/<catalog>/<schema>/<volume>`, provisioned out of band. */
22
+ const VOLUME_ROOT_DEPTH = 4;
23
+ /**
24
+ * {@link FileSystem} implementation over Databricks workspace files, UC
25
+ * volumes, and DBFS.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const fs = new DatabricksFileSystem({ root: "main.default.assets" });
30
+ * await fs.writeFile("notes/hello.txt", "hi");
31
+ *
32
+ * const home = await DatabricksFileSystem.create({ root: "~" });
33
+ * const listing = await home.readdir(".");
34
+ * ```
35
+ */
36
+ export class DatabricksFileSystem extends BaseFileSystem {
37
+ client;
38
+ clientOption;
39
+ constructor(options) {
40
+ const root = normalizeDatabricksRoot(options.root, { userName: options.userName });
41
+ super({
42
+ id: options.id ?? `databricks-${hash.fnvHash(root)}`,
43
+ backend: "databricks",
44
+ root,
45
+ readOnly: options.readOnly,
46
+ createRoot: options.createRoot ?? false,
47
+ });
48
+ this.clientOption = options.client;
49
+ this.client = options.client;
50
+ }
51
+ /**
52
+ * Construct a {@link DatabricksFileSystem}, resolving `~` roots via the
53
+ * workspace current user when needed.
54
+ */
55
+ static async create(options) {
56
+ if (!isHomeRelativePath(options.root) || options.userName?.trim()) {
57
+ return new DatabricksFileSystem(options);
58
+ }
59
+ const client = options.client ?? (await getWorkspaceClient());
60
+ const root = await resolveDatabricksRoot(options.root, { client });
61
+ return new DatabricksFileSystem({ ...options, root, client });
62
+ }
63
+ async onInit() {
64
+ this.client = this.clientOption ?? (await getWorkspaceClient());
65
+ }
66
+ /** Run the handler for `absolutePath`'s Databricks API with the live client. */
67
+ dispatch(absolutePath, handlers) {
68
+ if (!this.client) {
69
+ throw new FileSystemError("IO_ERROR", "Databricks filesystem is not initialized (no WorkspaceClient)", absolutePath);
70
+ }
71
+ return handlers[resolveDatabricksFilesBackend(absolutePath)](this.client);
72
+ }
73
+ /* ------------------------------------------------------------------ */
74
+ /* Primitives */
75
+ /* ------------------------------------------------------------------ */
76
+ async createRootDirectory() {
77
+ await this.createDirectoryAt(this.root);
78
+ }
79
+ async readBytesAt(resolvedPath) {
80
+ const buffer = await this.dispatch(resolvedPath, {
81
+ dbfs: (client) => this.readDbfsFile(client, resolvedPath),
82
+ workspace: async (client) => {
83
+ const response = await client.workspace.export({ path: resolvedPath, format: "AUTO" });
84
+ return decodeBase64(response.content);
85
+ },
86
+ volumes: async (client) => {
87
+ const response = await client.files.download({ file_path: resolvedPath });
88
+ return readResponseBody(response.contents);
89
+ },
90
+ });
91
+ return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
92
+ }
93
+ async writeBytesAt(resolvedPath, content, options) {
94
+ const buffer = Buffer.from(content);
95
+ const overwrite = options.overwrite;
96
+ await this.dispatch(resolvedPath, {
97
+ dbfs: (client) => this.writeDbfsFile(client, resolvedPath, buffer, overwrite),
98
+ workspace: (client) => client.workspace.import({
99
+ path: resolvedPath,
100
+ format: "AUTO",
101
+ content: buffer.toString("base64"),
102
+ overwrite,
103
+ }),
104
+ volumes: (client) => client.files.upload({
105
+ file_path: resolvedPath,
106
+ contents: bufferToReadableStream(buffer),
107
+ overwrite,
108
+ }),
109
+ });
110
+ }
111
+ async deleteFileAt(resolvedPath) {
112
+ await this.dispatch(resolvedPath, {
113
+ dbfs: (client) => client.dbfs.delete({ path: resolvedPath, recursive: false }),
114
+ workspace: (client) => client.workspace.delete({ path: resolvedPath, recursive: false }),
115
+ volumes: (client) => client.files.delete({ file_path: resolvedPath }),
116
+ });
117
+ }
118
+ async createDirectoryAt(resolvedPath) {
119
+ await this.dispatch(resolvedPath, {
120
+ dbfs: (client) => client.dbfs.mkdirs({ path: resolvedPath }),
121
+ workspace: (client) => client.workspace.mkdirs({ path: resolvedPath }),
122
+ volumes: (client) => this.createVolumeDirectories(client, resolvedPath),
123
+ });
124
+ }
125
+ async removeDirectoryAt(resolvedPath) {
126
+ await this.dispatch(resolvedPath, {
127
+ dbfs: (client) => client.dbfs.delete({ path: resolvedPath, recursive: false }),
128
+ workspace: (client) => client.workspace.delete({ path: resolvedPath, recursive: false }),
129
+ volumes: (client) => client.files.deleteDirectory({ directory_path: resolvedPath }),
130
+ });
131
+ }
132
+ async listDirectoryAt(resolvedPath) {
133
+ return this.dispatch(resolvedPath, {
134
+ dbfs: (client) => collect(client.dbfs.list({ path: resolvedPath }), (info) => ({
135
+ name: posixPath.basename(info.path ?? ""),
136
+ type: info.is_dir ? "directory" : "file",
137
+ size: info.file_size,
138
+ })),
139
+ workspace: (client) => collect(client.workspace.list({ path: resolvedPath }), (info) => ({
140
+ name: posixPath.basename(info.path ?? ""),
141
+ type: info.object_type === "DIRECTORY" ? "directory" : "file",
142
+ })),
143
+ volumes: (client) => collect(client.files.listDirectoryContents({ directory_path: resolvedPath }), (entry) => ({
144
+ name: entry.name ?? posixPath.basename(entry.path ?? ""),
145
+ type: entry.is_directory ? "directory" : "file",
146
+ size: entry.file_size,
147
+ })),
148
+ });
149
+ }
150
+ async statAt(resolvedPath) {
151
+ const fallbackName = posixPath.basename(resolvedPath) || posixPath.basename(this.root);
152
+ return this.dispatch(resolvedPath, {
153
+ dbfs: async (client) => {
154
+ const info = await client.dbfs.getStatus({ path: resolvedPath });
155
+ const modified = toDate(info.modification_time);
156
+ return {
157
+ name: posixPath.basename(info.path ?? resolvedPath) || fallbackName,
158
+ type: info.is_dir ? "directory" : "file",
159
+ size: info.file_size,
160
+ createdAt: modified,
161
+ modifiedAt: modified,
162
+ };
163
+ },
164
+ workspace: async (client) => {
165
+ const info = await client.workspace.getStatus({ path: resolvedPath });
166
+ return {
167
+ name: posixPath.basename(info.path ?? resolvedPath) || fallbackName,
168
+ type: info.object_type === "DIRECTORY" ? "directory" : "file",
169
+ createdAt: toDate(info.created_at),
170
+ modifiedAt: toDate(info.modified_at),
171
+ };
172
+ },
173
+ volumes: (client) => this.statVolumePath(client, resolvedPath, fallbackName),
174
+ });
175
+ }
176
+ async tryMoveFileAt(sourcePath, destinationPath, _options) {
177
+ // Only DBFS exposes a server-side move; everything else falls back to the
178
+ // portable copy + delete in BaseFileSystem.
179
+ if (resolveDatabricksFilesBackend(sourcePath) !== "dbfs" ||
180
+ resolveDatabricksFilesBackend(destinationPath) !== "dbfs") {
181
+ return false;
182
+ }
183
+ await this.dispatch(sourcePath, {
184
+ dbfs: (client) => client.dbfs.move({ source_path: sourcePath, destination_path: destinationPath }),
185
+ workspace: unreachableBackend,
186
+ volumes: unreachableBackend,
187
+ });
188
+ return true;
189
+ }
190
+ /* ------------------------------------------------------------------ */
191
+ /* Backend-specific I/O */
192
+ /* ------------------------------------------------------------------ */
193
+ /**
194
+ * UC `createDirectory` is single-level, so walk the path creating each level
195
+ * below the volume itself. A level that already exists is not an error.
196
+ */
197
+ async createVolumeDirectories(client, absolutePath) {
198
+ const parts = absolutePath.split("/").filter(Boolean);
199
+ let current = "";
200
+ for (let i = 0; i < parts.length; i++) {
201
+ current = `${current}/${parts[i]}`;
202
+ if (i < VOLUME_ROOT_DEPTH)
203
+ continue;
204
+ try {
205
+ await client.files.createDirectory({ directory_path: current });
206
+ }
207
+ catch (err) {
208
+ // Already present is fine; anything else is a real failure.
209
+ try {
210
+ await client.files.getDirectoryMetadata({ directory_path: current });
211
+ }
212
+ catch {
213
+ throw err;
214
+ }
215
+ }
216
+ }
217
+ }
218
+ /** Stat a UC path: file metadata first, then a directory probe. */
219
+ async statVolumePath(client, absolutePath, fallbackName) {
220
+ try {
221
+ const metadata = await client.files.getMetadata({ file_path: absolutePath });
222
+ const modified = parseHttpDate(metadata["last-modified"]);
223
+ return {
224
+ name: fallbackName,
225
+ type: "file",
226
+ size: Number(metadata["content-length"] ?? 0),
227
+ createdAt: modified,
228
+ modifiedAt: modified,
229
+ mimeType: metadata["content-type"],
230
+ };
231
+ }
232
+ catch (fileErr) {
233
+ // A directory has no file metadata, and an unreadable one reports as
234
+ // missing / denied - both are worth a directory probe before failing.
235
+ const code = baseFS.mapFileSystemError(fileErr, absolutePath).code;
236
+ if (code !== "NOT_FOUND" && code !== "PERMISSION_DENIED")
237
+ throw fileErr;
238
+ await client.files.getDirectoryMetadata({ directory_path: absolutePath });
239
+ return { name: fallbackName, type: "directory" };
240
+ }
241
+ }
242
+ async readDbfsFile(client, absolutePath) {
243
+ const chunks = [];
244
+ let offset = 0;
245
+ while (true) {
246
+ const response = await client.dbfs.read({
247
+ path: absolutePath,
248
+ offset,
249
+ length: DBFS_READ_CHUNK_BYTES,
250
+ });
251
+ const chunk = decodeBase64(response.data);
252
+ if (chunk.length === 0)
253
+ break;
254
+ chunks.push(chunk);
255
+ offset += chunk.length;
256
+ if (chunk.length < DBFS_READ_CHUNK_BYTES)
257
+ break;
258
+ }
259
+ return Buffer.concat(chunks);
260
+ }
261
+ async writeDbfsFile(client, absolutePath, buffer, overwrite) {
262
+ if (buffer.length <= DBFS_PUT_MAX_BYTES) {
263
+ await client.dbfs.put({
264
+ path: absolutePath,
265
+ contents: buffer.toString("base64"),
266
+ overwrite,
267
+ });
268
+ return;
269
+ }
270
+ const created = await client.dbfs.create({ path: absolutePath, overwrite });
271
+ const handle = created.handle;
272
+ if (handle === undefined) {
273
+ throw new FileSystemError("IO_ERROR", "DBFS upload handle missing", absolutePath);
274
+ }
275
+ for (let offset = 0; offset < buffer.length; offset += DBFS_PUT_MAX_BYTES) {
276
+ const slice = buffer.subarray(offset, offset + DBFS_PUT_MAX_BYTES);
277
+ await client.dbfs.addBlock({ handle, data: slice.toString("base64") });
278
+ }
279
+ await client.dbfs.close({ handle });
280
+ }
281
+ }
282
+ /* ------------------------------ helpers ------------------------------ */
283
+ /** Drain an SDK async iterable into a mapped array. */
284
+ async function collect(source, map) {
285
+ const items = [];
286
+ for await (const item of source)
287
+ items.push(map(item));
288
+ return items;
289
+ }
290
+ /** Handler for a backend a call site has already ruled out. */
291
+ function unreachableBackend() {
292
+ throw new FileSystemError("NOT_SUPPORTED", "Unsupported Databricks backend for this operation");
293
+ }
294
+ function decodeBase64(data) {
295
+ if (!data)
296
+ return Buffer.alloc(0);
297
+ return Buffer.from(data, "base64");
298
+ }
299
+ async function readResponseBody(contents) {
300
+ if (!contents)
301
+ return Buffer.alloc(0);
302
+ const reader = contents.getReader();
303
+ const chunks = [];
304
+ while (true) {
305
+ const { done, value } = await reader.read();
306
+ if (done)
307
+ break;
308
+ if (value)
309
+ chunks.push(value);
310
+ }
311
+ return Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)));
312
+ }
313
+ function bufferToReadableStream(buffer) {
314
+ return new ReadableStream({
315
+ start(controller) {
316
+ controller.enqueue(new Uint8Array(buffer));
317
+ controller.close();
318
+ },
319
+ });
320
+ }
321
+ function toDate(value) {
322
+ return value === undefined ? undefined : new Date(value);
323
+ }
324
+ function parseHttpDate(value) {
325
+ if (!value)
326
+ return undefined;
327
+ const parsed = Date.parse(value);
328
+ return Number.isFinite(parsed) ? new Date(parsed) : undefined;
329
+ }
330
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YWJyaWNrcy1mcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhYnJpY2tzLWZzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7O0dBYUc7QUFHSCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDOUMsT0FBTyxFQUNMLGNBQWMsRUFDZCxNQUFNLEVBQ04sZUFBZSxFQUNmLFNBQVMsR0FLVixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsdUJBQXVCLEVBQ3ZCLDZCQUE2QixFQUM3QixxQkFBcUIsR0FFdEIsTUFBTSxzQkFBc0IsQ0FBQztBQUM5QixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVwRCxNQUFNLHFCQUFxQixHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFDMUMsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBRXZDLG1GQUFtRjtBQUNuRixNQUFNLGlCQUFpQixHQUFHLENBQUMsQ0FBQztBQStDNUI7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsTUFBTSxPQUFPLG9CQUFxQixTQUFRLGNBQTRCO0lBQzVELE1BQU0sQ0FBOEI7SUFDM0IsWUFBWSxDQUE4QjtJQUUzRCxZQUFZLE9BQW9DO1FBQzlDLE1BQU0sSUFBSSxHQUFHLHVCQUF1QixDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsRUFBRSxRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDbkYsS0FBSyxDQUFDO1lBQ0osRUFBRSxFQUFFLE9BQU8sQ0FBQyxFQUFFLElBQUksY0FBYyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ3BELE9BQU8sRUFBRSxZQUFZO1lBQ3JCLElBQUk7WUFDSixRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVE7WUFDMUIsVUFBVSxFQUFFLE9BQU8sQ0FB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S0FBSyxDQUFDLENBQUM7SUFDakMsT0FBTyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0FBQ2hFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIERhdGFicmlja3Mge0BsaW5rIEZpbGVTeXN0ZW19IGJhY2tlZCBieSB7QGxpbmsgV29ya3NwYWNlQ2xpZW50fS5cbiAqXG4gKiBFeHRlbmRzIHtAbGluayBCYXNlRmlsZVN5c3RlbX0uIFJvdXRlcyBJL08gYnkgYWJzb2x1dGUgcGF0aDpcbiAqIC0gYC9Xb3Jrc3BhY2VgLCBgL1VzZXJzYCwgYC9SZXBvc2AsIGAvU2hhcmVkYCDihpIgd29ya3NwYWNlIG9iamVjdHMgQVBJXG4gKiAtIGAvVm9sdW1lcy8uLi5gIChvciBgY2F0YWxvZy5zY2hlbWEudm9sdW1lYCByb290cykg4oaSIFVuaXR5IENhdGFsb2cgRmlsZXMgQVBJXG4gKiAtIGAvZGJmcy8uLi5gIOKGkiBEQkZTIEFQSVxuICpcbiAqIEV2ZXJ5IHByaW1pdGl2ZSBwaWNrcyBpdHMgQVBJIHRocm91Z2gge0BsaW5rIERhdGFicmlja3NGaWxlU3lzdGVtLmRpc3BhdGNofVxuICogcmF0aGVyIHRoYW4gcmUtYnJhbmNoaW5nIGJ5IGhhbmQsIGFuZCBlcnJvciBub3JtYWxpemF0aW9uIGlzIGluaGVyaXRlZCBmcm9tXG4gKiB7QGxpbmsgQmFzZUZpbGVTeXN0ZW19LCBzbyBhIHByaW1pdGl2ZSBoZXJlIGlzIGp1c3QgdGhlIFNESyBjYWxsLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBXb3Jrc3BhY2VDbGllbnQgfSBmcm9tIFwiQGRhdGFicmlja3Mvc2RrLWV4cGVyaW1lbnRhbFwiO1xuaW1wb3J0IHsgaGFzaCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQge1xuICBCYXNlRmlsZVN5c3RlbSxcbiAgYmFzZUZTLFxuICBGaWxlU3lzdGVtRXJyb3IsXG4gIHBvc2l4UGF0aCxcbiAgdHlwZSBDb3B5T3B0aW9ucyxcbiAgdHlwZSBGaWxlRW50cnksXG4gIHR5cGUgRmlsZVN0YXQsXG4gIHR5cGUgV3JpdGVGaWxlT3B0aW9ucyxcbn0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWZzXCI7XG5pbXBvcnQge1xuICBpc0hvbWVSZWxhdGl2ZVBhdGgsXG4gIG5vcm1hbGl6ZURhdGFicmlja3NSb290LFxuICByZXNvbHZlRGF0YWJyaWNrc0ZpbGVzQmFja2VuZCxcbiAgcmVzb2x2ZURhdGFicmlja3NSb290LFxuICB0eXBlIERhdGFicmlja3NGaWxlc0JhY2tlbmQsXG59IGZyb20gXCIuL2RhdGFicmlja3MtcGF0aC50c1wiO1xuaW1wb3J0IHsgZ2V0V29ya3NwYWNlQ2xpZW50IH0gZnJvbSBcIi4vd29ya3NwYWNlLnRzXCI7XG5cbmNvbnN0IERCRlNfUkVBRF9DSFVOS19CWVRFUyA9IDEwMjQgKiAxMDI0O1xuY29uc3QgREJGU19QVVRfTUFYX0JZVEVTID0gMTAyNCAqIDEwMjQ7XG5cbi8qKiBTZWdtZW50cyBpbiBgL1ZvbHVtZXMvPGNhdGFsb2c+LzxzY2hlbWE+Lzx2b2x1bWU+YCwgcHJvdmlzaW9uZWQgb3V0IG9mIGJhbmQuICovXG5jb25zdCBWT0xVTUVfUk9PVF9ERVBUSCA9IDQ7XG5cbi8qKlxuICogT25lIGhhbmRsZXIgcGVyIERhdGFicmlja3MgQVBJLCBrZXllZCBieSB7QGxpbmsgRGF0YWJyaWNrc0ZpbGVzQmFja2VuZH0gc29cbiAqIGFkZGluZyBhIGJhY2tlbmQgaXMgYSBjb21waWxlIGVycm9yIHVudGlsIGV2ZXJ5IGNhbGwgc2l0ZSBoYW5kbGVzIGl0LlxuICovXG50eXBlIEJhY2tlbmRIYW5kbGVyczxUPiA9IFJlY29yZDxEYXRhYnJpY2tzRmlsZXNCYWNrZW5kLCAoY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQpID0+IFByb21pc2U8VD4+O1xuXG4vKiogT3B0aW9ucyBmb3Ige0BsaW5rIERhdGFicmlja3NGaWxlU3lzdGVtfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRGF0YWJyaWNrc0ZpbGVTeXN0ZW1PcHRpb25zIHtcbiAgLyoqIFVuaXF1ZSBpZGVudGlmaWVyLiBEZWZhdWx0cyB0byBhIHN0YWJsZSBoYXNoIG9mIHRoZSBub3JtYWxpemVkIHJvb3QuICovXG4gIGlkPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBGaWxlc3lzdGVtIHJvb3QuIEFjY2VwdHM6XG4gICAqIC0gYC9Wb2x1bWVzL2NhdGFsb2cvc2NoZW1hL3ZvbHVtZWAgKGFsc28gYC9Wb2x1bWUvLi4uYClcbiAgICogLSBgY2F0YWxvZy5zY2hlbWEudm9sdW1lYFxuICAgKiAtIGB+YCAvIGB+Ly4uLmAg4oaSIGAvV29ya3NwYWNlL1VzZXJzLzx1c2VyTmFtZT4vLi4uYCAobmVlZHMge0BsaW5rIHVzZXJOYW1lfSxcbiAgICogICBvciB1c2Uge0BsaW5rIERhdGFicmlja3NGaWxlU3lzdGVtLmNyZWF0ZX0pXG4gICAqIC0gYC9Xb3Jrc3BhY2UvLi4uYCwgYC9Vc2Vycy8uLi5gLCBgL1JlcG9zLy4uLmAsIGAvU2hhcmVkLy4uLmBcbiAgICogLSBgL2RiZnMvLi4uYFxuICAgKi9cbiAgcm9vdDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBVc2VybmFtZSBmb3IgZXhwYW5kaW5nIGB+YC4gV2hlbiBvbWl0dGVkIGFuZCB7QGxpbmsgcm9vdH0gaXMgaG9tZS1yZWxhdGl2ZSxcbiAgICogcHJlZmVyIHtAbGluayBEYXRhYnJpY2tzRmlsZVN5c3RlbS5jcmVhdGV9IHdoaWNoIHJlc29sdmVzIGl0IHZpYVxuICAgKiBgZ2V0Q3VycmVudFVzZXJOYW1lYC5cbiAgICovXG4gIHVzZXJOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBEYXRhYnJpY2tzIHdvcmtzcGFjZSBjbGllbnQuIERlZmF1bHRzIHRvIGB0cnlHZXRXb3Jrc3BhY2VDbGllbnQoKWAsIG90aGVyd2lzZVxuICAgKiBhIGRlZmF1bHQge0BsaW5rIFdvcmtzcGFjZUNsaWVudH0gZnJvbSBlbnYgLyBwcm9maWxlIGF1dGguXG4gICAqL1xuICBjbGllbnQ/OiBXb3Jrc3BhY2VDbGllbnQ7XG5cbiAgLyoqIEJsb2NrIGFsbCB3cml0ZSBvcGVyYXRpb25zLiBEZWZhdWx0cyB0byBmYWxzZS4gKi9cbiAgcmVhZE9ubHk/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBDcmVhdGUge0BsaW5rIHJvb3R9IChhbmQgcGFyZW50cykgZHVyaW5nIGluaXQuIERlZmF1bHRzIHRvIGZhbHNlICh2b2x1bWVcbiAgICogYW5kIHdvcmtzcGFjZSByb290cyBhcmUgdXN1YWxseSBwcm92aXNpb25lZCBvdXQgb2YgYmFuZCkuXG4gICAqL1xuICBjcmVhdGVSb290PzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiB7QGxpbmsgRmlsZVN5c3RlbX0gaW1wbGVtZW50YXRpb24gb3ZlciBEYXRhYnJpY2tzIHdvcmtzcGFjZSBmaWxlcywgVUNcbiAqIHZvbHVtZXMsIGFuZCBEQkZTLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c1xuICogY29uc3QgZnMgPSBuZXcgRGF0YWJyaWNrc0ZpbGVTeXN0ZW0oeyByb290OiBcIm1haW4uZGVmYXVsdC5hc3NldHNcIiB9KTtcbiAqIGF3YWl0IGZzLndyaXRlRmlsZShcIm5vdGVzL2hlbGxvLnR4dFwiLCBcImhpXCIpO1xuICpcbiAqIGNvbnN0IGhvbWUgPSBhd2FpdCBEYXRhYnJpY2tzRmlsZVN5c3RlbS5jcmVhdGUoeyByb290OiBcIn5cIiB9KTtcbiAqIGNvbnN0IGxpc3RpbmcgPSBhd2FpdCBob21lLnJlYWRkaXIoXCIuXCIpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBjbGFzcyBEYXRhYnJpY2tzRmlsZVN5c3RlbSBleHRlbmRzIEJhc2VGaWxlU3lzdGVtPFwiZGF0YWJyaWNrc1wiPiB7XG4gIHByaXZhdGUgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQgfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgY2xpZW50T3B0aW9uOiBXb3Jrc3BhY2VDbGllbnQgfCB1bmRlZmluZWQ7XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogRGF0YWJyaWNrc0ZpbGVTeXN0ZW1PcHRpb25zKSB7XG4gICAgY29uc3Qgcm9vdCA9IG5vcm1hbGl6ZURhdGFicmlja3NSb290KG9wdGlvbnMucm9vdCwgeyB1c2VyTmFtZTogb3B0aW9ucy51c2VyTmFtZSB9KTtcbiAgICBzdXBlcih7XG4gICAgICBpZDogb3B0aW9ucy5pZCA/PyBgZGF0YWJyaWNrcy0ke2hhc2guZm52SGFzaChyb290KX1gLFxuICAgICAgYmFja2VuZDogXCJkYXRhYnJpY2tzXCIsXG4gICAgICByb290LFxuICAgICAgcmVhZE9ubHk6IG9wdGlvbnMucmVhZE9ubHksXG4gICAgICBjcmVhdGVSb290OiBvcHRpb25zLmNyZWF0ZVJvb3QgPz8gZmFsc2UsXG4gICAgfSk7XG4gICAgdGhpcy5jbGllbnRPcHRpb24gPSBvcHRpb25zLmNsaWVudDtcbiAgICB0aGlzLmNsaWVudCA9IG9wdGlvbnMuY2xpZW50O1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdCBhIHtAbGluayBEYXRhYnJpY2tzRmlsZVN5c3RlbX0sIHJlc29sdmluZyBgfmAgcm9vdHMgdmlhIHRoZVxuICAgKiB3b3Jrc3BhY2UgY3VycmVudCB1c2VyIHdoZW4gbmVlZGVkLlxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGNyZWF0ZShvcHRpb25zOiBEYXRhYnJpY2tzRmlsZVN5c3RlbU9wdGlvbnMpOiBQcm9taXNlPERhdGFicmlja3NGaWxlU3lzdGVtPiB7XG4gICAgaWYgKCFpc0hvbWVSZWxhdGl2ZVBhdGgob3B0aW9ucy5yb290KSB8fCBvcHRpb25zLnVzZXJOYW1lPy50cmltKCkpIHtcbiAgICAgIHJldHVybiBuZXcgRGF0YWJyaWNrc0ZpbGVTeXN0ZW0ob3B0aW9ucyk7XG4gICAgfVxuICAgIGNvbnN0IGNsaWVudCA9IG9wdGlvbnMuY2xpZW50ID8/IChhd2FpdCBnZXRXb3Jrc3BhY2VDbGllbnQoKSk7XG4gICAgY29uc3Qgcm9vdCA9IGF3YWl0IHJlc29sdmVEYXRhYnJpY2tzUm9vdChvcHRpb25zLnJvb3QsIHsgY2xpZW50IH0pO1xuICAgIHJldHVybiBuZXcgRGF0YWJyaWNrc0ZpbGVTeXN0ZW0oeyAuLi5vcHRpb25zLCByb290LCBjbGllbnQgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgb25Jbml0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMuY2xpZW50ID0gdGhpcy5jbGllbnRPcHRpb24gPz8gKGF3YWl0IGdldFdvcmtzcGFjZUNsaWVudCgpKTtcbiAgfVxuXG4gIC8qKiBSdW4gdGhlIGhhbmRsZXIgZm9yIGBhYnNvbHV0ZVBhdGhgJ3MgRGF0YWJyaWNrcyBBUEkgd2l0aCB0aGUgbGl2ZSBjbGllbnQuICovXG4gIHByaXZhdGUgZGlzcGF0Y2g8VD4oYWJzb2x1dGVQYXRoOiBzdHJpbmcsIGhhbmRsZXJzOiBCYWNrZW5kSGFuZGxlcnM8VD4pOiBQcm9taXNlPFQ+IHtcbiAgICBpZiAoIXRoaXMuY2xpZW50KSB7XG4gICAgICB0aHJvdyBuZXcgRmlsZVN5c3RlbUVycm9yKFxuICAgICAgICBcIklPX0VSUk9SXCIsXG4gICAgICAgIFwiRGF0YWJyaWNrcyBmaWxlc3lzdGVtIGlzIG5vdCBpbml0aWFsaXplZCAobm8gV29ya3NwYWNlQ2xpZW50KVwiLFxuICAgICAgICBhYnNvbHV0ZVBhdGgsXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gaGFuZGxlcnNbcmVzb2x2ZURhdGFicmlja3NGaWxlc0JhY2tlbmQoYWJzb2x1dGVQYXRoKV0odGhpcy5jbGllbnQpO1xuICB9XG5cbiAgLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG4gIC8qIFByaW1pdGl2ZXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqL1xuICAvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgY3JlYXRlUm9vdERpcmVjdG9yeSgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmNyZWF0ZURpcmVjdG9yeUF0KHRoaXMucm9vdCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgcmVhZEJ5dGVzQXQocmVzb2x2ZWRQYXRoOiBzdHJpbmcpOiBQcm9taXNlPFVpbnQ4QXJyYXk+IHtcbiAgICBjb25zdCBidWZmZXIgPSBhd2FpdCB0aGlzLmRpc3BhdGNoPEJ1ZmZlcj4ocmVzb2x2ZWRQYXRoLCB7XG4gICAgICBkYmZzOiAoY2xpZW50KSA9PiB0aGlzLnJlYWREYmZzRmlsZShjbGllbnQsIHJlc29sdmVkUGF0aCksXG4gICAgICB3b3Jrc3BhY2U6IGFzeW5jIChjbGllbnQpID0+IHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBjbGllbnQud29ya3NwYWNlLmV4cG9ydCh7IHBhdGg6IHJlc29sdmVkUGF0aCwgZm9ybWF0OiBcIkFVVE9cIiB9KTtcbiAgICAgICAgcmV0dXJuIGRlY29kZUJhc2U2NChyZXNwb25zZS5jb250ZW50KTtcbiAgICAgIH0sXG4gICAgICB2b2x1bWVzOiBhc3luYyAoY2xpZW50KSA9PiB7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LmZpbGVzLmRvd25sb2FkKHsgZmlsZV9wYXRoOiByZXNvbHZlZFBhdGggfSk7XG4gICAgICAgIHJldHVybiByZWFkUmVzcG9uc2VCb2R5KFxuICAgICAgICAgIHJlc3BvbnNlLmNvbnRlbnRzIGFzIGdsb2JhbFRoaXMuUmVhZGFibGVTdHJlYW08VWludDhBcnJheT4gfCB1bmRlZmluZWQsXG4gICAgICAgICk7XG4gICAgICB9LFxuICAgIH0pO1xuICAgIHJldHVybiBuZXcgVWludDhBcnJheShidWZmZXIuYnVmZmVyLCBidWZmZXIuYnl0ZU9mZnNldCwgYnVmZmVyLmJ5dGVMZW5ndGgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGFzeW5jIHdyaXRlQnl0ZXNBdChcbiAgICByZXNvbHZlZFBhdGg6IHN0cmluZyxcbiAgICBjb250ZW50OiBVaW50OEFycmF5LFxuICAgIG9wdGlvbnM6IFJlcXVpcmVkPFdyaXRlRmlsZU9wdGlvbnM+LFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBidWZmZXIgPSBCdWZmZXIuZnJvbShjb250ZW50KTtcbiAgICBjb25zdCBvdmVyd3JpdGUgPSBvcHRpb25zLm92ZXJ3cml0ZTtcbiAgICBhd2FpdCB0aGlzLmRpc3BhdGNoPHVua25vd24+KHJlc29sdmVkUGF0aCwge1xuICAgICAgZGJmczogKGNsaWVudCkgPT4gdGhpcy53cml0ZURiZnNGaWxlKGNsaWVudCwgcmVzb2x2ZWRQYXRoLCBidWZmZXIsIG92ZXJ3cml0ZSksXG4gICAgICB3b3Jrc3BhY2U6IChjbGllbnQpID0+XG4gICAgICAgIGNsaWVudC53b3Jrc3BhY2UuaW1wb3J0KHtcbiAgICAgICAgICBwYXRoOiByZXNvbHZlZFBhdGgsXG4gICAgICAgICAgZm9ybWF0OiBcIkFVVE9cIixcbiAgICAgICAgICBjb250ZW50OiBidWZmZXIudG9TdHJpbmcoXCJiYXNlNjRcIiksXG4gICAgICAgICAgb3ZlcndyaXRlLFxuICAgICAgICB9KSxcbiAgICAgIHZvbHVtZXM6IChjbGllbnQpID0+XG4gICAgICAgIGNsaWVudC5maWxlcy51cGxvYWQoe1xuICAgICAgICAgIGZpbGVfcGF0aDogcmVzb2x2ZWRQYXRoLFxuICAgICAgICAgIGNvbnRlbnRzOiBidWZmZXJUb1JlYWRhYmxlU3RyZWFtKGJ1ZmZlcikgYXMgbmV2ZXIsXG4gICAgICAgICAgb3ZlcndyaXRlLFxuICAgICAgICB9KSxcbiAgICB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvdmVycmlkZSBhc3luYyBkZWxldGVGaWxlQXQocmVzb2x2ZWRQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmRpc3BhdGNoPHVua25vd24+KHJlc29sdmVkUGF0aCwge1xuICAgICAgZGJmczogKGNsaWVudCkgPT4gY2xpZW50LmRiZnMuZGVsZXRlKHsgcGF0aDogcmVzb2x2ZWRQYXRoLCByZWN1cnNpdmU6IGZhbHNlIH0pLFxuICAgICAgd29ya3NwYWNlOiAoY2xpZW50KSA9PiBjbGllbnQud29ya3NwYWNlLmRlbGV0ZSh7IHBhdGg6IHJlc29sdmVkUGF0aCwgcmVjdXJzaXZlOiBmYWxzZSB9KSxcbiAgICAgIHZvbHVtZXM6IChjbGllbnQpID0+IGNsaWVudC5maWxlcy5kZWxldGUoeyBmaWxlX3BhdGg6IHJlc29sdmVkUGF0aCB9KSxcbiAgICB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBvdmVycmlkZSBhc3luYyBjcmVhdGVEaXJlY3RvcnlBdChyZXNvbHZlZFBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuZGlzcGF0Y2g8dW5rbm93bj4ocmVzb2x2ZWRQYXRoLCB7XG4gICAgICBkYmZzOiAoY2xpZW50KSA9PiBjbGllbnQuZGJmcy5ta2RpcnMoeyBwYXRoOiByZXNvbHZlZFBhdGggfSksXG4gICAgICB3b3Jrc3BhY2U6IChjbGllbnQpID0+IGNsaWVudC53b3Jrc3BhY2UubWtkaXJzKHsgcGF0aDogcmVzb2x2ZWRQYXRoIH0pLFxuICAgICAgdm9sdW1lczogKGNsaWVudCkgPT4gdGhpcy5jcmVhdGVWb2x1bWVEaXJlY3RvcmllcyhjbGllbnQsIHJlc29sdmVkUGF0aCksXG4gICAgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgcmVtb3ZlRGlyZWN0b3J5QXQocmVzb2x2ZWRQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmRpc3BhdGNoPHVua25vd24+KHJlc29sdmVkUGF0aCwge1xuICAgICAgZGJmczogKGNsaWVudCkgPT4gY2xpZW50LmRiZnMuZGVsZXRlKHsgcGF0aDogcmVzb2x2ZWRQYXRoLCByZWN1cnNpdmU6IGZhbHNlIH0pLFxuICAgICAgd29ya3NwYWNlOiAoY2xpZW50KSA9PiBjbGllbnQud29ya3NwYWNlLmRlbGV0ZSh7IHBhdGg6IHJlc29sdmVkUGF0aCwgcmVjdXJzaXZlOiBmYWxzZSB9KSxcbiAgICAgIHZvbHVtZXM6IChjbGllbnQpID0+IGNsaWVudC5maWxlcy5kZWxldGVEaXJlY3RvcnkoeyBkaXJlY3RvcnlfcGF0aDogcmVzb2x2ZWRQYXRoIH0pLFxuICAgIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGFzeW5jIGxpc3REaXJlY3RvcnlBdChyZXNvbHZlZFBhdGg6IHN0cmluZyk6IFByb21pc2U8RmlsZUVudHJ5W10+IHtcbiAgICByZXR1cm4gdGhpcy5kaXNwYXRjaDxGaWxlRW50cnlbXT4ocmVzb2x2ZWRQYXRoLCB7XG4gICAgICBkYmZzOiAoY2xpZW50KSA9PlxuICAgICAgICBjb2xsZWN0KGNsaWVudC5kYmZzLmxpc3QoeyBwYXRoOiByZXNvbHZlZFBhdGggfSksIChpbmZvKSA9PiAoe1xuICAgICAgICAgIG5hbWU6IHBvc2l4UGF0aC5iYXNlbmFtZShpbmZvLnBhdGggPz8gXCJcIiksXG4gICAgICAgICAgdHlwZTogaW5mby5pc19kaXIgPyBcImRpcmVjdG9yeVwiIDogXCJmaWxlXCIsXG4gICAgICAgICAgc2l6ZTogaW5mby5maWxlX3NpemUsXG4gICAgICAgIH0pKSxcbiAgICAgIHdvcmtzcGFjZTogKGNsaWVudCkgPT5cbiAgICAgICAgY29sbGVjdChjbGllbnQud29ya3NwYWNlLmxpc3QoeyBwYXRoOiByZXNvbHZlZFBhdGggfSksIChpbmZvKSA9PiAoe1xuICAgICAgICAgIG5hbWU6IHBvc2l4UGF0aC5iYXNlbmFtZShpbmZvLnBhdGggPz8gXCJcIiksXG4gICAgICAgICAgdHlwZTogaW5mby5vYmplY3RfdHlwZSA9PT0gXCJESVJFQ1RPUllcIiA/IFwiZGlyZWN0b3J5XCIgOiBcImZpbGVcIixcbiAgICAgICAgfSkpLFxuICAgICAgdm9sdW1lczogKGNsaWVudCkgPT5cbiAgICAgICAgY29sbGVjdChjbGllbnQuZmlsZXMubGlzdERpcmVjdG9yeUNvbnRlbnRzKHsgZGlyZWN0b3J5X3BhdGg6IHJlc29sdmVkUGF0aCB9KSwgKGVudHJ5KSA9PiAoe1xuICAgICAgICAgIG5hbWU6IGVudHJ5Lm5hbWUgPz8gcG9zaXhQYXRoLmJhc2VuYW1lKGVudHJ5LnBhdGggPz8gXCJcIiksXG4gICAgICAgICAgdHlwZTogZW50cnkuaXNfZGlyZWN0b3J5ID8gXCJkaXJlY3RvcnlcIiA6IFwiZmlsZVwiLFxuICAgICAgICAgIHNpemU6IGVudHJ5LmZpbGVfc2l6ZSxcbiAgICAgICAgfSkpLFxuICAgIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGFzeW5jIHN0YXRBdChyZXNvbHZlZFBhdGg6IHN0cmluZyk6IFByb21pc2U8T21pdDxGaWxlU3RhdCwgXCJwYXRoXCI+PiB7XG4gICAgY29uc3QgZmFsbGJhY2tOYW1lID0gcG9zaXhQYXRoLmJhc2VuYW1lKHJlc29sdmVkUGF0aCkgfHwgcG9zaXhQYXRoLmJhc2VuYW1lKHRoaXMucm9vdCk7XG4gICAgcmV0dXJuIHRoaXMuZGlzcGF0Y2g8T21pdDxGaWxlU3RhdCwgXCJwYXRoXCI+PihyZXNvbHZlZFBhdGgsIHtcbiAgICAgIGRiZnM6IGFzeW5jIChjbGllbnQpID0+IHtcbiAgICAgICAgY29uc3QgaW5mbyA9IGF3YWl0IGNsaWVudC5kYmZzLmdldFN0YXR1cyh7IHBhdGg6IHJlc29sdmVkUGF0aCB9KTtcbiAgICAgICAgY29uc3QgbW9kaWZpZWQgPSB0b0RhdGUoaW5mby5tb2RpZmljYXRpb25fdGltZSk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgbmFtZTogcG9zaXhQYXRoLmJhc2VuYW1lKGluZm8ucGF0aCA/PyByZXNvbHZlZFBhdGgpIHx8IGZhbGxiYWNrTmFtZSxcbiAgICAgICAgICB0eXBlOiBpbmZvLmlzX2RpciA/IFwiZGlyZWN0b3J5XCIgOiBcImZpbGVcIixcbiAgICAgICAgICBzaXplOiBpbmZvLmZpbGVfc2l6ZSxcbiAgICAgICAgICBjcmVhdGVkQXQ6IG1vZGlmaWVkLFxuICAgICAgICAgIG1vZGlmaWVkQXQ6IG1vZGlmaWVkLFxuICAgICAgICB9O1xuICAgICAgfSxcbiAgICAgIHdvcmtzcGFjZTogYXN5bmMgKGNsaWVudCkgPT4ge1xuICAgICAgICBjb25zdCBpbmZvID0gYXdhaXQgY2xpZW50LndvcmtzcGFjZS5nZXRTdGF0dXMoeyBwYXRoOiByZXNvbHZlZFBhdGggfSk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgbmFtZTogcG9zaXhQYXRoLmJhc2VuYW1lKGluZm8ucGF0aCA/PyByZXNvbHZlZFBhdGgpIHx8IGZhbGxiYWNrTmFtZSxcbiAgICAgICAgICB0eXBlOiBpbmZvLm9iamVjdF90eXBlID09PSBcIkRJUkVDVE9SWVwiID8gXCJkaXJlY3RvcnlcIiA6IFwiZmlsZVwiLFxuICAgICAgICAgIGNyZWF0ZWRBdDogdG9EYXRlKGluZm8uY3JlYXRlZF9hdCksXG4gICAgICAgICAgbW9kaWZpZWRBdDogdG9EYXRlKGluZm8ubW9kaWZpZWRfYXQpLFxuICAgICAgICB9O1xuICAgICAgfSxcbiAgICAgIHZvbHVtZXM6IChjbGllbnQpID0+IHRoaXMuc3RhdFZvbHVtZVBhdGgoY2xpZW50LCByZXNvbHZlZFBhdGgsIGZhbGxiYWNrTmFtZSksXG4gICAgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgb3ZlcnJpZGUgYXN5bmMgdHJ5TW92ZUZpbGVBdChcbiAgICBzb3VyY2VQYXRoOiBzdHJpbmcsXG4gICAgZGVzdGluYXRpb25QYXRoOiBzdHJpbmcsXG4gICAgX29wdGlvbnM6IFJlcXVpcmVkPENvcHlPcHRpb25zPixcbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgLy8gT25seSBEQkZTIGV4cG9zZXMgYSBzZXJ2ZXItc2lkZSBtb3ZlOyBldmVyeXRoaW5nIGVsc2UgZmFsbHMgYmFjayB0byB0aGVcbiAgICAvLyBwb3J0YWJsZSBjb3B5ICsgZGVsZXRlIGluIEJhc2VGaWxlU3lzdGVtLlxuICAgIGlmIChcbiAgICAgIHJlc29sdmVEYXRhYnJpY2tzRmlsZXNCYWNrZW5kKHNvdXJjZVBhdGgpICE9PSBcImRiZnNcIiB8fFxuICAgICAgcmVzb2x2ZURhdGFicmlja3NGaWxlc0JhY2tlbmQoZGVzdGluYXRpb25QYXRoKSAhPT0gXCJkYmZzXCJcbiAgICApIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgYXdhaXQgdGhpcy5kaXNwYXRjaDx1bmtub3duPihzb3VyY2VQYXRoLCB7XG4gICAgICBkYmZzOiAoY2xpZW50KSA9PlxuICAgICAgICBjbGllbnQuZGJmcy5tb3ZlKHsgc291cmNlX3BhdGg6IHNvdXJjZVBhdGgsIGRlc3RpbmF0aW9uX3BhdGg6IGRlc3RpbmF0aW9uUGF0aCB9KSxcbiAgICAgIHdvcmtzcGFjZTogdW5yZWFjaGFibGVCYWNrZW5kLFxuICAgICAgdm9sdW1lczogdW5yZWFjaGFibGVCYWNrZW5kLFxuICAgIH0pO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG4gIC8qIEJhY2tlbmQtc3BlY2lmaWMgSS9PICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqL1xuICAvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuICAvKipcbiAgICogVUMgYGNyZWF0ZURpcmVjdG9yeWAgaXMgc2luZ2xlLWxldmVsLCBzbyB3YWxrIHRoZSBwYXRoIGNyZWF0aW5nIGVhY2ggbGV2ZWxcbiAgICogYmVsb3cgdGhlIHZvbHVtZSBpdHNlbGYuIEEgbGV2ZWwgdGhhdCBhbHJlYWR5IGV4aXN0cyBpcyBub3QgYW4gZXJyb3IuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNyZWF0ZVZvbHVtZURpcmVjdG9yaWVzKFxuICAgIGNsaWVudDogV29ya3NwYWNlQ2xpZW50LFxuICAgIGFic29sdXRlUGF0aDogc3RyaW5nLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBwYXJ0cyA9IGFic29sdXRlUGF0aC5zcGxpdChcIi9cIikuZmlsdGVyKEJvb2xlYW4pO1xuICAgIGxldCBjdXJyZW50ID0gXCJcIjtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBhcnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjdXJyZW50ID0gYCR7Y3VycmVudH0vJHtwYXJ0c1tpXX1gO1xuICAgICAgaWYgKGkgPCBWT0xVTUVfUk9PVF9ERVBUSCkgY29udGludWU7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBjbGllbnQuZmlsZXMuY3JlYXRlRGlyZWN0b3J5KHsgZGlyZWN0b3J5X3BhdGg6IGN1cnJlbnQgfSk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgLy8gQWxyZWFkeSBwcmVzZW50IGlzIGZpbmU7IGFueXRoaW5nIGVsc2UgaXMgYSByZWFsIGZhaWx1cmUuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgY2xpZW50LmZpbGVzLmdldERpcmVjdG9yeU1ldGFkYXRhKHsgZGlyZWN0b3J5X3BhdGg6IGN1cnJlbnQgfSk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKiBTdGF0IGEgVUMgcGF0aDogZmlsZSBtZXRhZGF0YSBmaXJzdCwgdGhlbiBhIGRpcmVjdG9yeSBwcm9iZS4gKi9cbiAgcHJpdmF0ZSBhc3luYyBzdGF0Vm9sdW1lUGF0aChcbiAgICBjbGllbnQ6IFdvcmtzcGFjZUNsaWVudCxcbiAgICBhYnNvbHV0ZVBhdGg6IHN0cmluZyxcbiAgICBmYWxsYmFja05hbWU6IHN0cmluZyxcbiAgKTogUHJvbWlzZTxPbWl0PEZpbGVTdGF0LCBcInBhdGhcIj4+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgbWV0YWRhdGEgPSBhd2FpdCBjbGllbnQuZmlsZXMuZ2V0TWV0YWRhdGEoeyBmaWxlX3BhdGg6IGFic29sdXRlUGF0aCB9KTtcbiAgICAgIGNvbnN0IG1vZGlmaWVkID0gcGFyc2VIdHRwRGF0ZShtZXRhZGF0YVtcImxhc3QtbW9kaWZpZWRcIl0pO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbmFtZTogZmFsbGJhY2tOYW1lLFxuICAgICAgICB0eXBlOiBcImZpbGVcIixcbiAgICAgICAgc2l6ZTogTnVtYmVyKG1ldGFkYXRhW1wiY29udGVudC1sZW5ndGhcIl0gPz8gMCksXG4gICAgICAgIGNyZWF0ZWRBdDogbW9kaWZpZWQsXG4gICAgICAgIG1vZGlmaWVkQXQ6IG1vZGlmaWVkLFxuICAgICAgICBtaW1lVHlwZTogbWV0YWRhdGFbXCJjb250ZW50LXR5cGVcIl0sXG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGZpbGVFcnIpIHtcbiAgICAgIC8vIEEgZGlyZWN0b3J5IGhhcyBubyBmaWxlIG1ldGFkYXRhLCBhbmQgYW4gdW5yZWFkYWJsZSBvbmUgcmVwb3J0cyBhc1xuICAgICAgLy8gbWlzc2luZyAvIGRlbmllZCAtIGJvdGggYXJlIHdvcnRoIGEgZGlyZWN0b3J5IHByb2JlIGJlZm9yZSBmYWlsaW5nLlxuICAgICAgY29uc3QgY29kZSA9IGJhc2VGUy5tYXBGaWxlU3lzdGVtRXJyb3IoZmlsZUVyciwgYWJzb2x1dGVQYXRoKS5jb2RlO1xuICAgICAgaWYgKGNvZGUgIT09IFwiTk9UX0ZPVU5EXCIgJiYgY29kZSAhPT0gXCJQRVJNSVNTSU9OX0RFTklFRFwiKSB0aHJvdyBmaWxlRXJyO1xuICAgICAgYXdhaXQgY2xpZW50LmZpbGVzLmdldERpcmVjdG9yeU1ldGFkYXRhKHsgZGlyZWN0b3J5X3BhdGg6IGFic29sdXRlUGF0aCB9KTtcbiAgICAgIHJldHVybiB7IG5hbWU6IGZhbGxiYWNrTmFtZSwgdHlwZTogXCJkaXJlY3RvcnlcIiB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcmVhZERiZnNGaWxlKGNsaWVudDogV29ya3NwYWNlQ2xpZW50LCBhYnNvbHV0ZVBhdGg6IHN0cmluZyk6IFByb21pc2U8QnVmZmVyPiB7XG4gICAgY29uc3QgY2h1bmtzOiBCdWZmZXJbXSA9IFtdO1xuICAgIGxldCBvZmZzZXQgPSAwO1xuICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNsaWVudC5kYmZzLnJlYWQoe1xuICAgICAgICBwYXRoOiBhYnNvbHV0ZVBhdGgsXG4gICAgICAgIG9mZnNldCxcbiAgICAgICAgbGVuZ3RoOiBEQkZTX1JFQURfQ0hVTktfQllURVMsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGNodW5rID0gZGVjb2RlQmFzZTY0KHJlc3BvbnNlLmRhdGEpO1xuICAgICAgaWYgKGNodW5rLmxlbmd0aCA9PT0gMCkgYnJlYWs7XG4gICAgICBjaHVua3MucHVzaChjaHVuayk7XG4gICAgICBvZmZzZXQgKz0gY2h1bmsubGVuZ3RoO1xuICAgICAgaWYgKGNodW5rLmxlbmd0aCA8IERCRlNfUkVBRF9DSFVOS19CWVRFUykgYnJlYWs7XG4gICAgfVxuICAgIHJldHVybiBCdWZmZXIuY29uY2F0KGNodW5rcyk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHdyaXRlRGJmc0ZpbGUoXG4gICAgY2xpZW50OiBXb3Jrc3BhY2VDbGllbnQsXG4gICAgYWJzb2x1dGVQYXRoOiBzdHJpbmcsXG4gICAgYnVmZmVyOiBCdWZmZXIsXG4gICAgb3ZlcndyaXRlOiBib29sZWFuLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoYnVmZmVyLmxlbmd0aCA8PSBEQkZTX1BVVF9NQVhfQllURVMpIHtcbiAgICAgIGF3YWl0IGNsaWVudC5kYmZzLnB1dCh7XG4gICAgICAgIHBhdGg6IGFic29sdXRlUGF0aCxcbiAgICAgICAgY29udGVudHM6IGJ1ZmZlci50b1N0cmluZyhcImJhc2U2NFwiKSxcbiAgICAgICAgb3ZlcndyaXRlLFxuICAgICAgfSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCBjbGllbnQuZGJmcy5jcmVhdGUoeyBwYXRoOiBhYnNvbHV0ZVBhdGgsIG92ZXJ3cml0ZSB9KTtcbiAgICBjb25zdCBoYW5kbGUgPSBjcmVhdGVkLmhhbmRsZTtcbiAgICBpZiAoaGFuZGxlID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBGaWxlU3lzdGVtRXJyb3IoXCJJT19FUlJPUlwiLCBcIkRCRlMgdXBsb2FkIGhhbmRsZSBtaXNzaW5nXCIsIGFic29sdXRlUGF0aCk7XG4gICAgfVxuICAgIGZvciAobGV0IG9mZnNldCA9IDA7IG9mZnNldCA8IGJ1ZmZlci5sZW5ndGg7IG9mZnNldCArPSBEQkZTX1BVVF9NQVhfQllURVMpIHtcbiAgICAgIGNvbnN0IHNsaWNlID0gYnVmZmVyLnN1YmFycmF5KG9mZnNldCwgb2Zmc2V0ICsgREJGU19QVVRfTUFYX0JZVEVTKTtcbiAgICAgIGF3YWl0IGNsaWVudC5kYmZzLmFkZEJsb2NrKHsgaGFuZGxlLCBkYXRhOiBzbGljZS50b1N0cmluZyhcImJhc2U2NFwiKSB9KTtcbiAgICB9XG4gICAgYXdhaXQgY2xpZW50LmRiZnMuY2xvc2UoeyBoYW5kbGUgfSk7XG4gIH1cbn1cblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIGhlbHBlcnMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbi8qKiBEcmFpbiBhbiBTREsgYXN5bmMgaXRlcmFibGUgaW50byBhIG1hcHBlZCBhcnJheS4gKi9cbmFzeW5jIGZ1bmN0aW9uIGNvbGxlY3Q8UywgVD4oc291cmNlOiBBc3luY0l0ZXJhYmxlPFM+LCBtYXA6IChpdGVtOiBTKSA9PiBUKTogUHJvbWlzZTxUW10+IHtcbiAgY29uc3QgaXRlbXM6IFRbXSA9IFtdO1xuICBmb3IgYXdhaXQgKGNvbnN0IGl0ZW0gb2Ygc291cmNlKSBpdGVtcy5wdXNoKG1hcChpdGVtKSk7XG4gIHJldHVybiBpdGVtcztcbn1cblxuLyoqIEhhbmRsZXIgZm9yIGEgYmFja2VuZCBhIGNhbGwgc2l0ZSBoYXMgYWxyZWFkeSBydWxlZCBvdXQuICovXG5mdW5jdGlvbiB1bnJlYWNoYWJsZUJhY2tlbmQoKTogUHJvbWlzZTxuZXZlcj4ge1xuICB0aHJvdyBuZXcgRmlsZVN5c3RlbUVycm9yKFwiTk9UX1NVUFBPUlRFRFwiLCBcIlVuc3VwcG9ydGVkIERhdGFicmlja3MgYmFja2VuZCBmb3IgdGhpcyBvcGVyYXRpb25cIik7XG59XG5cbmZ1bmN0aW9uIGRlY29kZUJhc2U2NChkYXRhOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBCdWZmZXIge1xuICBpZiAoIWRhdGEpIHJldHVybiBCdWZmZXIuYWxsb2MoMCk7XG4gIHJldHVybiBCdWZmZXIuZnJvbShkYXRhLCBcImJhc2U2NFwiKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVhZFJlc3BvbnNlQm9keShcbiAgY29udGVudHM6IGdsb2JhbFRoaXMuUmVhZGFibGVTdHJlYW08VWludDhBcnJheT4gfCB1bmRlZmluZWQsXG4pOiBQcm9taXNlPEJ1ZmZlcj4ge1xuICBpZiAoIWNvbnRlbnRzKSByZXR1cm4gQnVmZmVyLmFsbG9jKDApO1xuICBjb25zdCByZWFkZXIgPSBjb250ZW50cy5nZXRSZWFkZXIoKTtcbiAgY29uc3QgY2h1bmtzOiBVaW50OEFycmF5W10gPSBbXTtcbiAgd2hpbGUgKHRydWUpIHtcbiAgICBjb25zdCB7IGRvbmUsIHZhbHVlIH0gPSBhd2FpdCByZWFkZXIucmVhZCgpO1xuICAgIGlmIChkb25lKSBicmVhaztcbiAgICBpZiAodmFsdWUpIGNodW5rcy5wdXNoKHZhbHVlKTtcbiAgfVxuICByZXR1cm4gQnVmZmVyLmNvbmNhdChjaHVua3MubWFwKChjaHVuaykgPT4gQnVmZmVyLmZyb20oY2h1bmspKSk7XG59XG5cbmZ1bmN0aW9uIGJ1ZmZlclRvUmVhZGFibGVTdHJlYW0oYnVmZmVyOiBCdWZmZXIpOiBnbG9iYWxUaGlzLlJlYWRhYmxlU3RyZWFtPFVpbnQ4QXJyYXk+IHtcbiAgcmV0dXJuIG5ldyBSZWFkYWJsZVN0cmVhbTxVaW50OEFycmF5Pih7XG4gICAgc3RhcnQoY29udHJvbGxlcikge1xuICAgICAgY29udHJvbGxlci5lbnF1ZXVlKG5ldyBVaW50OEFycmF5KGJ1ZmZlcikpO1xuICAgICAgY29udHJvbGxlci5jbG9zZSgpO1xuICAgIH0sXG4gIH0pO1xufVxuXG5mdW5jdGlvbiB0b0RhdGUodmFsdWU6IG51bWJlciB8IHVuZGVmaW5lZCk6IERhdGUgfCB1bmRlZmluZWQge1xuICByZXR1cm4gdmFsdWUgPT09IHVuZGVmaW5lZCA/IHVuZGVmaW5lZCA6IG5ldyBEYXRlKHZhbHVlKTtcbn1cblxuZnVuY3Rpb24gcGFyc2VIdHRwRGF0ZSh2YWx1ZTogc3RyaW5nIHwgdW5kZWZpbmVkKTogRGF0ZSB8IHVuZGVmaW5lZCB7XG4gIGlmICghdmFsdWUpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IHBhcnNlZCA9IERhdGUucGFyc2UodmFsdWUpO1xuICByZXR1cm4gTnVtYmVyLmlzRmluaXRlKHBhcnNlZCkgPyBuZXcgRGF0ZShwYXJzZWQpIDogdW5kZWZpbmVkO1xufVxuIl19