Wikipedia talk:Lua

Add topic
Active discussions

Generating unique IDsEdit

Here is the requirement: some template needs to assign ID attribute (e.g., in order to use mw-customtoggle-<unique-suffix>). Now, this template might appear multiple times in a page, and each one should have a unique ID (for practical reasons, and in order to have valid HTML). Is there a sane way to ensure that consecutive calls (from different invocations) to the same code will return different results? for obvious reasons, having multiple elements with same ID is not only "invalid html", but also dysfunctional. Did anyone encounter similar challenge before? i hope someone can show me i am stupid, and there's safe and simple way to do it. thanks, peace - קיפודנחש (aka kipod) (talk) 17:45, 18 February 2022 (UTC)

Use math.random( m, n ) to get pseudorandom number and modify it for the id. —  Jts1882 | talk  18:00, 18 February 2022 (UTC)
thanks for the advice, but unfortunately, it's not really good: the issue revolves around seeding, Math.random() reseeds on every call, which practically means it's not "pseudo random". if i could guarantee that each call will be executed in a different timeslice, it would work, but even then, the "pseudo random" is just a screen of smoke, and i could just as well use directly os.clock() modulo something.
by reseeding every time, random loses its randomness. calling mw.math.random directly also does not work - when not seeded, it always begins at the same spot. to see what i mean, visit User:קיפודנחש/sandbox: i created a tiny Module:Testrand to demonstrate how consecutive calls to math._random() can return the same value (when the clock did not tick between calls). this happens because each call re-seeds, using the clock, plus some slow moving counters.
admittedly, the parser is (currently) slow enough, such that on consecutive invocations the clock is "guaranteed" to move, but this approach is short-sighted.
allow me bore you with "old-timer" story (personal experience, but i searched and found a link which discusses it): somewhere in the 1980s and 90s, there was a popular development tool called Borland Pascal. now, this product was meant to run on ms-dos, IOW, with no operating system whatsoever for anything other than file access.
the lack of OS created a need for a "delay" library function (e.g., when you wanted to operate some hardware, like UART and such).
BP implemented "delay" in a very naïve and straightforward way, which was reasonable then and would be crazy now: they ran some loop with junk code (or maybe even empty) N number of times, based on the parameter. to translate the parameter of delay() in MS to the number of times the loop should run, a factor is needed, which depends on the speed of the machine.
so, as part of the initialization of the library, a "delay calibration" code was run: the loop was executed large number of times (~64K iirc), the RT clock was sampled before and after to determine the time it took, and divide 64K by the time to get the "delay factor" (so "delay" would execute the loop ms*factor times).
when computers became fast enough, the "delay calibration loop" started executing faster than the clock resolution, and started throwing "divide by zero" exception.
this happens only once, but unfortunately, this one time is during initialization, which basically meant that any program written in BP would fail to start on faster computers (at least, "fail to start reliably" - if you get lucky, your loop straddles a tick...). the sad part is the fact that it did not matter if you ever used or wanted to use "delay()" - vast majority of programs never did, and programmers who did not deal with hardware were typically not even aware of this !@#$% delay, but the "sudden death" affected everyone anyway.
luckily for me, i worked at a large enough company at the time, and we had access to the library source, which allowed me to patch the library (i could not simply remove the calibration, since i needed "delay" to work, as my thing did interface with hardware).
this story is only 12% relevant, but i enjoyed telling it, and i hope some of you enjoyed reading it. won't be surprised if some had first-hand acquaintance with it...
the moral of the story is, do not rely on clock ticks between calls your program makes - some day someone will build a machine fast enough, and you'll find the clock did not tick between the first and 2nd call. under the surface this means that math.random is deeply flawed, as my sandbox demonstrates (BTW, this can be easily fixed: keep a module-wise local variable and ensure that seeding only happens once per invocation).
going back to "random" (not in module math, but in scribuntu: mw.math.random): if it was possible to seed it once per wiki page parsing, such that consecutive calls continue to develop it without seeding, i was fine with going this route, even though there is no guarantee that N consecutve calls will return N distinct value for any N > 1.
however, scribuntu creates a fresh "sandbox" for each invocation, which means random should be seeded per each invocation, which only works when the servers are slow enough, or when mw code is inefficient enough to ensure at least one tick between invocations.
peace - קיפודנחש (aka kipod) (talk) 20:24, 18 February 2022 (UTC)
By design, different calls with the same parameters are supposed to be totally independent of each other so, for example, one section can be parsed without regard for what is in other sections. I think there should be some restricted method of defining page-global variables (for example, to say "use mdy date formats on this page"), but without that I don't think there is any way of guaranteeing different results with the same parameters. Johnuniq (talk) 22:33, 18 February 2022 (UTC)

