Skip to content

Commit d5776ac

Browse files
Release 3.4.0 (#10)
# Release 3.4.0 ## New features - Possibility to add a prefix and postfix for write messages ## Improvements - Plain text search is used now for pattern search - Automatically set a pattern search within read message when selecting single process data or parameter - Improved handling if connecting SLT device
1 parent 8fb0767 commit d5776ac

9 files changed

Lines changed: 888 additions & 416 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
# Changelog
22
All notable changes to this project will be documented in this file.
33

4+
## Release 3.4.0
5+
6+
### New features
7+
- Possibility to add a prefix and postfix for write messages
8+
9+
### Improvements
10+
- Plain text search is used now for pattern search
11+
- Automatically set a pattern search within read message when selecting single process data or parameter
12+
- Improved handling if connecting SLT device
13+
414
## Release 3.3.0
515

616
### Improvements

CSK_Module_MultiIOLinkSMI/pages/pages/CSK_Module_MultiIOLinkSMI/CSK_Module_MultiIOLinkSMI.html

Lines changed: 264 additions & 113 deletions
Large diffs are not rendered by default.

CSK_Module_MultiIOLinkSMI/project.mf.xml

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ The following functions can be used for reading or writing data by selected inst
8282
<desc>Event to share processing parameters to the instances.</desc>
8383
<param desc="Number of the instance to receive the parameter." multiplicity="1" name="objectNo" type="int"/>
8484
<param desc="Name of the parameter." multiplicity="1" name="parameter" type="string"/>
85-
<param desc="Value of the parameter." multiplicity="1" name="value" type="auto"/>
85+
<param desc="Value of the parameter." multiplicity="?" name="value" type="auto"/>
8686
<param desc="If parameter is for specifici internal used object, its number." multiplicity="?" name="internalObjectNo" type="int"/>
8787
</event>
8888
<event name="OnNewSelectedInstance">
@@ -526,6 +526,14 @@ INFO: Other modules can check via "Script.isServedAsEvent" if event exists.</des
526526
<desc>Notfiy payload after searched and cut relevant part within payload.</desc>
527527
<param desc="Final payload." multiplicity="1" name="payload" type="string"/>
528528
</event>
529+
<event name="OnNewWriteMessagePrefix">
530+
<desc>Notify prefix of currently selected write message.</desc>
531+
<param desc="Prefix" multiplicity="1" name="prefix" type="string"/>
532+
</event>
533+
<event name="OnNewWriteMessagePostfix">
534+
<desc>Notify profix of currently selected write message.</desc>
535+
<param desc="Profix" multiplicity="1" name="profix" type="string"/>
536+
</event>
529537
<function name="setParameterName">
530538
<desc>Function to set the name of the parameters if saved/loaded via the CSK_PersistentData module.</desc>
531539
<param desc="Name of the parameter" multiplicity="1" name="name" type="string"/>
@@ -1149,6 +1157,14 @@ NUM will be replaced by the number of instance (e.g. "readProcessDataBinary_1").
11491157
<desc>Function to set amount of extra bytes to add to process data byte length.</desc>
11501158
<param desc="Amount of extra bytes." multiplicity="1" name="extraBytes" type="int"/>
11511159
</function>
1160+
<function name="setWriteMessagePrefix">
1161+
<desc>Function to set prefix for currently selected write message.</desc>
1162+
<param desc="Prefix to use for currently selected write message." multiplicity="1" name="prefix" type="string"/>
1163+
</function>
1164+
<function name="setWriteMessagePostfix">
1165+
<desc>Function to set postfix for currently selected write message.</desc>
1166+
<param desc="Postfix to use for currently selected write message." multiplicity="1" name="postfix" type="string"/>
1167+
</function>
11521168
</serves>
11531169
</crown>
11541170
<crown name="MultiIOLinkSMI_FC">
@@ -1252,7 +1268,7 @@ Set source event of incoming data to use for writeMessage.</desc>
12521268
</crown>
12531269
</crown>
12541270
<meta key="author">SICK AG</meta>
1255-
<meta key="version">3.3.0</meta>
1271+
<meta key="version">3.4.0</meta>
12561272
<meta key="priority">low</meta>
12571273
<meta key="copy-protected">false</meta>
12581274
<meta key="read-protected">false</meta>

CSK_Module_MultiIOLinkSMI/scripts/CSK_MultiIOLinkSMI_Processing.lua

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -638,12 +638,12 @@ local function updateIODDReadMessages()
638638
local timestamp2 = DateTime.getTimestamp()
639639

640640
if messageContent and messageInfo.searchBegin ~= '' then
641-
local findString = string.find(messageContent, messageInfo.searchBegin, 0)
641+
local findString = string.find(messageContent, messageInfo.searchBegin, 0, true)
642642
if findString then
643643
if messageInfo.searchEnd == '' then
644644
messageContent = string.sub(messageContent, findString + #messageInfo.searchBegin)
645645
else
646-
local findString2 = string.find(messageContent, messageInfo.searchEnd, findString + #messageInfo.searchBegin)
646+
local findString2 = string.find(messageContent, messageInfo.searchEnd, findString + #messageInfo.searchBegin, true)
647647
if findString2 then
648648
messageContent = string.sub(messageContent, findString + #messageInfo.searchBegin, findString2 - 1)
649649
else
@@ -763,7 +763,7 @@ local function updateIODDWriteMessages()
763763
end
764764
local timestamp1 = DateTime.getTimestamp()
765765
local errorMessage = ''
766-
local messageWriteSuccess, messageWriteErrorMessage = writeIODDMessage(messageName, jsonDataToWrite)
766+
local messageWriteSuccess, messageWriteErrorMessage = writeIODDMessage(messageName, messageInfo.prefix .. jsonDataToWrite .. messageInfo.postfix)
767767
local queueSize = ioddWriteMessagesQueue:getSize()
768768
if not messageWriteSuccess then
769769
errorMessage = errorMessage .. 'Failed to write data to device;'
@@ -828,6 +828,16 @@ local function activateInstance()
828828
Script.sleep(200)
829829
end
830830

831+
local sltTmr = Timer.create()
832+
sltTmr:setPeriodic(false)
833+
sltTmr:setExpirationTime(1000)
834+
835+
local function handleOnExpired()
836+
writeParameterByteArray(204, 0, '{"value":[1]}')
837+
writeParameterByteArray(204, 0, '{"value":[0]}')
838+
end
839+
Timer.register(sltTmr, 'OnExpired', handleOnExpired)
840+
831841
--- Function to handle updates of processing parameters from Controller
832842
---@param multiIOLinkSMINo int Number of instance to update
833843
---@param parameter string Parameter to update
@@ -844,6 +854,12 @@ local function handleOnNewProcessingParameter(multiIOLinkSMINo, parameter, value
844854
ioddReadMessagesTimers[readMessageName]:start()
845855
end
846856
end
857+
858+
elseif parameter == 'checkSLT' then
859+
if value == processingParams.port then
860+
sltTmr:start()
861+
end
862+
847863
elseif multiIOLinkSMINo == multiIOLinkSMIInstanceNumber then -- set parameter only in selected script
848864
_G.logger:fine(nameOfModule .. ": Update parameter '" .. parameter .. "' of multiIOLinkSMIInstanceNo." .. tostring(multiIOLinkSMINo) .. " to value = " .. tostring(value))
849865
if parameter == "readMessages" then

CSK_Module_MultiIOLinkSMI/scripts/Communication/MultiIOLinkSMI/MultiIOLinkSMI_Controller.lua

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ Script.serveEvent('CSK_MultiIOLinkSMI.OnNewReadMessageEventName', 'M
165165
Script.serveEvent('CSK_MultiIOLinkSMI.OnNewWriteMessageFunctionName', 'MultiIOLinkSMI_OnNewWriteMessageFunctionName')
166166
Script.serveEvent('CSK_MultiIOLinkSMI.OnNewWriteMessageEventName', 'MultiIOLinkSMI_OnNewWriteMessageEventName')
167167

168+
Script.serveEvent('CSK_MultiIOLinkSMI.OnNewWriteMessagePrefix', 'MultiIOLinkSMI_OnNewWriteMessagePrefix')
169+
Script.serveEvent('CSK_MultiIOLinkSMI.OnNewWriteMessagePostfix', 'MultiIOLinkSMI_OnNewWriteMessagePostfix')
170+
168171
Script.serveEvent('CSK_MultiIOLinkSMI.OnNewReadJSONTemplate', 'MultiIOLinkSMI_OnNewReadJSONTemplate')
169172
Script.serveEvent('CSK_MultiIOLinkSMI.OnNewWriteJSONTemplate', 'MultiIOLinkSMI_OnNewWriteJSONTemplate')
170173
Script.serveEvent('CSK_MultiIOLinkSMI.OnNewReadDataMessage', 'MultiIOLinkSMI_OnNewReadDataMessage')
@@ -382,7 +385,7 @@ local function handleOnExpiredTmrMultiIOLinkSMI()
382385
end
383386

384387
Script.notifyEvent('MultiIOLinkSMI_OnNewStatusCSKIODDInterpreterAvailable', (CSK_IODDInterpreter ~= nil))
385-
Script.notifyEvent('MultiIOLinkSMI_OnNewStatusIODDMatchFound', (multiIOLinkSMI_Instances[selectedInstance].parameters.ioddInfo ~= nil))
388+
Script.notifyEvent('MultiIOLinkSMI_OnNewStatusIODDMatchFound', (multiIOLinkSMI_Instances[selectedInstance].parameters.ioddInfo ~= nil and multiIOLinkSMI_Instances[selectedInstance].status ~= 'PORT_NOT_ACTIVE' and multiIOLinkSMI_Instances[selectedInstance].status ~= 'DEACTIVATED'))
386389
if CSK_IODDInterpreter then
387390
CSK_IODDInterpreter.pageCalledInstances()
388391
end
@@ -458,6 +461,9 @@ local function handleOnExpiredTmrMultiIOLinkSMI()
458461
multiIOLinkSMI_Instances[selectedInstance].parameters.ioddWriteMessages[selectedIODDWriteMessage].jsonTemplate)
459462
)
460463
Script.notifyEvent('MultiIOLinkSMI_OnNewTestWriteIODDMessage', testIODDMessageToWrite)
464+
Script.notifyEvent('MultiIOLinkSMI_OnNewWriteMessagePrefix', multiIOLinkSMI_Instances[selectedInstance].parameters.ioddWriteMessages[selectedIODDWriteMessage].prefix)
465+
Script.notifyEvent('MultiIOLinkSMI_OnNewWriteMessagePostfix', multiIOLinkSMI_Instances[selectedInstance].parameters.ioddWriteMessages[selectedIODDWriteMessage].postfix)
466+
461467
local processDataTableContent, parameterTableContent = CSK_IODDInterpreter.getWriteDataTableContents('writeIOLink_')
462468
Script.notifyEvent('MultiIOLinkSMI_OnNewProcessDataOutTableContentCSKIODDInterpreter', processDataTableContent)
463469
Script.notifyEvent('MultiIOLinkSMI_OnNewWriteParametersTableContentCSKIODDInterpreter', parameterTableContent)
@@ -662,8 +668,8 @@ local function handleOnNewPortEvent(port, eventType, eventCode)
662668
ioddName,
663669
jsonNewIdentification
664670
)
665-
handleOnExpiredTmrMultiIOLinkSMI()
666671
end
672+
handleOnExpiredTmrMultiIOLinkSMI()
667673
end
668674
Script.serveFunction('CSK_MultiIOLinkSMI.handleOnNewPortEvent', handleOnNewPortEvent)
669675

@@ -1080,12 +1086,12 @@ local function triggerProcessDataTestViaUI()
10801086
Script.notifyEvent('MultiIOLinkSMI_OnNewStatusProcessDataTestResult', 'Payload = ' .. tostring(data))
10811087

10821088
if data and multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchBegin ~= '' then
1083-
local findString = string.find(data, multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchBegin, 0)
1089+
local findString = string.find(data, multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchBegin, 0, true)
10841090
if findString then
10851091
if multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchEnd == '' then
10861092
data = string.sub(data, findString + #multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchBegin)
10871093
else
1088-
local findString2 = string.find(data, multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchEnd, findString + #multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchBegin)
1094+
local findString2 = string.find(data, multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchEnd, findString + #multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchBegin, true)
10891095
if findString2 then
10901096
data = string.sub(data, findString + #multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchBegin, findString2 - 1)
10911097
else
@@ -1284,12 +1290,33 @@ local function handleOnNewListIODD(jsonIODDList)
12841290
end
12851291
Script.register('CSK_IODDInterpreter.OnNewListIODD', handleOnNewListIODD)
12861292

1293+
local function parseRowInformation(selection, pattern)
1294+
if selection ~= "" then
1295+
local _, pos = string.find(selection, pattern)
1296+
if pos ~= nil then
1297+
pos = tonumber(pos)
1298+
local endPos = string.find(selection, '"', pos+1)
1299+
local newSelection = string.sub(selection, pos+1, endPos-1)
1300+
if (newSelection ~= nil and newSelection ~= "" ) then
1301+
return newSelection
1302+
end
1303+
end
1304+
end
1305+
end
1306+
12871307
local function processDataInRowSelectedCSKIODDInterpreter(rowData)
12881308
if CSK_IODDInterpreter then
12891309
local jsonTemplate, jsonDataInfo = CSK_IODDInterpreter.processDataInRowSelected(rowData, 'readIOLink_')
12901310
handleOnNewReadDataJsonTemplateAndInfo(jsonTemplate, jsonDataInfo)
12911311
local processDataTableContent = CSK_IODDInterpreter.getReadDataTableContents('readIOLink_')
12921312
Script.notifyEvent('MultiIOLinkSMI_OnNewProcessDataInTableContentCSKIODDInterpreter', processDataTableContent)
1313+
local searchPattern = parseRowInformation(rowData, '"readIOLink_colPD2":"')
1314+
if searchPattern ~= nil then
1315+
setSearchBegin(searchPattern .. '":{"value":')
1316+
setSearchEnd('}')
1317+
Script.notifyEvent('MultiIOLinkSMI_OnNewSearchBegin', tostring(multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchBegin))
1318+
Script.notifyEvent('MultiIOLinkSMI_OnNewSearchEnd', tostring(multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchEnd))
1319+
end
12931320
else
12941321
_G.logger:info(nameOfModule .. ": CSK_IODDInterpreter not available.")
12951322
end
@@ -1302,15 +1329,50 @@ local function readParameterRowSelectedCSKIODDInterpreter(rowData)
13021329
handleOnNewReadDataJsonTemplateAndInfo(jsonTemplate, jsonDataInfo)
13031330
local _, parameterTableContent = CSK_IODDInterpreter.getReadDataTableContents('readIOLink_')
13041331
Script.notifyEvent('MultiIOLinkSMI_OnNewReadParametersTableContentCSKIODDInterpreter', parameterTableContent)
1332+
local searchPattern = parseRowInformation(rowData, '"readIOLink_colSD4":"')
1333+
if searchPattern ~= nil then
1334+
setSearchBegin(searchPattern .. '":{"value":')
1335+
setSearchEnd('}')
1336+
Script.notifyEvent('MultiIOLinkSMI_OnNewSearchBegin', tostring(multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchBegin))
1337+
Script.notifyEvent('MultiIOLinkSMI_OnNewSearchEnd', tostring(multiIOLinkSMI_Instances[selectedInstance].parameters.ioddReadMessages[selectedIODDReadMessage].searchEnd))
1338+
end
13051339
else
13061340
_G.logger:info(nameOfModule .. ": CSK_IODDInterpreter not available.")
13071341
end
13081342
end
13091343
Script.serveFunction('CSK_MultiIOLinkSMI.readParameterRowSelectedCSKIODDInterpreter', readParameterRowSelectedCSKIODDInterpreter)
13101344

1345+
local function checkForWriteMessagePrefixPostfix(content)
1346+
-- Check to set automatically prefix and postfix for write message
1347+
local prefix = ''
1348+
local postfix = ''
1349+
1350+
local _, amountOfValues = string.gsub(content, '"value":','')
1351+
if amountOfValues == 1 then
1352+
local tempPrefix = string.find(content, '"value":')
1353+
if tempPrefix then
1354+
prefix = string.sub(content, 1, tempPrefix+7)
1355+
local _, amountPostfix = string.gsub(content, '{','')
1356+
postfix = ''
1357+
for i=1, amountPostfix do
1358+
postfix = postfix .. '}'
1359+
end
1360+
end
1361+
end
1362+
1363+
if prefix ~= '' and postfix ~= '' then
1364+
CSK_MultiIOLinkSMI.setWriteMessagePrefix(prefix)
1365+
CSK_MultiIOLinkSMI.setWriteMessagePostfix(postfix)
1366+
else
1367+
CSK_MultiIOLinkSMI.setWriteMessagePrefix('')
1368+
CSK_MultiIOLinkSMI.setWriteMessagePostfix('')
1369+
end
1370+
end
1371+
13111372
local function processDataOutRowSelectedCSKIODDInterpreter(rowData)
13121373
if CSK_IODDInterpreter then
13131374
local jsonTemplate, jsonDataInfo = CSK_IODDInterpreter.processDataOutRowSelected(rowData, 'writeIOLink_')
1375+
checkForWriteMessagePrefixPostfix(jsonTemplate)
13141376
handleOnNewWriteDataJsonTemplateAndInfo(jsonTemplate, jsonDataInfo)
13151377
local processDataTableContent = CSK_IODDInterpreter.getWriteDataTableContents('writeIOLink_')
13161378
Script.notifyEvent('MultiIOLinkSMI_OnNewProcessDataOutTableContentCSKIODDInterpreter', processDataTableContent)
@@ -1320,6 +1382,20 @@ local function processDataOutRowSelectedCSKIODDInterpreter(rowData)
13201382
end
13211383
Script.serveFunction('CSK_MultiIOLinkSMI.processDataOutRowSelectedCSKIODDInterpreter', processDataOutRowSelectedCSKIODDInterpreter)
13221384

1385+
local function setWriteMessagePrefix(prefix)
1386+
multiIOLinkSMI_Instances[selectedInstance].parameters.ioddWriteMessages[selectedIODDWriteMessage].prefix = prefix
1387+
Script.notifyEvent('MultiIOLinkSMI_OnNewWriteMessagePrefix', multiIOLinkSMI_Instances[selectedInstance].parameters.ioddWriteMessages[selectedIODDWriteMessage].prefix)
1388+
Script.notifyEvent('MultiIOLinkSMI_OnNewProcessingParameter', selectedInstance, 'writeMessage', json.encode(multiIOLinkSMI_Instances[selectedInstance].parameters.ioddWriteMessages))
1389+
end
1390+
Script.serveFunction('CSK_MultiIOLinkSMI.setWriteMessagePrefix', setWriteMessagePrefix)
1391+
1392+
local function setWriteMessagePostfix(postfix)
1393+
multiIOLinkSMI_Instances[selectedInstance].parameters.ioddWriteMessages[selectedIODDWriteMessage].postfix = postfix
1394+
Script.notifyEvent('MultiIOLinkSMI_OnNewWriteMessagePostfix', multiIOLinkSMI_Instances[selectedInstance].parameters.ioddWriteMessages[selectedIODDWriteMessage].postfix)
1395+
Script.notifyEvent('MultiIOLinkSMI_OnNewProcessingParameter', selectedInstance, 'writeMessage', json.encode(multiIOLinkSMI_Instances[selectedInstance].parameters.ioddWriteMessages))
1396+
end
1397+
Script.serveFunction('CSK_MultiIOLinkSMI.setWriteMessagePostfix', setWriteMessagePostfix)
1398+
13231399
local function writeParameterRowSelectedCSKIODDInterpreter(rowData)
13241400
if CSK_IODDInterpreter then
13251401
local jsonTemplate, jsonDataInfo = CSK_IODDInterpreter.writeParameterRowSelected(rowData, 'writeIOLink_')

CSK_Module_MultiIOLinkSMI/scripts/Communication/MultiIOLinkSMI/MultiIOLinkSMI_Model.lua

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ function multiIOLinkSMI.getDeviceIdentification(port)
9393
local productName = multiIOLinkSMI.IOLinkSMIhandle:deviceRead(port, 18, 0)
9494
if productName then
9595
deviceInfo.productName = converter.toDataType(productName, 'StringT')
96+
if deviceInfo.productName == 'SLT060-0B010J700' then
97+
Script.notifyEvent('MultiIOLinkSMI_OnNewProcessingParameter', 0, 'checkSLT', port)
98+
end
9699
end
97100
local productID = multiIOLinkSMI.IOLinkSMIhandle:deviceRead(port, 19, 0)
98101
if productID then
@@ -409,6 +412,8 @@ function multiIOLinkSMI:createIODDWriteMessage(messageName)
409412
if CSK_IODDInterpreter then
410413
self.parameters.ioddWriteMessages[messageName] = {
411414
writeMessageEventName = "",
415+
prefix = "",
416+
postfix = "",
412417
ioddInstanceId = self.parameters.ioddInfo.ioddInstanceId .. '_WriteMessage_' .. messageName
413418
}
414419
CSK_IODDInterpreter.addInstance()

CSK_Module_MultiIOLinkSMI/scripts/Communication/MultiIOLinkSMI/helper/funcs.lua

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,6 @@ local function checkParameters(content, defaultTable)
196196
elseif content[key] == nil then
197197
_G.logger:info(nameOfModule .. ": Missing parameter '" .. tostring(key) .. "'. Adding default value '" .. tostring(defaultTable[key]) .. "'")
198198
content[key] = defaultTable[key]
199-
if key == 'cameraNo' then
200-
_G.logger:warning(nameOfModule .. ": '" .. tostring(key) .. "' is a major parameter! Default value might not work and needs to be edited!")
201-
end
202199
end
203200
end
204201
return content

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Tested on
6060

6161
|Device|Firmware version|Module version|
6262
|--|--|--|
63+
|SIM300|V1.2.0|V3.4.0|
6364
|SIM300|V1.1.0|V3.3.0|
6465
|SIM300|V1.1.0|V3.2.0|
6566
|SIM300|V0.2.1|V3.1.0|
@@ -69,8 +70,8 @@ Tested on
6970
|SIM1012|V2.4.2|V2.1.1|
7071
|SIM1012|V2.4.2|V2.1.0|
7172
|SIM1012|V2.4.2|V2.0.0|
72-
|SICK AppEngine|V1.7.0|V2.0.0|
7373
|SIM1012|V2.3.0|v1.0.0|
74+
|SICK AppEngine|V1.7.0|V2.0.0|
7475

7576
NOTE! Writing process data to IO-Link device works after SIM1012 firmware version 2.3.0
7677

0 commit comments

Comments
 (0)