Module:Haplogroup

Lua
CodeDiscussionLinksLink count SubpagesDocumentationTestsResultsSandboxLive code All modules

Module used at Wikidata:WikiProject Haplogroups. A derivative version of Template:Tree.

Tree structure is generated by tracking "followed by (P156)" from the first item. By setting direction = parent, tracking is done through "follows (P155)" toward ancestral direction.

If item page has link to Wikipedia (of your setting language), Wikimedia Commons, or haplogroup.org, it is shown next to each haplogroup name. (Do not use haplogroup.org as source but use it to find original sources.)

If there are other data (for example, "date of birth (P569)", "place of birth (P19)", or "locator map image (P242)"), it is shown by clicking [Show detail] button at the top-left of the tree.

Example edit

Input

{{ #invoke:Haplogroup | main | firstItemId = Q3491260| maxdepth = 10 | highlight = Q1584156}}

Output


Input

{{ #invoke:Haplogroup | main | firstItemId = Q3491260| maxdepth = 10 | highlight = Q45070466| direction = parent }}

Output

See also edit

Template:Tree, original of this module.

Code

-- This is derivative version of [[Module:Tree]]. See https://www.wikidata.org/wiki/Template:Tree
--
-- Usage example
--
-- {{#invoke:Haplogroup|main|firstItemId= Q221674|maxdepth=25}}
--
-- firstItemId: First item ID. This item become the root of the tree.
-- maxdepth: Maximum depth of the tree.

local p = {}

datas = {}


-- These setdata() and getdata() functions are used to access (read and write) to "datas" table
function p.setdata(n, key, val)
	if datas[n] == nil then
		datas[n] = {}
	end
	datas[n][key] = val
end

function p.getdata(n, key, defval)
	if  datas[n] == nil or datas[n][key] == nil then
		return defval
	else
		return datas[n][key] 
	end
end

function p.children(itemId, property, direction, maxdepth, lang1, lang2 )
 --------------------------------------------------------------------------------
 -- children function which listing all childrens that certain item has.
 -- Not listing grand childrens, or grand-grand childrens. Listing only childrens.
 -- Final returning value "childrens" is like {Q123123, Q3984198237, Q1874138746} 
 --------------------------------------------------------------------------------
	local childrens = {}
	local entity = mw.wikibase.getEntity( itemId )
	local claims = nil
	local x = 1
	local tmpValue = {}
	
	---------------------------------------------------------------
	-- Start collecting data from the retrieved entity, and save that into the datas[] table.
	-- Because getEntity() function is EXPENSIVE, so here, collecting all data at once.
	-- https://en.wikipedia.org/wiki/WP:EXPENSIVE
	-- https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua#mw.wikibase.getEntity
	----------------------------------------------------------------
	local globalSiteId_1 = lang1 .. 'wiki'
	local globalSiteId_2
	
	if lang2 and lang2 ~= '' then
		globalSiteId_2 = lang2 .. 'wiki'
	else
		globalSiteId_2 = nil
	end
	
	p.setdata(itemId, "sitelink_1", entity:getSitelink( globalSiteId_1 ))
	p.setdata(itemId, "label_1", entity:getLabelWithLang( lang1 ))
	
	local claimShort = entity['claims']['P1813'] -- variable for P1813 (Short name)
	if claimShort and claimShort ~= '' then
		p.setdata(itemId, "short", claimShort[1].mainsnak.datavalue.value.text) --
	end
	
	local claimDate = entity['claims']['P569'] -- variable for P569 (Date of birth)
	if claimDate and claimDate ~= '' then
		p.setdata(itemId, "date", claimDate[1].mainsnak.datavalue.value) --
	end
	
	local claimsPlace = entity['claims']['P19'] -- variable for P19 (Place of birth)
	local tmpPlcae = nil
	if claimsPlace and claimsPlace ~= '' then
		for  _,claim in pairs( claimsPlace ) do --Various place can be registered in this property. So marging these all places.
			if tmpPlcae and tmpPlcae ~= '' then
				tmpPlcae = tmpPlcae .. ', ' .. mw.getCurrentFrame():expandTemplate{ title = 'LinkedLabel', args = { claim.mainsnak.datavalue.value.id } }
			else
				tmpPlcae = mw.getCurrentFrame():expandTemplate{ title = 'LinkedLabel', args = { claim.mainsnak.datavalue.value.id } }
			end
		end
		p.setdata(itemId, "place", tmpPlcae)
	end
	
	local claimsPossessor = entity['claims']['P127'] -- variable for P127 (Owned by)
	local tmpPossessor = nil
	if claimsPossessor and claimsPossessor ~= '' then
		for  _,claim in pairs( claimsPossessor ) do --Various place can be registered in this property. So marging these all places.
			if tmpPossessor and tmpPossessor ~= '' then
				tmpPossessor = tmpPossessor .. ', ' .. mw.getCurrentFrame():expandTemplate{ title = 'LinkedLabel', args = { claim.mainsnak.datavalue.value.id } }
			else
				tmpPossessor = mw.getCurrentFrame():expandTemplate{ title = 'LinkedLabel', args = { claim.mainsnak.datavalue.value.id } }
			end
		end
		p.setdata(itemId, "possessor", tmpPossessor)
	end
	
	local claimsRefSeq = entity['claims']['P2249'] -- variable for P2249 (Refseq Genome ID)
	local tmpRefSeq = nil
	if claimsRefSeq and claimsRefSeq ~= '' then
		for  _,claim in pairs( claimsRefSeq ) do --Various place can be registered in this property. So marging these all places.
			if tmpRefSeq and tmpRefSeq ~= '' then
				tmpRefSeq = tmpRefSeq .. ', ' .. '[https://www.ncbi.nlm.nih.gov/nuccore/' .. claim.mainsnak.datavalue.value .. '?report=fasta ' .. claim.mainsnak.datavalue.value .. ']'
			else
			
				tmpRefSeq = '[https://www.ncbi.nlm.nih.gov/nuccore/' .. claim.mainsnak.datavalue.value .. '?report=fasta ' .. claim.mainsnak.datavalue.value .. ']'
			end
			tmpRefSeq = '<span class="plainlinks">' .. tmpRefSeq .. '</span>'
		end
		p.setdata(itemId, "refseq", tmpRefSeq)
	end
	
	local claimMapIamge = entity['claims']['P242'] -- variable for P242 (locator map image)
	if claimMapIamge and claimMapIamge ~= '' then
		p.setdata(itemId, "mapimage", claimMapIamge[1].mainsnak.datavalue.value) --
	end
	
	--{{#invoke: Wikidata|Dump|claims|P155|1|references|1|snaks|P854|1|datavalue|value}}
	local claimsPhyloTreeURL = entity['claims']['P155'] -- variable for phylotree.org URL taken from reference data in P155 (follows)
	local tmpPhyloTreeURL
	if claimsPhyloTreeURL then
		for  _,claim in pairs( claimsPhyloTreeURL ) do --Various website can be registered in this property. So picking-up only haplogroup.org website.
			for _,reference in pairs( claim.references ) do
				if reference.snaks['P854'] then
					tmpPhyloTreeURL = reference.snaks['P854'][1].datavalue.value
					if string.find( tmpPhyloTreeURL, 'phylotree.org') then
						p.setdata(itemId, "phylotree.org", tmpPhyloTreeURL)
					end
				end
			end
		end
	end
	
	local claimsDescribedURL = entity['claims']['P973'] -- variable for haplogroup.org URL in P973 (described at URL)
	local tmpDescribedURL
	if claimsDescribedURL then
		for  _,claim in pairs( claimsDescribedURL ) do --Various website can be registered in this property. So picking-up only haplogroup.org website.
			tmpDescribedURL = claim.mainsnak.datavalue.value
			if string.find( tmpDescribedURL, 'haplogroup.org') then
				p.setdata(itemId, "haplogroup.org", tmpDescribedURL)
			end
			if string.find( tmpDescribedURL, 'yfull.com') then
				p.setdata(itemId, "yfull.com", tmpDescribedURL)
			end
		end
	end
	
	local claimCommons = entity['sitelinks'] -- variable for Wikimedia Commons
	if claimCommons and claimCommons ~= '' then
		if claimCommons.commonswiki and claimCommons.commonswiki ~= '' then
			p.setdata(itemId, "commons", claimCommons['commonswiki'].title) --
		end
	end
	
	if lang2 and lang2 ~= '' then
		p.setdata(itemId, "sitelink_2", entity:getSitelink( globalSiteId_2 ))
		p.setdata(itemId, "label_2", entity:getLabelWithLang( lang2 ))
	end
	
	---------------------------------------------------------------		
	-- End collecting data
	---------------------------------------------------------------
	
	---------------------------------------------------------------		
	-- Start collecting childrens
	---------------------------------------------------------------
	claims = entity['claims'][property]
	
	if not claims then
		return {}
	end
	
	for  _,claim in pairs( claims ) do
		local value = claim.mainsnak.datavalue.value
		local nextitem = 'Q' .. value['numeric-id']

		childrens[x] = nextitem
		x = x + 1
	end
	
	return childrens
	---------------------------------------------------------------		
	-- End collecting childrens
	---------------------------------------------------------------
end
		
-- generator, see http://lua-users.org/wiki/LuaCoroutinesVersusPythonGenerators for lua doc
-- definition a function that when called several times will generate a sequence of strings
 
-- gensymbols = create_gensymbols("ABC")
-- gensymbols() == "A" 
-- gensymbols() == "B" g
-- gensymbols() == "C" 
-- gensymbols() == "AA" '
-- gensymbols() == "BABBA"
-- ...
function p.gensymbols(chars)
	local i = 0
	local charset = chars
 
	local generator = function ()
		local symbol = ""
		local rest
 
		rest = i
 
		repeat
			local j 
			j = rest % string.len(charset)
			rest = math.floor(rest / string.len(charset))
			symbol = symbol .. string.sub(charset, j+1, j+1)
		until rest <= 0
		i = i + 1
		return symbol
	end
	return generator
end

-------------------------------------------------------------------------------------------	
-- Start definition of itemOutput function which returns text like '[[' .. link .. '|' .. label .. ']]'
-------------------------------------------------------------------------------------------	
function p.itemOutput(item, lang1, lang2, datas, setdata, getdata, highlightItemID)
		
	local globalSiteId_1 = lang1 .. 'wiki'
	local globalSiteId_2 = lang2 .. 'wiki'
	local highlightItem = highlightItemID
	
	local currentLabel
	local currentLabel_temp
	local wpLinkText = nil
	local commonsLinkText = nil
	local mapImageName = nil
	local currentPage = tostring(mw.title.getCurrentTitle().text)
	
	local content
	
	
	currentLabel = p.getdata(item, "short", nil )
	if currentLabel == nil or currentLabel == '' then
		currentLabel = p.getdata(item, "label_1", nil )
		if currentLabel == nil or currentLabel == '' then
			currentLabel = p.getdata(item, "sitelink_1", nil )
			if currentLabel == nil or currentLabel == '' then
				currentLabel = p.getdata(item, "label_2", nil )
				if currentLabel == nil or currentLabel == '' then
					currentLabel = p.getdata(item, "sitelink_2", nil )
					if currentLabel == nil or currentLabel == '' then
						currentLabel = item
					end
				end
			end
		end
	end
	
	content = '[[' .. item .. '|' .. currentLabel .. ']]'
	
	wpLinkText = p.getdata(item, "sitelink_1", nil )
	commonsLinkText = p.getdata(item, "commons", nil )
	haplogroupDotOrgText = p.getdata(item, "haplogroup.org", nil ) 
	phylotreeDotOrgText = p.getdata(item, "phylotree.org", nil ) 
	yfullDotComText = p.getdata(item, "yfull.com", nil ) 
	dateText = p.getdata(item, "date", nil )
	placeText = p.getdata(item, "place", nil )
	possessorText = p.getdata(item, "possessor", nil )
	refseqText = p.getdata(item, "refseq", nil )
	mapImageName = p.getdata(item, "mapimage", nil )
	
	if wpLinkText or commonsLinkText or haplogroupDotOrgText or yfullDotComText then 
		content = content .. ' ('
	end
	--content = content .. '[[Talk:'.. item .. '|talk]]'
	
	if wpLinkText and wpLinkText ~= '' then
		--content = content .. ', '
		if highlightItem == item then
			content = content .. '[[:w:'.. lang1 ..':' .. wpLinkText .. '|' .. lang1 ..'wiki]]'
		else
			content = content .. '<span style="background-color: yellow;">[[:w:'.. lang1 ..':' .. wpLinkText .. '|' .. lang1 ..'wiki]]</span>'
		end
	end
		
	if commonsLinkText and commonsLinkText ~= '' then
		if wpLinkText then
			content = content .. ', '
		end
		if highlightItem == item then
			content = content .. '[[:commons:' .. commonsLinkText .. '|commons]]'
		else
			content = content .. '<span style="background-color: #dcdcf5;">[[:commons:' .. commonsLinkText .. '|commons]]</span>'
		end
	end
	
	if haplogroupDotOrgText and haplogroupDotOrgText ~= '' then
		if wpLinkText or commonsLinkText then
			content = content .. ', '
		end
		content = content .. '<span class="plainlinks">[' .. haplogroupDotOrgText .. ' haplogroup.org]</span>'
		--content = content .. haplogroupDotOrgText -- When checking bare URL
	end
	
	if yfullDotComText and yfullDotComText ~= '' then
		if wpLinkText or commonsLinkText or haplogroupDotOrgText then
			content = content .. ', '
		end
		content = content .. '<span class="plainlinks">[' .. yfullDotComText .. ' yfull.com]</span>'
		--content = content .. yfullDotComText -- When checking bare URL
	end
		
	if wpLinkText or commonsLinkText or haplogroupDotOrgText or yfullDotComText then 
		content = content .. ')'
	end
	--red #FFDFDF|#FF9797
	--blue '#D7D1F8', '#A095EE'
	if highlightItem == item then
		--'<span style="font-weight: bold;">' ..  .. '</span>'
		content =  '<span style="font-weight: bold;">' ..  mw.getCurrentFrame():expandTemplate{ title = 'Font & border color', args = {'black','#D7D1F8', '#A095EE', content} } .. '</span>'
	end
	
	if item == 'Q46999198' then --Q46999198 is 'Haplogroup H2a2a1' which is haplogroup for CRS (Cambridge Reference Sequence)
		content = content .. ' ' .. mw.getCurrentFrame():expandTemplate{ title = 'Font & border color', args = {'black','#FFEAB7', '#FFC848', '[[:w:en:Cambridge Reference Sequence|rCRS]]'} }
	end
	
	if phylotreeDotOrgText or dateText or placeText or possessorText or refseqText or mapImageName then 
		content = content .. '<div class="mw-collapsible mw-collapsed" id="mw-customcollapsible-1" style="padding:0px; border:0px;">'
		
		if phylotreeDotOrgText and phylotreeDotOrgText ~= '' then
			content = content .. 'Reference tree: ' .. '<span class="plainlinks">' .. phylotreeDotOrgText .. '</span>'
		end
		if dateText and dateText ~= '' then
			if phylotreeDotOrgText then
				content = content .. '<br/>'
			end
			content = content .. 'Age: ' .. dateText.time
			--mw.logObject(dateText)
		end
		if placeText and placeText ~= '' then
			if phylotreeDotOrgText or dateText then
				content = content .. '<br/>'
			end
			content = content .. 'Origin: ' .. placeText
		end
		if refseqText and refseqText ~= '' then
			if phylotreeDotOrgText or dateText or placeText then
				content = content .. '<br/>'
			end
			content = content .. 'Full DNA sequence: ' .. refseqText
		end
		if possessorText and possessorText ~= '' then
			if phylotreeDotOrgText or dateText or placeText or refseqText then
				content = content .. '<br/>'
			end
			content = content .. 'Possessor: ' .. possessorText
		end
		if mapImageName and mapImageName ~= '' then
			if phylotreeDotOrgText or dateText or placeText or refseqText or possessorText then
				content = content .. '<br/>'
			end
			content = content .. '[[File:' .. mapImageName .. '|x150px]]'
		end
		
		content = content .. '</div>'
		
	end
	
	--if mapImageName and mapImageName ~= '' then
	--content = content .. '<div class="mw-customtoggle-' .. item .. '" style="float: left;">&#x25BC;</div>'
	--content = content .. '<div class="mw-collapsible mw-collapsed" id="mw-customcollapsible-' .. item .. '" style="padding:0px; border:0px;">'
	--	content = content .. '[[File:' .. mapImageName .. '|x150px]]'
	--content = content .. '</div>'
	--end
			
	
	return content

end
-------------------------------------------------------------------------------------------	
-- End definition of itemOutput function which returns text like '[[' .. link .. '|' .. label .. ']]'
-------------------------------------------------------------------------------------------	

function p.outputTree( firstItemId, property, direction, maxdepth, lang1, lang2, highlightItemID)
-------------------------------------------------------------------------------------------	
-- Start preparation of functions
-------------------------------------------------------------------------------------------	
	----- topological sort and meta data of the DAG ( https://en.wikipedia.org/wiki/Topological_sorting )
		
	--This firstPass() function is called only once, at first
	local function firstPass( firstItemId, item_repr )
	
	
	--mw.log("firstItemId is: ")
	--mw.logObject(firstItemId)
	--mw.log("")
	--mw.log("")
	
	    local content = p.itemOutput(firstItemId, lang1, lang2, datas, setdata, getdata, highlightItemID)
 
	    local opened = 1 -- This means the downstream branch of the item is under processing.
						 -- If encountering opened item through the processing, it indicates that infinite loop exists.   
						 
	    local closed = 2 -- This means the processing of all downstream branches of the item reached to its end.
						 -- The downest item is showed with " ? " in tree.
						 
	    local incomplete = 3 -- This means the processing of all downstream branches of the item reached to its end.
							 -- If more downstream branches exist but not processed (because of limitation from maxdepth),
							 -- then the downest item showed with "…" in tree.
							 
	    local marks = {} --opened(1) or closed(2) or incomplete(3) for each QID (e.g. marks[Q12234234] -> closed)
		
 
	    --local datas = {} --datas[QID]["nparents"], datas[QID]["symbol"], datas[QID]["looped"], datas[QID]["rank"], datas[QID]["status"]
						--datas[QID]["nparents"] represents "number of parents" of certain item. This is normally 1.
						--If this is 2 or more, it means that the exact same item appears several times in defferent branches of the tree repeatedly.
						
		local childrens = {} -- for example, childrens[Q1234] contains data like {Q123123, Q3984198237, Q1874138746}, three childrens of Q1234
 		
		--while there are unmarked nodes do
		--    select an unmarked node n
		--    visit(n) 
		--function visit(node n)
		--    if n has a temporary mark then stop (not a DAG)
		--    if n is not marked (i.e. has not been visited yet) then
		--        mark n temporarily
		--        for each node m with an edge from n to m do
		--            visit(m)
		--        mark n permanently
		--        add n to head of L
 
		-- this function 
		-- * visits and builds the tree, DAG or graph,
		-- * in the same pass, computes a topological ordering for the DAG
		-- * annotates the nodes with informations
	    function visit(n, depth, rank)
	    	--mw.log("depth is " .. depth ..  ">=" .. "maxdepth is " .. maxdepth) 
 
			--mw.log(n .. ": mark is " .. tostring(marks[n]))
			if marks[n] == opened then 
				p.setdata(n, "status", "loop")
				p.setdata(n, "rank", rank)
				return rank
			elseif marks[n] ~= closed then
				marks[n] = opened
 
				childrens[n] = p.children( n, property, direction, maxdepth, lang1, lang2)
				for _, node in ipairs(childrens[n]) do
					p.setdata(node, "nparents", 
						p.getdata(node, "nparents", 0) + 1
					) 
					
					if depth <= maxdepth then
						rank = visit(node, depth + 1, rank + 1)
					end
				end
 
				if depth <= maxdepth then
					if p.getdata(n, "status", "complete") ~= "loop" then
						p.setdata(n, "status", "complete")
					end
					marks[n] = closed
				else
					p.setdata(n, "status", "incomplete")
					marks[n] = incomplete
				end
 
				p.setdata(n, "rank", rank)
			end
			return rank + 1
		end
		p.setdata(firstItemId, "nparents", 0)
		visit(firstItemId, 1, 0)
 
		return datas, childrens
	end

	local langobj = mw.language.new(lang1)
	-- link inside tree 
	local function formatSymbol(prefix)
		return '<span class="Unicode"><small>(' .. prefix .. ")</small></span>"
	end
	local function genAnchor(id)
		return '<span id="' .. firstItemId .. id .. '"></span>' 
	end
	local function anchorLink(id, content)
		return "[[#" .. firstItemId .. id .. "|" .. content .. "]]"
	end
	local function fmtTreeLinks(content)
		return mw.text.tag("sup", {}, content)
	end
 
	local function renderTree( itemId, datas, children, alreadyOuted, gs )
		local content = p.itemOutput( itemId, lang1, lang2, datas, setdata, getdata, highlightItemID)
		local state
 
		if datas[itemId]["status"] ~= nil then
			state = datas[itemId]["status"] 
		end
		--mw.log(itemId .. ": status is " .. state )
 
		if 	datas[itemId] ["nparents"] > 1 and datas[itemId]["symbol"] == nil then
			p.setdata(itemId, "symbol", gs() )
		end
		-- prevent infinite loops in non DAGs
		if state == "loop" then
			if datas[itemId]["looped"] == nil then
				datas[itemId]["looped"] = "treated"
				content =  fmtTreeLinks(" ∞") .. " " .. content .. genAnchor(itemId)
			else
				return content ..  fmtTreeLinks("∞" ..	" ↑ " .. anchorLink(itemId, formatSymbol( datas[itemId]["symbol"] )))
			end
		elseif state == "incomplete" or state == "unvisited" then
			content = content .. " " .. fmtTreeLinks("…")
			return content
		end
 
		-- has no chilren ? display as leaf
		if children[itemId] ~= nil and table.getn(children[itemId]) == 0 then
			--return " " .. content .. " ? " -- would be great to use "?b, but font problem
			return " " .. content
		end
 
 
		datas[itemId] ["nparents"] = datas[itemId]["nparents"] - 1
 
	    local parts = {}
 
		-- sort children topologycally
		if alreadyOuted[itemId] == nil then
 
 			local langobj = mw.language.new(lang1)
		    local prefix = " "
		    if datas[itemId] ["nparents"] > 0 then
		    	local arrow = langobj:getArrow()
		    	prefix = fmtTreeLinks(genAnchor(itemId) .. " " .. arrow .. " " .. formatSymbol(datas[itemId]["symbol"]))
	    	end
				
			order = children[itemId]
	    	table.sort(order, function (a, b) return datas[a]["rank"] < datas[b]["rank"] end )
 
		    for i, childId in ipairs(order) do
		        table.insert( parts, renderTree( childId, datas, children, alreadyOuted, gs ) )
		    end
	 
			if direction == "child" or direction == "brother" then 
				local l = table.maxn( parts )
				for i = 1,(l - 1) do
					parts[i] = mw.text.tag( 'li', {}, parts[i] )
				end
				parts[l] = mw.text.tag( 'li', { class = 'lastline' }, parts[l] )
				alreadyOuted[itemId] = prefix .. " " .. content  .. mw.text.tag( 'ul', {}, table.concat( parts ) )
			elseif direction == "parent" then 				
				local texttmp
				local matchCount = 0
				--mw.log("parts is: ")
				--mw.logObject(parts)
				texttmp = mw.text.tag( 'ul', {}, mw.text.tag( 'li', { class = 'lastline' }, content ) )
				
				alreadyOuted[itemId], matchCount = string.gsub(table.concat( parts ), "(</li></ul>)", texttmp .. "%1", 1)
				--mw.log('matchCount is:')
				--mw.log(matchCount)
				if matchCount == 0 then
					alreadyOuted[itemId] = prefix .. " " .. string.gsub(table.concat( parts ), "$", texttmp, 1)
				end
				alreadyOuted[itemId] = prefix .. " " .. alreadyOuted[itemId]
				--mw.log("alreadyOuted[itemId] is: ")
				--mw.logObject(alreadyOuted[itemId])
			end
			
		end
 
		if datas[itemId] ["nparents"] <= 0 or state == "loop" then
			return alreadyOuted[itemId]
		else 
			return content .. " " .. fmtTreeLinks(anchorLink(itemId, formatSymbol(datas[itemId]["symbol"])) .. " " .. langobj:getArrow(forward))
		end
	end
-------------------------------------------------------------------------------------------	
-- End preparation of functions
-------------------------------------------------------------------------------------------	
 
-------------------------
-- Start creating tree --
-------------------------
	-- gen = p.gensymbols("??")
	-- gen = p.gensymbols("12")
	-- gen = p.gensymbols("★☆?")
	-- These symbols are used as link button for "jumping" from certain branch to other branch.
	-- "jumping" functionality is used when same item appears multipul times in one tree.
	local gen = p.gensymbols("@*#") 
 
	local children 
	datas, children = firstPass( firstItemId, gen)
	-- alreadyOuted is the table which contains html code for each QID.
	-- For example, like this... alreadyOuted[Q1234] = "<li>[[Human body]]</li>"
	-- Actually items which located more nearer to the root (to say, FirstItemId) contain html codes of their branchs within it. 
	-- For example, like this... alreadyOuted[Q1234] = "<li>[[Human body]] <ul><li>[[Nervous system]]</li></ul></li>"
	-- This is done by recursive calling of renderTree() function inside the renderTree() function.
	local alreadyOuted = {} 
	rendering = {} -- What does this do?
	return  renderTree( firstItemId, datas, children, alreadyOuted, gen)
-----------------------
-- End creating tree --
-----------------------
end

function p.main( frame )
------------------------------------
-- Start adjustments of arguments 
------------------------------------
    local maxdepth
    --local lang1 = mw.language.getContentLanguage().code
    local lang1 = mw.getCurrentFrame():preprocess("{{int:lang}}")
	local lang2 = 'en'
	local firstItemId = frame.args.firstItemId
	local direction = frame.args.direction -- tree searching direction. "child", "parent" or "brother
	local highlightItemID = frame.args.highlight
	local maxdepth = frame.args.maxdepth
	
	if tonumber(firstItemId) then --legacy format
		firstItemId = 'Q'.. tostring(firstItemId)
	end
	
	if direction == nil or direction =='' then --Default direction is child
		direction = 'child'
	end
	
	if tonumber(highlightItemID) then --legacy format
		highlightItemID = 'Q'.. tostring(highlightItemID)
	end
	
	if maxdepth and maxdepth ~= '' then
		maxdepth = tonumber( maxdepth )
	else
		maxdepth = 25
	end
	
----------------------------------
-- End adjustments of arguments 
----------------------------------

-------------------------
-- Start creating tree --
-------------------------
    local content = ''
	local property -- property used to search items. For example "P156" (followed by) or "P155" (follows)
	
	--------------------------------------------------
	--Creating tree for child side (downstream side)
	--------------------------------------------------
	if direction == 'child' then
		property = "P156"
	elseif direction == 'parent' then
		property = "P155"
	end
	
	content = mw.text.tag( 'li', { class = 'lastline' }, p.outputTree( firstItemId, property, direction, maxdepth, lang1, lang2, highlightItemID ) )
	content = '<div class="mw-customtoggle-1" style="float: left;"><span style="color:#36b;">[Show detail]</span></div><br/><br/>' .. content 

	--mw.log("content is: ")
	--mw.logObject(content)
	
	--------------------------------------------------
	-- Final formatting 
	--------------------------------------------------
	res =  mw.text.tag( 'div', { class = 'treeview' }, mw.text.tag( 'ul', {}, content ) )
-----------------------
-- End creating tree --
-----------------------
    return res
end

return p