Jump to content

Module:sk-noun

From Wiktionary, the free dictionary


--[=[
	This module contains functions for creating inflection tables for Slovak
	nouns.
]=]--

local export = {}

-- Within this module, declensions are the functions that do the actual
-- declension by creating the forms of a basic noun.
-- They are defined further down.
--local lemma = "Bratislava"
local declensions = {}
local lang = require("Module:languages").getByCode("sk")
local m_table = require("Module:table")
local m_links = require("Module:links")
local m_adj = require("Module:sk-adjective")

local allowed_genders = {
	"m-pr", "m-anml", "m-in", "f", "n"
}
local allowed_genders_set = m_table.listToSet(allowed_genders)

local hard_consonants = {"d", "t", "n", "l", "h", "ch", "k", "g"}
local soft_consonants = {"ď", "ť", "ň", "ľ", "ž", "š", "č", "dž", "c", "dz", "j"}
local ambiguous_consonants = {"b", "m", "p", "r", "s", "v", "z", "f"}

local hard_consonants_set = m_table.listToSet(hard_consonants)
local soft_consonants_set = m_table.listToSet(soft_consonants)
local ambiguous_consonants_set = m_table.listToSet(ambiguous_consonants)

local consonants = m_table.append(hard_consonants, soft_consonants, ambiguous_consonants)
local consonants_set = m_table.listToSet(consonants)

local short_vowels = {"a", "e", "i", "o", "u", "y", "ä", "ö", "ü"}
local long_vowels = {"á", "é", "í", "ó", "ú", "ý", "ő", "ű"}
local diphthongs = {"ia", "ie", "iu", "ô"}

local short_vowels_set = m_table.listToSet(short_vowels)
local long_vowels_set = m_table.listToSet(long_vowels)
local diphthongs_set = m_table.listToSet(diphthongs)

local vowels = m_table.append(short_vowels, long_vowels)
local vowels_set = m_table.listToSet(vowels)

local obstruents = {"p", "t", "k", "b", "d", "g", "f", "s", "š", "ch", "z", "ž", "č", "dž"} --"v" removed??
local sonorants = {"m", "n", "l", "r", "ʋ", "v"} --"v" added??

local obstruents_set = m_table.listToSet(obstruents)
local sonorants_set = m_table.listToSet(sonorants)

local bigraphs = {"ch", "dz", "dž"}
local bigraphs_set = m_table.listToSet(bigraphs)

local prepositions = {"bez", "bezo", "cez", "cezo", "do", "k", "ku", "medzi",
	"na", "nad", "nado", "o", "do",	"okrem", "po", "pod", "podo", "pre", "pred",
	"predo", "pri", "proti", "naproti", "oproti", "s", "so", "skrz", "u", "v",
	"vo", "z", "zo", "za"}  -- Add more prepositions as needed
local prepositions_set = m_table.listToSet(prepositions)
local conjunctions = {"a"}  -- Add more conjunctions as needed
local conjunctions_set = m_table.listToSet(conjunctions)

-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
	local args = frame:getParent().args
	NAMESPACE = mw.title.getCurrentTitle().nsText
	if NAMESPACE == "" then
		PAGENAME = mw.title.getCurrentTitle().text
	else
		if args["pagename"] then
			PAGENAME = args["pagename"] -- TEST: lemma
		else
			error("Pagename not specified")
		end
	end
	
	GENDER = check_gender(args[1])
	NUMBER = args["n"]
	TYPE = args["t"]
	GEN_ENDING = args["g"]
	PLURAL = args["pl"]
	PLURAL2 = args["pl2"]
	PRONUNCIATION = args["p"]
	local genitive = args[2]
	local category = ""
 
	-- Check if PAGENAME is a multiword expression
	if not mw.ustring.find(PAGENAME, " ") then
		-- Single-word expression, handle as usual
		PATTERN = determine_pattern(PAGENAME, genitive)
		
		-- Category
		if NAMESPACE == "" then
			if PATTERN == "indeclinable" then
				category = "[[Category:Slovak indeclinable nouns|" .. PAGENAME .. "]]"
			elseif PATTERN == "irregular" then
				category = "[[Category:Slovak irregular nouns|" .. PAGENAME .. "]]"
			elseif PATTERN == "adjective" then
				category = "[[Category:Slovak adjectival nouns|" .. PAGENAME .. "]]"
			else
				category = "[[Category:Slovak terms with declension " .. PATTERN .. "|" .. PAGENAME .. "]]"
			end
			
			if GENDER == "m-anml" then
				category = category .. "[[Category:Slovak terms with declension chlap|" .. PAGENAME .. "]]"
			end
			
			if PAGENAME == "cól" then
				category = category .. "[[Category:Slovak terms with declension dub|" .. PAGENAME .. "]]"
			end
		end
		
		local forms, title 
		
		-- Find out if there are more genitive stems and if so, process them
		if genitive then
			if mw.ustring.find(genitive, "/") then
				forms, title = decline_with_more_stems(genitive)
			else
				forms, title = declensions[PATTERN](PAGENAME, genitive)
				normalize_forms(forms)
			end
		else
			forms, title = declensions[PATTERN](PAGENAME, genitive)
			normalize_forms(forms)
		end
		
		specified_by_user(forms, args)
		
		return make_table(forms, title) .. category
	end
	
	-- Multiword expressions
	-- Category
	if NAMESPACE == "" then
		category = "[[Category:Slovak multiword terms|" .. PAGENAME .. "]]"
	end

	-- Split into words
	local units, gen_units = split_into_units(PAGENAME, genitive)

	-- Process each unit to generate forms
	local combined_forms = generate_combined_forms(units, gen_units)
	
	-- Add forms specified by the user
	specified_by_user(combined_forms, args)

	-- Generate the final title and table
	local title = "Declension of ''" .. PAGENAME .. "'' (multiword term)"
	return make_table(combined_forms, title) .. category
end

--[=[
	Declension functions
]=]--

declensions["chlap"] = function(word, genitive)
	local forms = {}
	local syllable_count, syllables = split_into_syllables(word)
	local mobile_removed = false  -- Tracks if a mobile vowel was removed
	local words_with_mobile = {"kmotor", "švagor", "svokor", "lotor",
		"obor", "Uhor", "pochábeľ", "väzeň", "učeň",
		"posol", "diabol", "blázon", "Turek", "fanúšek", "center",
		"hypochonder", "Kafer", "neger", "gangster",
		"kapor", "zubor", "bobor", "orol", "pes"
	}
	local surn_ech_always_declined = {"Čech", "Plech", "Pech", "Štech", "Vojtech"}
	
	-- Determine the stem by removing mobile vowels if applicable
	local stem = word
	if (matches_any(word, words_with_mobile)
		or ends_with_any(word, {"ec", "ček", "íček", "ok"}))
		and not (TYPE == "surn"
			and (ends_with_any(word, {"[aeiouyáéíóúýäöüőű]ček", "[aeiouyáéíóúýäöüőű]čok"})
				or syllable_count == 1))
		and not matches_any(word, {"otrok"})
	then
		stem = remove_mobile_vowel(word)
		mobile_removed = true  -- Mark mobile vowel as removed
	end

	-- Adjust specific stems based on predefined mappings
	stem = ({["švec"] = "ševc", ["žnec"] = "ženc"})[word] or stem
	
	-- Remove certain endings for words ending with "us", "os", "es" and "o"
	if ends_with(word, "[uoea]s") then 
		stem = mw.ustring.sub(word, 1, -3)
	end
	if ends_with(word, "o") then 
		stem = remove_last_char(word)
	end
	
	-- Override if a specific argument is given
	if genitive and NUMBER ~= "pl" then 
		stem = remove_last_char(genitive)
	end

	-- Title for the declension table
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("chlap") .. ")"
	if TYPE == "surn" then
		if ends_with(word, "a[iy]") then
			title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("chlap") .. " or " .. pattern_link("kuli") .. ")"
		elseif ends_with_any(word, {"ých", "ech"}) and not matches_any(word, surn_ech_always_declined) then
			title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("chlap") .. " or indeclinable)"
		end
	end

	-- Helper variables for analyzing the last and penultimate characters
	local ultimate, penultimate = get_last_letters(stem)
	local first = get_first_char(word)

	-- Determine alternative dative and locative for some nouns
	if matches_any(word, {"človek", "pán", "čert", "diabol", "vlk", "pes",
		"Boh", "boh", "otec", "syn", "duch", "Kristus", "don", "šor"})
	then
		set_forms(forms, {"dat_sg2", "loc_sg2"}, {stem .. "u", stem .. "u"})
	end
	
	local nom_pl = "i"
	if PLURAL then
		if mw.ustring.find(PLURAL, "/") then
			local endings = {}
			for part in mw.ustring.gmatch(PLURAL, "[^/]+") do
				table.insert(endings, part)
			end
			nom_pl = endings[1]
			for i = 2, 4 do
				if endings[i] then
					set_forms(forms, {"nom_pl" .. i}, {append_ending(stem, endings[i])})
				else
					break
				end
			end
		else
			nom_pl = PLURAL
		end
	elseif (ends_with_any(word, {"fil", "fób", "graf", "nóm"})
		and not matches_any(word, {"xylograf", "typograf"}))
		or matches_any(word, {"cynik", "epik", "klasik", "stoik",
			"Brit", "Búr", "Gal", "Ír", "Dór", "Italik", "Ión", "Nór",
			"cár", "lodivod", "odkundes", "starík", "muž", "svat", "apoštol",
			"augur", "bán", "bogomil", "buržuj", "don", "druid", "eféb",
			"famulus", "héros", "man", "posol"
		})
	then
		set_forms(forms, {"nom_pl2"}, {append_ending(stem, "ovia")})
	elseif (ends_with_any(word, {"[^c]h", "g", "ček", "ek", "ik", "čik", "ok", "o", "duch"}) and word ~= "pes")
		or matches_any(word, {"otec", "syn", "ujec", "strýc", "svák", "svokor", "tesť", "švagor",
			"zať", "kmotor", "ded", "kmeť", "pobratim", "otčim", "zlosyn", "princ",
			"Bask", "Frank", "Ind", "Ink", "Kurd", "Dák", "Čudo", "Fríz", "Azték",
			"Asýr", "Etrusk", "Kazach", "Kašub", "odľud", "člen", "zved", "hňup", "cicerone"})
		or (ends_with(word, "ch") and TYPE == "loan")
		or (ends_with_any(word, {"us", "es"}) and genitive ~= word .. "a")
		or matches_any(TYPE, {"comp-deverb", "surn", "name"})
		or PLURAL == "ovia"
	then
		nom_pl = "ovia"
		
		if TYPE == "surn" then
			append_second_plural(forms, stem .. "ovci", stem .. "ovcov", stem .. "ovcom",
				stem .. "ovcov", stem .. "ovcoch", stem .. "ovcami")
		end
	elseif ends_with(word, "teľ")
		or (ends_with(word, "an") and is_capital(first))
		or matches_any(word, {"občan", "dedinčan", "mešťan", "zeman", "ostrovan",
			"krajan", "dolňan", "horňan", "južan", "severan", "rodič", "dedič", "brat", "hosť",
			"manžel", "exmanžel", "sused", "žid", "Žid", "kresťan", "nekresťan", "pohan"})
	then
		nom_pl = "ia"
		
		if word == "pohan" then
			set_forms(forms, {"nom_pl2"}, {append_ending(stem, "i")})
		end
	end

	-- Determine instrumental plural ending
	local ins_pl = "mi"  -- Default instrumental plural ending is "mi"
	if ultimate == "m"
		or mobile_removed
		or ends_with_any(word, {"o", "ius"})
		or matches_any(word, {"hosť", "tesť", "Kopt"}) --obstruents_set[penultimate] and obstruents_set[ultimate]
	then
		ins_pl = "ami"
	end

	-- Populate forms table with singular and plural endings
	append_endings(forms, word, stem,
		"a", "ovi", "a", "ovi", "om",
		nom_pl, append_ending(stem, "ov"), "om", "ov", "och", ins_pl
	)
	
	-- Surnames ending with -ých, -ech, -ai, -ay
	if TYPE == "surn" then
		if ends_with_any(word, {"ých", "ech"}) and not matches_any(word, surn_ech_always_declined) then
			append_alternative_singular(forms, word, word, word, word, word)
			append_alternative_plural(forms, word, word, word, word, word, word)
		elseif ends_with(word, "a[iy]") then
			append_alternative_singular(forms, word .. "ho", word .. "mu", word .. "ho", word .. "m", word .. "m")
			set_forms(forms, {"ins_pl2"}, {word .. "ami"})
		end
	end
	
	-- Exceptions
	if word == "človek" then
		set_forms(forms,
			{"nom_pl", "gen_pl", "dat_pl", "acc_pl", "loc_pl", "ins_pl"},
			{"ľudia", "ľudí", "ľuďom", "ľudí", "ľuďoch", "ľuďmi"}
		)
	elseif word == "héros" then
		set_forms(forms,
			{"gen_sg", "dat_sg", "acc_sg", "loc_sg", "ins_sg",
				"nom_pl", "gen_pl", "dat_pl", "acc_pl", "loc_pl", "ins_pl",
				"gen_sg2", "dat_sg2", "acc_sg2", "loc_sg2", "ins_sg2",
				"nom_pl2", "gen_pl2", "dat_pl2", "acc_pl2", "loc_pl2", "ins_pl2"},
			{"hérosa", "hérosovi", "hérosa", "hérosovi", "hérosom",
				"hérosi", "hérosov", "hérosom", "hérosov", "hérosoch", "hérosmi",
				"héroa", "héroovi", "héroa", "héroovi", "héroom",
				"héroovia", "héroov", "héroom", "héroov", "hérooch", "héroami"}
		)
	end
	
	-- Vocative
	if matches_any(word, {"syn", "sváko", "švagor", "kmotor", "brat", "synko",
		"synáčik", "pán", "chlapec", "priateľ", "majster", "Boh", "boh", "Pán", "Syn",
		"Duch", "Ježiš", "Ježiško", "Kristus", "Spasiteľ", "Vykupiteľ", "Stvoriteľ",
		"Premožiteľ", "Kráľ", "Hospodin", "baránok", "Baránok", "tešiteľ", "Tešiteľ",
		"hriešnik", "protivník", "kresťan", "otec", "Otec", "chlap", "človek"})
	then
		voc_stem = stem
		if word == "synáčik" then voc_stem = "synáčk" end
		if word == "pán" then voc_stem = "pan" end
		if word == "Pán" then voc_stem = "Pan" end
		
		if ends_with_any(word, {"teľ", "o"})
			or matches_any(word, {"syn", "Syn", "Duch", "Ježiš", "Kráľ",
				"hriešnik", "synáčik", "baránok", "Baránok"})
		then
			set_forms(forms, {"voc_sg"}, {append_ending(voc_stem, "u")})
		else
			if ends_with_any(voc_stem, {"k", "c"}) then
				voc_stem = remove_last_char(voc_stem) .. "č"
			elseif ends_with(voc_stem, "h") then
				voc_stem = remove_last_char(voc_stem) .. "ž"
			end
			
			set_forms(forms, {"voc_sg"}, {append_ending(voc_stem, "e")})
		end
		
		if not matches_any(word, {"človek", "pán", "brat"}) then
			set_forms(forms, {"voc_sg2"}, {word})
		elseif word == "brat" then
			set_forms(forms, {"voc_sg2", "voc_sg3"}, {"bratu", "brat"})
		end
	end

	return forms, title  -- Return forms table and title for declension
