Update scenario load ios
This commit is contained in:
parent
e55951d42c
commit
ef1ba4ac99
|
|
@ -26,6 +26,7 @@ import Line from '#models/line'
|
|||
import { ErrorRow, TestResult } from '../ultils/types.js'
|
||||
import momentTZ from 'moment-timezone'
|
||||
import { PhysicalPortTest } from './physical_test_service.js'
|
||||
import Station from '#models/station'
|
||||
|
||||
type Inventory = {
|
||||
pid: string
|
||||
|
|
@ -377,6 +378,7 @@ export default class LineConnection {
|
|||
this.breakSpam()
|
||||
}
|
||||
}
|
||||
|
||||
const now = Date.now()
|
||||
this.outputScenario += `\n\n---start-scenarios---${now}---${userName}---${script?.title}---\n---scenario---${script?.title}---${now}---\n`
|
||||
appendLog(
|
||||
|
|
@ -393,46 +395,54 @@ export default class LineConnection {
|
|||
const steps = typeof script?.body === 'string' ? JSON.parse(script?.body) : []
|
||||
let stepIndex = 0
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutTimer = setTimeout(
|
||||
() => {
|
||||
this.config.runningScenario = ''
|
||||
this.socketIO.emit('running_scenario', {
|
||||
stationId: this.config.stationId,
|
||||
lineId: this.config.id,
|
||||
title: '',
|
||||
})
|
||||
this.outputBuffer = ''
|
||||
this.outputScenario = ''
|
||||
this.config.output += 'Timeout run scenario'
|
||||
this.dataDPELP = {
|
||||
line: this.config.lineNumber,
|
||||
pid: '',
|
||||
vid: '',
|
||||
sn: '',
|
||||
ios: '',
|
||||
mac: '',
|
||||
license: [],
|
||||
issues: ['No data'],
|
||||
summary: '',
|
||||
}
|
||||
this.socketIO.emit('line_output', {
|
||||
stationId: this.config.stationId,
|
||||
lineId: this.config.id,
|
||||
data: 'Timeout run scenario',
|
||||
})
|
||||
this.outputScenario += `\n---end-scenarios---${now}---${userName}---\n`
|
||||
appendLog(
|
||||
`\n---end-scenarios---${now}---${userName}---\n`,
|
||||
this.config.stationId,
|
||||
this.config.stationName,
|
||||
this.config.stationIp,
|
||||
this.config.lineNumber
|
||||
)
|
||||
// reject(new Error('Script timeout'))
|
||||
},
|
||||
script.timeout ? Number(script.timeout) * 1000 : 300000
|
||||
// Create a timeout
|
||||
let timeoutTimer: NodeJS.Timeout | null = null
|
||||
const timeoutNumber = script.timeout ? Number(script.timeout) * 1000 : 300000
|
||||
const onTimeout = () => {
|
||||
this.config.runningScenario = ''
|
||||
this.socketIO.emit('running_scenario', {
|
||||
stationId: this.config.stationId,
|
||||
lineId: this.config.id,
|
||||
title: '',
|
||||
})
|
||||
this.outputBuffer = ''
|
||||
this.outputScenario = ''
|
||||
this.config.output += 'Timeout run scenario'
|
||||
this.dataDPELP = {
|
||||
line: this.config.lineNumber,
|
||||
pid: '',
|
||||
vid: '',
|
||||
sn: '',
|
||||
ios: '',
|
||||
mac: '',
|
||||
license: [],
|
||||
issues: ['No data'],
|
||||
summary: '',
|
||||
}
|
||||
this.socketIO.emit('line_output', {
|
||||
stationId: this.config.stationId,
|
||||
lineId: this.config.id,
|
||||
data: 'Timeout run scenario',
|
||||
})
|
||||
this.outputScenario += `\n---end-scenarios---${now}---${userName}---\n`
|
||||
appendLog(
|
||||
`\n---end-scenarios---${now}---${userName}---\n`,
|
||||
this.config.stationId,
|
||||
this.config.stationName,
|
||||
this.config.stationIp,
|
||||
this.config.lineNumber
|
||||
)
|
||||
// reject(new Error('Script timeout'))
|
||||
}
|
||||
const resetTimeout = () => {
|
||||
// console.log('resetTimeout', timeoutNumber)
|
||||
// this.outputBuffer = ''
|
||||
if (timeoutTimer) clearTimeout(timeoutTimer)
|
||||
timeoutTimer = setTimeout(onTimeout, timeoutNumber)
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
timeoutTimer = setTimeout(onTimeout, timeoutNumber)
|
||||
|
||||
const runStep = async (index: number) => {
|
||||
if (index >= steps.length) {
|
||||
|
|
@ -442,7 +452,7 @@ export default class LineConnection {
|
|||
runStep(index)
|
||||
}, 5000)
|
||||
return
|
||||
} else clearTimeout(timeoutTimer)
|
||||
} else if (timeoutTimer) clearTimeout(timeoutTimer)
|
||||
this.outputScenario += `\n---end-scenarios---${now}---${userName}---\n`
|
||||
this.outputBuffer = ''
|
||||
this.config.runningScenario = ''
|
||||
|
|
@ -536,8 +546,6 @@ export default class LineConnection {
|
|||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
// this.outputBuffer = ''
|
||||
// this.outputScenario += `\n---end-scenarios---${now}---${userName}---\n`
|
||||
appendLog(
|
||||
`\n---end-scenarios---${now}---${userName}---\n`,
|
||||
this.config.stationId,
|
||||
|
|
@ -548,19 +556,20 @@ export default class LineConnection {
|
|||
this.listScenarios = []
|
||||
resolve(true)
|
||||
return
|
||||
}
|
||||
} else resetTimeout()
|
||||
|
||||
const step = steps[index]
|
||||
let repeatCount = Number(step.repeat) || 1
|
||||
const delay = step?.delay ? Number(step?.delay) * 1000 : 1000
|
||||
const sendCommand = async () => {
|
||||
if (repeatCount <= 0) {
|
||||
// Done → next step
|
||||
stepIndex++
|
||||
return runStep(stepIndex)
|
||||
}
|
||||
// if (repeatCount <= 0) {
|
||||
// // Done → next step
|
||||
// stepIndex++
|
||||
// return runStep(stepIndex)
|
||||
// }
|
||||
|
||||
if (typeof step.send !== 'undefined') {
|
||||
console.log(Date.now() - now, (step?.send ?? '[ENTER]').toString())
|
||||
this.outputScenario += `\n---send-command---"${(step?.send ?? '[ENTER]').toString().replace(/\r/g, '\\r').replace(/\n/g, '\\n')}"---${now}---\n`
|
||||
appendLog(
|
||||
`\n---send-command---"${(step?.send ?? '[ENTER]').toString().replace(/\r/g, '\\r').replace(/\n/g, '\\n')}"---${now}---\n`,
|
||||
|
|
@ -573,7 +582,11 @@ export default class LineConnection {
|
|||
}
|
||||
|
||||
repeatCount--
|
||||
setTimeout(() => sendCommand(), delay)
|
||||
if (repeatCount <= 0) {
|
||||
// Done → next step
|
||||
stepIndex++
|
||||
return runStep(stepIndex)
|
||||
} else setTimeout(() => sendCommand(), delay)
|
||||
}
|
||||
|
||||
// Nếu expect rỗng → gửi ngay
|
||||
|
|
@ -1043,4 +1056,279 @@ export default class LineConnection {
|
|||
formReport
|
||||
)
|
||||
}
|
||||
|
||||
async loadIosRouter(nameIos: string, userName: string) {
|
||||
const station = await Station.find(this.config.stationId)
|
||||
if (!station) return
|
||||
const network = station?.gateway || '172.25.1.1'
|
||||
const [a, b] = network.split('.').map(Number)
|
||||
|
||||
const body = [
|
||||
{
|
||||
expect: '',
|
||||
send: `IP_ADDRESS=${a}.${b}.100.${this.config.id < 254 ? this.config.id : 254 - this.config.id}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'rommon',
|
||||
send: `IP_SUBNET_MASK=255.255.0.0`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'rommon',
|
||||
send: `DEFAULT_GATEWAY=${station?.gateway ? station?.gateway : '0.0.0.0'}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'rommon',
|
||||
send: `TFTP_SERVER=${station?.tftp_ip}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'rommon',
|
||||
send: `TFTP_FILE=ios/${nameIos}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'rommon',
|
||||
send: `tftpdnld`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'y/n',
|
||||
send: `y`,
|
||||
delay: '2',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'rommon',
|
||||
send: `boot usbflash0:${nameIos}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'Press RETURN to get started',
|
||||
send: ``,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: ``,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: `enable`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '#',
|
||||
send: `configure terminal`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: `boot system usbflash0:${nameIos}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: `end`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: `write memory`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: ``,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
]
|
||||
|
||||
const script = {
|
||||
id: 0,
|
||||
isReboot: true,
|
||||
sendResult: false,
|
||||
send_result: false,
|
||||
title: 'Load IOS Router',
|
||||
timeout: 1000000,
|
||||
body: JSON.stringify(body),
|
||||
}
|
||||
|
||||
this.runScript(script as any, userName)
|
||||
}
|
||||
|
||||
async loadIosSwitch(nameIos: string, userName: string) {
|
||||
const station = await Station.find(this.config.stationId)
|
||||
if (!station) return
|
||||
const network = station?.gateway || '172.25.1.1'
|
||||
const [a, b] = network.split('.').map(Number)
|
||||
|
||||
const body = [
|
||||
{
|
||||
expect: '',
|
||||
send: ``,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: `IP_ADDRESS=${a}.${b}.100.${this.config.id < 254 ? this.config.id : 254 - this.config.id}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'switch:',
|
||||
send: `IP_SUBNET_MASK=255.255.0.0`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'switch:',
|
||||
send: `DEFAULT_GATEWAY=${station?.gateway ? station?.gateway : '0.0.0.0'}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'switch:',
|
||||
send: `TFTP_SERVER=${station?.tftp_ip}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'switch:',
|
||||
send: `TFTP_FILE=ios/${nameIos}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'switch:',
|
||||
send: `tftpdnld`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'y/n',
|
||||
send: `y`,
|
||||
delay: '2',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'switch:',
|
||||
send: `boot flash:${nameIos}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: 'Press RETURN to get started',
|
||||
send: ``,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: ``,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: `enable`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '#',
|
||||
send: `configure terminal`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: `boot system usbflash0:${nameIos}`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: `end`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: `write memory`,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
{
|
||||
expect: '',
|
||||
send: ``,
|
||||
delay: '1',
|
||||
repeat: '1',
|
||||
note: '',
|
||||
},
|
||||
]
|
||||
|
||||
const script = {
|
||||
id: 0,
|
||||
isReboot: false,
|
||||
sendResult: false,
|
||||
send_result: false,
|
||||
title: 'Load IOS Switch',
|
||||
timeout: 1000000,
|
||||
body: JSON.stringify(body),
|
||||
}
|
||||
|
||||
this.runScript(script as any, userName)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import axios from 'axios'
|
|||
import moment from 'moment'
|
||||
|
||||
const mailTo = 'andrew.ng@apactech.io'
|
||||
// const mailCC = ['ips@ipsupply.com.au', 'kay@ipsupply.com.au', 'joseph@apactech.io']
|
||||
const mailCC = ''
|
||||
const mailCC = ['ips@ipsupply.com.au', 'kay@ipsupply.com.au', 'joseph@apactech.io']
|
||||
// const mailCC = ''
|
||||
|
||||
type DetectAI = {
|
||||
status: string[]
|
||||
|
|
|
|||
|
|
@ -339,57 +339,62 @@ export class WebSocketIo {
|
|||
})
|
||||
|
||||
socket.on('control_apc', async (data) => {
|
||||
const { outletNumbers, action, station, apcName } = data
|
||||
if (action === 'reconnect') {
|
||||
if (!station) return
|
||||
const apcIp = (station as any)[`${apcName}_ip`] as string
|
||||
const apc = this.apcsControl.get(apcIp)
|
||||
if (apc) {
|
||||
await apc.reconnect()
|
||||
this.keepConnectAPC(apcIp, io)
|
||||
} else await this.connectApc(io, apcName, station)
|
||||
} else {
|
||||
for (const outletNumber of outletNumbers) {
|
||||
if (!outletNumber || outletNumber < 0) return
|
||||
try {
|
||||
const { outletNumbers, action, station, apcName } = data
|
||||
if (action === 'reconnect') {
|
||||
if (!station) return
|
||||
// find line from station by apcName and outletNumber
|
||||
const lines = await Line.query()
|
||||
.where('station_id', station.id)
|
||||
.andWhere('apc_name', apcName)
|
||||
.andWhere('outlet', outletNumber)
|
||||
if (lines.length > 0) {
|
||||
const line = this.lineMap.get(lines[0].id)
|
||||
if (line) this.setTimeoutConnect(lines[0].id, line)
|
||||
}
|
||||
|
||||
const apcIp = (station as any)[`${apcName}_ip`] as string
|
||||
const apc = this.apcsControl.get(apcIp)
|
||||
if (apc && apc.status !== 'CONNECTED') {
|
||||
if (apc) {
|
||||
await apc.reconnect()
|
||||
this.keepConnectAPC(apcIp, io)
|
||||
}
|
||||
if (apc) {
|
||||
switch (action) {
|
||||
case 'on':
|
||||
await apc?.turnOnOutlet(outletNumber)
|
||||
break
|
||||
case 'off':
|
||||
await apc?.turnOffOutlet(outletNumber)
|
||||
break
|
||||
case 'restart':
|
||||
await apc?.restartOutlet(outletNumber)
|
||||
break
|
||||
case 'reconnect':
|
||||
await apc?.reconnect()
|
||||
break
|
||||
default:
|
||||
break
|
||||
} else await this.connectApc(io, apcName, station)
|
||||
} else {
|
||||
for (const outletNumber of outletNumbers) {
|
||||
if (!outletNumber || outletNumber < 0) return
|
||||
if (!station) return
|
||||
// find line from station by apcName and outletNumber
|
||||
const lines = await Line.query()
|
||||
.where('station_id', station.id)
|
||||
.andWhere('apc_name', apcName)
|
||||
.andWhere('outlet', outletNumber)
|
||||
if (lines.length > 0) {
|
||||
const line = this.lineMap.get(lines[0].id)
|
||||
if (line) this.setTimeoutConnect(lines[0].id, line)
|
||||
}
|
||||
|
||||
const apcIp = (station as any)[`${apcName}_ip`] as string
|
||||
if (!this.apcsControl.get(apcIp)) await this.connectApc(io, apcName, station)
|
||||
const apc = this.apcsControl.get(apcIp)
|
||||
if (apc && apc.status !== 'CONNECTED') {
|
||||
await apc.reconnect()
|
||||
this.keepConnectAPC(apcIp, io)
|
||||
}
|
||||
if (apc) {
|
||||
switch (action) {
|
||||
case 'on':
|
||||
await apc?.turnOnOutlet(outletNumber)
|
||||
break
|
||||
case 'off':
|
||||
await apc?.turnOffOutlet(outletNumber)
|
||||
break
|
||||
case 'restart':
|
||||
await apc?.restartOutlet(outletNumber)
|
||||
break
|
||||
case 'reconnect':
|
||||
await apc?.reconnect()
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
setTimeout(() => {
|
||||
apc?.navigateToOutlets()
|
||||
}, 10000)
|
||||
}
|
||||
setTimeout(() => {
|
||||
apc?.navigateToOutlets()
|
||||
}, 10000)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('control_apc', e)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -636,6 +641,32 @@ export class WebSocketIo {
|
|||
{}
|
||||
)
|
||||
})
|
||||
|
||||
socket.on('load_ios_router', async (data) => {
|
||||
const { stationId, lineId, iosName } = data
|
||||
await this.handleLineOperation(
|
||||
io,
|
||||
stationId,
|
||||
[lineId],
|
||||
async (lineCon) => {
|
||||
lineCon.loadIosRouter(iosName, userName)
|
||||
},
|
||||
{}
|
||||
)
|
||||
})
|
||||
|
||||
socket.on('load_ios_switch', async (data) => {
|
||||
const { stationId, lineId, iosName } = data
|
||||
await this.handleLineOperation(
|
||||
io,
|
||||
stationId,
|
||||
[lineId],
|
||||
async (lineCon) => {
|
||||
lineCon.loadIosSwitch(iosName, userName)
|
||||
},
|
||||
{}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
socketServer.listen(SOCKET_IO_PORT, () => {
|
||||
|
|
|
|||
|
|
@ -42,105 +42,105 @@ export const ButtonDPELP = ({
|
|||
{
|
||||
expect: "",
|
||||
send: "",
|
||||
delay: "1000",
|
||||
delay: "1",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: " no",
|
||||
delay: "1000",
|
||||
delay: "1",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: "\r\n",
|
||||
delay: "1000",
|
||||
delay: "1",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: "\r\n",
|
||||
delay: "2000",
|
||||
delay: "2",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
// {
|
||||
// expect: "",
|
||||
// send: " terminal length 0",
|
||||
// delay: "3000",
|
||||
// delay: "3",
|
||||
// repeat: "1",
|
||||
// note: "",
|
||||
// },
|
||||
{
|
||||
expect: "",
|
||||
send: "enable",
|
||||
delay: "3000",
|
||||
delay: "3",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: "show inventory",
|
||||
delay: "3000",
|
||||
delay: "3",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: "show version | include License",
|
||||
delay: "1000",
|
||||
delay: "1",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: "show version",
|
||||
delay: "1000",
|
||||
delay: "1",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: "show diag",
|
||||
delay: "3000",
|
||||
delay: "3",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: "show post",
|
||||
delay: "3000",
|
||||
delay: "3",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: "show env all",
|
||||
delay: "3000",
|
||||
delay: "3",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: "show license",
|
||||
delay: "3000",
|
||||
delay: "3",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: "show log",
|
||||
delay: "3000",
|
||||
delay: "3",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
{
|
||||
expect: "",
|
||||
send: "show platform",
|
||||
delay: "3000",
|
||||
delay: "3",
|
||||
repeat: "1",
|
||||
note: "",
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue