Hoppa till innehållet

Modul:Utility

Från Plutten

Dokumentationen för denna modul kan skapas på Modul:Utility/dok

rm = rm or {}
-- Returnerar dagens datum. För att avläsningar som läser av vid ett visst datum ska ha ett datum att utgå ifrån.
rm.now=function()
    local currentDateStr = os.date("%Y-%m-%d %H:%M:%S")
    return currentDateStr
end

--Returns a tbl with label, sitelink etc.
rm.tblWikilink=function (qid,asofdate,bDoNotCheckPartOf)
	local tbl={}
	local bHasLabel
	if (qid) then
		tbl.qid=qid
		-- Read label (for specific year if relevant)
		local txtLabelThis=getLabelFundamental(qid)
		if (asofdate==nil) then
			tbl.txtLabel=txtLabelThis
			else
			tbl.txtLabel=rm.getLabelFromEntityId(qid,asofdate)
		end
		if not tbl.txtLabel	then
			tbl.txtLabel=localisation.txtMissing .. '<!--'..qid..'-->' .. '[[' .. localisation.txtCategory .. ':' .. localisation.txtLinkWithoutLabel .. ']]'		-- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
			bHasLabel=false
			else
			bHasLabel=true
			end
		
		tbl.txtLabel_current=rm.getLabelFromEntityId(qid,rm.now())
		if not tbl.txtLabel_current	then
			tbl.txtLabel_current=localisation.txtMissing .. '<!--'..qid..'-->' .. '[[' .. localisation.txtCategory .. ':' .. localisation.txtLinkWithoutLabel .. ']]'		-- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
			end
		
		-- Get site link
		tbl.txtSitelink=mw.wikibase.getSitelink(qid)
		-- If site link exists - use it
		if tbl.txtSitelink then
			return tbl,true
			else
			if not(bDoNotCheckPartOf) then
				-- if there is no site link, check if the item (organisation) is part of another one (either as 'part of' or 'mother organisation')
				-- if so use it
				local claimsPartOf = mw.wikibase.getAllStatements(qid, 'P361' ) -- part of
			    if (claimsPartOf[1]) then	
					local iPartof=read(claimsPartOf[1],'id')
					local mytbl, isokpart
					mytbl,isokpart=rm.tblWikilink(iPartof,asofdate)
					if (isokpart) then
						tbl.txtSitelink=mytbl.txtSitelink			-- use sitelink from part of (but label from original organisation)
						return tbl,true
						end
					end
				local claimsPartOf2 = mw.wikibase.getAllStatements(qid,'P749' ) -- mother organisation
			    if (claimsPartOf2[1]) then	
					local iPartof2=read(claimsPartOf2[1],'id')
					local mytbl, isokpart
					mytbl,isokpart=rm.tblWikilink(iPartof2,asofdate)
					if (isokpart) then
						tbl.txtSitelink=mytbl.txtSitelink			-- use sitelink from part of (but label from original organisation)
						return tbl,true
						end
					else
					-- If no site link at the item or any parent, consider using the label as sitelink			
					if bHasLabel and not tbl.txtSitelink then
						idUsedLabel=mw.wikibase.getEntityIdForTitle(tbl.txtLabel)
						if (idUsedLabel) then
							tbl.txtSitelink=tbl.txtLabel
							return tbl,true
							else
							if (txtLabelThis==nil) then
								tbl.txtSitelink=tbl.txtLabel
								return tbl, true
								else
								tbl.txtSitelink=txtLabelThis
								return tbl, true
								end
							end
						else
							tbl.txtLabel=localisation.txtMissing .. '<!--'..qid..'-->' .. '[[' .. localisation.txtCategory .. ':' .. localisation.txtLinkWithoutLabel .. ']]'		-- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
							tbl.txtSitelink=false
						return tbl,false					-- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
						end
			    	end
			    end
			end
		end
	return tbl,false
end


rm.getLabelFromEntityId=function( qid, asofdate )
	if (asofdate==nil) then
		return getLabelFundamental(qid)
		else 
				
		--If available use P2561 (name), prioriticed as it can be edited with greater flexibility
		local bFoundName,txtName=getLabelFromNamePropertyId2(qid,'P2561',asofdate )
		if (not(bFoundName)) then
			--If P2561 not available try P1448 (official name)
			local bFoundName,txtName=getLabelFromNamePropertyId2(qid,'P1448',asofdate )
		end
		if (bFoundName) then
			return txtName
			else
				return getLabelFundamental(qid)
			end	
		end
end

--Returns a wikilink to the connect page if there is one. Otherwise create to the a page with the name of the label
function txtWikilink(qid,year)
	-- Read label (for specific year if relevant)
	local txtLabel
	local txtLabelThis=getLabelFundamental(qid)
	if (year==nil) then
		txtLabel=txtLabelThis
		else
		txtLabel=getLabelFromEntityId(qid,year)
	end
	-- Get site link
	local txtSitelink=mw.wikibase.getSitelink(qid)
	-- If site link exists - use it
	if (txtSitelink) then
		return '[[' .. txtSitelink .. '|' .. txtLabel .. ']]'
		else
		-- if there is no site link, check if the item (organisation) is part of another one (either as 'part of' or 'mother organisation')
		-- if so use it
		local claimsPartOf = mw.wikibase.getAllStatements(qid, 'P361' ) -- part of
	    if (claimsPartOf[1]) then	
			local iPartof=read(claimsPartOf[1],'id')
			local mytxt, isokpart
			mytxt,isokpart=txtWikilink(iPartof,year)
			if (isokpart) then
				return mytxt,true
				end
			end
		local claimsPartOf2 = mw.wikibase.getAllStatements(qid,'P749' ) -- mother organisation
	    if (claimsPartOf2[1]) then	
			local iPartof2=read(claimsPartOf2[1],'id')
			return txtWikilink(iPartof2,year)
		else
		-- If no site link at the item or any parent, consider using the label				
		if (txtLabel) then
			idThatLabel=mw.wikibase.getEntityIdForTitle(txtLabel)
			if (idThatLabel) then
				return txtLabel,true
				else
				if (txtLabelThis==nil) then
						return '[[' .. txtLabel .. ']]',true
					else
						return '[[' .. txtLabelThis .. '|' .. txtLabel .. ']]',true
					end
				end
			else
			return '('..localisation.txtMissing..')<!--'..qid..'-->' .. '[[' .. localisation.txtCategory .. ':' .. localisation.txtLinkWithoutLabel .. ']]',false					-- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
			end
	    end
	end
end

--Returns a wikilink to the connect page if there is one. Otherwise create to the a page with the name of the label
--Does not try to use the label as a sitelink if there is no sitelink
--Further, it does not try to use any part of or mother organisation relation
function txtWikilinkWOsitelink(qid,year)
	-- Read label (for specific year if relevant)
	local txtLabel
	local txtLabelThis=getLabelFundamental(qid)
	if (year==nil) then
		txtLabel=txtLabelThis
		else
		txtLabel=getLabelFromEntityId(qid,year)
	end
	-- Get site link
	txtSitelink=mw.wikibase.getSitelink(qid)
	-- If site link exists - use it
	if (txtSitelink) then
		return '[[' .. txtSitelink .. '|' .. txtLabel .. ']]'
		else
		if (txtLabel) then
				return txtLabel
			else
			return '('..localisation.txtMissing..')<!--'..qid..'-->'					-- The commented id can be used by functions to, for example provide informatation on the entity that misses a label
			end
	end
end

function emptyifNil(data)
	if (data) then
		return data
		else
		return ''
	end
end

function getLabelByEntity(qid)
	mw.log('getLabelByEntity')
	return getLabelFundamental(qid)
end

function getLabelFundamental(qid)
	return mw.wikibase.getLabel(qid, localisation.txtLanguageCode ) or mw.wikibase.getLabel(qid, 'mul')
end

function getLabelFromEntityId( qid, year )
	if (year==nil) then
		return mw.wikibase.getLabelByLang(qid, localisation.txtLanguageCode ) 
		else 
		--If available use P2561 (name), prioriticed as it can be edited with greater flexibility
		local bFoundName,txtName=getLabelFromNamePropertyId(qid,'P2561',year )
		if (not(bFoundName)) then
			--If P2561 not available try P1448 (official name)
			local bFoundName,txtName=getLabelFromNamePropertyId(qid,'P1448',year )
		end
		if (bFoundName) then
			return txtName
			else
				txtLabelDirect=getLabelFundamental(qid)
				if (txtLabelDirect) then
					return txtLabelDirect 
					else
					return localisation.txtMissing
					end
			end	
		end
end

function getLabelFromNamePropertyId(qid, pid,year )
	local claims = mw.wikibase.getBestStatements(qid,pid) -- If the club have had many names, loop through to find the one that was used when the player played at the club
	if (next(claims)) then
		-- Use label as default (if nothing is found that match year-wise)
		local txtName=mw.wikibase.getLabelByLang(qid, localisation.txtLanguageCode )
		-- Loop through names
	    for key, value in pairs( claims ) do
			local yearfrom,yearto,datefrom,dateto =  years(value) 
    		local lng=read(value,'language')
	    	if ((year >= yearfrom and year <= yearto) or (yearto=='' and year >= yearfrom)) and (not(lang_denylist[lng]==true)) then
	    		if (lng==txtLocalLanguage) then
		    		txtName=read(value,'text')
		    		if (txtName==nil) then
		    			txtName=txtNotLocalLanguage
		    			else --If name exists in local language return straight away, do not continue looping
		    			return true,txtName
			    		end
		    		else --set name for possible later return, but keep looping
		    		txtName=read(value,'text') 
	    			end
	    		end
	    	end
	--if name property (P1448 or P2561) is set then set name if one was found, otherwise write an error message
	return true,txtName
	else
	--if property was not set just use usual name
	return false,nil
	end
end


function getLabelFromEntityId2( qid, asofdate )
	if (year==nil) then
		return mw.wikibase.getLabelByLang(qid, localisation.txtLanguageCode ) 
		else 
		--If available use P2561 (name), prioriticed as it can be edited with greater flexibility
		local bFoundName,txtName=getLabelFromNamePropertyId2(qid,'P2561',asofdate )
		if (not(bFoundName)) then
			--If P2561 not available try P1448 (official name)
			local bFoundName,txtName=getLabelFromNamePropertyId2(qid,'P1448',asofdate )
		end
		if (bFoundName) then
			return txtName
			else
				return mw.wikibase.getLabelByLang(qid, localisation.txtLanguageCode )
			end	
		end
end

function getLabelFromNamePropertyId2(qid, pid,asofdate )
	local claims = mw.wikibase.getBestStatements(qid,pid) -- If the club have had many names, loop through to find the one that was used when the player played at the club
	if (next(claims)) then
		-- Use label as default (if nothing is found that match year-wise)
		local txtName=mw.wikibase.getLabelByLang(qid, localisation.txtLanguageCode )
		-- Loop through names
	    for key, value in pairs( claims ) do
			local yearfrom,yearto,datefrom,dateto =  years(value) 
    		local lng=read(value,'language')
	    	if ((asofdate >= datefrom and asofdate <= dateto) or (dateto=='' and asofdate >= datefrom)) and (not(localisation.lang_denylist[lng]==true)) then
	    		if (lng==localisation.txtLanguageCode) then
		    		txtName=read(value,'text')
		    		if (txtName==nil) then
		    			txtName=txtNotLocalLanguage
		    			else --If name exists in local language return straight away, do not continue looping
		    			return true,txtName
			    		end
		    		else --set name for possible later return, but keep looping
		    		txtName=read(value,'text') 
	    			end
	    		end
	    	end
	--if name property (P1448 or P2561) is set then set name if one was found, otherwise write an error message
	return true,txtName
	else
	--if property was not set just use usual name
	return false,nil
	end