end

declensions["hrdina"] = function(word, genitive)
	local forms = {}
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("hrdina") .. ")"
	
	local stem = remove_suffix(word, "a")
	if ends_with(word, "[oeě]") then
		stem = remove_last_char(word)
		
		if ends_with(word, "ě") and ends_with(stem, "[dtnl]") then
			stem = soften_last_consonant(stem)
		end
	end
	
	local nom_pl_ending = "ovia"
	if ends_with_any(word, {"ista", "ita"})
		or (ends_with(word, "ta") and TYPE == "loan") then
		nom_pl_ending = "i"
	end
	
	local ins_pl_ending = "ami"
	if ends_with(word, "[aeiouyáéíóúýäöüőű]ta") and TYPE == "loan" then
		ins_pl_ending = "i"
	end
	
	append_endings(forms, word, stem,
		"u", "ovi", "u", "ovi", "om",
		nom_pl_ending, stem .. "ov", "om", "ov", "och", ins_pl_ending
	)
	
	if TYPE == "surn" then
		append_second_plural(forms, stem .. "ovci", stem .. "ovcov", stem .. "ovcom",
			stem .. "ovcov", stem .. "ovcoch", stem .. "ovcami")
	end
	
	if word == "buržoa" then
		set_forms(forms,
			{"dat_sg", "loc_sg", "ins_sg",
				"nom_pl", "gen_pl", "dat_pl", "acc_pl", "loc_pl"},
			{"buržuovi", "buržuovi", "buržuom",
				"buržuovia", "buržuov", "buržuom", "buržuov", "buržuoch"}
		)
	end
	
	return forms, title
end

declensions["kuli"] = function(word, genitive)
	local forms = {}
	local stem = word
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("kuli") .. ")"
	
	append_endings(forms, word, stem,
		"ho", "mu", "ho", "m", "m",
		"ovia", stem .. "ov", "om", "ov", "och", "ami"
	)
	
	if TYPE == "surn" then
		append_second_plural(forms, stem .. "ovci", stem .. "ovcov", stem .. "ovcom",
			stem .. "ovcov", stem .. "ovcoch", stem .. "ovcami")
	end
 
	return forms, title
end

declensions["dub"] = function(word, genitive)
	local forms = {}
	local mobile_removed = false  -- Tracks if a mobile vowel was removed
	local words_with_mobile = {"priemysel", "počet", "ocot", "bahor", "chrbát",
		"ker", "cukor", "uhor", "vietor", "víchor", "vôdor", "kotol",
		"kapor", "zubor", "bobor", "orol", "pes", "mozog", "uhol"}
	
	local syllable_count, syllables = split_into_syllables(word)
	
	-- Determine the stem by removing mobile vowels if applicable
	local stem = word
	if (matches_any(word, words_with_mobile)
		or (ends_with_any(word, {"íček", "ýček", "ok"}) and syllable_count ~= 1))
		and not matches_any(word, {"polrok", "nárok", "zákrok", "rozkrok"})
	then
		stem = remove_mobile_vowel(word)
		mobile_removed = true  -- Mark mobile vowel as removed
	end

	-- Adjust specific stems based on predefined mappings
	stem = ({["mráz"] = "mraz", ["vietor"] = "vetr", ["kôl"] = "kol",
			 ["stôl"] = "stol", ["vôl"] = "vol", ["chlieb"] = "chleb",
			 ["ensemble"] = "ensembl"})[word] or stem
	
	-- Remove certain endings for words ending with "us", "os", "es" and "o"
	if (ends_with(word, "[uoe]s") and TYPE == "loan") or ends_with(word, "izmus") then 
		stem = mw.ustring.sub(word, 1, -3)
	end
	if ends_with(word, "o") then 
		stem = remove_last_char(word)
	end
	
	-- Pluralia tantum
	if NUMBER == "pl" then
		stem = remove_suffix(word, "y")
	end
	
	-- Override if a specific argument is given
	if genitive and NUMBER ~= "pl" then 
		stem = remove_last_char(genitive)
		
		if stem == remove_last_char(remove_last_char(word)) .. get_last_char(word) then
			mobile_removed = true
		elseif stem == word then
			mobile_removed = false
		end
	end

	-- Set "mobile_removed" if genitive was set by the user
	if ends_with(word, "e[lr]") and ends_with(stem, "[^e][lr]") then
		mobile_removed = true
	end

	-- Title for the declension table
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("dub") .. ")"
	if GENDER == "m-anml" then
		if matches_any(word, {"vták", "vlk", "pes"}) then
			title = "Declension of ''" .. word .. "'' (patterns " .. pattern_link("chlap") .. " <small>(singular, plural 1)</small> and " .. pattern_link("dub") .. " <small>(plural 2)</small>)"
		elseif PLURAL2 then
			title = "Declension of ''" .. word .. "'' (patterns " .. pattern_link("chlap") .. " <small>(singular, plural 2)</small> and " .. pattern_link("dub") .. " <small>(plural 1)</small>)"
		else
			title = "Declension of ''" .. word .. "'' (patterns " .. pattern_link("chlap") .. " <small>(singular)</small> and " .. pattern_link("dub") .. " <small>(plural)</small>)"
		end
	end

	-- Helper variables for analyzing the last and penultimate characters
	local ultimate, penultimate = get_last_letters(stem)
	local first = get_first_char(word)

	-- Determine genitive singular ending
	local gen_sg = "a"
	if (matches_any(TYPE, {"abstr", "comp-deverb", "material", "collect", "loan"})
		or matches_any(GEN_ENDING, {"u", "u/a"})
		or ends_with_any(word, {"izmus", "x"})
		or (ends_with(word, "m") and not is_capital(first))
		or (ends_with(word, "z") and is_capital(first)))
		and not matches_any(GEN_ENDING, {"a", "a/u"})
	then
		gen_sg = "u"
	end
	
	-- Override genitive singular ending if a specific argument is given
	if genitive then 
		gen_sg = get_last_char(genitive)
	end

	-- Determine locative singular ending based on specific suffixes and patterns
	local loc_sg = "e"
	if ends_with_any(word, {"k", "g", "h", "ch", "ius", "eus"}) then
		loc_sg = "u"
	elseif (ends_with(word, "ér")
			or (ends_with(word, "ál") and not matches_any(word, {"bál", "paškál", "paušál", "šál", "škandál", "žurnál"}))
			or matches_any(word, {"Alžír", "klavír", "apríl", "jún", "júl"}))
	then
		loc_sg = "i"
	end

	-- Determine genitive plural ending
	local gen_pl = stem .. "ov"  -- Default genitive plural ending is "ov"
	
	-- Adjust genitive plural for specific place names and patterns
	if is_capital(first) and (ends_with_any(word, {"any", "íky", "áky", "iaky"})
		or matches_any(word, {"Krompachy", "Kubachy", "Veľbachy", "Spišské Vlachy",
			"Žabokreky", "Čechy", "Brezolupy", "Bruty", "Rakoľuby", 
			"Rakúsy", "Prusy", "Veľaty", "Piešťany", "Bieščary"}))
	then
		local gen_stem = remove_last_char(word)  -- Remove last character to get the base stem
		local syllable_count, syllables = split_into_syllables(gen_stem)
		local last_syllable = syllables[1]
		local penultimate_syllable = syllables[2] or ""
		
		-- Lengthen the vowel if the penultimate syllable is short, otherwise use unchanged stem
		if is_long(penultimate_syllable) then
			gen_pl = gen_stem
		else
			gen_pl = remove_suffix(gen_stem, last_syllable) .. lengthen_vowel(last_syllable)
		end
	end

	-- Special cases for genitive plural of specific words
	if word == "čas" then
		gen_pl = "čias"
	elseif word == "raz" then
		gen_pl = "ráz"
	end

	-- Determine instrumental plural ending
	local ins_pl = "mi"  -- Default instrumental plural ending is "mi"
	if ultimate == "m"
		or mobile_removed
		or ends_with_any(word, {"o", "ius", "eus"})
		or (penultimate == "m" and consonants_set[ultimate])
	then
		ins_pl = "ami"
	end
	
	-- Doublets for instrumental plural
	if matches_any(word, {"schod", "schody", "fúz", "fúzy", "roh", "rohy",
		"paroh", "parohy", "čary", "orech"})
	then
		set_forms(forms, {"ins_pl2"}, {stem .. "ami"})
	elseif matches_any(word, {"zub", "dol", "most", "prst", "piest", "necht"}) then
		ins_pl = "ami"
		set_forms(forms, {"ins_pl2"}, {stem .. "mi"})
	end

	-- Populate forms table with singular and plural endings
	append_endings(forms, word, stem,
		gen_sg, "u", nil, loc_sg, "om",
		"y", gen_pl, "om", nil, "och", ins_pl
	)
	
	-- Alternative genitive ending
	if GEN_ENDING == "a/u" then
		set_forms(forms, {"gen_sg2"}, {stem .. "u"})
	elseif GEN_ENDING == "u/a" then
		set_forms(forms, {"gen_sg2"}, {stem .. "a"})
	end
	
	-- Exceptions
	if matches_any(word, {"sen", "dol"}) then
		set_forms(forms, {"loc_pl2"}, {stem .. "ách"})
	elseif word == "čas" then
		set_forms(forms, {"gen_pl2"}, {"časov"})
	end
	
	-- Animal nouns
	if GENDER == "m-anml" then
		append_animal_singular(forms, stem)
		
		if matches_any(word, {"vták", "vlk", "pes"}) or PLURAL2 then
			local forms2, title2 = declensions["chlap"](word, stem .. gen_sg)
			append_second_plural(forms, forms2["nom_pl"], forms2["gen_pl"], forms2["dat_pl"],
				forms2["acc_pl"], forms2["loc_pl"], forms2["ins_pl"])
			
			if matches_any(word, {"vták", "vlk", "pes"}) then
				switch_plural_forms(forms) --changes the prefered forms
			
				-- Determine alternative dative and locative for some nouns
				if matches_any(word, {"vlk", "pes"}) then
					set_forms(forms, {"dat_sg2", "loc_sg2"}, {stem .. "u", stem .. "u"})
				end
			end
		end
	end

	return forms, title  -- Return forms table and title for declension
