Modul:UKB
Hopp til navigering
Hopp til søk
Dokumentasjon for denne modulen kan opprettes på Modul:UKB/dok
require('strict')
local p = {}
local TNT = require('Module:TNT')
local I18NDATASET = 'I18n/UKB.tab'
local getArgs = require('Module:Arguments').getArgs
--- Get a localized message.
-- @param key The message key
-- @param ... Parameters to be passed to the message ($1, $2, etc.)
-- @return localized string
local function msg( key, ... )
return TNT.format( I18NDATASET, key, ... )
end
--- Reverse a mapping to get a list of localized names => canonical names
-- @param mapping A table containing key-value pairs where the key is the canonical name and the value is an array table of aliases
-- @return A table of localized names => canonical names
local function mappingReverser(mapping)
local ret = {}
for canonical, synonyms in pairs(mapping) do
for _, synonym in ipairs(synonyms) do
ret[synonym] = canonical
end
local keyIsPresent, translations = pcall(msg, 'arg-' .. canonical)
if keyIsPresent then
translations = mw.text.split(translations, '|')
for _, translation in ipairs(translations) do
ret[translation] = canonical
end
end
end
return ret
end
--- Get the argument mapping for a type of item
-- @param itemType The mapping subtype to get. Either 'criteria' or 'rules'
-- @param returnType Which mapping to get; 'canonical' or 'translated'
-- @return A table of mappings
local function getArgumentMapping(itemType, returnType)
-- if a new argument is added, it should also be added to the i18n module
-- in [[c:Data:I18n/UKB.tab]]
local argumentMapping = {
['criteria'] = {
['backlinks'] = { 'backlink' },
['bytes'] = { 'byte' },
['categories'] = { 'category' },
['forwardlinks'] = { 'forwardlink' },
['new'] = {},
['existing'] = {},
['namespaces'] = { 'namespace' },
['pages'] = { 'page' },
['sparql'] = {},
['stub'] = {}, -- deprecated, not in i18n
['templates'] = { 'template' }
},
['rules'] = {
['bytes'] = { 'byte' },
['bytebonus'] = {},
['categoryremoval'] = {},
['edit'] = {},
['eligiblepage'] = {},
['extlink'] = { 'exlink', 'externallink' },
['image'] = { 'images' },
['listbyte'] = { 'listbytes' },
['newpage'] = {},
['newredirect'] = {},
['reference'] = { 'ref' },
['section'] = {},
['templateremoval'] = {},
['wikidata'] = {},
['word'] = { 'words' },
['wordbonus'] = {}
},
['modifiers'] = {
['aliases'] = {},
['all'] = {},
['description'] = {},
['descriptions'] = {},
['distinct'] = {},
['ignore'] = {},
['initialimagelimit'] = {},
['labels'] = {},
['max'] = {},
['ownimage'] = {},
['properties'] = {},
['query'] = {},
['requirereference'] = { 'require reference', 'require_reference' },
['redirects'] = { 'redirect' },
['site'] = {},
}
}
if returnType == 'canonical' then
return argumentMapping[itemType]
end
local translatedMap = {
['criteria'] = mappingReverser(argumentMapping.criteria),
['rules'] = mappingReverser(argumentMapping.rules),
['modifiers'] = mappingReverser(argumentMapping.modifiers)
}
return translatedMap[itemType]
end
--[ Helper methods ] ------------------------------------------------------------------
--- Make an error string
-- @tparam string text Text to be wrapped in an error class
-- @treturn string The text wrapped in an error class
local function makeErrorString(text)
local html = mw.html.create('strong')
:addClass('error')
:wikitext(text)
return tostring(html)
end
--- Get an error string
-- @tparam string key A message key (from i18n)
-- @tparam string arg An argument to pass along to the message function
-- @treturn string An error message
local function getErrorString(key, arg)
return makeErrorString(msg(key, arg))
end
--- Parse and translate anonymous and named arguments
-- @tparam table frame A frame object
-- @tparam string|nil itemType An item type to return ('criteria', 'rules' or nil)
-- @treturn table A table of anonymous arguments (args)
-- @treturn table A table of named arguments (kwargs)
local function parseArgs(frame, itemType, translate)
local args = {}
local kwargs = {}
local canonicalMap = getArgumentMapping(itemType, 'translated')
if itemType == nil then
canonicalMap = {}
end
local kwargsMap = getArgumentMapping('modifiers', 'translated')
for k, v in pairs(getArgs(frame)) do
v = mw.text.trim(frame:preprocess(v))
if v ~= '' then
if type(k) == 'number' then
if k == 1 and canonicalMap[v] ~= nil and translate then
args[1] = canonicalMap[v]
else
args[k] = v
end
else
if kwargsMap[k] ~= nil and translate then
kwargs[kwargsMap[k]] = v
else
kwargs[k] = v
end
end
end
end
return args, kwargs
end
--- Turn an array table into a string in list form
-- @tparam table items An array of items
-- @tparam string itemType Maybe unnecessary?
-- @tparam string word The strings 'or' or 'and' (representing i18n message keys)
-- @treturn string A string with the table returned as a list
local function listify(items, itemType, word)
word = word or 'or'
if #items == 0 then
return getErrorString('anon-argument-missing', itemType)
end
if #items == 1 then
return items[1]
end
return mw.text.listToText(items, ', ', ' ' .. msg(word) .. ' ' )
end
--- Get link data for a link to a page in a specific namespace
-- @tparam table frame A frame object
-- @tparam string ns A canonical (English) namespace name; 'Template' and 'Category' supported
-- @tparam string page A page name
-- @treturn table A table containing: language code, link target and page name
local function makeNsLink(frame, ns, page)
local linkTarget
local nsNumbers = {
['Template'] = 10,
['Category'] = 14
}
local lang, pageName = mw.ustring.match(page, '^([a-z]+):(.+)$') -- FIXME: Better language code detection
if lang then
-- English namespace name is guaranteed to work, avoids need to maintain
-- lists of namespace names in the module
linkTarget = mw.ustring.format(':%s:%s:%s', lang, ns, pageName)
else
linkTarget = mw.ustring.format(':%s:%s', frame:callParserFunction('ns', nsNumbers[ns]), page)
end
return {
['lang'] = lang,
['linkTarget'] = linkTarget,
['pageName'] = pageName or page
}
end
--- Make a link to a single template, wrapped in curly brace syntax
-- @tparam table frame A frame object
-- @tparam template Name of a template (optionally with an interlanguage prefix)
-- @treturn string An HTML string linking to the template in question
local function makeTemplateLink(frame, template)
local nsLink = makeNsLink(frame, 'Template', template)
local wikitext = mw.text.nowiki('{{') .. mw.ustring.format('[[%s|%s]]', nsLink['linkTarget'], nsLink['pageName']) .. mw.text.nowiki('}}')
local html = mw.html.create('span')
:addClass('template-link')
:css('font-family', 'monospace,monospace')
:wikitext(wikitext)
return tostring(html)
end
--- Make a link to a single category
-- @tparam table frame A frame object
-- @tparam category Name of a category (optionally with an interlanguage prefix)
-- @treturn string An HTML string linking to the category in question
local function makeCategoryLink(frame, category)
local nsLink = makeNsLink(frame, 'Category', category)
return mw.ustring.format('[[%s|%s]]', nsLink['linkTarget'], nsLink['pageName'])
end
--- Make a list of templates
-- @tparam table frame A frame object
-- @tparam table args An array of template names (optionally with interlanguage prefixes)
-- @treturn table A table of template links
local function makeTemplateList(frame, args)
local templates = {}
for i, v in ipairs(args) do
table.insert(templates, makeTemplateLink(frame, v))
end
setmetatable(templates, {
__tostring = function(self)
return listify(templates, 'templates')
end
})
return templates
end
--- Make a list of categories
-- @tparam table frame A frame object
-- @tparam table args An array of category names (optionally with interlanguage prefixes)
-- @treturn table A table of category links
local function makeCategoryList(frame, args)
local categories = {}
for i, v in ipairs(args) do
v = mw.text.trim(v)
if v ~= '' then
table.insert(categories, makeCategoryLink(frame, v))
end
end
setmetatable(categories, {
__tostring = function(self)
return listify(categories, 'categories')
end
})
return categories
end
--- Make a list of templates
-- @tparam table args An array of page names (optionally with interlanguage prefixes)
-- @treturn table A table of page links
local function makePageList(args)
local pages = {}
for i, v in ipairs(args) do
v = mw.text.trim(v)
if v ~= '' then
local lang, page = string.match(v, '^([a-z]+):(.+)$')
if lang then
table.insert(pages, string.format('[[:%s:%s|%s]]', lang, page, page))
else
table.insert(pages, string.format('[[:%s]]', v))
end
end
end
setmetatable(pages, {
__tostring = function(self)
return listify(pages, 'pages')
end
})
return pages
end
--- Make a list of namespaces
-- @tparam table args An array of namespace IDs
-- @treturn table A table of namespace names
local function makeNsList(args)
local namespaces = {}
local namespaceName = msg('article')
for _, namespaceId in ipairs(args) do
namespaceId = mw.text.trim(namespaceId)
if namespaceId ~= '' then
if namespaceId ~= "0" then
namespaceName = '{{lc:{{ns:' .. namespaceId .. '}}}}'
end
table.insert(namespaces, namespaceName)
end
end
setmetatable(namespaces, {
__tostring = function(self)
return listify(namespaces, 'namespaces')
end
})
return namespaces
end
--[ Criterion format methods ]-------------------------------------------------------------
local criterion = {}
--- Formatter function for the backlinks criterion
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the criterion
function criterion.backlinks(args, kwargs, frame)
local pageList = makePageList(args)
return msg('criterion-backlinks', #pageList, tostring(pageList))
end
--- Formatter function for the bytes criterion
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the criterion
function criterion.bytes(args, kwargs, frame)
return msg('criterion-bytes', args[1])
end
--- Formatter function for the categories criterion
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the criterion
function criterion.categories(args, kwargs, frame)
local categoryList = makeCategoryList(frame, args)
local ret = msg('criterion-categories', #categoryList, tostring(categoryList))
if kwargs.ignore ~= nil then
local ignoredCats = mw.text.split(kwargs.ignore, ',')
ignoredCats = makeCategoryList(frame, ignoredCats)
ret = ret .. msg('categories-except', #ignoredCats, tostring(ignoredCats))
end
return ret
end
--- Formatter function for the existing criterion
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the criterion
function criterion.existing(args, kwargs, frame)
return msg('criterion-existing')
end
--- Formatter function for the forwardlinks criterion
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the criterion
function criterion.forwardlinks(args, kwargs, frame)
local pages = makePageList(args)
return msg('criterion-forwardlinks', #pages, tostring(pages))
end
--- Formatter function for the namespaces criterion
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the criterion
function criterion.namespaces(args, kwargs, frame)
local nsList = makeNsList(args)
local message
if #nsList == 1 and args[1] == '0' then
message = msg('criterion-namespace-0')
else
message = msg('criterion-namespace', #nsList, tostring(nsList))
end
if kwargs.site ~= nil then
return msg('page-at-site', message, mw.ustring.format('[https://%s %s]', kwargs.site, kwargs.site))
end
return message
end
--- Formatter function for the new page criterion
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the criterion
function criterion.new(args, kwargs, frame)
if kwargs.redirects ~= nil then
return msg('criterion-new-with-redirects')
end
return msg('criterion-new')
end
--- Formatter function for the pages (page list) criterion
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the criterion
function criterion.pages(args, kwargs, frame)
local pages = makePageList(args)
return msg('criterion-pages', #pages, tostring(pages))
end
--- Formatter function for the SPARQL criterion
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the criterion
function criterion.sparql(args, kwargs, frame)
local query = ''
if kwargs.distinct ~= nil then
query = 'SELECT DISTINCT ?item WHERE {\n ' .. kwargs.query .. '\n}'
else
query = 'SELECT ?item WHERE {\n ' .. kwargs.query .. '\n}'
end
local url = 'http://query.wikidata.org/#' .. mw.uri.encode(query, 'PATH')
if kwargs.description ~= nil then
return msg('criterion-sparql-with-explanation', kwargs.description, url)
end
return msg('criterion-sparql', url)
end
--- Formatter function for the templates criterion
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the criterion
function criterion.templates(args, kwargs, frame)
local templates = makeTemplateList(frame, args)
return msg('criterion-templates', #templates, tostring(templates))
end
--- Main function for getting criterion messages
-- @tparam table frame A frame object
-- @treturn string A string representing the criterion (or an error message string)
function p.criterion(frame)
local args, kwargs = parseArgs(frame, 'criteria', true)
local criterionArg = table.remove(args, 1)
local permittedCriteria = getArgumentMapping('criteria', 'canonical')
if criterionArg == nil or criterionArg == '' then
return frame:preprocess(getErrorString('argument-missing', 'criterion'))
elseif permittedCriteria[criterionArg] == nil or criterion[criterionArg] == nil then
return frame:preprocess(getErrorString('invalid-criterion', criterionArg))
end
-- Use manual description if given
if kwargs.description ~= nil and criterionArg ~= 'sparql' then
return kwargs.description
end
return frame:preprocess(criterion[criterionArg](args, kwargs, frame))
end
--[ Rule format methods ]-------------------------------------------------------------
local rule = {}
--- Formatter function for custom rules
-- @tparam number points A number of points; may by a float
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the rule
function rule.custom(points, args, kwargs, frame)
return msg('rule-custom', points, kwargs.description)
end
--- Formatter function for image rules
-- @tparam number points A number of points; may by a float
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the rule
function rule.image(points, args, kwargs, frame)
local out
local tplargs = {
['points'] = points,
}
if kwargs.initialimagelimit ~= nil then
out = msg('rule-image-limited', points, kwargs.initialimagelimit)
else
out = msg('rule-image', points)
end
if kwargs.ownimage ~= nil then
out = out .. ' ' .. msg('rule-image-own', kwargs.ownimage)
end
return out
end
--- Formatter function for Wikidata rules
-- @tparam number points A number of points; may by a float
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the rule
function rule.wikidata(points, args, kwargs, frame)
local out
local params
local argTypes = { msg('properties'), msg('labels'), msg('aliases'), msg('descriptions') }
local results = {}
if kwargs.properties == nil and kwargs.labels == nil and kwargs.aliases == nil and kwargs.descriptions == nil then
return getErrorString('argument-missing', listify(argTypes))
end
if kwargs.properties ~= nil then
params = mw.text.split(kwargs.properties, ',')
for k, v in pairs(params) do
params[k] = string.format('[[:d:Property:%s|%s]]', v, v)
end
table.insert(results, listify(params))
end
if kwargs.labels ~= nil then
params = mw.text.split(kwargs.labels, ',')
table.insert(results, msg('label') .. ' (' .. listify(params) .. ')')
end
if kwargs.aliases ~= nil then
params = mw.text.split(kwargs.aliases, ',')
table.insert(results, msg('alias') .. ' (' .. listify(params) .. ')')
end
if kwargs.descriptions ~= nil then
params = mw.text.split(kwargs.descriptions, ',')
table.insert(results, msg('description') .. ' (' .. listify(params) .. ')')
end
results = table.concat( results, ' ' .. msg('and') .. ' ' )
if kwargs.all ~= nil then
out = msg('rule-wikidata-all', points, results)
else
out = msg('rule-wikidata-first', points, results)
end
if kwargs.requireReference ~= nil then
out = out .. ' ' .. msg('rule-wikidata-require-reference')
end
return out
end
--- Formatter function for reference rules
-- @tparam number points A number of points; may by a float
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the rule
function rule.reference(points, args, kwargs, frame)
return msg('rule-reference', points, args[1])
end
--- Formatter function for template removal rules
-- @tparam number points A number of points; may by a float
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the rule
function rule.templateremoval(points, args, kwargs, frame)
local templateList = makeTemplateList(frame, args)
return msg('rule-templateremoval', points, #templateList, tostring(templateList))
end
--- Formatter function for category removal rules
-- @tparam number points A number of points; may by a float
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the rule
function rule.categoryremoval(points, args, kwargs, frame)
local categoryList = makeCategoryList(args)
return msg('rule-categoryremoval', points, #categoryList, tostring(categoryList))
end
--- Formatter function for section adding rules
-- @tparam number points A number of points; may by a float
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the rule
function rule.section(points, args, kwargs, frame)
if kwargs.description ~= nil then
return msg('rule-section-desc', points, kwargs.description)
end
return msg('rule-section', points, #args, listify(args))
end
--- Formatter function for byte bonus rules
-- @tparam number points A number of points; may by a float
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the rule
function rule.bytebonus(points, args, kwargs, frame)
return msg('rule-bytebonus', points, args[1])
end
--- Formatter function for word bonus rules
-- @tparam number points A number of points; may by a float
-- @tparam table args Anonymous arguments to the module
-- @tparam table kwargs Keyword arguments to the module
-- @treturn string A message corresponding to the rule
function rule.wordbonus(points, args, kwargs, frame)
return msg('rule-wordbonus', points, args[1])
end
--- Main function for getting criterion messages
-- @tparam table frame A frame object
-- @treturn string A string representing the rule (or an error message string)
function p.rule(frame)
local args, kwargs = parseArgs(frame, 'rules', true)
local ruleArg = table.remove(args, 1)
local points = table.remove(args, 1)
local permittedRules = getArgumentMapping('rules', 'canonical')
if ruleArg == nil or ruleArg == '' then
return frame:preprocess(getErrorString('argument-missing', 'rule'))
elseif permittedRules[ruleArg] == nil then
return frame:preprocess(getErrorString('invalid-rule', ruleArg))
end
if kwargs.description ~= nil then
ruleArg = 'custom'
end
-- All rules requires argument 1: number of points awarded
if points == nil then
return frame:preprocess(getErrorString('argument-missing', '1 (number of points)'))
end
points = mw.language.getContentLanguage():formatNum(tonumber(points))
-- If there's a rule formatter function, use it.
-- Otherwise, use the string from the messages table.
local out
if rule[ruleArg] ~= nil then
out = rule[ruleArg](points, args, kwargs, frame)
else
-- It shouldn't be necessary to check if the message exists here, because
-- of the previous check against permittedRules above
out = msg('rule-' .. ruleArg, points)
end
if kwargs.site ~= nil then
out = msg('rule-site', out, mw.ustring.format('[https://%s %s]', kwargs.site, kwargs.site))
end
if kwargs.max ~= nil then
out = msg('base-rule-max', out, mw.language.getContentLanguage():formatNum(tonumber(kwargs.max)))
end
return frame:preprocess(out)
end
--- Function to generate documentation for a module or template using this module
-- Not implemented yet
function p.generateDocs(frame)
-- Generate documentation subpage for templates using the module
end
--- Function to get warnings about duplicate or invalid i18n values
-- Not implemented yet
function p.getI18nWarnings(frame)
-- Function to be used on /doc page, to report any duplicate arguments
-- from the i18n, and potentially other things that should be fixed in the
-- i18n for the current language.
end
--- Get a single message string from the module's i18n, localized into the page
--- if possible
-- @tparam table frame A frame object
-- @treturn string A formatted message (or an HTML error string if the key doesn't exist)
function p.getMessage(frame)
local args, kwargs = parseArgs(frame, nil, false)
local key = table.remove(args, 1)
local exists, message = pcall(msg, key, args)
if exists then
if mw.isSubsting() then
-- substitute magic words etc. if the module proper is being substed
message = mw.ustring.gsub( message, '{{(#?%a+):', '{{subst:%1:' )
end
return frame:preprocess(message)
else
return getErrorString('message-key-missing', key)
end
end
--- Function to get i18n data for use by the bot
-- @treturn string A JSON-encoded string of all keys and (localized) values from the i18n dataset
function p.getAllI18n()
local lang = mw.title.getCurrentTitle().pageLang:getCode()
local sensible = {}
local i18n = mw.ext.data.get(I18NDATASET, lang)['data']
for _,v in ipairs(i18n) do
-- turn the array of message objects into a sensible key->value mapping
sensible[v[1]] = v[2]
end
return mw.text.jsonEncode(sensible)
end
--- Function to get a prize ribbon with a specified color
-- Takes three parameters: A file name or a color, a width, and a link target
-- @tparam table frame A frame object
-- @treturn string
function p.getRibbon(frame)
local args = getArgs(frame)
local color = args[1] or 'white'
local width = args[2] or '20px'
local link = args[3] or 'User:UKBot'
local alt = msg('ribbon')
if string.find( color, '%.%a%a%a%a?$' ) then
return '[[File:' .. color .. '|' .. width .. '|alt=' .. alt .. '|link=' .. link .. ']]'
end
local svgContent = [[
<defs>
<linearGradient id="path10250_1_" x1="301.8" x2="456.98" y1="663.18" y2="609.32" gradientTransform="translate(-301.52 -390.52)" gradientUnits="userSpaceOnUse">
<stop offset="0"/>
<stop stop-opacity="0" offset="1"/>
</linearGradient>
</defs>
<filter id="filter3" x="-.17993" y="-.11726" width="1.3779" height="1.2582">
<feGaussianBlur stdDeviation="4"/>
</filter>
<filter id="filter2" x="-.093808" y="-.094418" width="1.1878" height="1.1882">
<feGaussianBlur stdDeviation="5"/>
</filter>
<g enable-background="new" filter="url(#filter2)" opacity=".8">
<polygon points="145.65 230.41 122.62 201.35 100.76 231.31 91.545 195.39 59.394 213.88 65.582 177.31 28.69 181.12 49.217 150.23 13.965 138.71 45.281 118.84 17.764 93.973 54.454 88.559 39.429 54.651 75.149 64.627 75.215 27.54 103.79 51.183 118.94 17.329 135.42 50.55 163.03 25.782 164.58 62.837 199.87 51.439 186.21 85.921 223.09 89.863 196.59 115.81 228.68 134.41 193.91 147.34 215.66 177.38 178.65 175.05 186.29 211.34 153.43 194.15"/>
<polygon points="145.65 230.41 122.62 201.35 100.76 231.31 91.545 195.39 59.394 213.88 65.582 177.31 28.69 181.12 49.217 150.23 13.965 138.71 45.281 118.84 17.764 93.973 54.454 88.559 39.429 54.651 75.149 64.627 75.215 27.54 103.79 51.183 118.94 17.329 135.42 50.55 163.03 25.782 164.58 62.837 199.87 51.439 186.21 85.921 223.09 89.863 196.59 115.81 228.68 134.41 193.91 147.34 215.66 177.38 178.65 175.05 186.29 211.34 153.43 194.15" fill="none" stroke="#000" stroke-linecap="round" stroke-miterlimit="7.5" stroke-width="7"/>
</g>
<path d="m124.48 175.04 28.859-1.697 44.129 85.395-30.805-8.571-30.813 27.146z" fill="url(#path10250_1_)"/>
<g enable-background="new" filter="url(#filter3)" opacity=".8">
<polygon points="195.77 267.59 164.96 259.02 134.15 286.16 122.78 183.89 151.64 182.19"/>
<polygon points="195.77 267.59 164.96 259.02 134.15 286.16 122.78 183.89 151.64 182.19" fill="none" stroke="#000" stroke-linecap="round" stroke-miterlimit="7.5" stroke-width="5"/>
<polygon points="100.53 312.47 71.422 283.52 38.911 295.39 81.015 189.72 116.66 193.12"/>
<polygon points="100.53 312.47 71.422 283.52 38.911 295.39 81.015 189.72 116.66 193.12" fill="none" stroke="#000" stroke-linecap="round" stroke-miterlimit="7.5" stroke-width="5"/>
</g>
<g fill="COLOR" stroke="#000" stroke-linecap="round" stroke-miterlimit="7.5">
<path d="m123.03 174.57 28.859-1.697 44.127 85.393-30.804-8.57-30.813 27.145z" stroke-width="5.6384"/>
<path d="m78.469 182.21 35.65 3.396-16.138 119.34-29.106-28.943-32.511 11.866z" stroke-width="5.6384"/>
<path d="m186.29 211.34-32.865-17.186-7.774 36.264-23.035-29.066-21.853 29.965-9.22-35.924-32.152 18.486 6.188-36.566-36.891 3.812 20.526-30.889-35.253-11.525 31.316-19.87-27.517-24.865 36.69-5.415-15.025-33.908 35.721 9.977 0.065-37.087 28.575 23.643 15.145-33.855 16.487 33.221 27.605-24.768 1.551 37.055 35.291-11.398-13.654 34.481 36.877 3.942-26.5 25.946 32.086 18.601-34.763 12.927 21.746 30.043-37.014-2.332z" stroke-width="7" style="paint-order:normal"/>
</g>
]]
svgContent = mw.ustring.gsub(svgContent, 'COLOR', color)
local svg = mw.svg.new()
svg:setAttribute('viewBox', '0 0 245 320')
svg:setContent(svgContent)
svg:setImgAttribute('width', width)
svg:setImgAttribute('alt', alt)
return '[[' .. link .. '|' .. svg:toImage() .. ']]'
end
return p