end


function readFirstStatementId(entityid,txtProperty)
	statements=mw.wikibase.getBestStatements(entityid,txtProperty)
	if not(next(statements)==nil) then
		if not(statements[1]==nil) then
			return read(statements[1],'id')
			end
		end
	return nil
	end

function readFirstStatement(entityid,txtProperty)
	statements=mw.wikibase.getBestStatements(entityid,txtProperty)
	if not(next(statements)==nil) then
		if not(statements[1]==nil) then
			qid=read(statements[1],'id')
			if not (qid==nil) then
				return mw.wikibase.getLabelByLang(qid,localisation.txtLanguageCode)
				end
			end
		end
	return nil
	end

function getQualifier(value,txtQualifierId)
	if value['qualifiers'] and  value['qualifiers'][txtQualifierId] then
			txtValue=emptyifNil(mw.wikibase.renderSnak(value['qualifiers'][txtQualifierId][1]))
		else
			txtValue=nil
		end
	return txtValue
end

--Replace with (and move content to) getQualifier, which as a more sensible name
function getProperty(value,txtPropertyId)
	mw.log("Använder getProperty")
	if value['qualifiers'] and  value['qualifiers'][txtPropertyId] then
			txtValue=emptyifNil(mw.wikibase.renderSnak(value['qualifiers'][txtPropertyId][1]))
		else
			txtValue=nil
		end
	return txtValue
end

function getQualifierId(value,txtQualifierId)
	if value then
		if value['qualifiers'] then
			if value['qualifiers'][txtQualifierId] then
				txtSnaktype=value['qualifiers'][txtQualifierId][1].snaktype
				if (txtSnaktype=="value") then
					txtValue=value['qualifiers'][txtQualifierId][1].datavalue.value.id
					if (not txtValue) then
						txtValue=value['qualifiers'][txtQualifierId][1].datavalue.value.amount
						end
					else
					txtValue="Not Implemented"
					end
				else
				txtValue=nil
			end
			else
				txtValue=nil
		end	
	else 
		return nil
		end
	return txtValue
end

--Replace with (and move content to) getQualifierId, which as a more sensible name
function getPropertyId(value,txtPropertyId)
	mw.log("Använder getPropertyId")
	if value then
		if value['qualifiers'] then
			if value['qualifiers'][txtPropertyId] then
				txtSnaktype=value['qualifiers'][txtPropertyId][1].snaktype
				if (txtSnaktype=="value") then
					txtValue=value['qualifiers'][txtPropertyId][1].datavalue.value.id
					if (not txtValue) then
						txtValue=value['qualifiers'][txtPropertyId][1].datavalue.value.amount
						end
					else
					txtValue="Not Implemented"
					end
				else
				txtValue=nil
			end
			else
				txtValue=nil
		end	
	else 
		return nil
		end
	return txtValue
end

--Read a value of a property
function read(data,type)
	if (data) then
		if (data['mainsnak']) then
			return readQualifier(data['mainsnak'],type)
			else
			return nil
		end
		else
		return nil
		end
end

--Read a value of a qualifier
function readQualifier(data,type)
	if (data['datavalue']) then
		return data['datavalue']['value'][type]
		else
		return nil
		end
end

rm.readtext=function(claims, asofdate)
for key, value in pairs( claims ) do
	local yearfrom,yearto,datefrom,dateto =  years(value) 
	local lng=read(value,'language')
	if ((asofdate >= datefrom and asofdate <= dateto) or (dateto=='' and asofdate >= datefrom)) and (not(localisation.lang_denylist[lng]==true)) then
		if (lng==localisation.txtLocalLanguage) then
    		txtName=read(value,'text')
    		if (txtName==nil) then
    			txtName=localisation.txtNotLocalLanguage
    			else --If name exists in local language return straight away, do not continue looping
    			return true,txtName
	    		end
    		else --set name for possible later return, but keep looping
    		txtName=read(value,'text') 
			end
		end
	end
