@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,60 @@
1
+ import { V1 } from '@rosen-clients/ergo-explorer';
2
+ import { BlockInfo, OutputBox } from '@rosen-bridge/scanner-interfaces';
3
+ import { AbstractInitializableErgoExtractor, AbstractInitializableErgoExtractorAction } from '../../lib/ergo/initializable';
4
+ import { AbstractBoxData, AbstractErgoExtractorEntity } from '../../lib';
5
+ export declare class MockedInitializableErgoExtractor extends AbstractInitializableErgoExtractor<AbstractBoxData, AbstractErgoExtractorEntity> {
6
+ actions: AbstractInitializableErgoExtractorAction<AbstractBoxData, AbstractErgoExtractorEntity>;
7
+ getId: () => string;
8
+ hasData: (box: V1.OutputInfo | OutputBox) => boolean;
9
+ getTxBlock: (txId: string) => Promise<BlockInfo>;
10
+ getBoxesWithOffsetLimit: (offset: number, limit: number) => Promise<{
11
+ boxes: ({
12
+ boxId: string;
13
+ transactionId: string;
14
+ blockId: string;
15
+ value: bigint;
16
+ index: number;
17
+ creationHeight: number;
18
+ inclusionHeight: number;
19
+ ergoTree: string;
20
+ address: string;
21
+ assets: {
22
+ tokenId: string;
23
+ index: number;
24
+ amount: bigint;
25
+ name: string;
26
+ decimals: number;
27
+ }[];
28
+ additionalRegisters: {};
29
+ spentHeight?: undefined;
30
+ spentBlockId?: undefined;
31
+ spentTransactionId?: undefined;
32
+ spentIndex?: undefined;
33
+ } | {
34
+ boxId: string;
35
+ transactionId: string;
36
+ blockId: string;
37
+ value: bigint;
38
+ index: number;
39
+ creationHeight: number;
40
+ inclusionHeight: number;
41
+ ergoTree: string;
42
+ address: string;
43
+ assets: {
44
+ tokenId: string;
45
+ index: number;
46
+ amount: bigint;
47
+ name: string;
48
+ decimals: number;
49
+ }[];
50
+ additionalRegisters: {};
51
+ spentHeight: number;
52
+ spentBlockId: string;
53
+ spentTransactionId: string;
54
+ spentIndex: number;
55
+ })[];
56
+ hasNextBatch: boolean;
57
+ }>;
58
+ extractBoxData: (box: V1.OutputInfo | OutputBox) => undefined;
59
+ }
60
+ //# sourceMappingURL=AbstractInitializable.mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractInitializable.mock.d.ts","sourceRoot":"","sources":["../../../tests/initializable/AbstractInitializable.mock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,8BAA8B,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAExE,OAAO,EACL,kCAAkC,EAClC,wCAAwC,EACzC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,WAAW,CAAC;AAGzE,qBAAa,gCAAiC,SAAQ,kCAAkC,CACtF,eAAe,EACf,2BAA2B,CAC5B;IACC,OAAO,EAAE,wCAAwC,CAC/C,eAAe,EACf,2BAA2B,CAC5B,CAAC;IAEF,KAAK,eAAgB;IAErB,OAAO,QACA,GAAG,UAAU,GAAG,SAAS,aACrB;IAEX,UAAU,SACF,MAAM,KACX,QAAQ,SAAS,CAAC,CAEnB;IAEF,uBAAuB,WACb,MAAM,SACP,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAGb;IAEF,cAAc,QACP,GAAG,UAAU,GAAG,SAAS,eAG9B;CACH"}
@@ -0,0 +1,22 @@
1
+ import { AbstractInitializableErgoExtractor, } from '../../lib/ergo/initializable';
2
+ import { ergoBoxes } from './testData';
3
+ export class MockedInitializableErgoExtractor extends AbstractInitializableErgoExtractor {
4
+ actions;
5
+ getId = () => 'Test';
6
+ hasData = (box // eslint-disable-line @typescript-eslint/no-unused-vars
7
+ ) => false;
8
+ getTxBlock = async (txId // eslint-disable-line @typescript-eslint/no-unused-vars
9
+ ) => {
10
+ return { hash: 'hash', height: 100 };
11
+ };
12
+ getBoxesWithOffsetLimit = (offset, // eslint-disable-line @typescript-eslint/no-unused-vars
13
+ limit // eslint-disable-line @typescript-eslint/no-unused-vars
14
+ ) => {
15
+ return Promise.resolve({ boxes: ergoBoxes, hasNextBatch: true });
16
+ };
17
+ extractBoxData = (box // eslint-disable-line @typescript-eslint/no-unused-vars
18
+ ) => {
19
+ return undefined;
20
+ };
21
+ }
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RJbml0aWFsaXphYmxlLm1vY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0cy9pbml0aWFsaXphYmxlL0Fic3RyYWN0SW5pdGlhbGl6YWJsZS5tb2NrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBLE9BQU8sRUFDTCxrQ0FBa0MsR0FFbkMsTUFBTSw4QkFBOEIsQ0FBQztBQUV0QyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBRXZDLE1BQU0sT0FBTyxnQ0FBaUMsU0FBUSxrQ0FHckQ7SUFDQyxPQUFPLENBR0w7SUFFRixLQUFLLEdBQUcsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDO0lBRXJCLE9BQU8sR0FBRyxDQUNSLEdBQThCLENBQUMsd0RBQXdEO01BQ3ZGLEVBQUUsQ0FBQyxLQUFLLENBQUM7SUFFWCxVQUFVLEdBQUcsS0FBSyxFQUNoQixJQUFZLENBQUMsd0RBQXdEO01BQ2pELEVBQUU7UUFDdEIsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDO0lBQ3ZDLENBQUMsQ0FBQztJQUVGLHVCQUF1QixHQUFHLENBQ3hCLE1BQWMsRUFBRSx3REFBd0Q7SUFDeEUsS0FBYSxDQUFDLHdEQUF3RDtNQUN0RSxFQUFFO1FBQ0YsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNuRSxDQUFDLENBQUM7SUFFRixjQUFjLEdBQUcsQ0FDZixHQUE4QixDQUFDLHdEQUF3RDtNQUN2RixFQUFFO1FBQ0YsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQyxDQUFDO0NBQ0giLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBWMSB9IGZyb20gJ0Byb3Nlbi1jbGllbnRzL2VyZ28tZXhwbG9yZXInO1xuaW1wb3J0IHsgQmxvY2tJbmZvLCBPdXRwdXRCb3ggfSBmcm9tICdAcm9zZW4tYnJpZGdlL3NjYW5uZXItaW50ZXJmYWNlcyc7XG5cbmltcG9ydCB7XG4gIEFic3RyYWN0SW5pdGlhbGl6YWJsZUVyZ29FeHRyYWN0b3IsXG4gIEFic3RyYWN0SW5pdGlhbGl6YWJsZUVyZ29FeHRyYWN0b3JBY3Rpb24sXG59IGZyb20gJy4uLy4uL2xpYi9lcmdvL2luaXRpYWxpemFibGUnO1xuaW1wb3J0IHsgQWJzdHJhY3RCb3hEYXRhLCBBYnN0cmFjdEVyZ29FeHRyYWN0b3JFbnRpdHkgfSBmcm9tICcuLi8uLi9saWInO1xuaW1wb3J0IHsgZXJnb0JveGVzIH0gZnJvbSAnLi90ZXN0RGF0YSc7XG5cbmV4cG9ydCBjbGFzcyBNb2NrZWRJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvciBleHRlbmRzIEFic3RyYWN0SW5pdGlhbGl6YWJsZUVyZ29FeHRyYWN0b3I8XG4gIEFic3RyYWN0Qm94RGF0YSxcbiAgQWJzdHJhY3RFcmdvRXh0cmFjdG9yRW50aXR5XG4+IHtcbiAgYWN0aW9uczogQWJzdHJhY3RJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvckFjdGlvbjxcbiAgICBBYnN0cmFjdEJveERhdGEsXG4gICAgQWJzdHJhY3RFcmdvRXh0cmFjdG9yRW50aXR5XG4gID47XG5cbiAgZ2V0SWQgPSAoKSA9PiAnVGVzdCc7XG5cbiAgaGFzRGF0YSA9IChcbiAgICBib3g6IFYxLk91dHB1dEluZm8gfCBPdXRwdXRCb3ggLy8gZXNsaW50LWRpc2FibGUtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgKSA9PiBmYWxzZTtcblxuICBnZXRUeEJsb2NrID0gYXN5bmMgKFxuICAgIHR4SWQ6IHN0cmluZyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICApOiBQcm9taXNlPEJsb2NrSW5mbz4gPT4ge1xuICAgIHJldHVybiB7IGhhc2g6ICdoYXNoJywgaGVpZ2h0OiAxMDAgfTtcbiAgfTtcblxuICBnZXRCb3hlc1dpdGhPZmZzZXRMaW1pdCA9IChcbiAgICBvZmZzZXQ6IG51bWJlciwgLy8gZXNsaW50LWRpc2FibGUtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICBsaW1pdDogbnVtYmVyIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICkgPT4ge1xuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoeyBib3hlczogZXJnb0JveGVzLCBoYXNOZXh0QmF0Y2g6IHRydWUgfSk7XG4gIH07XG5cbiAgZXh0cmFjdEJveERhdGEgPSAoXG4gICAgYm94OiBWMS5PdXRwdXRJbmZvIHwgT3V0cHV0Qm94IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICkgPT4ge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH07XG59XG4iXX0=
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=AbstractInitializable.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractInitializable.spec.d.ts","sourceRoot":"","sources":["../../../tests/initializable/AbstractInitializable.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,300 @@
1
+ import { describe, expect, it, vi, vitest } from 'vitest';
2
+ import { ErgoNetworkType } from '@rosen-bridge/scanner-interfaces';
3
+ import { MockedInitializableErgoExtractor } from './AbstractInitializable.mock';
4
+ import { transactionBatch } from './testData';
5
+ import { RETRIAL_COUNT } from '../../lib/constants';
6
+ describe('AbstractInitializableErgoExtractor', () => {
7
+ describe('getTotalTxCount', () => {
8
+ /**
9
+ * @target getTotalTxCount should return the total tx count
10
+ * @dependencies
11
+ * - explorer network
12
+ * @scenario
13
+ * - mock extractor
14
+ * - mock `getAddressTransactionsWithOffsetLimit` in node network
15
+ * - run test (call `getTotalTxCount`)
16
+ * @expected
17
+ * - return one total tx count
18
+ */
19
+ it('should return the total tx count', async () => {
20
+ const extractor = new MockedInitializableErgoExtractor(ErgoNetworkType.Node, 'node_url', 'address');
21
+ extractor['network'].getAddressTransactionsWithOffsetLimit = vitest.fn().mockResolvedValue({
22
+ items: [],
23
+ total: 196704,
24
+ });
25
+ const totalTxCount = await extractor['getTotalTxCount']();
26
+ expect(totalTxCount).toEqual(196704);
27
+ });
28
+ });
29
+ describe('processTransactionBatch', () => {
30
+ /**
31
+ * @target processTransactionBatch should group transactions and process them in correct order
32
+ * @dependencies
33
+ * @scenario
34
+ * - mock extractor
35
+ * - spy `processTransactions`
36
+ * - run test (call `processTransactionBatch`)
37
+ * @expected
38
+ * - to group txs in two blocks
39
+ * - to process each blocks transaction separately
40
+ */
41
+ it('should group transactions and process them in correct order', async () => {
42
+ const extractor = new MockedInitializableErgoExtractor(ErgoNetworkType.Node, 'node_url', 'address');
43
+ const processSpy = vitest.fn().mockResolvedValue(true);
44
+ extractor.processTransactions = processSpy;
45
+ await extractor['processTransactionBatch'](transactionBatch);
46
+ expect(processSpy).toBeCalledTimes(2);
47
+ expect(processSpy).toHaveBeenCalledWith([transactionBatch[2]], {
48
+ hash: '92eaff11a4a1c29b8654473258f9d837e9ce99fc0a8a4f27c484d5871afcde64',
49
+ height: 1320698,
50
+ });
51
+ expect(processSpy).toHaveBeenLastCalledWith(transactionBatch.slice(0, 2), {
52
+ hash: 'b861e2134821fcf1fcdad7e6edd56c4e4495b42b2fd72762a4c79ed1db78b44b',
53
+ height: 1320705,
54
+ });
55
+ });
56
+ /**
57
+ * @target processTransactionBatch should throw error when processing transactions fails for a block
58
+ * @dependencies
59
+ * @scenario
60
+ * - mock extractor
61
+ * - spy `processTransactions` to return false (always fails)
62
+ * - run test (call `processTransactionBatch`)
63
+ * @expected
64
+ * - to throw error
65
+ */
66
+ it('should throw error when processing transactions fails for a block', async () => {
67
+ const extractor = new MockedInitializableErgoExtractor(ErgoNetworkType.Node, 'node_url', 'address');
68
+ extractor.processTransactions = vitest.fn().mockResolvedValue(false);
69
+ await expect(() => extractor['processTransactionBatch'](transactionBatch)).rejects.toThrowError();
70
+ });
71
+ });
72
+ describe('initWithRetrial', () => {
73
+ /**
74
+ * @target initWithRetrial should not run the init job when its not set
75
+ * @dependencies
76
+ * - database
77
+ * @scenario
78
+ * - mock extractor with false initialization
79
+ * - mock `removeAllData` in database actions
80
+ * - mock init job
81
+ * - run test (call `initWithRetrial`)
82
+ * @expected
83
+ * - not to remove database old data
84
+ * - not to run the init job
85
+ */
86
+ it('should not run the init job when its not set', async () => {
87
+ const extractor = new MockedInitializableErgoExtractor(ErgoNetworkType.Node, 'node_url', 'address', undefined, false);
88
+ const removeSpy = vitest.fn();
89
+ extractor['actions'] = {
90
+ removeAllData: removeSpy,
91
+ };
92
+ const initSpy = vitest.fn();
93
+ await extractor['initWithRetrial'](initSpy);
94
+ expect(removeSpy).not.toHaveBeenCalled();
95
+ expect(initSpy).not.toHaveBeenCalled();
96
+ });
97
+ /**
98
+ * @target initWithRetrial should call init job once
99
+ * @dependencies
100
+ * - database
101
+ * @scenario
102
+ * - mock extractor
103
+ * - mock `removeAllData` in database actions
104
+ * - mock init job
105
+ * - run test (call `initWithRetrial`)
106
+ * @expected
107
+ * - to remove database old data once
108
+ * - call init job once
109
+ */
110
+ it('should call init job once', async () => {
111
+ const extractor = new MockedInitializableErgoExtractor(ErgoNetworkType.Node, 'node_url', 'address');
112
+ const removeSpy = vitest.fn();
113
+ extractor['actions'] = {
114
+ removeAllData: removeSpy,
115
+ };
116
+ const initSpy = vitest.fn();
117
+ await extractor['initWithRetrial'](initSpy);
118
+ expect(removeSpy).toHaveBeenCalledOnce();
119
+ expect(initSpy).toHaveBeenCalledOnce();
120
+ });
121
+ /**
122
+ * @target initWithRetrial should call init job RETRIAL_COUNT number of times
123
+ * @dependencies
124
+ * - database
125
+ * @scenario
126
+ * - mock extractor
127
+ * - mock `removeAllData` in database actions
128
+ * - mock init job to throw error
129
+ * - run test (call `initWithRetrial`)
130
+ * @expected
131
+ * - to remove database old data once
132
+ * - call init job RETRIAL_COUNT number of times
133
+ * - to throw error after trials
134
+ */
135
+ it('should call init job RETRIAL_COUNT number of times', async () => {
136
+ const extractor = new MockedInitializableErgoExtractor(ErgoNetworkType.Node, 'node_url', 'address');
137
+ const removeSpy = vitest.fn();
138
+ extractor['actions'] = {
139
+ removeAllData: removeSpy,
140
+ };
141
+ const initSpy = vitest.fn().mockRejectedValue(0);
142
+ await expect(async () => await extractor['initWithRetrial'](initSpy)).rejects.toThrowError();
143
+ expect(removeSpy).toHaveBeenCalledOnce();
144
+ expect(initSpy).toHaveBeenCalledTimes(RETRIAL_COUNT);
145
+ });
146
+ });
147
+ describe('initializeWithNode', () => {
148
+ /**
149
+ * @target initializeWithNode should process all transactions bellow the init height twice
150
+ * @dependencies
151
+ * - node network
152
+ * @scenario
153
+ * - mock extractor
154
+ * - mock `getAddressTransactionsWithOffsetLimit` in node network
155
+ * - mock `initWithRetrial` to run the job once
156
+ * - mock `getTotalTxCount` to return 3
157
+ * - run test (call `initializeWithNode`)
158
+ * @expected
159
+ * - to filter the transactions and process the txs bellow the init height
160
+ * - to process all filtered transactions twice
161
+ */
162
+ it('should process all transactions bellow the init height twice', async () => {
163
+ const extractor = new MockedInitializableErgoExtractor(ErgoNetworkType.Node, 'node_url', 'address');
164
+ extractor['network'].getAddressTransactionsWithOffsetLimit = vitest.fn().mockResolvedValue({
165
+ items: transactionBatch,
166
+ total: 3,
167
+ });
168
+ extractor['initWithRetrial'] = async (job) => job();
169
+ extractor['getTotalTxCount'] = async () => 3;
170
+ const processSpy = vitest.fn();
171
+ extractor['processTransactionBatch'] = processSpy;
172
+ await extractor['initializeWithNode']({ hash: 'hash', height: 1320698 });
173
+ expect(processSpy).toBeCalledTimes(2);
174
+ expect(processSpy).toBeCalledWith([transactionBatch[2]]);
175
+ });
176
+ /**
177
+ * @target initializeWithNode should throw error when total transaction count changes
178
+ * @dependencies
179
+ * - node network
180
+ * @scenario
181
+ * - mock extractor
182
+ * - mock `getAddressTransactionsWithOffsetLimit` in node network
183
+ * - mock `initWithRetrial` to run the job once
184
+ * - mock `getTotalTxCount` to return 3 then 4
185
+ * - run test (call `initializeWithNode`)
186
+ * @expected
187
+ * - to throw error when the number of transactions change during initialization
188
+ */
189
+ it('should throw error when total transaction count changes', async () => {
190
+ const extractor = new MockedInitializableErgoExtractor(ErgoNetworkType.Node, 'node_url', 'address');
191
+ extractor['network'].getAddressTransactionsWithOffsetLimit = vitest.fn().mockResolvedValue({
192
+ items: transactionBatch,
193
+ total: 3,
194
+ });
195
+ extractor['initWithRetrial'] = async (job) => job();
196
+ extractor['getTotalTxCount'] = vitest
197
+ .fn()
198
+ .mockResolvedValueOnce(3)
199
+ .mockResolvedValue(4);
200
+ extractor['processTransactionBatch'] = vitest.fn();
201
+ expect(() => extractor['initializeWithNode']({ hash: 'hash', height: 1320698 })).rejects.toThrowError();
202
+ });
203
+ });
204
+ describe('initializeWithExplorer', () => {
205
+ /**
206
+ * @target initializeWithExplorer should limit the height and process
207
+ * transactions when they are less than the API_LIMIT
208
+ * @dependencies
209
+ * - explorer network
210
+ * @scenario
211
+ * - mock extractor
212
+ * - mock `initWithRetrial` to run the job once
213
+ * - mock `getAddressTransactionsWithHeight` in explorer network
214
+ * return API_LIMIT transactions in first call (to limit the height range)
215
+ * return 0 transactions in second call (to pass a range without process)
216
+ * return transactionBatch in last call (to process the transactions when they are less than API_LIMIT)
217
+ * - run test (call `initializeWithExplorer`)
218
+ * @expected
219
+ * - to limit the height when the transaction count is equal to API_LIMIT
220
+ * - to cover all height ranges
221
+ * - to process transactions when they are less than API_LIMIT
222
+ */
223
+ it(`should limit the height and process transactions when they are less than
224
+ the API_LIMIT`, async () => {
225
+ const extractor = new MockedInitializableErgoExtractor(ErgoNetworkType.Explorer, 'explorer_url', 'address');
226
+ extractor['initWithRetrial'] = async (job) => job();
227
+ const addressTxSpy = vitest
228
+ .fn()
229
+ .mockResolvedValueOnce(new Array(100).fill(transactionBatch[0]))
230
+ .mockResolvedValueOnce([])
231
+ .mockResolvedValueOnce(transactionBatch);
232
+ extractor['network'].getAddressTransactionsWithHeight = addressTxSpy;
233
+ const processSpy = vitest.fn();
234
+ extractor['processTransactionBatch'] = processSpy;
235
+ await extractor['initializeWithExplorer']({
236
+ hash: 'hash',
237
+ height: 1320800,
238
+ });
239
+ expect(addressTxSpy).toHaveBeenCalledWith('address', 0, 1320800);
240
+ expect(addressTxSpy).toHaveBeenCalledWith('address', 0, 660400);
241
+ expect(addressTxSpy).toHaveBeenLastCalledWith('address', 660401, 1320800);
242
+ expect(processSpy).toHaveBeenCalledTimes(1);
243
+ expect(processSpy).toHaveBeenCalledWith(transactionBatch);
244
+ });
245
+ /**
246
+ * @target initializeWithExplorer should process all block transactions when
247
+ * the number of transactions in the block is more than API_LIMIT
248
+ * @dependencies
249
+ * - explorer network
250
+ * @scenario
251
+ * - mock extractor
252
+ * - mock `initWithRetrial` to run the job once
253
+ * - mock `getAddressTransactionsWithHeight` to return 100 transactions in one block
254
+ * - spy all other functions to check the calls
255
+ * - run test (call `initializeWithExplorer`)
256
+ * @expected
257
+ * - to process all transactions in block 1320000
258
+ * - not to stuck at a large block and complete the process
259
+ */
260
+ it(`should process all block transactions when the number of transactions in
261
+ the block is more than API_LIMIT`, async () => {
262
+ // mock extractor
263
+ const extractor = new MockedInitializableErgoExtractor(ErgoNetworkType.Explorer, 'explorer_url', 'address');
264
+ // mock `initWithRetrial` to run the job once
265
+ extractor['initWithRetrial'] = async (job) => job();
266
+ // mock `getAddressTransactionsWithHeight` to return 100 transactions in one block
267
+ const exNetwork = extractor['network'];
268
+ const addressTxSpy = vitest
269
+ .fn()
270
+ .mockImplementation((address, fromHeight, toHeight) => {
271
+ if (fromHeight <= 1320000 && toHeight >= 1320000)
272
+ return new Array(100).fill(transactionBatch[0]);
273
+ return [];
274
+ });
275
+ exNetwork.getAddressTransactionsWithHeight = addressTxSpy;
276
+ // spy all other functions to check the calls
277
+ const blockIdSpy = vi.fn().mockResolvedValue('blockId');
278
+ const blockTxsSpy = vi.fn().mockResolvedValue([]);
279
+ exNetwork.getBlockIdAtHeight = blockIdSpy;
280
+ exNetwork.getBlockTxs = blockTxsSpy;
281
+ const processSpy = vitest.fn();
282
+ const processBatchSpy = vitest.fn();
283
+ extractor.processTransactions = processSpy;
284
+ extractor['processTransactionBatch'] = processBatchSpy;
285
+ // run test (call `initializeWithExplorer`)
286
+ await extractor['initializeWithExplorer']({
287
+ hash: 'hash',
288
+ height: 1320800,
289
+ });
290
+ expect(blockIdSpy).toHaveBeenCalledWith(1320000);
291
+ expect(blockTxsSpy).toHaveBeenCalledWith('blockId');
292
+ expect(processSpy).toHaveBeenCalledWith([], {
293
+ hash: 'blockId',
294
+ height: 1320000,
295
+ });
296
+ expect(processBatchSpy).not.toBeCalled();
297
+ });
298
+ });
299
+ });
300
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RJbml0aWFsaXphYmxlLnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0cy9pbml0aWFsaXphYmxlL0Fic3RyYWN0SW5pdGlhbGl6YWJsZS5zcGVjLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQzFELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQVFuRSxPQUFPLEVBQUUsZ0NBQWdDLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNoRixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDOUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBR3BELFFBQVEsQ0FBQyxvQ0FBb0MsRUFBRSxHQUFHLEVBQUU7SUFDbEQsUUFBUSxDQUFDLGlCQUFpQixFQUFFLEdBQUcsRUFBRTtRQUMvQjs7Ozs7Ozs7OztXQVVHO1FBQ0gsRUFBRSxDQUFDLGtDQUFrQyxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ2hELE1BQU0sU0FBUyxHQUFHLElBQUksZ0NBQWdDLENBQ3BELGVBQWUsQ0FBQyxJQUFJLEVBQ3BCLFVBQVUsRUFDVixTQUFTLENBQ1YsQ0FBQztZQUVBLFNBQVMsQ0FBQyxTQUFTLENBQ3BCLENBQUMscUNBQXFDLEdBQUcsTUFBTSxDQUFDLEVBQUUsRUFBRSxDQUFDLGlCQUFpQixDQUFDO2dCQUN0RSxLQUFLLEVBQUUsRUFBRTtnQkFDVCxLQUFLLEVBQUUsTUFBTTthQUNkLENBQUMsQ0FBQztZQUNILE1BQU0sWUFBWSxHQUFHLE1BQU0sU0FBUyxDQUFDLGlCQUFpQixDQUFDLEVBQUUsQ0FBQztZQUMxRCxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3ZDLENB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QyxFQUFFLEVBQUUsQ0FBQztZQUNwQyxTQUFTLENBQUMsbUJBQW1CLEdBQUcsVUFBVSxDQUFDO1lBQzNDLFNBQVMsQ0FBQyx5QkFBeUIsQ0FBQyxHQUFHLGVBQWUsQ0FBQztZQUN2RCwyQ0FBMkM7WUFDM0MsTUFBTSxTQUFTLENBQUMsd0JBQXdCLENBQUMsQ0FBQztnQkFDeEMsSUFBSSxFQUFFLE1BQU07Z0JBQ1osTUFBTSxFQUFFLE9BQU87YUFDaEIsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLG9CQUFvQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ2pELE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUNwRCxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsb0JBQW9CLENBQUMsRUFBRSxFQUFFO2dCQUMxQyxJQUFJLEVBQUUsU0FBUztnQkFDZixNQUFNLEVBQUUsT0FBTzthQUNoQixDQUFDLENBQUM7WUFDSCxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQzNDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGRlc2NyaWJlLCBleHBlY3QsIGl0LCB2aSwgdml0ZXN0IH0gZnJvbSAndml0ZXN0JztcbmltcG9ydCB7IEVyZ29OZXR3b3JrVHlwZSB9IGZyb20gJ0Byb3Nlbi1icmlkZ2Uvc2Nhbm5lci1pbnRlcmZhY2VzJztcblxuaW1wb3J0IHtcbiAgTm9kZU5ldHdvcmssXG4gIEFic3RyYWN0Qm94RGF0YSxcbiAgRXhwbG9yZXJOZXR3b3JrLFxuICBBYnN0cmFjdEVyZ29FeHRyYWN0b3JFbnRpdHksXG59IGZyb20gJy4uLy4uL2xpYic7XG5pbXBvcnQgeyBNb2NrZWRJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvciB9IGZyb20gJy4vQWJzdHJhY3RJbml0aWFsaXphYmxlLm1vY2snO1xuaW1wb3J0IHsgdHJhbnNhY3Rpb25CYXRjaCB9IGZyb20gJy4vdGVzdERhdGEnO1xuaW1wb3J0IHsgUkVUUklBTF9DT1VOVCB9IGZyb20gJy4uLy4uL2xpYi9jb25zdGFudHMnO1xuaW1wb3J0IHsgQWJzdHJhY3RJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvckFjdGlvbiB9IGZyb20gJy4uLy4uL2xpYi9lcmdvL2luaXRpYWxpemFibGUnO1xuXG5kZXNjcmliZSgnQWJzdHJhY3RJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvcicsICgpID0+IHtcbiAgZGVzY3JpYmUoJ2dldFRvdGFsVHhDb3VudCcsICgpID0+IHtcbiAgICAvKipcbiAgICAgKiBAdGFyZ2V0IGdldFRvdGFsVHhDb3VudCBzaG91bGQgcmV0dXJuIHRoZSB0b3RhbCB0eCBjb3VudFxuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiAtIGV4cGxvcmVyIG5ldHdvcmtcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIG1vY2sgZXh0cmFjdG9yXG4gICAgICogLSBtb2NrIGBnZXRBZGRyZXNzVHJhbnNhY3Rpb25zV2l0aE9mZnNldExpbWl0YCBpbiBub2RlIG5ldHdvcmtcbiAgICAgKiAtIHJ1biB0ZXN0IChjYWxsIGBnZXRUb3RhbFR4Q291bnRgKVxuICAgICAqIEBleHBlY3RlZFxuICAgICAqIC0gcmV0dXJuIG9uZSB0b3RhbCB0eCBjb3VudFxuICAgICAqL1xuICAgIGl0KCdzaG91bGQgcmV0dXJuIHRoZSB0b3RhbCB0eCBjb3VudCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGV4dHJhY3RvciA9IG5ldyBNb2NrZWRJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvcihcbiAgICAgICAgRXJnb05ldHdvcmtUeXBlLk5vZGUsXG4gICAgICAgICdub2RlX3VybCcsXG4gICAgICAgICdhZGRyZXNzJ1xuICAgICAgKTtcbiAgICAgIChcbiAgICAgICAgZXh0cmFjdG9yWyduZXR3b3JrJ10gYXMgTm9kZU5ldHdvcmtcbiAgICAgICkuZ2V0QWRkcmVzc1RyYW5zYWN0aW9uc1dpdGhPZmZzZXRMaW1pdCA9IHZpdGVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgICAgaXRlbXM6IFtdLFxuICAgICAgICB0b3RhbDogMTk2NzA0LFxuICAgICAgfSk7XG4gICAgICBjb25zdCB0b3RhbFR4Q291bnQgPSBhd2FpdCBleHRyYWN0b3JbJ2dldFRvdGFsVHhDb3VudCddKCk7XG4gICAgICBleHBlY3QodG90YWxUeENvdW50KS50b0VxdWFsKDE5NjcwNCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdwcm9jZXNzVHJhbnNhY3Rpb25CYXRjaCcsICgpID0+IHtcbiAgICAvKipcbiAgICAgKiBAdGFyZ2V0IHByb2Nlc3NUcmFuc2FjdGlvbkJhdGNoIHNob3VsZCBncm91cCB0cmFuc2FjdGlvbnMgYW5kIHByb2Nlc3MgdGhlbSBpbiBjb3JyZWN0IG9yZGVyXG4gICAgICogQGRlcGVuZGVuY2llc1xuICAgICAqIEBzY2VuYXJpb1xuICAgICAqIC0gbW9jayBleHRyYWN0b3JcbiAgICAgKiAtIHNweSBgcHJvY2Vzc1RyYW5zYWN0aW9uc2BcbiAgICAgKiAtIHJ1biB0ZXN0IChjYWxsIGBwcm9jZXNzVHJhbnNhY3Rpb25CYXRjaGApXG4gICAgICogQGV4cGVjdGVkXG4gICAgICogLSB0byBncm91cCB0eHMgaW4gdHdvIGJsb2Nrc1xuICAgICAqIC0gdG8gcHJvY2VzcyBlYWNoIGJsb2NrcyB0cmFuc2FjdGlvbiBzZXBhcmF0ZWx5XG4gICAgICovXG4gICAgaXQoJ3Nob3VsZCBncm91cCB0cmFuc2FjdGlvbnMgYW5kIHByb2Nlc3MgdGhlbSBpbiBjb3JyZWN0IG9yZGVyJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgZXh0cmFjdG9yID0gbmV3IE1vY2tlZEluaXRpYWxpemFibGVFcmdvRXh0cmFjdG9yKFxuICAgICAgICBFcmdvTmV0d29ya1R5cGUuTm9kZSxcbiAgICAgICAgJ25vZGVfdXJsJyxcbiAgICAgICAgJ2FkZHJlc3MnXG4gICAgICApO1xuICAgICAgY29uc3QgcHJvY2Vzc1NweSA9IHZpdGVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKHRydWUpO1xuICAgICAgZXh0cmFjdG9yLnByb2Nlc3NUcmFuc2FjdGlvbnMgPSBwcm9jZXNzU3B5O1xuICAgICAgYXdhaXQgZXh0cmFjdG9yWydwcm9jZXNzVHJhbnNhY3Rpb25CYXRjaCddKHRyYW5zYWN0aW9uQmF0Y2gpO1xuICAgICAgZXhwZWN0KHByb2Nlc3NTcHkpLnRvQmVDYWxsZWRUaW1lcygyKTtcbiAgICAgIGV4cGVjdChwcm9jZXNzU3B5KS50b0hhdmVCZWVuQ2FsbGVkV2l0aChbdHJhbnNhY3Rpb25CYXRjaFsyXV0sIHtcbiAgICAgICAgaGFzaDogJzkyZWFmZjExYTRhMWMyOWI4NjU0NDczMjU4ZjlkODM3ZTljZTk5ZmMwYThhNGYyN2M0ODRkNTg3MWFmY2RlNjQnLFxuICAgICAgICBoZWlnaHQ6IDEzMjA2OTgsXG4gICAgICB9KTtcbiAgICAgIGV4cGVjdChwcm9jZXNzU3B5KS50b0hhdmVCZWVuTGFzdENhbGxlZFdpdGgoXG4gICAgICAgIHRyYW5zYWN0aW9uQmF0Y2guc2xpY2UoMCwgMiksXG4gICAgICAgIHtcbiAgICAgICAgICBoYXNoOiAnYjg2MWUyMTM0ODIxZmNmMWZjZGFkN2U2ZWRkNTZjNGU0NDk1YjQyYjJmZDcyNzYyYTRjNzllZDFkYjc4YjQ0YicsXG4gICAgICAgICAgaGVpZ2h0OiAxMzIwNzA1LFxuICAgICAgICB9XG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogQHRhcmdldCBwcm9jZXNzVHJhbnNhY3Rpb25CYXRjaCBzaG91bGQgdGhyb3cgZXJyb3Igd2hlbiBwcm9jZXNzaW5nIHRyYW5zYWN0aW9ucyBmYWlscyBmb3IgYSBibG9ja1xuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIG1vY2sgZXh0cmFjdG9yXG4gICAgICogLSBzcHkgYHByb2Nlc3NUcmFuc2FjdGlvbnNgIHRvIHJldHVybiBmYWxzZSAoYWx3YXlzIGZhaWxzKVxuICAgICAqIC0gcnVuIHRlc3QgKGNhbGwgYHByb2Nlc3NUcmFuc2FjdGlvbkJhdGNoYClcbiAgICAgKiBAZXhwZWN0ZWRcbiAgICAgKiAtIHRvIHRocm93IGVycm9yXG4gICAgICovXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBlcnJvciB3aGVuIHByb2Nlc3NpbmcgdHJhbnNhY3Rpb25zIGZhaWxzIGZvciBhIGJsb2NrJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgZXh0cmFjdG9yID0gbmV3IE1vY2tlZEluaXRpYWxpemFibGVFcmdvRXh0cmFjdG9yKFxuICAgICAgICBFcmdvTmV0d29ya1R5cGUuTm9kZSxcbiAgICAgICAgJ25vZGVfdXJsJyxcbiAgICAgICAgJ2FkZHJlc3MnXG4gICAgICApO1xuICAgICAgZXh0cmFjdG9yLnByb2Nlc3NUcmFuc2FjdGlvbnMgPSB2aXRlc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZShmYWxzZSk7XG4gICAgICBhd2FpdCBleHBlY3QoKCkgPT5cbiAgICAgICAgZXh0cmFjdG9yWydwcm9jZXNzVHJhbnNhY3Rpb25CYXRjaCddKHRyYW5zYWN0aW9uQmF0Y2gpXG4gICAgICApLnJlamVjdHMudG9UaHJvd0Vycm9yKCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdpbml0V2l0aFJldHJpYWwnLCAoKSA9PiB7XG4gICAgLyoqXG4gICAgICogQHRhcmdldCBpbml0V2l0aFJldHJpYWwgc2hvdWxkIG5vdCBydW4gdGhlIGluaXQgam9iIHdoZW4gaXRzIG5vdCBzZXRcbiAgICAgKiBAZGVwZW5kZW5jaWVzXG4gICAgICogLSBkYXRhYmFzZVxuICAgICAqIEBzY2VuYXJpb1xuICAgICAqIC0gbW9jayBleHRyYWN0b3Igd2l0aCBmYWxzZSBpbml0aWFsaXphdGlvblxuICAgICAqIC0gbW9jayBgcmVtb3ZlQWxsRGF0YWAgaW4gZGF0YWJhc2UgYWN0aW9uc1xuICAgICAqIC0gbW9jayBpbml0IGpvYlxuICAgICAqIC0gcnVuIHRlc3QgKGNhbGwgYGluaXRXaXRoUmV0cmlhbGApXG4gICAgICogQGV4cGVjdGVkXG4gICAgICogLSBub3QgdG8gcmVtb3ZlIGRhdGFiYXNlIG9sZCBkYXRhXG4gICAgICogLSBub3QgdG8gcnVuIHRoZSBpbml0IGpvYlxuICAgICAqL1xuICAgIGl0KCdzaG91bGQgbm90IHJ1biB0aGUgaW5pdCBqb2Igd2hlbiBpdHMgbm90IHNldCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGV4dHJhY3RvciA9IG5ldyBNb2NrZWRJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvcihcbiAgICAgICAgRXJnb05ldHdvcmtUeXBlLk5vZGUsXG4gICAgICAgICdub2RlX3VybCcsXG4gICAgICAgICdhZGRyZXNzJyxcbiAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICBmYWxzZVxuICAgICAgKTtcbiAgICAgIGNvbnN0IHJlbW92ZVNweSA9IHZpdGVzdC5mbigpO1xuICAgICAgZXh0cmFjdG9yWydhY3Rpb25zJ10gPSB7XG4gICAgICAgIHJlbW92ZUFsbERhdGE6IHJlbW92ZVNweSxcbiAgICAgIH0gYXMgdW5rbm93biBhcyBBYnN0cmFjdEluaXRpYWxpemFibGVFcmdvRXh0cmFjdG9yQWN0aW9uPFxuICAgICAgICBBYnN0cmFjdEJveERhdGEsXG4gICAgICAgIEFic3RyYWN0RXJnb0V4dHJhY3RvckVudGl0eVxuICAgICAgPjtcbiAgICAgIGNvbnN0IGluaXRTcHkgPSB2aXRlc3QuZm4oKTtcbiAgICAgIGF3YWl0IGV4dHJhY3RvclsnaW5pdFdpdGhSZXRyaWFsJ10oaW5pdFNweSk7XG4gICAgICBleHBlY3QocmVtb3ZlU3B5KS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuICAgICAgZXhwZWN0KGluaXRTcHkpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBAdGFyZ2V0IGluaXRXaXRoUmV0cmlhbCBzaG91bGQgY2FsbCBpbml0IGpvYiBvbmNlXG4gICAgICogQGRlcGVuZGVuY2llc1xuICAgICAqIC0gZGF0YWJhc2VcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIG1vY2sgZXh0cmFjdG9yXG4gICAgICogLSBtb2NrIGByZW1vdmVBbGxEYXRhYCBpbiBkYXRhYmFzZSBhY3Rpb25zXG4gICAgICogLSBtb2NrIGluaXQgam9iXG4gICAgICogLSBydW4gdGVzdCAoY2FsbCBgaW5pdFdpdGhSZXRyaWFsYClcbiAgICAgKiBAZXhwZWN0ZWRcbiAgICAgKiAtIHRvIHJlbW92ZSBkYXRhYmFzZSBvbGQgZGF0YSBvbmNlXG4gICAgICogLSBjYWxsIGluaXQgam9iIG9uY2VcbiAgICAgKi9cbiAgICBpdCgnc2hvdWxkIGNhbGwgaW5pdCBqb2Igb25jZScsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGV4dHJhY3RvciA9IG5ldyBNb2NrZWRJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvcihcbiAgICAgICAgRXJnb05ldHdvcmtUeXBlLk5vZGUsXG4gICAgICAgICdub2RlX3VybCcsXG4gICAgICAgICdhZGRyZXNzJ1xuICAgICAgKTtcbiAgICAgIGNvbnN0IHJlbW92ZVNweSA9IHZpdGVzdC5mbigpO1xuICAgICAgZXh0cmFjdG9yWydhY3Rpb25zJ10gPSB7XG4gICAgICAgIHJlbW92ZUFsbERhdGE6IHJlbW92ZVNweSxcbiAgICAgIH0gYXMgdW5rbm93biBhcyBBYnN0cmFjdEluaXRpYWxpemFibGVFcmdvRXh0cmFjdG9yQWN0aW9uPFxuICAgICAgICBBYnN0cmFjdEJveERhdGEsXG4gICAgICAgIEFic3RyYWN0RXJnb0V4dHJhY3RvckVudGl0eVxuICAgICAgPjtcbiAgICAgIGNvbnN0IGluaXRTcHkgPSB2aXRlc3QuZm4oKTtcbiAgICAgIGF3YWl0IGV4dHJhY3RvclsnaW5pdFdpdGhSZXRyaWFsJ10oaW5pdFNweSk7XG4gICAgICBleHBlY3QocmVtb3ZlU3B5KS50b0hhdmVCZWVuQ2FsbGVkT25jZSgpO1xuICAgICAgZXhwZWN0KGluaXRTcHkpLnRvSGF2ZUJlZW5DYWxsZWRPbmNlKCk7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBAdGFyZ2V0IGluaXRXaXRoUmV0cmlhbCBzaG91bGQgY2FsbCBpbml0IGpvYiBSRVRSSUFMX0NPVU5UIG51bWJlciBvZiB0aW1lc1xuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiAtIGRhdGFiYXNlXG4gICAgICogQHNjZW5hcmlvXG4gICAgICogLSBtb2NrIGV4dHJhY3RvclxuICAgICAqIC0gbW9jayBgcmVtb3ZlQWxsRGF0YWAgaW4gZGF0YWJhc2UgYWN0aW9uc1xuICAgICAqIC0gbW9jayBpbml0IGpvYiB0byB0aHJvdyBlcnJvclxuICAgICAqIC0gcnVuIHRlc3QgKGNhbGwgYGluaXRXaXRoUmV0cmlhbGApXG4gICAgICogQGV4cGVjdGVkXG4gICAgICogLSB0byByZW1vdmUgZGF0YWJhc2Ugb2xkIGRhdGEgb25jZVxuICAgICAqIC0gY2FsbCBpbml0IGpvYiBSRVRSSUFMX0NPVU5UIG51bWJlciBvZiB0aW1lc1xuICAgICAqIC0gdG8gdGhyb3cgZXJyb3IgYWZ0ZXIgdHJpYWxzXG4gICAgICovXG4gICAgaXQoJ3Nob3VsZCBjYWxsIGluaXQgam9iIFJFVFJJQUxfQ09VTlQgbnVtYmVyIG9mIHRpbWVzJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgZXh0cmFjdG9yID0gbmV3IE1vY2tlZEluaXRpYWxpemFibGVFcmdvRXh0cmFjdG9yKFxuICAgICAgICBFcmdvTmV0d29ya1R5cGUuTm9kZSxcbiAgICAgICAgJ25vZGVfdXJsJyxcbiAgICAgICAgJ2FkZHJlc3MnXG4gICAgICApO1xuICAgICAgY29uc3QgcmVtb3ZlU3B5ID0gdml0ZXN0LmZuKCk7XG4gICAgICBleHRyYWN0b3JbJ2FjdGlvbnMnXSA9IHtcbiAgICAgICAgcmVtb3ZlQWxsRGF0YTogcmVtb3ZlU3B5LFxuICAgICAgfSBhcyB1bmtub3duIGFzIEFic3RyYWN0SW5pdGlhbGl6YWJsZUVyZ29FeHRyYWN0b3JBY3Rpb248XG4gICAgICAgIEFic3RyYWN0Qm94RGF0YSxcbiAgICAgICAgQWJzdHJhY3RFcmdvRXh0cmFjdG9yRW50aXR5XG4gICAgICA+O1xuICAgICAgY29uc3QgaW5pdFNweSA9IHZpdGVzdC5mbigpLm1vY2tSZWplY3RlZFZhbHVlKDApO1xuICAgICAgYXdhaXQgZXhwZWN0KFxuICAgICAgICBhc3luYyAoKSA9PiBhd2FpdCBleHRyYWN0b3JbJ2luaXRXaXRoUmV0cmlhbCddKGluaXRTcHkpXG4gICAgICApLnJlamVjdHMudG9UaHJvd0Vycm9yKCk7XG4gICAgICBleHBlY3QocmVtb3ZlU3B5KS50b0hhdmVCZWVuQ2FsbGVkT25jZSgpO1xuICAgICAgZXhwZWN0KGluaXRTcHkpLnRvSGF2ZUJlZW5DYWxsZWRUaW1lcyhSRVRSSUFMX0NPVU5UKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2luaXRpYWxpemVXaXRoTm9kZScsICgpID0+IHtcbiAgICAvKipcbiAgICAgKiBAdGFyZ2V0IGluaXRpYWxpemVXaXRoTm9kZSBzaG91bGQgcHJvY2VzcyBhbGwgdHJhbnNhY3Rpb25zIGJlbGxvdyB0aGUgaW5pdCBoZWlnaHQgdHdpY2VcbiAgICAgKiBAZGVwZW5kZW5jaWVzXG4gICAgICogLSBub2RlIG5ldHdvcmtcbiAgICAgKiBAc2NlbmFyaW9cbiAgICAgKiAtIG1vY2sgZXh0cmFjdG9yXG4gICAgICogLSBtb2NrIGBnZXRBZGRyZXNzVHJhbnNhY3Rpb25zV2l0aE9mZnNldExpbWl0YCBpbiBub2RlIG5ldHdvcmtcbiAgICAgKiAtIG1vY2sgYGluaXRXaXRoUmV0cmlhbGAgdG8gcnVuIHRoZSBqb2Igb25jZVxuICAgICAqIC0gbW9jayBgZ2V0VG90YWxUeENvdW50YCB0byByZXR1cm4gM1xuICAgICAqIC0gcnVuIHRlc3QgKGNhbGwgYGluaXRpYWxpemVXaXRoTm9kZWApXG4gICAgICogQGV4cGVjdGVkXG4gICAgICogLSB0byBmaWx0ZXIgdGhlIHRyYW5zYWN0aW9ucyBhbmQgcHJvY2VzcyB0aGUgdHhzIGJlbGxvdyB0aGUgaW5pdCBoZWlnaHRcbiAgICAgKiAtIHRvIHByb2Nlc3MgYWxsIGZpbHRlcmVkIHRyYW5zYWN0aW9ucyB0d2ljZVxuICAgICAqL1xuICAgIGl0KCdzaG91bGQgcHJvY2VzcyBhbGwgdHJhbnNhY3Rpb25zIGJlbGxvdyB0aGUgaW5pdCBoZWlnaHQgdHdpY2UnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBleHRyYWN0b3IgPSBuZXcgTW9ja2VkSW5pdGlhbGl6YWJsZUVyZ29FeHRyYWN0b3IoXG4gICAgICAgIEVyZ29OZXR3b3JrVHlwZS5Ob2RlLFxuICAgICAgICAnbm9kZV91cmwnLFxuICAgICAgICAnYWRkcmVzcydcbiAgICAgICk7XG4gICAgICAoXG4gICAgICAgIGV4dHJhY3RvclsnbmV0d29yayddIGFzIE5vZGVOZXR3b3JrXG4gICAgICApLmdldEFkZHJlc3NUcmFuc2FjdGlvbnNXaXRoT2Zmc2V0TGltaXQgPSB2aXRlc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZSh7XG4gICAgICAgIGl0ZW1zOiB0cmFuc2FjdGlvbkJhdGNoLFxuICAgICAgICB0b3RhbDogMyxcbiAgICAgIH0pO1xuICAgICAgZXh0cmFjdG9yWydpbml0V2l0aFJldHJpYWwnXSA9IGFzeW5jIChqb2I6ICgpID0+IFByb21pc2U8dm9pZD4pID0+IGpvYigpO1xuICAgICAgZXh0cmFjdG9yWydnZXRUb3RhbFR4Q291bnQnXSA9IGFzeW5jICgpID0+IDM7XG4gICAgICBjb25zdCBwcm9jZXNzU3B5ID0gdml0ZXN0LmZuKCk7XG4gICAgICBleHRyYWN0b3JbJ3Byb2Nlc3NUcmFuc2FjdGlvbkJhdGNoJ10gPSBwcm9jZXNzU3B5O1xuICAgICAgYXdhaXQgZXh0cmFjdG9yWydpbml0aWFsaXplV2l0aE5vZGUnXSh7IGhhc2g6ICdoYXNoJywgaGVpZ2h0OiAxMzIwNjk4IH0pO1xuICAgICAgZXhwZWN0KHByb2Nlc3NTcHkpLnRvQmVDYWxsZWRUaW1lcygyKTtcbiAgICAgIGV4cGVjdChwcm9jZXNzU3B5KS50b0JlQ2FsbGVkV2l0aChbdHJhbnNhY3Rpb25CYXRjaFsyXV0pO1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogQHRhcmdldCBpbml0aWFsaXplV2l0aE5vZGUgc2hvdWxkIHRocm93IGVycm9yIHdoZW4gdG90YWwgdHJhbnNhY3Rpb24gY291bnQgY2hhbmdlc1xuICAgICAqIEBkZXBlbmRlbmNpZXNcbiAgICAgKiAtIG5vZGUgbmV0d29ya1xuICAgICAqIEBzY2VuYXJpb1xuICAgICAqIC0gbW9jayBleHRyYWN0b3JcbiAgICAgKiAtIG1vY2sgYGdldEFkZHJlc3NUcmFuc2FjdGlvbnNXaXRoT2Zmc2V0TGltaXRgIGluIG5vZGUgbmV0d29ya1xuICAgICAqIC0gbW9jayBgaW5pdFdpdGhSZXRyaWFsYCB0byBydW4gdGhlIGpvYiBvbmNlXG4gICAgICogLSBtb2NrIGBnZXRUb3RhbFR4Q291bnRgIHRvIHJldHVybiAzIHRoZW4gNFxuICAgICAqIC0gcnVuIHRlc3QgKGNhbGwgYGluaXRpYWxpemVXaXRoTm9kZWApXG4gICAgICogQGV4cGVjdGVkXG4gICAgICogLSB0byB0aHJvdyBlcnJvciB3aGVuIHRoZSBudW1iZXIgb2YgdHJhbnNhY3Rpb25zIGNoYW5nZSBkdXJpbmcgaW5pdGlhbGl6YXRpb25cbiAgICAgKi9cbiAgICBpdCgnc2hvdWxkIHRocm93IGVycm9yIHdoZW4gdG90YWwgdHJhbnNhY3Rpb24gY291bnQgY2hhbmdlcycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGV4dHJhY3RvciA9IG5ldyBNb2NrZWRJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvcihcbiAgICAgICAgRXJnb05ldHdvcmtUeXBlLk5vZGUsXG4gICAgICAgICdub2RlX3VybCcsXG4gICAgICAgICdhZGRyZXNzJ1xuICAgICAgKTtcbiAgICAgIChcbiAgICAgICAgZXh0cmFjdG9yWyduZXR3b3JrJ10gYXMgTm9kZU5ldHdvcmtcbiAgICAgICkuZ2V0QWRkcmVzc1RyYW5zYWN0aW9uc1dpdGhPZmZzZXRMaW1pdCA9IHZpdGVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKHtcbiAgICAgICAgaXRlbXM6IHRyYW5zYWN0aW9uQmF0Y2gsXG4gICAgICAgIHRvdGFsOiAzLFxuICAgICAgfSk7XG4gICAgICBleHRyYWN0b3JbJ2luaXRXaXRoUmV0cmlhbCddID0gYXN5bmMgKGpvYjogKCkgPT4gUHJvbWlzZTx2b2lkPikgPT4gam9iKCk7XG4gICAgICBleHRyYWN0b3JbJ2dldFRvdGFsVHhDb3VudCddID0gdml0ZXN0XG4gICAgICAgIC5mbigpXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoMylcbiAgICAgICAgLm1vY2tSZXNvbHZlZFZhbHVlKDQpO1xuICAgICAgZXh0cmFjdG9yWydwcm9jZXNzVHJhbnNhY3Rpb25CYXRjaCddID0gdml0ZXN0LmZuKCk7XG4gICAgICBleHBlY3QoKCkgPT5cbiAgICAgICAgZXh0cmFjdG9yWydpbml0aWFsaXplV2l0aE5vZGUnXSh7IGhhc2g6ICdoYXNoJywgaGVpZ2h0OiAxMzIwNjk4IH0pXG4gICAgICApLnJlamVjdHMudG9UaHJvd0Vycm9yKCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdpbml0aWFsaXplV2l0aEV4cGxvcmVyJywgKCkgPT4ge1xuICAgIC8qKlxuICAgICAqIEB0YXJnZXQgaW5pdGlhbGl6ZVdpdGhFeHBsb3JlciBzaG91bGQgbGltaXQgdGhlIGhlaWdodCBhbmQgcHJvY2Vzc1xuICAgICAqIHRyYW5zYWN0aW9ucyB3aGVuIHRoZXkgYXJlIGxlc3MgdGhhbiB0aGUgQVBJX0xJTUlUXG4gICAgICogQGRlcGVuZGVuY2llc1xuICAgICAqIC0gZXhwbG9yZXIgbmV0d29ya1xuICAgICAqIEBzY2VuYXJpb1xuICAgICAqIC0gbW9jayBleHRyYWN0b3JcbiAgICAgKiAtIG1vY2sgYGluaXRXaXRoUmV0cmlhbGAgdG8gcnVuIHRoZSBqb2Igb25jZVxuICAgICAqIC0gbW9jayBgZ2V0QWRkcmVzc1RyYW5zYWN0aW9uc1dpdGhIZWlnaHRgIGluIGV4cGxvcmVyIG5ldHdvcmtcbiAgICAgKiAgICByZXR1cm4gQVBJX0xJTUlUIHRyYW5zYWN0aW9ucyBpbiBmaXJzdCBjYWxsICh0byBsaW1pdCB0aGUgaGVpZ2h0IHJhbmdlKVxuICAgICAqICAgIHJldHVybiAwIHRyYW5zYWN0aW9ucyBpbiBzZWNvbmQgY2FsbCAodG8gcGFzcyBhIHJhbmdlIHdpdGhvdXQgcHJvY2VzcylcbiAgICAgKiAgICByZXR1cm4gdHJhbnNhY3Rpb25CYXRjaCBpbiBsYXN0IGNhbGwgKHRvIHByb2Nlc3MgdGhlIHRyYW5zYWN0aW9ucyB3aGVuIHRoZXkgYXJlIGxlc3MgdGhhbiBBUElfTElNSVQpXG4gICAgICogLSBydW4gdGVzdCAoY2FsbCBgaW5pdGlhbGl6ZVdpdGhFeHBsb3JlcmApXG4gICAgICogQGV4cGVjdGVkXG4gICAgICogLSB0byBsaW1pdCB0aGUgaGVpZ2h0IHdoZW4gdGhlIHRyYW5zYWN0aW9uIGNvdW50IGlzIGVxdWFsIHRvIEFQSV9MSU1JVFxuICAgICAqIC0gdG8gY292ZXIgYWxsIGhlaWdodCByYW5nZXNcbiAgICAgKiAtIHRvIHByb2Nlc3MgdHJhbnNhY3Rpb25zIHdoZW4gdGhleSBhcmUgbGVzcyB0aGFuIEFQSV9MSU1JVFxuICAgICAqL1xuICAgIGl0KGBzaG91bGQgbGltaXQgdGhlIGhlaWdodCBhbmQgcHJvY2VzcyB0cmFuc2FjdGlvbnMgd2hlbiB0aGV5IGFyZSBsZXNzIHRoYW5cbiAgICAgIHRoZSBBUElfTElNSVRgLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBleHRyYWN0b3IgPSBuZXcgTW9ja2VkSW5pdGlhbGl6YWJsZUVyZ29FeHRyYWN0b3IoXG4gICAgICAgIEVyZ29OZXR3b3JrVHlwZS5FeHBsb3JlcixcbiAgICAgICAgJ2V4cGxvcmVyX3VybCcsXG4gICAgICAgICdhZGRyZXNzJ1xuICAgICAgKTtcbiAgICAgIGV4dHJhY3RvclsnaW5pdFdpdGhSZXRyaWFsJ10gPSBhc3luYyAoam9iOiAoKSA9PiBQcm9taXNlPHZvaWQ+KSA9PiBqb2IoKTtcbiAgICAgIGNvbnN0IGFkZHJlc3NUeFNweSA9IHZpdGVzdFxuICAgICAgICAuZm4oKVxuICAgICAgICAubW9ja1Jlc29sdmVkVmFsdWVPbmNlKG5ldyBBcnJheSgxMDApLmZpbGwodHJhbnNhY3Rpb25CYXRjaFswXSkpXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UoW10pXG4gICAgICAgIC5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2UodHJhbnNhY3Rpb25CYXRjaCk7XG4gICAgICAoXG4gICAgICAgIGV4dHJhY3RvclsnbmV0d29yayddIGFzIEV4cGxvcmVyTmV0d29ya1xuICAgICAgKS5nZXRBZGRyZXNzVHJhbnNhY3Rpb25zV2l0aEhlaWdodCA9IGFkZHJlc3NUeFNweTtcbiAgICAgIGNvbnN0IHByb2Nlc3NTcHkgPSB2aXRlc3QuZm4oKTtcbiAgICAgIGV4dHJhY3RvclsncHJvY2Vzc1RyYW5zYWN0aW9uQmF0Y2gnXSA9IHByb2Nlc3NTcHk7XG4gICAgICBhd2FpdCBleHRyYWN0b3JbJ2luaXRpYWxpemVXaXRoRXhwbG9yZXInXSh7XG4gICAgICAgIGhhc2g6ICdoYXNoJyxcbiAgICAgICAgaGVpZ2h0OiAxMzIwODAwLFxuICAgICAgfSk7XG4gICAgICBleHBlY3QoYWRkcmVzc1R4U3B5KS50b0hhdmVCZWVuQ2FsbGVkV2l0aCgnYWRkcmVzcycsIDAsIDEzMjA4MDApO1xuICAgICAgZXhwZWN0KGFkZHJlc3NUeFNweSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ2FkZHJlc3MnLCAwLCA2NjA0MDApO1xuICAgICAgZXhwZWN0KGFkZHJlc3NUeFNweSkudG9IYXZlQmVlbkxhc3RDYWxsZWRXaXRoKCdhZGRyZXNzJywgNjYwNDAxLCAxMzIwODAwKTtcbiAgICAgIGV4cGVjdChwcm9jZXNzU3B5KS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMSk7XG4gICAgICBleHBlY3QocHJvY2Vzc1NweSkudG9IYXZlQmVlbkNhbGxlZFdpdGgodHJhbnNhY3Rpb25CYXRjaCk7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBAdGFyZ2V0IGluaXRpYWxpemVXaXRoRXhwbG9yZXIgc2hvdWxkIHByb2Nlc3MgYWxsIGJsb2NrIHRyYW5zYWN0aW9ucyB3aGVuXG4gICAgICogdGhlIG51bWJlciBvZiB0cmFuc2FjdGlvbnMgaW4gdGhlIGJsb2NrIGlzIG1vcmUgdGhhbiBBUElfTElNSVRcbiAgICAgKiBAZGVwZW5kZW5jaWVzXG4gICAgICogLSBleHBsb3JlciBuZXR3b3JrXG4gICAgICogQHNjZW5hcmlvXG4gICAgICogLSBtb2NrIGV4dHJhY3RvclxuICAgICAqIC0gbW9jayBgaW5pdFdpdGhSZXRyaWFsYCB0byBydW4gdGhlIGpvYiBvbmNlXG4gICAgICogLSBtb2NrIGBnZXRBZGRyZXNzVHJhbnNhY3Rpb25zV2l0aEhlaWdodGAgdG8gcmV0dXJuIDEwMCB0cmFuc2FjdGlvbnMgaW4gb25lIGJsb2NrXG4gICAgICogLSBzcHkgYWxsIG90aGVyIGZ1bmN0aW9ucyB0byBjaGVjayB0aGUgY2FsbHNcbiAgICAgKiAtIHJ1biB0ZXN0IChjYWxsIGBpbml0aWFsaXplV2l0aEV4cGxvcmVyYClcbiAgICAgKiBAZXhwZWN0ZWRcbiAgICAgKiAtIHRvIHByb2Nlc3MgYWxsIHRyYW5zYWN0aW9ucyBpbiBibG9jayAxMzIwMDAwXG4gICAgICogLSBub3QgdG8gc3R1Y2sgYXQgYSBsYXJnZSBibG9jayBhbmQgY29tcGxldGUgdGhlIHByb2Nlc3NcbiAgICAgKi9cbiAgICBpdChgc2hvdWxkIHByb2Nlc3MgYWxsIGJsb2NrIHRyYW5zYWN0aW9ucyB3aGVuIHRoZSBudW1iZXIgb2YgdHJhbnNhY3Rpb25zIGluXG4gICAgICB0aGUgYmxvY2sgaXMgbW9yZSB0aGFuIEFQSV9MSU1JVGAsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIG1vY2sgZXh0cmFjdG9yXG4gICAgICBjb25zdCBleHRyYWN0b3IgPSBuZXcgTW9ja2VkSW5pdGlhbGl6YWJsZUVyZ29FeHRyYWN0b3IoXG4gICAgICAgIEVyZ29OZXR3b3JrVHlwZS5FeHBsb3JlcixcbiAgICAgICAgJ2V4cGxvcmVyX3VybCcsXG4gICAgICAgICdhZGRyZXNzJ1xuICAgICAgKTtcbiAgICAgIC8vIG1vY2sgYGluaXRXaXRoUmV0cmlhbGAgdG8gcnVuIHRoZSBqb2Igb25jZVxuICAgICAgZXh0cmFjdG9yWydpbml0V2l0aFJldHJpYWwnXSA9IGFzeW5jIChqb2I6ICgpID0+IFByb21pc2U8dm9pZD4pID0+IGpvYigpO1xuICAgICAgLy8gbW9jayBgZ2V0QWRkcmVzc1RyYW5zYWN0aW9uc1dpdGhIZWlnaHRgIHRvIHJldHVybiAxMDAgdHJhbnNhY3Rpb25zIGluIG9uZSBibG9ja1xuICAgICAgY29uc3QgZXhOZXR3b3JrID0gZXh0cmFjdG9yWyduZXR3b3JrJ10gYXMgRXhwbG9yZXJOZXR3b3JrO1xuICAgICAgY29uc3QgYWRkcmVzc1R4U3B5ID0gdml0ZXN0XG4gICAgICAgIC5mbigpXG4gICAgICAgIC5tb2NrSW1wbGVtZW50YXRpb24oXG4gICAgICAgICAgKGFkZHJlc3M6IHN0cmluZywgZnJvbUhlaWdodDogbnVtYmVyLCB0b0hlaWdodDogbnVtYmVyKSA9PiB7XG4gICAgICAgICAgICBpZiAoZnJvbUhlaWdodCA8PSAxMzIwMDAwICYmIHRvSGVpZ2h0ID49IDEzMjAwMDApXG4gICAgICAgICAgICAgIHJldHVybiBuZXcgQXJyYXkoMTAwKS5maWxsKHRyYW5zYWN0aW9uQmF0Y2hbMF0pO1xuICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgIGV4TmV0d29yay5nZXRBZGRyZXNzVHJhbnNhY3Rpb25zV2l0aEhlaWdodCA9IGFkZHJlc3NUeFNweTtcbiAgICAgIC8vIHNweSBhbGwgb3RoZXIgZnVuY3Rpb25zIHRvIGNoZWNrIHRoZSBjYWxsc1xuICAgICAgY29uc3QgYmxvY2tJZFNweSA9IHZpLmZuKCkubW9ja1Jlc29sdmVkVmFsdWUoJ2Jsb2NrSWQnKTtcbiAgICAgIGNvbnN0IGJsb2NrVHhzU3B5ID0gdmkuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZShbXSk7XG4gICAgICBleE5ldHdvcmsuZ2V0QmxvY2tJZEF0SGVpZ2h0ID0gYmxvY2tJZFNweTtcbiAgICAgIGV4TmV0d29yay5nZXRCbG9ja1R4cyA9IGJsb2NrVHhzU3B5O1xuICAgICAgY29uc3QgcHJvY2Vzc1NweSA9IHZpdGVzdC5mbigpO1xuICAgICAgY29uc3QgcHJvY2Vzc0JhdGNoU3B5ID0gdml0ZXN0LmZuKCk7XG4gICAgICBleHRyYWN0b3IucHJvY2Vzc1RyYW5zYWN0aW9ucyA9IHByb2Nlc3NTcHk7XG4gICAgICBleHRyYWN0b3JbJ3Byb2Nlc3NUcmFuc2FjdGlvbkJhdGNoJ10gPSBwcm9jZXNzQmF0Y2hTcHk7XG4gICAgICAvLyBydW4gdGVzdCAoY2FsbCBgaW5pdGlhbGl6ZVdpdGhFeHBsb3JlcmApXG4gICAgICBhd2FpdCBleHRyYWN0b3JbJ2luaXRpYWxpemVXaXRoRXhwbG9yZXInXSh7XG4gICAgICAgIGhhc2g6ICdoYXNoJyxcbiAgICAgICAgaGVpZ2h0OiAxMzIwODAwLFxuICAgICAgfSk7XG4gICAgICBleHBlY3QoYmxvY2tJZFNweSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoMTMyMDAwMCk7XG4gICAgICBleHBlY3QoYmxvY2tUeHNTcHkpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCdibG9ja0lkJyk7XG4gICAgICBleHBlY3QocHJvY2Vzc1NweSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoW10sIHtcbiAgICAgICAgaGFzaDogJ2Jsb2NrSWQnLFxuICAgICAgICBoZWlnaHQ6IDEzMjAwMDAsXG4gICAgICB9KTtcbiAgICAgIGV4cGVjdChwcm9jZXNzQmF0Y2hTcHkpLm5vdC50b0JlQ2FsbGVkKCk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=
@@ -0,0 +1,15 @@
1
+ import { DataSource } from '@rosen-bridge/extended-typeorm';
2
+ import { BlockInfo } from '@rosen-bridge/scanner-interfaces';
3
+ import { AbstractErgoExtractorEntity, AbstractBoxData, AbstractInitializableErgoExtractorAction } from '../../lib';
4
+ export declare class TestInitializableErgoExtractorAction extends AbstractInitializableErgoExtractorAction<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=AbstractInitializableAction.mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractInitializableAction.mock.d.ts","sourceRoot":"","sources":["../../../tests/initializable/AbstractInitializableAction.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,eAAe,EACf,wCAAwC,EACzC,MAAM,WAAW,CAAC;AAGnB,qBAAa,oCAAqC,SAAQ,wCAAwC,CAChG,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 { AbstractInitializableErgoExtractorAction, } from '../../lib';
3
+ import { TestEntity } from '../testUtils';
4
+ export class TestInitializableErgoExtractorAction extends AbstractInitializableErgoExtractorAction {
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RJbml0aWFsaXphYmxlQWN0aW9uLm1vY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0cy9pbml0aWFsaXphYmxlL0Fic3RyYWN0SW5pdGlhbGl6YWJsZUFjdGlvbi5tb2NrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFHakMsT0FBTyxFQUdMLHdDQUF3QyxHQUN6QyxNQUFNLFdBQVcsQ0FBQztBQUNuQixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRTFDLE1BQU0sT0FBTyxvQ0FBcUMsU0FBUSx3Q0FHekQ7SUFDQyxZQUFZLFVBQXNCO1FBQ2hDLEtBQUssQ0FBQyxVQUFVLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsWUFBWSxHQUFHLENBQ2IsS0FBd0IsRUFDeEIsS0FBZ0IsRUFDaEIsU0FBaUIsRUFDMEIsRUFBRTtRQUM3QyxPQUFPLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDekIsS0FBSyxFQUFFLEdBQUcsQ0FBQyxLQUFLO1lBQ2hCLEtBQUssRUFBRSxLQUFLLENBQUMsSUFBSTtZQUNqQixNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07WUFDcEIsVUFBVSxFQUFFLEdBQUcsQ0FBQyxVQUFVO1lBQzFCLFNBQVMsRUFBRSxTQUFTO1NBQ3JCLENBQUMsQ0FBQyxDQUFDO0lBQ04sQ0FBQyxDQUFDO0lBRUY7O09BRUc7SUFDSCxtQkFBbUIsR0FBRyxDQUNwQixRQUF1QyxFQUNwQixFQUFFO1FBQ3JCLE9BQU8sUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDckUsQ0FBQyxDQUFDO0NBQ0giLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEYXRhU291cmNlIH0gZnJvbSAnQHJvc2VuLWJyaWRnZS9leHRlbmRlZC10eXBlb3JtJztcbmltcG9ydCB7IHBpY2sgfSBmcm9tICdsb2Rhc2gtZXMnO1xuaW1wb3J0IHsgQmxvY2tJbmZvIH0gZnJvbSAnQHJvc2VuLWJyaWRnZS9zY2FubmVyLWludGVyZmFjZXMnO1xuXG5pbXBvcnQge1xuICBBYnN0cmFjdEVyZ29FeHRyYWN0b3JFbnRpdHksXG4gIEFic3RyYWN0Qm94RGF0YSxcbiAgQWJzdHJhY3RJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvckFjdGlvbixcbn0gZnJvbSAnLi4vLi4vbGliJztcbmltcG9ydCB7IFRlc3RFbnRpdHkgfSBmcm9tICcuLi90ZXN0VXRpbHMnO1xuXG5leHBvcnQgY2xhc3MgVGVzdEluaXRpYWxpemFibGVFcmdvRXh0cmFjdG9yQWN0aW9uIGV4dGVuZHMgQWJzdHJhY3RJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvckFjdGlvbjxcbiAgQWJzdHJhY3RCb3hEYXRhLFxuICBBYnN0cmFjdEVyZ29FeHRyYWN0b3JFbnRpdHlcbj4ge1xuICBjb25zdHJ1Y3RvcihkYXRhU291cmNlOiBEYXRhU291cmNlKSB7XG4gICAgc3VwZXIoZGF0YVNvdXJjZSwgVGVzdEVudGl0eSk7XG4gIH1cblxuICAvKipcbiAgICogY3JlYXRlIHRoZSB0ZXN0IGRhdGFiYXNlIGVudGl0eSBmcm9tIGRhdGEgYW5kIGJsb2NrIGluZm9ybWF0aW9uXG4gICAqL1xuICBjcmVhdGVFbnRpdHkgPSAoXG4gICAgYm94ZXM6IEFic3RyYWN0Qm94RGF0YVtdLFxuICAgIGJsb2NrOiBCbG9ja0luZm8sXG4gICAgZXh0cmFjdG9yOiBzdHJpbmdcbiAgKTogT21pdDxBYnN0cmFjdEVyZ29FeHRyYWN0b3JFbnRpdHksICdpZCc+W10gPT4ge1xuICAgIHJldHVybiBib3hlcy5tYXAoKGJveCkgPT4gKHtcbiAgICAgIGJveElkOiBib3guYm94SWQsXG4gICAgICBibG9jazogYmxvY2suaGFzaCxcbiAgICAgIGhlaWdodDogYmxvY2suaGVpZ2h0LFxuICAgICAgc2VyaWFsaXplZDogYm94LnNlcmlhbGl6ZWQsXG4gICAgICBleHRyYWN0b3I6IGV4dHJhY3RvcixcbiAgICB9KSk7XG4gIH07XG5cbiAgLyoqXG4gICAqIGNvbnZlcnQgdGhlIGRhdGFiYXNlIGVudGl0eSBiYWNrIHRvIHJhdyBkYXRhXG4gICAqL1xuICBjb252ZXJ0RW50aXR5VG9EYXRhID0gKFxuICAgIGVudGl0aWVzOiBBYnN0cmFjdEVyZ29FeHRyYWN0b3JFbnRpdHlbXVxuICApOiBBYnN0cmFjdEJveERhdGFbXSA9PiB7XG4gICAgcmV0dXJuIGVudGl0aWVzLm1hcCgoZGF0YSkgPT4gcGljayhkYXRhLCBbJ2JveElkJywgJ3NlcmlhbGl6ZWQnXSkpO1xuICB9O1xufVxuIl19
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=AbstractInitializableAction.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractInitializableAction.spec.d.ts","sourceRoot":"","sources":["../../../tests/initializable/AbstractInitializableAction.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,55 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { TestInitializableErgoExtractorAction } from './AbstractInitializableAction.mock';
3
+ import { createDatabase, TestEntity } from '../testUtils';
4
+ import { sampleEntities } from '../testData';
5
+ describe('AbstractErgoExtractorAction', () => {
6
+ let dataSource;
7
+ let action;
8
+ let repository;
9
+ beforeEach(async () => {
10
+ dataSource = await createDatabase();
11
+ action = new TestInitializableErgoExtractorAction(dataSource);
12
+ repository = dataSource.getRepository(TestEntity);
13
+ });
14
+ describe('removeAllData', () => {
15
+ /**
16
+ * @target removeAllData should remove all available data related to this extractor
17
+ * @dependencies
18
+ * @scenario
19
+ * - insert 4 entities related to this extractor
20
+ * - run test (call `removeAllData`)
21
+ * @expected
22
+ * - to have 4 entities before removing
23
+ * - to have no remaining entities after remove
24
+ */
25
+ it(`should remove all available data related to this extractor`, async () => {
26
+ await dataSource.getRepository(TestEntity).insert(sampleEntities);
27
+ const countBefore = await repository.count();
28
+ await action.removeAllData('extractor');
29
+ const countAfter = await repository.count();
30
+ expect(countBefore).toEqual(4);
31
+ expect(countAfter).toEqual(0);
32
+ });
33
+ /**
34
+ * @target removeAllData should not remove any data related to another extractor
35
+ * @dependencies
36
+ * @scenario
37
+ * - insert 4 entities related to another extractor
38
+ * - run test (call `removeAllData`)
39
+ * @expected
40
+ * - to have 4 entities after removing
41
+ */
42
+ it(`should not remove any data related to another extractor`, async () => {
43
+ await dataSource.getRepository(TestEntity).insert(sampleEntities.map((entity) => ({
44
+ ...entity,
45
+ extractor: 'extractor-new',
46
+ })));
47
+ const countBefore = await repository.count();
48
+ await action.removeAllData('extractor');
49
+ const countAfter = await repository.count();
50
+ expect(countBefore).toEqual(4);
51
+ expect(countAfter).toEqual(4);
52
+ });
53
+ });
54
+ });
55
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RJbml0aWFsaXphYmxlQWN0aW9uLnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0cy9pbml0aWFsaXphYmxlL0Fic3RyYWN0SW5pdGlhbGl6YWJsZUFjdGlvbi5zcGVjLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFMUQsT0FBTyxFQUFFLG9DQUFvQyxFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFDMUYsT0FBTyxFQUFFLGNBQWMsRUFBRSxVQUFVLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDMUQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUU3QyxRQUFRLENBQUMsNkJBQTZCLEVBQUUsR0FBRyxFQUFFO0lBQzNDLElBQUksVUFBc0IsQ0FBQztJQUMzQixJQUFJLE1BQTRDLENBQUM7SUFDakQsSUFBSSxVQUFrQyxDQUFDO0lBQ3ZDLFVBQVUsQ0FBQyxLQUFLLElBQUksRUFBRTtRQUNwQixVQUFVLEdBQUcsTUFBTSxjQUFjLEVBQUUsQ0FBQztRQUNwQyxNQUFNLEdBQUcsSUFBSSxvQ0FBb0MsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUM5RCxVQUFVLEdBQUcsVUFBVSxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNwRCxDQUFDLENBQUMsQ0FBQztJQUVILFFBQVEsQ0FBQyxlQUFlLEVBQUUsR0FBRyxFQUFFO1FBQzdCOzs7Ozs7Ozs7V0FTRztRQUNILEVBQUUsQ0FBQyw0REFBNEQsRUFBRSxLQUFLLElBQUksRUFBRTtZQUMxRSxNQUFNLFVBQVUsQ0FBQyxhQUFhLENBQUMsVUFBVSxDQUFDLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQ2xFLE1BQU0sV0FBVyxHQUFHLE1BQU0sVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBRTdDLE1BQU0sTUFBTSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUN4QyxNQUFNLFVBQVUsR0FBRyxNQUFNLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUU1QyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9CLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDaEMsQ0FBQyxDQUFDLENBQUM7UUFFSDs7Ozs7Ozs7V0FRRztRQUNILEVBQUUsQ0FBQyx5REFBeUQsRUFBRSxLQUFLLElBQUksRUFBRTtZQUN2RSxNQUFNLFVBQVUsQ0FBQyxhQUFhLENBQUMsVUFBVSxDQUFDLENBQUMsTUFBTSxDQUMvQyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDO2dCQUM5QixHQUFHLE1BQU07Z0JBQ1QsU0FBUyxFQUFFLGVBQWU7YUFDM0IsQ0FBQyxDQUFDLENBQ0osQ0FBQztZQUNGLE1BQU0sV0FBVyxHQUFHLE1BQU0sVUFBVSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBRTdDLE1BQU0sTUFBTSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUN4QyxNQUFNLFVBQVUsR0FBRyxNQUFNLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUU1QyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQy9CLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDaEMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGF0YVNvdXJjZSwgUmVwb3NpdG9yeSB9IGZyb20gJ0Byb3Nlbi1icmlkZ2UvZXh0ZW5kZWQtdHlwZW9ybSc7XG5pbXBvcnQgeyBkZXNjcmliZSwgaXQsIGV4cGVjdCwgYmVmb3JlRWFjaCB9IGZyb20gJ3ZpdGVzdCc7XG5cbmltcG9ydCB7IFRlc3RJbml0aWFsaXphYmxlRXJnb0V4dHJhY3RvckFjdGlvbiB9IGZyb20gJy4vQWJzdHJhY3RJbml0aWFsaXphYmxlQWN0aW9uLm1vY2snO1xuaW1wb3J0IHsgY3JlYXRlRGF0YWJhc2UsIFRlc3RFbnRpdHkgfSBmcm9tICcuLi90ZXN0VXRpbHMnO1xuaW1wb3J0IHsgc2FtcGxlRW50aXRpZXMgfSBmcm9tICcuLi90ZXN0RGF0YSc7XG5cbmRlc2NyaWJlKCdBYnN0cmFjdEVyZ29FeHRyYWN0b3JBY3Rpb24nLCAoKSA9PiB7XG4gIGxldCBkYXRhU291cmNlOiBEYXRhU291cmNlO1xuICBsZXQgYWN0aW9uOiBUZXN0SW5pdGlhbGl6YWJsZUVyZ29FeHRyYWN0b3JBY3Rpb247XG4gIGxldCByZXBvc2l0b3J5OiBSZXBvc2l0b3J5PFRlc3RFbnRpdHk+O1xuICBiZWZvcmVFYWNoKGFzeW5jICgpID0+IHtcbiAgICBkYXRhU291cmNlID0gYXdhaXQgY3JlYXRlRGF0YWJhc2UoKTtcbiAgICBhY3Rpb24gPSBuZXcgVGVzdEluaXRpYWxpemFibGVFcmdvRXh0cmFjdG9yQWN0aW9uKGRhdGFTb3VyY2UpO1xuICAgIHJlcG9zaXRvcnkgPSBkYXRhU291cmNlLmdldFJlcG9zaXRvcnkoVGVzdEVudGl0eSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdyZW1vdmVBbGxEYXRhJywgKCkgPT4ge1xuICAgIC8qKlxuICAgICAqIEB0YXJnZXQgcmVtb3ZlQWxsRGF0YSBzaG91bGQgcmVtb3ZlIGFsbCBhdmFpbGFibGUgZGF0YSByZWxhdGVkIHRvIHRoaXMgZXh0cmFjdG9yXG4gICAgICogQGRlcGVuZGVuY2llc1xuICAgICAqIEBzY2VuYXJpb1xuICAgICAqIC0gaW5zZXJ0IDQgZW50aXRpZXMgcmVsYXRlZCB0byB0aGlzIGV4dHJhY3RvclxuICAgICAqIC0gcnVuIHRlc3QgKGNhbGwgYHJlbW92ZUFsbERhdGFgKVxuICAgICAqIEBleHBlY3RlZFxuICAgICAqIC0gdG8gaGF2ZSA0IGVudGl0aWVzIGJlZm9yZSByZW1vdmluZ1xuICAgICAqIC0gdG8gaGF2ZSBubyByZW1haW5pbmcgZW50aXRpZXMgYWZ0ZXIgcmVtb3ZlXG4gICAgICovXG4gICAgaXQoYHNob3VsZCByZW1vdmUgYWxsIGF2YWlsYWJsZSBkYXRhIHJlbGF0ZWQgdG8gdGhpcyBleHRyYWN0b3JgLCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBkYXRhU291cmNlLmdldFJlcG9zaXRvcnkoVGVzdEVudGl0eSkuaW5zZXJ0KHNhbXBsZUVudGl0aWVzKTtcbiAgICAgIGNvbnN0IGNvdW50QmVmb3JlID0gYXdhaXQgcmVwb3NpdG9yeS5jb3VudCgpO1xuXG4gICAgICBhd2FpdCBhY3Rpb24ucmVtb3ZlQWxsRGF0YSgnZXh0cmFjdG9yJyk7XG4gICAgICBjb25zdCBjb3VudEFmdGVyID0gYXdhaXQgcmVwb3NpdG9yeS5jb3VudCgpO1xuXG4gICAgICBleHBlY3QoY291bnRCZWZvcmUpLnRvRXF1YWwoNCk7XG4gICAgICBleHBlY3QoY291bnRBZnRlcikudG9FcXVhbCgwKTtcbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIEB0YXJnZXQgcmVtb3ZlQWxsRGF0YSBzaG91bGQgbm90IHJlbW92ZSBhbnkgZGF0YSByZWxhdGVkIHRvIGFub3RoZXIgZXh0cmFjdG9yXG4gICAgICogQGRlcGVuZGVuY2llc1xuICAgICAqIEBzY2VuYXJpb1xuICAgICAqIC0gaW5zZXJ0IDQgZW50aXRpZXMgcmVsYXRlZCB0byBhbm90aGVyIGV4dHJhY3RvclxuICAgICAqIC0gcnVuIHRlc3QgKGNhbGwgYHJlbW92ZUFsbERhdGFgKVxuICAgICAqIEBleHBlY3RlZFxuICAgICAqIC0gdG8gaGF2ZSA0IGVudGl0aWVzIGFmdGVyIHJlbW92aW5nXG4gICAgICovXG4gICAgaXQoYHNob3VsZCBub3QgcmVtb3ZlIGFueSBkYXRhIHJlbGF0ZWQgdG8gYW5vdGhlciBleHRyYWN0b3JgLCBhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBkYXRhU291cmNlLmdldFJlcG9zaXRvcnkoVGVzdEVudGl0eSkuaW5zZXJ0KFxuICAgICAgICBzYW1wbGVFbnRpdGllcy5tYXAoKGVudGl0eSkgPT4gKHtcbiAgICAgICAgICAuLi5lbnRpdHksXG4gICAgICAgICAgZXh0cmFjdG9yOiAnZXh0cmFjdG9yLW5ldycsXG4gICAgICAgIH0pKVxuICAgICAgKTtcbiAgICAgIGNvbnN0IGNvdW50QmVmb3JlID0gYXdhaXQgcmVwb3NpdG9yeS5jb3VudCgpO1xuXG4gICAgICBhd2FpdCBhY3Rpb24ucmVtb3ZlQWxsRGF0YSgnZXh0cmFjdG9yJyk7XG4gICAgICBjb25zdCBjb3VudEFmdGVyID0gYXdhaXQgcmVwb3NpdG9yeS5jb3VudCgpO1xuXG4gICAgICBleHBlY3QoY291bnRCZWZvcmUpLnRvRXF1YWwoNCk7XG4gICAgICBleHBlY3QoY291bnRBZnRlcikudG9FcXVhbCg0KTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ==