quantumcoin 7.0.3 → 7.0.5
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/.github/workflows/publish-npmjs.yaml +22 -22
- package/.gitignore +15 -15
- package/LICENSE +21 -21
- package/README-SDK.md +758 -754
- package/README.md +165 -150
- package/SPEC.md +3845 -3843
- package/config.d.ts +50 -50
- package/config.js +115 -115
- package/examples/AllSolidityTypes.sol +184 -184
- package/examples/SimpleIERC20.sol +74 -74
- package/examples/events.js +41 -35
- package/examples/events.ts +35 -0
- package/examples/example-generator-sdk-js.js +100 -95
- package/examples/example-generator-sdk-js.ts +77 -0
- package/examples/example-generator-sdk-ts.js +100 -95
- package/examples/example-generator-sdk-ts.ts +77 -0
- package/examples/example.js +72 -61
- package/examples/example.ts +61 -0
- package/examples/offline-signing.js +79 -73
- package/examples/offline-signing.ts +66 -0
- package/examples/package-lock.json +596 -57
- package/examples/package.json +32 -16
- package/examples/read-operations.js +32 -27
- package/examples/read-operations.ts +31 -0
- package/examples/sdk-generator-erc20.inline.json +251 -251
- package/examples/solidity-types.ts +43 -43
- package/examples/wallet-offline.js +35 -29
- package/examples/wallet-offline.ts +34 -0
- package/generate-sdk.js +1824 -1490
- package/index.js +12 -12
- package/package.json +95 -75
- package/scripts/copy-declarations.js +31 -0
- package/scripts/run-all-one-by-one.js +151 -0
- package/src/abi/fragments.d.ts +42 -42
- package/src/abi/fragments.js +63 -63
- package/src/abi/index.d.ts +13 -13
- package/src/abi/index.js +9 -9
- package/src/abi/interface.d.ts +128 -132
- package/src/abi/interface.js +590 -590
- package/src/abi/js-abi-coder.d.ts +8 -0
- package/src/abi/js-abi-coder.js +474 -474
- package/src/constants.d.ts +66 -61
- package/src/constants.js +101 -94
- package/src/contract/contract-factory.d.ts +28 -28
- package/src/contract/contract-factory.js +105 -105
- package/src/contract/contract.d.ts +113 -114
- package/src/contract/contract.js +354 -354
- package/src/contract/index.d.ts +9 -9
- package/src/contract/index.js +9 -9
- package/src/errors/index.d.ts +92 -92
- package/src/errors/index.js +188 -188
- package/src/generator/index.d.ts +74 -0
- package/src/generator/index.js +1404 -1404
- package/src/index.d.ts +125 -127
- package/src/index.js +41 -41
- package/src/internal/hex.d.ts +61 -61
- package/src/internal/hex.js +144 -144
- package/src/providers/extra-providers.d.ts +139 -128
- package/src/providers/extra-providers.js +600 -575
- package/src/providers/index.d.ts +17 -16
- package/src/providers/index.js +10 -10
- package/src/providers/json-rpc-provider.d.ts +12 -12
- package/src/providers/json-rpc-provider.js +79 -79
- package/src/providers/provider.d.ts +208 -203
- package/src/providers/provider.js +393 -371
- package/src/types/index.d.ts +214 -462
- package/src/types/index.js +9 -9
- package/src/utils/address.d.ts +72 -72
- package/src/utils/address.js +181 -182
- package/src/utils/encoding.d.ts +120 -120
- package/src/utils/encoding.js +306 -306
- package/src/utils/hashing.d.ts +82 -76
- package/src/utils/hashing.js +313 -298
- package/src/utils/index.d.ts +65 -55
- package/src/utils/index.js +13 -13
- package/src/utils/result.d.ts +57 -57
- package/src/utils/result.js +128 -128
- package/src/utils/rlp.d.ts +12 -12
- package/src/utils/rlp.js +200 -200
- package/src/utils/units.d.ts +29 -29
- package/src/utils/units.js +107 -107
- package/src/wallet/index.d.ts +10 -10
- package/src/wallet/index.js +8 -8
- package/src/wallet/wallet.d.ts +168 -160
- package/src/wallet/wallet.js +500 -489
- package/test/e2e/all-solidity-types.dynamic.test.js +207 -200
- package/test/e2e/all-solidity-types.dynamic.test.ts +191 -0
- package/test/e2e/all-solidity-types.fixtures.js +231 -231
- package/test/e2e/all-solidity-types.generated-sdks.e2e.test.js +387 -368
- package/test/e2e/all-solidity-types.generated-sdks.e2e.test.ts +350 -0
- package/test/e2e/helpers.js +59 -47
- package/test/e2e/signing-context-and-fee.e2e.test.js +141 -0
- package/test/e2e/signing-context-and-fee.e2e.test.ts +128 -0
- package/test/e2e/simple-erc20.generated-sdks.e2e.test.js +168 -151
- package/test/e2e/simple-erc20.generated-sdks.e2e.test.ts +141 -0
- package/test/e2e/transactional.test.js +245 -191
- package/test/e2e/transactional.test.ts +208 -0
- package/test/e2e/typed-generator.e2e.test.js +407 -404
- package/test/e2e/typed-generator.e2e.test.ts +337 -0
- package/test/fixtures/ConstructorParam.sol +23 -23
- package/test/fixtures/MultiContracts.sol +37 -37
- package/test/fixtures/SimpleStorage.sol +18 -18
- package/test/fixtures/StakingContract.abi.json +1 -1
- package/test/integration/ipc-provider.test.js +49 -44
- package/test/integration/ipc-provider.test.ts +44 -0
- package/test/integration/provider.test.js +88 -72
- package/test/integration/provider.test.ts +85 -0
- package/test/integration/ws-provider.test.js +41 -33
- package/test/integration/ws-provider.test.ts +38 -0
- package/test/security/malformed-input.test.js +37 -31
- package/test/security/malformed-input.test.ts +35 -0
- package/test/unit/_encrypted-output.txt +6 -0
- package/test/unit/_log-encrypted-jsons.js +45 -0
- package/test/unit/_write-keystore-fixture.js +16 -0
- package/test/unit/abi-interface.test.js +103 -98
- package/test/unit/abi-interface.test.ts +102 -0
- package/test/unit/address-wallet.test.js +392 -257
- package/test/unit/address-wallet.test.ts +379 -0
- package/test/unit/browser-provider.test.js +85 -82
- package/test/unit/browser-provider.test.ts +79 -0
- package/test/unit/contract.test.js +85 -82
- package/test/unit/contract.test.ts +83 -0
- package/test/unit/encoding-units-rlp.test.js +92 -89
- package/test/unit/encoding-units-rlp.test.ts +91 -0
- package/test/unit/errors.test.js +77 -74
- package/test/unit/errors.test.ts +76 -0
- package/test/unit/filter-by-blockhash.test.js +55 -52
- package/test/unit/filter-by-blockhash.test.ts +54 -0
- package/test/unit/fixtures/encrypted-keystores-48-32-36.js +9 -0
- package/test/unit/generate-contract-cli.test.js +42 -39
- package/test/unit/generate-contract-cli.test.ts +41 -0
- package/test/unit/generate-sdk-artifacts-json.test.js +113 -110
- package/test/unit/generate-sdk-artifacts-json.test.ts +110 -0
- package/test/unit/generator.test.js +102 -99
- package/test/unit/generator.test.ts +101 -0
- package/test/unit/hashing.test.js +68 -54
- package/test/unit/hashing.test.ts +67 -0
- package/test/unit/init.test.js +39 -36
- package/test/unit/init.test.ts +38 -0
- package/test/unit/interface.test.js +56 -53
- package/test/unit/interface.test.ts +54 -0
- package/test/unit/internal-hex.test.js +50 -47
- package/test/unit/internal-hex.test.ts +49 -0
- package/test/unit/populate-transaction.test.js +65 -62
- package/test/unit/populate-transaction.test.ts +64 -0
- package/test/unit/providers.test.js +200 -144
- package/test/unit/providers.test.ts +196 -0
- package/test/unit/result.test.js +80 -77
- package/test/unit/result.test.ts +79 -0
- package/test/unit/solidity-types.test.js +49 -46
- package/test/unit/solidity-types.test.ts +39 -0
- package/test/unit/utils.test.js +57 -54
- package/test/unit/utils.test.ts +56 -0
- package/test/verbose-logger.js +74 -0
- package/tsconfig.build.json +14 -0
package/README.md
CHANGED
|
@@ -1,150 +1,165 @@
|
|
|
1
|
-
> **CAUTION:** This is an experimental SDK. Use at your own risk.
|
|
2
|
-
|
|
3
|
-
**Comprehensive SDK documentation:** see [`README-SDK.md`](./README-SDK.md).
|
|
4
|
-
|
|
5
|
-
## QuantumCoin.js
|
|
6
|
-
|
|
7
|
-
QuantumCoin.js is an **ethers.js v6-compatible** SDK surface for the QuantumCoin blockchain.
|
|
8
|
-
|
|
9
|
-
Key differences vs Ethereum/ethers:
|
|
10
|
-
|
|
11
|
-
- **Addresses are 32 bytes** (66 hex chars including `0x`)
|
|
12
|
-
- **No HDWallet support** (not applicable to QuantumCoin)
|
|
13
|
-
- **All signing, address derivation, and ABI packing/unpacking** are delegated to `quantum-coin-js-sdk` (as required by `SPEC.md`)
|
|
14
|
-
|
|
15
|
-
## Install
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npm install quantumcoin
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Initialize (required)
|
|
22
|
-
|
|
23
|
-
You **must** initialize once before using wallet/address/ABI helpers:
|
|
24
|
-
|
|
25
|
-
```js
|
|
26
|
-
const { Initialize, Config } = require("quantumcoin/config");
|
|
27
|
-
|
|
28
|
-
// defaults: chainId=123123, rpcEndpoint=https://public.rpc.quantumcoinapi.com
|
|
29
|
-
await Initialize(null);
|
|
30
|
-
|
|
31
|
-
// or custom
|
|
32
|
-
await Initialize(new Config(123123, "https://public.rpc.quantumcoinapi.com"));
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Provider (read-only)
|
|
36
|
-
|
|
37
|
-
```js
|
|
38
|
-
const { JsonRpcProvider } = require("quantumcoin");
|
|
39
|
-
|
|
40
|
-
const provider = new JsonRpcProvider("https://public.rpc.quantumcoinapi.com", 123123);
|
|
41
|
-
console.log(await provider.getBlockNumber());
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Wallet (offline + online)
|
|
45
|
-
|
|
46
|
-
```js
|
|
47
|
-
const { Wallet, verifyMessage } = require("quantumcoin");
|
|
48
|
-
const { Initialize } = require("quantumcoin/config");
|
|
49
|
-
|
|
50
|
-
await Initialize(null);
|
|
51
|
-
|
|
52
|
-
const wallet = Wallet.createRandom();
|
|
53
|
-
const sig = wallet.signMessageSync("Hello, QuantumCoin!");
|
|
54
|
-
console.log(verifyMessage("Hello, QuantumCoin!", sig));
|
|
55
|
-
|
|
56
|
-
const encrypted = wallet.encryptSync("mySecurePassword123");
|
|
57
|
-
const restored = Wallet.fromEncryptedJsonSync(encrypted, "mySecurePassword123");
|
|
58
|
-
console.log(restored.address);
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Contracts (read-only)
|
|
62
|
-
|
|
63
|
-
```js
|
|
64
|
-
const { Initialize } = require("quantumcoin/config");
|
|
65
|
-
const { JsonRpcProvider, Contract } = require("quantumcoin");
|
|
66
|
-
|
|
67
|
-
await Initialize(null);
|
|
68
|
-
|
|
69
|
-
const provider = new JsonRpcProvider("https://public.rpc.quantumcoinapi.com", 123123);
|
|
70
|
-
const abi = require("./test/fixtures/StakingContract.abi.json");
|
|
71
|
-
const address = "0x0000000000000000000000000000000000000000000000000000000000001000";
|
|
72
|
-
|
|
73
|
-
const staking = new Contract(address, abi, provider);
|
|
74
|
-
console.log(await staking.getDepositorCount());
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Typed contract generator
|
|
78
|
-
|
|
79
|
-
This repo includes a generator described in `SPEC.md` section 15.
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
# Non-interactive
|
|
83
|
-
node generate-sdk.js --abi path/to/abi.json --bin path/to/bytecode.bin --out ./generated --name MyContract --non-interactive
|
|
84
|
-
|
|
85
|
-
# JavaScript output (with TypeScript `.d.ts` types)
|
|
86
|
-
node generate-sdk.js --lang js --abi path/to/abi.json --bin path/to/bytecode.bin --out ./generated --name MyContract --non-interactive
|
|
87
|
-
|
|
88
|
-
# Interactive
|
|
89
|
-
node generate-sdk.js --abi path/to/abi.json --bin path/to/bytecode.bin
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
If installed as a package, you can also run:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
- **
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
- `
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
- `
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
npm
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
1
|
+
> **CAUTION:** This is an experimental SDK. Use at your own risk.
|
|
2
|
+
|
|
3
|
+
**Comprehensive SDK documentation:** see [`README-SDK.md`](./README-SDK.md).
|
|
4
|
+
|
|
5
|
+
## QuantumCoin.js
|
|
6
|
+
|
|
7
|
+
QuantumCoin.js is an **ethers.js v6-compatible** SDK surface for the QuantumCoin blockchain.
|
|
8
|
+
|
|
9
|
+
Key differences vs Ethereum/ethers:
|
|
10
|
+
|
|
11
|
+
- **Addresses are 32 bytes** (66 hex chars including `0x`)
|
|
12
|
+
- **No HDWallet support** (not applicable to QuantumCoin)
|
|
13
|
+
- **All signing, address derivation, and ABI packing/unpacking** are delegated to `quantum-coin-js-sdk` (as required by `SPEC.md`)
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install quantumcoin
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Initialize (required)
|
|
22
|
+
|
|
23
|
+
You **must** initialize once before using wallet/address/ABI helpers:
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
const { Initialize, Config } = require("quantumcoin/config");
|
|
27
|
+
|
|
28
|
+
// defaults: chainId=123123, rpcEndpoint=https://public.rpc.quantumcoinapi.com
|
|
29
|
+
await Initialize(null);
|
|
30
|
+
|
|
31
|
+
// or custom
|
|
32
|
+
await Initialize(new Config(123123, "https://public.rpc.quantumcoinapi.com"));
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Provider (read-only)
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
const { JsonRpcProvider } = require("quantumcoin");
|
|
39
|
+
|
|
40
|
+
const provider = new JsonRpcProvider("https://public.rpc.quantumcoinapi.com", 123123);
|
|
41
|
+
console.log(await provider.getBlockNumber());
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Wallet (offline + online)
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
const { Wallet, verifyMessage } = require("quantumcoin");
|
|
48
|
+
const { Initialize } = require("quantumcoin/config");
|
|
49
|
+
|
|
50
|
+
await Initialize(null);
|
|
51
|
+
|
|
52
|
+
const wallet = Wallet.createRandom();
|
|
53
|
+
const sig = wallet.signMessageSync("Hello, QuantumCoin!");
|
|
54
|
+
console.log(verifyMessage("Hello, QuantumCoin!", sig));
|
|
55
|
+
|
|
56
|
+
const encrypted = wallet.encryptSync("mySecurePassword123");
|
|
57
|
+
const restored = Wallet.fromEncryptedJsonSync(encrypted, "mySecurePassword123");
|
|
58
|
+
console.log(restored.address);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Contracts (read-only)
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
const { Initialize } = require("quantumcoin/config");
|
|
65
|
+
const { JsonRpcProvider, Contract } = require("quantumcoin");
|
|
66
|
+
|
|
67
|
+
await Initialize(null);
|
|
68
|
+
|
|
69
|
+
const provider = new JsonRpcProvider("https://public.rpc.quantumcoinapi.com", 123123);
|
|
70
|
+
const abi = require("./test/fixtures/StakingContract.abi.json");
|
|
71
|
+
const address = "0x0000000000000000000000000000000000000000000000000000000000001000";
|
|
72
|
+
|
|
73
|
+
const staking = new Contract(address, abi, provider);
|
|
74
|
+
console.log(await staking.getDepositorCount());
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Typed contract generator
|
|
78
|
+
|
|
79
|
+
This repo includes a generator described in `SPEC.md` section 15.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Non-interactive
|
|
83
|
+
node generate-sdk.js --abi path/to/abi.json --bin path/to/bytecode.bin --out ./generated --name MyContract --non-interactive
|
|
84
|
+
|
|
85
|
+
# JavaScript output (with TypeScript `.d.ts` types)
|
|
86
|
+
node generate-sdk.js --lang js --abi path/to/abi.json --bin path/to/bytecode.bin --out ./generated --name MyContract --non-interactive
|
|
87
|
+
|
|
88
|
+
# Interactive
|
|
89
|
+
node generate-sdk.js --abi path/to/abi.json --bin path/to/bytecode.bin
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
If installed as a package, you can also run:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npx sdkgen --abi path/to/abi.json --bin path/to/bytecode.bin --out ./generated --name MyContract --non-interactive
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
For more options (Solidity sources, artifacts JSON, package scaffolding), see [README-SDK.md](./README-SDK.md#typed-sdk-generator-generate-sdkjs).
|
|
99
|
+
|
|
100
|
+
### Generator typing model
|
|
101
|
+
|
|
102
|
+
- **Hard types**: generated wrappers use concrete types from `quantumcoin/types` (e.g. `Uint256Like` for inputs, `Uint256` for outputs).
|
|
103
|
+
- **Single return values are unwrapped**: a Solidity function returning one value returns that value directly (not `[value]`).
|
|
104
|
+
- **Multiple returns**: returned as a tuple type (e.g. `Promise<[Uint256, Bool]>`).
|
|
105
|
+
- **No returns**: `Promise<void>`.
|
|
106
|
+
- **Structs / tuples**: generated as `export type <Name>Input` / `export type <Name>Output` and used directly in method signatures.
|
|
107
|
+
|
|
108
|
+
## Solidity types (TypeScript)
|
|
109
|
+
|
|
110
|
+
QuantumCoin.js exports core Solidity-related typings from:
|
|
111
|
+
|
|
112
|
+
- `quantumcoin/types`
|
|
113
|
+
|
|
114
|
+
Common types:
|
|
115
|
+
|
|
116
|
+
- `AddressLike` (currently `string`, 32-byte address)
|
|
117
|
+
- `BytesLike` (`string | Uint8Array`)
|
|
118
|
+
- `BigNumberish` (`string | number | bigint`)
|
|
119
|
+
- **Hard Solidity aliases** (preferred for typed wrappers): `Uint256Like` / `Uint256`, `Int256Like` / `Int256`, `Bytes32Like` / `Bytes32`, and all widths `Uint8Like`…`Uint256Like`, `Int8Like`…`Int256Like`, plus `Bytes1Like`…`Bytes32Like`
|
|
120
|
+
- `SolidityTypeName`, `SolidityInputValue<T>`, `SolidityOutputValue<T>` (advanced type-level mapping helpers; the generator no longer uses these for wrapper signatures)
|
|
121
|
+
|
|
122
|
+
## Examples
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
npm run example
|
|
126
|
+
npm run example:wallet
|
|
127
|
+
npm run example:contract:read
|
|
128
|
+
npm run example:events
|
|
129
|
+
# Run all examples (including SDK generator JS/TS)
|
|
130
|
+
npm run examples
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
To try the typed SDK generator (generates a full package from Solidity or ABI+BIN):
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
node examples/example-generator-sdk-js.js # JavaScript output
|
|
137
|
+
node examples/example-generator-sdk-ts.js # TypeScript output
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Requires `solc` on `QC_SOLC_PATH` or `SOLC_PATH`, or at default `c:\solc\solc.exe`. See [README-SDK.md](./README-SDK.md) for all generator options (`--artifacts-json`, `--sol`, `--create-package`, etc.).
|
|
141
|
+
|
|
142
|
+
## Tests
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
npm test
|
|
146
|
+
npm run test:unit
|
|
147
|
+
npm run test:non-transactional
|
|
148
|
+
npm run test:e2e
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Troubleshooting
|
|
152
|
+
|
|
153
|
+
- **“SDK not initialized”**: call `Initialize(null)` once at startup.
|
|
154
|
+
- **JSON-RPC errors/timeouts**: verify `Config.rpcEndpoint` or pass an explicit URL to `JsonRpcProvider`.
|
|
155
|
+
- **Node version**: `quantum-coin-js-sdk` tooling is developed primarily against Node 20+. If you see runtime issues, try Node 20 LTS.
|
|
156
|
+
|
|
157
|
+
### Transactional (write) tests
|
|
158
|
+
|
|
159
|
+
The E2E tests broadcast real transactions and require a funded test wallet.
|
|
160
|
+
|
|
161
|
+
- Set RPC URL via env var: `QC_RPC_URL`
|
|
162
|
+
- (Optional) chain id via env var: `QC_CHAIN_ID` (default: 123123)
|
|
163
|
+
- (Optional) solc path via env var: `QC_SOLC_PATH` (default: `c:\solc\solc.exe`)
|
|
164
|
+
|
|
165
|
+
|