July 25, 2020

👭 Knight Challenge #11 👬

Want to try your hand at these challenges? There's a couple of things you can do!
From writing, to research, to images, find your preferred way to contribute with our eleventh theme: Couples!

Latest Announcements

Module:File

From Zelda Wiki, the Zelda encyclopedia
Jump to: navigation, search

image

image(filename, [options])

A higher-level version of utilsMarkup.file with awareness of whether the file exists or not.

Parameters
  • filename
    Filename of the image, with or without the namespace prefix.
  • [options]
    [size]
    Image size in pixels.
    [scale]
    Image scaling factor — the original image size is multitplied by scale. If both scale and size are present, the value which results in the smaller image will be used. By default this uses an expensive parser function.
    [scaleUsingCargo]
    If set to true, then a Cargo query is used to determine the original image size for the scale option above. You can use this to avoid hitting expensive parser function limit. This option has an additional performance cost of roughly 2-5 milliseconds per image.
    [link]
    Name of a page on the wiki or an external URL for the image thumbnail to link to.
    [caption]
    Alt text for the image.
Returns
  • Wikitext rendering an image thumbnail.
  • A boolean — true if the image exists, false otherwise.
Examples
InputOutputResultStatus
image(
  "File:TWW Great Fairy Figurine Model.png",
  {
    size = "100px",
    link = "Great Fairy",
  }
)
"[[File:TWW Great Fairy Figurine Model.png|100px|link=Great Fairy|TWW Great Fairy Figurine Model.png]]"
TWW Great Fairy Figurine Model.png
Green check.svg
true
Green check.svg
If file does not exist, show 'click to upload' thumbnail which links to Special:Upload.
image(
  "File:TWWHD Great Fairy Figurine Model.png",
  {
    size = "150px",
    link = "Great Fairy",
  }
)
"[[File:No Image Upload.png|150px|link=https://zelda.gamepedia.com/Special:Upload?wpDestFile=TWWHD+Great+Fairy+Figurine+Model.png|File:No Image Upload.png]]"
File:No Image Upload.png
Green check.svg
false
Green check.svg
'No image' thumbnail has minimum 100px width, because it is illegible at smaller sizes.
image(
  "File:TWWHD Great Fairy Figurine Model.png",
  { size = "64px" }
)
"[[File:No Image Upload.png|100px|link=https://zelda.gamepedia.com/Special:Upload?wpDestFile=TWWHD+Great+Fairy+Figurine+Model.png|File:No Image Upload.png]]"
File:No Image Upload.png
Green check.svg
false
Green check.svg
Scaling factor.
image("File:TMC Vaati Sprite.png", { scale = 2 })
"[[File:TMC Vaati Sprite.png|48x56px|TMC Vaati Sprite.png]]"
TMC Vaati Sprite.png
Green check.svg
true
Green check.svg
image(
  "File:TMC Vaati Sprite.png",
  {
    scale = 2,
    scaleUsingCargo = true,
  }
)
"[[File:TMC Vaati Sprite.png|48x56px|TMC Vaati Sprite.png]]"
TMC Vaati Sprite.png
Green check.svg
true
Green check.svg
If both scale and size are specified, the one resulting in the smaller image is used.
image(
  "File:TMC Vaati Sprite.png",
  {
    scale = 2,
    size = "80px",
  }
)
"[[File:TMC Vaati Sprite.png|48x56px|TMC Vaati Sprite.png]]"
TMC Vaati Sprite.png
Green check.svg
true
Green check.svg
image(
  "File:TMC Vaati Sprite.png",
  {
    scale = 10,
    size = "80px",
  }
)
"[[File:TMC Vaati Sprite.png|80px|TMC Vaati Sprite.png]]"
TMC Vaati Sprite.png
Green check.svg
true
Green check.svg

gameImage

gameImage(game, subject, type, [options])

A specialized version of image that infers the filename from game, subject, and type.

