Edge Rewrite
// HTMLRewriter · presentation

This page was redesigned at the edge.

Cloudflare fetched the original article and streamed it through HTMLRewriter to apply an entirely new visual system without rebuilding the source page.

Jump to content

Module:Sandbox/Thisasia

From Wikipedia, the free encyclopedia
local p = {}



local function dateCalculation(dateStr)
    local year , month, day = dateStr:match("(%d+)[/.,-](%d+)[/.,-](%d+)")
    if not year then
     day , month, year = dateStr:match("(%d+)[/.,-](%d+)[/.,-](%d+)")
    end 
    if not year then 
       return 'Invalid ' 
    end
    
        
    local currentDate = os.date("*t")
    local age = currentDate.year - tonumber(year)
    if currentDate.month < tonumber(month) or (currentDate.month == tonumber(month) and currentDate.day < tonumber(day)) then
        age = age - 1
    end
    
    local monthName = os.date("%B", os.time{year=tonumber(year), month=tonumber(month), day=tonumber(day)})
    return " ".. monthName .. " "..day..", " .. year.. " <br/>(Age " ..  age.. ")"
end





--[[ 
local function dateCalculation(dateStr)
    local year , month, day = dateStr:match("(%d+)[/.,-](%d+)[/.,-](%d+)")
    if not year then
        day , month, year = dateStr:match("(%d+)[/.,-](%d+)[/.,-](%d+)")
    end
    if not year then 
        return 'Invalid date format' 
    end
    
    local currentDate = os.date("*t")
    local age
        if tonumber(year) < 1582 or (tonumber(year) == 1582 and (tonumber(month) < 10 or (tonumber(month) == 10 and tonumber(day) < 4))) then
        age = currentDate.year - tonumber(year)
    else
         age = currentDate.year - tonumber(year)
        
         local leapYears = 0
        for i = tonumber(year), currentDate.year - 1 do
            if i % 4 == 0 then
                leapYears = leapYears + 1
            end
        end
                age = age - leapYears
    end
    
    if currentDate.month < tonumber(month) or (currentDate.month == tonumber(month) and currentDate.day < tonumber(day)) then
        age = age - 1
    end
    
    local monthName = os.date("%B", os.time{year=tonumber(year), month=tonumber(month), day=tonumber(day)})
    return " ".. monthName .. " "..day..", " .. year.. " <br/>(Age " ..  age.. ")"
end

]] 


--❗
--[[Volume conversions]] 
local function litersToGallons(liters)
    local litersValue = tonumber(liters:match("%d+%.?%d*"))
    if litersValue then
        local gallons = litersValue * 0.264172
        return "".. string.format("%.2f liters (%.2f gallons)", litersValue, gallons)
    end
    return liters
end

local function gallonsToLiters(gallons)
    local gallonsValue = tonumber(gallons:match("%d+%.?%d*"))
    if gallonsValue then
        local liters = gallonsValue * 3.78541
        return string.format("%.2f gallons (%.2f liters)", gallonsValue, liters)
    end
    return gallons
end

local function cubicMetersToCubicFeet(cubicMeters)
    local cubicMetersValue = tonumber(cubicMeters:match("%d+%.?%d*"))
    if cubicMetersValue then
        local cubicFeet = cubicMetersValue * 35.3147
        return string.format("%.2f cubic meters (%.2f cubic feet)", cubicMetersValue, cubicFeet)
    end
    return cubicMeters
end

local function cubicFeetToCubicMeters(cubicFeet)
    local cubicFeetValue = tonumber(cubicFeet:match("%d+%.?%d*"))
    if cubicFeetValue then
        local cubicMeters = cubicFeetValue * 0.0283168
        return string.format("%.2f cubic feet (%.2f cubic meters)", cubicFeetValue, cubicMeters)
    end
    return cubicFeet
end

-- Area conversions
local function squareMetersToSquareFeet(squareMeters)
    local squareMetersValue = tonumber(squareMeters:match("%d+%.?%d*"))
    if squareMetersValue then
        local squareFeet = squareMetersValue * 10.7639
        return string.format("%.2f square meters (%.2f square feet)", squareMetersValue, squareFeet)
    end
    return squareMeters
end

local function squareFeetToSquareMeters(squareFeet)
    local squareFeetValue = tonumber(squareFeet:match("%d+%.?%d*"))
    if squareFeetValue then
        local squareMeters = squareFeetValue * 0.092903
        return string.format("%.2f square feet (%.2f square meters)", squareFeetValue, squareMeters)
    end
    return squareFeet
end 

local function hectaresToAcres(hectares)
    local hectaresValue = tonumber(hectares:match("%d+%.?%d*"))
    if hectaresValue then
        local acres = hectaresValue * 2.47105
        return string.format("%.2f hectares (%.2f acres)", hectaresValue, acres)
    end
    return hectares
end

local function acresToHectares(acres)
    local acresValue = tonumber(acres:match("%d+%.?%d*"))
    if acresValue then
        local hectares = acresValue * 0.404686
        return string.format("%.2f acres (%.2f hectares)", acresValue, hectares)
    end
    return acres
end

-- Time conversions
local function hoursToMinutes(hours)
    local hoursValue = tonumber(hours:match("%d+%.?%d*"))
    if hoursValue then
        local minutes = hoursValue * 60
        return string.format("%.2f hours (%d minutes)", hoursValue, minutes)
    end
    return hours
end

local function minutesToHours(minutes)
    local minutesValue = tonumber(minutes:match("%d+%.?%d*"))
    if minutesValue then
        local hours = minutesValue / 60
        local decimalPart = minutes:match("%.(%d+)")
        if decimalPart then
            hours = hours + tonumber("0." .. decimalPart)
        end
        return string.format("%.2f minutes (%.2f hours)", minutesValue, hours)
    end
    return minutes
end


local function daysToHours(days)
    local daysValue = tonumber(days:match("%d+%.?%d*"))
    if daysValue then
        local hours = daysValue * 24
        return string.format("%.2f days (%d hours)", daysValue, hours)
    end
    return days
end

local function hoursToDays(hours)
    local hoursValue = tonumber(hours:match("%d+%.?%d*"))
    if hoursValue then
        local days = hoursValue / 24
        return string.format("%.2f hours (%.2f days)", hoursValue, days)
    end
    return hours
end

-- Energy conversions
local function joulesToCalories(joules)
    local joulesValue = tonumber(joules:match("%d+%.?%d*"))
    if joulesValue then
        local calories = joulesValue * 0.000239006
        return string.format("%.2f joules (%.6f calories)", joulesValue, calories)
    end
    return joules
