2012-07-24 07:30:08 +02:00
|
|
|
vipWindow = nil
|
|
|
|
vipButton = nil
|
|
|
|
addVipWindow = nil
|
2014-01-14 23:15:01 +01:00
|
|
|
editVipWindow = nil
|
|
|
|
vipInfo = {}
|
2011-09-02 06:29:00 +02:00
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
function init()
|
2013-02-18 17:16:22 +01:00
|
|
|
connect(g_game, { onGameStart = refresh,
|
|
|
|
onGameEnd = clear,
|
2012-07-24 07:30:08 +02:00
|
|
|
onAddVip = onAddVip,
|
|
|
|
onVipStateChange = onVipStateChange })
|
2011-11-03 13:17:10 +01:00
|
|
|
|
2012-03-29 01:48:33 +02:00
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
g_keyboard.bindKeyDown('Ctrl+P', toggle)
|
2012-03-29 01:48:33 +02:00
|
|
|
|
2013-01-21 22:36:53 +01:00
|
|
|
vipButton = modules.client_topmenu.addRightGameToggleButton('vipListButton', tr('VIP List') .. ' (Ctrl+P)', '/images/topbuttons/viplist', toggle)
|
2012-03-28 16:10:21 +02:00
|
|
|
vipButton:setOn(true)
|
2013-01-18 23:39:11 +01:00
|
|
|
vipWindow = g_ui.loadUI('viplist', modules.game_interface.getRightPanel())
|
2012-04-27 08:30:54 +02:00
|
|
|
|
2014-01-14 23:15:01 +01:00
|
|
|
if not g_game.getFeature(GameAdditionalVipInfo) then
|
|
|
|
loadVipInfo()
|
|
|
|
end
|
2012-07-24 07:30:08 +02:00
|
|
|
refresh()
|
2012-08-21 23:40:47 +02:00
|
|
|
vipWindow:setup()
|
2011-11-03 13:17:10 +01:00
|
|
|
end
|
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
function terminate()
|
2012-06-26 00:13:30 +02:00
|
|
|
g_keyboard.unbindKeyDown('Ctrl+P')
|
2013-02-18 17:16:22 +01:00
|
|
|
disconnect(g_game, { onGameStart = refresh,
|
|
|
|
onGameEnd = clear,
|
2012-07-24 07:30:08 +02:00
|
|
|
onAddVip = onAddVip,
|
|
|
|
onVipStateChange = onVipStateChange })
|
2012-03-29 01:48:33 +02:00
|
|
|
|
2014-01-14 23:15:01 +01:00
|
|
|
if not g_game.getFeature(GameAdditionalVipInfo) then
|
|
|
|
saveVipInfo()
|
|
|
|
end
|
|
|
|
|
|
|
|
if addVipWindow then
|
|
|
|
addVipWindow:destroy()
|
|
|
|
end
|
|
|
|
|
|
|
|
if editVipWindow then
|
|
|
|
editVipWindow:destroy()
|
|
|
|
end
|
|
|
|
|
2011-11-03 13:17:10 +01:00
|
|
|
vipWindow:destroy()
|
2012-01-23 14:47:15 +01:00
|
|
|
vipButton:destroy()
|
|
|
|
end
|
|
|
|
|
2014-01-14 23:15:01 +01:00
|
|
|
function loadVipInfo()
|
|
|
|
local settings = g_settings.getNode('VipList')
|
|
|
|
if not settings then
|
|
|
|
vipInfo = {}
|
|
|
|
return
|
|
|
|
end
|
|
|
|
vipInfo = settings['VipInfo'] or {}
|
|
|
|
end
|
|
|
|
|
|
|
|
function saveVipInfo()
|
|
|
|
settings = {}
|
|
|
|
settings['VipInfo'] = vipInfo
|
|
|
|
g_settings.mergeNode('VipList', settings)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
function refresh()
|
|
|
|
clear()
|
2012-04-27 08:30:54 +02:00
|
|
|
for id,vip in pairs(g_game.getVips()) do
|
2012-07-24 07:30:08 +02:00
|
|
|
onAddVip(id, unpack(vip))
|
2012-04-27 08:30:54 +02:00
|
|
|
end
|
2012-08-21 01:56:16 +02:00
|
|
|
|
|
|
|
vipWindow:setContentMinimumHeight(38)
|
2012-04-27 08:30:54 +02:00
|
|
|
end
|
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
function clear()
|
2012-03-29 01:48:33 +02:00
|
|
|
local vipList = vipWindow:getChildById('contentsPanel')
|
|
|
|
vipList:destroyChildren()
|
|
|
|
end
|
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
function toggle()
|
2012-06-21 21:31:22 +02:00
|
|
|
if vipButton:isOn() then
|
|
|
|
vipWindow:close()
|
|
|
|
vipButton:setOn(false)
|
|
|
|
else
|
|
|
|
vipWindow:open()
|
|
|
|
vipButton:setOn(true)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
function onMiniWindowClose()
|
2012-06-21 21:31:22 +02:00
|
|
|
vipButton:setOn(false)
|
2011-09-02 06:29:00 +02:00
|
|
|
end
|
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
function createAddWindow()
|
2013-01-18 23:39:11 +01:00
|
|
|
addVipWindow = g_ui.displayUI('addvip')
|
2012-01-04 19:11:11 +01:00
|
|
|
end
|
|
|
|
|
2014-01-14 23:15:01 +01:00
|
|
|
function createEditWindow(widget)
|
|
|
|
if editVipWindow then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
editVipWindow = g_ui.displayUI('editvip')
|
|
|
|
|
|
|
|
local name = widget:getText()
|
|
|
|
local id = widget:getId():sub(4)
|
|
|
|
|
|
|
|
local okButton = editVipWindow:getChildById('buttonOK')
|
|
|
|
local cancelButton = editVipWindow:getChildById('buttonCancel')
|
|
|
|
|
|
|
|
local nameLabel = editVipWindow:getChildById('nameLabel')
|
|
|
|
nameLabel:setText(name)
|
|
|
|
|
|
|
|
local descriptionText = editVipWindow:getChildById('descriptionText')
|
|
|
|
descriptionText:appendText(widget:getTooltip())
|
|
|
|
|
|
|
|
local notifyCheckBox = editVipWindow:getChildById('checkBoxNotify')
|
|
|
|
notifyCheckBox:setChecked(widget.notifyLogin)
|
|
|
|
|
|
|
|
local iconRadioGroup = UIRadioGroup.create()
|
|
|
|
for i = VipIconFirst, VipIconLast do
|
|
|
|
iconRadioGroup:addWidget(editVipWindow:recursiveGetChildById('icon' .. i))
|
|
|
|
end
|
|
|
|
iconRadioGroup:selectWidget(editVipWindow:recursiveGetChildById('icon' .. widget.iconId))
|
|
|
|
|
|
|
|
local cancelFunction = function()
|
|
|
|
editVipWindow:destroy()
|
|
|
|
iconRadioGroup:destroy()
|
|
|
|
editVipWindow = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
local saveFunction = function()
|
|
|
|
local vipList = vipWindow:getChildById('contentsPanel')
|
|
|
|
if not widget or not vipList:hasChild(widget) then
|
|
|
|
cancelFunction()
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local name = widget:getText()
|
|
|
|
local state = widget.vipState
|
|
|
|
local description = descriptionText:getText()
|
|
|
|
local iconId = tonumber(iconRadioGroup:getSelectedWidget():getId():sub(5))
|
|
|
|
local notify = notifyCheckBox:isChecked()
|
|
|
|
|
|
|
|
if g_game.getFeature(GameAdditionalVipInfo) then
|
|
|
|
g_game.editVip(id, description, iconId, notify)
|
|
|
|
else
|
|
|
|
if notify ~= false or #description > 0 or iconId > 0 then
|
|
|
|
vipInfo[id] = {description = description, iconId = iconId, notifyLogin = notify}
|
|
|
|
else
|
|
|
|
vipInfo[id] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
widget:destroy()
|
|
|
|
onAddVip(id, name, state, description, iconId, notify)
|
|
|
|
|
|
|
|
editVipWindow:destroy()
|
|
|
|
iconRadioGroup:destroy()
|
|
|
|
editVipWindow = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
cancelButton.onClick = cancelFunction
|
|
|
|
okButton.onClick = saveFunction
|
|
|
|
|
|
|
|
editVipWindow.onEscape = cancelFunction
|
|
|
|
editVipWindow.onEnter = saveFunction
|
|
|
|
end
|
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
function destroyAddWindow()
|
2012-01-04 19:11:11 +01:00
|
|
|
addVipWindow:destroy()
|
|
|
|
addVipWindow = nil
|
|
|
|
end
|
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
function addVip()
|
2012-02-08 22:23:15 +01:00
|
|
|
g_game.addVip(addVipWindow:getChildById('name'):getText())
|
2012-07-24 07:30:08 +02:00
|
|
|
destroyAddWindow()
|
2012-01-04 19:11:11 +01:00
|
|
|
end
|
|
|
|
|
2014-01-14 23:15:01 +01:00
|
|
|
function removeVip(widgetOrName)
|
|
|
|
if not widgetOrName then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local widget
|
|
|
|
local vipList = vipWindow:getChildById('contentsPanel')
|
|
|
|
if type(widgetOrName) == 'string' then
|
|
|
|
local entries = vipList:getChildren()
|
|
|
|
for i = 1, #entries do
|
|
|
|
if entries[i]:getText():lower() == widgetOrName:lower() then
|
|
|
|
widget = entries[i]
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if not widget then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
else
|
|
|
|
widget = widgetOrName
|
|
|
|
end
|
|
|
|
|
|
|
|
if widget then
|
|
|
|
local id = widget:getId():sub(4)
|
|
|
|
g_game.removeVip(id)
|
|
|
|
vipList:removeChild(widget)
|
|
|
|
if vipInfo[id] and g_game.getFeature(GameAdditionalVipInfo) then
|
|
|
|
vipInfo[id] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-01-18 23:39:11 +01:00
|
|
|
function hideOffline(state)
|
|
|
|
settings = {}
|
|
|
|
settings['hideOffline'] = state
|
|
|
|
g_settings.mergeNode('VipList', settings)
|
|
|
|
|
|
|
|
refresh()
|
|
|
|
end
|
|
|
|
|
|
|
|
function isHiddingOffline()
|
|
|
|
local settings = g_settings.getNode('VipList')
|
|
|
|
if not settings then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
return settings['hideOffline']
|
|
|
|
end
|
|
|
|
|
2013-07-01 22:59:51 +02:00
|
|
|
function getSortedBy()
|
|
|
|
local settings = g_settings.getNode('VipList')
|
2014-01-14 23:15:01 +01:00
|
|
|
if not settings or not settings['sortedBy'] then
|
2013-07-01 22:59:51 +02:00
|
|
|
return 'status'
|
|
|
|
end
|
|
|
|
return settings['sortedBy']
|
|
|
|
end
|
|
|
|
|
|
|
|
function sortBy(state)
|
|
|
|
settings = {}
|
|
|
|
settings['sortedBy'] = state
|
|
|
|
g_settings.mergeNode('VipList', settings)
|
|
|
|
|
|
|
|
refresh()
|
|
|
|
end
|
|
|
|
|
2014-01-14 23:15:01 +01:00
|
|
|
function onAddVip(id, name, state, description, iconId, notify)
|
2012-03-28 16:10:21 +02:00
|
|
|
local vipList = vipWindow:getChildById('contentsPanel')
|
2011-11-03 10:59:11 +01:00
|
|
|
|
2012-06-26 00:13:30 +02:00
|
|
|
local label = g_ui.createWidget('VipListLabel')
|
2012-07-27 00:13:47 +02:00
|
|
|
label.onMousePress = onVipListLabelMousePress
|
2011-09-02 06:29:00 +02:00
|
|
|
label:setId('vip' .. id)
|
|
|
|
label:setText(name)
|
2011-11-03 10:59:11 +01:00
|
|
|
|
2014-01-14 23:15:01 +01:00
|
|
|
if not g_game.getFeature(GameAdditionalVipInfo) then
|
|
|
|
local tmpVipInfo = vipInfo[tostring(id)]
|
|
|
|
label.iconId = 0
|
|
|
|
label.notifyLogin = false
|
|
|
|
if tmpVipInfo then
|
|
|
|
if tmpVipInfo.iconId then
|
|
|
|
label:setImageClip(torect((tmpVipInfo.iconId * 12) .. ' 0 12 12'))
|
|
|
|
label.iconId = tmpVipInfo.iconId
|
|
|
|
end
|
|
|
|
if tmpVipInfo.description then
|
|
|
|
label:setTooltip(tmpVipInfo.description)
|
|
|
|
end
|
|
|
|
label.notifyLogin = tmpVipInfo.notifyLogin or false
|
|
|
|
end
|
|
|
|
else
|
|
|
|
label:setTooltip(description)
|
|
|
|
label:setImageClip(torect((iconId * 12) .. ' 0 12 12'))
|
|
|
|
label.iconId = iconId
|
|
|
|
label.notifyLogin = notify
|
|
|
|
end
|
|
|
|
|
2012-12-28 17:15:57 +01:00
|
|
|
if state == VipState.Online then
|
2012-01-09 19:45:28 +01:00
|
|
|
label:setColor('#00ff00')
|
2012-12-28 17:15:57 +01:00
|
|
|
elseif state == VipState.Pending then
|
|
|
|
label:setColor('#ffca38')
|
2011-09-02 06:29:00 +02:00
|
|
|
else
|
2012-01-09 19:45:28 +01:00
|
|
|
label:setColor('#ff0000')
|
2011-09-02 06:29:00 +02:00
|
|
|
end
|
2011-11-03 10:59:11 +01:00
|
|
|
|
2012-12-28 17:15:57 +01:00
|
|
|
label.vipState = state
|
2012-01-15 16:13:22 +01:00
|
|
|
|
2012-02-03 07:20:58 +01:00
|
|
|
label:setPhantom(false)
|
2012-02-08 22:23:15 +01:00
|
|
|
connect(label, { onDoubleClick = function () g_game.openPrivateChannel(label:getText()) return true end } )
|
2012-02-08 00:54:33 +01:00
|
|
|
|
2013-01-18 23:39:11 +01:00
|
|
|
if state == VipState.Offline and isHiddingOffline() then
|
|
|
|
label:setVisible(false)
|
|
|
|
end
|
|
|
|
|
2012-01-11 19:08:56 +01:00
|
|
|
local nameLower = name:lower()
|
|
|
|
local childrenCount = vipList:getChildCount()
|
2013-01-08 02:38:23 +01:00
|
|
|
|
2012-01-11 23:31:23 +01:00
|
|
|
for i=1,childrenCount do
|
2012-01-11 19:08:56 +01:00
|
|
|
local child = vipList:getChildByIndex(i)
|
2014-01-14 23:15:01 +01:00
|
|
|
if (state == VipState.Online and child.vipState ~= VipState.Online and getSortedBy() == 'status')
|
|
|
|
or (label.iconId > child.iconId and getSortedBy() == 'type') then
|
2012-01-11 19:08:56 +01:00
|
|
|
vipList:insertChild(i, label)
|
|
|
|
return
|
|
|
|
end
|
2012-01-15 16:13:22 +01:00
|
|
|
|
2014-01-14 23:15:01 +01:00
|
|
|
if (((state ~= VipState.Online and child.vipState ~= VipState.Online) or (state == VipState.Online and child.vipState == VipState.Online)) and getSortedBy() == 'status')
|
|
|
|
or (label.iconId == child.iconId and getSortedBy() == 'type') or getSortedBy() == 'name' then
|
2013-01-08 03:55:41 +01:00
|
|
|
|
2012-01-11 23:31:23 +01:00
|
|
|
local childText = child:getText():lower()
|
|
|
|
local length = math.min(childText:len(), nameLower:len())
|
2012-01-15 16:13:22 +01:00
|
|
|
|
2012-01-11 23:31:23 +01:00
|
|
|
for j=1,length do
|
|
|
|
if nameLower:byte(j) < childText:byte(j) then
|
|
|
|
vipList:insertChild(i, label)
|
|
|
|
return
|
|
|
|
elseif nameLower:byte(j) > childText:byte(j) then
|
|
|
|
break
|
2013-01-08 02:38:23 +01:00
|
|
|
elseif j == nameLower:len() then -- We are at the end of nameLower, and its shorter than childText, thus insert before
|
|
|
|
vipList:insertChild(i, label)
|
2014-01-14 23:15:01 +01:00
|
|
|
return
|
2012-01-11 23:31:23 +01:00
|
|
|
end
|
2012-01-11 19:08:56 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2012-01-15 16:13:22 +01:00
|
|
|
|
2012-01-11 19:08:56 +01:00
|
|
|
vipList:insertChild(childrenCount+1, label)
|
2011-09-02 06:29:00 +02:00
|
|
|
end
|
|
|
|
|
2012-12-28 17:15:57 +01:00
|
|
|
function onVipStateChange(id, state)
|
2012-03-29 21:25:04 +02:00
|
|
|
local vipList = vipWindow:getChildById('contentsPanel')
|
2011-09-02 06:29:00 +02:00
|
|
|
local label = vipList:getChildById('vip' .. id)
|
2014-01-14 23:15:01 +01:00
|
|
|
local name = label:getText()
|
|
|
|
local description = label:getTooltip()
|
|
|
|
local iconId = label.iconId
|
|
|
|
local notify = label.notifyLogin
|
2012-04-27 22:21:11 +02:00
|
|
|
label:destroy()
|
2012-01-15 16:13:22 +01:00
|
|
|
|
2014-01-14 23:15:01 +01:00
|
|
|
onAddVip(id, name, state, description, iconId, notify)
|
|
|
|
|
|
|
|
if notify and state ~= VipState.Pending then
|
|
|
|
modules.game_textmessage.displayFailureMessage(tr('%s has logged %s.', name, (state == VipState.Online and 'in' or 'out')))
|
|
|
|
end
|
2011-09-02 06:29:00 +02:00
|
|
|
end
|
2011-11-03 21:54:53 +01:00
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
function onVipListMousePress(widget, mousePos, mouseButton)
|
2012-01-04 19:11:11 +01:00
|
|
|
if mouseButton ~= MouseRightButton then return end
|
|
|
|
|
2012-03-29 01:48:33 +02:00
|
|
|
local vipList = vipWindow:getChildById('contentsPanel')
|
2012-01-04 19:11:11 +01:00
|
|
|
|
2012-06-26 00:13:30 +02:00
|
|
|
local menu = g_ui.createWidget('PopupMenu')
|
2012-07-24 07:30:08 +02:00
|
|
|
menu:addOption(tr('Add new VIP'), function() createAddWindow() end)
|
2013-01-18 23:39:11 +01:00
|
|
|
|
2014-01-14 23:15:01 +01:00
|
|
|
menu:addSeparator()
|
2013-01-18 23:39:11 +01:00
|
|
|
if not isHiddingOffline() then
|
|
|
|
menu:addOption(tr('Hide Offline'), function() hideOffline(true) end)
|
|
|
|
else
|
|
|
|
menu:addOption(tr('Show Offline'), function() hideOffline(false) end)
|
|
|
|
end
|
2013-07-01 22:59:51 +02:00
|
|
|
|
|
|
|
if not(getSortedBy() == 'name') then
|
|
|
|
menu:addOption(tr('Sort by name'), function() sortBy('name') end)
|
|
|
|
end
|
|
|
|
|
|
|
|
if not(getSortedBy() == 'status') then
|
|
|
|
menu:addOption(tr('Sort by status'), function() sortBy('status') end)
|
|
|
|
end
|
2013-01-18 23:39:11 +01:00
|
|
|
|
2014-01-14 23:15:01 +01:00
|
|
|
if not(getSortedBy() == 'type') then
|
|
|
|
menu:addOption(tr('Sort by type'), function() sortBy('type') end)
|
|
|
|
end
|
|
|
|
|
2012-01-04 19:11:11 +01:00
|
|
|
menu:display(mousePos)
|
2012-01-15 16:13:22 +01:00
|
|
|
|
2012-01-04 19:11:11 +01:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2012-07-24 07:30:08 +02:00
|
|
|
function onVipListLabelMousePress(widget, mousePos, mouseButton)
|
2012-01-04 15:30:28 +01:00
|
|
|
if mouseButton ~= MouseRightButton then return end
|
|
|
|
|
2012-03-29 01:48:33 +02:00
|
|
|
local vipList = vipWindow:getChildById('contentsPanel')
|
2012-01-04 15:30:28 +01:00
|
|
|
|
2012-06-26 00:13:30 +02:00
|
|
|
local menu = g_ui.createWidget('PopupMenu')
|
2013-01-17 21:24:41 +01:00
|
|
|
menu:addOption(tr('Send Message'), function() g_game.openPrivateChannel(widget:getText()) end)
|
2012-07-24 07:30:08 +02:00
|
|
|
menu:addOption(tr('Add new VIP'), function() createAddWindow() end)
|
2014-01-14 23:15:01 +01:00
|
|
|
menu:addOption(tr('Edit %s', widget:getText()), function() if widget then createEditWindow(widget) end end)
|
|
|
|
menu:addOption(tr('Remove %s', widget:getText()), function() if widget then removeVip(widget) end end)
|
2012-01-04 19:11:11 +01:00
|
|
|
menu:addSeparator()
|
2013-02-26 03:16:15 +01:00
|
|
|
menu:addOption(tr('Copy Name'), function() g_window.setClipboardText(widget:getText()) end)
|
|
|
|
|
|
|
|
if modules.game_console.getOwnPrivateTab() then
|
2013-01-18 23:39:11 +01:00
|
|
|
menu:addSeparator()
|
2013-03-01 02:01:41 +01:00
|
|
|
menu:addOption(tr('Invite to private chat'), function() g_game.inviteToOwnChannel(widget:getText()) end)
|
|
|
|
menu:addOption(tr('Exclude from private chat'), function() g_game.excludeFromOwnChannel(widget:getText()) end)
|
2013-01-18 23:39:11 +01:00
|
|
|
end
|
2013-02-26 03:16:15 +01:00
|
|
|
|
2013-01-18 23:39:11 +01:00
|
|
|
if not isHiddingOffline() then
|
|
|
|
menu:addOption(tr('Hide Offline'), function() hideOffline(true) end)
|
|
|
|
else
|
|
|
|
menu:addOption(tr('Show Offline'), function() hideOffline(false) end)
|
|
|
|
end
|
2013-07-01 22:59:51 +02:00
|
|
|
|
|
|
|
if not(getSortedBy() == 'name') then
|
|
|
|
menu:addOption(tr('Sort by name'), function() sortBy('name') end)
|
|
|
|
end
|
|
|
|
|
|
|
|
if not(getSortedBy() == 'status') then
|
|
|
|
menu:addOption(tr('Sort by status'), function() sortBy('status') end)
|
|
|
|
end
|
|
|
|
|
2012-01-04 15:30:28 +01:00
|
|
|
menu:display(mousePos)
|
2012-01-15 16:13:22 +01:00
|
|
|
|
2012-01-04 19:11:11 +01:00
|
|
|
return true
|
2012-01-04 15:30:28 +01:00
|
|
|
end
|