FANDOM


--[[
* Modulo per implementare le funzionalità del template Bio.
]]
 
require("Module:No globals")
 
-- Variabili globali
local args            -- argomenti passati al template
local cfg             -- configurazione
local textTable = {}  -- table per contenere la risposta da ritornare
local SPACE = " " -- HTML Entity Code per lo spazio
local attivitaParams = { "Attività", "Attività2", "Attività3" }
local nazionalitaParams = { "Nazionalità", "NazionalitàNaturalizzato", "Cittadinanza" }
 
-------------------------------------------------------------------------------
--                           Funzioni di utilità
-------------------------------------------------------------------------------
 
-- Aggiunge testo alla risposta, svolge anche la funzione di concatenatore
local function dumpText(...)
	local arg = {...}
 
	for _, val in ipairs(arg) do
		table.insert(textTable, val)
	end
end
 
-- Aggiunge una categoria alla risposta
local function dumpCategory(category)
	if mw.title.getCurrentTitle().namespace == 0 then
		dumpText("[[Categoria:", category, "]]", "\n")
	end
end
 
-- Aggiunge un wlink alla risposta, se target è nil utilizza label come target.
-- labelPrefix, se presente, viene rimosso dalla label e anteposto al wlink.
local function dumpWlink(target, label, labelPrefix)
	if target and label and labelPrefix then
		local count
		label, count = label:gsub("^" .. labelPrefix .. " ", "")
		if count == 1 then
			dumpText(labelPrefix, SPACE)
		end
	end
 
	if target and label then
	   dumpText("[[", target, "|", label, "]]")
	else
	   dumpText("[[", target or label, "]]")
	end
end
 
-- Aggiunge una immagine alla risposta, size e caption sono opzionali
local function dumpImage(name, size, caption)
	dumpText("[[File:", name, "|thumb")
 
	if size then
		dumpText("|", size, "px")
	end
	if caption then
		dumpText("|", caption)
	end
 
	dumpText("]]", "\n")
end
 
-- Aggiunge l'output del [[Template:Avviso]] e una categoria di warning alla risposta
local function dumpAvviso(tipo, immagine, immagine_a_destra, testo, category)
	local text
 
	text = mw.getCurrentFrame():expandTemplate {
		title = "Avviso",
		args = {
			["tipo"] = tipo,
			["immagine"] = immagine,
			["immagine a destra"] = immagine_a_destra,
			["testo"] = testo
		}
	}
 
	dumpText(text)
	if category then
		dumpCategory(cfg.categorie[category])
	end
end
 
-- Wrapper di mw.title.exists, verifica sia che name sia valido, sia che esista
local function titleExists(name)
	local title = mw.title.new(name)
 
	return title and title.exists
end
 
-- Se date inizia con "1 " o "1°" ritorna una nuova data che inizia per "1º", altrimenti date
local function fixFirstOfMonth(date)
	date = date:gsub("^1%s", "1º ")
	date = date:gsub("^1\194\176", "1º")
 
	return date
end
 
-- Ritorna "ed" se nextWord inizia con "e", altrimenti "e"
local function getEufonica(nextWord)
	return nextWord:sub(1, 1) == "e" and "ed" or "e"
end
 
-- Parsifica un TimeValue di Wikidata e ne ritorna "giornomese, anno"
local function parseWikidataTimeValue(property)
	local entity, value, year, month, day, daymonth
 
	entity = mw.wikibase.getEntityObject()
	if entity and entity.claims and
	   entity.claims[property] and #entity.claims[property] > 0 and
	   entity.claims[property][1].mainsnak.snaktype == "value" then
		value = entity.claims[property][1].mainsnak.datavalue.value
		year, month, day = value.time:match(".+(%d%d%d%d%d)%-(%d%d)%-(%d%d).+")
		if value.precision == 11 then
			month = mw.getLanguage("it"):formatDate("F", tonumber(year) .. "-" .. month .. "-" .. day)
			daymonth = tonumber(day) .. " " .. month
		end
		if value.precision == 9 or value.precision == 11 then
			year = tonumber(year) .. (value.time:sub(1, 1) == "-" and " a.C." or "")
		end
	end
 
	return daymonth, year
end
 
-------------------------------------------------------------------------------
--                           Parsing parametri
-------------------------------------------------------------------------------
 