end

rm.readQualifier=function (value,qfid,type)
	if (value.qualifiers and value.qualifiers[qfid]) then
		return readQualifier(value.qualifiers[qfid][1],type)
		else
		return nil
	end 
end

-- Function to split a string by a delimiter (by chatgpt)
function split(inputStr, delimiter)
    local result = {}
    for match in (inputStr .. delimiter):gmatch("(.-)" .. delimiter) do
        table.insert(result, match)
    end
    return result
end

-- Function to merge two tables
function merge(table1, table2)
    local result = {}
    -- Insert all key-value pairs from table1 into result
    for key, value in pairs(table1) do
        result[key] = value
    end
    -- Insert all key-value pairs from table2 into result
    for key, value in pairs(table2) do
        result[key] = value
    end
    return result
end


-- Check if all values of a given property are the same. In such case there is often no need to show something for every individual item
--------------------------------------------------
--  qid       qid of the object
--  pid       pid of the property
--
-- The function returns a lua table with filename, description, width, height (as well as qid and pid)

function getImage(qid,pid)
	img=mw.wikibase.getBestStatements(qid, pid )
	bDescription=false -- variable to check if a description has been found
	if next(img) then
		image={}
		image.txtFilename = img[1]['mainsnak']['datavalue']['value']
--		txtFilename = read(img[1],'value')
	    if img[1].qualifiers and img[1].qualifiers.P2096 then
	    	-- Loop through all descriptions
		    for key, value in pairs(img[1].qualifiers.P2096) do
			    -- Only add if has the same language code as the local wikipedia
			    language=readQualifier(value,'language')
			    if (language==localisation.txtLanguageCode) then
			    	bDescription=true                                                                    -- description found!
				    image.txtDescription=readQualifier(value,'text')  -- add description (+ pen to make it easier to edit)
				    end
			    end
	    	end
	    image.width,image.height=getImageSize(image.txtFilename)
	    image.qid=qid
	    image.pid=pid
		return image
		end
	return
end

-- Get size of image. Used by the function above,
--------------------------------------------------
--  txtFilename       Name of image file
--
-- The function returns a lua table with width and height (if succesful) or error message (if unsuccesful)

function getImageSize(txtFileName)
    local title = mw.title.new(txtFileName, 'File')
    if not title then
        return nil, nil, "Invalid image name"
    end

    local file = title and title.file
    if not file then
        return nil, nil, "File not found"
    end

    return file.width, file.height
end


-- Adds image to lua table (myArgs) that is used to supply arguments to the infobox template
-- Assumes a lua table that has been filled by the getImage function above

function showImage(tblImage)
    myArgs[localisation.txtImage]='[[File:' .. tblImage.txtFilename .. '|' .. settings.iWidth_px .. 'px]]'
    p.myArgs[localisation.txtImage]='[[File:' .. tblImage.txtFilename .. '|' .. settings.iWidth_px .. 'px]]'
    if (tblImage.txtDescription) then
    	myArgs[localisation.txtCaption]=tblImage.txtDescription..txtEditPen(tblImage.qid,tblImage.pid)
    	p.myArgs[localisation.txtCaption]=tblImage.txtDescription..txtEditPen(tblImage.qid,tblImage.pid)
	else
    	myArgs[localisation.txtImage]=myArgs[localisation.txtImage]..txtEditPen(tblImage.qid,tblImage.pid)
    	p.myArgs[localisation.txtImage]=myArgs[localisation.txtImage]..txtEditPen(tblImage.qid,tblImage.pid)
	end
end


function datetotext (from,to)
mw.log('in function datetotext')
local txt =''
if not isempty(from) then
	txt=from.year
