@bitgo-beta/key-card 0.0.1-beta.22 → 0.0.1-beta.2200

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/src/drawKeycard.d.ts +5 -0
  2. package/dist/src/drawKeycard.d.ts.map +1 -0
  3. package/dist/src/drawKeycard.js +352 -0
  4. package/dist/src/extractKeycardFromPDF.d.ts +16 -0
  5. package/dist/src/extractKeycardFromPDF.d.ts.map +1 -0
  6. package/dist/src/extractKeycardFromPDF.js +77 -0
  7. package/dist/src/faq.d.ts +4 -0
  8. package/dist/src/faq.d.ts.map +1 -0
  9. package/dist/src/faq.js +89 -0
  10. package/dist/src/generateParamsForKeyCreation.d.ts +3 -0
  11. package/dist/src/generateParamsForKeyCreation.d.ts.map +1 -0
  12. package/dist/src/generateParamsForKeyCreation.js +72 -0
  13. package/dist/src/generateQrData.d.ts +10 -0
  14. package/dist/src/generateQrData.d.ts.map +1 -0
  15. package/dist/src/generateQrData.js +250 -0
  16. package/dist/src/index.d.ts +19 -0
  17. package/dist/src/index.d.ts.map +1 -0
  18. package/dist/src/index.js +83 -0
  19. package/dist/src/parseKeycard.d.ts +24 -0
  20. package/dist/src/parseKeycard.d.ts.map +1 -0
  21. package/dist/src/parseKeycard.js +164 -0
  22. package/dist/src/types.d.ts +81 -0
  23. package/dist/src/types.d.ts.map +1 -0
  24. package/dist/src/types.js +15 -0
  25. package/dist/src/upgradeWalletEncryption.d.ts +27 -0
  26. package/dist/src/upgradeWalletEncryption.d.ts.map +1 -0
  27. package/dist/src/upgradeWalletEncryption.js +106 -0
  28. package/dist/src/utils.d.ts +2 -0
  29. package/dist/src/utils.d.ts.map +1 -0
  30. package/dist/src/utils.js +16 -0
  31. package/dist/tsconfig.tsbuildinfo +1 -0
  32. package/package.json +11 -6
  33. package/.mocharc.js +0 -9
  34. package/src/drawKeycard.ts +0 -240
  35. package/src/faq.ts +0 -82
  36. package/src/generateQrData.ts +0 -167
  37. package/src/index.ts +0 -22
  38. package/src/utils.ts +0 -15
  39. package/test/unit/faq.ts +0 -14
  40. package/test/unit/generateQrData.ts +0 -213
  41. package/test/unit/utils.ts +0 -30
  42. package/tsconfig.json +0 -20