Module:Random uses both os.time and os.clock to set the random seed on each invocation. os.clock returns the number of seconds of CPU time used so far to build the page, with a precision in microseconds. my test indicates this technique is reliable in generating unique IDs within the same page and will be until CPUs are at least 20x faster than they are now. Thparkth (talk) 21:01, 20 September 2022 (UTC)

Changing flag icon formats from .svg.png and .png to .svgEdit

Is there anyway to change formats of flag icons from .png and .svg.png to .svg if possible? Any specific code or module? Let me know. FireDragonValo (talk) 19:12, 13 May 2022 (UTC)

@FireDragonValo: What are you trying to fix? A file cannot be simply converted between formats using Lua modules. NguoiDungKhongDinhDanh 20:12, 13 May 2022 (UTC)
There are online converters though (e.g.); perhaps not a Lua module, but a script could semi-automate that (as in adding a 'convert to svg' link next to png images on the page, and maybe even kick-start the upload process, pre-filling the upload form with the details of the converted img). — Guarapiranga  00:47, 29 July 2022 (UTC)
@Guarapiranga Have you actually tried those converters? They do a terrible job, and you end up with something that looks like it was drawn by a 3-year-old. --Ahecht (TALK
) 13:35, 29 July 2022 (UTC)
I did use one; only once, and can't remember which. — Guarapiranga  22:49, 30 July 2022 (UTC)


So I decided to upgrade WP:USRANK, and again bit more than I could chew (who remembers this adventure a year ago?). I thought it would be interesting to bring out data scripters had already documented inside the {{infobox user script}} on their scripts' help page (like skins and browsers compatibility, status of development, etc.). So I endeavoured to revamp and overhaul the module:user scripts table (which was the outcome from last year's debacle) in its sandbox. It started to work (preview this version against my sandbox, for instance), until... I flew too high, and MW's Lua memory constraints melted my wings. If you care to look at the code, you'll see I'm fumbling in the dark side of Lua; I'm sure there must be smarter ways of declaring the variables and writing the subroutines. Are there? Cheers. Guarapiranga  05:57, 16 June 2022 (UTC)

Loops, variables and tablesEdit

I have a number of variables, let's say: v1, v2, v3 ... v10, which I want to perform the same set of operations on relating to a wikitable and then add each to a table. Now I could write

function p.main(frame)
    local t={}
    table.insert(t, v1)
    table.insert(t, v2)
    table.insert(t, v3)
    table.insert(t, v10)

Is there a way of using a function that will take the variable root name v, add an integer and pass that back so in a loop I can use to replace all the table.insert lines?

for N=1,10,1 do

Nthep (talk) 15:38, 20 June 2022 (UTC)

If it has global scope then the variable can be addressed as _G['v'..N], but should you be using an array v[1] ... v[10] instead of variables v1 ... v10? Certes (talk) 17:55, 20 June 2022 (UTC)
We should see the example you are working on as better procedures might be suggested. However, something like the following would answer the question.
local t = {}
for i, v in ipairs({v1, v2, v3, v4}) do
    v = operate(i, v)
    table.insert(t, v)