-- Utilizzata da parseParams per controllare il valore di un parametro.
-- Ritorna true se il valore è valido altrimenti false.
local function checkParamValue(value, valueTest, otherArgs)
	local ret = true
 
	if type(valueTest) == "function" then
		ret = valueTest(value, otherArgs)
	elseif type(valueTest) == "string" and not value:match(valueTest) then
		ret = false
	end
 
	return ret
end
 
-- Parsifica i parametri passati al modulo e aggiunge eventuali categorie di errore.
-- Ritorna i parametri conosciuti scartando quelli valorizzati a stringa vuota.
local function parseParams(origArgs)
	local paramcfg = require("Modulo:Bio/Parametri")
	local retArgs = {}
 
	-- controlla i parametri conosciuti e li copia
	for k, v in pairs(origArgs) do
		if paramcfg.params[k] then
			if v ~= "" then
				retArgs[k] = v
			end
		else
			dumpAvviso(cfg.warningParams.tipo,
					   cfg.warningParams.immagine,
					   cfg.warningParams.immagine_a_destra,
					   cfg.warningParams.testo:gsub("$1", "il parametro '" ..
							(tonumber(k) and (v == "" and " " or v) or k ) .. "' è sconosciuto"), "unknown-params")
		end
	end
 
	-- controlla il valore
	for i, validator in pairs(paramcfg.validators) do
		if retArgs[validator.param] then
			if not checkParamValue(retArgs[validator.param], validator.valuetest, retArgs) then
				if validator.errmsg then
					dumpAvviso(cfg.warningParams.tipo,
							   cfg.warningParams.immagine,
							   cfg.warningParams.immagine_a_destra,
							   cfg.warningParams.testo:gsub("$1", validator.errmsg), nil)
				end
				dumpCategory(cfg.categorie["wrong-params"])
			end
		end
	end
 
	return retArgs
end
 
-- Cerca alcuni parametri se mancanti su Wikidata
local function checkWikidata()
	local daymonth, year
	-- GiornoMeseNascita e AnnoNascita
	if not args["GiornoMeseNascita"] or not args["AnnoNascita"] then
		daymonth, year = parseWikidataTimeValue("P569")
		args["GiornoMeseNascita"] = args["GiornoMeseNascita"] or daymonth
		args["AnnoNascita"] = args["AnnoNascita"] or year
	end
	-- GiornoMeseMorte e AnnoMorte
	if not args["GiornoMeseMorte"] or not args["AnnoMorte"] then
		daymonth, year = parseWikidataTimeValue("P570")
		args["GiornoMeseMorte"] = args["GiornoMeseMorte"] or daymonth
		args["AnnoMorte"] = args["AnnoMorte"] or year
	end
end
 
-------------------------------------------------------------------------------
--                           classe Categories
-------------------------------------------------------------------------------
 
local Categories = {}
 
function Categories:new()
	local self = {}
	local sortkey, plurals
	setmetatable(self, { __index = Categories,
						 __tostring = function(t) return self:_tostring() end })
	textTable = {}
	self.plurale_attivita = nil
	self.plurale_nazionalita = nil
	-- al di fuori del namespace 0 esegue comunque il controllo di attività e nazionalità
	plurals = self:_getPluralsAttivitaNazionalita()
 
	if mw.title.getCurrentTitle().namespace == 0 then
		-- imposta la magic word defaultsort
		if args["ForzaOrdinamento"] then
			sortkey = args["ForzaOrdinamento"]
		elseif args["Cognome"] and args["Nome"] then
			sortkey = args["Cognome"] .. " ," .. args["Nome"]
		end
		if sortkey then
			mw.getCurrentFrame():preprocess("{{DEFAULTSORT:" .. sortkey .. "}}")
		end
		-- Categorie impostato a "no" disabilita la categorizzazione per attività
		if args["Categorie"] ~= "no" then
			self:_addAttivitaCategories(plurals)
		end
		self:_addNatiMortiCategories()
		dumpCategory(cfg.categorie["bot"])
		-- Categoria temporanea, vedi richiesta:
		-- Speciale:LinkPermanente/66620402#Add_this_text_to_Template:Bio
		if args["Nazionalità"] then
			local entity = mw.wikibase.getEntityObject()
			if not entity or (entity.claims and not entity.claims["P27"]) then
				dumpCategory("Voci con template Bio e nazionalità assente su Wikidata")
			end
		end
	end
 
	return self
end
 
function Categories:_tostring()
	return table.concat(textTable)
end
 
-- Ritorna il plurale dell'attività o nil se non trovato (con eventuale warning)
function Categories:_getPluralAttivita(attivita, warning)
	local plural
 
	self.plurale_attivita = self.plurale_attivita or mw.loadData("Modulo:Bio/Plurale attività")
	plural = self.plurale_attivita[attivita]
	if not plural and warning then
		dumpAvviso(cfg.warningA.tipo, cfg.warningA.immagine, cfg.warningA.immagine_a_destra,
				   cfg.warningA.testo .. cfg.warningA.testo2a:gsub("$1", attivita) .. cfg.warningA.testo3, "warning")
	end
 
	return plural
end
 
-- Ritorna il plurale della nazionalità o nil se non trovato (con eventuale warning)
function Categories:_getPluralNazionalita(nazionalita, warning)
	local plural
 
	self.plurale_nazionalita = self.plurale_nazionalita or mw.loadData("Modulo:Bio/Plurale nazionalità")
	plural = self.plurale_nazionalita[nazionalita]
	if not plural and warning then
		dumpAvviso(cfg.warningN.tipo, cfg.warningN.immagine, cfg.warningN.immagine_a_destra,
				   cfg.warningN.testo .. cfg.warningN.testo2a:gsub("$1", nazionalita) .. cfg.warningN.testo3, "warning")
	end
 
	return plural
end
 
-- Ritorna il plurale dei parametri necessari per le categorie
function Categories:_getPluralsAttivitaNazionalita()
	local plurals = {}
 
	-- Nazionalità può essere vuota solo quando c'è Categorie=no e FineIncipit
	if not args["Nazionalità"] and not (args["Categorie"] == "no" and args["FineIncipit"]) then
		dumpAvviso(cfg.warningN.tipo, cfg.warningN.immagine, cfg.warningN.immagine_a_destra,
				   cfg.warningN.testo .. cfg.warningN.testo2b .. cfg.warningN.testo3, "warning")
	end
	-- Nazionalità può essere sbagliata solo quando c'è Categorie=no e manca FineIncipit
	if not (args["Categorie"] == "no" and not args["FineIncipit"]) then
		for _, nazionalita in ipairs(nazionalitaParams) do
			if args[nazionalita] then
				plurals[nazionalita] = self:_getPluralNazionalita(args[nazionalita], true)
			end
		end
	end
	-- Attività può essere vuota solo quando c'è Categorie=no e FineIncipit
	if not args["Attività"] and not (args["Categorie"] == "no" and args["FineIncipit"]) then
		dumpAvviso(cfg.warningA.tipo, cfg.warningA.immagine, cfg.warningA.immagine_a_destra,
				   cfg.warningA.testo .. cfg.warningA.testo2b .. cfg.warningA.testo3, "warning")
	end
	-- Attività può essere sbagliata solo quando c'è Categorie=no e manca FineIncipit
	if not (args["Categorie"] == "no" and not args["FineIncipit"]) then
		for _, attivita in ipairs(attivitaParams) do
			if args[attivita] then
				plurals[attivita] = self:_getPluralAttivita(args[attivita], true)
			end
		end
	end
 
	return plurals
end
 
-- Aggiunge le categorie: Attività nazionalità [del XYZ secolo]
function Categories:_addAttivitaCategories(plurals)
	local catname, epoca1, epoca2, added
 
	epoca1 = args["Epoca"] and cfg.epoche[args["Epoca"]]
	epoca2 = args["Epoca2"] and cfg.epoche[args["Epoca2"]]
	for _, attivita in ipairs(attivitaParams) do
		if plurals[attivita] then
			for _, nazionalita in ipairs(nazionalitaParams) do
				if plurals[nazionalita] then
					added = false
					catname = plurals[attivita] .. " " .. plurals[nazionalita]
					for _, epoca in ipairs({ epoca1, epoca2 }) do
						if epoca and titleExists("Categoria:" .. catname .. " " .. epoca) then
							dumpCategory(catname .. " " .. epoca)
							added = true
						end
					end
					-- se non è stata aggiunta la categoria per epoca1 e epoca2
					-- aggiunge la cat. semplice, e.g. "Scrittori italiani"
					if not added then
						dumpCategory(catname)
					end
				end
			end
		end
	end
