Change to modified dank-twitch-irc library
Also separate command listener into it's own client
This commit is contained in:
parent
8b12ccad36
commit
ba97c6b777
4 changed files with 76 additions and 63 deletions
|
@ -1,3 +1,3 @@
|
||||||
enableGlobalCache: true
|
enableGlobalCache: true
|
||||||
|
checksumBehavior: ignore
|
||||||
yarnPath: .yarn/releases/yarn-3.0.1.cjs
|
yarnPath: .yarn/releases/yarn-3.0.1.cjs
|
||||||
|
|
41
index.js
41
index.js
|
@ -1,10 +1,11 @@
|
||||||
const { extend: createGotClient } = require('got');
|
const { extend: createGotClient } = require('got');
|
||||||
const { ConnectionError, SayError, JoinError, TimeoutError, UserBanError, ChatClient } = require('dank-twitch-irc');
|
const { ConnectionError, SayError, TimeoutError, UserBanError, ChatClient } = require('dank-twitch-irc');
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
const WS = require('ws');
|
const WS = require('ws');
|
||||||
const Config = require('./config.json');
|
const Config = require('./config.json');
|
||||||
|
|
||||||
const clients = [];
|
const clients = [];
|
||||||
|
let listenClient = null;
|
||||||
const pingInterval = 120e3;
|
const pingInterval = 120e3;
|
||||||
let lastIndex = 0;
|
let lastIndex = 0;
|
||||||
const uuidRegex = /[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}/i;
|
const uuidRegex = /[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}/i;
|
||||||
|
@ -61,6 +62,8 @@ const fetchUrlList = async (list) => {
|
||||||
const runList = async (listData, listID, channel) => {
|
const runList = async (listData, listID, channel) => {
|
||||||
const banArr = listData.split('\n');
|
const banArr = listData.split('\n');
|
||||||
|
|
||||||
|
const targetChannel = Config.UseParallelUniverse === true ? channel : `#${channel}`;
|
||||||
|
|
||||||
if (banArr.length > Config.MaxChunkSize) {
|
if (banArr.length > Config.MaxChunkSize) {
|
||||||
const banChunks = [];
|
const banChunks = [];
|
||||||
while (banArr.length > 0) {
|
while (banArr.length > 0) {
|
||||||
|
@ -80,17 +83,12 @@ const runList = async (listData, listID, channel) => {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
[, user, ...reason] = entry.split(' ');
|
[, user, ...reason] = entry.split(' ');
|
||||||
if (Config.UseParallelUniverse === true) {
|
promises.push(getConnection().ban(targetChannel, user, reason.join(' ')));
|
||||||
const rawBanCommand = `PRIVMSG ${channel} :.ban ${user} ${reason.join(' ')}`;
|
|
||||||
promises.push(getConnection().sendRaw(rawBanCommand));
|
|
||||||
} else {
|
|
||||||
promises.push(getConnection().ban(channel, user, reason.join(' ')));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.allSettled(promises);
|
await Promise.allSettled(promises);
|
||||||
|
|
||||||
say(Config.Username, `${Config.UseParallelUniverse === true ? '[PU]' : ''} Chunk ${currentChunk}/${chunkCount} of ${listID} executed successfully on channel ${channel}`);
|
say(Config.Username, `${Config.UseParallelUniverse === true ? '[PU]' : ''} Chunk ${currentChunk}/${chunkCount} of ${listID} executed successfully on channel ${targetChannel}`);
|
||||||
|
|
||||||
if (currentChunk === chunkCount) {
|
if (currentChunk === chunkCount) {
|
||||||
break;
|
break;
|
||||||
|
@ -108,12 +106,7 @@ const runList = async (listData, listID, channel) => {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
[, user, ...reason] = entry.split(' ');
|
[, user, ...reason] = entry.split(' ');
|
||||||
if (Config.UseParallelUniverse === true) {
|
promises.push(getConnection().ban(targetChannel, user, reason.join(' ')));
|
||||||
const rawBanCommand = `PRIVMSG ${channel} :.ban ${user} ${reason.join(' ')}`;
|
|
||||||
promises.push(getConnection().sendRaw(rawBanCommand));
|
|
||||||
} else {
|
|
||||||
promises.push(getConnection().ban(channel, user, reason.join(' ')));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.allSettled(promises);
|
await Promise.allSettled(promises);
|
||||||
|
@ -134,7 +127,7 @@ const getConnection = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const say = (channel, message) => {
|
const say = (channel, message) => {
|
||||||
getConnection().say(channel, message);
|
listenClient.say(channel, message);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!Config.IgnorePNSL) {
|
if (!Config.IgnorePNSL) {
|
||||||
|
@ -160,7 +153,6 @@ if (!Config.IgnorePNSL) {
|
||||||
console.log(`${chalk.green('[P&SL]')} || New False Positive: ${payload.UserTwitchId} [${payload.BotListGuid}]`);
|
console.log(`${chalk.green('[P&SL]')} || New False Positive: ${payload.UserTwitchId} [${payload.BotListGuid}]`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -171,16 +163,10 @@ if (!Config.IgnorePNSL) {
|
||||||
await Promise.all([...Array(Config.MaxConnections)].map(async (_, i) => {
|
await Promise.all([...Array(Config.MaxConnections)].map(async (_, i) => {
|
||||||
clients[i] = createTwitchClient();
|
clients[i] = createTwitchClient();
|
||||||
clients[i].connect();
|
clients[i].connect();
|
||||||
clients[0].on('ready', async () => {
|
|
||||||
await clients[0].join(Config.Username);
|
|
||||||
});
|
|
||||||
clients[i].on('error', (error) => {
|
clients[i].on('error', (error) => {
|
||||||
if (error instanceof SayError) {
|
if (error instanceof SayError) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (error instanceof JoinError) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (error instanceof UserBanError) {
|
if (error instanceof UserBanError) {
|
||||||
return console.warn(`Failed to ban user ${error.username} from ${error.channelName}`);
|
return console.warn(`Failed to ban user ${error.username} from ${error.channelName}`);
|
||||||
}
|
}
|
||||||
|
@ -200,9 +186,16 @@ if (!Config.IgnorePNSL) {
|
||||||
return await new Promise((resolve) => clients[i].on('ready', () => resolve()));
|
return await new Promise((resolve) => clients[i].on('ready', () => resolve()));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
listenClient = createTwitchClient();
|
||||||
|
listenClient.connect();
|
||||||
|
listenClient.on('ready', async () => {
|
||||||
|
await listenClient.join(`#${Config.Username}`);
|
||||||
|
console.log(`${chalk.green('[TWITCH]')} || Command listener connected`);
|
||||||
|
});
|
||||||
|
|
||||||
console.log(`${chalk.green('[TWITCH]')} || ${clients.filter((i) => i.ready).length} Clients connected`);
|
console.log(`${chalk.green('[TWITCH]')} || ${clients.filter((i) => i.ready).length} Clients connected`);
|
||||||
|
|
||||||
clients[0].on('PRIVMSG', async ({ messageText, senderUserID, channelName }) => {
|
listenClient.on('PRIVMSG', async ({ messageText, senderUserID, channelName }) => {
|
||||||
if (!Config.Users.includes(senderUserID)) {
|
if (!Config.Users.includes(senderUserID)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -234,7 +227,7 @@ if (!Config.IgnorePNSL) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (channel) {
|
if (channel) {
|
||||||
const mods = await getConnection().getMods(channel);
|
const mods = await listenClient.getMods(`#${channel}`);
|
||||||
if (!mods.includes(Config.Username)) {
|
if (!mods.includes(Config.Username)) {
|
||||||
return say(Config.Username, `I am not a moderator in channel ${channel}!`);
|
return say(Config.Username, `I am not a moderator in channel ${channel}!`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,12 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node index.js"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
"dank-twitch-irc": "^4.3.0",
|
"dank-twitch-irc": "https://gitea.ivr.fi/Leppunen/dank-twitch-irc.git#master",
|
||||||
"got": "^11.8.2",
|
"got": "^11.8.2",
|
||||||
"ws": "^8.2.0"
|
"ws": "^8.2.0"
|
||||||
},
|
},
|
||||||
|
|
91
yarn.lock
91
yarn.lock
|
@ -359,9 +359,11 @@ __metadata:
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/debug@npm:^4.1.5":
|
"@types/debug@npm:^4.1.5":
|
||||||
version: 4.1.5
|
version: 4.1.7
|
||||||
resolution: "@types/debug@npm:4.1.5"
|
resolution: "@types/debug@npm:4.1.7"
|
||||||
checksum: 36bdb74909be193aeeb8c9bb64ef45d691f35181dcf75285728ec1e07103cb91042be2e8294f0624fc5922d9b4f68482faf5ea3068288577ebdccee76cd7870c
|
dependencies:
|
||||||
|
"@types/ms": "*"
|
||||||
|
checksum: 0a7b89d8ed72526858f0b61c6fd81f477853e8c4415bb97f48b1b5545248d2ae389931680b94b393b993a7cfe893537a200647d93defe6d87159b96812305adc
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -390,6 +392,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/ms@npm:*":
|
||||||
|
version: 0.7.31
|
||||||
|
resolution: "@types/ms@npm:0.7.31"
|
||||||
|
checksum: daadd354aedde024cce6f5aa873fefe7b71b22cd0e28632a69e8b677aeb48ae8caa1c60e5919bb781df040d116b01cb4316335167a3fc0ef6a63fa3614c0f6da
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/node@npm:*":
|
"@types/node@npm:*":
|
||||||
version: 14.14.13
|
version: 14.14.13
|
||||||
resolution: "@types/node@npm:14.14.13"
|
resolution: "@types/node@npm:14.14.13"
|
||||||
|
@ -707,9 +716,9 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"dank-twitch-irc@npm:^4.3.0":
|
"dank-twitch-irc@https://gitea.ivr.fi/Leppunen/dank-twitch-irc.git#master":
|
||||||
version: 4.3.0
|
version: 4.3.0
|
||||||
resolution: "dank-twitch-irc@npm:4.3.0"
|
resolution: "dank-twitch-irc@https://gitea.ivr.fi/Leppunen/dank-twitch-irc.git#commit=a5522f453e0c12e57f9c37794ef1d5b6e4039599"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/debug": ^4.1.5
|
"@types/debug": ^4.1.5
|
||||||
"@types/duplexify": ^3.6.0
|
"@types/duplexify": ^3.6.0
|
||||||
|
@ -724,8 +733,8 @@ __metadata:
|
||||||
semaphore-async-await: ^1.5.1
|
semaphore-async-await: ^1.5.1
|
||||||
simple-websocket: ^9.0.0
|
simple-websocket: ^9.0.0
|
||||||
split2: ^3.2.1
|
split2: ^3.2.1
|
||||||
ts-toolbelt: ^8.0.3
|
ts-toolbelt: ^9.1.7
|
||||||
checksum: 6d91eb8046b8fdd6884488334c739338ea8db262984722ea89a52fd25cc42c06607f18f86463788b1ccfef3527311a5c47c48196dc8f0dbd011b1caf70f6010d
|
checksum: 0432a765c8f9ccafd1d16a9cd2f6d09243ba6fda0ac3e67c488e52f0d77b7222040496fd97f03212b86b16bb8bab4c8a636ff31b63c75d3c5a3769daa85ddbfe
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -747,7 +756,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1":
|
"debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1":
|
||||||
version: 4.3.2
|
version: 4.3.2
|
||||||
resolution: "debug@npm:4.3.2"
|
resolution: "debug@npm:4.3.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -792,14 +801,14 @@ __metadata:
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"duplexify@npm:^4.1.1":
|
"duplexify@npm:^4.1.1":
|
||||||
version: 4.1.1
|
version: 4.1.2
|
||||||
resolution: "duplexify@npm:4.1.1"
|
resolution: "duplexify@npm:4.1.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
end-of-stream: ^1.4.1
|
end-of-stream: ^1.4.1
|
||||||
inherits: ^2.0.3
|
inherits: ^2.0.3
|
||||||
readable-stream: ^3.1.1
|
readable-stream: ^3.1.1
|
||||||
stream-shift: ^1.0.0
|
stream-shift: ^1.0.0
|
||||||
checksum: 1cf800f1dc1647d6e0272b811421d4ce78b7d9b12dd85c7ecd78b9e4bfba374d309ac9e3440c66461fc62adb69db49aebf49da15962c98a84d8fd33c7e9c5c5a
|
checksum: 964376c61c0e92f6ed0694b3ba97c84f199413dc40ab8dfdaef80b7a7f4982fcabf796214e28ed614a5bc1ec45488a29b81e7d46fa3f5ddf65bcb118c20145ad
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -1553,7 +1562,7 @@ __metadata:
|
||||||
resolution: "massbanner@workspace:."
|
resolution: "massbanner@workspace:."
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk: ^4.1.2
|
chalk: ^4.1.2
|
||||||
dank-twitch-irc: ^4.3.0
|
dank-twitch-irc: "https://gitea.ivr.fi/Leppunen/dank-twitch-irc.git#master"
|
||||||
eslint: ^7.32.0
|
eslint: ^7.32.0
|
||||||
eslint-plugin-unicorn: ^35.0.0
|
eslint-plugin-unicorn: ^35.0.0
|
||||||
got: ^11.8.2
|
got: ^11.8.2
|
||||||
|
@ -1794,10 +1803,10 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"queue-microtask@npm:^1.1.0":
|
"queue-microtask@npm:^1.2.2":
|
||||||
version: 1.2.2
|
version: 1.2.3
|
||||||
resolution: "queue-microtask@npm:1.2.2"
|
resolution: "queue-microtask@npm:1.2.3"
|
||||||
checksum: 94a7906b4ef8b22c81f0c1fa37db3799496bcefb5edf8a53f60fe2f30d254c672c0f916cd9935d818bb4a52c99eeb431ecfb814a5b7eef780966f92b6eee9c55
|
checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -1808,7 +1817,14 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"randombytes@npm:^2.0.3":
|
"randombytes@npm:2.0.3":
|
||||||
|
version: 2.0.3
|
||||||
|
resolution: "randombytes@npm:2.0.3"
|
||||||
|
checksum: 13e1abd143404dd87024bf345fb1a446b2e2ee46d8e1a5a073e8370c9b1e58000d81a97d4327ba7089087213eb6d8c77fa67ab4e91aa00605126d634fcccb9d4
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"randombytes@npm:^2.1.0":
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
resolution: "randombytes@npm:2.1.0"
|
resolution: "randombytes@npm:2.1.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1818,13 +1834,14 @@ __metadata:
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"randomstring@npm:^1.1.5":
|
"randomstring@npm:^1.1.5":
|
||||||
version: 1.1.5
|
version: 1.2.1
|
||||||
resolution: "randomstring@npm:1.1.5"
|
resolution: "randomstring@npm:1.2.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
array-uniq: 1.0.2
|
array-uniq: 1.0.2
|
||||||
|
randombytes: 2.0.3
|
||||||
bin:
|
bin:
|
||||||
randomstring: bin/randomstring
|
randomstring: bin/randomstring
|
||||||
checksum: 7e969682b4f6e32fd947870e3ec2b271359c98aecdd2d8370b87a13df5512ac0e19d5bc5846abbae8b204934b77db52ffa9ca5c0b16a8127a79543dbaa5c6a3c
|
checksum: 501da2ec59638d502dbb66c237ab80790dbb0b50b493347cbf6abc2dfbf6fe08f195d85e37911689bc406f85d31cf9826757398b5af8c9cae7c0ad4f808f3ac0
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -1851,7 +1868,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"readable-stream@npm:^3.0.0, readable-stream@npm:^3.1.1":
|
"readable-stream@npm:^3.0.0, readable-stream@npm:^3.1.1, readable-stream@npm:^3.6.0":
|
||||||
version: 3.6.0
|
version: 3.6.0
|
||||||
resolution: "readable-stream@npm:3.6.0"
|
resolution: "readable-stream@npm:3.6.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2026,15 +2043,15 @@ resolve@^1.10.0:
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"simple-websocket@npm:^9.0.0":
|
"simple-websocket@npm:^9.0.0":
|
||||||
version: 9.0.0
|
version: 9.1.0
|
||||||
resolution: "simple-websocket@npm:9.0.0"
|
resolution: "simple-websocket@npm:9.1.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: ^4.1.1
|
debug: ^4.3.1
|
||||||
queue-microtask: ^1.1.0
|
queue-microtask: ^1.2.2
|
||||||
randombytes: ^2.0.3
|
randombytes: ^2.1.0
|
||||||
readable-stream: ^3.1.1
|
readable-stream: ^3.6.0
|
||||||
ws: ^7.0.0
|
ws: ^7.4.2
|
||||||
checksum: c5f8dbd7018ae0576c042e8bb57709e5a0864e332ff0b4b5521d9115efad280d7ba6612ae4afa49ad2eb1ee0b99d753ad9644675d83d2414447b71bafb889ab8
|
checksum: 458af3cdf1dadd4eed4724f432fdbe2abd8432b4ea49064f3a9c2a98c7539a65a94d0aa24cd3140ac87274f1f16706287c433773e93696f8b82e67c6adcaaae9
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -2195,10 +2212,10 @@ resolve@^1.10.0:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"ts-toolbelt@npm:^8.0.3":
|
"ts-toolbelt@npm:^9.1.7":
|
||||||
version: 8.4.0
|
version: 9.6.0
|
||||||
resolution: "ts-toolbelt@npm:8.4.0"
|
resolution: "ts-toolbelt@npm:9.6.0"
|
||||||
checksum: 12e97e781dd0228e3a13f01f10752b8d65f4bb6c1168b55da0c9c651a12c8178cbc66207a92670abeffe095066ed3133c3c89e6d45b94ec132b6ab87e0a1d328
|
checksum: 9f35fd95d895a5d32ea9fd2e532a695b0bae6cbff6832b77292efa188a0ed1ed6e54f63f74a8920390f3d909a7a3adb20a144686372a8e78b420246a9bd3d58a
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
@ -2290,9 +2307,9 @@ resolve@^1.10.0:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"ws@npm:^7.0.0":
|
"ws@npm:^7.4.2":
|
||||||
version: 7.4.1
|
version: 7.5.3
|
||||||
resolution: "ws@npm:7.4.1"
|
resolution: "ws@npm:7.5.3"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
bufferutil: ^4.0.1
|
bufferutil: ^4.0.1
|
||||||
utf-8-validate: ^5.0.2
|
utf-8-validate: ^5.0.2
|
||||||
|
@ -2301,7 +2318,7 @@ resolve@^1.10.0:
|
||||||
optional: true
|
optional: true
|
||||||
utf-8-validate:
|
utf-8-validate:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 0b350e32a23fdca8bfd83aec06aa4333639c7c4b8bd78aa1082ead2fc8922de363508ec1eb4e6d26a6362ace28a3c2ba83ed5d858cd2a83c35ce8a3743f0c6ce
|
checksum: 423dc0d859fa74020f5555140905b862470a60ea1567bb9ad55a087263d7718b9c94f69678be1cee9868925c570f1e6fc79d09f90c39057bc63fa2edbb2c547b
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue