Перейти к содержанию

Модуль:Карточка блока: различия между версиями

Материал из LemonCraft Wiki
м 1 версия импортирована
новая система для инструментов из модификаций; добавлены "любые" инструменты для Эфира
Строка 2: Строка 2:
local p = {}
local p = {}


-- Зависимости
local modAliases = mw.loadData([[Модуль:Модификации]])
local modAliases = mw.loadData([[Модуль:Модификации]])
local blockValue = require([[Модуль:Значения блоков]]).value
local blockValue = require([[Модуль:Значения блоков]]).value
Строка 31: Строка 32:
["любой"]              = "Любой инструмент",
["любой"]              = "Любой инструмент",
-- из модификаций (старый синтаксис)
-- The Aether
-- The Aether
["небесная кирка"]      = "[[Файл:Grid Небесная кирка (The Aether).png|32px|link=The Aether/Небесная кирка]]",
["небесная кирка"]      = "[[Файл:Grid Небесная кирка (The Aether).png|32px|link=The Aether/Небесная кирка|Чтобы разрушить этот блок, нужна небесная кирка или лучше]]",
["священнокаменная кирка"]  = "[[Файл:Grid Священнокаменная кирка (The Aether).png|32px|link=The Aether/Священнокаменная кирка]]",
["священнокаменная кирка"]  = "[[Файл:Grid Священнокаменная кирка (The Aether).png|32px|link=The Aether/Священнокаменная кирка|Чтобы разрушить этот блок, нужна священнокаменная кирка или лучше]]",
["занитная кирка"]      = "[[Файл:Grid Занитная кирка (The Aether).png|32px|link=The Aether/Занитная кирка]]",
["занитная кирка"]      = "[[Файл:Grid Занитная кирка (The Aether).png|32px|link=The Aether/Занитная кирка|Чтобы разрушить этот блок, нужна занитая кирка или лучше]]",
["гравититная кирка"]  = "[[Файл:Grid Гравититная кирка (The Aether).png|32px|link=The Aether/Гравититная кирка]]",
["гравититная кирка"]  = "[[Файл:Grid Гравититная кирка (The Aether).png|32px|link=The Aether/Гравититная кирка|Чтобы разрушить этот блок, нужна гравититная кирка или лучше]]",
["небесная лопата"]    = "[[Файл:Grid Небесная лопата (The Aether).png|32px|link=The Aether/Небесная лопата]]",
["небесная лопата"]    = "[[Файл:Grid Небесная лопата (The Aether).png|32px|link=The Aether/Небесная лопата]]",
["небесный топор"]      = "[[Файл:Grid Небесный топор (The Aether).png|32px|link=The Aether/Небесный топор]]",
["небесный топор"]      = "[[Файл:Grid Небесный топор (The Aether).png|32px|link=The Aether/Небесный топор]]",
["занитный топор"]      = "[[Файл:Grid Занитный топор (The Aether).png|32px|link=The Aether/Занитный топор]]",
-- Applied Energistics 2
-- Applied Energistics 2
Строка 46: Строка 47:
["ссылка"] = "Applied Energistics 2/Сетевой инструмент"
["ссылка"] = "Applied Energistics 2/Сетевой инструмент"
},
},
-- Create
["ключ create"]    = "[[Файл:Grid Гаечный ключ (Create).png|32px|link=Create/Гаечный ключ|Гаечный ключ (Create) при использовании крадучись]]",
-- GregTech
-- GregTech
Строка 126: Строка 124:
}
}


-- Инструменты из модификаций (новый синтаксис)
local modInstruments = {
["The Aether"] = {
["кирка"] = "[[Файл:Спрайт-Aether любая-кирка.png|32px|link=The Aether/Кирки|Этот блок можно разрушить любым инструментом, но киркой из The Aether будет быстрее]]",
["лопата"] = "[[Файл:Спрайт-Aether любая-лопата.png|32px|link=The Aether/Лопаты|Этот блок можно разрушить любым инструментом, но лопатой из The Aether будет быстрее]]",
["топор"] = "[[Файл:Спрайт-Aether любой-топор.png|32px|link=The Aether/Топоры|Этот блок можно разрушить любым инструментом, но топором из The Aether будет быстрее]]",
["мотыга"] = "[[Файл:Спрайт-Aether любая-мотыга.png|32px|link=The Aether/Мотыги|Этот блок можно разрушить любым инструментом, но мотыгой из The Aether будет быстрее]]",
["занитный топор"] = "[[Файл:Grid Занитный топор (The Aether).png|32px|link=The Aether/Занитный топор|Этот блок рекомендуется добывать занитным топором или лучше]]",
},
["Create"] = {
["гаечный ключ"] = "[[Файл:Grid Гаечный ключ (Create).png|32px|link=Create/Гаечный ключ|Этот блок можно демонтировать, используя гаечный ключ из Create крадучись]]"
}
}
-- Выбор иконки инструмента
local function parseInstrument(arg, defaultMod)
local mod, name = arg:match("(.-)%s*:%s*(.+)")
if not mod then
name = mw.text.trim(arg)
mod = defaultMod
elseif mod == "" then
mod = defaultMod
elseif
mod == "v" or mod == "vanilla" or
mod == "mc" or mod == "minecraft"
then
mod = nil
else
mod = modAliases[mod] or ruLang:ucfirst(mod)
end
name = ruLang:lc(name)
local modInstrument
if mod and modInstruments[mod] then
modInstrument = modInstruments[mod][name]
end
return modInstrument or instruments[name]
end
p.parseInstrument = parseInstrument
-- TODO: Автоматически генерируемая таблица поддерживаемых инструментов
-- для документации
-- Создаёт собственно карточку
function p.blockInfobox(f)
function p.blockInfobox(f)
local args = require([[Модуль:ProcessArgs]]).merge(true)
local args = require([[Модуль:ProcessArgs]]).merge(true)
local mod = modAliases[args["мод"]] or args["мод"]
local mod = args["мод"]
if mod then
mod = modAliases[mod] or ruLang:ucfirst(mod)
end
local deprecatedParams = false
local deprecatedParams = false
local rows = {}
local rows = {}
Строка 186: Строка 231:
local toolRow = {"[[Инструменты|Инструмент]]", "?", ["класс"] = "pixel-image cancelLink"}
local toolRow = {"[[Инструменты|Инструмент]]", "?", ["класс"] = "pixel-image cancelLink"}
if args["инструмент"] then
if args["инструмент"] then
toolRow[2] = instruments[ruLang:lc(args["инструмент"])] or "?"
toolRow[2] = parseInstrument(args["инструмент"], mod) or "?"
if args["инструмент2"] then
if args["инструмент2"] then
local tools = { toolRow[2], instruments[ruLang:lc(args["инструмент2"])] or ""}
local tools = { toolRow[2], parseInstrument(args["инструмент2"], mod) or ""}
if args["инструмент3"] then
if args["инструмент3"] then
table.insert(tools, instruments[ruLang:lc(args["инструмент3"])] or "")
table.insert(tools, parseInstrument(args["инструмент3"], mod) or "")
end
end
toolRow = {"[[Инструменты]]", table.concat(tools)}
toolRow = {"[[Инструменты]]", table.concat(tools)}

Версия от 11:16, 26 марта 2025

Для документации этого модуля может быть создана страница Модуль:Карточка блока/doc

-- Реализует карточку для блока
local p = {}

-- Зависимости
local modAliases = mw.loadData([[Модуль:Модификации]])
local blockValue = require([[Модуль:Значения блоков]]).value
local sprite = require([[Модуль:Спрайт]]).sprite
local ruLang = mw.language.new("ru")

local curTitle = mw.title.getCurrentTitle()

-- Поддерживаемые инструменты
local instruments = {
	-- оригинальная игра
	["кирка"]               = "[[Файл:Use-pickaxe.png|32px|link=Кирка|Этот блок можно разрушить любым инструментом, но киркой будет быстрее]]",
	["деревянная кирка"]    = "[[Файл:ItemSprite wooden-pickaxe.png|32px|ссылка=Деревянная кирка|Чтобы разрушить этот блок, нужна деревянная кирка или лучше]]",
	["каменная кирка"]      = "[[Файл:ItemSprite stone-pickaxe.png|32px|ссылка=Каменная кирка|Чтобы разрушить этот блок, нужна каменная кирка или лучше]]",
	["железная кирка"]      = "[[Файл:ItemSprite iron-pickaxe.png|32px|ссылка=Железная кирка|Чтобы разрушить этот блок, нужна железная кирка или лучше]]",
	["алмазная кирка"]      = "[[Файл:ItemSprite diamond-pickaxe.png|32px|ссылка=Алмазная кирка|Чтобы разрушить этот блок, нужна алмазная кирка или лучше]]",
	["незеритовая кирка"]   = "[[Файл:ItemSprite netherite-pickaxe.png|32px|ссылка=Незеритовая кирка|Чтобы разрушить этот блок, нужна незеритовая кирка]]",
	["лопата"]              = "[[Файл:Use-spade.png|32px|link=Лопата|Этот блок можно разрушить любым инструментом, но лопатой будет быстрее]]",
	["деревянная лопата"]   = "[[Файл:ItemSprite wooden-shovel.png|32px|ссылка=Деревянная лопата]]",
	["алмазная лопата"]     = "[[Файл:ItemSprite diamond-shovel.png|32px|ссылка=Алмазная лопата]]",
	["топор"]               = "[[Файл:Use-axe.png|32px|link=Топор]]",
	["мотыга"]              = "[[Файл:Use-hoe.png|32px|link=Мотыга]]",
	["ведро"]               = "[[Файл:ItemSprite bucket.png|32px|ссылка=Ведро]]",
	["меч"]                 = "[[Файл:Use-sword.png|32px|link=Меч|Этот блок можно разрушить любым инструментом, но мечом будет быстрее]]",
	["ножницы"]             = "[[Файл:ItemSprite shears.png|32px|link=Ножницы|Ножницы]]",
	["кисть"]               = "[[Файл:ItemSprite brush.png|32px|link=Кисть|Кисть]]",
	["нет"]                 = "Нет",
	["все"]                 = "Любой инструмент",
	["любой"]               = "Любой инструмент",
	
	-- из модификаций (старый синтаксис)
	-- The Aether
	["небесная кирка"]      = "[[Файл:Grid Небесная кирка (The Aether).png|32px|link=The Aether/Небесная кирка|Чтобы разрушить этот блок, нужна небесная кирка или лучше]]",
	["священнокаменная кирка"]  = "[[Файл:Grid Священнокаменная кирка (The Aether).png|32px|link=The Aether/Священнокаменная кирка|Чтобы разрушить этот блок, нужна священнокаменная кирка или лучше]]",
	["занитная кирка"]      = "[[Файл:Grid Занитная кирка (The Aether).png|32px|link=The Aether/Занитная кирка|Чтобы разрушить этот блок, нужна занитая кирка или лучше]]",
	["гравититная кирка"]   = "[[Файл:Grid Гравититная кирка (The Aether).png|32px|link=The Aether/Гравититная кирка|Чтобы разрушить этот блок, нужна гравититная кирка или лучше]]",
	["небесная лопата"]     = "[[Файл:Grid Небесная лопата (The Aether).png|32px|link=The Aether/Небесная лопата]]",
	["небесный топор"]      = "[[Файл:Grid Небесный топор (The Aether).png|32px|link=The Aether/Небесный топор]]",
	
	-- Applied Energistics 2
	["сетевой инструмент"] = sprite{
		"Сетевой инструмент",
		["данные"] = "ИнвСпрайт/Applied Energistics 2",
		["ссылка"] = "Applied Energistics 2/Сетевой инструмент"
	},
	
	-- GregTech
	["гаечный ключ"]    = "[[Файл:Grid Гаечный ключ (GregTech).png|32px|link=GregTech/Ключ]]",
	["кирка 0"]         = "[[Файл:Grid Кирка 0 (GregTech).png|32px|link=GregTech/Деревянная кирка]]",
	["кирка 1"]         = "[[Файл:Grid Кирка 1 (GregTech).png|32px|link=GregTech/Кремнёвая кирка]]",
	["кирка 2"]         = "[[Файл:Grid Кирка 2 (GregTech).png|32px|link=GregTech/Железная кирка]]",
	["кирка 3"]         = "[[Файл:Grid Кирка 3 (GregTech).png|32px|link=GregTech/Алмазная кирка]]",
	["кирка 4"]         = "[[Файл:Grid Кирка 4 (GregTech).png|32px|link=GregTech/Иридиевая кирка]]",
	["кирка 5"]         = "[[Файл:Grid Кирка 5 (GregTech).png|32px|link=GregTech/Адамантиевая кирка]]",
	["бур 4"]           = "[[Файл:Grid Бур 4 (GregTech).png|32px|link=GregTech/Титановый шахтёрский бур ВН]]",
	["бур 5"]           = "[[Файл:Grid Бур 5 (GregTech).png|32px|link=GregTech/Иридиевый шахтёрский бур ВН]]",
	["бур 6"]           = "[[Файл:Grid Бур 6 (GregTech).png|32px|link=GregTech/Адамантиевый шахтёрский бур ВН]]",
	
	-- IndustrialCraft 2
	["ключ"] = sprite{
		"Гаечный ключ",
		["данные"] = "ИнвСпрайт/IndustrialCraft 2",
		["ссылка"] = "Гаечный ключ"
	},
	["капсула"] = sprite{
		"Универсальная жидкостная капсула",
		["данные"] = "ИнвСпрайт/IndustrialCraft 2",
		["ссылка"] = "Универсальная жидкостная капсула"
	},
	
	-- Immersive Engineering
	["молот инженера"] = "[[Файл:Grid Молот инженера (Immersive Engineering).png|32px|link=Immersive Engineering/Молот инженера]]",
	
	-- Mekanism
	["конфигуратор"] = sprite{
		"Конфигуратор",
		["данные"] = "ИнвСпрайт/Mekanism",
		["ссылка"] = "Mekanism/Конфигуратор",
		["выравн"] = "middle"
	},
	
	-- MineFactory Reloaded
	["точная кувалда"] = sprite{
		"Точная кувалда",
		["данные"] = "ИнвСпрайт/MineFactory Reloaded",
		["ссылка"] = "Точная кувалда",
		["выравн"] = "middle"
	},

	-- Railcraft
	["монтировка"] = "[[Файл:Grid Монтировка (Railcraft).png|32px|link=Railсraft/Монтировка]]",
	["железная монтировка"] = "[[Файл:Grid Железная монтировка (Railcraft).png|32px|link=Railcraft/Железная монтировка]]",
	
	-- Thermal Series
	["серповидный молоток"] = "[[Файл:Grid Серповидный молоток (Thermal Expansion).png|32px|link=Thermal Expansion/Серповидный молоток]]",
	["серповидный молот1"] = sprite{
		"Серповидный молот",
		["данные"] = "ИнвСпрайт/Thermal Expansion 1",
		["ссылка"] = "Thermal Expansion 1/Серповидный молот",
		["выравн"] = "middle"
	},
	["серповидный молот2"] = sprite{
		"Серповидный молот",
		["данные"] = "ИнвСпрайт/Thermal Expansion 2",
		["ссылка"] = "Thermal Expansion 2/Серповидный молот",
		["выравн"] = "middle"
	},
	["серповидный молот3"] = sprite{
		"Серповидный молот",
		["данные"] = "ИнвСпрайт/Thermal Expansion 3",
		["ссылка"] = "Thermal Expansion 3/Серповидный молот",
		["выравн"] = "middle"
	},
	["серповидный молот4"] = sprite{
		"Серповидный молот",
		["данные"] = "ИнвСпрайт/Thermal Expansion 4",
		["ссылка"] = "Thermal Expansion 4/Серповидный молот",
		["выравн"] = "middle"
	},
	["серповидный молот5"] = "[[Файл:Grid Серповидный молот (Thermal Foundation 2).png|32px|link=Thermal Foundation 2/Серповидный молоток]]",
}

-- Инструменты из модификаций (новый синтаксис)
local modInstruments = {
	["The Aether"] = {
		["кирка"] = "[[Файл:Спрайт-Aether любая-кирка.png|32px|link=The Aether/Кирки|Этот блок можно разрушить любым инструментом, но киркой из The Aether будет быстрее]]",
		["лопата"] = "[[Файл:Спрайт-Aether любая-лопата.png|32px|link=The Aether/Лопаты|Этот блок можно разрушить любым инструментом, но лопатой из The Aether будет быстрее]]",
		["топор"] = "[[Файл:Спрайт-Aether любой-топор.png|32px|link=The Aether/Топоры|Этот блок можно разрушить любым инструментом, но топором из The Aether будет быстрее]]",
		["мотыга"] = "[[Файл:Спрайт-Aether любая-мотыга.png|32px|link=The Aether/Мотыги|Этот блок можно разрушить любым инструментом, но мотыгой из The Aether будет быстрее]]",
		["занитный топор"] = "[[Файл:Grid Занитный топор (The Aether).png|32px|link=The Aether/Занитный топор|Этот блок рекомендуется добывать занитным топором или лучше]]",
	},
	["Create"] = {
		["гаечный ключ"] = "[[Файл:Grid Гаечный ключ (Create).png|32px|link=Create/Гаечный ключ|Этот блок можно демонтировать, используя гаечный ключ из Create крадучись]]"
	}
}

-- Выбор иконки инструмента
local function parseInstrument(arg, defaultMod)
	local mod, name = arg:match("(.-)%s*:%s*(.+)")
	if not mod then
		name = mw.text.trim(arg)
		mod = defaultMod
	elseif mod == "" then
		mod = defaultMod
	elseif
		mod == "v" or mod == "vanilla" or
		mod == "mc" or mod == "minecraft"
	then
		mod = nil
	else
		mod = modAliases[mod] or ruLang:ucfirst(mod)
	end
	
	name = ruLang:lc(name)
	
	local modInstrument
	if mod and modInstruments[mod] then
		modInstrument = modInstruments[mod][name]
	end
	return modInstrument or instruments[name]
end
p.parseInstrument = parseInstrument
-- TODO: Автоматически генерируемая таблица поддерживаемых инструментов
-- для документации

-- Создаёт собственно карточку
function p.blockInfobox(f)
	local args = require([[Модуль:ProcessArgs]]).merge(true)
	local mod = args["мод"]
	if mod then 
		mod = modAliases[mod] or ruLang:ucfirst(mod)
	end
	local deprecatedParams = false
	local rows = {}
	local categories = {}
	
	if args["тип"] then
		table.insert(rows, {"Тип", args["тип"]})
	end
	
	if args["редкость"] then
		table.insert(rows, {"[[Редкость]]", args["редкость"]})
	end
	
	if args["хранилище"] then
		table.insert(rows, {"Внутреннее хранилище", args["хранилище"]})
		--deprecatedParams = true
	end
	
	if args["альт"] then
		table.insert(rows, {"[[Высота]]", args["альт"]})
		--deprecatedParams = true
	end
	
	if args["гравит"] then
		table.insert(rows, {"[[Падающий блок|Падает]]?", args["гравит"]})
	end
	if mod == "The Aether" and args["антигравит"] then
		table.insert(rows, {"[[The Aether/Поднимащийся блок|Поднимается]]?", args["антигравит"]})
	end
	
	table.insert(rows, {"[[Прозрачность]]", args["прозр"] or "?"})
	table.insert(rows, {"[[Свет]]имость", args["свет"] or "?"})
	
	-- Взрывоустойчивость
	local blastResistance = args["взрывоуст"]
	if not blastResistance then
		if not mod then
			blastResistance = blockValue{args["взрывоустимя"] or curTitle.baseText, ["тип"] = "взрывоустойчивости", ["некат"] = args["некат"]}
		elseif not args["некат"] then
			table.insert(categories, "[[Категория:Отсутствующие значения взрывоустойчивости]]")
		end
	end
	table.insert(rows, {"[[Взрывоустойчивость]]", blastResistance or "?"})
	
	-- Прочность
	local hardness = args["прочн"]
	if not hardness then
		if not mod then
			hardness = blockValue{curTitle.text, ["тип"] = "прочности", ["некат"] = args["некат"]}
		elseif not args["некат"] then
			table.insert(categories, "[[Категория:Отсутствующие значения прочности]]")
		end
	end
	table.insert(rows, {"[[Добывание#Прочность блоков|Прочность]]", hardness or "?"})
	
	-- инструменты
	local toolRow = {"[[Инструменты|Инструмент]]", "?", ["класс"] = "pixel-image cancelLink"}
	if args["инструмент"] then
		toolRow[2] = parseInstrument(args["инструмент"], mod) or "?"
		if args["инструмент2"] then
			local tools = { toolRow[2], parseInstrument(args["инструмент2"], mod) or ""}
			if args["инструмент3"] then
				table.insert(tools, parseInstrument(args["инструмент3"], mod) or "")
			end
			toolRow = {"[[Инструменты]]", table.concat(tools)}
		end
	end
	table.insert(rows, toolRow)
	
	-- Дроп
	if args["дроп"] then
		table.insert(rows, {"[[Дроп]]", args["дроп"], ["класс"] = "list-style-none"})
		--deprecatedParams = true
	end
	if args["опыт"] then
		table.insert(rows, {"[[Опыт]]", args["опыт"]})
		--deprecatedParams = true
	end
	
	-- Возобновляемость
	local renewable = ruLang:ucfirst(args["возобн"] or "?")
	table.insert(rows, {"[[Возобновляемые ресурсы|Возобновляемый]]", renewable})
	if not args["некат"] then
		local category = "[[Категория:Ресурсы с неизвестной возобновляемостью]]"
		if renewable == "Да" then
			category = "[[Категория:Возобновляемые блоки]]"
		elseif renewable == "Нет" then
			category = "[[Категория:Невозобновляемые ресурсы]]"
		end
		table.insert(categories, category)
	end
	
	-- Складываемость
	local stackable = ruLang:ucfirst(args["склад"] or "?")
	table.insert(rows, {"Складываемый", stackable})
	if not args["некат"] then
		local category = "[[Категория:Ресурсы с неизвестной складываемостью]]"
		if mw.ustring.match(stackable, "Да") then
			category = "[[Категория:Складываемые ресурсы]]"
		elseif stackable == "Нет" then
			category = "[[Категория:Нескладываемые ресурсы]]"
		end
		table.insert(categories, category)
	end
	
	-- Свойства жидкости
	if args["тип"] and mw.ustring.match(args["тип"], "[Жж]идкость") then
		table.insert(rows, {"Скорость течения", args["жидскорость"] or "?"})
		table.insert(rows, {"Скорость движения<br>сквозь", args["движскорость"] or "?"})
	elseif args["затопл"] then
		table.insert(rows, {"[[Затопляемость|Затопляемый]]", args["затопл"]})
	end
	
	-- Огнеопасность
	table.insert(rows, {"[[Огонь|Воспламеняемый]]", args["восплам"] or "?"})
	if args["сгорвлаве"] or args["загоротлавы"] then
		table.insert(rows, {"Загорается от [[Лава|лавы]]?", args["сгорвлаве"] or args["загоротлавы"]})
	end
	
	-- Первое появление
	if args["перввер"] then
		--local versionRow = {"[[#История|Первое появление]]", args["перввер"]}
		local versionRow = {"[[История версий (значения)|Первое появление]]", args["перввер"]}
		if mod then
			versionRow[1] = "[[" .. mod .. "/История версий|Первое появление]]"
		end
		table.insert(rows, versionRow)
	end
	
	if args["доступность"] then
		table.insert(rows, {"Доступность", args["доступность"]})
		--deprecatedParams = true
	end
	
	-- Значения данных
	if args["номер"] then
		table.insert(rows, {
			mod and ("[[" .. mod .. "/Значения данных|Номер]]") or "[[Значения данных|Номер]]",
			f:expandTemplate{title = "Значение данных", args = { args["номер"] }}
		})
		--deprecatedParams = true
	end
	if args["многоданных"] then
		table.insert(rows, {
			mod and ("[[" .. mod .. "/Значения данных|Значения данных]]") or "[[Значения данных]]",
			args["многоданных"]
		})
		--deprecatedParams = true
	end
	if args["текст_id"] then
		table.insert(rows, {
			"Текстовый идентификатор",
			args["текст_id_моношрифт_нет"] and args["текст_id"] or ("<code>" .. args["текст_id"] .. "</code>")
		})
		--deprecatedParams = true
	end
	
	-- Теги
	if args["теги"] then
		table.insert(rows, {
			mod and ("[[" .. mod .. "/Теги|Теги]]") or "[[Тег]]и",
			mw.ustring.gsub(args["теги"], "#", "&#x23;")
		})
		--deprecatedParams = true
	end
	
	-- Звуки
	if args["звуки"] then
		table.insert(rows, {"Звуки", args["звуки"]})
		deprecatedParams = true
	end
	
	-- Если используются устаревшие параметры...
	if deprecatedParams then
		table.insert(categories, "[[Категория:Страницы с вызовом устаревших параметров]]")
	end
	
	args["ряды"] = rows
	return require([[Модуль:Карточка]]).infobox(args), table.concat(categories)
end

return p