Parameters
  • game
    A franchise code.
  • subject
  • type
  • [options]
    [size]
    Image size in pixels.
    [scale]
    Image scaling factor — the original image size is multitplied by scale. If both scale and size are present, the value which results in the smaller image will be used. By default this uses an expensive parser function.
    [scaleUsingCargo]
    If set to true, then a Cargo query is used to determine the original image size for the scale option above. You can use this to avoid hitting expensive parser function limit. This option has an additional performance cost of roughly 2-5 milliseconds per image.
    [link]
    Name of a page on the wiki or an external URL for the image thumbnail to link to.
    [caption]
    Alt text for the image.
Returns
  • A string of wikitext that renders a thumbnail.
  • A boolean — true if the image exists, false otherwise.
Examples
InputOutputResultStatus
gameImage(
  "TWW",
  "Great Fairy Figurine",
  "Model",
  {
    size = "100px",
    link = "Great Fairy",
  }
)
"[[File:TWW Great Fairy Figurine Model.png|100px|link=Great Fairy|TWW Great Fairy Figurine Model.png]]"
TWW Great Fairy Figurine Model.png
Green check.svg
true
Green check.svg

icon

icon(game, subject, [options])

Parameters
  • game
    A franchise code.
  • subject
  • [options]
    [size]
    Image size in pixels.
    [scale]
    Image scaling factor — the original image size is multitplied by scale. If both scale and size are present, the value which results in the smaller image will be used. By default this uses an expensive parser function.
    [scaleUsingCargo]
    If set to true, then a Cargo query is used to determine the original image size for the scale option above. You can use this to avoid hitting expensive parser function limit. This option has an additional performance cost of roughly 2-5 milliseconds per image.
    [link]
    Name of a page on the wiki or an external URL for the image thumbnail to link to.
    [caption]
    Alt text for the image.
Returns
  • An icon thumbnail for the subject in the given game.
Examples
InputOutputResultStatus
icon("LANS", "Pineapple")
"[[File:LANS Pineapple Icon.png|LANS Pineapple Icon.png]]"
LANS Pineapple Icon.png
Green check.svg
icon("LADX", "Pineapple")
"[[File:LADX Pineapple Sprite.png|LADX Pineapple Sprite.png]]"
LADX Pineapple Sprite.png
Green check.svg

logo(code, options)

Parameters
Returns
  • Given a valid franchise code, returns a logo thumbnail.
  • A boolean indicating whether a logo exists for the game yet.
Examples
InputOutputResultStatus
logo("LANS", { size = "200px" })
"[[File:LANS English Logo.png|200px|LANS English Logo.png]]"
LANS English Logo.png
Green check.svg
true
Green check.svg
logo("SSB4", { size = "200px" })
"[[File:SSB4 Logo.png|200px|SSB4 Logo.png]]"
SSB4 Logo.png
Green check.svg
true
Green check.svg
logo("SS (Himekawa)", { size = "200px" })
"[[File:Viz Media Logo.svg|200px|Viz Media Logo.svg]]"
Viz Media Logo.svg
Green check.svg
true
Green check.svg
logo("TLoZ (Mishouzaki)", { size = "200px" })
"[[File:TLoZ (Mishouzaki) Manga Cover Artwork.png|200px|TLoZ (Mishouzaki) Manga Cover Artwork.png]]"
TLoZ (Mishouzaki) Manga Cover Artwork.png
Green check.svg
true
Green check.svg
logo("TAoL (Mishouzaki)", { size = "200px" })
"[[File:No Image Upload.png|200px|link=https://zelda.gamepedia.com/Special:Upload?wpDestFile=TAoL+%28Mishouzaki%29+Manga+Cover+Artwork.png|File:No Image Upload.png]]"
File:No Image Upload.png
Green check.svg
false
Green check.svg
logo("E", { size = "200px" })
"[[File:The Legend of Zelda Encyclopedia Cover.png|200px|The Legend of Zelda Encyclopedia Cover.png]]"
The Legend of Zelda Encyclopedia Cover.png
Green check.svg
true
Green check.svg
logo("TMoL", { size = "200px" })
"[[File:Misadventures Link logo2.png|200px|Misadventures Link logo2.png]]"
Misadventures Link logo2.png
Green check.svg
true
Green check.svg

local p = {}
local h = {}

local Franchise = require("Module:Franchise")
local Term = require("Module:Term")
local utilsArg = require("Module:UtilsArg")  
local utilsCargo = require("Module:UtilsCargo")
local utilsLayout = require("Module:UtilsLayout")
local utilsMarkup = require("Module:UtilsMarkup")
local utilsPage = require("Module:UtilsPage")
local utilsString = require("Module:UtilsString")
local utilsTable = require("Module:UtilsTable")

local data = mw.loadData("Module:File/Data")
local CARGO_TABLE = "Files" 

-- Template:FileInfo
function p.StoreWidth(frame)
	return mw.title.getCurrentTitle().file.width
end
function p.StoreHeight(frame)
	return mw.title.getCurrentTitle().file.height
end
function p.FileInfo(frame)
	local args, err = utilsArg.parse(frame:getParent().args, p.Templates.FileInfo)
	local result = p.printFileInfo(args)
	if err then
		return result .. utilsMarkup.categories(err.categories)
	else
		return result
	end
end
function p.printFileInfo(args)
	return h.printFileInfoTable(args) .. h.categories(args.type, args.game, args.subject)
end
function h.printFileInfoTable(args)
	local gameDisplay
	if args.game then
		local gameLogo = Franchise.logo(args.game)
		local gameImage = gameLogo and utilsPage.exists(gameLogo) and utilsMarkup.file(gameLogo, { size = "130x130px" })
		local gameLink = Franchise.link(args.game)
		local gameText = gameLink and string.format("This is a file pertaining to %s.", gameLink)
		if gameImage and gameText then
			gameDisplay = gameImage .. " " .. gameText
		elseif gameText then
			gameDisplay = gameText
		else
			gameDisplay = ""
		end
	end
	
	local type = args.type and data.typesByKey[args.type]
	type = type and type.cat

	local license
	if args.licensing and utilsTable.includes(data.licenses, args.licensing) then
		license = mw.getCurrentFrame():expandTemplate({
			title = "FileInfo/" .. args.licensing,
			args = {
				trademark = args.trademark
			}
		})
	else
		license = mw.getCurrentFrame():expandTemplate({ title = "FileInfo/Unsure" })
	end

	local html = mw.html.create("table"):addClass("wikitable fileinfo")
	h.row(html, "Summary", args.summary)
	h.row(html, "Type", type)
	h.row(html, "Source", args.source)
	h.row(html, "Game", gameDisplay)
	h.row(html, "Licensing", license, {
		rowspan = args.trademark and "2" or "1" 
	})
	h.row(html, "Trademark", args.trademark and mw.getCurrentFrame():expandTemplate({ title = "FileInfo/Trademark" }))
	
	return tostring(html)
end
function h.row(html, field, value, attributes)
	if value then
		return html
			:tag("tr")
			:tag("th")
				:wikitext(field)
				:done()
			:tag("td")
				:wikitext(value)
				:done()
			:done()
	end
end
function h.categories(type, game, subjects)
	local gameName = game and Franchise.shortName(game)
	local typeCat = type and data.typesByKey[type] and data.typesByKey[type].cat
	
	local categories = {}
	if typeCat and not typeCat.nogame and gameName and game ~= "Series" then
		table.insert(categories, gameName .. " " .. typeCat)
	elseif typeCat then
		table.insert(categories, typeCat)
	elseif gameCat then
		table.insert(categories, gameName .. " Files")
	end
	if subjects then
		categories = utilsTable.concat(categories, h.subjectCategories(subjects, game))
	end
	if type == "sprite" and utilsString.endsWith(mw.title.getCurrentTitle().text, ".gif") then
		table.insert(categories, "GIF Sprites")
	end
	if not game then -- not necessarily invalid but worth tracking
		table.insert(categories, "Files without Game")
	end
	
	return utilsMarkup.categories(categories)