end

local function caloriesToJoules(calories)
    local caloriesValue = tonumber(calories:match("%d+%.?%d*"))
    if caloriesValue then
        local joules = caloriesValue / 0.000239006
        return string.format("%.2f calories (%.2f joules)", caloriesValue, joules)
    end
    return calories
end

local function kilowattHoursToJoules(kWh)
    local kWhValue = tonumber(kWh:match("%d+%.?%d*"))
    if kWhValue then
        local joules = kWhValue * 3600000
        return string.format("%.2e kWh (%.2e joules)", kWhValue, joules)
    end
    return kWh
end

local function joulesToKilowattHours(joules)
    local joulesValue = tonumber(joules:match("%d+%.?%d*"))
    if joulesValue then
        local kWh = joulesValue / 3600000
        return string.format("%.2e joules (%d kWh)", joulesValue, kWh)
    end
    return joules
end

-- 🔴Pressure conversions
local function pascalsToPSI(pascals)
    local pascalsValue = tonumber(pascals:match("%d+"))
    if pascalsValue then
        local psi = pascalsValue * 0.000145038
        return string.format("%d pascals (%.6f PSI)", pascalsValue, psi)
    end
    return pascals
end

local function psiToPascals(psi)
    local psiValue = tonumber(psi:match("%d+"))
    if psiValue then
        local pascals = psiValue / 0.000145038
        return string.format("%.6f PSI (%d pascals)", psiValue, pascals)
    end
    return psi
end

local function atmospheresToPascals(atmospheres)
    local atmospheresValue = tonumber(atmospheres:match("%d+"))
    if atmospheresValue then
        local pascals = atmospheresValue * 101325
        return string.format("%d atmospheres (%d pascals)", atmospheresValue, pascals)
    end
    return atmospheres
end

local function pascalsToAtmospheres(pascals)
    local pascalsValue = tonumber(pascals:match("%d+"))
    if pascalsValue then
        local atmospheres = pascalsValue / 101325
        return string.format("%d pascals (%.6f atmospheres)", pascalsValue, atmospheres)
    end
    return pascals
end

-- Frequency conversions
local function hertzToRPM(hertz)
    local hertzValue = tonumber(hertz:match("%d+"))
    if hertzValue then
        local rpm = hertzValue * 60
        return string.format("%d Hertz (%d RPM)", hertzValue, rpm)
    end
    return hertz
end

local function rpmToHertz(rpm)
    local rpmValue = tonumber(rpm:match("%d+"))
    if rpmValue then
        local hertz = rpmValue / 60
        return string.format("%d RPM (%.2f Hertz)", rpmValue, hertz)
    end
    return rpm
end

local function kilohertzToHertz(kHz)
    local kHzValue = tonumber(kHz:match("%d+"))
    if kHzValue then
        local hertz = kHzValue * 1000
        return string.format("%d kHz (%d Hertz)", kHzValue, hertz)
    end
    return kHz
end

local function hertzToKilohertz(hertz)
    local hertzValue = tonumber(hertz:match("%d+"))
    if hertzValue then
        local kHz = hertzValue / 1000
        return string.format("%d Hertz (%.2f kHz)", hertzValue, kHz)
    end
    return hertz
end

-- Power conversions
local function wattsToHorsepower(watts)
    local wattsValue = tonumber(watts:match("%d+"))
    if wattsValue then
        local horsepower = wattsValue * 0.00134102
        return string.format("%d watts (%.6f horsepower)", wattsValue, horsepower)
    end
    return watts
end

local function horsepowerToWatts(horsepower)
    local horsepowerValue = tonumber(horsepower:match("%d+"))
    if horsepowerValue then
        local watts = horsepowerValue / 0.00134102
        return string.format("%.6f horsepower (%d watts)", horsepowerValue, watts)
    end
    return horsepower
end

local function megawattsToHorsepower(megawatts)
    local megawattsValue = tonumber(megawatts:match("%d+"))
    if megawattsValue then
        local horsepower = megawattsValue * 1341.02
        return string.format("%d megawatts (%.2f horsepower)", megawattsValue, horsepower)
    end
    return megawatts
end

local function horsepowerToMegawatts(horsepower)
    local horsepowerValue = tonumber(horsepower:match("%d+"))
    if horsepowerValue then
        local megawatts = horsepowerValue / 1341.02
        return string.format("%.2f horsepower (%d megawatts)", horsepowerValue, megawatts)
    end
    return horsepower
end

-- Add these functions to the p dynamic function to integrate them into the infobox
--❗
local function ftToCm(ft)
    local ftValue = tonumber(ft:match("%d+%.?%d*"))
    if ftValue then
        local cm = ftValue * 30.48
        return string.format("%.2f ft (%.2f cm)", ftValue, cm)
    end
    return ft
end 

local function cmToFeetAndInches(cm)
    local cmValue = tonumber(cm:match("%d+%.?%d*"))
    if cmValue then
        local totalInches = cmValue / 2.54
        local feet = math.floor(totalInches / 12)
        local inches = math.floor(totalInches % 12)
        return string.format("%.2f cm (%d feet %d inches)", cmValue, feet, inches)
    end
    return cm
end

local function mphToKmh(mph)
    local mphValue = tonumber(mph:match("%d+%.?%d*"))
    if mphValue then
        local kmh = mphValue * 1.60934
        return string.format("%.2f mph (%.2f km/h)", mphValue, kmh)
    end
    return mph
end

local function kmhToMph(kmh)
    local kmhValue = tonumber(kmh:match("%d+%.?%d*"))
    if kmhValue then
        local mph = kmhValue / 1.60934
        return string.format("%.2f km/h (%.2f mph)", kmhValue, mph)
    end
    return kmh
end

local function kmToMi(km)
    local kmValue = tonumber(km:match("%d+%.?%d*"))
    if kmValue then
        local miles = kmValue * 0.621371
        return string.format("%.2f km (%.2f mi)", kmValue, miles)
    end
    return km
end

local function miToKm(mi)
    local miValue = tonumber(mi:match("%d+%.?%d*"))
    if miValue then
        local km = miValue / 0.621371
        return string.format("%.2f miles (%.2f km)", miValue, km)
    end
    return mi
end

local function hpToKw(hp)
    local hpValue = tonumber(hp:match("%d+%.?%d*"))
    if hpValue then
        local kw = hpValue * 0.735499
        return string.format("%.2f horsepower (%.2f kW)", hpValue, kw)
    end
    return hp
end

local function kwToHp(kw)
    local kwValue = tonumber(kw:match("%d+%.?%d*"))
    if kwValue then
        local hp = kwValue / 0.735499
        return string.format("%.2f Kilowatt(%.2f hp)", kwValue, hp)
    end
    return kw
