@rosen-bridge/abstract-extractor 2.0.1 → 2.0.3-52fc0239

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 (115) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/ergo/AbstractErgoExtractor.d.ts.map +1 -1
  3. package/dist/ergo/AbstractErgoExtractor.js +3 -2
  4. package/dist/ergo/AbstractErgoExtractorAction.d.ts +1 -1
  5. package/dist/ergo/AbstractErgoExtractorAction.d.ts.map +1 -1
  6. package/dist/ergo/AbstractErgoExtractorAction.js +23 -9
  7. package/dist/ergo/AbstractErgoExtractorEntity.js +2 -2
  8. package/dist/ergo/initializable/AbstractInitializableAction.d.ts +1 -1
  9. package/dist/ergo/initializable/AbstractInitializableAction.d.ts.map +1 -1
  10. package/dist/ergo/initializable/AbstractInitializableAction.js +4 -2
  11. package/dist/lib/abstractExtractor.d.ts +25 -0
  12. package/dist/lib/abstractExtractor.d.ts.map +1 -0
  13. package/dist/lib/abstractExtractor.js +3 -0
  14. package/dist/lib/constants.d.ts +4 -0
  15. package/dist/lib/constants.d.ts.map +1 -0
  16. package/dist/lib/constants.js +4 -0
  17. package/dist/lib/ergo/AbstractErgoExtractor.d.ts +80 -0
  18. package/dist/lib/ergo/AbstractErgoExtractor.d.ts.map +1 -0
  19. package/dist/lib/ergo/AbstractErgoExtractor.js +143 -0
  20. package/dist/lib/ergo/AbstractErgoExtractorAction.d.ts +87 -0
  21. package/dist/lib/ergo/AbstractErgoExtractorAction.d.ts.map +1 -0
  22. package/dist/lib/ergo/AbstractErgoExtractorAction.js +222 -0
  23. package/dist/lib/ergo/AbstractErgoExtractorEntity.d.ts +11 -0
  24. package/dist/lib/ergo/AbstractErgoExtractorEntity.d.ts.map +1 -0
  25. package/dist/lib/ergo/AbstractErgoExtractorEntity.js +57 -0
  26. package/dist/lib/ergo/index.d.ts +10 -0
  27. package/dist/lib/ergo/index.d.ts.map +1 -0
  28. package/dist/lib/ergo/index.js +10 -0
  29. package/dist/lib/ergo/initializable/AbstractInitializable.d.ts +48 -0
  30. package/dist/lib/ergo/initializable/AbstractInitializable.d.ts.map +1 -0
  31. package/dist/lib/ergo/initializable/AbstractInitializable.js +163 -0
  32. package/dist/lib/ergo/initializable/AbstractInitializableAction.d.ts +14 -0
  33. package/dist/lib/ergo/initializable/AbstractInitializableAction.d.ts.map +1 -0
  34. package/dist/lib/ergo/initializable/AbstractInitializableAction.js +16 -0
  35. package/dist/lib/ergo/initializable/index.d.ts +3 -0
  36. package/dist/lib/ergo/initializable/index.d.ts.map +1 -0
  37. package/dist/lib/ergo/initializable/index.js +3 -0
  38. package/dist/lib/ergo/interfaces.d.ts +47 -0
  39. package/dist/lib/ergo/interfaces.d.ts.map +1 -0
  40. package/dist/lib/ergo/interfaces.js +8 -0
  41. package/dist/lib/ergo/network/AbstractNetwork.d.ts +26 -0
  42. package/dist/lib/ergo/network/AbstractNetwork.d.ts.map +1 -0
  43. package/dist/lib/ergo/network/AbstractNetwork.js +3 -0
  44. package/dist/lib/ergo/network/ExplorerNetwork.d.ts +74 -0
  45. package/dist/lib/ergo/network/ExplorerNetwork.d.ts.map +1 -0
  46. package/dist/lib/ergo/network/ExplorerNetwork.js +185 -0
  47. package/dist/lib/ergo/network/NodeNetwork.d.ts +60 -0
  48. package/dist/lib/ergo/network/NodeNetwork.d.ts.map +1 -0
  49. package/dist/lib/ergo/network/NodeNetwork.js +131 -0
  50. package/dist/lib/ergo/utils.d.ts +8 -0
  51. package/dist/lib/ergo/utils.d.ts.map +1 -0
  52. package/dist/lib/ergo/utils.js +16 -0
  53. package/dist/lib/index.d.ts +4 -0
  54. package/dist/lib/index.d.ts.map +1 -0
  55. package/dist/lib/index.js +4 -0
  56. package/dist/tests/AbstractErgoExtractor.mock.d.ts +11 -0
  57. package/dist/tests/AbstractErgoExtractor.mock.d.ts.map +1 -0
  58. package/dist/tests/AbstractErgoExtractor.mock.js +13 -0
  59. package/dist/tests/AbstractErgoExtractor.spec.d.ts +2 -0
  60. package/dist/tests/AbstractErgoExtractor.spec.d.ts.map +1 -0
  61. package/dist/tests/AbstractErgoExtractor.spec.js +241 -0
  62. package/dist/tests/AbstractErgoExtractorAction.mock.d.ts +15 -0
  63. package/dist/tests/AbstractErgoExtractorAction.mock.d.ts.map +1 -0
  64. package/dist/tests/AbstractErgoExtractorAction.mock.js +27 -0
  65. package/dist/tests/AbstractErgoExtractorAction.spec.d.ts +2 -0
  66. package/dist/tests/AbstractErgoExtractorAction.spec.d.ts.map +1 -0
  67. package/dist/tests/AbstractErgoExtractorAction.spec.js +222 -0
  68. package/dist/tests/initializable/AbstractInitializable.mock.d.ts +60 -0
  69. package/dist/tests/initializable/AbstractInitializable.mock.d.ts.map +1 -0
  70. package/dist/tests/initializable/AbstractInitializable.mock.js +22 -0
  71. package/dist/tests/initializable/AbstractInitializable.spec.d.ts +2 -0
  72. package/dist/tests/initializable/AbstractInitializable.spec.d.ts.map +1 -0
  73. package/dist/tests/initializable/AbstractInitializable.spec.js +300 -0
  74. package/dist/tests/initializable/AbstractInitializableAction.mock.d.ts +15 -0
  75. package/dist/tests/initializable/AbstractInitializableAction.mock.d.ts.map +1 -0
  76. package/dist/tests/initializable/AbstractInitializableAction.mock.js +27 -0
  77. package/dist/tests/initializable/AbstractInitializableAction.spec.d.ts +2 -0
  78. package/dist/tests/initializable/AbstractInitializableAction.spec.d.ts.map +1 -0
  79. package/dist/tests/initializable/AbstractInitializableAction.spec.js +55 -0
  80. package/dist/tests/initializable/testData.d.ts +94 -0
  81. package/dist/tests/initializable/testData.d.ts.map +1 -0
  82. package/dist/tests/initializable/testData.js +235 -0
  83. package/dist/tests/network/ExplorerNetwork.spec.d.ts +2 -0
  84. package/dist/tests/network/ExplorerNetwork.spec.d.ts.map +1 -0
  85. package/dist/tests/network/ExplorerNetwork.spec.js +62 -0
  86. package/dist/tests/network/NodeNetwork.spec.d.ts +2 -0
  87. package/dist/tests/network/NodeNetwork.spec.d.ts.map +1 -0
  88. package/dist/tests/network/NodeNetwork.spec.js +49 -0
  89. package/dist/tests/network/testData.d.ts +752 -0
  90. package/dist/tests/network/testData.d.ts.map +1 -0
  91. package/dist/tests/network/testData.js +1401 -0
  92. package/dist/tests/testData.d.ts +32 -0
  93. package/dist/tests/testData.d.ts.map +1 -0
  94. package/dist/tests/testData.js +121 -0
  95. package/dist/tests/testUtils.d.ts +9 -0
  96. package/dist/tests/testUtils.d.ts.map +1 -0
  97. package/dist/tests/testUtils.js +31 -0
  98. package/dist/tsconfig.tsbuildinfo +1 -0
  99. package/dist/vitest.config.d.ts +3 -0
  100. package/dist/vitest.config.d.ts.map +1 -0
  101. package/dist/vitest.config.js +17 -0
  102. package/lib/ergo/AbstractErgoExtractor.ts +3 -1
  103. package/lib/ergo/AbstractErgoExtractorAction.ts +47 -36
  104. package/lib/ergo/AbstractErgoExtractorEntity.ts +1 -1
  105. package/lib/ergo/initializable/AbstractInitializableAction.ts +4 -2
  106. package/package.json +9 -14
  107. package/tests/AbstractErgoExtractor.mock.ts +4 -2
  108. package/tests/AbstractErgoExtractorAction.mock.ts +1 -1
  109. package/tests/AbstractErgoExtractorAction.spec.ts +1 -1
  110. package/tests/initializable/AbstractInitializable.mock.ts +13 -4
  111. package/tests/initializable/AbstractInitializable.spec.ts +1 -9
  112. package/tests/initializable/AbstractInitializableAction.mock.ts +1 -1
  113. package/tests/initializable/AbstractInitializableAction.spec.ts +1 -1
  114. package/tests/testUtils.ts +1 -1
  115. package/tsconfig.build.tsbuildinfo +1 -1
