@blinkk/root-cms 2.0.0-rc.1 → 2.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/dist/app.js CHANGED
@@ -3,8 +3,181 @@ import crypto from "node:crypto";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { render as renderToString } from "preact-render-to-string";
6
+
7
+ // package.json
8
+ var package_default = {
9
+ name: "@blinkk/root-cms",
10
+ version: "2.0.0",
11
+ author: "s@blinkk.com",
12
+ license: "MIT",
13
+ engines: {
14
+ node: ">=16.0.0"
15
+ },
16
+ repository: {
17
+ type: "git",
18
+ url: "git+https://github.com/blinkk/rootjs.git",
19
+ directory: "packages/root-cms"
20
+ },
21
+ files: [
22
+ "dist/**/*"
23
+ ],
24
+ bin: {
25
+ "root-cms": "./bin/root-cms.js"
26
+ },
27
+ type: "module",
28
+ module: "./dist/index.js",
29
+ types: "./dist/index.d.ts",
30
+ exports: {
31
+ ".": {
32
+ types: "./dist/core.d.ts",
33
+ import: "./dist/core.js"
34
+ },
35
+ "./client": {
36
+ types: "./dist/client.d.ts",
37
+ import: "./dist/client.js"
38
+ },
39
+ "./core": {
40
+ types: "./dist/core.d.ts",
41
+ import: "./dist/core.js"
42
+ },
43
+ "./functions": {
44
+ types: "./dist/functions.d.ts",
45
+ import: "./dist/functions.js"
46
+ },
47
+ "./plugin": {
48
+ types: "./dist/plugin.d.ts",
49
+ import: "./dist/plugin.js"
50
+ },
51
+ "./project": {
52
+ types: "./dist/project.d.ts",
53
+ import: "./dist/project.js"
54
+ },
55
+ "./richtext": {
56
+ types: "./dist/richtext.d.ts",
57
+ import: "./dist/richtext.js"
58
+ }
59
+ },
60
+ scripts: {
61
+ build: 'rm -rf dist && concurrently -n "core,signin,ui" npm:build:core npm:build:signin npm:build:ui',
62
+ "build:core": "tsup-node --config=./core/tsup.config.ts",
63
+ "//": "NOTE: esbuild is used here because tsup doesn't currently support aliases.",
64
+ "build:ui": "esbuild ui/ui.tsx --bundle --minify --alias:react=@preact/compat --alias:react-dom=@preact/compat --tsconfig=ui/tsconfig.json --outdir=dist/ui",
65
+ "build:signin": "esbuild signin/signin.tsx --bundle --minify --tsconfig=signin/tsconfig.json --outdir=dist/ui",
66
+ dev: 'rm -rf dist && concurrently -k -n "core,ui" npm:dev:core npm:dev:signin npm:dev:ui',
67
+ "dev:core": "pnpm build:core --watch",
68
+ "dev:signin": "pnpm build:signin --watch",
69
+ "dev:ui": "pnpm build:ui --watch",
70
+ test: "pnpm build && firebase emulators:exec 'vitest run'",
71
+ "test:watch": "pnpm build && firebase emulators:exec 'vitest'"
72
+ },
73
+ dependencies: {
74
+ "@genkit-ai/ai": "1.15.5",
75
+ "@genkit-ai/core": "1.15.5",
76
+ "@genkit-ai/vertexai": "1.15.5",
77
+ "@hello-pangea/dnd": "18.0.1",
78
+ "body-parser": "1.20.2",
79
+ commander: "11.0.0",
80
+ "csv-parse": "5.5.2",
81
+ "csv-stringify": "6.4.4",
82
+ "dts-dom": "3.7.0",
83
+ "fnv-plus": "1.3.1",
84
+ genkit: "1.15.5",
85
+ jsonwebtoken: "9.0.2",
86
+ kleur: "4.1.5",
87
+ sirv: "2.0.3",
88
+ "tiny-glob": "0.2.9"
89
+ },
90
+ "//": "NOTE(stevenle): due to compat issues with mantine and preact, mantine is pinned to v4.2.12",
91
+ devDependencies: {
92
+ "@babel/core": "7.17.9",
93
+ "@blinkk/root": "workspace:*",
94
+ "@editorjs/editorjs": "2.30.8",
95
+ "@editorjs/header": "2.8.8",
96
+ "@editorjs/image": "2.10.2",
97
+ "@editorjs/list": "2.0.6",
98
+ "@editorjs/nested-list": "1.4.3",
99
+ "@editorjs/raw": "2.5.1",
100
+ "@editorjs/table": "2.4.4",
101
+ "@editorjs/underline": "1.2.1",
102
+ "@emotion/react": "11.10.5",
103
+ "@firebase/app-compat": "0.2.19",
104
+ "@firebase/app-types": "0.9.0",
105
+ "@firebase/rules-unit-testing": "3.0.1",
106
+ "@mantine/core": "4.2.12",
107
+ "@mantine/hooks": "4.2.12",
108
+ "@mantine/modals": "4.2.12",
109
+ "@mantine/notifications": "4.2.12",
110
+ "@mantine/spotlight": "4.2.12",
111
+ "@preact/compat": "17.1.2",
112
+ "@tabler/icons-preact": "2.47.0",
113
+ "@types/body-parser": "1.19.3",
114
+ "@types/fnv-plus": "1.3.2",
115
+ "@types/gapi": "0.0.47",
116
+ "@types/gapi.client.drive-v3": "0.0.4",
117
+ "@types/gapi.client.sheets-v4": "0.0.4",
118
+ "@types/google.accounts": "0.0.14",
119
+ "@types/jsonwebtoken": "9.0.1",
120
+ "@types/node": "18.11.8",
121
+ concurrently: "7.6.0",
122
+ esbuild: "0.19.9",
123
+ firebase: "10.5.2",
124
+ "firebase-admin": "11.11.1",
125
+ "firebase-functions": "4.8.0",
126
+ "firebase-tools": "12.9.1",
127
+ "highlight.js": "11.6.0",
128
+ "json-diff-kit": "1.0.29",
129
+ marked: "9.1.1",
130
+ "mdast-util-from-markdown": "2.0.1",
131
+ "mdast-util-gfm": "3.0.0",
132
+ "micromark-extension-gfm": "3.0.0",
133
+ preact: "10.19.3",
134
+ "preact-render-to-string": "6.3.1",
135
+ "preact-router": "4.1.2",
136
+ react: "npm:@preact/compat@^17.1.2",
137
+ "react-dom": "npm:@preact/compat@^17.1.2",
138
+ "react-json-view-compare": "2.0.2",
139
+ tsup: "8.0.1",
140
+ typescript: "5.2.2",
141
+ vite: "5.0.8",
142
+ vitest: "0.34.6"
143
+ },
144
+ peerDependencies: {
145
+ "@blinkk/root": "2.0.0",
146
+ "firebase-admin": ">=11",
147
+ "firebase-functions": ">=4",
148
+ preact: ">=10",
149
+ "preact-render-to-string": ">=5"
150
+ },
151
+ peerDependenciesMeta: {
152
+ "firebase-functions": {
153
+ optional: true
154
+ }
155
+ }
156
+ };
157
+
158
+ // core/project.ts
159
+ var IGNORED_SCHEMA_FOLDERS = ["/appengine/", "/functions/", "/gae/"];
160
+ var SCHEMA_MODULES = import.meta.glob("/**/*.schema.ts", {
161
+ eager: true
162
+ });
163
+ function getProjectSchemas() {
164
+ const schemas = {};
165
+ for (const fileId in SCHEMA_MODULES) {
166
+ if (IGNORED_SCHEMA_FOLDERS.some((prefix) => fileId.startsWith(prefix))) {
167
+ continue;
168
+ }
169
+ const schemaModule = SCHEMA_MODULES[fileId];
170
+ if (schemaModule.default) {
171
+ schemas[fileId] = schemaModule.default;
172
+ }
173
+ }
174
+ return schemas;
175
+ }
176
+
177
+ // core/app.tsx
6
178
  import { jsx, jsxs } from "preact/jsx-runtime";