end

declensions["stroj"] = function(word, genitive)
	local forms = {}
	local mobile_removed = false  -- Tracks if a mobile vowel was removed
	local words_with_no_mobile = {"kúpeľ", "červeň", "kameň", "jačmeň", "koreň",
		"prameň", "prsteň", "jeleň"}
	local first = get_first_char(word)
	
	-- Determine the stem by removing mobile vowels if applicable
	local stem = word
	if (ends_with_any(word, {"ec", "iec", "[^ti]eľ", "oľ", "[^i]eň", "eť", "[^i]er", "el"})
		or (ends_with(word, "ac") and (is_capital(first) or word == "desaterac")))
		and not matches_any(word, words_with_no_mobile)
	then
		stem = remove_mobile_vowel(word)
		mobile_removed = true  -- Mark mobile vowel as removed
	end

	-- Adjust specific stems based on predefined mappings
	stem = ({["dážď"] = "dažď", ["kôš"] = "koš", ["nôž"] = "nož",
		["kôň"] = "koň", ["timbre"] = "timbr"})[word] or stem
	
	-- Pluralia tantum
	if NUMBER == "pl" then
		stem = remove_suffix(word, "e")
	end
	
	-- Override if a specific argument is given
	if genitive and NUMBER ~= "pl" then 
		stem = remove_last_char(genitive)
		
		if stem == remove_last_char(remove_last_char(word)) .. get_last_char(word) then
			mobile_removed = true
		elseif stem == word then
			mobile_removed = false
		end
	end

	-- Set "mobile_removed" if genitive was set by the user
	if ends_with(word, "e[lr]") and ends_with(stem, "[^e][lr]") then
		mobile_removed = true
	end

	-- Title for the declension table
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("stroj") .. ")"
	if GENDER == "m-anml" then
		if PLURAL2 then
			title = "Declension of ''" .. word .. "'' (patterns " .. pattern_link("chlap") .. " <small>(singular, plural 2)</small> and " .. pattern_link("stroj") .. " <small>(plural 1)</small>)"
		else
			title = "Declension of ''" .. word .. "'' (patterns " .. pattern_link("chlap") .. " <small>(singular)</small> and " .. pattern_link("stroj") .. " <small>(plural)</small>)"
		end
	elseif word == "cól" then
		title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("stroj") .. " or " .. pattern_link("dub") .. ")"
	end

	-- Helper variables for analyzing the last and penultimate characters
	local ultimate, penultimate = get_last_letters(stem)
	local first = get_first_char(word)

	-- Determine genitive singular ending
	local gen_sg = "a"
	if ((matches_any(TYPE, {"abstr", "material"})
		or matches_any(GEN_ENDING, {"u", "u/a"}))
		and not matches_any(word, {"jačmeň", "kameň", "olej", "loj", "vývoj", "rozvoj"}))
		and not matches_any(GEN_ENDING, {"a", "a/u"})
	then
		gen_sg = "u"
	end
	
	-- Override genitive singular ending if a specific argument is given
	if genitive then 
		gen_sg = get_last_char(genitive)
	end

	-- Determine genitive plural ending
	local gen_pl = stem .. "ov"  -- Default genitive plural ending is "ov"
	
	-- Adjust genitive plural for specific place names and patterns
	if is_capital(first) and (ends_with_any(word, {"áre", "iare"})
		or word == "Tlmače")
	then
		local gen_stem = remove_last_char(word)  -- Remove last character to get the base stem
		local syllable_count, syllables = split_into_syllables(gen_stem)
		local last_syllable = syllables[1]
		local penultimate_syllable = syllables[2] or ""
		
		-- Lengthen the vowel if the penultimate syllable is short, otherwise use unchanged stem
		if is_long(penultimate_syllable) then
			gen_pl = gen_stem
		else
			gen_pl = remove_suffix(gen_stem, last_syllable) .. lengthen_vowel(last_syllable)
		end
	end

	-- Special cases for genitive plural of specific words
	if word == "Ladce" then
		gen_pl = "Ladiec"
	elseif word == "Vráble" then
		gen_pl = "Vrábeľ"
	elseif word == "peniaze" then
		gen_pl = "peňazí"
	elseif matches_any(word, {"deň", "kôň", "groš"}) then
		gen_pl = append_ending(stem, "í")
	end

	-- Determine instrumental plural ending
	local ins_pl = "mi"  -- Default instrumental plural ending is "mi"
	if mobile_removed
		or (obstruents_set[penultimate] and obstruents_set[ultimate])
	then
		ins_pl = "ami"
	end

	-- Populate forms table with singular and plural endings
	append_endings(forms, word, stem,
		gen_sg, "u", nil, "i", "om",
		"e", gen_pl, "om", nil, "och", ins_pl
	)
	
	-- Alternative genitive ending
	if GEN_ENDING == "a/u" then
		set_forms(forms, {"gen_sg2"}, {stem .. "u"})
	elseif GEN_ENDING == "u/a" then
		set_forms(forms, {"gen_sg2"}, {stem .. "a"})
	end
	
	-- Exceptions
	if matches_any(word, {"deň", "poldeň"}) then
		set_forms(forms,
			{"nom_pl", "acc_pl", "loc_sg2"},
			{append_ending(stem, "i"), append_ending(stem, "i"), append_ending(stem, "e")}
		)
	elseif word == "ďateľ" then
		set_forms(forms,
			{"gen_sg2", "dat_sg2", "loc_sg2", "ins_sg2",
				"nom_pl2", "gen_pl2", "dat_pl2", "acc_pl2", "loc_pl2", "ins_pl2"},
			{"ďatľa", "ďatľovi", "ďatľovi", "ďatľom",
				"ďatle", "ďatľov", "ďatľom", "ďatle", "ďatľoch", "ďatľami"}
		)
	elseif word == "cól" then
		set_forms(forms,
			{"loc_sg2", "nom_pl2", "acc_pl2"},
			{"cóle", "cóly", "cóly"}
		)
	end
	
	-- Animal nouns
	if GENDER == "m-anml" then
		append_animal_singular(forms, stem)
		
		if PLURAL2 then
			local forms2, title2 = declensions["chlap"](word, stem .. gen_sg)
			append_second_plural(forms, forms2["nom_pl"], forms2["gen_pl"], forms2["dat_pl"],
				forms2["acc_pl"], forms2["loc_pl"], forms2["ins_pl"])
		end
	end

	return forms, title  -- Return forms table and title for declension
end

declensions["žena"] = function(word, genitive)
	local forms = {}
	local stem = remove_suffix(word, "a")
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("žena") .. ")"
	if ends_with(word, "ea") then
		title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("žena") .. ", loanword ending with ''-ea'')"
	end
	
	-- Pluralia tantum or genitive
	if NUMBER == "pl" then
		stem = remove_suffix(word, "y")
	end
	if genitive and NUMBER ~= "pl" then
		stem = remove_suffix(genitive, "y")
	end
	
	-- Split into syllables
	local gen_pl = ""
	local syllable_count, syllables = split_into_syllables(stem)
	local word_syllable_count, word_syllables = split_into_syllables(word)

	-- Get the last and second-to-last syllables for rule checks
	local last_syllable = syllables[1]
	local penultimate_syllable = syllables[2] or ""
	local word_penultimate_syllable = word_syllables[2] or ""
	
	local ultimate, penultimate = get_last_letters(stem)
	
	-- 1. Add a vowel between the last two consonants of a cluster at the end of the stem
	if ends_with_consonant_cluster(last_syllable) or word_syllable_count == 1 then
		if (ultimate == "k" and not matches_any(word, {"banka"}))
			or (ultimate == "b" and (TYPE == "der" or not sonorants_set[penultimate]))
			or sonorants_set[ultimate]
			or matches_any(word, {"farba", "karta", "buchta", "astma"})
			or (obstruents_set[penultimate] and ultimate == "v")
		then
			if penultimate ~= "j" and (word_syllable_count == 1 or is_short(word_penultimate_syllable)) then
				gen_pl = harden_last_consonant(remove_suffix(stem, ultimate)) .. "ie" .. ultimate
				
				if matches_any(word, {"handra", "perla", "metla", "slivka",
					"tehla", "vidly", "karta", "kvapka", "stovka", "doska"})
				then
					gen_pl = remove_suffix(stem, ultimate) .. "á" .. ultimate
					set_forms(forms, {"gen_pl2"}, {harden_last_consonant(remove_suffix(stem, ultimate)) .. "ie" .. ultimate})
				end
				
				if matches_any(word, {"jamka", "kvapka"}) then
					set_forms(forms, {"gen_pl2"}, {remove_suffix(stem, ultimate) .. "ô" .. ultimate})
				end
				
				if matches_any(word, {"astma"}) then
					set_forms(forms, {"gen_pl2"}, {stem .. "í"})
				end
			elseif obstruents_set[ultimate] and (is_long(word_penultimate_syllable) or penultimate == "j") then
				gen_pl = remove_suffix(stem, ultimate) .. "o" .. ultimate
			elseif (sonorants_set[ultimate] or ultimate == "v") and (is_long(word_penultimate_syllable) or penultimate == "j") then
				gen_pl = remove_suffix(stem, ultimate) .. "e" .. ultimate
				
				if penultimate ~= "j" then
					set_forms(forms, {"gen_pl2"}, {remove_suffix(stem, ultimate) .. "ie" .. ultimate})
				end
			end
		end
	end

	-- 2. Add "í" if stem ends with a vowel or a soft consonant
	if gen_pl == "" and (vowels_set[ultimate]
		or matches_any(word, {"medaila", "pera", "kanva", "panva", "skepsa", "nuansa"}))
	then
		gen_pl = stem .. "í"
		
		if matches_any(word, {"nuansa"}) then
			set_forms(forms, {"gen_pl2"}, {remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable)})
		end
	end
	
	-- 3. Return the stem with no change if conditions match
	if gen_pl == "" and (is_long(penultimate_syllable)
		or ends_with_any(stem, {"tvor", "ov"})
		or mw.ustring.find(last_syllable, "jo")
		or (TYPE == "loan" and matches_any(get_vowel(last_syllable), {"e", "o"}))) then
		gen_pl = stem
	end

	-- 4. Logic to use the lengthened vowel if conditions match
	if gen_pl == "" and (not (ends_with_consonant_cluster(last_syllable) or vowels_set[ultimate])
		or (ends_with_consonant_cluster(last_syllable) and sonorants_set[penultimate] and obstruents_set[ultimate])
		or (ends_with_consonant_cluster(last_syllable) and matches_any(penultimate, {"c", "s", "z", "š", "ž", "p"}) and matches_any(ultimate, {"t", "d"})))
		and not matches_any(word, {"šachta", "mzda"}) then
		gen_pl = remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable)
		
		if mw.ustring.find(stem, "au[bcčdďfghjklľmnňpqrsštťvwxzž]$") then
			gen_pl = remove_suffix(stem, "a" .. last_syllable) .. "á" .. last_syllable
		end
	end
	
	-- 5. long -á- instead of -ia- for some loanwords
	if matches_any(word, {"pyžama", "šachta"}) then
		gen_pl = (word == "pyžama") and "pyžám" or "šácht"
		
		if word == "šachta" then
			set_forms(forms, {"gen_pl2"}, {"šachiet"})
		end
	end
	
	-- 6. Exceptions
	if word == "mzda" then
		gen_pl = "miezd"
	end
	
	if gen_pl == "" then gen_pl = stem end
	
	local dat_pl, loc_pl
	if is_long(word_penultimate_syllable) then
		dat_pl, loc_pl = "am", "ach"
	else
		dat_pl, loc_pl = "ám", "ách"
	end
	
	local dat_sg, loc_sg
	if ultimate == "e" then
		dat_sg, loc_sg = "i", "i"
	else
		dat_sg, loc_sg = "e", "e"
	end
	
	append_endings(forms, word, stem,
		"y", dat_sg, "u", loc_sg, "ou",
		"y", gen_pl, dat_pl, nil, loc_pl, "ami"
	)
	
	if matches_any(word, {"zora", "žiara", "žiabra"}) then
		set_forms(forms,
			{"nom_pl", "acc_pl"},
			{stem .. "e", stem .. "e"}
		)
	end
 
	return forms, title
