@dockstat/outline-sync 1.0.0

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 ADDED
@@ -0,0 +1,217 @@
1
+ # Outline ↔ Git Markdown Sync (Bun CLI)
2
+
3
+ A small Bun-based CLI that bi-directionally syncs a Git-backed Markdown tree with a **single** Outline collection.
4
+
5
+ Features:
6
+
7
+ * Two-way sync (newer wins): push local (git) → Outline; pull Outline → local.
8
+ * Prefer **git commit timestamp** for local change detection (falls back to `mtime`).
9
+ * Single collection only (manifest top-level `collectionId` or CLI / env override).
10
+ * `--init` to bootstrap `pages.json` + `docs/` from an existing collection.
11
+ * `--list-collections` to print available collections (id + name).
12
+ * `--dry-run` to preview actions without writing.
13
+ * Safe local backups before overwriting (`*.outline-sync.bak.<ts>`).
14
+ * Bun + TypeScript single-file CLI (`sync.ts`) — drop in repo root and run with Bun.
15
+
16
+ ---
17
+
18
+ ## Table of contents
19
+
20
+ * # Quick start
21
+ * # Manifest (`pages.json`)
22
+ * # Commands / Flags
23
+ * # Init (bootstrap) flow
24
+ * # How sync decisions are made
25
+ * # CI integration example
26
+ * # Safety & backups
27
+ * # Troubleshooting
28
+ * # Extending / Roadmap
29
+ * # License
30
+
31
+ ---
32
+
33
+ # Quick start
34
+
35
+ 1. Install Bun: [https://bun.sh](https://bun.sh)
36
+ 2. Place the provided `sync.ts` in your repository root.
37
+ 3. Ensure you have a shell environment variable `OUTLINE_API_KEY` set to a valid Outline API key.
38
+
39
+ ```bash
40
+ export OUTLINE_API_KEY="sk_live_..." # REQUIRED
41
+ # optional:
42
+ export OUTLINE_BASE_URL="https://app.getoutline.com"
43
+ export OUTLINE_COLLECTION_ID="COLLECTION_UUID" # optional runtime override
44
+ ```
45
+
46
+ 4. To bootstrap a manifest from an existing collection (recommended first run):
47
+
48
+ ```bash
49
+ # list collections so you can pick the collection id
50
+ OUTLINE_API_KEY=sk_xxx bun run sync.ts --list-collections
51
+
52
+ # bootstrap files + pages.json from the collection
53
+ OUTLINE_API_KEY=sk_xxx bun run sync.ts --init --collection-id=COLLECTION_UUID
54
+ ```
55
+
56
+ 5. Review and commit `pages.json` and `docs/`:
57
+
58
+ ```bash
59
+ git add pages.json docs
60
+ git commit -m "chore: bootstrap Outline manifest"
61
+ ```
62
+
63
+ 6. Run normal sync:
64
+
65
+ ```bash
66
+ OUTLINE_API_KEY=sk_xxx bun run sync.ts
67
+ ```
68
+
69
+ Or preview only (no writes):
70
+
71
+ ```bash
72
+ OUTLINE_API_KEY=sk_xxx bun run sync.ts --dry-run
73
+ ```
74
+
75
+ ---
76
+
77
+ # Manifest (`pages.json`)
78
+
79
+ `pages.json` defines the single collection and the page tree. Example:
80
+
81
+ ```json
82
+ {
83
+ "collectionId": "YOUR_COLLECTION_UUID",
84
+ "pages": [
85
+ {
86
+ "title": "Home",
87
+ "file": "docs/home.md",
88
+ "id": null,
89
+ "children": [
90
+ {
91
+ "title": "Subpage",
92
+ "file": "docs/subpage.md",
93
+ "id": null,
94
+ "children": []
95
+ }
96
+ ]
97
+ },
98
+ {
99
+ "title": "About",
100
+ "file": "docs/about.md",
101
+ "id": null,
102
+ "children": []
103
+ }
104
+ ]
105
+ }
106
+ ```
107
+
108
+ Fields:
109
+
110
+ * `collectionId`: The single Outline collection the sync will write to. Required (or must be provided at runtime).
111
+ * `title`: Outline document title.
112
+ * `file`: Relative path to the markdown file.
113
+ * `id`: Outline document id (UUID). Use `null` for documents not yet created; `--init` will populate ids when bootstrapping.
114
+ * `children`: nested pages.
115
+
116
+ **Important:** Only the top-level `collectionId` (manifest) or a runtime override (`--collection-id` / `OUTLINE_COLLECTION_ID`) is used. Per-page collection fields are ignored.
117
+
118
+ ---
119
+
120
+ # Commands / Flags
121
+
122
+ * `--init` : Bootstrap `pages.json` + `docs/` from an existing Outline collection. Requires `--collection-id` (or `OUTLINE_COLLECTION_ID` env var).
123
+ * `--list-collections` : Print all collections you can access (id + name).
124
+ * `--collection-id=<ID>` : Override manifest collection id for this run (useful in CI).
125
+ * `--dry-run` : Preview actions without writing to Outline or local files.
126
+ * `--help` / `-h` : Show help.
127
+
128
+ Examples:
129
+
130
+ ```bash
131
+ # list collections
132
+ OUTLINE_API_KEY=sk_xxx bun run sync.ts --list-collections
133
+
134
+ # init from collection
135
+ OUTLINE_API_KEY=sk_xxx bun run sync.ts --init --collection-id=abc-uuid
136
+
137
+ # normal sync
138
+ OUTLINE_API_KEY=sk_xxx bun run sync.ts
139
+
140
+ # dry-run preview
141
+ OUTLINE_API_KEY=sk_xxx bun run sync.ts --dry-run
142
+ ```
143
+
144
+ ---
145
+
146
+ # Init (bootstrap) flow
147
+
148
+ `--init` performs:
149
+
150
+ 1. `collections.list` or `documents.list` to fetch documents from the collection.
151
+ 2. Creates `docs/<slug>.md` files for each document (slugified title). If slugs collide, a short id suffix is appended.
152
+ 3. Builds the parent/child tree and writes `pages.json` with each entry containing the Outline `id`.
153
+ 4. If not using `--dry-run`, files and `pages.json` are written to disk. Review and commit them.
154
+
155
+ This is the recommended first step when adopting the tool for an existing Outline collection.
156
+
157
+ ---
158
+
159
+ # How sync decisions are made
160
+
161
+ For each manifest page:
162
+
163
+ 1. If local file exists, determine local timestamp:
164
+
165
+ * Prefer **git last commit timestamp** (`git log -1 --format=%ct -- <file>`).
166
+ * If not available, use filesystem `mtime`.
167
+ 2. If `page.id` exists, fetch Outline metadata (`documents.info`) and read `updatedAt`.
168
+ 3. Compare timestamps (500ms tolerance):
169
+
170
+ * `local > remote` → **push** local content to Outline (`documents.update`).
171
+ * `remote > local` → **pull** remote content and overwrite local file (creates backup).
172
+ * equal → **skip**.
173
+ 4. If `page.id` is null → create doc in Outline (`documents.create`) under manifest collection and parent, then persist returned `id` into `pages.json`.
174
+
175
+ Note: Timestamp comparison uses git commit times where possible so that checkout/mtime changes don't cause accidental overrides.
176
+
177
+ ---
178
+
179
+ # CI integration example
180
+
181
+ A typical CI step (safe):
182
+
183
+ ```bash
184
+ # in CI, set OUTLINE_API_KEY as secret
185
+ bun run sync.ts --dry-run # preview what would change
186
+ bun run sync.ts # perform sync
187
+ git add pages.json
188
+ git commit -m "chore: outline sync update" || true
189
+ # optionally push — guard against CI loops
190
+ ```
191
+
192
+ Tip: Only commit when `pages.json` changed and be careful not to trigger infinite CI runs from the commit itself (e.g., detect CI and skip push).
193
+
194
+ ---
195
+
196
+ # Safety & backups
197
+
198
+ * Before overwriting a local file, the script copies it to `file.outline-sync.bak.<timestamp>` (same directory).
199
+ * `--dry-run` mode prints actions without writing to Outline or disk.
200
+ * The tool writes `id`s back to `pages.json`; commit that file after `--init`.
201
+ * Basic retry/backoff is implemented for API rate-limits (429). For very large collections you may want to add stronger batching.
202
+
203
+ ---
204
+
205
+ # Troubleshooting
206
+
207
+ * `ERROR: please set OUTLINE_API_KEY` — set `OUTLINE_API_KEY` env var.
208
+ * `Manifest pages.json not found` — run `--init --collection-id=<id>` to bootstrap.
209
+ * Duplicate pages after init: ensure you used the right collection; the tool does not attempt to dedupe across multiple collections.
210
+ * `git log` returns nothing for a file: file not committed; the script falls back to `mtime`.
211
+ * Hitting rate limits (429): rerun later or implement slower batching.
212
+
213
+ ---
214
+
215
+ # License
216
+
217
+ MIT — use, modify and share.
package/dist/sync.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ // Generated by dts-bundle-generator v9.5.1
2
+
3
+ export {};
package/dist/sync.js ADDED
@@ -0,0 +1,25 @@
1
+ // @bun
2
+ import j from"fs/promises";import{existsSync as Y}from"fs";import V from"path";var F="pages.json",R=process.argv.slice(2),M=process.env.OUTLINE_BASE_URL||null,D=process.env.OUTLINE_API_KEY||null,y=null,B=!1,A=!1,x=!1;for(let J of R)if(J.startsWith("--collection-id="))y=J.split("=")[1]||null;else if(J==="--dry-run")B=!0;else if(J==="--init")A=!0;else if(J==="--list-collections")x=!0;else if(J==="init")A=!0;else if(J==="list-collections")x=!0;else if(J==="--help"||J==="-h")C();else if(J.startsWith("--api-key="))D=J.split("=")[1]||null;else if(J.startsWith("--base-url="))M=J.split("=")[1]||null;if(!M)M="https://app.getoutline.com";var E={Authorization:`Bearer ${D}`,"Content-Type":"application/json"};function C(){console.log(`
3
+ Usage:
4
+ OUTLINE_API_KEY=... bun run sync.ts [options]
5
+
6
+ Options:
7
+ --init Bootstrap pages.json + markdown files from a collection
8
+ --collection-id=COL_ID Use this collection id (required with --init unless OUTLINE_COLLECTION_ID set)
9
+ --list-collections List collections you have access to (prints id + name)
10
+ --dry-run Print actions without writing anything
11
+ --help Show this help
12
+ Examples:
13
+ OUTLINE_API_KEY=... bun run sync.ts --list-collections
14
+ OUTLINE_API_KEY=... bun run sync.ts --init --collection-id=abc-uuid
15
+ OUTLINE_API_KEY=... bun run sync.ts # perform regular sync
16
+ OUTLINE_API_KEY=... bun run sync.ts --dry-run
17
+ `),process.exit(0)}var b=process.env.OUTLINE_COLLECTION_ID||null;function u(J){if(y)return y;if(b)return b;if(J)return J;throw new Error("No collection id found. Provide collectionId in pages.json, or set OUTLINE_COLLECTION_ID env var, or pass --collection-id=ID")}var L=(J)=>new Promise((Q)=>setTimeout(Q,J));function N(J){return J.toString().normalize("NFKD").replace(/[\u0300-\u036F]/g,"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/(^-|-$)+/g,"").slice(0,120)}function P(J){try{let Q=V.resolve(J),X=Bun.spawnSync(["git","log","-1","--format=%ct","--",Q],{cwd:process.cwd()});if(X.exitCode!==0)return null;let Z=new TextDecoder().decode(X.stdout).trim();if(!Z)return null;let $=Number(Z);if(Number.isNaN($))return null;return $*1000}catch{return null}}async function g(J){let Q=P(J);if(Q)return Q;return(await j.stat(J)).mtimeMs}async function _(J,Q){if(Y(J)){let X=`${J}.outline-sync.bak.${Date.now()}`;if(!B)await j.copyFile(J,X);console.log(`Backed up existing file to ${X}`)}else if(!B)await j.mkdir(V.dirname(J),{recursive:!0});if(!B)await j.writeFile(J,Q,"utf8");else console.log(`[dry-run] would write file ${J} (${Q.length} bytes)`)}async function v(J,Q,X=3){let Z=`${M}/api/${J}`;for(let $=0;$<X;$++)try{let G=await fetch(Z,{method:"POST",headers:E,body:JSON.stringify(Q)});if(G.status===429){let z=1000*($+1);console.warn(`Rate limited. Backing off ${z}ms`),await L(z);continue}let H=await G.json();if(!G.ok)throw console.error(`[Outline] ${G.status} ${J} payload=`,Q,"response=",H),new Error(`Outline API error ${G.status}: ${JSON.stringify(H)}`);return H}catch(G){if($===X-1)throw G;console.warn(`Request failed (attempt ${$+1}): ${G}. Retrying...`),await L(500*($+1))}throw new Error("outlineRequest: unreachable")}async function h(J){return(await v("documents.info",{id:J})).data??null}async function m(J,Q,X,Z){let $={title:J,text:Q,collectionId:X,parentDocumentId:Z||null,publish:!0};if(B)return console.log(`[dry-run] would create doc title="${J}" collection=${X} parent=${Z}`),{id:`dry-run-${Math.random().toString(36).slice(2,9)}`,title:J,text:Q,collectionId:X,parentDocumentId:Z};return(await v("documents.create",$)).data}async function I(J,Q,X){let Z={id:J,text:X,publish:!0};if(Q)Z.title=Q;if(B)return console.log(`[dry-run] would update doc id=${J} title=${Q}`),{id:J,title:Q,text:X};return(await v("documents.update",Z)).data}async function f(){let J=[],Q=0,X=100;while(!0)try{let $=(await v("collections.list",{offset:Q,limit:X})).data||[];for(let G of $)J.push({id:G.id,name:G.name});if($.length<X)break;Q+=$.length}catch(Z){if((Z?.message??"").includes("Pagination limit is too large")&&X!==100){console.warn("Outline API complained about limit; retrying with limit=100"),X=100;continue}throw Z}return J}async function r(J){let Q=[],X=0,Z=100;while(!0)try{let G=(await v("documents.list",{collectionId:J,offset:X,limit:Z})).data||[];for(let H of G)Q.push(H);if(G.length<Z)break;X+=G.length}catch($){if(($?.message??"").includes("Pagination limit is too large")&&Z!==100){console.warn("Outline API complained about limit; retrying with limit=100"),Z=100;continue}throw $}return Q}async function c(J,Q="docs"){let X=new Map,Z=new Set;for(let z of J){let w=N(z.title||"untitled"),k=`${w}.md`;if(Z.has(k)){let q=(z.id||"").slice(0,6),O=1,U=`${w}-${q}.md`;while(Z.has(U))O++,U=`${w}-${q}-${O}.md`;k=U}Z.add(k);let K=V.join(Q,k);X.set(z.id,K);let W=z.text??`# ${z.title}
18
+
19
+ `;if(!B)await j.mkdir(Q,{recursive:!0}),await j.writeFile(K,W,"utf8");else console.log(`[dry-run] would write ${K} (${W.length} bytes)`)}let $=new Map;for(let z of J)$.set(z.id,{title:z.title,file:X.get(z.id)||V.join(Q,`${N(z.title)}.md`),id:z.id,children:[],raw:z});let G=[];for(let z of $.values()){let w=z.raw||{},k=w.parentDocumentId??w.parentId??null;if(k&&$.has(k))$.get(k).children.push(z);else G.push(z)}function H(z){return{title:z.title,file:z.file,id:z.id,children:(z.children||[]).map(H)}}return G.map(H)}async function S(J,Q){if(B){console.log(`[dry-run] would persist manifest to ${Q}`);return}await j.writeFile(Q,`${JSON.stringify(J,null,2)}
20
+ `,"utf8")}async function p(J){if(!Y(J))throw new Error(`Manifest ${J} not found. Create ${J} with structure described in README.`);let Q=await j.readFile(J,"utf8");return JSON.parse(Q)}async function T(J,Q,X,Z,$){let G=Q.file,H=V.resolve(G),z=Y(H),w=0;if(z)try{w=await g(H)}catch(K){console.warn(`Couldn't stat file ${H}: ${K}`),w=0}if(Q.id){let K=null;try{K=await h(Q.id)}catch(W){console.error(`Failed to fetch Outline info for ${Q.title} (${Q.id}): ${W}`);return}if(!K)console.log(`Outline doc ${Q.id} not found - will create as new under collection ${$}.`),Q.id=null;else{let W=K.updatedAt?new Date(K.updatedAt).getTime():0;if(!z)console.log(`[PULL] Local file missing for "${Q.title}" -> fetching remote`),await _(H,K.text||"");else if(w>W+500){console.log(`[PUSH] Local newer for "${Q.title}" -> updating Outline`);try{let q=await j.readFile(H,"utf8");await I(Q.id,Q.title,q),console.log(` Updated Outline doc ${Q.id}`)}catch(q){console.error(` Failed to push ${Q.title}: ${q}`)}}else if(W>w+500){console.log(`[PULL] Outline newer for "${Q.title}" -> overwriting local file`);try{await _(H,K.text||""),console.log(` Wrote local file ${H}`)}catch(q){console.error(` Failed to write file ${H}: ${q}`)}}else console.log(`[SKIP] No changes for "${Q.title}"`)}}if(!Q.id){if(!Y(H))await j.mkdir(V.dirname(H),{recursive:!0}),await j.writeFile(H,`# ${Q.title}
21
+
22
+ `,"utf8"),console.log(`Created local placeholder file ${H}`);let K=await j.readFile(H,"utf8");try{let W=await m(Q.title,K,$,X);if(W?.id)Q.id=W.id,console.log(`Created Outline doc "${Q.title}" id=${Q.id} in collection ${$}`),await S(J,Z);else console.warn(`Create returned no id for "${Q.title}"`)}catch(W){console.error(`Failed to create Outline doc for "${Q.title}": ${W}`)}}let k=Q.id||X;if(Q.children?.length)for(let K of Q.children)await T(J,K,k,Z,$)}async function d(){if(x){console.log("Fetching collections...");try{let X=await f();for(let Z of X)console.log(`${Z.id} ${Z.name}`)}catch(X){console.error(`Failed to list collections: ${X}`)}return}if(A){let X=y||b;if(!X)console.error("Init requires a collection id. Provide with --collection-id=ID or set OUTLINE_COLLECTION_ID env var."),process.exit(1);console.log(`Bootstrapping manifest from collection ${X} (dry-run=${B})...`);try{let Z=await r(X);console.log(`Fetched ${Z.length} documents from Outline.`);let $=await c(Z,"docs");await S({collectionId:X,pages:$},F),console.log(`Wrote manifest to ${F} (pages saved into docs/).`)}catch(Z){console.error(`Init failed: ${Z}`)}return}if(!Y(F))console.error(`Manifest ${F} not found. Run with --init --collection-id=COLLECTION_ID to bootstrap.`),process.exit(1);let J=await p(F),Q=u(J.collectionId??null);if(console.log(`Syncing into single collection: ${Q}`),B)console.log("Running in dry-run mode; no destructive actions will be performed.");for(let X of J.pages)await T(J,X,null,V.resolve(F),Q);await S(J,V.resolve(F)),console.log("Sync complete.")}d();
23
+
24
+ //# debugId=50792B40EFF52C1C64756E2164756E21
25
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vc3luYy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsKICAgICIvKipcbiAqIE91dGxpbmUgPD4gR2l0IE1hcmtkb3duIHR3by13YXkgc3luYyAoc2luZ2xlLWNvbGxlY3Rpb24pICsgaW5pdFxuICogLSBCdW4gcnVudGltZSAodXNlcyBCdW4uc3Bhd25TeW5jLCBnbG9iYWwgZmV0Y2gpXG4gKlxuICogTmV3IGZlYXR1cmVzOlxuICogIC0gLS1pbml0IDogYm9vdHN0cmFwIHBhZ2VzLmpzb24gKyBtYXJrZG93biBmaWxlcyBmcm9tIGFuIGV4aXN0aW5nIGNvbGxlY3Rpb25cbiAqICAtIC0tbGlzdC1jb2xsZWN0aW9ucyA6IHByaW50cyBjb2xsZWN0aW9ucyAoaWQgKyBuYW1lKVxuICpcbiAqIFVzYWdlOlxuICogIE9VVExJTkVfQVBJX0tFWT0uLi4gYnVuIHJ1biBzeW5jLnRzIC0taW5pdCAtLWNvbGxlY3Rpb24taWQ9Q09MTEVDVElPTl9VVUlEXG4gKiAgT1VUTElORV9BUElfS0VZPS4uLiBidW4gcnVuIHN5bmMudHMgLS1saXN0LWNvbGxlY3Rpb25zXG4gKiAgT1VUTElORV9BUElfS0VZPS4uLiBidW4gcnVuIHN5bmMudHMgICAgICAgICAgICAjIG5vcm1hbCBzeW5jXG4gKlxuICogTk9URTogaWYgeW91IHJ1biAtLWluaXQgd2l0aG91dCAtLWRyeS1ydW4gaXQgd2lsbCBhY3R1YWxseSB3cml0ZSBmaWxlcyAmIHBhZ2VzLmpzb25cbiAqL1xuXG5pbXBvcnQgZnMgZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIjtcbmltcG9ydCB7IGV4aXN0c1N5bmMgfSBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcIm5vZGU6cGF0aFwiO1xuXG50eXBlIFBhZ2VFbnRyeSA9IHtcbiAgdGl0bGU6IHN0cmluZztcbiAgZmlsZTogc3RyaW5nO1xuICBpZDogc3RyaW5nIHwgbnVsbDtcbiAgY2hpbGRyZW4/OiBQYWdlRW50cnlbXTtcbn07XG5cbnR5cGUgTWFuaWZlc3QgPSB7XG4gIGNvbGxlY3Rpb25JZDogc3RyaW5nO1xuICBwYWdlczogUGFnZUVudHJ5W107XG59O1xuXG5jb25zdCBNQU5JRkVTVCA9IFwicGFnZXMuanNvblwiO1xuXG5jb25zdCBhcmd2ID0gcHJvY2Vzcy5hcmd2LnNsaWNlKDIpO1xubGV0IEJBU0VfVVJMID0gcHJvY2Vzcy5lbnYuT1VUTElORV9CQVNFX1VSTCB8fCBudWxsO1xubGV0IEFQSV9LRVkgPSBwcm9jZXNzLmVudi5PVVRMSU5FX0FQSV9LRVkgfHwgbnVsbDtcbmxldCBDTElfQ09MTEVDVElPTl9PVkVSUklERTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG5sZXQgRFJZX1JVTiA9IGZhbHNlO1xubGV0IERPX0lOSVQgPSBmYWxzZTtcbmxldCBMSVNUX0NPTExFQ1RJT05TID0gZmFsc2U7XG5cbmZvciAoY29uc3QgYSBvZiBhcmd2KSB7XG4gIGlmIChhLnN0YXJ0c1dpdGgoXCItLWNvbGxlY3Rpb24taWQ9XCIpKSB7XG4gICAgQ0xJX0NPTExFQ1RJT05fT1ZFUlJJREUgPSBhLnNwbGl0KFwiPVwiKVsxXSB8fCBudWxsO1xuICB9IGVsc2UgaWYgKGEgPT09IFwiLS1kcnktcnVuXCIpIHtcbiAgICBEUllfUlVOID0gdHJ1ZTtcbiAgfSBlbHNlIGlmIChhID09PSBcIi0taW5pdFwiKSB7XG4gICAgRE9fSU5JVCA9IHRydWU7XG4gIH0gZWxzZSBpZiAoYSA9PT0gXCItLWxpc3QtY29sbGVjdGlvbnNcIikge1xuICAgIExJU1RfQ09MTEVDVElPTlMgPSB0cnVlO1xuICB9IGVsc2UgaWYgKGEgPT09IFwiaW5pdFwiKSB7XG4gICAgRE9fSU5JVCA9IHRydWU7XG4gIH0gZWxzZSBpZiAoYSA9PT0gXCJsaXN0LWNvbGxlY3Rpb25zXCIpIHtcbiAgICBMSVNUX0NPTExFQ1RJT05TID0gdHJ1ZTtcbiAgfSBlbHNlIGlmIChhID09PSBcIi0taGVscFwiIHx8IGEgPT09IFwiLWhcIikge1xuICAgIHByaW50SGVscEFuZEV4aXQoKTtcbiAgfSBlbHNlIGlmIChhLnN0YXJ0c1dpdGgoXCItLWFwaS1rZXk9XCIpKSB7XG4gICAgQVBJX0tFWSA9IGEuc3BsaXQoXCI9XCIpWzFdIHx8IG51bGw7XG4gIH0gZWxzZSBpZiAoYS5zdGFydHNXaXRoKFwiLS1iYXNlLXVybD1cIikpIHtcbiAgICBCQVNFX1VSTCA9IGEuc3BsaXQoXCI9XCIpWzFdIHx8IG51bGw7XG4gIH0gZWxzZSB7XG4gICAgLy8gaWdub3JlIHVua25vd24sIGFsbG93IG90aGVyIGZsYWdzIGluIGZ1dHVyZVxuICB9XG59XG5cbmlmICghQkFTRV9VUkwpIHtcbiAgQkFTRV9VUkwgPSBcImh0dHBzOi8vYXBwLmdldG91dGxpbmUuY29tXCI7XG59XG5cbmNvbnN0IEhFQURFUlMgPSB7XG4gIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHtBUElfS0VZfWAsXG4gIFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxufTtcblxuZnVuY3Rpb24gcHJpbnRIZWxwQW5kRXhpdCgpIHtcbiAgY29uc29sZS5sb2coYFxuVXNhZ2U6XG4gIE9VVExJTkVfQVBJX0tFWT0uLi4gYnVuIHJ1biBzeW5jLnRzIFtvcHRpb25zXVxuXG5PcHRpb25zOlxuICAtLWluaXQgICAgICAgICAgICAgICAgICAgICAgQm9vdHN0cmFwIHBhZ2VzLmpzb24gKyBtYXJrZG93biBmaWxlcyBmcm9tIGEgY29sbGVjdGlvblxuICAtLWNvbGxlY3Rpb24taWQ9Q09MX0lEICAgICAgVXNlIHRoaXMgY29sbGVjdGlvbiBpZCAocmVxdWlyZWQgd2l0aCAtLWluaXQgdW5sZXNzIE9VVExJTkVfQ09MTEVDVElPTl9JRCBzZXQpXG4gIC0tbGlzdC1jb2xsZWN0aW9ucyAgICAgICAgICBMaXN0IGNvbGxlY3Rpb25zIHlvdSBoYXZlIGFjY2VzcyB0byAocHJpbnRzIGlkICsgbmFtZSlcbiAgLS1kcnktcnVuICAgICAgICAgICAgICAgICAgIFByaW50IGFjdGlvbnMgd2l0aG91dCB3cml0aW5nIGFueXRoaW5nXG4gIC0taGVscCAgICAgICAgICAgICAgICAgICAgICBTaG93IHRoaXMgaGVscFxuRXhhbXBsZXM6XG4gIE9VVExJTkVfQVBJX0tFWT0uLi4gYnVuIHJ1biBzeW5jLnRzIC0tbGlzdC1jb2xsZWN0aW9uc1xuICBPVVRMSU5FX0FQSV9LRVk9Li4uIGJ1biBydW4gc3luYy50cyAtLWluaXQgLS1jb2xsZWN0aW9uLWlkPWFiYy11dWlkXG4gIE9VVExJTkVfQVBJX0tFWT0uLi4gYnVuIHJ1biBzeW5jLnRzICAgICAgICAgICAgICAgICAgIyBwZXJmb3JtIHJlZ3VsYXIgc3luY1xuICBPVVRMSU5FX0FQSV9LRVk9Li4uIGJ1biBydW4gc3luYy50cyAtLWRyeS1ydW5cbmApO1xuICBwcm9jZXNzLmV4aXQoMCk7XG59XG5cbmNvbnN0IEVOVl9DT0xMRUNUSU9OID0gcHJvY2Vzcy5lbnYuT1VUTElORV9DT0xMRUNUSU9OX0lEIHx8IG51bGw7XG5mdW5jdGlvbiByZXNvbHZlQ29sbGVjdGlvbklkKG1hbmlmZXN0Q29sbGVjdGlvbklkOiBzdHJpbmcgfCBudWxsKTogc3RyaW5nIHtcbiAgaWYgKENMSV9DT0xMRUNUSU9OX09WRVJSSURFKSByZXR1cm4gQ0xJX0NPTExFQ1RJT05fT1ZFUlJJREU7XG4gIGlmIChFTlZfQ09MTEVDVElPTikgcmV0dXJuIEVOVl9DT0xMRUNUSU9OO1xuICBpZiAobWFuaWZlc3RDb2xsZWN0aW9uSWQpIHJldHVybiBtYW5pZmVzdENvbGxlY3Rpb25JZDtcbiAgdGhyb3cgbmV3IEVycm9yKFxuICAgIFwiTm8gY29sbGVjdGlvbiBpZCBmb3VuZC4gUHJvdmlkZSBjb2xsZWN0aW9uSWQgaW4gcGFnZXMuanNvbiwgb3Igc2V0IE9VVExJTkVfQ09MTEVDVElPTl9JRCBlbnYgdmFyLCBvciBwYXNzIC0tY29sbGVjdGlvbi1pZD1JRFwiLFxuICApO1xufVxuXG5jb25zdCBzbGVlcCA9IChtczogbnVtYmVyKSA9PiBuZXcgUHJvbWlzZSgocikgPT4gc2V0VGltZW91dChyLCBtcykpO1xuXG5mdW5jdGlvbiBzbHVnaWZ5VGl0bGUodGl0bGU6IHN0cmluZykge1xuICByZXR1cm4gdGl0bGVcbiAgICAudG9TdHJpbmcoKVxuICAgIC5ub3JtYWxpemUoXCJORktEXCIpXG4gICAgLnJlcGxhY2UoL1tcXHUwMzAwLVxcdTAzNkZdL2csIFwiXCIpIC8vIHJlbW92ZSBkaWFjcml0aWNzXG4gICAgLnRvTG93ZXJDYXNlKClcbiAgICAucmVwbGFjZSgvW15hLXowLTldKy9nLCBcIi1cIilcbiAgICAucmVwbGFjZSgvKF4tfC0kKSsvZywgXCJcIilcbiAgICAuc2xpY2UoMCwgMTIwKTtcbn1cblxuZnVuY3Rpb24gZ2V0R2l0VGltZXN0YW1wTXMoZmlsZVBhdGg6IHN0cmluZyk6IG51bWJlciB8IG51bGwge1xuICB0cnkge1xuICAgIGNvbnN0IHJlc29sdmVkID0gcGF0aC5yZXNvbHZlKGZpbGVQYXRoKTtcbiAgICBjb25zdCBvdXQgPSBCdW4uc3Bhd25TeW5jKFxuICAgICAgW1wiZ2l0XCIsIFwibG9nXCIsIFwiLTFcIiwgXCItLWZvcm1hdD0lY3RcIiwgXCItLVwiLCByZXNvbHZlZF0sXG4gICAgICB7IGN3ZDogcHJvY2Vzcy5jd2QoKSB9LFxuICAgICk7XG4gICAgaWYgKG91dC5leGl0Q29kZSAhPT0gMCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGNvbnN0IHR4dCA9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShvdXQuc3Rkb3V0KS50cmltKCk7XG4gICAgaWYgKCF0eHQpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IHNlYyA9IE51bWJlcih0eHQpO1xuICAgIGlmIChOdW1iZXIuaXNOYU4oc2VjKSkgcmV0dXJuIG51bGw7XG4gICAgcmV0dXJuIHNlYyAqIDEwMDA7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBudWxsO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldExvY2FsVGltZXN0YW1wTXMoZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8bnVtYmVyPiB7XG4gIGNvbnN0IGdpdFRzID0gZ2V0R2l0VGltZXN0YW1wTXMoZmlsZVBhdGgpO1xuICBpZiAoZ2l0VHMpIHJldHVybiBnaXRUcztcbiAgY29uc3Qgc3QgPSBhd2FpdCBmcy5zdGF0KGZpbGVQYXRoKTtcbiAgcmV0dXJuIHN0Lm10aW1lTXM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNhZmVXcml0ZUZpbGUoZmlsZVBhdGg6IHN0cmluZywgY29udGVudDogc3RyaW5nKSB7XG4gIGlmIChleGlzdHNTeW5jKGZpbGVQYXRoKSkge1xuICAgIGNvbnN0IGJhayA9IGAke2ZpbGVQYXRofS5vdXRsaW5lLXN5bmMuYmFrLiR7RGF0ZS5ub3coKX1gO1xuICAgIGlmICghRFJZX1JVTikge1xuICAgICAgYXdhaXQgZnMuY29weUZpbGUoZmlsZVBhdGgsIGJhayk7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKGBCYWNrZWQgdXAgZXhpc3RpbmcgZmlsZSB0byAke2Jha31gKTtcbiAgfSBlbHNlIHtcbiAgICBpZiAoIURSWV9SVU4pIHtcbiAgICAgIGF3YWl0IGZzLm1rZGlyKHBhdGguZGlybmFtZShmaWxlUGF0aCksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIH1cbiAgfVxuICBpZiAoIURSWV9SVU4pIHtcbiAgICBhd2FpdCBmcy53cml0ZUZpbGUoZmlsZVBhdGgsIGNvbnRlbnQsIFwidXRmOFwiKTtcbiAgfSBlbHNlIHtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIGBbZHJ5LXJ1bl0gd291bGQgd3JpdGUgZmlsZSAke2ZpbGVQYXRofSAoJHtjb250ZW50Lmxlbmd0aH0gYnl0ZXMpYCxcbiAgICApO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG91dGxpbmVSZXF1ZXN0KFxuICBlbmRwb2ludDogc3RyaW5nLFxuICBib2R5OiBhbnksXG4gIHJldHJpZXMgPSAzLFxuKTogUHJvbWlzZTxhbnk+IHtcbiAgY29uc3QgdXJsID0gYCR7QkFTRV9VUkx9L2FwaS8ke2VuZHBvaW50fWA7XG4gIGZvciAobGV0IGF0dGVtcHQgPSAwOyBhdHRlbXB0IDwgcmV0cmllczsgYXR0ZW1wdCsrKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IGZldGNoKHVybCwge1xuICAgICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgICBoZWFkZXJzOiBIRUFERVJTLFxuICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeShib2R5KSxcbiAgICAgIH0pO1xuICAgICAgaWYgKHJlcy5zdGF0dXMgPT09IDQyOSkge1xuICAgICAgICBjb25zdCBiYWNrb2ZmID0gMTAwMCAqIChhdHRlbXB0ICsgMSk7XG4gICAgICAgIGNvbnNvbGUud2FybihgUmF0ZSBsaW1pdGVkLiBCYWNraW5nIG9mZiAke2JhY2tvZmZ9bXNgKTtcbiAgICAgICAgYXdhaXQgc2xlZXAoYmFja29mZik7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QganNvbiA9IGF3YWl0IHJlcy5qc29uKCk7XG4gICAgICBpZiAoIXJlcy5vaykge1xuICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgIGBbT3V0bGluZV0gJHtyZXMuc3RhdHVzfSAke2VuZHBvaW50fSBwYXlsb2FkPWAsXG4gICAgICAgICAgYm9keSxcbiAgICAgICAgICBcInJlc3BvbnNlPVwiLFxuICAgICAgICAgIGpzb24sXG4gICAgICAgICk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgT3V0bGluZSBBUEkgZXJyb3IgJHtyZXMuc3RhdHVzfTogJHtKU09OLnN0cmluZ2lmeShqc29uKX1gLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGpzb247XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoYXR0ZW1wdCA9PT0gcmV0cmllcyAtIDEpIHRocm93IGVycjtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgYFJlcXVlc3QgZmFpbGVkIChhdHRlbXB0ICR7YXR0ZW1wdCArIDF9KTogJHtlcnJ9LiBSZXRyeWluZy4uLmAsXG4gICAgICApO1xuICAgICAgYXdhaXQgc2xlZXAoNTAwICogKGF0dGVtcHQgKyAxKSk7XG4gICAgfVxuICB9XG4gIHRocm93IG5ldyBFcnJvcihcIm91dGxpbmVSZXF1ZXN0OiB1bnJlYWNoYWJsZVwiKTtcbn1cblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgQVBJIGhlbHBlcnMgZm9yIG5vcm1hbCBzeW5jXG4gICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cbmFzeW5jIGZ1bmN0aW9uIGZldGNoT3V0bGluZUluZm8oZG9jdW1lbnRJZDogc3RyaW5nKSB7XG4gIGNvbnN0IHBheWxvYWQgPSB7IGlkOiBkb2N1bWVudElkIH07XG4gIGNvbnN0IGpzb24gPSBhd2FpdCBvdXRsaW5lUmVxdWVzdChcImRvY3VtZW50cy5pbmZvXCIsIHBheWxvYWQpO1xuICByZXR1cm4ganNvbi5kYXRhID8/IG51bGw7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNyZWF0ZU91dGxpbmVEb2N1bWVudChcbiAgdGl0bGU6IHN0cmluZyxcbiAgdGV4dDogc3RyaW5nLFxuICBjb2xsZWN0aW9uSWQ6IHN0cmluZyxcbiAgcGFyZW50RG9jdW1lbnRJZDogc3RyaW5nIHwgbnVsbCxcbikge1xuICBjb25zdCBwYXlsb2FkID0ge1xuICAgIHRpdGxlLFxuICAgIHRleHQsXG4gICAgY29sbGVjdGlvbklkLFxuICAgIHBhcmVudERvY3VtZW50SWQ6IHBhcmVudERvY3VtZW50SWQgfHwgbnVsbCxcbiAgICBwdWJsaXNoOiB0cnVlLFxuICB9O1xuICBpZiAoRFJZX1JVTikge1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgYFtkcnktcnVuXSB3b3VsZCBjcmVhdGUgZG9jIHRpdGxlPVwiJHt0aXRsZX1cIiBjb2xsZWN0aW9uPSR7Y29sbGVjdGlvbklkfSBwYXJlbnQ9JHtwYXJlbnREb2N1bWVudElkfWAsXG4gICAgKTtcbiAgICByZXR1cm4ge1xuICAgICAgaWQ6IGBkcnktcnVuLSR7TWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc2xpY2UoMiwgOSl9YCxcbiAgICAgIHRpdGxlLFxuICAgICAgdGV4dCxcbiAgICAgIGNvbGxlY3Rpb25JZCxcbiAgICAgIHBhcmVudERvY3VtZW50SWQsXG4gICAgfTtcbiAgfVxuICBjb25zdCBqc29uID0gYXdhaXQgb3V0bGluZVJlcXVlc3QoXCJkb2N1bWVudHMuY3JlYXRlXCIsIHBheWxvYWQpO1xuICByZXR1cm4ganNvbi5kYXRhO1xufVxuXG5hc3luYyBmdW5jdGlvbiB1cGRhdGVPdXRsaW5lRG9jdW1lbnQoXG4gIGlkOiBzdHJpbmcsXG4gIHRpdGxlOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIHRleHQ6IHN0cmluZyxcbikge1xuICBjb25zdCBwYXlsb2FkOiBhbnkgPSB7IGlkLCB0ZXh0LCBwdWJsaXNoOiB0cnVlIH07XG4gIGlmICh0aXRsZSkgcGF5bG9hZC50aXRsZSA9IHRpdGxlO1xuICBpZiAoRFJZX1JVTikge1xuICAgIGNvbnNvbGUubG9nKGBbZHJ5LXJ1bl0gd291bGQgdXBkYXRlIGRvYyBpZD0ke2lkfSB0aXRsZT0ke3RpdGxlfWApO1xuICAgIHJldHVybiB7IGlkLCB0aXRsZSwgdGV4dCB9O1xuICB9XG4gIGNvbnN0IGpzb24gPSBhd2FpdCBvdXRsaW5lUmVxdWVzdChcImRvY3VtZW50cy51cGRhdGVcIiwgcGF5bG9hZCk7XG4gIHJldHVybiBqc29uLmRhdGE7XG59XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgIEluaXQgaGVscGVyc1xuICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG4vKipcbiAqIExpc3QgT3V0bGluZSBjb2xsZWN0aW9ucyAocGFnZWQpXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGxpc3RDb2xsZWN0aW9ucygpOiBQcm9taXNlPHsgaWQ6IHN0cmluZzsgbmFtZTogc3RyaW5nIH1bXT4ge1xuICBjb25zdCBvdXQ6IHsgaWQ6IHN0cmluZzsgbmFtZTogc3RyaW5nIH1bXSA9IFtdO1xuICBsZXQgb2Zmc2V0ID0gMDtcbiAgbGV0IGxpbWl0ID0gMTAwOyAvLyBPdXRsaW5lIG1heCBpcyAxMDBcbiAgd2hpbGUgKHRydWUpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QganNvbiA9IGF3YWl0IG91dGxpbmVSZXF1ZXN0KFwiY29sbGVjdGlvbnMubGlzdFwiLCB7IG9mZnNldCwgbGltaXQgfSk7XG4gICAgICBjb25zdCBkYXRhID0ganNvbi5kYXRhIHx8IFtdO1xuICAgICAgZm9yIChjb25zdCBjIG9mIGRhdGEpIG91dC5wdXNoKHsgaWQ6IGMuaWQsIG5hbWU6IGMubmFtZSB9KTtcbiAgICAgIGlmIChkYXRhLmxlbmd0aCA8IGxpbWl0KSBicmVhaztcbiAgICAgIG9mZnNldCArPSBkYXRhLmxlbmd0aDtcbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgLy8gRGVmZW5zaXZlOiBpZiBBUEkgY29tcGxhaW5zIGFib3V0IGxpbWl0LCByZXRyeSBvbmNlIHdpdGggbGltaXQ9MTAwXG4gICAgICBjb25zdCBtc2cgPSBlcnI/Lm1lc3NhZ2UgPz8gXCJcIjtcbiAgICAgIGlmIChtc2cuaW5jbHVkZXMoXCJQYWdpbmF0aW9uIGxpbWl0IGlzIHRvbyBsYXJnZVwiKSAmJiBsaW1pdCAhPT0gMTAwKSB7XG4gICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICBcIk91dGxpbmUgQVBJIGNvbXBsYWluZWQgYWJvdXQgbGltaXQ7IHJldHJ5aW5nIHdpdGggbGltaXQ9MTAwXCIsXG4gICAgICAgICk7XG4gICAgICAgIGxpbWl0ID0gMTAwO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqXG4gKiBMaXN0IGFsbCBkb2N1bWVudHMgaW4gYSBjb2xsZWN0aW9uIChwYWdlZCkuXG4gKiBSZXR1cm5zIGFycmF5IG9mIGRvY3VtZW50cyB7IGlkLCB0aXRsZSwgdGV4dCwgcGFyZW50RG9jdW1lbnRJZCwgdXBkYXRlZEF0IH1cbiAqL1xuYXN5bmMgZnVuY3Rpb24gbGlzdERvY3VtZW50c0luQ29sbGVjdGlvbihjb2xsZWN0aW9uSWQ6IHN0cmluZyk6IFByb21pc2U8YW55W10+IHtcbiAgY29uc3Qgb3V0OiBhbnlbXSA9IFtdO1xuICBsZXQgb2Zmc2V0ID0gMDtcbiAgbGV0IGxpbWl0ID0gMTAwOyAvLyBtdXN0IGJlIDw9IDEwMCBwZXIgT3V0bGluZSBBUElcbiAgd2hpbGUgKHRydWUpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QganNvbiA9IGF3YWl0IG91dGxpbmVSZXF1ZXN0KFwiZG9jdW1lbnRzLmxpc3RcIiwge1xuICAgICAgICBjb2xsZWN0aW9uSWQsXG4gICAgICAgIG9mZnNldCxcbiAgICAgICAgbGltaXQsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGRhdGEgPSBqc29uLmRhdGEgfHwgW107XG4gICAgICBmb3IgKGNvbnN0IGQgb2YgZGF0YSkgb3V0LnB1c2goZCk7XG4gICAgICBpZiAoZGF0YS5sZW5ndGggPCBsaW1pdCkgYnJlYWs7XG4gICAgICBvZmZzZXQgKz0gZGF0YS5sZW5ndGg7XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgIGNvbnN0IG1zZyA9IGVycj8ubWVzc2FnZSA/PyBcIlwiO1xuICAgICAgaWYgKG1zZy5pbmNsdWRlcyhcIlBhZ2luYXRpb24gbGltaXQgaXMgdG9vIGxhcmdlXCIpICYmIGxpbWl0ICE9PSAxMDApIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIFwiT3V0bGluZSBBUEkgY29tcGxhaW5lZCBhYm91dCBsaW1pdDsgcmV0cnlpbmcgd2l0aCBsaW1pdD0xMDBcIixcbiAgICAgICAgKTtcbiAgICAgICAgbGltaXQgPSAxMDA7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cbiAgfVxuICByZXR1cm4gb3V0O1xufVxuXG4vKipcbiAqIFdyaXRlIGRvY3MgdG8gZGlzayBhbmQgcmV0dXJuIHBhZ2VzIGFycmF5ICh3aXRoIGZpbGUgcGF0aHMgc2V0KVxuICovXG5hc3luYyBmdW5jdGlvbiBtYXRlcmlhbGl6ZURvY3NUb0ZpbGVzKFxuICBkb2NzOiBhbnlbXSxcbiAgZGVzdERpciA9IFwiZG9jc1wiLFxuKTogUHJvbWlzZTxQYWdlRW50cnlbXT4ge1xuICAvLyBkb2NzIGlzIGZsYXQgYXJyYXkgd2l0aCBpZC90aXRsZS90ZXh0L3BhcmVudERvY3VtZW50SWQgKG9yIHBhcmVudElkKVxuICBjb25zdCBpZFRvRmlsZW5hbWUgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuICBjb25zdCB1c2VkID0gbmV3IFNldDxzdHJpbmc+KCk7XG5cbiAgLy8gMSkgYXNzaWduIHVuaXF1ZSBmaWxlbmFtZXMgYW5kIHdyaXRlIGZpbGVzXG4gIGZvciAoY29uc3QgZCBvZiBkb2NzKSB7XG4gICAgY29uc3Qgc2x1ZyA9IHNsdWdpZnlUaXRsZShkLnRpdGxlIHx8IFwidW50aXRsZWRcIik7XG4gICAgbGV0IGNhbmRpZGF0ZSA9IGAke3NsdWd9Lm1kYDtcbiAgICAvLyBlbnN1cmUgdW5pcXVlbmVzc1xuICAgIGlmICh1c2VkLmhhcyhjYW5kaWRhdGUpKSB7XG4gICAgICBjb25zdCBzaG9ydCA9IChkLmlkIHx8IFwiXCIpLnNsaWNlKDAsIDYpO1xuICAgICAgbGV0IGkgPSAxO1xuICAgICAgbGV0IGF0dGVtcHQgPSBgJHtzbHVnfS0ke3Nob3J0fS5tZGA7XG4gICAgICB3aGlsZSAodXNlZC5oYXMoYXR0ZW1wdCkpIHtcbiAgICAgICAgaSsrO1xuICAgICAgICBhdHRlbXB0ID0gYCR7c2x1Z30tJHtzaG9ydH0tJHtpfS5tZGA7XG4gICAgICB9XG4gICAgICBjYW5kaWRhdGUgPSBhdHRlbXB0O1xuICAgIH1cbiAgICB1c2VkLmFkZChjYW5kaWRhdGUpO1xuXG4gICAgY29uc3QgZnVsbFBhdGggPSBwYXRoLmpvaW4oZGVzdERpciwgY2FuZGlkYXRlKTtcbiAgICBpZFRvRmlsZW5hbWUuc2V0KGQuaWQsIGZ1bGxQYXRoKTtcblxuICAgIGNvbnN0IGNvbnRlbnQgPSBkLnRleHQgPz8gYCMgJHtkLnRpdGxlfVxcblxcbmA7XG4gICAgaWYgKCFEUllfUlVOKSB7XG4gICAgICBhd2FpdCBmcy5ta2RpcihkZXN0RGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgIGF3YWl0IGZzLndyaXRlRmlsZShmdWxsUGF0aCwgY29udGVudCwgXCJ1dGY4XCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgYFtkcnktcnVuXSB3b3VsZCB3cml0ZSAke2Z1bGxQYXRofSAoJHtjb250ZW50Lmxlbmd0aH0gYnl0ZXMpYCxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gMikgYnVpbGQgbm9kZXMgbWFwIChhbGwgbm9kZXMgcHJlc2VudCBiZWZvcmUgYXR0YWNoaW5nIGNoaWxkcmVuKVxuICBjb25zdCBtYXAgPSBuZXcgTWFwPHN0cmluZywgUGFnZUVudHJ5ICYgeyByYXc/OiBhbnkgfT4oKTtcbiAgZm9yIChjb25zdCBkIG9mIGRvY3MpIHtcbiAgICBtYXAuc2V0KGQuaWQsIHtcbiAgICAgIHRpdGxlOiBkLnRpdGxlLFxuICAgICAgZmlsZTpcbiAgICAgICAgaWRUb0ZpbGVuYW1lLmdldChkLmlkKSB8fFxuICAgICAgICBwYXRoLmpvaW4oZGVzdERpciwgYCR7c2x1Z2lmeVRpdGxlKGQudGl0bGUpfS5tZGApLFxuICAgICAgaWQ6IGQuaWQsXG4gICAgICBjaGlsZHJlbjogW10sXG4gICAgICByYXc6IGQsXG4gICAgfSBhcyBhbnkpO1xuICB9XG5cbiAgLy8gMykgYXR0YWNoIGNoaWxkcmVuIOKAlCByb2J1c3QgdG8gYm90aCBwYXJlbnREb2N1bWVudElkIGFuZCBwYXJlbnRJZFxuICBjb25zdCByb290czogKFBhZ2VFbnRyeSAmIHsgcmF3PzogYW55IH0pW10gPSBbXTtcbiAgZm9yIChjb25zdCBub2RlIG9mIG1hcC52YWx1ZXMoKSkge1xuICAgIGNvbnN0IHJhdyA9IG5vZGUucmF3IHx8IHt9O1xuICAgIGNvbnN0IHBhcmVudElkID0gcmF3LnBhcmVudERvY3VtZW50SWQgPz8gcmF3LnBhcmVudElkID8/IG51bGw7XG4gICAgaWYgKHBhcmVudElkICYmIG1hcC5oYXMocGFyZW50SWQpKSB7XG4gICAgICBtYXAuZ2V0KHBhcmVudElkKSEuY2hpbGRyZW4hLnB1c2gobm9kZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJvb3RzLnB1c2gobm9kZSk7XG4gICAgfVxuICB9XG5cbiAgLy8gNCkgc3RyaXAgaW50ZXJuYWwgYHJhd2AgYW5kIHJldHVybiB0cmVlIHJlY3Vyc2l2ZWx5XG4gIGZ1bmN0aW9uIHN0cmlwKG46IGFueSk6IFBhZ2VFbnRyeSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRpdGxlOiBuLnRpdGxlLFxuICAgICAgZmlsZTogbi5maWxlLFxuICAgICAgaWQ6IG4uaWQsXG4gICAgICBjaGlsZHJlbjogKG4uY2hpbGRyZW4gfHwgW10pLm1hcChzdHJpcCksXG4gICAgfTtcbiAgfVxuICByZXR1cm4gcm9vdHMubWFwKHN0cmlwKTtcbn1cblxuLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgRXhpc3Rpbmcgc3luYyBsb2dpYyAodW5jaGFuZ2VkKVxuICAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuXG5hc3luYyBmdW5jdGlvbiBwZXJzaXN0TWFuaWZlc3QobWFuaWZlc3Q6IE1hbmlmZXN0LCBmaWxlUGF0aDogc3RyaW5nKSB7XG4gIGlmIChEUllfUlVOKSB7XG4gICAgY29uc29sZS5sb2coYFtkcnktcnVuXSB3b3VsZCBwZXJzaXN0IG1hbmlmZXN0IHRvICR7ZmlsZVBhdGh9YCk7XG4gICAgcmV0dXJuO1xuICB9XG4gIGF3YWl0IGZzLndyaXRlRmlsZShcbiAgICBmaWxlUGF0aCxcbiAgICBgJHtKU09OLnN0cmluZ2lmeShtYW5pZmVzdCwgbnVsbCwgMil9XFxuYCxcbiAgICBcInV0ZjhcIixcbiAgKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gbG9hZE1hbmlmZXN0KGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPE1hbmlmZXN0PiB7XG4gIGlmICghZXhpc3RzU3luYyhmaWxlUGF0aCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgTWFuaWZlc3QgJHtmaWxlUGF0aH0gbm90IGZvdW5kLiBDcmVhdGUgJHtmaWxlUGF0aH0gd2l0aCBzdHJ1Y3R1cmUgZGVzY3JpYmVkIGluIFJFQURNRS5gLFxuICAgICk7XG4gIH1cbiAgY29uc3QgcmF3ID0gYXdhaXQgZnMucmVhZEZpbGUoZmlsZVBhdGgsIFwidXRmOFwiKTtcbiAgcmV0dXJuIEpTT04ucGFyc2UocmF3KSBhcyBNYW5pZmVzdDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gc3luY1BhZ2UoXG4gIG1hbmlmZXN0OiBNYW5pZmVzdCxcbiAgcGFnZTogUGFnZUVudHJ5LFxuICBwYXJlbnRJZDogc3RyaW5nIHwgbnVsbCxcbiAgbWFuaWZlc3RQYXRoOiBzdHJpbmcsXG4gIHJlc29sdmVkQ29sbGVjdGlvbklkOiBzdHJpbmcsXG4pIHtcbiAgY29uc3QgZmlsZVBhdGggPSBwYWdlLmZpbGU7XG4gIGNvbnN0IGFic1BhdGggPSBwYXRoLnJlc29sdmUoZmlsZVBhdGgpO1xuICBjb25zdCBmaWxlRXhpc3RzID0gZXhpc3RzU3luYyhhYnNQYXRoKTtcblxuICBsZXQgbG9jYWxUcyA9IDA7XG4gIGlmIChmaWxlRXhpc3RzKSB7XG4gICAgdHJ5IHtcbiAgICAgIGxvY2FsVHMgPSBhd2FpdCBnZXRMb2NhbFRpbWVzdGFtcE1zKGFic1BhdGgpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS53YXJuKGBDb3VsZG4ndCBzdGF0IGZpbGUgJHthYnNQYXRofTogJHtlcnJ9YCk7XG4gICAgICBsb2NhbFRzID0gMDtcbiAgICB9XG4gIH1cblxuICBpZiAocGFnZS5pZCkge1xuICAgIGxldCBkb2M6IGFueSA9IG51bGw7XG4gICAgdHJ5IHtcbiAgICAgIGRvYyA9IGF3YWl0IGZldGNoT3V0bGluZUluZm8ocGFnZS5pZCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICBgRmFpbGVkIHRvIGZldGNoIE91dGxpbmUgaW5mbyBmb3IgJHtwYWdlLnRpdGxlfSAoJHtwYWdlLmlkfSk6ICR7ZXJyfWAsXG4gICAgICApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICghZG9jKSB7XG4gICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgYE91dGxpbmUgZG9jICR7cGFnZS5pZH0gbm90IGZvdW5kIC0gd2lsbCBjcmVhdGUgYXMgbmV3IHVuZGVyIGNvbGxlY3Rpb24gJHtyZXNvbHZlZENvbGxlY3Rpb25JZH0uYCxcbiAgICAgICk7XG4gICAgICBwYWdlLmlkID0gbnVsbDtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgcmVtb3RlVXBkYXRlZEF0ID0gZG9jLnVwZGF0ZWRBdFxuICAgICAgICA/IG5ldyBEYXRlKGRvYy51cGRhdGVkQXQpLmdldFRpbWUoKVxuICAgICAgICA6IDA7XG5cbiAgICAgIGlmICghZmlsZUV4aXN0cykge1xuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICBgW1BVTExdIExvY2FsIGZpbGUgbWlzc2luZyBmb3IgXCIke3BhZ2UudGl0bGV9XCIgLT4gZmV0Y2hpbmcgcmVtb3RlYCxcbiAgICAgICAgKTtcbiAgICAgICAgYXdhaXQgc2FmZVdyaXRlRmlsZShhYnNQYXRoLCBkb2MudGV4dCB8fCBcIlwiKTtcbiAgICAgIH0gZWxzZSBpZiAobG9jYWxUcyA+IHJlbW90ZVVwZGF0ZWRBdCArIDUwMCkge1xuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICBgW1BVU0hdIExvY2FsIG5ld2VyIGZvciBcIiR7cGFnZS50aXRsZX1cIiAtPiB1cGRhdGluZyBPdXRsaW5lYCxcbiAgICAgICAgKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUoYWJzUGF0aCwgXCJ1dGY4XCIpO1xuICAgICAgICAgIGF3YWl0IHVwZGF0ZU91dGxpbmVEb2N1bWVudChwYWdlLmlkLCBwYWdlLnRpdGxlLCBjb250ZW50KTtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgICBVcGRhdGVkIE91dGxpbmUgZG9jICR7cGFnZS5pZH1gKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihgICBGYWlsZWQgdG8gcHVzaCAke3BhZ2UudGl0bGV9OiAke2Vycn1gKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChyZW1vdGVVcGRhdGVkQXQgPiBsb2NhbFRzICsgNTAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgIGBbUFVMTF0gT3V0bGluZSBuZXdlciBmb3IgXCIke3BhZ2UudGl0bGV9XCIgLT4gb3ZlcndyaXRpbmcgbG9jYWwgZmlsZWAsXG4gICAgICAgICk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgc2FmZVdyaXRlRmlsZShhYnNQYXRoLCBkb2MudGV4dCB8fCBcIlwiKTtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgICBXcm90ZSBsb2NhbCBmaWxlICR7YWJzUGF0aH1gKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihgICBGYWlsZWQgdG8gd3JpdGUgZmlsZSAke2Fic1BhdGh9OiAke2Vycn1gKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc29sZS5sb2coYFtTS0lQXSBObyBjaGFuZ2VzIGZvciBcIiR7cGFnZS50aXRsZX1cImApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGlmICghcGFnZS5pZCkge1xuICAgIGlmICghZXhpc3RzU3luYyhhYnNQYXRoKSkge1xuICAgICAgYXdhaXQgZnMubWtkaXIocGF0aC5kaXJuYW1lKGFic1BhdGgpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgIGF3YWl0IGZzLndyaXRlRmlsZShhYnNQYXRoLCBgIyAke3BhZ2UudGl0bGV9XFxuXFxuYCwgXCJ1dGY4XCIpO1xuICAgICAgY29uc29sZS5sb2coYENyZWF0ZWQgbG9jYWwgcGxhY2Vob2xkZXIgZmlsZSAke2Fic1BhdGh9YCk7XG4gICAgfVxuICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShhYnNQYXRoLCBcInV0ZjhcIik7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGNyZWF0ZWQgPSBhd2FpdCBjcmVhdGVPdXRsaW5lRG9jdW1lbnQoXG4gICAgICAgIHBhZ2UudGl0bGUsXG4gICAgICAgIGNvbnRlbnQsXG4gICAgICAgIHJlc29sdmVkQ29sbGVjdGlvbklkLFxuICAgICAgICBwYXJlbnRJZCxcbiAgICAgICk7XG4gICAgICBpZiAoY3JlYXRlZD8uaWQpIHtcbiAgICAgICAgcGFnZS5pZCA9IGNyZWF0ZWQuaWQ7XG4gICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgIGBDcmVhdGVkIE91dGxpbmUgZG9jIFwiJHtwYWdlLnRpdGxlfVwiIGlkPSR7cGFnZS5pZH0gaW4gY29sbGVjdGlvbiAke3Jlc29sdmVkQ29sbGVjdGlvbklkfWAsXG4gICAgICAgICk7XG4gICAgICAgIGF3YWl0IHBlcnNpc3RNYW5pZmVzdChtYW5pZmVzdCwgbWFuaWZlc3RQYXRoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgQ3JlYXRlIHJldHVybmVkIG5vIGlkIGZvciBcIiR7cGFnZS50aXRsZX1cImApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS5lcnJvcihgRmFpbGVkIHRvIGNyZWF0ZSBPdXRsaW5lIGRvYyBmb3IgXCIke3BhZ2UudGl0bGV9XCI6ICR7ZXJyfWApO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IG5leHRQYXJlbnRJZCA9IHBhZ2UuaWQgfHwgcGFyZW50SWQ7XG4gIGlmIChwYWdlLmNoaWxkcmVuPy5sZW5ndGgpIHtcbiAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIHBhZ2UuY2hpbGRyZW4pIHtcbiAgICAgIGF3YWl0IHN5bmNQYWdlKFxuICAgICAgICBtYW5pZmVzdCxcbiAgICAgICAgY2hpbGQsXG4gICAgICAgIG5leHRQYXJlbnRJZCxcbiAgICAgICAgbWFuaWZlc3RQYXRoLFxuICAgICAgICByZXNvbHZlZENvbGxlY3Rpb25JZCxcbiAgICAgICk7XG4gICAgfVxuICB9XG59XG5cbi8qIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgIE1haW5cbiAgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpIHtcbiAgaWYgKExJU1RfQ09MTEVDVElPTlMpIHtcbiAgICBjb25zb2xlLmxvZyhcIkZldGNoaW5nIGNvbGxlY3Rpb25zLi4uXCIpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb2xzID0gYXdhaXQgbGlzdENvbGxlY3Rpb25zKCk7XG4gICAgICBmb3IgKGNvbnN0IGMgb2YgY29scykge1xuICAgICAgICBjb25zb2xlLmxvZyhgJHtjLmlkfVxcdCR7Yy5uYW1lfWApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS5lcnJvcihgRmFpbGVkIHRvIGxpc3QgY29sbGVjdGlvbnM6ICR7ZXJyfWApO1xuICAgIH1cbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoRE9fSU5JVCkge1xuICAgIGNvbnN0IGNvbGxlY3Rpb25JZCA9IENMSV9DT0xMRUNUSU9OX09WRVJSSURFIHx8IEVOVl9DT0xMRUNUSU9OO1xuICAgIGlmICghY29sbGVjdGlvbklkKSB7XG4gICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICBcIkluaXQgcmVxdWlyZXMgYSBjb2xsZWN0aW9uIGlkLiBQcm92aWRlIHdpdGggLS1jb2xsZWN0aW9uLWlkPUlEIG9yIHNldCBPVVRMSU5FX0NPTExFQ1RJT05fSUQgZW52IHZhci5cIixcbiAgICAgICk7XG4gICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKFxuICAgICAgYEJvb3RzdHJhcHBpbmcgbWFuaWZlc3QgZnJvbSBjb2xsZWN0aW9uICR7Y29sbGVjdGlvbklkfSAoZHJ5LXJ1bj0ke0RSWV9SVU59KS4uLmAsXG4gICAgKTtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZG9jcyA9IGF3YWl0IGxpc3REb2N1bWVudHNJbkNvbGxlY3Rpb24oY29sbGVjdGlvbklkKTtcbiAgICAgIGNvbnNvbGUubG9nKGBGZXRjaGVkICR7ZG9jcy5sZW5ndGh9IGRvY3VtZW50cyBmcm9tIE91dGxpbmUuYCk7XG4gICAgICBjb25zdCByb290cyA9IGF3YWl0IG1hdGVyaWFsaXplRG9jc1RvRmlsZXMoZG9jcywgXCJkb2NzXCIpO1xuICAgICAgY29uc3QgbWFuaWZlc3Q6IE1hbmlmZXN0ID0ge1xuICAgICAgICBjb2xsZWN0aW9uSWQsXG4gICAgICAgIHBhZ2VzOiByb290cyxcbiAgICAgIH07XG4gICAgICBhd2FpdCBwZXJzaXN0TWFuaWZlc3QobWFuaWZlc3QsIE1BTklGRVNUKTtcbiAgICAgIGNvbnNvbGUubG9nKGBXcm90ZSBtYW5pZmVzdCB0byAke01BTklGRVNUfSAocGFnZXMgc2F2ZWQgaW50byBkb2NzLykuYCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLmVycm9yKGBJbml0IGZhaWxlZDogJHtlcnJ9YCk7XG4gICAgfVxuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIG5vcm1hbCBzeW5jIGZsb3dcbiAgLy8gaWYgbWFuaWZlc3QgbWlzc2luZywgZXJyb3IgYW5kIGhpbnQgdG8gdXNlIC0taW5pdFxuICBpZiAoIWV4aXN0c1N5bmMoTUFOSUZFU1QpKSB7XG4gICAgY29uc29sZS5lcnJvcihcbiAgICAgIGBNYW5pZmVzdCAke01BTklGRVNUfSBub3QgZm91bmQuIFJ1biB3aXRoIC0taW5pdCAtLWNvbGxlY3Rpb24taWQ9Q09MTEVDVElPTl9JRCB0byBib290c3RyYXAuYCxcbiAgICApO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfVxuICBjb25zdCBtYW5pZmVzdCA9IGF3YWl0IGxvYWRNYW5pZmVzdChNQU5JRkVTVCk7XG4gIGNvbnN0IGVmZmVjdGl2ZUNvbGxlY3Rpb25JZCA9IHJlc29sdmVDb2xsZWN0aW9uSWQoXG4gICAgbWFuaWZlc3QuY29sbGVjdGlvbklkID8/IG51bGwsXG4gICk7XG4gIGNvbnNvbGUubG9nKGBTeW5jaW5nIGludG8gc2luZ2xlIGNvbGxlY3Rpb246ICR7ZWZmZWN0aXZlQ29sbGVjdGlvbklkfWApO1xuICBpZiAoRFJZX1JVTilcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIFwiUnVubmluZyBpbiBkcnktcnVuIG1vZGU7IG5vIGRlc3RydWN0aXZlIGFjdGlvbnMgd2lsbCBiZSBwZXJmb3JtZWQuXCIsXG4gICAgKTtcblxuICBmb3IgKGNvbnN0IHAgb2YgbWFuaWZlc3QucGFnZXMpIHtcbiAgICBhd2FpdCBzeW5jUGFnZShcbiAgICAgIG1hbmlmZXN0LFxuICAgICAgcCxcbiAgICAgIG51bGwsXG4gICAgICBwYXRoLnJlc29sdmUoTUFOSUZFU1QpLFxuICAgICAgZWZmZWN0aXZlQ29sbGVjdGlvbklkLFxuICAgICk7XG4gIH1cbiAgYXdhaXQgcGVyc2lzdE1hbmlmZXN0KG1hbmlmZXN0LCBwYXRoLnJlc29sdmUoTUFOSUZFU1QpKTtcbiAgY29uc29sZS5sb2coXCJTeW5jIGNvbXBsZXRlLlwiKTtcbn1cblxubWFpbigpO1xuIgogIF0sCiAgIm1hcHBpbmdzIjogIjtBQWdCQSwyQkFDQSxxQkFBUyxXQUNULG9CQWNBLElBQU0sRUFBVyxhQUVYLEVBQU8sUUFBUSxLQUFLLE1BQU0sQ0FBQyxFQUM3QixFQUFXLFFBQVEsSUFBSSxrQkFBb0IsS0FDM0MsRUFBVSxRQUFRLElBQUksaUJBQW1CLEtBQ3pDLEVBQXlDLEtBQ3pDLEVBQVUsR0FDVixFQUFVLEdBQ1YsRUFBbUIsR0FFdkIsUUFBVyxLQUFLLEVBQ2QsR0FBSSxFQUFFLFdBQVcsa0JBQWtCLEVBQ2pDLEVBQTBCLEVBQUUsTUFBTSxHQUFHLEVBQUUsSUFBTSxLQUN4QyxRQUFJLElBQU0sWUFD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QUFRLEVBQ3hDLFFBQVEsSUFBSSxxQkFBcUIsNkJBQW9DLEVBQ3JFLE1BQU8sRUFBSyxDQUNaLFFBQVEsTUFBTSxnQkFBZ0IsR0FBSyxFQUVyQyxPQUtGLElBQUssRUFBVyxDQUFRLEVBQ3RCLFFBQVEsTUFDTixZQUFZLDBFQUNkLEVBQ0EsUUFBUSxLQUFLLENBQUMsRUFFaEIsSUFBTSxFQUFXLE1BQU0sRUFBYSxDQUFRLEVBQ3RDLEVBQXdCLEVBQzVCLEVBQVMsY0FBZ0IsSUFDM0IsRUFFQSxHQURBLFFBQVEsSUFBSSxtQ0FBbUMsR0FBdUIsRUFDbEUsRUFDRixRQUFRLElBQ04sb0VBQ0YsRUFFRixRQUFXLEtBQUssRUFBUyxNQUN2QixNQUFNLEVBQ0osRUFDQSxFQUNBLEtBQ0EsRUFBSyxRQUFRLENBQVEsRUFDckIsQ0FDRixFQUVGLE1BQU0sRUFBZ0IsRUFBVSxFQUFLLFFBQVEsQ0FBUSxDQUFDLEVBQ3RELFFBQVEsSUFBSSxnQkFBZ0IsRUFHOUIsRUFBSyIsCiAgImRlYnVnSWQiOiAiNTA3OTJCNDBFRkY1MkMxQzY0NzU2RTIxNjQ3NTZFMjEiLAogICJuYW1lcyI6IFtdCn0=
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@dockstat/outline-sync",
3
+ "version": "1.0.0",
4
+ "description": "A simple outline git-sync library",
5
+ "type": "module",
6
+ "main": "./dist/sync.js",
7
+ "types": "./dist/sync.d.ts",
8
+ "bin": {
9
+ "outline-sync": "./dist/sync.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/sync.d.ts",
14
+ "import": "./dist/sync.js",
15
+ "default": "./dist/sync.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist/**/*",
20
+ "README.md"
21
+ ],
22
+ "scripts": {
23
+ "build": "bun run ./build.ts",
24
+ "dev": "bun build sync.ts",
25
+ "lint": "biome lint .",
26
+ "lint:fix": "biome lint --write .",
27
+ "check-types": "bunx tsc --noEmit",
28
+ "test": "bun run test.ts",
29
+ "clean": "rm -rf dist",
30
+ "prepublishOnly": "npm run clean && npm run build"
31
+ },
32
+ "keywords": [
33
+ "outline",
34
+ "sync",
35
+ "documentation",
36
+ "typescript",
37
+ "bun",
38
+ "git-sync",
39
+ "cli"
40
+ ],
41
+ "author": "Its4Nik",
42
+ "license": "MIT",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/Its4Nik/DockStat",
46
+ "directory": "packages/outline-sync"
47
+ },
48
+ "bugs": {
49
+ "url": "https://github.com/Its4Nik/DockStat/issues"
50
+ },
51
+ "homepage": "https://github.com/Its4Nik/DockStat/tree/main/packages/outline-sync",
52
+ "engines": {
53
+ "bun": ">=1.0.0"
54
+ },
55
+ "peerDependencies": {
56
+ "typescript": "^5"
57
+ },
58
+ "devDependencies": {
59
+ "@types/bun": "latest"
60
+ }
61
+ }