@@ -0,0 +1,241 @@
1
+ import { describe, it, expect, vitest } from 'vitest';
2
+ import { CallbackType, } from '../lib';
3
+ import { block, extractedData, tx } from './testData';
4
+ import { MockedErgoExtractor } from './AbstractErgoExtractor.mock';
5
+ describe('AbstractErgoExtractor', () => {
6
+ describe('processTransactions', () => {
7
+ /**
8
+ * @target processTransactions should initialize extractor with specified id and insert status into db
9
+ * @dependencies
10
+ * @scenario
11
+ * - mock extractor
12
+ * - mock `hasData` to return true for one box
13
+ * - spy `extractBoxData` and `storeBoxes`
14
+ * - run test (call `processTransactions`)
15
+ * @expected
16
+ * - to call `extractBoxData` for the specific box and all input extensions
17
+ * - to insert the extracted box to database
18
+ * - to return true when total procedure is successful
19
+ * - to trigger `INSERT` callbacks with correct data
20
+ */
21
+ it('should process boxes with data and insert data into database', async () => {
22
+ const extractor = new MockedErgoExtractor();
23
+ const triggerCallbacks = vitest.fn();
24
+ extractor['triggerCallbacks'] = triggerCallbacks;
25
+ extractor.hasData = (box) => {
26
+ if (box.boxId == tx.outputs[0].boxId)
27
+ return true;
28
+ return false;
29
+ };
30
+ const extractSpy = vitest.fn().mockReturnValue(extractedData);
31
+ extractor.extractBoxData = extractSpy;
32
+ const storeSpy = vitest.fn().mockResolvedValue(true);
33
+ const spendSpy = vitest.fn().mockResolvedValue([]);
34
+ extractor['actions'] = {
35
+ storeBoxes: storeSpy,
36
+ spendBoxes: spendSpy,
37
+ };
38
+ const result = await extractor.processTransactions([tx], block);
39
+ expect(extractSpy).toBeCalledTimes(1);
40
+ expect(extractSpy).toBeCalledWith(tx.outputs[0], [tx.inputs[0].extension, {}], {});
41
+ expect(storeSpy).toBeCalledWith([extractedData], block, 'Test');
42
+ expect(result).toEqual(true);
43
+ expect(triggerCallbacks).toBeCalledWith(CallbackType.Insert, [
44
+ extractedData,
45
+ ]);
46
+ });
47
+ /**
48
+ * @target processTransactions should extract spending information of all input boxes
49
+ * @dependencies
50
+ * @scenario
51
+ * - mock extractor (hasData returns false as default)
52
+ * - spy `extractBoxData`, `storeBoxes` and `spendBoxes`
53
+ * - run test (call `processTransactions`)
54
+ * @expected
55
+ * - not to call `extractBoxData` and `storeBoxes` when there is not any box with data
56
+ * - to extractor spend info of input boxes and call `spendBoxes`
57
+ * - to return true when total procedure is successful
58
+ * - to trigger `SPEND` callbacks with correct data
59
+ */
60
+ it('should extract spending information of all input boxes', async () => {
61
+ const extractor = new MockedErgoExtractor();
62
+ const triggerCallbacks = vitest.fn();
63
+ extractor['triggerCallbacks'] = triggerCallbacks;
64
+ const extractSpy = vitest.fn();
65
+ extractor.extractBoxData = extractSpy;
66
+ const storeSpy = vitest.fn().mockResolvedValue(true);
67
+ const spendSpy = vitest
68
+ .fn()
69
+ .mockResolvedValue([
70
+ { boxId: tx.inputs[0].boxId },
71
+ { boxId: tx.inputs[1].boxId },
72
+ ]);
73
+ extractor['actions'] = {
74
+ storeBoxes: storeSpy,
75
+ spendBoxes: spendSpy,
76
+ };
77
+ const result = await extractor.processTransactions([tx], block);
78
+ expect(extractSpy).not.toBeCalled();
79
+ expect(storeSpy).not.toBeCalled();
80
+ expect(spendSpy).toBeCalledWith([
81
+ { boxId: tx.inputs[0].boxId, txId: tx.id, index: 1 },
82
+ { boxId: tx.inputs[1].boxId, txId: tx.id, index: 2 },
83
+ ], block, 'Test');
84
+ expect(result).toEqual(true);
85
+ expect(triggerCallbacks).toBeCalledWith(CallbackType.Spend, [
86
+ { boxId: tx.inputs[0].boxId },
87
+ { boxId: tx.inputs[1].boxId },
88
+ ]);
89
+ });
90
+ /**
91
+ * @target processTransactions should return false if data insertion fails
92
+ * @dependencies
93
+ * @scenario
94
+ * - mock extractor
95
+ * - mock `hasData` to return true for one box
96
+ * - spy `extractBoxData` and `storeBoxes`
97
+ * - run test (call `processTransactions`)
98
+ * @expected
99
+ * - to return false when `insertBoxes` returns false
100
+ * - not to call `spendBoxes` if data insertion fails
101
+ */
102
+ it('should return false if data insertion fails', async () => {
103
+ const extractor = new MockedErgoExtractor();
104
+ extractor.hasData = (box) => {
105
+ if (box.boxId == tx.outputs[0].boxId)
106
+ return true;
107
+ return false;
108
+ };
109
+ const extractSpy = vitest.fn().mockReturnValue(extractedData);
110
+ extractor.extractBoxData = extractSpy;
111
+ const storeSpy = vitest.fn().mockResolvedValue(false);
112
+ const spendSpy = vitest.fn();
113
+ extractor['actions'] = {
114
+ storeBoxes: storeSpy,
115
+ spendBoxes: spendSpy,
116
+ };
117
+ const result = await extractor.processTransactions([tx], block);
118
+ expect(result).toEqual(false);
119
+ expect(spendSpy).not.toBeCalled();
120
+ });
121
+ });
122
+ describe('forkBlock', () => {
123
+ /**
124
+ * @target forkBlock should remove all data extracted from the specified block
125
+ * @dependencies
126
+ * @scenario
127
+ * - mock extractor
128
+ * - spy `deleteBlockBoxes`
129
+ * - run test (call `forkBlock`)
130
+ * @expected
131
+ * - to call `deleteBlockBoxes` for the specific box
132
+ * - to trigger `DELETE` callbacks for the deleted box
133
+ * - to trigger `UPDATE` callbacks for the spent box
134
+ */
135
+ it('should remove all data extracted from the specified block', async () => {
136
+ const extractor = new MockedErgoExtractor();
137
+ const removeSpy = vitest.fn().mockResolvedValue({
138
+ deletedData: [{ boxId: 'box1' }],
139
+ updatedData: [{ boxId: 'box2' }],
140
+ });
141
+ extractor['actions'] = {
142
+ deleteBlockBoxes: removeSpy,
143
+ };
144
+ const triggerCallbackSpy = vitest.fn().mockClear();
145
+ extractor['triggerCallbacks'] = triggerCallbackSpy;
146
+ await extractor.forkBlock(block.hash);
147
+ expect(removeSpy).toBeCalledWith(block.hash, 'Test');
148
+ expect(triggerCallbackSpy).toBeCalledWith(CallbackType.Delete, [
149
+ { boxId: 'box1' },
150
+ ]);
151
+ expect(triggerCallbackSpy).toBeCalledWith(CallbackType.Update, [
152
+ { boxId: 'box2' },
153
+ ]);
154
+ });
155
+ });
156
+ describe('hook', () => {
157
+ /**
158
+ * @target hook should hook a new callback on insert with the new id
159
+ * @dependencies
160
+ * @scenario
161
+ * - mock extractor
162
+ * - mock a callback for insert
163
+ * - run test (call `hook`)
164
+ * @expected
165
+ * - hook the callback with the specified id
166
+ * - return true
167
+ */
168
+ it('should hook a new callback on insert with the new id', async () => {
169
+ const extractor = new MockedErgoExtractor();
170
+ const insertCallback = vitest.fn();
171
+ const id = await extractor.hook(CallbackType.Insert, insertCallback);
172
+ expect(extractor['callbacks'][CallbackType.Insert]).toEqual(new Map().set(id, insertCallback));
173
+ });
174
+ });
175
+ describe('unhook', () => {
176
+ /**
177
+ * @target unhook should unhook the callback on insert with the specified id
178
+ * @dependencies
179
+ * @scenario
180
+ * - mock extractor
181
+ * - mock a callback for insert
182
+ * - hook the callback
183
+ * - run test (call `unhook`)
184
+ * @expected
185
+ * - unhook the callback with the specified id
186
+ * - return true
187
+ */
188
+ it('should unhook the callback on insert with the specified id', async () => {
189
+ const extractor = new MockedErgoExtractor();
190
+ const insertCallback = vitest.fn();
191
+ const id = await extractor.hook(CallbackType.Insert, insertCallback);
192
+ const result = await extractor.unhook(CallbackType.Insert, id);
193
+ expect(result).toBeTruthy();
194
+ expect(extractor['callbacks'][CallbackType.Insert].get(id)).toEqual(undefined);
195
+ });
196
+ /**
197
+ * @target unhook should not unhook callbacks with the same id on other types
198
+ * @dependencies
199
+ * @scenario
200
+ * - mock extractor
201
+ * - mock two callbacks for insert
202
+ * - hook the first callback
203
+ * - run test (call `unhook` with the same id for second callback)
204
+ * @expected
205
+ * - not to change hooked callbacks when the callback with the id
206
+ * doesn't exists on the specified type
207
+ * - return false
208
+ */
209
+ it('should not unhook callbacks with the same id on other types', async () => {
210
+ const extractor = new MockedErgoExtractor();
211
+ const insertCallback = vitest.fn();
212
+ const id = await extractor.hook(CallbackType.Insert, insertCallback);
213
+ const result = await extractor.unhook(CallbackType.Update, id);
214
+ expect(result).toBeFalsy();
215
+ expect(extractor['callbacks'][CallbackType.Insert].get(id)).toEqual(insertCallback);
216
+ expect(extractor['callbacks'][CallbackType.Update].get(id)).toEqual(undefined);
217
+ });
218
+ });
219
+ describe('triggerCallbacks', () => {
220
+ /**
221
+ * @target triggerCallbacks should trigger all callbacks hooked on a type
222
+ * @dependencies
223
+ * @scenario
224
+ * - mock extractor
225
+ * - mock a callback for insert
226
+ * - hook the callback
227
+ * - run test (call `triggerCallbacks` for insert type)
228
+ * @expected
229
+ * - trigger all callbacks with the specified id
230
+ */
231
+ it('should trigger all callbacks hooked on a type', async () => {
232
+ const extractor = new MockedErgoExtractor();
233
+ const insertCallback = vitest.fn();
234
+ await extractor.hook(CallbackType.Insert, insertCallback);
235
+ const insertedData = [{ boxId: 'boxId', serialized: 'serialized' }];
236
+ await extractor['triggerCallbacks'](CallbackType.Insert, insertedData);
237
+ expect(insertCallback).toBeCalledWith(insertedData);
238
+ });
239
+ });
240
+ });
241
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RFcmdvRXh0cmFjdG9yLnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90ZXN0cy9BYnN0cmFjdEVyZ29FeHRyYWN0b3Iuc3BlYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBR3RELE9BQU8sRUFHTCxZQUFZLEdBRWIsTUFBTSxRQUFRLENBQUM7QUFDaEIsT0FBTyxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsRUFBRSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3RELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRW5FLFFBQVEsQ0FBQyx1QkFBdUIsRUFBRSxHQUFHLEVBQUU7SUFDckMsUUFBUSxDQUFDLHFCQUFxQixFQUFFLEdBQUcsRUFBRTtRQUNuQzs7Ozs7Ozs7Ozs7OztXQWFHO1FBQ0gsRUFBRSxDQUFDLDhEQUE4RCxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQzVFLE1BQU0sU0FBUyxHQUFHLElBQUksbUJBQW1CLEVBQUUsQ0FBQztZQUM1QyxNQUFNLGdCQUFnQixHQUFHLE1BQU0sQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNyQyxTQUFTLENBQUMsa0JBQWtCLENBQUMsR0FBRyxnQkFBZ0IsQ0FBQztZQUNqRCxTQUFTLENBQUMsT0FBTyxHQUFHLENBQUMsR0FBOEIsRUFBRSxFQUFFO2dCQUNyRCxJQUFJLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLO29CQUFFLE9BQU8sSUFBSSxDQUFDO2dCQUNsRCxPQUFPLEtBQUssQ0FBQztZQUNmLENBQUMsQ0FBQztZQUNGLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsYUFBYSxDQUFDLENBQUM7WUFDOUQsU0FBUyxD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LE9BQU8sQ0FDakUsY0FBYyxDQUNmLENBQUM7WUFDRixNQUFNLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQ2pFLFNBQVMsQ0FDVixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILFFBQVEsQ0FBQyxrQkFBa0IsRUFBRSxHQUFHLEVBQUU7UUFDaEM7Ozs7Ozs7Ozs7V0FVRztRQUNILEVBQUUsQ0FBQywrQ0FBK0MsRUFBRSxLQUFLLElBQUksRUFBRTtZQUM3RCxNQUFNLFNBQVMsR0FBRyxJQUFJLG1CQUFtQixFQUFFLENBQUM7WUFDNUMsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ25DLE1BQU0sU0FBUyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBQzFELE1BQU0sWUFBWSxHQUFHLENBQUMsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDO1lBQ3BFLE1BQU0sU0FBUyxDQUFDLGtCQUFrQixDQUFDLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxZQUFZLENBQUMsQ0FBQztZQUN2RSxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUMsY0FBYyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3RELENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFYxIH0gZnJvbSAnQHJvc2VuLWNsaWVudHMvZXJnby1leHBsb3Jlcic7XG5pbXBvcnQgeyBkZXNjcmliZSwgaXQsIGV4cGVjdCwgdml0ZXN0IH0gZnJvbSAndml0ZXN0JztcbmltcG9ydCB7IE91dHB1dEJveCB9IGZyb20gJ0Byb3Nlbi1icmlkZ2Uvc2Nhbm5lci1pbnRlcmZhY2VzJztcblxuaW1wb3J0IHtcbiAgQWJzdHJhY3RCb3hEYXRhLFxuICBBYnN0cmFjdEVyZ29FeHRyYWN0b3JBY3Rpb24sXG4gIENhbGxiYWNrVHlwZSxcbiAgQWJzdHJhY3RFcmdvRXh0cmFjdG9yRW50aXR5LFxufSBmcm9tICcuLi9saWInO1xuaW1wb3J0IHsgYmxvY2ssIGV4dHJhY3RlZERhdGEsIHR4IH0gZnJvbSAnLi90ZXN0RGF0YSc7XG5pbXBvcnQgeyBNb2NrZWRFcmdvRXh0cmFjdG9yIH0gZnJvbSAnLi9BYnN0cmFjdEVyZ29FeHRyYWN0b3IubW9jayc7XG5cbmRlc2NyaWJlKCdBYnN0cmFjdEVyZ29FeHRyYWN0b3InLCAoKSA9PiB7XG4gIGRlc2NyaWJlKCdwcm9jZXNzVHJhbnNhY3Rpb25zJywgKCkgPT4ge1xuICAgIC8qKlxuICAgICAqIEB0YXJnZXQgcHJvY2Vzc1RyYW5zYWN0aW9ucyBzaG91bGQgaW5pdGlhbGl6ZSBleHRyYWN0b3Igd2l0aCBzcGVjaWZpZWQgaWQgYW5kIGluc2VydCBzdGF0dXMgaW50byBkYlxuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIG1vY2sgZXh0cmFjdG9yXG4gICAgICogLSBtb2NrIGBoYXNEYXRhYCB0byByZXR1cm4gdHJ1ZSBmb3Igb25lIGJveFxuICAgICAqIC0gc3B5IGBleHRyYWN0Qm94RGF0YWAgYW5kIGBzdG9yZUJveGVzYFxuICAgICAqIC0gcnVuIHRlc3QgKGNhbGwgYHByb2Nlc3NUcmFuc2FjdGlvbnNgKVxuICAgICAqIEBleHBlY3RlZFxuICAgICAqIC0gdG8gY2FsbCBgZXh0cmFjdEJveERhdGFgIGZvciB0aGUgc3BlY2lmaWMgYm94IGFuZCBhbGwgaW5wdXQgZXh0ZW5zaW9uc1xuICAgICAqIC0gdG8gaW5zZXJ0IHRoZSBleHRyYWN0ZWQgYm94IHRvIGRhdGFiYXNlXG4gICAgICogLSB0byByZXR1cm4gdHJ1ZSB3aGVuIHRvdGFsIHByb2NlZHVyZSBpcyBzdWNjZXNzZnVsXG4gICAgICogLSB0byB0cmlnZ2VyIGBJTlNFUlRgIGNhbGxiYWNrcyB3aXRoIGNvcnJlY3QgZGF0YVxuICAgICAqL1xuICAgIGl0KCdzaG91bGQgcHJvY2VzcyBib3hlcyB3aXRoIGRhdGEgYW5kIGluc2VydCBkYXRhIGludG8gZGF0YWJhc2UnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBleHRyYWN0b3IgPSBuZXcgTW9ja2VkRXJnb0V4dHJhY3RvcigpO1xuICAgICAgY29uc3QgdHJpZ2dlckNhbGxiYWNrcyA9IHZpdGVzdC5mbigpO1xuICAgICAgZXh0cmFjdG9yWyd0cmlnZ2VyQ2FsbGJhY2tzJ10gPSB0cmlnZ2VyQ2FsbGJhY2tzO1xuICAgICAgZXh0cmFjdG9yLmhhc0RhdGEgPSAoYm94OiBWMS5PdXRwdXRJbmZvIHwgT3V0cHV0Qm94KSA9PiB7XG4gICAgICAgIGlmIChib3guYm94SWQgPT0gdHgub3V0cHV0c1swXS5ib3hJZCkgcmV0dXJuIHRydWU7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH07XG4gICAgICBjb25zdCBleHRyYWN0U3B5ID0gdml0ZXN0LmZuKCkubW9ja1JldHVyblZhbHVlKGV4dHJhY3RlZERhdGEpO1xuICAgICAgZXh0cmFjdG9yLmV4dHJhY3RCb3hEYXRhID0gZXh0cmFjdFNweTtcbiAgICAgIGNvbnN0IHN0b3JlU3B5ID0gdml0ZXN0LmZuKCkubW9ja1Jlc29sdmVkVmFsdWUodHJ1ZSk7XG4gICAgICBjb25zdCBzcGVuZFNweSA9IHZpdGVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKFtdKTtcbiAgICAgIGV4dHJhY3RvclsnYWN0aW9ucyddID0ge1xuICAgICAgICBzdG9yZUJveGVzOiBzdG9yZVNweSxcbiAgICAgICAgc3BlbmRCb3hlczogc3BlbmRTcHksXG4gICAgICB9IGFzIHVua25vd24gYXMgQWJzdHJhY3RFcmdvRXh0cmFjdG9yQWN0aW9uPFxuICAgICAgICBBYnN0cmFjdEJveERhdGEsXG4gICAgICAgIEFic3RyYWN0RXJnb0V4dHJhY3RvckVudGl0eVxuICAgICAgPjtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGV4dHJhY3Rvci5wcm9jZXNzVHJhbnNhY3Rpb25zKFt0eF0sIGJsb2NrKTtcblxuICAgICAgZXhwZWN0KGV4dHJhY3RTcHkpLnRvQmVDYWxsZWRUaW1lcygxKTtcbiAgICAgIGV4cGVjdChleHRyYWN0U3B5KS50b0JlQ2FsbGVkV2l0aChcbiAgICAgICAgdHgub3V0cHV0c1swXSxcbiAgICAgICAgW3R4LmlucHV0c1swXS5leHRlbnNpb24sIHt9XSxcbiAgICAgICAge31cbiAgICAgICk7XG4gICAgICBleHBlY3Qoc3RvcmVTcHkpLnRvQmVDYWxsZWRXaXRoKFtleHRyYWN0ZWREYXRhXSwgYmxvY2ssICdUZXN0Jyk7XG4gICAgICBleHBlY3QocmVzdWx0KS50b0VxdWFsKHRydWUpO1xuICAgICAgZXhwZWN0KHRyaWdnZXJDYWxsYmFja3MpLnRvQmVDYWxsZWRXaXRoKENhbGxiYWNrVHlwZS5JbnNlcnQsIFtcbiAgICAgICAgZXh0cmFjdGVkRGF0YSxcbiAgICAgIF0pO1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogQHRhcmdldCBwcm9jZXNzVHJhbnNhY3Rpb25zIHNob3VsZCBleHRyYWN0IHNwZW5kaW5nIGluZm9ybWF0aW9uIG9mIGFsbCBpbnB1dCBib3hlc1xuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIG1vY2sgZXh0cmFjdG9yIChoYXNEYXRhIHJldHVybnMgZmFsc2UgYXMgZGVmYXVsdClcbiAgICAgKiAtIHNweSBgZXh0cmFjdEJveERhdGFgLCBgc3RvcmVCb3hlc2AgYW5kIGBzcGVuZEJveGVzYFxuICAgICAqIC0gcnVuIHRlc3QgKGNhbGwgYHByb2Nlc3NUcmFuc2FjdGlvbnNgKVxuICAgICAqIEBleHBlY3RlZFxuICAgICAqIC0gbm90IHRvIGNhbGwgYGV4dHJhY3RCb3hEYXRhYCBhbmQgYHN0b3JlQm94ZXNgIHdoZW4gdGhlcmUgaXMgbm90IGFueSBib3ggd2l0aCBkYXRhXG4gICAgICogLSB0byBleHRyYWN0b3Igc3BlbmQgaW5mbyBvZiBpbnB1dCBib3hlcyBhbmQgY2FsbCBgc3BlbmRCb3hlc2BcbiAgICAgKiAtIHRvIHJldHVybiB0cnVlIHdoZW4gdG90YWwgcHJvY2VkdXJlIGlzIHN1Y2Nlc3NmdWxcbiAgICAgKiAtIHRvIHRyaWdnZXIgYFNQRU5EYCBjYWxsYmFja3Mgd2l0aCBjb3JyZWN0IGRhdGFcbiAgICAgKi9cbiAgICBpdCgnc2hvdWxkIGV4dHJhY3Qgc3BlbmRpbmcgaW5mb3JtYXRpb24gb2YgYWxsIGlucHV0IGJveGVzJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgZXh0cmFjdG9yID0gbmV3IE1vY2tlZEVyZ29FeHRyYWN0b3IoKTtcbiAgICAgIGNvbnN0IHRyaWdnZXJDYWxsYmFja3MgPSB2aXRlc3QuZm4oKTtcbiAgICAgIGV4dHJhY3RvclsndHJpZ2dlckNhbGxiYWNrcyddID0gdHJpZ2dlckNhbGxiYWNrcztcbiAgICAgIGNvbnN0IGV4dHJhY3RTcHkgPSB2aXRlc3QuZm4oKTtcbiAgICAgIGV4dHJhY3Rvci5leHRyYWN0Qm94RGF0YSA9IGV4dHJhY3RTcHk7XG4gICAgICBjb25zdCBzdG9yZVNweSA9IHZpdGVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKHRydWUpO1xuICAgICAgY29uc3Qgc3BlbmRTcHkgPSB2aXRlc3RcbiAgICAgICAgLmZuKClcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlKFtcbiAgICAgICAgICB7IGJveElkOiB0eC5pbnB1dHNbMF0uYm94SWQgfSxcbiAgICAgICAgICB7IGJveElkOiB0eC5pbnB1dHNbMV0uYm94SWQgfSxcbiAgICAgICAgXSk7XG4gICAgICBleHRyYWN0b3JbJ2FjdGlvbnMnXSA9IHtcbiAgICAgICAgc3RvcmVCb3hlczogc3RvcmVTcHksXG4gICAgICAgIHNwZW5kQm94ZXM6IHNwZW5kU3B5LFxuICAgICAgfSBhcyB1bmtub3duIGFzIEFic3RyYWN0RXJnb0V4dHJhY3RvckFjdGlvbjxcbiAgICAgICAgQWJzdHJhY3RCb3hEYXRhLFxuICAgICAgICBBYnN0cmFjdEVyZ29FeHRyYWN0b3JFbnRpdHlcbiAgICAgID47XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBleHRyYWN0b3IucHJvY2Vzc1RyYW5zYWN0aW9ucyhbdHhdLCBibG9jayk7XG5cbiAgICAgIGV4cGVjdChleHRyYWN0U3B5KS5ub3QudG9CZUNhbGxlZCgpO1xuICAgICAgZXhwZWN0KHN0b3JlU3B5KS5ub3QudG9CZUNhbGxlZCgpO1xuICAgICAgZXhwZWN0KHNwZW5kU3B5KS50b0JlQ2FsbGVkV2l0aChcbiAgICAgICAgW1xuICAgICAgICAgIHsgYm94SWQ6IHR4LmlucHV0c1swXS5ib3hJZCwgdHhJZDogdHguaWQsIGluZGV4OiAxIH0sXG4gICAgICAgICAgeyBib3hJZDogdHguaW5wdXRzWzFdLmJveElkLCB0eElkOiB0eC5pZCwgaW5kZXg6IDIgfSxcbiAgICAgICAgXSxcbiAgICAgICAgYmxvY2ssXG4gICAgICAgICdUZXN0J1xuICAgICAgKTtcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwodHJ1ZSk7XG4gICAgICBleHBlY3QodHJpZ2dlckNhbGxiYWNrcykudG9CZUNhbGxlZFdpdGgoQ2FsbGJhY2tUeXBlLlNwZW5kLCBbXG4gICAgICAgIHsgYm94SWQ6IHR4LmlucHV0c1swXS5ib3hJZCB9LFxuICAgICAgICB7IGJveElkOiB0eC5pbnB1dHNbMV0uYm94SWQgfSxcbiAgICAgIF0pO1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogQHRhcmdldCBwcm9jZXNzVHJhbnNhY3Rpb25zIHNob3VsZCByZXR1cm4gZmFsc2UgaWYgZGF0YSBpbnNlcnRpb24gZmFpbHNcbiAgICAgKiBAZGVwZW5kZW5jaWVzXG4gICAgICogQHNjZW5hcmlvXG4gICAgICogLSBtb2NrIGV4dHJhY3RvclxuICAgICAqIC0gbW9jayBgaGFzRGF0YWAgdG8gcmV0dXJuIHRydWUgZm9yIG9uZSBib3hcbiAgICAgKiAtIHNweSBgZXh0cmFjdEJveERhdGFgIGFuZCBgc3RvcmVCb3hlc2BcbiAgICAgKiAtIHJ1biB0ZXN0IChjYWxsIGBwcm9jZXNzVHJhbnNhY3Rpb25zYClcbiAgICAgKiBAZXhwZWN0ZWRcbiAgICAgKiAtIHRvIHJldHVybiBmYWxzZSB3aGVuIGBpbnNlcnRCb3hlc2AgcmV0dXJucyBmYWxzZVxuICAgICAqIC0gbm90IHRvIGNhbGwgYHNwZW5kQm94ZXNgIGlmIGRhdGEgaW5zZXJ0aW9uIGZhaWxzXG4gICAgICovXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gZmFsc2UgaWYgZGF0YSBpbnNlcnRpb24gZmFpbHMnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBleHRyYWN0b3IgPSBuZXcgTW9ja2VkRXJnb0V4dHJhY3RvcigpO1xuICAgICAgZXh0cmFjdG9yLmhhc0RhdGEgPSAoYm94OiBWMS5PdXRwdXRJbmZvIHwgT3V0cHV0Qm94KSA9PiB7XG4gICAgICAgIGlmIChib3guYm94SWQgPT0gdHgub3V0cHV0c1swXS5ib3hJZCkgcmV0dXJuIHRydWU7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH07XG4gICAgICBjb25zdCBleHRyYWN0U3B5ID0gdml0ZXN0LmZuKCkubW9ja1JldHVyblZhbHVlKGV4dHJhY3RlZERhdGEpO1xuICAgICAgZXh0cmFjdG9yLmV4dHJhY3RCb3hEYXRhID0gZXh0cmFjdFNweTtcbiAgICAgIGNvbnN0IHN0b3JlU3B5ID0gdml0ZXN0LmZuKCkubW9ja1Jlc29sdmVkVmFsdWUoZmFsc2UpO1xuICAgICAgY29uc3Qgc3BlbmRTcHkgPSB2aXRlc3QuZm4oKTtcbiAgICAgIGV4dHJhY3RvclsnYWN0aW9ucyddID0ge1xuICAgICAgICBzdG9yZUJveGVzOiBzdG9yZVNweSxcbiAgICAgICAgc3BlbmRCb3hlczogc3BlbmRTcHksXG4gICAgICB9IGFzIHVua25vd24gYXMgQWJzdHJhY3RFcmdvRXh0cmFjdG9yQWN0aW9uPFxuICAgICAgICBBYnN0cmFjdEJveERhdGEsXG4gICAgICAgIEFic3RyYWN0RXJnb0V4dHJhY3RvckVudGl0eVxuICAgICAgPjtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGV4dHJhY3Rvci5wcm9jZXNzVHJhbnNhY3Rpb25zKFt0eF0sIGJsb2NrKTtcblxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbChmYWxzZSk7XG4gICAgICBleHBlY3Qoc3BlbmRTcHkpLm5vdC50b0JlQ2FsbGVkKCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdmb3JrQmxvY2snLCAoKSA9PiB7XG4gICAgLyoqXG4gICAgICogQHRhcmdldCBmb3JrQmxvY2sgc2hvdWxkIHJlbW92ZSBhbGwgZGF0YSBleHRyYWN0ZWQgZnJvbSB0aGUgc3BlY2lmaWVkIGJsb2NrXG4gICAgICogQGRlcGVuZGVuY2llc1xuICAgICAqIEBzY2VuYXJpb1xuICAgICAqIC0gbW9jayBleHRyYWN0b3JcbiAgICAgKiAtIHNweSBgZGVsZXRlQmxvY2tCb3hlc2BcbiAgICAgKiAtIHJ1biB0ZXN0IChjYWxsIGBmb3JrQmxvY2tgKVxuICAgICAqIEBleHBlY3RlZFxuICAgICAqIC0gdG8gY2FsbCBgZGVsZXRlQmxvY2tCb3hlc2AgZm9yIHRoZSBzcGVjaWZpYyBib3hcbiAgICAgKiAtIHRvIHRyaWdnZXIgYERFTEVURWAgY2FsbGJhY2tzIGZvciB0aGUgZGVsZXRlZCBib3hcbiAgICAgKiAtIHRvIHRyaWdnZXIgYFVQREFURWAgY2FsbGJhY2tzIGZvciB0aGUgc3BlbnQgYm94XG4gICAgICovXG4gICAgaXQoJ3Nob3VsZCByZW1vdmUgYWxsIGRhdGEgZXh0cmFjdGVkIGZyb20gdGhlIHNwZWNpZmllZCBibG9jaycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGV4dHJhY3RvciA9IG5ldyBNb2NrZWRFcmdvRXh0cmFjdG9yKCk7XG4gICAgICBjb25zdCByZW1vdmVTcHkgPSB2aXRlc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICAgIGRlbGV0ZWREYXRhOiBbeyBib3hJZDogJ2JveDEnIH1dLFxuICAgICAgICB1cGRhdGVkRGF0YTogW3sgYm94SWQ6ICdib3gyJyB9XSxcbiAgICAgIH0pO1xuICAgICAgZXh0cmFjdG9yWydhY3Rpb25zJ10gPSB7XG4gICAgICAgIGRlbGV0ZUJsb2NrQm94ZXM6IHJlbW92ZVNweSxcbiAgICAgIH0gYXMgdW5rbm93biBhcyBBYnN0cmFjdEVyZ29FeHRyYWN0b3JBY3Rpb248XG4gICAgICAgIEFic3RyYWN0Qm94RGF0YSxcbiAgICAgICAgQWJzdHJhY3RFcmdvRXh0cmFjdG9yRW50aXR5XG4gICAgICA+O1xuICAgICAgY29uc3QgdHJpZ2dlckNhbGxiYWNrU3B5ID0gdml0ZXN0LmZuKCkubW9ja0NsZWFyKCk7XG4gICAgICBleHRyYWN0b3JbJ3RyaWdnZXJDYWxsYmFja3MnXSA9IHRyaWdnZXJDYWxsYmFja1NweTtcbiAgICAgIGF3YWl0IGV4dHJhY3Rvci5mb3JrQmxvY2soYmxvY2suaGFzaCk7XG4gICAgICBleHBlY3QocmVtb3ZlU3B5KS50b0JlQ2FsbGVkV2l0aChibG9jay5oYXNoLCAnVGVzdCcpO1xuICAgICAgZXhwZWN0KHRyaWdnZXJDYWxsYmFja1NweSkudG9CZUNhbGxlZFdpdGgoQ2FsbGJhY2tUeXBlLkRlbGV0ZSwgW1xuICAgICAgICB7IGJveElkOiAnYm94MScgfSxcbiAgICAgIF0pO1xuICAgICAgZXhwZWN0KHRyaWdnZXJDYWxsYmFja1NweSkudG9CZUNhbGxlZFdpdGgoQ2FsbGJhY2tUeXBlLlVwZGF0ZSwgW1xuICAgICAgICB7IGJveElkOiAnYm94MicgfSxcbiAgICAgIF0pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnaG9vaycsICgpID0+IHtcbiAgICAvKipcbiAgICAgKiBAdGFyZ2V0IGhvb2sgc2hvdWxkIGhvb2sgYSBuZXcgY2FsbGJhY2sgb24gaW5zZXJ0IHdpdGggdGhlIG5ldyBpZFxuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIG1vY2sgZXh0cmFjdG9yXG4gICAgICogLSBtb2NrIGEgY2FsbGJhY2sgZm9yIGluc2VydFxuICAgICAqIC0gcnVuIHRlc3QgKGNhbGwgYGhvb2tgKVxuICAgICAqIEBleHBlY3RlZFxuICAgICAqIC0gaG9vayB0aGUgY2FsbGJhY2sgd2l0aCB0aGUgc3BlY2lmaWVkIGlkXG4gICAgICogLSByZXR1cm4gdHJ1ZVxuICAgICAqL1xuICAgIGl0KCdzaG91bGQgaG9vayBhIG5ldyBjYWxsYmFjayBvbiBpbnNlcnQgd2l0aCB0aGUgbmV3IGlkJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgZXh0cmFjdG9yID0gbmV3IE1vY2tlZEVyZ29FeHRyYWN0b3IoKTtcbiAgICAgIGNvbnN0IGluc2VydENhbGxiYWNrID0gdml0ZXN0LmZuKCk7XG4gICAgICBjb25zdCBpZCA9IGF3YWl0IGV4dHJhY3Rvci5ob29rKENhbGxiYWNrVHlwZS5JbnNlcnQsIGluc2VydENhbGxiYWNrKTtcbiAgICAgIGV4cGVjdChleHRyYWN0b3JbJ2NhbGxiYWNrcyddW0NhbGxiYWNrVHlwZS5JbnNlcnRdKS50b0VxdWFsKFxuICAgICAgICBuZXcgTWFwKCkuc2V0KGlkLCBpbnNlcnRDYWxsYmFjaylcbiAgICAgICk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCd1bmhvb2snLCAoKSA9PiB7XG4gICAgLyoqXG4gICAgICogQHRhcmdldCB1bmhvb2sgc2hvdWxkIHVuaG9vayB0aGUgY2FsbGJhY2sgb24gaW5zZXJ0IHdpdGggdGhlIHNwZWNpZmllZCBpZFxuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIG1vY2sgZXh0cmFjdG9yXG4gICAgICogLSBtb2NrIGEgY2FsbGJhY2sgZm9yIGluc2VydFxuICAgICAqIC0gaG9vayB0aGUgY2FsbGJhY2tcbiAgICAgKiAtIHJ1biB0ZXN0IChjYWxsIGB1bmhvb2tgKVxuICAgICAqIEBleHBlY3RlZFxuICAgICAqIC0gdW5ob29rIHRoZSBjYWxsYmFjayB3aXRoIHRoZSBzcGVjaWZpZWQgaWRcbiAgICAgKiAtIHJldHVybiB0cnVlXG4gICAgICovXG4gICAgaXQoJ3Nob3VsZCB1bmhvb2sgdGhlIGNhbGxiYWNrIG9uIGluc2VydCB3aXRoIHRoZSBzcGVjaWZpZWQgaWQnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBleHRyYWN0b3IgPSBuZXcgTW9ja2VkRXJnb0V4dHJhY3RvcigpO1xuICAgICAgY29uc3QgaW5zZXJ0Q2FsbGJhY2sgPSB2aXRlc3QuZm4oKTtcbiAgICAgIGNvbnN0IGlkID0gYXdhaXQgZXh0cmFjdG9yLmhvb2soQ2FsbGJhY2tUeXBlLkluc2VydCwgaW5zZXJ0Q2FsbGJhY2spO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZXh0cmFjdG9yLnVuaG9vayhDYWxsYmFja1R5cGUuSW5zZXJ0LCBpZCk7XG4gICAgICBleHBlY3QocmVzdWx0KS50b0JlVHJ1dGh5KCk7XG4gICAgICBleHBlY3QoZXh0cmFjdG9yWydjYWxsYmFja3MnXVtDYWxsYmFja1R5cGUuSW5zZXJ0XS5nZXQoaWQpKS50b0VxdWFsKFxuICAgICAgICB1bmRlZmluZWRcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBAdGFyZ2V0IHVuaG9vayBzaG91bGQgbm90IHVuaG9vayBjYWxsYmFja3Mgd2l0aCB0aGUgc2FtZSBpZCBvbiBvdGhlciB0eXBlc1xuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIG1vY2sgZXh0cmFjdG9yXG4gICAgICogLSBtb2NrIHR3byBjYWxsYmFja3MgZm9yIGluc2VydFxuICAgICAqIC0gaG9vayB0aGUgZmlyc3QgY2FsbGJhY2tcbiAgICAgKiAtIHJ1biB0ZXN0IChjYWxsIGB1bmhvb2tgIHdpdGggdGhlIHNhbWUgaWQgZm9yIHNlY29uZCBjYWxsYmFjaylcbiAgICAgKiBAZXhwZWN0ZWRcbiAgICAgKiAtIG5vdCB0byBjaGFuZ2UgaG9va2VkIGNhbGxiYWNrcyB3aGVuIHRoZSBjYWxsYmFjayB3aXRoIHRoZSBpZFxuICAgICAqIGRvZXNuJ3QgZXhpc3RzIG9uIHRoZSBzcGVjaWZpZWQgdHlwZVxuICAgICAqIC0gcmV0dXJuIGZhbHNlXG4gICAgICovXG4gICAgaXQoJ3Nob3VsZCBub3QgdW5ob29rIGNhbGxiYWNrcyB3aXRoIHRoZSBzYW1lIGlkIG9uIG90aGVyIHR5cGVzJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgZXh0cmFjdG9yID0gbmV3IE1vY2tlZEVyZ29FeHRyYWN0b3IoKTtcbiAgICAgIGNvbnN0IGluc2VydENhbGxiYWNrID0gdml0ZXN0LmZuKCk7XG4gICAgICBjb25zdCBpZCA9IGF3YWl0IGV4dHJhY3Rvci5ob29rKENhbGxiYWNrVHlwZS5JbnNlcnQsIGluc2VydENhbGxiYWNrKTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGV4dHJhY3Rvci51bmhvb2soQ2FsbGJhY2tUeXBlLlVwZGF0ZSwgaWQpO1xuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZUZhbHN5KCk7XG4gICAgICBleHBlY3QoZXh0cmFjdG9yWydjYWxsYmFja3MnXVtDYWxsYmFja1R5cGUuSW5zZXJ0XS5nZXQoaWQpKS50b0VxdWFsKFxuICAgICAgICBpbnNlcnRDYWxsYmFja1xuICAgICAgKTtcbiAgICAgIGV4cGVjdChleHRyYWN0b3JbJ2NhbGxiYWNrcyddW0NhbGxiYWNrVHlwZS5VcGRhdGVdLmdldChpZCkpLnRvRXF1YWwoXG4gICAgICAgIHVuZGVmaW5lZFxuICAgICAgKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ3RyaWdnZXJDYWxsYmFja3MnLCAoKSA9PiB7XG4gICAgLyoqXG4gICAgICogQHRhcmdldCB0cmlnZ2VyQ2FsbGJhY2tzIHNob3VsZCB0cmlnZ2VyIGFsbCBjYWxsYmFja3MgaG9va2VkIG9uIGEgdHlwZVxuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIG1vY2sgZXh0cmFjdG9yXG4gICAgICogLSBtb2NrIGEgY2FsbGJhY2sgZm9yIGluc2VydFxuICAgICAqIC0gaG9vayB0aGUgY2FsbGJhY2tcbiAgICAgKiAtIHJ1biB0ZXN0IChjYWxsIGB0cmlnZ2VyQ2FsbGJhY2tzYCBmb3IgaW5zZXJ0IHR5cGUpXG4gICAgICogQGV4cGVjdGVkXG4gICAgICogLSB0cmlnZ2VyIGFsbCBjYWxsYmFja3Mgd2l0aCB0aGUgc3BlY2lmaWVkIGlkXG4gICAgICovXG4gICAgaXQoJ3Nob3VsZCB0cmlnZ2VyIGFsbCBjYWxsYmFja3MgaG9va2VkIG9uIGEgdHlwZScsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGV4dHJhY3RvciA9IG5ldyBNb2NrZWRFcmdvRXh0cmFjdG9yKCk7XG4gICAgICBjb25zdCBpbnNlcnRDYWxsYmFjayA9IHZpdGVzdC5mbigpO1xuICAgICAgYXdhaXQgZXh0cmFjdG9yLmhvb2soQ2FsbGJhY2tUeXBlLkluc2VydCwgaW5zZXJ0Q2FsbGJhY2spO1xuICAgICAgY29uc3QgaW5zZXJ0ZWREYXRhID0gW3sgYm94SWQ6ICdib3hJZCcsIHNlcmlhbGl6ZWQ6ICdzZXJpYWxpemVkJyB9XTtcbiAgICAgIGF3YWl0IGV4dHJhY3RvclsndHJpZ2dlckNhbGxiYWNrcyddKENhbGxiYWNrVHlwZS5JbnNlcnQsIGluc2VydGVkRGF0YSk7XG4gICAgICBleHBlY3QoaW5zZXJ0Q2FsbGJhY2spLnRvQmVDYWxsZWRXaXRoKGluc2VydGVkRGF0YSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=
@@ -0,0 +1,15 @@
1
+ import { DataSource } from '@rosen-bridge/extended-typeorm';
2
+ import { BlockInfo } from '@rosen-bridge/scanner-interfaces';
3
+ import { AbstractErgoExtractorAction, AbstractErgoExtractorEntity, AbstractBoxData } from '../lib';
4
+ export declare class TestErgoExtractorAction extends AbstractErgoExtractorAction<AbstractBoxData, AbstractErgoExtractorEntity> {
5
+ constructor(dataSource: DataSource);
6
+ /**
7
+ * create the test database entity from data and block information
8
+ */
9
+ createEntity: (boxes: AbstractBoxData[], block: BlockInfo, extractor: string) => Omit<AbstractErgoExtractorEntity, 'id'>[];
10
+ /**
11
+ * convert the database entity back to raw data
12
+ */
13
+ convertEntityToData: (entities: AbstractErgoExtractorEntity[]) => AbstractBoxData[];
14
+ }
15
+ //# sourceMappingURL=AbstractErgoExtractorAction.mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractErgoExtractorAction.mock.d.ts","sourceRoot":"","sources":["../../tests/AbstractErgoExtractorAction.mock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAE5D,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAE7D,OAAO,EACL,2BAA2B,EAC3B,2BAA2B,EAC3B,eAAe,EAChB,MAAM,QAAQ,CAAC;AAGhB,qBAAa,uBAAwB,SAAQ,2BAA2B,CACtE,eAAe,EACf,2BAA2B,CAC5B;gBACa,UAAU,EAAE,UAAU;IAIlC;;OAEG;IACH,YAAY,UACH,eAAe,EAAE,SACjB,SAAS,aACL,MAAM,KAChB,KAAK,2BAA2B,EAAE,IAAI,CAAC,EAAE,CAQ1C;IAEF;;OAEG;IACH,mBAAmB,aACP,2BAA2B,EAAE,KACtC,eAAe,EAAE,CAElB;CACH"}
@@ -0,0 +1,27 @@
1
+ import { pick } from 'lodash-es';
2
+ import { AbstractErgoExtractorAction, } from '../lib';
3
+ import { TestEntity } from './testUtils';
4
+ export class TestErgoExtractorAction extends AbstractErgoExtractorAction {
5
+ constructor(dataSource) {
6
+ super(dataSource, TestEntity);
7
+ }
8
+ /**
9
+ * create the test database entity from data and block information
10
+ */
11
+ createEntity = (boxes, block, extractor) => {
12
+ return boxes.map((box) => ({
13
+ boxId: box.boxId,
14
+ block: block.hash,
15
+ height: block.height,
16
+ serialized: box.serialized,
17
+ extractor: extractor,
18
+ }));
19
+ };
20
+ /**
21
+ * convert the database entity back to raw data
22
+ */
23
+ convertEntityToData = (entities) => {
24
+ return entities.map((data) => pick(data, ['boxId', 'serialized']));
25
+ };
26
+ }
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RFcmdvRXh0cmFjdG9yQWN0aW9uLm1vY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90ZXN0cy9BYnN0cmFjdEVyZ29FeHRyYWN0b3JBY3Rpb24ubW9jay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBR2pDLE9BQU8sRUFDTCwyQkFBMkIsR0FHNUIsTUFBTSxRQUFRLENBQUM7QUFDaEIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUV6QyxNQUFNLE9BQU8sdUJBQXdCLFNBQVEsMkJBRzVDO0lBQ0MsWUFBWSxVQUFzQjtRQUNoQyxLQUFLLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7T0FFRztJQUNILFlBQVksR0FBRyxDQUNiLEtBQXdCLEVBQ3hCLEtBQWdCLEVBQ2hCLFNBQWlCLEVBQzBCLEVBQUU7UUFDN0MsT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3pCLEtBQUssRUFBRSxHQUFHLENBQUMsS0FBSztZQUNoQixLQUFLLEVBQUUsS0FBSyxDQUFDLElBQUk7WUFDakIsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNO1lBQ3BCLFVBQVUsRUFBRSxHQUFHLENBQUMsVUFBVTtZQUMxQixTQUFTLEVBQUUsU0FBUztTQUNyQixDQUFDLENBQUMsQ0FBQztJQUNOLENBQUMsQ0FBQztJQUVGOztPQUVHO0lBQ0gsbUJBQW1CLEdBQUcsQ0FDcEIsUUFBdUMsRUFDcEIsRUFBRTtRQUNyQixPQUFPLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxPQUFPLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JFLENBQUMsQ0FBQztDQUNIIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGF0YVNvdXJjZSB9IGZyb20gJ0Byb3Nlbi1icmlkZ2UvZXh0ZW5kZWQtdHlwZW9ybSc7XG5pbXBvcnQgeyBwaWNrIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IEJsb2NrSW5mbyB9IGZyb20gJ0Byb3Nlbi1icmlkZ2Uvc2Nhbm5lci1pbnRlcmZhY2VzJztcblxuaW1wb3J0IHtcbiAgQWJzdHJhY3RFcmdvRXh0cmFjdG9yQWN0aW9uLFxuICBBYnN0cmFjdEVyZ29FeHRyYWN0b3JFbnRpdHksXG4gIEFic3RyYWN0Qm94RGF0YSxcbn0gZnJvbSAnLi4vbGliJztcbmltcG9ydCB7IFRlc3RFbnRpdHkgfSBmcm9tICcuL3Rlc3RVdGlscyc7XG5cbmV4cG9ydCBjbGFzcyBUZXN0RXJnb0V4dHJhY3RvckFjdGlvbiBleHRlbmRzIEFic3RyYWN0RXJnb0V4dHJhY3RvckFjdGlvbjxcbiAgQWJzdHJhY3RCb3hEYXRhLFxuICBBYnN0cmFjdEVyZ29FeHRyYWN0b3JFbnRpdHlcbj4ge1xuICBjb25zdHJ1Y3RvcihkYXRhU291cmNlOiBEYXRhU291cmNlKSB7XG4gICAgc3VwZXIoZGF0YVNvdXJjZSwgVGVzdEVudGl0eSk7XG4gIH1cblxuICAvKipcbiAgICogY3JlYXRlIHRoZSB0ZXN0IGRhdGFiYXNlIGVudGl0eSBmcm9tIGRhdGEgYW5kIGJsb2NrIGluZm9ybWF0aW9uXG4gICAqL1xuICBjcmVhdGVFbnRpdHkgPSAoXG4gICAgYm94ZXM6IEFic3RyYWN0Qm94RGF0YVtdLFxuICAgIGJsb2NrOiBCbG9ja0luZm8sXG4gICAgZXh0cmFjdG9yOiBzdHJpbmdcbiAgKTogT21pdDxBYnN0cmFjdEVyZ29FeHRyYWN0b3JFbnRpdHksICdpZCc+W10gPT4ge1xuICAgIHJldHVybiBib3hlcy5tYXAoKGJveCkgPT4gKHtcbiAgICAgIGJveElkOiBib3guYm94SWQsXG4gICAgICBibG9jazogYmxvY2suaGFzaCxcbiAgICAgIGhlaWdodDogYmxvY2suaGVpZ2h0LFxuICAgICAgc2VyaWFsaXplZDogYm94LnNlcmlhbGl6ZWQsXG4gICAgICBleHRyYWN0b3I6IGV4dHJhY3RvcixcbiAgICB9KSk7XG4gIH07XG5cbiAgLyoqXG4gICAqIGNvbnZlcnQgdGhlIGRhdGFiYXNlIGVudGl0eSBiYWNrIHRvIHJhdyBkYXRhXG4gICAqL1xuICBjb252ZXJ0RW50aXR5VG9EYXRhID0gKFxuICAgIGVudGl0aWVzOiBBYnN0cmFjdEVyZ29FeHRyYWN0b3JFbnRpdHlbXVxuICApOiBBYnN0cmFjdEJveERhdGFbXSA9PiB7XG4gICAgcmV0dXJuIGVudGl0aWVzLm1hcCgoZGF0YSkgPT4gcGljayhkYXRhLCBbJ2JveElkJywgJ3NlcmlhbGl6ZWQnXSkpO1xuICB9O1xufVxuIl19
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=AbstractErgoExtractorAction.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractErgoExtractorAction.spec.d.ts","sourceRoot":"","sources":["../../tests/AbstractErgoExtractorAction.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,222 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { pick } from 'lodash-es';
3
+ import { TestErgoExtractorAction } from './AbstractErgoExtractorAction.mock';
4
+ import { createDatabase, TestEntity } from './testUtils';
5
+ import { block, block2, sampleEntities } from './testData';
6
+ describe('AbstractErgoExtractorAction', () => {
7
+ let dataSource;
8
+ let action;
9
+ let repository;
10
+ beforeEach(async () => {
11
+ dataSource = await createDatabase();
12
+ action = new TestErgoExtractorAction(dataSource);
13
+ repository = dataSource.getRepository(TestEntity);
14
+ });
15
+ describe('storeBoxes', () => {
16
+ /**
17
+ * @target storeBoxes should save the passed box entities to database
18
+ * @dependencies
19
+ * @scenario
20
+ * - run test (call `storeBoxes` with 2 new boxes)
21
+ * @expected
22
+ * - to save 2 new entities
23
+ * - to return 2 inserted entity data
24
+ */
25
+ it(`should save the passed box entities to database`, async () => {
26
+ const result = await action.storeBoxes(sampleEntities.slice(0, 2), block, 'extractor1');
27
+ const [rows, rowsCount] = await repository.findAndCount();
28
+ expect(rowsCount).toEqual(2);
29
+ expect(rows[0]).toMatchObject({
30
+ ...sampleEntities[0],
31
+ extractor: 'extractor1',
32
+ block: block.hash,
33
+ height: block.height,
34
+ spendBlock: null,
35
+ spendHeight: null,
36
+ });
37
+ expect(rows[1]).toMatchObject({
38
+ ...sampleEntities[1],
39
+ extractor: 'extractor1',
40
+ block: block.hash,
41
+ height: block.height,
42
+ spendBlock: null,
43
+ spendHeight: null,
44
+ });
45
+ expect(result).toEqual(true);
46
+ });
47
+ /**
48
+ * @target storeBoxes should correctly save boxes with different extractors
49
+ * @dependencies
50
+ * @scenario
51
+ * - insert 2 boxes belonging to first-extractor
52
+ * - run test (call `storeBoxes` with same boxes for the second-extractor)
53
+ * @expected
54
+ * - to save 2 new entities belonging to second-extractor
55
+ * - to return 2 new inserted entity data
56
+ */
57
+ it(`should correctly save boxes with different extractors`, async () => {
58
+ await repository.insert([
59
+ {
60
+ ...sampleEntities[0],
61
+ extractor: 'first-extractor',
62
+ block: '1',
63
+ height: 1,
64
+ },
65
+ {
66
+ ...sampleEntities[1],
67
+ extractor: 'first-extractor',
68
+ block: '1',
69
+ height: 1,
70
+ },
71
+ ]);
72
+ const result = await action.storeBoxes([sampleEntities[0], sampleEntities[1]], block, 'second-extractor');
73
+ const [insertedRows] = await repository.findAndCount();
74
+ expect(insertedRows[2]).toMatchObject({
75
+ ...sampleEntities[0],
76
+ extractor: 'second-extractor',
77
+ block: 'hash',
78
+ height: block.height,
79
+ spendBlock: null,
80
+ spendHeight: null,
81
+ });
82
+ expect(insertedRows[3]).toMatchObject({
83
+ ...sampleEntities[1],
84
+ extractor: 'second-extractor',
85
+ block: 'hash',
86
+ height: block.height,
87
+ spendBlock: null,
88
+ spendHeight: null,
89
+ });
90
+ expect(result).toEqual(true);
91
+ });
92
+ /**
93
+ * @target storeBoxes should update boxes correctly
94
+ * @dependencies
95
+ * @scenario
96
+ * - insert 2 boxes
97
+ * - run test (call `storeBoxes` with the same boxes and updated info)
98
+ * @expected
99
+ * - to update the existing box in database
100
+ * - to return updated box id
101
+ */
102
+ it(`storeBoxes should update boxes correctly`, async () => {
103
+ await repository.insert([
104
+ {
105
+ ...sampleEntities[0],
106
+ extractor: 'extractor',
107
+ block: '1',
108
+ height: 1,
109
+ },
110
+ {
111
+ ...sampleEntities[1],
112
+ extractor: 'extractor',
113
+ block: '1',
114
+ height: 1,
115
+ },
116
+ ]);
117
+ const result = await action.storeBoxes([
118
+ {
119
+ ...sampleEntities[0],
120
+ serialized: 'updatedBoxSerialized',
121
+ },
122
+ ], block, 'extractor');
123
+ const [secondInsertRows, secondInsertRowsCount] = await repository.findAndCount();
124
+ expect(secondInsertRowsCount).toEqual(2);
125
+ expect(secondInsertRows[0]).toMatchObject({
126
+ ...sampleEntities[0],
127
+ extractor: 'extractor',
128
+ serialized: 'updatedBoxSerialized',
129
+ block: block.hash,
130
+ height: block.height,
131
+ spendBlock: null,
132
+ spendHeight: null,
133
+ });
134
+ expect(result).toEqual(true);
135
+ });
136
+ });
137
+ describe('spendBoxes', () => {
138
+ /**
139
+ * @target spendBoxes should set spendBlock and spendHeight for a set of boxes
140
+ * @dependencies
141
+ * @scenario
142
+ * - insert two boxes
143
+ * - mock spending information for the first box
144
+ * - run test (call `spendBoxes`)
145
+ * @expected
146
+ * - spend the first box
147
+ * - return boxId and serialized of spent box
148
+ */
149
+ it(`should set spendBlock and spendHeight for a set of boxes`, async () => {
150
+ await action.storeBoxes(sampleEntities.slice(0, 2), block, 'extractor1');
151
+ const spendBlock = { ...block, hash: 'spendHash', height: 10006016 };
152
+ const spendInfos = [
153
+ { txId: 'txId', boxId: sampleEntities[0].boxId, index: 0 },
154
+ ];
155
+ const spentBoxIds = await action.spendBoxes(spendInfos, spendBlock, 'extractor1');
156
+ const spentBoxes = await repository.findOneBy({
157
+ boxId: sampleEntities[0].boxId,
158
+ extractor: 'extractor1',
159
+ });
160
+ expect(spentBoxes).toMatchObject({
161
+ ...sampleEntities[0],
162
+ block: block.hash,
163
+ height: block.height,
164
+ extractor: 'extractor1',
165
+ spendBlock: spendBlock.hash,
166
+ spendHeight: spendBlock.height,
167
+ });
168
+ expect(spentBoxIds).toEqual([pick(sampleEntities[0], ['boxId'])]);
169
+ });
170
+ });
171
+ describe('deleteBlockBoxes', () => {
172
+ /**
173
+ * @target deleteBlockBoxes should delete the boxes created in the specified block
174
+ * @dependencies
175
+ * @scenario
176
+ * - insert four boxes created in two different blocks
177
+ * - run test(call `deleteBlockBoxes` to delete block2)
178
+ * @expected
179
+ * - to delete the two boxes created in block2
180
+ * - to return the deleted entity data
181
+ */
182
+ it(`should delete the boxes created in the specified block`, async () => {
183
+ await action.storeBoxes(sampleEntities.slice(0, 2), block, 'extractor1');
184
+ await action.storeBoxes(sampleEntities.slice(2), block2, 'extractor1');
185
+ const result = await action.deleteBlockBoxes(block2.hash, 'extractor1');
186
+ const [rows, rowsCount] = await repository.findAndCount();
187
+ expect(rowsCount).toEqual(2);
188
+ expect(rows.map((row) => row.boxId)).not.toContain(sampleEntities.slice(2).map((box) => box.boxId));
189
+ expect(result).toEqual({
190
+ deletedData: action.convertEntityToData(sampleEntities.slice(2)),
191
+ updatedData: [],
192
+ });
193
+ });
194
+ /**
195
+ * @target deleteBlockBoxes should update the boxes spent in the specified block
196
+ * @dependencies
197
+ * @scenario
198
+ * - insert four boxes created in a block
199
+ * - spend one of the in the block2
200
+ * - run test(call `deleteBlockBoxes` to delete block2)
201
+ * @expected
202
+ * - to update the box spent in block2
203
+ * - to return the updated entity boxId and serialized
204
+ */
205
+ it(`should update the boxes spent in the specified block`, async () => {
206
+ await action.storeBoxes(sampleEntities, block, 'extractor1');
207
+ const spendInfos = [
208
+ { txId: 'txId', boxId: sampleEntities[0].boxId, index: 0 },
209
+ ];
210
+ await action.spendBoxes(spendInfos, block2, 'extractor1');
211
+ const result = await action.deleteBlockBoxes(block2.hash, 'extractor1');
212
+ const [rows, rowsCount] = await repository.findAndCount();
213
+ expect(rowsCount).toEqual(4);
214
+ expect(rows.map((row) => row.boxId)).not.toContain(sampleEntities.slice(2).map((box) => box.boxId));
215
+ expect(result).toEqual({
216
+ deletedData: [],
217
+ updatedData: [pick(sampleEntities[0], ['boxId'])],
218
+ });
219
+ });
220
+ });
221
+ });
222
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RFcmdvRXh0cmFjdG9yQWN0aW9uLnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90ZXN0cy9BYnN0cmFjdEVyZ29FeHRyYWN0b3JBY3Rpb24uc3BlYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQzFELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFakMsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFDN0UsT0FBTyxFQUFFLGNBQWMsRUFBRSxVQUFVLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDekQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsY0FBYyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRzNELFFBQVEsQ0FBQyw2QkFBNkIsRUFBRSxHQUFHLEVBQUU7SUFDM0MsSUFBSSxVQUFzQixDQUFDO0lBQzNCLElBQUksTUFBK0IsQ0FBQztJQUNwQyxJQUFJLFVBQWtDLENBQUM7SUFDdkMsVUFBVSxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQ3BCLFVBQVUsR0FBRyxNQUFNLGNBQWMsRUFBRSxDQUFDO1FBQ3BDLE1BQU0sR0FBRyxJQUFJLHVCQUF1QixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2pELFVBQVUsR0FBRyxVQUFVLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3BELENBQUMsQ0FBQyxDQUFDO0lBRUgsUUFBUSxDQUFDLFlBQVksRUFBRSxHQUFHLEVBQUU7UUFDMUI7Ozs7Ozs7O1dBUUc7UUFDSCxFQUFFLENBQUMsaURBQWlELEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDL0QsTUFBTSxNQUFNLEdBQUcsTUFBTSxNQUFNLENBQUMsVUFBVSxDQUNwQyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMs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QkFDckIsV0FBVyxFQUFFLEVBQUU7Z0JBQ2YsV0FBVyxFQUFFLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7YUFDbEQsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGF0YVNvdXJjZSwgUmVwb3NpdG9yeSB9IGZyb20gJ0Byb3Nlbi1icmlkZ2UvZXh0ZW5kZWQtdHlwZW9ybSc7XG5pbXBvcnQgeyBkZXNjcmliZSwgaXQsIGV4cGVjdCwgYmVmb3JlRWFjaCB9IGZyb20gJ3ZpdGVzdCc7XG5pbXBvcnQgeyBwaWNrIH0gZnJvbSAnbG9kYXNoLWVzJztcblxuaW1wb3J0IHsgVGVzdEVyZ29FeHRyYWN0b3JBY3Rpb24gfSBmcm9tICcuL0Fic3RyYWN0RXJnb0V4dHJhY3RvckFjdGlvbi5tb2NrJztcbmltcG9ydCB7IGNyZWF0ZURhdGFiYXNlLCBUZXN0RW50aXR5IH0gZnJvbSAnLi90ZXN0VXRpbHMnO1xuaW1wb3J0IHsgYmxvY2ssIGJsb2NrMiwgc2FtcGxlRW50aXRpZXMgfSBmcm9tICcuL3Rlc3REYXRhJztcbmltcG9ydCB7IFNwZW5kSW5mbyB9IGZyb20gJy4uL2xpYic7XG5cbmRlc2NyaWJlKCdBYnN0cmFjdEVyZ29FeHRyYWN0b3JBY3Rpb24nLCAoKSA9PiB7XG4gIGxldCBkYXRhU291cmNlOiBEYXRhU291cmNlO1xuICBsZXQgYWN0aW9uOiBUZXN0RXJnb0V4dHJhY3RvckFjdGlvbjtcbiAgbGV0IHJlcG9zaXRvcnk6IFJlcG9zaXRvcnk8VGVzdEVudGl0eT47XG4gIGJlZm9yZUVhY2goYXN5bmMgKCkgPT4ge1xuICAgIGRhdGFTb3VyY2UgPSBhd2FpdCBjcmVhdGVEYXRhYmFzZSgpO1xuICAgIGFjdGlvbiA9IG5ldyBUZXN0RXJnb0V4dHJhY3RvckFjdGlvbihkYXRhU291cmNlKTtcbiAgICByZXBvc2l0b3J5ID0gZGF0YVNvdXJjZS5nZXRSZXBvc2l0b3J5KFRlc3RFbnRpdHkpO1xuICB9KTtcblxuICBkZXNjcmliZSgnc3RvcmVCb3hlcycsICgpID0+IHtcbiAgICAvKipcbiAgICAgKiBAdGFyZ2V0IHN0b3JlQm94ZXMgc2hvdWxkIHNhdmUgdGhlIHBhc3NlZCBib3ggZW50aXRpZXMgdG8gZGF0YWJhc2VcbiAgICAgKiBAZGVwZW5kZW5jaWVzXG4gICAgICogQHNjZW5hcmlvXG4gICAgICogLSBydW4gdGVzdCAoY2FsbCBgc3RvcmVCb3hlc2Agd2l0aCAyIG5ldyBib3hlcylcbiAgICAgKiBAZXhwZWN0ZWRcbiAgICAgKiAtIHRvIHNhdmUgMiBuZXcgZW50aXRpZXNcbiAgICAgKiAtIHRvIHJldHVybiAyIGluc2VydGVkIGVudGl0eSBkYXRhXG4gICAgICovXG4gICAgaXQoYHNob3VsZCBzYXZlIHRoZSBwYXNzZWQgYm94IGVudGl0aWVzIHRvIGRhdGFiYXNlYCwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYWN0aW9uLnN0b3JlQm94ZXMoXG4gICAgICAgIHNhbXBsZUVudGl0aWVzLnNsaWNlKDAsIDIpLFxuICAgICAgICBibG9jayxcbiAgICAgICAgJ2V4dHJhY3RvcjEnXG4gICAgICApO1xuXG4gICAgICBjb25zdCBbcm93cywgcm93c0NvdW50XSA9IGF3YWl0IHJlcG9zaXRvcnkuZmluZEFuZENvdW50KCk7XG5cbiAgICAgIGV4cGVjdChyb3dzQ291bnQpLnRvRXF1YWwoMik7XG4gICAgICBleHBlY3Qocm93c1swXSkudG9NYXRjaE9iamVjdCh7XG4gICAgICAgIC4uLnNhbXBsZUVudGl0aWVzWzBdLFxuICAgICAgICBleHRyYWN0b3I6ICdleHRyYWN0b3IxJyxcbiAgICAgICAgYmxvY2s6IGJsb2NrLmhhc2gsXG4gICAgICAgIGhlaWdodDogYmxvY2suaGVpZ2h0LFxuICAgICAgICBzcGVuZEJsb2NrOiBudWxsLFxuICAgICAgICBzcGVuZEhlaWdodDogbnVsbCxcbiAgICAgIH0pO1xuICAgICAgZXhwZWN0KHJvd3NbMV0pLnRvTWF0Y2hPYmplY3Qoe1xuICAgICAgICAuLi5zYW1wbGVFbnRpdGllc1sxXSxcbiAgICAgICAgZXh0cmFjdG9yOiAnZXh0cmFjdG9yMScsXG4gICAgICAgIGJsb2NrOiBibG9jay5oYXNoLFxuICAgICAgICBoZWlnaHQ6IGJsb2NrLmhlaWdodCxcbiAgICAgICAgc3BlbmRCbG9jazogbnVsbCxcbiAgICAgICAgc3BlbmRIZWlnaHQ6IG51bGwsXG4gICAgICB9KTtcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBAdGFyZ2V0IHN0b3JlQm94ZXMgc2hvdWxkIGNvcnJlY3RseSBzYXZlIGJveGVzIHdpdGggZGlmZmVyZW50IGV4dHJhY3RvcnNcbiAgICAgKiBAZGVwZW5kZW5jaWVzXG4gICAgICogQHNjZW5hcmlvXG4gICAgICogLSBpbnNlcnQgMiBib3hlcyBiZWxvbmdpbmcgdG8gZmlyc3QtZXh0cmFjdG9yXG4gICAgICogLSBydW4gdGVzdCAoY2FsbCBgc3RvcmVCb3hlc2Agd2l0aCBzYW1lIGJveGVzIGZvciB0aGUgc2Vjb25kLWV4dHJhY3RvcilcbiAgICAgKiBAZXhwZWN0ZWRcbiAgICAgKiAtIHRvIHNhdmUgMiBuZXcgZW50aXRpZXMgYmVsb25naW5nIHRvIHNlY29uZC1leHRyYWN0b3JcbiAgICAgKiAtIHRvIHJldHVybiAyIG5ldyBpbnNlcnRlZCBlbnRpdHkgZGF0YVxuICAgICAqL1xuICAgIGl0KGBzaG91bGQgY29ycmVjdGx5IHNhdmUgYm94ZXMgd2l0aCBkaWZmZXJlbnQgZXh0cmFjdG9yc2AsIGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHJlcG9zaXRvcnkuaW5zZXJ0KFtcbiAgICAgICAge1xuICAgICAgICAgIC4uLnNhbXBsZUVudGl0aWVzWzBdLFxuICAgICAgICAgIGV4dHJhY3RvcjogJ2ZpcnN0LWV4dHJhY3RvcicsXG4gICAgICAgICAgYmxvY2s6ICcxJyxcbiAgICAgICAgICBoZWlnaHQ6IDEsXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICAuLi5zYW1wbGVFbnRpdGllc1sxXSxcbiAgICAgICAgICBleHRyYWN0b3I6ICdmaXJzdC1leHRyYWN0b3InLFxuICAgICAgICAgIGJsb2NrOiAnMScsXG4gICAgICAgICAgaGVpZ2h0OiAxLFxuICAgICAgICB9LFxuICAgICAgXSk7XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGFjdGlvbi5zdG9yZUJveGVzKFxuICAgICAgICBbc2FtcGxlRW50aXRpZXNbMF0sIHNhbXBsZUVudGl0aWVzWzFdXSxcbiAgICAgICAgYmxvY2ssXG4gICAgICAgICdzZWNvbmQtZXh0cmFjdG9yJ1xuICAgICAgKTtcblxuICAgICAgY29uc3QgW2luc2VydGVkUm93c10gPSBhd2FpdCByZXBvc2l0b3J5LmZpbmRBbmRDb3VudCgpO1xuICAgICAgZXhwZWN0KGluc2VydGVkUm93c1syXSkudG9NYXRjaE9iamVjdCh7XG4gICAgICAgIC4uLnNhbXBsZUVudGl0aWVzWzBdLFxuICAgICAgICBleHRyYWN0b3I6ICdzZWNvbmQtZXh0cmFjdG9yJyxcbiAgICAgICAgYmxvY2s6ICdoYXNoJyxcbiAgICAgICAgaGVpZ2h0OiBibG9jay5oZWlnaHQsXG4gICAgICAgIHNwZW5kQmxvY2s6IG51bGwsXG4gICAgICAgIHNwZW5kSGVpZ2h0OiBudWxsLFxuICAgICAgfSk7XG5cbiAgICAgIGV4cGVjdChpbnNlcnRlZFJvd3NbM10pLnRvTWF0Y2hPYmplY3Qoe1xuICAgICAgICAuLi5zYW1wbGVFbnRpdGllc1sxXSxcbiAgICAgICAgZXh0cmFjdG9yOiAnc2Vjb25kLWV4dHJhY3RvcicsXG4gICAgICAgIGJsb2NrOiAnaGFzaCcsXG4gICAgICAgIGhlaWdodDogYmxvY2suaGVpZ2h0LFxuICAgICAgICBzcGVuZEJsb2NrOiBudWxsLFxuICAgICAgICBzcGVuZEhlaWdodDogbnVsbCxcbiAgICAgIH0pO1xuICAgICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIEB0YXJnZXQgc3RvcmVCb3hlcyBzaG91bGQgdXBkYXRlIGJveGVzIGNvcnJlY3RseVxuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIGluc2VydCAyIGJveGVzXG4gICAgICogLSBydW4gdGVzdCAoY2FsbCBgc3RvcmVCb3hlc2Agd2l0aCB0aGUgc2FtZSBib3hlcyBhbmQgdXBkYXRlZCBpbmZvKVxuICAgICAqIEBleHBlY3RlZFxuICAgICAqIC0gdG8gdXBkYXRlIHRoZSBleGlzdGluZyBib3ggaW4gZGF0YWJhc2VcbiAgICAgKiAtIHRvIHJldHVybiB1cGRhdGVkIGJveCBpZFxuICAgICAqL1xuICAgIGl0KGBzdG9yZUJveGVzIHNob3VsZCB1cGRhdGUgYm94ZXMgY29ycmVjdGx5YCwgYXN5bmMgKCkgPT4ge1xuICAgICAgYXdhaXQgcmVwb3NpdG9yeS5pbnNlcnQoW1xuICAgICAgICB7XG4gICAgICAgICAgLi4uc2FtcGxlRW50aXRpZXNbMF0sXG4gICAgICAgICAgZXh0cmFjdG9yOiAnZXh0cmFjdG9yJyxcbiAgICAgICAgICBibG9jazogJzEnLFxuICAgICAgICAgIGhlaWdodDogMSxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIC4uLnNhbXBsZUVudGl0aWVzWzFdLFxuICAgICAgICAgIGV4dHJhY3RvcjogJ2V4dHJhY3RvcicsXG4gICAgICAgICAgYmxvY2s6ICcxJyxcbiAgICAgICAgICBoZWlnaHQ6IDEsXG4gICAgICAgIH0sXG4gICAgICBdKTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYWN0aW9uLnN0b3JlQm94ZXMoXG4gICAgICAgIFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICAuLi5zYW1wbGVFbnRpdGllc1swXSxcbiAgICAgICAgICAgIHNlcmlhbGl6ZWQ6ICd1cGRhdGVkQm94U2VyaWFsaXplZCcsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgICAgYmxvY2ssXG4gICAgICAgICdleHRyYWN0b3InXG4gICAgICApO1xuICAgICAgY29uc3QgW3NlY29uZEluc2VydFJvd3MsIHNlY29uZEluc2VydFJvd3NDb3VudF0gPVxuICAgICAgICBhd2FpdCByZXBvc2l0b3J5LmZpbmRBbmRDb3VudCgpO1xuICAgICAgZXhwZWN0KHNlY29uZEluc2VydFJvd3NDb3VudCkudG9FcXVhbCgyKTtcbiAgICAgIGV4cGVjdChzZWNvbmRJbnNlcnRSb3dzWzBdKS50b01hdGNoT2JqZWN0KHtcbiAgICAgICAgLi4uc2FtcGxlRW50aXRpZXNbMF0sXG4gICAgICAgIGV4dHJhY3RvcjogJ2V4dHJhY3RvcicsXG4gICAgICAgIHNlcmlhbGl6ZWQ6ICd1cGRhdGVkQm94U2VyaWFsaXplZCcsXG4gICAgICAgIGJsb2NrOiBibG9jay5oYXNoLFxuICAgICAgICBoZWlnaHQ6IGJsb2NrLmhlaWdodCxcbiAgICAgICAgc3BlbmRCbG9jazogbnVsbCxcbiAgICAgICAgc3BlbmRIZWlnaHQ6IG51bGwsXG4gICAgICB9KTtcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwodHJ1ZSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdzcGVuZEJveGVzJywgKCkgPT4ge1xuICAgIC8qKlxuICAgICAqIEB0YXJnZXQgc3BlbmRCb3hlcyBzaG91bGQgc2V0IHNwZW5kQmxvY2sgYW5kIHNwZW5kSGVpZ2h0IGZvciBhIHNldCBvZiBib3hlc1xuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIGluc2VydCB0d28gYm94ZXNcbiAgICAgKiAtIG1vY2sgc3BlbmRpbmcgaW5mb3JtYXRpb24gZm9yIHRoZSBmaXJzdCBib3hcbiAgICAgKiAtIHJ1biB0ZXN0IChjYWxsIGBzcGVuZEJveGVzYClcbiAgICAgKiBAZXhwZWN0ZWRcbiAgICAgKiAtIHNwZW5kIHRoZSBmaXJzdCBib3hcbiAgICAgKiAtIHJldHVybiBib3hJZCBhbmQgc2VyaWFsaXplZCBvZiBzcGVudCBib3hcbiAgICAgKi9cbiAgICBpdChgc2hvdWxkIHNldCBzcGVuZEJsb2NrIGFuZCBzcGVuZEhlaWdodCBmb3IgYSBzZXQgb2YgYm94ZXNgLCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBhY3Rpb24uc3RvcmVCb3hlcyhzYW1wbGVFbnRpdGllcy5zbGljZSgwLCAyKSwgYmxvY2ssICdleHRyYWN0b3IxJyk7XG5cbiAgICAgIGNvbnN0IHNwZW5kQmxvY2sgPSB7IC4uLmJsb2NrLCBoYXNoOiAnc3BlbmRIYXNoJywgaGVpZ2h0OiAxMDAwNjAxNiB9O1xuICAgICAgY29uc3Qgc3BlbmRJbmZvczogQXJyYXk8U3BlbmRJbmZvPiA9IFtcbiAgICAgICAgeyB0eElkOiAndHhJZCcsIGJveElkOiBzYW1wbGVFbnRpdGllc1swXS5ib3hJZCwgaW5kZXg6IDAgfSxcbiAgICAgIF07XG5cbiAgICAgIGNvbnN0IHNwZW50Qm94SWRzID0gYXdhaXQgYWN0aW9uLnNwZW5kQm94ZXMoXG4gICAgICAgIHNwZW5kSW5mb3MsXG4gICAgICAgIHNwZW5kQmxvY2ssXG4gICAgICAgICdleHRyYWN0b3IxJ1xuICAgICAgKTtcblxuICAgICAgY29uc3Qgc3BlbnRCb3hlcyA9IGF3YWl0IHJlcG9zaXRvcnkuZmluZE9uZUJ5KHtcbiAgICAgICAgYm94SWQ6IHNhbXBsZUVudGl0aWVzWzBdLmJveElkLFxuICAgICAgICBleHRyYWN0b3I6ICdleHRyYWN0b3IxJyxcbiAgICAgIH0pO1xuXG4gICAgICBleHBlY3Qoc3BlbnRCb3hlcykudG9NYXRjaE9iamVjdCh7XG4gICAgICAgIC4uLnNhbXBsZUVudGl0aWVzWzBdLFxuICAgICAgICBibG9jazogYmxvY2suaGFzaCxcbiAgICAgICAgaGVpZ2h0OiBibG9jay5oZWlnaHQsXG4gICAgICAgIGV4dHJhY3RvcjogJ2V4dHJhY3RvcjEnLFxuICAgICAgICBzcGVuZEJsb2NrOiBzcGVuZEJsb2NrLmhhc2gsXG4gICAgICAgIHNwZW5kSGVpZ2h0OiBzcGVuZEJsb2NrLmhlaWdodCxcbiAgICAgIH0pO1xuICAgICAgZXhwZWN0KHNwZW50Qm94SWRzKS50b0VxdWFsKFtwaWNrKHNhbXBsZUVudGl0aWVzWzBdLCBbJ2JveElkJ10pXSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdkZWxldGVCbG9ja0JveGVzJywgKCkgPT4ge1xuICAgIC8qKlxuICAgICAqIEB0YXJnZXQgZGVsZXRlQmxvY2tCb3hlcyBzaG91bGQgZGVsZXRlIHRoZSBib3hlcyBjcmVhdGVkIGluIHRoZSBzcGVjaWZpZWQgYmxvY2tcbiAgICAgKiBAZGVwZW5kZW5jaWVzXG4gICAgICogQHNjZW5hcmlvXG4gICAgICogLSBpbnNlcnQgZm91ciBib3hlcyBjcmVhdGVkIGluIHR3byBkaWZmZXJlbnQgYmxvY2tzXG4gICAgICogLSBydW4gdGVzdChjYWxsIGBkZWxldGVCbG9ja0JveGVzYCB0byBkZWxldGUgYmxvY2syKVxuICAgICAqIEBleHBlY3RlZFxuICAgICAqIC0gdG8gZGVsZXRlIHRoZSB0d28gYm94ZXMgY3JlYXRlZCBpbiBibG9jazJcbiAgICAgKiAtIHRvIHJldHVybiB0aGUgZGVsZXRlZCBlbnRpdHkgZGF0YVxuICAgICAqL1xuICAgIGl0KGBzaG91bGQgZGVsZXRlIHRoZSBib3hlcyBjcmVhdGVkIGluIHRoZSBzcGVjaWZpZWQgYmxvY2tgLCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBhY3Rpb24uc3RvcmVCb3hlcyhzYW1wbGVFbnRpdGllcy5zbGljZSgwLCAyKSwgYmxvY2ssICdleHRyYWN0b3IxJyk7XG4gICAgICBhd2FpdCBhY3Rpb24uc3RvcmVCb3hlcyhzYW1wbGVFbnRpdGllcy5zbGljZSgyKSwgYmxvY2syLCAnZXh0cmFjdG9yMScpO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBhY3Rpb24uZGVsZXRlQmxvY2tCb3hlcyhibG9jazIuaGFzaCwgJ2V4dHJhY3RvcjEnKTtcblxuICAgICAgY29uc3QgW3Jvd3MsIHJvd3NDb3VudF0gPSBhd2FpdCByZXBvc2l0b3J5LmZpbmRBbmRDb3VudCgpO1xuXG4gICAgICBleHBlY3Qocm93c0NvdW50KS50b0VxdWFsKDIpO1xuICAgICAgZXhwZWN0KHJvd3MubWFwKChyb3cpID0+IHJvdy5ib3hJZCkpLm5vdC50b0NvbnRhaW4oXG4gICAgICAgIHNhbXBsZUVudGl0aWVzLnNsaWNlKDIpLm1hcCgoYm94KSA9PiBib3guYm94SWQpXG4gICAgICApO1xuICAgICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbCh7XG4gICAgICAgIGRlbGV0ZWREYXRhOiBhY3Rpb24uY29udmVydEVudGl0eVRvRGF0YShcbiAgICAgICAgICBzYW1wbGVFbnRpdGllcy5zbGljZSgyKSBhcyBUZXN0RW50aXR5W11cbiAgICAgICAgKSxcbiAgICAgICAgdXBkYXRlZERhdGE6IFtdLFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBAdGFyZ2V0IGRlbGV0ZUJsb2NrQm94ZXMgc2hvdWxkIHVwZGF0ZSB0aGUgYm94ZXMgc3BlbnQgaW4gdGhlIHNwZWNpZmllZCBibG9ja1xuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIGluc2VydCBmb3VyIGJveGVzIGNyZWF0ZWQgaW4gYSBibG9ja1xuICAgICAqIC0gc3BlbmQgb25lIG9mIHRoZSBpbiB0aGUgYmxvY2syXG4gICAgICogLSBydW4gdGVzdChjYWxsIGBkZWxldGVCbG9ja0JveGVzYCB0byBkZWxldGUgYmxvY2syKVxuICAgICAqIEBleHBlY3RlZFxuICAgICAqIC0gdG8gdXBkYXRlIHRoZSBib3ggc3BlbnQgaW4gYmxvY2syXG4gICAgICogLSB0byByZXR1cm4gdGhlIHVwZGF0ZWQgZW50aXR5IGJveElkIGFuZCBzZXJpYWxpemVkXG4gICAgICovXG4gICAgaXQoYHNob3VsZCB1cGRhdGUgdGhlIGJveGVzIHNwZW50IGluIHRoZSBzcGVjaWZpZWQgYmxvY2tgLCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBhY3Rpb24uc3RvcmVCb3hlcyhzYW1wbGVFbnRpdGllcywgYmxvY2ssICdleHRyYWN0b3IxJyk7XG4gICAgICBjb25zdCBzcGVuZEluZm9zOiBBcnJheTxTcGVuZEluZm8+ID0gW1xuICAgICAgICB7IHR4SWQ6ICd0eElkJywgYm94SWQ6IHNhbXBsZUVudGl0aWVzWzBdLmJveElkLCBpbmRleDogMCB9LFxuICAgICAgXTtcbiAgICAgIGF3YWl0IGFjdGlvbi5zcGVuZEJveGVzKHNwZW5kSW5mb3MsIGJsb2NrMiwgJ2V4dHJhY3RvcjEnKTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGFjdGlvbi5kZWxldGVCbG9ja0JveGVzKGJsb2NrMi5oYXNoLCAnZXh0cmFjdG9yMScpO1xuXG4gICAgICBjb25zdCBbcm93cywgcm93c0NvdW50XSA9IGF3YWl0IHJlcG9zaXRvcnkuZmluZEFuZENvdW50KCk7XG5cbiAgICAgIGV4cGVjdChyb3dzQ291bnQpLnRvRXF1YWwoNCk7XG4gICAgICBleHBlY3Qocm93cy5tYXAoKHJvdykgPT4gcm93LmJveElkKSkubm90LnRvQ29udGFpbihcbiAgICAgICAgc2FtcGxlRW50aXRpZXMuc2xpY2UoMikubWFwKChib3gpID0+IGJveC5ib3hJZClcbiAgICAgICk7XG4gICAgICBleHBlY3QocmVzdWx0KS50b0VxdWFsKHtcbiAgICAgICAgZGVsZXRlZERhdGE6IFtdLFxuICAgICAgICB1cGRhdGVkRGF0YTogW3BpY2soc2FtcGxlRW50aXRpZXNbMF0sIFsnYm94SWQnXSldLFxuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=