end

declensions["gazdiná"] = function(word, genitive)
	local forms = {}
	local stem = remove_suffix(word, "á")
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("gazdiná") .. ")"
	
	local syllable_count, syllables = split_into_syllables(stem)
	local last_syllable = syllables[1]
	
	local gen_pl = ""
	if ends_with_consonant_cluster(last_syllable) then
		gen_pl = mw.ustring.sub(stem, 1, -2) .. "ien"
	else
		gen_pl = remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable)
	end
	
	append_endings(forms, word, stem,
		"ej", "ej", "ú", "ej", "ou",
		"é", gen_pl, "ám", nil, "ách", "ami"
	)
 
	return forms, title
end

declensions["ulica"] = function(word, genitive)
	local forms = {}
	local stem = remove_suffix(word, "a")
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("ulica") .. ")"
	
	-- Pluralia tantum
	if NUMBER == "pl" then
		stem = remove_suffix(word, "e")
		if ends_with_any(stem, {"d", "t", "n", "l"}) then
			stem = soften_last_consonant(stem)
		end
	end
	
	-- Split into syllables
	local gen_pl = ""
	local syllable_count, syllables = split_into_syllables(stem)
	local word_syllable_count, word_syllables = split_into_syllables(word)

	-- Get the last and second-to-last syllables for rule checks
	local last_syllable = syllables[1]
	local penultimate_syllable = syllables[2] or ""
	local word_penultimate_syllable = word_syllables[2] or ""
	
	local ultimate, penultimate = get_last_letters(stem)
	local first = get_first_char(word)
	
	-- 1. Add a vowel between the last two consonants of a cluster at the end of the stem
	if ends_with_consonant_cluster(last_syllable) then
		if (is_capital(first) and ends_with(word, "ce"))
			or matches_any(word, {"dverce", "ovca", "fakľa", "drumbľa", "husle", "jasle",
				"kachle", "hrable", "šabľa", "mašľa", "žemľa", "ríbezľa", "čerešňa", "sukňa", "višňa"})
		then
			gen_pl = harden_last_consonant(remove_suffix(stem, ultimate)) .. "ie" .. ultimate
			
			if matches_any(word, {"drumbľa", "husle", "jasle", "kachle", "hrable",
				"šabľa", "mašľa", "žemľa", "ríbezľa", "čerešňa", "sukňa", "višňa"}) then
				set_forms(forms, {"gen_pl2"}, {append_ending(stem, "í")})
			end
		end
	end

	-- 2. Add "í" if stem ends with a vowel or a soft consonant
	if gen_pl == "" and (matches_any(ultimate, {"dz", "dž", "ž", "ť", "ď", "j", "i", "y"})
		or ends_with_any(word, {"nca", "oľa", "ôľa", "aľa", "ša", "ča"})
		or matches_any(word, {"liace", "pasca", "páľa", "trúbeľa", "mrľa", "konope", "večera", "rozopra"})
		or (matches_any(ultimate, {"ľ"}) and consonants_set[penultimate])
		or (matches_any(ultimate, {"ň"}) and penultimate ~= "y"))
		and not matches_any(word, {"papuča", "priča", "hrča", "paprča",
			"garniža", "fakľa", "skriňa", "sviňa", "abatiša", "čaša", "fľaša",
			"Krkonoše", "ríša", "skrýša"})
	then
		gen_pl = append_ending(stem, "í")
	end

	-- 3. Logic to use the lengthened vowel if conditions match
	if gen_pl == "" and not ends_with_consonant_cluster(last_syllable) and not vowels_set[ultimate]
		and ((ends_with(word, "ca") and TYPE ~= "der")
			or ends_with_any(word, {"yňa", "uľa"})
			or matches_any(word, {"papuča", "priča", "hrča", "chvíľa", "míľa", "košeľa", "nedeľa",
				"guľa", "hoľa", "homoľa", "skriňa", "sviňa", "abatiša", "čaša", "fľaša",
				"Krkonoše", "ríša", "skrýša", "garniža", "Hybe", "dvere", "kuša", "moruša"}))
	then
		if is_long(penultimate_syllable) then
			gen_pl = stem
		else
			gen_pl = remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable)
			if matches_any(word, {"homoľa", "kuša", "moruša", "hrča", "paprča",
				"guľa", "hoľa"})
			then
				set_forms(forms, {"gen_pl2"}, {append_ending(stem, "í")})
			end
		end
	end
	
	if gen_pl == "" then gen_pl = stem end
	
	local dat_pl, loc_pl
	if ends_with_any(stem, {"i", "y"}) or word == "pizza" then
		dat_pl, loc_pl = "ám", "ách"
	elseif is_long(word_penultimate_syllable) or ends_with(stem, "j") then
		dat_pl, loc_pl = "am", "ach"
	else
		dat_pl, loc_pl = "iam", "iach"
	end
	
	append_endings(forms, word, stem,
		"e", "i", "u", "i", "ou",
		"e", gen_pl, dat_pl, nil, loc_pl, "ami"
	)
	
	if word == "rozopra" then
		set_forms(forms,
			{"dat_pl2", "loc_pl2"},
			{"rozoprám", "rozoprách"}
		)
	elseif word == "dvere" then
		set_forms(forms,
			{"dat_pl", "loc_pl", "gen_pl2", "ins_pl2"},
			{"dverám", "dverách", "dverí", "dvermi"}
		)
	end
 
	return forms, title
end

declensions["irregular"] = function(word, genitive)
	local forms = {}
	local title = "Declension of ''" .. word .. "'' (irregular)"
	
	if matches_any(word, {"mať", "mater", "mati"}) then
		local stem = "mater"
		append_endings(forms, word, stem,
			"e", "i", "", "i", "ou",
			"e", stem .. "í", "iam", nil, "iach", "ami"
		)
		local accusative = (word == "mater") and {"mater", "mať"} or {"mať", "mater"}
		set_forms(forms, {"acc_sg", "acc_sg2"}, accusative)
	elseif ends_with(word, "pani") then
		local stem = remove_suffix(word, "ni") .. "ň"
		append_endings(forms, word, stem,
			"ej", "ej", "iu", "ej", "ou",
			"ie", stem .. "í", "iam", nil, "iach", "iami"
		)
	end
 
	return forms, title
end

declensions["dlaň"] = function(word, genitive)
	local forms = {}
	local words_with_mobile_vowel = {"faloš", "osuheľ", "siheľ", "myseľ"}
	local stem = (matches_any(word, words_with_mobile_vowel) or ends_with(word, "eň"))
		and remove_mobile_vowel(word) or word
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("dlaň") .. ")"
	
	local syllable_count, syllables = split_into_syllables(word)
	local last_syllable = syllables[1]
	local penultimate_syllable = syllables[2] or ""
	local last_char = get_last_char(word)
	
	local dat_pl, loc_pl
	
	if is_long(penultimate_syllable) or last_char == "j" then
		dat_pl, loc_pl = "am", "ach"
	elseif word == "kader" then
		dat_pl, loc_pl = "ám", "ách"
	else
		dat_pl, loc_pl = "iam", "iach"
	end
	
	append_endings(forms, word, stem,
		"e", "i", nil, "i", "ou",
		"e", append_ending(stem, "í"), dat_pl, nil, loc_pl, "ami"
	)
	
	if matches_any(word, {"myseľ", "tvár", "hneď", "raž"}) then
		set_forms(forms, {"gen_sg2"}, {append_ending(stem, "i")})
	end
 
	return forms, title
end

declensions["kosť"] = function(word, genitive)
	local forms = {}
	local words_with_mobile_vowel = {"voš", "lož", "Ves", "cirkev", "reďkev"}
	local stem = (matches_any(word, words_with_mobile_vowel))
		and remove_mobile_vowel(word) or word
	if word == "česť" then stem = "cť" end
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("kosť") .. ")"
	
	append_endings(forms, word, stem,
		"i", "i", nil, "i", "ou",
		"i", append_ending(stem, "í"), "iam", nil, "iach", "ami"
	)
	
	if word == "hrsť" then
		set_forms(forms,
			{"nom_pl", "acc_pl"},
			{"hrste", "hrste"}
		)
	elseif word == "lesť" then
		append_alternative_singular(forms, "ľsti", "ľsti", nil, "ľsti", "ľsťou")
		append_alternative_plural(forms, "ľsti", "ľstí", "ľstiam", nil, "ľstiach", "ľsťami")
	elseif matches_any(word, {"cirkev", "reďkev"}) then
		set_forms(forms,
			{"dat_pl", "loc_pl"},
			{stem .. "ám", stem .. "ách"}
		)
	end
 
	return forms, title
end
 
declensions["mesto"] = function(word, genitive)
	local forms = {}
	local ultimate, penultimate = get_last_letters(word)
	
	local special_type = ""
	local stem = remove_suffix(word, "o")
	
	if penultimate == "u" and ultimate == "m" then
		stem = remove_suffix(word, "um")
		special_type = ", of Latin origin ending with ''-um''"
	elseif penultimate == "o" and ultimate == "n" then
		stem = remove_suffix(word, "on")
		special_type = ", of Greek origin ending with ''-on''"
	elseif penultimate == "m" and ultimate == "ä" then
		stem = remove_suffix(word, "ä") .. "en"
		special_type = ", archaic type ending with ''-mä''"
	end
	
	-- Pluralia tantum
	if NUMBER == "pl" then
		stem = remove_suffix(word, ultimate)
	end
	
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("mesto") .. special_type .. ")"
	
	local stem_ultimate, stem_penultimate = get_last_letters(stem)
	
	local loc_sg = "e"
	if vowels[stem_ultimate] or matches_any(stem_ultimate, {"k", "g", "ch", "h"}) then
		loc_sg = "u"
	elseif matches_any(word, {"vnútro", "nebo"}) then
		loc_sg = "i"
	end
	
	-- Split into syllables
	local gen_pl = ""
	local syllable_count, syllables = split_into_syllables(stem)
	local word_syllable_count, word_syllables = split_into_syllables(word)

	-- Get the last and second-to-last syllables for rule checks
	local last_syllable = syllables[1]
	local penultimate_syllable = syllables[2] or ""
	local word_penultimate_syllable = word_syllables[2] or ""
	
	-- 1. Add a vowel between the last two consonants of a cluster at the end of the stem
	if ends_with_consonant_cluster(last_syllable) then
		if matches_any(word, {"jedlo", "predjedlo", "jutro", "vrecko", "brvno"}) then
			if matches_any(word, {"jedlo", "predjedlo", "jutro"}) then
				gen_pl = remove_suffix(stem, stem_ultimate) .. "á" .. stem_ultimate
			else
				gen_pl = remove_suffix(stem, stem_ultimate) .. "ie" .. stem_ultimate
				set_forms(forms, {"gen_pl2"}, {remove_suffix(stem, stem_ultimate) .. "á" .. stem_ultimate})
			end
		elseif sonorants_set[stem_ultimate] or ends_with_any(last_syllable, {"stv", "ctv", "íčk", "ečk", "očk"}) or TYPE == "dim" then
			if stem_penultimate ~= "j" and (word_syllable_count == 1 or ends_with_any(last_syllable, {"stv", "ctv"}) or is_short(word_penultimate_syllable)) then
				gen_pl = remove_suffix(stem, stem_ultimate) .. "ie" .. stem_ultimate
			elseif obstruents_set[stem_ultimate] and (is_long(word_penultimate_syllable) or stem_penultimate == "j") then
				gen_pl = remove_suffix(stem, stem_ultimate) .. "o" .. stem_ultimate
			elseif sonorants_set[stem_ultimate] and (is_long(word_penultimate_syllable) or stem_penultimate == "j") then
				gen_pl = remove_suffix(stem, stem_ultimate) .. "e" .. stem_ultimate
				if stem_penultimate ~= "j" then
					set_forms(forms, {"gen_pl2"}, {remove_suffix(stem, stem_ultimate) .. "ie" .. stem_ultimate})
				end
			end
		end
	end

	-- 2. Add "í" if stem ends with a vowel or a soft consonant
	if gen_pl == "" and (vowels_set[stem_ultimate] or soft_consonants_set[stem_ultimate]) then
		gen_pl = stem .. "í"
	end
	
	-- 3. Return the stem with no change if conditions match
	if gen_pl == "" and (is_long(penultimate_syllable)
		or ends_with_any(stem, {"vojsk", "ov"})
		or (TYPE == "loan" and matches_any(get_vowel(last_syllable), {"e", "o"}))) then
		gen_pl = stem
	end

	-- 4. Logic to use the lengthened vowel if conditions match
	if gen_pl == "" and (not (ends_with_consonant_cluster(last_syllable) or vowels_set[stem_ultimate])
		or (ends_with_consonant_cluster(last_syllable) and obstruents_set[stem_ultimate])) then
		gen_pl = remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable)
	end

	local nom_pl = "á"
	if NUMBER == "pl" then
		nom_pl = ultimate
	end
	
	if gen_pl == "" then gen_pl = stem end
	
	if is_long(word_penultimate_syllable) or word == "jojo" then
		append_endings(forms, word, stem,
			"a", "u", nil, loc_sg, "om",
			"a", gen_pl, "am", nil, "ach", "ami"
		)
	else
		append_endings(forms, word, stem,
			"a", "u", nil, loc_sg, "om",
			nom_pl, gen_pl, "ám", nil, "ách", "ami"
		)
	end
	
	if matches_any(word, {"oko", "ucho"}) then
		local pl_stem = (word == "oko") and "oč" or "uš"
		append_second_plural(forms, pl_stem .. "i", pl_stem .. "í", pl_stem .. "iam",
			nil, pl_stem .. "iach", pl_stem .. "ami")
		switch_plural_forms(forms) --changes the prefered forms
		set_forms(forms,
			{"gen_pl2"},
			{pl_stem .. "ú"}
		)
	elseif word == "nebo" then
		set_forms(forms,
			{"nom_pl", "nom_pl2", "gen_pl", "dat_pl", "dat_pl2", "acc_pl",
				"acc_pl2", "loc_pl", "loc_pl2", "ins_pl"},
			{"nebesá", "nebesia", "nebies", "nebesám", "nebesiam", "nebesá",
				"nebesia", "nebesách", "nebesiach", "nebesami"}
		)
	end
	
	return forms, title