end
 
-- Aggiunge le categorie: Nati/Morti nell'anno/giorno/luogo
function Categories:_addNatiMortiCategories()
	local cat1, cat2
 
	if args["AnnoNascita"] then
		cat1 = "Nati nel " .. args["AnnoNascita"]
		cat2 = "Nati nell'" .. args["AnnoNascita"]
		if titleExists("Categoria:" .. cat1) then
			dumpCategory(cat1)
		elseif titleExists("Categoria:" .. cat2) then
			dumpCategory(cat2)
		end
	end
 
	if args["AnnoMorte"] then
		if args["AnnoMorte"] == "?" then
			dumpCategory(cfg.categorie["annomorte-punto-interrogativo"])
		else
			cat1 = "Morti nel " .. args["AnnoMorte"]
			cat2 = "Morti nell'" .. args["AnnoMorte"]	
			if titleExists("Categoria:" .. cat1) then
				dumpCategory(cat1)
			elseif titleExists("Categoria:" .. cat2) then
				dumpCategory(cat2)
			end
		end
	else
		dumpCategory("Persone viventi")
	end
 
	if args["GiornoMeseNascita"] then
		cat1 = "Nati il " .. fixFirstOfMonth(args["GiornoMeseNascita"])
		cat2 = "Nati l'" .. args["GiornoMeseNascita"]
		if titleExists("Categoria:" .. cat1) then
			dumpCategory(cat1)
		elseif titleExists("Categoria:" .. cat2) then
			dumpCategory(cat2)
		end			   
	end
 
	if args["GiornoMeseMorte"] then
		cat1 = "Morti il " .. fixFirstOfMonth(args["GiornoMeseMorte"])
		cat2 = "Morti l'" .. args["GiornoMeseMorte"]
		if titleExists("Categoria:" .. cat1) then
			dumpCategory(cat1)
		elseif titleExists("Categoria:" .. cat2) then
			dumpCategory(cat2)
		end			   
	end
 
	if args["LuogoNascitaLink"] then
		cat1 = "Nati a " .. args["LuogoNascitaLink"]
		cat2 = "Nati ad " .. args["LuogoNascitaLink"]
		if titleExists("Categoria:" .. cat1) then
			dumpCategory(cat1)
		elseif titleExists("Categoria:" .. cat2) then
			dumpCategory(cat2)
		end
	elseif args["LuogoNascita"] then
		cat1 = "Nati a " .. args["LuogoNascita"]
		cat2 = "Nati ad " .. args["LuogoNascita"]
		if titleExists("Categoria:" .. cat1) then
			dumpCategory(cat1)
		elseif titleExists("Categoria:" .. cat2) then
			dumpCategory(cat2)
		end
	end
 
	if args["LuogoMorteLink"] then
		cat1 = "Morti a " .. args["LuogoMorteLink"]
		cat2 = "Morti ad " .. args["LuogoMorteLink"]
		if titleExists("Categoria:" .. cat1) then
			dumpCategory(cat1)
		elseif titleExists("Categoria:" .. cat2) then
			dumpCategory(cat2)
		end
	elseif args["LuogoMorte"] then
		cat1 = "Morti a " .. args["LuogoMorte"]
		cat2 = "Morti ad " .. args["LuogoMorte"]
		if titleExists("Categoria:" .. cat1) then
			dumpCategory(cat1)
		elseif titleExists("Categoria:" .. cat2) then
			dumpCategory(cat2)
		end
	end
end
 
-------------------------------------------------------------------------------
--                           classe Incipit
-------------------------------------------------------------------------------
 
local Incipit = {}
 
function Incipit:new()
	local self = {}
 
	setmetatable(self, { __index = Incipit,
						 __tostring = function(t) return self:_tostring() end })
	textTable = {}
	self:_addImmagine()
	self:_addNomeCognome()
	self:_addNascitaMorte()
	if args["PostCognomeVirgola"] then
		dumpText(",")
	end
	if args["FineIncipit"] ~= "," then
		dumpText(SPACE)
	end
	if args["FineIncipit"] then
		dumpText(args["FineIncipit"])
	else
		self:_addAttivita()
	end
	if args["Punto"] ~= "no" then
		dumpText((args["FineIncipit"] == "e" or
				  args["FineIncipit"] == "ed" or 
				  args["FineIncipit"] == ",") and
				  SPACE or ".")
	end
 
	return self