end
function h.subjectCategories(subjects, game)
	local categories = utilsTable.flatMap(subjects, function(subject)
		local term, err = Term.fetchTerm(subject, game)
		if not term then
			return err.categories -- add term-related maintenance categories, if any
		end
		term = string.gsub(term, "#", "") -- strip # from term because categories can't have them in their name
		local category = "Images of "..term
		 -- only add subject-based categories if they already exist, to avoid spamming Special:WantedCategories
		if utilsPage.exists("Category:" .. category) then
			return {category}
		else
			return {}
		end
	end)
	return categories
end

-- Module:File/Data
function p.Data(frame)
	local result = ""
	
	result = result .. utilsMarkup.heading(2, "Types")
	result = result .. utilsLayout.table({
		sortable = true,
		headers = {"Type", "Category"},
		rows = utilsTable.map(data.types, function(type)
			local key = utilsMarkup.code(type.key)
			local cat = "[[:Category:"..type.cat.."]]"
			return {key, cat}
		end)
	})
	
	result = result .. utilsMarkup.heading(2, "Licenses")
	result = result .. utilsLayout.table({
		sortable = true,
		headers = {"License", "Template", "Output"},
		rows = utilsTable.map(data.licenses, function(license)
			local template = "FileInfo/"..license
			local templateLink = "[[Template:"..template.."]]"
			local templateOutput = mw.getCurrentFrame():expandTemplate({title = template})
			return {utilsMarkup.code(license), templateLink, templateOutput} 
		end)
	})

	return result
end

-- Queries Cargo for the 100 most-used subjects, uses DPL to determine which ones don't exist as categories yet.
-- Repeat for the next 100 subjects, and so on until there are ~100 table rows or no more subjects to process.
function p.WantedSubjectCategories(frame)
	local BATCH_SIZE = 100
	local MAX_ROWS = 100
	local offset = 0
	local rows = {}
	local cargoResults
	repeat 
		cargoResults = utilsCargo.query(CARGO_TABLE.."__subject", "_value=subject, COUNT(*)=count", {
			groupBy = "_value",
			orderBy = "COUNT(*) DESC",
			limit = BATCH_SIZE,
			offset = offset
		})
		offset = offset + BATCH_SIZE
	
		local dplArgs = utilsTable.map(cargoResults, function(result)
			return {
				param = "titlematch",
				value = "Images of "..result.subject
			}
		end)
		dplArgs.namespace = "Category"
		local existingCats = utilsTable.invert(utilsPage.dpl(dplArgs))
		
		for _, result in ipairs(cargoResults) do
			local cat = "Category:Images of "..result.subject
			if not existingCats[cat] then
				table.insert(rows, { utilsMarkup.link(cat), result.count})
			end
		end
	until #rows >= MAX_ROWS or #cargoResults == 0
	return utilsLayout.table({
		sortable = true,
		headers = {"Category", "Count"},
		rows = rows
	})
end

-- Various templates
function p.Icon(frame)
	local args = frame.args
	local img = p.icon(args[1], args[2], {
		size = args.size
	})
	return img
end

-- Utilities
function p.image(filename, options)
	filename = utilsPage.stripNamespace(filename)
	options = options or {}
	local sizeWidth, sizeHeight = p.dimensions(options.size)
	
	-- in case the file is a redirect
	local redirectTarget = mw.title.new("File:"..filename).redirectTarget
	redirectTarget = redirectTarget and redirectTarget.text
	local originalFilename = filename
	if redirectTarget then
		filename = redirectTarget
	end
	
	if not utilsPage.exists("File:" .. filename, true) then
		return h.noimage(filename, sizeWidth, sizeHeight, options), false
	end
	
	if options.scale then
		local file
		if options.scaleUsingCargo then
			results = utilsCargo.query(CARGO_TABLE, "width, height", {
				where = utilsCargo.allOf({
					["_pageName"] = "File:"..filename,
				}),
				limit = 1,
			})
			file = results[1]
		end
		if not file or utilsString.isEmpty(file.width) or utilsString.isEmpty(file.height) then -- if scaleUsingCargo = false or data does not return from Cargo query for some reason, then use the title object (an expensive parser function)
			file = mw.title.new("File:"..filename).file
		end

		local width = math.floor(tonumber(file.width) * options.scale)
		local height = math.floor(tonumber(file.height) * options.scale)
		if (sizeWidth and sizeWidth < width) or (sizeHeight and sizeHeight < height) then
			width = sizeWidth
			height = sizeHeight
		end
		size = ""
		if width then
			size = width
		end
		if height then
			size = size .. "x" .. height
		end
		size = size .. "px"
		options = utilsTable.merge({}, options, {
			size = size
		})
	end
	return utilsMarkup.file(originalFilename, options), true
end
function p.dimensions(size)
	if not size then
		return nil
	end
	local s, e
	s, e = size:find("^[0-9]+")
	local width = s and size:sub(s, e) or ""
	
	s, e = size:find("x[0-9]+")
	local height = s and size:sub(s+1, e) or ""
	
	return tonumber(width), tonumber(height)
end
function h.noimage(filename, sizeWidth, sizeHeight, options)
	local uploadUrl = mw.uri.fullUrl("Special:Upload")
	uploadUrl:extend({
		wpDestFile = filename
	})
	local options = utilsTable.merge({}, options, {
		link = tostring(uploadUrl)
	})
	-- Make sure thumbnail for 'no image' is no less than 100x100px
	if (sizeWidth and sizeWidth < 100) or (sizeHeight and sizeHeight < 100) then
		options.size = "100px"
	end
	return utilsMarkup.file("File:No Image Upload.png", options)
end

function p.gameImage(game, subject, type, options)
	local parts = utilsTable._filter(utilsString.notEmpty)({game, subject, type})
	local filename = table.concat(parts, " ") .. ".png"
	return p.image(filename, options)
end

function p.icon(game, subject, options)
	local type = "Icon"
	if Franchise.graphics(game) == "2D" then
		type = "Sprite"
	end
	return p.gameImage(game, subject, type, options)
end

function p.logo(code, options)
	local filename = Franchise.logo(code)
	return p.image(filename, options)
end

p.Templates = {
	FileInfo = {
		purpose = "Displays, categorizes, and stores file information. See [[Guidelines:Files]] for further guidance.",
		format = "block",
		paramOrder = {"summary", "subject", "type", "source", "game", "licensing", "trademark"},
		params = {
			summary = {
				--required = true,
				type = "content",
				desc = "A short description of the file.",
				trim = true,
				nilIfEmpty = true,
			},
			type = {
				required = "Category:Files Lacking Type",
				type = "string",
				desc = "The type of file, which determines how it is [[:Category:Files by Type|categorized]].",
				enum = data.typesEnum,
				trim = true,
				nilIfEmpty = true,
			},
			source = {
				required = "Category:Files Lacking Sources",
				type = "string",
				desc = "The original source of the file. It may be in the form of a URL or author recognition. [[Template:Source]] exists for this purpose.",
				trim = true,
				nilIfEmpty = true,
			},
			subject = {
				type = "string",
				desc = "Wiki article names of all the subjects depicted in the file. A comma-separated list.",
				split = true,
				trim = true,
				nilIfEmpty = true,
			},
			game = {
				--required = true,
				type = "string",
				desc = "A valid [[Data:Franchise|code]] for a game, book, comic, manga, or TV show (or <code>Series</code>).",
				enum = Franchise.enum({ 
					includeSeries = true,
					includeGroups = true,
				}),
				trim = true,
				nilIfEmpty = true,
			},
			licensing = {
				required = "Category:Unlicensed Files",
				type = "string",
				desc = "The copyright licensing for the file. For the vast majority of files, <code>Copyright</code> is the correct value here.",
				enum = data.licenses,
				trim = true,
				nilIfEmpty = true,
			},
			trademark = {
				type = "boolean",
				desc = "Enter any text to add a trademark notice to the licensing. Use on all [[:Category:Trademarks|trademarks]] (usually denoted by an ® or ™ symbol).",
				trim = true,
				nilIfEmpty = true,
			}
		},
		examples = {
			vertical = true,
			{
				summary = "{{Term|LADX|Animal Village|link}}",
				subject = "Animal Village, Rabbit",
				type = "map",
				source = "{{Source|Original|MannedTooth}}",
				game = "LADX",
				licensing = "Copyright",
			},
			{
				summary = "The [[Timeline]]",
				source = "{{Cite Book|book= E |page= 10}}",
				type = "print",
				game = "Series",
				licensing = "Copyright"
			},
			{
				summary = "Nintendo's current logo.",
				type = "logo",
				source = "",
				licensing = "PD-Simple",
				trademark = "yes",
			},
			{
				summary = "File missing required info"
			},
		},
	}
}

