Jump to content
Wikipedia The Free Encyclopedia

Module:Excerpt/portals

From Wikipedia, the free encyclopedia
Module documentation[view] [edit] [history] [purge]
This module is rated as beta. It is considered ready for widespread use, but as it is still relatively new, it should be applied with some caution to ensure results are as expected.
Page extended-confirmed-protected This module is currently under extended confirmed protection.
Extended confirmed protection prevents edits from all unregistered editors and registered users with fewer than 30 days tenure and 500 edits. The policy on community use specifies that extended confirmed protection can be applied to combat disruption, if semi-protection has proven to be ineffective. Extended confirmed protection may also be applied to enforce arbitration sanctions. Please discuss any changes on the talk page; you may submit an edit request to ask for uncontroversial changes supported by consensus.
Warning This Lua module is used on approximately 4,800 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them.
This module depends on the following other modules:

Usage

{{#invoke:Excerpt/portals|lead}}
Transcludes the lead of an article as an excerpt. Main documentation: {{Transclude lead excerpt/doc }}
{{#invoke:Excerpt/portals|linked}}
Transcludes as an excerpt the lead of an article selected randomly from wikilinks on a page. Main documentation: {{Transclude linked excerpt/doc }}
{{#invoke:Excerpt/portals|listitem}}
Transcludes as an excerpt the lead of an article selected randomly from list items on a page. Main documentation: {{Transclude list item excerpt/doc }}
{{#invoke:Excerpt/portals|random}}
Transcludes as an excerpt the lead of an article selected randomly from the parameters. Main documentation: {{Transclude random excerpt/doc }}
{{#invoke:Excerpt/portals|selected}}
Transcludes the lead of a selected article as an excerpt. Main documentation: {{Transclude selected excerpt/doc }}

Note

Before saving a change to this module, please preview with:

See also

Portal templates
Layout and formatting
Content transclusion
Content slideshows
Content randomisation
General
Linking templates
Talk pages / Maintenance
Images
Modules
Usage
The above documentation is transcluded from Module:Excerpt/portals/doc. (edit | history)
Editors can experiment in this module's sandbox (edit | diff) and testcases (create) pages.
Subpages of this module.

 -- ATTENTION !
 -- This version of Excerpt is designed specifically for the portal namespace and its associated templates
 -- Prefer Module:Excerpt whenever possible

 -- Name of the category to track content pages with errors
 localerrorCategory="Articles with broken excerpts"

 -- Error messages
 localerrorMessages={
 prefix="Excerpt error: ",
 noPage="No page given",
 pageNotFound="Page '%s' not found",
 leadEmpty="Lead section is empty",
 sectionEmpty="Section '%s' is empty",
 sectionNotFound="Section '%s' not found",
 fragmentEmpty="Fragment '%s' is empty",
 fragmentNotFound="Fragment '%s' not found"
 }

 -- Regular expressions to match all aliases of the file namespace
 localfileNamespaces={
 "[Ff]ile",
 "[Ii]mage"
 }

 -- Regular expressions to match all image parameters
 localimageParams={
 {"thumb","thumbnail","frame","framed","frameless"},
 {"right","left","center","centre","none"},
 {"baseline","middle","sub","super","text-top","text-bottom","top","bottom"}
 }

 -- Regular expressions to match all infobox parameters for image captions
 localcaptionParams={
 "[^=|]*[Cc]aption[^=|]*",
 "[^=|]*[Ll]egend[^=|]*"
 }

 -- List of file types that are allowed to be transcluded
 localfileTypes={"[Gg][Ii][Ff]","[Jj][Pp][Ee]?[Gg]","[Pp][Nn][Gg]","[Ss][Vv][Gg]","[Tt][Ii][Ff][Ff]","[Xx][Cc][Ff]"}

 -- Regular expressions to match all inline templates that are undesirable in excerpts
 localunwantedInlineTemplates={
 "[Ee]fn","[Ee]fn%-[lu][arg]","[Ee]fn [%a ]-","[Ee]l[mn]","[Rr]p?","[Ss]fn[bmp]","[Ss]f[bn]","[Nn]ote[Tt]ag","#[Tt]ag:%s*[Rr]ef","[Rr]efn?","[Ff]amily[ _]name[ _]footnote",
 "[CcDd]n","[Cc]itation[%- _]needed","[Dd]isambiguation needed","[Ff]eatured article","[Gg]ood article",
 "[Dd]ISPLAYTITLE","[Ss]hort[ _]+description","[Cc]itation","[Cc]ite[%- _]+[%w_%s]-","[Cc]oor[%w_%s]-",
 "[Uu]?n?[Rr]eliable source[%?%w_%s]-","[Rr]s%??","[Vv]c","[Vv]erify credibility","[Bb]y[ _]*[Ww]ho[m]*%??","[Ww]ikisource[ -_]*multi","[Ii]nflation[ _/-]*[Ff]n",
 "[Bb]iblesource",
 "[Dd]ecadebox",
 "[Ee]vents by year for decade",
 -- aliases for Clarification needed
 "[Cc]f[ny]","[Cc]larification[ _]+inline","[Cc]larification[%- _]*needed","[Cc]larification","[Cc]larify%-inline","[Cc]larify%-?me",
 "[Cc]larify[ _]+inline","[Cc]larify","[Cc]LARIFY","[Cc]onfusing%-inline","[Cc]onfusing%-short","[Ee]xplainme","[Hh]uh[ _]*%??","[Ww]hat%?",
 "[Ii]nline[ _]+[Uu]nclear","[Ii]n[ _]+what[ _]+sense","[Oo]bscure","[Pp]lease[ _]+clarify","[Uu]nclear[ _]+inline","[Ww]hat's[ _]+this%?",
 "[Gg]eoQuelle","[Nn]eed[s]+[%- _]+[Ii][Pp][Aa]","[Ii]PA needed",
 -- aliases for Clarification needed lead
 "[Cc]itation needed %(?lea?de?%)?","[Cc]nl","[Ff]act %(?lea?de?%)?","[Ll]ead citation needed","[Nn]ot in body","[Nn]ot verified in body",
 -- Primary source etc.
 "[Pp]s[ci]","[Nn]psn","[Nn]on%-primary[ _]+source[ _]+needed","[Ss]elf%-published[%w_%s]-","[Uu]ser%-generated[%w_%s]-",
 "[Pp]rimary source[%w_%s]-","[Ss]econdary source[%w_%s]-","[Tt]ertiary source[%w_%s]-","[Tt]hird%-party[%w_%s]-",
 -- aliases for Disambiguation (page) and similar
 "[Bb]egriffsklärung","[Dd][Aa][Bb]","[Dd]big","[%w_%s]-%f[%w][Dd]isam[%w_%s]-","[Hh][Nn][Dd][Ii][Ss]",
 -- aliases for Failed verification
 "[Bb]adref","[Ff]aile?[ds] ?[rv][%w_%s]-","[Ff][Vv]","[Nn][Ii]?[Cc][Gg]","[Nn]ot ?in ?[crs][%w_%s]-","[Nn]ot specifically in source",
 "[Vv]erification[%- _]failed",
 -- aliases for When
 "[Aa]s[ _]+of[ _]+when%??","[Aa]s[ _%-]+of%?","[Cc]larify date","[Dd]ate[ _]*needed","[Nn]eeds?[ _]+date","[Rr]ecently","[Ss]ince[ _]+when%??",
 "[Ww]HEN","[Ww]hen%??",
 -- aliases for Update
 "[Nn]ot[ _]*up[ _]*to[ _]*date","[Oo]u?[Tt][Dd]","[Oo]ut[%- _]*o?f?[%- _]*dated?","[Uu]pdate","[Uu]pdate[ _]+sect","[Uu]pdate[ _]+Watch",
 -- aliases for Pronunciation needed
 "[Pp]ronunciation%??[%- _]*n?e?e?d?e?d?","[Pp]ronounce","[Rr]equested[%- _]*pronunciation","[Rr]e?q?pron","[Nn]eeds[%- _]*pronunciation",
 -- Chart, including Chart/start etc.
 "[Cc]hart","[Cc]hart/[%w_%s]-",
 -- Cref and others
 "[Cc]ref2?","[Cc]note",
 -- Explain and others
 "[Ee]xplain","[Ff]urther[ ]*explanation[ ]*needed","[Ee]laboration[ ]*needed","[Ee]xplanation[ ]*needed",
 -- TOC templates
 "[Cc][Oo][Mm][Pp][Aa][Cc][Tt][ _]*[Tt][Oo][Cc][8]*[5]*","[Tt][Oo][Cc]","09[Aa][Zz]","[Tt][Oo][Cc][ ]*[Cc][Oo][Mm][Pp][Aa][Cc][Tt]","[Tt][Oo][Cc][ ]*[Ss][Mm][Aa][Ll][Ll]","[Cc][Oo][Mm][Pp][Aa][Cc][Tt][ _]*[Aa][Ll][Pp][Hh][Aa][Bb][Ee][Tt][Ii][Cc][ _]*[Tt][Oo][Cc]",
 "DEFAULTSORT:.-",
 "[Oo]ne[ _]+source",
 "[Cc]ontains[ _]+special[ _]+characters",
 "[Ii]nfobox[ _]+[Cc]hinese"
 }

 -- Regular expressions to match all block templates that are desirable in excerpts
 localwantedBlockTemplates={
 "[Bb]asketball[ _]roster[ _]header",
 "[Cc]abinet[ _]table[^|}]*",
 "[Cc]hart[^|}]*",
 "[Cc]lear",
 "[Cc]ol[%- es][^|}]*",-- all abbreviated column templates without excessively matching ({{col-2}}, {{colend}}, etc.)
 "[Cc]olumn[^|}]*",-- all other column templates
 "COVID-19[ _]pandemic[ _]data[^|}]*",
 "[Cc]ycling[ _]squad[^|}]*",
 "[Dd]ynamic[ _]list",
 "[Ee]lection[ _]box[^|}]*",
 "[Gg]allery",
 "[Gg]raph[^|}]*",
 "[Hh]idden",
 "[Hh]istorical[ _]populations",
 "[Ll]egend[ _]inline",
 "[Pp]lainlist",
 "[Pp]layer[^|}]*",
 "[Ss]eries[ _]overview",
 "[Ss]ide[ _]box",
 "[Ss]witcher",
 "[Tt]ree[ _]chart[^|}]*",
 "[Tt]elevision[ _]ratings[ _]graph"
 }

 -- Regular expressions to match non-free file templates
 localnonFreeFileTemplates={
 "[Nn]on%-free",
 }

 localTranscluder=require("Module:Transcluder")
 localescapeString=require("Module:String")._escapePattern
 localyesno=require('Module:Yesno')
 localp={}

 -- Helper function to test for truthy and falsy values
 localfunctionis(value)
 ifnotvalueorvalue==""orvalue=="0"orvalue=="false"orvalue=="no"then
 returnfalse
 end
 returntrue
 end

 -- Error handling function
 -- Throws a Lua error or returns an empty string if error reporting is disabled
 localerrors=true-- show errors by default
 localfunctionluaError(message,value)
 ifnotis(errors)thenreturn''end-- error reporting is disabled
 message=errorMessages[message]ormessageor''
 message=mw.ustring.format(message,value)
 error(message,2)
 end

 -- Error handling function
 -- Returns a wiki friendly error or an empty string if error reporting is disabled
 localfunctionwikiError(message,value)
 ifnotis(errors)thenreturn''end-- error reporting is disabled
 message=errorMessages[message]ormessageor''
 message=mw.ustring.format(message,value)
 message=errorMessages.prefix..message
 ifmw.title.getCurrentTitle().isContentPagethen
 localerrorCategory=mw.title.new(errorCategory,'Category')
 iferrorCategorythenmessage=message..'[['..errorCategory.prefixedText..']]'end
 end
 message=mw.html.create('div'):addClass('error'):wikitext(message)
 returnmessage
 end

 -- Helper function to match from a list regular expressions
 -- Like so: match pre..list[1]..post or pre..list[2]..post or ...
 localfunctionmatchAny(text,pre,list,post,init)
 localmatch={}
 fori=1,#listdo
 match={mw.ustring.match(text,pre..list[i]..post,init)}
 ifmatch[1]thenreturnunpack(match)end
 end
 returnnil
 end

 -- Helper function to convert imagemaps into standard images
 localfunctionconvertImageMap(imagemap)
 localimage=matchAny(imagemap,"[>\n]%s*",fileNamespaces,"[^\n]*")
 ifimagethen
 return"<!--imagemap-->[["..mw.ustring.gsub(image,"[>\n]%s*","",1).."]]"
 else
 return""-- remove entire block if image can't be extracted
 end
 end

 -- Helper function to convert a comma-separated list of numbers or min-max ranges into a list of booleans
 -- For example: "1,3-5" to {1=true,2=false,3=true,4=true,5=true}
 localfunctionnumberFlags(str)
 ifnotstrthenreturn{}end
 localflags={}
 localranges=mw.text.split(str,",")-- parse ranges: "1,3-5" to {"1","3-5"}
 for_,rinpairs(ranges)do
 localmin,max=mw.ustring.match(r,"^%s*(%d+)%s*[-–—]%s*(%d+)%s*$")-- "3-5" to min=3 max=5
 ifnotmaxthenmin,max=mw.ustring.match(r,"^%s*((%d+))%s*$")end-- "1" to min=1 max=1
 ifmaxthen
 forp=min,maxdoflags[p]=trueend
 end
 end
 returnflags
 end

 -- Helper function to convert template arguments into an array of arguments fit for get()
 localfunctionparseArgs(frame)
 localargs={}
 forkey,valueinpairs(frame:getParent().args)doargs[key]=valueend
 forkey,valueinpairs(frame.args)doargs[key]=valueend-- args from a Lua call have priority over parent args from template
 args.paraflags=numberFlags(args["paragraphs"]or"")-- parse paragraphs: "1,3-5" to {"1","3-5"}
 args.fileflags=numberFlags(args["files"]or"")-- parse file numbers
 returnargs
 end

 -- simulate {{Airreg}} without the footnote, given "N|485US|," or similar
 localfunctionairreg(p)
 locals=mw.text.split(p,"%s*|%s*")
 ifs[1]~="N"ands[1]~="HL"ands[1]~="JA"thens[1]=s[1].."-"end
 returntable.concat(s,"")
 end

 -- Helper function to remove unwanted templates and pseudo-templates such as #tag:ref and DEFAULTSORT
 localfunctionstripTemplate(t)
 -- If template is unwanted then return "" (gsub will replace by nothing), else return nil (gsub will keep existing string)
 ifmatchAny(t,"^{{%s*",unwantedInlineTemplates,"%s*%f[|}]")thenreturn""end

 -- If template is wanted but produces an unwanted reference then return the string with |Note=, |ref or |shortref removed
 localnoRef=mw.ustring.gsub(t,"|%s*Note%s*=.-%f[|}]","")
 noRef=mw.ustring.gsub(noRef,"|%s*ref%s*%f[|}]","")
 noRef=mw.ustring.gsub(noRef,"|%s*shortref%s*%f[|}]","")

 -- If a wanted template has unwanted nested templates, purge them too
 noRef=mw.ustring.sub(noRef,1,2)..mw.ustring.gsub(mw.ustring.sub(noRef,3),"%b{}",stripTemplate)

 -- Hide pipes in wikilinks for the next bit of processing
 noRef=mw.ustring.gsub(noRef,"%[(%b[])%]",function(s)
 return"["..mw.ustring.gsub(s,"|","27円_PIPE_27円").."]"
 end)

 -- Replace {{audio}} by its text parameter: {{Audio|Foo.ogg|Bar}} → Bar
 noRef=mw.ustring.gsub(noRef,"^{{%s*[Aa]udio.-|.-|(.-)%f[|}].*","%1")

 -- Replace {{Nihongo foot}} by its text parameter: {{Nihongo foot|English|英語|eigo}} → English
 noRef=mw.ustring.gsub(noRef,"^{{%s*[Nn]ihongo[ _]+foot%s*|(.-)%f[|}].*","%1")

 -- Replace {{Airreg}} by its text parameter: {{Airreg|N|485US|,}} → N485US,
 noRef=mw.ustring.gsub(noRef,"^{{%s*[Aa]irreg%s*|%s*(.-)}}",airreg)

 -- Bring back the hidden wikilink pipes
 noRef=mw.ustring.gsub(noRef,"27円_PIPE_27円","|")

 ifnoRef~=tthenreturnnoRefend

 returnnil-- not an unwanted template: keep
 end

 -- Get a page's content, following redirects
 -- Also returns the page name, or the target page name if a redirect was followed, or false if no page found
 -- For file pages, returns the content of the file description page
 localfunctiongetContent(page)
 localtitle=mw.title.new(page)
 ifnottitlethenreturnfalse,falseend

 localtarget=title.redirectTarget
 iftargetthentitle=targetend

 returntitle:getContent(),title.prefixedText
 end

 -- Get the tables only
 localfunctiongetTables(text,options)
 localtables={}
 forcandidateinmw.ustring.gmatch(text,"%b{}")do
 ifmw.ustring.sub(candidate,1,2)=='{|'then
 table.insert(tables,candidate)
 end
 end
 returntable.concat(tables,'\n')
 end

 -- Get the lists only
 localfunctiongetLists(text,options)
 locallists={}
 forlistinmw.ustring.gmatch(text,"\n[*#][^\n]+")do
 table.insert(lists,list)
 end
 returntable.concat(lists,'\n')
 end

 -- Check image for suitability
 localfunctioncheckImage(image)
 iftype(image)=="table"then
 --Infobox image. Pass in a quick string equivilant of the image, since we should still check it for things like non-free files
 returncheckImage("[[File:"..image.file.."]]")
 end
 localpage=matchAny(image,"",fileNamespaces,"%s*:[^|%]]*")-- match File:(name) or Image:(name)
 ifnotpagethenreturnfalseend

 -- Limit to image types: .gif, .jpg, .jpeg, .png, .svg, .tiff, .xcf (exclude .ogg, audio, etc.)
 ifnotmatchAny(page,"%.",fileTypes,"%s*$")thenreturnfalseend

 -- Check the local wiki
 localfileDescription,fileTitle=getContent(page)-- get file description and title after following any redirect
 ifnotfileTitleorfileTitle==""thenreturnfalseend-- the image doesn't exist

 -- Check Commons
 ifnotfileDescriptionorfileDescription==""then
 localframe=mw.getCurrentFrame()
 fileDescription=frame:preprocess("{{"..fileTitle.."}}")
 end

 -- Filter non-free images
 ifnotfileDescriptionorfileDescription==""ormatchAny(fileDescription,"",nonFreeFileTemplates,"")then
 returnfalse
 end

 returntrue
 end

 -- Attempt to parse [[File:...]] or [[Image:...]], either anywhere (start=false) or at the start only (start=true)
 localfunctionparseImage(text,start)
 localstartre=""
 ifstartthenstartre="^"end-- a true flag restricts search to start of string
 localimage=matchAny(text,startre.."%[%[%s*",fileNamespaces,"%s*:.*")-- [[File: or [[Image: ...
 ifimagethen
 image=mw.ustring.match(image,"%b[]%s*")-- matching [[...]] to handle wikilinks nested in caption
 end
 returnimage
 end

 -- Returns the file name and the arg data of the file if it exists
 localfunctionextractFileData(str,notmultiline)
 localreg="^%[?%[?%a-:([^{|]+)(.-)%]?%]?$"
 localname,args,_=mw.ustring.match(str,reg)
 ifnamethen
 returnname,args
 else
 returnstr,""--Default fallback
 end
 end

 --Modifies an image's parameters, automatically fixing related parameters in the process
 localfunctionmodifyImage(image,fileArgs)
 iftype(image)=="table"then
 --Pass in a dummy string version and use that to handle modification
 localnewversion=modifyImage("[[File:"..image.file..string.gsub(image.args,"{{!}}","|").."]]",fileArgs)
 --Since we know the format is strictly controlled, we can do a lazy sub grab for the args
 image.args=string.sub(newversion,8+#image.file,-3)
 returnimage
 end
 iffileArgsthen
 for_,filearginpairs(mw.text.split(fileArgs,"|"))do-- handle fileArgs=left|border etc.
 localfa=mw.ustring.gsub(filearg,"=.*","")-- "upright=0.75" → "upright"
 localgroup={fa}-- group of "border" is ["border"]...
 for_,ginpairs(imageParams)do
 for_,ainpairs(g)do
 iffa==athengroup=gend-- ...but group of "left" is ["right", "left", "center", "centre", "none"]
 end
 end
 for_,ainpairs(group)do
 image=mw.ustring.gsub(image,"|%s*"..a.."%f[%A]%s*=[^|%]]*","")-- remove "|upright=0.75" etc.
 image=mw.ustring.gsub(image,"|%s*"..a.."%s*([|%]])","%1")-- replace "|left|" by "|" etc.
 end
 image=mw.ustring.gsub(image,"([|%]])","|"..filearg.."%1",1)-- replace "|" by "|left|" etc.
 end
 end
 image=mw.ustring.gsub(image,"(|%s*%d*x?%d+%s*px%s*.-)|%s*%d*x?%d+%s*px%s*([|%]])","%1%2")-- double px args
 returnimage
 end

 -- Turns a template's file table into a [[File:...]] string
 localfunctionformatTemplateImage(image,allowFancy)
 --Certain positional elements may need to apply to the containing infobox, and not the file itself, so we should check that here
 ifis(image.caption)andallowFancythen--Will be displayed like an infobox
 localalignment=
 (string.find(image.args,"|left")and"left")
 or(string.find(image.args,"|center")orstring.find(image.args,"|centre"))and"center"
 or"right"
 modifyImage(image,"none")--Remove all positioning elements from the image
 modifyImage(image,"frameless")
 localargs=image.args
 args=string.gsub(args,"|thumb","")--Don't allow using |thumb in this mode

 returnmw.text.unstrip(mw.getCurrentFrame():expandTemplate({
 title="Image frame",
 args={
 content="[[File:"..image.file..args.."]]",caption='<div class="center">'..image.caption.."</div>",
 align=alignment,["max-width"]=300,mode="scrollable"
 }
 })).."\n"
 else
 localcaptionText=(is(image.caption)and"|"..image.caption)or""
 return"[[File:"..image.file..captionText..image.args.."]]\n"
 end
 end

 -- Attempts to construct a [[File:...]] block from {{infobox ... |image= ...}} or other templates
 localfunctiongetTemplateImages(text)
 localhasNamedArgs=mw.ustring.find(text,"|")andmw.ustring.find(text,"=")
 ifnothasNamedArgsthenreturnnilend-- filter out any template that obviously doesn't contain an image

 -- ensure image map is captured, while removing anything beyond it
 text=mw.ustring.gsub(text,'<!%-%-imagemap%-%->(%[%b[]%])[^|]+','|imagemap=%1')

 -- filter through parameters for image related ones
 localimages={}
 localparameters,_,parameterOrder=Transcluder.getParameters(text)

 --Search all template parameters for file-like objects
 localpositionalImages={}
 localposition=1
 for_,keyinipairs(parameterOrder)do
 position=position+1--Cant rely on ipairs due to potentially weird manipulation later
 localvalue=parameters[key]
 ifis(value)then--Ensure its not empty
 ifstring.sub(value,1,2)=="{{"andstring.sub(value,-2,-1)=="}}"then--Template in a template
 --Extract files from the template and insert files if any appear
 localinternalImages=getTemplateImages(value)or{}
 localinitialPosition=position
 forindex,imageinipairs(internalImages)do
 positionalImages[initialPosition+index]=image--Still positional, technically
 position=position+1--Advance our own counter to avoid overlap
 end
 else
 ifmatchAny(key,"",captionParams,"%s*")then
 --Caption-like parameter name, try to associate it with an image
 localscanPosition=position
 whilescanPosition>0do
 scanPosition=scanPosition-1
 localimage=positionalImages[scanPosition]
 ifimageandimage.caption==""then
 image.caption=mw.getCurrentFrame():preprocess(value)--Assign caption to most recently defined image
 break
 end
 end

 elseifmatchAny(value,"%.",fileTypes,"%s*$")then
 --File-like value, assume its an image
 localfilename,fileargs=extractFileData(value)
 positionalImages[position]={file=filename,caption="",args=fileargs}

 elseifmw.ustring.match(key,"[Ii][Mm][Aa][Gg][Ee]")ormw.ustring.match(key,"[Pp][Hh][Oo][Tt][Oo]")ormw.ustring.match(key,"[Ss][Yy][Mm][Bb][Oo][Ll]")then
 --File-like parameter name, assume its an image after some scrutinization
 localkeyLower=string.lower(key)
 ifstring.find(keyLower,"caption")
 orstring.find(keyLower,"size")orstring.find(keyLower,"width")
 orstring.find(keyLower,"upright")
 orstring.find(keyLower,"alt")then--Argument is defining image settings, not an image
 --Do nothing for now
 --TODO: we really should extract some of this for later use
 else
 localfilename,fileargs=extractFileData(value)
 positionalImages[position]={file=filename,caption="",args=fileargs}
 end
 end
 end--End of "Is template in template" check
 end--End of "is(value)" check
 end

 --Append entries from positionalImages into the main images table
 fori=1,positiondo
 localvalue=positionalImages[i]
 ifvaluethen
 table.insert(images,value)
 end
 end

 returnimages
 end

 -- a basic parser to trim down extracted wikitext
 -- @param text : Wikitext to be processed
 -- @param options : A table of options...
 -- options.paraflags : Which number paragraphs to keep, as either a string (e.g. '1,3-5') or a table (e.g. {1=true,2=false,3=true,4=true,5=true}. If not present, all paragraphs will be kept.
 -- options.fileflags : table of which files to keep, as either a string (e.g. '1,3-5') or a table (e.g. {1=true,2=false,3=true,4=true,5=true}
 -- options.fileargs : args for the [[File:]] syntax, such as 'left'
 --			options.filesOnly : only return the files and not the prose
 localfunctionparse(text,options)
 localallParagraphs=true-- keep all paragraphs?
 ifoptions.paraflagsthen
 iftype(options.paraflags)~="table"thenoptions.paraflags=numberFlags(options.paraflags)end
 for_,vinpairs(options.paraflags)do
 ifvthenallParagraphs=falseend-- if any para specifically requested, don't keep all
 end
 end
 ifis(options.filesOnly)then
 allParagraphs=false
 options.paraflags={}
 end

 localmaxfile=0-- for efficiency, stop checking images after this many have been found
 ifoptions.fileflagsthen
 iftype(options.fileflags)~="table"thenoptions.fileflags=numberFlags(options.fileflags)end
 fork,vinpairs(options.fileflags)do
 ifvandk>maxfilethenmaxfile=kend-- set maxfile = highest key in fileflags
 end
 end

 localfileArgs=options.fileargsandmw.text.trim(options.fileargs)
 iffileArgs==''thenfileArgs=nilend
 localdoFancyFiles=yesno(options.doFancyFiles)
 ifdoFancyFiles==nilthendoFancyFiles=trueend

 localleadStart=nil-- have we found some text yet?
 localt=""-- the stripped down output text
 localfileText=""-- output text with concatenated [[File:Foo|...]]\n entries
 localfiles=0-- how many images so far
 localparas=0-- how many paragraphs so far
 localstartLine=true-- at the start of a line (no non-spaces found since last \n)?

 text=mw.ustring.gsub(text,"^%s*","")-- remove initial white space

 -- Add named files
 localf=options.files
 iffandmw.ustring.match(f,"[^%d%s%-,]")then-- filename rather than number list
 f=mw.ustring.gsub(f,"^%s*File%s*:%s*","",1)
 f=mw.ustring.gsub(f,"^%s*Image%s*:%s*","",1)
 f="[[File:"..f.."]]"
 f=modifyImage(f,"thumb")
 f=modifyImage(f,fileArgs)
 ifcheckImage(f)thenfileText=fileText..f.."\n"end
 end

 repeat-- loop around parsing a template, image or paragraph
 localtoken=mw.ustring.match(text,"^%b{}%s*")orfalse-- {{Template}} or {| Table |}
 ifnotleadStartandnottokenthentoken=mw.ustring.match(text,"^%b<>%s*%b{}%s*")end-- allow <tag>{{template}} before lead has started

 localline=mw.ustring.match(text,"[^\n]*")
 iftokenandlineandmw.ustring.len(token)<mw.ustring.len(line)then-- template is followed by text (but it may just be other templates)
 line=mw.ustring.gsub(line,"%b{}","")-- remove all templates from this line
 line=mw.ustring.gsub(line,"%b<>","")-- remove all HTML tags from this line
 -- if anything is left, other than an incomplete further template or an image, keep the template: it counts as part of the line
 ifmw.ustring.find(line,"%S")andnotmatchAny(line,"^%s*",{"{{","%[%[%s*[Ff]ile:","%[%[%s*[Ii]mage:"},"")then
 token=nil
 end
 end

 iftokenthen-- found a template which is not the prefix to a line of text

 ifis(options.keepTables)andmw.ustring.sub(token,1,2)=='{|'then
 t=t..token-- keep tables

 elseifmw.ustring.sub(token,1,3)=='{{#'then
 t=t..token-- keep parser functions

 elseifleadStartthen-- lead has already started, so keep the template within the text, unless it's a whole line (navbox etc.)
 ifnotis(options.filesOnly)andnotstartLinethent=t..tokenend

 elseifmatchAny(token,"^{{%s*",wantedBlockTemplates,"%s*%f[|}]")then
 t=t..token-- keep wanted block templates

 elseiffiles<maxfilethen-- Check it for images if we need those, and then discard it
 localimages=getTemplateImages(token)or{}
 for_,imageinipairs(images)do
 iffiles<maxfileandcheckImage(image)then-- if image is found and qualifies (not a sound file, not non-free, etc.)
 files=files+1-- count the file, whether displaying it or not
 ifoptions.fileflagsandoptions.fileflags[files]then-- if displaying this image
 image=modifyImage(image,"thumb")
 image=modifyImage(image,fileArgs)
 fileText=fileText..formatTemplateImage(image,doFancyFiles)
 end
 end
 end
 end
 else-- the next token in text is not a template
 token=parseImage(text,true)
 iftokenthen-- the next token in text looks like an image
 iffiles<maxfileandcheckImage(token)then-- if more images are wanted and this is a wanted image
 files=files+1
 ifoptions.fileflagsandoptions.fileflags[files]then
 localimage=token-- copy token for manipulation by adding |right etc. without changing the original
 image=modifyImage(image,fileArgs)
 fileText=fileText..image
 end
 end
 else-- got a paragraph, which ends at a file, image, blank line or end of text
 localafterEnd=mw.ustring.len(text)+1
 localblankPosition=mw.ustring.find(text,"\n%s*\n")orafterEnd-- position of next paragraph delimiter (or end of text)
 localendPosition=math.min(-- find position of whichever comes first: [[File:, [[Image: or paragraph delimiter
 mw.ustring.find(text,"%[%[%s*[Ff]ile%s*:")orafterEnd,
 mw.ustring.find(text,"%[%[%s*[Ii]mage%s*:")orafterEnd,
 blankPosition)
 token=mw.ustring.sub(text,1,endPosition-1)
 ifblankPosition<afterEndandblankPosition==endPositionthen-- paragraph ends with a blank line
 token=token..mw.ustring.match(text,"\n%s*\n",blankPosition)
 end
 localisHatnote=not(leadStart)andmw.ustring.sub(token,1,1)==':'
 ifnotisHatnotethen
 leadStart=leadStartormw.ustring.len(t)+1-- we got a paragraph, so mark the start of the lead section
 paras=paras+1
 ifallParagraphsor(options.paraflagsandoptions.paraflags[paras])thent=t..tokenend-- add if this paragraph wanted
 end
 end-- of "else got a paragraph"
 end-- of "else not a template"

 iftokenthentext=mw.ustring.sub(text,mw.ustring.len(token)+1)end-- remove parsed token from remaining text
 startLine=mw.ustring.find(token,"\n%s*$")-- will the next token be the first non-space on a line?
 untilnottextortext==""ornottokenortoken==""-- loop until all text parsed

 text=mw.ustring.gsub(t,"\n+$","")-- remove trailing line feeds, so "{{Transclude text excerpt|Foo}} more" flows on one line

 returnfileText..text
 end

 localfunctioncleanupText(text,options)
 text=mw.ustring.gsub(text,"<!%-%-.-%-%->","")-- remove HTML comments
 text=mw.ustring.gsub(text,"<[Nn][Oo][Ii][Nn][Cc][Ll][Uu][Dd][Ee]>.-</[Nn][Oo][Ii][Nn][Cc][Ll][Uu][Dd][Ee]>","")-- remove noinclude bits
 ifnotis(options.ignoreOnlyincludes)andmw.ustring.find(text,"[Oo][Nn][Ll][Yy][Ii][Nn][Cc][Ll][Uu][Dd][Ee]")then-- avoid expensive search if possible
 text=mw.ustring.gsub(text,"</[Oo][Nn][Ll][Yy][Ii][Nn][Cc][Ll][Uu][Dd][Ee]>.-<[Oo][Nn][Ll][Yy][Ii][Nn][Cc][Ll][Uu][Dd][Ee]>","")-- remove text between onlyinclude sections
 text=mw.ustring.gsub(text,"^.-<[Oo][Nn][Ll][Yy][Ii][Nn][Cc][Ll][Uu][Dd][Ee]>","")-- remove text before first onlyinclude section
 text=mw.ustring.gsub(text,"</[Oo][Nn][Ll][Yy][Ii][Nn][Cc][Ll][Uu][Dd][Ee]>.*","")-- remove text after last onlyinclude section
 end
 ifnotis(options.keepSubsections)then
 text=mw.ustring.gsub(text,"\n==.*","")-- remove first ==Heading== and everything after it
 text=mw.ustring.gsub(text,"^==.*","")-- ...even if the lead is empty
 end
 ifnotis(options.keepRefs)then
 text=mw.ustring.gsub(text,"<%s*[Rr][Ee][Ff][^>]-/%s*>","")-- remove refs cited elsewhere
 text=mw.ustring.gsub(text,"<%s*[Rr][Ee][Ff].->.-<%s*/%s*[Rr][Ee][Ff]%s*>","")-- remove refs
 text=mw.ustring.gsub(text,"{%b{}}",stripTemplate)-- remove unwanted templates such as references
 end
 text=mw.ustring.gsub(text,"<%s*[Ss][Cc][Oo][Rr][Ee].->.-<%s*/%s*[Ss][Cc][Oo][Rr][Ee]%s*>","")-- remove musical scores
 text=mw.ustring.gsub(text,"<%s*[Ii][Mm][Aa][Gg][Ee][Mm][Aa][Pp].->.-<%s*/%s*[Ii][Mm][Aa][Gg][Ee][Mm][Aa][Pp]%s*>",convertImageMap)-- convert imagemaps into standard images
 text=mw.ustring.gsub(text,"%s*{{%s*[Tt][Oo][Cc].-}}","")-- remove most common tables of contents
 text=mw.ustring.gsub(text,"%s*__[A-Z]*TOC__","")-- remove TOC behavior switches
 text=mw.ustring.gsub(text,"\n%s*{{%s*[Pp]p%-.-}}","\n")-- remove protection templates
 text=mw.ustring.gsub(text,"%s*{{[^{|}]*[Ss]idebar%s*}}","")-- remove most sidebars
 text=mw.ustring.gsub(text,"%s*{{[^{|}]*%-[Ss]tub%s*}}","")-- remove most stub templates
 text=mw.ustring.gsub(text,"%s*%[%[%s*:?[Cc]ategory:.-%]%]","")-- remove categories
 text=mw.ustring.gsub(text,"^:[^\n]+\n","")-- remove DIY hatnote indented with a colon
 returntext
 end

 -- Parse a ==Section== from a page
 localfunctiongetSection(text,section,mainOnly)
 localescapedSection=mw.ustring.gsub(mw.uri.decode(section),"([%^%$%(%)%%%.%[%]%*%+%-%?])","%%%1")-- %26 → & etc, then ^ → %^ etc.
 locallevel,content=mw.ustring.match(text.."\n","\n(==+)%s*"..escapedSection.."%s*==.-\n(.*)")
 ifnotcontentthenreturnluaError("sectionNotFound",section)end
 localnextSection
 ifmainOnlythen
 nextSection="\n==.*"-- Main part of section terminates at any level of header
 else
 nextSection="\n=="..mw.ustring.rep("=?",#level-2).."[^=].*"-- "===" → "\n===?[^=].*", matching "==" or "===" but not "===="
 end
 content=mw.ustring.gsub(content,nextSection,"")-- remove later sections with headings at this level or higher
 ifmw.ustring.match(content,"^%s*$")thenreturnluaError("sectionEmpty",section)end
 returncontent
 end

 -- Parse a <section begin="Name of the fragment">
 -- @todo Implement custom parsing of fragments rather than relying on #lst
 localfunctiongetFragment(page,fragment)
 localframe=mw.getCurrentFrame()
 localtext=frame:callParserFunction('#lst',page,fragment)
 ifmw.ustring.match(text,"^%s*$")thenreturnluaError("fragmentEmpty",fragment)end
 returntext
 end

 -- Remove unmatched <tag> or </tag> tags
 localfunctionfixTags(text,tag)
 localstartCount=0
 foriinmw.ustring.gmatch(text,"<%s*"..tag.."%f[^%w_].->")dostartCount=startCount+1end

 localendCount=0
 foriinmw.ustring.gmatch(text,"</"..tag.."%s*>")doendCount=endCount+1end

 ifstartCount>endCountthen-- more <tag> than </tag>: remove the last few <tag>s
 locali=0
 text=mw.ustring.gsub(text,"<%s*"..tag.."%f[^%w_].->",function(t)
 i=i+1
 ifi>endCountthenreturn""elsereturnnilend
 end)-- "end" here terminates the anonymous replacement function(t) passed to gsub
 elseifendCount>startCountthen-- more </tag> than <tag>: remove the first few </tag>s
 text=mw.ustring.gsub(text,"</"..tag.."%s*>","",endCount-startCount)
 end
 returntext
 end

 localfunctionfixTemplates(text)
 repeat-- hide matched {{template}}s including nested templates
 localt=text
 text=mw.ustring.gsub(text,"{(%b{})}","27円{27円%127円}27円")-- {{sometemplate}} → E{E{sometemplate}E}E where E represents escape
 text=mw.ustring.gsub(text,"(< *math[^>]*>[^<]-)}}(.-< */math *>)","%1}27円}27円%2")-- <math>\{sqrt\{hat{x}}</math> → <math>\{sqrt\{hat{x}E}E</math>
 untiltext==t
 text=text.gsub(text,"([{}])%1[^27円].*","")-- remove unmatched {{, }} and everything thereafter, avoiding }E}E etc.
 text=text.gsub(text,"([{}])%1$","")-- remove unmatched {{, }} at end of text
 text=mw.ustring.gsub(text,"27円","")-- unhide matched pairs: E{E{ → {{, etc.
 returntext
 end

 localfunctionfixTables(text)
 repeat-- hide matched {|tables|}s
 localt=text
 forpotentialTableinstring.gmatch(text,"\n%b{}")do
 ifstring.sub(potentialTable,1,3)=="\n{|"then
 localinnerContent=mw.ustring.sub(potentialTable,3,-2)
 text=mw.ustring.gsub(text,escapeString(potentialTable),"\n27円{27円"..mw.ustring.gsub(innerContent,"%%","%%%%").."27円}27円")
 -- {|sometable|} → E{E|sometable|E}E where E represents escape
 end
 end
 untiltext==t
 text=mw.ustring.gsub(text,"\n{|.*","")-- remove unmatched {| and everything after it
 text=mw.ustring.gsub(text,"27円","")-- unhide matched pairs: E{E| → {|, etc.
 returntext
 end

 localfunctionfixLinks(text)
 repeat-- hide matched [[wikilink]]s including nested links like [[File:Example.jpg|Some [[nested]] link.]]
 localt=text
 text=mw.ustring.gsub(text,"%[(%b[])%]","27円[27円%127円]27円")
 untiltext==t
 text=text.gsub(text,"([%[%]])%1[^27円].*","")-- remove unmatched [[ or ]] and everything thereafter, avoiding ]E]E etc.
 text=text.gsub(text,"([%[%]])%1$","")-- remove unmatched [[ or ]] at end of text
 text=mw.ustring.gsub(text,"27円","")-- unhide matched pairs: ]E]E → ]], etc.
 returntext
 end

 -- Replace the first call to each reference defined outside of the text for the full reference, to prevent undefined references
 -- Then prefix the page title to the reference names to prevent conflicts
 -- that is, replace <ref name="Foo"> for <ref name="Title of the article Foo">
 -- and also <ref name="Foo" /> for <ref name="Title of the article Foo" />
 -- also remove reference groups: <ref name="Foo" group="Bar"> for <ref name="Title of the article Foo">
 -- and <ref group="Bar"> for <ref>
 -- @todo The current regex may fail in cases with both kinds of quotes, like <ref name="Darwin's book">
 localfunctionfixRefs(text,page,full)
 ifnotfullthenfull=getContent(page)end
 localrefNames={}
 localrefName
 localrefBody
 localposition=1
 whileposition<mw.ustring.len(text)do
 refName,position=mw.ustring.match(text,"<%s*[Rr][Ee][Ff][^>]*name%s*=%s*[\"']?([^\"'>]+)[\"']?[^>]*/%s*>()",position)
 ifrefNamethen
 refName=mw.text.trim(refName)
 ifnotrefNames[refName]then-- make sure we process each ref name only once
 table.insert(refNames,refName)
 refName=mw.ustring.gsub(refName,"[%^%$%(%)%.%[%]%*%+%-%?%%]","%%%0")-- escape special characters
 refBody=mw.ustring.match(text,"<%s*[Rr][Ee][Ff][^>]*name%s*=%s*[\"']?%s*"..refName.."%s*[\"']?[^>/]*>.-<%s*/%s*[Rr][Ee][Ff]%s*>")
 ifnotrefBodythen-- the ref body is not in the excerpt
 refBody=mw.ustring.match(full,"<%s*[Rr][Ee][Ff][^>]*name%s*=%s*[\"']?%s*"..refName.."%s*[\"']?[^/>]*>.-<%s*/%s*[Rr][Ee][Ff]%s*>")
 ifrefBodythen-- the ref body was found elsewhere
 text=mw.ustring.gsub(text,"<%s*[Rr][Ee][Ff][^>]*name%s*=%s*[\"']?%s*"..refName.."%s*[\"']?[^>]*/?%s*>",refBody,1)
 end
 end
 end
 else
 position=mw.ustring.len(text)
 end
 end
 text=mw.ustring.gsub(text,"<%s*[Rr][Ee][Ff][^>]*name%s*=%s*[\"']?([^\"'>/]+)[\"']?[^>/]*(/?)%s*>",'<ref name="'..page..' %1" %2>')
 text=mw.ustring.gsub(text,"<%s*[Rr][Ee][Ff][^>]*group%s*=%s*[\"']?[^\"'>/]+[\"']%s*>",'<ref>')
 returntext
 end

 -- Replace the bold title or synonym near the start of the article by a wikilink to the article
 functionlinkBold(text,page)
 locallang=mw.language.getContentLanguage()
 localposition=mw.ustring.find(text,"'''"..lang:ucfirst(page).."'''",1,true)-- look for "'''Foo''' is..." (uc) or "A '''foo''' is..." (lc)
 ormw.ustring.find(text,"'''"..lang:lcfirst(page).."'''",1,true)-- plain search: special characters in page represent themselves
 ifpositionthen
 locallength=mw.ustring.len(page)
 text=mw.ustring.sub(text,1,position+2).."[["..mw.ustring.sub(text,position+3,position+length+2).."]]"..mw.ustring.sub(text,position+length+3,-1)-- link it
 else-- look for anything unlinked in bold, assumed to be a synonym of the title (e.g. a person's birth name)
 text=mw.ustring.gsub(text,"()'''(.-'*)'''",function(a,b)
 ifnotmw.ustring.find(b,"%[")then-- if not wikilinked
 return"'''[["..page.."|"..b.."]]'''"-- replace '''Foo''' by '''[[page|Foo]]'''
 else
 returnnil-- instruct gsub to make no change
 end
 end,1)-- "end" here terminates the anonymous replacement function(a, b) passed to gsub
 end
 returntext
 end

 -- Main function for modules
 localfunctionget(page,options)
 ifoptions.errorsthenerrors=options.errorsend

 ifnotpageorpage==""thenreturnluaError("noPage")end

 localtext
 page,section=mw.ustring.match(page,"([^#]+)#?([^#]*)")
 text,page=getContent(page)
 ifnotpagethenreturnluaError("noPage")end
 ifnottextthenreturnluaError("pageNotFound",page)end
 localfull=text-- save the full text for later

 ifis(options.fragment)then
 text=getFragment(page,options.fragment)
 end

 ifis(section)then
 text=getSection(text,section)
 end

 -- Strip text of all undersirables
 text=cleanupText(text,options)
 text=parse(text,options)

 -- Replace the bold title or synonym near the start of the article by a wikilink to the article
 text=linkBold(text,page)

 -- Remove '''bold text''' if requested
 ifis(options.nobold)thentext=mw.ustring.gsub(text,"'''","")end

 -- Keep only tables if requested
 ifis(options.tablesOnly)thentext=getTables(text)end

 -- Keep only lists if requested
 ifis(options.listsOnly)thentext=getLists(text)end

 -- Seek and destroy unterminated templates, tables, links and tags
 text=fixTemplates(text)
 text=fixTables(text)
 text=fixLinks(text)
 text=fixTags(text,"div")

 -- Fix broken references
 ifis(options.keepRefs)thentext=fixRefs(text,page,full)end

 -- Trim trailing newlines to avoid appending text weirdly
 text=mw.text.trim(text)

 -- Add (Full article...) link
 ifoptions.moreLinkTextthen
 text=text.." ('''[["..page.."|"..options.moreLinkText.."]]''')"
 end

 returntext
 end

 -- Main invocation function for templates
 localfunctionmain(frame)
 localargs=parseArgs(frame)
 localpage=args[1]
 localok,text=pcall(get,page,args)
 ifnotokthen
 text=errorMessages.prefix..text
 iferrorCategoryanderrorCategory~=''andmw.title.getCurrentTitle().isContentPagethen
 text=text..'[['..errorCategory..']]'
 end
 returnmw.html.create('div'):addClass('error'):wikitext(text)
 end
 returnframe:preprocess(text)
 end

 localfunctiongetMoreLinkText(more)
 localdefaultText="Full article..."-- default text, same as in [[Template:TFAFULL]]
 ifnotmoreormore==''then-- nil/empty => use default
 returndefaultText
 end
 ifnotyesno(more,true)then-- falsy values => suppress the link
 returnnil
 end
 returnmore
 end

 -- Shared invocation function used by templates meant for portals
 localfunctionportal(frame,template)
 localargs=parseArgs(frame)

 errors=args['errors']orfalse-- disable error reporting unless requested

 -- There should be at least one argument except with selected=Foo and Foo=Somepage
 if#args<1andnot(template=="selected"andargs[template]andargs[args[template]])then
 returnwikiError("noPage")
 end

 -- Figure out the page to excerpt
 localpage
 localcandidates={}

 iftemplate=="lead"then
 page=args[1]
 page=mw.text.trim(page)
 ifnotpageorpage==""thenreturnwikiError("noPage")end
 candidates={page}

 elseiftemplate=="selected"then
 localkey=args[template]
 localcount=#args
 iftonumber(key)then-- normalise article number into the range 1..#args
 key=key%count
 ifkey==0thenkey=countend
 end
 page=args[key]
 page=mw.text.trim(page)
 ifnotpageorpage==""thenreturnwikiError("noPage")end
 candidates={page}

 elseiftemplate=="linked"ortemplate=="listitem"then
 localsource=args[1]
 localtext,source=getContent(source)
 ifnotsourcethen
 returnwikiError("noPage")
 elseifnottextthen
 returnwikiError("noPage")
 end
 localsection=args.section
 ifsectionthen-- check relevant section only
 text=getSection(text,section)
 ifnottextthenreturnwikiError("sectionNotFound",section)end
 end
 -- Replace annotated links with real links
 text=mw.ustring.gsub(text,"{{%s*[Aa]nnotated[ _]link%s*|%s*(.-)%s*}}","[[%1]]")
 iftemplate=="linked"then
 forcandidateinmw.ustring.gmatch(text,"%[%[%s*([^%]|\n]*)")dotable.insert(candidates,candidate)end
 else-- listitem: first wikilink on a line beginning *, :#, etc. except in "See also" or later section
 text=mw.ustring.gsub(text,"\n== *See also.*","")
 forcandidateinmw.ustring.gmatch(text,"\n:*[%*#][^\n]-%[%[%s*([^%]|\n]*)")dotable.insert(candidates,candidate)end
 end

 elseiftemplate=="random"then
 forkey,valueinpairs(args)do
 ifvalueandtype(key)=="number"then
 table.insert(candidates,mw.text.trim(value))
 end
 end
 end

 -- Build an options array for the Excerpt module out of the arguments and the desired defaults
 localoptions={
 errors=args['errors']orfalse,
 fileargs=args['fileargs'],
 fileflags=numberFlags(args['files']),
 paraflags=numberFlags(args['paragraphs']),
 moreLinkText=getMoreLinkText(args['more']),
 keepSubsections=args['keepSubsections'],
 keepRefs=args['keepRefs'],
 nobold=args['nobold'],
 doFancyFiles=args['fancyfiles']
 }

 -- Select a random candidate and make sure its valid
 localtext
 localcandidateCount=#candidates
 ifcandidateCount>0then
 localcandidateKey=1
 localcandidateString
 localcandidateArgs
 ifcandidateCount>1thenmath.randomseed(os.time())end
 while(nottextortext=="")andcandidateCount>0do
 ifcandidateCount>1thencandidateKey=math.random(candidateCount)end-- pick a random candidate
 candidateString=candidates[candidateKey]
 ifcandidateStringandcandidateString~=""then
 -- We have page or [[page]] or [[page|text]], possibly followed by |opt1|opt2...
 page,candidateArgs=mw.ustring.match(candidateString,"^%s*(%[%b[]%])%s*|?(.*)")
 ifpageandpage~=""then
 page=mw.ustring.match(page,"%[%[([^|%]]*)")-- turn [[page|text]] into page, discarding text
 else-- we have page or page|opt...
 page,candidateArgs=mw.ustring.match(candidateString,"%s*([^|]*[^|%s])%s*|?(.*)")
 end
 -- candidate arguments (even if value is "") have priority over global arguments
 ifcandidateArgsandcandidateArgs~=""then
 for_,tinpairs(mw.text.split(candidateArgs,"|"))do
 localk,v=mw.ustring.match(t,"%s*([^=]-)%s*=(.-)%s*$")
 ifk=='files'thenoptions.fileflags=numberFlags(v)
 elseifk=='paragraphs'thenoptions.paraflags=numberFlags(v)
 elseifk=='more'thenargs.more=v
 elseoptions[k]=vend
 end
 end
 ifpageandpage~=""then
 localsection=mw.ustring.match(page,"[^#]+#([^#]+)")-- save the section
 text,page=getContent(page)-- make sure the page exists
 ifpageandpage~=""andtextandtext~=""then
 ifargs.nostubsthen
 localisStub=mw.ustring.find(text,"%s*{{[^{|}]*%-[Ss]tub%s*}}")
 ifisStubthentext=nilend
 end
 ifsectionandsection~=""then
 page=page..'#'..section-- restore the section
 end
 text=get(page,options)
 end
 end
 end
 table.remove(candidates,candidateKey)-- candidate processed
 candidateCount=candidateCount-1-- ensure that we exit the loop after all candidates are done
 end
 end
 ifnottextortext==""thenreturnwikiError("No valid pages found")end

 -- Store all candidates before processing
 localallCandidates={page}-- Include current page
 for_,candidateinpairs(candidates)do
 table.insert(allCandidates,candidate)
 end

 ifargs.showallthen
 localseparator=args.showall
 ifseparator==""thenseparator="{{clear}}{{hr}}"end
 -- Add list at the top for showall if list parameter is not present
 ifnotargs.listthen
 locallistText="{{collapse top|title={{resize|85%|List of articles in rotation}}|bg=var(--background-color-base, #fff)|fc=inherit}}{{hlist"
 for_,candidateinpairs(allCandidates)do
 ifmw.ustring.match(candidate,"%S")then
 listText=listText.."|[["..mw.text.trim(candidate).."]]"
 end
 end
 listText=listText.."}}\n{{collapse bottom}}\n"
 text=listText..text
 end
 for_,candidateinpairs(candidates)do
 localt=get(candidate,options)
 ift~=""then
 text=text..separator..t
 end
 end
 end

 -- Add a collapsed list of pages which might appear
 ifargs.listthen
 locallist=args.list
 iflist==""thenlist="Other articles"end
 text=text.."{{collapse top|title={{resize|85%|"..list.."}}|bg=var(--background-color-base, #fff)|fc=inherit}}{{hlist"
 for_,candidateinpairs(candidates)do
 ifmw.ustring.match(candidate,"%S")thentext=text.."|[["..mw.text.trim(candidate).."]]"end
 end
 text=text.."}}\n{{collapse bottom}}"
 end

 returnframe:preprocess(text)
 end

 -- Old invocation function used by {{Excerpt}}
 localfunctionexcerpt(frame)
 localargs=parseArgs(frame)

 -- Make sure the requested page exists
 localpage=args[1]orargs.articleorargs.sourceorargs.page
 ifnotpagethenreturnwikiError("noPage")end
 localtitle=mw.title.new(page)
 ifnottitlethenreturnwikiError("noPage")end
 iftitle.isRedirectthentitle=title.redirectTargetend
 ifnottitle.existsthenreturnwikiError("pageNotFound",page)end
 page=title.prefixedText

 -- Define some useful variables
 localsection=args[2]orargs.sectionormw.ustring.match(args[1],"[^#]+#([^#]+)")
 localtag=args.tagor'div'

 -- Define the HTML elements
 localblock=mw.html.create(tag):addClass('excerpt-block')
 ifis(args.indicator)thenblock:addClass('excerpt-indicator')end

 localstyle=frame:extensionTag{name='templatestyles',args={src='Excerpt/styles.css'}}

 localhatnote
 ifnotargs.nohatthen
 ifargs.thisthen
 hatnote=args.this
 elseifargs.indicatorthen
 hatnote='This is'
 elseifargs.only=='file'then
 hatnote='This file is'
 elseifargs.only=='file'then
 hatnote='These files are'
 elseifargs.only=='list'then
 hatnote='This list is'
 elseifargs.only=='lists'then
 hatnote='These lists are'
 elseifargs.only=='table'then
 hatnote='This table is'
 elseifargs.only=='tables'then
 hatnote='These tables are'
 else
 hatnote='This section is'
 end
 hatnote=hatnote..' an excerpt from '
 ifsectionthen
 hatnote=hatnote..'[['..page..'#'..section..'|'..page..' § '..section..']]'
 else
 hatnote=hatnote..'[['..page..']]'
 end
 hatnote=hatnote.."''"..'<span class="mw-editsection-like plainlinks"><span class="mw-editsection-bracket">[</span>['
 hatnote=hatnote..title:fullUrl('action=edit')..' edit'
 hatnote=hatnote..']<span class="mw-editsection-bracket">]</span></span>'.."''"
 hatnote=require('Module:Hatnote')._hatnote(hatnote,{selfref=true})orwikiError('Error generating hatnote')
 end

 -- Build the module options out of the template arguments and the desired defaults
 localoptions={
 fileflags=numberFlags(args['files']or1),
 paraflags=numberFlags(args['paragraphs']),
 filesOnly=is(args['only']=='file'orargs['only']=='files'),
 listsOnly=is(args['only']=='list'orargs['only']=='lists'),
 tablesOnly=is(args['only']=='table'orargs['only']=='tables'),
 keepTables=is(args['tables']ortrue),
 keepRefs=is(args['references']ortrue),
 keepSubsections=is(args['subsections']),
 nobold=notis(args['bold']),
 fragment=args['fragment']
 }

 -- Get the excerpt itself
 ifsectionthenpage=page..'#'..sectionend
 localok,excerpt=pcall(e.get,page,options)
 ifnotokthenreturnwikiError(excerpt)end
 excerpt="\n"..excerpt-- line break is necessary to prevent broken tables and lists
 ifmw.title.getCurrentTitle().isContentPagethenexcerpt=excerpt..'[[Category:Articles with excerpts]]'end
 excerpt=frame:preprocess(excerpt)
 excerpt=mw.html.create(tag):addClass('excerpt'):wikitext(excerpt)

 -- Combine and return the elements
 returnblock:node(style):node(hatnote):node(excerpt)
 end

 -- Entry points for templates
 functionp.main(frame)returnmain(frame)end
 functionp.lead(frame)returnportal(frame,"lead")end-- {{Transclude lead excerpt}} reads a randomly selected article linked from the given page
 functionp.linked(frame)returnportal(frame,"linked")end-- {{Transclude linked excerpt}} reads a randomly selected article linked from the given page
 functionp.listitem(frame)returnportal(frame,"listitem")end-- {{Transclude list item excerpt}} reads a randomly selected article listed on the given page
 functionp.random(frame)returnportal(frame,"random")end-- {{Transclude random excerpt}} reads any article (default for invoke with one argument)
 functionp.selected(frame)returnportal(frame,"selected")end-- {{Transclude selected excerpt}} reads the article whose key is in the selected= parameter
 functionp.excerpt(frame)returnexcerpt(frame)end-- {{Excerpt}} transcludes part of an article into another article

 -- Entry points for other Lua modules
 functionp.get(page,options)returnget(page,options)end
 functionp.getContent(page)returngetContent(page)end
 functionp.getSection(text,section)returngetSection(text,section)end
 functionp.getTables(text,options)returngetTables(text,options)end
 functionp.getLists(text,options)returngetLists(text,options)end
 functionp.parse(text,options)returnparse(text,options)end
 functionp.parseImage(text,start)returnparseImage(text,start)end
 functionp.parseArgs(frame)returnparseArgs(frame)end
 functionp.getTemplateImages(text)returngetTemplateImages(text)end
 functionp.checkImage(image)returncheckImage(image)end
 functionp.cleanupText(text,options)returncleanupText(text,options)end
 functionp.numberFlags(str)returnnumberFlags(str)end
 functionp.getMoreLinkText(more)returngetMoreLinkText(more)end

 returnp

AltStyle によって変換されたページ (->オリジナル) /