Johnuniq (talk) 23:24, 20 June 2022 (UTC)
Thanks. I don't have an example as yet but what I am considering is to create a template to create tables similar to the squad lists at 1936–37 Challenge Cup#Final but with a couple more fields dealing with numbers. TBH it is probably solvable using #switch etc but i find LUA easier to understand than expression syntax. What complicates it are things to do with the numbers are also the position names which differ depending on where in the world you are. So my thought was to take each position associate it with 2 names and 2 numbers and create a table row on that. So each row would have 5 parameters, position, home player, home number, away player and away number, then just loop through the required number of rows. Nthep (talk) 08:43, 21 June 2022 (UTC)
When you're ready, consider posting sample input and wanted output, keeping it very simple and short. Then there could be ideas on how to achieve that. Johnuniq (talk) 09:02, 21 June 2022 (UTC)
That sounds like a case where you want to be using tables, not numbered variables. If I were doing it, I would have the input be something like {{template_name|pos_1=|hplayer_1=|hnumber_1=|aplayer_1=|anumber1=|position_2=|...}} and then read that into a table:
local t = {}
for k, v in pairs(frame:getParent().args) do
    row = k:sub(k:find("_")+1, nil)
    column = k:sub(1,k:find("_")-1)
    if (t[row]) then
        t[row][column] = v
        t[row] = {[column] = v}
You would probably want a little more data validation than that, but in essence that will create a table containing numbered rows and named columns with the input. You can then use for i, v in ipairs(t) do to iterate over the rows in your table and call out each column by name, e.g. t[1].hplayer. --Ahecht (TALK
) 13:57, 21 June 2022 (UTC)
Thanks but I can't get this to work. You can see what I'm trying to achieve at Module:Rugby league match squad/sandbox. User:Nthep/sandbox10 is the page I'm calling it from. Nthep (talk) 22:04, 5 July 2022 (UTC)

Regardless of the specific question asked, I'd like to comment that having a set of variables named v1, v2, v3...v11 is usually not a good practice (this was very common when the leading programming language was fortran 4, thankfully those days are gone). Variables ideally have meaningful names, which indicate what do their values mean. Typically, vX like in the example all mean the same thing (and should better have more meaningful name than "v"), maybe at different data points. If this is the case, it's usually preferable to have one var, of type "table" to hold the values, indexed by some identification of the data point - can be 1,2,3 or 'china', 'russia', 'usa', or whatever.

Peace - קיפודנחש (aka kipod) (talk) 18:29, 31 July 2022 (UTC)

Mnemonic, we used to call'em back in the day. — Guarapiranga  01:13, 1 August 2022 (UTC)

Lua error / running scripts expired - Norodom Sihamoni pageEdit

