Deadfire_

Messageboxes Export

Feb 15th, 2022
456
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
XML 373.75 KB | None | 0 0
  1. <mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en">
  2.   <siteinfo>
  3.     <sitename>Wikipedia</sitename>
  4.     <dbname>enwiki</dbname>
  5.     <base>https://en.wikipedia.org/wiki/Main_Page</base>
  6.     <generator>MediaWiki 1.38.0-wmf.21</generator>
  7.     <case>first-letter</case>
  8.     <namespaces>
  9.       <namespace key="-2" case="first-letter">Media</namespace>
  10.       <namespace key="-1" case="first-letter">Special</namespace>
  11.       <namespace key="0" case="first-letter" />
  12.       <namespace key="1" case="first-letter">Talk</namespace>
  13.       <namespace key="2" case="first-letter">User</namespace>
  14.       <namespace key="3" case="first-letter">User talk</namespace>
  15.       <namespace key="4" case="first-letter">Wikipedia</namespace>
  16.       <namespace key="5" case="first-letter">Wikipedia talk</namespace>
  17.       <namespace key="6" case="first-letter">File</namespace>
  18.       <namespace key="7" case="first-letter">File talk</namespace>
  19.       <namespace key="8" case="first-letter">MediaWiki</namespace>
  20.       <namespace key="9" case="first-letter">MediaWiki talk</namespace>
  21.       <namespace key="10" case="first-letter">Template</namespace>
  22.       <namespace key="11" case="first-letter">Template talk</namespace>
  23.       <namespace key="12" case="first-letter">Help</namespace>
  24.       <namespace key="13" case="first-letter">Help talk</namespace>
  25.       <namespace key="14" case="first-letter">Category</namespace>
  26.       <namespace key="15" case="first-letter">Category talk</namespace>
  27.       <namespace key="100" case="first-letter">Portal</namespace>
  28.       <namespace key="101" case="first-letter">Portal talk</namespace>
  29.       <namespace key="118" case="first-letter">Draft</namespace>
  30.       <namespace key="119" case="first-letter">Draft talk</namespace>
  31.       <namespace key="710" case="first-letter">TimedText</namespace>
  32.       <namespace key="711" case="first-letter">TimedText talk</namespace>
  33.       <namespace key="828" case="first-letter">Module</namespace>
  34.       <namespace key="829" case="first-letter">Module talk</namespace>
  35.       <namespace key="2300" case="first-letter">Gadget</namespace>
  36.       <namespace key="2301" case="first-letter">Gadget talk</namespace>
  37.       <namespace key="2302" case="case-sensitive">Gadget definition</namespace>
  38.       <namespace key="2303" case="case-sensitive">Gadget definition talk</namespace>
  39.     </namespaces>
  40.   </siteinfo>
  41.   <page>
  42.     <title>Module:Message box</title>
  43.     <ns>828</ns>
  44.     <id>40574910</id>
  45.     <revision>
  46.       <id>1027212344</id>
  47.       <parentid>970994177</parentid>
  48.       <timestamp>2021-06-06T18:51:34Z</timestamp>
  49.       <contributor>
  50.         <username>Izno</username>
  51.         <id>2927383</id>
  52.       </contributor>
  53.       <comment>per tper</comment>
  54.       <model>Scribunto</model>
  55.       <format>text/plain</format>
  56.       <text bytes="18348" xml:space="preserve">-- This is a meta-module for producing message box templates, including
  57. -- {{mbox}}, {{ambox}}, {{imbox}}, {{tmbox}}, {{ombox}}, {{cmbox}} and {{fmbox}}.
  58.  
  59. -- Load necessary modules.
  60. require('Module:No globals')
  61. local getArgs
  62. local yesno = require('Module:Yesno')
  63.  
  64. -- Get a language object for formatDate and ucfirst.
  65. local lang = mw.language.getContentLanguage()
  66.  
  67. -- Define constants
  68. local CONFIG_MODULE = 'Module:Message box/configuration'
  69. local DEMOSPACES = {talk = 'tmbox', image = 'imbox', file = 'imbox', category = 'cmbox', article = 'ambox', main = 'ambox'}
  70.  
  71. --------------------------------------------------------------------------------
  72. -- Helper functions
  73. --------------------------------------------------------------------------------
  74.  
  75. local function getTitleObject(...)
  76.     -- Get the title object, passing the function through pcall
  77.     -- in case we are over the expensive function count limit.
  78.     local success, title = pcall(mw.title.new, ...)
  79.     if success then
  80.         return title
  81.     end
  82. end
  83.  
  84. local function union(t1, t2)
  85.     -- Returns the union of two arrays.
  86.     local vals = {}
  87.     for i, v in ipairs(t1) do
  88.         vals[v] = true
  89.     end
  90.     for i, v in ipairs(t2) do
  91.         vals[v] = true
  92.     end
  93.     local ret = {}
  94.     for k in pairs(vals) do
  95.         table.insert(ret, k)
  96.     end
  97.     table.sort(ret)
  98.     return ret
  99. end
  100.  
  101. local function getArgNums(args, prefix)
  102.     local nums = {}
  103.     for k, v in pairs(args) do
  104.         local num = mw.ustring.match(tostring(k), '^' .. prefix .. '([1-9]%d*)$')
  105.         if num then
  106.             table.insert(nums, tonumber(num))
  107.         end
  108.     end
  109.     table.sort(nums)
  110.     return nums
  111. end
  112.  
  113. --------------------------------------------------------------------------------
  114. -- Box class definition
  115. --------------------------------------------------------------------------------
  116.  
  117. local MessageBox = {}
  118. MessageBox.__index = MessageBox
  119.  
  120. function MessageBox.new(boxType, args, cfg)
  121.     args = args or {}
  122.     local obj = {}
  123.  
  124.     -- Set the title object and the namespace.
  125.     obj.title = getTitleObject(args.page) or mw.title.getCurrentTitle()
  126.  
  127.     -- Set the config for our box type.
  128.     obj.cfg = cfg[boxType]
  129.     if not obj.cfg then
  130.         local ns = obj.title.namespace
  131.         -- boxType is "mbox" or invalid input
  132.         if args.demospace and args.demospace ~= '' then
  133.             -- implement demospace parameter of mbox
  134.             local demospace = string.lower(args.demospace)
  135.             if DEMOSPACES[demospace] then
  136.                 -- use template from DEMOSPACES
  137.                 obj.cfg = cfg[DEMOSPACES[demospace]]
  138.             elseif string.find( demospace, 'talk' ) then
  139.                 -- demo as a talk page
  140.                 obj.cfg = cfg.tmbox
  141.             else
  142.                 -- default to ombox
  143.                 obj.cfg = cfg.ombox
  144.             end
  145.         elseif ns == 0 then
  146.             obj.cfg = cfg.ambox -- main namespace
  147.         elseif ns == 6 then
  148.             obj.cfg = cfg.imbox -- file namespace
  149.         elseif ns == 14 then
  150.             obj.cfg = cfg.cmbox -- category namespace
  151.         else
  152.             local nsTable = mw.site.namespaces[ns]
  153.             if nsTable and nsTable.isTalk then
  154.                 obj.cfg = cfg.tmbox -- any talk namespace
  155.             else
  156.                 obj.cfg = cfg.ombox -- other namespaces or invalid input
  157.             end
  158.         end
  159.     end
  160.  
  161.     -- Set the arguments, and remove all blank arguments except for the ones
  162.     -- listed in cfg.allowBlankParams.
  163.     do
  164.         local newArgs = {}
  165.         for k, v in pairs(args) do
  166.             if v ~= '' then
  167.                 newArgs[k] = v
  168.             end
  169.         end
  170.         for i, param in ipairs(obj.cfg.allowBlankParams or {}) do
  171.             newArgs[param] = args[param]
  172.         end
  173.         obj.args = newArgs
  174.     end
  175.  
  176.     -- Define internal data structure.
  177.     obj.categories = {}
  178.     obj.classes = {}
  179.     -- For lazy loading of [[Module:Category handler]].
  180.     obj.hasCategories = false
  181.  
  182.     return setmetatable(obj, MessageBox)
  183. end
  184.  
  185. function MessageBox:addCat(ns, cat, sort)
  186.     if not cat then
  187.         return nil
  188.     end
  189.     if sort then
  190.         cat = string.format('[[Category:%s|%s]]', cat, sort)
  191.     else
  192.         cat = string.format('[[Category:%s]]', cat)
  193.     end
  194.     self.hasCategories = true
  195.     self.categories[ns] = self.categories[ns] or {}
  196.     table.insert(self.categories[ns], cat)
  197. end
  198.  
  199. function MessageBox:addClass(class)
  200.     if not class then
  201.         return nil
  202.     end
  203.     table.insert(self.classes, class)
  204. end
  205.  
  206. function MessageBox:setParameters()
  207.     local args = self.args
  208.     local cfg = self.cfg
  209.  
  210.     -- Get type data.
  211.     self.type = args.type
  212.     local typeData = cfg.types[self.type]
  213.     self.invalidTypeError = cfg.showInvalidTypeError
  214.         and self.type
  215.         and not typeData
  216.     typeData = typeData or cfg.types[cfg.default]
  217.     self.typeClass = typeData.class
  218.     self.typeImage = typeData.image
  219.  
  220.     -- Find if the box has been wrongly substituted.
  221.     self.isSubstituted = cfg.substCheck and args.subst == 'SUBST'
  222.  
  223.     -- Find whether we are using a small message box.
  224.     self.isSmall = cfg.allowSmall and (
  225.         cfg.smallParam and args.small == cfg.smallParam
  226.         or not cfg.smallParam and yesno(args.small)
  227.     )
  228.  
  229.     -- Add attributes, classes and styles.
  230.     self.id = args.id
  231.     self.name = args.name
  232.     if self.name then
  233.         self:addClass('box-' .. string.gsub(self.name,' ','_'))
  234.     end
  235.     if yesno(args.plainlinks) ~= false then
  236.         self:addClass('plainlinks')
  237.     end
  238.     for _, class in ipairs(cfg.classes or {}) do
  239.         self:addClass(class)
  240.     end
  241.     if self.isSmall then
  242.         self:addClass(cfg.smallClass or 'mbox-small')
  243.     end
  244.     self:addClass(self.typeClass)
  245.     self:addClass(args.class)
  246.     self.style = args.style
  247.     self.attrs = args.attrs
  248.  
  249.     -- Set text style.
  250.     self.textstyle = args.textstyle
  251.  
  252.     -- Find if we are on the template page or not. This functionality is only
  253.     -- used if useCollapsibleTextFields is set, or if both cfg.templateCategory
  254.     -- and cfg.templateCategoryRequireName are set.
  255.     self.useCollapsibleTextFields = cfg.useCollapsibleTextFields
  256.     if self.useCollapsibleTextFields
  257.         or cfg.templateCategory
  258.         and cfg.templateCategoryRequireName
  259.     then
  260.         if self.name then
  261.             local templateName = mw.ustring.match(
  262.                 self.name,
  263.                 '^[tT][eE][mM][pP][lL][aA][tT][eE][%s_]*:[%s_]*(.*)$'
  264.             ) or self.name
  265.             templateName = 'Template:' .. templateName
  266.             self.templateTitle = getTitleObject(templateName)
  267.         end
  268.         self.isTemplatePage = self.templateTitle
  269.             and mw.title.equals(self.title, self.templateTitle)
  270.     end
  271.    
  272.     -- Process data for collapsible text fields. At the moment these are only
  273.     -- used in {{ambox}}.
  274.     if self.useCollapsibleTextFields then
  275.         -- Get the self.issue value.
  276.         if self.isSmall and args.smalltext then
  277.             self.issue = args.smalltext
  278.         else
  279.             local sect
  280.             if args.sect == '' then
  281.                 sect = 'This ' .. (cfg.sectionDefault or 'page')
  282.             elseif type(args.sect) == 'string' then
  283.                 sect = 'This ' .. args.sect
  284.             end
  285.             local issue = args.issue
  286.             issue = type(issue) == 'string' and issue ~= '' and issue or nil
  287.             local text = args.text
  288.             text = type(text) == 'string' and text or nil
  289.             local issues = {}
  290.             table.insert(issues, sect)
  291.             table.insert(issues, issue)
  292.             table.insert(issues, text)
  293.             self.issue = table.concat(issues, ' ')
  294.         end
  295.  
  296.         -- Get the self.talk value.
  297.         local talk = args.talk
  298.         -- Show talk links on the template page or template subpages if the talk
  299.         -- parameter is blank.
  300.         if talk == ''
  301.             and self.templateTitle
  302.             and (
  303.                 mw.title.equals(self.templateTitle, self.title)
  304.                 or self.title:isSubpageOf(self.templateTitle)
  305.             )
  306.         then
  307.             talk = '#'
  308.         elseif talk == '' then
  309.             talk = nil
  310.         end
  311.         if talk then
  312.             -- If the talk value is a talk page, make a link to that page. Else
  313.             -- assume that it's a section heading, and make a link to the talk
  314.             -- page of the current page with that section heading.
  315.             local talkTitle = getTitleObject(talk)
  316.             local talkArgIsTalkPage = true
  317.             if not talkTitle or not talkTitle.isTalkPage then
  318.                 talkArgIsTalkPage = false
  319.                 talkTitle = getTitleObject(
  320.                     self.title.text,
  321.                     mw.site.namespaces[self.title.namespace].talk.id
  322.                 )
  323.             end
  324.             if talkTitle and talkTitle.exists then
  325.                 local talkText
  326.                 if self.isSmall then
  327.                     local talkLink = talkArgIsTalkPage and talk or (talkTitle.prefixedText .. '#' .. talk)
  328.                     talkText = string.format('([[%s|talk]])', talkLink)
  329.                 else
  330.                     talkText = 'Relevant discussion may be found on'
  331.                     if talkArgIsTalkPage then
  332.                         talkText = string.format(
  333.                             '%s [[%s|%s]].',
  334.                             talkText,
  335.                             talk,
  336.                             talkTitle.prefixedText
  337.                         )
  338.                     else
  339.                         talkText = string.format(
  340.                             '%s the [[%s#%s|talk page]].',
  341.                             talkText,
  342.                             talkTitle.prefixedText,
  343.                             talk
  344.                         )
  345.                     end
  346.                 end
  347.                 self.talk = talkText
  348.             end
  349.         end
  350.  
  351.         -- Get other values.
  352.         self.fix = args.fix ~= '' and args.fix or nil
  353.         local date
  354.         if args.date and args.date ~= '' then
  355.             date = args.date
  356.         elseif args.date == '' and self.isTemplatePage then
  357.             date = lang:formatDate('F Y')
  358.         end
  359.         if date then
  360.             self.date = string.format(" &lt;span class='date-container'&gt;''(&lt;span class='date'&gt;%s&lt;/span&gt;)''&lt;/span&gt;", date)
  361.         end
  362.         self.info = args.info
  363.         if yesno(args.removalnotice) then
  364.             self.removalNotice = cfg.removalNotice
  365.         end
  366.     end
  367.  
  368.     -- Set the non-collapsible text field. At the moment this is used by all box
  369.     -- types other than ambox, and also by ambox when small=yes.
  370.     if self.isSmall then
  371.         self.text = args.smalltext or args.text
  372.     else
  373.         self.text = args.text
  374.     end
  375.  
  376.     -- Set the below row.
  377.     self.below = cfg.below and args.below
  378.  
  379.     -- General image settings.
  380.     self.imageCellDiv = not self.isSmall and cfg.imageCellDiv
  381.     self.imageEmptyCell = cfg.imageEmptyCell
  382.     if cfg.imageEmptyCellStyle then
  383.         self.imageEmptyCellStyle = 'border:none;padding:0;width:1px'
  384.     end
  385.  
  386.     -- Left image settings.
  387.     local imageLeft = self.isSmall and args.smallimage or args.image
  388.     if cfg.imageCheckBlank and imageLeft ~= 'blank' and imageLeft ~= 'none'
  389.         or not cfg.imageCheckBlank and imageLeft ~= 'none'
  390.     then
  391.         self.imageLeft = imageLeft
  392.         if not imageLeft then
  393.             local imageSize = self.isSmall
  394.                 and (cfg.imageSmallSize or '30x30px')
  395.                 or '40x40px'
  396.             self.imageLeft = string.format('[[File:%s|%s|link=|alt=]]', self.typeImage
  397.                 or 'Imbox notice.png', imageSize)
  398.         end
  399.     end
  400.  
  401.     -- Right image settings.
  402.     local imageRight = self.isSmall and args.smallimageright or args.imageright
  403.     if not (cfg.imageRightNone and imageRight == 'none') then
  404.         self.imageRight = imageRight
  405.     end
  406. end
  407.  
  408. function MessageBox:setMainspaceCategories()
  409.     local args = self.args
  410.     local cfg = self.cfg
  411.  
  412.     if not cfg.allowMainspaceCategories then
  413.         return nil
  414.     end
  415.  
  416.     local nums = {}
  417.     for _, prefix in ipairs{'cat', 'category', 'all'} do
  418.         args[prefix .. '1'] = args[prefix]
  419.         nums = union(nums, getArgNums(args, prefix))
  420.     end
  421.  
  422.     -- The following is roughly equivalent to the old {{Ambox/category}}.
  423.     local date = args.date
  424.     date = type(date) == 'string' and date
  425.     local preposition = 'from'
  426.     for _, num in ipairs(nums) do
  427.         local mainCat = args['cat' .. tostring(num)]
  428.             or args['category' .. tostring(num)]
  429.         local allCat = args['all' .. tostring(num)]
  430.         mainCat = type(mainCat) == 'string' and mainCat
  431.         allCat = type(allCat) == 'string' and allCat
  432.         if mainCat and date and date ~= '' then
  433.             local catTitle = string.format('%s %s %s', mainCat, preposition, date)
  434.             self:addCat(0, catTitle)
  435.             catTitle = getTitleObject('Category:' .. catTitle)
  436.             if not catTitle or not catTitle.exists then
  437.                 self:addCat(0, 'Articles with invalid date parameter in template')
  438.             end
  439.         elseif mainCat and (not date or date == '') then
  440.             self:addCat(0, mainCat)
  441.         end
  442.         if allCat then
  443.             self:addCat(0, allCat)
  444.         end
  445.     end
  446. end
  447.  
  448. function MessageBox:setTemplateCategories()
  449.     local args = self.args
  450.     local cfg = self.cfg
  451.  
  452.     -- Add template categories.
  453.     if cfg.templateCategory then
  454.         if cfg.templateCategoryRequireName then
  455.             if self.isTemplatePage then
  456.                 self:addCat(10, cfg.templateCategory)
  457.             end
  458.         elseif not self.title.isSubpage then
  459.             self:addCat(10, cfg.templateCategory)
  460.         end
  461.     end
  462.  
  463.     -- Add template error categories.
  464.     if cfg.templateErrorCategory then
  465.         local templateErrorCategory = cfg.templateErrorCategory
  466.         local templateCat, templateSort
  467.         if not self.name and not self.title.isSubpage then
  468.             templateCat = templateErrorCategory
  469.         elseif self.isTemplatePage then
  470.             local paramsToCheck = cfg.templateErrorParamsToCheck or {}
  471.             local count = 0
  472.             for i, param in ipairs(paramsToCheck) do
  473.                 if not args[param] then
  474.                     count = count + 1
  475.                 end
  476.             end
  477.             if count &gt; 0 then
  478.                 templateCat = templateErrorCategory
  479.                 templateSort = tostring(count)
  480.             end
  481.             if self.categoryNums and #self.categoryNums &gt; 0 then
  482.                 templateCat = templateErrorCategory
  483.                 templateSort = 'C'
  484.             end
  485.         end
  486.         self:addCat(10, templateCat, templateSort)
  487.     end
  488. end
  489.  
  490. function MessageBox:setAllNamespaceCategories()
  491.     -- Set categories for all namespaces.
  492.     if self.invalidTypeError then
  493.         local allSort = (self.title.namespace == 0 and 'Main:' or '') .. self.title.prefixedText
  494.         self:addCat('all', 'Wikipedia message box parameter needs fixing', allSort)
  495.     end
  496.     if self.isSubstituted then
  497.         self:addCat('all', 'Pages with incorrectly substituted templates')
  498.     end
  499. end
  500.  
  501. function MessageBox:setCategories()
  502.     if self.title.namespace == 0 then
  503.         self:setMainspaceCategories()
  504.     elseif self.title.namespace == 10 then
  505.         self:setTemplateCategories()
  506.     end
  507.     self:setAllNamespaceCategories()
  508. end
  509.  
  510. function MessageBox:renderCategories()
  511.     if not self.hasCategories then
  512.         -- No categories added, no need to pass them to Category handler so,
  513.         -- if it was invoked, it would return the empty string.
  514.         -- So we shortcut and return the empty string.
  515.         return ""
  516.     end
  517.     -- Convert category tables to strings and pass them through
  518.     -- [[Module:Category handler]].
  519.     return require('Module:Category handler')._main{
  520.         main = table.concat(self.categories[0] or {}),
  521.         template = table.concat(self.categories[10] or {}),
  522.         all = table.concat(self.categories.all or {}),
  523.         nocat = self.args.nocat,
  524.         page = self.args.page
  525.     }
  526. end
  527.  
  528. function MessageBox:export()
  529.     local root = mw.html.create()
  530.  
  531.     -- Add the subst check error.
  532.     if self.isSubstituted and self.name then
  533.         root:tag('b')
  534.             :addClass('error')
  535.             :wikitext(string.format(
  536.                 'Template &lt;code&gt;%s[[Template:%s|%s]]%s&lt;/code&gt; has been incorrectly substituted.',
  537.                 mw.text.nowiki('{{'), self.name, self.name, mw.text.nowiki('}}')
  538.             ))
  539.     end
  540.  
  541.     -- Create the box table.
  542.     local boxTable = root:tag('table')
  543.     boxTable:attr('id', self.id or nil)
  544.     for i, class in ipairs(self.classes or {}) do
  545.         boxTable:addClass(class or nil)
  546.     end
  547.     boxTable
  548.         :cssText(self.style or nil)
  549.         :attr('role', 'presentation')
  550.  
  551.     if self.attrs then
  552.         boxTable:attr(self.attrs)
  553.     end
  554.  
  555.     -- Add the left-hand image.
  556.     local row = boxTable:tag('tr')
  557.     if self.imageLeft then
  558.         local imageLeftCell = row:tag('td'):addClass('mbox-image')
  559.         if self.imageCellDiv then
  560.             -- If we are using a div, redefine imageLeftCell so that the image
  561.             -- is inside it. Divs use style="width: 52px;", which limits the
  562.             -- image width to 52px. If any images in a div are wider than that,
  563.             -- they may overlap with the text or cause other display problems.
  564.             imageLeftCell = imageLeftCell:tag('div'):css('width', '52px')
  565.         end
  566.         imageLeftCell:wikitext(self.imageLeft or nil)
  567.     elseif self.imageEmptyCell then
  568.         -- Some message boxes define an empty cell if no image is specified, and
  569.         -- some don't. The old template code in templates where empty cells are
  570.         -- specified gives the following hint: "No image. Cell with some width
  571.         -- or padding necessary for text cell to have 100% width."
  572.         row:tag('td')
  573.             :addClass('mbox-empty-cell')
  574.             :cssText(self.imageEmptyCellStyle or nil)
  575.     end
  576.  
  577.     -- Add the text.
  578.     local textCell = row:tag('td'):addClass('mbox-text')
  579.     if self.useCollapsibleTextFields then
  580.         -- The message box uses advanced text parameters that allow things to be
  581.         -- collapsible. At the moment, only ambox uses this.
  582.         textCell:cssText(self.textstyle or nil)
  583.         local textCellDiv = textCell:tag('div')
  584.         textCellDiv
  585.             :addClass('mbox-text-span')
  586.             :wikitext(self.issue or nil)
  587.         if (self.talk or self.fix) then
  588.             textCellDiv:tag('span')
  589.                 :addClass('hide-when-compact')
  590.                 :wikitext(self.talk and (' ' .. self.talk) or nil)
  591.                 :wikitext(self.fix and (' ' .. self.fix) or nil)
  592.         end
  593.         textCellDiv:wikitext(self.date and (' ' .. self.date) or nil)
  594.         if self.info and not self.isSmall then
  595.             textCellDiv
  596.                 :tag('span')
  597.                 :addClass('hide-when-compact')
  598.                 :wikitext(self.info and (' ' .. self.info) or nil)
  599.         end
  600.         if self.removalNotice then
  601.             textCellDiv:tag('span')
  602.                 :addClass('hide-when-compact')
  603.                 :tag('i')
  604.                     :wikitext(string.format(" (%s)", self.removalNotice))
  605.         end
  606.     else
  607.         -- Default text formatting - anything goes.
  608.         textCell
  609.             :cssText(self.textstyle or nil)
  610.             :wikitext(self.text or nil)
  611.     end
  612.  
  613.     -- Add the right-hand image.
  614.     if self.imageRight then
  615.         local imageRightCell = row:tag('td'):addClass('mbox-imageright')
  616.         if self.imageCellDiv then
  617.             -- If we are using a div, redefine imageRightCell so that the image
  618.             -- is inside it.
  619.             imageRightCell = imageRightCell:tag('div'):css('width', '52px')
  620.         end
  621.         imageRightCell
  622.             :wikitext(self.imageRight or nil)
  623.     end
  624.  
  625.     -- Add the below row.
  626.     if self.below then
  627.         boxTable:tag('tr')
  628.             :tag('td')
  629.                 :attr('colspan', self.imageRight and '3' or '2')
  630.                 :addClass('mbox-text')
  631.                 :cssText(self.textstyle or nil)
  632.                 :wikitext(self.below or nil)
  633.     end
  634.  
  635.     -- Add error message for invalid type parameters.
  636.     if self.invalidTypeError then
  637.         root:tag('div')
  638.             :css('text-align', 'center')
  639.             :wikitext(string.format(
  640.                 'This message box is using an invalid "type=%s" parameter and needs fixing.',
  641.                 self.type or ''
  642.             ))
  643.     end
  644.  
  645.     -- Add categories.
  646.     root:wikitext(self:renderCategories() or nil)
  647.  
  648.     return tostring(root)
  649. end
  650.  
  651. --------------------------------------------------------------------------------
  652. -- Exports
  653. --------------------------------------------------------------------------------
  654.  
  655. local p, mt = {}, {}
  656.  
  657. function p._exportClasses()
  658.     -- For testing.
  659.     return {
  660.         MessageBox = MessageBox
  661.     }
  662. end
  663.  
  664. function p.main(boxType, args, cfgTables)
  665.     local box = MessageBox.new(boxType, args, cfgTables or mw.loadData(CONFIG_MODULE))
  666.     box:setParameters()
  667.     box:setCategories()
  668.     return box:export()
  669. end
  670.  
  671. function mt.__index(t, k)
  672.     return function (frame)
  673.         if not getArgs then
  674.             getArgs = require('Module:Arguments').getArgs
  675.         end
  676.         return t.main(k, getArgs(frame, {trim = false, removeBlanks = false}))
  677.     end
  678. end
  679.  
  680. return setmetatable(p, mt)</text>
  681.       <sha1>kshc0gmfnt1xkzycgdb25urt4m770p1</sha1>
  682.     </revision>
  683.   </page>
  684.   <page>
  685.     <title>Module:Message box/configuration</title>
  686.     <ns>828</ns>
  687.     <id>40627038</id>
  688.     <revision>
  689.       <id>948472514</id>
  690.       <parentid>948472513</parentid>
  691.       <timestamp>2020-04-01T06:12:44Z</timestamp>
  692.       <contributor>
  693.         <username>MusikAnimal</username>
  694.         <id>14882394</id>
  695.       </contributor>
  696.       <minor/>
  697.       <comment>1 revision imported</comment>
  698.       <model>Scribunto</model>
  699.       <format>text/plain</format>
  700.       <text bytes="6141" xml:space="preserve">--------------------------------------------------------------------------------
  701. --                          Message box configuration                         --
  702. --                                                                            --
  703. -- This module contains configuration data for [[Module:Message box]].        --
  704. --------------------------------------------------------------------------------
  705.  
  706. return {
  707.     ambox = {
  708.         types = {
  709.             speedy = {
  710.                 class = 'ambox-speedy',
  711.                 image = 'Ambox warning pn.svg'
  712.             },
  713.             delete = {
  714.                 class = 'ambox-delete',
  715.                 image = 'Ambox warning pn.svg'
  716.             },
  717.             content = {
  718.                 class = 'ambox-content',
  719.                 image = 'Ambox important.svg'
  720.             },
  721.             style = {
  722.                 class = 'ambox-style',
  723.                 image = 'Edit-clear.svg'
  724.             },
  725.             move = {
  726.                 class = 'ambox-move',
  727.                 image = 'Merge-split-transwiki default.svg'
  728.             },
  729.             protection = {
  730.                 class = 'ambox-protection',
  731.                 image = 'Semi-protection-shackle-keyhole.svg'
  732.             },
  733.             notice = {
  734.                 class = 'ambox-notice',
  735.                 image = 'Information icon4.svg'
  736.             }
  737.         },
  738.         default                     = 'notice',
  739.         allowBlankParams            = {'talk', 'sect', 'date', 'issue', 'fix', 'subst', 'hidden'},
  740.         allowSmall                  = true,
  741.         smallParam                  = 'left',
  742.         smallClass                  = 'mbox-small-left',
  743.         substCheck                  = true,
  744.         classes                     = {'metadata', 'ambox'},
  745.         imageEmptyCell              = true,
  746.         imageCheckBlank             = true,
  747.         imageSmallSize              = '20x20px',
  748.         imageCellDiv                = true,
  749.         useCollapsibleTextFields    = true,
  750.         imageRightNone              = true,
  751.         sectionDefault              = 'article',
  752.         allowMainspaceCategories    = true,
  753.         templateCategory            = 'Article message templates',
  754.             templateCategoryRequireName = true,
  755.         templateErrorCategory       = 'Article message templates with missing parameters',
  756.         templateErrorParamsToCheck  = {'issue', 'fix', 'subst'},
  757.         removalNotice               = '[[Help:Maintenance template removal|Learn how and when to remove this template message]]'
  758.     },
  759.    
  760.     cmbox = {
  761.         types = {
  762.             speedy = {
  763.                 class = 'cmbox-speedy',
  764.                 image = 'Ambox warning pn.svg'
  765.             },
  766.             delete = {
  767.                 class = 'cmbox-delete',
  768.                 image = 'Ambox warning pn.svg'
  769.             },
  770.             content = {
  771.                 class = 'cmbox-content',
  772.                 image = 'Ambox important.svg'
  773.             },
  774.             style = {
  775.                 class = 'cmbox-style',
  776.                 image = 'Edit-clear.svg'
  777.             },
  778.             move = {
  779.                 class = 'cmbox-move',
  780.                 image = 'Merge-split-transwiki default.svg'
  781.             },
  782.             protection = {
  783.                 class = 'cmbox-protection',
  784.                 image = 'Semi-protection-shackle-keyhole.svg'
  785.             },
  786.             notice = {
  787.                 class = 'cmbox-notice',
  788.                 image = 'Information icon4.svg'
  789.             }
  790.         },
  791.         default              = 'notice',
  792.         showInvalidTypeError = true,
  793.         classes              = {'cmbox'},
  794.         imageEmptyCell       = true
  795.     },
  796.    
  797.     fmbox = {
  798.         types = {
  799.             warning = {
  800.                 class = 'fmbox-warning',
  801.                 image = 'Ambox warning pn.svg'
  802.             },
  803.             editnotice = {
  804.                 class = 'fmbox-editnotice',
  805.                 image = 'Information icon4.svg'
  806.             },
  807.             system = {
  808.                 class = 'fmbox-system',
  809.                 image = 'Information icon4.svg'
  810.             }
  811.         },
  812.         default              = 'system',
  813.         showInvalidTypeError = true,
  814.         classes              = {'fmbox'},
  815.         imageEmptyCell       = false,
  816.         imageRightNone       = false
  817.     },
  818.    
  819.     imbox = {
  820.         types = {
  821.             speedy = {
  822.                 class = 'imbox-speedy',
  823.                 image = 'Ambox warning pn.svg'
  824.             },
  825.             delete = {
  826.                 class = 'imbox-delete',
  827.                 image = 'Ambox warning pn.svg'
  828.             },
  829.             content = {
  830.                 class = 'imbox-content',
  831.                 image = 'Ambox important.svg'
  832.             },
  833.             style = {
  834.                 class = 'imbox-style',
  835.                 image = 'Edit-clear.svg'
  836.             },
  837.             move = {
  838.                 class = 'imbox-move',
  839.                 image = 'Merge-split-transwiki default.svg'
  840.             },
  841.             protection = {
  842.                 class = 'imbox-protection',
  843.                 image = 'Semi-protection-shackle-keyhole.svg'
  844.             },
  845.             license = {
  846.                 class = 'imbox-license licensetpl',
  847.                 image = 'Imbox license.png' -- @todo We need an SVG version of this
  848.             },
  849.             featured = {
  850.                 class = 'imbox-featured',
  851.                 image = 'Cscr-featured.svg'
  852.             },
  853.             notice = {
  854.                 class = 'imbox-notice',
  855.                 image = 'Information icon4.svg'
  856.             }
  857.         },
  858.         default              = 'notice',
  859.         showInvalidTypeError = true,
  860.         classes              = {'imbox'},
  861.         imageEmptyCell       = true,
  862.         below                = true,
  863.         templateCategory     = 'File message boxes'
  864.     },
  865.    
  866.     ombox = {
  867.         types = {
  868.             speedy = {
  869.                 class = 'ombox-speedy',
  870.                 image = 'Ambox warning pn.svg'
  871.             },
  872.             delete = {
  873.                 class = 'ombox-delete',
  874.                 image = 'Ambox warning pn.svg'
  875.             },
  876.             content = {
  877.                 class = 'ombox-content',
  878.                 image = 'Ambox important.svg'
  879.             },
  880.             style = {
  881.                 class = 'ombox-style',
  882.                 image = 'Edit-clear.svg'
  883.             },
  884.             move = {
  885.                 class = 'ombox-move',
  886.                 image = 'Merge-split-transwiki default.svg'
  887.             },
  888.             protection = {
  889.                 class = 'ombox-protection',
  890.                 image = 'Semi-protection-shackle-keyhole.svg'
  891.             },
  892.             notice = {
  893.                 class = 'ombox-notice',
  894.                 image = 'Information icon4.svg'
  895.             }
  896.         },
  897.         default              = 'notice',
  898.         showInvalidTypeError = true,
  899.         classes              = {'ombox'},
  900.         allowSmall           = true,
  901.         imageEmptyCell       = true,
  902.         imageRightNone       = true
  903.     },
  904.    
  905.     tmbox = {
  906.         types = {
  907.             speedy = {
  908.                 class = 'tmbox-speedy',
  909.                 image = 'Ambox warning pn.svg'
  910.             },
  911.             delete = {
  912.                 class = 'tmbox-delete',
  913.                 image = 'Ambox warning pn.svg'
  914.             },
  915.             content = {
  916.                 class = 'tmbox-content',
  917.                 image = 'Ambox important.svg'
  918.             },
  919.             style = {
  920.                 class = 'tmbox-style',
  921.                 image = 'Edit-clear.svg'
  922.             },
  923.             move = {
  924.                 class = 'tmbox-move',
  925.                 image = 'Merge-split-transwiki default.svg'
  926.             },
  927.             protection = {
  928.                 class = 'tmbox-protection',
  929.                 image = 'Semi-protection-shackle-keyhole.svg'
  930.             },
  931.             notice = {
  932.                 class = 'tmbox-notice',
  933.                 image = 'Information icon4.svg'
  934.             }
  935.         },
  936.         default              = 'notice',
  937.         showInvalidTypeError = true,
  938.         classes              = {'tmbox'},
  939.         allowSmall           = true,
  940.         imageRightNone       = true,
  941.         imageEmptyCell       = true,
  942.         imageEmptyCellStyle  = true,
  943.         templateCategory     = 'Talk message boxes'
  944.     }
  945. }</text>
  946.       <sha1>rz63o9789otb966y0k5pcntqf0bl6te</sha1>
  947.     </revision>
  948.   </page>
  949.   <page>
  950.     <title>Module:No globals</title>
  951.     <ns>828</ns>
  952.     <id>42567026</id>
  953.     <revision>
  954.       <id>948473889</id>
  955.       <parentid>948472526</parentid>
  956.       <timestamp>2020-04-01T06:28:55Z</timestamp>
  957.       <contributor>
  958.         <username>MusikAnimal</username>
  959.         <id>14882394</id>
  960.       </contributor>
  961.       <comment>Undid revision 948472525 by [[Special:Contributions/w&gt;DiBabelYurikBot|w&gt;DiBabelYurikBot]] ([[User talk:w&gt;DiBabelYurikBot|talk]])</comment>
  962.       <model>Scribunto</model>
  963.       <format>text/plain</format>
  964.       <text bytes="307" xml:space="preserve">local mt = getmetatable(_G) or {}
  965. function mt.__index (t, k)
  966.     if k ~= 'arg' then
  967.         error('Tried to read nil global ' .. tostring(k), 2)
  968.     end
  969.     return nil
  970. end
  971. function mt.__newindex(t, k, v)
  972.     if k ~= 'arg' then
  973.         error('Tried to write global ' .. tostring(k), 2)
  974.     end
  975.     rawset(t, k, v)
  976. end
  977. setmetatable(_G, mt)</text>
  978.       <sha1>gggsv54pq7f94l3up48hr91qtxnskdm</sha1>
  979.     </revision>
  980.   </page>
  981.   <page>
  982.     <title>Module:Category handler</title>
  983.     <ns>828</ns>
  984.     <id>39772274</id>
  985.     <revision>
  986.       <id>948472489</id>
  987.       <parentid>948472486</parentid>
  988.       <timestamp>2020-04-01T06:12:40Z</timestamp>
  989.       <contributor>
  990.         <username>MusikAnimal</username>
  991.         <id>14882394</id>
  992.       </contributor>
  993.       <minor/>
  994.       <comment>1 revision imported</comment>
  995.       <model>Scribunto</model>
  996.       <format>text/plain</format>
  997.       <text bytes="7871" xml:space="preserve">--------------------------------------------------------------------------------
  998. --                                                                            --
  999. --                              CATEGORY HANDLER                              --
  1000. --                                                                            --
  1001. --      This module implements the {{category handler}} template in Lua,      --
  1002. --      with a few improvements: all namespaces and all namespace aliases     --
  1003. --      are supported, and namespace names are detected automatically for     --
  1004. --      the local wiki. This module requires [[Module:Namespace detect]]      --
  1005. --      and [[Module:Yesno]] to be available on the local wiki. It can be     --
  1006. --      configured for different wikis by altering the values in              --
  1007. --      [[Module:Category handler/config]], and pages can be blacklisted      --
  1008. --      from categorisation by using [[Module:Category handler/blacklist]].   --
  1009. --                                                                            --
  1010. --------------------------------------------------------------------------------
  1011.  
  1012. -- Load required modules
  1013. local yesno = require('Module:Yesno')
  1014.  
  1015. -- Lazily load things we don't always need
  1016. local mShared, mappings
  1017.  
  1018. local p = {}
  1019.  
  1020. --------------------------------------------------------------------------------
  1021. -- Helper functions
  1022. --------------------------------------------------------------------------------
  1023.  
  1024. local function trimWhitespace(s, removeBlanks)
  1025.     if type(s) ~= 'string' then
  1026.         return s
  1027.     end
  1028.     s = s:match('^%s*(.-)%s*$')
  1029.     if removeBlanks then
  1030.         if s ~= '' then
  1031.             return s
  1032.         else
  1033.             return nil
  1034.         end
  1035.     else
  1036.         return s
  1037.     end
  1038. end
  1039.  
  1040. --------------------------------------------------------------------------------
  1041. -- CategoryHandler class
  1042. --------------------------------------------------------------------------------
  1043.  
  1044. local CategoryHandler = {}
  1045. CategoryHandler.__index = CategoryHandler
  1046.  
  1047. function CategoryHandler.new(data, args)
  1048.     local obj = setmetatable({ _data = data, _args = args }, CategoryHandler)
  1049.    
  1050.     -- Set the title object
  1051.     do
  1052.         local pagename = obj:parameter('demopage')
  1053.         local success, titleObj
  1054.         if pagename then
  1055.             success, titleObj = pcall(mw.title.new, pagename)
  1056.         end
  1057.         if success and titleObj then
  1058.             obj.title = titleObj
  1059.             if titleObj == mw.title.getCurrentTitle() then
  1060.                 obj._usesCurrentTitle = true
  1061.             end
  1062.         else
  1063.             obj.title = mw.title.getCurrentTitle()
  1064.             obj._usesCurrentTitle = true
  1065.         end
  1066.     end
  1067.  
  1068.     -- Set suppression parameter values
  1069.     for _, key in ipairs{'nocat', 'categories'} do
  1070.         local value = obj:parameter(key)
  1071.         value = trimWhitespace(value, true)
  1072.         obj['_' .. key] = yesno(value)
  1073.     end
  1074.     do
  1075.         local subpage = obj:parameter('subpage')
  1076.         local category2 = obj:parameter('category2')
  1077.         if type(subpage) == 'string' then
  1078.             subpage = mw.ustring.lower(subpage)
  1079.         end
  1080.         if type(category2) == 'string' then
  1081.             subpage = mw.ustring.lower(category2)
  1082.         end
  1083.         obj._subpage = trimWhitespace(subpage, true)
  1084.         obj._category2 = trimWhitespace(category2) -- don't remove blank values
  1085.     end
  1086.     return obj
  1087. end
  1088.  
  1089. function CategoryHandler:parameter(key)
  1090.     local parameterNames = self._data.parameters[key]
  1091.     local pntype = type(parameterNames)
  1092.     if pntype == 'string' or pntype == 'number' then
  1093.         return self._args[parameterNames]
  1094.     elseif pntype == 'table' then
  1095.         for _, name in ipairs(parameterNames) do
  1096.             local value = self._args[name]
  1097.             if value ~= nil then
  1098.                 return value
  1099.             end
  1100.         end
  1101.         return nil
  1102.     else
  1103.         error(string.format(
  1104.             'invalid config key "%s"',
  1105.             tostring(key)
  1106.         ), 2)
  1107.     end
  1108. end
  1109.  
  1110. function CategoryHandler:isSuppressedByArguments()
  1111.     return
  1112.         -- See if a category suppression argument has been set.
  1113.         self._nocat == true
  1114.         or self._categories == false
  1115.         or (
  1116.             self._category2
  1117.             and self._category2 ~= self._data.category2Yes
  1118.             and self._category2 ~= self._data.category2Negative
  1119.         )
  1120.  
  1121.         -- Check whether we are on a subpage, and see if categories are
  1122.         -- suppressed based on our subpage status.
  1123.         or self._subpage == self._data.subpageNo and self.title.isSubpage
  1124.         or self._subpage == self._data.subpageOnly and not self.title.isSubpage
  1125. end
  1126.  
  1127. function CategoryHandler:shouldSkipBlacklistCheck()
  1128.     -- Check whether the category suppression arguments indicate we
  1129.     -- should skip the blacklist check.
  1130.     return self._nocat == false
  1131.         or self._categories == true
  1132.         or self._category2 == self._data.category2Yes
  1133. end
  1134.  
  1135. function CategoryHandler:matchesBlacklist()
  1136.     if self._usesCurrentTitle then
  1137.         return self._data.currentTitleMatchesBlacklist
  1138.     else
  1139.         mShared = mShared or require('Module:Category handler/shared')
  1140.         return mShared.matchesBlacklist(
  1141.             self.title.prefixedText,
  1142.             mw.loadData('Module:Category handler/blacklist')
  1143.         )
  1144.     end
  1145. end
  1146.  
  1147. function CategoryHandler:isSuppressed()
  1148.     -- Find if categories are suppressed by either the arguments or by
  1149.     -- matching the blacklist.
  1150.     return self:isSuppressedByArguments()
  1151.         or not self:shouldSkipBlacklistCheck() and self:matchesBlacklist()
  1152. end
  1153.  
  1154. function CategoryHandler:getNamespaceParameters()
  1155.     if self._usesCurrentTitle then
  1156.         return self._data.currentTitleNamespaceParameters
  1157.     else
  1158.         if not mappings then
  1159.             mShared = mShared or require('Module:Category handler/shared')
  1160.             mappings = mShared.getParamMappings(true) -- gets mappings with mw.loadData
  1161.         end
  1162.         return mShared.getNamespaceParameters(
  1163.             self.title,
  1164.             mappings
  1165.         )
  1166.     end
  1167. end
  1168.  
  1169. function CategoryHandler:namespaceParametersExist()
  1170.     -- Find whether any namespace parameters have been specified.
  1171.     -- We use the order "all" --&gt; namespace params --&gt; "other" as this is what
  1172.     -- the old template did.
  1173.     if self:parameter('all') then
  1174.         return true
  1175.     end
  1176.     if not mappings then
  1177.         mShared = mShared or require('Module:Category handler/shared')
  1178.         mappings = mShared.getParamMappings(true) -- gets mappings with mw.loadData
  1179.     end
  1180.     for ns, params in pairs(mappings) do
  1181.         for i, param in ipairs(params) do
  1182.             if self._args[param] then
  1183.                 return true
  1184.             end
  1185.         end
  1186.     end
  1187.     if self:parameter('other') then
  1188.         return true
  1189.     end
  1190.     return false
  1191. end
  1192.  
  1193. function CategoryHandler:getCategories()
  1194.     local params = self:getNamespaceParameters()
  1195.     local nsCategory
  1196.     for i, param in ipairs(params) do
  1197.         local value = self._args[param]
  1198.         if value ~= nil then
  1199.             nsCategory = value
  1200.             break
  1201.         end
  1202.     end
  1203.     if nsCategory ~= nil or self:namespaceParametersExist() then
  1204.         -- Namespace parameters exist - advanced usage.
  1205.         if nsCategory == nil then
  1206.             nsCategory = self:parameter('other')
  1207.         end
  1208.         local ret = {self:parameter('all')}
  1209.         local numParam = tonumber(nsCategory)
  1210.         if numParam and numParam &gt;= 1 and math.floor(numParam) == numParam then
  1211.             -- nsCategory is an integer
  1212.             ret[#ret + 1] = self._args[numParam]
  1213.         else
  1214.             ret[#ret + 1] = nsCategory
  1215.         end
  1216.         if #ret &lt; 1 then
  1217.             return nil
  1218.         else
  1219.             return table.concat(ret)
  1220.         end
  1221.     elseif self._data.defaultNamespaces[self.title.namespace] then
  1222.         -- Namespace parameters don't exist, simple usage.
  1223.         return self._args[1]
  1224.     end
  1225.     return nil
  1226. end
  1227.  
  1228. --------------------------------------------------------------------------------
  1229. -- Exports
  1230. --------------------------------------------------------------------------------
  1231.  
  1232. local p = {}
  1233.  
  1234. function p._exportClasses()
  1235.     -- Used for testing purposes.
  1236.     return {
  1237.         CategoryHandler = CategoryHandler
  1238.     }
  1239. end
  1240.  
  1241. function p._main(args, data)
  1242.     data = data or mw.loadData('Module:Category handler/data')
  1243.     local handler = CategoryHandler.new(data, args)
  1244.     if handler:isSuppressed() then
  1245.         return nil
  1246.     end
  1247.     return handler:getCategories()
  1248. end
  1249.  
  1250. function p.main(frame, data)
  1251.     data = data or mw.loadData('Module:Category handler/data')
  1252.     local args = require('Module:Arguments').getArgs(frame, {
  1253.         wrappers = data.wrappers,
  1254.         valueFunc = function (k, v)
  1255.             v = trimWhitespace(v)
  1256.             if type(k) == 'number' then
  1257.                 if v ~= '' then
  1258.                     return v
  1259.                 else
  1260.                     return nil
  1261.                 end
  1262.             else
  1263.                 return v
  1264.             end
  1265.         end
  1266.     })
  1267.     return p._main(args, data)
  1268. end
  1269.  
  1270. return p</text>
  1271.       <sha1>letwavu3yvlayfzew66uuwixmwebq5b</sha1>
  1272.     </revision>
  1273.   </page>
  1274.   <page>
  1275.     <title>Module:Yesno</title>
  1276.     <ns>828</ns>
  1277.     <id>38665046</id>
  1278.     <revision>
  1279.       <id>948473803</id>
  1280.       <parentid>948472535</parentid>
  1281.       <timestamp>2020-04-01T06:27:55Z</timestamp>
  1282.       <contributor>
  1283.         <username>MusikAnimal</username>
  1284.         <id>14882394</id>
  1285.       </contributor>
  1286.       <comment>Undid revision 948472533 by [[Special:Contributions/w&gt;Vogone|w&gt;Vogone]] ([[User talk:w&gt;Vogone|talk]])</comment>
  1287.       <model>Scribunto</model>
  1288.       <format>text/plain</format>
  1289.       <text bytes="745" xml:space="preserve">-- Function allowing for consistent treatment of boolean-like wikitext input.
  1290. -- It works similarly to the template {{yesno}}.
  1291.  
  1292. return function (val, default)
  1293.     -- If your wiki uses non-ascii characters for any of "yes", "no", etc., you
  1294.     -- should replace "val:lower()" with "mw.ustring.lower(val)" in the
  1295.     -- following line.
  1296.     val = type(val) == 'string' and val:lower() or val
  1297.     if val == nil then
  1298.         return nil
  1299.     elseif val == true
  1300.         or val == 'yes'
  1301.         or val == 'y'
  1302.         or val == 'true'
  1303.         or val == 't'
  1304.         or val == 'on'
  1305.         or tonumber(val) == 1
  1306.     then
  1307.         return true
  1308.     elseif val == false
  1309.         or val == 'no'
  1310.         or val == 'n'
  1311.         or val == 'false'
  1312.         or val == 'f'
  1313.         or val == 'off'
  1314.         or tonumber(val) == 0
  1315.     then
  1316.         return false
  1317.     else
  1318.         return default
  1319.     end
  1320. end</text>
  1321.       <sha1>swdskn7svew8i9wuydn9uj5l3r2ghcs</sha1>
  1322.     </revision>
  1323.   </page>
  1324.   <page>
  1325.     <title>Template:Lua</title>
  1326.     <ns>10</ns>
  1327.     <id>38752725</id>
  1328.     <revision>
  1329.       <id>888711835</id>
  1330.       <parentid>886057621</parentid>
  1331.       <timestamp>2019-03-20T22:04:45Z</timestamp>
  1332.       <contributor>
  1333.         <username>RMCD bot</username>
  1334.         <id>17216044</id>
  1335.       </contributor>
  1336.       <comment>Removing notice of move discussion</comment>
  1337.       <model>wikitext</model>
  1338.       <format>text/x-wiki</format>
  1339.       <text bytes="196" xml:space="preserve">&lt;includeonly&gt;{{#invoke:Lua banner|main}}&lt;/includeonly&gt;&lt;noinclude&gt;
  1340. {{Lua|Module:Lua banner}}
  1341. {{documentation}}
  1342. &lt;!-- Categories go on the /doc subpage and interwikis go on Wikidata. --&gt;
  1343. &lt;/noinclude&gt;</text>
  1344.       <sha1>pnmjp3f3fl321yf2jpg5syebi412n7b</sha1>
  1345.     </revision>
  1346.   </page>
  1347.   <page>
  1348.     <title>Template:Module other</title>
  1349.     <ns>10</ns>
  1350.     <id>38821035</id>
  1351.     <revision>
  1352.       <id>1050945039</id>
  1353.       <parentid>929909970</parentid>
  1354.       <timestamp>2021-10-20T19:50:22Z</timestamp>
  1355.       <contributor>
  1356.         <username>MusikBot II</username>
  1357.         <id>29539620</id>
  1358.       </contributor>
  1359.       <minor/>
  1360.       <comment>Changed protection settings for "[[Template:Module other]]": [[Wikipedia:High-risk templates|High-risk template or module]]: 3570 transclusions ([[User:MusikBot II/TemplateProtector|more info]]) ([Edit=Require extended confirmed access] (indefinite) [Move=Require extended confirmed access] (indefinite))</comment>
  1361.       <model>wikitext</model>
  1362.       <format>text/x-wiki</format>
  1363.       <text bytes="414" xml:space="preserve">{{#switch:
  1364.   &lt;!--If no or empty "demospace" parameter then detect namespace--&gt;
  1365.   {{#if:{{{demospace|}}}
  1366.   | {{lc: {{{demospace}}} }}    &lt;!--Use lower case "demospace"--&gt;
  1367.   | {{#ifeq:{{NAMESPACE}}|{{ns:Module}}
  1368.     | module
  1369.     | other
  1370.     }}
  1371.   }}
  1372. | module = {{{1|}}}
  1373. | other
  1374. | #default = {{{2|}}}
  1375. }}&lt;!--End switch--&gt;&lt;noinclude&gt;
  1376.  
  1377. {{documentation}}
  1378. &lt;!-- Add categories to the /doc subpage, not here! --&gt;
  1379. &lt;/noinclude&gt;</text>
  1380.       <sha1>9db98vx09purrfch7wguurzjgqz7u93</sha1>
  1381.     </revision>
  1382.   </page>
  1383.   <page>
  1384.     <title>Template:Module rating</title>
  1385.     <ns>10</ns>
  1386.     <id>39134544</id>
  1387.     <revision>
  1388.       <id>1059797183</id>
  1389.       <parentid>986097640</parentid>
  1390.       <timestamp>2021-12-11T17:54:10Z</timestamp>
  1391.       <contributor>
  1392.         <username>Alexis Jazz</username>
  1393.         <id>2521907</id>
  1394.       </contributor>
  1395.       <comment>do not show protection level of the module on the doc page, use the second (and optionally third) parameter if the doc page is also protected</comment>
  1396.       <model>wikitext</model>
  1397.       <format>text/x-wiki</format>
  1398.       <text bytes="5531" xml:space="preserve">&lt;includeonly&gt;{{#ifeq:{{SUBPAGENAME}}|doc|&lt;!--do not show protection level of the module on the doc page, use the second and optionally third parameter if the doc page is also protected --&gt;{{#if:{{{2|}}}|{{Pp|{{{2}}}|action={{{3|}}}}}}}|{{Module other|{{ombox
  1399.  | type      = notice
  1400.  | image     = {{#switch: {{{1|}}}
  1401.    | pre-alpha | prealpha | pa = [[File:Ambox warning blue construction.svg|40x40px|link=|alt=Pre-alpha]]
  1402.    | alpha | a                 = [[File:Alpha lowercase.svg|26x26px|link=|alt=Alpha]]
  1403.    | beta | b                  = [[File:Greek lc beta.svg|40x40px|link=|alt=Beta]]
  1404.    | release | r | general | g = [[File:Green check.svg|40x40px|link=|alt=Ready for use]]
  1405.    | protected | protect | p   = [[File:{{#switch:{{#invoke:Effective protection level|edit|{{#switch:{{SUBPAGENAME}}|doc|sandbox={{FULLBASEPAGENAME}}|{{FULLPAGENAME}}}}}}|autoconfirmed=Semi|extendedconfirmed=Extended|accountcreator|templateeditor=Template|#default=Full}}-protection-shackle.svg|40x40px|link=|alt=Protected]]
  1406.    | semiprotected | semiprotect | semi =[[File:Semi-protection-shackle.svg|40x40px|link=|alt=Semi-protected]]
  1407.   }}
  1408.  | style     =
  1409.  | textstyle =
  1410.  | text      = {{#switch: {{{1|}}}
  1411.    | pre-alpha | prealpha | pa = This module is rated as [[:Category:Modules in pre-alpha development|pre-alpha]]. It is unfinished, and may or may not be in active development. It should not be used from article namespace pages. Modules remain pre-alpha until the original editor (or someone who takes one over if it is abandoned for some time) is satisfied with the basic structure.&lt;!--
  1412.    --&gt;{{#switch: {{SUBPAGENAME}}|doc|sandbox=&lt;!-- No category for /doc or /sandbox subpages --&gt;
  1413.        | {{#ifeq: {{{nocat|}}} | true | &lt;!-- No category if user sets nocat=true --&gt; | [[Category:Modules in pre-alpha development|{{PAGENAME}}]] }}
  1414.       }}
  1415.    | alpha | a                 = This module is rated as [[:Category:Modules in alpha|alpha]]. It is ready for third-party input, and may be used on a few pages to see if problems arise, but should be watched. Suggestions for new features or changes in their input and output mechanisms are welcome.&lt;!--
  1416.    --&gt;{{#switch: {{SUBPAGENAME}}|doc|sandbox=&lt;!-- No category for /doc or /sandbox subpages --&gt;
  1417.        | {{#ifeq: {{{nocat|}}} | true | &lt;!-- No category if user sets nocat=true --&gt; | [[Category:Modules in alpha|{{PAGENAME}}]] }}
  1418.       }}
  1419.    | beta | b                  = This module is rated as [[:Category:Modules in beta|beta]], and is ready for widespread use. It is still new and should be used with some caution to ensure the results are as expected.&lt;!--
  1420.    --&gt;{{#switch: {{SUBPAGENAME}}|doc|sandbox=&lt;!-- No category for /doc or /sandbox subpages --&gt;
  1421.        | {{#ifeq: {{{nocat|}}} | true | &lt;!-- No category if user sets nocat=true --&gt; | [[Category:Modules in beta|{{PAGENAME}}]] }}
  1422.       }}
  1423.    | release | r | general | g = This module is rated as [[:Category:Modules for general use|ready for general use]]. It has reached a mature form and is thought to be relatively bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by [[Wikipedia:Template sandbox and test cases|sandbox testing]] rather than repeated trial-and-error editing.&lt;!--
  1424.    --&gt;{{#switch: {{SUBPAGENAME}}|doc|sandbox=&lt;!-- No category for /doc or /sandbox subpages --&gt;
  1425.        | {{#ifeq: {{{nocat|}}} | true | &lt;!-- No category if user sets nocat=true --&gt; | [[Category:Modules for general use|{{PAGENAME}}]] }}
  1426.       }}
  1427.    | protected | protect | p   = This module is [[:Category:Modules subject to page protection|subject to page protection]]. It is a [[Wikipedia:High-risk templates|highly visible module]] in use by a very large number of pages, or is [[Wikipedia:Substitution|substituted]] very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is [[Wikipedia:Protection policy|protected]] from editing.&lt;!--
  1428.    --&gt;{{#switch: {{SUBPAGENAME}}|doc|sandbox=&lt;!-- No category for /doc or /sandbox subpages --&gt;
  1429.        | {{#ifeq: {{{nocat|}}} | true | &lt;!-- No category if user sets nocat=true --&gt; | [[Category:Modules subject to page protection|{{PAGENAME}}]] }}
  1430.       }}
  1431.    | semiprotected | semiprotect | semi   = This module is [[:Category:Modules subject to page protection|subject to page protection]]. It is a [[Wikipedia:High-risk templates|highly visible module]] in use by a very large number of pages, or is [[Wikipedia:Substitution|substituted]] very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is [[WP:SEMI|semi-protected]] from editing.&lt;!--
  1432.    --&gt;{{#switch: {{SUBPAGENAME}}|doc|sandbox=&lt;!-- No category for /doc or /sandbox subpages --&gt;
  1433.        | {{#ifeq: {{{nocat|}}} | true | &lt;!-- No category if user sets nocat=true --&gt; | [[Category:Modules subject to page protection|{{PAGENAME}}]] }}
  1434.       }}
  1435.    | #default                  = {{error|Module rating is invalid or not specified.}}
  1436.   }}
  1437. }}|{{error|Error: {{tl|Module rating}} must be placed in the Module namespace.}} [[Category:Pages with templates in the wrong namespace]]|demospace={{{demospace|&lt;noinclude&gt;module&lt;/noinclude&gt;}}}}}}}&lt;/includeonly&gt;&lt;noinclude&gt;
  1438. {{module rating|release|nocat=true|demospace=module}}
  1439. {{documentation}}
  1440. &lt;!-- Categories go on the /doc subpage, and interwikis go in Wikidata. --&gt;
  1441. &lt;/noinclude&gt;</text>
  1442.       <sha1>lxtrdpq6pzbeyc3gi5sruxh2ktsy58c</sha1>
  1443.     </revision>
  1444.   </page>
  1445.   <page>
  1446.     <title>Template:Ombox</title>
  1447.     <ns>10</ns>
  1448.     <id>17522403</id>
  1449.     <revision>
  1450.       <id>948472472</id>
  1451.       <parentid>948472468</parentid>
  1452.       <timestamp>2020-04-01T06:12:36Z</timestamp>
  1453.       <contributor>
  1454.         <username>MusikAnimal</username>
  1455.         <id>14882394</id>
  1456.       </contributor>
  1457.       <minor/>
  1458.       <comment>1 revision imported</comment>
  1459.       <model>wikitext</model>
  1460.       <format>text/x-wiki</format>
  1461.       <text bytes="146" xml:space="preserve">{{#invoke:Message box|ombox}}&lt;noinclude&gt;
  1462. {{documentation}}
  1463. &lt;!-- Categories go on the /doc subpage, and interwikis go on Wikidata. --&gt;
  1464. &lt;/noinclude&gt;</text>
  1465.       <sha1>1o93yrjvq6v2ylug2k0uaaltljurje2</sha1>
  1466.     </revision>
  1467.   </page>
  1468.   <page>
  1469.     <title>Template:Sandbox other</title>
  1470.     <ns>10</ns>
  1471.     <id>48540583</id>
  1472.     <revision>
  1473.       <id>948779760</id>
  1474.       <parentid>929909975</parentid>
  1475.       <timestamp>2020-04-03T00:08:09Z</timestamp>
  1476.       <contributor>
  1477.         <username>Evad37</username>
  1478.         <id>16958448</id>
  1479.       </contributor>
  1480.       <comment>Also match subpage names beginning with "sandbox", per [[Template_talk:Sandbox_other#Template-protected_edit_request_on_28_March_2020|edit request]]</comment>
  1481.       <model>wikitext</model>
  1482.       <format>text/x-wiki</format>
  1483.       <text bytes="260" xml:space="preserve">{{#if:{{#ifeq:{{#invoke:String|sublength|s={{SUBPAGENAME}}|i=0|len=7}}|sandbox|1}}{{#ifeq:{{SUBPAGENAME}}|doc|1}}{{#invoke:String|match|{{PAGENAME}}|/sandbox/styles.css$|plain=false|nomatch=}}|{{{1|}}}|{{{2|}}}}}&lt;!--
  1484. --&gt;&lt;noinclude&gt;{{documentation}}&lt;/noinclude&gt;</text>
  1485.       <sha1>h1idujwaw20aducxsd1gc4ovgnjikqa</sha1>
  1486.     </revision>
  1487.   </page>
  1488.   <page>
  1489.     <title>Template:Tag</title>
  1490.     <ns>10</ns>
  1491.     <id>7252577</id>
  1492.     <revision>
  1493.       <id>852104887</id>
  1494.       <parentid>848709005</parentid>
  1495.       <timestamp>2018-07-26T17:17:13Z</timestamp>
  1496.       <contributor>
  1497.         <username>SMcCandlish</username>
  1498.         <id>378390</id>
  1499.       </contributor>
  1500.       <comment>These are called attributes; no one who does HTML calls them "parameters".</comment>
  1501.       <model>wikitext</model>
  1502.       <format>text/x-wiki</format>
  1503.       <text bytes="835" xml:space="preserve">&lt;code class="{{#ifeq:{{{wrap|}}}|yes|wrap|nowrap}}" style="{{#ifeq:{{{style|}}}|plain|border:none;background:transparent;|{{{style|}}}}}"&gt;&lt;!--
  1504.  Opening tag
  1505. --&gt;{{#switch:{{{2|pair}}}
  1506.   |c|close =
  1507.   |e|empty|s|single|v|void
  1508.   |o|open
  1509.   |p|pair = &amp;lt;{{#if:{{{link|}}}|[[HTML element#{{{1|tag}}}|{{{1|tag}}}]]|{{{1|tag}}}}}{{#if:{{{params|{{{attribs|}}}}}}|&amp;#32;{{{params|{{{attribs}}}}}}}}
  1510.  }}&lt;!--
  1511.  Content between tags
  1512. --&gt;{{#switch:{{{2|pair}}}
  1513.   |c|close = {{{content|}}}
  1514.   |e|empty|s|single|v|void = &amp;#32;&amp;#47;&amp;gt;
  1515.   |o|open = &amp;gt;{{{content|}}}
  1516.   |p|pair = {{#ifeq:{{{1|tag}}}|!--||&amp;gt;}}{{{content|...}}}
  1517.  }}&lt;!--
  1518.  Closing tag
  1519. --&gt;{{#switch:{{{2|pair}}}
  1520.   |e|empty|s|single|v|void
  1521.   |o|open =
  1522.   |c|close
  1523.   |p|pair = {{#ifeq:{{{1|tag}}}|!--|--&amp;gt;|&amp;lt;&amp;#47;{{{1|tag}}}&amp;gt;}}
  1524.  }}&lt;!--
  1525. --&gt;&lt;/code&gt;&lt;noinclude&gt;
  1526. {{Documentation}}
  1527. &lt;/noinclude&gt;</text>
  1528.       <sha1>rfqa950ndrmgt6ozaa81dwgyr2n28ea</sha1>
  1529.     </revision>
  1530.   </page>
  1531.   <page>
  1532.     <title>Template:Template link</title>
  1533.     <ns>10</ns>
  1534.     <id>1487430</id>
  1535.     <revision>
  1536.       <id>1014201710</id>
  1537.       <parentid>1012903429</parentid>
  1538.       <timestamp>2021-03-25T19:03:22Z</timestamp>
  1539.       <contributor>
  1540.         <username>Izno</username>
  1541.         <id>2927383</id>
  1542.       </contributor>
  1543.       <comment>[[Wikipedia:Templates for discussion/Log/2021 March 18#Template:Tlu]] closed as keep ([[WP:XFDC#4.0.11|XFDcloser]])</comment>
  1544.       <model>wikitext</model>
  1545.       <format>text/x-wiki</format>
  1546.       <text bytes="167" xml:space="preserve">&amp;#123;&amp;#123;[[Template:{{{1}}}|{{{1}}}]]&amp;#125;&amp;#125;&lt;noinclude&gt;{{documentation}}
  1547. &lt;!-- Categories go on the /doc subpage and interwikis go on Wikidata. --&gt;
  1548. &lt;/noinclude&gt;</text>
  1549.       <sha1>rf3qx5cilaxlnjqq9fivevkah92ncil</sha1>
  1550.     </revision>
  1551.   </page>
  1552.   <page>
  1553.     <title>Template:Tl</title>
  1554.     <ns>10</ns>
  1555.     <id>66733012</id>
  1556.     <redirect title="Template:Template link" />
  1557.     <revision>
  1558.       <id>1006436965</id>
  1559.       <timestamp>2021-02-12T22:03:00Z</timestamp>
  1560.       <contributor>
  1561.         <username>Anthony Appleyard</username>
  1562.         <id>119438</id>
  1563.       </contributor>
  1564.       <comment>Anthony Appleyard moved page [[Template:Tl]] to [[Template:Template link]]: [[Special:Permalink/1006428669|Requested]] by Buidhe at [[WP:RM/TR]]: RM closed as move</comment>
  1565.       <model>wikitext</model>
  1566.       <format>text/x-wiki</format>
  1567.       <text bytes="83" xml:space="preserve">#REDIRECT [[Template:Template link]]
  1568.  
  1569. {{Redirect category shell|
  1570. {{R from move}}
  1571. }}</text>
  1572.       <sha1>p1dn3i2ckb7gtckkrbn0xh6ckx8nei1</sha1>
  1573.     </revision>
  1574.   </page>
  1575.   <page>
  1576.     <title>Template:Used in system</title>
  1577.     <ns>10</ns>
  1578.     <id>22491619</id>
  1579.     <revision>
  1580.       <id>1046926249</id>
  1581.       <parentid>1036596609</parentid>
  1582.       <timestamp>2021-09-28T03:41:32Z</timestamp>
  1583.       <contributor>
  1584.         <username>MusikBot II</username>
  1585.         <id>29539620</id>
  1586.       </contributor>
  1587.       <minor/>
  1588.       <comment>Protected "[[Template:Used in system]]": [[Wikipedia:High-risk templates|High-risk template or module]]: 428 transclusions ([[User:MusikBot II/TemplateProtector|more info]]) ([Edit=Require autoconfirmed or confirmed access] (indefinite))</comment>
  1589.       <model>wikitext</model>
  1590.       <format>text/x-wiki</format>
  1591.       <text bytes="235" xml:space="preserve">{{#invoke:High-use|main|1=|2={{{2|}}}|system={{#if:{{{1|}}}|{{{1}}}|in system messages}}&lt;noinclude&gt;|nocat=true&lt;/noinclude&gt;}}&lt;noinclude&gt;
  1592. {{documentation}}&lt;!-- Add categories and interwikis to the /doc subpage, not here! --&gt;
  1593. &lt;/noinclude&gt;</text>
  1594.       <sha1>196bkrax8m9r9spo90sxgyczdyxm0j6</sha1>
  1595.     </revision>
  1596.   </page>
  1597.   <page>
  1598.     <title>Module:Arguments</title>
  1599.     <ns>828</ns>
  1600.     <id>41298065</id>
  1601.     <revision>
  1602.       <id>948472485</id>
  1603.       <parentid>948472482</parentid>
  1604.       <timestamp>2020-04-01T06:12:40Z</timestamp>
  1605.       <contributor>
  1606.         <username>MusikAnimal</username>
  1607.         <id>14882394</id>
  1608.       </contributor>
  1609.       <minor/>
  1610.       <comment>1 revision imported</comment>
  1611.       <model>Scribunto</model>
  1612.       <format>text/plain</format>
  1613.       <text bytes="10054" xml:space="preserve">-- This module provides easy processing of arguments passed to Scribunto from
  1614. -- #invoke. It is intended for use by other Lua modules, and should not be
  1615. -- called from #invoke directly.
  1616.  
  1617. local libraryUtil = require('libraryUtil')
  1618. local checkType = libraryUtil.checkType
  1619.  
  1620. local arguments = {}
  1621.  
  1622. -- Generate four different tidyVal functions, so that we don't have to check the
  1623. -- options every time we call it.
  1624.  
  1625. local function tidyValDefault(key, val)
  1626.     if type(val) == 'string' then
  1627.         val = val:match('^%s*(.-)%s*$')
  1628.         if val == '' then
  1629.             return nil
  1630.         else
  1631.             return val
  1632.         end
  1633.     else
  1634.         return val
  1635.     end
  1636. end
  1637.  
  1638. local function tidyValTrimOnly(key, val)
  1639.     if type(val) == 'string' then
  1640.         return val:match('^%s*(.-)%s*$')
  1641.     else
  1642.         return val
  1643.     end
  1644. end
  1645.  
  1646. local function tidyValRemoveBlanksOnly(key, val)
  1647.     if type(val) == 'string' then
  1648.         if val:find('%S') then
  1649.             return val
  1650.         else
  1651.             return nil
  1652.         end
  1653.     else
  1654.         return val
  1655.     end
  1656. end
  1657.  
  1658. local function tidyValNoChange(key, val)
  1659.     return val
  1660. end
  1661.  
  1662. local function matchesTitle(given, title)
  1663.     local tp = type( given )
  1664.     return (tp == 'string' or tp == 'number') and mw.title.new( given ).prefixedText == title
  1665. end
  1666.  
  1667. local translate_mt = { __index = function(t, k) return k end }
  1668.  
  1669. function arguments.getArgs(frame, options)
  1670.     checkType('getArgs', 1, frame, 'table', true)
  1671.     checkType('getArgs', 2, options, 'table', true)
  1672.     frame = frame or {}
  1673.     options = options or {}
  1674.  
  1675.     --[[
  1676.     -- Set up argument translation.
  1677.     --]]
  1678.     options.translate = options.translate or {}
  1679.     if getmetatable(options.translate) == nil then
  1680.         setmetatable(options.translate, translate_mt)
  1681.     end
  1682.     if options.backtranslate == nil then
  1683.         options.backtranslate = {}
  1684.         for k,v in pairs(options.translate) do
  1685.             options.backtranslate[v] = k
  1686.         end
  1687.     end
  1688.     if options.backtranslate and getmetatable(options.backtranslate) == nil then
  1689.         setmetatable(options.backtranslate, {
  1690.             __index = function(t, k)
  1691.                 if options.translate[k] ~= k then
  1692.                     return nil
  1693.                 else
  1694.                     return k
  1695.                 end
  1696.             end
  1697.         })
  1698.     end
  1699.  
  1700.     --[[
  1701.     -- Get the argument tables. If we were passed a valid frame object, get the
  1702.     -- frame arguments (fargs) and the parent frame arguments (pargs), depending
  1703.     -- on the options set and on the parent frame's availability. If we weren't
  1704.     -- passed a valid frame object, we are being called from another Lua module
  1705.     -- or from the debug console, so assume that we were passed a table of args
  1706.     -- directly, and assign it to a new variable (luaArgs).
  1707.     --]]
  1708.     local fargs, pargs, luaArgs
  1709.     if type(frame.args) == 'table' and type(frame.getParent) == 'function' then
  1710.         if options.wrappers then
  1711.             --[[
  1712.             -- The wrappers option makes Module:Arguments look up arguments in
  1713.             -- either the frame argument table or the parent argument table, but
  1714.             -- not both. This means that users can use either the #invoke syntax
  1715.             -- or a wrapper template without the loss of performance associated
  1716.             -- with looking arguments up in both the frame and the parent frame.
  1717.             -- Module:Arguments will look up arguments in the parent frame
  1718.             -- if it finds the parent frame's title in options.wrapper;
  1719.             -- otherwise it will look up arguments in the frame object passed
  1720.             -- to getArgs.
  1721.             --]]
  1722.             local parent = frame:getParent()
  1723.             if not parent then
  1724.                 fargs = frame.args
  1725.             else
  1726.                 local title = parent:getTitle():gsub('/sandbox$', '')
  1727.                 local found = false
  1728.                 if matchesTitle(options.wrappers, title) then
  1729.                     found = true
  1730.                 elseif type(options.wrappers) == 'table' then
  1731.                     for _,v in pairs(options.wrappers) do
  1732.                         if matchesTitle(v, title) then
  1733.                             found = true
  1734.                             break
  1735.                         end
  1736.                     end
  1737.                 end
  1738.  
  1739.                 -- We test for false specifically here so that nil (the default) acts like true.
  1740.                 if found or options.frameOnly == false then
  1741.                     pargs = parent.args
  1742.                 end
  1743.                 if not found or options.parentOnly == false then
  1744.                     fargs = frame.args
  1745.                 end
  1746.             end
  1747.         else
  1748.             -- options.wrapper isn't set, so check the other options.
  1749.             if not options.parentOnly then
  1750.                 fargs = frame.args
  1751.             end
  1752.             if not options.frameOnly then
  1753.                 local parent = frame:getParent()
  1754.                 pargs = parent and parent.args or nil
  1755.             end
  1756.         end
  1757.         if options.parentFirst then
  1758.             fargs, pargs = pargs, fargs
  1759.         end
  1760.     else
  1761.         luaArgs = frame
  1762.     end
  1763.  
  1764.     -- Set the order of precedence of the argument tables. If the variables are
  1765.     -- nil, nothing will be added to the table, which is how we avoid clashes
  1766.     -- between the frame/parent args and the Lua args.
  1767.     local argTables = {fargs}
  1768.     argTables[#argTables + 1] = pargs
  1769.     argTables[#argTables + 1] = luaArgs
  1770.  
  1771.     --[[
  1772.     -- Generate the tidyVal function. If it has been specified by the user, we
  1773.     -- use that; if not, we choose one of four functions depending on the
  1774.     -- options chosen. This is so that we don't have to call the options table
  1775.     -- every time the function is called.
  1776.     --]]
  1777.     local tidyVal = options.valueFunc
  1778.     if tidyVal then
  1779.         if type(tidyVal) ~= 'function' then
  1780.             error(
  1781.                 "bad value assigned to option 'valueFunc'"
  1782.                     .. '(function expected, got '
  1783.                     .. type(tidyVal)
  1784.                     .. ')',
  1785.                 2
  1786.             )
  1787.         end
  1788.     elseif options.trim ~= false then
  1789.         if options.removeBlanks ~= false then
  1790.             tidyVal = tidyValDefault
  1791.         else
  1792.             tidyVal = tidyValTrimOnly
  1793.         end
  1794.     else
  1795.         if options.removeBlanks ~= false then
  1796.             tidyVal = tidyValRemoveBlanksOnly
  1797.         else
  1798.             tidyVal = tidyValNoChange
  1799.         end
  1800.     end
  1801.  
  1802.     --[[
  1803.     -- Set up the args, metaArgs and nilArgs tables. args will be the one
  1804.     -- accessed from functions, and metaArgs will hold the actual arguments. Nil
  1805.     -- arguments are memoized in nilArgs, and the metatable connects all of them
  1806.     -- together.
  1807.     --]]
  1808.     local args, metaArgs, nilArgs, metatable = {}, {}, {}, {}
  1809.     setmetatable(args, metatable)
  1810.  
  1811.     local function mergeArgs(tables)
  1812.         --[[
  1813.         -- Accepts multiple tables as input and merges their keys and values
  1814.         -- into one table. If a value is already present it is not overwritten;
  1815.         -- tables listed earlier have precedence. We are also memoizing nil
  1816.         -- values, which can be overwritten if they are 's' (soft).
  1817.         --]]
  1818.         for _, t in ipairs(tables) do
  1819.             for key, val in pairs(t) do
  1820.                 if metaArgs[key] == nil and nilArgs[key] ~= 'h' then
  1821.                     local tidiedVal = tidyVal(key, val)
  1822.                     if tidiedVal == nil then
  1823.                         nilArgs[key] = 's'
  1824.                     else
  1825.                         metaArgs[key] = tidiedVal
  1826.                     end
  1827.                 end
  1828.             end
  1829.         end
  1830.     end
  1831.  
  1832.     --[[
  1833.     -- Define metatable behaviour. Arguments are memoized in the metaArgs table,
  1834.     -- and are only fetched from the argument tables once. Fetching arguments
  1835.     -- from the argument tables is the most resource-intensive step in this
  1836.     -- module, so we try and avoid it where possible. For this reason, nil
  1837.     -- arguments are also memoized, in the nilArgs table. Also, we keep a record
  1838.     -- in the metatable of when pairs and ipairs have been called, so we do not
  1839.     -- run pairs and ipairs on the argument tables more than once. We also do
  1840.     -- not run ipairs on fargs and pargs if pairs has already been run, as all
  1841.     -- the arguments will already have been copied over.
  1842.     --]]
  1843.  
  1844.     metatable.__index = function (t, key)
  1845.         --[[
  1846.         -- Fetches an argument when the args table is indexed. First we check
  1847.         -- to see if the value is memoized, and if not we try and fetch it from
  1848.         -- the argument tables. When we check memoization, we need to check
  1849.         -- metaArgs before nilArgs, as both can be non-nil at the same time.
  1850.         -- If the argument is not present in metaArgs, we also check whether
  1851.         -- pairs has been run yet. If pairs has already been run, we return nil.
  1852.         -- This is because all the arguments will have already been copied into
  1853.         -- metaArgs by the mergeArgs function, meaning that any other arguments
  1854.         -- must be nil.
  1855.         --]]
  1856.         if type(key) == 'string' then
  1857.             key = options.translate[key]
  1858.         end
  1859.         local val = metaArgs[key]
  1860.         if val ~= nil then
  1861.             return val
  1862.         elseif metatable.donePairs or nilArgs[key] then
  1863.             return nil
  1864.         end
  1865.         for _, argTable in ipairs(argTables) do
  1866.             local argTableVal = tidyVal(key, argTable[key])
  1867.             if argTableVal ~= nil then
  1868.                 metaArgs[key] = argTableVal
  1869.                 return argTableVal
  1870.             end
  1871.         end
  1872.         nilArgs[key] = 'h'
  1873.         return nil
  1874.     end
  1875.  
  1876.     metatable.__newindex = function (t, key, val)
  1877.         -- This function is called when a module tries to add a new value to the
  1878.         -- args table, or tries to change an existing value.
  1879.         if type(key) == 'string' then
  1880.             key = options.translate[key]
  1881.         end
  1882.         if options.readOnly then
  1883.             error(
  1884.                 'could not write to argument table key "'
  1885.                     .. tostring(key)
  1886.                     .. '"; the table is read-only',
  1887.                 2
  1888.             )
  1889.         elseif options.noOverwrite and args[key] ~= nil then
  1890.             error(
  1891.                 'could not write to argument table key "'
  1892.                     .. tostring(key)
  1893.                     .. '"; overwriting existing arguments is not permitted',
  1894.                 2
  1895.             )
  1896.         elseif val == nil then
  1897.             --[[
  1898.             -- If the argument is to be overwritten with nil, we need to erase
  1899.             -- the value in metaArgs, so that __index, __pairs and __ipairs do
  1900.             -- not use a previous existing value, if present; and we also need
  1901.             -- to memoize the nil in nilArgs, so that the value isn't looked
  1902.             -- up in the argument tables if it is accessed again.
  1903.             --]]
  1904.             metaArgs[key] = nil
  1905.             nilArgs[key] = 'h'
  1906.         else
  1907.             metaArgs[key] = val
  1908.         end
  1909.     end
  1910.  
  1911.     local function translatenext(invariant)
  1912.         local k, v = next(invariant.t, invariant.k)
  1913.         invariant.k = k
  1914.         if k == nil then
  1915.             return nil
  1916.         elseif type(k) ~= 'string' or not options.backtranslate then
  1917.             return k, v
  1918.         else
  1919.             local backtranslate = options.backtranslate[k]
  1920.             if backtranslate == nil then
  1921.                 -- Skip this one. This is a tail call, so this won't cause stack overflow
  1922.                 return translatenext(invariant)
  1923.             else
  1924.                 return backtranslate, v
  1925.             end
  1926.         end
  1927.     end
  1928.  
  1929.     metatable.__pairs = function ()
  1930.         -- Called when pairs is run on the args table.
  1931.         if not metatable.donePairs then
  1932.             mergeArgs(argTables)
  1933.             metatable.donePairs = true
  1934.         end
  1935.         return translatenext, { t = metaArgs }
  1936.     end
  1937.  
  1938.     local function inext(t, i)
  1939.         -- This uses our __index metamethod
  1940.         local v = t[i + 1]
  1941.         if v ~= nil then
  1942.             return i + 1, v
  1943.         end
  1944.     end
  1945.  
  1946.     metatable.__ipairs = function (t)
  1947.         -- Called when ipairs is run on the args table.
  1948.         return inext, t, 0
  1949.     end
  1950.  
  1951.     return args
  1952. end
  1953.  
  1954. return arguments</text>
  1955.       <sha1>5qx9tzlul9ser30uxj9nbasjt92cevn</sha1>
  1956.     </revision>
  1957.   </page>
  1958.   <page>
  1959.     <title>Module:Documentation</title>
  1960.     <ns>828</ns>
  1961.     <id>40256557</id>
  1962.     <revision>
  1963.       <id>1065934020</id>
  1964.       <parentid>1061447122</parentid>
  1965.       <timestamp>2022-01-16T01:32:10Z</timestamp>
  1966.       <contributor>
  1967.         <username>Matt Fitzpatrick</username>
  1968.         <id>291848</id>
  1969.       </contributor>
  1970.       <comment>sync from sandbox, add aria role and label to container</comment>
  1971.       <model>Scribunto</model>
  1972.       <format>text/plain</format>
  1973.       <text bytes="35027" xml:space="preserve">-- This module implements {{documentation}}.
  1974.  
  1975. -- Get required modules.
  1976. local getArgs = require('Module:Arguments').getArgs
  1977.  
  1978. -- Get the config table.
  1979. local cfg = mw.loadData('Module:Documentation/config')
  1980.  
  1981. local p = {}
  1982.  
  1983. -- Often-used functions.
  1984. local ugsub = mw.ustring.gsub
  1985.  
  1986. ----------------------------------------------------------------------------
  1987. -- Helper functions
  1988. --
  1989. -- These are defined as local functions, but are made available in the p
  1990. -- table for testing purposes.
  1991. ----------------------------------------------------------------------------
  1992.  
  1993. local function message(cfgKey, valArray, expectType)
  1994.     --[[
  1995.     -- Gets a message from the cfg table and formats it if appropriate.
  1996.     -- The function raises an error if the value from the cfg table is not
  1997.     -- of the type expectType. The default type for expectType is 'string'.
  1998.     -- If the table valArray is present, strings such as $1, $2 etc. in the
  1999.     -- message are substituted with values from the table keys [1], [2] etc.
  2000.     -- For example, if the message "foo-message" had the value 'Foo $2 bar $1.',
  2001.     -- message('foo-message', {'baz', 'qux'}) would return "Foo qux bar baz."
  2002.     --]]
  2003.     local msg = cfg[cfgKey]
  2004.     expectType = expectType or 'string'
  2005.     if type(msg) ~= expectType then
  2006.         error('message: type error in message cfg.' .. cfgKey .. ' (' .. expectType .. ' expected, got ' .. type(msg) .. ')', 2)
  2007.     end
  2008.     if not valArray then
  2009.         return msg
  2010.     end
  2011.  
  2012.     local function getMessageVal(match)
  2013.         match = tonumber(match)
  2014.         return valArray[match] or error('message: no value found for key $' .. match .. ' in message cfg.' .. cfgKey, 4)
  2015.     end
  2016.  
  2017.     return ugsub(msg, '$([1-9][0-9]*)', getMessageVal)
  2018. end
  2019.  
  2020. p.message = message
  2021.  
  2022. local function makeWikilink(page, display)
  2023.     if display then
  2024.         return mw.ustring.format('[[%s|%s]]', page, display)
  2025.     else
  2026.         return mw.ustring.format('[[%s]]', page)
  2027.     end
  2028. end
  2029.  
  2030. p.makeWikilink = makeWikilink
  2031.  
  2032. local function makeCategoryLink(cat, sort)
  2033.     local catns = mw.site.namespaces[14].name
  2034.     return makeWikilink(catns .. ':' .. cat, sort)
  2035. end
  2036.  
  2037. p.makeCategoryLink = makeCategoryLink
  2038.  
  2039. local function makeUrlLink(url, display)
  2040.     return mw.ustring.format('[%s %s]', url, display)
  2041. end
  2042.  
  2043. p.makeUrlLink = makeUrlLink
  2044.  
  2045. local function makeToolbar(...)
  2046.     local ret = {}
  2047.     local lim = select('#', ...)
  2048.     if lim &lt; 1 then
  2049.         return nil
  2050.     end
  2051.     for i = 1, lim do
  2052.         ret[#ret + 1] = select(i, ...)
  2053.     end
  2054.     -- 'documentation-toolbar'
  2055.     return '&lt;span class="' .. message('toolbar-class') .. '"&gt;('
  2056.         .. table.concat(ret, ' &amp;#124; ') .. ')&lt;/span&gt;'
  2057. end
  2058.  
  2059. p.makeToolbar = makeToolbar
  2060.  
  2061. ----------------------------------------------------------------------------
  2062. -- Argument processing
  2063. ----------------------------------------------------------------------------
  2064.  
  2065. local function makeInvokeFunc(funcName)
  2066.     return function (frame)
  2067.         local args = getArgs(frame, {
  2068.             valueFunc = function (key, value)
  2069.                 if type(value) == 'string' then
  2070.                     value = value:match('^%s*(.-)%s*$') -- Remove whitespace.
  2071.                     if key == 'heading' or value ~= '' then
  2072.                         return value
  2073.                     else
  2074.                         return nil
  2075.                     end
  2076.                 else
  2077.                     return value
  2078.                 end
  2079.             end
  2080.         })
  2081.         return p[funcName](args)
  2082.     end
  2083. end
  2084.  
  2085. ----------------------------------------------------------------------------
  2086. -- Entry points
  2087. ----------------------------------------------------------------------------
  2088.  
  2089. function p.nonexistent(frame)
  2090.     if mw.title.getCurrentTitle().subpageText == 'testcases' then
  2091.         return frame:expandTemplate{title = 'module test cases notice'}
  2092.     else
  2093.         return p.main(frame)
  2094.     end
  2095. end
  2096.  
  2097. p.main = makeInvokeFunc('_main')
  2098.  
  2099. function p._main(args)
  2100.     --[[
  2101.     -- This function defines logic flow for the module.
  2102.     -- @args - table of arguments passed by the user
  2103.     --]]
  2104.     local env = p.getEnvironment(args)
  2105.     local root = mw.html.create()
  2106.     root
  2107.         :wikitext(p._getModuleWikitext(args, env))
  2108.         :wikitext(p.protectionTemplate(env))
  2109.         :wikitext(p.sandboxNotice(args, env))
  2110.         :tag('div')
  2111.             -- 'documentation-container'
  2112.             :addClass(message('container'))
  2113.             :attr('role', 'complementary')
  2114.             :attr('aria-labelledby', args.heading ~= '' and 'documentation-heading' or nil)
  2115.             :attr('aria-label', args.heading == '' and 'Documentation' or nil)
  2116.             :newline()
  2117.             :tag('div')
  2118.                 -- 'documentation'
  2119.                 :addClass(message('main-div-classes'))
  2120.                 :newline()
  2121.                 :wikitext(p._startBox(args, env))
  2122.                 :wikitext(p._content(args, env))
  2123.                 :tag('div')
  2124.                     -- 'documentation-clear'
  2125.                     :addClass(message('clear'))
  2126.                     :done()
  2127.                 :newline()
  2128.                 :done()
  2129.             :wikitext(p._endBox(args, env))
  2130.             :done()
  2131.         :wikitext(p.addTrackingCategories(env))
  2132.     -- 'Module:Documentation/styles.css'
  2133.     return mw.getCurrentFrame():extensionTag (
  2134.         'templatestyles', '', {src=cfg['templatestyles']
  2135.     }) .. tostring(root)
  2136. end
  2137.  
  2138. ----------------------------------------------------------------------------
  2139. -- Environment settings
  2140. ----------------------------------------------------------------------------
  2141.  
  2142. function p.getEnvironment(args)
  2143.     --[[
  2144.     -- Returns a table with information about the environment, including title
  2145.     -- objects and other namespace- or path-related data.
  2146.     -- @args - table of arguments passed by the user
  2147.     --
  2148.     -- Title objects include:
  2149.     -- env.title - the page we are making documentation for (usually the current title)
  2150.     -- env.templateTitle - the template (or module, file, etc.)
  2151.     -- env.docTitle - the /doc subpage.
  2152.     -- env.sandboxTitle - the /sandbox subpage.
  2153.     -- env.testcasesTitle - the /testcases subpage.
  2154.     --
  2155.     -- Data includes:
  2156.     -- env.protectionLevels - the protection levels table of the title object.
  2157.     -- env.subjectSpace - the number of the title's subject namespace.
  2158.     -- env.docSpace - the number of the namespace the title puts its documentation in.
  2159.     -- env.docpageBase - the text of the base page of the /doc, /sandbox and /testcases pages, with namespace.
  2160.     -- env.compareUrl - URL of the Special:ComparePages page comparing the sandbox with the template.
  2161.     --
  2162.     -- All table lookups are passed through pcall so that errors are caught. If an error occurs, the value
  2163.     -- returned will be nil.
  2164.     --]]
  2165.    
  2166.     local env, envFuncs = {}, {}
  2167.  
  2168.     -- Set up the metatable. If triggered we call the corresponding function in the envFuncs table. The value
  2169.     -- returned by that function is memoized in the env table so that we don't call any of the functions
  2170.     -- more than once. (Nils won't be memoized.)
  2171.     setmetatable(env, {
  2172.         __index = function (t, key)
  2173.             local envFunc = envFuncs[key]
  2174.             if envFunc then
  2175.                 local success, val = pcall(envFunc)
  2176.                 if success then
  2177.                     env[key] = val -- Memoise the value.
  2178.                     return val
  2179.                 end
  2180.             end
  2181.             return nil
  2182.         end
  2183.     }) 
  2184.  
  2185.     function envFuncs.title()
  2186.         -- The title object for the current page, or a test page passed with args.page.
  2187.         local title
  2188.         local titleArg = args.page
  2189.         if titleArg then
  2190.             title = mw.title.new(titleArg)
  2191.         else
  2192.             title = mw.title.getCurrentTitle()
  2193.         end
  2194.         return title
  2195.     end
  2196.  
  2197.     function envFuncs.templateTitle()
  2198.         --[[
  2199.         -- The template (or module, etc.) title object.
  2200.         -- Messages:
  2201.         -- 'sandbox-subpage' --&gt; 'sandbox'
  2202.         -- 'testcases-subpage' --&gt; 'testcases'
  2203.         --]]
  2204.         local subjectSpace = env.subjectSpace
  2205.         local title = env.title
  2206.         local subpage = title.subpageText
  2207.         if subpage == message('sandbox-subpage') or subpage == message('testcases-subpage') then
  2208.             return mw.title.makeTitle(subjectSpace, title.baseText)
  2209.         else
  2210.             return mw.title.makeTitle(subjectSpace, title.text)
  2211.         end
  2212.     end
  2213.  
  2214.     function envFuncs.docTitle()
  2215.         --[[
  2216.         -- Title object of the /doc subpage.
  2217.         -- Messages:
  2218.         -- 'doc-subpage' --&gt; 'doc'
  2219.         --]]
  2220.         local title = env.title
  2221.         local docname = args[1] -- User-specified doc page.
  2222.         local docpage
  2223.         if docname then
  2224.             docpage = docname
  2225.         else
  2226.             docpage = env.docpageBase .. '/' .. message('doc-subpage')
  2227.         end
  2228.         return mw.title.new(docpage)
  2229.     end
  2230.    
  2231.     function envFuncs.sandboxTitle()
  2232.         --[[
  2233.         -- Title object for the /sandbox subpage.
  2234.         -- Messages:
  2235.         -- 'sandbox-subpage' --&gt; 'sandbox'
  2236.         --]]
  2237.         return mw.title.new(env.docpageBase .. '/' .. message('sandbox-subpage'))
  2238.     end
  2239.    
  2240.     function envFuncs.testcasesTitle()
  2241.         --[[
  2242.         -- Title object for the /testcases subpage.
  2243.         -- Messages:
  2244.         -- 'testcases-subpage' --&gt; 'testcases'
  2245.         --]]
  2246.         return mw.title.new(env.docpageBase .. '/' .. message('testcases-subpage'))
  2247.     end
  2248.  
  2249.     function envFuncs.protectionLevels()
  2250.         -- The protection levels table of the title object.
  2251.         return env.title.protectionLevels
  2252.     end
  2253.  
  2254.     function envFuncs.subjectSpace()
  2255.         -- The subject namespace number.
  2256.         return mw.site.namespaces[env.title.namespace].subject.id
  2257.     end
  2258.  
  2259.     function envFuncs.docSpace()
  2260.         -- The documentation namespace number. For most namespaces this is the
  2261.         -- same as the subject namespace. However, pages in the Article, File,
  2262.         -- MediaWiki or Category namespaces must have their /doc, /sandbox and
  2263.         -- /testcases pages in talk space.
  2264.         local subjectSpace = env.subjectSpace
  2265.         if subjectSpace == 0 or subjectSpace == 6 or subjectSpace == 8 or subjectSpace == 14 then
  2266.             return subjectSpace + 1
  2267.         else
  2268.             return subjectSpace
  2269.         end
  2270.     end
  2271.  
  2272.     function envFuncs.docpageBase()
  2273.         -- The base page of the /doc, /sandbox, and /testcases subpages.
  2274.         -- For some namespaces this is the talk page, rather than the template page.
  2275.         local templateTitle = env.templateTitle
  2276.         local docSpace = env.docSpace
  2277.         local docSpaceText = mw.site.namespaces[docSpace].name
  2278.         -- Assemble the link. docSpace is never the main namespace, so we can hardcode the colon.
  2279.         return docSpaceText .. ':' .. templateTitle.text
  2280.     end
  2281.    
  2282.     function envFuncs.compareUrl()
  2283.         -- Diff link between the sandbox and the main template using [[Special:ComparePages]].
  2284.         local templateTitle = env.templateTitle
  2285.         local sandboxTitle = env.sandboxTitle
  2286.         if templateTitle.exists and sandboxTitle.exists then
  2287.             local compareUrl = mw.uri.fullUrl(
  2288.                 'Special:ComparePages',
  2289.                 { page1 = templateTitle.prefixedText, page2 = sandboxTitle.prefixedText}
  2290.             )
  2291.             return tostring(compareUrl)
  2292.         else
  2293.             return nil
  2294.         end
  2295.     end    
  2296.  
  2297.     return env
  2298. end
  2299.  
  2300. ----------------------------------------------------------------------------
  2301. -- Auxiliary templates
  2302. ----------------------------------------------------------------------------
  2303.  
  2304. p.getModuleWikitext = makeInvokeFunc('_getModuleWikitext')
  2305.  
  2306. function p._getModuleWikitext(args, env)
  2307.     local currentTitle = mw.title.getCurrentTitle()
  2308.     if currentTitle.contentModel ~= 'Scribunto' then return end
  2309.     pcall(require, currentTitle.prefixedText) -- if it fails, we don't care
  2310.     local moduleWikitext =  package.loaded["Module:Module wikitext"]
  2311.     if moduleWikitext then
  2312.         return moduleWikitext.main()
  2313.     end
  2314. end
  2315.  
  2316. function p.sandboxNotice(args, env)
  2317.     --[=[
  2318.     -- Generates a sandbox notice for display above sandbox pages.
  2319.     -- @args - a table of arguments passed by the user
  2320.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2321.     --
  2322.     -- Messages:
  2323.     -- 'sandbox-notice-image' --&gt; '[[Image:Sandbox.svg|50px|alt=|link=]]'
  2324.     -- 'sandbox-notice-blurb' --&gt; 'This is the $1 for $2.'
  2325.     -- 'sandbox-notice-diff-blurb' --&gt; 'This is the $1 for $2 ($3).'
  2326.     -- 'sandbox-notice-pagetype-template' --&gt; '[[Wikipedia:Template test cases|template sandbox]] page'
  2327.     -- 'sandbox-notice-pagetype-module' --&gt; '[[Wikipedia:Template test cases|module sandbox]] page'
  2328.     -- 'sandbox-notice-pagetype-other' --&gt; 'sandbox page'
  2329.     -- 'sandbox-notice-compare-link-display' --&gt; 'diff'
  2330.     -- 'sandbox-notice-testcases-blurb' --&gt; 'See also the companion subpage for $1.'
  2331.     -- 'sandbox-notice-testcases-link-display' --&gt; 'test cases'
  2332.     -- 'sandbox-category' --&gt; 'Template sandboxes'
  2333.     --]=]
  2334.     local title = env.title
  2335.     local sandboxTitle = env.sandboxTitle
  2336.     local templateTitle = env.templateTitle
  2337.     local subjectSpace = env.subjectSpace
  2338.     if not (subjectSpace and title and sandboxTitle and templateTitle
  2339.         and mw.title.equals(title, sandboxTitle)) then
  2340.         return nil
  2341.     end
  2342.     -- Build the table of arguments to pass to {{ombox}}. We need just two fields, "image" and "text".
  2343.     local omargs = {}
  2344.     omargs.image = message('sandbox-notice-image')
  2345.     -- Get the text. We start with the opening blurb, which is something like
  2346.     -- "This is the template sandbox for [[Template:Foo]] (diff)."
  2347.     local text = ''
  2348.     local pagetype
  2349.     if subjectSpace == 10 then
  2350.         pagetype = message('sandbox-notice-pagetype-template')
  2351.     elseif subjectSpace == 828 then
  2352.         pagetype = message('sandbox-notice-pagetype-module')
  2353.     else
  2354.         pagetype = message('sandbox-notice-pagetype-other')
  2355.     end
  2356.     local templateLink = makeWikilink(templateTitle.prefixedText)
  2357.     local compareUrl = env.compareUrl
  2358.     if compareUrl then
  2359.         local compareDisplay = message('sandbox-notice-compare-link-display')
  2360.         local compareLink = makeUrlLink(compareUrl, compareDisplay)
  2361.         text = text .. message('sandbox-notice-diff-blurb', {pagetype, templateLink, compareLink})
  2362.     else
  2363.         text = text .. message('sandbox-notice-blurb', {pagetype, templateLink})
  2364.     end
  2365.     -- Get the test cases page blurb if the page exists. This is something like
  2366.     -- "See also the companion subpage for [[Template:Foo/testcases|test cases]]."
  2367.     local testcasesTitle = env.testcasesTitle
  2368.     if testcasesTitle and testcasesTitle.exists then
  2369.         if testcasesTitle.contentModel == "Scribunto" then
  2370.             local testcasesLinkDisplay = message('sandbox-notice-testcases-link-display')
  2371.             local testcasesRunLinkDisplay = message('sandbox-notice-testcases-run-link-display')
  2372.             local testcasesLink = makeWikilink(testcasesTitle.prefixedText, testcasesLinkDisplay)
  2373.             local testcasesRunLink = makeWikilink(testcasesTitle.talkPageTitle.prefixedText, testcasesRunLinkDisplay)
  2374.             text = text .. '&lt;br /&gt;' .. message('sandbox-notice-testcases-run-blurb', {testcasesLink, testcasesRunLink})
  2375.         else
  2376.             local testcasesLinkDisplay = message('sandbox-notice-testcases-link-display')
  2377.             local testcasesLink = makeWikilink(testcasesTitle.prefixedText, testcasesLinkDisplay)
  2378.             text = text .. '&lt;br /&gt;' .. message('sandbox-notice-testcases-blurb', {testcasesLink})
  2379.         end
  2380.     end
  2381.     -- Add the sandbox to the sandbox category.
  2382.     omargs.text = text .. makeCategoryLink(message('sandbox-category'))
  2383.  
  2384.     -- 'documentation-clear'
  2385.     return '&lt;div class="' .. message('clear') .. '"&gt;&lt;/div&gt;'
  2386.         .. require('Module:Message box').main('ombox', omargs)
  2387. end
  2388.  
  2389. function p.protectionTemplate(env)
  2390.     -- Generates the padlock icon in the top right.
  2391.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2392.     -- Messages:
  2393.     -- 'protection-template' --&gt; 'pp-template'
  2394.     -- 'protection-template-args' --&gt; {docusage = 'yes'}
  2395.     local protectionLevels = env.protectionLevels
  2396.     if not protectionLevels then
  2397.         return nil
  2398.     end
  2399.     local editProt = protectionLevels.edit and protectionLevels.edit[1]
  2400.     local moveProt = protectionLevels.move and protectionLevels.move[1]
  2401.     if editProt then
  2402.         -- The page is edit-protected.
  2403.         return require('Module:Protection banner')._main{
  2404.             message('protection-reason-edit'), small = true
  2405.         }
  2406.     elseif moveProt and moveProt ~= 'autoconfirmed' then
  2407.         -- The page is move-protected but not edit-protected. Exclude move
  2408.         -- protection with the level "autoconfirmed", as this is equivalent to
  2409.         -- no move protection at all.
  2410.         return require('Module:Protection banner')._main{
  2411.             action = 'move', small = true
  2412.         }
  2413.     else
  2414.         return nil
  2415.     end
  2416. end
  2417.  
  2418. ----------------------------------------------------------------------------
  2419. -- Start box
  2420. ----------------------------------------------------------------------------
  2421.  
  2422. p.startBox = makeInvokeFunc('_startBox')
  2423.  
  2424. function p._startBox(args, env)
  2425.     --[[
  2426.     -- This function generates the start box.
  2427.     -- @args - a table of arguments passed by the user
  2428.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2429.     --
  2430.     -- The actual work is done by p.makeStartBoxLinksData and p.renderStartBoxLinks which make
  2431.     -- the [view] [edit] [history] [purge] links, and by p.makeStartBoxData and p.renderStartBox
  2432.     -- which generate the box HTML.
  2433.     --]]
  2434.     env = env or p.getEnvironment(args)
  2435.     local links
  2436.     local content = args.content
  2437.     if not content or args[1] then
  2438.         -- No need to include the links if the documentation is on the template page itself.
  2439.         local linksData = p.makeStartBoxLinksData(args, env)
  2440.         if linksData then
  2441.             links = p.renderStartBoxLinks(linksData)
  2442.         end
  2443.     end
  2444.     -- Generate the start box html.
  2445.     local data = p.makeStartBoxData(args, env, links)
  2446.     if data then
  2447.         return p.renderStartBox(data)
  2448.     else
  2449.         -- User specified no heading.
  2450.         return nil
  2451.     end
  2452. end
  2453.  
  2454. function p.makeStartBoxLinksData(args, env)
  2455.     --[[
  2456.     -- Does initial processing of data to make the [view] [edit] [history] [purge] links.
  2457.     -- @args - a table of arguments passed by the user
  2458.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2459.     --
  2460.     -- Messages:
  2461.     -- 'view-link-display' --&gt; 'view'
  2462.     -- 'edit-link-display' --&gt; 'edit'
  2463.     -- 'history-link-display' --&gt; 'history'
  2464.     -- 'purge-link-display' --&gt; 'purge'
  2465.     -- 'module-preload' --&gt; 'Template:Documentation/preload-module-doc'
  2466.     -- 'docpage-preload' --&gt; 'Template:Documentation/preload'
  2467.     -- 'create-link-display' --&gt; 'create'
  2468.     --]]
  2469.     local subjectSpace = env.subjectSpace
  2470.     local title = env.title
  2471.     local docTitle = env.docTitle
  2472.     if not title or not docTitle then
  2473.         return nil
  2474.     end
  2475.     if docTitle.isRedirect then
  2476.         docTitle = docTitle.redirectTarget
  2477.     end
  2478.  
  2479.     local data = {}
  2480.     data.title = title
  2481.     data.docTitle = docTitle
  2482.     -- View, display, edit, and purge links if /doc exists.
  2483.     data.viewLinkDisplay = message('view-link-display')
  2484.     data.editLinkDisplay = message('edit-link-display')
  2485.     data.historyLinkDisplay = message('history-link-display')
  2486.     data.purgeLinkDisplay = message('purge-link-display')
  2487.     -- Create link if /doc doesn't exist.
  2488.     local preload = args.preload
  2489.     if not preload then
  2490.         if subjectSpace == 828 then -- Module namespace
  2491.             preload = message('module-preload')
  2492.         else
  2493.             preload = message('docpage-preload')
  2494.         end
  2495.     end
  2496.     data.preload = preload
  2497.     data.createLinkDisplay = message('create-link-display')
  2498.     return data
  2499. end
  2500.  
  2501. function p.renderStartBoxLinks(data)
  2502.     --[[
  2503.     -- Generates the [view][edit][history][purge] or [create][purge] links from the data table.
  2504.     -- @data - a table of data generated by p.makeStartBoxLinksData
  2505.     --]]
  2506.    
  2507.     local function escapeBrackets(s)
  2508.         -- Escapes square brackets with HTML entities.
  2509.         s = s:gsub('%[', '&amp;#91;') -- Replace square brackets with HTML entities.
  2510.         s = s:gsub('%]', '&amp;#93;')
  2511.         return s
  2512.     end
  2513.  
  2514.     local ret
  2515.     local docTitle = data.docTitle
  2516.     local title = data.title
  2517.     local purgeLink = makeUrlLink(title:fullUrl{action = 'purge'}, data.purgeLinkDisplay)
  2518.     if docTitle.exists then
  2519.         local viewLink = makeWikilink(docTitle.prefixedText, data.viewLinkDisplay)
  2520.         local editLink = makeUrlLink(docTitle:fullUrl{action = 'edit'}, data.editLinkDisplay)
  2521.         local historyLink = makeUrlLink(docTitle:fullUrl{action = 'history'}, data.historyLinkDisplay)
  2522.         ret = '[%s] [%s] [%s] [%s]'
  2523.         ret = escapeBrackets(ret)
  2524.         ret = mw.ustring.format(ret, viewLink, editLink, historyLink, purgeLink)
  2525.     else
  2526.         local createLink = makeUrlLink(docTitle:fullUrl{action = 'edit', preload = data.preload}, data.createLinkDisplay)
  2527.         ret = '[%s] [%s]'
  2528.         ret = escapeBrackets(ret)
  2529.         ret = mw.ustring.format(ret, createLink, purgeLink)
  2530.     end
  2531.     return ret
  2532. end
  2533.  
  2534. function p.makeStartBoxData(args, env, links)
  2535.     --[=[
  2536.     -- Does initial processing of data to pass to the start-box render function, p.renderStartBox.
  2537.     -- @args - a table of arguments passed by the user
  2538.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2539.     -- @links - a string containing the [view][edit][history][purge] links - could be nil if there's an error.
  2540.     --
  2541.     -- Messages:
  2542.     -- 'documentation-icon-wikitext' --&gt; '[[File:Test Template Info-Icon - Version (2).svg|50px|link=|alt=]]'
  2543.     -- 'template-namespace-heading' --&gt; 'Template documentation'
  2544.     -- 'module-namespace-heading' --&gt; 'Module documentation'
  2545.     -- 'file-namespace-heading' --&gt; 'Summary'
  2546.     -- 'other-namespaces-heading' --&gt; 'Documentation'
  2547.     -- 'testcases-create-link-display' --&gt; 'create'
  2548.     --]=]
  2549.     local subjectSpace = env.subjectSpace
  2550.     if not subjectSpace then
  2551.         -- Default to an "other namespaces" namespace, so that we get at least some output
  2552.         -- if an error occurs.
  2553.         subjectSpace = 2
  2554.     end
  2555.     local data = {}
  2556.    
  2557.     -- Heading
  2558.     local heading = args.heading -- Blank values are not removed.
  2559.     if heading == '' then
  2560.         -- Don't display the start box if the heading arg is defined but blank.
  2561.         return nil
  2562.     end
  2563.     if heading then
  2564.         data.heading = heading
  2565.     elseif subjectSpace == 10 then -- Template namespace
  2566.         data.heading = message('documentation-icon-wikitext') .. ' ' .. message('template-namespace-heading')
  2567.     elseif subjectSpace == 828 then -- Module namespace
  2568.         data.heading = message('documentation-icon-wikitext') .. ' ' .. message('module-namespace-heading')
  2569.     elseif subjectSpace == 6 then -- File namespace
  2570.         data.heading = message('file-namespace-heading')
  2571.     else
  2572.         data.heading = message('other-namespaces-heading')
  2573.     end
  2574.    
  2575.     -- Heading CSS
  2576.     local headingStyle = args['heading-style']
  2577.     if headingStyle then
  2578.         data.headingStyleText = headingStyle
  2579.     else
  2580.         -- 'documentation-heading'
  2581.         data.headingClass = message('main-div-heading-class')
  2582.     end
  2583.    
  2584.     -- Data for the [view][edit][history][purge] or [create] links.
  2585.     if links then
  2586.         -- 'mw-editsection-like plainlinks'
  2587.         data.linksClass = message('start-box-link-classes')
  2588.         data.links = links
  2589.     end
  2590.    
  2591.     return data
  2592. end
  2593.  
  2594. function p.renderStartBox(data)
  2595.     -- Renders the start box html.
  2596.     -- @data - a table of data generated by p.makeStartBoxData.
  2597.     local sbox = mw.html.create('div')
  2598.     sbox
  2599.         -- 'documentation-startbox'
  2600.         :addClass(message('start-box-class'))
  2601.         :newline()
  2602.         :tag('span')
  2603.             :addClass(data.headingClass)
  2604.             :attr('id', 'documentation-heading')
  2605.             :cssText(data.headingStyleText)
  2606.             :wikitext(data.heading)
  2607.     local links = data.links
  2608.     if links then
  2609.         sbox:tag('span')
  2610.             :addClass(data.linksClass)
  2611.             :attr('id', data.linksId)
  2612.             :wikitext(links)
  2613.     end
  2614.     return tostring(sbox)
  2615. end
  2616.  
  2617. ----------------------------------------------------------------------------
  2618. -- Documentation content
  2619. ----------------------------------------------------------------------------
  2620.  
  2621. p.content = makeInvokeFunc('_content')
  2622.  
  2623. function p._content(args, env)
  2624.     -- Displays the documentation contents
  2625.     -- @args - a table of arguments passed by the user
  2626.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2627.     env = env or p.getEnvironment(args)
  2628.     local docTitle = env.docTitle
  2629.     local content = args.content
  2630.     if not content and docTitle and docTitle.exists then
  2631.         content = args._content or mw.getCurrentFrame():expandTemplate{title = docTitle.prefixedText}
  2632.     end
  2633.     -- The line breaks below are necessary so that "=== Headings ===" at the start and end
  2634.     -- of docs are interpreted correctly.
  2635.     return '\n' .. (content or '') .. '\n'
  2636. end
  2637.  
  2638. p.contentTitle = makeInvokeFunc('_contentTitle')
  2639.  
  2640. function p._contentTitle(args, env)
  2641.     env = env or p.getEnvironment(args)
  2642.     local docTitle = env.docTitle
  2643.     if not args.content and docTitle and docTitle.exists then
  2644.         return docTitle.prefixedText
  2645.     else
  2646.         return ''
  2647.     end
  2648. end
  2649.  
  2650. ----------------------------------------------------------------------------
  2651. -- End box
  2652. ----------------------------------------------------------------------------
  2653.  
  2654. p.endBox = makeInvokeFunc('_endBox')
  2655.  
  2656. function p._endBox(args, env)
  2657.     --[=[
  2658.     -- This function generates the end box (also known as the link box).
  2659.     -- @args - a table of arguments passed by the user
  2660.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2661.     --
  2662.     --]=]
  2663.    
  2664.     -- Get environment data.
  2665.     env = env or p.getEnvironment(args)
  2666.     local subjectSpace = env.subjectSpace
  2667.     local docTitle = env.docTitle
  2668.     if not subjectSpace or not docTitle then
  2669.         return nil
  2670.     end
  2671.        
  2672.     -- Check whether we should output the end box at all. Add the end
  2673.     -- box by default if the documentation exists or if we are in the
  2674.     -- user, module or template namespaces.
  2675.     local linkBox = args['link box']
  2676.     if linkBox == 'off'
  2677.         or not (
  2678.             docTitle.exists
  2679.             or subjectSpace == 2
  2680.             or subjectSpace == 828
  2681.             or subjectSpace == 10
  2682.         )
  2683.     then
  2684.         return nil
  2685.     end
  2686.  
  2687.     -- Assemble the link box.
  2688.     local text = ''
  2689.     if linkBox then
  2690.         text = text .. linkBox
  2691.     else
  2692.         text = text .. (p.makeDocPageBlurb(args, env) or '') -- "This documentation is transcluded from [[Foo]]."
  2693.         if subjectSpace == 2 or subjectSpace == 10 or subjectSpace == 828 then
  2694.             -- We are in the user, template or module namespaces.
  2695.             -- Add sandbox and testcases links.
  2696.             -- "Editors can experiment in this template's sandbox and testcases pages."
  2697.             text = text .. (p.makeExperimentBlurb(args, env) or '') .. '&lt;br /&gt;'
  2698.             if not args.content and not args[1] then
  2699.                 -- "Please add categories to the /doc subpage."
  2700.                 -- Don't show this message with inline docs or with an explicitly specified doc page,
  2701.                 -- as then it is unclear where to add the categories.
  2702.                 text = text .. (p.makeCategoriesBlurb(args, env) or '')
  2703.             end
  2704.             text = text .. ' ' .. (p.makeSubpagesBlurb(args, env) or '') --"Subpages of this template"
  2705.         end
  2706.     end
  2707.    
  2708.     local box = mw.html.create('div')
  2709.     -- 'documentation-metadata'
  2710.     box:attr('role', 'note')
  2711.         :addClass(message('end-box-class'))
  2712.         -- 'plainlinks'
  2713.         :addClass(message('end-box-plainlinks'))
  2714.         :wikitext(text)
  2715.         :done()
  2716.  
  2717.     return '\n' .. tostring(box)
  2718. end
  2719.  
  2720. function p.makeDocPageBlurb(args, env)
  2721.     --[=[
  2722.     -- Makes the blurb "This documentation is transcluded from [[Template:Foo]] (edit, history)".
  2723.     -- @args - a table of arguments passed by the user
  2724.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2725.     --
  2726.     -- Messages:
  2727.     -- 'edit-link-display' --&gt; 'edit'
  2728.     -- 'history-link-display' --&gt; 'history'
  2729.     -- 'transcluded-from-blurb' --&gt;
  2730.     -- 'The above [[Wikipedia:Template documentation|documentation]]
  2731.     -- is [[Help:Transclusion|transcluded]] from $1.'
  2732.     -- 'module-preload' --&gt; 'Template:Documentation/preload-module-doc'
  2733.     -- 'create-link-display' --&gt; 'create'
  2734.     -- 'create-module-doc-blurb' --&gt;
  2735.     -- 'You might want to $1 a documentation page for this [[Wikipedia:Lua|Scribunto module]].'
  2736.     --]=]
  2737.     local docTitle = env.docTitle
  2738.     if not docTitle then
  2739.         return nil
  2740.     end
  2741.     local ret
  2742.     if docTitle.exists then
  2743.         -- /doc exists; link to it.
  2744.         local docLink = makeWikilink(docTitle.prefixedText)
  2745.         local editUrl = docTitle:fullUrl{action = 'edit'}
  2746.         local editDisplay = message('edit-link-display')
  2747.         local editLink = makeUrlLink(editUrl, editDisplay)
  2748.         local historyUrl = docTitle:fullUrl{action = 'history'}
  2749.         local historyDisplay = message('history-link-display')
  2750.         local historyLink = makeUrlLink(historyUrl, historyDisplay)
  2751.         ret = message('transcluded-from-blurb', {docLink})
  2752.             .. ' '
  2753.             .. makeToolbar(editLink, historyLink)
  2754.             .. '&lt;br /&gt;'
  2755.     elseif env.subjectSpace == 828 then
  2756.         -- /doc does not exist; ask to create it.
  2757.         local createUrl = docTitle:fullUrl{action = 'edit', preload = message('module-preload')}
  2758.         local createDisplay = message('create-link-display')
  2759.         local createLink = makeUrlLink(createUrl, createDisplay)
  2760.         ret = message('create-module-doc-blurb', {createLink})
  2761.             .. '&lt;br /&gt;'
  2762.     end
  2763.     return ret
  2764. end
  2765.  
  2766. function p.makeExperimentBlurb(args, env)
  2767.     --[[
  2768.     -- Renders the text "Editors can experiment in this template's sandbox (edit | diff) and testcases (edit) pages."
  2769.     -- @args - a table of arguments passed by the user
  2770.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2771.     --
  2772.     -- Messages:
  2773.     -- 'sandbox-link-display' --&gt; 'sandbox'
  2774.     -- 'sandbox-edit-link-display' --&gt; 'edit'
  2775.     -- 'compare-link-display' --&gt; 'diff'
  2776.     -- 'module-sandbox-preload' --&gt; 'Template:Documentation/preload-module-sandbox'
  2777.     -- 'template-sandbox-preload' --&gt; 'Template:Documentation/preload-sandbox'
  2778.     -- 'sandbox-create-link-display' --&gt; 'create'
  2779.     -- 'mirror-edit-summary' --&gt; 'Create sandbox version of $1'
  2780.     -- 'mirror-link-display' --&gt; 'mirror'
  2781.     -- 'mirror-link-preload' --&gt; 'Template:Documentation/mirror'
  2782.     -- 'sandbox-link-display' --&gt; 'sandbox'
  2783.     -- 'testcases-link-display' --&gt; 'testcases'
  2784.     -- 'testcases-edit-link-display'--&gt; 'edit'
  2785.     -- 'template-sandbox-preload' --&gt; 'Template:Documentation/preload-sandbox'
  2786.     -- 'testcases-create-link-display' --&gt; 'create'
  2787.     -- 'testcases-link-display' --&gt; 'testcases'
  2788.     -- 'testcases-edit-link-display' --&gt; 'edit'
  2789.     -- 'module-testcases-preload' --&gt; 'Template:Documentation/preload-module-testcases'
  2790.     -- 'template-testcases-preload' --&gt; 'Template:Documentation/preload-testcases'
  2791.     -- 'experiment-blurb-module' --&gt; 'Editors can experiment in this module's $1 and $2 pages.'
  2792.     -- 'experiment-blurb-template' --&gt; 'Editors can experiment in this template's $1 and $2 pages.'
  2793.     --]]
  2794.     local subjectSpace = env.subjectSpace
  2795.     local templateTitle = env.templateTitle
  2796.     local sandboxTitle = env.sandboxTitle
  2797.     local testcasesTitle = env.testcasesTitle
  2798.     local templatePage = templateTitle.prefixedText
  2799.     if not subjectSpace or not templateTitle or not sandboxTitle or not testcasesTitle then
  2800.         return nil
  2801.     end
  2802.     -- Make links.
  2803.     local sandboxLinks, testcasesLinks
  2804.     if sandboxTitle.exists then
  2805.         local sandboxPage = sandboxTitle.prefixedText
  2806.         local sandboxDisplay = message('sandbox-link-display')
  2807.         local sandboxLink = makeWikilink(sandboxPage, sandboxDisplay)
  2808.         local sandboxEditUrl = sandboxTitle:fullUrl{action = 'edit'}
  2809.         local sandboxEditDisplay = message('sandbox-edit-link-display')
  2810.         local sandboxEditLink = makeUrlLink(sandboxEditUrl, sandboxEditDisplay)
  2811.         local compareUrl = env.compareUrl
  2812.         local compareLink
  2813.         if compareUrl then
  2814.             local compareDisplay = message('compare-link-display')
  2815.             compareLink = makeUrlLink(compareUrl, compareDisplay)
  2816.         end
  2817.         sandboxLinks = sandboxLink .. ' ' .. makeToolbar(sandboxEditLink, compareLink)
  2818.     else
  2819.         local sandboxPreload
  2820.         if subjectSpace == 828 then
  2821.             sandboxPreload = message('module-sandbox-preload')
  2822.         else
  2823.             sandboxPreload = message('template-sandbox-preload')
  2824.         end
  2825.         local sandboxCreateUrl = sandboxTitle:fullUrl{action = 'edit', preload = sandboxPreload}
  2826.         local sandboxCreateDisplay = message('sandbox-create-link-display')
  2827.         local sandboxCreateLink = makeUrlLink(sandboxCreateUrl, sandboxCreateDisplay)
  2828.         local mirrorSummary = message('mirror-edit-summary', {makeWikilink(templatePage)})
  2829.         local mirrorPreload = message('mirror-link-preload')
  2830.         local mirrorUrl = sandboxTitle:fullUrl{action = 'edit', preload = mirrorPreload, summary = mirrorSummary}
  2831.         if subjectSpace == 828 then
  2832.             mirrorUrl = sandboxTitle:fullUrl{action = 'edit', preload = templateTitle.prefixedText, summary = mirrorSummary}
  2833.         end
  2834.         local mirrorDisplay = message('mirror-link-display')
  2835.         local mirrorLink = makeUrlLink(mirrorUrl, mirrorDisplay)
  2836.         sandboxLinks = message('sandbox-link-display') .. ' ' .. makeToolbar(sandboxCreateLink, mirrorLink)
  2837.     end
  2838.     if testcasesTitle.exists then
  2839.         local testcasesPage = testcasesTitle.prefixedText
  2840.         local testcasesDisplay = message('testcases-link-display')
  2841.         local testcasesLink = makeWikilink(testcasesPage, testcasesDisplay)
  2842.         local testcasesEditUrl = testcasesTitle:fullUrl{action = 'edit'}
  2843.         local testcasesEditDisplay = message('testcases-edit-link-display')
  2844.         local testcasesEditLink = makeUrlLink(testcasesEditUrl, testcasesEditDisplay)
  2845.         -- for Modules, add testcases run link if exists
  2846.         if testcasesTitle.contentModel == "Scribunto"  and testcasesTitle.talkPageTitle and testcasesTitle.talkPageTitle.exists then
  2847.             local testcasesRunLinkDisplay = message('testcases-run-link-display')
  2848.             local testcasesRunLink = makeWikilink(testcasesTitle.talkPageTitle.prefixedText, testcasesRunLinkDisplay)
  2849.             testcasesLinks = testcasesLink .. ' ' .. makeToolbar(testcasesEditLink, testcasesRunLink)
  2850.         else
  2851.             testcasesLinks = testcasesLink .. ' ' .. makeToolbar(testcasesEditLink)
  2852.         end
  2853.     else
  2854.         local testcasesPreload
  2855.         if subjectSpace == 828 then
  2856.             testcasesPreload = message('module-testcases-preload')
  2857.         else
  2858.             testcasesPreload = message('template-testcases-preload')
  2859.         end
  2860.         local testcasesCreateUrl = testcasesTitle:fullUrl{action = 'edit', preload = testcasesPreload}
  2861.         local testcasesCreateDisplay = message('testcases-create-link-display')
  2862.         local testcasesCreateLink = makeUrlLink(testcasesCreateUrl, testcasesCreateDisplay)
  2863.         testcasesLinks = message('testcases-link-display') .. ' ' .. makeToolbar(testcasesCreateLink)
  2864.     end
  2865.     local messageName
  2866.     if subjectSpace == 828 then
  2867.         messageName = 'experiment-blurb-module'
  2868.     else
  2869.         messageName = 'experiment-blurb-template'
  2870.     end
  2871.     return message(messageName, {sandboxLinks, testcasesLinks})
  2872. end
  2873.  
  2874. function p.makeCategoriesBlurb(args, env)
  2875.     --[[
  2876.     -- Generates the text "Please add categories to the /doc subpage."
  2877.     -- @args - a table of arguments passed by the user
  2878.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2879.     -- Messages:
  2880.     -- 'doc-link-display' --&gt; '/doc'
  2881.     -- 'add-categories-blurb' --&gt; 'Please add categories to the $1 subpage.'
  2882.     --]]
  2883.     local docTitle = env.docTitle
  2884.     if not docTitle then
  2885.         return nil
  2886.     end
  2887.     local docPathLink = makeWikilink(docTitle.prefixedText, message('doc-link-display'))
  2888.     return message('add-categories-blurb', {docPathLink})
  2889. end
  2890.  
  2891. function p.makeSubpagesBlurb(args, env)
  2892.     --[[
  2893.     -- Generates the "Subpages of this template" link.
  2894.     -- @args - a table of arguments passed by the user
  2895.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2896.    
  2897.     -- Messages:
  2898.     -- 'template-pagetype' --&gt; 'template'
  2899.     -- 'module-pagetype' --&gt; 'module'
  2900.     -- 'default-pagetype' --&gt; 'page'
  2901.     -- 'subpages-link-display' --&gt; 'Subpages of this $1'
  2902.     --]]
  2903.     local subjectSpace = env.subjectSpace
  2904.     local templateTitle = env.templateTitle
  2905.     if not subjectSpace or not templateTitle then
  2906.         return nil
  2907.     end
  2908.     local pagetype
  2909.     if subjectSpace == 10 then
  2910.         pagetype = message('template-pagetype')
  2911.     elseif subjectSpace == 828 then
  2912.         pagetype = message('module-pagetype')
  2913.     else
  2914.         pagetype = message('default-pagetype')
  2915.     end
  2916.     local subpagesLink = makeWikilink(
  2917.         'Special:PrefixIndex/' .. templateTitle.prefixedText .. '/',
  2918.         message('subpages-link-display', {pagetype})
  2919.     )
  2920.     return message('subpages-blurb', {subpagesLink})
  2921. end
  2922.  
  2923. ----------------------------------------------------------------------------
  2924. -- Tracking categories
  2925. ----------------------------------------------------------------------------
  2926.  
  2927. function p.addTrackingCategories(env)
  2928.     --[[
  2929.     -- Check if {{documentation}} is transcluded on a /doc or /testcases page.
  2930.     -- @env - environment table containing title objects, etc., generated with p.getEnvironment
  2931.    
  2932.     -- Messages:
  2933.     -- 'display-strange-usage-category' --&gt; true
  2934.     -- 'doc-subpage' --&gt; 'doc'
  2935.     -- 'testcases-subpage' --&gt; 'testcases'
  2936.     -- 'strange-usage-category' --&gt; 'Wikipedia pages with strange ((documentation)) usage'
  2937.     --
  2938.     -- /testcases pages in the module namespace are not categorised, as they may have
  2939.     -- {{documentation}} transcluded automatically.
  2940.     --]]
  2941.     local title = env.title
  2942.     local subjectSpace = env.subjectSpace
  2943.     if not title or not subjectSpace then
  2944.         return nil
  2945.     end
  2946.     local subpage = title.subpageText
  2947.     local ret = ''
  2948.     if message('display-strange-usage-category', nil, 'boolean')
  2949.         and (
  2950.             subpage == message('doc-subpage')
  2951.             or subjectSpace ~= 828 and subpage == message('testcases-subpage')
  2952.         )
  2953.     then
  2954.         ret = ret .. makeCategoryLink(message('strange-usage-category'))
  2955.     end
  2956.     return ret
  2957. end
  2958.  
  2959. return p</text>
  2960.       <sha1>hhe6rl9gdvqywjk6r1tbi4ymwotbf24</sha1>
  2961.     </revision>
  2962.   </page>
  2963.   <page>
  2964.     <title>Module:Documentation/config</title>
  2965.     <ns>828</ns>
  2966.     <id>41520829</id>
  2967.     <revision>
  2968.       <id>1067946425</id>
  2969.       <parentid>1061447213</parentid>
  2970.       <timestamp>2022-01-25T23:46:11Z</timestamp>
  2971.       <contributor>
  2972.         <username>Ianblair23</username>
  2973.         <id>145927</id>
  2974.       </contributor>
  2975.       <comment>link</comment>
  2976.       <model>Scribunto</model>
  2977.       <format>text/plain</format>
  2978.       <text bytes="17433" xml:space="preserve">----------------------------------------------------------------------------------------------------
  2979. --
  2980. --                               Configuration for Module:Documentation
  2981. --
  2982. -- Here you can set the values of the parameters and messages used in Module:Documentation to
  2983. -- localise it to your wiki and your language. Unless specified otherwise, values given here
  2984. -- should be string values.
  2985. ----------------------------------------------------------------------------------------------------
  2986.  
  2987. local cfg = {} -- Do not edit this line.
  2988.  
  2989. ----------------------------------------------------------------------------------------------------
  2990. -- Protection template configuration
  2991. ----------------------------------------------------------------------------------------------------
  2992.  
  2993. -- cfg['protection-reason-edit']
  2994. -- The protection reason for edit-protected templates to pass to
  2995. -- [[Module:Protection banner]].
  2996. cfg['protection-reason-edit'] = 'template'
  2997.  
  2998. --[[
  2999. ----------------------------------------------------------------------------------------------------
  3000. -- Sandbox notice configuration
  3001. --
  3002. -- On sandbox pages the module can display a template notifying users that the current page is a
  3003. -- sandbox, and the location of test cases pages, etc. The module decides whether the page is a
  3004. -- sandbox or not based on the value of cfg['sandbox-subpage']. The following settings configure the
  3005. -- messages that the notices contains.
  3006. ----------------------------------------------------------------------------------------------------
  3007. --]]
  3008.  
  3009. -- cfg['sandbox-notice-image']
  3010. -- The image displayed in the sandbox notice.
  3011. cfg['sandbox-notice-image'] = '[[File:Sandbox.svg|50px|alt=|link=]]'
  3012.  
  3013. --[[
  3014. -- cfg['sandbox-notice-pagetype-template']
  3015. -- cfg['sandbox-notice-pagetype-module']
  3016. -- cfg['sandbox-notice-pagetype-other']
  3017. -- The page type of the sandbox page. The message that is displayed depends on the current subject
  3018. -- namespace. This message is used in either cfg['sandbox-notice-blurb'] or
  3019. -- cfg['sandbox-notice-diff-blurb'].
  3020. --]]
  3021. cfg['sandbox-notice-pagetype-template'] = '[[Wikipedia:Template test cases|template sandbox]] page'
  3022. cfg['sandbox-notice-pagetype-module'] = '[[Wikipedia:Template test cases|module sandbox]] page'
  3023. cfg['sandbox-notice-pagetype-other'] = 'sandbox page'
  3024.  
  3025. --[[
  3026. -- cfg['sandbox-notice-blurb']
  3027. -- cfg['sandbox-notice-diff-blurb']
  3028. -- cfg['sandbox-notice-diff-display']
  3029. -- Either cfg['sandbox-notice-blurb'] or cfg['sandbox-notice-diff-blurb'] is the opening sentence
  3030. -- of the sandbox notice. The latter has a diff link, but the former does not. $1 is the page
  3031. -- type, which is either cfg['sandbox-notice-pagetype-template'],
  3032. -- cfg['sandbox-notice-pagetype-module'] or cfg['sandbox-notice-pagetype-other'] depending what
  3033. -- namespace we are in. $2 is a link to the main template page, and $3 is a diff link between
  3034. -- the sandbox and the main template. The display value of the diff link is set by
  3035. -- cfg['sandbox-notice-compare-link-display'].
  3036. --]]
  3037. cfg['sandbox-notice-blurb'] = 'This is the $1 for $2.'
  3038. cfg['sandbox-notice-diff-blurb'] = 'This is the $1 for $2 ($3).'
  3039. cfg['sandbox-notice-compare-link-display'] = 'diff'
  3040.  
  3041. --[[
  3042. -- cfg['sandbox-notice-testcases-blurb']
  3043. -- cfg['sandbox-notice-testcases-link-display']
  3044. -- cfg['sandbox-notice-testcases-run-blurb']
  3045. -- cfg['sandbox-notice-testcases-run-link-display']
  3046. -- cfg['sandbox-notice-testcases-blurb'] is a sentence notifying the user that there is a test cases page
  3047. -- corresponding to this sandbox that they can edit. $1 is a link to the test cases page.
  3048. -- cfg['sandbox-notice-testcases-link-display'] is the display value for that link.
  3049. -- cfg['sandbox-notice-testcases-run-blurb'] is a sentence notifying the user that there is a test cases page
  3050. -- corresponding to this sandbox that they can edit, along with a link to run it. $1 is a link to the test
  3051. -- cases page, and $2 is a link to the page to run it.
  3052. -- cfg['sandbox-notice-testcases-run-link-display'] is the display value for the link to run the test
  3053. -- cases.
  3054. --]]
  3055. cfg['sandbox-notice-testcases-blurb'] = 'See also the companion subpage for $1.'
  3056. cfg['sandbox-notice-testcases-link-display'] = 'test cases'
  3057. cfg['sandbox-notice-testcases-run-blurb'] = 'See also the companion subpage for $1 ($2).'
  3058. cfg['sandbox-notice-testcases-run-link-display'] = 'run'
  3059.  
  3060. -- cfg['sandbox-category']
  3061. -- A category to add to all template sandboxes.
  3062. cfg['sandbox-category'] = 'Template sandboxes'
  3063.  
  3064. ----------------------------------------------------------------------------------------------------
  3065. -- Start box configuration
  3066. ----------------------------------------------------------------------------------------------------
  3067.  
  3068. -- cfg['documentation-icon-wikitext']
  3069. -- The wikitext for the icon shown at the top of the template.
  3070. cfg['documentation-icon-wikitext'] = '[[File:Test Template Info-Icon - Version (2).svg|50px|link=|alt=]]'
  3071.  
  3072. -- cfg['template-namespace-heading']
  3073. -- The heading shown in the template namespace.
  3074. cfg['template-namespace-heading'] = 'Template documentation'
  3075.  
  3076. -- cfg['module-namespace-heading']
  3077. -- The heading shown in the module namespace.
  3078. cfg['module-namespace-heading'] = 'Module documentation'
  3079.  
  3080. -- cfg['file-namespace-heading']
  3081. -- The heading shown in the file namespace.
  3082. cfg['file-namespace-heading'] = 'Summary'
  3083.  
  3084. -- cfg['other-namespaces-heading']
  3085. -- The heading shown in other namespaces.
  3086. cfg['other-namespaces-heading'] = 'Documentation'
  3087.  
  3088. -- cfg['view-link-display']
  3089. -- The text to display for "view" links.
  3090. cfg['view-link-display'] = 'view'
  3091.  
  3092. -- cfg['edit-link-display']
  3093. -- The text to display for "edit" links.
  3094. cfg['edit-link-display'] = 'edit'
  3095.  
  3096. -- cfg['history-link-display']
  3097. -- The text to display for "history" links.
  3098. cfg['history-link-display'] = 'history'
  3099.  
  3100. -- cfg['purge-link-display']
  3101. -- The text to display for "purge" links.
  3102. cfg['purge-link-display'] = 'purge'
  3103.  
  3104. -- cfg['create-link-display']
  3105. -- The text to display for "create" links.
  3106. cfg['create-link-display'] = 'create'
  3107.  
  3108. ----------------------------------------------------------------------------------------------------
  3109. -- Link box (end box) configuration
  3110. ----------------------------------------------------------------------------------------------------
  3111.  
  3112. -- cfg['transcluded-from-blurb']
  3113. -- Notice displayed when the docs are transcluded from another page. $1 is a wikilink to that page.
  3114. cfg['transcluded-from-blurb'] = 'The above [[Wikipedia:Template documentation|documentation]] is [[Help:Transclusion|transcluded]] from $1.'
  3115.  
  3116. --[[
  3117. -- cfg['create-module-doc-blurb']
  3118. -- Notice displayed in the module namespace when the documentation subpage does not exist.
  3119. -- $1 is a link to create the documentation page with the preload cfg['module-preload'] and the
  3120. -- display cfg['create-link-display'].
  3121. --]]
  3122. cfg['create-module-doc-blurb'] = 'You might want to $1 a documentation page for this [[Wikipedia:Lua|Scribunto module]].'
  3123.  
  3124. ----------------------------------------------------------------------------------------------------
  3125. -- Experiment blurb configuration
  3126. ----------------------------------------------------------------------------------------------------
  3127.  
  3128. --[[
  3129. -- cfg['experiment-blurb-template']
  3130. -- cfg['experiment-blurb-module']
  3131. -- The experiment blurb is the text inviting editors to experiment in sandbox and test cases pages.
  3132. -- It is only shown in the template and module namespaces. With the default English settings, it
  3133. -- might look like this:
  3134. --
  3135. -- Editors can experiment in this template's sandbox (edit | diff) and testcases (edit) pages.
  3136. --
  3137. -- In this example, "sandbox", "edit", "diff", "testcases", and "edit" would all be links.
  3138. --
  3139. -- There are two versions, cfg['experiment-blurb-template'] and cfg['experiment-blurb-module'], depending
  3140. -- on what namespace we are in.
  3141. --
  3142. -- Parameters:
  3143. --
  3144. -- $1 is a link to the sandbox page. If the sandbox exists, it is in the following format:
  3145. --
  3146. --     cfg['sandbox-link-display'] (cfg['sandbox-edit-link-display'] | cfg['compare-link-display'])
  3147. --
  3148. -- If the sandbox doesn't exist, it is in the format:
  3149. --
  3150. --     cfg['sandbox-link-display'] (cfg['sandbox-create-link-display'] | cfg['mirror-link-display'])
  3151. --
  3152. -- The link for cfg['sandbox-create-link-display'] link preloads the page with cfg['template-sandbox-preload']
  3153. -- or cfg['module-sandbox-preload'], depending on the current namespace. The link for cfg['mirror-link-display']
  3154. -- loads a default edit summary of cfg['mirror-edit-summary'].
  3155. --
  3156. -- $2 is a link to the test cases page. If the test cases page exists, it is in the following format:
  3157. --
  3158. --     cfg['testcases-link-display'] (cfg['testcases-edit-link-display'] | cfg['testcases-run-link-display'])
  3159. --
  3160. -- If the test cases page doesn't exist, it is in the format:
  3161. --
  3162. --     cfg['testcases-link-display'] (cfg['testcases-create-link-display'])
  3163. --
  3164. -- If the test cases page doesn't exist, the link for cfg['testcases-create-link-display'] preloads the
  3165. -- page with cfg['template-testcases-preload'] or cfg['module-testcases-preload'], depending on the current
  3166. -- namespace.
  3167. --]]
  3168. cfg['experiment-blurb-template'] = "Editors can experiment in this template's $1 and $2 pages."
  3169. cfg['experiment-blurb-module'] = "Editors can experiment in this module's $1 and $2 pages."
  3170.  
  3171. ----------------------------------------------------------------------------------------------------
  3172. -- Sandbox link configuration
  3173. ----------------------------------------------------------------------------------------------------
  3174.  
  3175. -- cfg['sandbox-subpage']
  3176. -- The name of the template subpage typically used for sandboxes.
  3177. cfg['sandbox-subpage'] = 'sandbox'
  3178.  
  3179. -- cfg['template-sandbox-preload']
  3180. -- Preload file for template sandbox pages.
  3181. cfg['template-sandbox-preload'] = 'Template:Documentation/preload-sandbox'
  3182.  
  3183. -- cfg['module-sandbox-preload']
  3184. -- Preload file for Lua module sandbox pages.
  3185. cfg['module-sandbox-preload'] = 'Template:Documentation/preload-module-sandbox'
  3186.  
  3187. -- cfg['sandbox-link-display']
  3188. -- The text to display for "sandbox" links.
  3189. cfg['sandbox-link-display'] = 'sandbox'
  3190.  
  3191. -- cfg['sandbox-edit-link-display']
  3192. -- The text to display for sandbox "edit" links.
  3193. cfg['sandbox-edit-link-display'] = 'edit'
  3194.  
  3195. -- cfg['sandbox-create-link-display']
  3196. -- The text to display for sandbox "create" links.
  3197. cfg['sandbox-create-link-display'] = 'create'
  3198.  
  3199. -- cfg['compare-link-display']
  3200. -- The text to display for "compare" links.
  3201. cfg['compare-link-display'] = 'diff'
  3202.  
  3203. -- cfg['mirror-edit-summary']
  3204. -- The default edit summary to use when a user clicks the "mirror" link. $1 is a wikilink to the
  3205. -- template page.
  3206. cfg['mirror-edit-summary'] = 'Create sandbox version of $1'
  3207.  
  3208. -- cfg['mirror-link-display']
  3209. -- The text to display for "mirror" links.
  3210. cfg['mirror-link-display'] = 'mirror'
  3211.  
  3212. -- cfg['mirror-link-preload']
  3213. -- The page to preload when a user clicks the "mirror" link.
  3214. cfg['mirror-link-preload'] = 'Template:Documentation/mirror'
  3215.  
  3216. ----------------------------------------------------------------------------------------------------
  3217. -- Test cases link configuration
  3218. ----------------------------------------------------------------------------------------------------
  3219.  
  3220. -- cfg['testcases-subpage']
  3221. -- The name of the template subpage typically used for test cases.
  3222. cfg['testcases-subpage'] = 'testcases'
  3223.  
  3224. -- cfg['template-testcases-preload']
  3225. -- Preload file for template test cases pages.
  3226. cfg['template-testcases-preload'] = 'Template:Documentation/preload-testcases'
  3227.  
  3228. -- cfg['module-testcases-preload']
  3229. -- Preload file for Lua module test cases pages.
  3230. cfg['module-testcases-preload'] = 'Template:Documentation/preload-module-testcases'
  3231.  
  3232. -- cfg['testcases-link-display']
  3233. -- The text to display for "testcases" links.
  3234. cfg['testcases-link-display'] = 'testcases'
  3235.  
  3236. -- cfg['testcases-edit-link-display']
  3237. -- The text to display for test cases "edit" links.
  3238. cfg['testcases-edit-link-display'] = 'edit'
  3239.  
  3240. -- cfg['testcases-run-link-display']
  3241. -- The text to display for test cases "run" links.
  3242. cfg['testcases-run-link-display'] = 'run'
  3243.  
  3244. -- cfg['testcases-create-link-display']
  3245. -- The text to display for test cases "create" links.
  3246. cfg['testcases-create-link-display'] = 'create'
  3247.  
  3248. ----------------------------------------------------------------------------------------------------
  3249. -- Add categories blurb configuration
  3250. ----------------------------------------------------------------------------------------------------
  3251.  
  3252. --[[
  3253. -- cfg['add-categories-blurb']
  3254. -- Text to direct users to add categories to the /doc subpage. Not used if the "content" or
  3255. -- "docname fed" arguments are set, as then it is not clear where to add the categories. $1 is a
  3256. -- link to the /doc subpage with a display value of cfg['doc-link-display'].
  3257. --]]
  3258. cfg['add-categories-blurb'] = 'Add categories to the $1 subpage.'
  3259.  
  3260. -- cfg['doc-link-display']
  3261. -- The text to display when linking to the /doc subpage.
  3262. cfg['doc-link-display'] = '/doc'
  3263.  
  3264. ----------------------------------------------------------------------------------------------------
  3265. -- Subpages link configuration
  3266. ----------------------------------------------------------------------------------------------------
  3267.  
  3268. --[[
  3269. -- cfg['subpages-blurb']
  3270. -- The "Subpages of this template" blurb. $1 is a link to the main template's subpages with a
  3271. -- display value of cfg['subpages-link-display']. In the English version this blurb is simply
  3272. -- the link followed by a period, and the link display provides the actual text.
  3273. --]]
  3274. cfg['subpages-blurb'] = '$1.'
  3275.  
  3276. --[[
  3277. -- cfg['subpages-link-display']
  3278. -- The text to display for the "subpages of this page" link. $1 is cfg['template-pagetype'],
  3279. -- cfg['module-pagetype'] or cfg['default-pagetype'], depending on whether the current page is in
  3280. -- the template namespace, the module namespace, or another namespace.
  3281. --]]
  3282. cfg['subpages-link-display'] = 'Subpages of this $1'
  3283.  
  3284. -- cfg['template-pagetype']
  3285. -- The pagetype to display for template pages.
  3286. cfg['template-pagetype'] = 'template'
  3287.  
  3288. -- cfg['module-pagetype']
  3289. -- The pagetype to display for Lua module pages.
  3290. cfg['module-pagetype'] = 'module'
  3291.  
  3292. -- cfg['default-pagetype']
  3293. -- The pagetype to display for pages other than templates or Lua modules.
  3294. cfg['default-pagetype'] = 'page'
  3295.  
  3296. ----------------------------------------------------------------------------------------------------
  3297. -- Doc link configuration
  3298. ----------------------------------------------------------------------------------------------------
  3299.  
  3300. -- cfg['doc-subpage']
  3301. -- The name of the subpage typically used for documentation pages.
  3302. cfg['doc-subpage'] = 'doc'
  3303.  
  3304. -- cfg['docpage-preload']
  3305. -- Preload file for template documentation pages in all namespaces.
  3306. cfg['docpage-preload'] = 'Template:Documentation/preload'
  3307.  
  3308. -- cfg['module-preload']
  3309. -- Preload file for Lua module documentation pages.
  3310. cfg['module-preload'] = 'Template:Documentation/preload-module-doc'
  3311.  
  3312. ----------------------------------------------------------------------------------------------------
  3313. -- HTML and CSS configuration
  3314. ----------------------------------------------------------------------------------------------------
  3315.  
  3316. -- cfg['templatestyles']
  3317. -- The name of the TemplateStyles page where CSS is kept.
  3318. -- Sandbox CSS will be at Module:Documentation/sandbox/styles.css when needed.
  3319. cfg['templatestyles'] = 'Module:Documentation/styles.css'
  3320.  
  3321. -- cfg['container']
  3322. -- Class which can be used to set flex or grid CSS on the
  3323. -- two child divs documentation and documentation-metadata
  3324. cfg['container'] = 'documentation-container'
  3325.  
  3326. -- cfg['main-div-classes']
  3327. -- Classes added to the main HTML "div" tag.
  3328. cfg['main-div-classes'] = 'documentation'
  3329.  
  3330. -- cfg['main-div-heading-class']
  3331. -- Class for the main heading for templates and modules and assoc. talk spaces
  3332. cfg['main-div-heading-class'] = 'documentation-heading'
  3333.  
  3334. -- cfg['start-box-class']
  3335. -- Class for the start box
  3336. cfg['start-box-class'] = 'documentation-startbox'
  3337.  
  3338. -- cfg['start-box-link-classes']
  3339. -- Classes used for the [view][edit][history] or [create] links in the start box.
  3340. -- mw-editsection-like is per [[Wikipedia:Village pump (technical)/Archive 117]]
  3341. cfg['start-box-link-classes'] = 'mw-editsection-like plainlinks'
  3342.  
  3343. -- cfg['end-box-class']
  3344. -- Class for the end box.
  3345. cfg['end-box-class'] = 'documentation-metadata'
  3346.  
  3347. -- cfg['end-box-plainlinks']
  3348. -- Plainlinks
  3349. cfg['end-box-plainlinks'] = 'plainlinks'
  3350.  
  3351. -- cfg['toolbar-class']
  3352. -- Class added for toolbar links.
  3353. cfg['toolbar-class'] = 'documentation-toolbar'
  3354.  
  3355. -- cfg['clear']
  3356. -- Just used to clear things.
  3357. cfg['clear'] = 'documentation-clear'
  3358.  
  3359.  
  3360. ----------------------------------------------------------------------------------------------------
  3361. -- Tracking category configuration
  3362. ----------------------------------------------------------------------------------------------------
  3363.  
  3364. -- cfg['display-strange-usage-category']
  3365. -- Set to true to enable output of cfg['strange-usage-category'] if the module is used on a /doc subpage
  3366. -- or a /testcases subpage. This should be a boolean value (either true or false).
  3367. cfg['display-strange-usage-category'] = true
  3368.  
  3369. -- cfg['strange-usage-category']
  3370. -- Category to output if cfg['display-strange-usage-category'] is set to true and the module is used on a
  3371. -- /doc subpage or a /testcases subpage.
  3372. cfg['strange-usage-category'] = 'Wikipedia pages with strange ((documentation)) usage'
  3373.  
  3374. --[[
  3375. ----------------------------------------------------------------------------------------------------
  3376. -- End configuration
  3377. --
  3378. -- Don't edit anything below this line.
  3379. ----------------------------------------------------------------------------------------------------
  3380. --]]
  3381.  
  3382. return cfg</text>
  3383.       <sha1>da6pt1lzpy4z0skaztwblaqnfhizyf7</sha1>
  3384.     </revision>
  3385.   </page>
  3386.   <page>
  3387.     <title>Module:Documentation/styles.css</title>
  3388.     <ns>828</ns>
  3389.     <id>61440006</id>
  3390.     <revision>
  3391.       <id>989579069</id>
  3392.       <parentid>989578481</parentid>
  3393.       <timestamp>2020-11-19T20:21:58Z</timestamp>
  3394.       <contributor>
  3395.         <username>Izno</username>
  3396.         <id>2927383</id>
  3397.       </contributor>
  3398.       <minor/>
  3399.       <comment>Changed protection level for "[[Module:Documentation/styles.css]]": actually match module ([Edit=Require template editor access] (indefinite) [Move=Require template editor access] (indefinite))</comment>
  3400.       <model>sanitized-css</model>
  3401.       <format>text/css</format>
  3402.       <text bytes="716" xml:space="preserve">/* {{pp|small=yes}} */
  3403. .documentation,
  3404. .documentation-metadata {
  3405.     border: 1px solid #a2a9b1;
  3406.     background-color: #ecfcf4;
  3407.     clear: both;
  3408. }
  3409.  
  3410. .documentation {
  3411.     margin: 1em 0 0 0;
  3412.     padding: 1em;
  3413. }
  3414.  
  3415. .documentation-metadata {
  3416.     margin: 0.2em 0; /* same margin left-right as .documentation */
  3417.     font-style: italic;
  3418.     padding: 0.4em 1em; /* same padding left-right as .documentation */
  3419. }
  3420.  
  3421. .documentation-startbox {
  3422.     padding-bottom: 3px;
  3423.     border-bottom: 1px solid #aaa;
  3424.     margin-bottom: 1ex;
  3425. }
  3426.  
  3427. .documentation-heading {
  3428.     font-weight: bold;
  3429.     font-size: 125%;
  3430. }
  3431.  
  3432. .documentation-clear { /* Don't want things to stick out where they shouldn't. */
  3433.     clear: both;
  3434. }
  3435.  
  3436. .documentation-toolbar {
  3437.     font-style: normal;
  3438.     font-size: 85%;
  3439. }</text>
  3440.       <sha1>o2ia525en7wbq32mq4fpdevtl5d6pcb</sha1>
  3441.     </revision>
  3442.   </page>
  3443.   <page>
  3444.     <title>Module:Effective protection expiry</title>
  3445.     <ns>828</ns>
  3446.     <id>48785459</id>
  3447.     <revision>
  3448.       <id>948472505</id>
  3449.       <parentid>948472504</parentid>
  3450.       <timestamp>2020-04-01T06:12:42Z</timestamp>
  3451.       <contributor>
  3452.         <username>MusikAnimal</username>
  3453.         <id>14882394</id>
  3454.       </contributor>
  3455.       <minor/>
  3456.       <comment>1 revision imported</comment>
  3457.       <model>Scribunto</model>
  3458.       <format>text/plain</format>
  3459.       <text bytes="1494" xml:space="preserve">local p = {}
  3460.  
  3461. -- Returns the expiry of a restriction of an action on a given title, or unknown if it cannot be known.
  3462. -- If no title is specified, the title of the page being displayed is used.
  3463. function p._main(action, pagename)
  3464.     local title
  3465.     if type(pagename) == 'table' and pagename.prefixedText then
  3466.         title = pagename
  3467.     elseif pagename then
  3468.         title = mw.title.new(pagename)
  3469.     else
  3470.         title = mw.title.getCurrentTitle()
  3471.     end
  3472.     pagename = title.prefixedText
  3473.     if action == 'autoreview' then
  3474.         local stabilitySettings = mw.ext.FlaggedRevs.getStabilitySettings(title)
  3475.         return stabilitySettings and stabilitySettings.expiry or 'unknown'
  3476.     elseif action ~= 'edit' and action ~= 'move' and action ~= 'create' and action ~= 'upload' then
  3477.         error( 'First parameter must be one of edit, move, create, upload, autoreview', 2 )
  3478.     end
  3479.     local rawExpiry = mw.getCurrentFrame():callParserFunction('PROTECTIONEXPIRY', action, pagename)
  3480.     if rawExpiry == 'infinity' then
  3481.         return 'infinity'
  3482.     elseif rawExpiry == '' then
  3483.         return 'unknown'
  3484.     else
  3485.         local year, month, day, hour, minute, second = rawExpiry:match(
  3486.             '^(%d%d%d%d)(%d%d)(%d%d)(%d%d)(%d%d)(%d%d)$'
  3487.         )
  3488.         if year then
  3489.             return string.format(
  3490.                 '%s-%s-%sT%s:%s:%s',
  3491.                 year, month, day, hour, minute, second
  3492.             )
  3493.         else
  3494.             error('internal error in Module:Effective protection expiry; malformed expiry timestamp')
  3495.         end
  3496.     end
  3497. end
  3498.  
  3499. setmetatable(p, { __index = function(t, k)
  3500.     return function(frame)
  3501.         return t._main(k, frame.args[1])
  3502.     end
  3503. end })
  3504.  
  3505. return p</text>
  3506.       <sha1>i1wms02y1w048cq6uttka18a5pjzp63</sha1>
  3507.     </revision>
  3508.   </page>
  3509.   <page>
  3510.     <title>Module:Effective protection level</title>
  3511.     <ns>828</ns>
  3512.     <id>41617327</id>
  3513.     <revision>
  3514.       <id>980896975</id>
  3515.       <parentid>948472507</parentid>
  3516.       <timestamp>2020-09-29T03:38:47Z</timestamp>
  3517.       <contributor>
  3518.         <username>Jackmcbarn</username>
  3519.         <id>19285809</id>
  3520.       </contributor>
  3521.       <comment>bring in changes from sandbox</comment>
  3522.       <model>Scribunto</model>
  3523.       <format>text/plain</format>
  3524.       <text bytes="3438" xml:space="preserve">local p = {}
  3525.  
  3526. -- Returns the permission required to perform a given action on a given title.
  3527. -- If no title is specified, the title of the page being displayed is used.
  3528. function p._main(action, pagename)
  3529.     local title
  3530.     if type(pagename) == 'table' and pagename.prefixedText then
  3531.         title = pagename
  3532.     elseif pagename then
  3533.         title = mw.title.new(pagename)
  3534.     else
  3535.         title = mw.title.getCurrentTitle()
  3536.     end
  3537.     pagename = title.prefixedText
  3538.     if action == 'autoreview' then
  3539.         local level = mw.ext.FlaggedRevs.getStabilitySettings(title)
  3540.         level = level and level.autoreview
  3541.         if level == 'review' then
  3542.             return 'reviewer'
  3543.         elseif level ~= '' then
  3544.             return level
  3545.         else
  3546.             return nil -- not '*'. a page not being PC-protected is distinct from it being PC-protected with anyone able to review. also not '', as that would mean PC-protected but nobody can review
  3547.         end
  3548.     elseif action ~= 'edit' and action ~= 'move' and action ~= 'create' and action ~= 'upload' and action ~= 'undelete' then
  3549.         error( 'First parameter must be one of edit, move, create, upload, undelete, autoreview', 2 )
  3550.     end
  3551.     if title.namespace == 8 then -- MediaWiki namespace
  3552.         if title.text:sub(-3) == '.js' or title.text:sub(-4) == '.css' or title.contentModel == 'javascript' or title.contentModel == 'css' then -- site JS or CSS page
  3553.             return 'interfaceadmin'
  3554.         else -- any non-JS/CSS MediaWiki page
  3555.             return 'sysop'
  3556.         end
  3557.     elseif title.namespace == 2 and title.isSubpage then
  3558.         if title.contentModel == 'javascript' or title.contentModel == 'css' then -- user JS or CSS page
  3559.             return 'interfaceadmin'
  3560.         elseif title.contentModel == 'json' then -- user JSON page
  3561.             return 'sysop'
  3562.         end
  3563.     end
  3564.     if action == 'undelete' then
  3565.         return 'sysop'
  3566.     end
  3567.     local level = title.protectionLevels[action] and title.protectionLevels[action][1]
  3568.     if level == 'sysop' or level == 'editprotected' then
  3569.         return 'sysop'
  3570.     elseif title.cascadingProtection.restrictions[action] and title.cascadingProtection.restrictions[action][1] then -- used by a cascading-protected page
  3571.         return 'sysop'
  3572.     elseif level == 'templateeditor' then
  3573.         return 'templateeditor'
  3574.     elseif action == 'move' then
  3575.         local blacklistentry = mw.ext.TitleBlacklist.test('edit', pagename) -- Testing action edit is correct, since this is for the source page. The target page name gets tested with action move.
  3576.         if blacklistentry and not blacklistentry.params.autoconfirmed then
  3577.             return 'templateeditor'
  3578.         elseif title.namespace == 6 then
  3579.             return 'filemover'
  3580.         elseif level == 'extendedconfirmed' then
  3581.             return 'extendedconfirmed'
  3582.         else
  3583.             return 'autoconfirmed'
  3584.         end
  3585.     end
  3586.     local blacklistentry = mw.ext.TitleBlacklist.test(action, pagename)
  3587.     if blacklistentry then
  3588.         if not blacklistentry.params.autoconfirmed then
  3589.             return 'templateeditor'
  3590.         elseif level == 'extendedconfirmed' then
  3591.             return 'extendedconfirmed'
  3592.         else
  3593.             return 'autoconfirmed'
  3594.         end
  3595.     elseif level == 'editsemiprotected' then -- create-semiprotected pages return this for some reason
  3596.         return 'autoconfirmed'
  3597.     elseif level then
  3598.         return level
  3599.     elseif action == 'upload' then
  3600.         return 'autoconfirmed'
  3601.     elseif action == 'create' and title.namespace % 2 == 0 and title.namespace ~= 118 then -- You need to be registered, but not autoconfirmed, to create non-talk pages other than drafts
  3602.         return 'user'
  3603.     else
  3604.         return '*'
  3605.     end
  3606. end
  3607.  
  3608. setmetatable(p, { __index = function(t, k)
  3609.     return function(frame)
  3610.         return t._main(k, frame.args[1])
  3611.     end
  3612. end })
  3613.  
  3614. return p</text>
  3615.       <sha1>d3lhy0comfcfe9lnnj8klmrfqm1oxw7</sha1>
  3616.     </revision>
  3617.   </page>
  3618.   <page>
  3619.     <title>Module:File link</title>
  3620.     <ns>828</ns>
  3621.     <id>42903140</id>
  3622.     <revision>
  3623.       <id>948474149</id>
  3624.       <parentid>948472509</parentid>
  3625.       <timestamp>2020-04-01T06:31:54Z</timestamp>
  3626.       <contributor>
  3627.         <username>MusikAnimal</username>
  3628.         <id>14882394</id>
  3629.       </contributor>
  3630.       <comment>Undid revision 948472508 by [[Special:Contributions/w&gt;IPad365|w&gt;IPad365]] ([[User talk:w&gt;IPad365|talk]])</comment>
  3631.       <model>Scribunto</model>
  3632.       <format>text/plain</format>
  3633.       <text bytes="2544" xml:space="preserve">-- This module provides a library for formatting file wikilinks.
  3634.  
  3635. local yesno = require('Module:Yesno')
  3636. local checkType = require('libraryUtil').checkType
  3637.  
  3638. local p = {}
  3639.  
  3640. function p._main(args)
  3641.     checkType('_main', 1, args, 'table')
  3642.  
  3643.     -- This is basically libraryUtil.checkTypeForNamedArg, but we are rolling our
  3644.     -- own function to get the right error level.
  3645.     local function checkArg(key, val, level)
  3646.         if type(val) ~= 'string' then
  3647.             error(string.format(
  3648.                 "type error in '%s' parameter of '_main' (expected string, got %s)",
  3649.                 key, type(val)
  3650.             ), level)
  3651.         end
  3652.     end
  3653.  
  3654.     local ret = {}
  3655.  
  3656.     -- Adds a positional parameter to the buffer.
  3657.     local function addPositional(key)
  3658.         local val = args[key]
  3659.         if not val then
  3660.             return nil
  3661.         end
  3662.         checkArg(key, val, 4)
  3663.         ret[#ret + 1] = val
  3664.     end
  3665.  
  3666.     -- Adds a named parameter to the buffer. We assume that the parameter name
  3667.     -- is the same as the argument key.
  3668.     local function addNamed(key)
  3669.         local val = args[key]
  3670.         if not val then
  3671.             return nil
  3672.         end
  3673.         checkArg(key, val, 4)
  3674.         ret[#ret + 1] = key .. '=' .. val
  3675.     end
  3676.  
  3677.     -- Filename
  3678.     checkArg('file', args.file, 3)
  3679.     ret[#ret + 1] = 'File:' .. args.file
  3680.  
  3681.     -- Format
  3682.     if args.format then
  3683.         checkArg('format', args.format)
  3684.         if args.formatfile then
  3685.             checkArg('formatfile', args.formatfile)
  3686.             ret[#ret + 1] = args.format .. '=' .. args.formatfile
  3687.         else
  3688.             ret[#ret + 1] = args.format
  3689.         end
  3690.     end
  3691.  
  3692.     -- Border
  3693.     if yesno(args.border) then
  3694.         ret[#ret + 1] = 'border'
  3695.     end
  3696.  
  3697.     addPositional('location')
  3698.     addPositional('alignment')
  3699.     addPositional('size')
  3700.     addNamed('upright')
  3701.     addNamed('link')
  3702.     addNamed('alt')
  3703.     addNamed('page')
  3704.     addNamed('class')
  3705.     addNamed('lang')
  3706.     addNamed('start')
  3707.     addNamed('end')
  3708.     addNamed('thumbtime')
  3709.     addPositional('caption')
  3710.  
  3711.     return string.format('[[%s]]', table.concat(ret, '|'))
  3712. end
  3713.  
  3714. function p.main(frame)
  3715.     local origArgs = require('Module:Arguments').getArgs(frame, {
  3716.         wrappers = 'Template:File link'
  3717.     })
  3718.     if not origArgs.file then
  3719.         error("'file' parameter missing from [[Template:File link]]", 0)
  3720.     end
  3721.  
  3722.     -- Copy the arguments that were passed to a new table to avoid looking up
  3723.     -- every possible parameter in the frame object.
  3724.     local args = {}
  3725.     for k, v in pairs(origArgs) do
  3726.         -- Make _BLANK a special argument to add a blank parameter. For use in
  3727.         -- conditional templates etc. it is useful for blank arguments to be
  3728.         -- ignored, but we still need a way to specify them so that we can do
  3729.         -- things like [[File:Example.png|link=]].
  3730.         if v == '_BLANK' then
  3731.             v = ''
  3732.         end
  3733.         args[k] = v
  3734.     end
  3735.     return p._main(args)
  3736. end
  3737.  
  3738. return p</text>
  3739.       <sha1>bzc22v133v9z5yc4aisazripn6l94p8</sha1>
  3740.     </revision>
  3741.   </page>
  3742.   <page>
  3743.     <title>Module:High-use</title>
  3744.     <ns>828</ns>
  3745.     <id>62062952</id>
  3746.     <revision>
  3747.       <id>1053091615</id>
  3748.       <parentid>1050945202</parentid>
  3749.       <timestamp>2021-11-01T21:11:55Z</timestamp>
  3750.       <contributor>
  3751.         <username>GKFX</username>
  3752.         <id>14918984</id>
  3753.       </contributor>
  3754.       <comment>Link to https://linkcount.toolforge.org/ which is more detailed and mobile-friendly</comment>
  3755.       <model>Scribunto</model>
  3756.       <format>text/plain</format>
  3757.       <text bytes="6690" xml:space="preserve">local p = {}
  3758.  
  3759. -- _fetch looks at the "demo" argument.
  3760. local _fetch = require('Module:Transclusion_count').fetch
  3761. local yesno = require('Module:Yesno')
  3762.  
  3763. function p.num(frame, count)
  3764.     if count == nil then
  3765.         if yesno(frame.args['fetch']) == false then
  3766.             if (frame.args[1] or '') ~= '' then count = tonumber(frame.args[1]) end
  3767.         else
  3768.             count = _fetch(frame)
  3769.         end
  3770.     end
  3771.    
  3772.     -- Build output string
  3773.     local return_value = ""
  3774.     if count == nil then
  3775.         if frame.args[1] == "risk" then
  3776.             return_value = "a very large number of"
  3777.         else
  3778.             return_value = "many"
  3779.         end
  3780.     else
  3781.         -- Use 2 significant figures for smaller numbers and 3 for larger ones
  3782.         local sigfig = 2
  3783.         if count &gt;= 100000 then
  3784.             sigfig = 3
  3785.         end
  3786.        
  3787.         -- Prepare to round to appropriate number of sigfigs
  3788.         local f = math.floor(math.log10(count)) - sigfig + 1
  3789.        
  3790.         -- Round and insert "approximately" or "+" when appropriate
  3791.         if (frame.args[2] == "yes") or (mw.ustring.sub(frame.args[1],-1) == "+") then
  3792.             -- Round down
  3793.             return_value = string.format("%s+", mw.getContentLanguage():formatNum(math.floor( (count / 10^(f)) ) * (10^(f))) )
  3794.         else
  3795.             -- Round to nearest
  3796.             return_value = string.format("approximately&amp;#x20;%s", mw.getContentLanguage():formatNum(math.floor( (count / 10^(f)) + 0.5) * (10^(f))) )
  3797.         end
  3798.  
  3799.         -- Insert percentage of pages if that is likely to be &gt;= 1% and when |no-percent= not set to yes
  3800.         if count and count &gt; 250000 and not yesno (frame:getParent().args['no-percent']) then
  3801.             local percent = math.floor( ( (count/frame:callParserFunction('NUMBEROFPAGES', 'R') ) * 100) + 0.5)
  3802.             if percent &gt;= 1 then
  3803.                 return_value = string.format("%s&amp;#x20;pages, or roughly %s%% of all", return_value, percent)
  3804.             end
  3805.         end
  3806.     end
  3807.    
  3808.     return return_value
  3809. end
  3810. -- Actions if there is a large (greater than or equal to 100,000) transclusion count
  3811. function p.risk(frame)
  3812.     local return_value = ""
  3813.     if frame.args[1] == "risk" then
  3814.         return_value = "risk"
  3815.     else
  3816.         local count = _fetch(frame)
  3817.         if count and count &gt;= 100000 then return_value = "risk" end
  3818.     end
  3819.     return return_value
  3820. end
  3821.  
  3822. function p.text(frame, count)
  3823.     -- Only show the information about how this template gets updated if someone
  3824.     -- is actually editing the page and maybe trying to update the count.
  3825.     local bot_text = (frame:preprocess("{{REVISIONID}}") == "") and "\n\n----\n'''Preview message''': Transclusion count updated automatically ([[Template:High-use/doc#Technical details|see documentation]])." or ''
  3826.    
  3827.     if count == nil then
  3828.         if yesno(frame.args['fetch']) == false then
  3829.             if (frame.args[1] or '') ~= '' then count = tonumber(frame.args[1]) end
  3830.         else
  3831.             count = _fetch(frame)
  3832.         end
  3833.     end
  3834.     local title = mw.title.getCurrentTitle()
  3835.     if title.subpageText == "doc" or title.subpageText == "sandbox" then
  3836.         title = title.basePageTitle
  3837.     end
  3838.    
  3839.     local systemMessages = frame.args['system']
  3840.     if frame.args['system'] == '' then
  3841.         systemMessages = nil
  3842.     end
  3843.    
  3844.     -- This retrieves the project URL automatically to simplify localiation.
  3845.     local templateCount = ('on [https://linkcount.toolforge.org/index.php?project=%s&amp;page=%s %s pages]'):format(
  3846.         mw.title.getCurrentTitle():fullUrl():gsub('//(.-)/.*', '%1'),
  3847.         mw.uri.encode(title.fullText), p.num(frame, count))
  3848.     local used_on_text = "'''This " .. (mw.title.getCurrentTitle().namespace == 828 and "Lua module" or "template") .. ' is used ';
  3849.     if systemMessages then
  3850.         used_on_text = used_on_text .. systemMessages ..
  3851.             ((count and count &gt; 2000) and (",''' and " .. templateCount) or ("'''"))
  3852.     else
  3853.         used_on_text = used_on_text .. templateCount .. "'''"
  3854.     end
  3855.    
  3856.    
  3857.     local sandbox_text =  ("%s's [[%s/sandbox|/sandbox]] or [[%s/testcases|/testcases]] subpages, or in your own [[%s]]. "):format(
  3858.         (mw.title.getCurrentTitle().namespace == 828 and "module" or "template"),
  3859.         title.fullText, title.fullText,
  3860.         mw.title.getCurrentTitle().namespace == 828 and "Module:Sandbox|module sandbox" or "Wikipedia:User pages#SUB|user subpage"
  3861.     )
  3862.    
  3863.     local infoArg = frame.args["info"] ~= "" and frame.args["info"]
  3864.     if (systemMessages or frame.args[1] == "risk" or (count and count &gt;= 100000) ) then
  3865.         local info = systemMessages and '.&lt;br/&gt;Changes to it can cause immediate changes to the Wikipedia user interface.' or '.'
  3866.         if infoArg then
  3867.             info = info .. "&lt;br /&gt;" .. infoArg
  3868.         end
  3869.         sandbox_text = info .. '&lt;br /&gt; To avoid major disruption' ..
  3870.             (count and count &gt;= 100000 and ' and server load' or '') ..
  3871.             ', any changes should be tested in the ' .. sandbox_text ..
  3872.             'The tested changes can be added to this page in a single edit. '
  3873.     else
  3874.         sandbox_text = (infoArg and ('.&lt;br /&gt;' .. infoArg .. ' C') or ' and c') ..
  3875.             'hanges may be widely noticed. Test changes in the ' .. sandbox_text
  3876.     end
  3877.  
  3878.    
  3879.     local discussion_text = systemMessages and 'Please discuss changes ' or 'Consider discussing changes '
  3880.     if frame.args["2"] and frame.args["2"] ~= "" and frame.args["2"] ~= "yes" then
  3881.         discussion_text = string.format("%sat [[%s]]", discussion_text, frame.args["2"])
  3882.     else
  3883.         discussion_text = string.format("%son the [[%s|talk page]]", discussion_text, title.talkPageTitle.fullText )
  3884.     end
  3885.    
  3886.     return used_on_text .. sandbox_text .. discussion_text .. " before implementing them." .. bot_text
  3887. end
  3888.  
  3889. function p.main(frame)
  3890.     local count = nil
  3891.     if yesno(frame.args['fetch']) == false then
  3892.         if (frame.args[1] or '') ~= '' then count = tonumber(frame.args[1]) end
  3893.     else
  3894.         count = _fetch(frame)
  3895.     end
  3896.     local image = "[[File:Ambox warning yellow.svg|40px|alt=Warning|link=]]"
  3897.     local type_param = "style"
  3898.     local epilogue = ''
  3899.     if frame.args['system'] and frame.args['system'] ~= '' then
  3900.         image = "[[File:Ambox important.svg|40px|alt=Warning|link=]]"
  3901.         type_param = "content"
  3902.         local nocat = frame:getParent().args['nocat'] or frame.args['nocat']
  3903.         local categorise = (nocat == '' or not yesno(nocat))
  3904.         if categorise then
  3905.             epilogue = frame:preprocess('{{Sandbox other||{{#switch:{{#invoke:Effective protection level|{{#switch:{{NAMESPACE}}|File=upload|#default=edit}}|{{FULLPAGENAME}}}}|sysop|templateeditor|interfaceadmin=|#default=[[Category:Pages used in system messages needing protection]]}}}}')
  3906.         end
  3907.     elseif (frame.args[1] == "risk" or (count and count &gt;= 100000)) then
  3908.         image = "[[File:Ambox warning orange.svg|40px|alt=Warning|link=]]"
  3909.         type_param = "content"
  3910.     end
  3911.    
  3912.     if frame.args["form"] == "editnotice" then
  3913.         return frame:expandTemplate{
  3914.                 title = 'editnotice',
  3915.                 args = {
  3916.                         ["image"] = image,
  3917.                         ["text"] = p.text(frame, count),
  3918.                         ["expiry"] = (frame.args["expiry"] or "")
  3919.                 }
  3920.         } .. epilogue
  3921.     else
  3922.         return require('Module:Message box').main('ombox', {
  3923.             type = type_param,
  3924.             image = image,
  3925.             text = p.text(frame, count),
  3926.             expiry = (frame.args["expiry"] or "")
  3927.         }) .. epilogue
  3928.     end
  3929. end
  3930.  
  3931. return p</text>
  3932.       <sha1>sy3y3omwgho4wnukvqxwejjpb2mjh3c</sha1>
  3933.     </revision>
  3934.   </page>
  3935.   <page>
  3936.     <title>Module:List</title>
  3937.     <ns>828</ns>
  3938.     <id>41068627</id>
  3939.     <revision>
  3940.       <id>915206629</id>
  3941.       <parentid>914636065</parentid>
  3942.       <timestamp>2019-09-11T21:05:14Z</timestamp>
  3943.       <contributor>
  3944.         <username>Paine Ellsworth</username>
  3945.         <id>9092818</id>
  3946.       </contributor>
  3947.       <comment>xfer from sandbox per edit request on talk page</comment>
  3948.       <model>Scribunto</model>
  3949.       <format>text/plain</format>
  3950.       <text bytes="5410" xml:space="preserve">-- This module outputs different kinds of lists. At the moment, bulleted,
  3951. -- unbulleted, horizontal, ordered, and horizontal ordered lists are supported.
  3952.  
  3953. local libUtil = require('libraryUtil')
  3954. local checkType = libUtil.checkType
  3955. local mTableTools = require('Module:TableTools')
  3956.  
  3957. local p = {}
  3958.  
  3959. local listTypes = {
  3960.     ['bulleted'] = true,
  3961.     ['unbulleted'] = true,
  3962.     ['horizontal'] = true,
  3963.     ['ordered'] = true,
  3964.     ['horizontal_ordered'] = true
  3965. }
  3966.  
  3967. function p.makeListData(listType, args)
  3968.     -- Constructs a data table to be passed to p.renderList.
  3969.     local data = {}
  3970.  
  3971.     -- Classes
  3972.     data.classes = {}
  3973.     if listType == 'horizontal' or listType == 'horizontal_ordered' then
  3974.         table.insert(data.classes, 'hlist hlist-separated')
  3975.     elseif listType == 'unbulleted' then
  3976.         table.insert(data.classes, 'plainlist')
  3977.     end
  3978.     table.insert(data.classes, args.class)
  3979.  
  3980.     -- Main div style
  3981.     data.style = args.style
  3982.  
  3983.     -- Indent for horizontal lists
  3984.     if listType == 'horizontal' or listType == 'horizontal_ordered' then
  3985.         local indent = tonumber(args.indent)
  3986.         indent = indent and indent * 1.6 or 0
  3987.         if indent &gt; 0 then
  3988.             data.marginLeft = indent .. 'em'
  3989.         end
  3990.     end
  3991.    
  3992.     -- List style types for ordered lists
  3993.     -- This could be "1, 2, 3", "a, b, c", or a number of others. The list style
  3994.     -- type is either set by the "type" attribute or the "list-style-type" CSS
  3995.     -- property.
  3996.     if listType == 'ordered' or listType == 'horizontal_ordered' then
  3997.         data.listStyleType = args.list_style_type or args['list-style-type']
  3998.         data.type = args['type']
  3999.  
  4000.         -- Detect invalid type attributes and attempt to convert them to
  4001.         -- list-style-type CSS properties.
  4002.         if data.type
  4003.             and not data.listStyleType
  4004.             and not tostring(data.type):find('^%s*[1AaIi]%s*$')
  4005.         then
  4006.             data.listStyleType = data.type
  4007.             data.type = nil
  4008.         end
  4009.     end
  4010.    
  4011.     -- List tag type
  4012.     if listType == 'ordered' or listType == 'horizontal_ordered' then
  4013.         data.listTag = 'ol'
  4014.     else
  4015.         data.listTag = 'ul'
  4016.     end
  4017.  
  4018.     -- Start number for ordered lists
  4019.     data.start = args.start
  4020.     if listType == 'horizontal_ordered' then
  4021.         -- Apply fix to get start numbers working with horizontal ordered lists.
  4022.         local startNum = tonumber(data.start)
  4023.         if startNum then
  4024.             data.counterReset = 'listitem ' .. tostring(startNum - 1)
  4025.         end
  4026.     end
  4027.  
  4028.     -- List style
  4029.      -- ul_style and ol_style are included for backwards compatibility. No
  4030.      -- distinction is made for ordered or unordered lists.
  4031.     data.listStyle = args.list_style
  4032.  
  4033.     -- List items
  4034.     -- li_style is included for backwards compatibility. item_style was included
  4035.     -- to be easier to understand for non-coders.
  4036.     data.itemStyle = args.item_style or args.li_style
  4037.     data.items = {}
  4038.     for i, num in ipairs(mTableTools.numKeys(args)) do
  4039.         local item = {}
  4040.         item.content = args[num]
  4041.         item.style = args['item' .. tostring(num) .. '_style']
  4042.             or args['item_style' .. tostring(num)]
  4043.         item.value = args['item' .. tostring(num) .. '_value']
  4044.             or args['item_value' .. tostring(num)]
  4045.         table.insert(data.items, item)
  4046.     end
  4047.    
  4048.     return data
  4049. end
  4050.  
  4051. function p.renderList(data)
  4052.     -- Renders the list HTML.
  4053.    
  4054.     -- Return the blank string if there are no list items.
  4055.     if type(data.items) ~= 'table' or #data.items &lt; 1 then
  4056.         return ''
  4057.     end
  4058.    
  4059.     -- Render the main div tag.
  4060.     local root = mw.html.create('div')
  4061.     for i, class in ipairs(data.classes or {}) do
  4062.         root:addClass(class)
  4063.     end
  4064.     root:css{['margin-left'] = data.marginLeft}
  4065.     if data.style then
  4066.         root:cssText(data.style)
  4067.     end
  4068.  
  4069.     -- Render the list tag.
  4070.     local list = root:tag(data.listTag or 'ul')
  4071.     list
  4072.         :attr{start = data.start, type = data.type}
  4073.         :css{
  4074.             ['counter-reset'] = data.counterReset,
  4075.             ['list-style-type'] = data.listStyleType
  4076.         }
  4077.     if data.listStyle then
  4078.         list:cssText(data.listStyle)
  4079.     end
  4080.  
  4081.     -- Render the list items
  4082.     for i, t in ipairs(data.items or {}) do
  4083.         local item = list:tag('li')
  4084.         if data.itemStyle then
  4085.             item:cssText(data.itemStyle)
  4086.         end
  4087.         if t.style then
  4088.             item:cssText(t.style)
  4089.         end
  4090.         item
  4091.             :attr{value = t.value}
  4092.             :wikitext(t.content)
  4093.     end
  4094.  
  4095.     return tostring(root)
  4096. end
  4097.  
  4098. function p.renderTrackingCategories(args)
  4099.     local isDeprecated = false -- Tracks deprecated parameters.
  4100.     for k, v in pairs(args) do
  4101.         k = tostring(k)
  4102.         if k:find('^item_style%d+$') or k:find('^item_value%d+$') then
  4103.             isDeprecated = true
  4104.             break
  4105.         end
  4106.     end
  4107.     local ret = ''
  4108.     if isDeprecated then
  4109.         ret = ret .. '[[Category:List templates with deprecated parameters]]'
  4110.     end
  4111.     return ret
  4112. end
  4113.  
  4114. function p.makeList(listType, args)
  4115.     if not listType or not listTypes[listType] then
  4116.         error(string.format(
  4117.             "bad argument #1 to 'makeList' ('%s' is not a valid list type)",
  4118.             tostring(listType)
  4119.         ), 2)
  4120.     end
  4121.     checkType('makeList', 2, args, 'table')
  4122.     local data = p.makeListData(listType, args)
  4123.     local list = p.renderList(data)
  4124.     local trackingCategories = p.renderTrackingCategories(args)
  4125.     return list .. trackingCategories
  4126. end
  4127.  
  4128. for listType in pairs(listTypes) do
  4129.     p[listType] = function (frame)
  4130.         local mArguments = require('Module:Arguments')
  4131.         local origArgs = mArguments.getArgs(frame, {
  4132.             valueFunc = function (key, value)
  4133.             if not value or not mw.ustring.find(value, '%S') then return nil end
  4134.             if mw.ustring.find(value, '^%s*[%*#;:]') then
  4135.                 return value
  4136.             else
  4137.                 return value:match('^%s*(.-)%s*$')
  4138.             end
  4139.             return nil
  4140.         end
  4141.         })
  4142.         -- Copy all the arguments to a new table, for faster indexing.
  4143.         local args = {}
  4144.         for k, v in pairs(origArgs) do
  4145.             args[k] = v
  4146.         end
  4147.         return p.makeList(listType, args)
  4148.     end
  4149. end
  4150.  
  4151. return p</text>
  4152.       <sha1>1kfxv6e8upfdko23gc41ky0lax25kzs</sha1>
  4153.     </revision>
  4154.   </page>
  4155.   <page>
  4156.     <title>Module:Lua banner</title>
  4157.     <ns>828</ns>
  4158.     <id>42951651</id>
  4159.     <revision>
  4160.       <id>1059679087</id>
  4161.       <parentid>1043920761</parentid>
  4162.       <timestamp>2021-12-10T22:30:39Z</timestamp>
  4163.       <contributor>
  4164.         <username>Fayenatic london</username>
  4165.         <id>1639942</id>
  4166.       </contributor>
  4167.       <comment>Update categories, see [[Wikipedia:Categories for discussion/Log/2021 October 31]]</comment>
  4168.       <model>Scribunto</model>
  4169.       <format>text/plain</format>
  4170.       <text bytes="3904" xml:space="preserve">-- This module implements the {{lua}} template.
  4171. local yesno = require('Module:Yesno')
  4172. local mList = require('Module:List')
  4173. local mTableTools = require('Module:TableTools')
  4174. local mMessageBox = require('Module:Message box')
  4175.  
  4176. local p = {}
  4177.  
  4178. function p.main(frame)
  4179.     local origArgs = frame:getParent().args
  4180.     local args = {}
  4181.     for k, v in pairs(origArgs) do
  4182.         v = v:match('^%s*(.-)%s*$')
  4183.         if v ~= '' then
  4184.             args[k] = v
  4185.         end
  4186.     end
  4187.     return p._main(args)
  4188. end
  4189.  
  4190. function p._main(args)
  4191.     local modules = mTableTools.compressSparseArray(args)
  4192.     local box = p.renderBox(modules)
  4193.     local trackingCategories = p.renderTrackingCategories(args, modules)
  4194.     return box .. trackingCategories
  4195. end
  4196.  
  4197. function p.renderBox(modules)
  4198.     local boxArgs = {}
  4199.     if #modules &lt; 1 then
  4200.         boxArgs.text = '&lt;strong class="error"&gt;Error: no modules specified&lt;/strong&gt;'
  4201.     else
  4202.         local moduleLinks = {}
  4203.         for i, module in ipairs(modules) do
  4204.             moduleLinks[i] = string.format('[[:%s]]', module)
  4205.             local maybeSandbox = mw.title.new(module .. '/sandbox')
  4206.             if maybeSandbox.exists then
  4207.                 moduleLinks[i] = moduleLinks[i] .. string.format(' ([[:%s|sandbox]])', maybeSandbox.fullText)
  4208.             end
  4209.         end
  4210.         local moduleList = mList.makeList('bulleted', moduleLinks)
  4211.         local title = mw.title.getCurrentTitle()
  4212.         if title.subpageText == "doc" then
  4213.             title = title.basePageTitle
  4214.         end
  4215.         if title.contentModel == "Scribunto" then
  4216.             boxArgs.text = 'This module depends on the following other modules:' .. moduleList
  4217.         else
  4218.             boxArgs.text = 'This template  uses [[Wikipedia:Lua|Lua]]:\n' .. moduleList
  4219.         end
  4220.     end
  4221.     boxArgs.type = 'notice'
  4222.     boxArgs.small = true
  4223.     boxArgs.image = '[[File:Lua-Logo.svg|30px|alt=|link=]]'
  4224.     return mMessageBox.main('mbox', boxArgs)
  4225. end
  4226.  
  4227. function p.renderTrackingCategories(args, modules, titleObj)
  4228.     if yesno(args.nocat) then
  4229.         return ''
  4230.     end
  4231.  
  4232.     local cats = {}
  4233.  
  4234.     -- Error category
  4235.     if #modules &lt; 1 then
  4236.         cats[#cats + 1] = 'Lua templates with errors'
  4237.     end
  4238.  
  4239.     -- Lua templates category
  4240.     titleObj = titleObj or mw.title.getCurrentTitle()
  4241.     local subpageBlacklist = {
  4242.         doc = true,
  4243.         sandbox = true,
  4244.         sandbox2 = true,
  4245.         testcases = true
  4246.     }
  4247.     if not subpageBlacklist[titleObj.subpageText] then
  4248.         local protCatName
  4249.         if titleObj.namespace == 10 then
  4250.             local category = args.category
  4251.             if not category then
  4252.                 local categories = {
  4253.                     ['Module:String'] = 'Templates based on the String Lua module',
  4254.                     ['Module:Math'] = 'Templates based on the Math Lua module',
  4255.                     ['Module:BaseConvert'] = 'Templates based on the BaseConvert Lua module',
  4256.                     ['Module:Citation'] = 'Templates based on the Citation/CS1 Lua module'
  4257.                 }
  4258.                 categories['Module:Citation/CS1'] = categories['Module:Citation']
  4259.                 category = modules[1] and categories[modules[1]]
  4260.                 category = category or 'Lua-based templates'
  4261.             end
  4262.             cats[#cats + 1] = category
  4263.             protCatName = "Templates using under-protected Lua modules"
  4264.         elseif titleObj.namespace == 828 then
  4265.             protCatName = "Modules depending on under-protected modules"
  4266.         end
  4267.         if not args.noprotcat and protCatName then
  4268.             local protLevels = {
  4269.                 autoconfirmed = 1,
  4270.                 extendedconfirmed = 2,
  4271.                 templateeditor = 3,
  4272.                 sysop = 4
  4273.             }
  4274.             local currentProt
  4275.             if titleObj.id ~= 0 then
  4276.                 -- id is 0 (page does not exist) if am previewing before creating a template.
  4277.                 currentProt = titleObj.protectionLevels["edit"][1]
  4278.             end
  4279.             if currentProt == nil then currentProt = 0 else currentProt = protLevels[currentProt] end
  4280.             for i, module in ipairs(modules) do
  4281.                 if module ~= "WP:libraryUtil" then
  4282.                     local moduleProt = mw.title.new(module).protectionLevels["edit"][1]
  4283.                     if moduleProt == nil then moduleProt = 0 else moduleProt = protLevels[moduleProt] end
  4284.                     if moduleProt &lt; currentProt then
  4285.                         cats[#cats + 1] = protCatName
  4286.                         break
  4287.                     end
  4288.                 end
  4289.             end
  4290.         end
  4291.     end
  4292.     for i, cat in ipairs(cats) do
  4293.         cats[i] = string.format('[[Category:%s]]', cat)
  4294.     end
  4295.     return table.concat(cats)
  4296. end
  4297.  
  4298. return p</text>
  4299.       <sha1>cvk1cpv9jtriqu1hfkfklnnsm49md8l</sha1>
  4300.     </revision>
  4301.   </page>
  4302.   <page>
  4303.     <title>Module:Message box/doc</title>
  4304.     <ns>828</ns>
  4305.     <id>40677928</id>
  4306.     <revision>
  4307.       <id>1051963995</id>
  4308.       <parentid>1051901519</parentid>
  4309.       <timestamp>2021-10-26T15:50:54Z</timestamp>
  4310.       <contributor>
  4311.         <username>Pppery</username>
  4312.         <id>28032115</id>
  4313.       </contributor>
  4314.       <comment>Ugh, more undetected vandalism</comment>
  4315.       <model>wikitext</model>
  4316.       <format>text/x-wiki</format>
  4317.       <text bytes="5323" xml:space="preserve">{{Used in system}}
  4318. {{module rating|p}}
  4319. {{Lua|Module:Message box/configuration|Module:No globals|Module:Yesno|Module:Arguments|Module:Category handler}}
  4320.  
  4321. This is a meta-module that implements the message box templates {{tl|mbox}}, {{tl|ambox}}, {{tl|cmbox}}, {{tl|fmbox}}, {{tl|imbox}}, {{tl|ombox}}, and {{tl|tmbox}}. It is intended to be used from Lua modules, and should not be used directly from wiki pages. If you want to use this module's functionality from a wiki page, please use the individual message box templates instead.
  4322.  
  4323. == Usage ==
  4324.  
  4325. To use this module from another Lua module, first you need to load it.
  4326.  
  4327. &lt;syntaxhighlight lang="lua"&gt;
  4328. local messageBox = require('Module:Message box')
  4329. &lt;/syntaxhighlight&gt;
  4330.  
  4331. To create a message box, use the &lt;code&gt;main&lt;/code&gt; function. It takes two parameters: the first is the box type (as a string), and the second is a table containing the message box parameters.
  4332.  
  4333. &lt;syntaxhighlight lang="lua"&gt;
  4334. local box = messageBox.main( boxType, {
  4335.     param1 = param1,
  4336.     param2 = param2,
  4337.     -- More parameters...
  4338. })
  4339. &lt;/syntaxhighlight&gt;
  4340.  
  4341. There are seven available box types:
  4342.  
  4343. {| class="wikitable"
  4344. ! Box type !! Template !! Purpose
  4345. |-
  4346. | &lt;code&gt;mbox&lt;/code&gt; || {{tl|mbox}} || For message boxes to be used in multiple namespaces
  4347. |-
  4348. | &lt;code&gt;ambox&lt;/code&gt; || {{tl|ambox}} || For article message boxes
  4349. |-
  4350. | &lt;code&gt;cmbox&lt;/code&gt; || {{tl|cmbox}} || For category message boxes
  4351. |-
  4352. | &lt;code&gt;fmbox&lt;/code&gt; || {{tl|fmbox}} || For interface message boxes
  4353. |-
  4354. | &lt;code&gt;imbox&lt;/code&gt; || {{tl|imbox}} || For file namespace message boxes
  4355. |-
  4356. | &lt;code&gt;tmbox&lt;/code&gt; || {{tl|tmbox}} || For talk page message boxes
  4357. |-
  4358. | &lt;code&gt;ombox&lt;/code&gt; || {{tl|ombox}} || For message boxes in other namespaces
  4359. |}
  4360.  
  4361. See the template page of each box type for the available parameters.
  4362.  
  4363. == Usage from #invoke ==
  4364.  
  4365. As well as the &lt;code&gt;main&lt;/code&gt; function, this module has separate functions for each box type. They are accessed using the code &lt;code&gt;&lt;nowiki&gt;{{#invoke:Message box|mbox|...}}&lt;/nowiki&gt;&lt;/code&gt;, &lt;code&gt;&lt;nowiki&gt;{{#invoke:Message box|ambox|...}}&lt;/nowiki&gt;&lt;/code&gt;, etc. These will work when called from other modules, but they access code used to process arguments passed from #invoke, and so calling them will be less efficient than calling &lt;code&gt;main&lt;/code&gt;.
  4366.  
  4367. == Technical details ==
  4368.  
  4369. The module uses the same basic code for each of the templates listed above; the differences between each of them are configured using the data at [[Module:Message box/configuration]]. Here are the various configuration options and what they mean:
  4370.  
  4371. * &lt;code&gt;types&lt;/code&gt; – a table containing data used by the type parameter of the message box. The table keys are the values that can be passed to the type parameter, and the table values are tables containing the class and the image used by that type.
  4372. * &lt;code&gt;default&lt;/code&gt; – the type to use if no value was passed to the type parameter, or if an invalid value was specified.
  4373. * &lt;code&gt;showInvalidTypeError&lt;/code&gt; – whether to show an error if the value passed to the type parameter was invalid.
  4374. * &lt;code&gt;allowBlankParams&lt;/code&gt; – usually blank values are stripped from parameters passed to the module. However, whitespace is preserved for the parameters included in the allowBlankParams table.
  4375. * &lt;code&gt;allowSmall&lt;/code&gt; – whether a small version of the message box can be produced with "small=yes".
  4376. * &lt;code&gt;smallParam&lt;/code&gt; – a custom name for the small parameter. For example, if set to "left" you can produce a small message box using "small=left".
  4377. * &lt;code&gt;smallClass&lt;/code&gt; – the class to use for small message boxes.
  4378. * &lt;code&gt;substCheck&lt;/code&gt; – whether to perform a subst check or not.
  4379. * &lt;code&gt;classes&lt;/code&gt; – an array of classes to use with the message box.
  4380. * &lt;code&gt;imageEmptyCell&lt;/code&gt; – whether to use an empty {{tag|td}} cell if there is no image set. This is used to preserve spacing for message boxes with a width of less than 100% of the screen.
  4381. * &lt;code&gt;imageEmptyCellStyle&lt;/code&gt; – whether empty image cells should be styled.
  4382. * &lt;code&gt;imageCheckBlank&lt;/code&gt; – whether "image=blank" results in no image being displayed.
  4383. * &lt;code&gt;imageSmallSize&lt;/code&gt; – usually, images used in small message boxes are set to 30x30px. This sets a custom size.
  4384. * &lt;code&gt;imageCellDiv&lt;/code&gt; – whether to enclose the image in a div enforcing a maximum image size.
  4385. * &lt;code&gt;useCollapsibleTextFields&lt;/code&gt; – whether to use text fields that can be collapsed, i.e. "issue", "fix", "talk", etc. Currently only used in ambox.
  4386. * &lt;code&gt;imageRightNone&lt;/code&gt; – whether imageright=none results in no image being displayed on the right-hand side of the message box.
  4387. * &lt;code&gt;sectionDefault&lt;/code&gt; – the default name for the "section" parameter. Depends on &lt;code&gt;useCollapsibleTextFields&lt;/code&gt;.
  4388. * &lt;code&gt;allowMainspaceCategories&lt;/code&gt; – allow categorisation in the main namespace.
  4389. * &lt;code&gt;templateCategory&lt;/code&gt; – the name of a category to be placed on the template page.
  4390. * &lt;code&gt;templateCategoryRequireName&lt;/code&gt; – whether the &lt;code&gt;name&lt;/code&gt; parameter is required to display the template category.
  4391. * &lt;code&gt;templateErrorCategory&lt;/code&gt; – the name of the error category to be used on the template page.
  4392. * &lt;code&gt;templateErrorParamsToCheck&lt;/code&gt; – an array of parameter names to check. If any are absent, the &lt;code&gt;templateErrorCategory&lt;/code&gt; is applied to the template page.</text>
  4393.       <sha1>gylas5sr0c7uo5g3nrxklnd0k774pvd</sha1>
  4394.     </revision>
  4395.   </page>
  4396.   <page>
  4397.     <title>Module:Protection banner</title>
  4398.     <ns>828</ns>
  4399.     <id>42040984</id>
  4400.     <revision>
  4401.       <id>1033879006</id>
  4402.       <parentid>1013845490</parentid>
  4403.       <timestamp>2021-07-16T11:59:29Z</timestamp>
  4404.       <contributor>
  4405.         <username>ProcrastinatingReader</username>
  4406.         <id>32939139</id>
  4407.       </contributor>
  4408.       <comment>add catonly param which hides both the banner and padlock if set to yes. all testcases pass. tested in sandbox.</comment>
  4409.       <model>Scribunto</model>
  4410.       <format>text/plain</format>
  4411.       <text bytes="26029" xml:space="preserve">-- This module implements {{pp-meta}} and its daughter templates such as
  4412. -- {{pp-dispute}}, {{pp-vandalism}} and {{pp-sock}}.
  4413.  
  4414. -- Initialise necessary modules.
  4415. require('Module:No globals')
  4416. local makeFileLink = require('Module:File link')._main
  4417. local effectiveProtectionLevel = require('Module:Effective protection level')._main
  4418. local effectiveProtectionExpiry = require('Module:Effective protection expiry')._main
  4419. local yesno = require('Module:Yesno')
  4420.  
  4421. -- Lazily initialise modules and objects we don't always need.
  4422. local getArgs, makeMessageBox, lang
  4423.  
  4424. -- Set constants.
  4425. local CONFIG_MODULE = 'Module:Protection banner/config'
  4426.  
  4427. --------------------------------------------------------------------------------
  4428. -- Helper functions
  4429. --------------------------------------------------------------------------------
  4430.  
  4431. local function makeCategoryLink(cat, sort)
  4432.     if cat then
  4433.         return string.format(
  4434.             '[[%s:%s|%s]]',
  4435.             mw.site.namespaces[14].name,
  4436.             cat,
  4437.             sort
  4438.         )
  4439.     end
  4440. end
  4441.  
  4442. -- Validation function for the expiry and the protection date
  4443. local function validateDate(dateString, dateType)
  4444.     if not lang then
  4445.         lang = mw.language.getContentLanguage()
  4446.     end
  4447.     local success, result = pcall(lang.formatDate, lang, 'U', dateString)
  4448.     if success then
  4449.         result = tonumber(result)
  4450.         if result then
  4451.             return result
  4452.         end
  4453.     end
  4454.     error(string.format(
  4455.         'invalid %s: %s',
  4456.         dateType,
  4457.         tostring(dateString)
  4458.     ), 4)
  4459. end
  4460.  
  4461. local function makeFullUrl(page, query, display)
  4462.     return string.format(
  4463.         '[%s %s]',
  4464.         tostring(mw.uri.fullUrl(page, query)),
  4465.         display
  4466.     )
  4467. end
  4468.  
  4469. -- Given a directed graph formatted as node -&gt; table of direct successors,
  4470. -- get a table of all nodes reachable from a given node (though always
  4471. -- including the given node).
  4472. local function getReachableNodes(graph, start)
  4473.     local toWalk, retval = {[start] = true}, {}
  4474.     while true do
  4475.         -- Can't use pairs() since we're adding and removing things as we're iterating
  4476.         local k = next(toWalk) -- This always gets the "first" key
  4477.         if k == nil then
  4478.             return retval
  4479.         end
  4480.         toWalk[k] = nil
  4481.         retval[k] = true
  4482.         for _,v in ipairs(graph[k]) do
  4483.             if not retval[v] then
  4484.                 toWalk[v] = true
  4485.             end
  4486.         end
  4487.     end
  4488. end
  4489.  
  4490. --------------------------------------------------------------------------------
  4491. -- Protection class
  4492. --------------------------------------------------------------------------------
  4493.  
  4494. local Protection = {}
  4495. Protection.__index = Protection
  4496.  
  4497. Protection.supportedActions = {
  4498.     edit = true,
  4499.     move = true,
  4500.     autoreview = true,
  4501.     upload = true
  4502. }
  4503.  
  4504. Protection.bannerConfigFields = {
  4505.     'text',
  4506.     'explanation',
  4507.     'tooltip',
  4508.     'alt',
  4509.     'link',
  4510.     'image'
  4511. }
  4512.  
  4513. function Protection.new(args, cfg, title)
  4514.     local obj = {}
  4515.     obj._cfg = cfg
  4516.     obj.title = title or mw.title.getCurrentTitle()
  4517.  
  4518.     -- Set action
  4519.     if not args.action then
  4520.         obj.action = 'edit'
  4521.     elseif Protection.supportedActions[args.action] then
  4522.         obj.action = args.action
  4523.     else
  4524.         error(string.format(
  4525.             'invalid action: %s',
  4526.             tostring(args.action)
  4527.         ), 3)
  4528.     end
  4529.  
  4530.     -- Set level
  4531.     obj.level = args.demolevel or effectiveProtectionLevel(obj.action, obj.title)
  4532.     if not obj.level or (obj.action == 'move' and obj.level == 'autoconfirmed') then
  4533.         -- Users need to be autoconfirmed to move pages anyway, so treat
  4534.         -- semi-move-protected pages as unprotected.
  4535.         obj.level = '*'
  4536.     end
  4537.  
  4538.     -- Set expiry
  4539.     local effectiveExpiry = effectiveProtectionExpiry(obj.action, obj.title)
  4540.     if effectiveExpiry == 'infinity' then
  4541.         obj.expiry = 'indef'
  4542.     elseif effectiveExpiry ~= 'unknown' then
  4543.         obj.expiry = validateDate(effectiveExpiry, 'expiry date')
  4544.     end
  4545.  
  4546.     -- Set reason
  4547.     if args[1] then
  4548.         obj.reason = mw.ustring.lower(args[1])
  4549.         if obj.reason:find('|') then
  4550.             error('reasons cannot contain the pipe character ("|")', 3)
  4551.         end
  4552.     end
  4553.  
  4554.     -- Set protection date
  4555.     if args.date then
  4556.         obj.protectionDate = validateDate(args.date, 'protection date')
  4557.     end
  4558.    
  4559.     -- Set banner config
  4560.     do
  4561.         obj.bannerConfig = {}
  4562.         local configTables = {}
  4563.         if cfg.banners[obj.action] then
  4564.             configTables[#configTables + 1] = cfg.banners[obj.action][obj.reason]
  4565.         end
  4566.         if cfg.defaultBanners[obj.action] then
  4567.             configTables[#configTables + 1] = cfg.defaultBanners[obj.action][obj.level]
  4568.             configTables[#configTables + 1] = cfg.defaultBanners[obj.action].default
  4569.         end
  4570.         configTables[#configTables + 1] = cfg.masterBanner
  4571.         for i, field in ipairs(Protection.bannerConfigFields) do
  4572.             for j, t in ipairs(configTables) do
  4573.                 if t[field] then
  4574.                     obj.bannerConfig[field] = t[field]
  4575.                     break
  4576.                 end
  4577.             end
  4578.         end
  4579.     end
  4580.     return setmetatable(obj, Protection)
  4581. end
  4582.  
  4583. function Protection:isUserScript()
  4584.     -- Whether the page is a user JavaScript or CSS page.
  4585.     local title = self.title
  4586.     return title.namespace == 2 and (
  4587.         title.contentModel == 'javascript' or title.contentModel == 'css'
  4588.     )
  4589. end
  4590.  
  4591. function Protection:isProtected()
  4592.     return self.level ~= '*'
  4593. end
  4594.  
  4595. function Protection:shouldShowLock()
  4596.     -- Whether we should output a banner/padlock
  4597.     return self:isProtected() and not self:isUserScript()
  4598. end
  4599.  
  4600. -- Whether this page needs a protection category.
  4601. Protection.shouldHaveProtectionCategory = Protection.shouldShowLock
  4602.  
  4603. function Protection:isTemporary()
  4604.     return type(self.expiry) == 'number'
  4605. end
  4606.  
  4607. function Protection:makeProtectionCategory()
  4608.     if not self:shouldHaveProtectionCategory() then
  4609.         return ''
  4610.     end
  4611.  
  4612.     local cfg = self._cfg
  4613.     local title = self.title
  4614.    
  4615.     -- Get the expiry key fragment.
  4616.     local expiryFragment
  4617.     if self.expiry == 'indef' then
  4618.         expiryFragment = self.expiry
  4619.     elseif type(self.expiry) == 'number' then
  4620.         expiryFragment = 'temp'
  4621.     end
  4622.  
  4623.     -- Get the namespace key fragment.
  4624.     local namespaceFragment = cfg.categoryNamespaceKeys[title.namespace]
  4625.     if not namespaceFragment and title.namespace % 2 == 1 then
  4626.             namespaceFragment = 'talk'
  4627.     end
  4628.  
  4629.     -- Define the order that key fragments are tested in. This is done with an
  4630.     -- array of tables containing the value to be tested, along with its
  4631.     -- position in the cfg.protectionCategories table.
  4632.     local order = {
  4633.         {val = expiryFragment,    keypos = 1},
  4634.         {val = namespaceFragment, keypos = 2},
  4635.         {val = self.reason,       keypos = 3},
  4636.         {val = self.level,        keypos = 4},
  4637.         {val = self.action,       keypos = 5}
  4638.     }
  4639.  
  4640.     --[[
  4641.     -- The old protection templates used an ad-hoc protection category system,
  4642.     -- with some templates prioritising namespaces in their categories, and
  4643.     -- others prioritising the protection reason. To emulate this in this module
  4644.     -- we use the config table cfg.reasonsWithNamespacePriority to set the
  4645.     -- reasons for which namespaces have priority over protection reason.
  4646.     -- If we are dealing with one of those reasons, move the namespace table to
  4647.     -- the end of the order table, i.e. give it highest priority. If not, the
  4648.     -- reason should have highest priority, so move that to the end of the table
  4649.     -- instead.
  4650.     --]]
  4651.     table.insert(order, table.remove(order, self.reason and cfg.reasonsWithNamespacePriority[self.reason] and 2 or 3))
  4652.  
  4653.     --[[
  4654.     -- Define the attempt order. Inactive subtables (subtables with nil "value"
  4655.     -- fields) are moved to the end, where they will later be given the key
  4656.     -- "all". This is to cut down on the number of table lookups in
  4657.     -- cfg.protectionCategories, which grows exponentially with the number of
  4658.     -- non-nil keys. We keep track of the number of active subtables with the
  4659.     -- noActive parameter.
  4660.     --]]
  4661.     local noActive, attemptOrder
  4662.     do
  4663.         local active, inactive = {}, {}
  4664.         for i, t in ipairs(order) do
  4665.             if t.val then
  4666.                 active[#active + 1] = t
  4667.             else
  4668.                 inactive[#inactive + 1] = t
  4669.             end
  4670.         end
  4671.         noActive = #active
  4672.         attemptOrder = active
  4673.         for i, t in ipairs(inactive) do
  4674.             attemptOrder[#attemptOrder + 1] = t
  4675.         end
  4676.     end
  4677.  
  4678.     --[[
  4679.     -- Check increasingly generic key combinations until we find a match. If a
  4680.     -- specific category exists for the combination of key fragments we are
  4681.     -- given, that match will be found first. If not, we keep trying different
  4682.     -- key fragment combinations until we match using the key
  4683.     -- "all-all-all-all-all".
  4684.     --
  4685.     -- To generate the keys, we index the key subtables using a binary matrix
  4686.     -- with indexes i and j. j is only calculated up to the number of active
  4687.     -- subtables. For example, if there were three active subtables, the matrix
  4688.     -- would look like this, with 0 corresponding to the key fragment "all", and
  4689.     -- 1 corresponding to other key fragments.
  4690.     --
  4691.     --   j 1  2  3
  4692.     -- i  
  4693.     -- 1   1  1  1
  4694.     -- 2   0  1  1
  4695.     -- 3   1  0  1
  4696.     -- 4   0  0  1
  4697.     -- 5   1  1  0
  4698.     -- 6   0  1  0
  4699.     -- 7   1  0  0
  4700.     -- 8   0  0  0
  4701.     --
  4702.     -- Values of j higher than the number of active subtables are set
  4703.     -- to the string "all".
  4704.     --
  4705.     -- A key for cfg.protectionCategories is constructed for each value of i.
  4706.     -- The position of the value in the key is determined by the keypos field in
  4707.     -- each subtable.
  4708.     --]]
  4709.     local cats = cfg.protectionCategories
  4710.     for i = 1, 2^noActive do
  4711.         local key = {}
  4712.         for j, t in ipairs(attemptOrder) do
  4713.             if j &gt; noActive then
  4714.                 key[t.keypos] = 'all'
  4715.             else
  4716.                 local quotient = i / 2 ^ (j - 1)
  4717.                 quotient = math.ceil(quotient)
  4718.                 if quotient % 2 == 1 then
  4719.                     key[t.keypos] = t.val
  4720.                 else
  4721.                     key[t.keypos] = 'all'
  4722.                 end
  4723.             end
  4724.         end
  4725.         key = table.concat(key, '|')
  4726.         local attempt = cats[key]
  4727.         if attempt then
  4728.             return makeCategoryLink(attempt, title.text)
  4729.         end
  4730.     end
  4731.     return ''
  4732. end
  4733.  
  4734. function Protection:isIncorrect()
  4735.     local expiry = self.expiry
  4736.     return not self:shouldHaveProtectionCategory()
  4737.         or type(expiry) == 'number' and expiry &lt; os.time()
  4738. end
  4739.  
  4740. function Protection:isTemplateProtectedNonTemplate()
  4741.     local action, namespace = self.action, self.title.namespace
  4742.     return self.level == 'templateeditor'
  4743.         and (
  4744.             (action ~= 'edit' and action ~= 'move')
  4745.             or (namespace ~= 10 and namespace ~= 828)
  4746.         )
  4747. end
  4748.  
  4749. function Protection:makeCategoryLinks()
  4750.     local msg = self._cfg.msg
  4751.     local ret = {self:makeProtectionCategory()}
  4752.     if self:isIncorrect() then
  4753.         ret[#ret + 1] = makeCategoryLink(
  4754.             msg['tracking-category-incorrect'],
  4755.             self.title.text
  4756.         )
  4757.     end
  4758.     if self:isTemplateProtectedNonTemplate() then
  4759.         ret[#ret + 1] = makeCategoryLink(
  4760.             msg['tracking-category-template'],
  4761.             self.title.text
  4762.         )
  4763.     end
  4764.     return table.concat(ret)
  4765. end
  4766.  
  4767. --------------------------------------------------------------------------------
  4768. -- Blurb class
  4769. --------------------------------------------------------------------------------
  4770.  
  4771. local Blurb = {}
  4772. Blurb.__index = Blurb
  4773.  
  4774. Blurb.bannerTextFields = {
  4775.     text = true,
  4776.     explanation = true,
  4777.     tooltip = true,
  4778.     alt = true,
  4779.     link = true
  4780. }
  4781.  
  4782. function Blurb.new(protectionObj, args, cfg)
  4783.     return setmetatable({
  4784.         _cfg = cfg,
  4785.         _protectionObj = protectionObj,
  4786.         _args = args
  4787.     }, Blurb)
  4788. end
  4789.  
  4790. -- Private methods --
  4791.  
  4792. function Blurb:_formatDate(num)
  4793.     -- Formats a Unix timestamp into dd Month, YYYY format.
  4794.     lang = lang or mw.language.getContentLanguage()
  4795.     local success, date = pcall(
  4796.         lang.formatDate,
  4797.         lang,
  4798.         self._cfg.msg['expiry-date-format'] or 'j F Y',
  4799.         '@' .. tostring(num)
  4800.     )
  4801.     if success then
  4802.         return date
  4803.     end
  4804. end
  4805.  
  4806. function Blurb:_getExpandedMessage(msgKey)
  4807.     return self:_substituteParameters(self._cfg.msg[msgKey])
  4808. end
  4809.  
  4810. function Blurb:_substituteParameters(msg)
  4811.     if not self._params then
  4812.         local parameterFuncs = {}
  4813.  
  4814.         parameterFuncs.CURRENTVERSION     = self._makeCurrentVersionParameter
  4815.         parameterFuncs.EDITREQUEST        = self._makeEditRequestParameter
  4816.         parameterFuncs.EXPIRY             = self._makeExpiryParameter
  4817.         parameterFuncs.EXPLANATIONBLURB   = self._makeExplanationBlurbParameter
  4818.         parameterFuncs.IMAGELINK          = self._makeImageLinkParameter
  4819.         parameterFuncs.INTROBLURB         = self._makeIntroBlurbParameter
  4820.         parameterFuncs.INTROFRAGMENT      = self._makeIntroFragmentParameter
  4821.         parameterFuncs.PAGETYPE           = self._makePagetypeParameter
  4822.         parameterFuncs.PROTECTIONBLURB    = self._makeProtectionBlurbParameter
  4823.         parameterFuncs.PROTECTIONDATE     = self._makeProtectionDateParameter
  4824.         parameterFuncs.PROTECTIONLEVEL    = self._makeProtectionLevelParameter
  4825.         parameterFuncs.PROTECTIONLOG      = self._makeProtectionLogParameter
  4826.         parameterFuncs.TALKPAGE           = self._makeTalkPageParameter
  4827.         parameterFuncs.TOOLTIPBLURB       = self._makeTooltipBlurbParameter
  4828.         parameterFuncs.TOOLTIPFRAGMENT    = self._makeTooltipFragmentParameter
  4829.         parameterFuncs.VANDAL             = self._makeVandalTemplateParameter
  4830.        
  4831.         self._params = setmetatable({}, {
  4832.             __index = function (t, k)
  4833.                 local param
  4834.                 if parameterFuncs[k] then
  4835.                     param = parameterFuncs[k](self)
  4836.                 end
  4837.                 param = param or ''
  4838.                 t[k] = param
  4839.                 return param
  4840.             end
  4841.         })
  4842.     end
  4843.    
  4844.     msg = msg:gsub('${(%u+)}', self._params)
  4845.     return msg
  4846. end
  4847.  
  4848. function Blurb:_makeCurrentVersionParameter()
  4849.     -- A link to the page history or the move log, depending on the kind of
  4850.     -- protection.
  4851.     local pagename = self._protectionObj.title.prefixedText
  4852.     if self._protectionObj.action == 'move' then
  4853.         -- We need the move log link.
  4854.         return makeFullUrl(
  4855.             'Special:Log',
  4856.             {type = 'move', page = pagename},
  4857.             self:_getExpandedMessage('current-version-move-display')
  4858.         )
  4859.     else
  4860.         -- We need the history link.
  4861.         return makeFullUrl(
  4862.             pagename,
  4863.             {action = 'history'},
  4864.             self:_getExpandedMessage('current-version-edit-display')
  4865.         )
  4866.     end
  4867. end
  4868.  
  4869. function Blurb:_makeEditRequestParameter()
  4870.     local mEditRequest = require('Module:Submit an edit request')
  4871.     local action = self._protectionObj.action
  4872.     local level = self._protectionObj.level
  4873.    
  4874.     -- Get the edit request type.
  4875.     local requestType
  4876.     if action == 'edit' then
  4877.         if level == 'autoconfirmed' then
  4878.             requestType = 'semi'
  4879.         elseif level == 'extendedconfirmed' then
  4880.             requestType = 'extended'
  4881.         elseif level == 'templateeditor' then
  4882.             requestType = 'template'
  4883.         end
  4884.     end
  4885.     requestType = requestType or 'full'
  4886.    
  4887.     -- Get the display value.
  4888.     local display = self:_getExpandedMessage('edit-request-display')
  4889.  
  4890.     return mEditRequest._link{type = requestType, display = display}
  4891. end
  4892.  
  4893. function Blurb:_makeExpiryParameter()
  4894.     local expiry = self._protectionObj.expiry
  4895.     if type(expiry) == 'number' then
  4896.         return self:_formatDate(expiry)
  4897.     else
  4898.         return expiry
  4899.     end
  4900. end
  4901.  
  4902. function Blurb:_makeExplanationBlurbParameter()
  4903.     -- Cover special cases first.
  4904.     if self._protectionObj.title.namespace == 8 then
  4905.         -- MediaWiki namespace
  4906.         return self:_getExpandedMessage('explanation-blurb-nounprotect')
  4907.     end
  4908.  
  4909.     -- Get explanation blurb table keys
  4910.     local action = self._protectionObj.action
  4911.     local level = self._protectionObj.level
  4912.     local talkKey = self._protectionObj.title.isTalkPage and 'talk' or 'subject'
  4913.  
  4914.     -- Find the message in the explanation blurb table and substitute any
  4915.     -- parameters.
  4916.     local explanations = self._cfg.explanationBlurbs
  4917.     local msg
  4918.     if explanations[action][level] and explanations[action][level][talkKey] then
  4919.         msg = explanations[action][level][talkKey]
  4920.     elseif explanations[action][level] and explanations[action][level].default then
  4921.         msg = explanations[action][level].default
  4922.     elseif explanations[action].default and explanations[action].default[talkKey] then
  4923.         msg = explanations[action].default[talkKey]
  4924.     elseif explanations[action].default and explanations[action].default.default then
  4925.         msg = explanations[action].default.default
  4926.     else
  4927.         error(string.format(
  4928.             'could not find explanation blurb for action "%s", level "%s" and talk key "%s"',
  4929.             action,
  4930.             level,
  4931.             talkKey
  4932.         ), 8)
  4933.     end
  4934.     return self:_substituteParameters(msg)
  4935. end
  4936.  
  4937. function Blurb:_makeImageLinkParameter()
  4938.     local imageLinks = self._cfg.imageLinks
  4939.     local action = self._protectionObj.action
  4940.     local level = self._protectionObj.level
  4941.     local msg
  4942.     if imageLinks[action][level] then
  4943.         msg = imageLinks[action][level]
  4944.     elseif imageLinks[action].default then
  4945.         msg = imageLinks[action].default
  4946.     else
  4947.         msg = imageLinks.edit.default
  4948.     end
  4949.     return self:_substituteParameters(msg)
  4950. end
  4951.  
  4952. function Blurb:_makeIntroBlurbParameter()
  4953.     if self._protectionObj:isTemporary() then
  4954.         return self:_getExpandedMessage('intro-blurb-expiry')
  4955.     else
  4956.         return self:_getExpandedMessage('intro-blurb-noexpiry')
  4957.     end
  4958. end
  4959.  
  4960. function Blurb:_makeIntroFragmentParameter()
  4961.     if self._protectionObj:isTemporary() then
  4962.         return self:_getExpandedMessage('intro-fragment-expiry')
  4963.     else
  4964.         return self:_getExpandedMessage('intro-fragment-noexpiry')
  4965.     end
  4966. end
  4967.  
  4968. function Blurb:_makePagetypeParameter()
  4969.     local pagetypes = self._cfg.pagetypes
  4970.     return pagetypes[self._protectionObj.title.namespace]
  4971.         or pagetypes.default
  4972.         or error('no default pagetype defined', 8)
  4973. end
  4974.  
  4975. function Blurb:_makeProtectionBlurbParameter()
  4976.     local protectionBlurbs = self._cfg.protectionBlurbs
  4977.     local action = self._protectionObj.action
  4978.     local level = self._protectionObj.level
  4979.     local msg
  4980.     if protectionBlurbs[action][level] then
  4981.         msg = protectionBlurbs[action][level]
  4982.     elseif protectionBlurbs[action].default then
  4983.         msg = protectionBlurbs[action].default
  4984.     elseif protectionBlurbs.edit.default then
  4985.         msg = protectionBlurbs.edit.default
  4986.     else
  4987.         error('no protection blurb defined for protectionBlurbs.edit.default', 8)
  4988.     end
  4989.     return self:_substituteParameters(msg)
  4990. end
  4991.  
  4992. function Blurb:_makeProtectionDateParameter()
  4993.     local protectionDate = self._protectionObj.protectionDate
  4994.     if type(protectionDate) == 'number' then
  4995.         return self:_formatDate(protectionDate)
  4996.     else
  4997.         return protectionDate
  4998.     end
  4999. end
  5000.  
  5001. function Blurb:_makeProtectionLevelParameter()
  5002.     local protectionLevels = self._cfg.protectionLevels
  5003.     local action = self._protectionObj.action
  5004.     local level = self._protectionObj.level
  5005.     local msg
  5006.     if protectionLevels[action][level] then
  5007.         msg = protectionLevels[action][level]
  5008.     elseif protectionLevels[action].default then
  5009.         msg = protectionLevels[action].default
  5010.     elseif protectionLevels.edit.default then
  5011.         msg = protectionLevels.edit.default
  5012.     else
  5013.         error('no protection level defined for protectionLevels.edit.default', 8)
  5014.     end
  5015.     return self:_substituteParameters(msg)
  5016. end
  5017.  
  5018. function Blurb:_makeProtectionLogParameter()
  5019.     local pagename = self._protectionObj.title.prefixedText
  5020.     if self._protectionObj.action == 'autoreview' then
  5021.         -- We need the pending changes log.
  5022.         return makeFullUrl(
  5023.             'Special:Log',
  5024.             {type = 'stable', page = pagename},
  5025.             self:_getExpandedMessage('pc-log-display')
  5026.         )
  5027.     else
  5028.         -- We need the protection log.
  5029.         return makeFullUrl(
  5030.             'Special:Log',
  5031.             {type = 'protect', page = pagename},
  5032.             self:_getExpandedMessage('protection-log-display')
  5033.         )
  5034.     end
  5035. end
  5036.  
  5037. function Blurb:_makeTalkPageParameter()
  5038.     return string.format(
  5039.         '[[%s:%s#%s|%s]]',
  5040.         mw.site.namespaces[self._protectionObj.title.namespace].talk.name,
  5041.         self._protectionObj.title.text,
  5042.         self._args.section or 'top',
  5043.         self:_getExpandedMessage('talk-page-link-display')
  5044.     )
  5045. end
  5046.  
  5047. function Blurb:_makeTooltipBlurbParameter()
  5048.     if self._protectionObj:isTemporary() then
  5049.         return self:_getExpandedMessage('tooltip-blurb-expiry')
  5050.     else
  5051.         return self:_getExpandedMessage('tooltip-blurb-noexpiry')
  5052.     end
  5053. end
  5054.  
  5055. function Blurb:_makeTooltipFragmentParameter()
  5056.     if self._protectionObj:isTemporary() then
  5057.         return self:_getExpandedMessage('tooltip-fragment-expiry')
  5058.     else
  5059.         return self:_getExpandedMessage('tooltip-fragment-noexpiry')
  5060.     end
  5061. end
  5062.  
  5063. function Blurb:_makeVandalTemplateParameter()
  5064.     return mw.getCurrentFrame():expandTemplate{
  5065.         title="vandal-m",
  5066.         args={self._args.user or self._protectionObj.title.baseText}
  5067.     }
  5068. end
  5069.  
  5070. -- Public methods --
  5071.  
  5072. function Blurb:makeBannerText(key)
  5073.     -- Validate input.
  5074.     if not key or not Blurb.bannerTextFields[key] then
  5075.         error(string.format(
  5076.             '"%s" is not a valid banner config field',
  5077.             tostring(key)
  5078.         ), 2)
  5079.     end
  5080.  
  5081.     -- Generate the text.
  5082.     local msg = self._protectionObj.bannerConfig[key]
  5083.     if type(msg) == 'string' then
  5084.         return self:_substituteParameters(msg)
  5085.     elseif type(msg) == 'function' then
  5086.         msg = msg(self._protectionObj, self._args)
  5087.         if type(msg) ~= 'string' then
  5088.             error(string.format(
  5089.                 'bad output from banner config function with key "%s"'
  5090.                     .. ' (expected string, got %s)',
  5091.                 tostring(key),
  5092.                 type(msg)
  5093.             ), 4)
  5094.         end
  5095.         return self:_substituteParameters(msg)
  5096.     end
  5097. end
  5098.  
  5099. --------------------------------------------------------------------------------
  5100. -- BannerTemplate class
  5101. --------------------------------------------------------------------------------
  5102.  
  5103. local BannerTemplate = {}
  5104. BannerTemplate.__index = BannerTemplate
  5105.  
  5106. function BannerTemplate.new(protectionObj, cfg)
  5107.     local obj = {}
  5108.     obj._cfg = cfg
  5109.  
  5110.     -- Set the image filename.
  5111.     local imageFilename = protectionObj.bannerConfig.image
  5112.     if imageFilename then
  5113.         obj._imageFilename = imageFilename
  5114.     else
  5115.         -- If an image filename isn't specified explicitly in the banner config,
  5116.         -- generate it from the protection status and the namespace.
  5117.         local action = protectionObj.action
  5118.         local level = protectionObj.level
  5119.         local namespace = protectionObj.title.namespace
  5120.         local reason = protectionObj.reason
  5121.        
  5122.         -- Deal with special cases first.
  5123.         if (
  5124.             namespace == 10
  5125.             or namespace == 828
  5126.             or reason and obj._cfg.indefImageReasons[reason]
  5127.             )
  5128.             and action == 'edit'
  5129.             and level == 'sysop'
  5130.             and not protectionObj:isTemporary()
  5131.         then
  5132.             -- Fully protected modules and templates get the special red "indef"
  5133.             -- padlock.
  5134.             obj._imageFilename = obj._cfg.msg['image-filename-indef']
  5135.         else
  5136.             -- Deal with regular protection types.
  5137.             local images = obj._cfg.images
  5138.             if images[action] then
  5139.                 if images[action][level] then
  5140.                     obj._imageFilename = images[action][level]
  5141.                 elseif images[action].default then
  5142.                     obj._imageFilename = images[action].default
  5143.                 end
  5144.             end
  5145.         end
  5146.     end
  5147.     return setmetatable(obj, BannerTemplate)
  5148. end
  5149.  
  5150. function BannerTemplate:renderImage()
  5151.     local filename = self._imageFilename
  5152.         or self._cfg.msg['image-filename-default']
  5153.         or 'Transparent.gif'
  5154.     return makeFileLink{
  5155.         file = filename,
  5156.         size = (self.imageWidth or 20) .. 'px',
  5157.         alt = self._imageAlt,
  5158.         link = self._imageLink,
  5159.         caption = self.imageCaption
  5160.     }
  5161. end
  5162.  
  5163. --------------------------------------------------------------------------------
  5164. -- Banner class
  5165. --------------------------------------------------------------------------------
  5166.  
  5167. local Banner = setmetatable({}, BannerTemplate)
  5168. Banner.__index = Banner
  5169.  
  5170. function Banner.new(protectionObj, blurbObj, cfg)
  5171.     local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.
  5172.     obj.imageWidth = 40
  5173.     obj.imageCaption = blurbObj:makeBannerText('alt') -- Large banners use the alt text for the tooltip.
  5174.     obj._reasonText = blurbObj:makeBannerText('text')
  5175.     obj._explanationText = blurbObj:makeBannerText('explanation')
  5176.     obj._page = protectionObj.title.prefixedText -- Only makes a difference in testing.
  5177.     return setmetatable(obj, Banner)
  5178. end
  5179.  
  5180. function Banner:__tostring()
  5181.     -- Renders the banner.
  5182.     makeMessageBox = makeMessageBox or require('Module:Message box').main
  5183.     local reasonText = self._reasonText or error('no reason text set', 2)
  5184.     local explanationText = self._explanationText
  5185.     local mbargs = {
  5186.         page = self._page,
  5187.         type = 'protection',
  5188.         image = self:renderImage(),
  5189.         text = string.format(
  5190.             "'''%s'''%s",
  5191.             reasonText,
  5192.             explanationText and '&lt;br /&gt;' .. explanationText or ''
  5193.         )
  5194.     }
  5195.     return makeMessageBox('mbox', mbargs)
  5196. end
  5197.  
  5198. --------------------------------------------------------------------------------
  5199. -- Padlock class
  5200. --------------------------------------------------------------------------------
  5201.  
  5202. local Padlock = setmetatable({}, BannerTemplate)
  5203. Padlock.__index = Padlock
  5204.  
  5205. function Padlock.new(protectionObj, blurbObj, cfg)
  5206.     local obj = BannerTemplate.new(protectionObj, cfg) -- This doesn't need the blurb.
  5207.     obj.imageWidth = 20
  5208.     obj.imageCaption = blurbObj:makeBannerText('tooltip')
  5209.     obj._imageAlt = blurbObj:makeBannerText('alt')
  5210.     obj._imageLink = blurbObj:makeBannerText('link')
  5211.     obj._indicatorName = cfg.padlockIndicatorNames[protectionObj.action]
  5212.         or cfg.padlockIndicatorNames.default
  5213.         or 'pp-default'
  5214.     return setmetatable(obj, Padlock)
  5215. end
  5216.  
  5217. function Padlock:__tostring()
  5218.     local frame = mw.getCurrentFrame()
  5219.     -- The nowiki tag helps prevent whitespace at the top of articles.
  5220.     return frame:extensionTag{name = 'nowiki'} .. frame:extensionTag{
  5221.         name = 'indicator',
  5222.         args = {name = self._indicatorName},
  5223.         content = self:renderImage()
  5224.     }
  5225. end
  5226.  
  5227. --------------------------------------------------------------------------------
  5228. -- Exports
  5229. --------------------------------------------------------------------------------
  5230.  
  5231. local p = {}
  5232.  
  5233. function p._exportClasses()
  5234.     -- This is used for testing purposes.
  5235.     return {
  5236.         Protection = Protection,
  5237.         Blurb = Blurb,
  5238.         BannerTemplate = BannerTemplate,
  5239.         Banner = Banner,
  5240.         Padlock = Padlock,
  5241.     }
  5242. end
  5243.  
  5244. function p._main(args, cfg, title)
  5245.     args = args or {}
  5246.     cfg = cfg or require(CONFIG_MODULE)
  5247.  
  5248.     local protectionObj = Protection.new(args, cfg, title)
  5249.  
  5250.     local ret = {}
  5251.  
  5252.     -- If a page's edit protection is equally or more restrictive than its
  5253.     -- protection from some other action, then don't bother displaying anything
  5254.     -- for the other action (except categories).
  5255.     if not yesno(args.catonly) and (protectionObj.action == 'edit' or
  5256.         args.demolevel or
  5257.         not getReachableNodes(
  5258.             cfg.hierarchy,
  5259.             protectionObj.level
  5260.         )[effectiveProtectionLevel('edit', protectionObj.title)])
  5261.     then
  5262.         -- Initialise the blurb object
  5263.         local blurbObj = Blurb.new(protectionObj, args, cfg)
  5264.    
  5265.         -- Render the banner
  5266.         if protectionObj:shouldShowLock() then
  5267.             ret[#ret + 1] = tostring(
  5268.                 (yesno(args.small) and Padlock or Banner)
  5269.                 .new(protectionObj, blurbObj, cfg)
  5270.             )
  5271.         end
  5272.     end
  5273.  
  5274.     -- Render the categories
  5275.     if yesno(args.category) ~= false then
  5276.         ret[#ret + 1] = protectionObj:makeCategoryLinks()
  5277.     end
  5278.    
  5279.     return table.concat(ret)   
  5280. end
  5281.  
  5282. function p.main(frame, cfg)
  5283.     cfg = cfg or require(CONFIG_MODULE)
  5284.  
  5285.     -- Find default args, if any.
  5286.     local parent = frame.getParent and frame:getParent()
  5287.     local defaultArgs = parent and cfg.wrappers[parent:getTitle():gsub('/sandbox$', '')]
  5288.  
  5289.     -- Find user args, and use the parent frame if we are being called from a
  5290.     -- wrapper template.
  5291.     getArgs = getArgs or require('Module:Arguments').getArgs
  5292.     local userArgs = getArgs(frame, {
  5293.         parentOnly = defaultArgs,
  5294.         frameOnly = not defaultArgs
  5295.     })
  5296.  
  5297.     -- Build the args table. User-specified args overwrite default args.
  5298.     local args = {}
  5299.     for k, v in pairs(defaultArgs or {}) do
  5300.         args[k] = v
  5301.     end
  5302.     for k, v in pairs(userArgs) do
  5303.         args[k] = v
  5304.     end
  5305.     return p._main(args, cfg)
  5306. end
  5307.  
  5308. return p</text>
  5309.       <sha1>ktral6mmlw9hhlxwgaq85237qklrdx8</sha1>
  5310.     </revision>
  5311.   </page>
  5312.   <page>
  5313.     <title>Module:Protection banner/config</title>
  5314.     <ns>828</ns>
  5315.     <id>42982788</id>
  5316.     <revision>
  5317.       <id>1069763876</id>
  5318.       <parentid>1053458493</parentid>
  5319.       <timestamp>2022-02-03T23:49:55Z</timestamp>
  5320.       <contributor>
  5321.         <username>Andrybak</username>
  5322.         <id>23735172</id>
  5323.       </contributor>
  5324.       <comment>add categorization into [[:Category:Wikipedia extended-confirmed-protected modules]] per [[Special:Diff/1069761256|request]]</comment>
  5325.       <model>Scribunto</model>
  5326.       <format>text/plain</format>
  5327.       <text bytes="46228" xml:space="preserve">-- This module provides configuration data for [[Module:Protection banner]].
  5328.  
  5329. return {
  5330.  
  5331. --------------------------------------------------------------------------------
  5332. --
  5333. --                                BANNER DATA
  5334. --
  5335. --------------------------------------------------------------------------------
  5336.  
  5337. --[[
  5338. -- Banner data consists of six fields:
  5339. -- * text - the main protection text that appears at the top of protection
  5340. --   banners.
  5341. -- * explanation - the text that appears below the main protection text, used
  5342. --   to explain the details of the protection.
  5343. -- * tooltip - the tooltip text you see when you move the mouse over a small
  5344. --   padlock icon.
  5345. -- * link - the page that the small padlock icon links to.
  5346. -- * alt - the alt text for the small padlock icon. This is also used as tooltip
  5347. --   text for the large protection banners.
  5348. -- * image - the padlock image used in both protection banners and small padlock
  5349. --   icons.
  5350. --
  5351. -- The module checks in three separate tables to find a value for each field.
  5352. -- First it checks the banners table, which has values specific to the reason
  5353. -- for the page being protected. Then the module checks the defaultBanners
  5354. -- table, which has values specific to each protection level. Finally, the
  5355. -- module checks the masterBanner table, which holds data for protection
  5356. -- templates to use if no data has been found in the previous two tables.
  5357. --
  5358. -- The values in the banner data can take parameters. These are specified
  5359. -- using ${TEXTLIKETHIS} (a dollar sign preceding a parameter name
  5360. -- enclosed in curly braces).
  5361. --
  5362. --                          Available parameters:
  5363. --
  5364. -- ${CURRENTVERSION} - a link to the page history or the move log, with the
  5365. -- display message "current-version-edit-display" or
  5366. -- "current-version-move-display".
  5367. --
  5368. -- ${EDITREQUEST} - a link to create an edit request for the current page.
  5369. --
  5370. -- ${EXPLANATIONBLURB} - an explanation blurb, e.g. "Please discuss any changes
  5371. -- on the talk page; you may submit a request to ask an administrator to make
  5372. -- an edit if it is minor or supported by consensus."
  5373. --
  5374. -- ${IMAGELINK} - a link to set the image to, depending on the protection
  5375. -- action and protection level.
  5376. --
  5377. -- ${INTROBLURB} - the PROTECTIONBLURB parameter, plus the expiry if an expiry
  5378. -- is set. E.g. "Editing of this page by new or unregistered users is currently
  5379. -- disabled until dd Month YYYY."
  5380. --
  5381. -- ${INTROFRAGMENT} - the same as ${INTROBLURB}, but without final punctuation
  5382. -- so that it can be used in run-on sentences.
  5383. --
  5384. -- ${PAGETYPE} - the type of the page, e.g. "article" or "template".
  5385. -- Defined in the cfg.pagetypes table.
  5386. --
  5387. -- ${PROTECTIONBLURB} - a blurb explaining the protection level of the page, e.g.
  5388. -- "Editing of this page by new or unregistered users is currently disabled"
  5389. --
  5390. -- ${PROTECTIONDATE} - the protection date, if it has been supplied to the
  5391. -- template.
  5392. --
  5393. -- ${PROTECTIONLEVEL} - the protection level, e.g. "fully protected" or
  5394. -- "semi-protected".
  5395. --
  5396. -- ${PROTECTIONLOG} - a link to the protection log or the pending changes log,
  5397. -- depending on the protection action.
  5398. --
  5399. -- ${TALKPAGE} - a link to the talk page. If a section is specified, links
  5400. -- straight to that talk page section.
  5401. --
  5402. -- ${TOOLTIPBLURB} - uses the PAGETYPE, PROTECTIONTYPE and EXPIRY parameters to
  5403. -- create a blurb like "This template is semi-protected", or "This article is
  5404. -- move-protected until DD Month YYYY".
  5405. --
  5406. -- ${VANDAL} - links for the specified username (or the root page name)
  5407. -- using Module:Vandal-m.
  5408. --
  5409. --                                 Functions
  5410. --
  5411. -- For advanced users, it is possible to use Lua functions instead of strings
  5412. -- in the banner config tables. Using functions gives flexibility that is not
  5413. -- possible just by using parameters. Functions take two arguments, the
  5414. -- protection object and the template arguments, and they must output a string.
  5415. --
  5416. -- For example:
  5417. --
  5418. -- text = function (protectionObj, args)
  5419. --     if protectionObj.level == 'autoconfirmed' then
  5420. --         return 'foo'
  5421. --     else
  5422. --         return 'bar'
  5423. --     end
  5424. -- end
  5425. --
  5426. -- Some protection object properties and methods that may be useful:
  5427. -- protectionObj.action - the protection action
  5428. -- protectionObj.level - the protection level
  5429. -- protectionObj.reason - the protection reason
  5430. -- protectionObj.expiry - the expiry. Nil if unset, the string "indef" if set
  5431. --     to indefinite, and the protection time in unix time if temporary.
  5432. -- protectionObj.protectionDate - the protection date in unix time, or nil if
  5433. --     unspecified.
  5434. -- protectionObj.bannerConfig - the banner config found by the module. Beware
  5435. --     of editing the config field used by the function, as it could create an
  5436. --     infinite loop.
  5437. -- protectionObj:isProtected - returns a boolean showing whether the page is
  5438. --     protected.
  5439. -- protectionObj:isTemporary - returns a boolean showing whether the expiry is
  5440. --     temporary.
  5441. -- protectionObj:isIncorrect - returns a boolean showing whether the protection
  5442. --     template is incorrect.
  5443. --]]
  5444.  
  5445. -- The master banner data, used if no values have been found in banners or
  5446. -- defaultBanners.
  5447. masterBanner = {
  5448.     text = '${INTROBLURB}',
  5449.     explanation = '${EXPLANATIONBLURB}',
  5450.     tooltip = '${TOOLTIPBLURB}',
  5451.     link = '${IMAGELINK}',
  5452.     alt = 'Page ${PROTECTIONLEVEL}'
  5453. },
  5454.  
  5455. -- The default banner data. This holds banner data for different protection
  5456. -- levels.
  5457. -- *required* - this table needs edit, move, autoreview and upload subtables.
  5458. defaultBanners = {
  5459.     edit = {},
  5460.     move = {},
  5461.     autoreview = {
  5462.         default = {
  5463.             alt = 'Page protected with pending changes',
  5464.             tooltip = 'All edits by unregistered and new users are subject to review prior to becoming visible to unregistered users',
  5465.             image = 'Pending-protection-shackle.svg'
  5466.         }
  5467.     },
  5468.     upload = {}
  5469. },
  5470.  
  5471. -- The banner data. This holds banner data for different protection reasons.
  5472. -- In fact, the reasons specified in this table control which reasons are
  5473. -- valid inputs to the first positional parameter.
  5474. --
  5475. -- There is also a non-standard "description" field that can be used for items
  5476. -- in this table. This is a description of the protection reason for use in the
  5477. -- module documentation.
  5478. --
  5479. -- *required* - this table needs edit, move, autoreview and upload subtables.
  5480. banners = {
  5481.     edit = {
  5482.         blp = {
  5483.             description = 'For pages protected to promote compliance with the'
  5484.                 .. ' [[Wikipedia:Biographies of living persons'
  5485.                 .. '|biographies of living persons]] policy',
  5486.             text = '${INTROFRAGMENT} to promote compliance with'
  5487.                 .. ' [[Wikipedia:Biographies of living persons'
  5488.                 .. "|Wikipedia's&amp;nbsp;policy on&amp;nbsp;the&amp;nbsp;biographies"
  5489.                 .. ' of&amp;nbsp;living&amp;nbsp;people]].',
  5490.             tooltip = '${TOOLTIPFRAGMENT} to promote compliance with the policy on'
  5491.                 .. ' biographies of living persons',
  5492.         },
  5493.         dmca = {
  5494.             description = 'For pages protected by the Wikimedia Foundation'
  5495.                 .. ' due to [[Digital Millennium Copyright Act]] takedown requests',
  5496.             explanation = function (protectionObj, args)
  5497.                 local ret = 'Pursuant to a rights owner notice under the Digital'
  5498.                     .. ' Millennium Copyright Act (DMCA) regarding some content'
  5499.                     .. ' in this article, the Wikimedia Foundation acted under'
  5500.                     .. ' applicable law and took down and restricted the content'
  5501.                     .. ' in question.'
  5502.                 if args.notice then
  5503.                     ret = ret .. ' A copy of the received notice can be found here: '
  5504.                         .. args.notice .. '.'
  5505.                 end
  5506.                 ret = ret .. ' For more information, including websites discussing'
  5507.                     .. ' how to file a counter-notice, please see'
  5508.                     .. " [[Wikipedia:Office actions]] and the article's ${TALKPAGE}."
  5509.                     .. "'''Do not remove this template from the article until the"
  5510.                     .. " restrictions are withdrawn'''."
  5511.                 return ret
  5512.             end,
  5513.             image = 'Office-protection-shackle.svg',
  5514.         },
  5515.         dispute = {
  5516.             description = 'For pages protected due to editing disputes',
  5517.             text = function (protectionObj, args)
  5518.                 -- Find the value of "disputes".
  5519.                 local display = 'disputes'
  5520.                 local disputes
  5521.                 if args.section then
  5522.                     disputes = string.format(
  5523.                         '[[%s:%s#%s|%s]]',
  5524.                         mw.site.namespaces[protectionObj.title.namespace].talk.name,
  5525.                         protectionObj.title.text,
  5526.                         args.section,
  5527.                         display
  5528.                     )
  5529.                 else
  5530.                     disputes = display
  5531.                 end
  5532.  
  5533.                 -- Make the blurb, depending on the expiry.
  5534.                 local msg
  5535.                 if type(protectionObj.expiry) == 'number' then
  5536.                     msg = '${INTROFRAGMENT} or until editing %s have been resolved.'
  5537.                 else
  5538.                     msg = '${INTROFRAGMENT} until editing %s have been resolved.'
  5539.                 end
  5540.                 return string.format(msg, disputes)
  5541.             end,
  5542.             explanation = "This protection is '''not''' an endorsement of the"
  5543.                 .. ' ${CURRENTVERSION}. ${EXPLANATIONBLURB}',
  5544.             tooltip = '${TOOLTIPFRAGMENT} due to editing disputes',
  5545.         },
  5546.         ecp = {
  5547.             description = 'For articles in topic areas authorized by'
  5548.                 .. ' [[Wikipedia:Arbitration Committee|ArbCom]] or'
  5549.                 .. ' meets the criteria for community use',
  5550.             tooltip = 'This ${PAGETYPE} is extended-confirmed protected',
  5551.             alt = 'Extended-protected ${PAGETYPE}',
  5552.         },
  5553.         mainpage = {
  5554.             description = 'For pages protected for being displayed on the [[Main Page]]',
  5555.             text = 'This file is currently'
  5556.                 .. ' [[Wikipedia:This page is protected|protected]] from'
  5557.                 .. ' editing because it is currently or will soon be displayed'
  5558.                 .. ' on the [[Main Page]].',
  5559.             explanation = 'Images on the Main Page are protected due to their high'
  5560.                 .. ' visibility. Please discuss any necessary changes on the ${TALKPAGE}.'
  5561.                 .. '&lt;br /&gt;&lt;span style="font-size:90%;"&gt;'
  5562.                 .. "'''Administrators:''' Once this image is definitely off the Main Page,"
  5563.                 .. ' please unprotect this file, or reduce to semi-protection,'
  5564.                 .. ' as appropriate.&lt;/span&gt;',
  5565.         },
  5566.         office = {
  5567.             description = 'For pages protected by the Wikimedia Foundation',
  5568.             text = function (protectionObj, args)
  5569.                 local ret = 'This ${PAGETYPE} is currently under the'
  5570.                     .. ' scrutiny of the'
  5571.                     .. ' [[Wikipedia:Office actions|Wikimedia Foundation Office]]'
  5572.                     .. ' and is protected.'
  5573.                 if protectionObj.protectionDate then
  5574.                     ret = ret .. ' It has been protected since ${PROTECTIONDATE}.'
  5575.                 end
  5576.                 return ret
  5577.             end,
  5578.             explanation = "If you can edit this page, please discuss all changes and"
  5579.                 .. " additions on the ${TALKPAGE} first. '''Do not remove protection from this"
  5580.                 .. " page unless you are authorized by the Wikimedia Foundation to do"
  5581.                 .. " so.'''",
  5582.             image = 'Office-protection-shackle.svg',
  5583.         },
  5584.         reset = {
  5585.             description = 'For pages protected by the Wikimedia Foundation and'
  5586.                 .. ' "reset" to a bare-bones version',
  5587.             text = 'This ${PAGETYPE} is currently under the'
  5588.                     .. ' scrutiny of the'
  5589.                     .. ' [[Wikipedia:Office actions|Wikimedia Foundation Office]]'
  5590.                     .. ' and is protected.',
  5591.             explanation = function (protectionObj, args)
  5592.                 local ret = ''
  5593.                 if protectionObj.protectionDate then
  5594.                     ret = ret .. 'On ${PROTECTIONDATE} this ${PAGETYPE} was'
  5595.                 else
  5596.                     ret = ret .. 'This ${PAGETYPE} has been'
  5597.                 end
  5598.                 ret = ret .. ' reduced to a'
  5599.                 .. ' simplified, "bare bones" version so that it may be completely'
  5600.                 .. ' rewritten to ensure it meets the policies of'
  5601.                 .. ' [[WP:NPOV|Neutral Point of View]] and [[WP:V|Verifiability]].'
  5602.                 .. ' Standard Wikipedia policies will apply to its rewriting—which'
  5603.                 .. ' will eventually be open to all editors—and will be strictly'
  5604.                 .. ' enforced. The ${PAGETYPE} has been ${PROTECTIONLEVEL} while'
  5605.                 .. ' it is being rebuilt.\n\n'
  5606.                 .. 'Any insertion of material directly from'
  5607.                 .. ' pre-protection revisions of the ${PAGETYPE} will be removed, as'
  5608.                 .. ' will any material added to the ${PAGETYPE} that is not properly'
  5609.                 .. ' sourced. The associated talk page(s) were also cleared on the'
  5610.                 .. " same date.\n\n"
  5611.                 .. "If you can edit this page, please discuss all changes and"
  5612.                 .. " additions on the ${TALKPAGE} first. '''Do not override"
  5613.                 .. " this action, and do not remove protection from this page,"
  5614.                 .. " unless you are authorized by the Wikimedia Foundation"
  5615.                 .. " to do so. No editor may remove this notice.'''"
  5616.  
  5617.                 return ret
  5618.             end,
  5619.             image = 'Office-protection-shackle.svg',
  5620.         },
  5621.         sock = {
  5622.             description = 'For pages protected due to'
  5623.                 .. ' [[Wikipedia:Sock puppetry|sock puppetry]]',
  5624.             text = '${INTROFRAGMENT} to prevent [[Wikipedia:Sock puppetry|sock puppets]] of'
  5625.                 .. ' [[Wikipedia:Blocking policy|blocked]] or'
  5626.                 .. ' [[Wikipedia:Banning policy|banned users]]'
  5627.                 .. ' from editing it.',
  5628.             tooltip = '${TOOLTIPFRAGMENT} to prevent sock puppets of blocked or banned users from'
  5629.                 .. ' editing it',
  5630.         },
  5631.         template = {
  5632.             description = 'For [[Wikipedia:High-risk templates|high-risk]]'
  5633.                 .. ' templates and Lua modules',
  5634.             text = 'This is a permanently [[Help:Protection|protected]] ${PAGETYPE},'
  5635.                 .. ' as it is [[Wikipedia:High-risk templates|high-risk]].',
  5636.             explanation = 'Please discuss any changes on the ${TALKPAGE}; you may'
  5637.                 .. ' ${EDITREQUEST} to ask an'
  5638.                 .. ' [[Wikipedia:Administrators|administrator]] or'
  5639.                 .. ' [[Wikipedia:Template editor|template editor]] to make an edit if'
  5640.                 .. ' it is [[Help:Minor edit#When to mark an edit as a minor edit'
  5641.                 .. '|uncontroversial]] or supported by'
  5642.                 .. ' [[Wikipedia:Consensus|consensus]]. You can also'
  5643.                 .. ' [[Wikipedia:Requests for page protection|request]] that the page be'
  5644.                 .. ' unprotected.',
  5645.             tooltip = 'This high-risk ${PAGETYPE} is permanently ${PROTECTIONLEVEL}'
  5646.                 .. ' to prevent vandalism',
  5647.             alt = 'Permanently protected ${PAGETYPE}',
  5648.         },
  5649.         usertalk = {
  5650.             description = 'For pages protected against disruptive edits by a'
  5651.                 .. ' particular user',
  5652.             text = '${INTROFRAGMENT} to prevent ${VANDAL} from using it to make disruptive edits,'
  5653.                 .. ' such as abusing the'
  5654.                 .. ' &amp;#123;&amp;#123;[[Template:unblock|unblock]]&amp;#125;&amp;#125; template.',
  5655.             explanation = 'If you cannot edit this user talk page and you need to'
  5656.                 .. ' make a change or leave a message, you can'
  5657.                 .. ' [[Wikipedia:Requests for page protection'
  5658.                 .. '#Current requests for edits to a protected page'
  5659.                 .. '|request an edit]],'
  5660.                 .. ' [[Wikipedia:Requests for page protection'
  5661.                 .. '#Current requests for reduction in protection level'
  5662.                 .. '|request unprotection]],'
  5663.                 .. ' [[Special:Userlogin|log in]],'
  5664.                 .. ' or [[Special:UserLogin/signup|create an account]].',
  5665.         },
  5666.         vandalism = {
  5667.             description = 'For pages protected against'
  5668.                 .. ' [[Wikipedia:Vandalism|vandalism]]',
  5669.             text = '${INTROFRAGMENT} due to [[Wikipedia:Vandalism|vandalism]].',
  5670.             explanation = function (protectionObj, args)
  5671.                 local ret = ''
  5672.                 if protectionObj.level == 'sysop' then
  5673.                     ret = ret .. "This protection is '''not''' an endorsement of the"
  5674.                         .. ' ${CURRENTVERSION}. '
  5675.                 end
  5676.                 return ret .. '${EXPLANATIONBLURB}'
  5677.             end,
  5678.             tooltip = '${TOOLTIPFRAGMENT} due to vandalism',
  5679.         }
  5680.     },
  5681.     move = {
  5682.         dispute = {
  5683.             description = 'For pages protected against page moves due to'
  5684.                 .. ' disputes over the page title',
  5685.             explanation = "This protection is '''not''' an endorsement of the"
  5686.                 .. ' ${CURRENTVERSION}. ${EXPLANATIONBLURB}',
  5687.             image = 'Move-protection-shackle.svg'
  5688.         },
  5689.         vandalism = {
  5690.             description = 'For pages protected against'
  5691.                 .. ' [[Wikipedia:Vandalism#Page-move vandalism'
  5692.                 .. ' |page-move vandalism]]'
  5693.         }
  5694.     },
  5695.     autoreview = {},
  5696.     upload = {}
  5697. },
  5698.  
  5699. --------------------------------------------------------------------------------
  5700. --
  5701. --                            GENERAL DATA TABLES
  5702. --
  5703. --------------------------------------------------------------------------------
  5704.  
  5705. --------------------------------------------------------------------------------
  5706. -- Protection blurbs
  5707. --------------------------------------------------------------------------------
  5708.  
  5709. -- This table produces the protection blurbs available with the
  5710. -- ${PROTECTIONBLURB} parameter. It is sorted by protection action and
  5711. -- protection level, and is checked by the module in the following order:
  5712. -- 1. page's protection action, page's protection level
  5713. -- 2. page's protection action, default protection level
  5714. -- 3. "edit" protection action, default protection level
  5715. --
  5716. -- It is possible to use banner parameters inside this table.
  5717. -- *required* - this table needs edit, move, autoreview and upload subtables.
  5718. protectionBlurbs = {
  5719.     edit = {
  5720.         default = 'This ${PAGETYPE} is currently [[Help:Protection|'
  5721.             .. 'protected]] from editing',
  5722.         autoconfirmed = 'Editing of this ${PAGETYPE} by [[Wikipedia:User access'
  5723.             .. ' levels#New users|new]] or [[Wikipedia:User access levels#Unregistered'
  5724.             .. ' users|unregistered]] users is currently [[Help:Protection|disabled]]',
  5725.         extendedconfirmed = 'This ${PAGETYPE} is currently under extended confirmed protection',
  5726.     },
  5727.     move = {
  5728.         default = 'This ${PAGETYPE} is currently [[Help:Protection|protected]]'
  5729.             .. ' from [[Help:Moving a page|page moves]]'
  5730.     },
  5731.     autoreview = {
  5732.         default = 'All edits made to this ${PAGETYPE} by'
  5733.             .. ' [[Wikipedia:User access levels#New users|new]] or'
  5734.             .. ' [[Wikipedia:User access levels#Unregistered users|unregistered]]'
  5735.             .. ' users are currently'
  5736.             .. ' [[Wikipedia:Pending changes|subject to review]]'
  5737.     },
  5738.     upload = {
  5739.         default = 'Uploading new versions of this ${PAGETYPE} is currently disabled'
  5740.     }
  5741. },
  5742.  
  5743.  
  5744. --------------------------------------------------------------------------------
  5745. -- Explanation blurbs
  5746. --------------------------------------------------------------------------------
  5747.  
  5748. -- This table produces the explanation blurbs available with the
  5749. -- ${EXPLANATIONBLURB} parameter. It is sorted by protection action,
  5750. -- protection level, and whether the page is a talk page or not. If the page is
  5751. -- a talk page it will have a talk key of "talk"; otherwise it will have a talk
  5752. -- key of "subject". The table is checked in the following order:
  5753. -- 1. page's protection action, page's protection level, page's talk key
  5754. -- 2. page's protection action, page's protection level, default talk key
  5755. -- 3. page's protection action, default protection level, page's talk key
  5756. -- 4. page's protection action, default protection level, default talk key
  5757. --
  5758. -- It is possible to use banner parameters inside this table.
  5759. -- *required* - this table needs edit, move, autoreview and upload subtables.
  5760. explanationBlurbs = {
  5761.     edit = {
  5762.         autoconfirmed = {
  5763.             subject = 'See the [[Wikipedia:Protection policy|'
  5764.                 .. 'protection policy]] and ${PROTECTIONLOG} for more details. If you'
  5765.                 .. ' cannot edit this ${PAGETYPE} and you wish to make a change, you can'
  5766.                 .. ' ${EDITREQUEST}, discuss changes on the ${TALKPAGE},'
  5767.                 .. ' [[Wikipedia:Requests for page protection'
  5768.                 .. '#Current requests for reduction in protection level'
  5769.                 .. '|request unprotection]], [[Special:Userlogin|log in]], or'
  5770.                 .. ' [[Special:UserLogin/signup|create an account]].',
  5771.             default = 'See the [[Wikipedia:Protection policy|'
  5772.                 .. 'protection policy]] and ${PROTECTIONLOG} for more details. If you'
  5773.                 .. ' cannot edit this ${PAGETYPE} and you wish to make a change, you can'
  5774.                 .. ' [[Wikipedia:Requests for page protection'
  5775.                 .. '#Current requests for reduction in protection level'
  5776.                 .. '|request unprotection]], [[Special:Userlogin|log in]], or'
  5777.                 .. ' [[Special:UserLogin/signup|create an account]].',
  5778.         },
  5779.         extendedconfirmed = {
  5780.             default = 'Extended confirmed protection prevents edits from all unregistered editors'
  5781.                 .. ' and registered users with fewer than 30 days tenure and 500 edits.'
  5782.                 .. ' The [[Wikipedia:Protection policy#extended|policy on community use]]'
  5783.                 .. ' specifies that extended confirmed protection can be applied to combat'
  5784.                 .. ' disruption, if semi-protection has proven to be ineffective.'
  5785.                 .. ' Extended confirmed protection may also be applied to enforce'
  5786.                 .. ' [[Wikipedia:Arbitration Committee|arbitration sanctions]].'
  5787.                 .. ' Please discuss any changes on the ${TALKPAGE}; you may'
  5788.                 .. ' ${EDITREQUEST} to ask for uncontroversial changes supported by'
  5789.                 .. ' [[Wikipedia:Consensus|consensus]].'
  5790.         },
  5791.         default = {
  5792.             subject = 'See the [[Wikipedia:Protection policy|'
  5793.                 .. 'protection policy]] and ${PROTECTIONLOG} for more details.'
  5794.                 .. ' Please discuss any changes on the ${TALKPAGE}; you'
  5795.                 .. ' may ${EDITREQUEST} to ask an'
  5796.                 .. ' [[Wikipedia:Administrators|administrator]] to make an edit if it'
  5797.                 .. ' is [[Help:Minor edit#When to mark an edit as a minor edit'
  5798.                 .. '|uncontroversial]] or supported by [[Wikipedia:Consensus'
  5799.                 .. '|consensus]]. You may also [[Wikipedia:Requests for'
  5800.                 .. ' page protection#Current requests for reduction in protection level'
  5801.                 .. '|request]] that this page be unprotected.',
  5802.             default = 'See the [[Wikipedia:Protection policy|'
  5803.                 .. 'protection policy]] and ${PROTECTIONLOG} for more details.'
  5804.                 .. ' You may [[Wikipedia:Requests for page'
  5805.                 .. ' protection#Current requests for edits to a protected page|request an'
  5806.                 .. ' edit]] to this page, or [[Wikipedia:Requests for'
  5807.                 .. ' page protection#Current requests for reduction in protection level'
  5808.                 .. '|ask]] for it to be unprotected.'
  5809.         }
  5810.     },
  5811.     move = {
  5812.         default = {
  5813.             subject = 'See the [[Wikipedia:Protection policy|'
  5814.                 .. 'protection policy]] and ${PROTECTIONLOG} for more details.'
  5815.                 .. ' The page may still be edited but cannot be moved'
  5816.                 .. ' until unprotected. Please discuss any suggested moves on the'
  5817.                 .. ' ${TALKPAGE} or at [[Wikipedia:Requested moves]]. You can also'
  5818.                 .. ' [[Wikipedia:Requests for page protection|request]] that the page be'
  5819.                 .. ' unprotected.',
  5820.             default = 'See the [[Wikipedia:Protection policy|'
  5821.                 .. 'protection policy]] and ${PROTECTIONLOG} for more details.'
  5822.                 .. ' The page may still be edited but cannot be moved'
  5823.                 .. ' until unprotected. Please discuss any suggested moves at'
  5824.                 .. ' [[Wikipedia:Requested moves]]. You can also'
  5825.                 .. ' [[Wikipedia:Requests for page protection|request]] that the page be'
  5826.                 .. ' unprotected.'
  5827.         }
  5828.     },
  5829.     autoreview = {
  5830.         default = {
  5831.             default = 'See the [[Wikipedia:Protection policy|'
  5832.                 .. 'protection policy]] and ${PROTECTIONLOG} for more details.'
  5833.                 .. ' Edits to this ${PAGETYPE} by new and unregistered users'
  5834.                 .. ' will not be visible to readers until they are accepted by'
  5835.                 .. ' a reviewer. To avoid the need for your edits to be'
  5836.                 .. ' reviewed, you may'
  5837.                 .. ' [[Wikipedia:Requests for page protection'
  5838.                 .. '#Current requests for reduction in protection level'
  5839.                 .. '|request unprotection]], [[Special:Userlogin|log in]], or'
  5840.                 .. ' [[Special:UserLogin/signup|create an account]].'
  5841.         },
  5842.     },
  5843.     upload = {
  5844.         default = {
  5845.             default = 'See the [[Wikipedia:Protection policy|'
  5846.                 .. 'protection policy]] and ${PROTECTIONLOG} for more details.'
  5847.                 .. ' The page may still be edited but new versions of the file'
  5848.                 .. ' cannot be uploaded until it is unprotected. You can'
  5849.                 .. ' request that a new version be uploaded by using a'
  5850.                 .. ' [[Wikipedia:Edit requests|protected edit request]], or you'
  5851.                 .. ' can  [[Wikipedia:Requests for page protection|request]]'
  5852.                 .. ' that the file be unprotected.'
  5853.         }
  5854.     }
  5855. },
  5856.  
  5857. --------------------------------------------------------------------------------
  5858. -- Protection levels
  5859. --------------------------------------------------------------------------------
  5860.  
  5861. -- This table provides the data for the ${PROTECTIONLEVEL} parameter, which
  5862. -- produces a short label for different protection levels. It is sorted by
  5863. -- protection action and protection level, and is checked in the following
  5864. -- order:
  5865. -- 1. page's protection action, page's protection level
  5866. -- 2. page's protection action, default protection level
  5867. -- 3. "edit" protection action, default protection level
  5868. --
  5869. -- It is possible to use banner parameters inside this table.
  5870. -- *required* - this table needs edit, move, autoreview and upload subtables.
  5871. protectionLevels = {
  5872.     edit = {
  5873.         default = 'protected',
  5874.         templateeditor = 'template-protected',
  5875.         extendedconfirmed = 'extended-protected',
  5876.         autoconfirmed = 'semi-protected',
  5877.     },
  5878.     move = {
  5879.         default = 'move-protected'
  5880.     },
  5881.     autoreview = {
  5882.     },
  5883.     upload = {
  5884.         default = 'upload-protected'
  5885.     }
  5886. },
  5887.  
  5888. --------------------------------------------------------------------------------
  5889. -- Images
  5890. --------------------------------------------------------------------------------
  5891.  
  5892. -- This table lists different padlock images for each protection action and
  5893. -- protection level. It is used if an image is not specified in any of the
  5894. -- banner data tables, and if the page does not satisfy the conditions for using
  5895. -- the ['image-filename-indef'] image. It is checked in the following order:
  5896. -- 1. page's protection action, page's protection level
  5897. -- 2. page's protection action, default protection level
  5898. images = {
  5899.     edit = {
  5900.         default = 'Full-protection-shackle.svg',
  5901.         templateeditor = 'Template-protection-shackle.svg',
  5902.         extendedconfirmed = 'Extended-protection-shackle.svg',
  5903.         autoconfirmed = 'Semi-protection-shackle.svg'
  5904.     },
  5905.     move = {
  5906.         default = 'Move-protection-shackle.svg',
  5907.     },
  5908.     autoreview = {
  5909.         default = 'Pending-protection-shackle.svg'
  5910.     },
  5911.     upload = {
  5912.         default = 'Upload-protection-shackle.svg'
  5913.     }
  5914. },
  5915.  
  5916. -- Pages with a reason specified in this table will show the special "indef"
  5917. -- padlock, defined in the 'image-filename-indef' message, if no expiry is set.
  5918. indefImageReasons = {
  5919.     template = true
  5920. },
  5921.  
  5922. --------------------------------------------------------------------------------
  5923. -- Image links
  5924. --------------------------------------------------------------------------------
  5925.  
  5926. -- This table provides the data for the ${IMAGELINK} parameter, which gets
  5927. -- the image link for small padlock icons based on the page's protection action
  5928. -- and protection level. It is checked in the following order:
  5929. -- 1. page's protection action, page's protection level
  5930. -- 2. page's protection action, default protection level
  5931. -- 3. "edit" protection action, default protection level
  5932. --
  5933. -- It is possible to use banner parameters inside this table.
  5934. -- *required* - this table needs edit, move, autoreview and upload subtables.
  5935. imageLinks = {
  5936.     edit = {
  5937.         default = 'Wikipedia:Protection policy#full',
  5938.         templateeditor = 'Wikipedia:Protection policy#template',
  5939.         extendedconfirmed = 'Wikipedia:Protection policy#extended',
  5940.         autoconfirmed = 'Wikipedia:Protection policy#semi'
  5941.     },
  5942.     move = {
  5943.         default = 'Wikipedia:Protection policy#move'
  5944.     },
  5945.     autoreview = {
  5946.         default = 'Wikipedia:Protection policy#pending'
  5947.     },
  5948.     upload = {
  5949.         default = 'Wikipedia:Protection policy#upload'
  5950.     }
  5951. },
  5952.  
  5953. --------------------------------------------------------------------------------
  5954. -- Padlock indicator names
  5955. --------------------------------------------------------------------------------
  5956.  
  5957. -- This table provides the "name" attribute for the &lt;indicator&gt; extension tag
  5958. -- with which small padlock icons are generated. All indicator tags on a page
  5959. -- are displayed in alphabetical order based on this attribute, and with
  5960. -- indicator tags with duplicate names, the last tag on the page wins.
  5961. -- The attribute is chosen based on the protection action; table keys must be a
  5962. -- protection action name or the string "default".
  5963. padlockIndicatorNames = {
  5964.     autoreview = 'pp-autoreview',
  5965.     default = 'pp-default'
  5966. },
  5967.  
  5968. --------------------------------------------------------------------------------
  5969. -- Protection categories
  5970. --------------------------------------------------------------------------------
  5971.  
  5972. --[[
  5973. -- The protection categories are stored in the protectionCategories table.
  5974. -- Keys to this table are made up of the following strings:
  5975. --
  5976. -- 1. the expiry date
  5977. -- 2. the namespace
  5978. -- 3. the protection reason (e.g. "dispute" or "vandalism")
  5979. -- 4. the protection level (e.g. "sysop" or "autoconfirmed")
  5980. -- 5. the action (e.g. "edit" or "move")
  5981. --
  5982. -- When the module looks up a category in the table, first it will will check to
  5983. -- see a key exists that corresponds to all five parameters. For example, a
  5984. -- user page semi-protected from vandalism for two weeks would have the key
  5985. -- "temp-user-vandalism-autoconfirmed-edit". If no match is found, the module
  5986. -- changes the first part of the key to "all" and checks the table again. It
  5987. -- keeps checking increasingly generic key combinations until it finds the
  5988. -- field, or until it reaches the key "all-all-all-all-all".
  5989. --
  5990. -- The module uses a binary matrix to determine the order in which to search.
  5991. -- This is best demonstrated by a table. In this table, the "0" values
  5992. -- represent "all", and the "1" values represent the original data (e.g.
  5993. -- "indef" or "file" or "vandalism").
  5994. --
  5995. --        expiry    namespace reason   level     action
  5996. -- order
  5997. -- 1      1         1         1        1         1
  5998. -- 2      0         1         1        1         1
  5999. -- 3      1         0         1        1         1
  6000. -- 4      0         0         1        1         1
  6001. -- 5      1         1         0        1         1
  6002. -- 6      0         1         0        1         1
  6003. -- 7      1         0         0        1         1
  6004. -- 8      0         0         0        1         1
  6005. -- 9      1         1         1        0         1
  6006. -- 10     0         1         1        0         1
  6007. -- 11     1         0         1        0         1
  6008. -- 12     0         0         1        0         1
  6009. -- 13     1         1         0        0         1
  6010. -- 14     0         1         0        0         1
  6011. -- 15     1         0         0        0         1
  6012. -- 16     0         0         0        0         1
  6013. -- 17     1         1         1        1         0
  6014. -- 18     0         1         1        1         0
  6015. -- 19     1         0         1        1         0
  6016. -- 20     0         0         1        1         0
  6017. -- 21     1         1         0        1         0
  6018. -- 22     0         1         0        1         0
  6019. -- 23     1         0         0        1         0
  6020. -- 24     0         0         0        1         0
  6021. -- 25     1         1         1        0         0
  6022. -- 26     0         1         1        0         0
  6023. -- 27     1         0         1        0         0
  6024. -- 28     0         0         1        0         0
  6025. -- 29     1         1         0        0         0
  6026. -- 30     0         1         0        0         0
  6027. -- 31     1         0         0        0         0
  6028. -- 32     0         0         0        0         0
  6029. --
  6030. -- In this scheme the action has the highest priority, as it is the last
  6031. -- to change, and the expiry has the least priority, as it changes the most.
  6032. -- The priorities of the expiry, the protection level and the action are
  6033. -- fixed, but the priorities of the reason and the namespace can be swapped
  6034. -- through the use of the cfg.bannerDataNamespaceHasPriority table.
  6035. --]]
  6036.  
  6037. -- If the reason specified to the template is listed in this table,
  6038. -- namespace data will take priority over reason data in the protectionCategories
  6039. -- table.
  6040. reasonsWithNamespacePriority = {
  6041.     vandalism = true,
  6042. },
  6043.  
  6044. -- The string to use as a namespace key for the protectionCategories table for each
  6045. -- namespace number.
  6046. categoryNamespaceKeys = {
  6047.     [  2] = 'user',
  6048.     [  3] = 'user',
  6049.     [  4] = 'project',
  6050.     [  6] = 'file',
  6051.     [  8] = 'mediawiki',
  6052.     [ 10] = 'template',
  6053.     [ 12] = 'project',
  6054.     [ 14] = 'category',
  6055.     [100] = 'portal',
  6056.     [828] = 'module',
  6057. },
  6058.  
  6059. protectionCategories = {
  6060.     ['all|all|all|all|all']                     = 'Wikipedia fully protected pages',
  6061.     ['all|all|office|all|all']                  = 'Wikipedia Office-protected pages',
  6062.     ['all|all|reset|all|all']                   = 'Wikipedia Office-protected pages',
  6063.     ['all|all|dmca|all|all']                    = 'Wikipedia Office-protected pages',
  6064.     ['all|all|mainpage|all|all']                = 'Wikipedia fully-protected main page files',
  6065.     ['all|all|all|extendedconfirmed|all']       = 'Wikipedia extended-confirmed-protected pages',
  6066.     ['all|all|ecp|extendedconfirmed|all']       = 'Wikipedia extended-confirmed-protected pages',
  6067.     ['all|template|all|all|edit']               = 'Wikipedia fully protected templates',
  6068.     ['all|all|all|autoconfirmed|edit']          = 'Wikipedia semi-protected pages',
  6069.     ['indef|all|all|autoconfirmed|edit']        = 'Wikipedia indefinitely semi-protected pages',
  6070.     ['all|all|blp|autoconfirmed|edit']          = 'Wikipedia indefinitely semi-protected biographies of living people',
  6071.     ['temp|all|blp|autoconfirmed|edit']         = 'Wikipedia temporarily semi-protected biographies of living people',
  6072.     ['all|all|dispute|autoconfirmed|edit']      = 'Wikipedia pages semi-protected due to dispute',
  6073.     ['all|all|sock|autoconfirmed|edit']         = 'Wikipedia pages semi-protected from banned users',
  6074.     ['all|all|vandalism|autoconfirmed|edit']    = 'Wikipedia pages semi-protected against vandalism',
  6075.     ['all|category|all|autoconfirmed|edit']     = 'Wikipedia semi-protected categories',
  6076.     ['all|file|all|autoconfirmed|edit']         = 'Wikipedia semi-protected files',
  6077.     ['all|portal|all|autoconfirmed|edit']       = 'Wikipedia semi-protected portals',
  6078.     ['all|project|all|autoconfirmed|edit']      = 'Wikipedia semi-protected project pages',
  6079.     ['all|talk|all|autoconfirmed|edit']         = 'Wikipedia semi-protected talk pages',
  6080.     ['all|template|all|autoconfirmed|edit']     = 'Wikipedia semi-protected templates',
  6081.     ['all|user|all|autoconfirmed|edit']         = 'Wikipedia semi-protected user and user talk pages',
  6082.     ['all|all|all|templateeditor|edit']         = 'Wikipedia template-protected pages other than templates and modules',
  6083.     ['all|template|all|templateeditor|edit']    = 'Wikipedia template-protected templates',
  6084.     ['all|template|all|templateeditor|move']    = 'Wikipedia template-protected templates', -- move-protected templates
  6085.     ['all|all|blp|sysop|edit']                  = 'Wikipedia indefinitely protected biographies of living people',
  6086.     ['temp|all|blp|sysop|edit']                 = 'Wikipedia temporarily protected biographies of living people',
  6087.     ['all|all|dispute|sysop|edit']              = 'Wikipedia pages protected due to dispute',
  6088.     ['all|all|sock|sysop|edit']                 = 'Wikipedia pages protected from banned users',
  6089.     ['all|all|vandalism|sysop|edit']            = 'Wikipedia pages protected against vandalism',
  6090.     ['all|category|all|sysop|edit']             = 'Wikipedia fully protected categories',
  6091.     ['all|file|all|sysop|edit']                 = 'Wikipedia fully-protected files',
  6092.     ['all|project|all|sysop|edit']              = 'Wikipedia fully-protected project pages',
  6093.     ['all|talk|all|sysop|edit']                 = 'Wikipedia fully-protected talk pages',
  6094.     ['all|template|all|extendedconfirmed|edit'] = 'Wikipedia extended-confirmed-protected templates',
  6095.     ['all|template|all|sysop|edit']             = 'Wikipedia fully protected templates',
  6096.     ['all|user|all|sysop|edit']                 = 'Wikipedia fully protected user and user talk pages',
  6097.     ['all|module|all|all|edit']                 = 'Wikipedia fully-protected modules',
  6098.     ['all|module|all|templateeditor|edit']      = 'Wikipedia template-protected modules',
  6099.     ['all|module|all|extendedconfirmed|edit']   = 'Wikipedia extended-confirmed-protected modules',
  6100.     ['all|module|all|autoconfirmed|edit']       = 'Wikipedia semi-protected modules',
  6101.     ['all|all|all|sysop|move']                  = 'Wikipedia move-protected pages',
  6102.     ['indef|all|all|sysop|move']                = 'Wikipedia indefinitely move-protected pages',
  6103.     ['all|all|dispute|sysop|move']              = 'Wikipedia pages move-protected due to dispute',
  6104.     ['all|all|vandalism|sysop|move']            = 'Wikipedia pages move-protected due to vandalism',
  6105.     ['all|portal|all|sysop|move']               = 'Wikipedia move-protected portals',
  6106.     ['all|project|all|sysop|move']              = 'Wikipedia move-protected project pages',
  6107.     ['all|talk|all|sysop|move']                 = 'Wikipedia move-protected talk pages',
  6108.     ['all|template|all|sysop|move']             = 'Wikipedia move-protected templates',
  6109.     ['all|user|all|sysop|move']                 = 'Wikipedia move-protected user and user talk pages',
  6110.     ['all|all|all|autoconfirmed|autoreview']    = 'Wikipedia pending changes protected pages',
  6111.     ['all|file|all|all|upload']                 = 'Wikipedia upload-protected files',
  6112. },
  6113.  
  6114. --------------------------------------------------------------------------------
  6115. -- Expiry category config
  6116. --------------------------------------------------------------------------------
  6117.  
  6118. -- This table configures the expiry category behaviour for each protection
  6119. -- action.
  6120. -- * If set to true, setting that action will always categorise the page if
  6121. --   an expiry parameter is not set.
  6122. -- * If set to false, setting that action will never categorise the page.
  6123. -- * If set to nil, the module will categorise the page if:
  6124. --   1) an expiry parameter is not set, and
  6125. --   2) a reason is provided, and
  6126. --   3) the specified reason is not blacklisted in the reasonsWithoutExpiryCheck
  6127. --      table.
  6128.  
  6129. expiryCheckActions = {
  6130.     edit = nil,
  6131.     move = false,
  6132.     autoreview = true,
  6133.     upload = false
  6134. },
  6135.  
  6136. reasonsWithoutExpiryCheck = {
  6137.     blp = true,
  6138.     template = true,
  6139. },
  6140.  
  6141. --------------------------------------------------------------------------------
  6142. -- Pagetypes
  6143. --------------------------------------------------------------------------------
  6144.  
  6145. -- This table produces the page types available with the ${PAGETYPE} parameter.
  6146. -- Keys are namespace numbers, or the string "default" for the default value.
  6147. pagetypes = {
  6148.     [0] = 'article',
  6149.     [6] = 'file',
  6150.     [10] = 'template',
  6151.     [14] = 'category',
  6152.     [828] = 'module',
  6153.     default = 'page'
  6154. },
  6155.  
  6156. --------------------------------------------------------------------------------
  6157. -- Strings marking indefinite protection
  6158. --------------------------------------------------------------------------------
  6159.  
  6160. -- This table contains values passed to the expiry parameter that mean the page
  6161. -- is protected indefinitely.
  6162. indefStrings = {
  6163.     ['indef'] = true,
  6164.     ['indefinite'] = true,
  6165.     ['indefinitely'] = true,
  6166.     ['infinite'] = true,
  6167. },
  6168.  
  6169. --------------------------------------------------------------------------------
  6170. -- Group hierarchy
  6171. --------------------------------------------------------------------------------
  6172.  
  6173. -- This table maps each group to all groups that have a superset of the original
  6174. -- group's page editing permissions.
  6175. hierarchy = {
  6176.     sysop = {},
  6177.     reviewer = {'sysop'},
  6178.     filemover = {'sysop'},
  6179.     templateeditor = {'sysop'},
  6180.     extendedconfirmed = {'sysop'},
  6181.     autoconfirmed = {'reviewer', 'filemover', 'templateeditor', 'extendedconfirmed'},
  6182.     user = {'autoconfirmed'},
  6183.     ['*'] = {'user'}
  6184. },
  6185.  
  6186. --------------------------------------------------------------------------------
  6187. -- Wrapper templates and their default arguments
  6188. --------------------------------------------------------------------------------
  6189.  
  6190. -- This table contains wrapper templates used with the module, and their
  6191. -- default arguments. Templates specified in this table should contain the
  6192. -- following invocation, and no other template content:
  6193. --
  6194. -- {{#invoke:Protection banner|main}}
  6195. --
  6196. -- If other content is desired, it can be added between
  6197. -- &lt;noinclude&gt;...&lt;/noinclude&gt; tags.
  6198. --
  6199. -- When a user calls one of these wrapper templates, they will use the
  6200. -- default arguments automatically. However, users can override any of the
  6201. -- arguments.
  6202. wrappers = {
  6203.     ['Template:Pp']                         = {},
  6204.     ['Template:Pp-extended']                = {'ecp'},
  6205.     ['Template:Pp-blp']                     = {'blp'},
  6206.     -- we don't need Template:Pp-create
  6207.     ['Template:Pp-dispute']                 = {'dispute'},
  6208.     ['Template:Pp-main-page']               = {'mainpage'},
  6209.     ['Template:Pp-move']                    = {action = 'move', catonly = 'yes'},
  6210.     ['Template:Pp-move-dispute']            = {'dispute', action = 'move', catonly = 'yes'},
  6211.     -- we don't need Template:Pp-move-indef
  6212.     ['Template:Pp-move-vandalism']          = {'vandalism', action = 'move', catonly = 'yes'},
  6213.     ['Template:Pp-office']                  = {'office'},
  6214.     ['Template:Pp-office-dmca']             = {'dmca'},
  6215.     ['Template:Pp-pc']                      = {action = 'autoreview', small = true},
  6216.     ['Template:Pp-pc1']                     = {action = 'autoreview', small = true},
  6217.     ['Template:Pp-reset']                   = {'reset'},
  6218.     ['Template:Pp-semi-indef']              = {small = true},
  6219.     ['Template:Pp-sock']                    = {'sock'},
  6220.     ['Template:Pp-template']                = {'template', small = true},
  6221.     ['Template:Pp-upload']                  = {action = 'upload'},
  6222.     ['Template:Pp-usertalk']                = {'usertalk'},
  6223.     ['Template:Pp-vandalism']               = {'vandalism'},
  6224. },
  6225.  
  6226. --------------------------------------------------------------------------------
  6227. --
  6228. --                                 MESSAGES
  6229. --
  6230. --------------------------------------------------------------------------------
  6231.  
  6232. msg = {
  6233.  
  6234. --------------------------------------------------------------------------------
  6235. -- Intro blurb and intro fragment
  6236. --------------------------------------------------------------------------------
  6237.  
  6238. -- These messages specify what is produced by the ${INTROBLURB} and
  6239. -- ${INTROFRAGMENT} parameters. If the protection is temporary they use the
  6240. -- intro-blurb-expiry or intro-fragment-expiry, and if not they use
  6241. -- intro-blurb-noexpiry or intro-fragment-noexpiry.
  6242. -- It is possible to use banner parameters in these messages.
  6243. ['intro-blurb-expiry'] = '${PROTECTIONBLURB} until ${EXPIRY}.',
  6244. ['intro-blurb-noexpiry'] = '${PROTECTIONBLURB}.',
  6245. ['intro-fragment-expiry'] = '${PROTECTIONBLURB} until ${EXPIRY},',
  6246. ['intro-fragment-noexpiry'] = '${PROTECTIONBLURB}',
  6247.  
  6248. --------------------------------------------------------------------------------
  6249. -- Tooltip blurb
  6250. --------------------------------------------------------------------------------
  6251.  
  6252. -- These messages specify what is produced by the ${TOOLTIPBLURB} parameter.
  6253. -- If the protection is temporary the tooltip-blurb-expiry message is used, and
  6254. -- if not the tooltip-blurb-noexpiry message is used.
  6255. -- It is possible to use banner parameters in these messages.
  6256. ['tooltip-blurb-expiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL} until ${EXPIRY}.',
  6257. ['tooltip-blurb-noexpiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL}.',
  6258. ['tooltip-fragment-expiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL} until ${EXPIRY},',
  6259. ['tooltip-fragment-noexpiry'] = 'This ${PAGETYPE} is ${PROTECTIONLEVEL}',
  6260.  
  6261. --------------------------------------------------------------------------------
  6262. -- Special explanation blurb
  6263. --------------------------------------------------------------------------------
  6264.  
  6265. -- An explanation blurb for pages that cannot be unprotected, e.g. for pages
  6266. -- in the MediaWiki namespace.
  6267. -- It is possible to use banner parameters in this message.
  6268. ['explanation-blurb-nounprotect'] = 'See the [[Wikipedia:Protection policy|'
  6269.     .. 'protection policy]] and ${PROTECTIONLOG} for more details.'
  6270.     .. ' Please discuss any changes on the ${TALKPAGE}; you'
  6271.     .. ' may ${EDITREQUEST} to ask an'
  6272.     .. ' [[Wikipedia:Administrators|administrator]] to make an edit if it'
  6273.     .. ' is [[Help:Minor edit#When to mark an edit as a minor edit'
  6274.     .. '|uncontroversial]] or supported by [[Wikipedia:Consensus'
  6275.     .. '|consensus]].',
  6276.  
  6277. --------------------------------------------------------------------------------
  6278. -- Protection log display values
  6279. --------------------------------------------------------------------------------
  6280.  
  6281. -- These messages determine the display values for the protection log link
  6282. -- or the pending changes log link produced by the ${PROTECTIONLOG} parameter.
  6283. -- It is possible to use banner parameters in these messages.
  6284. ['protection-log-display'] = 'protection log',
  6285. ['pc-log-display'] = 'pending changes log',
  6286.  
  6287. --------------------------------------------------------------------------------
  6288. -- Current version display values
  6289. --------------------------------------------------------------------------------
  6290.  
  6291. -- These messages determine the display values for the page history link
  6292. -- or the move log link produced by the ${CURRENTVERSION} parameter.
  6293. -- It is possible to use banner parameters in these messages.
  6294. ['current-version-move-display'] = 'current title',
  6295. ['current-version-edit-display'] = 'current version',
  6296.  
  6297. --------------------------------------------------------------------------------
  6298. -- Talk page
  6299. --------------------------------------------------------------------------------
  6300.  
  6301. -- This message determines the display value of the talk page link produced
  6302. -- with the ${TALKPAGE} parameter.
  6303. -- It is possible to use banner parameters in this message.
  6304. ['talk-page-link-display'] = 'talk page',
  6305.  
  6306. --------------------------------------------------------------------------------
  6307. -- Edit requests
  6308. --------------------------------------------------------------------------------
  6309.  
  6310. -- This message determines the display value of the edit request link produced
  6311. -- with the ${EDITREQUEST} parameter.
  6312. -- It is possible to use banner parameters in this message.
  6313. ['edit-request-display'] = 'submit an edit request',
  6314.  
  6315. --------------------------------------------------------------------------------
  6316. -- Expiry date format
  6317. --------------------------------------------------------------------------------
  6318.  
  6319. -- This is the format for the blurb expiry date. It should be valid input for
  6320. -- the first parameter of the #time parser function.
  6321. ['expiry-date-format'] = 'F j, Y "at" H:i e',
  6322.  
  6323. --------------------------------------------------------------------------------
  6324. -- Tracking categories
  6325. --------------------------------------------------------------------------------
  6326.  
  6327. -- These messages determine which tracking categories the module outputs.
  6328. ['tracking-category-incorrect'] = 'Wikipedia pages with incorrect protection templates',
  6329. ['tracking-category-template'] = 'Wikipedia template-protected pages other than templates and modules',
  6330.  
  6331. --------------------------------------------------------------------------------
  6332. -- Images
  6333. --------------------------------------------------------------------------------
  6334.  
  6335. -- These are images that are not defined by their protection action and protection level.
  6336. ['image-filename-indef'] = 'Full-protection-shackle.svg',
  6337. ['image-filename-default'] = 'Transparent.gif',
  6338.  
  6339. --------------------------------------------------------------------------------
  6340. -- End messages
  6341. --------------------------------------------------------------------------------
  6342. }
  6343.  
  6344. --------------------------------------------------------------------------------
  6345. -- End configuration
  6346. --------------------------------------------------------------------------------
  6347. }</text>
  6348.       <sha1>eeb6sgpzkp24z3uln44ko8rah6nhotf</sha1>
  6349.     </revision>
  6350.   </page>
  6351.   <page>
  6352.     <title>Module:String</title>
  6353.     <ns>828</ns>
  6354.     <id>38569505</id>
  6355.     <revision>
  6356.       <id>970815276</id>
  6357.       <parentid>924313232</parentid>
  6358.       <timestamp>2020-08-02T15:49:42Z</timestamp>
  6359.       <contributor>
  6360.         <username>RexxS</username>
  6361.         <id>6112901</id>
  6362.       </contributor>
  6363.       <comment>separate annotations for str.match from those for str._match</comment>
  6364.       <model>Scribunto</model>
  6365.       <format>text/plain</format>
  6366.       <text bytes="18033" xml:space="preserve">--[[
  6367.  
  6368. This module is intended to provide access to basic string functions.
  6369.  
  6370. Most of the functions provided here can be invoked with named parameters,
  6371. unnamed parameters, or a mixture.  If named parameters are used, Mediawiki will
  6372. automatically remove any leading or trailing whitespace from the parameter.
  6373. Depending on the intended use, it may be advantageous to either preserve or
  6374. remove such whitespace.
  6375.  
  6376. Global options
  6377.     ignore_errors: If set to 'true' or 1, any error condition will result in
  6378.         an empty string being returned rather than an error message.
  6379.  
  6380.     error_category: If an error occurs, specifies the name of a category to
  6381.         include with the error message.  The default category is
  6382.         [Category:Errors reported by Module String].
  6383.  
  6384.     no_category: If set to 'true' or 1, no category will be added if an error
  6385.         is generated.
  6386.  
  6387. Unit tests for this module are available at Module:String/tests.
  6388. ]]
  6389.  
  6390. local str = {}
  6391.  
  6392. --[[
  6393. len
  6394.  
  6395. This function returns the length of the target string.
  6396.  
  6397. Usage:
  6398. {{#invoke:String|len|target_string|}}
  6399. OR
  6400. {{#invoke:String|len|s=target_string}}
  6401.  
  6402. Parameters
  6403.     s: The string whose length to report
  6404.  
  6405. If invoked using named parameters, Mediawiki will automatically remove any leading or
  6406. trailing whitespace from the target string.
  6407. ]]
  6408. function str.len( frame )
  6409.     local new_args = str._getParameters( frame.args, {'s'} )
  6410.     local s = new_args['s'] or ''
  6411.     return mw.ustring.len( s )
  6412. end
  6413.  
  6414. --[[
  6415. sub
  6416.  
  6417. This function returns a substring of the target string at specified indices.
  6418.  
  6419. Usage:
  6420. {{#invoke:String|sub|target_string|start_index|end_index}}
  6421. OR
  6422. {{#invoke:String|sub|s=target_string|i=start_index|j=end_index}}
  6423.  
  6424. Parameters
  6425.     s: The string to return a subset of
  6426.     i: The fist index of the substring to return, defaults to 1.
  6427.     j: The last index of the string to return, defaults to the last character.
  6428.  
  6429. The first character of the string is assigned an index of 1.  If either i or j
  6430. is a negative value, it is interpreted the same as selecting a character by
  6431. counting from the end of the string.  Hence, a value of -1 is the same as
  6432. selecting the last character of the string.
  6433.  
  6434. If the requested indices are out of range for the given string, an error is
  6435. reported.
  6436. ]]
  6437. function str.sub( frame )
  6438.     local new_args = str._getParameters( frame.args, { 's', 'i', 'j' } )
  6439.     local s = new_args['s'] or ''
  6440.     local i = tonumber( new_args['i'] ) or 1
  6441.     local j = tonumber( new_args['j'] ) or -1
  6442.  
  6443.     local len = mw.ustring.len( s )
  6444.  
  6445.     -- Convert negatives for range checking
  6446.     if i &lt; 0 then
  6447.         i = len + i + 1
  6448.     end
  6449.     if j &lt; 0 then
  6450.         j = len + j + 1
  6451.     end
  6452.  
  6453.     if i &gt; len or j &gt; len or i &lt; 1 or j &lt; 1 then
  6454.         return str._error( 'String subset index out of range' )
  6455.     end
  6456.     if j &lt; i then
  6457.         return str._error( 'String subset indices out of order' )
  6458.     end
  6459.  
  6460.     return mw.ustring.sub( s, i, j )
  6461. end
  6462.  
  6463. --[[
  6464. This function implements that features of {{str sub old}} and is kept in order
  6465. to maintain these older templates.
  6466. ]]
  6467. function str.sublength( frame )
  6468.     local i = tonumber( frame.args.i ) or 0
  6469.     local len = tonumber( frame.args.len )
  6470.     return mw.ustring.sub( frame.args.s, i + 1, len and ( i + len ) )
  6471. end
  6472.  
  6473. --[[
  6474. _match
  6475.  
  6476. This function returns a substring from the source string that matches a
  6477. specified pattern. It is exported for use in other modules
  6478.  
  6479. Usage:
  6480. strmatch = require("Module:String")._match
  6481. sresult = strmatch( s, pattern, start, match, plain, nomatch )
  6482.  
  6483. Parameters
  6484.     s: The string to search
  6485.     pattern: The pattern or string to find within the string
  6486.     start: The index within the source string to start the search.  The first
  6487.         character of the string has index 1.  Defaults to 1.
  6488.     match: In some cases it may be possible to make multiple matches on a single
  6489.         string.  This specifies which match to return, where the first match is
  6490.         match= 1.  If a negative number is specified then a match is returned
  6491.         counting from the last match.  Hence match = -1 is the same as requesting
  6492.         the last match.  Defaults to 1.
  6493.     plain: A flag indicating that the pattern should be understood as plain
  6494.         text.  Defaults to false.
  6495.     nomatch: If no match is found, output the "nomatch" value rather than an error.
  6496.  
  6497. For information on constructing Lua patterns, a form of [regular expression], see:
  6498.  
  6499. * http://www.lua.org/manual/5.1/manual.html#5.4.1
  6500. * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
  6501. * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns
  6502.  
  6503. ]]
  6504. -- This sub-routine is exported for use in other modules
  6505. function str._match( s, pattern, start, match_index, plain_flag, nomatch )
  6506.     if s == '' then
  6507.         return str._error( 'Target string is empty' )
  6508.     end
  6509.     if pattern == '' then
  6510.         return str._error( 'Pattern string is empty' )
  6511.     end
  6512.     start = tonumber(start) or 1
  6513.     if math.abs(start) &lt; 1 or math.abs(start) &gt; mw.ustring.len( s ) then
  6514.         return str._error( 'Requested start is out of range' )
  6515.     end
  6516.     if match_index == 0 then
  6517.         return str._error( 'Match index is out of range' )
  6518.     end
  6519.     if plain_flag then
  6520.         pattern = str._escapePattern( pattern )
  6521.     end
  6522.  
  6523.     local result
  6524.     if match_index == 1 then
  6525.         -- Find first match is simple case
  6526.         result = mw.ustring.match( s, pattern, start )
  6527.     else
  6528.         if start &gt; 1 then
  6529.             s = mw.ustring.sub( s, start )
  6530.         end
  6531.  
  6532.         local iterator = mw.ustring.gmatch(s, pattern)
  6533.         if match_index &gt; 0 then
  6534.             -- Forward search
  6535.             for w in iterator do
  6536.                 match_index = match_index - 1
  6537.                 if match_index == 0 then
  6538.                     result = w
  6539.                     break
  6540.                 end
  6541.             end
  6542.         else
  6543.             -- Reverse search
  6544.             local result_table = {}
  6545.             local count = 1
  6546.             for w in iterator do
  6547.                 result_table[count] = w
  6548.                 count = count + 1
  6549.             end
  6550.  
  6551.             result = result_table[ count + match_index ]
  6552.         end
  6553.     end
  6554.  
  6555.     if result == nil then
  6556.         if nomatch == nil then
  6557.             return str._error( 'Match not found' )
  6558.         else
  6559.             return nomatch
  6560.         end
  6561.     else
  6562.         return result
  6563.     end
  6564. end
  6565.  
  6566. --[[
  6567. match
  6568.  
  6569. This function returns a substring from the source string that matches a
  6570. specified pattern.
  6571.  
  6572. Usage:
  6573. {{#invoke:String|match|source_string|pattern_string|start_index|match_number|plain_flag|nomatch_output}}
  6574. OR
  6575. {{#invoke:String|match|s=source_string|pattern=pattern_string|start=start_index
  6576.     |match=match_number|plain=plain_flag|nomatch=nomatch_output}}
  6577.  
  6578. Parameters
  6579.     s: The string to search
  6580.     pattern: The pattern or string to find within the string
  6581.     start: The index within the source string to start the search.  The first
  6582.         character of the string has index 1.  Defaults to 1.
  6583.     match: In some cases it may be possible to make multiple matches on a single
  6584.         string.  This specifies which match to return, where the first match is
  6585.         match= 1.  If a negative number is specified then a match is returned
  6586.         counting from the last match.  Hence match = -1 is the same as requesting
  6587.         the last match.  Defaults to 1.
  6588.     plain: A flag indicating that the pattern should be understood as plain
  6589.         text.  Defaults to false.
  6590.     nomatch: If no match is found, output the "nomatch" value rather than an error.
  6591.  
  6592. If invoked using named parameters, Mediawiki will automatically remove any leading or
  6593. trailing whitespace from each string.  In some circumstances this is desirable, in
  6594. other cases one may want to preserve the whitespace.
  6595.  
  6596. If the match_number or start_index are out of range for the string being queried, then
  6597. this function generates an error.  An error is also generated if no match is found.
  6598. If one adds the parameter ignore_errors=true, then the error will be suppressed and
  6599. an empty string will be returned on any failure.
  6600.  
  6601. For information on constructing Lua patterns, a form of [regular expression], see:
  6602.  
  6603. * http://www.lua.org/manual/5.1/manual.html#5.4.1
  6604. * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
  6605. * http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns
  6606.  
  6607. ]]
  6608. -- This is the entry point for #invoke:String|match
  6609. function str.match( frame )
  6610.     local new_args = str._getParameters( frame.args, {'s', 'pattern', 'start', 'match', 'plain', 'nomatch'} )
  6611.     local s = new_args['s'] or ''
  6612.     local start = tonumber( new_args['start'] ) or 1
  6613.     local plain_flag = str._getBoolean( new_args['plain'] or false )
  6614.     local pattern = new_args['pattern'] or ''
  6615.     local match_index = math.floor( tonumber(new_args['match']) or 1 )
  6616.     local nomatch = new_args['nomatch']
  6617.  
  6618.     return str._match( s, pattern, start, match_index, plain_flag, nomatch )
  6619. end
  6620.  
  6621. --[[
  6622. pos
  6623.  
  6624. This function returns a single character from the target string at position pos.
  6625.  
  6626. Usage:
  6627. {{#invoke:String|pos|target_string|index_value}}
  6628. OR
  6629. {{#invoke:String|pos|target=target_string|pos=index_value}}
  6630.  
  6631. Parameters
  6632.     target: The string to search
  6633.     pos: The index for the character to return
  6634.  
  6635. If invoked using named parameters, Mediawiki will automatically remove any leading or
  6636. trailing whitespace from the target string.  In some circumstances this is desirable, in
  6637. other cases one may want to preserve the whitespace.
  6638.  
  6639. The first character has an index value of 1.
  6640.  
  6641. If one requests a negative value, this function will select a character by counting backwards
  6642. from the end of the string.  In other words pos = -1 is the same as asking for the last character.
  6643.  
  6644. A requested value of zero, or a value greater than the length of the string returns an error.
  6645. ]]
  6646. function str.pos( frame )
  6647.     local new_args = str._getParameters( frame.args, {'target', 'pos'} )
  6648.     local target_str = new_args['target'] or ''
  6649.     local pos = tonumber( new_args['pos'] ) or 0
  6650.  
  6651.     if pos == 0 or math.abs(pos) &gt; mw.ustring.len( target_str ) then
  6652.         return str._error( 'String index out of range' )
  6653.     end
  6654.  
  6655.     return mw.ustring.sub( target_str, pos, pos )
  6656. end
  6657.  
  6658. --[[
  6659. str_find
  6660.  
  6661. This function duplicates the behavior of {{str_find}}, including all of its quirks.
  6662. This is provided in order to support existing templates, but is NOT RECOMMENDED for
  6663. new code and templates.  New code is recommended to use the "find" function instead.
  6664.  
  6665. Returns the first index in "source" that is a match to "target".  Indexing is 1-based,
  6666. and the function returns -1 if the "target" string is not present in "source".
  6667.  
  6668. Important Note: If the "target" string is empty / missing, this function returns a
  6669. value of "1", which is generally unexpected behavior, and must be accounted for
  6670. separatetly.
  6671. ]]
  6672. function str.str_find( frame )
  6673.     local new_args = str._getParameters( frame.args, {'source', 'target'} )
  6674.     local source_str = new_args['source'] or ''
  6675.     local target_str = new_args['target'] or ''
  6676.  
  6677.     if target_str == '' then
  6678.         return 1
  6679.     end
  6680.  
  6681.     local start = mw.ustring.find( source_str, target_str, 1, true )
  6682.     if start == nil then
  6683.         start = -1
  6684.     end
  6685.  
  6686.     return start
  6687. end
  6688.  
  6689. --[[
  6690. find
  6691.  
  6692. This function allows one to search for a target string or pattern within another
  6693. string.
  6694.  
  6695. Usage:
  6696. {{#invoke:String|find|source_str|target_string|start_index|plain_flag}}
  6697. OR
  6698. {{#invoke:String|find|source=source_str|target=target_str|start=start_index|plain=plain_flag}}
  6699.  
  6700. Parameters
  6701.     source: The string to search
  6702.     target: The string or pattern to find within source
  6703.     start: The index within the source string to start the search, defaults to 1
  6704.     plain: Boolean flag indicating that target should be understood as plain
  6705.         text and not as a Lua style regular expression, defaults to true
  6706.  
  6707. If invoked using named parameters, Mediawiki will automatically remove any leading or
  6708. trailing whitespace from the parameter.  In some circumstances this is desirable, in
  6709. other cases one may want to preserve the whitespace.
  6710.  
  6711. This function returns the first index &gt;= "start" where "target" can be found
  6712. within "source".  Indices are 1-based.  If "target" is not found, then this
  6713. function returns 0.  If either "source" or "target" are missing / empty, this
  6714. function also returns 0.
  6715.  
  6716. This function should be safe for UTF-8 strings.
  6717. ]]
  6718. function str.find( frame )
  6719.     local new_args = str._getParameters( frame.args, {'source', 'target', 'start', 'plain' } )
  6720.     local source_str = new_args['source'] or ''
  6721.     local pattern = new_args['target'] or ''
  6722.     local start_pos = tonumber(new_args['start']) or 1
  6723.     local plain = new_args['plain'] or true
  6724.  
  6725.     if source_str == '' or pattern == '' then
  6726.         return 0
  6727.     end
  6728.  
  6729.     plain = str._getBoolean( plain )
  6730.  
  6731.     local start = mw.ustring.find( source_str, pattern, start_pos, plain )
  6732.     if start == nil then
  6733.         start = 0
  6734.     end
  6735.  
  6736.     return start
  6737. end
  6738.  
  6739. --[[
  6740. replace
  6741.  
  6742. This function allows one to replace a target string or pattern within another
  6743. string.
  6744.  
  6745. Usage:
  6746. {{#invoke:String|replace|source_str|pattern_string|replace_string|replacement_count|plain_flag}}
  6747. OR
  6748. {{#invoke:String|replace|source=source_string|pattern=pattern_string|replace=replace_string|
  6749.    count=replacement_count|plain=plain_flag}}
  6750.  
  6751. Parameters
  6752.     source: The string to search
  6753.     pattern: The string or pattern to find within source
  6754.     replace: The replacement text
  6755.     count: The number of occurences to replace, defaults to all.
  6756.     plain: Boolean flag indicating that pattern should be understood as plain
  6757.         text and not as a Lua style regular expression, defaults to true
  6758. ]]
  6759. function str.replace( frame )
  6760.     local new_args = str._getParameters( frame.args, {'source', 'pattern', 'replace', 'count', 'plain' } )
  6761.     local source_str = new_args['source'] or ''
  6762.     local pattern = new_args['pattern'] or ''
  6763.     local replace = new_args['replace'] or ''
  6764.     local count = tonumber( new_args['count'] )
  6765.     local plain = new_args['plain'] or true
  6766.  
  6767.     if source_str == '' or pattern == '' then
  6768.         return source_str
  6769.     end
  6770.     plain = str._getBoolean( plain )
  6771.  
  6772.     if plain then
  6773.         pattern = str._escapePattern( pattern )
  6774.         replace = mw.ustring.gsub( replace, "%%", "%%%%" ) --Only need to escape replacement sequences.
  6775.     end
  6776.  
  6777.     local result
  6778.  
  6779.     if count ~= nil then
  6780.         result = mw.ustring.gsub( source_str, pattern, replace, count )
  6781.     else
  6782.         result = mw.ustring.gsub( source_str, pattern, replace )
  6783.     end
  6784.  
  6785.     return result
  6786. end
  6787.  
  6788. --[[
  6789.     simple function to pipe string.rep to templates.
  6790. ]]
  6791. function str.rep( frame )
  6792.     local repetitions = tonumber( frame.args[2] )
  6793.     if not repetitions then
  6794.         return str._error( 'function rep expects a number as second parameter, received "' .. ( frame.args[2] or '' ) .. '"' )
  6795.     end
  6796.     return string.rep( frame.args[1] or '', repetitions )
  6797. end
  6798.  
  6799. --[[
  6800. escapePattern
  6801.  
  6802. This function escapes special characters from a Lua string pattern. See [1]
  6803. for details on how patterns work.
  6804.  
  6805. [1] https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
  6806.  
  6807. Usage:
  6808. {{#invoke:String|escapePattern|pattern_string}}
  6809.  
  6810. Parameters
  6811.     pattern_string: The pattern string to escape.
  6812. ]]
  6813. function str.escapePattern( frame )
  6814.     local pattern_str = frame.args[1]
  6815.     if not pattern_str then
  6816.         return str._error( 'No pattern string specified' )
  6817.     end
  6818.     local result = str._escapePattern( pattern_str )
  6819.     return result
  6820. end
  6821.  
  6822. --[[
  6823. count
  6824. This function counts the number of occurrences of one string in another.
  6825. ]]
  6826. function str.count(frame)
  6827.     local args = str._getParameters(frame.args, {'source', 'pattern', 'plain'})
  6828.     local source = args.source or ''
  6829.     local pattern = args.pattern or ''
  6830.     local plain = str._getBoolean(args.plain or true)
  6831.     if plain then
  6832.         pattern = str._escapePattern(pattern)
  6833.     end
  6834.     local _, count = mw.ustring.gsub(source, pattern, '')
  6835.     return count
  6836. end
  6837.  
  6838. --[[
  6839. endswith
  6840. This function determines whether a string ends with another string.
  6841. ]]
  6842. function str.endswith(frame)
  6843.     local args = str._getParameters(frame.args, {'source', 'pattern'})
  6844.     local source = args.source or ''
  6845.     local pattern = args.pattern or ''
  6846.     if pattern == '' then
  6847.         -- All strings end with the empty string.
  6848.         return "yes"
  6849.     end
  6850.     if mw.ustring.sub(source, -mw.ustring.len(pattern), -1) == pattern then
  6851.         return "yes"
  6852.     else
  6853.         return ""
  6854.     end
  6855. end
  6856.  
  6857. --[[
  6858. join
  6859.  
  6860. Join all non empty arguments together; the first argument is the separator.
  6861. Usage:
  6862. {{#invoke:String|join|sep|one|two|three}}
  6863. ]]
  6864. function str.join(frame)
  6865.     local args = {}
  6866.     local sep
  6867.     for _, v in ipairs( frame.args ) do
  6868.         if sep then
  6869.             if v ~= '' then
  6870.                 table.insert(args, v)
  6871.             end
  6872.         else
  6873.             sep = v
  6874.         end
  6875.     end
  6876.     return table.concat( args, sep or '' )
  6877. end
  6878.  
  6879. --[[
  6880. Helper function that populates the argument list given that user may need to use a mix of
  6881. named and unnamed parameters.  This is relevant because named parameters are not
  6882. identical to unnamed parameters due to string trimming, and when dealing with strings
  6883. we sometimes want to either preserve or remove that whitespace depending on the application.
  6884. ]]
  6885. function str._getParameters( frame_args, arg_list )
  6886.     local new_args = {}
  6887.     local index = 1
  6888.     local value
  6889.  
  6890.     for _, arg in ipairs( arg_list ) do
  6891.         value = frame_args[arg]
  6892.         if value == nil then
  6893.             value = frame_args[index]
  6894.             index = index + 1
  6895.         end
  6896.         new_args[arg] = value
  6897.     end
  6898.  
  6899.     return new_args
  6900. end
  6901.  
  6902. --[[
  6903. Helper function to handle error messages.
  6904. ]]
  6905. function str._error( error_str )
  6906.     local frame = mw.getCurrentFrame()
  6907.     local error_category = frame.args.error_category or 'Errors reported by Module String'
  6908.     local ignore_errors = frame.args.ignore_errors or false
  6909.     local no_category = frame.args.no_category or false
  6910.  
  6911.     if str._getBoolean(ignore_errors) then
  6912.         return ''
  6913.     end
  6914.  
  6915.     local error_str = '&lt;strong class="error"&gt;String Module Error: ' .. error_str .. '&lt;/strong&gt;'
  6916.     if error_category ~= '' and not str._getBoolean( no_category ) then
  6917.         error_str = '[[Category:' .. error_category .. ']]' .. error_str
  6918.     end
  6919.  
  6920.     return error_str
  6921. end
  6922.  
  6923. --[[
  6924. Helper Function to interpret boolean strings
  6925. ]]
  6926. function str._getBoolean( boolean_str )
  6927.     local boolean_value
  6928.  
  6929.     if type( boolean_str ) == 'string' then
  6930.         boolean_str = boolean_str:lower()
  6931.         if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0'
  6932.                 or boolean_str == '' then
  6933.             boolean_value = false
  6934.         else
  6935.             boolean_value = true
  6936.         end
  6937.     elseif type( boolean_str ) == 'boolean' then
  6938.         boolean_value = boolean_str
  6939.     else
  6940.         error( 'No boolean value found' )
  6941.     end
  6942.     return boolean_value
  6943. end
  6944.  
  6945. --[[
  6946. Helper function that escapes all pattern characters so that they will be treated
  6947. as plain text.
  6948. ]]
  6949. function str._escapePattern( pattern_str )
  6950.     return mw.ustring.gsub( pattern_str, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" )
  6951. end
  6952.  
  6953. return str</text>
  6954.       <sha1>cufmbepw7ml3gut4lchtqrhtj5r63cp</sha1>
  6955.     </revision>
  6956.   </page>
  6957.   <page>
  6958.     <title>Module:TableTools</title>
  6959.     <ns>828</ns>
  6960.     <id>41371028</id>
  6961.     <revision>
  6962.       <id>1069058368</id>
  6963.       <parentid>1048120640</parentid>
  6964.       <timestamp>2022-01-31T13:08:18Z</timestamp>
  6965.       <contributor>
  6966.         <username>MSGJ</username>
  6967.         <id>42630</id>
  6968.       </contributor>
  6969.       <comment>updates/fixes requested by [[User:Uzume]]</comment>
  6970.       <model>Scribunto</model>
  6971.       <format>text/plain</format>
  6972.       <text bytes="15281" xml:space="preserve">------------------------------------------------------------------------------------
  6973. --                                   TableTools                                   --
  6974. --                                                                                --
  6975. -- This module includes a number of functions for dealing with Lua tables.        --
  6976. -- It is a meta-module, meant to be called from other Lua modules, and should not --
  6977. -- be called directly from #invoke.                                               --
  6978. ------------------------------------------------------------------------------------
  6979.  
  6980. local libraryUtil = require('libraryUtil')
  6981.  
  6982. local p = {}
  6983.  
  6984. -- Define often-used variables and functions.
  6985. local floor = math.floor
  6986. local infinity = math.huge
  6987. local checkType = libraryUtil.checkType
  6988. local checkTypeMulti = libraryUtil.checkTypeMulti
  6989.  
  6990. ------------------------------------------------------------------------------------
  6991. -- isPositiveInteger
  6992. --
  6993. -- This function returns true if the given value is a positive integer, and false
  6994. -- if not. Although it doesn't operate on tables, it is included here as it is
  6995. -- useful for determining whether a given table key is in the array part or the
  6996. -- hash part of a table.
  6997. ------------------------------------------------------------------------------------
  6998. function p.isPositiveInteger(v)
  6999.     return type(v) == 'number' and v &gt;= 1 and floor(v) == v and v &lt; infinity
  7000. end
  7001.  
  7002. ------------------------------------------------------------------------------------
  7003. -- isNan
  7004. --
  7005. -- This function returns true if the given number is a NaN value, and false if
  7006. -- not. Although it doesn't operate on tables, it is included here as it is useful
  7007. -- for determining whether a value can be a valid table key. Lua will generate an
  7008. -- error if a NaN is used as a table key.
  7009. ------------------------------------------------------------------------------------
  7010. function p.isNan(v)
  7011.     return type(v) == 'number' and v ~= v
  7012. end
  7013.  
  7014. ------------------------------------------------------------------------------------
  7015. -- shallowClone
  7016. --
  7017. -- This returns a clone of a table. The value returned is a new table, but all
  7018. -- subtables and functions are shared. Metamethods are respected, but the returned
  7019. -- table will have no metatable of its own.
  7020. ------------------------------------------------------------------------------------
  7021. function p.shallowClone(t)
  7022.     checkType('shallowClone', 1, t, 'table')
  7023.     local ret = {}
  7024.     for k, v in pairs(t) do
  7025.         ret[k] = v
  7026.     end
  7027.     return ret
  7028. end
  7029.  
  7030. ------------------------------------------------------------------------------------
  7031. -- removeDuplicates
  7032. --
  7033. -- This removes duplicate values from an array. Non-positive-integer keys are
  7034. -- ignored. The earliest value is kept, and all subsequent duplicate values are
  7035. -- removed, but otherwise the array order is unchanged.
  7036. ------------------------------------------------------------------------------------
  7037. function p.removeDuplicates(arr)
  7038.     checkType('removeDuplicates', 1, arr, 'table')
  7039.     local isNan = p.isNan
  7040.     local ret, exists = {}, {}
  7041.     for _, v in ipairs(arr) do
  7042.         if isNan(v) then
  7043.             -- NaNs can't be table keys, and they are also unique, so we don't need to check existence.
  7044.             ret[#ret + 1] = v
  7045.         else
  7046.             if not exists[v] then
  7047.                 ret[#ret + 1] = v
  7048.                 exists[v] = true
  7049.             end
  7050.         end
  7051.     end
  7052.     return ret
  7053. end
  7054.  
  7055. ------------------------------------------------------------------------------------
  7056. -- numKeys
  7057. --
  7058. -- This takes a table and returns an array containing the numbers of any numerical
  7059. -- keys that have non-nil values, sorted in numerical order.
  7060. ------------------------------------------------------------------------------------
  7061. function p.numKeys(t)
  7062.     checkType('numKeys', 1, t, 'table')
  7063.     local isPositiveInteger = p.isPositiveInteger
  7064.     local nums = {}
  7065.     for k in pairs(t) do
  7066.         if isPositiveInteger(k) then
  7067.             nums[#nums + 1] = k
  7068.         end
  7069.     end
  7070.     table.sort(nums)
  7071.     return nums
  7072. end
  7073.  
  7074. ------------------------------------------------------------------------------------
  7075. -- affixNums
  7076. --
  7077. -- This takes a table and returns an array containing the numbers of keys with the
  7078. -- specified prefix and suffix. For example, for the table
  7079. -- {a1 = 'foo', a3 = 'bar', a6 = 'baz'} and the prefix "a", affixNums will return
  7080. -- {1, 3, 6}.
  7081. ------------------------------------------------------------------------------------
  7082. function p.affixNums(t, prefix, suffix)
  7083.     checkType('affixNums', 1, t, 'table')
  7084.     checkType('affixNums', 2, prefix, 'string', true)
  7085.     checkType('affixNums', 3, suffix, 'string', true)
  7086.  
  7087.     local function cleanPattern(s)
  7088.         -- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally.
  7089.         return s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])', '%%%1')
  7090.     end
  7091.  
  7092.     prefix = prefix or ''
  7093.     suffix = suffix or ''
  7094.     prefix = cleanPattern(prefix)
  7095.     suffix = cleanPattern(suffix)
  7096.     local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$'
  7097.  
  7098.     local nums = {}
  7099.     for k in pairs(t) do
  7100.         if type(k) == 'string' then
  7101.             local num = mw.ustring.match(k, pattern)
  7102.             if num then
  7103.                 nums[#nums + 1] = tonumber(num)
  7104.             end
  7105.         end
  7106.     end
  7107.     table.sort(nums)
  7108.     return nums
  7109. end
  7110.  
  7111. ------------------------------------------------------------------------------------
  7112. -- numData
  7113. --
  7114. -- Given a table with keys like {"foo1", "bar1", "foo2", "baz2"}, returns a table
  7115. -- of subtables in the format
  7116. -- {[1] = {foo = 'text', bar = 'text'}, [2] = {foo = 'text', baz = 'text'}}.
  7117. -- Keys that don't end with an integer are stored in a subtable named "other". The
  7118. -- compress option compresses the table so that it can be iterated over with
  7119. -- ipairs.
  7120. ------------------------------------------------------------------------------------
  7121. function p.numData(t, compress)
  7122.     checkType('numData', 1, t, 'table')
  7123.     checkType('numData', 2, compress, 'boolean', true)
  7124.     local ret = {}
  7125.     for k, v in pairs(t) do
  7126.         local prefix, num = mw.ustring.match(tostring(k), '^([^0-9]*)([1-9][0-9]*)$')
  7127.         if num then
  7128.             num = tonumber(num)
  7129.             local subtable = ret[num] or {}
  7130.             if prefix == '' then
  7131.                 -- Positional parameters match the blank string; put them at the start of the subtable instead.
  7132.                 prefix = 1
  7133.             end
  7134.             subtable[prefix] = v
  7135.             ret[num] = subtable
  7136.         else
  7137.             local subtable = ret.other or {}
  7138.             subtable[k] = v
  7139.             ret.other = subtable
  7140.         end
  7141.     end
  7142.     if compress then
  7143.         local other = ret.other
  7144.         ret = p.compressSparseArray(ret)
  7145.         ret.other = other
  7146.     end
  7147.     return ret
  7148. end
  7149.  
  7150. ------------------------------------------------------------------------------------
  7151. -- compressSparseArray
  7152. --
  7153. -- This takes an array with one or more nil values, and removes the nil values
  7154. -- while preserving the order, so that the array can be safely traversed with
  7155. -- ipairs.
  7156. ------------------------------------------------------------------------------------
  7157. function p.compressSparseArray(t)
  7158.     checkType('compressSparseArray', 1, t, 'table')
  7159.     local ret = {}
  7160.     local nums = p.numKeys(t)
  7161.     for _, num in ipairs(nums) do
  7162.         ret[#ret + 1] = t[num]
  7163.     end
  7164.     return ret
  7165. end
  7166.  
  7167. ------------------------------------------------------------------------------------
  7168. -- sparseIpairs
  7169. --
  7170. -- This is an iterator for sparse arrays. It can be used like ipairs, but can
  7171. -- handle nil values.
  7172. ------------------------------------------------------------------------------------
  7173. function p.sparseIpairs(t)
  7174.     checkType('sparseIpairs', 1, t, 'table')
  7175.     local nums = p.numKeys(t)
  7176.     local i = 0
  7177.     local lim = #nums
  7178.     return function ()
  7179.         i = i + 1
  7180.         if i &lt;= lim then
  7181.             local key = nums[i]
  7182.             return key, t[key]
  7183.         else
  7184.             return nil, nil
  7185.         end
  7186.     end
  7187. end
  7188.  
  7189. ------------------------------------------------------------------------------------
  7190. -- size
  7191. --
  7192. -- This returns the size of a key/value pair table. It will also work on arrays,
  7193. -- but for arrays it is more efficient to use the # operator.
  7194. ------------------------------------------------------------------------------------
  7195. function p.size(t)
  7196.     checkType('size', 1, t, 'table')
  7197.     local i = 0
  7198.     for _ in pairs(t) do
  7199.         i = i + 1
  7200.     end
  7201.     return i
  7202. end
  7203.  
  7204. local function defaultKeySort(item1, item2)
  7205.     -- "number" &lt; "string", so numbers will be sorted before strings.
  7206.     local type1, type2 = type(item1), type(item2)
  7207.     if type1 ~= type2 then
  7208.         return type1 &lt; type2
  7209.     elseif type1 == 'table' or type1 == 'boolean' or type1 == 'function' then
  7210.         return tostring(item1) &lt; tostring(item2)
  7211.     else
  7212.         return item1 &lt; item2
  7213.     end
  7214. end
  7215. ------------------------------------------------------------------------------------
  7216. -- keysToList
  7217. --
  7218. -- Returns an array of the keys in a table, sorted using either a default
  7219. -- comparison function or a custom keySort function.
  7220. ------------------------------------------------------------------------------------
  7221. function p.keysToList(t, keySort, checked)
  7222.     if not checked then
  7223.         checkType('keysToList', 1, t, 'table')
  7224.         checkTypeMulti('keysToList', 2, keySort, {'function', 'boolean', 'nil'})
  7225.     end
  7226.  
  7227.     local arr = {}
  7228.     local index = 1
  7229.     for k in pairs(t) do
  7230.         arr[index] = k
  7231.         index = index + 1
  7232.     end
  7233.  
  7234.     if keySort ~= false then
  7235.         keySort = type(keySort) == 'function' and keySort or defaultKeySort
  7236.         table.sort(arr, keySort)
  7237.     end
  7238.  
  7239.     return arr
  7240. end
  7241.  
  7242. ------------------------------------------------------------------------------------
  7243. -- sortedPairs
  7244. --
  7245. -- Iterates through a table, with the keys sorted using the keysToList function.
  7246. -- If there are only numerical keys, sparseIpairs is probably more efficient.
  7247. ------------------------------------------------------------------------------------
  7248. function p.sortedPairs(t, keySort)
  7249.     checkType('sortedPairs', 1, t, 'table')
  7250.     checkType('sortedPairs', 2, keySort, 'function', true)
  7251.  
  7252.     local arr = p.keysToList(t, keySort, true)
  7253.  
  7254.     local i = 0
  7255.     return function ()
  7256.         i = i + 1
  7257.         local key = arr[i]
  7258.         if key ~= nil then
  7259.             return key, t[key]
  7260.         else
  7261.             return nil, nil
  7262.         end
  7263.     end
  7264. end
  7265.  
  7266. ------------------------------------------------------------------------------------
  7267. -- isArray
  7268. --
  7269. -- Returns true if the given value is a table and all keys are consecutive
  7270. -- integers starting at 1.
  7271. ------------------------------------------------------------------------------------
  7272. function p.isArray(v)
  7273.     if type(v) ~= 'table' then
  7274.         return false
  7275.     end
  7276.     local i = 0
  7277.     for _ in pairs(v) do
  7278.         i = i + 1
  7279.         if v[i] == nil then
  7280.             return false
  7281.         end
  7282.     end
  7283.     return true
  7284. end
  7285.  
  7286. ------------------------------------------------------------------------------------
  7287. -- isArrayLike
  7288. --
  7289. -- Returns true if the given value is iterable and all keys are consecutive
  7290. -- integers starting at 1.
  7291. ------------------------------------------------------------------------------------
  7292. function p.isArrayLike(v)
  7293.     if not pcall(pairs, v) then
  7294.         return false
  7295.     end
  7296.     local i = 0
  7297.     for _ in pairs(v) do
  7298.         i = i + 1
  7299.         if v[i] == nil then
  7300.             return false
  7301.         end
  7302.     end
  7303.     return true
  7304. end
  7305.  
  7306. ------------------------------------------------------------------------------------
  7307. -- invert
  7308. --
  7309. -- Transposes the keys and values in an array. For example, {"a", "b", "c"} -&gt;
  7310. -- {a = 1, b = 2, c = 3}. Duplicates are not supported (result values refer to
  7311. -- the index of the last duplicate) and NaN values are ignored.
  7312. ------------------------------------------------------------------------------------
  7313. function p.invert(arr)
  7314.     checkType("invert", 1, arr, "table")
  7315.     local isNan = p.isNan
  7316.     local map = {}
  7317.     for i, v in ipairs(arr) do
  7318.         if not isNan(v) then
  7319.             map[v] = i
  7320.         end
  7321.     end
  7322.  
  7323.     return map
  7324. end
  7325.  
  7326. ------------------------------------------------------------------------------------
  7327. -- listToSet
  7328. --
  7329. -- Creates a set from the array part of the table. Indexing the set by any of the
  7330. -- values of the array returns true. For example, {"a", "b", "c"} -&gt;
  7331. -- {a = true, b = true, c = true}. NaN values are ignored as Lua considers them
  7332. -- never equal to any value (including other NaNs or even themselves).
  7333. ------------------------------------------------------------------------------------
  7334. function p.listToSet(arr)
  7335.     checkType("listToSet", 1, arr, "table")
  7336.     local isNan = p.isNan
  7337.     local set = {}
  7338.     for _, v in ipairs(arr) do
  7339.         if not isNan(v) then
  7340.             set[v] = true
  7341.         end
  7342.     end
  7343.  
  7344.     return set
  7345. end
  7346.  
  7347. ------------------------------------------------------------------------------------
  7348. -- deepCopy
  7349. --
  7350. -- Recursive deep copy function. Preserves identities of subtables.
  7351. ------------------------------------------------------------------------------------
  7352. local function _deepCopy(orig, includeMetatable, already_seen)
  7353.     -- Stores copies of tables indexed by the original table.
  7354.     already_seen = already_seen or {}
  7355.  
  7356.     local copy = already_seen[orig]
  7357.     if copy ~= nil then
  7358.         return copy
  7359.     end
  7360.  
  7361.     if type(orig) == 'table' then
  7362.         copy = {}
  7363.         for orig_key, orig_value in pairs(orig) do
  7364.             copy[_deepCopy(orig_key, includeMetatable, already_seen)] = _deepCopy(orig_value, includeMetatable, already_seen)
  7365.         end
  7366.         already_seen[orig] = copy
  7367.  
  7368.         if includeMetatable then
  7369.             local mt = getmetatable(orig)
  7370.             if mt ~= nil then
  7371.                 local mt_copy = _deepCopy(mt, includeMetatable, already_seen)
  7372.                 setmetatable(copy, mt_copy)
  7373.                 already_seen[mt] = mt_copy
  7374.             end
  7375.         end
  7376.     else -- number, string, boolean, etc
  7377.         copy = orig
  7378.     end
  7379.     return copy
  7380. end
  7381.  
  7382. function p.deepCopy(orig, noMetatable, already_seen)
  7383.     checkType("deepCopy", 3, already_seen, "table", true)
  7384.     return _deepCopy(orig, not noMetatable, already_seen)
  7385. end
  7386.  
  7387. ------------------------------------------------------------------------------------
  7388. -- sparseConcat
  7389. --
  7390. -- Concatenates all values in the table that are indexed by a number, in order.
  7391. -- sparseConcat{a, nil, c, d}  =&gt;  "acd"
  7392. -- sparseConcat{nil, b, c, d}  =&gt;  "bcd"
  7393. ------------------------------------------------------------------------------------
  7394. function p.sparseConcat(t, sep, i, j)
  7395.     local arr = {}
  7396.  
  7397.     local arr_i = 0
  7398.     for _, v in p.sparseIpairs(t) do
  7399.         arr_i = arr_i + 1
  7400.         arr[arr_i] = v
  7401.     end
  7402.  
  7403.     return table.concat(arr, sep, i, j)
  7404. end
  7405.  
  7406. ------------------------------------------------------------------------------------
  7407. -- length
  7408. --
  7409. -- Finds the length of an array, or of a quasi-array with keys such as "data1",
  7410. -- "data2", etc., using an exponential search algorithm. It is similar to the
  7411. -- operator #, but may return a different value when there are gaps in the array
  7412. -- portion of the table. Intended to be used on data loaded with mw.loadData. For
  7413. -- other tables, use #.
  7414. -- Note: #frame.args in frame object always be set to 0, regardless of  the number
  7415. -- of unnamed template parameters, so use this function for frame.args.
  7416. ------------------------------------------------------------------------------------
  7417. function p.length(t, prefix)
  7418.     -- requiring module inline so that [[Module:Exponential search]] which is
  7419.     -- only needed by this one function doesn't get millions of transclusions
  7420.     local expSearch = require("Module:Exponential search")
  7421.     checkType('length', 1, t, 'table')
  7422.     checkType('length', 2, prefix, 'string', true)
  7423.     return expSearch(function (i)
  7424.         local key
  7425.         if prefix then
  7426.             key = prefix .. tostring(i)
  7427.         else
  7428.             key = i
  7429.         end
  7430.         return t[key] ~= nil
  7431.     end) or 0
  7432. end
  7433.  
  7434. ------------------------------------------------------------------------------------
  7435. -- inArray
  7436. --
  7437. -- Returns true if valueToFind is a member of the array, and false otherwise.
  7438. ------------------------------------------------------------------------------------
  7439. function p.inArray(arr, valueToFind)
  7440.     checkType("inArray", 1, arr, "table")
  7441.     -- if valueToFind is nil, error?
  7442.  
  7443.     for _, v in ipairs(arr) do
  7444.         if v == valueToFind then
  7445.             return true
  7446.         end
  7447.     end
  7448.     return false
  7449. end
  7450.  
  7451. return p</text>
  7452.       <sha1>0z6y1iz1ggzcjp1rhkrrhgprosuh475</sha1>
  7453.     </revision>
  7454.   </page>
  7455.   <page>
  7456.     <title>Module:Transclusion count</title>
  7457.     <ns>828</ns>
  7458.     <id>61792794</id>
  7459.     <revision>
  7460.       <id>1061635767</id>
  7461.       <parentid>1057474521</parentid>
  7462.       <timestamp>2021-12-22T22:48:57Z</timestamp>
  7463.       <contributor>
  7464.         <username>GKFX</username>
  7465.         <id>14918984</id>
  7466.       </contributor>
  7467.       <comment>Correction to tabulate function</comment>
  7468.       <model>Scribunto</model>
  7469.       <format>text/plain</format>
  7470.       <text bytes="2174" xml:space="preserve">local p = {}
  7471.  
  7472. function p.fetch(frame)
  7473.     local template = nil
  7474.     local return_value = nil
  7475.  
  7476.     -- Use demo parameter if it exists, otherswise use current template name
  7477.     local namespace = mw.title.getCurrentTitle().namespace
  7478.     if frame.args["demo"] and frame.args["demo"] ~= "" then
  7479.         template = frame.args["demo"]
  7480.     elseif namespace == 10 then -- Template namespace
  7481.         template = mw.title.getCurrentTitle().text
  7482.     elseif namespace == 828 then -- Module namespace
  7483.         template = (mw.site.namespaces[828].name .. ":" .. mw.title.getCurrentTitle().text)
  7484.     end
  7485.  
  7486.     -- If in template or module namespace, look up count in /data
  7487.     if template ~= nil then
  7488.         namespace = mw.title.new(template, "Template").namespace
  7489.         if namespace == 10 or namespace == 828 then
  7490.             template =  mw.ustring.gsub(template, "/doc$", "") -- strip /doc from end
  7491.             local index = mw.ustring.sub(mw.title.new(template).text,1,1)
  7492.             local status, data = pcall(function ()
  7493.                 return(mw.loadData('Module:Transclusion_count/data/' .. (mw.ustring.find(index, "%a") and index or "other")))
  7494.             end)
  7495.             if status then
  7496.                 return_value = tonumber(data[mw.ustring.gsub(template, " ", "_")])
  7497.             end
  7498.         end
  7499.     end
  7500.    
  7501.     -- If database value doesn't exist, use value passed to template
  7502.     if return_value == nil and frame.args[1] ~= nil then
  7503.         local arg1=mw.ustring.match(frame.args[1], '[%d,]+')
  7504.         if arg1 and arg1 ~= '' then
  7505.             return_value = tonumber(frame:callParserFunction('formatnum', arg1, 'R'))
  7506.         end
  7507.     end
  7508.    
  7509.     return return_value
  7510. end
  7511.  
  7512. -- Tabulate this data for [[Wikipedia:Database reports/Templates transcluded on the most pages]]
  7513. function p.tabulate(frame)
  7514.     local list = {}
  7515.     for i = 65, 91 do
  7516.         local data = mw.loadData('Module:Transclusion count/data/' .. ((i == 91) and 'other' or string.char(i)))
  7517.         for name, count in pairs(data) do
  7518.             table.insert(list, {mw.title.new(name, "Template").fullText, count})   
  7519.         end
  7520.     end
  7521.     table.sort(list, function(a, b)
  7522.         return (a[2] == b[2]) and (a[1] &lt; b[1]) or (a[2] &gt; b[2])
  7523.     end)
  7524.     local lang = mw.getContentLanguage();
  7525.     for i = 1, #list do
  7526.         list[i] = ('|-\n| %d || [[%s]] || %s\n'):format(i, list[i][1]:gsub('_', ' '), lang:formatNum(list[i][2]))
  7527.     end
  7528.     return table.concat(list)
  7529. end
  7530.  
  7531. return p</text>
  7532.       <sha1>i4hf4ogs2jqprtn91iinnikcxeyynd9</sha1>
  7533.     </revision>
  7534.   </page>
  7535.   <page>
  7536.     <title>Module:Transclusion count/data/M</title>
  7537.     <ns>828</ns>
  7538.     <id>61481077</id>
  7539.     <revision>
  7540.       <id>1071544693</id>
  7541.       <parentid>1070187754</parentid>
  7542.       <timestamp>2022-02-13T05:13:35Z</timestamp>
  7543.       <contributor>
  7544.         <username>Ahechtbot</username>
  7545.         <id>26109785</id>
  7546.       </contributor>
  7547.       <minor/>
  7548.       <comment>[[Wikipedia:BOT|Bot]]: Updated page.</comment>
  7549.       <model>Scribunto</model>
  7550.       <format>text/plain</format>
  7551.       <text bytes="3889" xml:space="preserve">return {
  7552. ["MAD"] = 2000,
  7553. ["MAR"] = 2600,
  7554. ["MAS"] = 2400,
  7555. ["MDG"] = 2200,
  7556. ["MEX"] = 6000,
  7557. ["MILHIST"] = 12000,
  7558. ["MINUTE"] = 2300,
  7559. ["MKD"] = 2300,
  7560. ["MLB_Farm_System"] = 2100,
  7561. ["MLB_Year"] = 13000,
  7562. ["MLB_standings"] = 3700,
  7563. ["MLBplayer"] = 4000,
  7564. ["MMA_record_start"] = 3500,
  7565. ["MMArecordbox"] = 3500,
  7566. ["MMSI_Number"] = 3000,
  7567. ["MONTH"] = 6400,
  7568. ["MONTHNAME"] = 740000,
  7569. ["MONTHNUMBER"] = 751000,
  7570. ["MS"] = 4600,
  7571. ["MV"] = 8400,
  7572. ["MYS"] = 3500,
  7573. ["MacTutor"] = 2000,
  7574. ["Main"] = 309000,
  7575. ["Main_article"] = 27000,
  7576. ["Main_other"] = 8960000,
  7577. ["Main_page_image"] = 20000,
  7578. ["Main_page_image/DYK"] = 5800,
  7579. ["Main_page_image/TFA"] = 3600,
  7580. ["Maintenance_category"] = 35000,
  7581. ["Map_requested"] = 9800,
  7582. ["Map_requested/Category_helper"] = 8300,
  7583. ["Maplink"] = 18000,
  7584. ["Marriage"] = 57000,
  7585. ["Math"] = 7900,
  7586. ["MathGenealogy"] = 6700,
  7587. ["MathWorld"] = 2400,
  7588. ["Maths_rating"] = 20000,
  7589. ["Max"] = 230000,
  7590. ["Mbox"] = 2190000,
  7591. ["Mdash"] = 7900,
  7592. ["MeSH_name"] = 6000,
  7593. ["Medal"] = 104000,
  7594. ["MedalBottom"] = 17000,
  7595. ["MedalBronze"] = 50000,
  7596. ["MedalCompetition"] = 80000,
  7597. ["MedalCount"] = 2400,
  7598. ["MedalCountry"] = 73000,
  7599. ["MedalGold"] = 49000,
  7600. ["MedalOlympic"] = 3900,
  7601. ["MedalOlympics"] = 6000,
  7602. ["MedalSilver"] = 49000,
  7603. ["MedalSport"] = 73000,
  7604. ["MedalTableTop"] = 17000,
  7605. ["MedalTop"] = 4400,
  7606. ["MedalWorldChampionships"] = 2200,
  7607. ["MedalistTable"] = 13000,
  7608. ["Medals_table"] = 12000,
  7609. ["Media"] = 2500,
  7610. ["Medical_resources"] = 6700,
  7611. ["Merge_done"] = 2700,
  7612. ["Merge_partner"] = 3000,
  7613. ["Merged-from"] = 14000,
  7614. ["Merged-to"] = 16000,
  7615. ["Merged_to"] = 2100,
  7616. ["MeshName"] = 5900,
  7617. ["Metacritic_film"] = 4100,
  7618. ["Metadata_Population_DE-BY"] = 2100,
  7619. ["Metadata_Population_DE-RP"] = 2300,
  7620. ["Mhof"] = 6700,
  7621. ["Mid-Class"] = 15000,
  7622. ["Mid-importance"] = 15000,
  7623. ["Middot"] = 79000,
  7624. ["MilHist"] = 2500,
  7625. ["Military_navigation"] = 79000,
  7626. ["Min"] = 18000,
  7627. ["Minor_planet"] = 4800,
  7628. ["Minor_planet_link"] = 2600,
  7629. ["Minor_planet_list_link"] = 4100,
  7630. ["Minor_planets_navigator"] = 3100,
  7631. ["MirrorH"] = 4700,
  7632. ["Missing_information"] = 3000,
  7633. ["Mlby"] = 13000,
  7634. ["Mobile_IP"] = 9900,
  7635. ["MobyGames"] = 7600,
  7636. ["Moby_game"] = 6100,
  7637. ["Mod"] = 14000,
  7638. ["Module_other"] = 3100,
  7639. ["Mojo_title"] = 7800,
  7640. ["Molecular_formula_index"] = 2200,
  7641. ["Monday"] = 2600,
  7642. ["Mono"] = 17000,
  7643. ["Mono/styles.css"] = 18000,
  7644. ["MonthCategoryNav"] = 28000,
  7645. ["MonthlyArchive"] = 2700,
  7646. ["MonthlyLinks"] = 2700,
  7647. ["Monthly_archive_list"] = 2700,
  7648. ["Monthly_clean-up_category"] = 14000,
  7649. ["Monthly_clean-up_category/core"] = 14000,
  7650. ["Monthly_clean-up_category/monthname"] = 15000,
  7651. ["Monthly_clean-up_category/monthno"] = 15000,
  7652. ["Monthly_clean-up_category/name_part"] = 15000,
  7653. ["Monthly_clean-up_category/outer_core"] = 14000,
  7654. ["Monthly_clean-up_category/to_add"] = 2500,
  7655. ["Monthly_clean_up_category"] = 7600,
  7656. ["Monthyear"] = 89000,
  7657. ["Monthyear-1"] = 87000,
  7658. ["More_citations_needed"] = 365000,
  7659. ["More_citations_needed_section"] = 16000,
  7660. ["More_footnotes"] = 47000,
  7661. ["More_footnotes_needed"] = 50000,
  7662. ["More_references"] = 3400,
  7663. ["Moresources"] = 5900,
  7664. ["Motorcycling"] = 3200,
  7665. ["Motorsport_season"] = 4600,
  7666. ["Motorsport_season/styles.css"] = 4600,
  7667. ["Moved_discussion_from"] = 2400,
  7668. ["Moved_discussion_to"] = 2300,
  7669. ["Mp"] = 4800,
  7670. ["Mpl"] = 2600,
  7671. ["MultiReplace"] = 198000,
  7672. ["Multiple_image"] = 39000,
  7673. ["Multiple_image/styles.css"] = 39000,
  7674. ["Multiple_issues"] = 120000,
  7675. ["Music"] = 7200,
  7676. ["MusicBrainz_artist"] = 2100,
  7677. ["MusicBrainz_meta"] = 4400,
  7678. ["Mvar"] = 5400,
  7679. ["Mw_lang"] = 68000,
  7680. ["My"] = 2400,
  7681. ["My_sandbox"] = 3800,
  7682. ["Myprefs"] = 9000,
  7683. ["Module:MLB_standings"] = 3700,
  7684. ["Module:MLB_standings/data"] = 3700,
  7685. ["Module:Main_page_image"] = 9900,
  7686. ["Module:Mapframe"] = 362000,
  7687. ["Module:Math"] = 1480000,
  7688. ["Module:Medals_table"] = 12000,
  7689. ["Module:Message_box"] = 8920000,
  7690. ["Module:Message_box/configuration"] = 8920000,
  7691. ["Module:Military_navigation"] = 79000,
  7692. ["Module:Minor_planet_list_link"] = 4100,
  7693. ["Module:MultiReplace"] = 580000,
  7694. ["Module:Multiple_image"] = 39000,
  7695. ["Module:Mw_lang"] = 69000,
  7696. }</text>
  7697.       <sha1>qdzbibfhs0x3zmqrqgv33umbkeln73y</sha1>
  7698.     </revision>
  7699.   </page>
  7700.   <page>
  7701.     <title>Module:Message box/configuration/doc</title>
  7702.     <ns>828</ns>
  7703.     <id>41157099</id>
  7704.     <revision>
  7705.       <id>1044612974</id>
  7706.       <parentid>1044543567</parentid>
  7707.       <timestamp>2021-09-16T04:44:59Z</timestamp>
  7708.       <contributor>
  7709.         <username>Pppery</username>
  7710.         <id>28032115</id>
  7711.       </contributor>
  7712.       <comment>Undid revision 1044543567 by [[Special:Contributions/Tiwutt12|Tiwutt12]] ([[User talk:Tiwutt12|talk]])</comment>
  7713.       <model>wikitext</model>
  7714.       <format>text/x-wiki</format>
  7715.       <text bytes="228" xml:space="preserve">{{Used in system}}
  7716. {{Module rating|protected}}
  7717. {{#ifeq:{{PAGENAME}}|Message box/configuration/sandbox|
  7718. {{Mbox|small=yes|type=notice|text=See related module:
  7719. * [[Module:Message box]] ([[Module:Message box/sandbox|sandbox]])
  7720. }}
  7721. }}</text>
  7722.       <sha1>fj3zeas2cqac302rr9ff1x8xdr4obio</sha1>
  7723.     </revision>
  7724.   </page>
  7725.   <page>
  7726.     <title>Module:No globals/doc</title>
  7727.     <ns>828</ns>
  7728.     <id>42567040</id>
  7729.     <revision>
  7730.       <id>1061323199</id>
  7731.       <parentid>1022000984</parentid>
  7732.       <timestamp>2021-12-21T01:09:31Z</timestamp>
  7733.       <contributor>
  7734.         <username>EthanGaming7640</username>
  7735.         <id>42316941</id>
  7736.       </contributor>
  7737.       <minor/>
  7738.       <model>wikitext</model>
  7739.       <format>text/x-wiki</format>
  7740.       <text bytes="923" xml:space="preserve">{{used in system}}
  7741. {{module rating|protected}}
  7742. &lt;!-- Template categories go at the bottom of this page. --&gt;
  7743.  
  7744. This module causes an error if any nil [[global variable|global]] is read or if any global is written to, with the exception of &lt;var&gt;arg&lt;/var&gt;. To use, add &lt;syntaxhighlight lang="lua" inline&gt;require('Module:No globals')&lt;/syntaxhighlight&gt; to the top of the module using it. The &lt;var&gt;arg&lt;/var&gt; variable is excluded because it is necessary for Scribunto's [[mw:Extension:Scribunto/Lua reference manual#require|require]] function to work properly. (See the Scribunto source code [[phab:diffusion/ELUA/browse/master/includes/engines/LuaCommon/lualib/package.lua;1fad4da13706f4dbdd0477a834675b9d09757bf6|here]].)
  7745.  
  7746. == See also ==
  7747. * [[Module:Log globals]] – adds all nil global reads/writes to the Lua log
  7748.  
  7749. &lt;includeonly&gt;{{Sandbox other||
  7750. &lt;!-- Template categories go here. --&gt;
  7751. [[Category:Lua metamodules]]
  7752. }}&lt;/includeonly&gt;</text>
  7753.       <sha1>4h7oec1hp3umv1zzbntaenb888t73cg</sha1>
  7754.     </revision>
  7755.   </page>
  7756.   <page>
  7757.     <title>Module:Transclusion count/data/N</title>
  7758.     <ns>828</ns>
  7759.     <id>61481068</id>
  7760.     <revision>
  7761.       <id>1071545058</id>
  7762.       <parentid>1070187547</parentid>
  7763.       <timestamp>2022-02-13T05:15:36Z</timestamp>
  7764.       <contributor>
  7765.         <username>Ahechtbot</username>
  7766.         <id>26109785</id>
  7767.       </contributor>
  7768.       <minor/>
  7769.       <comment>[[Wikipedia:BOT|Bot]]: Updated page.</comment>
  7770.       <model>Scribunto</model>
  7771.       <format>text/plain</format>
  7772.       <text bytes="7724" xml:space="preserve">return {
  7773. ["N"] = 11000,
  7774. ["N/A"] = 20000,
  7775. ["N/a"] = 45000,
  7776. ["NA-Class"] = 14000,
  7777. ["NASTRO_comment"] = 29000,
  7778. ["NBA_Draft_template_list"] = 3200,
  7779. ["NBA_Year"] = 5400,
  7780. ["NBA_color"] = 3600,
  7781. ["NBA_color_cell"] = 4300,
  7782. ["NBA_color_cell2"] = 3400,
  7783. ["NBA_player_statistics_legend"] = 3700,
  7784. ["NBA_player_statistics_start"] = 3300,
  7785. ["NBbox"] = 3400,
  7786. ["NCAA_color_cell"] = 8000,
  7787. ["NCAA_secondary_color_cell"] = 3800,
  7788. ["NED"] = 9500,
  7789. ["NEXTYEAR"] = 6300,
  7790. ["NFLAltPrimaryColor"] = 2100,
  7791. ["NFLAltPrimaryStyle"] = 5700,
  7792. ["NFLAltSecondaryColor"] = 2400,
  7793. ["NFLPrimaryColor"] = 2100,
  7794. ["NFLPrimaryStyle"] = 27000,
  7795. ["NFLSecondaryColor"] = 18000,
  7796. ["NFL_Roster_navbox_template_list"] = 2500,
  7797. ["NFL_Year"] = 21000,
  7798. ["NFL_predraft"] = 4200,
  7799. ["NFL_predraft/check"] = 4200,
  7800. ["NFL_predraft/ftin"] = 4200,
  7801. ["NFT"] = 6200,
  7802. ["NFT_player"] = 30000,
  7803. ["NGA"] = 2900,
  7804. ["NGR"] = 2100,
  7805. ["NHLE"] = 16000,
  7806. ["NHLS_url"] = 2200,
  7807. ["NLD"] = 11000,
  7808. ["NLM_content"] = 2800,
  7809. ["NOINDEX"] = 418000,
  7810. ["NOMIS2011"] = 2200,
  7811. ["NOR"] = 8900,
  7812. ["NRDB_species"] = 5900,
  7813. ["NRHP-PA"] = 2600,
  7814. ["NRHPGoogleMapFootnote"] = 2500,
  7815. ["NRHP_Focus"] = 75000,
  7816. ["NRHP_color"] = 3700,
  7817. ["NRHP_date_for_lists"] = 3100,
  7818. ["NRHP_date_for_lists/dates"] = 3100,
  7819. ["NRHP_header"] = 3300,
  7820. ["NRHP_navigation_box"] = 8000,
  7821. ["NRHP_row"] = 3400,
  7822. ["NRHP_style"] = 69000,
  7823. ["NRHP_url"] = 28000,
  7824. ["NRHP_url/core"] = 30000,
  7825. ["NRISref"] = 72000,
  7826. ["NSWcity"] = 2200,
  7827. ["NSWcity/core"] = 2200,
  7828. ["NUMBEROFSECTIONS"] = 3300,
  7829. ["NYCS_br"] = 2700,
  7830. ["NYCS_time_2"] = 3100,
  7831. ["NZL"] = 6700,
  7832. ["NZ_electorate_link"] = 2200,
  7833. ["Nac"] = 2200,
  7834. ["Namespace_detect"] = 522000,
  7835. ["Namespace_detect_showall"] = 5300,
  7836. ["Nastaliq"] = 9300,
  7837. ["Nat_fs_end"] = 2200,
  7838. ["National_Heritage_List_for_England"] = 20000,
  7839. ["National_Rail_style"] = 5500,
  7840. ["National_Register_of_Historic_Places"] = 29000,
  7841. ["National_Register_of_Historic_Places_in_Massachusetts"] = 4300,
  7842. ["National_Register_of_Historic_Places_in_New_York"] = 5500,
  7843. ["National_Register_of_Historic_Places_in_North_Carolina"] = 2900,
  7844. ["National_Register_of_Historic_Places_in_Pennsylvania"] = 3200,
  7845. ["National_Register_of_Historic_Places_in_Virginia"] = 3100,
  7846. ["National_basketball_squad"] = 3300,
  7847. ["National_field_hockey_squad"] = 3800,
  7848. ["National_football_squad_end"] = 2800,
  7849. ["National_football_squad_start/styles.css"] = 2300,
  7850. ["National_rugby_union_team"] = 3400,
  7851. ["National_squad"] = 39000,
  7852. ["National_squad_no_numbers"] = 16000,
  7853. ["Native_name"] = 13000,
  7854. ["Native_name_checker"] = 76000,
  7855. ["Naval"] = 2100,
  7856. ["Naval/core"] = 2100,
  7857. ["Navbar"] = 939000,
  7858. ["Navbar-collapsible"] = 3400,
  7859. ["Navbar-header"] = 15000,
  7860. ["Navbar-header/styles.css"] = 15000,
  7861. ["Navbox"] = 2940000,
  7862. ["Navbox_GR_munic"] = 3400,
  7863. ["Navbox_Musical_artist"] = 9600,
  7864. ["Navbox_bottom"] = 14000,
  7865. ["Navbox_decade_list"] = 11000,
  7866. ["Navbox_musical_artist"] = 212000,
  7867. ["Navbox_musical_artist/color"] = 212000,
  7868. ["Navbox_rugby_league_squad"] = 5100,
  7869. ["Navbox_season_by_team"] = 3100,
  7870. ["Navbox_top"] = 14000,
  7871. ["Navbox_with_collapsible_groups"] = 130000,
  7872. ["Navbox_with_collapsible_sections"] = 2200,
  7873. ["Navbox_with_columns"] = 23000,
  7874. ["Navboxes"] = 50000,
  7875. ["Navboxes_colour"] = 7200,
  7876. ["Navseasoncats"] = 446000,
  7877. ["Navseasoncats_with_centuries_below_decade"] = 6100,
  7878. ["Navseasoncats_with_decades_below_year"] = 19000,
  7879. ["Navsource"] = 2500,
  7880. ["Navy"] = 18000,
  7881. ["Navy/core"] = 18000,
  7882. ["Nay"] = 13000,
  7883. ["Nbay"] = 5400,
  7884. ["Nbsp"] = 445000,
  7885. ["Nbsp_to_space"] = 17000,
  7886. ["Ndash"] = 17000,
  7887. ["Nee"] = 5300,
  7888. ["NeilBrownPlayers"] = 3100,
  7889. ["New_York_Stock_Exchange"] = 2000,
  7890. ["New_user_bar"] = 57000,
  7891. ["Newbot"] = 4100,
  7892. ["Next_period"] = 19000,
  7893. ["Nfly"] = 2000,
  7894. ["Nihongo"] = 98000,
  7895. ["Nihongo2"] = 12000,
  7896. ["Nihongo_foot"] = 2200,
  7897. ["No"] = 7100,
  7898. ["No."] = 14000,
  7899. ["No2"] = 9100,
  7900. ["NoSpam"] = 4100,
  7901. ["NoSpamEmail"] = 17000,
  7902. ["No_col_break"] = 2100,
  7903. ["No_col_break/styles.css"] = 2100,
  7904. ["No_footnotes"] = 52000,
  7905. ["No_ping"] = 434000,
  7906. ["No_plot"] = 4100,
  7907. ["No_redirect"] = 522000,
  7908. ["No_spam"] = 241000,
  7909. ["No_wrap"] = 2100,
  7910. ["Nobold"] = 360000,
  7911. ["Nobold/styles.css"] = 360000,
  7912. ["Nobr"] = 4000,
  7913. ["Nobreak"] = 28000,
  7914. ["Nochange"] = 2300,
  7915. ["Noflag"] = 2100,
  7916. ["Nofootnotes"] = 2100,
  7917. ["Noindex"] = 4700,
  7918. ["Noitalic"] = 4500,
  7919. ["Noitalic/styles.css"] = 4500,
  7920. ["Nom"] = 33000,
  7921. ["Nominated"] = 5900,
  7922. ["Non-admin_closure"] = 2300,
  7923. ["Non-diffusing_subcategory"] = 12000,
  7924. ["Non-free_2D_art"] = 6300,
  7925. ["Non-free_3D_art"] = 2100,
  7926. ["Non-free_album_cover"] = 192000,
  7927. ["Non-free_audio_sample"] = 8600,
  7928. ["Non-free_biog-pic"] = 21000,
  7929. ["Non-free_book_cover"] = 52000,
  7930. ["Non-free_comic"] = 11000,
  7931. ["Non-free_fair_use"] = 18000,
  7932. ["Non-free_fair_use_in"] = 15000,
  7933. ["Non-free_film_screenshot"] = 5100,
  7934. ["Non-free_game_cover"] = 6500,
  7935. ["Non-free_game_screenshot"] = 4100,
  7936. ["Non-free_historic_image"] = 16000,
  7937. ["Non-free_image_data"] = 8300,
  7938. ["Non-free_image_rationale"] = 9500,
  7939. ["Non-free_in_US"] = 2100,
  7940. ["Non-free_logo"] = 159000,
  7941. ["Non-free_magazine_cover"] = 7400,
  7942. ["Non-free_media"] = 698000,
  7943. ["Non-free_media_data"] = 9400,
  7944. ["Non-free_media_rationale"] = 11000,
  7945. ["Non-free_movie_poster"] = 19000,
  7946. ["Non-free_poster"] = 96000,
  7947. ["Non-free_promotional"] = 9000,
  7948. ["Non-free_school_logo"] = 2300,
  7949. ["Non-free_seal"] = 3500,
  7950. ["Non-free_symbol"] = 6200,
  7951. ["Non-free_television_screenshot"] = 16000,
  7952. ["Non-free_title-card"] = 4700,
  7953. ["Non-free_use_rationale"] = 449000,
  7954. ["Non-free_use_rationale_2"] = 190000,
  7955. ["Non-free_use_rationale_album_cover"] = 127000,
  7956. ["Non-free_use_rationale_book_cover"] = 17000,
  7957. ["Non-free_use_rationale_logo"] = 97000,
  7958. ["Non-free_use_rationale_poster"] = 47000,
  7959. ["Non-free_use_rationale_title-card"] = 2100,
  7960. ["Non-free_use_rationale_video_cover"] = 5600,
  7961. ["Non-free_use_rationale_video_game_cover"] = 9500,
  7962. ["Non-free_video_cover"] = 16000,
  7963. ["Non-free_video_game_cover"] = 20000,
  7964. ["Non-free_video_game_cover/platform"] = 20000,
  7965. ["Non-free_video_game_screenshot"] = 9800,
  7966. ["Non-free_video_game_screenshot/platform"] = 9100,
  7967. ["Non-free_with_permission"] = 2200,
  7968. ["Nonumtoc"] = 2200,
  7969. ["Nonumtoc/styles.css"] = 2200,
  7970. ["Noping"] = 359000,
  7971. ["Noprint"] = 2800,
  7972. ["Noredirect"] = 7900,
  7973. ["Normalwraplink"] = 3100,
  7974. ["NorthAmNative"] = 2600,
  7975. ["North_America_topic"] = 3700,
  7976. ["Northern_Ireland_tasks"] = 19000,
  7977. ["Nospam"] = 13000,
  7978. ["Not-PD-US-expired-min-year"] = 26000,
  7979. ["Not_a_ballot"] = 7400,
  7980. ["Not_a_forum"] = 7300,
  7981. ["Not_a_typo"] = 8200,
  7982. ["Not_around"] = 2700,
  7983. ["Not_done"] = 18000,
  7984. ["Notability"] = 59000,
  7985. ["Notavote"] = 2000,
  7986. ["Notdone"] = 5200,
  7987. ["Note"] = 25000,
  7988. ["NoteFoot"] = 3000,
  7989. ["NoteTag"] = 3000,
  7990. ["Note_label"] = 8600,
  7991. ["Notelist"] = 140000,
  7992. ["Notelist-lr"] = 3000,
  7993. ["Notelist-ua"] = 5500,
  7994. ["Notes"] = 6400,
  7995. ["Noteslist"] = 2800,
  7996. ["Notice"] = 104000,
  7997. ["NovelsWikiProject"] = 19000,
  7998. ["Nowiki_="] = 3800,
  7999. ["Nowrap"] = 1390000,
  8000. ["Npby"] = 2100,
  8001. ["Nq"] = 2800,
  8002. ["Nrut"] = 3400,
  8003. ["Ns"] = 2300,
  8004. ["Ns0"] = 328000,
  8005. ["Ns_has_subpages"] = 1820000,
  8006. ["Nts"] = 15000,
  8007. ["Ntsh"] = 3000,
  8008. ["Number_of_defined_parameters"] = 4400,
  8009. ["Number_table_sorting"] = 27000,
  8010. ["Number_table_sorting_hidden"] = 3000,
  8011. ["Nutshell"] = 3700,
  8012. ["Nw="] = 3800,
  8013. ["Module:NUMBEROFSECTIONS"] = 3300,
  8014. ["Module:Namespace_detect"] = 14300000,
  8015. ["Module:Namespace_detect/config"] = 15600000,
  8016. ["Module:Namespace_detect/data"] = 15600000,
  8017. ["Module:National_squad"] = 52000,
  8018. ["Module:Native_name"] = 85000,
  8019. ["Module:Navbar"] = 6090000,
  8020. ["Module:Navbar/configuration"] = 5410000,
  8021. ["Module:Navbar/styles.css"] = 4790000,
  8022. ["Module:Navbox"] = 4250000,
  8023. ["Module:Navbox/configuration"] = 4120000,
  8024. ["Module:Navbox/styles.css"] = 4120000,
  8025. ["Module:Navbox_top_and_bottom"] = 14000,
  8026. ["Module:Navbox_with_collapsible_groups"] = 135000,
  8027. ["Module:Navboxes"] = 51000,
  8028. ["Module:Navseasoncats"] = 446000,
  8029. ["Module:Nihongo"] = 100000,
  8030. ["Module:No_globals"] = 18000000,
  8031. ["Module:No_ping"] = 434000,
  8032. ["Module:Noinclude"] = 368000,
  8033. ["Module:Ns_has_subpages"] = 1820000,
  8034. ["Module:Number_table_sorting"] = 29000,
  8035. }</text>
  8036.       <sha1>iy6voi40ghymue0cyb4o5zma8u59cvh</sha1>
  8037.     </revision>
  8038.   </page>
  8039.   <page>
  8040.     <title>Template:Template link with link off</title>
  8041.     <ns>10</ns>
  8042.     <id>16451586</id>
  8043.     <revision>
  8044.       <id>989853150</id>
  8045.       <parentid>989724556</parentid>
  8046.       <timestamp>2020-11-21T12:06:17Z</timestamp>
  8047.       <contributor>
  8048.         <username>Primefac</username>
  8049.         <id>11508456</id>
  8050.       </contributor>
  8051.       <comment>update</comment>
  8052.       <model>wikitext</model>
  8053.       <format>text/x-wiki</format>
  8054.       <text bytes="231" xml:space="preserve">&lt;includeonly&gt;{{#Invoke:Template link general|main|nowrap=yes|nolink=yes}}&lt;/includeonly&gt;&lt;noinclude&gt;
  8055. {{Documentation|1=Template:Tlg/doc
  8056. |content = {{tlg/doc|tlf}}
  8057. }}
  8058. &lt;!-- Add categories to the /doc subpage, not here! --&gt;
  8059. &lt;/noinclude&gt;</text>
  8060.       <sha1>kmn80yu5079jyyvwn623d36xsqq3dch</sha1>
  8061.     </revision>
  8062.   </page>
  8063.   <page>
  8064.     <title>Template:Tlf</title>
  8065.     <ns>10</ns>
  8066.     <id>63645417</id>
  8067.     <redirect title="Template:Template link with link off" />
  8068.     <revision>
  8069.       <id>950726704</id>
  8070.       <timestamp>2020-04-13T14:42:57Z</timestamp>
  8071.       <contributor>
  8072.         <username>Primefac</username>
  8073.         <id>11508456</id>
  8074.       </contributor>
  8075.       <comment>Primefac moved page [[Template:Tlf]] to [[Template:Template link with link off]]: full name to indicate what it does</comment>
  8076.       <model>wikitext</model>
  8077.       <format>text/x-wiki</format>
  8078.       <text bytes="97" xml:space="preserve">#REDIRECT [[Template:Template link with link off]]
  8079.  
  8080. {{Redirect category shell|
  8081. {{R from move}}
  8082. }}</text>
  8083.       <sha1>9mrb4gzoa8i94zzxq5i6opzke6v5ntr</sha1>
  8084.     </revision>
  8085.   </page>
  8086.   <page>
  8087.     <title>Module:Category handler/blacklist</title>
  8088.     <ns>828</ns>
  8089.     <id>43232926</id>
  8090.     <revision>
  8091.       <id>951673917</id>
  8092.       <parentid>948472491</parentid>
  8093.       <timestamp>2020-04-18T08:48:05Z</timestamp>
  8094.       <contributor>
  8095.         <username>Jo-Jo Eumerus</username>
  8096.         <id>17449355</id>
  8097.       </contributor>
  8098.       <comment>Per category talk page</comment>
  8099.       <model>Scribunto</model>
  8100.       <format>text/plain</format>
  8101.       <text bytes="761" xml:space="preserve">-- This module contains the blacklist used by [[Module:Category handler]].
  8102. -- Pages that match Lua patterns in this list will not be categorised unless
  8103. -- categorisation is explicitly requested.
  8104.  
  8105. return {
  8106.     '^Main Page$', -- don't categorise the main page.
  8107.  
  8108.     -- Don't categorise the following pages or their subpages.
  8109.     -- "%f[/\0]" matches if the next character is "/" or the end of the string.
  8110.     '^Wikipedia:Cascade%-protected items%f[/\0]',
  8111.     '^User:UBX%f[/\0]', -- The userbox "template" space.
  8112.     '^User talk:UBX%f[/\0]',
  8113.  
  8114.     -- Don't categorise subpages of these pages, but allow
  8115.     -- categorisation of the base page.
  8116.     '^Wikipedia:Template index/.*$',
  8117.  
  8118.     -- Don't categorise archives.
  8119.     '/[aA]rchive',
  8120.     "^Wikipedia:Administrators' noticeboard/IncidentArchive%d+$",
  8121. }</text>
  8122.       <sha1>fsv1drcay6t25e91hzhqxtyp7pckbpx</sha1>
  8123.     </revision>
  8124.   </page>
  8125.   <page>
  8126.     <title>Module:Category handler/config</title>
  8127.     <ns>828</ns>
  8128.     <id>42291997</id>
  8129.     <revision>
  8130.       <id>948472494</id>
  8131.       <parentid>894414603</parentid>
  8132.       <timestamp>2020-04-01T06:12:40Z</timestamp>
  8133.       <contributor>
  8134.         <username>MusikAnimal</username>
  8135.         <id>14882394</id>
  8136.       </contributor>
  8137.       <minor/>
  8138.       <comment>1 revision imported</comment>
  8139.       <model>Scribunto</model>
  8140.       <format>text/plain</format>
  8141.       <text bytes="5755" xml:space="preserve">--------------------------------------------------------------------------------
  8142. --            [[Module:Category handler]] configuration data                  --
  8143. --       Language-specific parameter names and values can be set here.        --
  8144. --       For blacklist config, see [[Module:Category handler/blacklist]].     --
  8145. --------------------------------------------------------------------------------
  8146.  
  8147. local cfg = {} -- Don't edit this line.
  8148.  
  8149. --------------------------------------------------------------------------------
  8150. --                       Start configuration data                             --
  8151. --------------------------------------------------------------------------------
  8152.  
  8153. --------------------------------------------------------------------------------
  8154. --                              Parameter names                               --
  8155. -- These configuration items specify custom parameter names.                  --
  8156. -- To add one extra name, you can use this format:                            --
  8157. --                                                                            --
  8158. -- foo = 'parameter name',                                                    --
  8159. --                                                                            --
  8160. -- To add multiple names, you can use this format:                            --
  8161. --                                                                            --
  8162. -- foo = {'parameter name 1', 'parameter name 2', 'parameter name 3'},        --
  8163. --------------------------------------------------------------------------------
  8164.  
  8165. cfg.parameters = {
  8166.    
  8167.     -- The nocat and categories parameter suppress
  8168.     -- categorisation. They are used with Module:Yesno, and work as follows:
  8169.     --
  8170.     -- cfg.nocat:
  8171.     -- Result of yesno()                        Effect
  8172.     -- true                                     Categorisation is suppressed
  8173.     -- false                                    Categorisation is allowed, and
  8174.     --                                          the blacklist check is skipped
  8175.     -- nil                                      Categorisation is allowed
  8176.     --
  8177.     -- cfg.categories:
  8178.     -- Result of yesno()                        Effect
  8179.     -- true                                     Categorisation is allowed, and
  8180.     --                                          the blacklist check is skipped
  8181.     -- false                                    Categorisation is suppressed
  8182.     -- nil                                      Categorisation is allowed
  8183.     nocat = 'nocat',
  8184.     categories = 'categories',
  8185.    
  8186.     -- The parameter name for the legacy "category2" parameter. This skips the
  8187.     -- blacklist if set to the cfg.category2Yes value, and suppresses
  8188.     -- categorisation if present but equal to anything other than
  8189.     -- cfg.category2Yes or cfg.category2Negative.
  8190.     category2 = 'category2',
  8191.    
  8192.     -- cfg.subpage is the parameter name to specify how to behave on subpages.
  8193.     subpage = 'subpage',
  8194.    
  8195.     -- The parameter for data to return in all namespaces.
  8196.     all = 'all',
  8197.    
  8198.     -- The parameter name for data to return if no data is specified for the
  8199.     -- namespace that is detected.
  8200.     other = 'other',
  8201.    
  8202.     -- The parameter name used to specify a page other than the current page;
  8203.     -- used for testing and demonstration.
  8204.     demopage = 'page',
  8205. }
  8206.  
  8207. --------------------------------------------------------------------------------
  8208. --                              Parameter values                              --
  8209. -- These are set values that can be used with certain parameters. Only one    --
  8210. -- value can be specified, like this:                                         --
  8211. --                                                                            --
  8212. -- cfg.foo = 'value name'                                                     --                                               --
  8213. --------------------------------------------------------------------------------
  8214.  
  8215. -- The following settings are used with the cfg.category2 parameter. Setting
  8216. -- cfg.category2 to cfg.category2Yes skips the blacklist, and if cfg.category2
  8217. -- is present but equal to anything other than cfg.category2Yes or
  8218. -- cfg.category2Negative then it supresses cateogrisation.
  8219. cfg.category2Yes = 'yes'
  8220. cfg.category2Negative = '¬'
  8221.  
  8222. -- The following settings are used with the cfg.subpage parameter.
  8223. -- cfg.subpageNo is the value to specify to not categorise on subpages;
  8224. -- cfg.subpageOnly is the value to specify to only categorise on subpages.
  8225. cfg.subpageNo = 'no'
  8226. cfg.subpageOnly = 'only'
  8227.  
  8228. --------------------------------------------------------------------------------
  8229. --                           Default namespaces                               --
  8230. -- This is a table of namespaces to categorise by default. The keys are the   --
  8231. -- namespace numbers.                                                         --
  8232. --------------------------------------------------------------------------------
  8233.  
  8234. cfg.defaultNamespaces = {
  8235.     [  0] = true, -- main
  8236.     [  6] = true, -- file
  8237.     [ 12] = true, -- help
  8238.     [ 14] = true, -- category
  8239.     [100] = true, -- portal
  8240.     [108] = true, -- book
  8241. }
  8242.  
  8243. --------------------------------------------------------------------------------
  8244. --                                Wrappers                                    --
  8245. -- This is a wrapper template or a list of wrapper templates to be passed to  --
  8246. -- [[Module:Arguments]].                                                      --
  8247. --------------------------------------------------------------------------------
  8248.  
  8249. cfg.wrappers = 'Template:Category handler'
  8250.  
  8251. --------------------------------------------------------------------------------
  8252. --                           End configuration data                           --
  8253. --------------------------------------------------------------------------------
  8254.  
  8255. return cfg -- Don't edit this line.</text>
  8256.       <sha1>6ga9hbq2pdwalsvx68i53dmbr421rq5</sha1>
  8257.     </revision>
  8258.   </page>
  8259.   <page>
  8260.     <title>Module:Category handler/data</title>
  8261.     <ns>828</ns>
  8262.     <id>43233647</id>
  8263.     <revision>
  8264.       <id>948472496</id>
  8265.       <parentid>894414581</parentid>
  8266.       <timestamp>2020-04-01T06:12:41Z</timestamp>
  8267.       <contributor>
  8268.         <username>MusikAnimal</username>
  8269.         <id>14882394</id>
  8270.       </contributor>
  8271.       <minor/>
  8272.       <comment>1 revision imported</comment>
  8273.       <model>Scribunto</model>
  8274.       <format>text/plain</format>
  8275.       <text bytes="631" xml:space="preserve">-- This module assembles data to be passed to [[Module:Category handler]] using
  8276. -- mw.loadData. This includes the configuration data and whether the current
  8277. -- page matches the title blacklist.
  8278.  
  8279. local data = require('Module:Category handler/config')
  8280. local mShared = require('Module:Category handler/shared')
  8281. local blacklist = require('Module:Category handler/blacklist')
  8282. local title = mw.title.getCurrentTitle()
  8283.  
  8284. data.currentTitleMatchesBlacklist = mShared.matchesBlacklist(
  8285.     title.prefixedText,
  8286.     blacklist
  8287. )
  8288.  
  8289. data.currentTitleNamespaceParameters = mShared.getNamespaceParameters(
  8290.     title,
  8291.     mShared.getParamMappings()
  8292. )
  8293.  
  8294. return data</text>
  8295.       <sha1>k26mwixuaeijisfddb0sxkg82iux8v4</sha1>
  8296.     </revision>
  8297.   </page>
  8298.   <page>
  8299.     <title>Module:Category handler/doc</title>
  8300.     <ns>828</ns>
  8301.     <id>40436042</id>
  8302.     <revision>
  8303.       <id>1016534711</id>
  8304.       <parentid>966506718</parentid>
  8305.       <timestamp>2021-04-07T17:55:55Z</timestamp>
  8306.       <contributor>
  8307.         <username>GKFX</username>
  8308.         <id>14918984</id>
  8309.       </contributor>
  8310.       <comment>Remove {{high-use}} as now redundant to {{used in system}}</comment>
  8311.       <model>wikitext</model>
  8312.       <format>text/x-wiki</format>
  8313.       <text bytes="17231" xml:space="preserve">{{Used in system}}
  8314. {{Module rating|p}}
  8315.  
  8316. This module implements the {{tl|category handler}} template. The category handler template helps other templates to automate both categorization and [[Wikipedia:Category suppression|category suppression]]. For information about using the category handler template in other templates, please see the '''[[Template:Category handler|template documentation]]'''. Keep reading for information about using the category handler module in other Lua modules, or for information on exporting this module to other wikis.
  8317.  
  8318. == Use from other Lua modules ==
  8319.  
  8320. === When not to use this module ===
  8321.  
  8322. For cases where a module only needs to categorise in one of the namespaces main (articles), file (images) or category, then using this module is overkill. Instead, you can simply get a title object using [[mw:Extension:Scribunto/Lua reference manual#mw.title.getCurrentTitle|mw.title.getCurrentTitle]] and check the &lt;code&gt;nsText&lt;/code&gt; field. For example:
  8323. &lt;syntaxhighlight lang="lua"&gt;
  8324. local title = mw.title.getCurrentTitle()
  8325. if title.nsText == 'File' then
  8326.     -- do something
  8327. end
  8328. &lt;/syntaxhighlight&gt;
  8329. However, if your module needs to categorize in any other namespace, then we recommend you use this module, since it provides proper category suppression and makes it easy to select how to categorize in the different namespaces.
  8330.  
  8331. === Namespaces ===
  8332.  
  8333. This module detects and groups all the different [[Wikipedia:Namespace|namespaces]] used on Wikipedia into several types. These types are used as parameter names in this module.
  8334.  
  8335. :'''main''' = Main/article space, as in normal Wikipedia articles.
  8336. :'''talk''' = Any talk space, such as page names that start with "Talk:", "User talk:", "File talk:" and so on.
  8337. :'''user, wikipedia, file ... = The other namespaces except the talk pages. Namespace aliases are also accepted. See the table below for the full list.'''
  8338. :'''other''' = Any namespaces that were not specified as a parameter to the template. See examples below.
  8339.  
  8340. ;List of possible namespace parameters
  8341. (excluding &lt;code&gt;''talk''&lt;/code&gt; and &lt;code&gt;''other''&lt;/code&gt;)
  8342. {{#invoke:Namespace detect|table}}
  8343.  
  8344. === Basic usage ===
  8345.  
  8346. This module takes two or more parameters. Here's an example using a hello world program:
  8347.  
  8348. &lt;syntaxhighlight lang="lua"&gt;
  8349. p = {}
  8350. local categoryHandler = require( 'Module:Category handler' ).main
  8351.  
  8352. function p.main( frame )
  8353.     local result = 'Hello world!'
  8354.     local category = categoryHandler{
  8355.         '[[Category:Somecat]]',
  8356.         nocat = frame.args.nocat -- So "nocat=true/false" works
  8357.     }
  8358.     category = category or '' -- Check that we don't have a nil value for the category variable.
  8359.     return result .. category
  8360. end
  8361.  
  8362. return p
  8363. &lt;/syntaxhighlight&gt;
  8364.  
  8365. The above example uses the default settings for the category handler module. That means the example module will categorize on pages in the following namespaces:
  8366. :'''main''', '''file''', '''help''', '''category''', '''portal''' and '''book'''
  8367. But it will ''not'' categorize in any other namespaces, e.g.:
  8368. :'''talk''', '''user''', '''wikipedia''', '''mediawiki''', '''template''' ...
  8369.  
  8370. And it will ''not'' categorize on blacklisted pages. (See section [[#Blacklist|blacklist]] below.)
  8371.  
  8372. The reason the category handler module does not categorize in some of the namespaces is that in those namespaces most modules and templates are just demonstrated or listed, not used. Thus most modules and templates should not categorize in those namespaces.
  8373.  
  8374. Any module or template that is meant for one or more of the namespaces where this module categorizes can use the basic syntax as shown above.
  8375.  
  8376. === Advanced usage ===
  8377.  
  8378. This module takes one or more parameters named after the different page types as listed in section [[#Namespaces|namespaces]] above. By using those parameters you can specify exactly in which namespaces your template should categorize. Like this:
  8379.  
  8380. &lt;syntaxhighlight lang="lua"&gt;
  8381. p = {}
  8382. local categoryHandler = require( 'Module:Category handler' ).main
  8383.  
  8384. function p.main( frame )
  8385.     local result = 'This is a module meant for articles and talk pages.'
  8386.     local category = categoryHandler{
  8387.         main = '[[Category:Somecat1]]', -- Categorize in main (article) space
  8388.         talk = '[[Category:Somecat2]]', -- Categorize in talk space
  8389.         nocat = frame.args.nocat -- So "nocat=true/false" works
  8390.     }
  8391.     category = category or '' -- Check that we don't have a nil value for the category variable.
  8392.     return result .. category
  8393. end
  8394.  
  8395. return p
  8396. &lt;/syntaxhighlight&gt;
  8397.  
  8398. The above module will only categorize in main and talk space. But it will not categorize on /archive pages since they are blacklisted. (See section [[#Blacklist|blacklist]] below.) And if you need to demonstrate (discuss) the module on a talkpage, then you can feed "&lt;code&gt;nocat='true'&lt;/code&gt;" to prevent that template from categorizing. (See section [[#Nocat|nocat]] below.) Like this:
  8399.  
  8400. &lt;pre&gt;
  8401. == My new module ==
  8402. Hey guys, have you seen my new module?
  8403. {{#invoke:mymodule|main|nocat=true}}
  8404. Nice, isn't it?
  8405. --~~~~
  8406. &lt;/pre&gt;
  8407.  
  8408. Sometimes we want to use the same category in several namespaces, then do like this:
  8409.  
  8410. &lt;syntaxhighlight lang="lua"&gt;
  8411. p = {}
  8412. local categoryHandler = require( 'Module:Category handler' ).main
  8413.  
  8414. function p.main( frame )
  8415.     local result = 'This is a module used in several namespaces.'
  8416.     local category = categoryHandler{
  8417.         main = '[[Category:Somecat1]]',
  8418.         [ 1 ] = '[[Category:Somecat2]]', -- For help and user space
  8419.         help = 1,
  8420.         user = 1,
  8421.         talk = '', -- No categories on talk pages
  8422.         other = '[[Category:Somecat3]]', -- For all other namespaces
  8423.         nocat = frame.args.nocat -- So "nocat=true/false" works
  8424.     }
  8425.     category = category or '' -- Check that we don't have a nil value for the category variable.
  8426.     return result .. category
  8427. end
  8428.  
  8429. return p
  8430. &lt;/syntaxhighlight&gt;
  8431.  
  8432. In the above example we use a numbered parameter to feed one of the categories, and then we tell this module to use that numbered parameter for both the help and user space.
  8433.  
  8434. The category handler module understands an unlimited number of numbered parameters.
  8435.  
  8436. The '''other''' parameter defines what should be used in the remaining namespaces that have not explicitly been fed data.
  8437.  
  8438. Note the empty but defined '''talk''' parameter. That stops this module from showing what has been fed to the '''other''' parameter, when in talk space.
  8439.  
  8440. The category handler module also has a parameter called '''all'''. It works like this:
  8441.  
  8442. &lt;syntaxhighlight lang="lua"&gt;
  8443. p = {}
  8444. local categoryHandler = require( 'Module:Category handler' ).main
  8445.  
  8446. function p.main( frame )
  8447.     local result = 'This is a module used in all namespaces.'
  8448.     local category = categoryHandler{
  8449.         all = '[[Category:Somecat1]]', -- Categorize in all namespaces
  8450.         nocat = frame.args.nocat -- So "nocat=true/false" works
  8451.     }
  8452.     category = category or '' -- Check that we don't have a nil value for the category variable.
  8453.     return result .. category
  8454. end
  8455.  
  8456. return p
  8457. &lt;/syntaxhighlight&gt;
  8458.  
  8459. The above example will categorize in all namespaces, but not on blacklisted pages. If you want to demonstrate that module on a page, then use "&lt;code&gt;nocat=true&lt;/code&gt;" to prevent the template from categorizing.
  8460.  
  8461. We suggest avoiding the '''all''' parameter, since modules and templates should preferably only categorize in the namespaces they need to.
  8462.  
  8463. The all parameter can also be combined with the rest of the parameters. Like this:
  8464.  
  8465. &lt;syntaxhighlight lang="lua"&gt;
  8466. p = {}
  8467. local categoryHandler = require( 'Module:Category handler' ).main
  8468.  
  8469. function p.main( frame )
  8470.     local result = 'This is a module used in all namespaces.'
  8471.     local category = categoryHandler{
  8472.         all = '[[Category:Somecat1]]', -- Categorize in all namespaces
  8473.         main = '[[Category:Somecat2]]', -- And add this in main space
  8474.         other = '[[Category:Somecat3]]', -- And add this in all other namespaces
  8475.         nocat = frame.args.nocat -- So "nocat=true/false" works
  8476.     }
  8477.     category = category or '' -- Check that we don't have a nil value for the category variable.
  8478.     return result .. category
  8479. end
  8480.  
  8481. return p
  8482. &lt;/syntaxhighlight&gt;
  8483.  
  8484. If the above module is placed on an article, then it will add the categories "Somecat1" and "Somecat2". But on all other types of pages it will instead add "Somecat1" and "Somecat3". As the example shows, the all parameter works independently of the rest of the parameters.
  8485.  
  8486. === Subpages ===
  8487.  
  8488. The category handler module understands the '''subpage''' parameter. Like this:
  8489.  
  8490. &lt;syntaxhighlight lang="lua"&gt;
  8491. p = {}
  8492. local categoryHandler = require( 'Module:Category handler' ).main
  8493.  
  8494. function p.main( frame )
  8495.     local result = 'This is a module used in all namespaces.'
  8496.     local category = categoryHandler{
  8497.         subpage = 'no' -- Don't categorize on subpages
  8498.         wikipedia = '[[Category:Somecat]]',
  8499.         nocat = frame.args.nocat -- So "nocat=true/false" works
  8500.     }
  8501.     category = category or '' -- Check that we don't have a nil value for the category variable.
  8502.     return result .. category
  8503. end
  8504.  
  8505. return p
  8506. &lt;/syntaxhighlight&gt;
  8507.  
  8508. If "&lt;code&gt;subpage='no'&lt;/code&gt;" then this template will ''not'' categorize on subpages. For the rare occasion you ''only'' want to categorize on subpages, then use "&lt;code&gt;subpage='only'&lt;/code&gt;". If '''subpage''' is empty or undefined then this template categorizes both on basepages and on subpages.
  8509.  
  8510. === Blacklist ===
  8511.  
  8512. This module has a blacklist of the pages and page types where templates should not auto-categorize. Thus modules that use this meta-template will for instance not categorize on /archive pages and on the subpages of [[Wikipedia:Template messages]].
  8513.  
  8514. If you want a template to categorize on a blacklisted page, then feed "&lt;code&gt;&lt;nowiki&gt;nocat = false&lt;/nowiki&gt;&lt;/code&gt;" to the module when you place it on the page, thus skipping the blacklist check. Note that this module only categorizes if it has data for the namespace. For instance, if the basic syntax is used (see [[#Basic usage|basic usage]] above), then even if you set "&lt;code&gt;nocat = false&lt;/code&gt;" the template will not categorize on a talk page, since it has no data for talk pages. But it has data for help space, so on a blacklisted help page it will categorize.
  8515.  
  8516. The blacklist is located in the configuration table &lt;code&gt;cfg.blacklist&lt;/code&gt; near the top of the module code.
  8517.  
  8518. === The "nocat" parameter ===
  8519.  
  8520. This module understands the '''nocat''' parameter:
  8521.  
  8522. * If "&lt;code&gt;nocat = true&lt;/code&gt;" then this template does ''not'' categorize.
  8523. * If '''nocat''' is &lt;code&gt;nil&lt;/code&gt; then this template categorizes as usual.
  8524. * If "&lt;code&gt;nocat = false&lt;/code&gt;" this template categorizes even when on blacklisted pages. (See section [[#Blacklist|blacklist]] above.)
  8525. * The nocat parameter also accepts aliases for &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; as defined by [[Module:Yesno]], e.g. "yes", "y", "true", and 1 for &lt;code&gt;true&lt;/code&gt;, and "no", "n", "false", and 0 for &lt;code&gt;false&lt;/code&gt;.
  8526.  
  8527. Modules and templates that use {{tlf|category handler}} should forward '''nocat''', so they too understand '''nocat'''. The code "&lt;code&gt;nocat = frame.args.nocat&lt;/code&gt;" shown in the examples on this page does that.
  8528.  
  8529. === The "categories" parameter ===
  8530.  
  8531. For backwards compatibility this module also understands the '''categories''' parameter. It works the same as '''nocat'''. Like this:
  8532.  
  8533. * If "&lt;code&gt;categories = false&lt;/code&gt;" then this template does ''not'' categorize.
  8534. * If '''categories''' is empty or undefined then this template categorizes as usual.
  8535. * If "&lt;code&gt;categories = true&lt;/code&gt;" this template categorizes even when on blacklisted pages.
  8536. * The categories parameter also accepts aliases for &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; as defined by [[Module:Yesno]], e.g. "yes", "y", "true", and 1 for &lt;code&gt;true&lt;/code&gt;, and "no", "n", "false", and 0 for &lt;code&gt;false&lt;/code&gt;.
  8537.  
  8538. === The "category2" parameter ===
  8539.  
  8540. For backwards compatibility this template kind of supports the old "category =" parameter. But the parameter name "category" is already used in this module to feed category data for when in category space. So instead this template uses '''category2''' for the usage similar to '''nocat'''. Like this:
  8541.  
  8542. * If "&lt;code&gt;category2 = "&lt;/code&gt;" (empty but defined), or "&lt;code&gt;category2 = 'no'&lt;/code&gt;", or if '''category2''' is fed any other data (except as described in the next two points), then this template does ''not'' categorize.
  8543. * If '''category2''' is undefined or if "&lt;code&gt;category2 = '¬'&lt;/code&gt;", then this template categorizes as usual.
  8544. * If "&lt;code&gt;category2 = 'yes'&lt;/code&gt;" this template categorizes even when on blacklisted pages.
  8545.  
  8546. === Categories and text ===
  8547.  
  8548. Besides from categories, you can feed anything else to this module, for instance some text. Like this:
  8549.  
  8550. &lt;syntaxhighlight lang="lua"&gt;
  8551. p = {}
  8552. local categoryHandler = require( 'Module:Category handler' ).main
  8553.  
  8554. function p.main( frame )
  8555.     local result = 'This is a module used on talk pages.'
  8556.     local category = categoryHandler{
  8557.         talk = '[[Category:Somecat]]',
  8558.         other = '&lt;p class="error"&gt;This module should only be used on talk pages.&lt;/p&gt;',
  8559.         nocat = frame.args.nocat -- So "nocat=true/false" works
  8560.     }
  8561.     category = category or '' -- Check that we don't have a nil value for the category variable.
  8562.     return result .. category
  8563. end
  8564.  
  8565. return p
  8566. &lt;/syntaxhighlight&gt;
  8567.  
  8568. When the module code above is used on anything other than a talk page, it will look like this:
  8569.  
  8570. :This is a module used on talk pages.{{#invoke:category handler|main
  8571. | talk = [[Category:Somecat]]
  8572. | other = &lt;p class="error"&gt;This module should only be used on talk pages.&lt;/p&gt;
  8573. | nocat = {{{nocat|}}} &lt;!--So "nocat=true/false" works--&gt;
  8574. }}
  8575.  
  8576. That text will not show on blacklisted pages, so don't use this method to show any important information. Feeding "&lt;code&gt;nocat = 'true'&lt;/code&gt;" to the template hides the text, just as it suppresses any categories.
  8577.  
  8578. === The "page" parameter ===
  8579.  
  8580. For testing and demonstration purposes this module can take a parameter named '''page'''. Like this:
  8581.  
  8582. &lt;syntaxhighlight lang="lua"&gt;
  8583. p = {}
  8584. local categoryHandler = require( 'Module:Category handler' ).main
  8585.  
  8586. function p.main( frame )
  8587.     local category = categoryHandler{
  8588.         main = 'Category:Some cat',
  8589.         talk = 'Category:Talk cat',
  8590.         nocat = frame.args.nocat, -- So "nocat=true/false" works
  8591.         page = 'User talk:Example'
  8592.     }
  8593.     return category
  8594. end
  8595.  
  8596. return p
  8597. &lt;/syntaxhighlight&gt;
  8598.  
  8599. In the above code we on purpose left out the brackets around the category names so we see the output on the page. No matter on what kind of page the code above is used it will return this:
  8600.  
  8601. :{{#invoke:category handler|main
  8602. | main = Category:Some cat
  8603. | talk = Category:Talk cat
  8604. | nocat = {{{nocat|}}}   &lt;!--So "nocat=true/false" works--&gt;
  8605. | page = User talk:Example
  8606. }}
  8607.  
  8608. The '''page''' parameter makes this module behave exactly as if on that page. Even the blacklist works. The pagename doesn't have to be an existing page.
  8609.  
  8610. If the '''page''' parameter is empty or undefined, the name of the current page determines the result.
  8611.  
  8612. You can make it so your module also understands the '''page''' parameter. That means you can test how your template will categorize on different pages, without having to actually edit those pages. Then do like this:
  8613.  
  8614. &lt;syntaxhighlight lang="lua"&gt;
  8615. p = {}
  8616. local categoryHandler = require( 'Module:Category handler' ).main
  8617.  
  8618. function p.main( frame )
  8619.     local category = categoryHandler{
  8620.         main = 'Category:Some cat',
  8621.         talk = 'Category:Talk cat',
  8622.         nocat = frame.args.nocat, -- So "nocat=true/false" works
  8623.         page = frame.args.page -- For testing
  8624.     }
  8625.     return category
  8626. end
  8627.  
  8628. return p
  8629. &lt;/syntaxhighlight&gt;
  8630.  
  8631. === Parameters ===
  8632.  
  8633. List of all parameters:
  8634.  
  8635. * First positional parameter - for default settings
  8636. * subpage = 'no' / 'only'
  8637. * 1, 2, 3 ...
  8638. * all = '&lt;nowiki&gt;[[Category:Somecat]]&lt;/nowiki&gt;' / 'Text'
  8639. * main = 1, 2, 3 ... / '&lt;nowiki&gt;[[Category:Somecat]]&lt;/nowiki&gt;' / 'Text'
  8640. * ...
  8641. * other = 1, 2, 3 ... / '&lt;nowiki&gt;[[Category:Somecat]]&lt;/nowiki&gt;' / 'Text'
  8642. * nocat = frame.args.nocat / true / false / 'yes' / 'no' / 'y' / 'n' / 'true' / 'false' / 1 / 0
  8643. * categories = frame.args.categories / false / true / 'no' / 'yes' / 'n' / 'y' / 'false' / 'true' / 0 / 1
  8644. * category2 = frame.args.category or '¬' / 'no' / 'not defined' / '¬' / 'yes'
  8645. * page  = frame.args.page / 'User:Example'
  8646.  
  8647. Note that empty values to the "main" ... "other" parameters have special meaning (see examples above). The "all" parameter doesn't understand numbered parameters, since there should never be a need for that.
  8648.  
  8649. == Exporting to other wikis ==
  8650.  
  8651. This module can be exported to other wikis by changing the configuration values in the &lt;code&gt;cfg&lt;/code&gt; table. All the variable values are configurable, so after the configuration values have been set there should be no need to alter the main module code. Details of each configuration value are included in the module code comments. In addition, this module requires [[Module:Namespace detect]] to be available on the local wiki.
  8652.  
  8653. == See also ==
  8654.  
  8655. * {{tl|Category handler}} – for using this module with templates, rather than Lua modules.
  8656. * [[Wikipedia:Category suppression]] – The how-to guide.
  8657. * [[Wikipedia:WikiProject Category Suppression]] – The WikiProject.
  8658. * [[Wikipedia:Namespace]] – Lists all the namespaces.</text>
  8659.       <sha1>gkkejpxqs4okdrj4sjelcpufg10t90l</sha1>
  8660.     </revision>
  8661.   </page>
  8662.   <page>
  8663.     <title>Module:Category handler/shared</title>
  8664.     <ns>828</ns>
  8665.     <id>43232937</id>
  8666.     <revision>
  8667.       <id>948472498</id>
  8668.       <parentid>894414384</parentid>
  8669.       <timestamp>2020-04-01T06:12:41Z</timestamp>
  8670.       <contributor>
  8671.         <username>MusikAnimal</username>
  8672.         <id>14882394</id>
  8673.       </contributor>
  8674.       <minor/>
  8675.       <comment>1 revision imported</comment>
  8676.       <model>Scribunto</model>
  8677.       <format>text/plain</format>
  8678.       <text bytes="888" xml:space="preserve">-- This module contains shared functions used by [[Module:Category handler]]
  8679. -- and its submodules.
  8680.  
  8681. local p = {}
  8682.  
  8683. function p.matchesBlacklist(page, blacklist)
  8684.     for i, pattern in ipairs(blacklist) do
  8685.         local match = mw.ustring.match(page, pattern)
  8686.         if match then
  8687.             return true
  8688.         end
  8689.     end
  8690.     return false
  8691. end
  8692.  
  8693. function p.getParamMappings(useLoadData)
  8694.     local dataPage = 'Module:Namespace detect/data'
  8695.     if useLoadData then
  8696.         return mw.loadData(dataPage).mappings
  8697.     else
  8698.         return require(dataPage).mappings
  8699.     end
  8700. end
  8701.  
  8702. function p.getNamespaceParameters(titleObj, mappings)
  8703.     -- We don't use title.nsText for the namespace name because it adds
  8704.     -- underscores.
  8705.     local mappingsKey
  8706.     if titleObj.isTalkPage then
  8707.         mappingsKey = 'talk'
  8708.     else
  8709.         mappingsKey = mw.site.namespaces[titleObj.namespace].name
  8710.     end
  8711.     mappingsKey = mw.ustring.lower(mappingsKey)
  8712.     return mappings[mappingsKey] or {}
  8713. end
  8714.  
  8715. return p</text>
  8716.       <sha1>omlsnhudxz6juptvtxz7ns97jutbzc5</sha1>
  8717.     </revision>
  8718.   </page>
  8719.   <page>
  8720.     <title>Module:Namespace detect</title>
  8721.     <ns>828</ns>
  8722.     <id>39762919</id>
  8723.     <revision>
  8724.       <id>602886406</id>
  8725.       <parentid>601020017</parentid>
  8726.       <timestamp>2014-04-05T17:01:23Z</timestamp>
  8727.       <contributor>
  8728.         <username>Mr. Stradivarius</username>
  8729.         <id>4708675</id>
  8730.       </contributor>
  8731.       <comment>use demopage instead of page as the main "page" parameter</comment>
  8732.       <model>Scribunto</model>
  8733.       <format>text/plain</format>
  8734.       <text bytes="5992" xml:space="preserve">--[[
  8735. --------------------------------------------------------------------------------
  8736. --                                                                            --
  8737. --                            NAMESPACE DETECT                                --
  8738. --                                                                            --
  8739. -- This module implements the {{namespace detect}} template in Lua, with a    --
  8740. -- few improvements: all namespaces and all namespace aliases are supported,  --
  8741. -- and namespace names are detected automatically for the local wiki. The     --
  8742. -- module can also use the corresponding subject namespace value if it is     --
  8743. -- used on a talk page. Parameter names can be configured for different wikis --
  8744. -- by altering the values in the "cfg" table in                               --
  8745. -- Module:Namespace detect/config.                                            --
  8746. --                                                                            --
  8747. --------------------------------------------------------------------------------
  8748. --]]
  8749.  
  8750. local data = mw.loadData('Module:Namespace detect/data')
  8751. local argKeys = data.argKeys
  8752. local cfg = data.cfg
  8753. local mappings = data.mappings
  8754.  
  8755. local yesno = require('Module:Yesno')
  8756. local mArguments -- Lazily initialise Module:Arguments
  8757. local mTableTools -- Lazily initilalise Module:TableTools
  8758. local ustringLower = mw.ustring.lower
  8759.  
  8760. local p = {}
  8761.  
  8762. local function fetchValue(t1, t2)
  8763.     -- Fetches a value from the table t1 for the first key in array t2 where
  8764.     -- a non-nil value of t1 exists.
  8765.     for i, key in ipairs(t2) do
  8766.         local value = t1[key]
  8767.         if value ~= nil then
  8768.             return value
  8769.         end
  8770.     end
  8771.     return nil
  8772. end
  8773.  
  8774. local function equalsArrayValue(t, value)
  8775.     -- Returns true if value equals a value in the array t. Otherwise
  8776.     -- returns false.
  8777.     for i, arrayValue in ipairs(t) do
  8778.         if value == arrayValue then
  8779.             return true
  8780.         end
  8781.     end
  8782.     return false
  8783. end
  8784.  
  8785. function p.getPageObject(page)
  8786.     -- Get the page object, passing the function through pcall in case of
  8787.     -- errors, e.g. being over the expensive function count limit.
  8788.     if page then
  8789.         local success, pageObject = pcall(mw.title.new, page)
  8790.         if success then
  8791.             return pageObject
  8792.         else
  8793.             return nil
  8794.         end
  8795.     else
  8796.         return mw.title.getCurrentTitle()
  8797.     end
  8798. end
  8799.  
  8800. -- Provided for backward compatibility with other modules
  8801. function p.getParamMappings()
  8802.     return mappings
  8803. end
  8804.  
  8805. local function getNamespace(args)
  8806.     -- This function gets the namespace name from the page object.
  8807.     local page = fetchValue(args, argKeys.demopage)
  8808.     if page == '' then
  8809.         page = nil
  8810.     end
  8811.     local demospace = fetchValue(args, argKeys.demospace)
  8812.     if demospace == '' then
  8813.         demospace = nil
  8814.     end
  8815.     local subjectns = fetchValue(args, argKeys.subjectns)
  8816.     local ret
  8817.     if demospace then
  8818.         -- Handle "demospace = main" properly.
  8819.         if equalsArrayValue(argKeys.main, ustringLower(demospace)) then
  8820.             ret = mw.site.namespaces[0].name
  8821.         else
  8822.             ret = demospace
  8823.         end
  8824.     else
  8825.         local pageObject = p.getPageObject(page)
  8826.         if pageObject then
  8827.             if pageObject.isTalkPage then
  8828.                 -- Get the subject namespace if the option is set,
  8829.                 -- otherwise use "talk".
  8830.                 if yesno(subjectns) then
  8831.                     ret = mw.site.namespaces[pageObject.namespace].subject.name
  8832.                 else
  8833.                     ret = 'talk'
  8834.                 end
  8835.             else
  8836.                 ret = pageObject.nsText
  8837.             end
  8838.         else
  8839.             return nil -- return nil if the page object doesn't exist.
  8840.         end
  8841.     end
  8842.     ret = ret:gsub('_', ' ')
  8843.     return ustringLower(ret)
  8844. end
  8845.  
  8846. function p._main(args)
  8847.     -- Check the parameters stored in the mappings table for any matches.
  8848.     local namespace = getNamespace(args) or 'other' -- "other" avoids nil table keys
  8849.     local params = mappings[namespace] or {}
  8850.     local ret = fetchValue(args, params)
  8851.     --[[
  8852.     -- If there were no matches, return parameters for other namespaces.
  8853.     -- This happens if there was no text specified for the namespace that
  8854.     -- was detected or if the demospace parameter is not a valid
  8855.     -- namespace. Note that the parameter for the detected namespace must be
  8856.     -- completely absent for this to happen, not merely blank.
  8857.     --]]
  8858.     if ret == nil then
  8859.         ret = fetchValue(args, argKeys.other)
  8860.     end
  8861.     return ret
  8862. end
  8863.  
  8864. function p.main(frame)
  8865.     mArguments = require('Module:Arguments')
  8866.     local args = mArguments.getArgs(frame, {removeBlanks = false})
  8867.     local ret = p._main(args)
  8868.     return ret or ''
  8869. end
  8870.  
  8871. function p.table(frame)
  8872.     --[[
  8873.     -- Create a wikitable of all subject namespace parameters, for
  8874.     -- documentation purposes. The talk parameter is optional, in case it
  8875.     -- needs to be excluded in the documentation.
  8876.     --]]
  8877.    
  8878.     -- Load modules and initialise variables.
  8879.     mTableTools = require('Module:TableTools')
  8880.     local namespaces = mw.site.namespaces
  8881.     local cfg = data.cfg
  8882.     local useTalk = type(frame) == 'table'
  8883.         and type(frame.args) == 'table'
  8884.         and yesno(frame.args.talk) -- Whether to use the talk parameter.
  8885.    
  8886.     -- Get the header names.
  8887.     local function checkValue(value, default)
  8888.         if type(value) == 'string' then
  8889.             return value
  8890.         else
  8891.             return default
  8892.         end
  8893.     end
  8894.     local nsHeader = checkValue(cfg.wikitableNamespaceHeader, 'Namespace')
  8895.     local aliasesHeader = checkValue(cfg.wikitableAliasesHeader, 'Aliases')
  8896.  
  8897.     -- Put the namespaces in order.
  8898.     local mappingsOrdered = {}
  8899.     for nsname, params in pairs(mappings) do
  8900.         if useTalk or nsname ~= 'talk' then
  8901.             local nsid = namespaces[nsname].id
  8902.             -- Add 1, as the array must start with 1; nsid 0 would be lost otherwise.
  8903.             nsid = nsid + 1
  8904.             mappingsOrdered[nsid] = params
  8905.         end
  8906.     end
  8907.     mappingsOrdered = mTableTools.compressSparseArray(mappingsOrdered)
  8908.  
  8909.     -- Build the table.
  8910.     local ret = '{| class="wikitable"'
  8911.         .. '\n|-'
  8912.         .. '\n! ' .. nsHeader
  8913.         .. '\n! ' .. aliasesHeader
  8914.     for i, params in ipairs(mappingsOrdered) do
  8915.         for j, param in ipairs(params) do
  8916.             if j == 1 then
  8917.                 ret = ret .. '\n|-'
  8918.                     .. '\n| &lt;code&gt;' .. param .. '&lt;/code&gt;'
  8919.                     .. '\n| '
  8920.             elseif j == 2 then
  8921.                 ret = ret .. '&lt;code&gt;' .. param .. '&lt;/code&gt;'
  8922.             else
  8923.                 ret = ret .. ', &lt;code&gt;' .. param .. '&lt;/code&gt;'
  8924.             end
  8925.         end
  8926.     end
  8927.     ret = ret .. '\n|-'
  8928.         .. '\n|}'
  8929.     return ret
  8930. end
  8931.  
  8932. return p</text>
  8933.       <sha1>j7kygz1y56jpz4doq0m2c6x1td5d8ar</sha1>
  8934.     </revision>
  8935.   </page>
  8936.   <page>
  8937.     <title>Module:Namespace detect/config</title>
  8938.     <ns>828</ns>
  8939.     <id>42256703</id>
  8940.     <revision>
  8941.       <id>948472518</id>
  8942.       <parentid>948472515</parentid>
  8943.       <timestamp>2020-04-01T06:12:44Z</timestamp>
  8944.       <contributor>
  8945.         <username>MusikAnimal</username>
  8946.         <id>14882394</id>
  8947.       </contributor>
  8948.       <minor/>
  8949.       <comment>1 revision imported</comment>
  8950.       <model>Scribunto</model>
  8951.       <format>text/plain</format>
  8952.       <text bytes="3545" xml:space="preserve">--------------------------------------------------------------------------------
  8953. --                    Namespace detect configuration data                     --
  8954. --                                                                            --
  8955. -- This module stores configuration data for Module:Namespace detect. Here    --
  8956. -- you can localise the module to your wiki's language.                       --
  8957. --                                                                            --
  8958. -- To activate a configuration item, you need to uncomment it. This means     --
  8959. -- that you need to remove the text "-- " at the start of the line.           --
  8960. --------------------------------------------------------------------------------
  8961.  
  8962. local cfg = {} -- Don't edit this line.
  8963.  
  8964. --------------------------------------------------------------------------------
  8965. --                              Parameter names                               --
  8966. -- These configuration items specify custom parameter names. Values added     --
  8967. -- here will work in addition to the default English parameter names.         --
  8968. -- To add one extra name, you can use this format:                            --
  8969. --                                                                            --
  8970. -- cfg.foo = 'parameter name'                                                 --
  8971. --                                                                            --
  8972. -- To add multiple names, you can use this format:                            --
  8973. --                                                                            --
  8974. -- cfg.foo = {'parameter name 1', 'parameter name 2', 'parameter name 3'}     --
  8975. --------------------------------------------------------------------------------
  8976.  
  8977. ---- This parameter displays content for the main namespace:
  8978. -- cfg.main = 'main'
  8979.  
  8980. ---- This parameter displays in talk namespaces:
  8981. -- cfg.talk = 'talk'
  8982.  
  8983. ---- This parameter displays content for "other" namespaces (namespaces for which
  8984. ---- parameters have not been specified):
  8985. -- cfg.other = 'other'
  8986.  
  8987. ---- This parameter makes talk pages behave as though they are the corresponding
  8988. ---- subject namespace. Note that this parameter is used with [[Module:Yesno]].
  8989. ---- Edit that module to change the default values of "yes", "no", etc.
  8990. -- cfg.subjectns = 'subjectns'
  8991.  
  8992. ---- This parameter sets a demonstration namespace:
  8993. -- cfg.demospace = 'demospace'
  8994.  
  8995. ---- This parameter sets a specific page to compare:
  8996. cfg.demopage = 'page'
  8997.  
  8998. --------------------------------------------------------------------------------
  8999. --                           Table configuration                              --
  9000. -- These configuration items allow customisation of the "table" function,     --
  9001. -- used to generate a table of possible parameters in the module              --
  9002. -- documentation.                                                             --
  9003. --------------------------------------------------------------------------------
  9004.  
  9005. ---- The header for the namespace column in the wikitable containing the list of
  9006. ---- possible subject-space parameters.
  9007. -- cfg.wikitableNamespaceHeader = 'Namespace'
  9008.  
  9009. ---- The header for the wikitable containing the list of possible subject-space
  9010. ---- parameters.
  9011. -- cfg.wikitableAliasesHeader = 'Aliases'
  9012.  
  9013. --------------------------------------------------------------------------------
  9014. --                        End of configuration data                           --
  9015. --------------------------------------------------------------------------------
  9016.  
  9017. return cfg -- Don't edit this line.</text>
  9018.       <sha1>1o6ozz56i8q0xgyl6xa41n2v7kelhli</sha1>
  9019.     </revision>
  9020.   </page>
  9021.   <page>
  9022.     <title>Module:Namespace detect/data</title>
  9023.     <ns>828</ns>
  9024.     <id>42257476</id>
  9025.     <revision>
  9026.       <id>948472520</id>
  9027.       <parentid>948472519</parentid>
  9028.       <timestamp>2020-04-01T06:12:45Z</timestamp>
  9029.       <contributor>
  9030.         <username>MusikAnimal</username>
  9031.         <id>14882394</id>
  9032.       </contributor>
  9033.       <minor/>
  9034.       <comment>1 revision imported</comment>
  9035.       <model>Scribunto</model>
  9036.       <format>text/plain</format>
  9037.       <text bytes="2569" xml:space="preserve">--------------------------------------------------------------------------------
  9038. --                          Namespace detect data                             --
  9039. -- This module holds data for [[Module:Namespace detect]] to be loaded per    --
  9040. -- page, rather than per #invoke, for performance reasons.                    --
  9041. --------------------------------------------------------------------------------
  9042.  
  9043. local cfg = require('Module:Namespace detect/config')
  9044.  
  9045. local function addKey(t, key, defaultKey)
  9046.     if key ~= defaultKey then
  9047.         t[#t + 1] = key
  9048.     end
  9049. end
  9050.  
  9051. -- Get a table of parameters to query for each default parameter name.
  9052. -- This allows wikis to customise parameter names in the cfg table while
  9053. -- ensuring that default parameter names will always work. The cfg table
  9054. -- values can be added as a string, or as an array of strings.
  9055.  
  9056. local defaultKeys = {
  9057.     'main',
  9058.     'talk',
  9059.     'other',
  9060.     'subjectns',
  9061.     'demospace',
  9062.     'demopage'
  9063. }
  9064.  
  9065. local argKeys = {}
  9066. for i, defaultKey in ipairs(defaultKeys) do
  9067.     argKeys[defaultKey] = {defaultKey}
  9068. end
  9069.  
  9070. for defaultKey, t in pairs(argKeys) do
  9071.     local cfgValue = cfg[defaultKey]
  9072.     local cfgValueType = type(cfgValue)
  9073.     if cfgValueType == 'string' then
  9074.         addKey(t, cfgValue, defaultKey)
  9075.     elseif cfgValueType == 'table' then
  9076.         for i, key in ipairs(cfgValue) do
  9077.             addKey(t, key, defaultKey)
  9078.         end
  9079.     end
  9080.     cfg[defaultKey] = nil -- Free the cfg value as we don't need it any more.
  9081. end
  9082.  
  9083. local function getParamMappings()
  9084.     --[[
  9085.     -- Returns a table of how parameter names map to namespace names. The keys
  9086.     -- are the actual namespace names, in lower case, and the values are the
  9087.     -- possible parameter names for that namespace, also in lower case. The
  9088.     -- table entries are structured like this:
  9089.     -- {
  9090.     --   [''] = {'main'},
  9091.     --   ['wikipedia'] = {'wikipedia', 'project', 'wp'},
  9092.     --   ...
  9093.     -- }
  9094.     --]]
  9095.     local mappings = {}
  9096.     local mainNsName = mw.site.subjectNamespaces[0].name
  9097.     mainNsName = mw.ustring.lower(mainNsName)
  9098.     mappings[mainNsName] = mw.clone(argKeys.main)
  9099.     mappings['talk'] = mw.clone(argKeys.talk)
  9100.     for nsid, ns in pairs(mw.site.subjectNamespaces) do
  9101.         if nsid ~= 0 then -- Exclude main namespace.
  9102.             local nsname = mw.ustring.lower(ns.name)
  9103.             local canonicalName = mw.ustring.lower(ns.canonicalName)
  9104.             mappings[nsname] = {nsname}
  9105.             if canonicalName ~= nsname then
  9106.                 table.insert(mappings[nsname], canonicalName)
  9107.             end
  9108.             for _, alias in ipairs(ns.aliases) do
  9109.                 table.insert(mappings[nsname], mw.ustring.lower(alias))
  9110.             end
  9111.         end
  9112.     end
  9113.     return mappings
  9114. end
  9115.  
  9116. return {
  9117.     argKeys = argKeys,
  9118.     cfg = cfg,
  9119.     mappings = getParamMappings()
  9120. }</text>
  9121.       <sha1>ojp6d3pc8mql5nufaqdg576c9so3479</sha1>
  9122.     </revision>
  9123.   </page>
  9124.   <page>
  9125.     <title>Module:Template link general</title>
  9126.     <ns>828</ns>
  9127.     <id>63673341</id>
  9128.     <revision>
  9129.       <id>1068594348</id>
  9130.       <parentid>1068517629</parentid>
  9131.       <timestamp>2022-01-29T09:02:36Z</timestamp>
  9132.       <contributor>
  9133.         <username>Primefac</username>
  9134.         <id>11508456</id>
  9135.       </contributor>
  9136.       <comment>bit flip per previous</comment>
  9137.       <model>Scribunto</model>
  9138.       <format>text/plain</format>
  9139.       <text bytes="3940" xml:space="preserve">-- This implements Template:Tlg
  9140. local getArgs = require('Module:Arguments').getArgs
  9141. local p = {}
  9142.  
  9143. -- Is a string non-empty?
  9144. local function _ne(s)
  9145.     return s ~= nil and s ~= ""
  9146. end
  9147.  
  9148. local nw = mw.text.nowiki
  9149.  
  9150. local function addTemplate(s)
  9151.     local i, _ = s:find(':', 1, true)
  9152.     if i == nil then
  9153.         return 'Template:' .. s
  9154.     end
  9155.     local ns = s:sub(1, i - 1)
  9156.     if ns == '' or mw.site.namespaces[ns] then
  9157.         return s
  9158.     else
  9159.         return 'Template:' .. s
  9160.     end
  9161. end
  9162.  
  9163. local function trimTemplate(s)
  9164.     local needle = 'template:'
  9165.     if s:sub(1, needle:len()):lower() == needle then
  9166.         return s:sub(needle:len() + 1) 
  9167.     else
  9168.         return s
  9169.     end
  9170. end
  9171.  
  9172. local function linkTitle(args)
  9173.     if _ne(args.nolink) then
  9174.         return args['1']
  9175.     end
  9176.    
  9177.     local titleObj
  9178.     local titlePart = '[['
  9179.     if args['1'] then
  9180.         -- This handles :Page and other NS
  9181.         titleObj = mw.title.new(args['1'], 'Template')
  9182.     else
  9183.         titleObj = mw.title.getCurrentTitle()
  9184.     end
  9185.    
  9186.     titlePart = titlePart .. (titleObj ~= nil and titleObj.fullText or
  9187.                 addTemplate(args['1']))
  9188.    
  9189.     local textPart = args.alttext
  9190.     if not _ne(textPart) then
  9191.         if titleObj ~= nil then
  9192.             textPart = titleObj:inNamespace("Template") and args['1'] or titleObj.fullText
  9193.         else
  9194.             -- redlink
  9195.             textPart = args['1']
  9196.         end
  9197.     end
  9198.    
  9199.     if _ne(args.subst) then
  9200.         -- HACK: the ns thing above is probably broken
  9201.         textPart = 'subst:' .. textPart
  9202.     end
  9203.    
  9204.     if _ne(args.brace) then
  9205.         textPart = nw('{{') .. textPart .. nw('}}')
  9206.     elseif _ne(args.braceinside) then
  9207.         textPart = nw('{') .. textPart .. nw('}')
  9208.     end
  9209.    
  9210.     titlePart = titlePart .. '|' .. textPart .. ']]'
  9211.     if _ne(args.braceinside) then
  9212.         titlePart = nw('{') .. titlePart .. nw('}')
  9213.     end
  9214.     return titlePart
  9215. end
  9216.  
  9217. function p.main(frame)
  9218.     local args = getArgs(frame, {
  9219.         trim = true,
  9220.         removeBlanks = false
  9221.     })
  9222.     return p._main(args)
  9223. end
  9224.  
  9225. function p._main(args)
  9226.     local bold = _ne(args.bold) or _ne(args.boldlink) or _ne(args.boldname)
  9227.     local italic = _ne(args.italic) or _ne(args.italics)
  9228.     local dontBrace = _ne(args.brace) or _ne(args.braceinside)
  9229.     local code = _ne(args.code) or _ne(args.tt)
  9230.     local show_result = _ne(args._show_result)
  9231.    
  9232.     -- Build the link part
  9233.     local titlePart = linkTitle(args)
  9234.     if bold then titlePart = "'''" .. titlePart .. "'''" end
  9235.     if _ne(args.nowrapname) then titlePart = '&lt;span class="nowrap"&gt;' .. titlePart .. '&lt;/span&gt;' end
  9236.    
  9237.     -- Build the arguments
  9238.     local textPart = ""
  9239.     local textPartBuffer = ""
  9240.     local codeArguments = {}
  9241.     local i = 2
  9242.     while args[i] do
  9243.         local val = args[i]
  9244.         textPartBuffer = textPartBuffer .. '&amp;#124;'
  9245.         if val ~= "" then
  9246.             if _ne(args.nowiki) then
  9247.                 -- Unstrip nowiki tags first because calling nw on something that already contains nowiki tags will
  9248.                 -- mangle the nowiki strip marker and result in literal UNIQ...QINU showing up
  9249.                 val = nw(mw.text.unstripNoWiki(val))
  9250.             end
  9251.             local k, v = string.match(val, "(.*)=(.*)")
  9252.             if not k then
  9253.                 codeArguments[i - 1] = val
  9254.             else
  9255.                 codeArguments[k] = v
  9256.             end
  9257.             if italic then val = '&lt;span style="font-style:italic;"&gt;' .. val .. '&lt;/span&gt;' end
  9258.             textPart = textPart .. textPartBuffer .. val
  9259.             textPartBuffer = ""
  9260.         end
  9261.         i = i+1
  9262.     end
  9263.  
  9264.     -- final wrap
  9265.     local ret = titlePart .. textPart
  9266.     if not dontBrace then ret = nw('{{') .. ret .. nw('}}') end
  9267.     if _ne(args.a) then ret = nw('*') .. '&amp;nbsp;' .. ret end
  9268.     if _ne(args.kbd) then ret = '&lt;kbd&gt;' .. ret .. '&lt;/kbd&gt;' end
  9269.     if code then
  9270.         ret = '&lt;code&gt;' .. ret .. '&lt;/code&gt;'
  9271.     elseif _ne(args.plaincode) then
  9272.         ret = '&lt;code style="border:none;background:transparent;"&gt;' .. ret .. '&lt;/code&gt;'
  9273.     end
  9274.     if _ne(args.nowrap) then ret = '&lt;span class="nowrap"&gt;' .. ret .. '&lt;/span&gt;' end
  9275.    
  9276.     --[[ Wrap as html??
  9277.     local span = mw.html.create('span')
  9278.     span:wikitext(ret)
  9279.     --]]
  9280.     if _ne(args.debug) then ret = ret .. '\n&lt;pre&gt;' .. mw.text.encode(mw.dumpObject(args)) .. '&lt;/pre&gt;' end
  9281.    
  9282.     if show_result then
  9283.         local result = mw.getCurrentFrame():expandTemplate{title = "Template:" .. args[1], args = codeArguments}
  9284.         ret = ret .. " → " .. result
  9285.     end
  9286.     return ret
  9287. end
  9288.  
  9289. return p</text>
  9290.       <sha1>04bt81vpnxlycj9xx6ol27d6jgthsoy</sha1>
  9291.     </revision>
  9292.   </page>
  9293.   <page>
  9294.     <title>Module:Transclusion count/data/C</title>
  9295.     <ns>828</ns>
  9296.     <id>61481071</id>
  9297.     <revision>
  9298.       <id>1071544600</id>
  9299.       <parentid>1070187690</parentid>
  9300.       <timestamp>2022-02-13T05:12:55Z</timestamp>
  9301.       <contributor>
  9302.         <username>Ahechtbot</username>
  9303.         <id>26109785</id>
  9304.       </contributor>
  9305.       <minor/>
  9306.       <comment>[[Wikipedia:BOT|Bot]]: Updated page.</comment>
  9307.       <model>Scribunto</model>
  9308.       <format>text/plain</format>
  9309.       <text bytes="34820" xml:space="preserve">return {
  9310. ["C"] = 580000,
  9311. ["C-Class"] = 71000,
  9312. ["C-SPAN"] = 12000,
  9313. ["C-cmn"] = 2500,
  9314. ["C-pl"] = 52000,
  9315. ["CAN"] = 20000,
  9316. ["CANelec"] = 12000,
  9317. ["CANelec/gain"] = 2400,
  9318. ["CANelec/hold"] = 4300,
  9319. ["CANelec/source"] = 6300,
  9320. ["CANelec/top"] = 5500,
  9321. ["CANelec/total"] = 5500,
  9322. ["CAS"] = 3800,
  9323. ["CBB_Standings_End"] = 13000,
  9324. ["CBB_Standings_Entry"] = 13000,
  9325. ["CBB_Standings_Start"] = 13000,
  9326. ["CBB_Yearly_Record_End"] = 2800,
  9327. ["CBB_Yearly_Record_Entry"] = 2800,
  9328. ["CBB_Yearly_Record_Start"] = 2700,
  9329. ["CBB_Yearly_Record_Subhead"] = 3300,
  9330. ["CBB_Yearly_Record_Subtotal"] = 2600,
  9331. ["CBB_roster/Footer"] = 6600,
  9332. ["CBB_roster/Header"] = 6600,
  9333. ["CBB_roster/Player"] = 6600,
  9334. ["CBB_schedule_end"] = 9200,
  9335. ["CBB_schedule_entry"] = 9300,
  9336. ["CBB_schedule_start"] = 9300,
  9337. ["CBB_yearly_record_end"] = 3700,
  9338. ["CBB_yearly_record_end/legend"] = 3300,
  9339. ["CBB_yearly_record_entry"] = 3700,
  9340. ["CBB_yearly_record_start"] = 3600,
  9341. ["CBB_yearly_record_subhead"] = 3400,
  9342. ["CBB_yearly_record_subtotal"] = 3500,
  9343. ["CBSB_Standings_End"] = 3800,
  9344. ["CBSB_Standings_Entry"] = 3800,
  9345. ["CBSB_Standings_Start"] = 3800,
  9346. ["CBSB_link"] = 3200,
  9347. ["CC0"] = 4700,
  9348. ["CENTURY"] = 16000,
  9349. ["CFB_Standings_End"] = 31000,
  9350. ["CFB_Standings_Entry"] = 31000,
  9351. ["CFB_Standings_Start"] = 31000,
  9352. ["CFB_Yearly_Record_End"] = 6300,
  9353. ["CFB_Yearly_Record_End/legend"] = 2200,
  9354. ["CFB_Yearly_Record_Entry"] = 6300,
  9355. ["CFB_Yearly_Record_Start"] = 6300,
  9356. ["CFB_Yearly_Record_Subhead"] = 6300,
  9357. ["CFB_Yearly_Record_Subtotal"] = 6200,
  9358. ["CFB_schedule"] = 24000,
  9359. ["CFB_schedule_entry"] = 17000,
  9360. ["CFL_Year"] = 5300,
  9361. ["CGF_year"] = 2300,
  9362. ["CHE"] = 10000,
  9363. ["CHI"] = 2700,
  9364. ["CHL"] = 3500,
  9365. ["CHN"] = 11000,
  9366. ["CN"] = 2200,
  9367. ["COI"] = 14000,
  9368. ["COIUL"] = 123000,
  9369. ["COI_editnotice"] = 6100,
  9370. ["COL"] = 4600,
  9371. ["COLON"] = 13000,
  9372. ["CRI"] = 2100,
  9373. ["CRO"] = 4000,
  9374. ["CSK"] = 2800,
  9375. ["CSS_image_crop"] = 3600,
  9376. ["CUB"] = 3400,
  9377. ["CURRENTDATE"] = 3600,
  9378. ["CURRENTISOYEAR"] = 2000,
  9379. ["CURRENTMINUTE"] = 2500,
  9380. ["CZE"] = 13000,
  9381. ["Calendar"] = 2400,
  9382. ["California/color"] = 11000,
  9383. ["Call_sign_disambiguation"] = 2900,
  9384. ["Campaignbox"] = 21000,
  9385. ["CanadaByProvinceCatNav"] = 9600,
  9386. ["CanadaProvinceThe"] = 3900,
  9387. ["Canadian_English"] = 4800,
  9388. ["Canadian_Parliament_links"] = 4900,
  9389. ["Canadian_election_result"] = 12000,
  9390. ["Canadian_election_result/gain"] = 2400,
  9391. ["Canadian_election_result/hold"] = 4400,
  9392. ["Canadian_election_result/source"] = 7300,
  9393. ["Canadian_election_result/top"] = 11000,
  9394. ["Canadian_election_result/top/ElectionYearTest"] = 5100,
  9395. ["Canadian_election_result/total"] = 9400,
  9396. ["Canadian_party_colour"] = 7500,
  9397. ["Canadian_party_colour/colour"] = 15000,
  9398. ["Canadian_party_colour/colour/default"] = 15000,
  9399. ["Canadian_party_colour/name"] = 13000,
  9400. ["Canadian_party_colour/name/default"] = 5800,
  9401. ["Canned_search"] = 3500,
  9402. ["Cascite"] = 14000,
  9403. ["Caselaw_source"] = 3800,
  9404. ["Cast_listing"] = 9600,
  9405. ["Cat"] = 275000,
  9406. ["CatAutoTOC"] = 615000,
  9407. ["CatAutoTOC/core"] = 614000,
  9408. ["CatRel"] = 3800,
  9409. ["CatTrack"] = 3000,
  9410. ["Cat_class"] = 6700,
  9411. ["Cat_in_use"] = 50000,
  9412. ["Cat_main"] = 171000,
  9413. ["Cat_more"] = 108000,
  9414. ["Cat_more_if_exists"] = 44000,
  9415. ["Cat_see_also"] = 3300,
  9416. ["Catalog_lookup_link"] = 483000,
  9417. ["Category"] = 182000,
  9418. ["Category-Class"] = 14000,
  9419. ["Category-inline"] = 7600,
  9420. ["Category_TOC"] = 70000,
  9421. ["Category_TOC/tracking"] = 70000,
  9422. ["Category_U.S._State_elections_by_year"] = 7200,
  9423. ["Category_U.S._State_elections_by_year/core"] = 7200,
  9424. ["Category_class"] = 36000,
  9425. ["Category_class/column"] = 36000,
  9426. ["Category_class/second_row_column"] = 36000,
  9427. ["Category_described_in_year"] = 5600,
  9428. ["Category_diffuse"] = 7500,
  9429. ["Category_disambiguation"] = 2300,
  9430. ["Category_disambiguation/category_link"] = 2300,
  9431. ["Category_explanation"] = 73000,
  9432. ["Category_handler"] = 3150000,
  9433. ["Category_ifexist"] = 4700,
  9434. ["Category_importance"] = 11000,
  9435. ["Category_importance/column"] = 11000,
  9436. ["Category_importance/second_row_column"] = 11000,
  9437. ["Category_link"] = 289000,
  9438. ["Category_link_with_count"] = 5700,
  9439. ["Category_ordered_by_date"] = 9300,
  9440. ["Category_other"] = 836000,
  9441. ["Category_redirect"] = 102000,
  9442. ["Category_see_also"] = 33000,
  9443. ["Category_see_also/Category_pair_check"] = 33000,
  9444. ["Category_see_also_if_exists"] = 71000,
  9445. ["Category_see_also_if_exists_2"] = 83000,
  9446. ["Category_title"] = 2400,
  9447. ["Catexp"] = 7100,
  9448. ["CathEncy"] = 2300,
  9449. ["Catholic"] = 4200,
  9450. ["Catholic_Encyclopedia"] = 5000,
  9451. ["Catmain"] = 24000,
  9452. ["Catmore"] = 9300,
  9453. ["Caution"] = 2100,
  9454. ["Cbb_link"] = 7100,
  9455. ["Cbignore"] = 91000,
  9456. ["Cc-by-2.5"] = 4500,
  9457. ["Cc-by-3.0"] = 10000,
  9458. ["Cc-by-sa-2.5"] = 3200,
  9459. ["Cc-by-sa-2.5,2.0,1.0"] = 3300,
  9460. ["Cc-by-sa-3.0"] = 31000,
  9461. ["Cc-by-sa-3.0,2.5,2.0,1.0"] = 2900,
  9462. ["Cc-by-sa-3.0-migrated"] = 30000,
  9463. ["Cc-by-sa-4.0"] = 12000,
  9464. ["Cc-zero"] = 4600,
  9465. ["CensusAU"] = 11000,
  9466. ["Census_2016_AUS"] = 8700,
  9467. ["Cent"] = 5200,
  9468. ["Center"] = 224000,
  9469. ["Centralized_discussion"] = 5500,
  9470. ["Centralized_discussion/core"] = 5500,
  9471. ["Centralized_discussion/styles.css"] = 5500,
  9472. ["Centre"] = 2500,
  9473. ["Century"] = 2000,
  9474. ["Century_name_from_decade_or_year"] = 71000,
  9475. ["Century_name_from_title_decade"] = 7200,
  9476. ["Century_name_from_title_year"] = 6700,
  9477. ["Certification_Cite/Title"] = 24000,
  9478. ["Certification_Cite/URL"] = 27000,
  9479. ["Certification_Cite/archivedate"] = 4900,
  9480. ["Certification_Cite/archiveurl"] = 4900,
  9481. ["Certification_Cite_Ref"] = 24000,
  9482. ["Certification_Table_Bottom"] = 24000,
  9483. ["Certification_Table_Entry"] = 25000,
  9484. ["Certification_Table_Entry/Foot"] = 23000,
  9485. ["Certification_Table_Entry/Foot/helper"] = 23000,
  9486. ["Certification_Table_Entry/Region"] = 24000,
  9487. ["Certification_Table_Entry/Sales"] = 23000,
  9488. ["Certification_Table_Entry/Sales/DanishPeriod"] = 2600,
  9489. ["Certification_Table_Entry/Sales/DanishPeriodHelper1"] = 2600,
  9490. ["Certification_Table_Entry/Sales/DanishPeriodHelper2"] = 2600,
  9491. ["Certification_Table_Entry/Sales/GermanPeriod"] = 3100,
  9492. ["Certification_Table_Entry/Sales/ItalianHelper"] = 2800,
  9493. ["Certification_Table_Top"] = 25000,
  9494. ["Cfb_link"] = 23000,
  9495. ["Cfd_result"] = 2400,
  9496. ["Cfdend"] = 4000,
  9497. ["Chart"] = 4500,
  9498. ["Chart/end"] = 4600,
  9499. ["Chart/start"] = 4600,
  9500. ["Chart_bottom"] = 2800,
  9501. ["Chart_top"] = 2800,
  9502. ["Check_completeness_of_transclusions"] = 5900,
  9503. ["Check_talk"] = 25000,
  9504. ["Check_talk_wp"] = 1360000,
  9505. ["Check_winner_by_scores"] = 12000,
  9506. ["CheckedSockpuppet"] = 7100,
  9507. ["Checked_sockpuppet"] = 17000,
  9508. ["Checkedsockpuppet"] = 5300,
  9509. ["Checkip"] = 12000,
  9510. ["Checkuser"] = 68000,
  9511. ["Checkuserblock-account"] = 8300,
  9512. ["Chem"] = 4700,
  9513. ["Chem/atom"] = 4500,
  9514. ["Chem/link"] = 4700,
  9515. ["Chem_molar_mass"] = 16000,
  9516. ["Chem_molar_mass/format"] = 16000,
  9517. ["Chembox"] = 13000,
  9518. ["Chembox/styles.css"] = 13000,
  9519. ["Chembox_3DMet"] = 13000,
  9520. ["Chembox_3DMet/format"] = 13000,
  9521. ["Chembox_AllOtherNames"] = 12000,
  9522. ["Chembox_AllOtherNames/format"] = 12000,
  9523. ["Chembox_Appearance"] = 5500,
  9524. ["Chembox_BoilingPt"] = 3600,
  9525. ["Chembox_CASNo"] = 13000,
  9526. ["Chembox_CASNo/format"] = 13000,
  9527. ["Chembox_CalcTemperatures"] = 6300,
  9528. ["Chembox_ChEBI"] = 13000,
  9529. ["Chembox_ChEBI/format"] = 13000,
  9530. ["Chembox_ChEMBL"] = 13000,
  9531. ["Chembox_ChEMBL/format"] = 13000,
  9532. ["Chembox_ChemSpiderID"] = 13000,
  9533. ["Chembox_ChemSpiderID/format"] = 13000,
  9534. ["Chembox_CompTox"] = 13000,
  9535. ["Chembox_CompTox/format"] = 13000,
  9536. ["Chembox_Datapage_check"] = 13000,
  9537. ["Chembox_Density"] = 4600,
  9538. ["Chembox_DrugBank"] = 13000,
  9539. ["Chembox_DrugBank/format"] = 13000,
  9540. ["Chembox_ECHA"] = 7200,
  9541. ["Chembox_ECNumber"] = 13000,
  9542. ["Chembox_ECNumber/format"] = 13000,
  9543. ["Chembox_Elements"] = 13000,
  9544. ["Chembox_Elements/molecular_formula"] = 16000,
  9545. ["Chembox_Footer"] = 13000,
  9546. ["Chembox_Footer/tracking"] = 13000,
  9547. ["Chembox_GHS_(set)"] = 3200,
  9548. ["Chembox_Hazards"] = 11000,
  9549. ["Chembox_IUPHAR_ligand"] = 13000,
  9550. ["Chembox_IUPHAR_ligand/format"] = 13000,
  9551. ["Chembox_Identifiers"] = 13000,
  9552. ["Chembox_InChI"] = 12000,
  9553. ["Chembox_InChI/format"] = 12000,
  9554. ["Chembox_Indexlist"] = 13000,
  9555. ["Chembox_Jmol"] = 13000,
  9556. ["Chembox_Jmol/format"] = 13000,
  9557. ["Chembox_KEGG"] = 13000,
  9558. ["Chembox_KEGG/format"] = 13000,
  9559. ["Chembox_MeltingPt"] = 5400,
  9560. ["Chembox_Properties"] = 13000,
  9561. ["Chembox_PubChem"] = 13000,
  9562. ["Chembox_PubChem/format"] = 13000,
  9563. ["Chembox_RTECS"] = 13000,
  9564. ["Chembox_RTECS/format"] = 13000,
  9565. ["Chembox_Related"] = 2900,
  9566. ["Chembox_SMILES"] = 12000,
  9567. ["Chembox_SMILES/format"] = 12000,
  9568. ["Chembox_SolubilityInWater"] = 3600,
  9569. ["Chembox_UNII"] = 13000,
  9570. ["Chembox_UNII/format"] = 13000,
  9571. ["Chembox_headerbar"] = 13000,
  9572. ["Chembox_image"] = 12000,
  9573. ["Chembox_image_cell"] = 11000,
  9574. ["Chembox_image_sbs"] = 12000,
  9575. ["Chembox_parametercheck"] = 12000,
  9576. ["Chembox_setDatarow"] = 4200,
  9577. ["Chembox_setHeader"] = 4200,
  9578. ["Chembox_templatePar/formatPreviewMessage"] = 13000,
  9579. ["Chembox_verification"] = 7200,
  9580. ["Chemicals"] = 7500,
  9581. ["Chemistry"] = 2900,
  9582. ["Chemspidercite"] = 11000,
  9583. ["Chessgames_player"] = 3400,
  9584. ["Chinese"] = 7600,
  9585. ["Chr"] = 8900,
  9586. ["ChristianityWikiProject"] = 6100,
  9587. ["Circa"] = 46000,
  9588. ["Circular_reference"] = 4600,
  9589. ["Citation"] = 343000,
  9590. ["Citation/make_link"] = 5200,
  9591. ["Citation/styles.css"] = 44000,
  9592. ["Citation_needed"] = 489000,
  9593. ["Citation_needed_span"] = 3100,
  9594. ["Citation_style"] = 4300,
  9595. ["Cite_AV_media"] = 37000,
  9596. ["Cite_AV_media_notes"] = 23000,
  9597. ["Cite_Appletons'"] = 2400,
  9598. ["Cite_Australian_Dictionary_of_Biography"] = 2900,
  9599. ["Cite_Catholic_Encyclopedia"] = 8000,
  9600. ["Cite_Colledge2006"] = 3100,
  9601. ["Cite_DCB"] = 2800,
  9602. ["Cite_DNB"] = 17000,
  9603. ["Cite_EB1911"] = 23000,
  9604. ["Cite_GNIS"] = 2500,
  9605. ["Cite_Gaia_DR2"] = 2400,
  9606. ["Cite_Jewish_Encyclopedia"] = 2700,
  9607. ["Cite_NIE"] = 3600,
  9608. ["Cite_NSW_Parliament"] = 3300,
  9609. ["Cite_NSW_SHR"] = 2600,
  9610. ["Cite_ODNB"] = 14000,
  9611. ["Cite_Q"] = 52000,
  9612. ["Cite_QHR"] = 3000,
  9613. ["Cite_QPN"] = 3900,
  9614. ["Cite_Rowlett"] = 2500,
  9615. ["Cite_Russian_law"] = 7600,
  9616. ["Cite_Sports-Reference"] = 53000,
  9617. ["Cite_WoRMS"] = 4500,
  9618. ["Cite_arXiv"] = 4100,
  9619. ["Cite_bcgnis"] = 2900,
  9620. ["Cite_book"] = 1420000,
  9621. ["Cite_certification"] = 27000,
  9622. ["Cite_cgndb"] = 2700,
  9623. ["Cite_conference"] = 13000,
  9624. ["Cite_court"] = 4800,
  9625. ["Cite_dictionary"] = 4600,
  9626. ["Cite_document"] = 9000,
  9627. ["Cite_encyclopedia"] = 184000,
  9628. ["Cite_episode"] = 16000,
  9629. ["Cite_gnis"] = 34000,
  9630. ["Cite_interview"] = 6300,
  9631. ["Cite_iucn"] = 53000,
  9632. ["Cite_journal"] = 848000,
  9633. ["Cite_magazine"] = 167000,
  9634. ["Cite_map"] = 31000,
  9635. ["Cite_news"] = 1320000,
  9636. ["Cite_newspaper"] = 3600,
  9637. ["Cite_newspaper_The_Times"] = 6000,
  9638. ["Cite_patent"] = 4600,
  9639. ["Cite_patent/authors"] = 3400,
  9640. ["Cite_patent/core"] = 5000,
  9641. ["Cite_peakbagger"] = 3900,
  9642. ["Cite_podcast"] = 2800,
  9643. ["Cite_press_release"] = 53000,
  9644. ["Cite_report"] = 27000,
  9645. ["Cite_rowlett"] = 2500,
  9646. ["Cite_simbad"] = 4100,
  9647. ["Cite_sports-reference"] = 58000,
  9648. ["Cite_thesis"] = 22000,
  9649. ["Cite_tweet"] = 26000,
  9650. ["Cite_video"] = 12000,
  9651. ["Cite_video_game"] = 2900,
  9652. ["Cite_web"] = 4170000,
  9653. ["Cite_wikisource"] = 4900,
  9654. ["Cite_wikisource/make_link"] = 54000,
  9655. ["Civil_navigation"] = 2700,
  9656. ["Cl"] = 107000,
  9657. ["Clade"] = 6000,
  9658. ["Clade/styles.css"] = 6000,
  9659. ["Clarify"] = 38000,
  9660. ["Class"] = 9410000,
  9661. ["Class/colour"] = 9470000,
  9662. ["Class/icon"] = 9420000,
  9663. ["Class_mask"] = 9650000,
  9664. ["Class_mask/b"] = 322000,
  9665. ["Classical"] = 7100,
  9666. ["Classicon"] = 4600,
  9667. ["Clc"] = 4800,
  9668. ["Cleanup"] = 12000,
  9669. ["Cleanup_bare_URLs"] = 4700,
  9670. ["Cleanup_reorganize"] = 2600,
  9671. ["Cleanup_rewrite"] = 5400,
  9672. ["Clear"] = 3460000,
  9673. ["Clear-left"] = 19000,
  9674. ["Clear_left"] = 32000,
  9675. ["Clear_right"] = 2700,
  9676. ["Clerk-Note"] = 9000,
  9677. ["Clerknote"] = 6700,
  9678. ["Clickable_button"] = 12000,
  9679. ["Clickable_button_2"] = 837000,
  9680. ["Clr"] = 3600,
  9681. ["Cmbox"] = 389000,
  9682. ["Cn"] = 76000,
  9683. ["Cnote2_Begin"] = 2000,
  9684. ["Cnote2_End"] = 2000,
  9685. ["Coat_of_arms"] = 7800,
  9686. ["Cob"] = 11000,
  9687. ["Code"] = 44000,
  9688. ["Col-1-of-2"] = 2500,
  9689. ["Col-2"] = 162000,
  9690. ["Col-2-of-2"] = 2400,
  9691. ["Col-3"] = 9900,
  9692. ["Col-4"] = 3500,
  9693. ["Col-begin"] = 206000,
  9694. ["Col-break"] = 204000,
  9695. ["Col-end"] = 205000,
  9696. ["Col-float"] = 2300,
  9697. ["Col-float-break"] = 2200,
  9698. ["Col-float-end"] = 2300,
  9699. ["Col-float/styles.css"] = 2300,
  9700. ["Col-start"] = 21000,
  9701. ["Colbegin"] = 39000,
  9702. ["Colend"] = 50000,
  9703. ["Collapse"] = 11000,
  9704. ["Collapse_bottom"] = 47000,
  9705. ["Collapse_top"] = 48000,
  9706. ["Collapsebottom"] = 3800,
  9707. ["Collapsetop"] = 3800,
  9708. ["Collapsible_list"] = 48000,
  9709. ["Collapsible_option"] = 128000,
  9710. ["College"] = 7600,
  9711. ["CollegePrimaryHeader"] = 4700,
  9712. ["CollegePrimaryStyle"] = 88000,
  9713. ["CollegeSecondaryStyle"] = 2400,
  9714. ["College_Athlete_Recruit_End"] = 2600,
  9715. ["College_Athlete_Recruit_Entry"] = 2700,
  9716. ["College_Athlete_Recruit_Start"] = 2600,
  9717. ["College_athlete_recruit_end"] = 3600,
  9718. ["College_athlete_recruit_entry"] = 3800,
  9719. ["College_athlete_recruit_start"] = 3800,
  9720. ["College_color_list"] = 3600,
  9721. ["Colon"] = 17000,
  9722. ["Color"] = 366000,
  9723. ["Color_box"] = 68000,
  9724. ["Colorbox"] = 3200,
  9725. ["Colorbull"] = 5200,
  9726. ["Colored_link"] = 31000,
  9727. ["Colors"] = 3000,
  9728. ["Colour"] = 10000,
  9729. ["Coloured_link"] = 4800,
  9730. ["Column"] = 2000,
  9731. ["Column/styles.css"] = 2100,
  9732. ["Columns-list"] = 86000,
  9733. ["Comedy"] = 2700,
  9734. ["Comic_Book_DB"] = 3700,
  9735. ["Comicbookdb"] = 3600,
  9736. ["Comics-replaceability"] = 2900,
  9737. ["Comics_infobox_sec"] = 12000,
  9738. ["Comics_infobox_sec/creator_nat"] = 3000,
  9739. ["Comics_infobox_sec/formcat"] = 3100,
  9740. ["Comics_infobox_sec/genre"] = 3800,
  9741. ["Comics_infobox_sec/genrecat"] = 3500,
  9742. ["Comicsproj"] = 29000,
  9743. ["Comicsyrimage"] = 2000,
  9744. ["Comma_separated_entries"] = 327000,
  9745. ["Comment"] = 4500,
  9746. ["Committed_identity"] = 2800,
  9747. ["Committed_identity/styles.css"] = 2800,
  9748. ["Commons"] = 64000,
  9749. ["Commons-inline"] = 15000,
  9750. ["Commons_cat"] = 48000,
  9751. ["Commons_category"] = 811000,
  9752. ["Commons_category-inline"] = 128000,
  9753. ["Commons_category_inline"] = 6300,
  9754. ["Commonscat"] = 68000,
  9755. ["Commonscat-inline"] = 20000,
  9756. ["Commonscat_inline"] = 2700,
  9757. ["Commonscatinline"] = 7300,
  9758. ["Compact_TOC"] = 6800,
  9759. ["Compact_ToC"] = 5000,
  9760. ["Compare"] = 8500,
  9761. ["Compare_image_with_Wikidata"] = 8500,
  9762. ["Composition_bar"] = 9100,
  9763. ["Confirmed"] = 14000,
  9764. ["Confused"] = 2600,
  9765. ["Confusing"] = 2400,
  9766. ["CongBio"] = 9800,
  9767. ["CongLinks"] = 4400,
  9768. ["Connected_contributor"] = 16000,
  9769. ["Connected_contributor_(paid)"] = 6200,
  9770. ["Constellation_navbox"] = 5800,
  9771. ["Container"] = 9300,
  9772. ["Container_cat"] = 7200,
  9773. ["Container_category"] = 37000,
  9774. ["Containercat"] = 2700,
  9775. ["Contains_special_characters"] = 3600,
  9776. ["Contains_special_characters/core"] = 3600,
  9777. ["Content_category"] = 7300,
  9778. ["Context"] = 3200,
  9779. ["Continent2continental"] = 15000,
  9780. ["Continent_adjective_to_noun"] = 2200,
  9781. ["Controversial"] = 3100,
  9782. ["Convert"] = 1110000,
  9783. ["Convinfobox"] = 191000,
  9784. ["Convinfobox/2"] = 13000,
  9785. ["Convinfobox/3"] = 115000,
  9786. ["Convinfobox/pri2"] = 57000,
  9787. ["Convinfobox/prisec2"] = 2900,
  9788. ["Convinfobox/prisec3"] = 23000,
  9789. ["Convinfobox/sec2"] = 8000,
  9790. ["Coord"] = 1280000,
  9791. ["Coord_missing"] = 107000,
  9792. ["Coord_missing/CheckCat"] = 106000,
  9793. ["Coords"] = 7400,
  9794. ["Copied"] = 17000,
  9795. ["Copy_to_Wikimedia_Commons"] = 134000,
  9796. ["Copyvios"] = 3600,
  9797. ["Cospar"] = 3100,
  9798. ["Cot"] = 10000,
  9799. ["Count"] = 8100,
  9800. ["Country2continent"] = 25000,
  9801. ["Country2continental"] = 2400,
  9802. ["Country2nationality"] = 73000,
  9803. ["CountryPrefixThe"] = 101000,
  9804. ["Country_abbreviation"] = 84000,
  9805. ["Country_alias"] = 14000,
  9806. ["Country_at_games_navbox"] = 2500,
  9807. ["Country_at_games_navbox/below"] = 2500,
  9808. ["Country_data"] = 5000,
  9809. ["Country_data_ALB"] = 6200,
  9810. ["Country_data_ALG"] = 8200,
  9811. ["Country_data_AND"] = 2600,
  9812. ["Country_data_ANG"] = 4200,
  9813. ["Country_data_ARG"] = 44000,
  9814. ["Country_data_ARM"] = 6300,
  9815. ["Country_data_AUS"] = 70000,
  9816. ["Country_data_AUT"] = 41000,
  9817. ["Country_data_AZE"] = 7700,
  9818. ["Country_data_Afghanistan"] = 11000,
  9819. ["Country_data_Alaska"] = 2200,
  9820. ["Country_data_Albania"] = 17000,
  9821. ["Country_data_Alberta"] = 3400,
  9822. ["Country_data_Algeria"] = 21000,
  9823. ["Country_data_American_Samoa"] = 3100,
  9824. ["Country_data_Andorra"] = 7400,
  9825. ["Country_data_Angola"] = 11000,
  9826. ["Country_data_Anguilla"] = 2700,
  9827. ["Country_data_Antigua_and_Barbuda"] = 5800,
  9828. ["Country_data_Apulia"] = 7900,
  9829. ["Country_data_Argentina"] = 71000,
  9830. ["Country_data_Arizona"] = 2200,
  9831. ["Country_data_Arkansas"] = 2000,
  9832. ["Country_data_Armenia"] = 19000,
  9833. ["Country_data_Aruba"] = 3900,
  9834. ["Country_data_Australia"] = 110000,
  9835. ["Country_data_Austria"] = 66000,
  9836. ["Country_data_Azerbaijan"] = 24000,
  9837. ["Country_data_BAH"] = 3900,
  9838. ["Country_data_BAN"] = 3500,
  9839. ["Country_data_BAR"] = 2300,
  9840. ["Country_data_BEL"] = 46000,
  9841. ["Country_data_BER"] = 2100,
  9842. ["Country_data_BHR"] = 3800,
  9843. ["Country_data_BIH"] = 11000,
  9844. ["Country_data_BLR"] = 23000,
  9845. ["Country_data_BOL"] = 5800,
  9846. ["Country_data_BOT"] = 2200,
  9847. ["Country_data_BRA"] = 53000,
  9848. ["Country_data_BUL"] = 23000,
  9849. ["Country_data_Bahamas"] = 9500,
  9850. ["Country_data_Bahrain"] = 9900,
  9851. ["Country_data_Bangladesh"] = 16000,
  9852. ["Country_data_Barbados"] = 7800,
  9853. ["Country_data_Belarus"] = 37000,
  9854. ["Country_data_Belgium"] = 76000,
  9855. ["Country_data_Belize"] = 5200,
  9856. ["Country_data_Benin"] = 6800,
  9857. ["Country_data_Bermuda"] = 5600,
  9858. ["Country_data_Bhutan"] = 4500,
  9859. ["Country_data_Bolivia"] = 14000,
  9860. ["Country_data_Bosnia_and_Herzegovina"] = 25000,
  9861. ["Country_data_Botswana"] = 8800,
  9862. ["Country_data_Brazil"] = 90000,
  9863. ["Country_data_British_Columbia"] = 3100,
  9864. ["Country_data_British_Raj"] = 2000,
  9865. ["Country_data_British_Virgin_Islands"] = 3700,
  9866. ["Country_data_Brunei"] = 5800,
  9867. ["Country_data_Bulgaria"] = 45000,
  9868. ["Country_data_Burkina_Faso"] = 9600,
  9869. ["Country_data_Burma"] = 2700,
  9870. ["Country_data_Burundi"] = 5300,
  9871. ["Country_data_CAN"] = 55000,
  9872. ["Country_data_CGO"] = 2100,
  9873. ["Country_data_CHE"] = 4200,
  9874. ["Country_data_CHI"] = 16000,
  9875. ["Country_data_CHN"] = 38000,
  9876. ["Country_data_CIV"] = 7100,
  9877. ["Country_data_CMR"] = 7800,
  9878. ["Country_data_COD"] = 2900,
  9879. ["Country_data_COL"] = 23000,
  9880. ["Country_data_CRC"] = 6400,
  9881. ["Country_data_CRO"] = 30000,
  9882. ["Country_data_CUB"] = 8800,
  9883. ["Country_data_CYP"] = 8000,
  9884. ["Country_data_CZE"] = 42000,
  9885. ["Country_data_California"] = 6100,
  9886. ["Country_data_Cambodia"] = 8400,
  9887. ["Country_data_Cameroon"] = 16000,
  9888. ["Country_data_Canada"] = 107000,
  9889. ["Country_data_Cape_Verde"] = 5800,
  9890. ["Country_data_Catalonia"] = 2900,
  9891. ["Country_data_Cayman_Islands"] = 4400,
  9892. ["Country_data_Central_African_Republic"] = 4700,
  9893. ["Country_data_Chad"] = 5200,
  9894. ["Country_data_Chile"] = 35000,
  9895. ["Country_data_China"] = 72000,
  9896. ["Country_data_Chinese_Taipei"] = 16000,
  9897. ["Country_data_Colombia"] = 40000,
  9898. ["Country_data_Colorado"] = 5800,
  9899. ["Country_data_Comoros"] = 4200,
  9900. ["Country_data_Confederate_States_of_America"] = 3000,
  9901. ["Country_data_Connecticut"] = 3200,
  9902. ["Country_data_Cook_Islands"] = 3500,
  9903. ["Country_data_Costa_Rica"] = 16000,
  9904. ["Country_data_Croatia"] = 49000,
  9905. ["Country_data_Cuba"] = 19000,
  9906. ["Country_data_Curaçao"] = 3800,
  9907. ["Country_data_Cyprus"] = 19000,
  9908. ["Country_data_Czech_Republic"] = 69000,
  9909. ["Country_data_Czechoslovakia"] = 16000,
  9910. ["Country_data_DEN"] = 31000,
  9911. ["Country_data_DEU"] = 8000,
  9912. ["Country_data_DNK"] = 3300,
  9913. ["Country_data_DOM"] = 7600,
  9914. ["Country_data_Democratic_Republic_of_the_Congo"] = 11000,
  9915. ["Country_data_Denmark"] = 62000,
  9916. ["Country_data_Djibouti"] = 4400,
  9917. ["Country_data_Dominica"] = 4200,
  9918. ["Country_data_Dominican_Republic"] = 16000,
  9919. ["Country_data_ECU"] = 11000,
  9920. ["Country_data_EGY"] = 12000,
  9921. ["Country_data_ENG"] = 42000,
  9922. ["Country_data_ESA"] = 2300,
  9923. ["Country_data_ESP"] = 66000,
  9924. ["Country_data_EST"] = 13000,
  9925. ["Country_data_ETH"] = 3200,
  9926. ["Country_data_EU"] = 3600,
  9927. ["Country_data_East_Germany"] = 11000,
  9928. ["Country_data_East_Timor"] = 4700,
  9929. ["Country_data_Ecuador"] = 21000,
  9930. ["Country_data_Egypt"] = 28000,
  9931. ["Country_data_El_Salvador"] = 12000,
  9932. ["Country_data_Empire_of_Japan"] = 3600,
  9933. ["Country_data_England"] = 85000,
  9934. ["Country_data_Equatorial_Guinea"] = 5100,
  9935. ["Country_data_Eritrea"] = 5100,
  9936. ["Country_data_Estonia"] = 30000,
  9937. ["Country_data_Eswatini"] = 4700,
  9938. ["Country_data_Ethiopia"] = 11000,
  9939. ["Country_data_Europe"] = 2400,
  9940. ["Country_data_European_Union"] = 7300,
  9941. ["Country_data_FIJ"] = 3500,
  9942. ["Country_data_FIN"] = 31000,
  9943. ["Country_data_FRA"] = 89000,
  9944. ["Country_data_FRG"] = 13000,
  9945. ["Country_data_FR_Yugoslavia"] = 3700,
  9946. ["Country_data_Falkland_Islands"] = 2100,
  9947. ["Country_data_Faroe_Islands"] = 5100,
  9948. ["Country_data_Federated_States_of_Micronesia"] = 3000,
  9949. ["Country_data_Fiji"] = 10000,
  9950. ["Country_data_Finland"] = 57000,
  9951. ["Country_data_Florida"] = 6600,
  9952. ["Country_data_France"] = 185000,
  9953. ["Country_data_French_Guiana"] = 2000,
  9954. ["Country_data_French_Polynesia"] = 3500,
  9955. ["Country_data_GAB"] = 2300,
  9956. ["Country_data_GBR"] = 49000,
  9957. ["Country_data_GDR"] = 6000,
  9958. ["Country_data_GEO"] = 12000,
  9959. ["Country_data_GER"] = 73000,
  9960. ["Country_data_GHA"] = 9200,
  9961. ["Country_data_GRE"] = 23000,
  9962. ["Country_data_GUA"] = 5000,
  9963. ["Country_data_GUI"] = 2700,
  9964. ["Country_data_GUY"] = 2600,
  9965. ["Country_data_Gabon"] = 7400,
  9966. ["Country_data_Gambia"] = 6200,
  9967. ["Country_data_Georgia"] = 11000,
  9968. ["Country_data_Georgia_(U.S._state)"] = 2700,
  9969. ["Country_data_Georgia_(country)"] = 25000,
  9970. ["Country_data_German_Empire"] = 4900,
  9971. ["Country_data_Germany"] = 132000,
  9972. ["Country_data_Ghana"] = 21000,
  9973. ["Country_data_Gibraltar"] = 4700,
  9974. ["Country_data_Great_Britain"] = 59000,
  9975. ["Country_data_Greece"] = 50000,
  9976. ["Country_data_Greenland"] = 2700,
  9977. ["Country_data_Grenada"] = 4900,
  9978. ["Country_data_Guadeloupe"] = 2600,
  9979. ["Country_data_Guam"] = 4900,
  9980. ["Country_data_Guatemala"] = 12000,
  9981. ["Country_data_Guernsey"] = 2300,
  9982. ["Country_data_Guinea"] = 7800,
  9983. ["Country_data_Guinea-Bissau"] = 4700,
  9984. ["Country_data_Guyana"] = 7700,
  9985. ["Country_data_HAI"] = 3300,
  9986. ["Country_data_HKG"] = 12000,
  9987. ["Country_data_HON"] = 4300,
  9988. ["Country_data_HUN"] = 33000,
  9989. ["Country_data_Haiti"] = 8700,
  9990. ["Country_data_Honduras"] = 11000,
  9991. ["Country_data_Hong_Kong"] = 22000,
  9992. ["Country_data_Hungary"] = 58000,
  9993. ["Country_data_IDN"] = 4700,
  9994. ["Country_data_INA"] = 9700,
  9995. ["Country_data_IND"] = 28000,
  9996. ["Country_data_IRE"] = 10000,
  9997. ["Country_data_IRI"] = 4600,
  9998. ["Country_data_IRL"] = 19000,
  9999. ["Country_data_IRN"] = 5600,
  10000. ["Country_data_IRQ"] = 3700,
  10001. ["Country_data_ISL"] = 7900,
  10002. ["Country_data_ISR"] = 19000,
  10003. ["Country_data_ITA"] = 78000,
  10004. ["Country_data_Iceland"] = 20000,
  10005. ["Country_data_Idaho"] = 2200,
  10006. ["Country_data_Illinois"] = 5300,
  10007. ["Country_data_India"] = 96000,
  10008. ["Country_data_Indiana"] = 2800,
  10009. ["Country_data_Indonesia"] = 32000,
  10010. ["Country_data_Iowa"] = 3000,
  10011. ["Country_data_Iran"] = 83000,
  10012. ["Country_data_Iraq"] = 12000,
  10013. ["Country_data_Ireland"] = 31000,
  10014. ["Country_data_Isle_of_Man"] = 3000,
  10015. ["Country_data_Israel"] = 40000,
  10016. ["Country_data_Italy"] = 126000,
  10017. ["Country_data_Ivory_Coast"] = 15000,
  10018. ["Country_data_JAM"] = 9000,
  10019. ["Country_data_JOR"] = 3500,
  10020. ["Country_data_JP"] = 8000,
  10021. ["Country_data_JPN"] = 55000,
  10022. ["Country_data_Jamaica"] = 18000,
  10023. ["Country_data_Japan"] = 103000,
  10024. ["Country_data_Jersey"] = 2700,
  10025. ["Country_data_Jordan"] = 10000,
  10026. ["Country_data_KAZ"] = 17000,
  10027. ["Country_data_KEN"] = 6600,
  10028. ["Country_data_KGZ"] = 3400,
  10029. ["Country_data_KOR"] = 29000,
  10030. ["Country_data_KOS"] = 2000,
  10031. ["Country_data_KSA"] = 5200,
  10032. ["Country_data_KUW"] = 3600,
  10033. ["Country_data_Kazakhstan"] = 29000,
  10034. ["Country_data_Kenya"] = 17000,
  10035. ["Country_data_Kingdom_of_Great_Britain"] = 4400,
  10036. ["Country_data_Kingdom_of_Italy"] = 3700,
  10037. ["Country_data_Kiribati"] = 2900,
  10038. ["Country_data_Kosovo"] = 8000,
  10039. ["Country_data_Kuwait"] = 9700,
  10040. ["Country_data_Kyrgyzstan"] = 8700,
  10041. ["Country_data_LAT"] = 13000,
  10042. ["Country_data_LBN"] = 2100,
  10043. ["Country_data_LIB"] = 2600,
  10044. ["Country_data_LIE"] = 2800,
  10045. ["Country_data_LIT"] = 2900,
  10046. ["Country_data_LTU"] = 11000,
  10047. ["Country_data_LUX"] = 9500,
  10048. ["Country_data_LVA"] = 2300,
  10049. ["Country_data_Laos"] = 7200,
  10050. ["Country_data_Latvia"] = 28000,
  10051. ["Country_data_Lebanon"] = 14000,
  10052. ["Country_data_Lesotho"] = 4800,
  10053. ["Country_data_Liberia"] = 6900,
  10054. ["Country_data_Libya"] = 8300,
  10055. ["Country_data_Liechtenstein"] = 7300,
  10056. ["Country_data_Lithuania"] = 27000,
  10057. ["Country_data_Louisiana"] = 2000,
  10058. ["Country_data_Luxembourg"] = 20000,
  10059. ["Country_data_MAC"] = 2400,
  10060. ["Country_data_MAR"] = 11000,
  10061. ["Country_data_MAS"] = 9900,
  10062. ["Country_data_MDA"] = 6600,
  10063. ["Country_data_MEX"] = 29000,
  10064. ["Country_data_MGL"] = 2600,
  10065. ["Country_data_MKD"] = 6600,
  10066. ["Country_data_MLI"] = 3700,
  10067. ["Country_data_MLT"] = 5100,
  10068. ["Country_data_MNE"] = 7100,
  10069. ["Country_data_MON"] = 3200,
  10070. ["Country_data_MRI"] = 2100,
  10071. ["Country_data_MYA"] = 3000,
  10072. ["Country_data_MYS"] = 3900,
  10073. ["Country_data_Macau"] = 6200,
  10074. ["Country_data_Macedonia"] = 4800,
  10075. ["Country_data_Madagascar"] = 8500,
  10076. ["Country_data_Malawi"] = 5400,
  10077. ["Country_data_Malaysia"] = 33000,
  10078. ["Country_data_Maldives"] = 5800,
  10079. ["Country_data_Mali"] = 10000,
  10080. ["Country_data_Malta"] = 15000,
  10081. ["Country_data_Manitoba"] = 2300,
  10082. ["Country_data_Marshall_Islands"] = 3600,
  10083. ["Country_data_Martinique"] = 2600,
  10084. ["Country_data_Maryland"] = 3000,
  10085. ["Country_data_Massachusetts"] = 3000,
  10086. ["Country_data_Mauritania"] = 5400,
  10087. ["Country_data_Mauritius"] = 7900,
  10088. ["Country_data_Mexico"] = 55000,
  10089. ["Country_data_Michigan"] = 4200,
  10090. ["Country_data_Minnesota"] = 3700,
  10091. ["Country_data_Missouri"] = 2100,
  10092. ["Country_data_Moldova"] = 16000,
  10093. ["Country_data_Monaco"] = 9300,
  10094. ["Country_data_Mongolia"] = 9000,
  10095. ["Country_data_Montana"] = 2500,
  10096. ["Country_data_Montenegro"] = 16000,
  10097. ["Country_data_Montserrat"] = 2500,
  10098. ["Country_data_Morocco"] = 23000,
  10099. ["Country_data_Mozambique"] = 6900,
  10100. ["Country_data_Myanmar"] = 13000,
  10101. ["Country_data_NAM"] = 3400,
  10102. ["Country_data_NED"] = 54000,
  10103. ["Country_data_NEP"] = 2700,
  10104. ["Country_data_NGA"] = 7200,
  10105. ["Country_data_NGR"] = 7800,
  10106. ["Country_data_NIR"] = 9100,
  10107. ["Country_data_NLD"] = 5700,
  10108. ["Country_data_NOR"] = 26000,
  10109. ["Country_data_NZ"] = 2800,
  10110. ["Country_data_NZL"] = 30000,
  10111. ["Country_data_Namibia"] = 9500,
  10112. ["Country_data_Nauru"] = 2500,
  10113. ["Country_data_Nazi_Germany"] = 8900,
  10114. ["Country_data_Nepal"] = 15000,
  10115. ["Country_data_Netherlands"] = 96000,
  10116. ["Country_data_Netherlands_Antilles"] = 2300,
  10117. ["Country_data_New_Brunswick"] = 2400,
  10118. ["Country_data_New_Caledonia"] = 3300,
  10119. ["Country_data_New_Jersey"] = 4300,
  10120. ["Country_data_New_South_Wales"] = 5400,
  10121. ["Country_data_New_York"] = 4000,
  10122. ["Country_data_New_York_(state)"] = 6000,
  10123. ["Country_data_New_Zealand"] = 54000,
  10124. ["Country_data_Newfoundland_and_Labrador"] = 2200,
  10125. ["Country_data_Nicaragua"] = 8900,
  10126. ["Country_data_Niger"] = 5400,
  10127. ["Country_data_Nigeria"] = 29000,
  10128. ["Country_data_North_Carolina"] = 3400,
  10129. ["Country_data_North_Korea"] = 12000,
  10130. ["Country_data_North_Macedonia"] = 15000,
  10131. ["Country_data_Northern_Cyprus"] = 2100,
  10132. ["Country_data_Northern_Ireland"] = 13000,
  10133. ["Country_data_Northern_Mariana_Islands"] = 2800,
  10134. ["Country_data_Norway"] = 61000,
  10135. ["Country_data_Nova_Scotia"] = 2200,
  10136. ["Country_data_OMA"] = 2400,
  10137. ["Country_data_Ohio"] = 4900,
  10138. ["Country_data_Oman"] = 8200,
  10139. ["Country_data_Ontario"] = 3500,
  10140. ["Country_data_Ottoman_Empire"] = 2400,
  10141. ["Country_data_PAK"] = 7500,
  10142. ["Country_data_PAN"] = 6400,
  10143. ["Country_data_PAR"] = 9700,
  10144. ["Country_data_PER"] = 12000,
  10145. ["Country_data_PHI"] = 11000,
  10146. ["Country_data_PHL"] = 2900,
  10147. ["Country_data_PNG"] = 2500,
  10148. ["Country_data_POL"] = 45000,
  10149. ["Country_data_POR"] = 28000,
  10150. ["Country_data_PRC"] = 2900,
  10151. ["Country_data_PRK"] = 4100,
  10152. ["Country_data_PRT"] = 2700,
  10153. ["Country_data_PUR"] = 8000,
  10154. ["Country_data_Pakistan"] = 26000,
  10155. ["Country_data_Palau"] = 2900,
  10156. ["Country_data_Palestine"] = 6300,
  10157. ["Country_data_Panama"] = 15000,
  10158. ["Country_data_Papua_New_Guinea"] = 7400,
  10159. ["Country_data_Paraguay"] = 18000,
  10160. ["Country_data_Pennsylvania"] = 3600,
  10161. ["Country_data_People's_Republic_of_China"] = 3100,
  10162. ["Country_data_Peru"] = 28000,
  10163. ["Country_data_Philippines"] = 31000,
  10164. ["Country_data_Poland"] = 133000,
  10165. ["Country_data_Portugal"] = 56000,
  10166. ["Country_data_Prussia"] = 2400,
  10167. ["Country_data_Puerto_Rico"] = 16000,
  10168. ["Country_data_QAT"] = 6800,
  10169. ["Country_data_Qatar"] = 15000,
  10170. ["Country_data_Quebec"] = 4000,
  10171. ["Country_data_ROC"] = 2300,
  10172. ["Country_data_ROM"] = 12000,
  10173. ["Country_data_ROU"] = 23000,
  10174. ["Country_data_RSA"] = 29000,
  10175. ["Country_data_RUS"] = 60000,
  10176. ["Country_data_Republic_of_China"] = 6300,
  10177. ["Country_data_Republic_of_Ireland"] = 21000,
  10178. ["Country_data_Republic_of_the_Congo"] = 7100,
  10179. ["Country_data_Romania"] = 55000,
  10180. ["Country_data_Russia"] = 102000,
  10181. ["Country_data_Russian_Empire"] = 4500,
  10182. ["Country_data_Rwanda"] = 7200,
  10183. ["Country_data_SAM"] = 2800,
  10184. ["Country_data_SCG"] = 3000,
  10185. ["Country_data_SCO"] = 24000,
  10186. ["Country_data_SEN"] = 6900,
  10187. ["Country_data_SER"] = 3300,
  10188. ["Country_data_SGP"] = 2100,
  10189. ["Country_data_SIN"] = 7100,
  10190. ["Country_data_SLO"] = 18000,
  10191. ["Country_data_SLV"] = 3100,
  10192. ["Country_data_SMR"] = 2800,
  10193. ["Country_data_SPA"] = 4200,
  10194. ["Country_data_SRB"] = 24000,
  10195. ["Country_data_SRI"] = 4600,
  10196. ["Country_data_SUI"] = 38000,
  10197. ["Country_data_SVK"] = 26000,
  10198. ["Country_data_SVN"] = 6100,
  10199. ["Country_data_SWE"] = 52000,
  10200. ["Country_data_SWI"] = 4600,
  10201. ["Country_data_SYR"] = 3200,
  10202. ["Country_data_Saint_Kitts_and_Nevis"] = 4500,
  10203. ["Country_data_Saint_Lucia"] = 4900,
  10204. ["Country_data_Saint_Vincent_and_the_Grenadines"] = 4600,
  10205. ["Country_data_Samoa"] = 7300,
  10206. ["Country_data_San_Marino"] = 7900,
  10207. ["Country_data_Saskatchewan"] = 2700,
  10208. ["Country_data_Saudi_Arabia"] = 17000,
  10209. ["Country_data_Scotland"] = 45000,
  10210. ["Country_data_Senegal"] = 14000,
  10211. ["Country_data_Serbia"] = 47000,
  10212. ["Country_data_Serbia_and_Montenegro"] = 4900,
  10213. ["Country_data_Seychelles"] = 5100,
  10214. ["Country_data_Sierra_Leone"] = 6800,
  10215. ["Country_data_Singapore"] = 24000,
  10216. ["Country_data_Slovakia"] = 44000,
  10217. ["Country_data_Slovenia"] = 36000,
  10218. ["Country_data_Solomon_Islands"] = 4400,
  10219. ["Country_data_Somalia"] = 5700,
  10220. ["Country_data_South_Africa"] = 57000,
  10221. ["Country_data_South_Carolina"] = 3300,
  10222. ["Country_data_South_Korea"] = 55000,
  10223. ["Country_data_South_Sudan"] = 3600,
  10224. ["Country_data_South_Vietnam"] = 2000,
  10225. ["Country_data_Soviet_Union"] = 30000,
  10226. ["Country_data_Spain"] = 115000,
  10227. ["Country_data_Sri_Lanka"] = 17000,
  10228. ["Country_data_Sudan"] = 7500,
  10229. ["Country_data_Suriname"] = 6100,
  10230. ["Country_data_Swaziland"] = 2000,
  10231. ["Country_data_Sweden"] = 88000,
  10232. ["Country_data_Switzerland"] = 70000,
  10233. ["Country_data_Syria"] = 14000,
  10234. ["Country_data_São_Tomé_and_Príncipe"] = 3300,
  10235. ["Country_data_TAN"] = 2400,
  10236. ["Country_data_TCH"] = 9500,
  10237. ["Country_data_THA"] = 20000,
  10238. ["Country_data_TJK"] = 2300,
  10239. ["Country_data_TKM"] = 2500,
  10240. ["Country_data_TPE"] = 14000,
  10241. ["Country_data_TRI"] = 4700,
  10242. ["Country_data_TUN"] = 9200,
  10243. ["Country_data_TUR"] = 24000,
  10244. ["Country_data_Taiwan"] = 11000,
  10245. ["Country_data_Tajikistan"] = 8500,
  10246. ["Country_data_Tanzania"] = 10000,
  10247. ["Country_data_Texas"] = 5500,
  10248. ["Country_data_Thailand"] = 39000,
  10249. ["Country_data_Togo"] = 6400,
  10250. ["Country_data_Tonga"] = 6000,
  10251. ["Country_data_Trinidad_and_Tobago"] = 13000,
  10252. ["Country_data_Tunisia"] = 18000,
  10253. ["Country_data_Turkey"] = 66000,
  10254. ["Country_data_Turkmenistan"] = 7400,
  10255. ["Country_data_Turks_and_Caicos_Islands"] = 2800,
  10256. ["Country_data_Tuvalu"] = 2600,
  10257. ["Country_data_U.S."] = 2100,
  10258. ["Country_data_U.S._Virgin_Islands"] = 4900,
  10259. ["Country_data_UAE"] = 8300,
  10260. ["Country_data_UGA"] = 3500,
  10261. ["Country_data_UK"] = 18000,
  10262. ["Country_data_UKGBI"] = 2700,
  10263. ["Country_data_UKR"] = 33000,
  10264. ["Country_data_URS"] = 11000,
  10265. ["Country_data_URU"] = 14000,
  10266. ["Country_data_US"] = 5300,
  10267. ["Country_data_USA"] = 126000,
  10268. ["Country_data_USSR"] = 4400,
  10269. ["Country_data_UZB"] = 10000,
  10270. ["Country_data_Uganda"] = 11000,
  10271. ["Country_data_Ukraine"] = 57000,
  10272. ["Country_data_United_Arab_Emirates"] = 17000,
  10273. ["Country_data_United_Kingdom"] = 80000,
  10274. ["Country_data_United_Kingdom_of_Great_Britain_and_Ireland"] = 4000,
  10275. ["Country_data_United_Nations"] = 3700,
  10276. ["Country_data_United_States"] = 265000,
  10277. ["Country_data_United_States_of_America"] = 4600,
  10278. ["Country_data_Uruguay"] = 26000,
  10279. ["Country_data_Uzbekistan"] = 18000,
  10280. ["Country_data_VEN"] = 16000,
  10281. ["Country_data_VIE"] = 5900,
  10282. ["Country_data_Vanuatu"] = 4900,
  10283. ["Country_data_Vatican_City"] = 2300,
  10284. ["Country_data_Venezuela"] = 30000,
  10285. ["Country_data_Vietnam"] = 20000,
  10286. ["Country_data_Virginia"] = 2800,
  10287. ["Country_data_WAL"] = 16000,
  10288. ["Country_data_Wales"] = 30000,
  10289. ["Country_data_Washington"] = 3200,
  10290. ["Country_data_Washington,_D.C."] = 2200,
  10291. ["Country_data_Washington_(state)"] = 3500,
  10292. ["Country_data_West_Germany"] = 19000,
  10293. ["Country_data_West_Indies"] = 2400,
  10294. ["Country_data_Wisconsin"] = 5900,
  10295. ["Country_data_Wyoming"] = 2100,
  10296. ["Country_data_YUG"] = 8800,
  10297. ["Country_data_Yemen"] = 6800,
  10298. ["Country_data_Yugoslavia"] = 16000,
  10299. ["Country_data_ZAF"] = 4400,
  10300. ["Country_data_ZAM"] = 3000,
  10301. ["Country_data_ZIM"] = 7800,
  10302. ["Country_data_Zambia"] = 8900,
  10303. ["Country_data_Zimbabwe"] = 16000,
  10304. ["Country_flagbio"] = 24000,
  10305. ["Country_name"] = 9200,
  10306. ["Country_showdata"] = 5700,
  10307. ["Country_topics"] = 21000,
  10308. ["County"] = 7400,
  10309. ["County_(judet)_of_Romania"] = 3300,
  10310. ["Course_assignment"] = 4300,
  10311. ["Course_details"] = 5200,
  10312. ["Course_instructor"] = 2100,
  10313. ["Cquote"] = 36000,
  10314. ["Cr"] = 3900,
  10315. ["Create_taxonomy/link"] = 93000,
  10316. ["Cref2"] = 2000,
  10317. ["Cricinfo"] = 22000,
  10318. ["Cricketarchive"] = 3500,
  10319. ["Crime_opentask"] = 34000,
  10320. ["Croatian_Census_2011"] = 2000,
  10321. ["Cross"] = 3000,
  10322. ["Crossreference"] = 2200,
  10323. ["Crossreference/styles.css"] = 2200,
  10324. ["Csv"] = 2900,
  10325. ["Ct"] = 11000,
  10326. ["Curlie"] = 6900,
  10327. ["Currency"] = 2500,
  10328. ["Current_events_footer"] = 6100,
  10329. ["Current_events_header"] = 7100,
  10330. ["Currentdate"] = 22000,
  10331. ["Cvt"] = 98000,
  10332. ["Cycling_Archives"] = 5200,
  10333. ["Cycling_archives"] = 3600,
  10334. ["Cycling_team_link"] = 11000,
  10335. ["Module:CFB_schedule"] = 24000,
  10336. ["Module:CallAssert"] = 217000,
  10337. ["Module:CanElecResTopTest"] = 5100,
  10338. ["Module:CanadaByProvinceCatNav"] = 9600,
  10339. ["Module:Cat_main"] = 171000,
  10340. ["Module:Cat_more_if_exists"] = 44000,
  10341. ["Module:Catalog_lookup_link"] = 483000,
  10342. ["Module:Category_described_in_year"] = 5600,
  10343. ["Module:Category_described_in_year/conf"] = 5600,
  10344. ["Module:Category_handler"] = 4260000,
  10345. ["Module:Category_handler/blacklist"] = 4260000,
  10346. ["Module:Category_handler/config"] = 4260000,
  10347. ["Module:Category_handler/data"] = 4260000,
  10348. ["Module:Category_handler/shared"] = 4260000,
  10349. ["Module:Category_pair"] = 5700,
  10350. ["Module:Category_see_also"] = 33000,
  10351. ["Module:Celestial_object_quadrangle"] = 2500,
  10352. ["Module:Check_DYK_hook"] = 109000,
  10353. ["Module:Check_for_clobbered_parameters"] = 1140000,
  10354. ["Module:Check_for_unknown_parameters"] = 12600000,
  10355. ["Module:Check_isxn"] = 473000,
  10356. ["Module:Check_winner_by_scores"] = 12000,
  10357. ["Module:Citation/CS1"] = 5130000,
  10358. ["Module:Citation/CS1/COinS"] = 5130000,
  10359. ["Module:Citation/CS1/Configuration"] = 5130000,
  10360. ["Module:Citation/CS1/Date_validation"] = 5130000,
  10361. ["Module:Citation/CS1/Identifiers"] = 5130000,
  10362. ["Module:Citation/CS1/Suggestions"] = 30000,
  10363. ["Module:Citation/CS1/Utilities"] = 5140000,
  10364. ["Module:Citation/CS1/Whitelist"] = 5130000,
  10365. ["Module:Citation/CS1/styles.css"] = 5260000,
  10366. ["Module:Cite_Q"] = 52000,
  10367. ["Module:Cite_iucn"] = 53000,
  10368. ["Module:Cite_tweet"] = 26000,
  10369. ["Module:Cite_web"] = 29000,
  10370. ["Module:Clade"] = 6000,
  10371. ["Module:Clickable_button_2"] = 837000,
  10372. ["Module:Collapsible_list"] = 50000,
  10373. ["Module:College_color"] = 118000,
  10374. ["Module:College_color/data"] = 118000,
  10375. ["Module:Color_contrast"] = 473000,
  10376. ["Module:Color_contrast/colors"] = 475000,
  10377. ["Module:Commons_link"] = 228000,
  10378. ["Module:Complex_date"] = 65000,
  10379. ["Module:Convert"] = 1150000,
  10380. ["Module:Convert/data"] = 1150000,
  10381. ["Module:Convert/helper"] = 6600,
  10382. ["Module:Convert/text"] = 1150000,
  10383. ["Module:Convert/wikidata"] = 2500,
  10384. ["Module:Convert/wikidata/data"] = 2500,
  10385. ["Module:ConvertNumeric"] = 26000,
  10386. ["Module:Convert_character_width"] = 2800,
  10387. ["Module:Convert_character_width/data"] = 2800,
  10388. ["Module:Coordinates"] = 1290000,
  10389. ["Module:Coordinates/styles.css"] = 1290000,
  10390. ["Module:Copied"] = 17000,
  10391. ["Module:CountryAdjectiveDemonym"] = 42000,
  10392. ["Module:CountryAdjectiveDemonym/Adjectives"] = 42000,
  10393. ["Module:CountryAdjectiveDemonym/Demonyms"] = 42000,
  10394. ["Module:CountryAdjectiveDemonym/The"] = 42000,
  10395. ["Module:CountryData"] = 18000,
  10396. ["Module:CountryData/summary"] = 18000,
  10397. ["Module:Country_adjective"] = 3900,
  10398. ["Module:Country_alias"] = 49000,
  10399. ["Module:Country_alias/data"] = 49000,
  10400. ["Module:Currency"] = 2600,
  10401. ["Module:Currency/Presentation"] = 2600,
  10402. }</text>
  10403.       <sha1>32dp4ozqz2nqvm93a9ej329uu72fh49</sha1>
  10404.     </revision>
  10405.   </page>
  10406.   <page>
  10407.     <title>Module:Transclusion count/data/Y</title>
  10408.     <ns>828</ns>
  10409.     <id>61481074</id>
  10410.     <revision>
  10411.       <id>1071545150</id>
  10412.       <parentid>1070187821</parentid>
  10413.       <timestamp>2022-02-13T05:16:05Z</timestamp>
  10414.       <contributor>
  10415.         <username>Ahechtbot</username>
  10416.         <id>26109785</id>
  10417.       </contributor>
  10418.       <minor/>
  10419.       <comment>[[Wikipedia:BOT|Bot]]: Updated page.</comment>
  10420.       <model>Scribunto</model>
  10421.       <format>text/plain</format>
  10422.       <text bytes="2588" xml:space="preserve">return {
  10423. ["Y"] = 14000,
  10424. ["YEAR"] = 5200,
  10425. ["YUG"] = 2100,
  10426. ["YYYY_beginnings_or_endings_category_header"] = 3900,
  10427. ["YYYY_beginnings_or_endings_category_header/core"] = 3900,
  10428. ["YYYY_crimes_in_countryname_category_header"] = 2300,
  10429. ["YYYY_crimes_in_countryname_category_header/inner_core"] = 2300,
  10430. ["YYYY_crimes_in_countryname_category_header/outer_core"] = 2300,
  10431. ["YYYY_elections_in_countryname_category_header"] = 3100,
  10432. ["YYYY_elections_in_countryname_category_header/inner_core"] = 3100,
  10433. ["YYYY_elections_in_countryname_category_header/outer_core"] = 3100,
  10434. ["YYYY_in_nationality_sport_category_header"] = 12000,
  10435. ["YYYY_in_nationality_sport_category_header/inner_core"] = 12000,
  10436. ["YYYY_in_nationality_sport_category_header/outer_core"] = 12000,
  10437. ["Year"] = 4700,
  10438. ["YearInCountryPortalBox"] = 89000,
  10439. ["YearInCountryPortalBox/make"] = 89000,
  10440. ["YearInCountryPortalBox/parse"] = 89000,
  10441. ["Year_article"] = 6600,
  10442. ["Year_box"] = 2100,
  10443. ["Year_box/core"] = 2100,
  10444. ["Year_box/outer_core"] = 2100,
  10445. ["Year_category_header"] = 3100,
  10446. ["Year_category_header/core"] = 3100,
  10447. ["Year_category_name"] = 2500,
  10448. ["Year_category_name/AD_year"] = 2500,
  10449. ["Year_in_Europe"] = 5500,
  10450. ["Year_in_Europe/expr"] = 5500,
  10451. ["Year_in_US_state_category"] = 9400,
  10452. ["Year_in_US_state_category/core"] = 9400,
  10453. ["Year_in_continent/expr"] = 7500,
  10454. ["Year_in_continent/link"] = 7500,
  10455. ["Year_in_continent_category"] = 3700,
  10456. ["Year_in_continent_category/core"] = 3700,
  10457. ["Year_in_country_category"] = 38000,
  10458. ["Year_in_country_category/inner_core"] = 38000,
  10459. ["Year_in_country_category/outer_core"] = 38000,
  10460. ["Year_in_football"] = 2200,
  10461. ["Year_in_nationality_television_category"] = 3100,
  10462. ["Year_in_nationality_television_category/core"] = 3100,
  10463. ["Year_in_region"] = 11000,
  10464. ["Year_in_region/link"] = 11000,
  10465. ["Year_in_various_calendars"] = 2800,
  10466. ["Year_nationality_television_series_debuts_or_endings_category"] = 4600,
  10467. ["Year_nationality_television_series_debuts_or_endings_category/core"] = 4600,
  10468. ["Year_nav"] = 2800,
  10469. ["Year_nav_topic"] = 7200,
  10470. ["Year_nav_topic5"] = 7100,
  10471. ["Yearly_archive_list"] = 519000,
  10472. ["Yearly_archive_list/display"] = 519000,
  10473. ["YearsProject"] = 2200,
  10474. ["Years_or_months_ago"] = 63000,
  10475. ["Yel"] = 13000,
  10476. ["Yes"] = 8700,
  10477. ["Yes2"] = 9400,
  10478. ["YesNo-Yes"] = 57000,
  10479. ["Yesno"] = 12800000,
  10480. ["Yesno-no"] = 1910000,
  10481. ["Yesno-yes"] = 9690000,
  10482. ["Yo"] = 13000,
  10483. ["You've_got_mail"] = 9900,
  10484. ["YouTube"] = 53000,
  10485. ["Youtube"] = 7400,
  10486. ["Yy"] = 10000,
  10487. ["Yybottom"] = 10000,
  10488. ["Yycat"] = 2400,
  10489. ["Yyend"] = 10000,
  10490. ["Yytop"] = 10000,
  10491. ["Module:Year_category_type"] = 3100,
  10492. ["Module:Year_in_various_calendars"] = 2800,
  10493. ["Module:Yesno"] = 25700000,
  10494. }</text>
  10495.       <sha1>kd0hgsm3oh8tfd4jjvem2wi55xrkg5d</sha1>
  10496.     </revision>
  10497.   </page>
  10498.   <page>
  10499.     <title>Module:Yesno/doc</title>
  10500.     <ns>828</ns>
  10501.     <id>40585364</id>
  10502.     <revision>
  10503.       <id>1061900054</id>
  10504.       <parentid>1061886579</parentid>
  10505.       <timestamp>2021-12-24T18:54:34Z</timestamp>
  10506.       <contributor>
  10507.         <username>Pppery</username>
  10508.         <id>28032115</id>
  10509.       </contributor>
  10510.       <model>wikitext</model>
  10511.       <format>text/x-wiki</format>
  10512.       <text bytes="4316" xml:space="preserve">{{used in system}}
  10513. {{Module rating|protected}}
  10514. This module provides a consistent interface for processing boolean or boolean-style string input. While Lua allows the &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; boolean values, wikicode templates can only express boolean values through strings such as "yes", "no", etc. This module processes these kinds of strings and turns them into boolean input for Lua to process. It also returns &lt;code&gt;nil&lt;/code&gt; values as &lt;code&gt;nil&lt;/code&gt;, to allow for distinctions between &lt;code&gt;nil&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt;. The module also accepts other Lua structures as input, i.e. booleans, numbers, tables, and functions. If it is passed input that it does not recognise as boolean or &lt;code&gt;nil&lt;/code&gt;, it is possible to specify a default value to return.
  10515.  
  10516. == Syntax ==
  10517.  
  10518. &lt;syntaxhighlight lang="lua"&gt;yesno(value, default)&lt;/syntaxhighlight&gt;
  10519.  
  10520. &lt;code&gt;value&lt;/code&gt; is the value to be tested. Boolean input or boolean-style input (see below) always evaluates to either &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;, and &lt;code&gt;nil&lt;/code&gt; always evaluates to &lt;code&gt;nil&lt;/code&gt;. Other values evaluate to &lt;code&gt;default&lt;/code&gt;.
  10521.  
  10522. == Usage ==
  10523.  
  10524. First, load the module. Note that it can only be loaded from other Lua modules, not from normal wiki pages. For normal wiki pages you can use {{tl|yesno}} instead.
  10525.  
  10526. &lt;syntaxhighlight lang="lua"&gt;
  10527. local yesno = require('Module:Yesno')
  10528. &lt;/syntaxhighlight&gt;
  10529.  
  10530. Some input values always return &lt;code&gt;true&lt;/code&gt;, and some always return &lt;code&gt;false&lt;/code&gt;. &lt;code&gt;nil&lt;/code&gt; values always return &lt;code&gt;nil&lt;/code&gt;.
  10531.  
  10532. &lt;syntaxhighlight lang="lua"&gt;
  10533. -- These always return true:
  10534. yesno('yes')
  10535. yesno('y')
  10536. yesno('true')
  10537. yesno('t')
  10538. yesno('1')
  10539. yesno(1)
  10540. yesno(true)
  10541.  
  10542. -- These always return false:
  10543. yesno('no')
  10544. yesno('n')
  10545. yesno('false')
  10546. yesno('f')
  10547. yesno('0')
  10548. yesno(0)
  10549. yesno(false)
  10550.  
  10551. -- A nil value always returns nil:
  10552. yesno(nil)
  10553. &lt;/syntaxhighlight&gt;
  10554.  
  10555. String values are converted to lower case before they are matched:
  10556.  
  10557. &lt;syntaxhighlight lang="lua"&gt;
  10558. -- These always return true:
  10559. yesno('Yes')
  10560. yesno('YES')
  10561. yesno('yEs')
  10562. yesno('Y')
  10563. yesno('tRuE')
  10564.  
  10565. -- These always return false:
  10566. yesno('No')
  10567. yesno('NO')
  10568. yesno('nO')
  10569. yesno('N')
  10570. yesno('fALsE')
  10571. &lt;/syntaxhighlight&gt;
  10572.  
  10573. ===Undefined input ('foo')===
  10574. You can specify a default value if yesno receives input other than that listed above. If you don't supply a default, the module will return &lt;code&gt;nil&lt;/code&gt; for these inputs.
  10575.  
  10576. &lt;syntaxhighlight lang="lua"&gt;
  10577. -- These return nil:
  10578. yesno('foo')
  10579. yesno({})
  10580. yesno(5)
  10581. yesno(function() return 'This is a function.' end)
  10582. yesno(nil, true)
  10583. yesno(nil, 'bar')
  10584.  
  10585. -- These return true:
  10586. yesno('foo', true)
  10587. yesno({}, true)
  10588. yesno(5, true)
  10589. yesno(function() return 'This is a function.' end, true)
  10590.  
  10591. -- These return "bar":
  10592. yesno('foo', 'bar')
  10593. yesno({}, 'bar')
  10594. yesno(5, 'bar')
  10595. yesno(function() return 'This is a function.' end, 'bar')
  10596. &lt;/syntaxhighlight&gt;
  10597.  
  10598. Note that the empty string also functions this way:
  10599. &lt;syntaxhighlight lang="lua"&gt;
  10600. yesno('')        -- Returns nil.
  10601. yesno('', true)  -- Returns true.
  10602. yesno('', 'bar') -- Returns "bar".
  10603. &lt;/syntaxhighlight&gt;
  10604.  
  10605. Although the empty string usually evaluates to false in wikitext, it evaluates to true in Lua. This module prefers the Lua behaviour over the wikitext behaviour. If treating the empty string as false is important for your module, you will need to convert empty strings to a value that evaluates to false before passing them to this module. In the case of arguments received from wikitext, this can be done by using [[Module:Arguments]].
  10606.  
  10607. ===Handling nil results===
  10608. By definition
  10609. :&lt;syntaxhighlight lang="lua"&gt;
  10610. yesno(nil)         -- Returns nil.
  10611. yesno('foo')       -- Returns nil.
  10612. yesno(nil, true)   -- Returns nil.
  10613. yesno(nil, false)  -- Returns nil.
  10614. yesno('foo', true) -- Returns true.
  10615. &lt;/syntaxhighlight&gt;
  10616.  
  10617. To get the binary &lt;syntaxhighlight lang="lua" inline&gt;true/false&lt;/syntaxhighlight&gt;-only values, use code like:
  10618. &lt;syntaxhighlight lang="lua"&gt;
  10619. myvariable = yesno(value) or false -- When value is nil, result is false.
  10620. myvariable = yesno(value) or true  -- When value is nil, result is true.
  10621. myvariable = yesno('foo') or false  -- Unknown string returns nil, result is false.
  10622. myvariable = yesno('foo', true) or false  -- Default value (here: true) applies, result is true.
  10623. &lt;/syntaxhighlight&gt;&lt;!--
  10624.  
  10625. --&gt;&lt;includeonly&gt;{{sandbox other||
  10626. [[Category:Lua metamodules]]
  10627. }}&lt;/includeonly&gt;</text>
  10628.       <sha1>nrpba7al4tg6jf69dmn4yqegiu1jctj</sha1>
  10629.     </revision>
  10630.   </page>
  10631. </mediawiki>
  10632.  
Add Comment
Please, Sign In to add comment