end
 
function Incipit:_tostring()
	return table.concat(textTable)
end
 
-- Ritorna true se text (AttivitàAltre, PostNazionalità e PostCognome) necessita di uno spazio iniziale
function Incipit:_needSpace(text)
	return mw.ustring.match(mw.ustring.sub(text, 1, 1), "%w") ~= nil or
		   text:sub(1, 2) == "[[" or
		   text:sub(1, 1) == "(" or
		   text:sub(1, 1) == "'" or
		   mw.ustring.sub(text, 1, 1) == "–" or
		   text:sub(1, 5) == "<span"
end
 
function Incipit:_getArticleMan(attivita)
	local article
	if cfg.articoli_maschili["uno"][attivita] then
		article = "uno"
	elseif cfg.articoli_maschili["una"][attivita] then
		article = "una"
	else
		article = "un"
	end
	return article
end
 
function Incipit:_getArticleWoman(attivita)
	local article
	-- aggiunge anche uno spazio nel caso non usi l'apostrofo
	if cfg.articoli_femminili["un"][attivita] then
		article = "un" .. SPACE
	elseif attivita and attivita:match("^[aeiou]") then
		article = "un'"
	else
		article = "una" .. SPACE
	end
	return article
end
 
function Incipit:_addImmagine()
	local caption
	if args["Immagine"] then
		if args["Didascalia"] then
			caption = args["Didascalia"]
		else
			if args["Nome"] then
				caption = args["Nome"]
			end
			if args["Cognome"] then
				caption = (caption or "") .. " " .. args["Cognome"]
			end
		end
		if args["Didascalia2"] then
			caption = (caption or "") .. "<hr />" .. args["Didascalia2"]
		end
		dumpImage(args["Immagine"], args["DimImmagine"], caption)
	elseif args["Didascalia2"] then
		-- parentesi () extra per non ritornare anche il gsub.count
		dumpText( (cfg.didascalia2:gsub("$1", args["Didascalia2"])) )
	end
end
 
function Incipit:_addNomeCognome()
	if args["Titolo"] then
		dumpText(args["Titolo"], SPACE)
	end
 
	-- inizio grassetto
	dumpText("'''")
 
	if args["Nome"] then
		dumpText(args["Nome"])
	end
 
	if args["Cognome"] then
		dumpText(SPACE, args["Cognome"])
	end
 
	-- fine grassetto
	dumpText("'''")
 
	if args["PostCognomeVirgola"] then
		dumpText(",", SPACE, args["PostCognomeVirgola"])
	end
 
	if args["PostCognome"] then
		if self:_needSpace(args["PostCognome"]) then
			dumpText(SPACE)
		end
		dumpText(args["PostCognome"])
	end
end
 
function Incipit:_addNascitaMorte()
	-- si apre la parentesi
	dumpText(SPACE, "(")
 
	if args["PreData"] then
		 dumpText(args["PreData"], ";", SPACE)
	end
 
	if args["LuogoNascita"] then
		dumpWlink(args["LuogoNascitaLink"], args["LuogoNascita"])
		if args["LuogoNascitaAlt"] then
			dumpText(SPACE, args["LuogoNascitaAlt"])
		end
		dumpText(",", SPACE)
	end
 
	if args["GiornoMeseNascita"] then
		if titleExists(args["GiornoMeseNascita"]) then
			dumpWlink(args["GiornoMeseNascita"])
		else
			dumpText(args["GiornoMeseNascita"])
		end
		dumpText(SPACE)
	end
 
	if args["AnnoNascita"] then
		if titleExists(args["AnnoNascita"]) then
			dumpWlink(args["AnnoNascita"])
		else
			dumpText(args["AnnoNascita"])
		end
	else
		dumpText("...")
	end
 
	if args["NoteNascita"] then
		dumpText(args["NoteNascita"])
	end
 
	if args["AnnoMorte"] then
		dumpText(SPACE, "–", SPACE)
		if args["LuogoMorte"] then
			dumpWlink(args["LuogoMorteLink"], args["LuogoMorte"])
			if args["LuogoMorteAlt"] then
				dumpText(SPACE, args["LuogoMorteAlt"])
			end
			dumpText(",", SPACE)
		end
 
		if args["GiornoMeseMorte"] then
			if titleExists(args["GiornoMeseMorte"]) then
				dumpWlink(args["GiornoMeseMorte"])
			else
				dumpText(args["GiornoMeseMorte"])
			end
			dumpText(SPACE)
		end
 
		if args["AnnoMorte"] then
			if args["AnnoMorte"] == "?" then
				dumpText("...")
			else
				if titleExists(args["AnnoMorte"]) then
					dumpWlink(args["AnnoMorte"])
				else
					dumpText(args["AnnoMorte"])
				end
			end
		end
	end
 
	if args["NoteMorte"] then
		dumpText(args["NoteMorte"])
	end
 
	-- si chiude la parentesi
	dumpText(")")
