writr 4.0.0 → 4.1.1

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
@@ -28,17 +28,18 @@
28
28
  * Github Flavor Markdown (remark-gfm).
29
29
  * Emoji Support (remark-emoji).
30
30
  * MDX Support (remark-mdx).
31
- * ESM and Node 20+
32
31
 
33
- ## Getting Started
32
+ ## ESM and Node Version Support
33
+
34
+ This package is ESM only and tested on the current lts version and its previous. Please don't open issues for questions regarding CommonJS / ESM or previous Nodejs versions. To learn more about using ESM please read this from `sindresorhus`: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
34
35
 
35
- ## 1. Install Writr
36
+ ## Getting Started
36
37
 
37
38
  ```bash
38
39
  > npm install writr
39
40
  ```
40
41
 
41
- ## 2. Render from Markdown
42
+ Then you can use it like this:
42
43
 
43
44
  ```javascript
44
45
  import { Writr } from 'writr';
@@ -58,6 +59,26 @@ const options = {
58
59
  const html = await writr.render(options); // <h1>Hello World ::-):</h1><p>This is a test.</p>
59
60
  ```
60
61
 
62
+ An example passing in the options also via the constructor:
63
+
64
+ ```javascript
65
+ import { Writr, WritrOptions } from 'writr';
66
+ const writrOptions = {
67
+ renderOptions: {
68
+ emoji: true,
69
+ toc: true,
70
+ slug: true,
71
+ highlight: true,
72
+ gfm: true,
73
+ math: true,
74
+ mdx: true,
75
+ caching: true,
76
+ }
77
+ };
78
+ const writr = new Writr(`# Hello World ::-):\n\n This is a test.`, writrOptions);
79
+ const html = await writr.render(options); // <h1>Hello World ::-):</h1><p>This is a test.</p>
80
+ ```
81
+
61
82
  ## API
62
83
 
63
84
  ### `new Writr(arg?: string | WritrOptions, options?: WritrOptions)`
package/dist/writr.d.ts CHANGED
@@ -1,6 +1,30 @@
1
- import type React from 'react';
2
- import { type HTMLReactParserOptions } from 'html-react-parser';
3
- import { WritrCache } from './writr-cache.js';
1
+ import * as unified from 'unified';
2
+ import * as hast from 'hast';
3
+ import * as mdast from 'mdast';
4
+ import React from 'react';
5
+ import { HTMLReactParserOptions } from 'html-react-parser';
6
+ import { Cacheable, CacheableMemory, KeyvStoreAdapter } from 'cacheable';
7
+
8
+ declare class WritrCache {
9
+ private _markdownStore;
10
+ private readonly _markdownStoreSync;
11
+ private readonly _hashStore;
12
+ get markdownStore(): Cacheable;
13
+ get markdownStoreSync(): CacheableMemory;
14
+ get hashStore(): CacheableMemory;
15
+ getMarkdown(markdown: string, options?: RenderOptions): Promise<string | undefined>;
16
+ getMarkdownSync(markdown: string, options?: RenderOptions): string | undefined;
17
+ setMarkdown(markdown: string, value: string, options?: RenderOptions): Promise<boolean>;
18
+ setMarkdownSync(markdown: string, value: string, options?: RenderOptions): boolean;
19
+ get(key: string): Promise<string | undefined>;
20
+ getSync(key: string): string | undefined;
21
+ set(key: string, value: string): Promise<boolean>;
22
+ setSync(key: string, value: string): boolean;
23
+ clear(): Promise<void>;
24
+ setStorageAdapter(adapter: KeyvStoreAdapter): void;
25
+ hash(markdown: string, options?: RenderOptions): string;
26
+ }
27
+
4
28
  type WritrOptions = {
5
29
  openai?: string;
6
30
  renderOptions?: RenderOptions;
@@ -16,7 +40,7 @@ type RenderOptions = {
16
40
  caching?: boolean;
17
41
  };
18
42
  declare class Writr {
19
- engine: import("unified").Processor<import("mdast").Root, import("mdast").Root, import("hast").Root, import("hast").Root, string>;
43
+ engine: unified.Processor<mdast.Root, mdast.Root, hast.Root, hast.Root, string>;
20
44
  private readonly _options;
21
45
  private _content;
22
46
  private readonly _cache;
@@ -42,4 +66,5 @@ declare class Writr {
42
66
  private isCacheEnabled;
43
67
  private createProcessor;
44
68
  }
45
- export { Writr, type WritrOptions, type RenderOptions };
69
+
70
+ export { type RenderOptions, Writr, type WritrOptions };
package/dist/writr.js CHANGED
@@ -1,233 +1,286 @@
1
- import fs from 'node:fs';
2
- import { dirname } from 'node:path';
3
- import { unified } from 'unified';
4
- import remarkParse from 'remark-parse';
5
- import remarkRehype from 'remark-rehype';
6
- import rehypeSlug from 'rehype-slug';
7
- import rehypeHighlight from 'rehype-highlight';
8
- import rehypeStringify from 'rehype-stringify';
9
- import remarkToc from 'remark-toc';
10
- import remarkMath from 'remark-math';
11
- import rehypeKatex from 'rehype-katex';
12
- import remarkGfm from 'remark-gfm';
13
- import remarkEmoji from 'remark-emoji';
14
- import remarkMDX from 'remark-mdx';
15
- import parse from 'html-react-parser';
16
- import * as yaml from 'js-yaml';
17
- import { WritrCache } from './writr-cache.js';
18
- class Writr {
19
- engine = unified()
20
- .use(remarkParse)
21
- .use(remarkGfm) // Use GitHub Flavored Markdown
22
- .use(remarkToc) // Add table of contents
23
- .use(remarkEmoji) // Add emoji support
24
- .use(remarkRehype) // Convert markdown to HTML
25
- .use(rehypeSlug) // Add slugs to headings in HTML
26
- .use(remarkMath) // Add math support
27
- .use(rehypeKatex) // Add math support
28
- .use(rehypeHighlight) // Apply syntax highlighting
29
- .use(remarkMDX) // Add MDX support
30
- .use(rehypeStringify); // Stringify HTML
31
- _options = {
32
- openai: undefined,
33
- renderOptions: {
34
- emoji: true,
35
- toc: true,
36
- slug: true,
37
- highlight: true,
38
- gfm: true,
39
- math: true,
40
- mdx: true,
41
- caching: true,
42
- },
43
- };
44
- _content = '';
45
- _cache = new WritrCache();
46
- constructor(arguments1, arguments2) {
47
- if (typeof arguments1 === 'string') {
48
- this._content = arguments1;
49
- }
50
- else if (arguments1) {
51
- this._options = { ...this._options, ...arguments1 };
52
- if (this._options.renderOptions) {
53
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
54
- this.engine = this.createProcessor(this._options.renderOptions);
55
- }
56
- }
57
- if (arguments2) {
58
- this._options = { ...this._options, ...arguments2 };
59
- if (this._options.renderOptions) {
60
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
61
- this.engine = this.createProcessor(this._options.renderOptions);
62
- }
63
- }
1
+ // src/writr.ts
2
+ import fs from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import { unified } from "unified";
5
+ import remarkParse from "remark-parse";
6
+ import remarkRehype from "remark-rehype";
7
+ import rehypeSlug from "rehype-slug";
8
+ import rehypeHighlight from "rehype-highlight";
9
+ import rehypeStringify from "rehype-stringify";
10
+ import remarkToc from "remark-toc";
11
+ import remarkMath from "remark-math";
12
+ import rehypeKatex from "rehype-katex";
13
+ import remarkGfm from "remark-gfm";
14
+ import remarkEmoji from "remark-emoji";
15
+ import remarkMDX from "remark-mdx";
16
+ import parse from "html-react-parser";
17
+ import * as yaml from "js-yaml";
18
+
19
+ // src/writr-cache.ts
20
+ import { createHash } from "node:crypto";
21
+ import { Cacheable, CacheableMemory } from "cacheable";
22
+ var WritrCache = class {
23
+ _markdownStore = new Cacheable();
24
+ _markdownStoreSync = new CacheableMemory();
25
+ _hashStore = new CacheableMemory();
26
+ get markdownStore() {
27
+ return this._markdownStore;
28
+ }
29
+ get markdownStoreSync() {
30
+ return this._markdownStoreSync;
31
+ }
32
+ get hashStore() {
33
+ return this._hashStore;
34
+ }
35
+ async getMarkdown(markdown, options) {
36
+ const key = this.hash(markdown, options);
37
+ return this.get(key);
38
+ }
39
+ getMarkdownSync(markdown, options) {
40
+ const key = this.hash(markdown, options);
41
+ return this.getSync(key);
42
+ }
43
+ async setMarkdown(markdown, value, options) {
44
+ const key = this.hash(markdown, options);
45
+ return this.set(key, value);
46
+ }
47
+ setMarkdownSync(markdown, value, options) {
48
+ const key = this.hash(markdown, options);
49
+ this.setSync(key, value);
50
+ return true;
51
+ }
52
+ async get(key) {
53
+ return this._markdownStore.get(key);
54
+ }
55
+ getSync(key) {
56
+ return this._markdownStoreSync.get(key);
57
+ }
58
+ async set(key, value) {
59
+ return this._markdownStore.set(key, value);
60
+ }
61
+ setSync(key, value) {
62
+ this._markdownStoreSync.set(key, value);
63
+ return true;
64
+ }
65
+ async clear() {
66
+ await this._markdownStore.clear();
67
+ this._markdownStoreSync.clear();
68
+ this._hashStore.clear();
69
+ }
70
+ setStorageAdapter(adapter) {
71
+ this._markdownStore = new Cacheable({ primary: adapter });
72
+ }
73
+ hash(markdown, options) {
74
+ const key = JSON.stringify({ markdown, options });
75
+ let result = this._hashStore.get(key);
76
+ if (result) {
77
+ return result;
64
78
  }
65
- get options() {
66
- return this._options;
67
- }
68
- get content() {
69
- return this._content;
70
- }
71
- set content(value) {
72
- this._content = value;
73
- }
74
- get cache() {
75
- return this._cache;
76
- }
77
- get frontMatterRaw() {
78
- const start = this._content.indexOf('---\n');
79
- if (start === -1) {
80
- return '';
81
- } // Return empty string if no starting delimiter is found
82
- const end = this._content.indexOf('\n---\n', start + 4);
83
- if (end === -1) {
84
- return '';
85
- } // Return empty string if no ending delimiter is found
86
- return this._content.slice(start, end + 5); // Extract front matter including delimiters
87
- }
88
- get body() {
89
- const start = this._content.indexOf('---\n');
90
- if (start === -1) {
91
- return this._content;
92
- }
93
- const end = this._content.indexOf('\n---\n', start + 4);
94
- if (end === -1) {
95
- return this._content;
96
- }
97
- // Return the content after the closing --- marker
98
- return this._content.slice(Math.max(0, end + 5)).trim();
79
+ result = createHash("sha256").update(key).digest("hex");
80
+ this._hashStore.set(key, result);
81
+ return result;
82
+ }
83
+ };
84
+
85
+ // src/writr.ts
86
+ var Writr = class {
87
+ engine = unified().use(remarkParse).use(remarkGfm).use(remarkToc).use(remarkEmoji).use(remarkRehype).use(rehypeSlug).use(remarkMath).use(rehypeKatex).use(rehypeHighlight).use(remarkMDX).use(rehypeStringify);
88
+ // Stringify HTML
89
+ _options = {
90
+ openai: void 0,
91
+ renderOptions: {
92
+ emoji: true,
93
+ toc: true,
94
+ slug: true,
95
+ highlight: true,
96
+ gfm: true,
97
+ math: true,
98
+ mdx: true,
99
+ caching: true
99
100
  }
100
- get markdown() {
101
- return this.body;
101
+ };
102
+ _content = "";
103
+ _cache = new WritrCache();
104
+ constructor(arguments1, arguments2) {
105
+ if (typeof arguments1 === "string") {
106
+ this._content = arguments1;
107
+ } else if (arguments1) {
108
+ this._options = { ...this._options, ...arguments1 };
109
+ if (this._options.renderOptions) {
110
+ this.engine = this.createProcessor(this._options.renderOptions);
111
+ }
102
112
  }
103
- get frontMatter() {
104
- const frontMatter = this.frontMatterRaw;
105
- const match = /^---\s*([\s\S]*?)\s*---\s*/.exec(frontMatter);
106
- if (match) {
107
- return yaml.load(match[1].trim());
108
- }
109
- return {};
110
- }
111
- set frontMatter(data) {
112
- const frontMatter = this.frontMatterRaw;
113
- const yamlString = yaml.dump(data);
114
- const newFrontMatter = `---\n${yamlString}---\n`;
115
- this._content = this._content.replace(frontMatter, newFrontMatter);
116
- }
117
- getFrontMatterValue(key) {
118
- return this.frontMatter[key];
119
- }
120
- async render(options) {
121
- try {
122
- let result = '';
123
- if (this.isCacheEnabled(options)) {
124
- const cached = await this._cache.getMarkdown(this._content, options);
125
- if (cached) {
126
- return cached;
127
- }
128
- }
129
- let { engine } = this;
130
- if (options) {
131
- options = { ...this._options.renderOptions, ...options };
132
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
133
- engine = this.createProcessor(options);
134
- }
135
- const file = await engine.process(this.body);
136
- result = String(file);
137
- if (this.isCacheEnabled(options)) {
138
- await this._cache.setMarkdown(this._content, result, options);
139
- }
140
- return result;
141
- }
142
- catch (error) {
143
- throw new Error(`Failed to render markdown: ${error.message}`);
144
- }
113
+ if (arguments2) {
114
+ this._options = { ...this._options, ...arguments2 };
115
+ if (this._options.renderOptions) {
116
+ this.engine = this.createProcessor(this._options.renderOptions);
117
+ }
118
+ }
119
+ }
120
+ get options() {
121
+ return this._options;
122
+ }
123
+ get content() {
124
+ return this._content;
125
+ }
126
+ set content(value) {
127
+ this._content = value;
128
+ }
129
+ get cache() {
130
+ return this._cache;
131
+ }
132
+ get frontMatterRaw() {
133
+ const start = this._content.indexOf("---\n");
134
+ if (start === -1) {
135
+ return "";
136
+ }
137
+ const end = this._content.indexOf("\n---\n", start + 4);
138
+ if (end === -1) {
139
+ return "";
140
+ }
141
+ return this._content.slice(start, end + 5);
142
+ }
143
+ get body() {
144
+ const start = this._content.indexOf("---\n");
145
+ if (start === -1) {
146
+ return this._content;
145
147
  }
146
- renderSync(options) {
147
- try {
148
- let result = '';
149
- if (this.isCacheEnabled(options)) {
150
- const cached = this._cache.getMarkdownSync(this._content, options);
151
- if (cached) {
152
- return cached;
153
- }
154
- }
155
- let { engine } = this;
156
- if (options) {
157
- options = { ...this._options.renderOptions, ...options };
158
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
159
- engine = this.createProcessor(options);
160
- }
161
- const file = engine.processSync(this.body);
162
- result = String(file);
163
- if (this.isCacheEnabled(options)) {
164
- this._cache.setMarkdownSync(this._content, result, options);
165
- }
166
- return result;
148
+ const end = this._content.indexOf("\n---\n", start + 4);
149
+ if (end === -1) {
150
+ return this._content;
151
+ }
152
+ return this._content.slice(Math.max(0, end + 5)).trim();
153
+ }
154
+ get markdown() {
155
+ return this.body;
156
+ }
157
+ get frontMatter() {
158
+ const frontMatter = this.frontMatterRaw;
159
+ const match = /^---\s*([\s\S]*?)\s*---\s*/.exec(frontMatter);
160
+ if (match) {
161
+ return yaml.load(match[1].trim());
162
+ }
163
+ return {};
164
+ }
165
+ set frontMatter(data) {
166
+ const frontMatter = this.frontMatterRaw;
167
+ const yamlString = yaml.dump(data);
168
+ const newFrontMatter = `---
169
+ ${yamlString}---
170
+ `;
171
+ this._content = this._content.replace(frontMatter, newFrontMatter);
172
+ }
173
+ getFrontMatterValue(key) {
174
+ return this.frontMatter[key];
175
+ }
176
+ async render(options) {
177
+ try {
178
+ let result = "";
179
+ if (this.isCacheEnabled(options)) {
180
+ const cached = await this._cache.getMarkdown(this._content, options);
181
+ if (cached) {
182
+ return cached;
167
183
  }
168
- catch (error) {
169
- throw new Error(`Failed to render markdown: ${error.message}`);
184
+ }
185
+ let { engine } = this;
186
+ if (options) {
187
+ options = { ...this._options.renderOptions, ...options };
188
+ engine = this.createProcessor(options);
189
+ }
190
+ const file = await engine.process(this.body);
191
+ result = String(file);
192
+ if (this.isCacheEnabled(options)) {
193
+ await this._cache.setMarkdown(this._content, result, options);
194
+ }
195
+ return result;
196
+ } catch (error) {
197
+ throw new Error(`Failed to render markdown: ${error.message}`);
198
+ }
199
+ }
200
+ renderSync(options) {
201
+ try {
202
+ let result = "";
203
+ if (this.isCacheEnabled(options)) {
204
+ const cached = this._cache.getMarkdownSync(this._content, options);
205
+ if (cached) {
206
+ return cached;
170
207
  }
208
+ }
209
+ let { engine } = this;
210
+ if (options) {
211
+ options = { ...this._options.renderOptions, ...options };
212
+ engine = this.createProcessor(options);
213
+ }
214
+ const file = engine.processSync(this.body);
215
+ result = String(file);
216
+ if (this.isCacheEnabled(options)) {
217
+ this._cache.setMarkdownSync(this._content, result, options);
218
+ }
219
+ return result;
220
+ } catch (error) {
221
+ throw new Error(`Failed to render markdown: ${error.message}`);
171
222
  }
172
- async renderReact(options, reactParseOptions) {
173
- const html = await this.render(options);
174
- return parse(html, reactParseOptions);
223
+ }
224
+ async renderReact(options, reactParseOptions) {
225
+ const html = await this.render(options);
226
+ return parse(html, reactParseOptions);
227
+ }
228
+ renderReactSync(options, reactParseOptions) {
229
+ const html = this.renderSync(options);
230
+ return parse(html, reactParseOptions);
231
+ }
232
+ async loadFromFile(filePath) {
233
+ const { readFile } = fs.promises;
234
+ this._content = await readFile(filePath, "utf8");
235
+ }
236
+ loadFromFileSync(filePath) {
237
+ this._content = fs.readFileSync(filePath, "utf8");
238
+ }
239
+ async saveToFile(filePath) {
240
+ const { writeFile, mkdir } = fs.promises;
241
+ const directoryPath = dirname(filePath);
242
+ await mkdir(directoryPath, { recursive: true });
243
+ await writeFile(filePath, this._content, "utf8");
244
+ }
245
+ saveToFileSync(filePath) {
246
+ const directoryPath = dirname(filePath);
247
+ fs.mkdirSync(directoryPath, { recursive: true });
248
+ fs.writeFileSync(filePath, this._content, "utf8");
249
+ }
250
+ isCacheEnabled(options) {
251
+ if (options?.caching !== void 0) {
252
+ return options.caching;
175
253
  }
176
- renderReactSync(options, reactParseOptions) {
177
- const html = this.renderSync(options);
178
- return parse(html, reactParseOptions);
254
+ return this._options?.renderOptions?.caching ?? false;
255
+ }
256
+ createProcessor(options) {
257
+ const processor = unified().use(remarkParse);
258
+ if (options.gfm) {
259
+ processor.use(remarkGfm);
179
260
  }
180
- async loadFromFile(filePath) {
181
- const { readFile } = fs.promises;
182
- this._content = await readFile(filePath, 'utf8');
261
+ if (options.toc) {
262
+ processor.use(remarkToc, { heading: "toc|table of contents" });
183
263
  }
184
- loadFromFileSync(filePath) {
185
- this._content = fs.readFileSync(filePath, 'utf8');
264
+ if (options.emoji) {
265
+ processor.use(remarkEmoji);
186
266
  }
187
- async saveToFile(filePath) {
188
- const { writeFile, mkdir } = fs.promises;
189
- const directoryPath = dirname(filePath);
190
- await mkdir(directoryPath, { recursive: true });
191
- await writeFile(filePath, this._content, 'utf8');
267
+ processor.use(remarkRehype);
268
+ if (options.slug) {
269
+ processor.use(rehypeSlug);
192
270
  }
193
- saveToFileSync(filePath) {
194
- const directoryPath = dirname(filePath);
195
- fs.mkdirSync(directoryPath, { recursive: true });
196
- fs.writeFileSync(filePath, this._content, 'utf8');
271
+ if (options.highlight) {
272
+ processor.use(rehypeHighlight);
197
273
  }
198
- isCacheEnabled(options) {
199
- if (options?.caching !== undefined) {
200
- return options.caching;
201
- }
202
- return this._options?.renderOptions?.caching ?? false;
274
+ if (options.math) {
275
+ processor.use(remarkMath).use(rehypeKatex);
203
276
  }
204
- createProcessor(options) {
205
- const processor = unified().use(remarkParse);
206
- if (options.gfm) {
207
- processor.use(remarkGfm);
208
- }
209
- if (options.toc) {
210
- processor.use(remarkToc, { heading: 'toc|table of contents' });
211
- }
212
- if (options.emoji) {
213
- processor.use(remarkEmoji);
214
- }
215
- processor.use(remarkRehype);
216
- if (options.slug) {
217
- processor.use(rehypeSlug);
218
- }
219
- if (options.highlight) {
220
- processor.use(rehypeHighlight);
221
- }
222
- if (options.math) {
223
- processor.use(remarkMath).use(rehypeKatex);
224
- }
225
- if (options.mdx) {
226
- processor.use(remarkMDX);
227
- }
228
- processor.use(rehypeStringify);
229
- return processor;
277
+ if (options.mdx) {
278
+ processor.use(remarkMDX);
230
279
  }
231
- }
232
- export { Writr };
233
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3JpdHIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvd3JpdHIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3pCLE9BQU8sRUFBQyxPQUFPLEVBQUMsTUFBTSxXQUFXLENBQUM7QUFDbEMsT0FBTyxFQUFDLE9BQU8sRUFBQyxNQUFNLFNBQVMsQ0FBQztBQUNoQyxPQUFPLFdBQVcsTUFBTSxjQUFjLENBQUM7QUFDdkMsT0FBTyxZQUFZLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sVUFBVSxNQUFNLGFBQWEsQ0FBQztBQUNyQyxPQUFPLGVBQWUsTUFBTSxrQkFBa0IsQ0FBQztBQUMvQyxPQUFPLGVBQWUsTUFBTSxrQkFBa0IsQ0FBQztBQUMvQyxPQUFPLFNBQVMsTUFBTSxZQUFZLENBQUM7QUFDbkMsT0FBTyxVQUFVLE1BQU0sYUFBYSxDQUFDO0FBQ3JDLE9BQU8sV0FBVyxNQUFNLGNBQWMsQ0FBQztBQUN2QyxPQUFPLFNBQVMsTUFBTSxZQUFZLENBQUM7QUFDbkMsT0FBTyxXQUFXLE1BQU0sY0FBYyxDQUFDO0FBQ3ZDLE9BQU8sU0FBUyxNQUFNLFlBQVksQ0FBQztBQUVuQyxPQUFPLEtBQW9DLE1BQU0sbUJBQW1CLENBQUM7QUFDckUsT0FBTyxLQUFLLElBQUksTUFBTSxTQUFTLENBQUM7QUFDaEMsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLGtCQUFrQixDQUFDO0FBa0I1QyxNQUFNLEtBQUs7SUFDSCxNQUFNLEdBQUcsT0FBTyxFQUFFO1NBQ3ZCLEdBQUcsQ0FBQyxXQUFXLENBQUM7U0FDaEIsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLCtCQUErQjtTQUM5QyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsd0JBQXdCO1NBQ3ZDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxvQkFBb0I7U0FDckMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDLDJCQUEyQjtTQUM3QyxHQUFH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QUksT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ25CLFNBQVMsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDNUIsQ0FBQztRQUVELFNBQVMsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7UUFFNUIsSUFBSSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDbEIsU0FBUyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUMzQixDQUFDO1FBRUQsSUFBSSxPQUFPLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDdkIsU0FBUyxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUNoQyxDQUFDO1FBRUQsSUFBSSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDbEIsU0FBUyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDNUMsQ0FBQztRQUVELElBQUksT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ2pCLFNBQVMsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDMUIsQ0FBQztRQUVELFNBQVMsQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLENBQUM7UUFFL0IsT0FBTyxTQUFTLENBQUM7SUFDbEIsQ0FBQztDQUNEO0FBRUQsT0FBTyxFQUFDLEtBQUssRUFBd0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tICdub2RlOmZzJztcbmltcG9ydCB7ZGlybmFtZX0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7dW5pZmllZH0gZnJvbSAndW5pZmllZCc7XG5pbXBvcnQgcmVtYXJrUGFyc2UgZnJvbSAncmVtYXJrLXBhcnNlJztcbmltcG9ydCByZW1hcmtSZWh5cGUgZnJvbSAncmVtYXJrLXJlaHlwZSc7XG5pbXBvcnQgcmVoeXBlU2x1ZyBmcm9tICdyZWh5cGUtc2x1Zyc7XG5pbXBvcnQgcmVoeXBlSGlnaGxpZ2h0IGZyb20gJ3JlaHlwZS1oaWdobGlnaHQnO1xuaW1wb3J0IHJlaHlwZVN0cmluZ2lmeSBmcm9tICdyZWh5cGUtc3RyaW5naWZ5JztcbmltcG9ydCByZW1hcmtUb2MgZnJvbSAncmVtYXJrLXRvYyc7XG5pbXBvcnQgcmVtYXJrTWF0aCBmcm9tICdyZW1hcmstbWF0aCc7XG5pbXBvcnQgcmVoeXBlS2F0ZXggZnJvbSAncmVoeXBlLWthdGV4JztcbmltcG9ydCByZW1hcmtHZm0gZnJvbSAncmVtYXJrLWdmbSc7XG5pbXBvcnQgcmVtYXJrRW1vamkgZnJvbSAncmVtYXJrLWVtb2ppJztcbmltcG9ydCByZW1hcmtNRFggZnJvbSAncmVtYXJrLW1keCc7XG5pbXBvcnQgdHlwZSBSZWFjdCBmcm9tICdyZWFjdCc7XG5pbXBvcnQgcGFyc2UsIHt0eXBlIEhUTUxSZWFjdFBhcnNlck9wdGlvbnN9IGZyb20gJ2h0bWwtcmVhY3QtcGFyc2VyJztcbmltcG9ydCAqIGFzIHlhbWwgZnJvbSAnanMteWFtbCc7XG5pbXBvcnQge1dyaXRyQ2FjaGV9IGZyb20gJy4vd3JpdHItY2FjaGUuanMnO1xuXG50eXBlIFdyaXRyT3B0aW9ucyA9IHtcblx0b3BlbmFpPzogc3RyaW5nOyAvLyBPcGVuYWkgYXBpIGtleSAoZGVmYXVsdDogdW5kZWZpbmVkKVxuXHRyZW5kZXJPcHRpb25zPzogUmVuZGVyT3B0aW9uczsgLy8gRGVmYXVsdCByZW5kZXIgb3B0aW9ucyAoZGVmYXVsdDogdW5kZWZpbmVkKVxufTtcblxudHlwZSBSZW5kZXJPcHRpb25zID0ge1xuXHRlbW9qaT86IGJvb2xlYW47IC8vIEVtb2ppIHN1cHBvcnQgKGRlZmF1bHQ6IHRydWUpXG5cdHRvYz86IGJvb2xlYW47IC8vIFRhYmxlIG9mIGNvbnRlbnRzIGdlbmVyYXRpb24gKGRlZmF1bHQ6IHRydWUpXG5cdHNsdWc/OiBib29sZWFuOyAvLyBTbHVnIGdlbmVyYXRpb24gKGRlZmF1bHQ6IHRydWUpXG5cdGhpZ2hsaWdodD86IGJvb2xlYW47IC8vIENvZGUgaGlnaGxpZ2h0aW5nIChkZWZhdWx0OiB0cnVlKVxuXHRnZm0/OiBib29sZWFuOyAvLyBHaXRodWIgZmxhdm9yIG1hcmtkb3duIChkZWZhdWx0OiB0cnVlKVxuXHRtYXRoPzogYm9vbGVhbjsgLy8gTWF0aCBzdXBwb3J0IChkZWZhdWx0OiB0cnVlKVxuXHRtZHg/OiBib29sZWFuOyAvLyBNRFggc3VwcG9ydCAoZGVmYXVsdDogdHJ1ZSlcblx0Y2FjaGluZz86IGJvb2xlYW47IC8vIENhY2hpbmcgKGRlZmF1bHQ6IHRydWUpXG59O1xuXG5jbGFzcyBXcml0ciB7XG5cdHB1YmxpYyBlbmdpbmUgPSB1bmlmaWVkKClcblx0XHQudXNlKHJlbWFya1BhcnNlKVxuXHRcdC51c2UocmVtYXJrR2ZtKSAvLyBVc2UgR2l0SHViIEZsYXZvcmVkIE1hcmtkb3duXG5cdFx0LnVzZShyZW1hcmtUb2MpIC8vIEFkZCB0YWJsZSBvZiBjb250ZW50c1xuXHRcdC51c2UocmVtYXJrRW1vamkpIC8vIEFkZCBlbW9qaSBzdXBwb3J0XG5cdFx0LnVzZShyZW1hcmtSZWh5cGUpIC8vIENvbnZlcnQgbWFya2Rvd24gdG8gSFRNTFxuXHRcdC51c2UocmVoeXBlU2x1ZykgLy8gQWRkIHNsdWdzIHRvIGhlYWRpbmdzIGluIEhUTUxcblx0XHQudXNlKHJlbWFya01hdGgpIC8vIEFkZCBtYXRoIHN1cHBvcnRcblx0XHQudXNlKHJlaHlwZUthdGV4KSAvLyBBZGQgbWF0aCBzdXBwb3J0XG5cdFx0LnVzZShyZWh5cGVIaWdobGlnaHQpIC8vIEFwcGx5IHN5bnRheCBoaWdobGlnaHRpbmdcblx0XHQudXNlKHJlbWFya01EWCkgLy8gQWRkIE1EWCBzdXBwb3J0XG5cdFx0LnVzZShyZWh5cGVTdHJpbmdpZnkpOyAvLyBTdHJpbmdpZnkgSFRNTFxuXG5cdHByaXZhdGUgcmVhZG9ubHkgX29wdGlvbnM6IFdyaXRyT3B0aW9ucyA9IHtcblx0XHRvcGVuYWk6IHVuZGVmaW5lZCxcblx0XHRyZW5kZXJPcHRpb25zOiB7XG5cdFx0XHRlbW9qaTogdHJ1ZSxcblx0XHRcdHRvYzogdHJ1ZSxcblx0XHRcdHNsdWc6IHRydWUsXG5cdFx0XHRoaWdobGlnaHQ6IHRydWUsXG5cdFx0XHRnZm06IHRydWUsXG5cdFx0XHRtYXRoOiB0cnVlLFxuXHRcdFx0bWR4OiB0cnVlLFxuXHRcdFx0Y2FjaGluZzogdHJ1ZSxcblx0XHR9LFxuXHR9O1xuXG5cdHByaXZhdGUgX2NvbnRlbnQgPSAnJztcblxuXHRwcml2YXRlIHJlYWRvbmx5IF9jYWNoZSA9IG5ldyBXcml0ckNhY2hlKCk7XG5cblx0Y29uc3RydWN0b3IoYXJndW1lbnRzMT86IHN0cmluZyB8IFdyaXRyT3B0aW9ucywgYXJndW1lbnRzMj86IFdyaXRyT3B0aW9ucykge1xuXHRcdGlmICh0eXBlb2YgYXJndW1lbnRzMSA9PT0gJ3N0cmluZycpIHtcblx0XHRcdHRoaXMuX2NvbnRlbnQgPSBhcmd1bWVudHMxO1xuXHRcdH0gZWxzZSBpZiAoYXJndW1lbnRzMSkge1xuXHRcdFx0dGhpcy5fb3B0aW9ucyA9IHsuLi50aGlzLl9vcHRpb25zLCAuLi5hcmd1bWVudHMxfTtcblx0XHRcdGlmICh0aGlzLl9vcHRpb25zLnJlbmRlck9wdGlvbnMpIHtcblx0XHRcdFx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtYXNzaWdubWVudFxuXHRcdFx0XHR0aGlzLmVuZ2luZSA9IHRoaXMuY3JlYXRlUHJvY2Vzc29yKHRoaXMuX29wdGlvbnMucmVuZGVyT3B0aW9ucyk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKGFyZ3VtZW50czIpIHtcblx0XHRcdHRoaXMuX29wdGlvbnMgPSB7Li4udGhpcy5fb3B0aW9ucywgLi4uYXJndW1lbnRzMn07XG5cdFx0XHRpZiAodGhpcy5fb3B0aW9ucy5yZW5kZXJPcHRpb25zKSB7XG5cdFx0XHRcdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5zYWZlLWFzc2lnbm1lbnRcblx0XHRcdFx0dGhpcy5lbmdpbmUgPSB0aGlzLmNyZWF0ZVByb2Nlc3Nvcih0aGlzLl9vcHRpb25zLnJlbmRlck9wdGlvbnMpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHB1YmxpYyBnZXQgb3B0aW9ucygpOiBXcml0ck9wdGlvbnMge1xuXHRcdHJldHVybiB0aGlzLl9vcHRpb25zO1xuXHR9XG5cblx0cHVibGljIGdldCBjb250ZW50KCk6IHN0cmluZyB7XG5cdFx0cmV0dXJuIHRoaXMuX2NvbnRlbnQ7XG5cdH1cblxuXHRwdWJsaWMgc2V0IGNvbnRlbnQodmFsdWU6IHN0cmluZykge1xuXHRcdHRoaXMuX2NvbnRlbnQgPSB2YWx1ZTtcblx0fVxuXG5cdHB1YmxpYyBnZXQgY2FjaGUoKTogV3JpdHJDYWNoZSB7XG5cdFx0cmV0dXJuIHRoaXMuX2NhY2hlO1xuXHR9XG5cblx0Z2V0IGZyb250TWF0dGVyUmF3KCk6IHN0cmluZyB7XG5cdFx0Y29uc3Qgc3RhcnQgPSB0aGlzLl9jb250ZW50LmluZGV4T2YoJy0tLVxcbicpO1xuXHRcdGlmIChzdGFydCA9PT0gLTEpIHtcblx0XHRcdHJldHVybiAnJztcblx0XHR9IC8vIFJldHVybiBlbXB0eSBzdHJpbmcgaWYgbm8gc3RhcnRpbmcgZGVsaW1pdGVyIGlzIGZvdW5kXG5cblx0XHRjb25zdCBlbmQgPSB0aGlzLl9jb250ZW50LmluZGV4T2YoJ1xcbi0tLVxcbicsIHN0YXJ0ICsgNCk7XG5cdFx0aWYgKGVuZCA9PT0gLTEpIHtcblx0XHRcdHJldHVybiAnJztcblx0XHR9IC8vIFJldHVybiBlbXB0eSBzdHJpbmcgaWYgbm8gZW5kaW5nIGRlbGltaXRlciBpcyBmb3VuZFxuXG5cdFx0cmV0dXJuIHRoaXMuX2NvbnRlbnQuc2xpY2Uoc3RhcnQsIGVuZCArIDUpOyAvLyBFeHRyYWN0IGZyb250IG1hdHRlciBpbmNsdWRpbmcgZGVsaW1pdGVyc1xuXHR9XG5cblx0Z2V0IGJvZHkoKTogc3RyaW5nIHtcblx0XHRjb25zdCBzdGFydCA9IHRoaXMuX2NvbnRlbnQuaW5kZXhPZignLS0tXFxuJyk7XG5cdFx0aWYgKHN0YXJ0ID09PSAtMSkge1xuXHRcdFx0cmV0dXJuIHRoaXMuX2NvbnRlbnQ7XG5cdFx0fVxuXG5cdFx0Y29uc3QgZW5kID0gdGhpcy5fY29udGVudC5pbmRleE9mKCdcXG4tLS1cXG4nLCBzdGFydCArIDQpO1xuXHRcdGlmIChlbmQgPT09IC0xKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5fY29udGVudDtcblx0XHR9XG5cblx0XHQvLyBSZXR1cm4gdGhlIGNvbnRlbnQgYWZ0ZXIgdGhlIGNsb3NpbmcgLS0tIG1hcmtlclxuXHRcdHJldHVybiB0aGlzLl9jb250ZW50LnNsaWNlKE1hdGgubWF4KDAsIGVuZCArIDUpKS50cmltKCk7XG5cdH1cblxuXHRnZXQgbWFya2Rvd24oKTogc3RyaW5nIHtcblx0XHRyZXR1cm4gdGhpcy5ib2R5O1xuXHR9XG5cblx0Z2V0IGZyb250TWF0dGVyKCk6IFJlY29yZDxzdHJpbmcsIGFueT4ge1xuXHRcdGNvbnN0IGZyb250TWF0dGVyID0gdGhpcy5mcm9udE1hdHRlclJhdztcblx0XHRjb25zdCBtYXRjaCA9IC9eLS0tXFxzKihbXFxzXFxTXSo/KVxccyotLS1cXHMqLy5leGVjKGZyb250TWF0dGVyKTtcblx0XHRpZiAobWF0Y2gpIHtcblx0XHRcdHJldHVybiB5YW1sLmxvYWQobWF0Y2hbMV0udHJpbSgpKSBhcyBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuXHRcdH1cblxuXHRcdHJldHVybiB7fTtcblx0fVxuXG5cdHNldCBmcm9udE1hdHRlcihkYXRhOiBSZWNvcmQ8c3RyaW5nLCBhbnk+KSB7XG5cdFx0Y29uc3QgZnJvbnRNYXR0ZXIgPSB0aGlzLmZyb250TWF0dGVyUmF3O1xuXHRcdGNvbnN0IHlhbWxTdHJpbmcgPSB5YW1sLmR1bXAoZGF0YSk7XG5cdFx0Y29uc3QgbmV3RnJvbnRNYXR0ZXIgPSBgLS0tXFxuJHt5YW1sU3RyaW5nfS0tLVxcbmA7XG5cdFx0dGhpcy5fY29udGVudCA9IHRoaXMuX2NvbnRlbnQucmVwbGFjZShmcm9udE1hdHRlciwgbmV3RnJvbnRNYXR0ZXIpO1xuXHR9XG5cblx0cHVibGljIGdldEZyb250TWF0dGVyVmFsdWU8VD4oa2V5OiBzdHJpbmcpOiBUIHtcblx0XHRyZXR1cm4gdGhpcy5mcm9udE1hdHRlcltrZXldIGFzIFQ7XG5cdH1cblxuXHRhc3luYyByZW5kZXIob3B0aW9ucz86IFJlbmRlck9wdGlvbnMpOiBQcm9taXNlPHN0cmluZz4ge1xuXHRcdHRyeSB7XG5cdFx0XHRsZXQgcmVzdWx0ID0gJyc7XG5cdFx0XHRpZiAodGhpcy5pc0NhY2hlRW5hYmxlZChvcHRpb25zKSkge1xuXHRcdFx0XHRjb25zdCBjYWNoZWQgPSBhd2FpdCB0aGlzLl9jYWNoZS5nZXRNYXJrZG93bih0aGlzLl9jb250ZW50LCBvcHRpb25zKTtcblx0XHRcdFx0aWYgKGNhY2hlZCkge1xuXHRcdFx0XHRcdHJldHVybiBjYWNoZWQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0bGV0IHtlbmdpbmV9ID0gdGhpcztcblx0XHRcdGlmIChvcHRpb25zKSB7XG5cdFx0XHRcdG9wdGlvbnMgPSB7Li4udGhpcy5fb3B0aW9ucy5yZW5kZXJPcHRpb25zLCAuLi5vcHRpb25zfTtcblx0XHRcdFx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtYXNzaWdubWVudFxuXHRcdFx0XHRlbmdpbmUgPSB0aGlzLmNyZWF0ZVByb2Nlc3NvcihvcHRpb25zKTtcblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgZmlsZSA9IGF3YWl0IGVuZ2luZS5wcm9jZXNzKHRoaXMuYm9keSk7XG5cdFx0XHRyZXN1bHQgPSBTdHJpbmcoZmlsZSk7XG5cdFx0XHRpZiAodGhpcy5pc0NhY2hlRW5hYmxlZChvcHRpb25zKSkge1xuXHRcdFx0XHRhd2FpdCB0aGlzLl9jYWNoZS5zZXRNYXJrZG93bih0aGlzLl9jb250ZW50LCByZXN1bHQsIG9wdGlvbnMpO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gcmVzdWx0O1xuXHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byByZW5kZXIgbWFya2Rvd246ICR7KGVycm9yIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuXHRcdH1cblx0fVxuXG5cdHJlbmRlclN5bmMob3B0aW9ucz86IFJlbmRlck9wdGlvbnMpOiBzdHJpbmcge1xuXHRcdHRyeSB7XG5cdFx0XHRsZXQgcmVzdWx0ID0gJyc7XG5cdFx0XHRpZiAodGhpcy5pc0NhY2hlRW5hYmxlZChvcHRpb25zKSkge1xuXHRcdFx0XHRjb25zdCBjYWNoZWQgPSB0aGlzLl9jYWNoZS5nZXRNYXJrZG93blN5bmModGhpcy5fY29udGVudCwgb3B0aW9ucyk7XG5cdFx0XHRcdGlmIChjYWNoZWQpIHtcblx0XHRcdFx0XHRyZXR1cm4gY2FjaGVkO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGxldCB7ZW5naW5lfSA9IHRoaXM7XG5cdFx0XHRpZiAob3B0aW9ucykge1xuXHRcdFx0XHRvcHRpb25zID0gey4uLnRoaXMuX29wdGlvbnMucmVuZGVyT3B0aW9ucywgLi4ub3B0aW9uc307XG5cdFx0XHRcdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5zYWZlLWFzc2lnbm1lbnRcblx0XHRcdFx0ZW5naW5lID0gdGhpcy5jcmVhdGVQcm9jZXNzb3Iob3B0aW9ucyk7XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGZpbGUgPSBlbmdpbmUucHJvY2Vzc1N5bmModGhpcy5ib2R5KTtcblx0XHRcdHJlc3VsdCA9IFN0cmluZyhmaWxlKTtcblx0XHRcdGlmICh0aGlzLmlzQ2FjaGVFbmFibGVkKG9wdGlvbnMpKSB7XG5cdFx0XHRcdHRoaXMuX2NhY2hlLnNldE1hcmtkb3duU3luYyh0aGlzLl9jb250ZW50LCByZXN1bHQsIG9wdGlvbnMpO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gcmVzdWx0O1xuXHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byByZW5kZXIgbWFya2Rvd246ICR7KGVycm9yIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuXHRcdH1cblx0fVxuXG5cdGFzeW5jIHJlbmRlclJlYWN0KG9wdGlvbnM/OiBSZW5kZXJPcHRpb25zLCByZWFjdFBhcnNlT3B0aW9ucz86IEhUTUxSZWFjdFBhcnNlck9wdGlvbnMpOiBQcm9taXNlPHN0cmluZyB8IFJlYWN0LkpTWC5FbGVtZW50IHwgUmVhY3QuSlNYLkVsZW1lbnRbXT4ge1xuXHRcdGNvbnN0IGh0bWwgPSBhd2FpdCB0aGlzLnJlbmRlcihvcHRpb25zKTtcblxuXHRcdHJldHVybiBwYXJzZShodG1sLCByZWFjdFBhcnNlT3B0aW9ucyk7XG5cdH1cblxuXHRyZW5kZXJSZWFjdFN5bmMob3B0aW9ucz86IFJlbmRlck9wdGlvbnMsIHJlYWN0UGFyc2VPcHRpb25zPzogSFRNTFJlYWN0UGFyc2VyT3B0aW9ucyk6IHN0cmluZyB8IFJlYWN0LkpTWC5FbGVtZW50IHwgUmVhY3QuSlNYLkVsZW1lbnRbXSB7XG5cdFx0Y29uc3QgaHRtbCA9IHRoaXMucmVuZGVyU3luYyhvcHRpb25zKTtcblx0XHRyZXR1cm4gcGFyc2UoaHRtbCwgcmVhY3RQYXJzZU9wdGlvbnMpO1xuXHR9XG5cblx0YXN5bmMgbG9hZEZyb21GaWxlKGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcblx0XHRjb25zdCB7cmVhZEZpbGV9ID0gZnMucHJvbWlzZXM7XG5cdFx0dGhpcy5fY29udGVudCA9IGF3YWl0IHJlYWRGaWxlKGZpbGVQYXRoLCAndXRmOCcpO1xuXHR9XG5cblx0bG9hZEZyb21GaWxlU3luYyhmaWxlUGF0aDogc3RyaW5nKTogdm9pZCB7XG5cdFx0dGhpcy5fY29udGVudCA9IGZzLnJlYWRGaWxlU3luYyhmaWxlUGF0aCwgJ3V0ZjgnKTtcblx0fVxuXG5cdGFzeW5jIHNhdmVUb0ZpbGUoZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuXHRcdGNvbnN0IHt3cml0ZUZpbGUsIG1rZGlyfSA9IGZzLnByb21pc2VzO1xuXHRcdGNvbnN0IGRpcmVjdG9yeVBhdGggPSBkaXJuYW1lKGZpbGVQYXRoKTtcblx0XHRhd2FpdCBta2RpcihkaXJlY3RvcnlQYXRoLCB7cmVjdXJzaXZlOiB0cnVlfSk7XG5cdFx0YXdhaXQgd3JpdGVGaWxlKGZpbGVQYXRoLCB0aGlzLl9jb250ZW50LCAndXRmOCcpO1xuXHR9XG5cblx0c2F2ZVRvRmlsZVN5bmMoZmlsZVBhdGg6IHN0cmluZyk6IHZvaWQge1xuXHRcdGNvbnN0IGRpcmVjdG9yeVBhdGggPSBkaXJuYW1lKGZpbGVQYXRoKTtcblx0XHRmcy5ta2RpclN5bmMoZGlyZWN0b3J5UGF0aCwge3JlY3Vyc2l2ZTogdHJ1ZX0pO1xuXHRcdGZzLndyaXRlRmlsZVN5bmMoZmlsZVBhdGgsIHRoaXMuX2NvbnRlbnQsICd1dGY4Jyk7XG5cdH1cblxuXHRwcml2YXRlIGlzQ2FjaGVFbmFibGVkKG9wdGlvbnM/OiBSZW5kZXJPcHRpb25zKTogYm9vbGVhbiB7XG5cdFx0aWYgKG9wdGlvbnM/LmNhY2hpbmcgIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0cmV0dXJuIG9wdGlvbnMuY2FjaGluZztcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5fb3B0aW9ucz8ucmVuZGVyT3B0aW9ucz8uY2FjaGluZyA/PyBmYWxzZTtcblx0fVxuXG5cdHByaXZhdGUgY3JlYXRlUHJvY2Vzc29yKG9wdGlvbnM6IFJlbmRlck9wdGlvbnMpOiBhbnkge1xuXHRcdGNvbnN0IHByb2Nlc3NvciA9IHVuaWZpZWQoKS51c2UocmVtYXJrUGFyc2UpO1xuXG5cdFx0aWYgKG9wdGlvbnMuZ2ZtKSB7XG5cdFx0XHRwcm9jZXNzb3IudXNlKHJlbWFya0dmbSk7XG5cdFx0fVxuXG5cdFx0aWYgKG9wdGlvbnMudG9jKSB7XG5cdFx0XHRwcm9jZXNzb3IudXNlKHJlbWFya1RvYywge2hlYWRpbmc6ICd0b2N8dGFibGUgb2YgY29udGVudHMnfSk7XG5cdFx0fVxuXG5cdFx0aWYgKG9wdGlvbnMuZW1vamkpIHtcblx0XHRcdHByb2Nlc3Nvci51c2UocmVtYXJrRW1vamkpO1xuXHRcdH1cblxuXHRcdHByb2Nlc3Nvci51c2UocmVtYXJrUmVoeXBlKTtcblxuXHRcdGlmIChvcHRpb25zLnNsdWcpIHtcblx0XHRcdHByb2Nlc3Nvci51c2UocmVoeXBlU2x1Zyk7XG5cdFx0fVxuXG5cdFx0aWYgKG9wdGlvbnMuaGlnaGxpZ2h0KSB7XG5cdFx0XHRwcm9jZXNzb3IudXNlKHJlaHlwZUhpZ2hsaWdodCk7XG5cdFx0fVxuXG5cdFx0aWYgKG9wdGlvbnMubWF0aCkge1xuXHRcdFx0cHJvY2Vzc29yLnVzZShyZW1hcmtNYXRoKS51c2UocmVoeXBlS2F0ZXgpO1xuXHRcdH1cblxuXHRcdGlmIChvcHRpb25zLm1keCkge1xuXHRcdFx0cHJvY2Vzc29yLnVzZShyZW1hcmtNRFgpO1xuXHRcdH1cblxuXHRcdHByb2Nlc3Nvci51c2UocmVoeXBlU3RyaW5naWZ5KTtcblxuXHRcdHJldHVybiBwcm9jZXNzb3I7XG5cdH1cbn1cblxuZXhwb3J0IHtXcml0ciwgdHlwZSBXcml0ck9wdGlvbnMsIHR5cGUgUmVuZGVyT3B0aW9uc307XG5cbiJdfQ==
280
+ processor.use(rehypeStringify);
281
+ return processor;
282
+ }
283
+ };
284
+ export {
285
+ Writr
286
+ };
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "writr",
3
- "version": "4.0.0",
3
+ "version": "4.1.1",
4
4
  "description": "Markdown Rendering Simplified",
5
5
  "type": "module",
6
- "exports": "./dist/writr.js",
6
+ "main": "./dist/writr.js",
7
7
  "types": "./dist/writr.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/writr.js"
11
+ }
12
+ },
8
13
  "repository": "https://github.com/jaredwray/writr.git",
9
14
  "author": "Jared Wray <me@jaredwray.com>",
10
15
  "engines": {
@@ -41,44 +46,45 @@
41
46
  ],
42
47
  "scripts": {
43
48
  "clean": "rimraf ./dist ./coverage ./node_modules ./package-lock.json ./yarn.lock ./site/README.md ./site/dist",
44
- "build": "rimraf ./dist && tsc",
45
- "test": "xo --fix && vitest run --coverage",
49
+ "build": "rimraf ./dist && tsup src/writr.ts --format esm --dts --clean",
46
50
  "prepare": "npm run build",
51
+ "test": "xo --fix && vitest run --coverage",
47
52
  "website:build": "rimraf ./site/README.md ./site/dist && npx docula build -s ./site -o ./site/dist",
48
53
  "website:serve": "rimraf ./site/README.md ./site/dist && npx docula serve -s ./site -o ./site/dist"
49
54
  },
50
55
  "dependencies": {
56
+ "cacheable": "^1.8.0",
51
57
  "crypto": "^1.0.1",
52
58
  "fs": "^0.0.1-security",
53
- "html-react-parser": "^5.1.15",
59
+ "html-react-parser": "^5.1.17",
54
60
  "js-yaml": "^4.1.0",
55
- "keyv": "^5.0.1",
56
61
  "react": "^18.3.1",
57
62
  "rehype-highlight": "^7.0.0",
58
63
  "rehype-katex": "^7.0.1",
59
64
  "rehype-slug": "^6.0.0",
60
- "rehype-stringify": "^10.0.0",
65
+ "rehype-stringify": "^10.0.1",
61
66
  "remark-emoji": "^5.0.1",
62
67
  "remark-gfm": "^4.0.0",
63
68
  "remark-math": "^6.0.0",
64
69
  "remark-mdx": "^3.0.1",
65
70
  "remark-parse": "^11.0.0",
66
- "remark-rehype": "^11.1.0",
71
+ "remark-rehype": "^11.1.1",
67
72
  "remark-toc": "^9.0.0",
68
73
  "unified": "^11.0.5"
69
74
  },
70
75
  "devDependencies": {
71
76
  "@keyv/sqlite": "^4.0.1",
72
77
  "@types/js-yaml": "^4.0.9",
73
- "@types/node": "^22.5.1",
74
- "@types/react": "^18.3.5",
75
- "@vitest/coverage-v8": "^2.0.5",
76
- "docula": "^0.9.0",
78
+ "@types/node": "^22.7.4",
79
+ "@types/react": "^18.3.11",
80
+ "@vitest/coverage-v8": "^2.1.2",
81
+ "docula": "^0.9.1",
77
82
  "rimraf": "^6.0.1",
78
83
  "ts-node": "^10.9.2",
79
- "typescript": "^5.5.4",
80
- "vitest": "^2.0.5",
81
- "webpack": "^5.94.0",
84
+ "tsup": "^8.3.0",
85
+ "typescript": "^5.6.2",
86
+ "vitest": "^2.1.2",
87
+ "webpack": "^5.95.0",
82
88
  "xo": "^0.59.3"
83
89
  },
84
90
  "xo": {
@@ -1,22 +0,0 @@
1
- import { Keyv, type KeyvStoreAdapter } from 'keyv';
2
- import { type RenderOptions } from './writr.js';
3
- export declare class WritrCache {
4
- private _markdownStore;
5
- private _markdownStoreSync;
6
- private _hashStore;
7
- constructor();
8
- get markdownStore(): Keyv;
9
- get markdownStoreSync(): Map<string, string>;
10
- get hashStore(): Map<string, string>;
11
- getMarkdown(markdown: string, options?: RenderOptions): Promise<string | undefined>;
12
- getMarkdownSync(markdown: string, options?: RenderOptions): string | undefined;
13
- setMarkdown(markdown: string, value: string, options?: RenderOptions): Promise<boolean>;
14
- setMarkdownSync(markdown: string, value: string, options?: RenderOptions): boolean;
15
- get(key: string): Promise<string | undefined>;
16
- getSync(key: string): string | undefined;
17
- set(key: string, value: string): Promise<boolean>;
18
- setSync(key: string, value: string): boolean;
19
- clear(): Promise<void>;
20
- setStorageAdapter(adapter: KeyvStoreAdapter): void;
21
- hash(markdown: string, options?: RenderOptions): string;
22
- }
@@ -1,70 +0,0 @@
1
- import { createHash } from 'node:crypto';
2
- import { Keyv } from 'keyv';
3
- export class WritrCache {
4
- _markdownStore;
5
- _markdownStoreSync;
6
- _hashStore;
7
- constructor() {
8
- this._markdownStore = new Keyv();
9
- this._markdownStoreSync = new Map();
10
- this._hashStore = new Map();
11
- }
12
- get markdownStore() {
13
- return this._markdownStore;
14
- }
15
- get markdownStoreSync() {
16
- return this._markdownStoreSync;
17
- }
18
- get hashStore() {
19
- return this._hashStore;
20
- }
21
- async getMarkdown(markdown, options) {
22
- const key = this.hash(markdown, options);
23
- return this.get(key);
24
- }
25
- getMarkdownSync(markdown, options) {
26
- const key = this.hash(markdown, options);
27
- return this.getSync(key);
28
- }
29
- async setMarkdown(markdown, value, options) {
30
- const key = this.hash(markdown, options);
31
- return this.set(key, value);
32
- }
33
- setMarkdownSync(markdown, value, options) {
34
- const key = this.hash(markdown, options);
35
- this.setSync(key, value);
36
- return true;
37
- }
38
- async get(key) {
39
- return this._markdownStore.get(key);
40
- }
41
- getSync(key) {
42
- return this._markdownStoreSync.get(key);
43
- }
44
- async set(key, value) {
45
- return this._markdownStore.set(key, value);
46
- }
47
- setSync(key, value) {
48
- this._markdownStoreSync.set(key, value);
49
- return true;
50
- }
51
- async clear() {
52
- await this._markdownStore.clear();
53
- this._markdownStoreSync = new Map();
54
- this._hashStore = new Map();
55
- }
56
- setStorageAdapter(adapter) {
57
- this._markdownStore = new Keyv({ store: adapter });
58
- }
59
- hash(markdown, options) {
60
- const key = JSON.stringify({ markdown, options });
61
- let result = this._hashStore.get(key);
62
- if (result) {
63
- return result;
64
- }
65
- result = createHash('sha256').update(key).digest('hex');
66
- this._hashStore.set(key, result);
67
- return result;
68
- }
69
- }
70
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3JpdHItY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvd3JpdHItY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLGFBQWEsQ0FBQztBQUN2QyxPQUFPLEVBQUMsSUFBSSxFQUF3QixNQUFNLE1BQU0sQ0FBQztBQUdqRCxNQUFNLE9BQU8sVUFBVTtJQUNkLGNBQWMsQ0FBTztJQUNyQixrQkFBa0IsQ0FBc0I7SUFDeEMsVUFBVSxDQUFzQjtJQUV4QztRQUNDLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUNqQyxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNwQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7SUFDN0IsQ0FBQztJQUVELElBQVcsYUFBYTtRQUN2QixPQUFPLElBQUksQ0FBQyxjQUFjLENBQUM7SUFDNUIsQ0FBQztJQUVELElBQVcsaUJBQWlCO1FBQzNCLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDO0lBQ2hDLENBQUM7SUFFRCxJQUFXLFNBQVM7UUFDbkIsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDO0lBQ3hCLENBQUM7SUFFTSxLQUFLLENBQUMsV0FBVyxDQUFDLFFBQWdCLEVBQUUsT0FBdUI7UUFDakUsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDekMsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3RCLENBQUM7SUFFTSxlQUFlLENBQUMsUUFBZ0IsRUFBRSxPQUF1QjtRQUMvRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN6QyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQUVNLEtBQUssQ0FBQyxXQUFXLENBQUMsUUFBZ0IsRUFBRSxLQUFhLEVBQUUsT0FBdUI7UUFDaEYsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDekMsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUM3QixDQUFDO0lBRU0sZUFBZSxDQUFDLFFBQWdCLEVBQUUsS0FBYSxFQUFFLE9BQXVCO1FBQzlFLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3pDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3pCLE9BQU8sSUFBSSxDQUFDO0lBQ2IsQ0FBQztJQUVNLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBVztRQUMzQixPQUFPLElBQUksQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFTSxPQUFPLENBQUMsR0FBVztRQUN6QixPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVNLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBVyxFQUFFLEtBQWE7UUFDMUMsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUVNLE9BQU8sQ0FBQyxHQUFXLEVBQUUsS0FBYTtRQUN4QyxJQUFJLENBQUMsa0JBQWtCLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN4QyxPQUFPLElBQUksQ0FBQztJQUNiLENBQUM7SUFFTSxLQUFLLENBQUMsS0FBSztRQUNqQixNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDbEMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7UUFDcEMsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQzdCLENBQUM7SUFFTSxpQkFBaUIsQ0FBQyxPQUF5QjtRQUNqRCxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksSUFBSSxDQUFDLEVBQUMsS0FBSyxFQUFFLE9BQU8sRUFBQyxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVNLElBQUksQ0FBQyxRQUFnQixFQUFFLE9BQXVCO1FBQ3BELE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBQyxRQUFRLEVBQUUsT0FBTyxFQUFDLENBQUMsQ0FBQztRQUNoRCxJQUFJLE1BQU0sR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN0QyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ1osT0FBTyxNQUFNLENBQUM7UUFDZixDQUFDO1FBRUQsTUFBTSxHQUFHLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3hELElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUVqQyxPQUFPLE1BQU0sQ0FBQztJQUNmLENBQUM7Q0FDRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7Y3JlYXRlSGFzaH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuaW1wb3J0IHtLZXl2LCB0eXBlIEtleXZTdG9yZUFkYXB0ZXJ9IGZyb20gJ2tleXYnO1xuaW1wb3J0IHt0eXBlIFJlbmRlck9wdGlvbnN9IGZyb20gJy4vd3JpdHIuanMnO1xuXG5leHBvcnQgY2xhc3MgV3JpdHJDYWNoZSB7XG5cdHByaXZhdGUgX21hcmtkb3duU3RvcmU6IEtleXY7XG5cdHByaXZhdGUgX21hcmtkb3duU3RvcmVTeW5jOiBNYXA8c3RyaW5nLCBzdHJpbmc+O1xuXHRwcml2YXRlIF9oYXNoU3RvcmU6IE1hcDxzdHJpbmcsIHN0cmluZz47XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cdFx0dGhpcy5fbWFya2Rvd25TdG9yZSA9IG5ldyBLZXl2KCk7XG5cdFx0dGhpcy5fbWFya2Rvd25TdG9yZVN5bmMgPSBuZXcgTWFwKCk7XG5cdFx0dGhpcy5faGFzaFN0b3JlID0gbmV3IE1hcCgpO1xuXHR9XG5cblx0cHVibGljIGdldCBtYXJrZG93blN0b3JlKCk6IEtleXYge1xuXHRcdHJldHVybiB0aGlzLl9tYXJrZG93blN0b3JlO1xuXHR9XG5cblx0cHVibGljIGdldCBtYXJrZG93blN0b3JlU3luYygpOiBNYXA8c3RyaW5nLCBzdHJpbmc+IHtcblx0XHRyZXR1cm4gdGhpcy5fbWFya2Rvd25TdG9yZVN5bmM7XG5cdH1cblxuXHRwdWJsaWMgZ2V0IGhhc2hTdG9yZSgpOiBNYXA8c3RyaW5nLCBzdHJpbmc+IHtcblx0XHRyZXR1cm4gdGhpcy5faGFzaFN0b3JlO1xuXHR9XG5cblx0cHVibGljIGFzeW5jIGdldE1hcmtkb3duKG1hcmtkb3duOiBzdHJpbmcsIG9wdGlvbnM/OiBSZW5kZXJPcHRpb25zKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcblx0XHRjb25zdCBrZXkgPSB0aGlzLmhhc2gobWFya2Rvd24sIG9wdGlvbnMpO1xuXHRcdHJldHVybiB0aGlzLmdldChrZXkpO1xuXHR9XG5cblx0cHVibGljIGdldE1hcmtkb3duU3luYyhtYXJrZG93bjogc3RyaW5nLCBvcHRpb25zPzogUmVuZGVyT3B0aW9ucyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG5cdFx0Y29uc3Qga2V5ID0gdGhpcy5oYXNoKG1hcmtkb3duLCBvcHRpb25zKTtcblx0XHRyZXR1cm4gdGhpcy5nZXRTeW5jKGtleSk7XG5cdH1cblxuXHRwdWJsaWMgYXN5bmMgc2V0TWFya2Rvd24obWFya2Rvd246IHN0cmluZywgdmFsdWU6IHN0cmluZywgb3B0aW9ucz86IFJlbmRlck9wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcblx0XHRjb25zdCBrZXkgPSB0aGlzLmhhc2gobWFya2Rvd24sIG9wdGlvbnMpO1xuXHRcdHJldHVybiB0aGlzLnNldChrZXksIHZhbHVlKTtcblx0fVxuXG5cdHB1YmxpYyBzZXRNYXJrZG93blN5bmMobWFya2Rvd246IHN0cmluZywgdmFsdWU6IHN0cmluZywgb3B0aW9ucz86IFJlbmRlck9wdGlvbnMpOiBib29sZWFuIHtcblx0XHRjb25zdCBrZXkgPSB0aGlzLmhhc2gobWFya2Rvd24sIG9wdGlvbnMpO1xuXHRcdHRoaXMuc2V0U3luYyhrZXksIHZhbHVlKTtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXG5cdHB1YmxpYyBhc3luYyBnZXQoa2V5OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuXHRcdHJldHVybiB0aGlzLl9tYXJrZG93blN0b3JlLmdldChrZXkpO1xuXHR9XG5cblx0cHVibGljIGdldFN5bmMoa2V5OiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuXHRcdHJldHVybiB0aGlzLl9tYXJrZG93blN0b3JlU3luYy5nZXQoa2V5KTtcblx0fVxuXG5cdHB1YmxpYyBhc3luYyBzZXQoa2V5OiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcblx0XHRyZXR1cm4gdGhpcy5fbWFya2Rvd25TdG9yZS5zZXQoa2V5LCB2YWx1ZSk7XG5cdH1cblxuXHRwdWJsaWMgc2V0U3luYyhrZXk6IHN0cmluZywgdmFsdWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuXHRcdHRoaXMuX21hcmtkb3duU3RvcmVTeW5jLnNldChrZXksIHZhbHVlKTtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXG5cdHB1YmxpYyBhc3luYyBjbGVhcigpOiBQcm9taXNlPHZvaWQ+IHtcblx0XHRhd2FpdCB0aGlzLl9tYXJrZG93blN0b3JlLmNsZWFyKCk7XG5cdFx0dGhpcy5fbWFya2Rvd25TdG9yZVN5bmMgPSBuZXcgTWFwKCk7XG5cdFx0dGhpcy5faGFzaFN0b3JlID0gbmV3IE1hcCgpO1xuXHR9XG5cblx0cHVibGljIHNldFN0b3JhZ2VBZGFwdGVyKGFkYXB0ZXI6IEtleXZTdG9yZUFkYXB0ZXIpOiB2b2lkIHtcblx0XHR0aGlzLl9tYXJrZG93blN0b3JlID0gbmV3IEtleXYoe3N0b3JlOiBhZGFwdGVyfSk7XG5cdH1cblxuXHRwdWJsaWMgaGFzaChtYXJrZG93bjogc3RyaW5nLCBvcHRpb25zPzogUmVuZGVyT3B0aW9ucyk6IHN0cmluZyB7XG5cdFx0Y29uc3Qga2V5ID0gSlNPTi5zdHJpbmdpZnkoe21hcmtkb3duLCBvcHRpb25zfSk7XG5cdFx0bGV0IHJlc3VsdCA9IHRoaXMuX2hhc2hTdG9yZS5nZXQoa2V5KTtcblx0XHRpZiAocmVzdWx0KSB7XG5cdFx0XHRyZXR1cm4gcmVzdWx0O1xuXHRcdH1cblxuXHRcdHJlc3VsdCA9IGNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShrZXkpLmRpZ2VzdCgnaGV4Jyk7XG5cdFx0dGhpcy5faGFzaFN0b3JlLnNldChrZXksIHJlc3VsdCk7XG5cblx0XHRyZXR1cm4gcmVzdWx0O1xuXHR9XG59XG4iXX0=