@@ -0,0 +1,5 @@
1
+ import type { jsPDF } from 'jspdf';
2
+ import { IDrawKeyCard } from './types';
3
+ export declare const QRBinaryMaxLength = 1500;
4
+ export declare function drawKeycard({ activationCode, questions, keyCardImage, qrData, walletLabel, curve, pageBreakBeforeIndices, useQrPartHeaders, }: IDrawKeyCard): Promise<jsPDF>;
5
+ //# sourceMappingURL=drawKeycard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawKeycard.d.ts","sourceRoot":"","sources":["../../src/drawKeycard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA6BvC,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAqHtC,wBAAsB,WAAW,CAAC,EAChC,cAAc,EACd,SAAS,EACT,YAAY,EACZ,MAAM,EACN,WAAW,EACX,KAAK,EACL,sBAAmD,EACnD,gBAAwB,GACzB,EAAE,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,CAsN/B"}
@@ -0,0 +1,352 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.QRBinaryMaxLength = void 0;
37
+ exports.drawKeycard = drawKeycard;
38
+ const QRCode = __importStar(require("qrcode"));
39
+ const utils_1 = require("./utils");
40
+ const isNode = typeof window === 'undefined' || typeof window.document === 'undefined';
41
+ async function loadJSPDF() {
42
+ let jsPDF;
43
+ if (typeof window !== 'undefined' && typeof window.document !== 'undefined') {
44
+ // We are in the browser
45
+ jsPDF = await Promise.resolve().then(() => __importStar(require('jspdf')));
46
+ }
47
+ else {
48
+ // We are in Node.js
49
+ jsPDF = require('jspdf');
50
+ }
51
+ return jsPDF;
52
+ }
53
+ var KeyCurveName;
54
+ (function (KeyCurveName) {
55
+ KeyCurveName["ed25519"] = "EDDSA";
56
+ KeyCurveName["secp256k1"] = "ECDSA";
57
+ KeyCurveName["bls"] = "BLS";
58
+ })(KeyCurveName || (KeyCurveName = {}));
59
+ // Max for Binary/Byte Data https://github.com/soldair/node-qrcode#qr-code-capacity
60
+ // the largest theoretically possible value is actually 2953 but the QR codes get so dense that scanning them with a
61
+ // phone (off of a printed page) doesn't work anymore
62
+ // this limitation was chosen by trial and error
63
+ exports.QRBinaryMaxLength = 1500;
64
+ // Default page-break layout: start a new page before the 3rd box (index 2), matching the
65
+ // historical wallet keycard. Callers (e.g. the safe keycard) may override with their own indices.
66
+ const DEFAULT_PAGE_BREAK_INDICES = [2];
67
+ const font = {
68
+ header: 24,
69
+ subheader: 15,
70
+ body: 12,
71
+ };
72
+ const color = {
73
+ black: '#000000',
74
+ darkgray: '#4c4c4c',
75
+ gray: '#9b9b9b',
76
+ red: '#e21e1e',
77
+ };
78
+ const margin = 30;
79
+ // Helpers for data formatting / positioning on the paper
80
+ function left(x) {
81
+ return margin + x;
82
+ }
83
+ function moveDown(y, ydelta) {
84
+ return y + ydelta;
85
+ }
86
+ /**
87
+ * Prefixes one fragment of a split key with a part header so a QR scanner can reassemble the
88
+ * fragments without relying on scan order.
89
+ *
90
+ * When a key box's payload exceeds {@link QRBinaryMaxLength}, {@link splitKeys} divides it into
91
+ * multiple QR codes. Each fragment's QR payload is encoded as a 1-based part header followed by
92
+ * the fragment:
93
+ *
94
+ * "<index>/<total>|<fragment>" e.g. "1/3|<chunk>", "2/3|<chunk>", "3/3|<chunk>"
95
+ *
96
+ * A single-fragment payload is returned unchanged (no header).
97
+ *
98
+ * Reassembly contract for a consumer (e.g. a future recovery/scan tool):
99
+ * 1. Scan every QR code for a box.
100
+ * 2. Split each payload on the FIRST "|": the left side is "<index>/<total>", the right side
101
+ * is the fragment.
102
+ * 3. Verify parts 1..total are all present (total is identical in every header).
103
+ * 4. Concatenate the fragments in ascending index order to recover the full box payload.
104
+ * 5. Parse/decrypt as usual (for a safe box: JSON.parse, then decrypt each root value).
105
+ *
106
+ * Notes:
107
+ * - The "|" delimiter is safe: base64 ciphertext, JSON, and base58 xpubs never contain it.
108
+ * - This header exists ONLY inside the QR image. The human-readable "Data:" text printed on
109
+ * the card is the full, unheadered payload; the PDF-text parser reads that, so this header
110
+ * does not affect PDF-based recovery.
111
+ */
112
+ function encodeQrCodePart(fragment, index, total) {
113
+ return total > 1 ? `${index + 1}/${total}|${fragment}` : fragment;
114
+ }
115
+ // Draws QR codes down the left column, returning the index of the next QR still to draw (for
116
+ // continuation on a later page) and the y-offset just below the drawn QR column (so callers
117
+ // can place content, e.g. a note, under the QR codes).
118
+ function drawOnePageOfQrCodes(qrImages, doc, y, qrSize, startIndex) {
119
+ doc.setFont('helvetica');
120
+ let qrIndex = startIndex;
121
+ for (; qrIndex < qrImages.length; qrIndex++) {
122
+ const image = qrImages[qrIndex];
123
+ const textBuffer = 15;
124
+ if (y + qrSize + textBuffer >= doc.internal.pageSize.getHeight()) {
125
+ return { nextIndex: qrIndex, endY: y };
126
+ }
127
+ if (typeof image === 'string') {
128
+ doc.addImage(image, 'PNG', left(0), y, qrSize, qrSize);
129
+ }
130
+ else {
131
+ doc.addImage(image, left(0), y, qrSize, qrSize);
132
+ }
133
+ if (qrImages.length === 1) {
134
+ return { nextIndex: qrIndex + 1, endY: y + qrSize };
135
+ }
136
+ y = moveDown(y, qrSize + textBuffer);
137
+ doc.setFontSize(font.body).setTextColor(color.black);
138
+ doc.text('Part ' + (qrIndex + 1).toString(), left(0), y);
139
+ y = moveDown(y, 20);
140
+ }
141
+ return { nextIndex: qrIndex, endY: y };
142
+ }
143
+ function computeKeyCardImageDimensions(keyCardImage) {
144
+ // Max dimensions stablished by fixed available PDF space
145
+ const KEY_CARD_IMAGE_MAX_DIMENSIONS = {
146
+ width: 303,
147
+ height: 40,
148
+ };
149
+ const { width: imgWidth, height: imgHeight } = keyCardImage;
150
+ const { width: maxWidth, height: maxHeight } = KEY_CARD_IMAGE_MAX_DIMENSIONS;
151
+ // Try scaling ratio based on width
152
+ const wRatio = imgWidth / maxWidth;
153
+ let finalRatio = wRatio;
154
+ // If resized height exceeds the available height space, base ratio also on height
155
+ if (imgHeight / finalRatio > maxHeight) {
156
+ finalRatio = imgHeight / maxHeight;
157
+ }
158
+ return [imgWidth / finalRatio, imgHeight / finalRatio];
159
+ }
160
+ async function drawKeycard({ activationCode, questions, keyCardImage, qrData, walletLabel, curve, pageBreakBeforeIndices = DEFAULT_PAGE_BREAK_INDICES, useQrPartHeaders = false, }) {
161
+ const jsPDFModule = await loadJSPDF();
162
+ // document details
163
+ const width = 8.5 * 72;
164
+ let y = 0;
165
+ // Create the PDF instance
166
+ const doc = new jsPDFModule.jsPDF('portrait', 'pt', 'letter'); // jshint ignore:line
167
+ doc.setFont('helvetica');
168
+ // PDF Header Area - includes the logo and company name
169
+ // This is data for the BitGo logo in the top left of the PDF
170
+ y = moveDown(y, 30);
171
+ if (keyCardImage) {
172
+ const [imgWidth, imgHeight] = computeKeyCardImageDimensions(keyCardImage);
173
+ if (isNode) {
174
+ // In Node.js, jsPDF cannot extract pixels from an HTMLImageElement (no DOM/canvas).
175
+ // The script passes a duck-typed object whose .src is a base64 data URL — use it directly.
176
+ doc.addImage(keyCardImage.src, 'PNG', left(0), y, imgWidth, imgHeight);
177
+ }
178
+ else {
179
+ doc.addImage(keyCardImage, left(0), y, imgWidth, imgHeight);
180
+ }
181
+ }
182
+ // Activation Code
183
+ if (activationCode) {
184
+ y = moveDown(y, 8);
185
+ doc.setFontSize(font.body).setTextColor(color.gray);
186
+ doc.text('Activation Code', left(460), y);
187
+ }
188
+ doc.setFontSize(font.header).setTextColor(color.black);
189
+ y = moveDown(y, 25);
190
+ doc.text('KeyCard', left(curve && !activationCode ? 460 : 325), y - 1);
191
+ if (activationCode) {
192
+ doc.setFontSize(font.header).setTextColor(color.gray);
193
+ doc.text(activationCode, left(460), y);
194
+ }
195
+ // Subheader
196
+ // titles
197
+ const date = new Date().toDateString();
198
+ y = moveDown(y, margin);
199
+ doc.setFontSize(font.body).setTextColor(color.gray);
200
+ if (curve || walletLabel) {
201
+ const title = curve ? KeyCurveName[curve] + ' key:' : 'wallet named:';
202
+ doc.text('Created on ' + date + ' for ' + title, left(0), y);
203
+ // copy
204
+ y = moveDown(y, 25);
205
+ if (walletLabel) {
206
+ doc.setFontSize(font.subheader).setTextColor(color.black);
207
+ doc.text(walletLabel, left(0), y);
208
+ }
209
+ }
210
+ else {
211
+ doc.text('Created on ' + date, left(0), y);
212
+ y = moveDown(y, 25);
213
+ }
214
+ if (!curve) {
215
+ // Red Bar
216
+ y = moveDown(y, 20);
217
+ doc.setFillColor(255, 230, 230);
218
+ doc.rect(left(0), y, width - 2 * margin, 32, 'F');
219
+ // warning message
220
+ y = moveDown(y, 20);
221
+ doc.setFontSize(font.body).setTextColor(color.red);
222
+ doc.text('Print this document, or keep it securely offline. See below for FAQ.', left(75), y);
223
+ }
224
+ // Generate the first page's data for the backup PDF
225
+ y = moveDown(y, 35);
226
+ const qrSize = 130;
227
+ const qrKeys = ['user', 'userMasterPublicKey', 'backup', 'backupMasterPublicKey', 'bitgo', 'passcode'].filter((key) => !!qrData[key]);
228
+ for (let index = 0; index < qrKeys.length; index++) {
229
+ const name = qrKeys[index];
230
+ if (pageBreakBeforeIndices.includes(index)) {
231
+ // Start a new page for this box
232
+ doc.addPage();
233
+ // 2nd page title
234
+ y = 30;
235
+ }
236
+ const qr = qrData[name];
237
+ let topY = y;
238
+ const textLeft = left(qrSize + 15);
239
+ let textHeight = 0;
240
+ const qrImages = [];
241
+ const keys = (0, utils_1.splitKeys)(qr.data, exports.QRBinaryMaxLength);
242
+ for (let i = 0; i < keys.length; i++) {
243
+ const payload = useQrPartHeaders ? encodeQrCodePart(keys[i], i, keys.length) : keys[i];
244
+ if (isNode) {
245
+ qrImages.push(await QRCode.toDataURL(payload, { errorCorrectionLevel: 'L' }));
246
+ }
247
+ else {
248
+ qrImages.push(await QRCode.toCanvas(payload, { errorCorrectionLevel: 'L' }));
249
+ }
250
+ }
251
+ const isMultiPart = qr?.data?.length > exports.QRBinaryMaxLength;
252
+ const { nextIndex, endY: qrColumnEndY } = drawOnePageOfQrCodes(qrImages, doc, y, qrSize, 0);
253
+ let nextQrIndex = nextIndex;
254
+ // For a split key, place the "put all Parts together" note directly under the QR codes,
255
+ // wrapped to the QR column width so it stays in the left column and never overlaps the
256
+ // Data payload rendered on the right.
257
+ let qrColumnBottom = qrColumnEndY;
258
+ if (isMultiPart) {
259
+ doc.setFontSize(font.body - 2).setTextColor(color.darkgray);
260
+ const noteLines = doc.splitTextToSize('Note: you will need to put all Parts together for the full key', qrSize);
261
+ const noteY = moveDown(qrColumnEndY, 15);
262
+ doc.text(noteLines, left(0), noteY);
263
+ qrColumnBottom = noteY + noteLines.length * doc.getLineHeight();
264
+ }
265
+ doc.setFontSize(font.subheader).setTextColor(color.black);
266
+ y = moveDown(y, 10);
267
+ textHeight += 10;
268
+ doc.text(qr.title, textLeft, y);
269
+ textHeight += doc.getLineHeight();
270
+ y = moveDown(y, 15);
271
+ textHeight += 15;
272
+ doc.setFontSize(font.body).setTextColor(color.darkgray);
273
+ doc.text(qr.description, textLeft, y);
274
+ textHeight += doc.getLineHeight();
275
+ doc.setFontSize(font.body - 2);
276
+ y = moveDown(y, 30);
277
+ textHeight += 30;
278
+ doc.text('Data:', textLeft, y);
279
+ textHeight += doc.getLineHeight();
280
+ y = moveDown(y, 15);
281
+ textHeight += 15;
282
+ const width = 72 * 8.5 - textLeft - 30;
283
+ doc.setFont('courier').setFontSize(9).setTextColor(color.black);
284
+ const lines = doc.splitTextToSize(qr.data, width);
285
+ const buffer = 10;
286
+ for (let line = 0; line < lines.length; line++) {
287
+ // add new page if data does not fit on one page
288
+ if (y + buffer >= doc.internal.pageSize.getHeight()) {
289
+ doc.addPage();
290
+ textHeight = 0;
291
+ y = 30;
292
+ topY = y;
293
+ // Redraw remaining QRs on the new page and update the column bottom to THIS page, so
294
+ // the rowHeight math below stays same-page (avoids a stale page-1 coordinate).
295
+ const continued = drawOnePageOfQrCodes(qrImages, doc, y, qrSize, nextQrIndex);
296
+ nextQrIndex = continued.nextIndex;
297
+ qrColumnBottom = continued.endY;
298
+ doc.setFont('courier').setFontSize(9).setTextColor(color.black);
299
+ }
300
+ doc.text(lines[line], textLeft, y);
301
+ if (line !== lines.length - 1) {
302
+ y = moveDown(y, buffer);
303
+ textHeight += buffer;
304
+ }
305
+ }
306
+ // Add public key if exists
307
+ if (qr.publicMasterKey) {
308
+ const text = 'Key Id: ' + qr.publicMasterKey;
309
+ // Gray bar
310
+ y = moveDown(y, 20);
311
+ textHeight += 20;
312
+ doc.setFillColor(247, 249, 249); // Gray background
313
+ doc.setDrawColor(0, 0, 0); // Border
314
+ // Leave a bit of space for the side of the rectangle.
315
+ const splitKeyId = doc.splitTextToSize(text, width - 10);
316
+ // The height of the box must be at least 15 px (for single line case), or
317
+ // a multiple of 13 for each line. This allows for proper padding.
318
+ doc.rect(textLeft, y, width, Math.max(12 * splitKeyId.length, 15), 'FD');
319
+ textHeight += splitKeyId.length * doc.getLineHeight();
320
+ doc.text(splitKeyId, textLeft + 5, y + 10);
321
+ }
322
+ doc.setFont('helvetica');
323
+ // Move down past the taller of the two columns: the right-side text (textHeight) or the
324
+ // left-side QR column (plus the note printed under it for split keys), then add a margin.
325
+ const qrColumnHeight = isMultiPart ? qrColumnBottom - topY : qrSize;
326
+ const rowHeight = Math.max(qrColumnHeight, textHeight);
327
+ const marginBottom = 15;
328
+ y = moveDown(y, rowHeight - (y - topY) + marginBottom);
329
+ }
330
+ // Add next Page
331
+ doc.addPage();
332
+ // next pages title
333
+ y = 0;
334
+ y = moveDown(y, 55);
335
+ doc.setFontSize(font.header).setTextColor(color.black);
336
+ doc.text('BitGo KeyCard FAQ', left(0), y);
337
+ // Generate the second page's data for the backup PDF
338
+ y = moveDown(y, 30);
339
+ questions.forEach(function (q) {
340
+ doc.setFontSize(font.subheader).setTextColor(color.black);
341
+ doc.text(q.question, left(0), y);
342
+ y = moveDown(y, 20);
343
+ doc.setFontSize(font.body).setTextColor(color.darkgray);
344
+ q.answer.forEach(function (line) {
345
+ doc.text(line, left(0), y);
346
+ y = moveDown(y, font.body + 3);
347
+ });
348
+ y = moveDown(y, 22);
349
+ });
350
+ return doc;
351
+ }
352
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHJhd0tleWNhcmQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZHJhd0tleWNhcmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBb0pBLGtDQStOQztBQWxYRCwrQ0FBaUM7QUFFakMsbUNBQW9DO0FBR3BDLE1BQU0sTUFBTSxHQUFHLE9BQU8sTUFBTSxLQUFLLFdBQVcsSUFBSSxPQUFPLE1BQU0sQ0FBQyxRQUFRLEtBQUssV0FBVyxDQUFDO0FBRXZGLEtBQUssVUFBVSxTQUFTO0lBQ3RCLElBQUksS0FBa0IsQ0FBQztJQUV2QixJQUFJLE9BQU8sTUFBTSxLQUFLLFdBQVcsSUFBSSxPQUFPLE1BQU0sQ0FBQyxRQUFRLEtBQUssV0FBVyxFQUFFLENBQUM7UUFDNUUsd0JBQXdCO1FBQ3hCLEtBQUssR0FBRyx3REFBYSxPQUFPLEdBQUMsQ0FBQztJQUNoQyxDQUFDO1NBQU0sQ0FBQztRQUNOLG9CQUFvQjtRQUNwQixLQUFLLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRCxJQUFLLFlBSUo7QUFKRCxXQUFLLFlBQVk7SUFDZixpQ0FBaUIsQ0FBQTtJQUNqQixtQ0FBbUIsQ0FBQTtJQUNuQiwyQkFBVyxDQUFBO0FBQ2IsQ0FBQyxFQUpJLFlBQVksS0FBWixZQUFZLFFBSWhCO0FBRUQsbUZBQW1GO0FBQ25GLG9IQUFvSDtBQUNwSCxxREFBcUQ7QUFDckQsZ0RBQWdEO0FBQ25DLFFBQUEsaUJBQWlCLEdBQUcsSUFBSSxDQUFDO0FBRXRDLHlGQUF5RjtBQUN6RixrR0FBa0c7QUFDbEcsTUFBTSwwQkFBMEIsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBRXZDLE1BQU0sSUFBSSxHQUFHO0lBQ1gsTUFBTSxFQUFFLEVBQUU7SUFDVixTQUFTLEVBQUUsRUFBRTtJQUNiLElBQUksRUFB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QUFXLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDMUQsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNqQyxDQUFDLEdBQUcsUUFBUSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNwQixHQUFHLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3hELENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsSUFBSTtZQUM3QixHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDM0IsQ0FBQyxHQUFHLFFBQVEsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNqQyxDQUFDLENBQUMsQ0FBQztRQUNILENBQUMsR0FBRyxRQUFRLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3RCLENBQUMsQ0FBQyxDQUFDO0lBRUgsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBqc1BERiB9IGZyb20gJ2pzcGRmJztcbmltcG9ydCAqIGFzIFFSQ29kZSBmcm9tICdxcmNvZGUnO1xuaW1wb3J0IHsgSURyYXdLZXlDYXJkIH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBzcGxpdEtleXMgfSBmcm9tICcuL3V0aWxzJztcbnR5cGUganNQREZNb2R1bGUgPSB0eXBlb2YgaW1wb3J0KCdqc3BkZicpO1xuXG5jb25zdCBpc05vZGUgPSB0eXBlb2Ygd2luZG93ID09PSAndW5kZWZpbmVkJyB8fCB0eXBlb2Ygd2luZG93LmRvY3VtZW50ID09PSAndW5kZWZpbmVkJztcblxuYXN5bmMgZnVuY3Rpb24gbG9hZEpTUERGKCk6IFByb21pc2U8anNQREZNb2R1bGU+IHtcbiAgbGV0IGpzUERGOiBqc1BERk1vZHVsZTtcblxuICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIHdpbmRvdy5kb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAvLyBXZSBhcmUgaW4gdGhlIGJyb3dzZXJcbiAgICBqc1BERiA9IGF3YWl0IGltcG9ydCgnanNwZGYnKTtcbiAgfSBlbHNlIHtcbiAgICAvLyBXZSBhcmUgaW4gTm9kZS5qc1xuICAgIGpzUERGID0gcmVxdWlyZSgnanNwZGYnKTtcbiAgfVxuICByZXR1cm4ganNQREY7XG59XG5cbmVudW0gS2V5Q3VydmVOYW1lIHtcbiAgZWQyNTUxOSA9ICdFRERTQScsXG4gIHNlY3AyNTZrMSA9ICdFQ0RTQScsXG4gIGJscyA9ICdCTFMnLFxufVxuXG4vLyBNYXggZm9yIEJpbmFyeS9CeXRlIERhdGEgaHR0cHM6Ly9naXRodWIuY29tL3NvbGRhaXIvbm9kZS1xcmNvZGUjcXItY29kZS1jYXBhY2l0eVxuLy8gdGhlIGxhcmdlc3QgdGhlb3JldGljYWxseSBwb3NzaWJsZSB2YWx1ZSBpcyBhY3R1YWxseSAyOTUzIGJ1dCB0aGUgUVIgY29kZXMgZ2V0IHNvIGRlbnNlIHRoYXQgc2Nhbm5pbmcgdGhlbSB3aXRoIGFcbi8vIHBob25lIChvZmYgb2YgYSBwcmludGVkIHBhZ2UpIGRvZXNuJ3Qgd29yayBhbnltb3JlXG4vLyB0aGlzIGxpbWl0YXRpb24gd2FzIGNob3NlbiBieSB0cmlhbCBhbmQgZXJyb3JcbmV4cG9ydCBjb25zdCBRUkJpbmFyeU1heExlbmd0aCA9IDE1MDA7XG5cbi8vIERlZmF1bHQgcGFnZS1icmVhayBsYXlvdXQ6IHN0YXJ0IGEgbmV3IHBhZ2UgYmVmb3JlIHRoZSAzcmQgYm94IChpbmRleCAyKSwgbWF0Y2hpbmcgdGhlXG4vLyBoaXN0b3JpY2FsIHdhbGxldCBrZXljYXJkLiBDYWxsZXJzIChlLmcuIHRoZSBzYWZlIGtleWNhcmQpIG1heSBvdmVycmlkZSB3aXRoIHRoZWlyIG93biBpbmRpY2VzLlxuY29uc3QgREVGQVVMVF9QQUdFX0JSRUFLX0lORElDRVMgPSBbMl07XG5cbmNvbnN0IGZvbnQgPSB7XG4gIGhlYWRlcjogMjQsXG4gIHN1YmhlYWRlcjogMTUsXG4gIGJvZHk6IDEyLFxufTtcblxuY29uc3QgY29sb3IgPSB7XG4gIGJsYWNrOiAnIzAwMDAwMCcsXG4gIGRhcmtncmF5OiAnIzRjNGM0YycsXG4gIGdyYXk6ICcjOWI5YjliJyxcbiAgcmVkOiAnI2UyMWUxZScsXG59O1xuXG5jb25zdCBtYXJnaW4gPSAzMDtcblxuLy8gSGVscGVycyBmb3IgZGF0YSBmb3JtYXR0aW5nIC8gcG9zaXRpb25pbmcgb24gdGhlIHBhcGVyXG5mdW5jdGlvbiBsZWZ0KHg6IG51bWJlcik6IG51bWJlciB7XG4gIHJldHVybiBtYXJnaW4gKyB4O1xufVxuZnVuY3Rpb24gbW92ZURvd24oeTogbnVtYmVyLCB5ZGVsdGE6IG51bWJlcik6IG51bWJlciB7XG4gIHJldHVybiB5ICsgeWRlbHRhO1xufVxuXG4vKipcbiAqIFByZWZpeGVzIG9uZSBmcmFnbWVudCBvZiBhIHNwbGl0IGtleSB3aXRoIGEgcGFydCBoZWFkZXIgc28gYSBRUiBzY2FubmVyIGNhbiByZWFzc2VtYmxlIHRoZVxuICogZnJhZ21lbnRzIHdpdGhvdXQgcmVseWluZyBvbiBzY2FuIG9yZGVyLlxuICpcbiAqIFdoZW4gYSBrZXkgYm94J3MgcGF5bG9hZCBleGNlZWRzIHtAbGluayBRUkJpbmFyeU1heExlbmd0aH0sIHtAbGluayBzcGxpdEtleXN9IGRpdmlkZXMgaXQgaW50b1xuICogbXVsdGlwbGUgUVIgY29kZXMuIEVhY2ggZnJhZ21lbnQncyBRUiBwYXlsb2FkIGlzIGVuY29kZWQgYXMgYSAxLWJhc2VkIHBhcnQgaGVhZGVyIGZvbGxvd2VkIGJ5XG4gKiB0aGUgZnJhZ21lbnQ6XG4gKlxuICogICAgIFwiPGluZGV4Pi88dG90YWw+fDxmcmFnbWVudD5cIiAgICAgIGUuZy4gIFwiMS8zfDxjaHVuaz5cIiwgXCIyLzN8PGNodW5rPlwiLCBcIjMvM3w8Y2h1bms+XCJcbiAqXG4gKiBBIHNpbmdsZS1mcmFnbWVudCBwYXlsb2FkIGlzIHJldHVybmVkIHVuY2hhbmdlZCAobm8gaGVhZGVyKS5cbiAqXG4gKiBSZWFzc2VtYmx5IGNvbnRyYWN0IGZvciBhIGNvbnN1bWVyIChlLmcuIGEgZnV0dXJlIHJlY292ZXJ5L3NjYW4gdG9vbCk6XG4gKiAgIDEuIFNjYW4gZXZlcnkgUVIgY29kZSBmb3IgYSBib3guXG4gKiAgIDIuIFNwbGl0IGVhY2ggcGF5bG9hZCBvbiB0aGUgRklSU1QgXCJ8XCI6IHRoZSBsZWZ0IHNpZGUgaXMgXCI8aW5kZXg+Lzx0b3RhbD5cIiwgdGhlIHJpZ2h0IHNpZGVcbiAqICAgICAgaXMgdGhlIGZyYWdtZW50LlxuICogICAzLiBWZXJpZnkgcGFydHMgMS4udG90YWwgYXJlIGFsbCBwcmVzZW50ICh0b3RhbCBpcyBpZGVudGljYWwgaW4gZXZlcnkgaGVhZGVyKS5cbiAqICAgNC4gQ29uY2F0ZW5hdGUgdGhlIGZyYWdtZW50cyBpbiBhc2NlbmRpbmcgaW5kZXggb3JkZXIgdG8gcmVjb3ZlciB0aGUgZnVsbCBib3ggcGF5bG9hZC5cbiAqICAgNS4gUGFyc2UvZGVjcnlwdCBhcyB1c3VhbCAoZm9yIGEgc2FmZSBib3g6IEpTT04ucGFyc2UsIHRoZW4gZGVjcnlwdCBlYWNoIHJvb3QgdmFsdWUpLlxuICpcbiAqIE5vdGVzOlxuICogICAtIFRoZSBcInxcIiBkZWxpbWl0ZXIgaXMgc2FmZTogYmFzZTY0IGNpcGhlcnRleHQsIEpTT04sIGFuZCBiYXNlNTggeHB1YnMgbmV2ZXIgY29udGFpbiBpdC5cbiAqICAgLSBUaGlzIGhlYWRlciBleGlzdHMgT05MWSBpbnNpZGUgdGhlIFFSIGltYWdlLiBUaGUgaHVtYW4tcmVhZGFibGUgXCJEYXRhOlwiIHRleHQgcHJpbnRlZCBvblxuICogICAgIHRoZSBjYXJkIGlzIHRoZSBmdWxsLCB1bmhlYWRlcmVkIHBheWxvYWQ7IHRoZSBQREYtdGV4dCBwYXJzZXIgcmVhZHMgdGhhdCwgc28gdGhpcyBoZWFkZXJcbiAqICAgICBkb2VzIG5vdCBhZmZlY3QgUERGLWJhc2VkIHJlY292ZXJ5LlxuICovXG5mdW5jdGlvbiBlbmNvZGVRckNvZGVQYXJ0KGZyYWdtZW50OiBzdHJpbmcsIGluZGV4OiBudW1iZXIsIHRvdGFsOiBudW1iZXIpOiBzdHJpbmcge1xuICByZXR1cm4gdG90YWwgPiAxID8gYCR7aW5kZXggKyAxfS8ke3RvdGFsfXwke2ZyYWdtZW50fWAgOiBmcmFnbWVudDtcbn1cblxuLy8gRHJhd3MgUVIgY29kZXMgZG93biB0aGUgbGVmdCBjb2x1bW4sIHJldHVybmluZyB0aGUgaW5kZXggb2YgdGhlIG5leHQgUVIgc3RpbGwgdG8gZHJhdyAoZm9yXG4vLyBjb250aW51YXRpb24gb24gYSBsYXRlciBwYWdlKSBhbmQgdGhlIHktb2Zmc2V0IGp1c3QgYmVsb3cgdGhlIGRyYXduIFFSIGNvbHVtbiAoc28gY2FsbGVyc1xuLy8gY2FuIHBsYWNlIGNvbnRlbnQsIGUuZy4gYSBub3RlLCB1bmRlciB0aGUgUVIgY29kZXMpLlxuZnVuY3Rpb24gZHJhd09uZVBhZ2VPZlFyQ29kZXMoXG4gIHFySW1hZ2VzOiAoSFRNTENhbnZhc0VsZW1lbnQgfCBzdHJpbmcpW10sXG4gIGRvYzoganNQREYsXG4gIHk6IG51bWJlcixcbiAgcXJTaXplOiBudW1iZXIsXG4gIHN0YXJ0SW5kZXg6IG51bWJlclxuKTogeyBuZXh0SW5kZXg6IG51bWJlcjsgZW5kWTogbnVtYmVyIH0ge1xuICBkb2Muc2V0Rm9udCgnaGVsdmV0aWNhJyk7XG4gIGxldCBxckluZGV4OiBudW1iZXIgPSBzdGFydEluZGV4O1xuICBmb3IgKDsgcXJJbmRleCA8IHFySW1hZ2VzLmxlbmd0aDsgcXJJbmRleCsrKSB7XG4gICAgY29uc3QgaW1hZ2UgPSBxckltYWdlc1txckluZGV4XTtcbiAgICBjb25zdCB0ZXh0QnVmZmVyID0gMTU7XG4gICAgaWYgKHkgKyBxclNpemUgKyB0ZXh0QnVmZmVyID49IGRvYy5pbnRlcm5hbC5wYWdlU2l6ZS5nZXRIZWlnaHQoKSkge1xuICAgICAgcmV0dXJuIHsgbmV4dEluZGV4OiBxckluZGV4LCBlbmRZOiB5IH07XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBpbWFnZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGRvYy5hZGRJbWFnZShpbWFnZSwgJ1BORycsIGxlZnQoMCksIHksIHFyU2l6ZSwgcXJTaXplKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZG9jLmFkZEltYWdlKGltYWdlLCBsZWZ0KDApLCB5LCBxclNpemUsIHFyU2l6ZSk7XG4gICAgfVxuXG4gICAgaWYgKHFySW1hZ2VzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgcmV0dXJuIHsgbmV4dEluZGV4OiBxckluZGV4ICsgMSwgZW5kWTogeSArIHFyU2l6ZSB9O1xuICAgIH1cblxuICAgIHkgPSBtb3ZlRG93bih5LCBxclNpemUgKyB0ZXh0QnVmZmVyKTtcbiAgICBkb2Muc2V0Rm9udFNpemUoZm9udC5ib2R5KS5zZXRUZXh0Q29sb3IoY29sb3IuYmxhY2spO1xuICAgIGRvYy50ZXh0KCdQYXJ0ICcgKyAocXJJbmRleCArIDEpLnRvU3RyaW5nKCksIGxlZnQoMCksIHkpO1xuICAgIHkgPSBtb3ZlRG93bih5LCAyMCk7XG4gIH1cbiAgcmV0dXJuIHsgbmV4dEluZGV4OiBxckluZGV4LCBlbmRZOiB5IH07XG59XG5cbmZ1bmN0aW9uIGNvbXB1dGVLZXlDYXJkSW1hZ2VEaW1lbnNpb25zKGtleUNhcmRJbWFnZTogSFRNTEltYWdlRWxlbWVudCkge1xuICAvLyBNYXggZGltZW5zaW9ucyBzdGFibGlzaGVkIGJ5IGZpeGVkIGF2YWlsYWJsZSBQREYgc3BhY2VcbiAgY29uc3QgS0VZX0NBUkRfSU1BR0VfTUFYX0RJTUVOU0lPTlMgPSB7XG4gICAgd2lkdGg6IDMwMyxcbiAgICBoZWlnaHQ6IDQwLFxuICB9O1xuXG4gIGNvbnN0IHsgd2lkdGg6IGltZ1dpZHRoLCBoZWlnaHQ6IGltZ0hlaWdodCB9ID0ga2V5Q2FyZEltYWdlO1xuICBjb25zdCB7IHdpZHRoOiBtYXhXaWR0aCwgaGVpZ2h0OiBtYXhIZWlnaHQgfSA9IEtFWV9DQVJEX0lNQUdFX01BWF9ESU1FTlNJT05TO1xuXG4gIC8vIFRyeSBzY2FsaW5nIHJhdGlvIGJhc2VkIG9uIHdpZHRoXG4gIGNvbnN0IHdSYXRpbyA9IGltZ1dpZHRoIC8gbWF4V2lkdGg7XG4gIGxldCBmaW5hbFJhdGlvID0gd1JhdGlvO1xuXG4gIC8vIElmIHJlc2l6ZWQgaGVpZ2h0IGV4Y2VlZHMgdGhlIGF2YWlsYWJsZSBoZWlnaHQgc3BhY2UsIGJhc2UgcmF0aW8gYWxzbyBvbiBoZWlnaHRcbiAgaWYgKGltZ0hlaWdodCAvIGZpbmFsUmF0aW8gPiBtYXhIZWlnaHQpIHtcbiAgICBmaW5hbFJhdGlvID0gaW1nSGVpZ2h0IC8gbWF4SGVpZ2h0O1xuICB9XG4gIHJldHVybiBbaW1nV2lkdGggLyBmaW5hbFJhdGlvLCBpbWdIZWlnaHQgLyBmaW5hbFJhdGlvXTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGRyYXdLZXljYXJkKHtcbiAgYWN0aXZhdGlvbkNvZGUsXG4gIHF1ZXN0aW9ucyxcbiAga2V5Q2FyZEltYWdlLFxuICBxckRhdGEsXG4gIHdhbGxldExhYmVsLFxuICBjdXJ2ZSxcbiAgcGFnZUJyZWFrQmVmb3JlSW5kaWNlcyA9IERFRkFVTFRfUEFHRV9CUkVBS19JTkRJQ0VTLFxuICB1c2VRclBhcnRIZWFkZXJzID0gZmFsc2UsXG59OiBJRHJhd0tleUNhcmQpOiBQcm9taXNlPGpzUERGPiB7XG4gIGNvbnN0IGpzUERGTW9kdWxlID0gYXdhaXQgbG9hZEpTUERGKCk7XG5cbiAgLy8gZG9jdW1lbnQgZGV0YWlsc1xuICBjb25zdCB3aWR0aCA9IDguNSAqIDcyO1xuICBsZXQgeSA9IDA7XG5cbiAgLy8gQ3JlYXRlIHRoZSBQREYgaW5zdGFuY2VcbiAgY29uc3QgZG9jID0gbmV3IGpzUERGTW9kdWxlLmpzUERGKCdwb3J0cmFpdCcsICdwdCcsICdsZXR0ZXInKTsgLy8ganNoaW50IGlnbm9yZTpsaW5lXG4gIGRvYy5zZXRGb250KCdoZWx2ZXRpY2EnKTtcblxuICAvLyBQREYgSGVhZGVyIEFyZWEgLSBpbmNsdWRlcyB0aGUgbG9nbyBhbmQgY29tcGFueSBuYW1lXG4gIC8vIFRoaXMgaXMgZGF0YSBmb3IgdGhlIEJpdEdvIGxvZ28gaW4gdGhlIHRvcCBsZWZ0IG9mIHRoZSBQREZcbiAgeSA9IG1vdmVEb3duKHksIDMwKTtcblxuICBpZiAoa2V5Q2FyZEltYWdlKSB7XG4gICAgY29uc3QgW2ltZ1dpZHRoLCBpbWdIZWlnaHRdID0gY29tcHV0ZUtleUNhcmRJbWFnZURpbWVuc2lvbnMoa2V5Q2FyZEltYWdlKTtcbiAgICBpZiAoaXNOb2RlKSB7XG4gICAgICAvLyBJbiBOb2RlLmpzLCBqc1BERiBjYW5ub3QgZXh0cmFjdCBwaXhlbHMgZnJvbSBhbiBIVE1MSW1hZ2VFbGVtZW50IChubyBET00vY2FudmFzKS5cbiAgICAgIC8vIFRoZSBzY3JpcHQgcGFzc2VzIGEgZHVjay10eXBlZCBvYmplY3Qgd2hvc2UgLnNyYyBpcyBhIGJhc2U2NCBkYXRhIFVSTCDigJQgdXNlIGl0IGRpcmVjdGx5LlxuICAgICAgZG9jLmFkZEltYWdlKChrZXlDYXJkSW1hZ2UgYXMgdW5rbm93biBhcyB7IHNyYzogc3RyaW5nIH0pLnNyYywgJ1BORycsIGxlZnQoMCksIHksIGltZ1dpZHRoLCBpbWdIZWlnaHQpO1xuICAgIH0gZWxzZSB7XG4gICAgICBkb2MuYWRkSW1hZ2Uoa2V5Q2FyZEltYWdlLCBsZWZ0KDApLCB5LCBpbWdXaWR0aCwgaW1nSGVpZ2h0KTtcbiAgICB9XG4gIH1cblxuICAvLyBBY3RpdmF0aW9uIENvZGVcbiAgaWYgKGFjdGl2YXRpb25Db2RlKSB7XG4gICAgeSA9IG1vdmVEb3duKHksIDgpO1xuICAgIGRvYy5zZXRGb250U2l6ZShmb250LmJvZHkpLnNldFRleHRDb2xvcihjb2xvci5ncmF5KTtcbiAgICBkb2MudGV4dCgnQWN0aXZhdGlvbiBDb2RlJywgbGVmdCg0NjApLCB5KTtcbiAgfVxuICBkb2Muc2V0Rm9udFNpemUoZm9udC5oZWFkZXIpLnNldFRleHRDb2xvcihjb2xvci5ibGFjayk7XG4gIHkgPSBtb3ZlRG93bih5LCAyNSk7XG4gIGRvYy50ZXh0KCdLZXlDYXJkJywgbGVmdChjdXJ2ZSAmJiAhYWN0aXZhdGlvbkNvZGUgPyA0NjAgOiAzMjUpLCB5IC0gMSk7XG4gIGlmIChhY3RpdmF0aW9uQ29kZSkge1xuICAgIGRvYy5zZXRGb250U2l6ZShmb250LmhlYWRlcikuc2V0VGV4dENvbG9yKGNvbG9yLmdyYXkpO1xuICAgIGRvYy50ZXh0KGFjdGl2YXRpb25Db2RlLCBsZWZ0KDQ2MCksIHkpO1xuICB9XG5cbiAgLy8gU3ViaGVhZGVyXG4gIC8vIHRpdGxlc1xuICBjb25zdCBkYXRlID0gbmV3IERhdGUoKS50b0RhdGVTdHJpbmcoKTtcbiAgeSA9IG1vdmVEb3duKHksIG1hcmdpbik7XG4gIGRvYy5zZXRGb250U2l6ZShmb250LmJvZHkpLnNldFRleHRDb2xvcihjb2xvci5ncmF5KTtcblxuICBpZiAoY3VydmUgfHwgd2FsbGV0TGFiZWwpIHtcbiAgICBjb25zdCB0aXRsZSA9IGN1cnZlID8gS2V5Q3VydmVOYW1lW2N1cnZlXSArICcga2V5OicgOiAnd2FsbGV0IG5hbWVkOic7XG4gICAgZG9jLnRleHQoJ0NyZWF0ZWQgb24gJyArIGRhdGUgKyAnIGZvciAnICsgdGl0bGUsIGxlZnQoMCksIHkpO1xuICAgIC8vIGNvcHlcbiAgICB5ID0gbW92ZURvd24oeSwgMjUpO1xuICAgIGlmICh3YWxsZXRMYWJlbCkge1xuICAgICAgZG9jLnNldEZvbnRTaXplKGZvbnQuc3ViaGVhZGVyKS5zZXRUZXh0Q29sb3IoY29sb3IuYmxhY2spO1xuICAgICAgZG9jLnRleHQod2FsbGV0TGFiZWwsIGxlZnQoMCksIHkpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBkb2MudGV4dCgnQ3JlYXRlZCBvbiAnICsgZGF0ZSwgbGVmdCgwKSwgeSk7XG4gICAgeSA9IG1vdmVEb3duKHksIDI1KTtcbiAgfVxuICBpZiAoIWN1cnZlKSB7XG4gICAgLy8gUmVkIEJhclxuICAgIHkgPSBtb3ZlRG93bih5LCAyMCk7XG4gICAgZG9jLnNldEZpbGxDb2xvcigyNTUsIDIzMCwgMjMwKTtcbiAgICBkb2MucmVjdChsZWZ0KDApLCB5LCB3aWR0aCAtIDIgKiBtYXJnaW4sIDMyLCAnRicpO1xuXG4gICAgLy8gd2FybmluZyBtZXNzYWdlXG4gICAgeSA9IG1vdmVEb3duKHksIDIwKTtcbiAgICBkb2Muc2V0Rm9udFNpemUoZm9udC5ib2R5KS5zZXRUZXh0Q29sb3IoY29sb3IucmVkKTtcbiAgICBkb2MudGV4dCgnUHJpbnQgdGhpcyBkb2N1bWVudCwgb3Iga2VlcCBpdCBzZWN1cmVseSBvZmZsaW5lLiBTZWUgYmVsb3cgZm9yIEZBUS4nLCBsZWZ0KDc1KSwgeSk7XG4gIH1cbiAgLy8gR2VuZXJhdGUgdGhlIGZpcnN0IHBhZ2UncyBkYXRhIGZvciB0aGUgYmFja3VwIFBERlxuICB5ID0gbW92ZURvd24oeSwgMzUpO1xuICBjb25zdCBxclNpemUgPSAxMzA7XG4gIGNvbnN0IHFyS2V5cyA9IFsndXNlcicsICd1c2VyTWFzdGVyUHVibGljS2V5JywgJ2JhY2t1cCcsICdiYWNrdXBNYXN0ZXJQdWJsaWNLZXknLCAnYml0Z28nLCAncGFzc2NvZGUnXS5maWx0ZXIoXG4gICAgKGtleSkgPT4gISFxckRhdGFba2V5XVxuICApO1xuICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgcXJLZXlzLmxlbmd0aDsgaW5kZXgrKykge1xuICAgIGNvbnN0IG5hbWUgPSBxcktleXNbaW5kZXhdO1xuXG4gICAgaWYgKHBhZ2VCcmVha0JlZm9yZUluZGljZXMuaW5jbHVkZXMoaW5kZXgpKSB7XG4gICAgICAvLyBTdGFydCBhIG5ldyBwYWdlIGZvciB0aGlzIGJveFxuICAgICAgZG9jLmFkZFBhZ2UoKTtcblxuICAgICAgLy8gMm5kIHBhZ2UgdGl0bGVcbiAgICAgIHkgPSAzMDtcbiAgICB9XG5cbiAgICBjb25zdCBxciA9IHFyRGF0YVtuYW1lXTtcbiAgICBsZXQgdG9wWSA9IHk7XG4gICAgY29uc3QgdGV4dExlZnQgPSBsZWZ0KHFyU2l6ZSArIDE1KTtcbiAgICBsZXQgdGV4dEhlaWdodCA9IDA7XG5cbiAgICBjb25zdCBxckltYWdlczogKEhUTUxDYW52YXNFbGVtZW50IHwgc3RyaW5nKVtdID0gW107XG4gICAgY29uc3Qga2V5cyA9IHNwbGl0S2V5cyhxci5kYXRhLCBRUkJpbmFyeU1heExlbmd0aCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBwYXlsb2FkID0gdXNlUXJQYXJ0SGVhZGVycyA/IGVuY29kZVFyQ29kZVBhcnQoa2V5c1tpXSwgaSwga2V5cy5sZW5ndGgpIDoga2V5c1tpXTtcbiAgICAgIGlmIChpc05vZGUpIHtcbiAgICAgICAgcXJJbWFnZXMucHVzaChhd2FpdCBRUkNvZGUudG9EYXRhVVJMKHBheWxvYWQsIHsgZXJyb3JDb3JyZWN0aW9uTGV2ZWw6ICdMJyB9KSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBxckltYWdlcy5wdXNoKGF3YWl0IFFSQ29kZS50b0NhbnZhcyhwYXlsb2FkLCB7IGVycm9yQ29ycmVjdGlvbkxldmVsOiAnTCcgfSkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGlzTXVsdGlQYXJ0ID0gcXI/LmRhdGE/Lmxlbmd0aCA+IFFSQmluYXJ5TWF4TGVuZ3RoO1xuICAgIGNvbnN0IHsgbmV4dEluZGV4LCBlbmRZOiBxckNvbHVtbkVuZFkgfSA9IGRyYXdPbmVQYWdlT2ZRckNvZGVzKHFySW1hZ2VzLCBkb2MsIHksIHFyU2l6ZSwgMCk7XG4gICAgbGV0IG5leHRRckluZGV4ID0gbmV4dEluZGV4O1xuXG4gICAgLy8gRm9yIGEgc3BsaXQga2V5LCBwbGFjZSB0aGUgXCJwdXQgYWxsIFBhcnRzIHRvZ2V0aGVyXCIgbm90ZSBkaXJlY3RseSB1bmRlciB0aGUgUVIgY29kZXMsXG4gICAgLy8gd3JhcHBlZCB0byB0aGUgUVIgY29sdW1uIHdpZHRoIHNvIGl0IHN0YXlzIGluIHRoZSBsZWZ0IGNvbHVtbiBhbmQgbmV2ZXIgb3ZlcmxhcHMgdGhlXG4gICAgLy8gRGF0YSBwYXlsb2FkIHJlbmRlcmVkIG9uIHRoZSByaWdodC5cbiAgICBsZXQgcXJDb2x1bW5Cb3R0b20gPSBxckNvbHVtbkVuZFk7XG4gICAgaWYgKGlzTXVsdGlQYXJ0KSB7XG4gICAgICBkb2Muc2V0Rm9udFNpemUoZm9udC5ib2R5IC0gMikuc2V0VGV4dENvbG9yKGNvbG9yLmRhcmtncmF5KTtcbiAgICAgIGNvbnN0IG5vdGVMaW5lcyA9IGRvYy5zcGxpdFRleHRUb1NpemUoJ05vdGU6IHlvdSB3aWxsIG5lZWQgdG8gcHV0IGFsbCBQYXJ0cyB0b2dldGhlciBmb3IgdGhlIGZ1bGwga2V5JywgcXJTaXplKTtcbiAgICAgIGNvbnN0IG5vdGVZID0gbW92ZURvd24ocXJDb2x1bW5FbmRZLCAxNSk7XG4gICAgICBkb2MudGV4dChub3RlTGluZXMsIGxlZnQoMCksIG5vdGVZKTtcbiAgICAgIHFyQ29sdW1uQm90dG9tID0gbm90ZVkgKyBub3RlTGluZXMubGVuZ3RoICogZG9jLmdldExpbmVIZWlnaHQoKTtcbiAgICB9XG5cbiAgICBkb2Muc2V0Rm9udFNpemUoZm9udC5zdWJoZWFkZXIpLnNldFRleHRDb2xvcihjb2xvci5ibGFjayk7XG4gICAgeSA9IG1vdmVEb3duKHksIDEwKTtcbiAgICB0ZXh0SGVpZ2h0ICs9IDEwO1xuICAgIGRvYy50ZXh0KHFyLnRpdGxlLCB0ZXh0TGVmdCwgeSk7XG4gICAgdGV4dEhlaWdodCArPSBkb2MuZ2V0TGluZUhlaWdodCgpO1xuICAgIHkgPSBtb3ZlRG93bih5LCAxNSk7XG4gICAgdGV4dEhlaWdodCArPSAxNTtcbiAgICBkb2Muc2V0Rm9udFNpemUoZm9udC5ib2R5KS5zZXRUZXh0Q29sb3IoY29sb3IuZGFya2dyYXkpO1xuICAgIGRvYy50ZXh0KHFyLmRlc2NyaXB0aW9uLCB0ZXh0TGVmdCwgeSk7XG4gICAgdGV4dEhlaWdodCArPSBkb2MuZ2V0TGluZUhlaWdodCgpO1xuICAgIGRvYy5zZXRGb250U2l6ZShmb250LmJvZHkgLSAyKTtcbiAgICB5ID0gbW92ZURvd24oeSwgMzApO1xuICAgIHRleHRIZWlnaHQgKz0gMzA7XG4gICAgZG9jLnRleHQoJ0RhdGE6JywgdGV4dExlZnQsIHkpO1xuICAgIHRleHRIZWlnaHQgKz0gZG9jLmdldExpbmVIZWlnaHQoKTtcbiAgICB5ID0gbW92ZURvd24oeSwgMTUpO1xuICAgIHRleHRIZWlnaHQgKz0gMTU7XG4gICAgY29uc3Qgd2lkdGggPSA3MiAqIDguNSAtIHRleHRMZWZ0IC0gMzA7XG4gICAgZG9jLnNldEZvbnQoJ2NvdXJpZXInKS5zZXRGb250U2l6ZSg5KS5zZXRUZXh0Q29sb3IoY29sb3IuYmxhY2spO1xuICAgIGNvbnN0IGxpbmVzID0gZG9jLnNwbGl0VGV4dFRvU2l6ZShxci5kYXRhLCB3aWR0aCk7XG4gICAgY29uc3QgYnVmZmVyID0gMTA7XG4gICAgZm9yIChsZXQgbGluZSA9IDA7IGxpbmUgPCBsaW5lcy5sZW5ndGg7IGxpbmUrKykge1xuICAgICAgLy8gYWRkIG5ldyBwYWdlIGlmIGRhdGEgZG9lcyBub3QgZml0IG9uIG9uZSBwYWdlXG4gICAgICBpZiAoeSArIGJ1ZmZlciA+PSBkb2MuaW50ZXJuYWwucGFnZVNpemUuZ2V0SGVpZ2h0KCkpIHtcbiAgICAgICAgZG9jLmFkZFBhZ2UoKTtcbiAgICAgICAgdGV4dEhlaWdodCA9IDA7XG4gICAgICAgIHkgPSAzMDtcbiAgICAgICAgdG9wWSA9IHk7XG4gICAgICAgIC8vIFJlZHJhdyByZW1haW5pbmcgUVJzIG9uIHRoZSBuZXcgcGFnZSBhbmQgdXBkYXRlIHRoZSBjb2x1bW4gYm90dG9tIHRvIFRISVMgcGFnZSwgc29cbiAgICAgICAgLy8gdGhlIHJvd0hlaWdodCBtYXRoIGJlbG93IHN0YXlzIHNhbWUtcGFnZSAoYXZvaWRzIGEgc3RhbGUgcGFnZS0xIGNvb3JkaW5hdGUpLlxuICAgICAgICBjb25zdCBjb250aW51ZWQgPSBkcmF3T25lUGFnZU9mUXJDb2RlcyhxckltYWdlcywgZG9jLCB5LCBxclNpemUsIG5leHRRckluZGV4KTtcbiAgICAgICAgbmV4dFFySW5kZXggPSBjb250aW51ZWQubmV4dEluZGV4O1xuICAgICAgICBxckNvbHVtbkJvdHRvbSA9IGNvbnRpbnVlZC5lbmRZO1xuICAgICAgICBkb2Muc2V0Rm9udCgnY291cmllcicpLnNldEZvbnRTaXplKDkpLnNldFRleHRDb2xvcihjb2xvci5ibGFjayk7XG4gICAgICB9XG4gICAgICBkb2MudGV4dChsaW5lc1tsaW5lXSwgdGV4dExlZnQsIHkpO1xuICAgICAgaWYgKGxpbmUgIT09IGxpbmVzLmxlbmd0aCAtIDEpIHtcbiAgICAgICAgeSA9IG1vdmVEb3duKHksIGJ1ZmZlcik7XG4gICAgICAgIHRleHRIZWlnaHQgKz0gYnVmZmVyO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFkZCBwdWJsaWMga2V5IGlmIGV4aXN0c1xuICAgIGlmIChxci5wdWJsaWNNYXN0ZXJLZXkpIHtcbiAgICAgIGNvbnN0IHRleHQgPSAnS2V5IElkOiAnICsgcXIucHVibGljTWFzdGVyS2V5O1xuXG4gICAgICAvLyBHcmF5IGJhclxuICAgICAgeSA9IG1vdmVEb3duKHksIDIwKTtcbiAgICAgIHRleHRIZWlnaHQgKz0gMjA7XG4gICAgICBkb2Muc2V0RmlsbENvbG9yKDI0NywgMjQ5LCAyNDkpOyAvLyBHcmF5IGJhY2tncm91bmRcbiAgICAgIGRvYy5zZXREcmF3Q29sb3IoMCwgMCwgMCk7IC8vIEJvcmRlclxuXG4gICAgICAvLyBMZWF2ZSBhIGJpdCBvZiBzcGFjZSBmb3IgdGhlIHNpZGUgb2YgdGhlIHJlY3RhbmdsZS5cbiAgICAgIGNvbnN0IHNwbGl0S2V5SWQgPSBkb2Muc3BsaXRUZXh0VG9TaXplKHRleHQsIHdpZHRoIC0gMTApO1xuXG4gICAgICAvLyBUaGUgaGVpZ2h0IG9mIHRoZSBib3ggbXVzdCBiZSBhdCBsZWFzdCAxNSBweCAoZm9yIHNpbmdsZSBsaW5lIGNhc2UpLCBvclxuICAgICAgLy8gYSBtdWx0aXBsZSBvZiAxMyBmb3IgZWFjaCBsaW5lLiAgVGhpcyBhbGxvd3MgZm9yIHByb3BlciBwYWRkaW5nLlxuICAgICAgZG9jLnJlY3QodGV4dExlZnQsIHksIHdpZHRoLCBNYXRoLm1heCgxMiAqIHNwbGl0S2V5SWQubGVuZ3RoLCAxNSksICdGRCcpO1xuICAgICAgdGV4dEhlaWdodCArPSBzcGxpdEtleUlkLmxlbmd0aCAqIGRvYy5nZXRMaW5lSGVpZ2h0KCk7XG4gICAgICBkb2MudGV4dChzcGxpdEtleUlkLCB0ZXh0TGVmdCArIDUsIHkgKyAxMCk7XG4gICAgfVxuXG4gICAgZG9jLnNldEZvbnQoJ2hlbHZldGljYScpO1xuICAgIC8vIE1vdmUgZG93biBwYXN0IHRoZSB0YWxsZXIgb2YgdGhlIHR3byBjb2x1bW5zOiB0aGUgcmlnaHQtc2lkZSB0ZXh0ICh0ZXh0SGVpZ2h0KSBvciB0aGVcbiAgICAvLyBsZWZ0LXNpZGUgUVIgY29sdW1uIChwbHVzIHRoZSBub3RlIHByaW50ZWQgdW5kZXIgaXQgZm9yIHNwbGl0IGtleXMpLCB0aGVuIGFkZCBhIG1hcmdpbi5cbiAgICBjb25zdCBxckNvbHVtbkhlaWdodCA9IGlzTXVsdGlQYXJ0ID8gcXJDb2x1bW5Cb3R0b20gLSB0b3BZIDogcXJTaXplO1xuICAgIGNvbnN0IHJvd0hlaWdodCA9IE1hdGgubWF4KHFyQ29sdW1uSGVpZ2h0LCB0ZXh0SGVpZ2h0KTtcbiAgICBjb25zdCBtYXJnaW5Cb3R0b20gPSAxNTtcbiAgICB5ID0gbW92ZURvd24oeSwgcm93SGVpZ2h0IC0gKHkgLSB0b3BZKSArIG1hcmdpbkJvdHRvbSk7XG4gIH1cblxuICAvLyBBZGQgbmV4dCBQYWdlXG4gIGRvYy5hZGRQYWdlKCk7XG5cbiAgLy8gbmV4dCBwYWdlcyB0aXRsZVxuICB5ID0gMDtcbiAgeSA9IG1vdmVEb3duKHksIDU1KTtcbiAgZG9jLnNldEZvbnRTaXplKGZvbnQuaGVhZGVyKS5zZXRUZXh0Q29sb3IoY29sb3IuYmxhY2spO1xuICBkb2MudGV4dCgnQml0R28gS2V5Q2FyZCBGQVEnLCBsZWZ0KDApLCB5KTtcblxuICAvLyBHZW5lcmF0ZSB0aGUgc2Vjb25kIHBhZ2UncyBkYXRhIGZvciB0aGUgYmFja3VwIFBERlxuICB5ID0gbW92ZURvd24oeSwgMzApO1xuICBxdWVzdGlvbnMuZm9yRWFjaChmdW5jdGlvbiAocSkge1xuICAgIGRvYy5zZXRGb250U2l6ZShmb250LnN1YmhlYWRlcikuc2V0VGV4dENvbG9yKGNvbG9yLmJsYWNrKTtcbiAgICBkb2MudGV4dChxLnF1ZXN0aW9uLCBsZWZ0KDApLCB5KTtcbiAgICB5ID0gbW92ZURvd24oeSwgMjApO1xuICAgIGRvYy5zZXRGb250U2l6ZShmb250LmJvZHkpLnNldFRleHRDb2xvcihjb2xvci5kYXJrZ3JheSk7XG4gICAgcS5hbnN3ZXIuZm9yRWFjaChmdW5jdGlvbiAobGluZSkge1xuICAgICAgZG9jLnRleHQobGluZSwgbGVmdCgwKSwgeSk7XG4gICAgICB5ID0gbW92ZURvd24oeSwgZm9udC5ib2R5ICsgMyk7XG4gICAgfSk7XG4gICAgeSA9IG1vdmVEb3duKHksIDIyKTtcbiAgfSk7XG5cbiAgcmV0dXJuIGRvYztcbn1cbiJdfQ==
@@ -0,0 +1,16 @@
1
+ import { KeycardEntry } from './parseKeycard';
2
+ /**
3
+ * Extracts keycard entries from a PDF file (browser only).
4
+ *
5
+ * Before calling this function, configure the pdfjs worker:
6
+ * import { GlobalWorkerOptions } from 'pdfjs-dist';
7
+ * GlobalWorkerOptions.workerSrc = '<url to pdf.worker.min.js>';
8
+ *
9
+ * pdfjs-dist is loaded via dynamic import so this module can be safely
10
+ * imported in Node.js environments without triggering browser-only globals.
11
+ */
12
+ export declare function extractKeycardEntriesFromPDF(file: File): Promise<{
13
+ lines: string[];
14
+ entries: KeycardEntry[];
15
+ }>;
16
+ //# sourceMappingURL=extractKeycardFromPDF.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractKeycardFromPDF.d.ts","sourceRoot":"","sources":["../../src/extractKeycardFromPDF.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,YAAY,EAAsC,MAAM,gBAAgB,CAAC;AAE1G;;;;;;;;;GASG;AACH,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC;IACtE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC,CAkCD"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.extractKeycardEntriesFromPDF = extractKeycardEntriesFromPDF;
37
+ const parseKeycard_1 = require("./parseKeycard");
38
+ /**
39
+ * Extracts keycard entries from a PDF file (browser only).
40
+ *
41
+ * Before calling this function, configure the pdfjs worker:
42
+ * import { GlobalWorkerOptions } from 'pdfjs-dist';
43
+ * GlobalWorkerOptions.workerSrc = '<url to pdf.worker.min.js>';
44
+ *
45
+ * pdfjs-dist is loaded via dynamic import so this module can be safely
46
+ * imported in Node.js environments without triggering browser-only globals.
47
+ */
48
+ async function extractKeycardEntriesFromPDF(file) {
49
+ const pdfjsLib = await Promise.resolve().then(() => __importStar(require('pdfjs-dist')));
50
+ const arrayBuffer = await file.arrayBuffer();
51
+ const loadingTask = pdfjsLib.getDocument({ data: arrayBuffer });
52
+ const pdfDocument = await loadingTask.promise;
53
+ const nodes = [];
54
+ for (let pageNumber = 1; pageNumber <= pdfDocument.numPages; pageNumber++) {
55
+ const page = await pdfDocument.getPage(pageNumber);
56
+ const textContent = await page.getTextContent();
57
+ for (const item of textContent.items) {
58
+ if (!('str' in item) || !Array.isArray(item.transform)) {
59
+ continue;
60
+ }
61
+ const text = item.str.replace(/\s+/g, ' ').trim();
62
+ if (!text) {
63
+ continue;
64
+ }
65
+ const x = Number(item.transform[4] ?? 0);
66
+ const y = Number(item.transform[5] ?? 0);
67
+ const width = 'width' in item ? Number(item.width ?? 0) : 0;
68
+ nodes.push({ text, x, y, page: pageNumber, width });
69
+ }
70
+ }
71
+ const lines = (0, parseKeycard_1.buildLinesFromPDFNodes)(nodes);
72
+ return {
73
+ lines,
74
+ entries: (0, parseKeycard_1.parseKeycardFromLines)(lines),
75
+ };
76
+ }
77
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXh0cmFjdEtleWNhcmRGcm9tUERGLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2V4dHJhY3RLZXljYXJkRnJvbVBERi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQVlBLG9FQXFDQztBQWpERCxpREFBMEc7QUFFMUc7Ozs7Ozs7OztHQVNHO0FBQ0ksS0FBSyxVQUFVLDRCQUE0QixDQUFDLElBQVU7SUFJM0QsTUFBTSxRQUFRLEdBQUcsd0RBQWEsWUFBWSxHQUFDLENBQUM7SUFDNUMsTUFBTSxXQUFXLEdBQUcsTUFBTSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDN0MsTUFBTSxXQUFXLEdBQUcsUUFBUSxDQUFDLFdBQVcsQ0FBQyxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO0lBQ2hFLE1BQU0sV0FBVyxHQUFHLE1BQU0sV0FBVyxDQUFDLE9BQU8sQ0FBQztJQUM5QyxNQUFNLEtBQUssR0FBa0IsRUFBRSxDQUFDO0lBRWhDLEtBQUssSUFBSSxVQUFVLEdBQUcsQ0FBQyxFQUFFLFVBQVUsSUFBSSxXQUFXLENBQUMsUUFBUSxFQUFFLFVBQVUsRUFBRSxFQUFFLENBQUM7UUFDMUUsTUFBTSxJQUFJLEdBQUcsTUFBTSxXQUFXLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ25ELE1BQU0sV0FBVyxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBRWhELEtBQUssTUFBTSxJQUFJLElBQUksV0FBVyxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ3JDLElBQUksQ0FBQyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7Z0JBQ3ZELFNBQVM7WUFDWCxDQUFDO1lBRUQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2xELElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztnQkFDVixTQUFTO1lBQ1gsQ0FBQztZQUVELE1BQU0sQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3pDLE1BQU0sQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3pDLE1BQU0sS0FBSyxHQUFHLE9BQU8sSUFBSSxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFFNUQsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUN0RCxDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sS0FBSyxHQUFHLElBQUEscUNBQXNCLEVBQUMsS0FBSyxDQUFDLENBQUM7SUFDNUMsT0FBTztRQUNMLEtBQUs7UUFDTCxPQUFPLEVBQUUsSUFBQSxvQ0FBcUIsRUFBQyxLQUFLLENBQUM7S0FDdEMsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBidWlsZExpbmVzRnJvbVBERk5vZGVzLCBLZXljYXJkRW50cnksIHBhcnNlS2V5Y2FyZEZyb21MaW5lcywgUERGVGV4dE5vZGUgfSBmcm9tICcuL3BhcnNlS2V5Y2FyZCc7XG5cbi8qKlxuICogRXh0cmFjdHMga2V5Y2FyZCBlbnRyaWVzIGZyb20gYSBQREYgZmlsZSAoYnJvd3NlciBvbmx5KS5cbiAqXG4gKiBCZWZvcmUgY2FsbGluZyB0aGlzIGZ1bmN0aW9uLCBjb25maWd1cmUgdGhlIHBkZmpzIHdvcmtlcjpcbiAqICAgaW1wb3J0IHsgR2xvYmFsV29ya2VyT3B0aW9ucyB9IGZyb20gJ3BkZmpzLWRpc3QnO1xuICogICBHbG9iYWxXb3JrZXJPcHRpb25zLndvcmtlclNyYyA9ICc8dXJsIHRvIHBkZi53b3JrZXIubWluLmpzPic7XG4gKlxuICogcGRmanMtZGlzdCBpcyBsb2FkZWQgdmlhIGR5bmFtaWMgaW1wb3J0IHNvIHRoaXMgbW9kdWxlIGNhbiBiZSBzYWZlbHlcbiAqIGltcG9ydGVkIGluIE5vZGUuanMgZW52aXJvbm1lbnRzIHdpdGhvdXQgdHJpZ2dlcmluZyBicm93c2VyLW9ubHkgZ2xvYmFscy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RLZXljYXJkRW50cmllc0Zyb21QREYoZmlsZTogRmlsZSk6IFByb21pc2U8e1xuICBsaW5lczogc3RyaW5nW107XG4gIGVudHJpZXM6IEtleWNhcmRFbnRyeVtdO1xufT4ge1xuICBjb25zdCBwZGZqc0xpYiA9IGF3YWl0IGltcG9ydCgncGRmanMtZGlzdCcpO1xuICBjb25zdCBhcnJheUJ1ZmZlciA9IGF3YWl0IGZpbGUuYXJyYXlCdWZmZXIoKTtcbiAgY29uc3QgbG9hZGluZ1Rhc2sgPSBwZGZqc0xpYi5nZXREb2N1bWVudCh7IGRhdGE6IGFycmF5QnVmZmVyIH0pO1xuICBjb25zdCBwZGZEb2N1bWVudCA9IGF3YWl0IGxvYWRpbmdUYXNrLnByb21pc2U7XG4gIGNvbnN0IG5vZGVzOiBQREZUZXh0Tm9kZVtdID0gW107XG5cbiAgZm9yIChsZXQgcGFnZU51bWJlciA9IDE7IHBhZ2VOdW1iZXIgPD0gcGRmRG9jdW1lbnQubnVtUGFnZXM7IHBhZ2VOdW1iZXIrKykge1xuICAgIGNvbnN0IHBhZ2UgPSBhd2FpdCBwZGZEb2N1bWVudC5nZXRQYWdlKHBhZ2VOdW1iZXIpO1xuICAgIGNvbnN0IHRleHRDb250ZW50ID0gYXdhaXQgcGFnZS5nZXRUZXh0Q29udGVudCgpO1xuXG4gICAgZm9yIChjb25zdCBpdGVtIG9mIHRleHRDb250ZW50Lml0ZW1zKSB7XG4gICAgICBpZiAoISgnc3RyJyBpbiBpdGVtKSB8fCAhQXJyYXkuaXNBcnJheShpdGVtLnRyYW5zZm9ybSkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHRleHQgPSBpdGVtLnN0ci5yZXBsYWNlKC9cXHMrL2csICcgJykudHJpbSgpO1xuICAgICAgaWYgKCF0ZXh0KSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB4ID0gTnVtYmVyKGl0ZW0udHJhbnNmb3JtWzRdID8/IDApO1xuICAgICAgY29uc3QgeSA9IE51bWJlcihpdGVtLnRyYW5zZm9ybVs1XSA/PyAwKTtcbiAgICAgIGNvbnN0IHdpZHRoID0gJ3dpZHRoJyBpbiBpdGVtID8gTnVtYmVyKGl0ZW0ud2lkdGggPz8gMCkgOiAwO1xuXG4gICAgICBub2Rlcy5wdXNoKHsgdGV4dCwgeCwgeSwgcGFnZTogcGFnZU51bWJlciwgd2lkdGggfSk7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgbGluZXMgPSBidWlsZExpbmVzRnJvbVBERk5vZGVzKG5vZGVzKTtcbiAgcmV0dXJuIHtcbiAgICBsaW5lcyxcbiAgICBlbnRyaWVzOiBwYXJzZUtleWNhcmRGcm9tTGluZXMobGluZXMpLFxuICB9O1xufVxuIl19
@@ -0,0 +1,4 @@
1
+ import { FAQ } from './types';
2
+ export declare function generateFaq(coinName: string): FAQ[];
3
+ export declare function generateLightningFaq(coinName: string): FAQ[];
4
+ //# sourceMappingURL=faq.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"faq.d.ts","sourceRoot":"","sources":["../../src/faq.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAE9B,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,EAAE,CAuEnD;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,EAAE,CAY5D"}