mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-08-12 16:35:11 +09:00
Remove asserts the types already cover
The nil check burn down added guards which turned out redundant once the surrounding annotations landed. `_has_handlers` is set to true when the first handler registers, so it is a boolean rather than the literal false it was inferred as. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -170,7 +170,8 @@ Commands.server = setmetatable({
|
||||
--- @param msg LocalisedString? An optional message to be included when a command completes (only has an effect in command callbacks)
|
||||
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
|
||||
function Commands.status.success(msg)
|
||||
return Commands.status.success, msg == nil and { "exp-commands.success" } or msg
|
||||
if msg == nil then return Commands.status.success, { "exp-commands.success" } end
|
||||
return Commands.status.success, msg
|
||||
end
|
||||
|
||||
--- Used to signal an error has occurred in a command, data type parser, or permission authority
|
||||
@@ -178,7 +179,8 @@ end
|
||||
--- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided
|
||||
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
|
||||
function Commands.status.error(msg)
|
||||
return Commands.status.error, { "exp-commands.error", msg == nil and { "exp-commands.error-default" } or msg }
|
||||
if msg == nil then msg = { "exp-commands.error-default" } end
|
||||
return Commands.status.error, { "exp-commands.error", msg }
|
||||
end
|
||||
|
||||
--- Used to signal the player is unauthorised to use a command, primarily used by permission authorities but can be used in a command callback
|
||||
@@ -186,7 +188,8 @@ end
|
||||
--- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided
|
||||
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
|
||||
function Commands.status.unauthorised(msg)
|
||||
return Commands.status.unauthorised, { "exp-commands.unauthorized", msg == nil and { "exp-commands.unauthorized-default" } or msg }
|
||||
if msg == nil then msg = { "exp-commands.unauthorized-default" } end
|
||||
return Commands.status.unauthorised, { "exp-commands.unauthorized", msg }
|
||||
end
|
||||
|
||||
--- Used to signal the player provided invalid input to an command, primarily used by data type parsers but can be used in a command callback
|
||||
@@ -194,15 +197,16 @@ end
|
||||
--- @param msg LocalisedString? An optional error message to be included in the output, a generic message is used if not provided
|
||||
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
|
||||
function Commands.status.invalid_input(msg)
|
||||
return Commands.status.invalid_input, msg == nil and { "exp-commands.invalid-input" } or msg
|
||||
if msg == nil then return Commands.status.invalid_input, { "exp-commands.invalid-input" } end
|
||||
return Commands.status.invalid_input, msg
|
||||
end
|
||||
|
||||
--- Used to signal an internal error has occurred, this is reserved for internal use only
|
||||
--- @param msg LocalisedString A message detailing the error which has occurred, will be logged and outputted
|
||||
--- @param msg LocalisedString? A message detailing the error which has occurred, will be logged and outputted
|
||||
--- @return Commands.Status, LocalisedString # Should be returned directly without modification
|
||||
--- @package
|
||||
function Commands.status.internal_error(msg)
|
||||
return Commands.status.internal_error, { "exp-commands.internal-error", msg }
|
||||
return Commands.status.internal_error, { "exp-commands.internal-error", msg or "" }
|
||||
end
|
||||
|
||||
--- @type table<Commands.Status, string>
|
||||
|
||||
@@ -116,7 +116,8 @@ end
|
||||
--- @param player LuaPlayer
|
||||
--- @return LuaGuiElement
|
||||
function Gui.get_top_element(define, player)
|
||||
return (assert(assert(player_elements[player.index]).top[define.name], "Element is not on the top flow"))
|
||||
local value = assert(assert(player_elements[player.index]).top[define.name], "Element is not on the top flow")
|
||||
return value
|
||||
end
|
||||
|
||||
--- Register a element define to be drawn to the left flow on join
|
||||
@@ -124,7 +125,8 @@ end
|
||||
--- @param player LuaPlayer
|
||||
--- @return LuaGuiElement
|
||||
function Gui.get_left_element(define, player)
|
||||
return (assert(assert(player_elements[player.index]).left[define.name], "Element is not on the left flow"))
|
||||
local value = assert(assert(player_elements[player.index]).left[define.name], "Element is not on the left flow")
|
||||
return value
|
||||
end
|
||||
|
||||
--- Register a element define to be drawn to the relative flow on join
|
||||
@@ -132,7 +134,8 @@ end
|
||||
--- @param player LuaPlayer
|
||||
--- @return LuaGuiElement
|
||||
function Gui.get_relative_element(define, player)
|
||||
return (assert(assert(player_elements[player.index]).relative[define.name], "Element is not on the relative flow"))
|
||||
local value = assert(assert(player_elements[player.index]).relative[define.name], "Element is not on the relative flow")
|
||||
return value
|
||||
end
|
||||
|
||||
--- Ensure all the correct elements are visible and exist
|
||||
|
||||
@@ -165,7 +165,7 @@ Elements.container = Gui.define("container")
|
||||
--- @param container LuaGuiElement
|
||||
--- @return LuaGuiElement
|
||||
function Elements.container.get_root_element(container)
|
||||
return container.parent
|
||||
return assert(container.parent)
|
||||
end
|
||||
|
||||
--- A frame within a container
|
||||
@@ -319,14 +319,15 @@ Elements.screen_frame = Gui.define("screen_frame")
|
||||
--- @param screen_frame LuaGuiElement
|
||||
--- @return LuaGuiElement
|
||||
function Elements.screen_frame.get_button_flow(screen_frame)
|
||||
return (assert(Elements.screen_frame.data[screen_frame.parent], "Screen frame has no button flow"))
|
||||
local value = assert(Elements.screen_frame.data[assert(screen_frame.parent)], "Screen frame has no button flow")
|
||||
return value
|
||||
end
|
||||
|
||||
--- Get the root element of a screen frame
|
||||
--- @param screen_frame LuaGuiElement
|
||||
--- @return LuaGuiElement
|
||||
function Elements.screen_frame.get_root_element(screen_frame)
|
||||
return screen_frame.parent
|
||||
return assert(screen_frame.parent)
|
||||
end
|
||||
|
||||
return Elements
|
||||
|
||||
@@ -43,6 +43,8 @@ ExpElement.events = {}
|
||||
--- @field _force_data ExpElement.PostDrawCallback?
|
||||
--- @field _global_data ExpElement.PostDrawCallback?
|
||||
--- @field _events table<defines.events, ExpElement.EventHandler<EventData>[]>
|
||||
--- @field _has_handlers boolean
|
||||
--- @field _track_elements boolean
|
||||
--- @overload fun(parent: LuaGuiElement, ...: any): LuaGuiElement
|
||||
ExpElement._prototype = {
|
||||
_track_elements = false,
|
||||
@@ -166,7 +168,8 @@ end
|
||||
--- @param name string
|
||||
--- @return ExpElement
|
||||
function ExpElement.get(name)
|
||||
return (assert(ExpElement._elements[name], "ExpElement is not defined: " .. tostring(name)))
|
||||
local value = assert(ExpElement._elements[name], "ExpElement is not defined: " .. tostring(name))
|
||||
return value
|
||||
end
|
||||
|
||||
--- Create a new instance of this element definition
|
||||
|
||||
@@ -50,7 +50,8 @@ local servers = External.get_servers()
|
||||
]]
|
||||
function External.get_servers()
|
||||
assert(ext, "No external data was found, use External.valid() to ensure external data exists.")
|
||||
return (assert(ext.servers, "No server list was found, please ensure that the external service is running"))
|
||||
local value = assert(ext.servers, "No server list was found, please ensure that the external service is running")
|
||||
return value
|
||||
end
|
||||
|
||||
--[[-- Gets a table of all the servers filtered by name, key is the server id, value is the server details
|
||||
@@ -85,7 +86,8 @@ function External.get_current_server()
|
||||
assert(ext, "No external data was found, use External.valid() to ensure external data exists.")
|
||||
local servers = assert(ext.servers, "No server list was found, please ensure that the external service is running")
|
||||
local server_id = assert(ext.current, "No current id was found, please ensure that the external service is running")
|
||||
return (assert(servers[server_id], "No details found for server with id: " .. tostring(server_id)))
|
||||
local value = assert(servers[server_id], "No details found for server with id: " .. tostring(server_id))
|
||||
return value
|
||||
end
|
||||
|
||||
--[[-- Gets the details of the given server
|
||||
@@ -99,7 +101,8 @@ local server = External.get_server_details('eu-01')
|
||||
function External.get_server_details(server_id)
|
||||
assert(ext, "No external data was found, use External.valid() to ensure external data exists.")
|
||||
local servers = assert(ext.servers, "No server list was found, please ensure that the external service is running")
|
||||
return (assert(servers[server_id], "No details found for server with id: " .. tostring(server_id)))
|
||||
local value = assert(servers[server_id], "No details found for server with id: " .. tostring(server_id))
|
||||
return value
|
||||
end
|
||||
|
||||
--[[-- Gets the status of the given server
|
||||
|
||||
@@ -216,7 +216,7 @@ game.player.print(Roles.debug())
|
||||
function Roles.debug()
|
||||
local output = ""
|
||||
for index, role_name in ipairs(Roles.config.order) do
|
||||
local role = assert(Roles.config.roles[role_name])
|
||||
local role = Roles.config.roles[role_name]
|
||||
local color = (role.custom_color or Colours.white) --[[@as Color.struct]]
|
||||
local color_str = string.format("[color=%d, %d, %d]", color.r, color.g, color.b)
|
||||
output = output .. string.format("\n%s %s) %s[/color]", color_str, index, serpent.line(role))
|
||||
@@ -369,14 +369,15 @@ local role = Roles.get_player_highest_role(game.player)
|
||||
--- @return Roles.Role
|
||||
function Roles.get_player_highest_role(player)
|
||||
local roles = Roles.get_player_roles(player)
|
||||
local highest
|
||||
local highest --- @type Roles.Role?
|
||||
for _, role in ipairs(roles) do
|
||||
if not highest or role.index < highest.index then
|
||||
highest = role
|
||||
end
|
||||
end
|
||||
|
||||
return (assert(highest, "Player has no roles"))
|
||||
local value = assert(highest, "Player has no roles")
|
||||
return value
|
||||
end
|
||||
|
||||
--- Assignment.
|
||||
@@ -415,7 +416,7 @@ function Roles.assign_player(player, roles, by_player_name, skip_checks, silent)
|
||||
|
||||
-- If the player has a role that needs to defer the role changes, save the roles that need to be assigned later into a table
|
||||
if valid_player and Roles.player_has_flag(valid_player, "defer_role_changes") then
|
||||
local assign_later = Roles.config.deferred_roles[assert(valid_player).name] or {}
|
||||
local assign_later = Roles.config.deferred_roles[valid_player.name] or {}
|
||||
for _, role in ipairs(role_objects) do
|
||||
local role_change = assign_later[role.name]
|
||||
if role_change then
|
||||
@@ -431,7 +432,7 @@ function Roles.assign_player(player, roles, by_player_name, skip_checks, silent)
|
||||
end
|
||||
end
|
||||
|
||||
Roles.config.deferred_roles[assert(valid_player).name] = assign_later
|
||||
Roles.config.deferred_roles[valid_player.name] = assign_later
|
||||
return
|
||||
end
|
||||
|
||||
@@ -477,8 +478,8 @@ function Roles.unassign_player(player, roles, by_player_name, skip_checks, silen
|
||||
|
||||
-- If the player has a role that needs to defer the role changes, save the roles that need to be unassigned later into a table
|
||||
local defer_changes = Roles.player_has_flag(player, "defer_role_changes")
|
||||
if defer_changes then
|
||||
local assign_later = Roles.config.deferred_roles[assert(valid_player).name] or {}
|
||||
if defer_changes and valid_player then
|
||||
local assign_later = Roles.config.deferred_roles[valid_player.name] or {}
|
||||
for _, role in ipairs(role_objects) do
|
||||
local role_change = assign_later[role.name]
|
||||
if role_change then
|
||||
@@ -494,7 +495,7 @@ function Roles.unassign_player(player, roles, by_player_name, skip_checks, silen
|
||||
end
|
||||
end
|
||||
|
||||
Roles.config.deferred_roles[assert(valid_player).name] = assign_later
|
||||
Roles.config.deferred_roles[valid_player.name] = assign_later
|
||||
end
|
||||
|
||||
-- Remove the player from roles
|
||||
@@ -674,7 +675,7 @@ function Roles.define_role_order(order)
|
||||
|
||||
-- Re-links roles to they parents as this is called at the end of the config
|
||||
for index, role_name in pairs(Roles.config.order) do
|
||||
local role = assert(Roles.config.roles[role_name])
|
||||
local role = Roles.config.roles[role_name]
|
||||
if not role then
|
||||
error("Role with name " .. role_name .. " has not beed defined, either define it or remove it from the order list.", 2)
|
||||
end
|
||||
|
||||
@@ -291,7 +291,7 @@ function vlayer.remove_item(item_name, count)
|
||||
|
||||
if not config.unlimited_surface_area and item_properties.required_area and item_properties.required_area > 0 then
|
||||
-- Remove from the unallocated storage first
|
||||
remove_unallocated = math.min(count, assert(vlayer_data.storage.unallocated[item_name]))
|
||||
remove_unallocated = math.min(count, vlayer_data.storage.unallocated[item_name])
|
||||
|
||||
if remove_unallocated > 0 then
|
||||
vlayer_data.storage.items[item_name] = vlayer_data.storage.items[item_name] - count
|
||||
|
||||
@@ -381,14 +381,13 @@ local vlayer_gui_control_see = Gui.define("vlayer_gui_control_see")
|
||||
}:style{
|
||||
width = 200,
|
||||
}:on_click(function(def, player, element, event)
|
||||
local target = assert(assert(element.parent)[vlayer_gui_control_type.name]).selected_index
|
||||
local n = assert(assert(element.parent)[vlayer_gui_control_list.name]).selected_index
|
||||
local target = assert(element.parent)[vlayer_gui_control_type.name].selected_index
|
||||
local n = assert(element.parent)[vlayer_gui_control_list.name].selected_index
|
||||
|
||||
if target and vlayer_control_type_list[target] and n > 0 then
|
||||
local i = vlayer.get_interfaces()
|
||||
local entity = i[vlayer_control_type_list[target]][n]
|
||||
if entity and entity.valid then
|
||||
local player = Gui.get_player(event)
|
||||
player.set_controller{ type = defines.controllers.remote, position = entity.position, surface = entity.surface }
|
||||
player.print{ "vlayer.result-interface-location", { "vlayer.control-type-" .. vlayer_control_type_list[target]:gsub("_", "-") }, pos_to_gps_string(entity.position, entity.surface.name) }
|
||||
end
|
||||
@@ -425,8 +424,8 @@ local vlayer_gui_control_remove = Gui.define("vlayer_gui_control_remove")
|
||||
}:style{
|
||||
width = 200,
|
||||
}:on_click(function(def, player, element)
|
||||
local target = assert(assert(element.parent)[vlayer_gui_control_type.name]).selected_index
|
||||
local n = assert(assert(element.parent)[vlayer_gui_control_list.name]).selected_index
|
||||
local target = assert(element.parent)[vlayer_gui_control_type.name].selected_index
|
||||
local n = assert(element.parent)[vlayer_gui_control_list.name].selected_index
|
||||
|
||||
if target and vlayer_control_type_list[target] and n > 0 then
|
||||
local i = vlayer.get_interfaces()
|
||||
|
||||
@@ -294,10 +294,10 @@ local confirm_edit_button = Gui.define("confirm_edit_button")
|
||||
local parent = assert(element.parent)
|
||||
local grandparent = assert(parent.parent)
|
||||
local warp_id = parent.caption --[[@as string]]
|
||||
local name_flow = assert(grandparent["name-" .. warp_id])
|
||||
local icon_flow = assert(grandparent["icon-" .. warp_id])
|
||||
local warp_name = assert(name_flow[warp_textfield.name]).text
|
||||
local warp_icon = assert(icon_flow[warp_icon_editing.name]).elem_value --[[@as SignalID]]
|
||||
local name_flow = grandparent["name-" .. warp_id]
|
||||
local icon_flow = grandparent["icon-" .. warp_id]
|
||||
local warp_name = name_flow[warp_textfield.name].text
|
||||
local warp_icon = icon_flow[warp_icon_editing.name].elem_value --[[@as SignalID]]
|
||||
if warp_icon.type == nil then warp_icon.type = "item" end
|
||||
Warps.set_editing(warp_id, player.name)
|
||||
Warps.update_warp(warp_id, warp_name, warp_icon, player.name)
|
||||
|
||||
@@ -41,7 +41,7 @@ local function get_server_id(server)
|
||||
elseif status == "Offline" then
|
||||
return false, { "exp-commands_connect.offline", server_details.name }
|
||||
end
|
||||
return true, server_id
|
||||
return true, server_id --[[@as string]]
|
||||
elseif server_count_before > 0 then
|
||||
return false, { "exp-commands_connect.wrong-version", concat(server_names_before, ", ") }
|
||||
else
|
||||
|
||||
@@ -43,11 +43,11 @@ Commands.new("create-report", { "exp-commands_reports.description-create" })
|
||||
if Reports.report_player(other_player, player.name, reason) then
|
||||
local user_message = { "exp-commands_reports.response", other_player_name, reason }
|
||||
local admin_message = { "exp-commands_reports.response-admin", other_player_name, player_name, reason }
|
||||
for _, player in ipairs(game.connected_players) do
|
||||
if player.admin then
|
||||
player.print(admin_message)
|
||||
for _, connected_player in ipairs(game.connected_players) do
|
||||
if connected_player.admin then
|
||||
connected_player.print(admin_message)
|
||||
else
|
||||
player.print(user_message)
|
||||
connected_player.print(user_message)
|
||||
end
|
||||
end
|
||||
else
|
||||
|
||||
@@ -91,7 +91,7 @@ local function sort_results(results, func)
|
||||
end
|
||||
end
|
||||
|
||||
return sorted
|
||||
return sorted --[[@as SearchResult[] ]]
|
||||
end
|
||||
|
||||
local display_players_time_format = ExpUtil.format_time_factory_locale{ format = "short", hours = true, minutes = true }
|
||||
|
||||
@@ -32,7 +32,7 @@ end
|
||||
|
||||
--- Get the player name from an event
|
||||
--- @param event { player_index: uint, by_player_name: string? }
|
||||
--- @return string, string
|
||||
--- @return string, string?
|
||||
local function get_player_name(event)
|
||||
local player = game.players[event.player_index]
|
||||
return player.name, event.by_player_name
|
||||
|
||||
@@ -102,11 +102,11 @@ Elements.reason_confirm = Gui.define("player_list/reason_confirm")
|
||||
local action_name = Elements.container.get_selected_action(player)
|
||||
local button_data = action_name and config.buttons[action_name]
|
||||
if button_data and button_data.reason_callback then
|
||||
local reason = assert(assert(element.parent).entry).text --[[@as string?]]
|
||||
local reason = assert(element.parent).entry.text --[[@as string?]]
|
||||
if reason == nil or not reason:find("%S") then reason = "no reason given" end
|
||||
button_data.reason_callback(player, reason)
|
||||
end
|
||||
assert(assert(element.parent).entry).text = ""
|
||||
assert(element.parent).entry.text = ""
|
||||
Elements.container.set_selected_player(player, nil)
|
||||
Elements.player_table.refresh_player(player)
|
||||
end) --[[@as any]]
|
||||
|
||||
@@ -43,7 +43,7 @@ local function new_quick_action(command, on_click)
|
||||
:style{
|
||||
width = 160,
|
||||
}
|
||||
:on_click(on_click or function(def, player, element, event)
|
||||
:on_click(on_click or function(_def, player, _element, _event)
|
||||
command(player)
|
||||
end)
|
||||
|
||||
|
||||
@@ -270,10 +270,9 @@ Elements.container = Gui.define("research_milestones/container")
|
||||
local milestone_table = Elements.milestone_table(container)
|
||||
Elements.clock_label(header)
|
||||
|
||||
local force = Gui.get_player(parent).force
|
||||
local force = Gui.get_player(parent).force --[[@as LuaForce]]
|
||||
def.data[force] = def.data[force] or {} -- used by start index and row data
|
||||
|
||||
local force = Gui.get_player(parent).force --[[@as LuaForce]]
|
||||
local start_index = Elements.container.calculate_starting_research_index(force)
|
||||
for research_index = start_index, start_index + display_size - 1 do
|
||||
local row_data = Elements.milestone_table.calculate_row_data(force, research_index)
|
||||
@@ -297,7 +296,7 @@ end
|
||||
--- @param research_index number
|
||||
--- @return number
|
||||
function Elements.container.get_achieved_time(force, research_index)
|
||||
return Elements.container.data[force][research_index]
|
||||
return assert(Elements.container.data[force][research_index])
|
||||
end
|
||||
|
||||
--- Calculate the starting research index for a force
|
||||
|
||||
@@ -109,7 +109,7 @@ function Elements.production_label.calculate_display_data(tooltip, value, cutoff
|
||||
end
|
||||
|
||||
local suffix, caption = format_number(value)
|
||||
display_data = display_data or {}
|
||||
display_data = display_data or {} --[[@as Elements.production_label.display_data]]
|
||||
display_data.caption = caption
|
||||
display_data.suffix = suffix
|
||||
display_data.tooltip = tooltip
|
||||
@@ -221,7 +221,7 @@ function Elements.science_table.calculate_row_data(force, science_pack, row_data
|
||||
end
|
||||
|
||||
-- Return the pack data
|
||||
row_data = row_data or {}
|
||||
row_data = row_data or {} --[[@as ExpGui_ScienceProduction.elements.science_table.row_data]]
|
||||
row_data.visible = production.total.made > 0
|
||||
row_data.science_pack = science_pack
|
||||
row_data.icon_style = icon_style
|
||||
|
||||
@@ -612,7 +612,7 @@ function Elements.confirm_task_button.parse(message)
|
||||
-- Trim the spaces of the string
|
||||
local trimmed = string.gsub(message, "^%s*(.-)%s*$", "%1")
|
||||
local title, body = string.match(trimmed, "(.-)\n(.*)")
|
||||
local parsed = { title = title, body = body }
|
||||
local parsed = { title = title, body = body } --[[@as { title: string, body: string }]]
|
||||
if not title then
|
||||
-- If it doesn't match the pattern return the str as a title
|
||||
parsed.title = trimmed
|
||||
|
||||
@@ -284,7 +284,7 @@ function ExpUtil.format_any(value, options)
|
||||
end
|
||||
return inspect(value, { depth = options.depth or 5, indent = "", newline = "", process = ExpUtil.safe_value })
|
||||
end
|
||||
return formatted
|
||||
return formatted --[[@as LocalisedString]]
|
||||
end
|
||||
|
||||
--- @alias Common.format_time_param_format "short" | "long" | "clock"
|
||||
@@ -522,7 +522,7 @@ end
|
||||
|
||||
--- Insert a copy of the given items into the found entities. If no entities are found then they will be created if possible.
|
||||
--- @param options Common.copy_items_to_surface_param
|
||||
--- @return LuaEntity # The last entity inserted into
|
||||
--- @return LuaEntity? # The last entity inserted into, nil if there were no items
|
||||
function ExpUtil.copy_items_to_surface(options)
|
||||
local entity
|
||||
for item_index = 1, #options.items do
|
||||
@@ -542,7 +542,7 @@ end
|
||||
|
||||
--- Insert a copy of the given items into the found entities. If no entities are found then they will be created if possible.
|
||||
--- @param options Common.move_items_to_surface_param
|
||||
--- @return LuaEntity # The last entity inserted into
|
||||
--- @return LuaEntity? # The last entity inserted into, nil if there were no items
|
||||
function ExpUtil.move_items_to_surface(options)
|
||||
local entity
|
||||
for item_index = 1, #options.items do
|
||||
@@ -564,7 +564,7 @@ end
|
||||
|
||||
--- Move the given inventory into the found entities. If no entities are found then they will be created if possible.
|
||||
--- @param options Common.transfer_inventory_to_surface_param
|
||||
--- @return LuaEntity # The last entity inserted into
|
||||
--- @return LuaEntity? # The last entity inserted into, nil if there were no items
|
||||
function ExpUtil.transfer_inventory_to_surface(options)
|
||||
options.items = options.inventory
|
||||
local entity = ExpUtil.copy_items_to_surface(options)
|
||||
|
||||
Reference in New Issue
Block a user