end
if not (isempty(from) and isempty(to))  then
	txt=txt..'–'
	end
if not isempty(to) then
	txt=txt..to.year
end
if from and to and (from.year==to.year) then
	txt=from.year
	end
return txt
end

p.showdata = function(frame)
	p.frame=frame
	p=p.data()
	require(localisation.txtModule .. ':Debug' )
	return tprint(p)
end

p.showpartininfobox=function(txtThisLabel,propertyname,bCheckChildren,runfunc)
	local obj=p[propertyname]
    if (obj) then
	    if(obj[1]) then	--Safety check to check if obj is an array rather than a structure (since Lua for some reason lacks any built-in functionality to test the difference test for 1 is a quick fix)
			obj=nil
			end    	
		end
	if (obj) then
		local txtContent=obj.data
		if (obj.unit) then
			txtContent=txtContent .. ' ' .. obj.unit
		end
		txtContent=txtContent  .. txtUnpackReference_model(p.frame,obj.ref,obj.qid,obj.pid)
		if (runfunc) then
			txtContent=txtContent .. runfunc()
			end
		p.addContent(txtThisLabel,txtContent)
--		p.iCounter=p.iCounter+1
--	    myArgs[localisation.txtLabel .. p.iCounter]=txtThisLabel
--		myArgs[localisation.txtContent  .. p.iCounter]=txt  .. txtUnpackReference_model(p.frame,obj.ref,obj.qid,obj.pid)
--		if (runfunc) then
--			myArgs[localisation.txtContent  .. p.iCounter]=myArgs[localisation.txtContent  .. p.iCounter] .. runfunc()
--			end
	end
	if (bCheckChildren) then
		if (p.objectIds) then
			for key,value in pairs(p.objectIds) do
				obj=p[value][propertyname]
				if (obj) then
					local txtContent=obj.data
					if (obj.unit) then
						txtContent=txtContent .. ' ' .. obj.unit
						end
					txtContent=txtContent  .. txtUnpackReference_model(p.frame,obj.ref,obj.qid,obj.pid)
					if (runfunc) then
						txtContent=txtContent .. runfunc()
						end
					p.addContent('&nbsp;–&nbsp;' .. p[value]['label'],txtContent)
--					p.iCounter=p.iCounter+1
--				    myArgs[localisation.txtLabel .. p.iCounter]='&nbsp;–&nbsp;' .. p[value]['label']
--					myArgs[localisation.txtContent  .. p.iCounter]=txt  .. txtUnpackReference_model(p.frame,obj.ref,obj.qid,obj.pid)
--					if (runfunc) then
--						myArgs[localisation.txtContent  .. p.iCounter]=myArgs[localisation.txtContent  .. p.iCounter] .. runfunc()
--						end
				end
			end
		end
	end	
end

p.processoneiteminlist=function(item,func,specificproperties,separator,bHideReferences)
	local ret
	if (item.from or item.to) then
		txtYears=' (' .. datetotext (item.from,item.to) .. ')'
		else
		txtYears=''
		end
	if func then
		ret = func(item) 
		else
		if not (specificproperties==nil) then
			local txtCurrent=item[specificproperties[1]]
			for j=2,#specificproperties do
				if (item[specificproperties[j]]) then
					if not txtCurrent then
						txtCurrent=''
						end
					txtCurrent=txtCurrent .. separator .. item[specificproperties[j]]
					end
			end
			ret = txtCurrent
		else
			ret= item
		end
	end
	if (bHideReferences) then
		return ret .. txtYears
		else
		return ret .. txtYears .. txtUnpackReference_model(p.frame,item.ref,item.qid,item.pid)
		end
end