end
 
function Incipit:_addAttivita()
	local link_attivita = mw.loadData("Modulo:Bio/Link attività")
	local link_nazionalita = mw.loadData("Modulo:Bio/Link nazionalità")	
 
	if args["PreAttività"] then
		dumpText(args["PreAttività"], SPACE)
	else
		dumpText("è", SPACE)
		if args["AnnoMorte"] then
			dumpText((not args["Sesso"] or args["Sesso"] == "M")
					 and "stato" or "stata", SPACE)
		end
		if not args["Sesso"] or args["Sesso"] == "M" then
			dumpText(self:_getArticleMan(args["Attività"]), SPACE)
		else
			dumpText(self:_getArticleWoman(args["Attività"]))
		end
	end
 
	dumpWlink(link_attivita[args["Attività"]], args["Attività"] or "", "ex")
 
	if args["Attività2"] then
		if args["Attività3"] or args["AttivitàAltre"] then
			dumpText(",")
		else
			dumpText(SPACE, getEufonica(args["Attività2"]))
		end
		dumpText(SPACE)
		dumpWlink(link_attivita[args["Attività2"]], args["Attività2"], "ex")
	end
 
	if args["Attività3"] then
		if args["AttivitàAltre"] then
			dumpText(",")
		else
			dumpText(SPACE, getEufonica(args["Attività3"]))
		end
		dumpText(SPACE)
		dumpWlink(link_attivita[args["Attività3"]], args["Attività3"], "ex")
	end
 
	if args["AttivitàAltre"] then
		if self:_needSpace(args["AttivitàAltre"]) then
			dumpText(SPACE)
		end
		dumpText(args["AttivitàAltre"])
	end
 
	dumpText(SPACE)
	dumpWlink(link_nazionalita[args["Nazionalità"]], args["Nazionalità"] or "")
 
	if args["Cittadinanza"] then
		dumpText(SPACE, "con cittadinanza", SPACE)
		dumpWlink(link_nazionalita[args["Cittadinanza"]], args["Cittadinanza"])
	end
 
	if args["NazionalitàNaturalizzato"] then
		dumpText(SPACE)
		dumpWlink("Naturalizzazione",
				  (not args["Sesso"] or args["Sesso"] == "M" or
				  (args["Sesso"] == "F" and self:_getArticleWoman(args["Attività"]) == "un&#32;")) and
				  "naturalizzato" or "naturalizzata")
		dumpText(SPACE)
		dumpWlink(link_nazionalita[args["NazionalitàNaturalizzato"]], args["NazionalitàNaturalizzato"])
	end
 
	if args["PostNazionalità"] then
		if self:_needSpace(args["PostNazionalità"]) then
			dumpText(SPACE)
		end
		dumpText(args["PostNazionalità"])
	end
end
 
-------------------------------------------------------------------------------
--                                    API
-------------------------------------------------------------------------------
 
local p = {}
 
-- Entry-point per {{Bio}}
function p.bio(frame)
	-- lettura configurazione
	cfg = mw.loadData("Modulo:Bio/Configurazione")
 
	-- parsifica i parametri e aggiunge eventuali messaggi e categorie di errore 
	args = parseParams(frame:getParent().args)
 
	-- cerca alcuni parametri se mancanti su Wikidata
	if cfg.wikidata then
		checkWikidata()
	end
 
	return table.concat(textTable) .. tostring(Categories:new()) .. tostring(Incipit:new())
end
 
return p

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.

Inoltre su FANDOM

Wiki casuale