end
 
declensions["srdce"] = function(word, genitive)
	local forms = {}
	local stem = remove_suffix(word, "e")
	if ends_with(word, "ě") then
		stem = remove_suffix(word, "ě")
	end
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("srdce") .. ")"
	
	if NUMBER == "pl" then
		if ends_with(word, "ia") then
			stem = remove_suffix(word, "ia")
		else
			stem = remove_suffix(word, "a")
		end
	end
	
	if ends_with(stem, "[dtnl]") then
		stem = soften_last_consonant(stem)
	end
	
	-- Split into syllables
	local gen_pl = ""
	local syllable_count, syllables = split_into_syllables(stem)
	local word_syllable_count, word_syllables = split_into_syllables(word)
	
	-- Get the last and second-to-last syllables for rule checks
	local last_syllable = syllables[1]
	local penultimate_syllable = syllables[2] or ""
	local word_penultimate_syllable = word_syllables[2] or ""
	
	local last_char = get_last_char(stem)
	local stem_ultimate, stem_penultimate = get_last_letters(stem)
	
	-- 1 & 2. Lengthen the last syllable's vowel if conditions apply,
	-- otherwise leave the stem unchanged if penultimate syllable is long
	if not ends_with_consonant_cluster(last_syllable) 
		or (ends_with(word, "ce") and matches_any(get_vowel(word_penultimate_syllable), {"r", "l"}) and TYPE ~= "dim")
		or ends_with(word, "ište") then
		if is_long(penultimate_syllable) then
			gen_pl = stem  -- If penultimate syllable of the stem is long, use the stem unchanged
		else
			-- Otherwise, lengthen the last syllable's vowel
			gen_pl = remove_suffix(stem, last_syllable) .. lengthen_vowel(last_syllable)
		end
	end
	
	-- 3. Add a vowel between the last two consonants if the conditions apply
	if gen_pl == "" and (word == "citoslovce" or word == "vajce"
		or ends_with(word, "ce")) then
		if stem_penultimate ~= "j" and is_short(word_penultimate_syllable) then
			gen_pl = remove_suffix(stem, stem_ultimate) .. "ie" .. stem_ultimate
		elseif is_long(word_penultimate_syllable) or stem_penultimate == "j" then
			gen_pl = remove_suffix(stem, stem_ultimate) .. "e" .. stem_ultimate
		end
	end
	
	-- 4. Add "í" to the stem for specific words
	if matches_any(word, {"more", "oje", "pole", "lože"}) then
		gen_pl = harden_last_consonant(stem) .. "í"
	end
	
	-- Fallback: if none of the rules apply, return the original stem
	if gen_pl == "" then gen_pl = stem end
	
	if is_long(word_penultimate_syllable) or ends_with(stem, "j") then
		append_endings(forms, word, stem,
			"a", "u", nil, "i", "om",
			"a", gen_pl, "am", nil, "ach", "ami"
		)
	else
		append_endings(forms, word, stem,
			"a", "u", nil, "i", "om",
			"ia", gen_pl, "iam", nil, "iach", "ami"
		)
	end
	
	return forms, title
end

declensions["vysvedčenie"] = function(word, genitive)
	local forms = {}
	local stem = remove_suffix(word, "ie")
	if ends_with(word, "í") then
		stem = remove_suffix(word, "í")
	end
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("vysvedčenie") .. ")"
	
	append_endings(forms, word, stem,
		"ia", "iu", nil, "í", "ím",
		"ia", stem .. "í", "iam", nil, "iach", "iami"
	)
	
	if word == "storočie" then
		append_second_plural(forms, "stáročia", "stáročí", "stáročiam",
			nil, "stáročiach", "stáročiami")
	end
 
	return forms, title
end

declensions["dievča"] = function(word, genitive)
	local forms = {}
	local stem = remove_suffix(word, "a")
	if ends_with(word, "ä") then
		stem = remove_suffix(word, "ä")
	end
	local ending = get_last_char(word)
	local title = "Declension of ''" .. word .. "'' (pattern " .. pattern_link("dievča") .. ")"
	
	local gen_pl = ""
	local syllable_count, syllables = split_into_syllables(word)
	local last_syllable = syllables[1]
	local penultimate_syllable = syllables[2] or ""
	
	if is_long(penultimate_syllable) then
		gen_pl = stem .. ending .. "t"
	else
		gen_pl = append_ending(stem, "iat")
	end
	
	append_endings(forms, word, stem,
		ending .. "ťa", ending .. "ťu", nil, ending .. "ti", ending .. "ťom",
		ending .. "tá", gen_pl, ending .. "tám", nil, ending .. "tách", ending .. "tami"
	)
	
	local pl_stem = harden_last_consonant(stem)
	append_second_plural(forms, pl_stem .. "ence", pl_stem .. "eniec", pl_stem .. "encom",
		nil, pl_stem .. "encoch", pl_stem .. "encami")
	
	if matches_any(word, {"kura", "strídža", "drumblence", "gajdence", "deťúrence"}) then
		switch_plural_forms(forms) --changes the prefered forms
		unset_alt_forms(forms)
	elseif matches_any(word, {"páža", "knieža", "kurča", "plánča", "pôrča",
		"zviera", "pachoľa", "mláďa", "dúpä", "chlápä", "žieňa", "nemluvňa"}) then
		unset_alt_forms(forms)
	elseif matches_any(word, {"prasa", "teľa", "šteňa"}) then
		local pl_stem = (word == "šteňa") and "šten" or stem
		append_second_plural(forms, pl_stem .. "ce", append_ending(pl_stem, "iec"),
			pl_stem .. "com", nil, pl_stem .. "coch", pl_stem .. "cami")
		switch_plural_forms(forms) --changes the prefered forms
	elseif word == "dieťa" then
		set_forms(forms,
			{"nom_pl", "gen_pl", "dat_pl", "acc_pl", "loc_pl", "ins_pl"},
			{"deti", "detí", "deťom", "deti", "deťoch", "deťmi"}
		)
		unset_alt_forms(forms)
	end
 
	return forms, title
end

declensions["adjective"] = function(word, genitive)
	local forms = {}
	local title = "Declension of ''" .. word .. "'' (adjective declension)"
	local ultimate, penultimate = get_last_letters(word)
	
	local lemma_form = word
	if NUMBER == "pl" then
		if ends_with(word, "é") then
			lemma_form = remove_suffix(word, "é") .. "ý"
		elseif ends_with(word, "ie") then
			lemma_form = remove_suffix(word, "ie") .. "í"
		elseif ends_with_any(word, {"ove", "ine"}) then
			lemma_form = remove_suffix(word, "e")
		elseif ends_with(word, "e") then
			lemma_form = remove_suffix(word, "e") .. "y"
		elseif ends_with(word, "í") and not soft_consonants_set[penultimate] then
			lemma_form = remove_suffix(word, "í") .. "ý"
		elseif ends_with(word, "i") and not soft_consonants_set[penultimate] then
			lemma_form = remove_suffix(word, "i") .. "y"
		end
	else
		if GENDER == "f" or GENDER == "n" then
			if ends_with_any(word, {"á", "é"}) then
				lemma_form = remove_last_char(word) .. "ý"
			elseif ends_with_any(word, {"ia", "ie"}) then
				lemma_form = remove_suffix(remove_last_char(word), "i") .. "í"
			elseif ends_with_any(word, {"ova", "ovo", "ina", "ino"}) then
				lemma_form = remove_last_char(word)
			elseif ends_with_any(word, {"a", "e"}) then
				lemma_form = remove_last_char(word) .. "y"
			end
		end
	end
	
	local forms_raw = m_adj.do_generate_forms({pagename=lemma_form}, "adjective").forms
	
	set_forms(forms,
		{"nom_sg"},
		{forms_raw["nom_" .. get_first_char(GENDER)][1].form}
	)
	
	-- Singular
	if GENDER == "f" then
		set_forms(forms,
			{"gen_sg", "dat_sg", "loc_sg", "ins_sg"},
			{
				forms_raw["gen_f"][1].form, forms_raw["dat_f"][1].form,
				forms_raw["loc_f"][1].form, forms_raw["ins_f"][1].form
			}
		)
	else
		set_forms(forms,
			{"gen_sg", "dat_sg", "loc_sg", "ins_sg"},
			{
				forms_raw["gen_mn"][1].form, forms_raw["dat_mn"][1].form,
				forms_raw["loc_mn"][1].form, forms_raw["ins_mn"][1].form
			}
		)
	end
	
	-- special accusative singular
	if GENDER == "m-pr" or GENDER == "m-anml" then
		set_forms(forms,
			{"acc_sg"},
			{forms_raw["acc_m_an"][1].form}
		)
	elseif GENDER == "m-in" then
		set_forms(forms,
			{"acc_sg"},
			{forms_raw["acc_m_in"][1].form}
		)
	else
		set_forms(forms,
			{"acc_sg"},
			{forms_raw["acc_" .. get_first_char(GENDER)][1].form}
		)
	end
	
	-- Plural
	set_forms(forms,
		{"gen_pl", "dat_pl", "loc_pl", "ins_pl"},
		{
			forms_raw["gen_p"][1].form, forms_raw["dat_p"][1].form,
			forms_raw["loc_p"][1].form, forms_raw["ins_p"][1].form
		}
	)
	
	if GENDER == "m-pr" then
		set_forms(forms,
			{"nom_pl", "acc_sg", "acc_pl"},
			{forms_raw["nom_mp_an"][1].form, forms_raw["acc_m_an"][1].form, forms_raw["acc_mp_an"][1].form}
		)
	else
		set_forms(forms,
			{"nom_pl", "acc_pl"},
			{forms_raw["nom_fnp"][1].form, forms_raw["acc_fnp"][1].form}
		)
	end
 
	return forms, title
end

