Narutopedia
No edit summary
(add distances)
(3 intermediate revisions by one other user not shown)
Line 34: Line 34:
 
local function nameCheck ( target )
 
local function nameCheck ( target )
 
local nq = mw.smw.ask{ HF.Link(target:match(stripLinkToTarget)), '?Maintenance' }
 
local nq = mw.smw.ask{ HF.Link(target:match(stripLinkToTarget)), '?Maintenance' }
if type(nq) == 'table' and nq[1]['Maintenance'] == 'Name' then
+
if type(nq) == 'table'
 
and (
 
nq[1]['Maintenance'] == 'Name'
  +
or (type(nq[1]['Maintenance']) == 'table' and table.concat(nq[1]['Maintenance']):match('Name'))
 
)
 
then
 
return true
 
return true
 
else return nil
 
else return nil
Line 198: Line 203:
 
local args = getArgs(frame)
 
local args = getArgs(frame)
 
local ranges = {
 
local ranges = {
  +
['Short'] = 'Short range (0-5m)',
  +
['Mid'] = 'Mid range (5-10m)',
  +
['Long'] = 'Long range (10m+)',
 
['Short, Mid, Long'] = 'All ranges',
 
['Short, Mid, Long'] = 'All ranges',
['Short, Mid'] = 'Short to Mid range',
+
['Short, Mid'] = 'Short to Mid range (0-10m)',
['Mid, Long'] = 'Mid to Long range',
+
['Mid, Long'] = 'Mid to Long range (5m+)',
['Short, Long'] = 'Short or Long range'
+
['Short, Long'] = 'Short or Long range (0-5m or 10m+)'
 
}
 
}
 
arrayTable ( args['jutsu range'], ',%s*', { ['SemanticPropertyName'] = 'Jutsu range' } )
 
arrayTable ( args['jutsu range'], ',%s*', { ['SemanticPropertyName'] = 'Jutsu range' } )
Line 242: Line 250:
 
for _, parent in ipairs(mq) do
 
for _, parent in ipairs(mq) do
 
local mainlink =
 
local mainlink =
 
(
parent['Maintenance'] == 'Name'
 
  +
parent['Maintenance'] == 'Name'
 
or (
 
type(parent['Maintenance']) == 'table'
  +
and table.concat(parent['Maintenance']):match('Name')
 
)
 
)
 