end

local function lbToKg(lb)
    local lbValue = tonumber(lb:match("%d+%.?%d*"))
    if lbValue then
        local kg = lbValue * 0.453592
        return string.format("%.2f lb (%.2f kg)", lbValue, kg)
    end
    return lb
end

local function kgToPounds(kg)
    --local kgValu = tonumber(kg:match("%d+"))
    local kgValue = tonumber(kg:match("%d+%.?%d*"))
    if kgValue>1 then
        local pounds = kgValue * 2.20462
        return string.format("%.2f kgs (%.2f pounds)", kgValue, pounds)
        else
         local pounds = kgValue * 2.20462
        return string.format("%.2f kg (%.2f pounds)", kgValue, pounds)
    end
    return kg
end

local function mmToInches(mm)
    local mmValue = tonumber(mm:match("%d+%.?%d*"))
    if mmValue then
        local inches = mmValue * 0.0393701
        return string.format("%.2f mm (%.2f inches)", mmValue, inches)
    end
    return mm
end

local function inchesToMm(inches)
    local inchesValue = tonumber(inches:match("%d+%.?%d*")) 
    if inchesValue then
        local mm = inchesValue / 0.0393701
        return string.format("%.2f inches (%.2f mm)", inchesValue, mm)
    end
    return inches
end

local function msToFts(ms)
    local msValue = tonumber(ms:match("%d+%.?%d*"))
    if msValue then
        local fts = msValue * 3.28084
        return string.format("%.2f m/s(%.2f ft/s)", msValue, fts)
    end
    return ms
end

local function ftsToMs(fts)
    local ftsValue = tonumber(fts:match("%d+%.?%d*"))
    if ftsValue then
        local ms = ftsValue / 3.28084
        return string.format("%.2f ft/s(%.2f m/s)", ftsValue, ms)
    end
    return fts
end

local function mToFeet(m)
    local mValue = tonumber(m:match("%d+%.?%d*"))
    if mValue then
        local feet = mValue * 3.28084
        return string.format("%.2f meter (%.2f ft)", mValue, feet)
    end
    
    -- Check for variations of "m", "meter", and "metre"
    local mValueAlt = tonumber(m:match("(%d+%.?%d*)%s*[mM]"))
    if mValueAlt then
        local feetAlt = mValueAlt * 3.28084
        return string.format("%.2f m (%.2f ft)", mValueAlt, feetAlt)
    end
    
    local mValueAlt2 = tonumber(m:match("(%d+%.?%d*)%s*[mM][eE][tT][eE]?[rR]?"))
    if mValueAlt2 then
        local feetAlt2 = mValueAlt2 * 3.28084
        return string.format("%.2f metre (%.2f ft)", mValueAlt2, feetAlt2)
    end
    
    local mValueAlt3 = tonumber(m:match("(%d+%.?%d*)%s*[mM][eE][tT][eE][rR]?"))
    if mValueAlt3 then
        local feetAlt3 = mValueAlt3 * 3.28084
        return string.format("%.2f meter (%.2f ft)", mValueAlt3, feetAlt3)
    end
    
    return m
end
--//m///


local function celsiusToFahrenheit(c)
    local cValue = tonumber(c:match("%d+"))
    if cValue then
        local fahrenheit = cValue * 9/5 + 32
        return string.format("%.2f°C (%.2f°F)", cValue, fahrenheit)
    end
    return c  
end

local function fahrenheitToCelsius(f)
    local fValue = tonumber(f:match("%d+"))
    if fValue then
        local celsius = (fValue - 32) * 5/9
        return string.format("%.2f°F (%.2f°C)", fValue, celsius)
    end
    return f
end
function capitalizeFirstLetter(str)
    return str:gsub("^%l", string.upper)
end

-- Function to generate contrasting text color for a given background color
local function getContrastingTextColor(bgColor)
    -- Convert hex color to RGB
    local r = tonumber(bgColor:sub(2, 3), 16)
    local g = tonumber(bgColor:sub(4, 5), 16)
    local b = tonumber(bgColor:sub(6, 7), 16)

    -- Calculate relative luminance
    local luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255

    -- Choose white or black text color based on luminance
    if luminance > 0.5 then
        return "#000000"  -- Black text for light backgrounds
    else
        return "#FFFFFF"  -- White text for dark backgrounds
    end
end

-- Function to generate even lighter colors
function generateEvenLighterColor1()
    local r = math.random(0xF0, 0xFF) -- Red component
    local g = math.random(0xF0, 0xFF) -- Green component
    local b = math.random(0xF0, 0xFF) -- Blue component
    return string.format("#%02X%02X%02X", r, g, b) -- Format as hexadecimal color
end

-- Function to generate a very light color
function generateVeryLightColor2()
    local r = math.random(0xE0, 0xFF) -- Red component
    local g = math.random(0xE0, 0xFF) -- Green component
    local b = math.random(0xE0, 0xFF) -- Blue component
    return string.format("#%02X%02X%02X", r, g, b) -- Format as hexadecimal color
end

-- Function to generate a random light color
function generateLightColor3()
    local r = math.random(0xB0, 0xFF) -- Red component
    local g = math.random(0xB0, 0xFF) -- Green component
    local b = math.random(0xB0, 0xFF) -- Blue component
    return string.format("#%02X%02X%02X", r, g, b) -- Format as hexadecimal color
end

-- Functions to generate mixed light-dark colors
function generateDarkColor4()
    local r = math.random(0x60, 0x80) -- Red component
    local g = math.random(0x60, 0x80) -- Green component
    local b = math.random(0x60, 0x80) -- Blue component
    return string.format("#%02X%02X%02X", r, g, b) -- Format as hexadecimal color
end

function generateDarkColor5()
    local r = math.random(0x50, 0x70) -- Red component
    local g = math.random(0x50, 0x70) -- Green component
    local b = math.random(0x50, 0x70) -- Blue component
    return string.format("#%02X%02X%02X", r, g, b) -- Format as hexadecimal color
end

function generateDarkColor6()
    local r = math.random(0x40, 0x60) -- Red component
    local g = math.random(0x40, 0x60) -- Green component
    local b = math.random(0x40, 0x60) -- Blue component
    return string.format("#%02X%02X%02X", r, g, b) -- Format as hexadecimal color
end

function generateDarkColor7()
    local r = math.random(0x20, 0x40) -- Red component
    local g = math.random(0x20, 0x40) -- Green component
    local b = math.random(0x20, 0x40) -- Blue component
    return string.format("#%02X%02X%02X", r, g, b) -- Format as hexadecimal color
end

function generateDarkColor8()
    local r = math.random(0x30, 0x70) -- Red component
    local g = math.random(0x30, 0x70) -- Green component
    local b = math.random(0x30, 0x70) -- Blue component
    return string.format("#%02X%02X%02X", r, g, b) -- Format as hexadecimal color
end

function generateDarkColor9()
    return string.format("#%02x%02x%02x", math.random(0x30, 0x50), math.random(0x40, 0x70), math.random(0x50, 0x70))
end

function generateDarkColor10()
    return string.format("#%06x", math.random(0x30, 0x70))
end

-- Function to generate a random color
local function generateRandomColor()
    local r = math.random(0, 255)
    local g = math.random(0, 255)
    local b = math.random(0, 255)
    return string.format("#%02X%02X%02X", r, g, b)
end


--[[ local conversionPatterns = {
        { pattern = "%s*kilohertz%s*", convertedValue = kilohertzToHertz},
        { pattern = "%s*kg%s*", conversion = kgToPounds },
        { pattern = "%s*mph%s*", conversion = mphToKmh },
        -- Add more conversion patterns as needed
    } ]] 


function p.dynamic(frame)
    local args = frame:getParent().args
    local output = '<div colspan="2" class="infobox biography vcard" style="max-width: 100vw; width: auto; margin: 0 auto;">\n|-\n' 
    -- local firstDescriptionFound = false
    local cmProcessed = false
    local abvParams = {}  -- Store abv parameters separately
    local abvProcessed = false
    local upProcessed = false
    local imageProcessed =false 
    --[[go over arguments to find "up" and "abv" parameters
    for key, value in pairs(args) do
        if key:sub(1, 2) == 'up' then
            if value ~= "" then
                output = output .. '<tr><th style='..(args.header or"")..'"background:lightgra;font-size:20px;text-align: center; background-color: ' .. (args.headcolor or "#f2f2f2") .. '; color: ' .. (args.color or "inherit") .. '; font-weight: bold;"> ' .. value .. '\n</th></tr>\n'
                upProcessed = true
            end
        end
    end
]] 





local values = {}

for key, value in pairs(args) do
    if key:sub(1, 2) == 'up' and value ~= "" then
        table.insert(values, {key = key, value = value})
    end
end
table.sort(values, function(a, b) return a.key < b.key end)
for _, entry in ipairs(values) do
    local key = entry.key
    local value = entry.value
    value = value:gsub("^%l", string.upper)
    local first_char = value:match("%a") -- Find the first alphabet character
    if first_char then
    value = value:gsub("^" .. first_char, string.upper) -- Capitalize the first alphabet character
    end
    output = output .. '<tr><th style="font-size:20px;text-align:center;background-color:' .. (args.header or "") .. ';color:' .. (args.color or "") .. ';font-weight:bold;" colspan="2">' .. value .. '\n</th></tr>\n'
end

--[[ 
for key, value in pairs(args) do
        if value ~= "" then
            if key ~= 'image' and key ~= 'imagecaption' and key ~= 'caption' and key ~= 'headcolor' and key ~= 'color' and key ~= 'abvstyle' and key ~= 'abvheadcolor' and key ~= 'abvcolor'then
                if key ~= 'up' and not (key:sub(1, 2) == 'up' and upProcessed) and key ~= 'abv' and not abvProcessed then
                    -- Your existing conversion logic goes here
                end
            end
        end
end

for key, value in pairs(args) do
        if value ~= "" then
            if key ~= 'image' and key ~= 'imagecaption' and key ~= 'caption' and key ~= 'headcolor' and key ~= 'color' and key ~= 'abvstyle' and key ~= 'abvheadcolor' and key ~= 'abvcolor'then
                if key ~= 'abv' and not (key:sub(1, 3) == 'abv' and abvProcessed) and key ~= 'abv' and not upProcessed then
                    -- Your existing conversion logic goes here
                end
            end
        end
end
]] 
local hasImage = false
for key, _ in pairs(args) do
    if key:sub(1, 5) == "image" then
        hasImage = true
        break
    end
end

if not hasImage then
    local defaultImage = "[[File:default_image.jpg|thumb|center|Default Image]]\n"
    output = output .. defaultImage
end

