<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Maintenance+script</id>
	<title>Amateur Theatre Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Maintenance+script"/>
	<link rel="alternate" type="text/html" href="https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/index.php/Special:Contributions/Maintenance_script"/>
	<updated>2026-07-12T03:58:47Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/index.php?title=Template:AIGenerated&amp;diff=2038</id>
		<title>Template:AIGenerated</title>
		<link rel="alternate" type="text/html" href="https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/index.php?title=Template:AIGenerated&amp;diff=2038"/>
		<updated>2026-06-29T11:08:17Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Deployed from Ansible&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;onlyinclude&amp;gt;&amp;lt;div style=&amp;quot;border: 2px solid light-dark(#f0a500, #c47f00); background-color: light-dark(#fff8e7, #2a2000); color: light-dark(#3a2a00, #f5d78e); padding: 8px 12px; margin-bottom: 1em; font-size: 0.9em; color-scheme: light dark;&amp;quot;&amp;gt;&lt;br /&gt;
⚠️ &#039;&#039;&#039;This page was generated by an AI&#039;&#039;&#039; and has not yet been proofread by a human editor. Information may be incomplete or inaccurate.&lt;br /&gt;
&amp;lt;/div&amp;gt;[[Category:AI-Generated]]{{#ifeq:{{{patrolled|false}}}|true|[[Category:Patrolled]]|[[Category:ToPatrol]]}}&amp;lt;/onlyinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;noinclude&amp;gt;&lt;br /&gt;
== Usage ==&lt;br /&gt;
Place this template at the top of AI-generated pages to inform readers and track review status.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;{{AIGenerated}}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;{{AIGenerated|patrolled=true}}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;patrolled&amp;lt;/code&amp;gt; (optional, default: &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;)&lt;br /&gt;
: Set to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; once the page has been reviewed. Adds [[Category:Patrolled]] instead of [[Category:ToPatrol]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;templatedata&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;description&amp;quot;: &amp;quot;Marks a page as AI-generated and not yet proofread. Adds maintenance categories based on patrol status.&amp;quot;,&lt;br /&gt;
  &amp;quot;params&amp;quot;: {&lt;br /&gt;
    &amp;quot;patrolled&amp;quot;: {&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;boolean&amp;quot;,&lt;br /&gt;
      &amp;quot;label&amp;quot;: &amp;quot;Patrolled&amp;quot;,&lt;br /&gt;
      &amp;quot;description&amp;quot;: &amp;quot;Set to true if the page has been reviewed by a human editor. Defaults to false.&amp;quot;,&lt;br /&gt;
      &amp;quot;default&amp;quot;: &amp;quot;false&amp;quot;,&lt;br /&gt;
      &amp;quot;required&amp;quot;: false&lt;br /&gt;
    }&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;format&amp;quot;: &amp;quot;inline&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/templatedata&amp;gt;&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/index.php?title=Module:DynamicCapiunto&amp;diff=2037</id>
		<title>Module:DynamicCapiunto</title>
		<link rel="alternate" type="text/html" href="https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/index.php?title=Module:DynamicCapiunto&amp;diff=2037"/>
		<updated>2026-06-29T11:08:14Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Deployed from Ansible&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local capiunto = require &#039;capiunto&#039;&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
    local args = frame:getParent().args&lt;br /&gt;
    local qid = args.qid or args[1]&lt;br /&gt;
&lt;br /&gt;
    if not qid then&lt;br /&gt;
        return &#039;&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;Error: No Wikidata QID provided&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Register the entity association&lt;br /&gt;
    frame:callParserFunction(&#039;#unlinkedwikibase&#039;, &#039;id=&#039; .. qid)&lt;br /&gt;
&lt;br /&gt;
    -- Get entity data from UnlinkedWikibase&lt;br /&gt;
    local entity = mw.ext.UnlinkedWikibase.getEntity(qid)&lt;br /&gt;
&lt;br /&gt;
    if not entity then&lt;br /&gt;
        return &#039;&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;Error: Entity &#039; .. qid ..&lt;br /&gt;
                   &#039; not found&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper function to get property value from entity&lt;br /&gt;
    local function getPropertyValue(pid)&lt;br /&gt;
        if not entity.claims or not entity.claims[pid] then return nil end&lt;br /&gt;
&lt;br /&gt;
        local claims = entity.claims[pid]&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
&lt;br /&gt;
        local claim = claims[1]&lt;br /&gt;
        if not claim.mainsnak or not claim.mainsnak.datavalue then&lt;br /&gt;
            return nil&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        return claim.mainsnak.datavalue.value&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper function to format different value types&lt;br /&gt;
    local function formatValue(value, valueType)&lt;br /&gt;
        if not value then return nil end&lt;br /&gt;
&lt;br /&gt;
        if type(value) == &#039;table&#039; then&lt;br /&gt;
            -- Handle time values&lt;br /&gt;
            if value.time then&lt;br /&gt;
                -- Extract year-month-day from +2023-01-15T00:00:00Z format&lt;br /&gt;
                local dateStr = value.time&lt;br /&gt;
                local year, month, day =&lt;br /&gt;
                    dateStr:match(&#039;^[+-]?(%d+)-(%d+)-(%d+)&#039;)&lt;br /&gt;
                if year then&lt;br /&gt;
                    local y = tonumber(year)&lt;br /&gt;
                    local m = tonumber(month) or 0&lt;br /&gt;
                    local d = tonumber(day) or 0&lt;br /&gt;
                    -- If month or day are zero/unknown, show only the year&lt;br /&gt;
                    if m == 0 or d == 0 then&lt;br /&gt;
                        return string.format(&#039;%04d&#039;, y)&lt;br /&gt;
                    end&lt;br /&gt;
                    return string.format(&#039;%04d-%02d-%02d&#039;, y, m, d)&lt;br /&gt;
                end&lt;br /&gt;
                return value.time&lt;br /&gt;
                -- Handle entity references (Q-IDs)&lt;br /&gt;
            elseif value.id then&lt;br /&gt;
                -- Register a parser cache dependency so the page is invalidated&lt;br /&gt;
                -- when UnlinkedWikibase populates or updates this entity&#039;s data.&lt;br /&gt;
                mw.ext.UnlinkedWikibase.getLocalTitle(value.id)&lt;br /&gt;
                local linkedEntity = mw.ext.UnlinkedWikibase.getEntity(value.id)&lt;br /&gt;
                if linkedEntity then&lt;br /&gt;
                    local label = (linkedEntity.labels and&lt;br /&gt;
                                      linkedEntity.labels.en) and&lt;br /&gt;
                                      linkedEntity.labels.en.value or value.id&lt;br /&gt;
                    -- Then prefer an en.wikipedia sitelink (external link)&lt;br /&gt;
                    if linkedEntity.sitelinks and linkedEntity.sitelinks.enwiki and&lt;br /&gt;
                        linkedEntity.sitelinks.enwiki.url then&lt;br /&gt;
                        return&lt;br /&gt;
                            &#039;[&#039; .. linkedEntity.sitelinks.enwiki.url .. &#039; &#039; ..&lt;br /&gt;
                                label .. &#039;]&#039;&lt;br /&gt;
                    end&lt;br /&gt;
                    -- Fallback to the English label if available&lt;br /&gt;
                    if linkedEntity.labels and linkedEntity.labels.en then&lt;br /&gt;
                        return label&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
                return value.id&lt;br /&gt;
                -- Handle monolingual text&lt;br /&gt;
            elseif value.text then&lt;br /&gt;
                return value.text&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        return tostring(value)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get claim entity id (if the claim is an entity)&lt;br /&gt;
    local function getClaimEntityId(pid)&lt;br /&gt;
        local v = getPropertyValue(pid)&lt;br /&gt;
        if type(v) == &#039;table&#039; and v.id then return v.id end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get the first claim object for a property&lt;br /&gt;
    local function getFirstClaimObject(pid)&lt;br /&gt;
        if not entity.claims or not entity.claims[pid] then return nil end&lt;br /&gt;
        local claims = entity.claims[pid]&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
        return claims[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get a qualifier value (prefer English monolingual text for P2096)&lt;br /&gt;
    local function getQualifierValue(claim, qualPid)&lt;br /&gt;
        if not claim or not claim.qualifiers or not claim.qualifiers[qualPid] then&lt;br /&gt;
            return nil&lt;br /&gt;
        end&lt;br /&gt;
        local qsnaks = claim.qualifiers[qualPid]&lt;br /&gt;
        if not qsnaks or #qsnaks == 0 then return nil end&lt;br /&gt;
        for i, q in ipairs(qsnaks) do&lt;br /&gt;
            -- Check for valid snak with datavalue&lt;br /&gt;
            if q and q.snaktype == &#039;value&#039; and q.datavalue and q.datavalue.value then&lt;br /&gt;
                local v = q.datavalue.value&lt;br /&gt;
                if type(v) == &#039;table&#039; then&lt;br /&gt;
                    -- For monolingual text, prefer English&lt;br /&gt;
                    if v.language and v.language == &#039;en&#039; and v.text then&lt;br /&gt;
                        return v.text&lt;br /&gt;
                    end&lt;br /&gt;
                else&lt;br /&gt;
                    return tostring(v)&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Extract a {latitude, longitude} coordinate (P625) from an entity object.&lt;br /&gt;
    local function getCoordFromEntity(ent)&lt;br /&gt;
        if not ent or not ent.claims or not ent.claims.P625 then return nil end&lt;br /&gt;
        local claims = ent.claims.P625&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
        local snak = claims[1].mainsnak&lt;br /&gt;
        if not snak or not snak.datavalue then return nil end&lt;br /&gt;
        local v = snak.datavalue.value&lt;br /&gt;
        if type(v) == &#039;table&#039; and v.latitude and v.longitude then return v end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add a Leaflet/OpenStreetMap map for this entity.&lt;br /&gt;
    -- Prefer the entity&#039;s own coordinate location (P625). If it has none, fall&lt;br /&gt;
    -- back to the coordinates of the entity referenced as its headquarters&lt;br /&gt;
    -- location (P159), fetched via UnlinkedWikibase.&lt;br /&gt;
    -- Rendered via the Maps extension&#039;s #display_map parser function. A module&#039;s&lt;br /&gt;
    -- return value goes through the main parse pass but NOT the preprocessor, so&lt;br /&gt;
    -- parser-function syntax would otherwise be emitted literally. We expand it&lt;br /&gt;
    -- here with frame:preprocess() and add the resulting HTML to the infobox.&lt;br /&gt;
    local function addMap(box)&lt;br /&gt;
        local coord = getCoordFromEntity(entity)&lt;br /&gt;
        if not coord then&lt;br /&gt;
            local hqId = getClaimEntityId(&#039;P159&#039;)&lt;br /&gt;
            if hqId then&lt;br /&gt;
                -- Register a parser cache dependency on the HQ entity so the&lt;br /&gt;
                -- page is invalidated when its data is populated/updated.&lt;br /&gt;
                mw.ext.UnlinkedWikibase.getLocalTitle(hqId)&lt;br /&gt;
                coord = getCoordFromEntity(&lt;br /&gt;
                            mw.ext.UnlinkedWikibase.getEntity(hqId))&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        if not coord then return end&lt;br /&gt;
        local mapHtml = frame:preprocess(string.format(&lt;br /&gt;
                            &#039;{{#display_map:%s,%s|width=100%%|height=200|zoom=13|service=leaflet}}&#039;,&lt;br /&gt;
                            tostring(coord.latitude), tostring(coord.longitude)))&lt;br /&gt;
        box:addWikitext(mapHtml)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local function addWikidataLink(box)&lt;br /&gt;
        box:addWikitext(&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;width:100%; text-align:center; font-size:85%;&amp;quot;&amp;gt;[&#039; ..&lt;br /&gt;
                &#039;https://www.wikidata.org/wiki/&#039; .. qid ..&lt;br /&gt;
                &#039; View on Wikidata]&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Decide which infobox to render based on instance (P31)&lt;br /&gt;
    local instanceId = getClaimEntityId(&#039;P31&#039;)&lt;br /&gt;
    local infobox&lt;br /&gt;
&lt;br /&gt;
    if instanceId == &#039;Q5&#039; then&lt;br /&gt;
        -- Person infobox&lt;br /&gt;
        local personTitle = qid&lt;br /&gt;
        if entity.labels and entity.labels.en then&lt;br /&gt;
            personTitle = entity.labels.en.value&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        infobox = capiunto.create({&lt;br /&gt;
            title = personTitle,&lt;br /&gt;
            bodyClass = &#039;infobox vevent&#039;,&lt;br /&gt;
            bodyStyle = &#039;width: 300px;&#039;&lt;br /&gt;
        })&lt;br /&gt;
&lt;br /&gt;
        -- Add image (P18) with media legend (P2096) as caption&lt;br /&gt;
        local imageClaim = getFirstClaimObject(&#039;P18&#039;)&lt;br /&gt;
        if imageClaim then&lt;br /&gt;
            local imageVal = imageClaim.mainsnak and&lt;br /&gt;
                                 imageClaim.mainsnak.datavalue and&lt;br /&gt;
                                 imageClaim.mainsnak.datavalue.value&lt;br /&gt;
            if imageVal then&lt;br /&gt;
                local imageStr = tostring(imageVal)&lt;br /&gt;
                local caption = getQualifierValue(imageClaim, &#039;P2096&#039;)&lt;br /&gt;
                if caption and caption ~= &#039;&#039; then&lt;br /&gt;
                    infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;,&lt;br /&gt;
                                     caption)&lt;br /&gt;
                else&lt;br /&gt;
                    infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;)&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Birthplace (P19)&lt;br /&gt;
        local birthplace = getPropertyValue(&#039;P19&#039;)&lt;br /&gt;
        if birthplace then&lt;br /&gt;
            infobox:addRow(&#039;Birthplace&#039;, formatValue(birthplace))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Birthday (P569)&lt;br /&gt;
        local birthday = getPropertyValue(&#039;P569&#039;)&lt;br /&gt;
        if birthday then&lt;br /&gt;
            infobox:addRow(&#039;Birthday&#039;, formatValue(birthday))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Death (P570)&lt;br /&gt;
        local death = getPropertyValue(&#039;P570&#039;)&lt;br /&gt;
        if death then infobox:addRow(&#039;Death&#039;, formatValue(death)) end&lt;br /&gt;
&lt;br /&gt;
        -- Occupation (P106)&lt;br /&gt;
        local occupation = getPropertyValue(&#039;P106&#039;)&lt;br /&gt;
        if occupation then&lt;br /&gt;
            infobox:addRow(&#039;Occupation&#039;, formatValue(occupation))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        addMap(infobox)&lt;br /&gt;
        addWikidataLink(infobox)&lt;br /&gt;
&lt;br /&gt;
        return tostring(infobox) .. &#039;\n[[Category:People]]&#039;&lt;br /&gt;
    else&lt;br /&gt;
        -- Default: organisation/troupe infobox (existing behavior)&lt;br /&gt;
        local title = qid&lt;br /&gt;
        if entity.labels and entity.labels.en then&lt;br /&gt;
            title = entity.labels.en.value&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        infobox = capiunto.create({&lt;br /&gt;
            title = title,&lt;br /&gt;
            bodyClass = &#039;infobox vevent&#039;,&lt;br /&gt;
            bodyStyle = &#039;width: 300px;&#039;&lt;br /&gt;
        })&lt;br /&gt;
&lt;br /&gt;
        -- Add official name (P1448)&lt;br /&gt;
        local officialName = getPropertyValue(&#039;P1448&#039;)&lt;br /&gt;
        if officialName then&lt;br /&gt;
            infobox:addRow(&#039;Official Name&#039;, formatValue(officialName))&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add logo (P154)&lt;br /&gt;
    local logo = getPropertyValue(&#039;P154&#039;)&lt;br /&gt;
    if logo then&lt;br /&gt;
        local logoStr = formatValue(logo)&lt;br /&gt;
        if logoStr then&lt;br /&gt;
            infobox:addImage(&#039;[[File:&#039; .. logoStr .. &#039;|150px]]&#039;, &#039;Logo&#039;)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add image (P18) with media legend (P2096) as caption&lt;br /&gt;
    local imageClaim = getFirstClaimObject(&#039;P18&#039;)&lt;br /&gt;
    if imageClaim then&lt;br /&gt;
        local imageVal =&lt;br /&gt;
            imageClaim.mainsnak and imageClaim.mainsnak.datavalue and&lt;br /&gt;
                imageClaim.mainsnak.datavalue.value&lt;br /&gt;
        if imageVal then&lt;br /&gt;
            local imageStr = tostring(imageVal)&lt;br /&gt;
            local caption = getQualifierValue(imageClaim, &#039;P2096&#039;)&lt;br /&gt;
            if caption and caption ~= &#039;&#039; then&lt;br /&gt;
                infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;, caption)&lt;br /&gt;
            else&lt;br /&gt;
                infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;)&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add headquarters (P159)&lt;br /&gt;
    local headquarters = getPropertyValue(&#039;P159&#039;)&lt;br /&gt;
    if headquarters then&lt;br /&gt;
        infobox:addRow(&#039;Headquarters&#039;, formatValue(headquarters))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add founding date (P571)&lt;br /&gt;
    local foundingDate = getPropertyValue(&#039;P571&#039;)&lt;br /&gt;
    if foundingDate then&lt;br /&gt;
        infobox:addRow(&#039;Founding Date&#039;, formatValue(foundingDate))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add dissolution date (P576)&lt;br /&gt;
    local dissolutionDate = getPropertyValue(&#039;P576&#039;)&lt;br /&gt;
    if dissolutionDate then&lt;br /&gt;
        infobox:addRow(&#039;Dissolution Date&#039;, formatValue(dissolutionDate))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add country (P17)&lt;br /&gt;
    local country = getPropertyValue(&#039;P17&#039;)&lt;br /&gt;
    if country then infobox:addRow(&#039;Country&#039;, formatValue(country)) end&lt;br /&gt;
&lt;br /&gt;
    -- Add parent organization (P749)&lt;br /&gt;
    local parentOrg = getPropertyValue(&#039;P749&#039;)&lt;br /&gt;
    if parentOrg then&lt;br /&gt;
        infobox:addRow(&#039;Parent Organization&#039;, formatValue(parentOrg))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add official website (P856) as full-width row at bottom&lt;br /&gt;
    local website = getPropertyValue(&#039;P856&#039;)&lt;br /&gt;
    if website then&lt;br /&gt;
        local websiteStr = formatValue(website)&lt;br /&gt;
        if websiteStr then&lt;br /&gt;
            -- Strip http:// or https:// from display text&lt;br /&gt;
            local displayUrl = websiteStr:gsub(&#039;^https?://&#039;, &#039;&#039;)&lt;br /&gt;
            infobox:addWikitext(&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%; text-align:center;&amp;quot;&amp;gt;[&#039; .. websiteStr ..&lt;br /&gt;
                    &#039; &#039; .. displayUrl .. &#039;]&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    addMap(infobox)&lt;br /&gt;
    addWikidataLink(infobox)&lt;br /&gt;
&lt;br /&gt;
    return tostring(infobox) ..&lt;br /&gt;
               &#039;\n[[Category:Clubs, Societies and Institutions]]&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/index.php?title=Module:DynamicCapiunto&amp;diff=2035</id>
		<title>Module:DynamicCapiunto</title>
		<link rel="alternate" type="text/html" href="https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/index.php?title=Module:DynamicCapiunto&amp;diff=2035"/>
		<updated>2026-06-28T11:20:09Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Deployed from Ansible&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local capiunto = require &#039;capiunto&#039;&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
    local args = frame:getParent().args&lt;br /&gt;
    local qid = args.qid or args[1]&lt;br /&gt;
&lt;br /&gt;
    if not qid then&lt;br /&gt;
        return &#039;&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;Error: No Wikidata QID provided&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Register the entity association&lt;br /&gt;
    frame:callParserFunction(&#039;#unlinkedwikibase&#039;, &#039;id=&#039; .. qid)&lt;br /&gt;
&lt;br /&gt;
    -- Get entity data from UnlinkedWikibase&lt;br /&gt;
    local entity = mw.ext.UnlinkedWikibase.getEntity(qid)&lt;br /&gt;
&lt;br /&gt;
    if not entity then&lt;br /&gt;
        return &#039;&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;Error: Entity &#039; .. qid ..&lt;br /&gt;
                   &#039; not found&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper function to get property value from entity&lt;br /&gt;
    local function getPropertyValue(pid)&lt;br /&gt;
        if not entity.claims or not entity.claims[pid] then return nil end&lt;br /&gt;
&lt;br /&gt;
        local claims = entity.claims[pid]&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
&lt;br /&gt;
        local claim = claims[1]&lt;br /&gt;
        if not claim.mainsnak or not claim.mainsnak.datavalue then&lt;br /&gt;
            return nil&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        return claim.mainsnak.datavalue.value&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper function to format different value types&lt;br /&gt;
    local function formatValue(value, valueType)&lt;br /&gt;
        if not value then return nil end&lt;br /&gt;
&lt;br /&gt;
        if type(value) == &#039;table&#039; then&lt;br /&gt;
            -- Handle time values&lt;br /&gt;
            if value.time then&lt;br /&gt;
                -- Extract year-month-day from +2023-01-15T00:00:00Z format&lt;br /&gt;
                local dateStr = value.time&lt;br /&gt;
                local year, month, day =&lt;br /&gt;
                    dateStr:match(&#039;^[+-]?(%d+)-(%d+)-(%d+)&#039;)&lt;br /&gt;
                if year then&lt;br /&gt;
                    local y = tonumber(year)&lt;br /&gt;
                    local m = tonumber(month) or 0&lt;br /&gt;
                    local d = tonumber(day) or 0&lt;br /&gt;
                    -- If month or day are zero/unknown, show only the year&lt;br /&gt;
                    if m == 0 or d == 0 then&lt;br /&gt;
                        return string.format(&#039;%04d&#039;, y)&lt;br /&gt;
                    end&lt;br /&gt;
                    return string.format(&#039;%04d-%02d-%02d&#039;, y, m, d)&lt;br /&gt;
                end&lt;br /&gt;
                return value.time&lt;br /&gt;
                -- Handle entity references (Q-IDs)&lt;br /&gt;
            elseif value.id then&lt;br /&gt;
                -- Register a parser cache dependency so the page is invalidated&lt;br /&gt;
                -- when UnlinkedWikibase populates or updates this entity&#039;s data.&lt;br /&gt;
                mw.ext.UnlinkedWikibase.getLocalTitle(value.id)&lt;br /&gt;
                local linkedEntity = mw.ext.UnlinkedWikibase.getEntity(value.id)&lt;br /&gt;
                if linkedEntity then&lt;br /&gt;
                    local label = (linkedEntity.labels and&lt;br /&gt;
                                      linkedEntity.labels.en) and&lt;br /&gt;
                                      linkedEntity.labels.en.value or value.id&lt;br /&gt;
                    -- Then prefer an en.wikipedia sitelink (external link)&lt;br /&gt;
                    if linkedEntity.sitelinks and linkedEntity.sitelinks.enwiki and&lt;br /&gt;
                        linkedEntity.sitelinks.enwiki.url then&lt;br /&gt;
                        return&lt;br /&gt;
                            &#039;[&#039; .. linkedEntity.sitelinks.enwiki.url .. &#039; &#039; ..&lt;br /&gt;
                                label .. &#039;]&#039;&lt;br /&gt;
                    end&lt;br /&gt;
                    -- Fallback to the English label if available&lt;br /&gt;
                    if linkedEntity.labels and linkedEntity.labels.en then&lt;br /&gt;
                        return label&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
                return value.id&lt;br /&gt;
                -- Handle monolingual text&lt;br /&gt;
            elseif value.text then&lt;br /&gt;
                return value.text&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        return tostring(value)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get claim entity id (if the claim is an entity)&lt;br /&gt;
    local function getClaimEntityId(pid)&lt;br /&gt;
        local v = getPropertyValue(pid)&lt;br /&gt;
        if type(v) == &#039;table&#039; and v.id then return v.id end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get the first claim object for a property&lt;br /&gt;
    local function getFirstClaimObject(pid)&lt;br /&gt;
        if not entity.claims or not entity.claims[pid] then return nil end&lt;br /&gt;
        local claims = entity.claims[pid]&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
        return claims[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get a qualifier value (prefer English monolingual text for P2096)&lt;br /&gt;
    local function getQualifierValue(claim, qualPid)&lt;br /&gt;
        if not claim or not claim.qualifiers or not claim.qualifiers[qualPid] then&lt;br /&gt;
            return nil&lt;br /&gt;
        end&lt;br /&gt;
        local qsnaks = claim.qualifiers[qualPid]&lt;br /&gt;
        if not qsnaks or #qsnaks == 0 then return nil end&lt;br /&gt;
        for i, q in ipairs(qsnaks) do&lt;br /&gt;
            -- Check for valid snak with datavalue&lt;br /&gt;
            if q and q.snaktype == &#039;value&#039; and q.datavalue and q.datavalue.value then&lt;br /&gt;
                local v = q.datavalue.value&lt;br /&gt;
                if type(v) == &#039;table&#039; then&lt;br /&gt;
                    -- For monolingual text, prefer English&lt;br /&gt;
                    if v.language and v.language == &#039;en&#039; and v.text then&lt;br /&gt;
                        return v.text&lt;br /&gt;
                    end&lt;br /&gt;
                else&lt;br /&gt;
                    return tostring(v)&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Extract a {latitude, longitude} coordinate (P625) from an entity object.&lt;br /&gt;
    local function getCoordFromEntity(ent)&lt;br /&gt;
        if not ent or not ent.claims or not ent.claims.P625 then return nil end&lt;br /&gt;
        local claims = ent.claims.P625&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
        local snak = claims[1].mainsnak&lt;br /&gt;
        if not snak or not snak.datavalue then return nil end&lt;br /&gt;
        local v = snak.datavalue.value&lt;br /&gt;
        if type(v) == &#039;table&#039; and v.latitude and v.longitude then return v end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add a Leaflet/OpenStreetMap map for this entity.&lt;br /&gt;
    -- Prefer the entity&#039;s own coordinate location (P625). If it has none, fall&lt;br /&gt;
    -- back to the coordinates of the entity referenced as its headquarters&lt;br /&gt;
    -- location (P159), fetched via UnlinkedWikibase.&lt;br /&gt;
    -- Rendered via the Maps extension&#039;s #display_map parser function. A module&#039;s&lt;br /&gt;
    -- return value goes through the main parse pass but NOT the preprocessor, so&lt;br /&gt;
    -- parser-function syntax would otherwise be emitted literally. We expand it&lt;br /&gt;
    -- here with frame:preprocess() and add the resulting HTML to the infobox.&lt;br /&gt;
    local function addMap(box)&lt;br /&gt;
        local coord = getCoordFromEntity(entity)&lt;br /&gt;
        if not coord then&lt;br /&gt;
            local hqId = getClaimEntityId(&#039;P159&#039;)&lt;br /&gt;
            if hqId then&lt;br /&gt;
                -- Register a parser cache dependency on the HQ entity so the&lt;br /&gt;
                -- page is invalidated when its data is populated/updated.&lt;br /&gt;
                mw.ext.UnlinkedWikibase.getLocalTitle(hqId)&lt;br /&gt;
                coord = getCoordFromEntity(&lt;br /&gt;
                            mw.ext.UnlinkedWikibase.getEntity(hqId))&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        if not coord then return end&lt;br /&gt;
        local mapHtml = frame:preprocess(string.format(&lt;br /&gt;
                            &#039;{{#display_map:%s,%s|width=100%%|height=200|zoom=13|service=leaflet}}&#039;,&lt;br /&gt;
                            tostring(coord.latitude), tostring(coord.longitude)))&lt;br /&gt;
        box:addWikitext(mapHtml)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add a full-width link to the source Wikidata item so the underlying data&lt;br /&gt;
    -- can always be inspected, even when a referenced entity has not resolved to&lt;br /&gt;
    -- a label yet. (Replaces the Wikidata interlanguage links, which are off.)&lt;br /&gt;
    local function addWikidataLink(box)&lt;br /&gt;
        box:addWikitext(&lt;br /&gt;
            &#039;&amp;lt;div style=&amp;quot;width:100%; text-align:center; font-size:85%;&amp;quot;&amp;gt;[&#039; ..&lt;br /&gt;
                &#039;https://www.wikidata.org/wiki/&#039; .. qid ..&lt;br /&gt;
                &#039; View on Wikidata]&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Decide which infobox to render based on instance (P31)&lt;br /&gt;
    local instanceId = getClaimEntityId(&#039;P31&#039;)&lt;br /&gt;
    local infobox&lt;br /&gt;
&lt;br /&gt;
    if instanceId == &#039;Q5&#039; then&lt;br /&gt;
        -- Person infobox&lt;br /&gt;
        local personTitle = qid&lt;br /&gt;
        if entity.labels and entity.labels.en then&lt;br /&gt;
            personTitle = entity.labels.en.value&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        infobox = capiunto.create({&lt;br /&gt;
            title = personTitle,&lt;br /&gt;
            bodyClass = &#039;infobox vevent&#039;,&lt;br /&gt;
            bodyStyle = &#039;width: 300px;&#039;&lt;br /&gt;
        })&lt;br /&gt;
&lt;br /&gt;
        -- Add image (P18) with media legend (P2096) as caption&lt;br /&gt;
        local imageClaim = getFirstClaimObject(&#039;P18&#039;)&lt;br /&gt;
        if imageClaim then&lt;br /&gt;
            local imageVal = imageClaim.mainsnak and&lt;br /&gt;
                                 imageClaim.mainsnak.datavalue and&lt;br /&gt;
                                 imageClaim.mainsnak.datavalue.value&lt;br /&gt;
            if imageVal then&lt;br /&gt;
                local imageStr = tostring(imageVal)&lt;br /&gt;
                local caption = getQualifierValue(imageClaim, &#039;P2096&#039;)&lt;br /&gt;
                if caption and caption ~= &#039;&#039; then&lt;br /&gt;
                    infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;,&lt;br /&gt;
                                     caption)&lt;br /&gt;
                else&lt;br /&gt;
                    infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;)&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Birthplace (P19)&lt;br /&gt;
        local birthplace = getPropertyValue(&#039;P19&#039;)&lt;br /&gt;
        if birthplace then&lt;br /&gt;
            infobox:addRow(&#039;Birthplace&#039;, formatValue(birthplace))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Birthday (P569)&lt;br /&gt;
        local birthday = getPropertyValue(&#039;P569&#039;)&lt;br /&gt;
        if birthday then&lt;br /&gt;
            infobox:addRow(&#039;Birthday&#039;, formatValue(birthday))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Death (P570)&lt;br /&gt;
        local death = getPropertyValue(&#039;P570&#039;)&lt;br /&gt;
        if death then infobox:addRow(&#039;Death&#039;, formatValue(death)) end&lt;br /&gt;
&lt;br /&gt;
        -- Occupation (P106)&lt;br /&gt;
        local occupation = getPropertyValue(&#039;P106&#039;)&lt;br /&gt;
        if occupation then&lt;br /&gt;
            infobox:addRow(&#039;Occupation&#039;, formatValue(occupation))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        addMap(infobox)&lt;br /&gt;
        addWikidataLink(infobox)&lt;br /&gt;
&lt;br /&gt;
        return tostring(infobox) .. &#039;\n[[Category:People]]&#039;&lt;br /&gt;
    else&lt;br /&gt;
        -- Default: organisation/troupe infobox (existing behavior)&lt;br /&gt;
        local title = qid&lt;br /&gt;
        if entity.labels and entity.labels.en then&lt;br /&gt;
            title = entity.labels.en.value&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        infobox = capiunto.create({&lt;br /&gt;
            title = title,&lt;br /&gt;
            bodyClass = &#039;infobox vevent&#039;,&lt;br /&gt;
            bodyStyle = &#039;width: 300px;&#039;&lt;br /&gt;
        })&lt;br /&gt;
&lt;br /&gt;
        -- Add official name (P1448)&lt;br /&gt;
        local officialName = getPropertyValue(&#039;P1448&#039;)&lt;br /&gt;
        if officialName then&lt;br /&gt;
            infobox:addRow(&#039;Official Name&#039;, formatValue(officialName))&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add logo (P154)&lt;br /&gt;
    local logo = getPropertyValue(&#039;P154&#039;)&lt;br /&gt;
    if logo then&lt;br /&gt;
        local logoStr = formatValue(logo)&lt;br /&gt;
        if logoStr then&lt;br /&gt;
            infobox:addImage(&#039;[[File:&#039; .. logoStr .. &#039;|150px]]&#039;, &#039;Logo&#039;)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add image (P18) with media legend (P2096) as caption&lt;br /&gt;
    local imageClaim = getFirstClaimObject(&#039;P18&#039;)&lt;br /&gt;
    if imageClaim then&lt;br /&gt;
        local imageVal =&lt;br /&gt;
            imageClaim.mainsnak and imageClaim.mainsnak.datavalue and&lt;br /&gt;
                imageClaim.mainsnak.datavalue.value&lt;br /&gt;
        if imageVal then&lt;br /&gt;
            local imageStr = tostring(imageVal)&lt;br /&gt;
            local caption = getQualifierValue(imageClaim, &#039;P2096&#039;)&lt;br /&gt;
            if caption and caption ~= &#039;&#039; then&lt;br /&gt;
                infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;, caption)&lt;br /&gt;
            else&lt;br /&gt;
                infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;)&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add headquarters (P159)&lt;br /&gt;
    local headquarters = getPropertyValue(&#039;P159&#039;)&lt;br /&gt;
    if headquarters then&lt;br /&gt;
        infobox:addRow(&#039;Headquarters&#039;, formatValue(headquarters))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add founding date (P571)&lt;br /&gt;
    local foundingDate = getPropertyValue(&#039;P571&#039;)&lt;br /&gt;
    if foundingDate then&lt;br /&gt;
        infobox:addRow(&#039;Founding Date&#039;, formatValue(foundingDate))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add dissolution date (P576)&lt;br /&gt;
    local dissolutionDate = getPropertyValue(&#039;P576&#039;)&lt;br /&gt;
    if dissolutionDate then&lt;br /&gt;
        infobox:addRow(&#039;Dissolution Date&#039;, formatValue(dissolutionDate))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add country (P17)&lt;br /&gt;
    local country = getPropertyValue(&#039;P17&#039;)&lt;br /&gt;
    if country then infobox:addRow(&#039;Country&#039;, formatValue(country)) end&lt;br /&gt;
&lt;br /&gt;
    -- Add parent organization (P749)&lt;br /&gt;
    local parentOrg = getPropertyValue(&#039;P749&#039;)&lt;br /&gt;
    if parentOrg then&lt;br /&gt;
        infobox:addRow(&#039;Parent Organization&#039;, formatValue(parentOrg))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add official website (P856) as full-width row at bottom&lt;br /&gt;
    local website = getPropertyValue(&#039;P856&#039;)&lt;br /&gt;
    if website then&lt;br /&gt;
        local websiteStr = formatValue(website)&lt;br /&gt;
        if websiteStr then&lt;br /&gt;
            -- Strip http:// or https:// from display text&lt;br /&gt;
            local displayUrl = websiteStr:gsub(&#039;^https?://&#039;, &#039;&#039;)&lt;br /&gt;
            infobox:addWikitext(&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%; text-align:center;&amp;quot;&amp;gt;[&#039; .. websiteStr ..&lt;br /&gt;
                    &#039; &#039; .. displayUrl .. &#039;]&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    addMap(infobox)&lt;br /&gt;
    addWikidataLink(infobox)&lt;br /&gt;
&lt;br /&gt;
    return tostring(infobox) ..&lt;br /&gt;
               &#039;\n[[Category:Clubs, Societies and Institutions]]&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/index.php?title=Module:DynamicCapiunto&amp;diff=2033</id>
		<title>Module:DynamicCapiunto</title>
		<link rel="alternate" type="text/html" href="https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/index.php?title=Module:DynamicCapiunto&amp;diff=2033"/>
		<updated>2026-06-28T10:44:35Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Deployed from Ansible&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local capiunto = require &#039;capiunto&#039;&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
    local args = frame:getParent().args&lt;br /&gt;
    local qid = args.qid or args[1]&lt;br /&gt;
&lt;br /&gt;
    if not qid then&lt;br /&gt;
        return &#039;&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;Error: No Wikidata QID provided&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Register the entity association&lt;br /&gt;
    frame:callParserFunction(&#039;#unlinkedwikibase&#039;, &#039;id=&#039; .. qid)&lt;br /&gt;
&lt;br /&gt;
    -- Get entity data from UnlinkedWikibase&lt;br /&gt;
    local entity = mw.ext.UnlinkedWikibase.getEntity(qid)&lt;br /&gt;
&lt;br /&gt;
    if not entity then&lt;br /&gt;
        return &#039;&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;Error: Entity &#039; .. qid ..&lt;br /&gt;
                   &#039; not found&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper function to get property value from entity&lt;br /&gt;
    local function getPropertyValue(pid)&lt;br /&gt;
        if not entity.claims or not entity.claims[pid] then return nil end&lt;br /&gt;
&lt;br /&gt;
        local claims = entity.claims[pid]&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
&lt;br /&gt;
        local claim = claims[1]&lt;br /&gt;
        if not claim.mainsnak or not claim.mainsnak.datavalue then&lt;br /&gt;
            return nil&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        return claim.mainsnak.datavalue.value&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper function to format different value types&lt;br /&gt;
    local function formatValue(value, valueType)&lt;br /&gt;
        if not value then return nil end&lt;br /&gt;
&lt;br /&gt;
        if type(value) == &#039;table&#039; then&lt;br /&gt;
            -- Handle time values&lt;br /&gt;
            if value.time then&lt;br /&gt;
                -- Extract year-month-day from +2023-01-15T00:00:00Z format&lt;br /&gt;
                local dateStr = value.time&lt;br /&gt;
                local year, month, day =&lt;br /&gt;
                    dateStr:match(&#039;^[+-]?(%d+)-(%d+)-(%d+)&#039;)&lt;br /&gt;
                if year then&lt;br /&gt;
                    local y = tonumber(year)&lt;br /&gt;
                    local m = tonumber(month) or 0&lt;br /&gt;
                    local d = tonumber(day) or 0&lt;br /&gt;
                    -- If month or day are zero/unknown, show only the year&lt;br /&gt;
                    if m == 0 or d == 0 then&lt;br /&gt;
                        return string.format(&#039;%04d&#039;, y)&lt;br /&gt;
                    end&lt;br /&gt;
                    return string.format(&#039;%04d-%02d-%02d&#039;, y, m, d)&lt;br /&gt;
                end&lt;br /&gt;
                return value.time&lt;br /&gt;
                -- Handle entity references (Q-IDs)&lt;br /&gt;
            elseif value.id then&lt;br /&gt;
                -- Register a parser cache dependency so the page is invalidated&lt;br /&gt;
                -- when UnlinkedWikibase populates or updates this entity&#039;s data.&lt;br /&gt;
                mw.ext.UnlinkedWikibase.getLocalTitle(value.id)&lt;br /&gt;
                local linkedEntity = mw.ext.UnlinkedWikibase.getEntity(value.id)&lt;br /&gt;
                if linkedEntity then&lt;br /&gt;
                    local label = (linkedEntity.labels and&lt;br /&gt;
                                      linkedEntity.labels.en) and&lt;br /&gt;
                                      linkedEntity.labels.en.value or value.id&lt;br /&gt;
                    -- Then prefer an en.wikipedia sitelink (external link)&lt;br /&gt;
                    if linkedEntity.sitelinks and linkedEntity.sitelinks.enwiki and&lt;br /&gt;
                        linkedEntity.sitelinks.enwiki.url then&lt;br /&gt;
                        return&lt;br /&gt;
                            &#039;[&#039; .. linkedEntity.sitelinks.enwiki.url .. &#039; &#039; ..&lt;br /&gt;
                                label .. &#039;]&#039;&lt;br /&gt;
                    end&lt;br /&gt;
                    -- Fallback to the English label if available&lt;br /&gt;
                    if linkedEntity.labels and linkedEntity.labels.en then&lt;br /&gt;
                        return label&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
                return value.id&lt;br /&gt;
                -- Handle monolingual text&lt;br /&gt;
            elseif value.text then&lt;br /&gt;
                return value.text&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        return tostring(value)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get claim entity id (if the claim is an entity)&lt;br /&gt;
    local function getClaimEntityId(pid)&lt;br /&gt;
        local v = getPropertyValue(pid)&lt;br /&gt;
        if type(v) == &#039;table&#039; and v.id then return v.id end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get the first claim object for a property&lt;br /&gt;
    local function getFirstClaimObject(pid)&lt;br /&gt;
        if not entity.claims or not entity.claims[pid] then return nil end&lt;br /&gt;
        local claims = entity.claims[pid]&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
        return claims[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get a qualifier value (prefer English monolingual text for P2096)&lt;br /&gt;
    local function getQualifierValue(claim, qualPid)&lt;br /&gt;
        if not claim or not claim.qualifiers or not claim.qualifiers[qualPid] then&lt;br /&gt;
            return nil&lt;br /&gt;
        end&lt;br /&gt;
        local qsnaks = claim.qualifiers[qualPid]&lt;br /&gt;
        if not qsnaks or #qsnaks == 0 then return nil end&lt;br /&gt;
        for i, q in ipairs(qsnaks) do&lt;br /&gt;
            -- Check for valid snak with datavalue&lt;br /&gt;
            if q and q.snaktype == &#039;value&#039; and q.datavalue and q.datavalue.value then&lt;br /&gt;
                local v = q.datavalue.value&lt;br /&gt;
                if type(v) == &#039;table&#039; then&lt;br /&gt;
                    -- For monolingual text, prefer English&lt;br /&gt;
                    if v.language and v.language == &#039;en&#039; and v.text then&lt;br /&gt;
                        return v.text&lt;br /&gt;
                    end&lt;br /&gt;
                else&lt;br /&gt;
                    return tostring(v)&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Extract a {latitude, longitude} coordinate (P625) from an entity object.&lt;br /&gt;
    local function getCoordFromEntity(ent)&lt;br /&gt;
        if not ent or not ent.claims or not ent.claims.P625 then return nil end&lt;br /&gt;
        local claims = ent.claims.P625&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
        local snak = claims[1].mainsnak&lt;br /&gt;
        if not snak or not snak.datavalue then return nil end&lt;br /&gt;
        local v = snak.datavalue.value&lt;br /&gt;
        if type(v) == &#039;table&#039; and v.latitude and v.longitude then return v end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add a Leaflet/OpenStreetMap map for this entity.&lt;br /&gt;
    -- Prefer the entity&#039;s own coordinate location (P625). If it has none, fall&lt;br /&gt;
    -- back to the coordinates of the entity referenced as its headquarters&lt;br /&gt;
    -- location (P159), fetched via UnlinkedWikibase.&lt;br /&gt;
    -- Rendered via the Maps extension&#039;s #display_map parser function. A module&#039;s&lt;br /&gt;
    -- return value goes through the main parse pass but NOT the preprocessor, so&lt;br /&gt;
    -- parser-function syntax would otherwise be emitted literally. We expand it&lt;br /&gt;
    -- here with frame:preprocess() and add the resulting HTML to the infobox.&lt;br /&gt;
    local function addMap(box)&lt;br /&gt;
        local coord = getCoordFromEntity(entity)&lt;br /&gt;
        if not coord then&lt;br /&gt;
            local hqId = getClaimEntityId(&#039;P159&#039;)&lt;br /&gt;
            if hqId then&lt;br /&gt;
                -- Register a parser cache dependency on the HQ entity so the&lt;br /&gt;
                -- page is invalidated when its data is populated/updated.&lt;br /&gt;
                mw.ext.UnlinkedWikibase.getLocalTitle(hqId)&lt;br /&gt;
                coord = getCoordFromEntity(&lt;br /&gt;
                            mw.ext.UnlinkedWikibase.getEntity(hqId))&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        if not coord then return end&lt;br /&gt;
        local mapHtml = frame:preprocess(string.format(&lt;br /&gt;
                            &#039;{{#display_map:%s,%s|width=100%%|height=200|zoom=13|service=leaflet}}&#039;,&lt;br /&gt;
                            tostring(coord.latitude), tostring(coord.longitude)))&lt;br /&gt;
        box:addWikitext(mapHtml)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Decide which infobox to render based on instance (P31)&lt;br /&gt;
    local instanceId = getClaimEntityId(&#039;P31&#039;)&lt;br /&gt;
    local infobox&lt;br /&gt;
&lt;br /&gt;
    if instanceId == &#039;Q5&#039; then&lt;br /&gt;
        -- Person infobox&lt;br /&gt;
        local personTitle = qid&lt;br /&gt;
        if entity.labels and entity.labels.en then&lt;br /&gt;
            personTitle = entity.labels.en.value&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        infobox = capiunto.create({&lt;br /&gt;
            title = personTitle,&lt;br /&gt;
            bodyClass = &#039;infobox vevent&#039;,&lt;br /&gt;
            bodyStyle = &#039;width: 300px;&#039;&lt;br /&gt;
        })&lt;br /&gt;
&lt;br /&gt;
        -- Add image (P18) with media legend (P2096) as caption&lt;br /&gt;
        local imageClaim = getFirstClaimObject(&#039;P18&#039;)&lt;br /&gt;
        if imageClaim then&lt;br /&gt;
            local imageVal = imageClaim.mainsnak and&lt;br /&gt;
                                 imageClaim.mainsnak.datavalue and&lt;br /&gt;
                                 imageClaim.mainsnak.datavalue.value&lt;br /&gt;
            if imageVal then&lt;br /&gt;
                local imageStr = tostring(imageVal)&lt;br /&gt;
                local caption = getQualifierValue(imageClaim, &#039;P2096&#039;)&lt;br /&gt;
                if caption and caption ~= &#039;&#039; then&lt;br /&gt;
                    infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;,&lt;br /&gt;
                                     caption)&lt;br /&gt;
                else&lt;br /&gt;
                    infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;)&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Birthplace (P19)&lt;br /&gt;
        local birthplace = getPropertyValue(&#039;P19&#039;)&lt;br /&gt;
        if birthplace then&lt;br /&gt;
            infobox:addRow(&#039;Birthplace&#039;, formatValue(birthplace))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Birthday (P569)&lt;br /&gt;
        local birthday = getPropertyValue(&#039;P569&#039;)&lt;br /&gt;
        if birthday then&lt;br /&gt;
            infobox:addRow(&#039;Birthday&#039;, formatValue(birthday))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Death (P570)&lt;br /&gt;
        local death = getPropertyValue(&#039;P570&#039;)&lt;br /&gt;
        if death then infobox:addRow(&#039;Death&#039;, formatValue(death)) end&lt;br /&gt;
&lt;br /&gt;
        -- Occupation (P106)&lt;br /&gt;
        local occupation = getPropertyValue(&#039;P106&#039;)&lt;br /&gt;
        if occupation then&lt;br /&gt;
            infobox:addRow(&#039;Occupation&#039;, formatValue(occupation))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        addMap(infobox)&lt;br /&gt;
&lt;br /&gt;
        return tostring(infobox) .. &#039;\n[[Category:People]]&#039;&lt;br /&gt;
    else&lt;br /&gt;
        -- Default: organisation/troupe infobox (existing behavior)&lt;br /&gt;
        local title = qid&lt;br /&gt;
        if entity.labels and entity.labels.en then&lt;br /&gt;
            title = entity.labels.en.value&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        infobox = capiunto.create({&lt;br /&gt;
            title = title,&lt;br /&gt;
            bodyClass = &#039;infobox vevent&#039;,&lt;br /&gt;
            bodyStyle = &#039;width: 300px;&#039;&lt;br /&gt;
        })&lt;br /&gt;
&lt;br /&gt;
        -- Add official name (P1448)&lt;br /&gt;
        local officialName = getPropertyValue(&#039;P1448&#039;)&lt;br /&gt;
        if officialName then&lt;br /&gt;
            infobox:addRow(&#039;Official Name&#039;, formatValue(officialName))&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add logo (P154)&lt;br /&gt;
    local logo = getPropertyValue(&#039;P154&#039;)&lt;br /&gt;
    if logo then&lt;br /&gt;
        local logoStr = formatValue(logo)&lt;br /&gt;
        if logoStr then&lt;br /&gt;
            infobox:addImage(&#039;[[File:&#039; .. logoStr .. &#039;|150px]]&#039;, &#039;Logo&#039;)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add image (P18) with media legend (P2096) as caption&lt;br /&gt;
    local imageClaim = getFirstClaimObject(&#039;P18&#039;)&lt;br /&gt;
    if imageClaim then&lt;br /&gt;
        local imageVal =&lt;br /&gt;
            imageClaim.mainsnak and imageClaim.mainsnak.datavalue and&lt;br /&gt;
                imageClaim.mainsnak.datavalue.value&lt;br /&gt;
        if imageVal then&lt;br /&gt;
            local imageStr = tostring(imageVal)&lt;br /&gt;
            local caption = getQualifierValue(imageClaim, &#039;P2096&#039;)&lt;br /&gt;
            if caption and caption ~= &#039;&#039; then&lt;br /&gt;
                infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;, caption)&lt;br /&gt;
            else&lt;br /&gt;
                infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;)&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add headquarters (P159)&lt;br /&gt;
    local headquarters = getPropertyValue(&#039;P159&#039;)&lt;br /&gt;
    if headquarters then&lt;br /&gt;
        infobox:addRow(&#039;Headquarters&#039;, formatValue(headquarters))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add founding date (P571)&lt;br /&gt;
    local foundingDate = getPropertyValue(&#039;P571&#039;)&lt;br /&gt;
    if foundingDate then&lt;br /&gt;
        infobox:addRow(&#039;Founding Date&#039;, formatValue(foundingDate))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add dissolution date (P576)&lt;br /&gt;
    local dissolutionDate = getPropertyValue(&#039;P576&#039;)&lt;br /&gt;
    if dissolutionDate then&lt;br /&gt;
        infobox:addRow(&#039;Dissolution Date&#039;, formatValue(dissolutionDate))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add country (P17)&lt;br /&gt;
    local country = getPropertyValue(&#039;P17&#039;)&lt;br /&gt;
    if country then infobox:addRow(&#039;Country&#039;, formatValue(country)) end&lt;br /&gt;
&lt;br /&gt;
    -- Add parent organization (P749)&lt;br /&gt;
    local parentOrg = getPropertyValue(&#039;P749&#039;)&lt;br /&gt;
    if parentOrg then&lt;br /&gt;
        infobox:addRow(&#039;Parent Organization&#039;, formatValue(parentOrg))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add official website (P856) as full-width row at bottom&lt;br /&gt;
    local website = getPropertyValue(&#039;P856&#039;)&lt;br /&gt;
    if website then&lt;br /&gt;
        local websiteStr = formatValue(website)&lt;br /&gt;
        if websiteStr then&lt;br /&gt;
            -- Strip http:// or https:// from display text&lt;br /&gt;
            local displayUrl = websiteStr:gsub(&#039;^https?://&#039;, &#039;&#039;)&lt;br /&gt;
            infobox:addWikitext(&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%; text-align:center;&amp;quot;&amp;gt;[&#039; .. websiteStr ..&lt;br /&gt;
                    &#039; &#039; .. displayUrl .. &#039;]&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    addMap(infobox)&lt;br /&gt;
&lt;br /&gt;
    return tostring(infobox) ..&lt;br /&gt;
               &#039;\n[[Category:Clubs, Societies and Institutions]]&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
	<entry>
		<id>https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/index.php?title=Module:DynamicCapiunto&amp;diff=2032</id>
		<title>Module:DynamicCapiunto</title>
		<link rel="alternate" type="text/html" href="https://www.amateur-theatre-wiki.gwi.uni-muenchen.de/index.php?title=Module:DynamicCapiunto&amp;diff=2032"/>
		<updated>2026-06-28T10:37:06Z</updated>

		<summary type="html">&lt;p&gt;Maintenance script: Deployed from Ansible&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;local capiunto = require &#039;capiunto&#039;&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
    local args = frame:getParent().args&lt;br /&gt;
    local qid = args.qid or args[1]&lt;br /&gt;
&lt;br /&gt;
    if not qid then&lt;br /&gt;
        return &#039;&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;Error: No Wikidata QID provided&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Register the entity association&lt;br /&gt;
    frame:callParserFunction(&#039;#unlinkedwikibase&#039;, &#039;id=&#039; .. qid)&lt;br /&gt;
&lt;br /&gt;
    -- Get entity data from UnlinkedWikibase&lt;br /&gt;
    local entity = mw.ext.UnlinkedWikibase.getEntity(qid)&lt;br /&gt;
&lt;br /&gt;
    if not entity then&lt;br /&gt;
        return &#039;&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;Error: Entity &#039; .. qid ..&lt;br /&gt;
                   &#039; not found&amp;lt;/span&amp;gt;&#039;&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper function to get property value from entity&lt;br /&gt;
    local function getPropertyValue(pid)&lt;br /&gt;
        if not entity.claims or not entity.claims[pid] then return nil end&lt;br /&gt;
&lt;br /&gt;
        local claims = entity.claims[pid]&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
&lt;br /&gt;
        local claim = claims[1]&lt;br /&gt;
        if not claim.mainsnak or not claim.mainsnak.datavalue then&lt;br /&gt;
            return nil&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        return claim.mainsnak.datavalue.value&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper function to format different value types&lt;br /&gt;
    local function formatValue(value, valueType)&lt;br /&gt;
        if not value then return nil end&lt;br /&gt;
&lt;br /&gt;
        if type(value) == &#039;table&#039; then&lt;br /&gt;
            -- Handle time values&lt;br /&gt;
            if value.time then&lt;br /&gt;
                -- Extract year-month-day from +2023-01-15T00:00:00Z format&lt;br /&gt;
                local dateStr = value.time&lt;br /&gt;
                local year, month, day =&lt;br /&gt;
                    dateStr:match(&#039;^[+-]?(%d+)-(%d+)-(%d+)&#039;)&lt;br /&gt;
                if year then&lt;br /&gt;
                    local y = tonumber(year)&lt;br /&gt;
                    local m = tonumber(month) or 0&lt;br /&gt;
                    local d = tonumber(day) or 0&lt;br /&gt;
                    -- If month or day are zero/unknown, show only the year&lt;br /&gt;
                    if m == 0 or d == 0 then&lt;br /&gt;
                        return string.format(&#039;%04d&#039;, y)&lt;br /&gt;
                    end&lt;br /&gt;
                    return string.format(&#039;%04d-%02d-%02d&#039;, y, m, d)&lt;br /&gt;
                end&lt;br /&gt;
                return value.time&lt;br /&gt;
                -- Handle entity references (Q-IDs)&lt;br /&gt;
            elseif value.id then&lt;br /&gt;
                -- Register a parser cache dependency so the page is invalidated&lt;br /&gt;
                -- when UnlinkedWikibase populates or updates this entity&#039;s data.&lt;br /&gt;
                mw.ext.UnlinkedWikibase.getLocalTitle(value.id)&lt;br /&gt;
                local linkedEntity = mw.ext.UnlinkedWikibase.getEntity(value.id)&lt;br /&gt;
                if linkedEntity then&lt;br /&gt;
                    local label = (linkedEntity.labels and&lt;br /&gt;
                                      linkedEntity.labels.en) and&lt;br /&gt;
                                      linkedEntity.labels.en.value or value.id&lt;br /&gt;
                    -- Then prefer an en.wikipedia sitelink (external link)&lt;br /&gt;
                    if linkedEntity.sitelinks and linkedEntity.sitelinks.enwiki and&lt;br /&gt;
                        linkedEntity.sitelinks.enwiki.url then&lt;br /&gt;
                        return&lt;br /&gt;
                            &#039;[&#039; .. linkedEntity.sitelinks.enwiki.url .. &#039; &#039; ..&lt;br /&gt;
                                label .. &#039;]&#039;&lt;br /&gt;
                    end&lt;br /&gt;
                    -- Fallback to the English label if available&lt;br /&gt;
                    if linkedEntity.labels and linkedEntity.labels.en then&lt;br /&gt;
                        return label&lt;br /&gt;
                    end&lt;br /&gt;
                end&lt;br /&gt;
                return value.id&lt;br /&gt;
                -- Handle monolingual text&lt;br /&gt;
            elseif value.text then&lt;br /&gt;
                return value.text&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        return tostring(value)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get claim entity id (if the claim is an entity)&lt;br /&gt;
    local function getClaimEntityId(pid)&lt;br /&gt;
        local v = getPropertyValue(pid)&lt;br /&gt;
        if type(v) == &#039;table&#039; and v.id then return v.id end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get the first claim object for a property&lt;br /&gt;
    local function getFirstClaimObject(pid)&lt;br /&gt;
        if not entity.claims or not entity.claims[pid] then return nil end&lt;br /&gt;
        local claims = entity.claims[pid]&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
        return claims[1]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Helper to get a qualifier value (prefer English monolingual text for P2096)&lt;br /&gt;
    local function getQualifierValue(claim, qualPid)&lt;br /&gt;
        if not claim or not claim.qualifiers or not claim.qualifiers[qualPid] then&lt;br /&gt;
            return nil&lt;br /&gt;
        end&lt;br /&gt;
        local qsnaks = claim.qualifiers[qualPid]&lt;br /&gt;
        if not qsnaks or #qsnaks == 0 then return nil end&lt;br /&gt;
        for i, q in ipairs(qsnaks) do&lt;br /&gt;
            -- Check for valid snak with datavalue&lt;br /&gt;
            if q and q.snaktype == &#039;value&#039; and q.datavalue and q.datavalue.value then&lt;br /&gt;
                local v = q.datavalue.value&lt;br /&gt;
                if type(v) == &#039;table&#039; then&lt;br /&gt;
                    -- For monolingual text, prefer English&lt;br /&gt;
                    if v.language and v.language == &#039;en&#039; and v.text then&lt;br /&gt;
                        return v.text&lt;br /&gt;
                    end&lt;br /&gt;
                else&lt;br /&gt;
                    return tostring(v)&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Extract a {latitude, longitude} coordinate (P625) from an entity object.&lt;br /&gt;
    local function getCoordFromEntity(ent)&lt;br /&gt;
        if not ent or not ent.claims or not ent.claims.P625 then return nil end&lt;br /&gt;
        local claims = ent.claims.P625&lt;br /&gt;
        if not claims or #claims == 0 then return nil end&lt;br /&gt;
        local snak = claims[1].mainsnak&lt;br /&gt;
        if not snak or not snak.datavalue then return nil end&lt;br /&gt;
        local v = snak.datavalue.value&lt;br /&gt;
        if type(v) == &#039;table&#039; and v.latitude and v.longitude then return v end&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add a Leaflet/OpenStreetMap map for this entity.&lt;br /&gt;
    -- Prefer the entity&#039;s own coordinate location (P625). If it has none, fall&lt;br /&gt;
    -- back to the coordinates of the entity referenced as its headquarters&lt;br /&gt;
    -- location (P159), fetched via UnlinkedWikibase.&lt;br /&gt;
    -- Rendered via the Maps extension&#039;s #display_map parser function, which the&lt;br /&gt;
    -- wiki resolves when it parses this module&#039;s returned wikitext.&lt;br /&gt;
    local function addMap(box)&lt;br /&gt;
        local coord = getCoordFromEntity(entity)&lt;br /&gt;
        if not coord then&lt;br /&gt;
            local hqId = getClaimEntityId(&#039;P159&#039;)&lt;br /&gt;
            if hqId then&lt;br /&gt;
                -- Register a parser cache dependency on the HQ entity so the&lt;br /&gt;
                -- page is invalidated when its data is populated/updated.&lt;br /&gt;
                mw.ext.UnlinkedWikibase.getLocalTitle(hqId)&lt;br /&gt;
                coord = getCoordFromEntity(&lt;br /&gt;
                            mw.ext.UnlinkedWikibase.getEntity(hqId))&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
        if not coord then return end&lt;br /&gt;
        box:addWikitext(string.format(&lt;br /&gt;
                            &#039;{{#display_map:%s,%s|width=100%%|height=200|zoom=13|service=leaflet}}&#039;,&lt;br /&gt;
                            tostring(coord.latitude), tostring(coord.longitude)))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Decide which infobox to render based on instance (P31)&lt;br /&gt;
    local instanceId = getClaimEntityId(&#039;P31&#039;)&lt;br /&gt;
    local infobox&lt;br /&gt;
&lt;br /&gt;
    if instanceId == &#039;Q5&#039; then&lt;br /&gt;
        -- Person infobox&lt;br /&gt;
        local personTitle = qid&lt;br /&gt;
        if entity.labels and entity.labels.en then&lt;br /&gt;
            personTitle = entity.labels.en.value&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        infobox = capiunto.create({&lt;br /&gt;
            title = personTitle,&lt;br /&gt;
            bodyClass = &#039;infobox vevent&#039;,&lt;br /&gt;
            bodyStyle = &#039;width: 300px;&#039;&lt;br /&gt;
        })&lt;br /&gt;
&lt;br /&gt;
        -- Add image (P18) with media legend (P2096) as caption&lt;br /&gt;
        local imageClaim = getFirstClaimObject(&#039;P18&#039;)&lt;br /&gt;
        if imageClaim then&lt;br /&gt;
            local imageVal = imageClaim.mainsnak and&lt;br /&gt;
                                 imageClaim.mainsnak.datavalue and&lt;br /&gt;
                                 imageClaim.mainsnak.datavalue.value&lt;br /&gt;
            if imageVal then&lt;br /&gt;
                local imageStr = tostring(imageVal)&lt;br /&gt;
                local caption = getQualifierValue(imageClaim, &#039;P2096&#039;)&lt;br /&gt;
                if caption and caption ~= &#039;&#039; then&lt;br /&gt;
                    infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;,&lt;br /&gt;
                                     caption)&lt;br /&gt;
                else&lt;br /&gt;
                    infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;)&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Birthplace (P19)&lt;br /&gt;
        local birthplace = getPropertyValue(&#039;P19&#039;)&lt;br /&gt;
        if birthplace then&lt;br /&gt;
            infobox:addRow(&#039;Birthplace&#039;, formatValue(birthplace))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Birthday (P569)&lt;br /&gt;
        local birthday = getPropertyValue(&#039;P569&#039;)&lt;br /&gt;
        if birthday then&lt;br /&gt;
            infobox:addRow(&#039;Birthday&#039;, formatValue(birthday))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        -- Death (P570)&lt;br /&gt;
        local death = getPropertyValue(&#039;P570&#039;)&lt;br /&gt;
        if death then infobox:addRow(&#039;Death&#039;, formatValue(death)) end&lt;br /&gt;
&lt;br /&gt;
        -- Occupation (P106)&lt;br /&gt;
        local occupation = getPropertyValue(&#039;P106&#039;)&lt;br /&gt;
        if occupation then&lt;br /&gt;
            infobox:addRow(&#039;Occupation&#039;, formatValue(occupation))&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        addMap(infobox)&lt;br /&gt;
&lt;br /&gt;
        return tostring(infobox) .. &#039;\n[[Category:People]]&#039;&lt;br /&gt;
    else&lt;br /&gt;
        -- Default: organisation/troupe infobox (existing behavior)&lt;br /&gt;
        local title = qid&lt;br /&gt;
        if entity.labels and entity.labels.en then&lt;br /&gt;
            title = entity.labels.en.value&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        infobox = capiunto.create({&lt;br /&gt;
            title = title,&lt;br /&gt;
            bodyClass = &#039;infobox vevent&#039;,&lt;br /&gt;
            bodyStyle = &#039;width: 300px;&#039;&lt;br /&gt;
        })&lt;br /&gt;
&lt;br /&gt;
        -- Add official name (P1448)&lt;br /&gt;
        local officialName = getPropertyValue(&#039;P1448&#039;)&lt;br /&gt;
        if officialName then&lt;br /&gt;
            infobox:addRow(&#039;Official Name&#039;, formatValue(officialName))&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add logo (P154)&lt;br /&gt;
    local logo = getPropertyValue(&#039;P154&#039;)&lt;br /&gt;
    if logo then&lt;br /&gt;
        local logoStr = formatValue(logo)&lt;br /&gt;
        if logoStr then&lt;br /&gt;
            infobox:addImage(&#039;[[File:&#039; .. logoStr .. &#039;|150px]]&#039;, &#039;Logo&#039;)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add image (P18) with media legend (P2096) as caption&lt;br /&gt;
    local imageClaim = getFirstClaimObject(&#039;P18&#039;)&lt;br /&gt;
    if imageClaim then&lt;br /&gt;
        local imageVal =&lt;br /&gt;
            imageClaim.mainsnak and imageClaim.mainsnak.datavalue and&lt;br /&gt;
                imageClaim.mainsnak.datavalue.value&lt;br /&gt;
        if imageVal then&lt;br /&gt;
            local imageStr = tostring(imageVal)&lt;br /&gt;
            local caption = getQualifierValue(imageClaim, &#039;P2096&#039;)&lt;br /&gt;
            if caption and caption ~= &#039;&#039; then&lt;br /&gt;
                infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;, caption)&lt;br /&gt;
            else&lt;br /&gt;
                infobox:addImage(&#039;[[File:&#039; .. imageStr .. &#039;|300px]]&#039;)&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add headquarters (P159)&lt;br /&gt;
    local headquarters = getPropertyValue(&#039;P159&#039;)&lt;br /&gt;
    if headquarters then&lt;br /&gt;
        infobox:addRow(&#039;Headquarters&#039;, formatValue(headquarters))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add founding date (P571)&lt;br /&gt;
    local foundingDate = getPropertyValue(&#039;P571&#039;)&lt;br /&gt;
    if foundingDate then&lt;br /&gt;
        infobox:addRow(&#039;Founding Date&#039;, formatValue(foundingDate))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add dissolution date (P576)&lt;br /&gt;
    local dissolutionDate = getPropertyValue(&#039;P576&#039;)&lt;br /&gt;
    if dissolutionDate then&lt;br /&gt;
        infobox:addRow(&#039;Dissolution Date&#039;, formatValue(dissolutionDate))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add country (P17)&lt;br /&gt;
    local country = getPropertyValue(&#039;P17&#039;)&lt;br /&gt;
    if country then infobox:addRow(&#039;Country&#039;, formatValue(country)) end&lt;br /&gt;
&lt;br /&gt;
    -- Add parent organization (P749)&lt;br /&gt;
    local parentOrg = getPropertyValue(&#039;P749&#039;)&lt;br /&gt;
    if parentOrg then&lt;br /&gt;
        infobox:addRow(&#039;Parent Organization&#039;, formatValue(parentOrg))&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Add official website (P856) as full-width row at bottom&lt;br /&gt;
    local website = getPropertyValue(&#039;P856&#039;)&lt;br /&gt;
    if website then&lt;br /&gt;
        local websiteStr = formatValue(website)&lt;br /&gt;
        if websiteStr then&lt;br /&gt;
            -- Strip http:// or https:// from display text&lt;br /&gt;
            local displayUrl = websiteStr:gsub(&#039;^https?://&#039;, &#039;&#039;)&lt;br /&gt;
            infobox:addWikitext(&lt;br /&gt;
                &#039;&amp;lt;div style=&amp;quot;width:100%; text-align:center;&amp;quot;&amp;gt;[&#039; .. websiteStr ..&lt;br /&gt;
                    &#039; &#039; .. displayUrl .. &#039;]&amp;lt;/div&amp;gt;&#039;)&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    addMap(infobox)&lt;br /&gt;
&lt;br /&gt;
    return tostring(infobox) ..&lt;br /&gt;
               &#039;\n[[Category:Clubs, Societies and Institutions]]&#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Maintenance script</name></author>
	</entry>
</feed>