-- Function: Loopitems
-- Purpose: To fill an infobox row with values based on the content of ,general property, that will contain an array that is looped through
-- Arguments:
--    label					- Label for the infobox row
--    generalproperty       - Property to read the data from.
--    specificproperties	- Subproperties that are used to fill the content of the infobox row. 
--    separator		   		- Separator between the different items of the list (except the last one)
--    lastseparator			- Separator between the second last and the last item of the list

p.loopitems=function(label,generalproperty,func,specificproperties,separator,lastseparator,bHideReferences)
	local listDataitems=p[generalproperty]
	local iItems=1
	if listDataitems and next(listDataitems) then
		iItems=#listDataitems
		local txt
		if (iItems>0) then
			txt=''
			for i=1,iItems do
				if(i>1) then
					if (i==iItems) then
						txt=txt..lastseparator
						else				
						txt=txt..separator
						end
					end
				local txtCurrent=p.processoneiteminlist(listDataitems[i],func,specificproperties,", ",bHideReferences)
				if (i==1) then
					txt=txt..firstToUpper(txtCurrent)
					else
					txt=txt..txtCurrent
					end
				end
			else
				txt=p.processoneiteminlist(listDataitems,func,specificproperties,", ",bHideReferences)
			end
		local txtLabel
		if type(label) == "string" then
	    	txtLabel=label
	    	else
    		if (iItems>1) then
		    	txtLabel=label[2]
		    	else
		    	txtLabel=label[1]
		    	end
    		end
		p.addContent(txtLabel,txt)
	end
end



-- the "qualifiers" and "snaks" field have a respective "qualifiers-order" and "snaks-order" field
-- use these as the second parameter and this function instead of the built-in "pairs" function
-- to iterate over all qualifiers and snaks in the intended order.
local function orderedpairs(array, order)
	mw.log('in function orderedpairs')
	if not order then return pairs(array) end

	-- return iterator function
	local i = 0
	return function()
		i = i + 1
		if order[i] then
			return order[i], array[order[i]]
		end
	end
end

function __genOrderedIndex( t )
    local orderedIndex = {}
    for key in pairs(t) do
        table.insert( orderedIndex, key )
    end
    table.sort( orderedIndex )
    return orderedIndex
end

function orderedNext(t, state)
--	mw.log('in function orderedNext')
    -- Equivalent of the next function, but returns the keys in the alphabetic
    -- order. We use a temporary ordered key table that is stored in the
    -- table being iterated.

    local key = nil
    --print("orderedNext: state = "..tostring(state) )
    if state == nil then
        -- the first time, generate the index
        t.__orderedIndex = __genOrderedIndex( t )
        key = t.__orderedIndex[1]
    else
        -- fetch the next value
        for i = 1,table.getn(t.__orderedIndex) do
            if t.__orderedIndex[i] == state then
                key = t.__orderedIndex[i+1]
            end
        end
    end

    if key then
        return key, t[key]
    end

    -- no more value to return, cleanup
    t.__orderedIndex = nil
    return
end

function orderedPairs(t)
--	mw.log('in function orderedPairs')
    -- Equivalent of the pairs() function on tables. Allows to iterate
    -- in order
    return orderedNext, t, nil
end

function isempty(foo)
	return (foo==nil) or (foo=='') or (foo==0)
end

-- from: https://stackoverflow.com/questions/2421695/first-character-uppercase-lua
function firstToUpper(str)
	if (str) then
	    return (str:gsub("^%l", string.upper))
	    else
	    return ''
	    end
end

function inTable(table, val)
    for _, value in ipairs(table) do
        if value == val then
            return true
        end
    end
    return false
end

--Functions to ensure that urls are handled correctly
--from http://lua-users.org/wiki/StringRecipes
function url_encode(str)
   if str then
      str = str:gsub("\n", "\r\n")
      str = str:gsub(" ", "+")
   end
   return str	
end

function url_decode(str)
   str = str:gsub("+", " ")
   str = str:gsub("%%(%x%x)", function(h)
      return string.char(tonumber(h,16))
   end)
   str = str:gsub("\r\n", "\n")
   return str
end