declensions["indeclinable"] = function(word, genitive)
	local forms = {}
	local title = "Declension of ''" .. word .. "'' (indeclinable)"
	
	local cases = {"nom", "gen", "dat", "acc", "loc", "ins"}  -- List of cases
	local numbers = {"sg", "pl"}
	for _, case in ipairs(cases) do
		for _, number in ipairs(numbers) do
			local form_key = case .. "_" .. number
			forms[form_key] = word
		end
	end
	
	-- Surnames ending with -ů, -eje, -oje and -ovie
	if TYPE == "surn" and ends_with_any(word, {"ů", "eje", "e", "oje", "ovie"}) then
		append_second_plural(forms, word .. "ovci", word .. "ovcov", word .. "ovcom",
			word .. "ovcov", word .. "ovcoch", word .. "ovcami")
	end
	
	return forms, title
end

--[=[
	Partial declination functions
]=]--

function check_gender(gender)
	if gender == nil then
		return error("No gender entered. Please pass one of these values as parameter 1: m-pr, m-anml, m-in, f, n.")
	elseif allowed_genders_set[gender] then
		return gender
	else
		return error("Unknown gender. Please pass one of these values as parameter 1: m-pr, m-anml, m-in, f, n.")
	end
end

function determine_pattern(word, genitive)
	local pattern
	
	local phon_word = (PRONUNCIATION) and PRONUNCIATION or word
	
	local ultimate, penultimate = get_last_letters(phon_word)
	local first = get_first_char(phon_word)
	
	local dlan_endings = m_table.listToSet({"ň", "č", "ž", "ľ", "ď", "j", "š", "m", "z", "dz", "x"})
	local dlan_exceptions_neg = m_table.listToSet({"reč", "seč", "lož", "beľ", "soľ", "mlaď", "meď", "myš", "voš"})
	local dlan_exceptions_pos = m_table.listToSet({"obec", "pec", "čelusť", "kysť", "päsť", "Provence"})
	local dlan_end_with_r_t = m_table.listToSet({"kader", "neter", "šír", "tvár",
		"činovať", "drobäť", "droboť", "hať", "hrochoť", "Hrochoť", "hrsť", "inovať", "labuť",
		"niť", "obeť", "paruť", "pažiť", "pečať", "perepúť", "perleť", "peruť", "pípeť", "plť",
		"postať", "prť", "púť", "sieť", "sihoť", "stať", "štvrť", "trať", "úvrať", "vňať",
		"violeť", "záhať", "žlť"})
	local stroj_exceptions_pos = {"timbre", "cól", "gáfor", "hámor", "kôpor",
		"kufor", "Pôtor", "šiator", "pedál", "sandál", "kanál", "peniaz", "daniel"}
	local stroj_exceptions_neg = {"nesvár", "nešvár", "pár", "suchopár", "svár", "ker"}
	
	if matches_any(ultimate, {"r", "l"}) and penultimate == "e" and not ends_with(phon_word, "ier") and genitive == nil then
		genitive = phon_word .. "a"
	end
	
	if mw.ustring.find(phon_word, " ") then
		return "indeclinable"
	end
	
	if NUMBER == "pl" then
		if matches_any(ultimate, {"é", "i", "í"}) or (ultimate == "e" and ends_with(genitive, "ch")) then
			pattern = "adjective"
		elseif GENDER == "m-in" then
			if ultimate == "y" then
				pattern = "dub"
			else
				pattern = "stroj"
			end
		elseif GENDER == "f" then
			if ultimate == "y" then
				pattern = "žena"
			else
				pattern = "ulica"
			end
		elseif GENDER == "n" then
			if ultimate == "á" then
				pattern = "mesto"
			elseif penultimate == "i" and ultimate == "a" then
				pattern = "srdce"
			else
				if soft_consonants_set[penultimate] then
					pattern = "srdce"
				else
					pattern = "mesto"
				end
			end
		end
	else
		if GENDER == "m-pr" then
			if (matches_any(ultimate, {"y", "ý", "i", "í"}) and not ends_with_any(genitive, {"[yií]ho", "a"})
				and not (TYPE == "surn" and matches_any(penultimate .. ultimate, {"ay", "ai"})))
				or (matches_any(penultimate .. ultimate, {"ov", "in"}) and ends_with_any(genitive, {"ovho", "inho"}))
			then
				pattern = "adjective"
			elseif ultimate == "a"
				or (TYPE == "surn" and matches_any(ultimate, {"e", "ě"}) and (penultimate .. ultimate == "ně" or ends_with(genitive, "u")))
			then
				pattern = "hrdina"
			elseif (matches_any(ultimate, {"i", "í", "y", "e", "é", "ä"})
				or (TYPE == "name" and matches_any(ultimate, {"ü", "ö", "ő"}))
				or matches_any(phon_word, {"Hrabě", "Poupě"}))
				and not (TYPE == "surn" and (ends_with_any(phon_word, {"ay", "ai", "eje", "oje", "ovie"}) or ends_with(genitive, "a")))
			then
				pattern = "kuli"
			elseif TYPE == "surn" and ends_with_any(phon_word, {"ů", "eje", "oje", "ovie"}) then
				pattern = "indeclinable"
			else
				pattern = "chlap"
			end
		elseif GENDER == "m-in" or GENDER == "m-anml" then
			if matches_any(ultimate, {"y", "ý", "i", "í"})
				or (matches_any(penultimate .. ultimate, {"ov", "in"}) and ends_with(genitive, "ho"))
			then
				pattern = "adjective"
			elseif (soft_consonants_set[ultimate]
				or (matches_any(ultimate, {"r", "l"}) and penultimate == "e"
					and (ends_with(genitive, "[^e][rl]a")))
				or ends_with_any(phon_word, {"ár", "iar", "ier"})
				or matches_any(phon_word, stroj_exceptions_pos))
				and not matches_any(phon_word, stroj_exceptions_neg)
			then
				pattern = "stroj"
			else
				pattern = "dub"
			end
		elseif GENDER == "f" then
			if matches_any(phon_word, {"gazdiná", "švagriná", "testiná", "ujčiná", "stryná",
				"kňažná", "kráľovná", "cisárovná", "cárovná", "šľachtičná", "princezná"
			}) then
				pattern = "gazdiná"
			elseif ultimate == "a" and not ends_with(genitive, "ej") then
				if soft_consonants_set[penultimate] or matches_any(penultimate, {"i", "y"}) or matches_any(phon_word, {"rozopra", "konopa", "večera"}) then
					pattern = "ulica"
				else
					pattern = "žena"
				end
			elseif matches_any(ultimate, {"a", "á"})
				or (matches_any(penultimate .. ultimate, {"ova", "ina"}) and ends_with(genitive, "ej"))	
			then
				pattern = "adjective"
			elseif ends_with(phon_word, "pani") or matches_any(phon_word, {"Mať", "mať", "mater", "mati"}) then
				pattern = "irregular"
			else
				if not dlan_exceptions_neg[phon_word]
					and (dlan_endings[ultimate] or dlan_exceptions_pos[phon_word]
						or dlan_end_with_r_t[phon_word] or (penultimate == "š" and ultimate == "ť" and not is_capital(first)))
				then
					pattern = "dlaň"
				else
					pattern = "kosť"
				end
			end
			
			if genitive then
				local g_ultimate = get_last_char(genitive)
				if g_ultimate == "y" then
					pattern = "žena"
				elseif g_ultimate == "i" then
					pattern = "kosť"
				end
			end
		elseif GENDER == "n" then
			if (ultimate == "o" or (penultimate == "u" and ultimate == "m")
				or (penultimate == "o" and ultimate == "n")
				or (penultimate == "m" and ultimate == "ä"))
				and not ends_with(genitive, "ho")
			then
				pattern = "mesto"
			elseif (penultimate == "i" and ultimate == "e")
				or ultimate == "í"
			then
				pattern = "vysvedčenie"
			elseif (ultimate == "e" or ultimate == "ě")
				and not ends_with(genitive, "ho")
			then
				pattern = "srdce"
			elseif matches_any(ultimate, {"a", "ä"}) then
				pattern = "dievča"
			elseif matches_any(ultimate, {"e", "é"})
				or matches_any(penultimate .. ultimate, {"ovo", "ino"})
			then
				pattern = "adjective"
			else
				pattern = "indeclinable"
			end
		end
	end
	
	return pattern
end

function append_ending(stem1, ending)
	if matches_any(get_first_char(ending), {"e", "i", "é", "í"}) then
		return harden_last_consonant(stem1) .. ending
	else
		return stem1 .. ending
	end
end

function append_endings(forms, word, stem, end2, end3, end4, end5, end6, end7, gen_pl, end9, end10, end11, end12)
	forms["nom_sg"] = word
	forms["gen_sg"] = append_ending(stem, end2)
	forms["dat_sg"] = append_ending(stem, end3)
	if GENDER == "m-pr"
		or (GENDER == "f"
			and (ends_with_any(word, {"pani", "a", "á"})
				or matches_any(word, {"Mať", "mať", "mater", "mati"})))
	then
		forms["acc_sg"] = append_ending(stem, end4)
	else
		forms["acc_sg"] = word
	end
	forms["loc_sg"] = append_ending(stem, end5)
	forms["ins_sg"] = append_ending(stem, end6)
	
	local nom_pl = stem
	if ends_with_any(stem, {"k", "ch"}) and matches_any(GENDER, {"m-pr", "m-anml"}) and end7 == "i" then
		if ends_with(stem, "k") then
			nom_pl = remove_suffix(stem, "k") .. "c"
		else
			nom_pl = remove_suffix(stem, "ch") .. "s"
		end
	end
	forms["nom_pl"] = append_ending(nom_pl, end7)
	forms["gen_pl"] = gen_pl
	forms["dat_pl"] = append_ending(stem, end9)
	if GENDER == "m-pr"
		or end10
		or (GENDER == "f"
			and (ends_with_any(word, {"pani"})
				or matches_any(word, {"Mať", "mať", "mater", "mati"})))
	then
		forms["acc_pl"] = append_ending(stem, end10)
	else
		forms["acc_pl"] = forms["nom_pl"]
	end
	forms["loc_pl"] = append_ending(stem, end11)
	forms["ins_pl"] = append_ending(stem, end12)
end

function set_forms(forms, indices, values)
	for i = 1, #indices do
		forms[indices[i]] = values[i]
	end
end

function switch_plural_forms(forms)
	local indices = {"nom_pl", "gen_pl", "dat_pl", "acc_pl", "loc_pl", "ins_pl"}
	for _, index in ipairs(indices) do
		forms[index], forms[index .. "_alt"] = forms[index .. "_alt"], forms[index]
	end
end

function unset_alt_forms(forms)
	for key in pairs(forms) do
		if mw.ustring.find(key, "_alt$") then
			forms[key] = nil
		end
	end
end

function append_alternative_singular(forms, form2, form3, form4, form5, form6)
	forms["gen_sg2"] = (forms["gen_sg"] ~= form2) and form2
	forms["dat_sg2"] = (forms["dat_sg"] ~= form3) and form3
	if matches_any(GENDER, {"m-pr", "m-anml"})
		or (GENDER == "f"
			and (ends_with_any(word, {"pani", "a", "á"})
				or matches_any(word, {"Mať", "mať", "mater", "mati"})))
	then
		forms["acc_sg2"] = (forms["acc_sg"] ~= form4) and form4
	end
	forms["loc_sg2"] = (forms["loc_sg"] ~= form5) and form5
	forms["ins_sg2"] = (forms["ins_sg"] ~= form6) and form6
end

function append_alternative_plural(forms, form1, form2, form3, form4, form5, form6)
	forms["nom_pl2"] = (forms["nom_pl"] ~= form2) and form1
	forms["gen_pl2"] = (forms["gen_pl"] ~= form2) and form2
	forms["dat_pl2"] = (forms["dat_pl"] ~= form2) and form3
	if form4 ~= nil and forms["acc_pl"] ~= form4 then
		forms["acc_pl2"] = form4
	elseif forms["acc_pl"] ~= form1 then
		forms["acc_pl2"] = form1
	end
	forms["loc_pl2"] = (forms["loc_pl"] ~= form2) and form5
	forms["ins_pl2"] = (forms["ins_pl"] ~= form2) and form6
end

function append_second_plural(forms, form1, form2, form3, form4, form5, form6)
	forms["nom_pl_alt"] = form1
	forms["gen_pl_alt"] = form2
	forms["dat_pl_alt"] = form3
	if form4 ~= nil then
		forms["acc_pl_alt"] = form4
	else
		forms["acc_pl_alt"] = forms["nom_pl_alt"]
	end
	forms["loc_pl_alt"] = form5
	forms["ins_pl_alt"] = form6
