@leofcoin/chain 1.4.44 → 1.4.46
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/exports/browser/chain.js +53 -21
- package/exports/browser/{client-91364a04-457da758.js → client-31b62450-447815f7.js} +1 -1
- package/exports/browser/{index-2c7d7136-ba66b864.js → index-e407f1a3-a07c9df0.js} +1 -1
- package/exports/browser/{messages-bcb7873b-22fd727d.js → messages-2465e07d-6cd91c3d.js} +1 -1
- package/exports/browser/{node-browser-cf761de2.js → node-browser-5de1f022.js} +23 -18
- package/exports/browser/node-browser.js +1 -1
- package/exports/chain.js +53 -21
- package/package.json +1 -1
package/exports/browser/chain.js
CHANGED
|
@@ -7861,6 +7861,8 @@ globalThis.BigNumber = BigNumber;
|
|
|
7861
7861
|
// check if browser or local
|
|
7862
7862
|
class Chain extends Contract {
|
|
7863
7863
|
#state;
|
|
7864
|
+
#lastResolved;
|
|
7865
|
+
#slotTime = 10000;
|
|
7864
7866
|
id;
|
|
7865
7867
|
utils;
|
|
7866
7868
|
/** {Address[]} */
|
|
@@ -8137,6 +8139,19 @@ class Chain extends Contract {
|
|
|
8137
8139
|
return 'synced';
|
|
8138
8140
|
}
|
|
8139
8141
|
async #syncChain(lastBlock) {
|
|
8142
|
+
let current;
|
|
8143
|
+
const timeout = () => current = setTimeout(() => {
|
|
8144
|
+
if (this.#chainSyncing) {
|
|
8145
|
+
if (this.#lastResolved + 10000 > Date.now())
|
|
8146
|
+
timeout();
|
|
8147
|
+
else {
|
|
8148
|
+
this.#chainSyncing = false;
|
|
8149
|
+
console.log('resyncing');
|
|
8150
|
+
this.#syncChain(lastBlock);
|
|
8151
|
+
}
|
|
8152
|
+
}
|
|
8153
|
+
}, 10000);
|
|
8154
|
+
timeout();
|
|
8140
8155
|
if (this.#chainSyncing || !lastBlock || !lastBlock.hash || !lastBlock.hash)
|
|
8141
8156
|
return;
|
|
8142
8157
|
this.#chainSyncing = true;
|
|
@@ -8161,6 +8176,7 @@ class Chain extends Contract {
|
|
|
8161
8176
|
await this.#loadBlocks(this.blocks.slice(start));
|
|
8162
8177
|
await this.#updateState(new BlockMessage(this.#blocks[this.#blocks.length - 1]));
|
|
8163
8178
|
}
|
|
8179
|
+
clearTimeout(current);
|
|
8164
8180
|
this.#chainSyncing = false;
|
|
8165
8181
|
}
|
|
8166
8182
|
async #prepareRequest(request) {
|
|
@@ -8236,6 +8252,7 @@ class Chain extends Contract {
|
|
|
8236
8252
|
this.#blocks[index] = { hash, ...block.decoded };
|
|
8237
8253
|
this.#blockHashMap.set(hash, index);
|
|
8238
8254
|
console.log(`resolved block: ${hash} @${index} ${formatBytes(size)}`);
|
|
8255
|
+
this.#lastResolved = Date.now();
|
|
8239
8256
|
if (previousHash !== '0x0') {
|
|
8240
8257
|
return this.resolveBlock(previousHash);
|
|
8241
8258
|
}
|
|
@@ -8300,7 +8317,7 @@ class Chain extends Contract {
|
|
|
8300
8317
|
}
|
|
8301
8318
|
catch (error) {
|
|
8302
8319
|
console.log({ error });
|
|
8303
|
-
globalThis.peernet.
|
|
8320
|
+
globalThis.peernet.publish('invalid-transaction', hash);
|
|
8304
8321
|
globalThis.pubsub.publish(`transaction.completed.${hash}`, { status: 'fail', hash, error: error });
|
|
8305
8322
|
throw { error, hash, from, to, params, nonce };
|
|
8306
8323
|
}
|
|
@@ -8382,11 +8399,12 @@ class Chain extends Contract {
|
|
|
8382
8399
|
if (Object.keys(transactions)?.length === 0)
|
|
8383
8400
|
return;
|
|
8384
8401
|
const keys = await globalThis.transactionPoolStore.keys();
|
|
8402
|
+
const timestamp = Date.now();
|
|
8385
8403
|
let block = {
|
|
8386
8404
|
transactions: [],
|
|
8387
8405
|
validators: [],
|
|
8388
8406
|
fees: BigNumber.from(0),
|
|
8389
|
-
timestamp
|
|
8407
|
+
timestamp,
|
|
8390
8408
|
previousHash: '',
|
|
8391
8409
|
reward: parseUnits('150'),
|
|
8392
8410
|
index: 0
|
|
@@ -8396,24 +8414,34 @@ class Chain extends Contract {
|
|
|
8396
8414
|
transactions = transactions.sort((a, b) => a.nonce - b.nonce);
|
|
8397
8415
|
for (let transaction of transactions) {
|
|
8398
8416
|
const hash = await transaction.hash();
|
|
8399
|
-
const
|
|
8400
|
-
|
|
8417
|
+
const doubleTransactions = [];
|
|
8418
|
+
for (const block of this.#blocks) {
|
|
8419
|
+
for (const transaction of block.transactions) {
|
|
8420
|
+
if (transaction.hash === hash) {
|
|
8421
|
+
doubleTransactions.push(hash);
|
|
8422
|
+
}
|
|
8423
|
+
}
|
|
8424
|
+
}
|
|
8425
|
+
console.log();
|
|
8426
|
+
if (doubleTransactions.length > 0) {
|
|
8401
8427
|
await globalThis.transactionPoolStore.delete(hash);
|
|
8402
8428
|
await globalThis.peernet.publish('invalid-transaction', hash);
|
|
8403
8429
|
}
|
|
8404
8430
|
else {
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8431
|
+
if (timestamp + this.#slotTime > Date.now()) {
|
|
8432
|
+
try {
|
|
8433
|
+
const result = await this.#executeTransaction({ ...transaction.decoded, hash });
|
|
8434
|
+
console.log({ result });
|
|
8435
|
+
block.transactions.push({ hash, ...transaction.decoded });
|
|
8436
|
+
block.fees = block.fees.add(await calculateFee(transaction.decoded));
|
|
8437
|
+
await globalThis.accountsStore.put(transaction.decoded.from, new TextEncoder().encode(String(transaction.decoded.nonce)));
|
|
8438
|
+
}
|
|
8439
|
+
catch (e) {
|
|
8440
|
+
console.log(keys.includes(hash));
|
|
8441
|
+
console.log({ e });
|
|
8442
|
+
console.log(hash);
|
|
8443
|
+
await globalThis.transactionPoolStore.delete(hash);
|
|
8444
|
+
}
|
|
8417
8445
|
}
|
|
8418
8446
|
}
|
|
8419
8447
|
}
|
|
@@ -8496,17 +8524,21 @@ class Chain extends Contract {
|
|
|
8496
8524
|
// transactionStore.put(message.hash, message.encoded)
|
|
8497
8525
|
}
|
|
8498
8526
|
async #addTransaction(transaction) {
|
|
8527
|
+
transaction = await new TransactionMessage(transaction);
|
|
8528
|
+
const hash = await transaction.hash();
|
|
8499
8529
|
try {
|
|
8500
|
-
transaction = await new TransactionMessage(transaction);
|
|
8501
|
-
const hash = await transaction.hash();
|
|
8502
8530
|
const has = await globalThis.transactionPoolStore.has(hash);
|
|
8503
|
-
if (!has)
|
|
8531
|
+
if (!has) {
|
|
8504
8532
|
await globalThis.transactionPoolStore.put(hash, transaction.encoded);
|
|
8505
|
-
|
|
8506
|
-
|
|
8533
|
+
if (this.#participating && !this.#runningEpoch)
|
|
8534
|
+
this.#runEpoch();
|
|
8535
|
+
}
|
|
8536
|
+
else
|
|
8537
|
+
globalThis.peernet.publish('invalid-transaction', hash);
|
|
8507
8538
|
}
|
|
8508
8539
|
catch (e) {
|
|
8509
8540
|
console.log(e);
|
|
8541
|
+
globalThis.peernet.publish('invalid-transaction', hash);
|
|
8510
8542
|
throw new Error('invalid transaction');
|
|
8511
8543
|
}
|
|
8512
8544
|
}
|
|
@@ -4868,12 +4868,13 @@ const isUint8Array$1 = (type) => type === 'uint8Array';
|
|
|
4868
4868
|
const isBigNumber = (type) => type === 'bigNumber';
|
|
4869
4869
|
const tokenize = (key, value) => {
|
|
4870
4870
|
const optional = key.endsWith('?');
|
|
4871
|
-
let type = value;
|
|
4872
|
-
|
|
4873
|
-
if (value instanceof Uint8Array)
|
|
4871
|
+
let type = value === undefined ? key : value;
|
|
4872
|
+
if (type instanceof Uint8Array)
|
|
4874
4873
|
type = 'uint8Array';
|
|
4875
|
-
else if (
|
|
4874
|
+
else if (type?._isBigNumber || type.isBigNumber)
|
|
4876
4875
|
type = 'bigNumber';
|
|
4876
|
+
else
|
|
4877
|
+
type = Array.isArray(type) ? 'array' : typeof type;
|
|
4877
4878
|
const parts = key.split('?');
|
|
4878
4879
|
const minimumLength = parts[2]?.includes('min') ? parts[2].split['min:'][1] : 0;
|
|
4879
4880
|
return { type, optional, key: parts[0], minimumLength };
|
|
@@ -4885,6 +4886,7 @@ const toType = (data) => {
|
|
|
4885
4886
|
// returns the ArrayBuffer as a UintArray
|
|
4886
4887
|
if (data instanceof ArrayBuffer)
|
|
4887
4888
|
return new Uint8Array(data);
|
|
4889
|
+
// returns the bigNumbers hex as a UintArray
|
|
4888
4890
|
if (data._isBigNumber)
|
|
4889
4891
|
return new TextEncoder().encode(data._hex || data.toHexString());
|
|
4890
4892
|
// returns the string as a UintArray
|
|
@@ -4898,11 +4900,11 @@ const toType = (data) => {
|
|
|
4898
4900
|
return new TextEncoder().encode(data.toString());
|
|
4899
4901
|
throw new Error(`unsuported type ${typeof data || data}`);
|
|
4900
4902
|
};
|
|
4901
|
-
const encode$3 = (proto, input) => {
|
|
4903
|
+
const encode$3 = (proto, input, compress) => {
|
|
4902
4904
|
const keys = Object.keys(proto);
|
|
4903
4905
|
const values = Object.values(proto);
|
|
4904
4906
|
const set = [];
|
|
4905
|
-
for (let i = 0; i <
|
|
4907
|
+
for (let i = 0; i < values.length; i++) {
|
|
4906
4908
|
const token = tokenize(keys[i], values[i]);
|
|
4907
4909
|
const data = input[token.key];
|
|
4908
4910
|
if (!token.optional && data === undefined)
|
|
@@ -4915,14 +4917,14 @@ const encode$3 = (proto, input) => {
|
|
|
4915
4917
|
}
|
|
4916
4918
|
return index$6(set);
|
|
4917
4919
|
};
|
|
4918
|
-
const decode$4 = (proto, uint8Array) => {
|
|
4920
|
+
const decode$4 = (proto, uint8Array, compressed) => {
|
|
4919
4921
|
let deconcated = index$5(uint8Array);
|
|
4920
4922
|
const output = {};
|
|
4921
4923
|
const keys = Object.keys(proto);
|
|
4922
4924
|
const values = Object.values(proto);
|
|
4923
4925
|
if (keys.length !== deconcated.length)
|
|
4924
4926
|
console.warn(`length mismatch: expected ${keys.length} got ${uint8Array.length}`);
|
|
4925
|
-
for (let i = 0; i <
|
|
4927
|
+
for (let i = 0; i < values.length; i++) {
|
|
4926
4928
|
const token = tokenize(keys[i], values[i]);
|
|
4927
4929
|
if (isUint8Array$1(token.type))
|
|
4928
4930
|
output[token.key] = deconcated[i];
|
|
@@ -6009,7 +6011,7 @@ let FormatInterface$1 = class FormatInterface extends BasicInterface$1 {
|
|
|
6009
6011
|
this.fromUint8Array(buffer);
|
|
6010
6012
|
else if (buffer instanceof ArrayBuffer)
|
|
6011
6013
|
this.fromArrayBuffer(buffer);
|
|
6012
|
-
else if (buffer instanceof FormatInterface
|
|
6014
|
+
else if (buffer instanceof FormatInterface && buffer?.name === this.name)
|
|
6013
6015
|
return buffer;
|
|
6014
6016
|
else if (typeof buffer === 'string') {
|
|
6015
6017
|
if (this.isHex(buffer))
|
|
@@ -6281,6 +6283,7 @@ const lastFetched = {
|
|
|
6281
6283
|
timestamp: 0,
|
|
6282
6284
|
},
|
|
6283
6285
|
};
|
|
6286
|
+
const fetchedCoordinates = {};
|
|
6284
6287
|
const getAddress = async () => {
|
|
6285
6288
|
const { address } = lastFetched;
|
|
6286
6289
|
const now = Math.round(new Date().getTime() / 1000);
|
|
@@ -6318,12 +6321,14 @@ class DhtEarth {
|
|
|
6318
6321
|
* @return {Object} {latitude: lat, longitude: lon}
|
|
6319
6322
|
*/
|
|
6320
6323
|
async getCoordinates(address) {
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6324
|
+
if (!fetchedCoordinates[address]) {
|
|
6325
|
+
const request = `https://whereis.leofcoin.org/?ip=${address}`;
|
|
6326
|
+
let response = await fetch(request);
|
|
6327
|
+
response = await response.json();
|
|
6328
|
+
const { lat, lon } = response;
|
|
6329
|
+
fetchedCoordinates[address] = { latitude: lat, longitude: lon };
|
|
6330
|
+
}
|
|
6331
|
+
return fetchedCoordinates[address];
|
|
6327
6332
|
}
|
|
6328
6333
|
/**
|
|
6329
6334
|
* @param {Object} peer
|
|
@@ -20263,7 +20268,7 @@ class Identity {
|
|
|
20263
20268
|
globalThis.peernet.selectedAccount = new TextDecoder().decode(selected);
|
|
20264
20269
|
}
|
|
20265
20270
|
else {
|
|
20266
|
-
const importee = await import(/* webpackChunkName: "generate-account" */ './index-
|
|
20271
|
+
const importee = await import(/* webpackChunkName: "generate-account" */ './index-e407f1a3-a07c9df0.js');
|
|
20267
20272
|
const { identity, accounts } = await importee.default(password, this.network);
|
|
20268
20273
|
await globalThis.accountStore.put('public', JSON.stringify({ walletId: identity.walletId }));
|
|
20269
20274
|
await globalThis.walletStore.put('version', String(1));
|
|
@@ -20434,7 +20439,7 @@ class Peernet {
|
|
|
20434
20439
|
this.root = options.root;
|
|
20435
20440
|
const { RequestMessage, ResponseMessage, PeerMessage, PeerMessageResponse, PeernetMessage, DHTMessage, DHTMessageResponse, DataMessage, DataMessageResponse, PsMessage, ChatMessage, PeernetFile
|
|
20436
20441
|
// FolderMessageResponse
|
|
20437
|
-
} = await import(/* webpackChunkName: "messages" */ './messages-
|
|
20442
|
+
} = await import(/* webpackChunkName: "messages" */ './messages-2465e07d-6cd91c3d.js');
|
|
20438
20443
|
/**
|
|
20439
20444
|
* proto Object containing protos
|
|
20440
20445
|
* @type {Object}
|
|
@@ -20506,7 +20511,7 @@ class Peernet {
|
|
|
20506
20511
|
if (this.#starting || this.#started)
|
|
20507
20512
|
return;
|
|
20508
20513
|
this.#starting = true;
|
|
20509
|
-
const importee = await import('./client-
|
|
20514
|
+
const importee = await import('./client-31b62450-447815f7.js');
|
|
20510
20515
|
/**
|
|
20511
20516
|
* @access public
|
|
20512
20517
|
* @type {PeernetClient}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { N as default } from './node-browser-
|
|
1
|
+
export { N as default } from './node-browser-5de1f022.js';
|
|
2
2
|
import './contract-f76383c3.js';
|
package/exports/chain.js
CHANGED
|
@@ -456,6 +456,8 @@ globalThis.BigNumber = BigNumber;
|
|
|
456
456
|
// check if browser or local
|
|
457
457
|
class Chain extends Contract {
|
|
458
458
|
#state;
|
|
459
|
+
#lastResolved;
|
|
460
|
+
#slotTime = 10000;
|
|
459
461
|
id;
|
|
460
462
|
utils;
|
|
461
463
|
/** {Address[]} */
|
|
@@ -732,6 +734,19 @@ class Chain extends Contract {
|
|
|
732
734
|
return 'synced';
|
|
733
735
|
}
|
|
734
736
|
async #syncChain(lastBlock) {
|
|
737
|
+
let current;
|
|
738
|
+
const timeout = () => current = setTimeout(() => {
|
|
739
|
+
if (this.#chainSyncing) {
|
|
740
|
+
if (this.#lastResolved + 10000 > Date.now())
|
|
741
|
+
timeout();
|
|
742
|
+
else {
|
|
743
|
+
this.#chainSyncing = false;
|
|
744
|
+
console.log('resyncing');
|
|
745
|
+
this.#syncChain(lastBlock);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}, 10000);
|
|
749
|
+
timeout();
|
|
735
750
|
if (this.#chainSyncing || !lastBlock || !lastBlock.hash || !lastBlock.hash)
|
|
736
751
|
return;
|
|
737
752
|
this.#chainSyncing = true;
|
|
@@ -756,6 +771,7 @@ class Chain extends Contract {
|
|
|
756
771
|
await this.#loadBlocks(this.blocks.slice(start));
|
|
757
772
|
await this.#updateState(new BlockMessage(this.#blocks[this.#blocks.length - 1]));
|
|
758
773
|
}
|
|
774
|
+
clearTimeout(current);
|
|
759
775
|
this.#chainSyncing = false;
|
|
760
776
|
}
|
|
761
777
|
async #prepareRequest(request) {
|
|
@@ -831,6 +847,7 @@ class Chain extends Contract {
|
|
|
831
847
|
this.#blocks[index] = { hash, ...block.decoded };
|
|
832
848
|
this.#blockHashMap.set(hash, index);
|
|
833
849
|
console.log(`resolved block: ${hash} @${index} ${formatBytes(size)}`);
|
|
850
|
+
this.#lastResolved = Date.now();
|
|
834
851
|
if (previousHash !== '0x0') {
|
|
835
852
|
return this.resolveBlock(previousHash);
|
|
836
853
|
}
|
|
@@ -895,7 +912,7 @@ class Chain extends Contract {
|
|
|
895
912
|
}
|
|
896
913
|
catch (error) {
|
|
897
914
|
console.log({ error });
|
|
898
|
-
globalThis.peernet.
|
|
915
|
+
globalThis.peernet.publish('invalid-transaction', hash);
|
|
899
916
|
globalThis.pubsub.publish(`transaction.completed.${hash}`, { status: 'fail', hash, error: error });
|
|
900
917
|
throw { error, hash, from, to, params, nonce };
|
|
901
918
|
}
|
|
@@ -977,11 +994,12 @@ class Chain extends Contract {
|
|
|
977
994
|
if (Object.keys(transactions)?.length === 0)
|
|
978
995
|
return;
|
|
979
996
|
const keys = await globalThis.transactionPoolStore.keys();
|
|
997
|
+
const timestamp = Date.now();
|
|
980
998
|
let block = {
|
|
981
999
|
transactions: [],
|
|
982
1000
|
validators: [],
|
|
983
1001
|
fees: BigNumber.from(0),
|
|
984
|
-
timestamp
|
|
1002
|
+
timestamp,
|
|
985
1003
|
previousHash: '',
|
|
986
1004
|
reward: parseUnits('150'),
|
|
987
1005
|
index: 0
|
|
@@ -991,24 +1009,34 @@ class Chain extends Contract {
|
|
|
991
1009
|
transactions = transactions.sort((a, b) => a.nonce - b.nonce);
|
|
992
1010
|
for (let transaction of transactions) {
|
|
993
1011
|
const hash = await transaction.hash();
|
|
994
|
-
const
|
|
995
|
-
|
|
1012
|
+
const doubleTransactions = [];
|
|
1013
|
+
for (const block of this.#blocks) {
|
|
1014
|
+
for (const transaction of block.transactions) {
|
|
1015
|
+
if (transaction.hash === hash) {
|
|
1016
|
+
doubleTransactions.push(hash);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
console.log();
|
|
1021
|
+
if (doubleTransactions.length > 0) {
|
|
996
1022
|
await globalThis.transactionPoolStore.delete(hash);
|
|
997
1023
|
await globalThis.peernet.publish('invalid-transaction', hash);
|
|
998
1024
|
}
|
|
999
1025
|
else {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1026
|
+
if (timestamp + this.#slotTime > Date.now()) {
|
|
1027
|
+
try {
|
|
1028
|
+
const result = await this.#executeTransaction({ ...transaction.decoded, hash });
|
|
1029
|
+
console.log({ result });
|
|
1030
|
+
block.transactions.push({ hash, ...transaction.decoded });
|
|
1031
|
+
block.fees = block.fees.add(await calculateFee(transaction.decoded));
|
|
1032
|
+
await globalThis.accountsStore.put(transaction.decoded.from, new TextEncoder().encode(String(transaction.decoded.nonce)));
|
|
1033
|
+
}
|
|
1034
|
+
catch (e) {
|
|
1035
|
+
console.log(keys.includes(hash));
|
|
1036
|
+
console.log({ e });
|
|
1037
|
+
console.log(hash);
|
|
1038
|
+
await globalThis.transactionPoolStore.delete(hash);
|
|
1039
|
+
}
|
|
1012
1040
|
}
|
|
1013
1041
|
}
|
|
1014
1042
|
}
|
|
@@ -1091,17 +1119,21 @@ class Chain extends Contract {
|
|
|
1091
1119
|
// transactionStore.put(message.hash, message.encoded)
|
|
1092
1120
|
}
|
|
1093
1121
|
async #addTransaction(transaction) {
|
|
1122
|
+
transaction = await new TransactionMessage(transaction);
|
|
1123
|
+
const hash = await transaction.hash();
|
|
1094
1124
|
try {
|
|
1095
|
-
transaction = await new TransactionMessage(transaction);
|
|
1096
|
-
const hash = await transaction.hash();
|
|
1097
1125
|
const has = await globalThis.transactionPoolStore.has(hash);
|
|
1098
|
-
if (!has)
|
|
1126
|
+
if (!has) {
|
|
1099
1127
|
await globalThis.transactionPoolStore.put(hash, transaction.encoded);
|
|
1100
|
-
|
|
1101
|
-
|
|
1128
|
+
if (this.#participating && !this.#runningEpoch)
|
|
1129
|
+
this.#runEpoch();
|
|
1130
|
+
}
|
|
1131
|
+
else
|
|
1132
|
+
globalThis.peernet.publish('invalid-transaction', hash);
|
|
1102
1133
|
}
|
|
1103
1134
|
catch (e) {
|
|
1104
1135
|
console.log(e);
|
|
1136
|
+
globalThis.peernet.publish('invalid-transaction', hash);
|
|
1105
1137
|
throw new Error('invalid transaction');
|
|
1106
1138
|
}
|
|
1107
1139
|
}
|