local optionsSchema =  {
	type = "record",
	properties = {
		{
			name = "size",
			type = "string",
			desc = "Image size in pixels.",
		},
		{
			name = "scale",
			type = "number",
			desc = "Image scaling factor — the original image size is multitplied by <code>scale</code>. If both <code>scale</code> and <code>size</code> are present, the value which results in the smaller image will be used. <b>By default this uses an {{Mediawiki|Manual:$wgExpensiveParserFunctionLimit|expensive parser function}}</b>.",
		},
		{
			name = "scaleUsingCargo",
			type = "boolean",
			desc = "If set to true, then a Cargo query is used to determine the original image size for the <code>scale</code> option above. You can use this to avoid hitting expensive parser function limit. This option has an additional performance cost of roughly 2-5 milliseconds per image.",
		},
		{
			name = "link",
			type = "string",
			desc = "Name of a page on the wiki or an external URL for the image thumbnail to link to.",
		},
		{
			name = "caption",
			type = "string",
			desc = "[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img Alt text] for the image.",
		},
	}
}
local franchiseCode = {
	required = true,
	type = "string",
	desc = "A [[Data:Franchise|franchise code]]."
}

p.Schemas = {
	image = {
		filename = {
			required = true,
			type = "string",
			desc = "Filename of the image, with or without the namespace prefix.",
		},
		options = optionsSchema,
	},
	gameImage = {
		game = franchiseCode,
		subject = {
			type = "string",
			required = true,
		},
		type = {
			type = "string",
			required = true,
			enum = {"", "Artwork", "Icon", "Model", "Render", "Screenshot", "Sprite", "Texture"},
		},
		options = optionsSchema,
	},
	icon = {
		game = franchiseCode,
		subject = {
			type = "string",
			required = true,
		},
		options = optionsSchema,
	},
	logo = {
		code = franchiseCode,
		optons = optionsSchema,
	},
}