end

function append_animal_singular(forms, stem)
	set_forms(forms,
		{"gen_sg", "dat_sg", "acc_sg", "loc_sg"},
		{
			append_ending(stem, "a"),
			append_ending(stem, "ovi"),
			append_ending(stem, "a"),
			append_ending(stem, "ovi")
		}
	)
end

function get_last_char(str)
	local last = mw.ustring.sub(str, -1, -1)
	return last
end

function get_first_char(str)
	local first = mw.ustring.sub(str, 1, 1)
	return first
end

function remove_last_char(str)
	local stem = mw.ustring.sub(str, 1, -2)
	return stem
end

function is_capital(str)
	return mw.ustring.find(str, "[A-Z]")
end

function get_last_letters(word)
	local ultimate = get_last_char(word)
	local penultimate = get_last_char(remove_last_char(word))
	local antepenultimate = get_last_char(remove_last_char(remove_last_char(word)))
	
	if (penultimate == "c" and ultimate == "h")
		or (penultimate == "d" and (ultimate == "z" or ultimate == "ž"))
	then
		ultimate = penultimate .. ultimate
		penultimate = antepenultimate
		antepenultimate = get_last_char(remove_last_char(remove_last_char(remove_last_char(word))))
	end
	
	if (antepenultimate == "c" and penultimate == "h")
		or (antepenultimate == "d" and (penultimate == "z" or penultimate == "ž"))
	then
		penultimate = antepenultimate .. penultimate
	end
	
	if penultimate == "v" and consonants_set[ultimate] and not matches_any(ultimate, {"r", "l", "ŕ", "ĺ"}) then
		penultimate = "ʋ"
	end
	
	return ultimate, penultimate
end

function ends_with(word, suffix)
	-- Check if suffix matches the end of word
	word = (word ~= nil) and word or ""
	return mw.ustring.find(word, suffix .. "$") ~= nil
end

function ends_with_any(word, suffixes)
	for _, suffix in ipairs(suffixes) do
		if ends_with(word, suffix) then
			return true  -- Return true if any suffix matches
		end
	end
	return false  -- Return false if no suffix matches
end

function matches_any(value, list)
	for _, item in ipairs(list) do
		if value == item then
			return true
		end
	end
	return false
end

function get_vowel(syllable)
	-- Define patterns for diphthongs and vowels
	local diphthong_pattern = "ia|ie|iu|ô"
	local vowel_pattern = "[aeiouyáéíóúýäöőüű]"
	local syllabic_consonant_pattern = "[rl]"

	-- Check for a diphthong first
	local diphthong = mw.ustring.match(syllable, diphthong_pattern)
	if diphthong then
		return diphthong
	end

	-- Check for a single vowel
	local vowel = mw.ustring.match(syllable, vowel_pattern)
	if vowel then
		return vowel
	end

	-- Check for a syllabic consonant if no vowel is found
	local syllabic_consonant = mw.ustring.match(syllable, syllabic_consonant_pattern)
	if syllabic_consonant then
		return syllabic_consonant
	end

	return nil  -- Return nil if no vowel or syllabic consonant is found
end

-- Function to split a word into characters and bigraphs
function split_into_letter_units(word)
	local units = {}
	local i = 1
	local length = mw.ustring.len(word)

	while i <= length do
		local two_char = mw.ustring.sub(word, i, i + 1)
		
		-- Check if the two-character sequence is a bigraph or diphthong
		if bigraphs_set[two_char] or diphthongs_set[two_char] then
			table.insert(units, two_char)
			i = i + 2
		else
			-- If not a bigraph/diphthong, treat it as a single character
			table.insert(units, mw.ustring.sub(word, i, i))
			i = i + 1
		end
	end
	
	return units
end

-- check if a unit is a vowel or syllabic element
function is_vowel(unit, prev_unit, next_unit)
	if diphthongs_set[unit] then return true end
	if vowels_set[unit] then return true end
	
	-- Check if 'r' or 'l' are syllabic (preceded and followed by consonants)
	if matches_any(unit, {"r", "ŕ", "l", "ĺ"})
		and prev_unit and next_unit
		and not (vowels_set[prev_unit] or vowels_set[next_unit]
		or diphthongs_set[prev_unit] or diphthongs_set[next_unit])
	then
		return true
	end
	
	return false
end