Hello Team, may I please seek team's technical expertise and assistance. King Norodom Sihamoni's wikipedia page is experiencing this error in the references section, with error messages, "The time allocated for running scripts has expired. The time allocated for running scripts has expired. The time allocated for running scripts has expired.The time allocated for running scripts has expired", "The time allocated for running scripts has expired", " Lua error in Module:Citation/CS1/Date_validation at line 946: attempt to index field 'inv_local_long' (a nil value)." On the wikipedia app, the references appear fine, but on desktop version, it appears all strange. I have no idea how to fix it as Im not a technical person :( May I please seek support on this issue so this error is all remedied or will it be auto-remedied? Thanks team. Contributorthewise (talk) 13:22, 1 August 2022 (UTC)

Update 13:23 - oh wow, looks like it all fixed ? Not sure who did the fix - but thank you so much!! — Preceding unsigned comment added by Contributorthewise (talkcontribs) 13:24, 1 August 2022 (UTC)

Extension of Graph:Chart for step function?Edit

I didn't find a possiblity to create a true step function plot with the Template:Graph:Chart.

It is only possible to mimic it by a line plot with steep increases, but that graph has (almost) vertical lines that look "non-mathematican":

Or with his complex workaround:

{{Graph:Chart | width=400 | height=150 | xAxisTitle=X | yAxisTitle=Y | type=line | x=1,1.99,2,2.99,3,3.99,4,4.99,5,5.99 | y1=10,10 | y2=,,12,12 | y3=,,,,6,6 | y4=,,,,,,14,14 | y5=,,,,,,,,,2,2 | colors=SteelBlue,CornflowerBlue,CornflowerBlue,CornflowerBlue,CornflowerBlue | yAxisMin=0 }}

Myosci (talk) 08:35, 13 August 2022 (UTC)

well, you don't have to twist the values (1.99 instead of 2). it's legit to repeat x values for line graph.

 | width=400 | height=150
 | xAxisTitle=X
 | yAxisTitle=Y
 | type=line
 | x=1.00001,2,2,3,3,4,4,5,5,6
 | y=10,10,12,12,6,6,14,14,2,2
 | yAxisMin=0
 | colors=SteelBlue,CornflowerBlue,CornflowerBlue,CornflowerBlue,CornflowerBlue

note that i did use one "perverted" x value, for the first data point (1.00001). the reason for this is that the X axis legends behave a bit differently when all values are integers (see below). if any of the data points has non-integer X value, this perversion is not required.

same graph with all integer x values

peace - קיפודנחש (aka kipod) (talk) 00:01, 14 August 2022 (UTC)

Chinese date conversionEdit

Does Lua have a library that allow for conversion of dates such that one can enter 2024-01-01 (Gregorian New Year) and receive 2024-02-10 (Chinese New Year)? This is a moveable date based on the lunar cycle. -- GreenC 16:10, 24 August 2022 (UTC)

did you look at mw.language:formatDate ?
peace קיפודנחש (aka kipod) (talk) 16:28, 24 August 2022 (UTC)
I presume that you meant to link to mw.language:formatDate rather than formatNum. formatDate uses the same formatting (and so likely is the same code as) the #time parser function.
Trappist the monk (talk) 16:36, 24 August 2022 (UTC)
If the #time parser function doesn't have Chinese date conversions (it doesn't) then I doubt that MediaWiki has a separate Lua implementation of such a library. You might search module space; mayhaps someone has written something that will suit or that can be adapted. You might start with this search.
Trappist the monk (talk) 16:36, 24 August 2022 (UTC)
You might also pose this question at zh:Wikipedia talk:Lua.
Trappist the monk (talk) 16:39, 24 August 2022 (UTC)
I don't think there is such a library at Wikipedia. The navbox at the bottom of {{age}} attempts to show all relevant functions but it's not there. On the other hand, I seem to recall a template like this being deleted as unused. Searching finds Template:New Year's Eve (created February 2015, deleted January 2021). The creator is no longer active. I have no idea what this does, but the wikitext for the template was
{{ctime:x|{{{1|{{#time:Y|+8hours}}}}}|1|0}}<noinclude>[[Category:Chinese Traditional Festival]]<templatedata>
	"description": "To get the date of New Year's Eve",
	"params": {
		"1": {
			"aliases": [
			"label": "year",
			"description": "The year number",
			"type": "number"
Johnuniq (talk) 23:57, 24 August 2022 (UTC)

Using a Module:Wikidata function in LuaEdit

I would like to know how to translate the following line into a Lua command (feel free to refer me to a better method to get the correct data, if this module is inefficient):


Animal lover |666| 10:51, 19 September 2022 (UTC)

Does this do what you want?
local something_viewed = frame:callParserFunction ({name = '#invoke', args = {'Wikidata', 'ViewSomething', 'labels', 'en', 'value'}})
If you are going to use more than this one function there may be better ways of implementing this.
Trappist the monk (talk) 16:39, 19 September 2022 (UTC)
I only need to use it once, which I assign to a variable, if blank replace with a different value, and make a single use of this variable. In fact, the bigger context is:{{{name|{{#if:{{#invoke:Wikidata|ViewSomething|labels|en|value}}|{{#invoke:Wikidata|ViewSomething|labels|en|value}}|{{PAGENAMEBASE}}}}}}}. Animal lover |666| 19:20, 19 September 2022 (UTC)
@Animal lover 666 and Trappist the monk: Using callParserFunction to invoke a Lua module is inefficient, use require('Module:Wikidata').ViewSomething(frame) instead. However, ViewSomething is essentially just doing mw.wikibase.getEntity().labels.en.value, which is much slower than the proper way to get the label: mw.wikibase.getLabel(). See the mw.wikibase docs for more useful Lua functions. Dexxor (talk) 06:43, 20 September 2022 (UTC)