@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.
- package/CHANGELOG.md +14 -0
- package/dist/ergo/AbstractErgoExtractor.d.ts.map +1 -1
- package/dist/ergo/AbstractErgoExtractor.js +3 -2
- package/dist/ergo/AbstractErgoExtractorAction.d.ts +1 -1
- package/dist/ergo/AbstractErgoExtractorAction.d.ts.map +1 -1
- package/dist/ergo/AbstractErgoExtractorAction.js +23 -9
- package/dist/ergo/AbstractErgoExtractorEntity.js +2 -2
- package/dist/ergo/initializable/AbstractInitializableAction.d.ts +1 -1
- package/dist/ergo/initializable/AbstractInitializableAction.d.ts.map +1 -1
- package/dist/ergo/initializable/AbstractInitializableAction.js +4 -2
- package/dist/lib/abstractExtractor.d.ts +25 -0
- package/dist/lib/abstractExtractor.d.ts.map +1 -0
- package/dist/lib/abstractExtractor.js +3 -0
- package/dist/lib/constants.d.ts +4 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +4 -0
- package/dist/lib/ergo/AbstractErgoExtractor.d.ts +80 -0
- package/dist/lib/ergo/AbstractErgoExtractor.d.ts.map +1 -0
- package/dist/lib/ergo/AbstractErgoExtractor.js +143 -0
- package/dist/lib/ergo/AbstractErgoExtractorAction.d.ts +87 -0
- package/dist/lib/ergo/AbstractErgoExtractorAction.d.ts.map +1 -0
- package/dist/lib/ergo/AbstractErgoExtractorAction.js +222 -0
- package/dist/lib/ergo/AbstractErgoExtractorEntity.d.ts +11 -0
- package/dist/lib/ergo/AbstractErgoExtractorEntity.d.ts.map +1 -0
- package/dist/lib/ergo/AbstractErgoExtractorEntity.js +57 -0
- package/dist/lib/ergo/index.d.ts +10 -0
- package/dist/lib/ergo/index.d.ts.map +1 -0
- package/dist/lib/ergo/index.js +10 -0
- package/dist/lib/ergo/initializable/AbstractInitializable.d.ts +48 -0
- package/dist/lib/ergo/initializable/AbstractInitializable.d.ts.map +1 -0
- package/dist/lib/ergo/initializable/AbstractInitializable.js +163 -0
- package/dist/lib/ergo/initializable/AbstractInitializableAction.d.ts +14 -0
- package/dist/lib/ergo/initializable/AbstractInitializableAction.d.ts.map +1 -0
- package/dist/lib/ergo/initializable/AbstractInitializableAction.js +16 -0
- package/dist/lib/ergo/initializable/index.d.ts +3 -0
- package/dist/lib/ergo/initializable/index.d.ts.map +1 -0
- package/dist/lib/ergo/initializable/index.js +3 -0
- package/dist/lib/ergo/interfaces.d.ts +47 -0
- package/dist/lib/ergo/interfaces.d.ts.map +1 -0
- package/dist/lib/ergo/interfaces.js +8 -0
- package/dist/lib/ergo/network/AbstractNetwork.d.ts +26 -0
- package/dist/lib/ergo/network/AbstractNetwork.d.ts.map +1 -0
- package/dist/lib/ergo/network/AbstractNetwork.js +3 -0
- package/dist/lib/ergo/network/ExplorerNetwork.d.ts +74 -0
- package/dist/lib/ergo/network/ExplorerNetwork.d.ts.map +1 -0
- package/dist/lib/ergo/network/ExplorerNetwork.js +185 -0
- package/dist/lib/ergo/network/NodeNetwork.d.ts +60 -0
- package/dist/lib/ergo/network/NodeNetwork.d.ts.map +1 -0
- package/dist/lib/ergo/network/NodeNetwork.js +131 -0
- package/dist/lib/ergo/utils.d.ts +8 -0
- package/dist/lib/ergo/utils.d.ts.map +1 -0
- package/dist/lib/ergo/utils.js +16 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +4 -0
- package/dist/tests/AbstractErgoExtractor.mock.d.ts +11 -0
- package/dist/tests/AbstractErgoExtractor.mock.d.ts.map +1 -0
- package/dist/tests/AbstractErgoExtractor.mock.js +13 -0
- package/dist/tests/AbstractErgoExtractor.spec.d.ts +2 -0
- package/dist/tests/AbstractErgoExtractor.spec.d.ts.map +1 -0
- package/dist/tests/AbstractErgoExtractor.spec.js +241 -0
- package/dist/tests/AbstractErgoExtractorAction.mock.d.ts +15 -0
- package/dist/tests/AbstractErgoExtractorAction.mock.d.ts.map +1 -0
- package/dist/tests/AbstractErgoExtractorAction.mock.js +27 -0
- package/dist/tests/AbstractErgoExtractorAction.spec.d.ts +2 -0
- package/dist/tests/AbstractErgoExtractorAction.spec.d.ts.map +1 -0
- package/dist/tests/AbstractErgoExtractorAction.spec.js +222 -0
- package/dist/tests/initializable/AbstractInitializable.mock.d.ts +60 -0
- package/dist/tests/initializable/AbstractInitializable.mock.d.ts.map +1 -0
- package/dist/tests/initializable/AbstractInitializable.mock.js +22 -0
- package/dist/tests/initializable/AbstractInitializable.spec.d.ts +2 -0
- package/dist/tests/initializable/AbstractInitializable.spec.d.ts.map +1 -0
- package/dist/tests/initializable/AbstractInitializable.spec.js +300 -0
- package/dist/tests/initializable/AbstractInitializableAction.mock.d.ts +15 -0
- package/dist/tests/initializable/AbstractInitializableAction.mock.d.ts.map +1 -0
- package/dist/tests/initializable/AbstractInitializableAction.mock.js +27 -0
- package/dist/tests/initializable/AbstractInitializableAction.spec.d.ts +2 -0
- package/dist/tests/initializable/AbstractInitializableAction.spec.d.ts.map +1 -0
- package/dist/tests/initializable/AbstractInitializableAction.spec.js +55 -0
- package/dist/tests/initializable/testData.d.ts +94 -0
- package/dist/tests/initializable/testData.d.ts.map +1 -0
- package/dist/tests/initializable/testData.js +235 -0
- package/dist/tests/network/ExplorerNetwork.spec.d.ts +2 -0
- package/dist/tests/network/ExplorerNetwork.spec.d.ts.map +1 -0
- package/dist/tests/network/ExplorerNetwork.spec.js +62 -0
- package/dist/tests/network/NodeNetwork.spec.d.ts +2 -0
- package/dist/tests/network/NodeNetwork.spec.d.ts.map +1 -0
- package/dist/tests/network/NodeNetwork.spec.js +49 -0
- package/dist/tests/network/testData.d.ts +752 -0
- package/dist/tests/network/testData.d.ts.map +1 -0
- package/dist/tests/network/testData.js +1401 -0
- package/dist/tests/testData.d.ts +32 -0
- package/dist/tests/testData.d.ts.map +1 -0
- package/dist/tests/testData.js +121 -0
- package/dist/tests/testUtils.d.ts +9 -0
- package/dist/tests/testUtils.d.ts.map +1 -0
- package/dist/tests/testUtils.js +31 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +17 -0
- package/lib/ergo/AbstractErgoExtractor.ts +3 -1
- package/lib/ergo/AbstractErgoExtractorAction.ts +47 -36
- package/lib/ergo/AbstractErgoExtractorEntity.ts +1 -1
- package/lib/ergo/initializable/AbstractInitializableAction.ts +4 -2
- package/package.json +9 -14
- package/tests/AbstractErgoExtractor.mock.ts +4 -2
- package/tests/AbstractErgoExtractorAction.mock.ts +1 -1
- package/tests/AbstractErgoExtractorAction.spec.ts +1 -1
- package/tests/initializable/AbstractInitializable.mock.ts +13 -4
- package/tests/initializable/AbstractInitializable.spec.ts +1 -9
- package/tests/initializable/AbstractInitializableAction.mock.ts +1 -1
- package/tests/initializable/AbstractInitializableAction.spec.ts +1 -1
- package/tests/testUtils.ts +1 -1
- 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 @@
|
|
|
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=
|