p.Documentation = {
	image = {
		desc = "A higher-level version of [[Module:UtilsMarkup#file|utilsMarkup.file]] with awareness of whether the file exists or not.",
		params = {"filename", "options"},
		returns = {
			"Wikitext rendering an image thumbnail.",
			"A boolean — true if the image exists, false otherwise.",
		},
		cases = {
			{
				args = {"File:TWW Great Fairy Figurine Model.png", { 
					link = "Great Fairy", 
					size = "100px"
				}},
				expect = {"[[File:TWW Great Fairy Figurine Model.png|100px|link=Great Fairy|TWW Great Fairy Figurine Model.png]]", true}
			},
			{
				desc = "If file does not exist, show 'click to upload' thumbnail which links to [[Special:Upload]].",
				args = {"File:TWWHD Great Fairy Figurine Model.png", {
					link = "Great Fairy", 
					size = "150px",
				}},
				expect = {"[[File:No Image Upload.png|150px|link=https://zelda.gamepedia.com/Special:Upload?wpDestFile=TWWHD+Great+Fairy+Figurine+Model.png|File:No Image Upload.png]]", false}
			},
			{
				desc = "'No image' thumbnail has minimum 100px width, because it is illegible at smaller sizes.",
				args = {"File:TWWHD Great Fairy Figurine Model.png", {
					size = "64px",
				}},
				expect = {"[[File:No Image Upload.png|100px|link=https://zelda.gamepedia.com/Special:Upload?wpDestFile=TWWHD+Great+Fairy+Figurine+Model.png|File:No Image Upload.png]]", false},
			},
			{
				desc = "Scaling factor.",
				args = {"File:TMC Vaati Sprite.png", { scale = 2 }},
				expect = {"[[File:TMC Vaati Sprite.png|48x56px|TMC Vaati Sprite.png]]", true}
			},
			{
				args = {"File:TMC Vaati Sprite.png", { scale = 2, scaleUsingCargo = true }},
				expect = {"[[File:TMC Vaati Sprite.png|48x56px|TMC Vaati Sprite.png]]", true},
			},
			{
				desc = "If both <code>scale</code> and <code>size</code> are specified, the one resulting in the smaller image is used.",
				args = {"File:TMC Vaati Sprite.png", { scale = 2, size = "80px" }},
				expect = {"[[File:TMC Vaati Sprite.png|48x56px|TMC Vaati Sprite.png]]", true},
			},
			{
				args = {"File:TMC Vaati Sprite.png", { scale = 10, size = "80px" }},
				expect = {"[[File:TMC Vaati Sprite.png|80px|TMC Vaati Sprite.png]]", true},
			},
		},
	},
	gameImage = {
		desc = "A specialized version of [[Module:File#image|image]] that infers the filename from game, subject, and type.",
		params = {"game", "subject", "type", "options"},
		returns = {
			"A <code>string</code> of wikitext that renders a thumbnail.",
			"A boolean — true if the image exists, false otherwise.",
		},
		cases = {
			{
				args = {"TWW", "Great Fairy Figurine", "Model", { 
					link = "Great Fairy", 
					size = "100px"
				}},
				expect = {"[[File:TWW Great Fairy Figurine Model.png|100px|link=Great Fairy|TWW Great Fairy Figurine Model.png]]", true}
			},
		}
	},
	icon = {
		params = {"game", "subject", "options"},
		returns = "An icon thumbnail for the subject in the given game.",
		cases = {
			{
				args = {"LANS", "Pineapple"},
				expect = "[[File:LANS Pineapple Icon.png|LANS Pineapple Icon.png]]"
			},
			{
				args = {"LADX", "Pineapple"},
				expect = "[[File:LADX Pineapple Sprite.png|LADX Pineapple Sprite.png]]"
			},
		}
	},
	logo = {
		params = {"code", "options"},
		returns = {
			"Given a valid [[Data:Franchise|franchise code]], returns a logo thumbnail.",
			"A boolean indicating whether a logo exists for the game yet.",
		},
		cases = {
			{
				args = {"LANS", { size = "200px" }},
				expect = {"[[File:LANS English Logo.png|200px|LANS English Logo.png]]", true}
			},
			{
				args = {"SSB4", { size = "200px" }},
				expect = {"[[File:SSB4 Logo.png|200px|SSB4 Logo.png]]", true},
			},
			{
				args = {"SS (Himekawa)", { size = "200px" }},
				expect = {"[[File:Viz Media Logo.svg|200px|Viz Media Logo.svg]]", true}
			},
			{
				args = {"TLoZ (Mishouzaki)", { size = "200px" }},
				expect = {"[[File:TLoZ (Mishouzaki) Manga Cover Artwork.png|200px|TLoZ (Mishouzaki) Manga Cover Artwork.png]]", true},
			},
			{
				args = {"TAoL (Mishouzaki)", { size = "200px" }},
				expect = {"[[File:No Image Upload.png|200px|link=https://zelda.gamepedia.com/Special:Upload?wpDestFile=TAoL+%28Mishouzaki%29+Manga+Cover+Artwork.png|File:No Image Upload.png]]", false},
			},
			{
				args = {"E", { size = "200px" }},
				expect = {"[[File:The Legend of Zelda Encyclopedia Cover.png|200px|The Legend of Zelda Encyclopedia Cover.png]]", true},
			},
			{
				args = {"TMoL", { size = "200px" }},
				expect = {"[[File:Misadventures Link logo2.png|200px|Misadventures Link logo2.png]]", true},
			},
		}
	}
}

return p