yolkbot 0.1.0 → 0.1.1-alpha.11
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/build/browser.js +6 -6
- package/package.json +13 -5
- package/src/api.js +5 -5
- package/src/bot.js +97 -56
- package/src/constants/challenges.js +1822 -0
- package/src/constants/index.js +2 -0
- package/src/dispatches/LookAtPosDispatch.js +0 -2
- package/src/dispatches/LookDispatch2.js +18 -0
- package/src/dispatches/SaveLoadoutDispatch.js +1 -1
- package/src/matchmaker.js +2 -5
- package/src/pathing/mapnode.js +10 -4
- package/src/socket.js +2 -3
- package/src/types/bot.d.ts +51 -4
- package/src/types/constants/challenges.d.ts +19 -0
- package/src/types/constants/index.d.ts +2 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yolkbot",
|
|
3
3
|
"description": "create a shell shockers (self) bot in under 10 lines.",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1-alpha.11",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"shell shockers",
|
|
7
7
|
"shellshock.io",
|
|
@@ -35,10 +35,6 @@
|
|
|
35
35
|
"import": "./src/api.js",
|
|
36
36
|
"types": "./src/types/api.d.ts"
|
|
37
37
|
},
|
|
38
|
-
"./bot": {
|
|
39
|
-
"import": "./src/bot.js",
|
|
40
|
-
"types": "./src/types/bot.d.ts"
|
|
41
|
-
},
|
|
42
38
|
"./browser": "./build/browser.js",
|
|
43
39
|
"./comm": "./src/comm/index.js",
|
|
44
40
|
"./matchmaker": {
|
|
@@ -48,6 +44,18 @@
|
|
|
48
44
|
"./packets": "./src/packet.js",
|
|
49
45
|
"./pathing/*": "./src/pathing/*.js",
|
|
50
46
|
"./pathing/*.js": "./src/pathing/*.js",
|
|
47
|
+
"./bot": {
|
|
48
|
+
"import": "./src/bot.js",
|
|
49
|
+
"types": "./src/types/bot.d.ts"
|
|
50
|
+
},
|
|
51
|
+
"./bot/*": {
|
|
52
|
+
"import": "./src/bot/*.js",
|
|
53
|
+
"types": "./src/types/bot/*.d.ts"
|
|
54
|
+
},
|
|
55
|
+
"./bot/*.js": {
|
|
56
|
+
"import": "./src/bot/*.js",
|
|
57
|
+
"types": "./src/types/bot/*.d.ts"
|
|
58
|
+
},
|
|
51
59
|
"./constants": {
|
|
52
60
|
"import": "./src/constants/index.js",
|
|
53
61
|
"types": "./src/types/constants/index.d.ts"
|
package/src/api.js
CHANGED
|
@@ -2,10 +2,10 @@ import axios from 'axios';
|
|
|
2
2
|
|
|
3
3
|
import yolkws from './socket.js';
|
|
4
4
|
|
|
5
|
-
import { FirebaseKey,
|
|
5
|
+
import { FirebaseKey, ProxiesEnabled, UserAgent } from '#constants';
|
|
6
6
|
|
|
7
7
|
let SocksProxyAgent;
|
|
8
|
-
if (
|
|
8
|
+
if (ProxiesEnabled) SocksProxyAgent = (await import('smallsocks')).SocksProxyAgent;
|
|
9
9
|
|
|
10
10
|
const queryServices = async (request, proxy = '', instance = 'shellshock.io') => {
|
|
11
11
|
let ws;
|
|
@@ -91,7 +91,7 @@ async function loginWithCredentials(email, password, prox = '', instance = 'shel
|
|
|
91
91
|
'user-agent': UserAgent,
|
|
92
92
|
'x-client-version': 'Chrome/JsCore/9.17.2/FirebaseCore-web'
|
|
93
93
|
},
|
|
94
|
-
httpsAgent: (
|
|
94
|
+
httpsAgent: (ProxiesEnabled && prox) ? new SocksProxyAgent(prox) : false
|
|
95
95
|
})
|
|
96
96
|
body = request.data
|
|
97
97
|
token = body.idToken;
|
|
@@ -143,7 +143,7 @@ async function loginWithRefreshToken(refreshToken, prox = '', instance = 'shells
|
|
|
143
143
|
'user-agent': UserAgent,
|
|
144
144
|
'x-client-version': 'Chrome/JsCore/9.17.2/FirebaseCore-web'
|
|
145
145
|
},
|
|
146
|
-
httpsAgent: (
|
|
146
|
+
httpsAgent: (ProxiesEnabled && prox) ? new SocksProxyAgent(prox) : false
|
|
147
147
|
})
|
|
148
148
|
body = request.data
|
|
149
149
|
token = body.id_token;
|
|
@@ -185,7 +185,7 @@ async function loginAnonymously(prox = '', instance = 'shellshock.io') {
|
|
|
185
185
|
'user-agent': UserAgent,
|
|
186
186
|
'x-client-version': 'Chrome/JsCore/9.17.2/FirebaseCore-web'
|
|
187
187
|
},
|
|
188
|
-
httpsAgent: (
|
|
188
|
+
httpsAgent: (ProxiesEnabled && prox) ? new SocksProxyAgent(prox) : false
|
|
189
189
|
});
|
|
190
190
|
|
|
191
191
|
const token = body.idToken;
|
package/src/bot.js
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
ItemTypes,
|
|
22
22
|
Movements,
|
|
23
23
|
PlayTypes,
|
|
24
|
+
ProxiesEnabled,
|
|
24
25
|
ShellStreaks
|
|
25
26
|
} from '#constants';
|
|
26
27
|
|
|
@@ -41,7 +42,8 @@ const intents = {
|
|
|
41
42
|
BUFFERS: 4,
|
|
42
43
|
PING: 5,
|
|
43
44
|
COSMETIC_DATA: 6,
|
|
44
|
-
PLAYER_HEALTH: 7
|
|
45
|
+
PLAYER_HEALTH: 7,
|
|
46
|
+
PACKET_HOOK: 8
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
export class Bot {
|
|
@@ -49,7 +51,7 @@ export class Bot {
|
|
|
49
51
|
Intents = intents;
|
|
50
52
|
|
|
51
53
|
constructor(params = {}) {
|
|
52
|
-
if (params.proxy &&
|
|
54
|
+
if (params.proxy && !ProxiesEnabled)
|
|
53
55
|
throw new Error('proxies do not work and hence are not supported in the browser');
|
|
54
56
|
|
|
55
57
|
this.intents = params.intents || [];
|
|
@@ -249,7 +251,7 @@ export class Bot {
|
|
|
249
251
|
this.account.password = pass;
|
|
250
252
|
|
|
251
253
|
const loginData = await createAccount(email, pass, this.proxy, this.instance);
|
|
252
|
-
return this.#processLoginData(loginData);
|
|
254
|
+
return await this.#processLoginData(loginData);
|
|
253
255
|
}
|
|
254
256
|
|
|
255
257
|
async login(email, pass) {
|
|
@@ -257,12 +259,12 @@ export class Bot {
|
|
|
257
259
|
this.account.password = pass;
|
|
258
260
|
|
|
259
261
|
const loginData = await loginWithCredentials(email, pass, this.proxy, this.instance);
|
|
260
|
-
return this.#processLoginData(loginData);
|
|
262
|
+
return await this.#processLoginData(loginData);
|
|
261
263
|
}
|
|
262
264
|
|
|
263
265
|
async loginWithRefreshToken(refreshToken) {
|
|
264
266
|
const loginData = await loginWithRefreshToken(refreshToken, this.proxy, this.instance);
|
|
265
|
-
return this.#processLoginData(loginData);
|
|
267
|
+
return await this.#processLoginData(loginData);
|
|
266
268
|
}
|
|
267
269
|
|
|
268
270
|
async loginAnonymously() {
|
|
@@ -270,10 +272,10 @@ export class Bot {
|
|
|
270
272
|
delete this.account.password;
|
|
271
273
|
|
|
272
274
|
const loginData = await loginAnonymously(this.proxy, this.instance);
|
|
273
|
-
return this.#processLoginData(loginData);
|
|
275
|
+
return await this.#processLoginData(loginData);
|
|
274
276
|
}
|
|
275
277
|
|
|
276
|
-
#processLoginData(loginData) {
|
|
278
|
+
async #processLoginData(loginData) {
|
|
277
279
|
if (typeof loginData == 'string') {
|
|
278
280
|
this.emit('authFail', loginData);
|
|
279
281
|
return false;
|
|
@@ -297,6 +299,29 @@ export class Bot {
|
|
|
297
299
|
this.account.sessionId = loginData.sessionId;
|
|
298
300
|
this.account.vip = loginData.upgradeProductId && !loginData.upgradeIsExpired;
|
|
299
301
|
|
|
302
|
+
if (this.intents.includes(this.Intents.STATS)) this.account.stats = {
|
|
303
|
+
lifetime: loginData.statsLifetime,
|
|
304
|
+
monthly: loginData.statsCurrent
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
if (this.intents.includes(this.Intents.CHALLENGES)) {
|
|
308
|
+
this.account.challenges = [];
|
|
309
|
+
|
|
310
|
+
const { Challenges } = await import('./constants/challenges.js');
|
|
311
|
+
|
|
312
|
+
for (const challenge of loginData.challenges) {
|
|
313
|
+
const challengeData = Challenges.find(c => c.id == challenge.challengeId);
|
|
314
|
+
if (!challengeData) continue;
|
|
315
|
+
|
|
316
|
+
delete challenge.playerId;
|
|
317
|
+
|
|
318
|
+
this.account.challenges.push({
|
|
319
|
+
...challengeData,
|
|
320
|
+
...challenge
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
300
325
|
return this.account;
|
|
301
326
|
}
|
|
302
327
|
|
|
@@ -410,7 +435,7 @@ export class Bot {
|
|
|
410
435
|
this.game.socket.onmessage = (msg) => this._packetQueue.push(msg.data);
|
|
411
436
|
|
|
412
437
|
if (this.autoUpdate)
|
|
413
|
-
setInterval(() => this.update(), this.updateInterval);
|
|
438
|
+
this.updateIntervalId = setInterval(() => this.update(), this.updateInterval);
|
|
414
439
|
|
|
415
440
|
if (this.intents.includes(this.Intents.PING)) {
|
|
416
441
|
const out = CommOut.getBuffer();
|
|
@@ -699,7 +724,7 @@ export class Bot {
|
|
|
699
724
|
|
|
700
725
|
return data;
|
|
701
726
|
} else {
|
|
702
|
-
const data = await (await fetch(`https
|
|
727
|
+
const data = await (await fetch(`https://esm.sh/gh/yolkorg/maps/maps/${name}.json`)).json();
|
|
703
728
|
return data;
|
|
704
729
|
}
|
|
705
730
|
}
|
|
@@ -875,7 +900,15 @@ export class Bot {
|
|
|
875
900
|
const climbing = CommIn.unPackInt8U();
|
|
876
901
|
|
|
877
902
|
const player = this.players[id];
|
|
878
|
-
if (!player)
|
|
903
|
+
if (!player || player.id == this.me.id) {
|
|
904
|
+
for (let i2 = 0; i2 < 3 /* FramesBetweenSyncs */; i2++) {
|
|
905
|
+
CommIn.unPackInt8U();
|
|
906
|
+
CommIn.unPackRadU();
|
|
907
|
+
CommIn.unPackRad();
|
|
908
|
+
CommIn.unPackInt8U();
|
|
909
|
+
}
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
879
912
|
|
|
880
913
|
if (player.position.x !== x) player.position.x = x;
|
|
881
914
|
if (player.position.z !== z) player.position.z = z;
|
|
@@ -888,24 +921,13 @@ export class Bot {
|
|
|
888
921
|
if (this.intents.includes(this.Intents.BUFFERS)) {
|
|
889
922
|
if (!player.buffer) return;
|
|
890
923
|
|
|
891
|
-
if (player.id == this.me.id) {
|
|
892
|
-
for (let i2 = 0; i2 < 3 /* FramesBetweenSyncs */; i2++) {
|
|
893
|
-
CommIn.unPackInt8U();
|
|
894
|
-
CommIn.unPackRadU();
|
|
895
|
-
CommIn.unPackRad();
|
|
896
|
-
CommIn.unPackInt8U();
|
|
897
|
-
}
|
|
898
|
-
return;
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
let yaw, pitch;
|
|
902
924
|
for (let i2 = 0; i2 < 3; i2++) {
|
|
903
925
|
player.buffer[i2].controlKeys = CommIn.unPackInt8U();
|
|
904
926
|
|
|
905
|
-
yaw = CommIn.unPackRadU();
|
|
927
|
+
const yaw = CommIn.unPackRadU();
|
|
906
928
|
if (!isNaN(yaw)) player.buffer[i2].yaw_ = yaw
|
|
907
929
|
|
|
908
|
-
pitch = CommIn.unPackRad();
|
|
930
|
+
const pitch = CommIn.unPackRad();
|
|
909
931
|
if (!isNaN(pitch)) player.buffer[i2].pitch_ = pitch
|
|
910
932
|
|
|
911
933
|
CommIn.unPackInt8U();
|
|
@@ -1476,9 +1498,28 @@ export class Bot {
|
|
|
1476
1498
|
}
|
|
1477
1499
|
}
|
|
1478
1500
|
|
|
1501
|
+
#processChallengeCompletePacket() {
|
|
1502
|
+
const id = CommIn.unPackInt8U();
|
|
1503
|
+
const challengeId = CommIn.unPackInt8U();
|
|
1504
|
+
|
|
1505
|
+
const player = this.players[id];
|
|
1506
|
+
if (!player) return;
|
|
1507
|
+
|
|
1508
|
+
if (!this.intents.includes(this.Intents.CHALLENGES))
|
|
1509
|
+
return this.emit('challengeComplete', player, challengeId);
|
|
1510
|
+
|
|
1511
|
+
const challenge = this.account.challenges.find(c => c.id == challengeId);
|
|
1512
|
+
this.emit('challengeComplete', player, challenge);
|
|
1513
|
+
|
|
1514
|
+
if (player.id == this.me.id) this.refreshChallenges();
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1479
1517
|
#handlePacket(packet) {
|
|
1480
1518
|
CommIn.init(packet);
|
|
1481
1519
|
|
|
1520
|
+
if (this.intents.includes(this.Intents.PACKET_HOOK))
|
|
1521
|
+
this.emit('packet', packet);
|
|
1522
|
+
|
|
1482
1523
|
let lastCommand = 0;
|
|
1483
1524
|
let abort = false;
|
|
1484
1525
|
|
|
@@ -1487,91 +1528,91 @@ export class Bot {
|
|
|
1487
1528
|
|
|
1488
1529
|
switch (cmd) {
|
|
1489
1530
|
case CommCode.syncThem:
|
|
1490
|
-
this.#processSyncThemPacket(
|
|
1531
|
+
this.#processSyncThemPacket();
|
|
1491
1532
|
break;
|
|
1492
1533
|
|
|
1493
1534
|
case CommCode.fire:
|
|
1494
|
-
this.#processFirePacket(
|
|
1535
|
+
this.#processFirePacket();
|
|
1495
1536
|
break;
|
|
1496
1537
|
|
|
1497
1538
|
case CommCode.hitThem:
|
|
1498
|
-
this.#processHitThemPacket(
|
|
1539
|
+
this.#processHitThemPacket();
|
|
1499
1540
|
break;
|
|
1500
1541
|
|
|
1501
1542
|
case CommCode.syncMe:
|
|
1502
|
-
this.#processSyncMePacket(
|
|
1543
|
+
this.#processSyncMePacket();
|
|
1503
1544
|
break;
|
|
1504
1545
|
|
|
1505
1546
|
case CommCode.hitMe:
|
|
1506
|
-
this.#processHitMePacket(
|
|
1547
|
+
this.#processHitMePacket();
|
|
1507
1548
|
break;
|
|
1508
1549
|
|
|
1509
1550
|
case CommCode.swapWeapon:
|
|
1510
|
-
this.#processSwapWeaponPacket(
|
|
1551
|
+
this.#processSwapWeaponPacket();
|
|
1511
1552
|
break;
|
|
1512
1553
|
|
|
1513
1554
|
case CommCode.collectItem:
|
|
1514
|
-
this.#processCollectPacket(
|
|
1555
|
+
this.#processCollectPacket();
|
|
1515
1556
|
break;
|
|
1516
1557
|
|
|
1517
1558
|
case CommCode.respawn:
|
|
1518
|
-
this.#processRespawnPacket(
|
|
1559
|
+
this.#processRespawnPacket();
|
|
1519
1560
|
break;
|
|
1520
1561
|
|
|
1521
1562
|
case CommCode.die:
|
|
1522
|
-
this.#processDeathPacket(
|
|
1563
|
+
this.#processDeathPacket();
|
|
1523
1564
|
break;
|
|
1524
1565
|
|
|
1525
1566
|
case CommCode.pause:
|
|
1526
|
-
this.#processPausePacket(
|
|
1567
|
+
this.#processPausePacket();
|
|
1527
1568
|
break;
|
|
1528
1569
|
|
|
1529
1570
|
case CommCode.chat:
|
|
1530
|
-
this.#processChatPacket(
|
|
1571
|
+
this.#processChatPacket();
|
|
1531
1572
|
break;
|
|
1532
1573
|
|
|
1533
1574
|
case CommCode.addPlayer:
|
|
1534
|
-
this.#processAddPlayerPacket(
|
|
1575
|
+
this.#processAddPlayerPacket();
|
|
1535
1576
|
break;
|
|
1536
1577
|
|
|
1537
1578
|
case CommCode.removePlayer:
|
|
1538
|
-
this.#processRemovePlayerPacket(
|
|
1579
|
+
this.#processRemovePlayerPacket();
|
|
1539
1580
|
break;
|
|
1540
1581
|
|
|
1541
1582
|
case CommCode.eventModifier:
|
|
1542
|
-
this.#processEventModifierPacket(
|
|
1583
|
+
this.#processEventModifierPacket();
|
|
1543
1584
|
break;
|
|
1544
1585
|
|
|
1545
1586
|
case CommCode.metaGameState:
|
|
1546
|
-
this.#processGameStatePacket(
|
|
1587
|
+
this.#processGameStatePacket();
|
|
1547
1588
|
break;
|
|
1548
1589
|
|
|
1549
1590
|
case CommCode.beginShellStreak:
|
|
1550
|
-
this.#processBeginStreakPacket(
|
|
1591
|
+
this.#processBeginStreakPacket();
|
|
1551
1592
|
break;
|
|
1552
1593
|
|
|
1553
1594
|
case CommCode.endShellStreak:
|
|
1554
|
-
this.#processEndStreakPacket(
|
|
1595
|
+
this.#processEndStreakPacket();
|
|
1555
1596
|
break;
|
|
1556
1597
|
|
|
1557
1598
|
case CommCode.hitMeHardBoiled:
|
|
1558
|
-
this.#processHitShieldPacket(
|
|
1599
|
+
this.#processHitShieldPacket();
|
|
1559
1600
|
break;
|
|
1560
1601
|
|
|
1561
1602
|
case CommCode.gameOptions:
|
|
1562
|
-
this.#processGameOptionsPacket(
|
|
1603
|
+
this.#processGameOptionsPacket();
|
|
1563
1604
|
break;
|
|
1564
1605
|
|
|
1565
1606
|
case CommCode.ping:
|
|
1566
|
-
this.#processPingPacket(
|
|
1607
|
+
this.#processPingPacket();
|
|
1567
1608
|
break;
|
|
1568
1609
|
|
|
1569
1610
|
case CommCode.switchTeam:
|
|
1570
|
-
this.#processSwitchTeamPacket(
|
|
1611
|
+
this.#processSwitchTeamPacket();
|
|
1571
1612
|
break;
|
|
1572
1613
|
|
|
1573
1614
|
case CommCode.changeCharacter:
|
|
1574
|
-
this.#processChangeCharacterPacket(
|
|
1615
|
+
this.#processChangeCharacterPacket();
|
|
1575
1616
|
break;
|
|
1576
1617
|
|
|
1577
1618
|
case CommCode.reload:
|
|
@@ -1595,11 +1636,15 @@ export class Bot {
|
|
|
1595
1636
|
break;
|
|
1596
1637
|
|
|
1597
1638
|
case CommCode.updateBalance:
|
|
1598
|
-
this.#processUpdateBalancePacket(
|
|
1639
|
+
this.#processUpdateBalancePacket();
|
|
1640
|
+
break;
|
|
1641
|
+
|
|
1642
|
+
case CommCode.challengeCompleted:
|
|
1643
|
+
this.#processChallengeCompletePacket();
|
|
1599
1644
|
break;
|
|
1600
1645
|
|
|
1601
1646
|
case CommCode.gameAction:
|
|
1602
|
-
this.#processGameActionPacket(
|
|
1647
|
+
this.#processGameActionPacket();
|
|
1603
1648
|
break;
|
|
1604
1649
|
|
|
1605
1650
|
case CommCode.requestGameOptions:
|
|
@@ -1607,7 +1652,7 @@ export class Bot {
|
|
|
1607
1652
|
break;
|
|
1608
1653
|
|
|
1609
1654
|
case CommCode.respawnDenied:
|
|
1610
|
-
this.#processRespawnDeniedPacket(
|
|
1655
|
+
this.#processRespawnDeniedPacket();
|
|
1611
1656
|
break;
|
|
1612
1657
|
|
|
1613
1658
|
// we do not plan to implement these
|
|
@@ -1620,11 +1665,6 @@ export class Bot {
|
|
|
1620
1665
|
CommIn.unPackLongString();
|
|
1621
1666
|
break;
|
|
1622
1667
|
|
|
1623
|
-
case CommCode.challengeCompleted:
|
|
1624
|
-
CommIn.unPackInt8U();
|
|
1625
|
-
CommIn.unPackInt8U();
|
|
1626
|
-
break;
|
|
1627
|
-
|
|
1628
1668
|
default:
|
|
1629
1669
|
console.error(`handlePacket: I got but did not handle a: ${Object.keys(CommCode).find(k => CommCode[k] === cmd)}`);
|
|
1630
1670
|
if (lastCommand) console.error(`handlePacket: It may be a result of the ${lastCommand} command.`);
|
|
@@ -1716,7 +1756,7 @@ export class Bot {
|
|
|
1716
1756
|
return this.pathing.nodeList.hasLineOfSight(this.me.position, target.position);
|
|
1717
1757
|
}
|
|
1718
1758
|
|
|
1719
|
-
getBestTarget() {
|
|
1759
|
+
getBestTarget(customFilter) {
|
|
1720
1760
|
const options = Object.values(this.players)
|
|
1721
1761
|
.filter((player) => player)
|
|
1722
1762
|
.filter((player) => player !== this.me)
|
|
@@ -1724,7 +1764,8 @@ export class Bot {
|
|
|
1724
1764
|
.filter((player) => player.hp > 0)
|
|
1725
1765
|
.filter((player) => player.name !== this.me.name)
|
|
1726
1766
|
.filter((player) => this.me.team === 0 || player.team !== this.me.team)
|
|
1727
|
-
.filter((player) => this.canSee(player))
|
|
1767
|
+
.filter((player) => this.canSee(player))
|
|
1768
|
+
.filter((player) => !!customFilter(player));
|
|
1728
1769
|
|
|
1729
1770
|
let minDistance = 200;
|
|
1730
1771
|
let targetPlayer = null;
|
|
@@ -1831,7 +1872,7 @@ export class Bot {
|
|
|
1831
1872
|
if (this.intents.includes(this.Intents.PLAYER_HEALTH))
|
|
1832
1873
|
clearInterval(this.healthIntervalId);
|
|
1833
1874
|
|
|
1834
|
-
clearInterval(this.
|
|
1875
|
+
clearInterval(this.updateIntervalId);
|
|
1835
1876
|
|
|
1836
1877
|
this.game.socket.close();
|
|
1837
1878
|
this.matchmaker.close();
|