and ("''%s''"):format(
 
and ("''%s''"):format(
 
HF.Link(
 
HF.Link(
Line 264: Line 278:
 
if type( dq ) == 'table' then
 
if type( dq ) == 'table' then
 
for _, derived in ipairs(dq) do
 
for _, derived in ipairs(dq) do
local dlink = derived['Maintenance'] == 'Name'
+
local dlink = (
  +
derived['Maintenance'] == 'Name'
  +
or type(derived['Maintenance']) == 'table'
  +
and table.concat(derived['Maintenance']):match('Name')
 
)
 
and ("''%s''"):format(
 
and ("''%s''"):format(
 
HF.Link(
 
HF.Link(
Line 307: Line 325:
   
 
function Infobox.jutsuUsers(frame)
 
function Infobox.jutsuUsers(frame)
local args = getArgs(frame)
 
local out = {}
 
local mtypes = {
 
anime = true,
 
manga = true,
 
novel = true,
 
game = true,
 
movie = true,
 
['movie canon'] = true
 
}
 
local users = mw.text.split( args['users'], ',%s*' )
 
for _,user in ipairs( users ) do
 
local userX = mw.text.split( user, '~')
 
local link =
 
nameCheck( base( user ) ) == true
 
and ("''%s''"):format(
 
HF.Link(
 
base( user ):match(stripLinkToTarget),
 
base( user ):match(stripLinkToTarget):match(stripPageTitleToBase)
 
)
 
)
 
or HF.Link(
 
base( user ):match(stripLinkToTarget),
 
base( user ):match(stripLinkToTarget):match(stripPageTitleToBase)
 
)
 
local AdditionalInfo =
 
( userX[3] and userX[3] == 'puppet' )
 
and (' ([[Puppetry]] using %s)'):format( table.concat( userX, " and ", 4 ) )
 
or ( userX[3] and userX[3] == 'with' )
 
and (' (with %s)'):format(userX[4])
 
or ''
 
local Media =
 
( userX[2] and mtypes[userX[2]:lower()] and mtypes[userX[2]:lower()] ~= 'movie canon' )
 
and ('<sup> (%s only)</sup>'):format( language:ucfirst( userX[2] ) )
 
or ( userX[2] and mtypes[userX[2]:lower()] and mtypes[userX[2]:lower()] == 'movie canon' )
 
and '<sup> (Movie only)</sup>'
 
or ''
 
local cq = mw.smw.ask {
 
(HF.Link('Contract::%s')):format( user:match(stripLinkToTarget) ),
 
'mainlabel=main'
 
}
 
local sl = {}
 
if type(cq) == 'table' then
 
for _,v in ipairs( cq ) do
 
table.insert( sl, v['main'] )
 
end
 
end
 
local Summons = ((#sl > 0)
 
and ( pageTitle == 'Summoning Technique' or pageTitle == 'Destruction Bug Host Technique' ))
 
and ( ' (%s)' ):format( table.concat( sl, ", " ) )
 
or ''
 
local setmtype = ( extra1( user ) and mtypes[ extra1( user ):lower() ] )
 
and language:ucfirst( extra1( user ):lower() )
 
or 'null'
 
mw.smw.set {
 
['User tech'] = base( user ) .. ';' .. setmtype
 
}
 
table.insert( out, link .. AdditionalInfo .. Summons .. Media )
 
end
 
return L.makeList( 'bulleted', out )
 
end
 
 
function Infobox.jutsuUsersTest(frame)
 
 
local args = getArgs(frame)
 
local args = getArgs(frame)
 
local out = {}
 
local out = {}
 
-- Valid media types
 
local mtypes = {
 
local mtypes = {
 
anime = true, manga = true, novel = true,
 
anime = true, manga = true, novel = true,
 
game = true, movie = true, ['movie canon'] = true
 
game = true, movie = true, ['movie canon'] = true
 
}
 
}
  +
-- Divides users into actionable items (even if there's only one)
 
local users = args['users'] and mw.text.split( args['users'], ',%s*' )
 
local users = args['users'] and mw.text.split( args['users'], ',%s*' )
  +
-- Checks if any user entries exist, and if they don't, return nil
if type(users) == 'table' then
+
if type(users) ~= 'table' then return nil end
for _, user in ipairs( users ) do
 
  +
-- For each user
if type(user) == 'string' and #user > 1 then
 
 
for _, user in ipairs( users ) do
local prime, media = user:match('([^%~]*)%~?([^%~]*)')
 
local link = HF.Link(
+
-- checks if the entry is real or empty
 
if type(user) == 'string' and #user < 1 then break end
base( prime ):match(stripLinkToTarget),
 
  +
-- separates user name from media
base( prime ):match(stripLinkToTarget):match(stripPageTitleToBase)
 
 
local prime, media = user:match('([^%~]*)%~?([^%~]*)')
)
 
link = nameCheck( prime ) == true
+
local link = HF.Link(
 
base( prime ):match(stripLinkToTarget),
and ("''%s''"):format( link )
 
 
base( prime ):match(stripLinkToTarget):match(stripPageTitleToBase)
or link
 
 
)
local puppetry = user:match('~~puppet~(.*)$')
 
if puppetry then
+
link = nameCheck( prime ) == true
puppetry = (' ([[Puppetry]] using %s)')
+
and ("''%s''"):format( link )
 
or link
:format(mw.text.listToText(mw.text.split(puppetry, '~')))
 
end
 
local with = user:match('~~with~([^%~]*)')
 
and (' (with %s)'):format(user:match('~~with~([^%~]*)'))
 
local AdditionalInfo = puppetry or with or ''
 
 
local Media = ''
 
if media
 
and mtypes[media:lower()]
 
and mtypes[media:lower()] ~= 'movie canon'
 
then
 
Media = ('<sup> (%s only)</sup>')
 
:format( language:ucfirst( media ) )
 
elseif media
 
and mtypes[media:lower()] == 'movie canon'
 
then
 
Media = '<sup> (Movie only)</sup>'
 
end
 
   
  +
--- AdditionalInfo
local cq = mw.smw.ask {
 
  +
-- Puppetry handling
(HF.Link('Contract::%s')):format( prime:match(stripLinkToTarget) ),
 
 
local puppetry = user:match('~~puppet~(.*)$')
'mainlabel=main'
 
}
+
if puppetry then
local sl = {}
+
puppetry = (' ([[Puppetry]] using %s)')
 
:format(mw.text.listToText(mw.text.split(puppetry, '~')))
if type(cq) == 'table' then
 
 
end
for _, v in ipairs( cq ) do
 
  +
-- "with" handling
table.insert( sl, v['main'] )
 
 
local with = user:match('~~with~([^%~]*)')
end
 
 
and (' (with %s)'):format(user:match('~~with~([^%~]*)'))
end
 
 
local AdditionalInfo = puppetry or with or ''
local Summons = ((#sl > 0)
 
  +
and ( pageTitle == 'Summoning Technique' or pageTitle == 'Destruction Bug Host Technique' ))
 
 
--- Media
and ( ' (%s)' ):format( table.concat( sl, ", " ) )
 
or ''
+
local Media = ''
  +
if media
local setmtype = ( media and mtypes[ media:lower() ] )
 
and language:ucfirst( media:lower() )
+
and mtypes[media:lower()]
or 'null'
+
and media:lower() ~= 'movie canon'
  +
then
mw.smw.set {
 
 
Media = ('<sup> (%s only)</sup>')
['User tech'] = prime .. ';' .. setmtype
 
 
:format( language:ucfirst( media ) )
}
 
 
elseif media
table.insert( out, link .. AdditionalInfo .. Summons .. Media )
 
 
and media:lower() == 'movie canon'
 
then
 
Media = '<sup> (Movie only)</sup>'
 
end
  +
  +
--- Summons
 
local cq = mw.smw.ask {
 
(HF.Link('Contract::%s')):format( prime:match(stripLinkToTarget) ),
 
'mainlabel=main'
  +
}
 
local sl = {}
 
if type(cq) == 'table' then
 
for _, v in ipairs( cq ) do
 
table.insert( sl, v['main'] )
 
end
 
end
 
end
 
end
 
local Summons = ((#sl > 0)
 
and ( pageTitle == 'Summoning Technique' or pageTitle == 'Destruction Bug Host Technique' ))
 
and ( ' (%s)' ):format( table.concat( sl, ", " ) )
 
or ''
  +
  +
-- SMW set
 
local setmtype = ( media and mtypes[ media:lower() ] )
 
and language:ucfirst( media:lower() )
 
or 'null'
 
mw.smw.set {
 
['User tech'] = prime .. ';' .. setmtype
  +
}
  +
 
table.insert( out, link .. AdditionalInfo .. Summons .. Media )
 
end
 
end
 
return L.makeList( 'bulleted', out )
 
return L.makeList( 'bulleted', out )

Revision as of 20:21, 15 April 2019

Documentation for this module may be created at Module:HF/Infobox/Jutsu/doc

local Infobox = {}

------------------------------------
-- Libraries and Global functions --
------------------------------------
-- "High Frequency" functions
local HF = require('Module:HF')
-- Parses invocation and template parameters, trims whitespace, and removes blanks.
local getArgs = require('Dev:Arguments').getArgs
-- Generates lists
local L = require('Dev:List')
-- Language functions
local language = mw.language.new('en')

-- Helper functions (local to not have to worry about namespaces)
local arraymap = require('Module:HF/Infobox').arraymap
local arrayTable = require('Module:HF/Infobox').arrayTable
local base = require('Module:HF/Infobox').base
local extra1 = require('Module:HF/Infobox').extra1

-- The page title of whatever page is calling the function
local pageTitle = mw.title.getCurrentTitle().text

-- Convenient constants
local stripLinkToTarget = '^%[*([^%[|]*)|?'
local stripPageTitleToBase = "[^(]*"
local basepattern = '^[^~]*'
local extra1pattern = '^[^~]*~([^~]*)'

------------------------------------------------
-- Local functions (used only in this Module) --
------------------------------------------------
-- Replaces {{IsUnnamed}}
local function nameCheck ( target )
	local nq = mw.smw.ask{ HF.Link(target:match(stripLinkToTarget)), '?Maintenance' }
	if type(nq) == 'table' 
	    and (
	        nq[1]['Maintenance'] == 'Name'
	        or (type(nq[1]['Maintenance']) == 'table' and table.concat(nq[1]['Maintenance']):match('Name'))
	    )
        then
		return true
	else return nil
	end
end

----------------------------------------------------------
-- Public functions (called from a Template or article) --
----------------------------------------------------------
-- Creates the infobox main title
function Infobox.titleJutsu(frame)
	local args = getArgs(frame)
	local out = {}
	if mw.title.getCurrentTitle().isContentPage == true then
		table.insert( out, HF.Category('Jutsu') )
		local _editFormURL = mw.html.create('span')
			:css('float','right'):css('font-size','x-small')
            :wikitext( HF.Link('Special:FormEdit/Jutsu/' .. pageTitle, 'edit') ):allDone()			
		local editFormURL = tostring(_editFormURL)
		if args['english'] then
			mw.smw.set {
				['English name'] = args['english'],
				['Names'] = args['english']
			}
		end
		if args['kanji'] then
			mw.smw.set {
				['Kanji name'] = args['kanji'],
				['Names'] = args['kanji']
			}
		else
			mw.smw.set { ['Maintenance'] = 'Kanji' }
		end
		if args['romaji'] then
			mw.smw.set{
				['Romaji_name'] = args['romaji']:match(stripLinkToTarget),
				['Names'] = args['romaji']
			}
		end
		if args['teams'] then
			local teams = mw.text.split( args['teams'], ',%s*' )
			for _, v in ipairs(teams) do
				mw.smw.set{ ['Team'] = mw.text.trim(v) }
			end
		end
		if args['image'] then
			local images = mw.text.split( args['image'], '\n')
			for _, image in ipairs(images) do
				if type(image) == 'string' then
					mw.smw.set{ ['Picture'] = 'File:' .. image:match("[^:;]*") }
				end
			end
		else
			mw.smw.set{ ['Maintenance'] = 'Missing image' }
		end
		if args['unnamed jutsu'] == 'Yes' then
			mw.smw.set{ ['Maintenance'] = 'Name' }
			table.insert( out, ("''%s''"):format( pageTitle:match("[^(]*") ) )
		else
				table.insert( out, pageTitle:match("[^(]*") )
		end
		local popup = frame:newParserValue(
			"<span class='ultisup-image-popup'>" ..
			"{{#queryformlink:form=Image query|link text=" ..
			"[[File:Camera font awesome.svg|15px|link=]]" ..
			"|query string=Image_query[jutsu]=" .. pageTitle ..
			"&wpRunQuery=true|tooltip=Images of " .. pageTitle .. " }}</span>"
		)
		return table.concat( out ) .. popup:expand() .. ( args['ref'] or '' ) .. editFormURL
	elseif mw.title.getCurrentTitle().namespace == 10
	    and not pageTitle:match('/testcases') then
	    return nil
	else
		if args['unnamed jutsu'] == 'Yes' then
			table.insert( out, ("''%s''"):format( args['english'] or pageTitle:match("[^(]*") ) )
		else
			table.insert( out, args['english'] or pageTitle:match("[^(]*") )
		end
		return table.concat( out ) .. ( args['ref'] or '' )
	end
end

function Infobox.jutsuClassification(frame)
	local args = getArgs(frame)
	local classifications =
		type(args['jutsu classification']) == 'string'
		and mw.text.split( args['jutsu classification'], ',%s*' )
	if type(classifications) == 'table' then
		local out = {}
		local icons = {}
		local kekkei = {
			['kekkei mōra'] = true,
			['kekkei tōta'] = true,
			['kekkei genkai'] = true
		}
		for _,classification in ipairs(classifications) do
			if classification:match(extra1pattern) then
				if classification:match(basepattern):lower() == 'hiden' then
					local options = {
						['SemanticPropertyName'] = 'Clan',
						['PrependText'] = 'Icon Type=Ninja clan',
						['PrependTemplate'] = 'Infobox_icon',
						['Print'] = 'none',
						['Link'] = 'default'
					}
					local clans = arrayTable( classification:match('^[^~]*~(.*)'), '~', options, frame )
					table.insert( icons, table.concat( clans ) )
				elseif kekkei[classification:match(basepattern):lower()] then
					local options = {
						['SemanticPropertyName'] = 'Kekkei Genkai',
						['PrependText'] = 'Icon Type=Kekkei Genkai',
						['PrependTemplate'] = 'Infobox_icon',
						['Print'] = 'none',
						['Link'] = 'default'
					}
					local clans = arrayTable( classification:match('^[^~]*~(.*)'), '~', options, frame )
					table.insert( icons, table.concat( clans ) )
				end
			end
			if classification:match(basepattern) and #classification > 1 then
				mw.smw.set { ['Jutsu classification'] = classification:match(basepattern) }
				table.insert( out, HF.Link(classification:match(basepattern)) )
			end
		end
		return table.concat( icons ) .. table.concat( out, ', ' )
	else return nil
	end
end

function Infobox.jutsuType(frame)
	local args = getArgs(frame)
	local options = {
		['SemanticPropertyName'] = 'Chakra Nature',
		['PrependText'] = 'Nature',
		['PrependTemplate'] = 'Infobox_icon',
		['Link'] = 'default'
	}
	local values = arrayTable ( args['jutsu type'], ',%s*', options, frame )
	return L.makeList( 'unbulleted' , values )
end

function Infobox.jutsuRank(frame)
	local args = getArgs(frame)
	local array = mw.text.split( args['jutsu rank'], ',' )
	local out = {}
	for _, v in ipairs( array ) do
		table.insert( out , HF.Link('Jutsu rank::'..v, v..'-rank') )
	end
	return table.concat( out, ',' )
end

function Infobox.jutsuClass(frame)
	local args = getArgs(frame)
	local options = {
		['SemanticPropertyName'] = 'Jutsu class type',
		['Link'] = 'none'
	}
	local classes = arrayTable ( args['jutsu class type'], ',%s*', options, frame )
	return table.concat( classes, ', ' )
end

function Infobox.jutsuRange(frame)
	local args = getArgs(frame)
	local ranges = {
		['Short'] = 'Short range (0-5m)',
		['Mid'] = 'Mid range (5-10m)',
		['Long'] = 'Long range (10m+)',
		['Short, Mid, Long'] = 'All ranges',
		['Short, Mid'] = 'Short to Mid range (0-10m)',
		['Mid, Long'] = 'Mid to Long range (5m+)',
		['Short, Long'] = 'Short or Long range (0-5m or 10m+)'
	}
	arrayTable ( args['jutsu range'], ',%s*', { ['SemanticPropertyName'] = 'Jutsu range' } )
	return ranges[args['jutsu range']] or args['jutsu range']..'-range'
end

function Infobox.jutsuParent(frame)
	local args = getArgs(frame)
	local options = {
		['SemanticPropertyName'] = 'Parent',
		['Link'] = 'Unnamed',
		['UnnamedFormat'] = true
	}
	local parents = arrayTable ( args['parent jutsu'], ',%s*', options )
	return L.makeList( 'unbulleted', parents )
end

function Infobox.jutsuMedia(frame)
	local args = getArgs(frame)
	local out = {}
	local mtypes = {
		['Movie'] = 'Jutsu/NonCanon',
		['Game'] = 'Jutsu/NonCanon',
		['Game, Movie'] = 'Jutsu/NonCanon'
	}
	local mq = mw.smw.ask {
		(HF.Link('Concept:%s')):format( mtypes[args['jutsu media']] or 'Jutsu/Canon' ),
		(HF.Link('Parent::%s')):format( mw.title.getCurrentTitle().prefixedText ),
		'?Appears in',
		'?Maintenance',
		('userparam=%s'):format(args['jutsu media']),
		'mainlabel=main',
		'limit=200'
	}
	local hasNCderivatives = mw.smw.ask {
		(HF.Link('Concept:%s')):format( 'Jutsu/NonCanon' ),
		(HF.Link('Parent::%s')):format( mw.title.getCurrentTitle().prefixedText )
	}
	if type(mq) == 'table' then
		for _, parent in ipairs(mq) do
			local mainlink =
				(
				    parent['Maintenance'] == 'Name'
				    or (
				        type(parent['Maintenance']) == 'table'
				        and table.concat(parent['Maintenance']):match('Name')
		            )
			    )
				and ("''%s''"):format(
					HF.Link(
						parent['main']:match(stripLinkToTarget),
						parent['main']:match('%[%[:?([^|]*)|?'):match(stripPageTitleToBase)
					)
				)
				or HF.Link(
					parent['main']:match(stripLinkToTarget),
					parent['main']:match('%[%[:?([^|]*)|?'):match(stripPageTitleToBase)
				)
			local dq = mw.smw.ask {
				(HF.Link('Concept:%s')):format( mtypes[args['jutsu media']] or 'Jutsu/Canon' ),
				(HF.Link('Parent::%s')):format( parent['main']:match(stripLinkToTarget) ),
				('userparam=%s'):format( args['jutsu media'] or 'Anime, Manga' ),
				'mainlabel=main',
				'named args=yes',
				'limit=20'
			}
			local derivatives = {}
			if type( dq ) == 'table' then
				for _, derived in ipairs(dq) do
					local dlink = (
					    derived['Maintenance'] == 'Name'
					    or type(derived['Maintenance']) == 'table'
				        and table.concat(derived['Maintenance']):match('Name')
					    )
					and ("''%s''"):format(
						HF.Link(
							derived['main']:match(stripLinkToTarget),
							derived['main']:match('%[%[:?([^|]*)|?'):match(stripPageTitleToBase)
						)
					)
					or HF.Link(
						derived['main']:match(stripLinkToTarget),
						derived['main']:match('%[%[:?([^|]*)|?'):match(stripPageTitleToBase)
					)
					table.insert( derivatives, dlink )
				end
				table.insert( out, mainlink .. L.makeList( 'bulleted', derivatives ) )
			else
				table.insert( out, mainlink )
			end
		end
		return L.makeList( 'bulleted', out )
	elseif type(hasNCderivatives) == 'table' then
	    local t = 
	        mw.title.new( 'SearchByProperty', 'Special' ).prefixedText
	    local q = mw.uri.buildQueryString{ 
	        ['property'] = 'Parent',
	        ['value'] = mw.uri.encode(
	            mw.title.getCurrentTitle().prefixedText,
	            'WIKI'
	            )
        }
        local searchlink = HF.ExternalLink(
            tostring(mw.uri.fullUrl(t,q)),
            'All derived jutsu'
        )
	    return ('<center class="smwsearch">%s</center>'):format( searchlink )
	end
end

function Infobox.jutsuRelated(frame)
	local args = getArgs(frame)
	return arraymap( args['related jutsu'], ',%s*', HF.Link('%s'), ', ' )
end

function Infobox.jutsuUsers(frame)
  local args = getArgs(frame)
  local out = {}
  -- Valid media types
  local mtypes = {
    anime = true, manga = true, novel = true,
    game = true, movie = true, ['movie canon'] = true
  }
  -- Divides users into actionable items (even if there's only one)
  local users = args['users'] and mw.text.split( args['users'], ',%s*' )
  -- Checks if any user entries exist, and if they don't, return nil
  if type(users) ~= 'table' then return nil end
  -- For each user
  for _, user in ipairs( users ) do
    -- checks if the entry is real or empty
    if type(user) == 'string' and #user < 1 then break end
    -- separates user name from media
    local prime, media = user:match('([^%~]*)%~?([^%~]*)')
    local link = HF.Link(
      base( prime ):match(stripLinkToTarget),
      base( prime ):match(stripLinkToTarget):match(stripPageTitleToBase)
    )
    link = nameCheck( prime ) == true
      and ("''%s''"):format( link )
      or link

    --- AdditionalInfo
    -- Puppetry handling
    local puppetry = user:match('~~puppet~(.*)$')
    if puppetry then
      puppetry = (' ([[Puppetry]] using %s)')
        :format(mw.text.listToText(mw.text.split(puppetry, '~')))
    end
    -- "with" handling
    local with = user:match('~~with~([^%~]*)')
      and (' (with %s)'):format(user:match('~~with~([^%~]*)'))
    local AdditionalInfo = puppetry or with or ''

    --- Media
    local Media = ''
    if media
      and mtypes[media:lower()]
      and media:lower() ~= 'movie canon'
    then
      Media = ('<sup> (%s only)</sup>')
        :format( language:ucfirst( media ) )
    elseif media
      and media:lower() == 'movie canon'
      then
        Media = '<sup> (Movie only)</sup>'
    end

    --- Summons
    local cq = mw.smw.ask {
      (HF.Link('Contract::%s')):format( prime:match(stripLinkToTarget) ),
      'mainlabel=main'
    }
    local sl = {}
    if type(cq) == 'table' then
      for _, v in ipairs( cq ) do
        table.insert( sl, v['main'] )
      end
    end
    local Summons = ((#sl > 0)
        and ( pageTitle == 'Summoning Technique' or pageTitle == 'Destruction Bug Host Technique' ))
      and ( ' (%s)' ):format( table.concat( sl, ", " ) )
      or ''

    -- SMW set
    local setmtype = ( media and mtypes[ media:lower() ] )
      and language:ucfirst( media:lower() )
      or 'null'
    mw.smw.set {
      ['User tech'] = prime .. ';' .. setmtype
    }

    table.insert( out, link .. AdditionalInfo .. Summons .. Media )
  end
  return L.makeList( 'bulleted', out )
end
---------------------------------------------------------
-- Exported functions (used in this and other Modules) --
---------------------------------------------------------
-- None.
-------------------------------------------------
-- Output (send it back to whatever called it) --
-------------------------------------------------
return Infobox