@cardano-sdk/e2e 0.16.6-patch.0 → 0.16.6
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/.env.example +4 -6
- package/CHANGELOG.md +11 -9
- package/README.md +2 -18
- package/dist/cjs/environment.d.ts +1 -1
- package/dist/cjs/environment.d.ts.map +1 -1
- package/dist/cjs/environment.js +1 -15
- package/dist/cjs/environment.js.map +1 -1
- package/dist/cjs/factories.d.ts +0 -2
- package/dist/cjs/factories.d.ts.map +1 -1
- package/dist/cjs/factories.js +6 -12
- package/dist/cjs/factories.js.map +1 -1
- package/dist/cjs/index.d.ts +0 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +0 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/scripts/is-local-network-ready.js +5 -28
- package/dist/cjs/scripts/is-local-network-ready.js.map +1 -1
- package/dist/cjs/tools/multi-delegation-data-gen/index.js +13 -3
- package/dist/cjs/tools/multi-delegation-data-gen/index.js.map +1 -1
- package/dist/cjs/tools/multi-delegation-data-gen/utils/config.d.ts +1 -0
- package/dist/cjs/tools/multi-delegation-data-gen/utils/config.d.ts.map +1 -1
- package/dist/cjs/tools/multi-delegation-data-gen/utils/config.js +12 -0
- package/dist/cjs/tools/multi-delegation-data-gen/utils/config.js.map +1 -1
- package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.d.ts +2 -5
- package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.d.ts.map +1 -1
- package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.js +12 -49
- package/dist/cjs/tools/multi-delegation-data-gen/utils/utils.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/util/util.d.ts +0 -1
- package/dist/cjs/util/util.d.ts.map +1 -1
- package/dist/cjs/util/util.js +2 -43
- package/dist/cjs/util/util.js.map +1 -1
- package/dist/esm/environment.d.ts +1 -1
- package/dist/esm/environment.d.ts.map +1 -1
- package/dist/esm/environment.js +1 -15
- package/dist/esm/environment.js.map +1 -1
- package/dist/esm/factories.d.ts +0 -2
- package/dist/esm/factories.d.ts.map +1 -1
- package/dist/esm/factories.js +6 -12
- package/dist/esm/factories.js.map +1 -1
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +0 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/scripts/is-local-network-ready.js +5 -5
- package/dist/esm/scripts/is-local-network-ready.js.map +1 -1
- package/dist/esm/tools/multi-delegation-data-gen/index.js +14 -4
- package/dist/esm/tools/multi-delegation-data-gen/index.js.map +1 -1
- package/dist/esm/tools/multi-delegation-data-gen/utils/config.d.ts +1 -0
- package/dist/esm/tools/multi-delegation-data-gen/utils/config.d.ts.map +1 -1
- package/dist/esm/tools/multi-delegation-data-gen/utils/config.js +12 -0
- package/dist/esm/tools/multi-delegation-data-gen/utils/config.js.map +1 -1
- package/dist/esm/tools/multi-delegation-data-gen/utils/utils.d.ts +2 -5
- package/dist/esm/tools/multi-delegation-data-gen/utils/utils.d.ts.map +1 -1
- package/dist/esm/tools/multi-delegation-data-gen/utils/utils.js +11 -45
- package/dist/esm/tools/multi-delegation-data-gen/utils/utils.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/util/util.d.ts +0 -1
- package/dist/esm/util/util.d.ts.map +1 -1
- package/dist/esm/util/util.js +3 -20
- package/dist/esm/util/util.js.map +1 -1
- package/docker-compose.yml +3 -21
- package/local-network/scripts/mint-handles.sh +108 -6
- package/local-network/scripts/mint-tokens.sh +21 -2
- package/local-network/scripts/mnemonic_keys.sh +14 -0
- package/local-network/scripts/setup-wallets.sh +18 -0
- package/local-network/scripts/start.sh +1 -2
- package/package.json +22 -20
- package/src/environment.ts +1 -19
- package/src/factories.ts +5 -13
- package/src/index.ts +0 -1
- package/src/scripts/is-local-network-ready.ts +6 -8
- package/src/tools/multi-delegation-data-gen/example.json +1 -0
- package/src/tools/multi-delegation-data-gen/index.ts +18 -8
- package/src/tools/multi-delegation-data-gen/utils/config.ts +13 -0
- package/src/tools/multi-delegation-data-gen/utils/utils.ts +13 -110
- package/src/util/util.ts +2 -29
- package/test/k6/endpoints/asset/get-asset.test.js +15 -14
- package/test/k6/endpoints/asset/get-assets.test.js +269 -269
- package/test/k6/endpoints/chain-history/blocks/by-hashes.test.js +12 -11
- package/test/k6/endpoints/chain-history/txs/by-addresses.test.js +18 -15
- package/test/k6/endpoints/chain-history/txs/by-hashes.test.js +12 -11
- package/test/k6/endpoints/network-info/era-summaries.test.js +11 -10
- package/test/k6/endpoints/network-info/genesis-parameters.test.js +11 -10
- package/test/k6/endpoints/network-info/ledger-tip.test.js +11 -10
- package/test/k6/endpoints/network-info/lovelace-supply.test.js +11 -10
- package/test/k6/endpoints/network-info/protocol-parameters.test.js +11 -10
- package/test/k6/endpoints/network-info/stake.test.js +11 -10
- package/test/k6/endpoints/rewards/account-balance.test.js +12 -11
- package/test/k6/endpoints/stake-pool/stats.test.js +11 -10
- package/test/k6/endpoints/utxo/utxo-by-addresses.test.js +16 -11
- package/test/k6/scenarios/tx-submission.test.js +47 -46
- package/test/k6/scenarios/wallet-creation.test.js +127 -120
- package/test/k6/scenarios/wallet-restoration.test.js +264 -126
- package/test/long-running/cache-invalidation.test.ts +64 -13
- package/test/providers/HandleProvider.test.ts +39 -0
- package/test/wallet/PersonalWallet/handle.test.ts +38 -16
- package/test/web-extension/webpack.config.base.js +0 -4
- package/dist/cjs/FaucetProvider/index.d.ts +0 -3
- package/dist/cjs/FaucetProvider/index.d.ts.map +0 -1
- package/dist/cjs/FaucetProvider/index.js +0 -19
- package/dist/cjs/FaucetProvider/index.js.map +0 -1
- package/dist/cjs/FaucetProvider/providers/cardanoWalletFaucetProvider.d.ts +0 -15
- package/dist/cjs/FaucetProvider/providers/cardanoWalletFaucetProvider.d.ts.map +0 -1
- package/dist/cjs/FaucetProvider/providers/cardanoWalletFaucetProvider.js +0 -148
- package/dist/cjs/FaucetProvider/providers/cardanoWalletFaucetProvider.js.map +0 -1
- package/dist/cjs/FaucetProvider/types.d.ts +0 -22
- package/dist/cjs/FaucetProvider/types.d.ts.map +0 -1
- package/dist/cjs/FaucetProvider/types.js +0 -14
- package/dist/cjs/FaucetProvider/types.js.map +0 -1
- package/dist/esm/FaucetProvider/index.d.ts +0 -3
- package/dist/esm/FaucetProvider/index.d.ts.map +0 -1
- package/dist/esm/FaucetProvider/index.js +0 -3
- package/dist/esm/FaucetProvider/index.js.map +0 -1
- package/dist/esm/FaucetProvider/providers/cardanoWalletFaucetProvider.d.ts +0 -15
- package/dist/esm/FaucetProvider/providers/cardanoWalletFaucetProvider.d.ts.map +0 -1
- package/dist/esm/FaucetProvider/providers/cardanoWalletFaucetProvider.js +0 -141
- package/dist/esm/FaucetProvider/providers/cardanoWalletFaucetProvider.js.map +0 -1
- package/dist/esm/FaucetProvider/types.d.ts +0 -22
- package/dist/esm/FaucetProvider/types.d.ts.map +0 -1
- package/dist/esm/FaucetProvider/types.js +0 -10
- package/dist/esm/FaucetProvider/types.js.map +0 -1
- package/local-network/faucet/README.md +0 -12
- package/local-network/faucet/faucet-addresses.json +0 -45
- package/local-network/faucet/faucet-mnemonic.json +0 -6
- package/local-network/faucet/faucet-send-funds.json +0 -23
- package/local-network/scripts/is-faucet-ready.sh +0 -29
- package/src/FaucetProvider/index.ts +0 -2
- package/src/FaucetProvider/providers/cardanoWalletFaucetProvider.ts +0 -233
- package/src/FaucetProvider/types.ts +0 -94
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
/* eslint-disable func-style */
|
|
3
3
|
import { Counter, Trend } from 'k6/metrics';
|
|
4
|
+
import { check, sleep } from 'k6';
|
|
5
|
+
import http from 'k6/http';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Script overall description:
|
|
@@ -22,8 +24,8 @@ import { Counter, Trend } from 'k6/metrics';
|
|
|
22
24
|
*/
|
|
23
25
|
|
|
24
26
|
const RunMode = {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
Onboard: 'Onboard',
|
|
28
|
+
Restore: 'Restore'
|
|
27
29
|
};
|
|
28
30
|
/** Determines run mode: Restore or Onboard */
|
|
29
31
|
const RUN_MODE = RunMode.Onboard;
|
|
@@ -34,17 +36,18 @@ const RUN_MODE = RunMode.Onboard;
|
|
|
34
36
|
*/
|
|
35
37
|
const SPIN_ON_NEW_WALLETS = true;
|
|
36
38
|
|
|
39
|
+
// eslint-disable-next-line no-undef
|
|
37
40
|
const PROVIDER_SERVER_URL = __ENV.PROVIDER_SERVER_URL;
|
|
38
41
|
|
|
39
42
|
/** URL of the JSON file containing the wallets */
|
|
40
43
|
const WALLET_ADDRESSES_URL =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
RUN_MODE === RunMode.Restore
|
|
45
|
+
? 'https://raw.githubusercontent.com/input-output-hk/cardano-js-sdk/master/packages/e2e/test/dump/addresses/mainnet.json'
|
|
46
|
+
: 'https://raw.githubusercontent.com/input-output-hk/cardano-js-sdk/master/packages/e2e/test/dump/addresses/no-history-mainnet.json';
|
|
44
47
|
|
|
45
48
|
/** URL of the JSON file containing the stake pool addresses */
|
|
46
49
|
const POOL_ADDRESSES_URL =
|
|
47
|
-
|
|
50
|
+
'https://raw.githubusercontent.com/input-output-hk/cardano-js-sdk/master/packages/e2e/test/dump/pool_addresses/mainnet.json';
|
|
48
51
|
|
|
49
52
|
/**
|
|
50
53
|
* Define the maximum number of virtual users to simulate
|
|
@@ -66,146 +69,150 @@ const walletSyncTrend = new Trend('wallet_sync', true);
|
|
|
66
69
|
/** Custom count statistic to measure how many wallets were successfully syncd */
|
|
67
70
|
const walletSyncCount = new Counter('wallet_sync_count');
|
|
68
71
|
|
|
72
|
+
/** Repetitive entpoints */
|
|
73
|
+
const TIP_URL = 'network-info/ledger-tip';
|
|
74
|
+
|
|
69
75
|
/** Grab the wallets json file to be used by the scenario */
|
|
70
76
|
export function setup() {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
77
|
+
console.log(`Running in ${RUN_MODE} mode`);
|
|
78
|
+
const res = http.batch([WALLET_ADDRESSES_URL, POOL_ADDRESSES_URL]);
|
|
79
|
+
check(res, { 'get wallets and pools files': (r) => r.every(({ status }) => status >= 200 && status < 300) });
|
|
80
|
+
|
|
81
|
+
const [{ body: resBodyWallets }, { body: resBodyPools }] = res;
|
|
82
|
+
const wallets = JSON.parse(resBodyWallets);
|
|
83
|
+
const walletCount = wallets ? wallets.length : 0;
|
|
84
|
+
check(walletCount, {
|
|
85
|
+
'At least one wallet is required to run the test': (count) => count > 0
|
|
86
|
+
});
|
|
87
|
+
console.log(`Wallet addresses configuration file contains ${walletCount} wallets`);
|
|
88
|
+
if (walletCount < MAX_VU) {
|
|
89
|
+
console.warn(
|
|
90
|
+
`Requested VU count: (${MAX_VU}), is greater than the available walled addresses: ${walletCount}. Some addresses will be reused`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const poolAddresses = JSON.parse(resBodyPools);
|
|
95
|
+
check(poolAddresses, {
|
|
96
|
+
'At least one stake pool address is required to run the test': (p) => p && p.length > 0
|
|
97
|
+
});
|
|
98
|
+
return { poolAddresses, wallets: wallets.slice(0, MAX_VU) };
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
/** Keeps track of wallets that were successfully syncd to avoid restoring twice */
|
|
96
102
|
const syncedWallets = new Set();
|
|
97
103
|
|
|
98
|
-
export
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
thresholds: {
|
|
106
|
-
wallet_sync_count: ['count >= ' + MAX_VU], // All wallets should have syncd
|
|
107
|
-
// Use https://k6.io/docs/using-k6/thresholds/ to set more thresholds. E.g.:
|
|
108
|
-
// wallet_sync: ['p(95)<5000'], // 95% of wallets should sync in under 5 seconds
|
|
109
|
-
wallet_sync: [{ threshold: 'p(95) < 30000', delayAbortEval: '5s' }] // We get a nice graph if we enable thresholds. See this stat on a graph
|
|
110
|
-
},
|
|
111
|
-
scenarios: {
|
|
112
|
-
SyncDifferentSizeWallets: {
|
|
113
|
-
executor: 'ramping-vus',
|
|
114
|
-
startVUs: 1,
|
|
115
|
-
stages: [
|
|
116
|
-
{ duration: RAMP_UP_DURATION, target: MAX_VU },
|
|
117
|
-
{ duration: STEADY_STATE_DURATION, target: MAX_VU }
|
|
118
|
-
],
|
|
119
|
-
gracefulRampDown: '0s',
|
|
120
|
-
gracefulStop: '0s'
|
|
121
|
-
}
|
|
104
|
+
export const options = {
|
|
105
|
+
ext: {
|
|
106
|
+
loadimpact: {
|
|
107
|
+
apm: [],
|
|
108
|
+
distribution: { 'amazon:us:portland': { loadZone: 'amazon:us:portland', percent: 100 } }
|
|
122
109
|
}
|
|
110
|
+
},
|
|
111
|
+
scenarios: {
|
|
112
|
+
SyncDifferentSizeWallets: {
|
|
113
|
+
executor: 'ramping-vus',
|
|
114
|
+
gracefulRampDown: '0s',
|
|
115
|
+
gracefulStop: '0s',
|
|
116
|
+
stages: [
|
|
117
|
+
{ duration: RAMP_UP_DURATION, target: MAX_VU },
|
|
118
|
+
{ duration: STEADY_STATE_DURATION, target: MAX_VU }
|
|
119
|
+
],
|
|
120
|
+
startVUs: 1
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
thresholds: {
|
|
124
|
+
// All wallets should have syncd
|
|
125
|
+
// Use https://k6.io/docs/using-k6/thresholds/ to set more thresholds. E.g.:
|
|
126
|
+
// wallet_sync: ['p(95)<5000'], // 95% of wallets should sync in under 5 seconds
|
|
127
|
+
wallet_sync: [{ delayAbortEval: '5s', threshold: 'p(95) < 30000' }],
|
|
128
|
+
|
|
129
|
+
wallet_sync_count: [`count >= ${MAX_VU}`] // We get a nice graph if we enable thresholds. See this stat on a graph
|
|
130
|
+
}
|
|
123
131
|
};
|
|
124
132
|
|
|
125
133
|
/** Util functions for sending the http post requests to cardano-sdk services */
|
|
126
134
|
const cardanoHttpPost = (url, body = {}) => {
|
|
127
|
-
|
|
128
|
-
|
|
135
|
+
const opts = { headers: { 'content-type': 'application/json' } };
|
|
136
|
+
return http.post(`${PROVIDER_SERVER_URL}/${url}`, JSON.stringify(body), opts);
|
|
129
137
|
};
|
|
130
138
|
const txsByAddress = (address) => {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
139
|
+
let startAt = 0;
|
|
140
|
+
const pageSize = 25;
|
|
141
|
+
let txCount = 0;
|
|
142
|
+
do {
|
|
143
|
+
const resp = cardanoHttpPost('chain-history/txs/by-addresses', {
|
|
144
|
+
addresses: [address],
|
|
145
|
+
blockRange: { lowerBound: { __type: 'undefined' } },
|
|
146
|
+
pagination: { limit: pageSize, startAt }
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (resp.status !== 200) {
|
|
150
|
+
// No point in trying to get the other pages.
|
|
151
|
+
// Should we log this? it will show up as if the restoration was quicker since this wallet did not fetch all the pages
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const { pageResults } = JSON.parse(resp.body);
|
|
156
|
+
startAt += pageSize;
|
|
157
|
+
txCount = pageResults.length;
|
|
158
|
+
} while (txCount === pageSize);
|
|
151
159
|
};
|
|
152
160
|
const utxosByAddresses = (address) => cardanoHttpPost('utxo/utxo-by-addresses', { addresses: [address] });
|
|
153
|
-
const rewardsAccBalance = (rewardAccount) =>
|
|
154
|
-
cardanoHttpPost('rewards/account-balance', { rewardAccount: rewardAccount });
|
|
161
|
+
const rewardsAccBalance = (rewardAccount) => cardanoHttpPost('rewards/account-balance', { rewardAccount });
|
|
155
162
|
const stakePoolSearch = (poolAddress) =>
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
163
|
+
cardanoHttpPost('stake-pool/search', {
|
|
164
|
+
filters: { identifier: { values: [{ id: poolAddress }] } },
|
|
165
|
+
pagination: { limit: 1, startAt: 0 }
|
|
166
|
+
});
|
|
160
167
|
|
|
161
168
|
/** Simulation of requests performed by a wallet while restoring */
|
|
162
169
|
const syncWallet = ({ wallet, poolAddress }) => {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
170
|
+
const startTime = Date.now();
|
|
171
|
+
const { address, stake_address: rewardAccount } = wallet;
|
|
172
|
+
cardanoHttpPost('network-info/era-summaries');
|
|
173
|
+
cardanoHttpPost(TIP_URL);
|
|
174
|
+
txsByAddress(address);
|
|
175
|
+
utxosByAddresses(address);
|
|
176
|
+
cardanoHttpPost('network-info/era-summaries');
|
|
177
|
+
cardanoHttpPost('network-info/genesis-parameters');
|
|
178
|
+
cardanoHttpPost('network-info/protocol-parameters');
|
|
179
|
+
rewardsAccBalance(rewardAccount);
|
|
180
|
+
cardanoHttpPost(TIP_URL);
|
|
181
|
+
cardanoHttpPost('network-info/lovelace-supply');
|
|
182
|
+
cardanoHttpPost('network-info/stake');
|
|
183
|
+
if (RUN_MODE === RunMode.Restore) {
|
|
184
|
+
stakePoolSearch(poolAddress);
|
|
185
|
+
}
|
|
186
|
+
cardanoHttpPost('stake-pool/stats');
|
|
187
|
+
|
|
188
|
+
syncedWallets.add(address);
|
|
189
|
+
walletSyncTrend.add(Date.now() - startTime);
|
|
190
|
+
walletSyncCount.add(1);
|
|
184
191
|
};
|
|
185
192
|
|
|
186
193
|
function getRandomInt(max) {
|
|
187
|
-
|
|
194
|
+
return Math.floor(Math.random() * max);
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
/**
|
|
191
198
|
* Simulate keeping wallet in sync
|
|
192
199
|
* For now, just polling the tip
|
|
193
200
|
*/
|
|
194
|
-
const emulateIdleClient = () => cardanoHttpPost(
|
|
201
|
+
const emulateIdleClient = () => cardanoHttpPost(TIP_URL);
|
|
195
202
|
|
|
196
203
|
export default function ({ wallets, poolAddresses }) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
204
|
+
// Pick a new wallet or reuse the same one?
|
|
205
|
+
// eslint-disable-next-line no-undef
|
|
206
|
+
const walletIdx = SPIN_ON_NEW_WALLETS ? getRandomInt(wallets.length) : __VU;
|
|
207
|
+
|
|
208
|
+
// Get the wallet for the current virtual user
|
|
209
|
+
const wallet = wallets[walletIdx % wallets.length];
|
|
210
|
+
const poolAddress = poolAddresses[walletIdx % poolAddresses.length];
|
|
211
|
+
|
|
212
|
+
if (SPIN_ON_NEW_WALLETS || !syncedWallets.has(wallet.address)) {
|
|
213
|
+
syncWallet({ poolAddress, wallet });
|
|
214
|
+
} else {
|
|
215
|
+
emulateIdleClient();
|
|
216
|
+
sleep(ITERATION_SLEEP);
|
|
217
|
+
}
|
|
218
|
+
}
|