7
179
  var __dirname = path.dirname(fileURLToPath(import.meta.url));
180
+ var DEFAULT_FAVICON_URL = "https://lh3.googleusercontent.com/ijK50TfQlV_yJw3i-CMlnD6osH4PboZBILZrJcWhoNMEmoyCD5e1bAxXbaOPe5w4gG_Scf37EXrmZ6p8sP2lue5fLZ419m5JyLMs=e385-w256";
8
181
  function App(props) {
9
182
  return /* @__PURE__ */ jsxs("html", { children: [
10
183
  /* @__PURE__ */ jsxs("head", { children: [
@@ -40,7 +213,7 @@ function App(props) {
40
213
  "link",
41
214
  {
42
215
  rel: "icon",
43
- href: "https://lh3.googleusercontent.com/ijK50TfQlV_yJw3i-CMlnD6osH4PboZBILZrJcWhoNMEmoyCD5e1bAxXbaOPe5w4gG_Scf37EXrmZ6p8sP2lue5fLZ419m5JyLMs=e385-w256",
216
+ href: props.favicon || DEFAULT_FAVICON_URL,
44
217
  type: "image/png"
45
218
  }
46
219
  ),
@@ -74,15 +247,9 @@ function App(props) {
74
247
  }
75
248
  async function renderApp(req, res, options) {
76
249
  var _a;
77
- const collectionModules = import.meta.glob("/collections/*.schema.ts", {
78
- eager: true
79
- });
80
250
  const collections = {};
81
- Object.keys(collectionModules).forEach((moduleId) => {
82
- const collectionId = path.parse(moduleId).base.split(".")[0];
83
- const module = collectionModules[moduleId];
84
- const collection = module.default;
85
- collections[collectionId] = collection;
251
+ Object.entries(getCollections()).forEach(([collectionId, collection]) => {
252
+ collections[collectionId] = serializeCollection(collection);
86
253
  });
87
254
  const rootConfig = options.rootConfig || {};
88
255
  const cmsConfig = options.cmsConfig || {};
@@ -110,26 +277,42 @@ async function renderApp(req, res, options) {
110
277
  };
111
278
  const projectName = cmsConfig.name || cmsConfig.id || "";
112
279
  const title = projectName ? `${projectName} \u2013 Root CMS` : "Root CMS";
113
- const mainHtml = renderToString(/* @__PURE__ */ jsx(App, { title, ctx }));
280
+ const mainHtml = renderToString(
281
+ /* @__PURE__ */ jsx(App, { title, ctx, favicon: cmsConfig.favicon })
282
+ );
114
283
  let html = `<!doctype html>
115
284
  ${mainHtml}`;
116
285
  const nonce = generateNonce();
117
286
  if (req.viteServer) {
118
287
  const uiCssPath = path.join(__dirname, "ui/ui.css");
119
288
  const uiJsPath = path.join(__dirname, "ui/ui.js");
120
- const tpl = html.replace("{CSS_URL}", cachebust(`/@fs${uiCssPath}`)).replace("{JS_URL}", cachebust(`/@fs${uiJsPath}`)).replaceAll("{NONCE}", nonce);
289
+ const tpl = html.replace("{CSS_URL}", cachebust(req, `/@fs${uiCssPath}`)).replace("{JS_URL}", cachebust(req, `/@fs${uiJsPath}`)).replaceAll("{NONCE}", nonce);
121
290
  html = await req.viteServer.transformIndexHtml(req.originalUrl, tpl);
122
291
  html = html.replace(
123
292
  '<script type="module" src="/@vite/client"></script>',
124
293
  `<script type="module" src="/@vite/client" nonce="${nonce}"></script>`
125
294
  );
126
295
  } else {
127
- html = html.replace("{CSS_URL}", cachebust("/cms/static/ui.css")).replace("{JS_URL}", cachebust("/cms/static/ui.js")).replaceAll("{NONCE}", nonce);
296
+ html = html.replace("{CSS_URL}", cachebust(req, "/cms/static/ui.css")).replace("{JS_URL}", cachebust(req, "/cms/static/ui.js")).replaceAll("{NONCE}", nonce);
128
297
  }
129
298
  res.setHeader("Content-Type", "text/html");
130
299
  setSecurityHeaders(options, req, res, nonce);
131
300
  res.send(html);
132
301
  }
302
+ function serializeCollection(collection) {
303
+ return {
304
+ id: collection.id,
305
+ name: collection.name ?? collection.id,
306
+ description: collection.description,
307
+ domain: collection.domain,
308
+ url: collection.url,
309
+ previewUrl: collection.previewUrl,
310
+ preview: collection.preview,
311
+ slugRegex: collection.slugRegex,
312
+ autolock: collection.autolock,
313
+ autolockReason: collection.autolockReason
314
+ };
315
+ }
133
316
  function SignIn(props) {
134
317
  return /* @__PURE__ */ jsxs("html", { children: [
135
318
  /* @__PURE__ */ jsxs("head", { children: [
@@ -158,7 +341,7 @@ function SignIn(props) {
158
341
  "link",
159
342
  {
160
343
  rel: "icon",
161
- href: "https://lh3.googleusercontent.com/ijK50TfQlV_yJw3i-CMlnD6osH4PboZBILZrJcWhoNMEmoyCD5e1bAxXbaOPe5w4gG_Scf37EXrmZ6p8sP2lue5fLZ419m5JyLMs=e385-w256",
344
+ href: props.favicon || DEFAULT_FAVICON_URL,
162
345
  type: "image/png"
163
346
  }
164
347
  ),
@@ -187,27 +370,50 @@ async function renderSignIn(req, res, options) {
187
370
  name: options.cmsConfig.name || options.cmsConfig.id || "",
188
371
  firebaseConfig: options.cmsConfig.firebaseConfig
189
372
  };
190
- const mainHtml = renderToString(/* @__PURE__ */ jsx(SignIn, { title: "Sign in", ctx }));
373
+ const mainHtml = renderToString(
374
+ /* @__PURE__ */ jsx(
375
+ SignIn,
376
+ {
377
+ title: "Sign in",
378
+ ctx,
379
+ favicon: options.cmsConfig.favicon
380
+ }
381
+ )
382
+ );
191
383
  let html = `<!doctype html>
192
384
  ${mainHtml}`;
193
385
  const nonce = generateNonce();
194
386
  if (req.viteServer) {
195
387
  const cssPath = path.join(__dirname, "ui/signin.css");
196
388
  const jsPath = path.join(__dirname, "ui/signin.js");
197
- const tpl = html.replace("{CSS_URL}", cachebust(`/@fs${cssPath}`)).replace("{JS_URL}", cachebust(`/@fs${jsPath}`)).replaceAll("{NONCE}", nonce);
389
+ const tpl = html.replace("{CSS_URL}", cachebust(req, `/@fs${cssPath}`)).replace("{JS_URL}", cachebust(req, `/@fs${jsPath}`)).replaceAll("{NONCE}", nonce);
198
390
  html = await req.viteServer.transformIndexHtml(req.originalUrl, tpl);
199
391
  html = html.replace(
200
392
  '<script type="module" src="/@vite/client"></script>',
201
393
  `<script type="module" src="/@vite/client" nonce="${nonce}"></script>`
202
394
  );
203
395
  } else {
204
- html = html.replace("{CSS_URL}", cachebust("/cms/static/signin.css")).replace("{JS_URL}", cachebust("/cms/static/signin.js")).replaceAll("{NONCE}", nonce);
396
+ html = html.replace("{CSS_URL}", cachebust(req, "/cms/static/signin.css")).replace("{JS_URL}", cachebust(req, "/cms/static/signin.js")).replaceAll("{NONCE}", nonce);
205
397
  }
206
398
  res.setHeader("Content-Type", "text/html");
207
399
  setSecurityHeaders(options, req, res, nonce);
208
400
  res.status(403);
209
401
  res.send(html);
210
402
  }
403
+ function getCollections() {
404
+ const collections = {};
405
+ const schemas = getProjectSchemas();
406
+ Object.entries(schemas).forEach(([fileId, schema]) => {
407
+ if (fileId.startsWith("/collections/")) {
408
+ const collectionId = parseCollectionId(fileId);
409
+ collections[collectionId] = { ...schema, id: collectionId };
410
+ }
411
+ });
412
+ return collections;
413
+ }
414
+ function parseCollectionId(fileId) {
415
+ return path.basename(fileId).split(".")[0];
416
+ }
211
417
  function generateNonce() {
212
418
  return crypto.randomBytes(16).toString("base64");
213
419
  }
@@ -243,12 +449,12 @@ function getRefererOrigin(req) {
243
449
  const refererOrigin = `${parsedReferer.protocol}//${parsedReferer.hostname}`;
244
450
  return refererOrigin;
245
451
  }
246
- function cachebust(url) {
247
- const ts = Math.floor((/* @__PURE__ */ new Date()).getTime() / 1e3);
248
- return `${url}?c=${ts}`;
452
+ function cachebust(req, url) {
453
+ const value = req.hostname === "localhost" ? Math.floor((/* @__PURE__ */ new Date()).getTime() / 1e3) : package_default.version;
454
+ return `${url}?c=${value}`;
249
455
  }
250
456
  export {
457
+ getCollections,
251
458
  renderApp,
252
459
  renderSignIn
253
460
  };
254
- //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vY29yZS9hcHAudHN4Il0sCiAgInNvdXJjZXNDb250ZW50IjogWyJpbXBvcnQgY3J5cHRvIGZyb20gJ25vZGU6Y3J5cHRvJztcbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQge2ZpbGVVUkxUb1BhdGh9IGZyb20gJ25vZGU6dXJsJztcbmltcG9ydCB7UmVxdWVzdCwgUmVzcG9uc2UsIFJvb3RDb25maWd9IGZyb20gJ0BibGlua2svcm9vdCc7XG5pbXBvcnQge3JlbmRlciBhcyByZW5kZXJUb1N0cmluZ30gZnJvbSAncHJlYWN0LXJlbmRlci10by1zdHJpbmcnO1xuaW1wb3J0IHtDTVNQbHVnaW5PcHRpb25zfSBmcm9tICcuL3BsdWdpbi5qcyc7XG5pbXBvcnQge0NvbGxlY3Rpb259IGZyb20gJy4vc2NoZW1hLmpzJztcblxuY29uc3QgX19kaXJuYW1lID0gcGF0aC5kaXJuYW1lKGZpbGVVUkxUb1BhdGgoaW1wb3J0Lm1ldGEudXJsKSk7XG5cbmludGVyZmFjZSBBcHBQcm9wcyB7XG4gIHRpdGxlOiBzdHJpbmc7XG4gIGN0eDogYW55O1xufVxuXG5mdW5jdGlvbiBBcHAocHJvcHM6IEFwcFByb3BzKSB7XG4gIHJldHVybiAoXG4gICAgPGh0bWw+XG4gICAgICA8aGVhZD5cbiAgICAgICAgPG1ldGEgY2hhcnNldD1cInV0Zi04XCIgLz5cbiAgICAgICAgPHRpdGxlPntwcm9wcy50aXRsZX08L3RpdGxlPlxuICAgICAgICA8bWV0YSBuYW1lPVwicm9ib3RzXCIgY29udGVudD1cIm5vaW5kZXhcIiAvPlxuICAgICAgICA8bGluayByZWw9XCJwcmVjb25uZWN0XCIgaHJlZj1cImh0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb21cIiAvPlxuICAgICAgICA8bGlua1xuICAgICAgICAgIHJlbD1cInByZWNvbm5lY3RcIlxuICAgICAgICAgIGhyZWY9XCJodHRwczovL2ZvbnRzLmdzdGF0aWMuY29tXCJcbiAgICAgICAgICBjcm9zc09yaWdpbj1cImFub255bW91c1wiXG4gICAgICAgIC8+XG4gICAgICAgIDxsaW5rXG4gICAgICAgICAgcmVsPVwic3R5bGVzaGVldFwiXG4gICAgICAgICAgaHJlZj1cImh0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzMj9mYW1pbHk9SW50ZXI6d2dodEAzMDA7NDAwOzUwMDs2MDA7NzAwOzkwMCZkaXNwbGF5PXN3YXBcIlxuICAgICAgICAgIG5vbmNlPVwie05PTkNFfVwiXG4gICAgICAgIC8+XG4gICAgICAgIDxsaW5rXG4gICAgICAgICAgcmVsPVwic3R5bGVzaGVldFwiXG4gICAgICAgICAgaHJlZj1cImh0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzMj9mYW1pbHk9R29vZ2xlK1NhbnM6d2dodEA1MDAmZGlzcGxheT1zd2FwXCJcbiAgICAgICAgICBub25jZT1cIntOT05DRX1cIlxuICAgICAgICAvPlxuICAgICAgICA8bGlua1xuICAgICAgICAgIHJlbD1cImljb25cIlxuICAgICAgICAgIGhyZWY9XCJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vaWpLNTBUZlFsVl95SnczaS1DTWxuRDZvc0g0UGJvWkJJTFpySmNXaG9OTUVtb3lDRDVlMWJBeFhiYU9QZTV3NGdHX1NjZjM3RVhybVo2cDhzUDJsdWU1ZkxaNDE5bTVKeUxNcz1lMzg1LXcyNTZcIlxuICAgICAgICAgIHR5cGU9XCJpbWFnZS9wbmdcIlxuICAgICAgICAvPlxuICAgICAgICA8bGlua1xuICAgICAgICAgIHJlbD1cInN0eWxlc2hlZXRcIlxuICAgICAgICAgIGhyZWY9XCJodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9oaWdobGlnaHQuanMvMTEuNi4wL3N0eWxlcy9hdG9tLW9uZS1saWdodC5taW4uY3NzXCJcbiAgICAgICAgICBub25jZT1cIntOT05DRX1cIlxuICAgICAgICAvPlxuICAgICAgICA8bGluayByZWw9XCJzdHlsZXNoZWV0XCIgaHJlZj1cIntDU1NfVVJMfVwiIG5vbmNlPVwie05PTkNFfVwiIC8+XG4gICAgICA8L2hlYWQ+XG4gICAgICA8Ym9keT5cbiAgICAgICAgPGRpdiBpZD1cInJvb3RcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cImJvb3RzdHJhcFwiPlxuICAgICAgICAgICAgPGgxIGNsYXNzTmFtZT1cImJvb3RzdHJhcF9fbG9hZGluZ1wiPkxvYWRpbmcuLi48L2gxPlxuICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJib290c3RyYXAtZXJyb3JcIj5cbiAgICAgICAgICAgICAgSWYgdGhpcyBwYWdlIGZhaWxzIHRvIGxvYWQsIHRyeSBhIGZvcmNlIHJlZnJlc2ggYnkgaG9sZGluZyB0aGVcbiAgICAgICAgICAgICAgc2hpZnQga2V5IHdoaWxlIHJlZnJlc2hpbmcgdGhlIHBhZ2UuXG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxzY3JpcHRcbiAgICAgICAgICBkYW5nZXJvdXNseVNldElubmVySFRNTD17e1xuICAgICAgICAgICAgX19odG1sOiBgd2luZG93Ll9fUk9PVF9DVFggPSAke0pTT04uc3RyaW5naWZ5KHByb3BzLmN0eCl9YCxcbiAgICAgICAgICB9fVxuICAgICAgICAgIG5vbmNlPVwie05PTkNFfVwiXG4gICAgICAgIC8+XG4gICAgICAgIDxzY3JpcHQgdHlwZT1cIm1vZHVsZVwiIHNyYz1cIntKU19VUkx9XCIgbm9uY2U9XCJ7Tk9OQ0V9XCI+PC9zY3JpcHQ+XG4gICAgICA8L2JvZHk+XG4gICAgPC9odG1sPlxuICApO1xufVxuXG5pbnRlcmZhY2UgUmVuZGVyT3B0aW9ucyB7XG4gIHJvb3RDb25maWc6IFJvb3RDb25maWc7XG4gIGNtc0NvbmZpZzogQ01TUGx1Z2luT3B0aW9ucztcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlbmRlckFwcChcbiAgcmVxOiBSZXF1ZXN0LFxuICByZXM6IFJlc3BvbnNlLFxuICBvcHRpb25zOiBSZW5kZXJPcHRpb25zXG4pIHtcbiAgY29uc3QgY29sbGVjdGlvbk1vZHVsZXMgPSBpbXBvcnQubWV0YS5nbG9iKCcvY29sbGVjdGlvbnMvKi5zY2hlbWEudHMnLCB7XG4gICAgZWFnZXI6IHRydWUsXG4gIH0pIGFzIGFueTtcbiAgY29uc3QgY29sbGVjdGlvbnM6IFJlY29yZDxzdHJpbmcsIENvbGxlY3Rpb24+ID0ge307XG4gIE9iamVjdC5rZXlzKGNvbGxlY3Rpb25Nb2R1bGVzKS5mb3JFYWNoKChtb2R1bGVJZDogc3RyaW5nKSA9PiB7XG4gICAgY29uc3QgY29sbGVjdGlvbklkID0gcGF0aC5wYXJzZShtb2R1bGVJZCkuYmFzZS5zcGxpdCgnLicpWzBdO1xuICAgIGNvbnN0IG1vZHVsZSA9IGNvbGxlY3Rpb25Nb2R1bGVzW21vZHVsZUlkXTtcbiAgICBjb25zdCBjb2xsZWN0aW9uID0gbW9kdWxlLmRlZmF1bHQgYXMgQ29sbGVjdGlvbjtcbiAgICBjb2xsZWN0aW9uc1tjb2xsZWN0aW9uSWRdID0gY29sbGVjdGlvbjtcbiAgfSk7XG4gIGNvbnN0IHJvb3RDb25maWcgPSBvcHRpb25zLnJvb3RDb25maWcgfHwge307XG4gIGNvbnN0IGNtc0NvbmZpZyA9IG9wdGlvbnMuY21zQ29uZmlnIHx8IHt9O1xuICBsZXQgZ2NpID0gY21zQ29uZmlnLmdjaTtcbiAgaWYgKGdjaSA9PT0gdHJ1ZSkge1xuICAgIGdjaSA9ICdodHRwczovL2djaS5yb290anMuZGV2JztcbiAgfVxuICBjb25zdCBjdHggPSB7XG4gICAgcm9vdENvbmZpZzoge1xuICAgICAgcHJvamVjdElkOiBjbXNDb25maWcuaWQgfHwgJ2RlZmF1bHQnLFxuICAgICAgcHJvamVjdE5hbWU6IGNtc0NvbmZpZy5uYW1lIHx8IGNtc0NvbmZpZy5pZCB8fCAnJyxcbiAgICAgIGRvbWFpbjogcm9vdENvbmZpZy5kb21haW4gfHwgJ2h0dHBzOi8vZXhhbXBsZS5jb20nLFxuICAgICAgYmFzZTogcm9vdENvbmZpZy5iYXNlIHx8ICcvJyxcbiAgICAgIGdjaTogZ2NpLFxuICAgICAgaTE4bjogcm9vdENvbmZpZy5pMThuLFxuICAgICAgc2VydmVyOiB7XG4gICAgICAgIHRyYWlsaW5nU2xhc2g6IHJvb3RDb25maWcuc2VydmVyPy50cmFpbGluZ1NsYXNoLFxuICAgICAgfSxcbiAgICB9LFxuICAgIGZpcmViYXNlQ29uZmlnOiBjbXNDb25maWcuZmlyZWJhc2VDb25maWcsXG4gICAgZ2FwaTogY21zQ29uZmlnLmdhcGksXG4gICAgY29sbGVjdGlvbnM6IGNvbGxlY3Rpb25zLFxuICAgIHNpZGViYXI6IGNtc0NvbmZpZy5zaWRlYmFyLFxuICAgIGV4cGVyaW1lbnRzOiBjbXNDb25maWcuZXhwZXJpbWVudHMsXG4gIH07XG4gIGNvbnN0IHByb2plY3ROYW1lID0gY21zQ29uZmlnLm5hbWUgfHwgY21zQ29uZmlnLmlkIHx8ICcnO1xuICBjb25zdCB0aXRsZSA9IHByb2plY3ROYW1lID8gYCR7cHJvamVjdE5hbWV9IFx1MjAxMyBSb290IENNU2AgOiAnUm9vdCBDTVMnO1xuXG4gIGNvbnN0IG1haW5IdG1sID0gcmVuZGVyVG9TdHJpbmcoPEFwcCB0aXRsZT17dGl0bGV9IGN0eD17Y3R4fSAvPik7XG4gIGxldCBodG1sID0gYDwhZG9jdHlwZSBodG1sPlxcbiR7bWFpbkh0bWx9YDtcbiAgY29uc3Qgbm9uY2UgPSBnZW5lcmF0ZU5vbmNlKCk7XG4gIGlmIChyZXEudml0ZVNlcnZlcikge1xuICAgIGNvbnN0IHVpQ3NzUGF0aCA9IHBhdGguam9pbihfX2Rpcm5hbWUsICd1aS91aS5jc3MnKTtcbiAgICBjb25zdCB1aUpzUGF0aCA9IHBhdGguam9pbihfX2Rpcm5hbWUsICd1aS91aS5qcycpO1xuICAgIGNvbnN0IHRwbCA9IGh0bWxcbiAgICAgIC5yZXBsYWNlKCd7Q1NTX1VSTH0nLCBjYWNoZWJ1c3QoYC9AZnMke3VpQ3NzUGF0aH1gKSlcbiAgICAgIC5yZXBsYWNlKCd7SlNfVVJMfScsIGNhY2hlYnVzdChgL0BmcyR7dWlKc1BhdGh9YCkpXG4gICAgICAucmVwbGFjZUFsbCgne05PTkNFfScsIG5vbmNlKTtcbiAgICBodG1sID0gYXdhaXQgcmVxLnZpdGVTZXJ2ZXIhLnRyYW5zZm9ybUluZGV4SHRtbChyZXEub3JpZ2luYWxVcmwsIHRwbCk7XG4gICAgaHRtbCA9IGh0bWwucmVwbGFjZShcbiAgICAgICc8c2NyaXB0IHR5cGU9XCJtb2R1bGVcIiBzcmM9XCIvQHZpdGUvY2xpZW50XCI+PC9zY3JpcHQ+JyxcbiAgICAgIGA8c2NyaXB0IHR5cGU9XCJtb2R1bGVcIiBzcmM9XCIvQHZpdGUvY2xpZW50XCIgbm9uY2U9XCIke25vbmNlfVwiPjwvc2NyaXB0PmBcbiAgICApO1xuICB9IGVsc2Uge1xuICAgIGh0bWwgPSBodG1sXG4gICAgICAucmVwbGFjZSgne0NTU19VUkx9JywgY2FjaGVidXN0KCcvY21zL3N0YXRpYy91aS5jc3MnKSlcbiAgICAgIC5yZXBsYWNlKCd7SlNfVVJMfScsIGNhY2hlYnVzdCgnL2Ntcy9zdGF0aWMvdWkuanMnKSlcbiAgICAgIC5yZXBsYWNlQWxsKCd7Tk9OQ0V9Jywgbm9uY2UpO1xuICB9XG4gIHJlcy5zZXRIZWFkZXIoJ0NvbnRlbnQtVHlwZScsICd0ZXh0L2h0bWwnKTtcbiAgc2V0U2VjdXJpdHlIZWFkZXJzKG9wdGlvbnMsIHJlcSwgcmVzLCBub25jZSk7XG4gIHJlcy5zZW5kKGh0bWwpO1xufVxuXG5pbnRlcmZhY2UgU2lnbkluUHJvcHMge1xuICB0aXRsZTogc3RyaW5nO1xuICBjdHg6IGFueTtcbn1cblxuZnVuY3Rpb24gU2lnbkluKHByb3BzOiBTaWduSW5Qcm9wcykge1xuICByZXR1cm4gKFxuICAgIDxodG1sPlxuICAgICAgPGhlYWQ+XG4gICAgICAgIDxtZXRhIGNoYXJzZXQ9XCJ1dGYtOFwiIC8+XG4gICAgICAgIDx0aXRsZT57cHJvcHMudGl0bGV9PC90aXRsZT5cbiAgICAgICAgPG1ldGEgbmFtZT1cInJvYm90c1wiIGNvbnRlbnQ9XCJub2luZGV4XCIgLz5cbiAgICAgICAgPGxpbmsgcmVsPVwicHJlY29ubmVjdFwiIGhyZWY9XCJodHRwczovL2ZvbnRzLmdvb2dsZWFwaXMuY29tXCIgLz5cbiAgICAgICAgPG1ldGEgbmFtZT1cInZpZXdwb3J0XCIgY29udGVudD1cIndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xLjBcIiAvPlxuICAgICAgICA8bGlua1xuICAgICAgICAgIHJlbD1cInByZWNvbm5lY3RcIlxuICAgICAgICAgIGhyZWY9XCJodHRwczovL2ZvbnRzLmdzdGF0aWMuY29tXCJcbiAgICAgICAgICBjcm9zc09yaWdpbj1cImFub255bW91c1wiXG4gICAgICAgIC8+XG4gICAgICAgIDxsaW5rXG4gICAgICAgICAgcmVsPVwic3R5bGVzaGVldFwiXG4gICAgICAgICAgaHJlZj1cImh0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzP2ZhbWlseT1Hb29nbGUrU2Fuczo0MDAsNTAwJmRpc3BsYXk9c3dhcFwiXG4gICAgICAgICAgbm9uY2U9XCJ7Tk9OQ0V9XCJcbiAgICAgICAgLz5cbiAgICAgICAgPGxpbmtcbiAgICAgICAgICByZWw9XCJpY29uXCJcbiAgICAgICAgICBocmVmPVwiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2lqSzUwVGZRbFZfeUp3M2ktQ01sbkQ2b3NINFBib1pCSUxackpjV2hvTk1FbW95Q0Q1ZTFiQXhYYmFPUGU1dzRnR19TY2YzN0VYcm1aNnA4c1AybHVlNWZMWjQxOW01SnlMTXM9ZTM4NS13MjU2XCJcbiAgICAgICAgICB0eXBlPVwiaW1hZ2UvcG5nXCJcbiAgICAgICAgLz5cbiAgICAgICAgPGxpbmsgcmVsPVwic3R5bGVzaGVldFwiIGhyZWY9XCJ7Q1NTX1VSTH1cIiBub25jZT1cIntOT05DRX1cIiAvPlxuICAgICAgPC9oZWFkPlxuICAgICAgPGJvZHk+XG4gICAgICAgIDxkaXYgaWQ9XCJyb290XCI+XG4gICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJib290c3RyYXBcIj5cbiAgICAgICAgICAgIDxoMSBjbGFzc05hbWU9XCJib290c3RyYXBfX2xvYWRpbmdcIj5Mb2FkaW5nLi4uPC9oMT5cbiAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwiYm9vdHN0cmFwLWVycm9yXCI+XG4gICAgICAgICAgICAgIElmIHRoaXMgcGFnZSBmYWlscyB0byBsb2FkLCB0cnkgYSBmb3JjZSByZWZyZXNoIGJ5IGhvbGRpbmcgdGhlXG4gICAgICAgICAgICAgIHNoaWZ0IGtleSB3aGlsZSByZWZyZXNoaW5nIHRoZSBwYWdlLlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8c2NyaXB0XG4gICAgICAgICAgZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUw9e3tcbiAgICAgICAgICAgIF9faHRtbDogYHdpbmRvdy5fX1JPT1RfQ1RYID0gJHtKU09OLnN0cmluZ2lmeShwcm9wcy5jdHgpfWAsXG4gICAgICAgICAgfX1cbiAgICAgICAgICBub25jZT1cIntOT05DRX1cIlxuICAgICAgICAvPlxuICAgICAgICA8c2NyaXB0IHR5cGU9XCJtb2R1bGVcIiBzcmM9XCJ7SlNfVVJMfVwiIG5vbmNlPVwie05PTkNFfVwiPjwvc2NyaXB0PlxuICAgICAgPC9ib2R5PlxuICAgIDwvaHRtbD5cbiAgKTtcbn1cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZW5kZXJTaWduSW4oXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgb3B0aW9uczogUmVuZGVyT3B0aW9uc1xuKSB7XG4gIGNvbnN0IGN0eCA9IHtcbiAgICBuYW1lOiBvcHRpb25zLmNtc0NvbmZpZy5uYW1lIHx8IG9wdGlvbnMuY21zQ29uZmlnLmlkIHx8ICcnLFxuICAgIGZpcmViYXNlQ29uZmlnOiBvcHRpb25zLmNtc0NvbmZpZy5maXJlYmFzZUNvbmZpZyxcbiAgfTtcbiAgY29uc3QgbWFpbkh0bWwgPSByZW5kZXJUb1N0cmluZyg8U2lnbkluIHRpdGxlPVwiU2lnbiBpblwiIGN0eD17Y3R4fSAvPik7XG4gIGxldCBodG1sID0gYDwhZG9jdHlwZSBodG1sPlxcbiR7bWFpbkh0bWx9YDtcbiAgY29uc3Qgbm9uY2UgPSBnZW5lcmF0ZU5vbmNlKCk7XG4gIGlmIChyZXEudml0ZVNlcnZlcikge1xuICAgIGNvbnN0IGNzc1BhdGggPSBwYXRoLmpvaW4oX19kaXJuYW1lLCAndWkvc2lnbmluLmNzcycpO1xuICAgIGNvbnN0IGpzUGF0aCA9IHBhdGguam9pbihfX2Rpcm5hbWUsICd1aS9zaWduaW4uanMnKTtcbiAgICBjb25zdCB0cGwgPSBodG1sXG4gICAgICAucmVwbGFjZSgne0NTU19VUkx9JywgY2FjaGVidXN0KGAvQGZzJHtjc3NQYXRofWApKVxuICAgICAgLnJlcGxhY2UoJ3tKU19VUkx9JywgY2FjaGVidXN0KGAvQGZzJHtqc1BhdGh9YCkpXG4gICAgICAucmVwbGFjZUFsbCgne05PTkNFfScsIG5vbmNlKTtcbiAgICBodG1sID0gYXdhaXQgcmVxLnZpdGVTZXJ2ZXIhLnRyYW5zZm9ybUluZGV4SHRtbChyZXEub3JpZ2luYWxVcmwsIHRwbCk7XG4gICAgaHRtbCA9IGh0bWwucmVwbGFjZShcbiAgICAgICc8c2NyaXB0IHR5cGU9XCJtb2R1bGVcIiBzcmM9XCIvQHZpdGUvY2xpZW50XCI+PC9zY3JpcHQ+JyxcbiAgICAgIGA8c2NyaXB0IHR5cGU9XCJtb2R1bGVcIiBzcmM9XCIvQHZpdGUvY2xpZW50XCIgbm9uY2U9XCIke25vbmNlfVwiPjwvc2NyaXB0PmBcbiAgICApO1xuICB9IGVsc2Uge1xuICAgIGh0bWwgPSBodG1sXG4gICAgICAucmVwbGFjZSgne0NTU19VUkx9JywgY2FjaGVidXN0KCcvY21zL3N0YXRpYy9zaWduaW4uY3NzJykpXG4gICAgICAucmVwbGFjZSgne0pTX1VSTH0nLCBjYWNoZWJ1c3QoJy9jbXMvc3RhdGljL3NpZ25pbi5qcycpKVxuICAgICAgLnJlcGxhY2VBbGwoJ3tOT05DRX0nLCBub25jZSk7XG4gIH1cbiAgcmVzLnNldEhlYWRlcignQ29udGVudC1UeXBlJywgJ3RleHQvaHRtbCcpO1xuICBzZXRTZWN1cml0eUhlYWRlcnMob3B0aW9ucywgcmVxLCByZXMsIG5vbmNlKTtcbiAgcmVzLnN0YXR1cyg0MDMpO1xuICByZXMuc2VuZChodG1sKTtcbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVOb25jZSgpIHtcbiAgcmV0dXJuIGNyeXB0by5yYW5kb21CeXRlcygxNikudG9TdHJpbmcoJ2Jhc2U2NCcpO1xufVxuXG5mdW5jdGlvbiBzZXRTZWN1cml0eUhlYWRlcnMoXG4gIG9wdGlvbnM6IFJlbmRlck9wdGlvbnMsXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbm9uY2U6IHN0cmluZ1xuKSB7XG4gIHJlcy5zZXRIZWFkZXIoXG4gICAgJ3N0cmljdC10cmFuc3BvcnQtc2VjdXJpdHknLFxuICAgICdtYXgtYWdlPTYzMDcyMDAwOyBpbmNsdWRlU3ViZG9tYWluczsgcHJlbG9hZCdcbiAgKTtcbiAgcmVzLnNldEhlYWRlcigneC1jb250ZW50LXR5cGUtb3B0aW9ucycsICdub3NuaWZmJyk7XG4gIHJlcy5zZXRIZWFkZXIoJ3gteHNzLXByb3RlY3Rpb24nLCAnMTsgbW9kZT1ibG9jaycpO1xuXG4gIGNvbnN0IGZyYW1lQW5jZXN0b3JzID0gW1wiJ3NlbGYnXCJdO1xuICBjb25zdCBhbGxvd2VkSWZyYW1lT3JpZ2lucyA9IG9wdGlvbnMuY21zQ29uZmlnLmFsbG93ZWRJZnJhbWVPcmlnaW5zO1xuICBpZiAoYWxsb3dlZElmcmFtZU9yaWdpbnMgJiYgYWxsb3dlZElmcmFtZU9yaWdpbnMubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IHJlZmVyZXJPcmlnaW4gPSBnZXRSZWZlcmVyT3JpZ2luKHJlcSk7XG4gICAgaWYgKGFsbG93ZWRJZnJhbWVPcmlnaW5zLmluY2x1ZGVzKHJlZmVyZXJPcmlnaW4pKSB7XG4gICAgICBmcmFtZUFuY2VzdG9ycy5wdXNoKHJlZmVyZXJPcmlnaW4pO1xuICAgIH1cbiAgfVxuXG4gIC8vIGh0dHBzOi8vY3NwLndpdGhnb29nbGUuY29tL2RvY3Mvc3RyaWN0LWNzcC5odG1sXG4gIGNvbnN0IGRpcmVjdGl2ZXMgPSBbXG4gICAgXCJiYXNlLXVyaSAnbm9uZSdcIixcbiAgICBcIm9iamVjdC1zcmMgJ25vbmUnXCIsXG4gICAgYHNjcmlwdC1zcmMgJ25vbmNlLSR7bm9uY2V9JyAndW5zYWZlLWlubGluZScgJ3Vuc2FmZS1ldmFsJyAnc3RyaWN0LWR5bmFtaWMnIGh0dHBzOiBodHRwOmAsXG4gICAgYGZyYW1lLWFuY2VzdG9ycyAke2ZyYW1lQW5jZXN0b3JzLmpvaW4oJyAnKX1gLFxuICBdO1xuICByZXMuc2V0SGVhZGVyKCdjb250ZW50LXNlY3VyaXR5LXBvbGljeS1yZXBvcnQtb25seScsIGRpcmVjdGl2ZXMuam9pbignOyAnKSk7XG59XG5cbmZ1bmN0aW9uIGdldFJlZmVyZXJPcmlnaW4ocmVxOiBSZXF1ZXN0KTogc3RyaW5nIHtcbiAgY29uc3QgcmVmZXJlclVybCA9IHJlcS5oZWFkZXJzLnJlZmVyZXI7XG4gIGlmICghcmVmZXJlclVybCkge1xuICAgIHJldHVybiAnJztcbiAgfVxuICBjb25zdCBwYXJzZWRSZWZlcmVyID0gbmV3IFVSTChyZWZlcmVyVXJsKTtcbiAgY29uc3QgcmVmZXJlck9yaWdpbiA9IGAke3BhcnNlZFJlZmVyZXIucHJvdG9jb2x9Ly8ke3BhcnNlZFJlZmVyZXIuaG9zdG5hbWV9YDtcbiAgcmV0dXJuIHJlZmVyZXJPcmlnaW47XG59XG5cbmZ1bmN0aW9uIGNhY2hlYnVzdCh1cmw6IHN0cmluZykge1xuICBjb25zdCB0cyA9IE1hdGguZmxvb3IobmV3IERhdGUoKS5nZXRUaW1lKCkgLyAxMDAwKTtcbiAgcmV0dXJuIGAke3VybH0/Yz0ke3RzfWA7XG59XG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQUEsT0FBTyxZQUFZO0FBQ25CLE9BQU8sVUFBVTtBQUNqQixTQUFRLHFCQUFvQjtBQUU1QixTQUFRLFVBQVUsc0JBQXFCO0FBY2pDLFNBQ0UsS0FERjtBQVZOLElBQU0sWUFBWSxLQUFLLFFBQVEsY0FBYyxZQUFZLEdBQUcsQ0FBQztBQU83RCxTQUFTLElBQUksT0FB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