if args.image then
    local processedKeys = {}
    local processedSizeCaption = {}
    local images = {}
    local div = '<div style="display:grid;grid-template-columns: repeat(2, auto); gap: -2px; text-align: center; margin: 2px;">'

    for key, value in pairs(args) do
        if key:sub(1, 5) == "image" and value ~= "" and not processedKeys[key] then
            processedKeys[key] = true
            local captionKey = "caption" .. key:sub(6)
            local sizeKey = "size" .. key:sub(6)

            if not processedSizeCaption[captionKey] and not processedSizeCaption[sizeKey] then
                processedSizeCaption[captionKey] = true
                processedSizeCaption[sizeKey] = true

                local caption = args[captionKey] or ""
                local imagesize = args[sizeKey] or ""
                local isFrameless = string.match(value, '|frameless')
                local imageExtension = value:match("%.([^.]+)$")

               if not imageExtension then
                    value = value:gsub("|", "".. ".jpg|").. ".jpg"
                end
                local grid =""
                local wikiMarkup = ''
                if isFrameless then
                    local remo = value:gsub("(%[%[.-|)File:", "%1")
                    wikiMarkup = wikiMarkup .. '|' .. '<div style="text-align:center;">' .. remo .. '</div>' .. '<small style="display: block; text-align: center;">' .. caption .. '</small>\n|-\n'
                else
                    local imageName, imageSize = value:match("%[%[File:(.-)|([^|%]]+)]]")
                    if imageName then
                        wikiMarkup = wikiMarkup .. "[[File:" .. imageName
                        if imageSize then
                            wikiMarkup = wikiMarkup .. "|" .. imageSize
                        end
                        wikiMarkup = wikiMarkup .. "]]"
                    else
                        local imageSizeMarkup = ""
                        if imagesize ~= "" then
                            imageSizeMarkup = "|" .. imagesize
                        end
                        wikiMarkup = wikiMarkup .. "[[File:" .. value:gsub("%[%[", ""):gsub("%]%]", "") .. imageSizeMarkup .. "]]"
                    end
                    wikiMarkup = '<div style="text-align:center;">' .. wikiMarkup  .. '<small style="display: block; text-align: center;">' .. caption .. '</small></div>\n'
                   end

                -- Store the image markup along with its key
                table.insert(images, { key = key, markup = wikiMarkup, insertionOrder = #images + 1 })            end
        end
    end

    -- Sort the images based on their keys to maintain the insertion order
   --table.sort(images, function(a, b) return a.key < b.key end)

-- Generate the output markup
local columnCount = 0
local gridOpen = false
for _, imageData in ipairs(images) do
    local wikiMarkup = imageData.markup
    if imageData.key:sub(-1) == "+" then
        if not gridOpen then
            output = output .. '|<div colspan="2">' .. div.. '</div>\n|-\n' -- Open the grid container if it's not already open
            gridOpen = true
        end
        --output = output ..'|'.. wikiMarkup .. '\n|-\n' -- For keys not ending with '+', display normally

        output = output .. '|<div class="grid-item"colspan="2">' .. wikiMarkup .. '</div>\n'
        columnCount = (columnCount + 1) % 2
    else
        if gridOpen then
            output = output .. '</div>\n|-\n' -- Close the grid container if it's open
            gridOpen = false
        end
       output = output ..'<tr><th colspan="2">'.. wikiMarkup .. '</th><tr>\n|-\n' -- For keys not ending with '+', display normally
    end
end

-- If there are unclosed div tags, close them
if gridOpen then
    output = output .. '</div>\n|-\n'
end
end

local values = {}

for key, value in pairs(args) do
    if key:sub(1, 3) == "mdl"or key:match("^(%d+)mdl") and value ~= "" then
        table.insert(values, { key = key, value = value, position = mw.ustring.match(key, "%d+") })
    end
end

table.sort(values, function(a, b) return tonumber(a.position) < tonumber(b.position) end)

for _, entry in ipairs(values) do
    local key = entry.key
    local value = entry.value
    value = value:gsub("^%l", string.upper)
    local first_char = value:match("%a") -- Find the first alphabet character
    if first_char then
        value = value:gsub("^" .. first_char, string.upper) -- Capitalize the first alphabet character
    end
--   local transcludedContent = transcludeTemplate("User:Thisasia/sandbox3", { value = "" })
    --output = output .. '<tr><th colspan="2" style="font-size:20px;text-align:center;background-color:' .. (args.downheade or "rgba(0,0,0,0.020)") .. ';color:' .. (args.downcolo or "") .. ';font-weight:bold;"> {{User:Thisasia/Signature|'.. frame:preprocess('{{User:Thisasia/Signature|'.. value.. '}}').. value .. '}}</th></tr>\n|-\n'
    output = output .. '<tr><th colspan="2" style="font-size:20px;text-align:center;background-color:' .. (args.downheade or "rgba(0,0,0,0.020)") .. ';color:' .. (args.downcolo or "") .. ';font-weight:bold;">'.. value .. '</th></tr>\n|-\n'
end

--[[ 
 if key:sub(6, 6) == "+" then
                    table.insert(gridImages, {value = value, caption = caption, isFrameless = isFrameless})
                else
                    table.insert(normalImages, {value = value, caption = caption, imagesize = imagesize, isFrameless = isFrameless})
                end
            end
        end
    end
    
    -- Begin HTML output for grid layout
    local div='<div class="grid-container" style="  display: grid; grid-template-columns: repeat(2, 1fr); gap: 2px; text-align: center; margin-bottom: 5px; ">\n' 
    
    -- Output grid images
    for _, image in ipairs(gridImages) do
        local wikiMarkup = ""
        local remo = image.value
        wikiMarkup = wikiMarkup .. div.. '<div class="grid-item">' ..'<div style="text-align:center;">'.. remo.. '</div>'..'<small style="display: block; text-align: center;">' .. image.caption .. '</small>\n</div>\n'
        output = output .. wikiMarkup
    end
                  


   if args.image then
        local caption = args.caption or ""
        local imagesize = args.imagesize or ""  
        output = output .. '|' ..'<div style="text-align:center;">'.. args.image.. '</div>'..'<small style="display: block; text-align: center;">' .. caption .. '</small>\n|-\n'
    end
    --/// 
]] 

--[[ 
]] 
--
local values = {}
for key, value in pairs(args) do
    if key == key and value ~= "" then
        table.insert(values, {key = key, value = value})
    end
end
--[[local function generateUUID()
    return uuid()
end
]] 
local function extractNumber(key)
    return tonumber(key:match("^%d+")) or 0
end



--❗ Insertion Sort algorithm
for i = 1, #values do
    local current = values[i]
    local j = i - 1
    while j > 0 and (extractNumber(values[j].key) > extractNumber(current.key) or 
                     (extractNumber(values[j].key) == extractNumber(current.key) and values[j].key > current.key)) do
        values[j + 1] = values[j]
        j = j - 1
    end
    values[j + 1] = current
end


 --[[ 
table.sort(values, function(a, b)
    local aKey = a.key:match(".*%*$") and 1 or 0
    local bKey = b.key:match(".*%*$") and 1 or 0

    -- Keys with asterisks should come before keys without asterisks
    if aKey ~= bKey then
        return aKey < bKey
    else
        if aKey == 1 and bKey == 1 then
            return a.key < b.key
        elseif aKey == 0 and bKey == 0 then
            local numA = tonumber(a.key)
            local numB = tonumber(b.key)
            if numA and numB then
                return numA < numB
            else
                return a.key < b.key
            end
        else
            -- If one has asterisk and the other doesn't, prioritize the one with the asterisk
            return aKey == 1
        end
    end
end)
]] 
--[[

--Insertion Sort algorithm for modified_key
for i = 2, #values do
    local current = values[i]
    local j = i - 1
    while j > 0 and values[j].key > current.key do
        values[j + 1] = values[j]
        j = j - 1
    end
    values[j + 1] = current
end
 
for i = 2, #values do
    local current = values[i]
    local j = i - 1
    while j > 0 and values[j].key > current.key do
        values[j + 1] = values[j]
        j = j - 1
    end
    values[j + 1] = current
end
]] 

local matchedKeys = {}
local bgStyles = {}  -- Table to store background styles for each matched key
local generatedColors = {}  


for _, entry in ipairs(values) do
    local key = entry.key
    local value = entry.value
    local modified_key = key:gsub("^[%d]*", "")
    local found_alpha = false 
    
    for i = 1, #modified_key do
        if modified_key:sub(i, i):match("%a") then
            modified_key = modified_key:sub(1, i - 1) .. modified_key:sub(i, i):upper() .. modified_key:sub(i + 1)
            found_alpha = true
            break
        end
    end
    
    if not found_alpha then
        modified_key = modified_key:gsub("^.", string.upper, 5) 
    end
    
    local matched = false
    repeat
        local bgs = modified_key:match(".*%*$") or ""
        if bgs ~= "" and not matchedKeys[modified_key] then
            local bgStyle = bgStyles[modified_key]
            if not bgStyle then
                local manualBgColor = args["bgColor_" .. (modified_key:match(".*%*$"))] or ""
                local manualTextColor = args["textColor_" .. (modified_key:match(".*%*$"))] or ""
                local bgColor, textColor

                if generatedColors[modified_key] then
                    bgColor, textColor = generatedColors[modified_key].bgColor, generatedColors[modified_key].textColor
                else
                    local randf1=args.rd1 =="yes" or args.Rd1=="yes" 
                    local randf2=args.rd2 =="yes" or args.Rd2=="yes" 
                    local randf3=args.rd3 =="yes" or args.Rd3=="yes" 
                    local randf4=args.rd4 =="yes" or args.Rd4=="yes" 
                    local randf5=args.rd5 =="yes" or args.Rd5=="yes" 
                    local randf6=args.rd6 =="yes" or args.Rd6=="yes" 
                    local randf7=args.rd7 =="yes" or args.Rd7=="yes" 
                    local randf8=args.rd8 =="yes" or args.Rd8=="yes" 
                    local randf9=args.rd9 =="yes" or args.Rd9=="yes" 
                    local randf10=args.rd10 =="yes" or args.Rd10=="yes" 
                    local randf11=args.rd11 =="yes" or args.Rd11=="yes" 
                    local randf12=args.rd12 =="yes" or args.Rd12=="yes" 

                    if manualBgColor ~= "" and manualTextColor ~= "" then
                        bgColor = manualBgColor
                        textColor = manualTextColor
                    elseif randf1 then
                        bgColor = generateEvenLighterColor1()
                        textColor = getContrastingTextColor(bgColor)
                    elseif randf2 then
                        bgColor = generateVeryLightColor2()
                        textColor = getContrastingTextColor(bgColor)
                    elseif randf3 then
                        bgColor = generateLightColor3()
                        textColor = getContrastingTextColor(bgColor)
                    elseif randf4 then
                        bgColor = generateDarkColor4()
                        textColor = getContrastingTextColor(bgColor)
                    elseif randf5 then
                        bgColor = generateDarkColor5()
                        textColor = getContrastingTextColor(bgColor)
                    elseif randf6 then
                        bgColor = generateDarkColor6()
                        textColor = getContrastingTextColor(bgColor) 
                    elseif randf7 then
                        bgColor = generateDarkColor7()
                        textColor = getContrastingTextColor(bgColor)
                    elseif randf8 then
                        bgColor = generateDarkColor8()
                        textColor = getContrastingTextColor(bgColor)
                    elseif randf9 then
                        bgColor = generateDarkColor9()
                        textColor = getContrastingTextColor(bgColor)
                    elseif randf10 then
                        bgColor = generateDarkColor10() 
                        textColor = getContrastingTextColor(bgColor)
                    elseif randf11 then
                        bgColor = generateRandomColor()
                        textColor = getContrastingTextColor(bgColor)
                    else
                        bgColor = "#" .. string.format("%06x", math.random(0x000000, 0xFFFFFF))
                        bgColor = bgColor .. "00" -- append alpha value (00 for fully transparent)
                        textColor = "#000000"
                    end

                    generatedColors[modified_key] = {bgColor = bgColor, textColor = textColor}
                end

                bgStyle = string.format("background-color: %s; color: %s;", bgColor, textColor)
                bgStyles[modified_key] = bgStyle
            end
            for _, val in pairs(args) do
                if val == value and val ~= "" then
                    local alreadyAdded = string.match(output, val:gsub("^%l", string.upper))
                    if not alreadyAdded then
                        output = output .. string.format('<tr><th colspan="2" style="%s; %s; font-size:16px; text-align:center; font-weight:bold;">%s</th>\n</tr>\n', args.style or "", bgStyle, val:gsub("^%l", string.upper))
                        matchedKeys[modified_key] = true
                        matched = true
                        break
                    end
                end
            end
        end
        modified_key = modified_key:gsub("%*+$", "")  -- Remove the last asterisks
    until not modified_key:match(".*%*+%*$") or matched

    
 --[[ local randFlag = args["*rand"] == "yes" -- Check if *rand=yes flag is present
    if randFlag then
        bgColor = generateRandomColor() -- Generate a random color
    else
        -- Handle other cases or default behavior for background color
    end 
   ]] 
-- Handle infinite occurrences of modified_key:match(".*%*$")








    --local modified_key = key:gsub("^%D*(%d+).*", "%1")
  --[[
  if tonumber(string.sub(key, 1, 1)) ~= nil then
        modified_key= string.sub(key, 2)  -- Exclude the first character if it's a number
       
    end
   ]] 
   
   
        if key ~= 'image'and not key:match("^image[%a%d]+$") --[[and not (key:sub(1, 5)=="image")]] 
            and key ~= 'caption' and not key:match(".*%*$") 
            and key ~= 'headcolor' and key ~= 'color' and key~='header' 
            and not key:match("^abv%d+$")and not key:match("^up[%a%d]+$") and not key:match("^%d+mdl[%a%d]+$") then
            if key ~= 'up' and not (key:sub(1, 2) == 'up'=="image"and upProcessed) and key ~= 'abv'and key~="imagesize" and key~="rd" and not abvProcessed and not key:match("^Rd%d+$")then
              --if key ~= 'up' and not (key:sub(1, 2) == 'up' and upProcessed)  then
            if key ~= 'abv' and not (key:sub(1, 3) == 'abv' and abvProcessed) and not key:match("^rd%d+$") and not key:match("^mdl[%a%d]+$")then
            if key~="size" and not key:match("^size[%a%d]+$")and not(key:sub(-1)=="+") and not key:match("^caption[%a%d]+$") and key~="rd"and not(key:sub(1, 3)=="mdl")  and not key:match("^(%d+)mdl") then 
                  --//m 
                  
                  local convertedValue = value
                local originalValue = value  
                    if not cmProcessed and (value:match("%s*cm#%s*")or value:match("%s*centimeters#%s*")or value:match("%s*centimetres#%s*") or value:match("%s*centimeter#%s*") or value:match("%s*centimetre#%s*")) then
                    -- If centimeters conversion not done yet, do it here
                      --cmProcessed = true
                        convertedValue = cmToFeetAndInches(value)
                end
                    --/////❗ 
                 if type(value) == "string" then
                      
                       local age=dateCalculation(value)
                      --[[]] 
                       --local ag = calculateAg(value )
                      --if value:match("%d%d%d%d[/.-]%d%d[/.-]%d%d[./-]") then 
                      if value:match("%d+%d+%d+[./-]") then
                       --value =value:gsub("(%d%d%d%d)[/.-](%d%d)[/.-](%d%d)[./-]", "%1".. age )--:gsub("(%d%d%d%d)", "") 
                        value =value:gsub("(%d+%d+%d+)[/.-]", "".. age ):gsub("%d+[./-]", "")--:gsub("(%d%d%d%d)[/.-](%d%d)[/.-](%d%d)[./-]", "".. age ) 
                     --else 
                     	--value="Invalid date format"
                      end
                     --end
                        value = value:gsub("(%d+[/.%-]+%d+[/.%-]+%d+[%d/.%-]*)", ""):gsub("(%d+[/.%-]+%d+[/.%-]+%d+[%d/.%-]*)", ""):gsub("<i></i>", "")
                        value = value:gsub("(%d+[/.,-]%d+[/.,-]%d+)", "")
            
--[[ 
if value:match("%d+%d+%d+[/.,~]") then
    value = value:gsub("(%d+%d+%d+)[/.,~]", "%1<i></i>"..age)
end

value = value:gsub("(%d%d%d%d)[. /-] (%d%d)[/-.] (%d%d)", ""):gsub("(%d%d)[. - /] (%d%d)", ""):gsub("<i></i>", "")
--value = value:gsub("(%d%d%d%d)%p(%d%d)%p(%d%d)", ""):gsub("<i></i>", "")
]] 


                    if value:match("%s*cm%W%s*")or value:match("%s*centimeters#%s*")or value:match("%s*centimetres#%s*") or value:match("%s*centimeter#%s*") or value:match("%s*centimetre#%s*")   then
                        convertedValue = cmToFeetAndInches(value)..""
                    elseif value:match("%s*kg%W%s*") or value:match("%s*kgs#%s*")or value:match("%s*kilograms#%s*") or value:match("%s*kilogram#%s*") then
                        convertedValue = kgToPounds(value)
                    elseif value:match("%s*mph#%s*")or value:match("%s*mp/h#%s*")or value:match("%s*miles per hour#%s*")or value:match("%s*mile per hour#%s*") then
                        convertedValue = mphToKmh(value)
                    elseif value:match("%s*kmh#%s*")or value:match("%s*km/h#%s*")or value:match("%s*kilometers per hour#%s*")or value:match("%s*kilometer per hour#%s*")or value:match("%s*kilometres per hour#%s*")or value:match("%s*kilometre per hour#%s*") then
                        convertedValue = kmhToMph(value)
                    elseif value:match("%s*kms#%s*")or value:match("%s*km#%s*")or value:match("%s*kilometer#%s*")or value:match("%s*kilometers#%s*")or value:match("%s*kilometre#%s*")or value:match("%s*kilometres#%s*") then
                        convertedValue = kmToMi(value)
                    elseif value:match("%s*mi#%s*")or value:match("%s*mile#%s*")or value:match("%s*miles#%s*") then
                        convertedValue = miToKm(value)
                    elseif value:match("%s*hp#%s*")or value:match("%s*hps#%s*")or value:match("%s*horsepower#%s*")or value:match("%s*horsepowers#%s*") then
                        convertedValue = hpToKw(value)
                    elseif value:match("%s*kw#%s*")or value:match("%s*kws#%s*")or value:match("%s*kilowatt#%s*")or value:match("%s*kilowatts#%s*") then
                        convertedValue = kwToHp(value)                    elseif value:match("%s*ft#%s*") then                                          elseif value:match("%s*lb#%s*")or value:match("%s*pound#%s*")or value:match("%s*pounds#%s*") then
                        convertedValue = lbToKg(value)
                    elseif value:match("%s*mmms#%s*")or value:match("%s*mm#%s*")or value:match("%s*millimeter#%s*")or value:match("%s*millimetre#%s*")or value:match("%s*millimeters#%s*")or value:match("%s*millimetres#%s*") then
                        convertedValue = mmToInches(value)
                    elseif value:match("%s*in#%s*")or value:match("%s*ins#%s*")or value:match("%s*inch#%s*")or value:match("%s*inche#%s*")or value:match("%s*inches#%s*") then
                        convertedValue = inchesToMm(value)
                    elseif value:match("%s*ms#%s*")or value:match("%s*millisecond#%s*")or value:match("%s*milliseconds#%s*")  then
                        convertedValue = msToFts(value)
                    elseif value:match("%s*fts#%s*")or value:match("%s*ft/s#%s*")or value:match("%s*fps#%s*")or value:match("%s*footperseconds#%s*") then
                        convertedValue = ftsToMs(value)
                    elseif value:match("%s*°c#%s*") or value:match("%s*celsius#%s*") or value:match("%s*Celsius#%s*")  then
                        convertedValue = celsiusToFahrenheit(value)
                    elseif value:match("%s*°f#%s*") or value:match("%s*fahrenheit#%s*") then
                        convertedValue = fahrenheitToCelsius(value)
                   --❗ 
                        elseif value:match("%s*liters#%s*")or value:match("%s*litres#%s*")or value:match("%s*litre#%s*")or value:match("%s*liter#%s*") then
                        convertedValue = litersToGallons(value)
                    elseif value:match("%s*gallons#%s*")or value:match("%s*gallon#%s*") then
                        convertedValue = gallonsToLiters(value)
                    elseif value:match("%s*m³#%s*")or value:match("%s*m3#%s*")or value:match("%s*cubicmeters#%s*")or value:match("%s*cubicmetres#%s*")or value:match("%s*cubicmetre#%s*")or value:match("%s*cubicmeter#%s*") then
                        convertedValue = cubicMetersToCubicFeet(value)
                    elseif value:match("%s*ft³#%s*")or value:match("%s*ft3#%s*")or value:match("%s*cubicfeet#%s*")or value:match("%s*cubicfoot#%s*")or value:match("%s*cubicfeets#%s*")or value:match("%s*cubicfoots#%s*") then
                    	convertedValue = cubicFeetToCubicMeters(value)                                         elseif value:match("%s*sqm#%s*")or value:match("%s*sqms#%s*")or value:match("%s*sqmetre#%s*")or value:match("%s*sqmetres#%s*")or value:match("%s*squaremeter#%s*")or value:match("%s*squaremeters#%s*")or value:match("%s*sqmeter#%s*")or value:match("%s*sqmeters#%s*") then
                        convertedValue = squareMetersToSquareFeet(value)
                    elseif value:match("%s*sqft#%s*")or value:match("%s*sqfoot#%s*")or value:match("%s*sqfeet#%s*")or value:match("%s*squarefoots#%s*")or value:match("%s*squarefeets#%s*")or value:match("%s*squarefeet#%s*") then
                        convertedValue = squareFeetToSquareMeters(value)
                    elseif value:match("%s*hectares#%s*")or value:match("%s*hectare#%s*") then
                        convertedValue = hectaresToAcres(value)
                    elseif value:match("%s*acres#%s*")or value:match("%s*acre#%s*") then
                        convertedValue = acresToHectares(value)
                    elseif value:match("%s*hours#%s*")or value:match("%s*hour#%s*") then
                        convertedValue = hoursToMinutes(value)
                    elseif value:match("%s*minutes#%s*")or value:match("%s*minute#%s*") then
                        convertedValue = minutesToHours(value)
                    elseif value:match("%s*days#%s*")or value:match("%s*day#%s*") then
                        convertedValue = daysToHours(value)
                    elseif value:match("%s*joules#%s*")or value:match("%s*joule#%s*") then
                        convertedValue = joulesToCalories(value)
                    elseif value:match("%s*calories#%s*")or value:match("%s*calorie#%s*") then
                        convertedValue = caloriesToJoules(value)
                    elseif value:match("%s*kwh#%s*")or value:match("%s*kilowatthours#%s*")or value:match("%s*kilowatthour#%s*") then
                        convertedValue = kilowattHoursToJoules(value)
                    elseif value:match("%s*psi#%s*")or value:match("%s*pounds per square inch#%s*")or value:match("%s*pound per square inches#%s*") then
                        convertedValue = psiToPascals(value)
                    elseif value:match("%s*pascals#%s*")or value:match("%s*pascal#%s*") then
                        convertedValue = pascalsToPsi(value)
                    elseif value:match("%s*atm#%s*")or value:match("%s*atmospheres#%s*")or value:match("%s*atmosphere#%s*") then
                        convertedValue = atmospheresToPascals(value)
                    elseif value:match("%s*rpm#%s*") then
                        convertedValue = rpmToHertz(value)
                    elseif value:match("%s*kilohertz#%s*")or value:match("%s*khz#%s*") then
                        convertedValue = kilohertzToHertz(value)
                    elseif value:match("%s*hertz#%s*") then
                        convertedValue = hertzToRPM(value)
                    elseif value:match("%s*horsepower#%s*") then
                        convertedValue = horsepowerToWatts(value)
                    elseif value:match("%s*megawatts#%s*") or value:match("%s*megawatt#%s*")then
                        convertedValue = megawattsToHorsepower(value)
                    elseif value:match("%s*watts#%s*") or value:match("%s*watt#%s*")then
                        convertedValue = wattsToHorsepower(value)
                    elseif value:match("%s*hp#%s*") then
                        convertedValue = horsepowerToMegawatts(value)
                    elseif value:match("%s*m#%s*")or value:match("%s*meters#%s*")or value:match("%s*metres#%s*")or value:match("%s*meter#%s*")or value:match("%s*metre#%s*") then
                        convertedValue = mToFeet(value)
                    elseif value:match("%s*ft%W%s*") or value:match("%s*feet%P%s*")or value:match("%s*feets%P%s*")or value:match("%s*foot%P%s*")or value:match("%s*foots%P%s*") then
                       --local ft=convertedValue 
                        --convertedValue =convertValue:gsub("^ft[%a%d]+$", "" .. ft) --ftToCm(value)
                    value =ftToCm(value)
                    
                   end 
                    --local age=calculateAge(value)
                    --value = value:gsub("(%d+[/.,-]%d+[/.,-]%d+)", "")

                    
        --❗            modified_key = key:gsub("^[_%d]*", "")

        
                   value = value:gsub("^%l", string.upper)
                   local first_char = value:match("%a") -- Find the first alphabet character
                   if first_char then
                      value = value:gsub("^" .. first_char, string.upper) -- Capitalize the first alphabet character
                   end
                    output = output .. '| style="font-size:15px; font-weight:bolder;padding-right:1em;" | ' ..modified_key:gsub("^[_()%-%d]*", "") .. "\n"
                    if originalValue ~= convertedValue then
                       output = output .. '| '..convertedValue.. '\n|-\n'
                    else
                        output = output .. '| ' .. value .. '\n|-\n' 
                    end
                    

                  end
            	end
            
             end
          end
      end
end


                  
--[[

local values = {}

for key, value in pairs(args) do
    if key:sub(1, 3) == 'abv' and value ~= "" then
        table.insert(values, {key = key, value = value})
    end
end
table.sort(values, function(a, b) return a.key < b.key end)
for _, entry in ipairs(values) do
    local key = entry.key
    local value = entry.value
    output = output .. '| style="background:lightgray;font-size:20px;text-align:center;background-color:' .. (args.abvheadcolor or "#f2f2f2") .. ';color:' .. (args.abvcolor or "inherit") .. ';font-weight:bold;" | ' .. value .. '\n|-\n'
end
mw.text.unstrip

local frame = mw.getCurrentFrame()
--local infoboxContent = frame:preprocess('{{User:Thisasia/Signature|' ..value..'}}')

local function transcludeTemplate(templateName, args)
    local frame = mw.getCurrentFrame()
    local templateContent = frame:expandTemplate { title = templateName, args = args }
    return templateContent
end
]] 
--local frame = mw.getCurrentFrame()
local values = {}

for key, value in pairs(args) do
    if key:sub(1, 3) == "abv" and value ~= "" then
        table.insert(values, { key = key, value = value, position = mw.ustring.match(key, "%d+") })
    end
end

table.sort(values, function(a, b) return tonumber(a.position) < tonumber(b.position) end)

for _, entry in ipairs(values) do
    local key = entry.key
    local value = entry.value
    value = value:gsub("^%l", string.upper)
    local first_char = value:match("%a") -- Find the first alphabet character
    if first_char then
        value = value:gsub("^" .. first_char, string.upper) -- Capitalize the first alphabet character
    end
    output = output .. '<tr><th colspan="2" style="font-size:20px;text-align:center;background-color:' .. (args.downheader or "rgba(0,0,0,0.020)") .. ';color:' .. (args.downcolor or "") .. ';font-weight:bold;"> '.. value .. '</th></tr>\n|-\n'
--output = mw.getCurrentFrame():preprocess('{{User:Thisasia/sandbox3|\n' .. output .. '}}')
end
   output = output .. '</div>\n'
--   output = mw.getCurrentFrame():preprocess('{{User:Thisasia/sandbox3|\n' .. output .. '}}')
    return output
end

return p