-- Function to split a word into syllables according to Slovak rules
function split_into_syllables(word)
	local units = split_into_letter_units(word)
	local syllables = {}
	local current_syllable = ""
	local i = 1
	local length = #units
	local first_vowel_found = false  -- Flag to indicate when the first vowel has been encountered

	-- Iterate over the units in the word
	while i <= length do
		local unit = units[i]
		local next_unit = i < length and units[i + 1] or nil
		local previous_unit = i > 1 and units[i - 1] or nil
		local is_current_vowel = is_vowel(unit, previous_unit, next_unit)
		
		-- If we haven't encountered the first vowel, keep adding to the first syllable
		if not first_vowel_found then
			current_syllable = current_syllable .. unit
			if is_current_vowel then
				first_vowel_found = true  -- Mark that the first vowel has been found
			end
		else
			if is_current_vowel then
				-- If a vowel is encountered after the first vowel has been found, finalize the current syllable
				if current_syllable ~= "" and is_vowel(previous_unit, nil, nil) then
					table.insert(syllables, current_syllable)
					current_syllable = ""
				end
				current_syllable = current_syllable .. unit
			else
				-- Handling consonants between vowels
				local consonant_cluster = unit

				-- Collect any consecutive consonants into a cluster
				local j = i + 1
				while j <= length and not is_vowel(units[j], units[j - 1], units[j + 1]) do
					consonant_cluster = consonant_cluster .. units[j]
					j = j + 1
				end

				local consonant_count = mw.ustring.len(consonant_cluster)

				if next_unit and is_vowel(next_unit, unit, units[j]) then
					-- Apply syllable rules based on the number of consonants in the cluster
					if consonant_count == 1 then
						-- Rule 3: Single consonant goes to the next syllable
						table.insert(syllables, current_syllable)  -- End the current syllable without the consonant
						current_syllable = consonant_cluster	   -- Start the next syllable with the consonant
					elseif consonant_count == 2 then
						-- Rule 4: Two consonants split between syllables
						current_syllable = current_syllable .. mw.ustring.sub(consonant_cluster, 1, 1)
						table.insert(syllables, current_syllable)
						current_syllable = mw.ustring.sub(consonant_cluster, 2, 2)
					else
						-- Rule 5: Three or more consonants - first goes with current syllable, rest with next
						current_syllable = current_syllable .. mw.ustring.sub(consonant_cluster, 1, 1)
						table.insert(syllables, current_syllable)
						current_syllable = mw.ustring.sub(consonant_cluster, 2)
					end
					i = j - 1  -- Adjust the index to skip the processed consonants
				else
					current_syllable = current_syllable .. unit
				end
			end
		end

		i = i + 1
	end

	-- Add any remaining characters as the final syllable
	if #current_syllable > 0 then
		table.insert(syllables, current_syllable)
	end

	-- Reverse the syllables array for the requested output order
	local reversed_syllables = {}
	for j = #syllables, 1, -1 do
		reversed_syllables[#reversed_syllables + 1] = syllables[j]
	end

	-- Return the count of syllables and the reversed syllable array
	return #syllables, reversed_syllables
end

function is_long(syllable)
	return mw.ustring.find(syllable, "[áéíóúýôĺŕ]") ~= nil or mw.ustring.find(syllable, "i[aeu]") ~= nil
end

function is_short(syllable)
	return not is_long(syllable)
end

local function get_last_consonant_before_vowel(syllable)
	local vowel = get_vowel(syllable)
	
	-- If there is no vowel in the syllable, return false
	if not vowel then
		return false
	end

	-- Find the position of the vowel in the syllable
	local vowel_pos = mw.ustring.find(syllable, vowel)

	-- Loop backwards from the position of the vowel to find the last consonant
	for i = vowel_pos - 1, 1, -1 do
		local char = mw.ustring.sub(syllable, i, i)
		if not mw.ustring.find(char, "[aeiouáéíóúýôä]") then
			return char  -- Return the last consonant before the vowel
		end
	end

	return false  -- Return false if no consonant is found before the vowel
end

-- Function to lengthen the last vowel in a syllable if it’s not already long
function lengthen_vowel(syllable)
	if is_long(syllable) then
		return syllable  -- Return as-is if the syllable is already long
	end

	local lengthening_map = {
		["a"] = "á", ["i"] = "í", ["y"] = "ý", ["u"] = "ú",
		["ä"] = "ia", ["e"] = "ie", ["o"] = "ô"
	}
	
	local cons_map = {
		["ď"] = "d", ["ť"] = "t", ["ň"] = "n", ["ľ"] = "l"
	}

	-- Check for regular vowels first and replace if found
	for vowel, long_vowel in pairs(lengthening_map) do
		if mw.ustring.find(syllable, vowel) then
			-- if there is a soft consonant before "a", it becomes "ia" instead of "á"
			local last_cons = get_last_consonant_before_vowel(syllable) or ""
			if soft_consonants_set[last_cons] and last_cons ~= "j" and vowel == "a" then
				long_vowel = "ia"
			end
			
			-- if a or ä changes into "ia", the previous consonant should be written as hard
			if matches_any(vowel, {"ä", "a"}) and matches_any(last_cons, {"ď", "ť", "ň", "ľ"}) then
				syllable = mw.ustring.gsub(syllable, last_cons .. vowel, cons_map[last_cons] .. vowel, 1)
			end
			
			syllable = mw.ustring.gsub(syllable, vowel, long_vowel, 1)
			return syllable  -- Return immediately after replacing a regular vowel
		end
	end

	-- Only replace "r" and "l" if no other vowels were found
	if not mw.ustring.find(syllable, "[aeiouyáéíóúýôä]") then
		syllable = mw.ustring.gsub(syllable, "r", "ŕ")
		syllable = mw.ustring.gsub(syllable, "l", "ĺ")
	end

	return syllable
end

-- Helper function to determine if the syllable ends with a consonant cluster
function ends_with_consonant_cluster(last_syllable)
	local last_char = get_last_char(last_syllable)
	local second_last_char = mw.ustring.sub(last_syllable, -2, -2)
	local third_last_char = mw.ustring.sub(last_syllable, -3, -3)
	local last_two_chars = mw.ustring.sub(last_syllable, -2)

	-- Check if the syllable contains any regular vowels
	local has_vowel = mw.ustring.find(last_syllable, "[aeiouyáéíóúýôä]")

	if has_vowel then
		-- If the last two characters form a digraph, check the third-last character for a cluster
		if bigraphs_set[last_two_chars] then
			return not vowels_set[third_last_char]
		else
			-- If no digraph, just check the last two characters
			return not (vowels_set[last_char] or vowels_set[second_last_char]
				or diphthongs_set[last_char] or diphthongs_set[second_last_char])
		end
	else
		-- No regular vowel; treat `r` or `l` as syllabic if either is in the last two characters
		if matches_any(last_char, {'ŕ', 'ĺ'}) or matches_any(second_last_char, {'ŕ', 'ĺ'}) then
			return false
		elseif mw.ustring.find(last_syllable, "[bcčdďfghjkľmnňpqsštťvwxzž][rl][bcčdďfghjkľmnňpqysštťvwxzž][rl]$") then
			return true
		else
			-- No syllabic `r` or `l`, so both characters are treated as consonants
			return not vowels_set[last_char] and not vowels_set[second_last_char]
		end
	end
end

function remove_mobile_vowel(word)
	local units = split_into_letter_units(word)  -- Split word into units
	for i = #units, 1, -1 do
		local unit = units[i]
		if matches_any(unit, {"e", "ie", "o", "i", "á"}) then
			-- Remove the mobile vowel unit and reassemble the word
			table.remove(units, i)
			return table.concat(units)
		end
	end
	return word  -- Return the original word if no mobile vowel is found
end

function soften_last_consonant(str)

	local consonants_t = { ["c"] = "č", ["d"] = "ď", ["l"] = "ľ", ["n"] = "ň",
		["s"] = "š", ["t"] = "ť", ["z"] = "ž" }
	local last_char = get_last_char(str)
	
	-- Check if the last character is in consonants_t and replace if needed
	return consonants_t[last_char] and remove_last_char(str) .. consonants_t[last_char] or str
end

function harden_last_consonant(str)
	local soft_to_hard = { ["ď"] = "d", ["ť"] = "t", ["ň"] = "n", ["ľ"] = "l" }
	local last_char = get_last_char(str)
	
	-- Check if the last character is a soft consonant and replace if needed
	return soft_to_hard[last_char] and remove_last_char(str) .. soft_to_hard[last_char] or str
end

function remove_suffix(form, suffix)
	if mw.ustring.find(form, suffix .. "$") then
		local length = mw.ustring.len(suffix)
		return mw.ustring.sub(form, 1, -length-1)
	end

	return form
end

function pattern_link(pattern)
	return "''[[Appendix:Slovak declension pattern " .. pattern .. "|" .. pattern .. "]]''"
end

function decline_with_more_stems(genitive)
	local genitives = {}
	for part in mw.ustring.gmatch(genitive, "[^/]+") do
		table.insert(genitives, part)
	end
	
	local forms, title = declensions[PATTERN](PAGENAME, genitives[1])
	normalize_forms(forms)
	local forms2, title2 = declensions[PATTERN](PAGENAME, genitives[2])
	normalize_forms(forms2)
	
	append_alternative_singular(forms, forms2["gen_sg"], forms2["dat_sg"], forms2["acc_sg"],
		forms2["loc_sg"], forms2["ins_sg"])
	append_alternative_plural(forms, forms2["nom_pl"], forms2["gen_pl"], forms2["dat_pl"],
		forms2["acc_pl"], forms2["loc_pl"], forms2["ins_pl"])
	
	return forms, title
end

function split_into_units(expression, genitive)
	-- Split the original expression into words
	local words = {}
	for word in mw.ustring.gmatch(expression, "%S+") do
		table.insert(words, word)
	end

	-- Split the genitive phrase into words, if provided
	local gen_words = {}
	if genitive then
		for word in mw.ustring.gmatch(genitive, "%S+") do
			table.insert(gen_words, word)
		end
		-- Check if the genitive phrase has the same structure as the original
		if #gen_words ~= #words then
			error("Genitive phrase must have the same number of words as the original expression.")
		end
	end

	-- Combine words into units, grouping prepositional phrases for both expressions
	local units = {}
	local gen_units = {}
	local i = 1
	while i <= #words do
		if prepositions_set[words[i]] and words[i + 1] then
			-- Combine preposition with the following words as one unit
			local phrase = words[i]
			local gen_phrase = genitive and gen_words[i] or nil
			
			i = i + 1
			while i <= #words do
				phrase = phrase .. " " .. words[i]
				if genitive then
					gen_phrase = gen_phrase .. " " .. gen_words[i]
				end
				if i == #words then
					table.insert(units, phrase)
					if genitive then table.insert(gen_units, gen_phrase) end
				end
				i = i + 1
			end
		else
			-- Add standalone word as a unit
			table.insert(units, words[i])
			if genitive then
				table.insert(gen_units, gen_words[i])
			end
			i = i + 1
		end
	end

	-- Return both units and genitive units
	return units, gen_units
end

function generate_combined_forms(units, gen_units)
	-- Process each unit to generate forms
	local all_forms = {}
	local patterns = ""
	for i = 1, #units do
		local unit = units[i]
		local gen_unit = gen_units[i]
		if conjunctions_set[unit] or unit == gen_unit then
			-- Conjunctions are indeclinable
			local forms = declensions["indeclinable"](unit, gen_unit)
			table.insert(all_forms, forms)
		else
			-- Decline each unit using determine_pattern and declensions
			local pattern = determine_pattern(unit, gen_unit)
			local forms, title = declensions[pattern](unit, gen_unit)
			normalize_forms(forms)
			table.insert(all_forms, forms)
		end
	end
	
	-- Combine forms into a single forms table
	local combined_forms = {}
	local cases = {"nom", "gen", "dat", "acc", "loc", "ins"}
	local numbers = {"sg", "pl"}
	
	-- check if vocative and plural 2 forms are necessary
	for _, forms in ipairs(all_forms) do
		if forms["voc_sg"] and #cases == 6 then
			table.insert(cases, "voc")
		end
		if forms["nom_pl_alt"] and #numbers == 2 then
			table.insert(numbers, "pl_alt")
		end
	end

	for _, case in ipairs(cases) do
		for _, number in ipairs(numbers) do
			local form_key = case .. "_" .. number
			local combined_form, highest_index = {}, 1

			-- Gather primary and numbered alternative forms (e.g., gen_sg2, gen_sg3)
			for _, forms in ipairs(all_forms) do
				local primary_form = forms[form_key] or forms["nom_" .. number] or forms[case .. "_pl"]
				table.insert(combined_form, primary_form)

				-- Check the highest alternative index
				for alt_index = 2, 4 do
					local alt_key = form_key .. alt_index
					if forms[alt_key] then
						highest_index = alt_index
					end
				end
			end

			-- Combine primary forms
			combined_forms[form_key] = mw.ustring.gsub(table.concat(combined_form, " "), "^%s+", "")

			-- Combine alternative forms if present
			if highest_index > 1 then
				for alt_index = 2, highest_index do
					-- Check and add numbered alternative forms
					local alt_key = form_key .. alt_index
					alt_form = {}
					for _, forms in ipairs(all_forms) do
						local primary_form = forms[form_key] or forms["nom_" .. number]
						if forms[alt_key] then
							table.insert(alt_form, forms[alt_key])
						else
							table.insert(alt_form, primary_form)
						end
					end
					combined_forms[alt_key] = mw.ustring.gsub(table.concat(alt_form, " "), "^%s+", "")
				end
			end
		end
	end
	
	return combined_forms
end

function normalize_forms(forms)
	-- Step 1: Remove forms based on NUMBER
	if NUMBER == "sg" then
		for key in pairs(forms) do
			if mw.ustring.find(key, "_pl") then
				forms[key] = nil  -- Remove plural forms if "n" is "sg"
			end
		end
	elseif NUMBER == "pl" then
		for key in pairs(forms) do
			if mw.ustring.find(key, "_sg") then
				forms[key] = nil  -- Remove singular forms if "n" is "pl"
			end
		end
	end

	-- Step 2: Ensure all mandatory indices are set
	local cases = {"nom", "gen", "dat", "acc", "loc", "ins"}
	local numbers = {"sg", "pl"}
	for _, case in ipairs(cases) do
		for _, number in ipairs(numbers) do
			local form_key = case .. "_" .. number
			if not forms[form_key] then
				forms[form_key] = "&mdash;"  -- Set missing forms to &mdash;
			end
		end
	end

	-- Step 3: Create missing _pl_alt indices if at least one exists
	local has_alt_plural = false
	for key in pairs(forms) do
		if mw.ustring.find(key, "_pl_alt") then
			has_alt_plural = true
			break
		end
	end
	if has_alt_plural then
		for _, case in ipairs(cases) do
			local form_key_alt = case .. "_pl_alt"
			if not forms[form_key_alt] then
				forms[form_key_alt] = "&mdash;"  -- Create missing _pl_alt forms
			end
		end
	end

	-- Step 4: Create vocative plural forms if voc_sg exists
	if forms["voc_sg"] then
		forms["voc_pl"] = forms["nom_pl"]  -- Set voc_pl to nom_pl
		if has_alt_plural then
			forms["voc_pl_alt"] = forms["nom_pl_alt"]  -- Set voc_pl_alt to nom_pl_alt if it exists
		end
	end
end

function specified_by_user(forms, args)
	local cases = {nom = true, gen = true, dat = true, acc = true, voc = true, loc = true, ins = true}
	local numbers = {sg = true, pl = true}
	
	for key, value in pairs(args) do
		-- Match the pattern "<case>_<number><optional digit>" using mw.ustring.match
		local case, number, optional_digit = mw.ustring.match(key, "^(%a%a%a)_(%a%a)(%d?)$")
		
		-- Check if it matches the cases and numbers you want
		if case and cases[case] and number and numbers[number] then
			forms[key] = make_link(value, case .. "|" .. get_first_char(number))
		end
	end
end

function make_link(link, accel_form)
	local new_link = link

	-- If link is not empty, valid, and not "&mdash;", create the full link
	if link ~= "" and link and link ~= "&mdash;" then
		new_link = m_links.full_link({lang = lang, term = link, accel = {form = accel_form}})
	end

	return new_link
end

function make_table_header(title)
	local header = [=[<div class="NavFrame" style="max-width:50em">
	<div class="NavHead">]=] .. title .. [=[</div>
	<div class="NavContent">
	<table style="text-align:center" class="inflection-table">]=]

	return header
end

function make_simple_row(forms, case)
	local case_code = mw.ustring.sub(case, 1, 3)
	local row = "<tr><td style=\"background:#eff7ff\">'''" .. case .. "'''</td>"
	
	-- Singular
	if NUMBER ~= "pl" then
		row = row .. "<td><span lang=\"sk\">" .. make_link(forms[case_code .. "_sg"], case_code .. "|s") .. "</span>"
		
		-- Loop to check and display secondary singular forms in the same cell
		for i = 2, 4 do
			local form_key = case_code .. "_sg" .. i
			if not forms[form_key] then
				break  -- Exit loop if form doesn't exist
			end
			row = row .. ",<br /><span lang=\"sk\">" .. make_link(forms[form_key], case_code .. "|s") .. "</span>"
		end
		row = row .. "</td>"
	end

	-- Plural
	if NUMBER ~= "sg" then
		-- Primary plural form
		row = row .. "<td><span lang=\"sk\">" .. make_link(forms[case_code .. "_pl"], case_code .. "|p") .. "</span>"
	
		-- Loop to check and display secondary plural forms in the same cell
		for i = 2, 4 do
			local form_key = case_code .. "_pl" .. i
			if not forms[form_key] then
				break  -- Exit loop if form doesn't exist
			end
			row = row .. ",<br /><span lang=\"sk\">" .. make_link(forms[form_key], case_code .. "|p") .. "</span>"
		end
		row = row .. "</td>"
	
		-- Check for alternative plural and add it in a separate cell
		if forms[case_code .. "_pl_alt"] then
			row = row .. "<td><span lang=\"sk\">" .. make_link(forms[case_code .. "_pl_alt"], case_code .. "|p") .. "</span></td>"
		end
	end

	row = row .. "</tr>"

	return row
end

function make_table_header2(forms)
	local tr_open = "<tr><th style=\"background:#d9ebff; width: 10em;\"></th>"
	local singular = "<th style=\"background:#d9ebff\">singular</th>"
	local plural = "<th style=\"background:#d9ebff\">plural</th>"
	local plural1 = "<th style=\"background:#d9ebff\">plural 1</th>"
	local plural2 = "<th style=\"background:#d9ebff\">plural 2</th>"
	local tr_close = "</tr>"
	
	local alt_plural = false
	if forms["nom_pl_alt"] or forms["gen_pl_alt"] or forms["dat_pl_alt"]
		or forms["acc_pl_alt"] or forms["loc_pl_alt"] or forms["ins_pl_alt"]
	then
		alt_plural = true
	end
	
	local header
	
	if NUMBER == "sg" then
		header = tr_open .. singular .. tr_close
	elseif NUMBER == "pl" then
		if alt_plural then
			header = tr_open .. plural1 .. plural2 .. tr_close
		else
			header = tr_open .. plural .. tr_close
		end
	elseif alt_plural then
		header = tr_open .. singular .. plural1 .. plural2 .. tr_close
	else
		header = tr_open .. singular .. plural .. tr_close
	end

	return header
end

function make_table_footer()
	return "</table></div></div>"
end
 
-- Make the table
function make_table(forms, title)
	for key, form in pairs(forms) do
		-- check for empty strings and nil's
		if form == "" or not form then
			forms[key] = "&mdash;"
		end
	end

	local final = make_table_header(title)
	final = final .. make_table_header2(forms)
	final = final .. make_simple_row(forms, "nominative")
	final = final .. make_simple_row(forms, "genitive")
	final = final .. make_simple_row(forms, "dative")
	final = final .. make_simple_row(forms, "accusative")
	if forms["voc_sg"] then
		final = final .. make_simple_row(forms, "vocative")
	end
	final = final .. make_simple_row(forms, "locative")
	final = final .. make_simple_row(forms, "instrumental")

	final = final .. make_table_footer()
 
	return final
end
 
return export