Modulo:mtwoimage

El Vikivortaro
Salti al navigilo Salti al serĉilo

Dokumentado por ĉi tiu modulo povas esti kreata ĉe Modulo:mtwoimage/dokumentado

--[===[

MODULE "MTWOIMAGE" (two images)

"eo.wiktionary.org/wiki/Modulo:mtwoimage" <!--2021-May-09-->
"id.wiktionary.org/wiki/Modul:mtwoimage"

Purpose: places one image or two images on the right side of the
         screen, 2 images will be arranged horizontally

Utilo: lokigas unu bildon aux du bildojn dekstre sur la
       ekrano, 2 bildoj estos arangxitaj horizontale

Manfaat: meletakkan satu atau dua gambar di ...

Syfte: placerar en eller tvaa bilder paa ...

Used by templates / Uzata far sxablonoj / Digunakan oleh templat:
- bildodek (EO) | gamkan (ID)

Required submodules / Bezonataj submoduloj / Submodul yang diperlukan:
- none

This module can accept parameters whether sent to itself (own frame) or
to the caller (caller's frame). If there is a parameter "caller=true"
on the own frame then that own frame is discarded in favor of the
caller's one.

Incoming: - 1...4 anonymous parameters
            - a) (1) image name
            - b) (2) image name and description
            - c) (2) two image names
            - d) (3) two image names and one description
            - e) (4) image name, description, image name, description
            Same rules apply to both image names and descriptions:
            - must be 2...108 octet:s long
            - must not contain double rectangular
              brackets ("[[" and "]]") nor "<center>" nor "[http"
          - 1 named parameter "duon=1" or "half=1" (acceptance
              depends on site language, reduces lengths by factor ca
              1.5 and areas by factor ca 2.25)
          - 3 hidden named parameters
            - "pagenameoverridetestonly="
            - "nsnumberoverridetestonly="
            - "nocat=true"

Returned: - one string with a HTML table or inline error message

To distinguish cases b) and c) both with 2 parameters the latter
parameter is analyzed in the following way:

if (less than 7 octet:s) then
  assume b)
  done
endif
loop (walk back from the end copying into a new string writing backwards too)
  if (length of copied text is 5) then
    assume b)
    exit loop and done
  endif
  pick char
  if (dot found) then
    exit loop
  endif
  if (other value than ASCII letter found) then
    assume b)
    exit loop and done
  endif
  keep UPPERcase, change lowercase to UPPERcase
  store char into new string backwards
endloop
if (new string is equal PNG BMP GIF JPG JPEG SVG) then
  assume c)
else
  assume b)
endif

The 5 input cases map onto 3 possible output cases and tables:

b) one image (two table rows each with one cell)
d) two images with a common description (two table rows, the upper one
   with two cells and the lower one with "colspan=2")
e) two images with two separate descriptions (2 table rows,
   each with 2 cells)

If no description is provided then {{PAGENAME}} is seized,
and a) maps to b) and c) maps to d).

The image syntax fed to the wiki parser used (see also string "strsizes") is
  [[File: (name) |center| (size) ]]
thus we do not use the description parameter. The reasons for doing so are:
* allow for a common description for the case d)
* avoid risk that a description like "999px" or similar breaks the layout
* reserve sufficient horizontal space for the text even if the image
  is high and very narrow

One image is showed with "size" parameter "240x240px" or reduced "160x160px",
two images with "240x160px" or reduced "160x120px".

]===]

local twoimage = {}

------------------------------------------------------------------------

---- CONSTANTS ----

------------------------------------------------------------------------

  -- uncommentable EO vs ID constant strings (core site-related features)

  local constrpriv = "eo"                 -- EO (privileged site language)
  -- local constrpriv = "id"                 -- ID (privileged site language)
  local constrkatp = "Kategorio:"         -- EO (good and bad tracking cat:s only)
  -- local constrkatp = "Kategori:"          -- ID (good and bad tracking cat:s only)

  -- constant table (transcoding table for X-surrogates, only needed for EO)

  local contabtransiltable = {}
  contabtransiltable[ 67] = 0xC488 -- CX
  contabtransiltable[ 99] = 0xC489 -- cx
  contabtransiltable[ 71] = 0xC49C -- GX
  contabtransiltable[103] = 0xC49D -- gx
  contabtransiltable[ 74] = 0xC4B4 -- JX
  contabtransiltable[106] = 0xC4B5 -- jx
  contabtransiltable[ 83] = 0xC59C -- SX
  contabtransiltable[115] = 0xC59D -- sx
  contabtransiltable[ 85] = 0xC5AC -- UX breve
  contabtransiltable[117] = 0xC5AD -- ux breve

  -- constant strings (error circumfixes)

  local constrelabg = '<span class="error"><b>'  -- lagom whining begin
  local constrelaen = '</b></span>'              -- lagom whining end
  local constrlaxhu = '&nbsp;&#91;&#93;&nbsp;'   -- lagom -> huge circumfix " [] "

  -- uncommentable EO vs ID string (caller name for error messages)

  -- this goes through "lffillname" and subsequently
  -- through "lfkodeosg", X-surrogates permitted

  local constrkoll = 'sxablono "bildodek"'  -- EO augmented name of the caller (semi-hardcoded, we do NOT peek it)
  -- local constrkoll = 'templat "gamkan"'     -- ID augmented name of the caller (semi-hardcoded, we do NOT peek it)

  -- uncommentable EO vs ID constant table (error messages)

  -- #E02...#E99, holes permitted (max 3 consecutive)
  -- note that #E00 and #E01 are NOT supposed to be included here
  -- separate "constrkoll" needed for "\\@"

  local contaberaroj = {}
  contaberaroj[2] = 'Erara uzo de \\@, legu gxian dokumentajxon'                                            -- EO #E02 number of params
  -- contaberaroj[2] = 'Penggunaan salah \\@, bacalah dokumentasinya'                                          -- ID #E02
  contaberaroj[3] = 'Erara uzo de \\@ pro transdonita signocxeno, estu 2...108 bitokoj'                     -- EO #E03 length and content
  -- contaberaroj[3] = 'Penggunaan salah \\@ oleh karena string datang, sebaiknya 2...108 oktet'               -- ID #E03
  contaberaroj[4] = 'Erara uzo de \\@ pro nomspaco, estu 0 (kapvorto) aux 102 (Aldono:)'                    -- EO #E04 ns
  -- contaberaroj[4] = 'Penggunaan salah \\@ oleh karena ruang nama, sebaiknya 0 (lema) atau 102 (Lampiran:)'  -- ID #E04

  -- constant table (HTML)

  -- note that we need "clear:right", not "clear:both" !!!

  local contabhtml = {}
  contabhtml[0] = '<table style="clear:right; float:right; margin:0 0 0.3em 0.3em; padding:0.2em; border:2px solid #909090;">'
  contabhtml[1] = '<td style="padding:0.2em;">' -- cell with image
  contabhtml[2] = '<td style="padding:0.2em; text-align:center;">' -- cell with text
  contabhtml[3] = '<td style="padding:0.2em; text-align:center;" colspan="2">' -- cell with common description
  contabhtml[4] = '</table>'

  -- uncommentable EO vs ID constant table (cat:s)

  local contabkatoj = {}
  contabkatoj = {"Kapvortaj pagxoj kun bildo","Aldonaj vortaraj pagxoj kun bildo"   ,"Erara uzo de sxablono (bildodek)" ,"Erara uzo de sxablono"   } -- EO
  -- contabkatoj = {"Halaman lema dengan gambar","Halaman lampiran kamus dengan gambar","Penggunaan salah templat (gamkan)","Penggunaan salah templat"} -- ID

  -- constant table (3 integers for preliminary parameter check)

  local contabparam = {}
  contabparam[0] = 1   -- minimal number of anon parameters
  contabparam[1] = 4   -- maximal number of anon parameters
  contabparam[2] = 160 -- maximal length of single para (min is hardcoded ONE)

------------------------------------------------------------------------

---- SPECIAL STUFF OUTSIDE MAIN FUNCTION ----

------------------------------------------------------------------------

---- VAR:S ----

local qbooguard = false  -- only for the guard test, pass to other var ASAP

---- GUARD AGAINST INTERNAL ERROR ----

if ((type(constrpriv)~="string") or (type(constrkatp)~="string") or (type(constrkoll)~="string")) then
  qbooguard = true
end--if

------------------------------------------------------------------------

---- MATH FUNCTIONS ----

------------------------------------------------------------------------

-- Local function MATHDIV

local function mathdiv (xdividend, xdivisor)
  local resultdiv = 0 -- DIV operator lacks in LUA :-(
  resultdiv = math.floor (xdividend / xdivisor)
  return resultdiv
end--function mathdiv

-- Local function MATHMOD

local function mathmod (xdividendo, xdivisoro)
  local resultmod = 0 -- MOD operator is "%" and bitwise AND operator lack too
  resultmod = xdividendo % xdivisoro
  return resultmod
end--function mathmod

------------------------------------------------------------------------

---- CONVERSION FUNCTIONS ----

------------------------------------------------------------------------

-- Local function LFNUMTO2DIGIT

-- This is needed for "HIGH LEVEL FUNCTIONS"\"lfbrewerror".

-- This sub depends on "MATH FUNCTIONS"\"mathdiv"
-- and "MATH FUNCTIONS"\"mathmod".

local function lfnumto2digit (numzerotoninetynine)
  local strtwodig = ''
  strtwodig = mathdiv(numzerotoninetynine,10) .. mathmod(numzerotoninetynine,10)
  return strtwodig
end--function lfnumto2digit

------------------------------------------------------------------------

---- STRING FUNCTIONS ----

------------------------------------------------------------------------

-- test whether char is an ASCII uppercase letter, return boolean

local function lftestuc (numkode)
  local booupperc = false
  booupperc = ((numkode>=65) and (numkode<=90))
  return booupperc
end--function lftestuc

------------------------------------------------------------------------

-- test whether char is an ASCII lowercase letter, return boolean

local function lftestlc (numcode)
  local boolowerc = false
  boolowerc = ((numcode>=97) and (numcode<=122))
  return boolowerc
end--function lftestlc

------------------------------------------------------------------------

---- HIGH LEVEL FUNCTIONS ----

------------------------------------------------------------------------

-- Local function LFBREWERROR

-- #E02...#E99, note that #E00 and #E01 are NOT supposed to be included here.

-- We need 3 const strings "constrelabg", "constrelaen",
-- "constrlaxhu" and const table "contaberaroj".

-- This sub depends on "CONVERSION FUNCTIONS"\"lfnumto2digit".

local function lfbrewerror (numerrorcode)
  local vardeskrip = 0
  local strytsux = '#E'
  vardeskrip = contaberaroj[numerrorcode] -- risk of type "nil"
  if (type(vardeskrip)=="string") then
    strytsux = strytsux .. lfnumto2digit(numerrorcode) .. ' ' .. vardeskrip
  else
    strytsux = strytsux .. '??'
  end--if
  strytsux = constrlaxhu .. constrelabg .. strytsux .. constrelaen .. constrlaxhu
  return strytsux
end--function lfbrewerror

------------------------------------------------------------------------

-- Local function LFCHKPARAM

-- Check whether a desc parameter is illegal.

local function lfchkparam (strinputstring)

  local numlongoo = 0
  local boobrottsligt = false -- return "true" if illegal

  numlongoo = string.len (strinputstring)
  boobrottsligt = ((numlongoo<2) or (numlongoo>108)) -- must be 2...108

  boobrottsligt = boobrottsligt or (string.find(strinputstring,"[[",1,true)~=nil)
  boobrottsligt = boobrottsligt or (string.find(strinputstring,"]]",1,true)~=nil)
  boobrottsligt = boobrottsligt or (string.find(strinputstring,"<center>",1,true)~=nil)
  boobrottsligt = boobrottsligt or (string.find(strinputstring,"[http",1,true)~=nil)

  return boobrottsligt

end--function lfchkparam

------------------------------------------------------------------------

-- Local function LFTESTFILE

-- Check whether parameter can be a filename ie name of a picture.

-- Example:
-- "blackhole.png" len = 13 (positions 1...13 ONE-based)
--  1234567890123  last dot at position 10 (ONE-based)
-- difference 3 (4 would be OK too)
-- seized substring comes from positions 11...13 (difference 2, length 3)

local function lftestfile (strparanometer)

  local strsubu = ''
  local numlen = 0
  local numchhar = 0
  local numiindeks = 0
  local boogotcee = false -- "false" is b) and "true" is c)

  while (true) do -- fake loop
    numlen = string.len (strparanometer)
    if (numlen<7) then
      break -- no way
    end--if
    numiindeks = numlen -- ONE-based counts down
    while (true) do -- inner loop
      if ((numiindeks+5)==numlen) then
        numiindeks = 0 -- F**K
        break -- inner loop -- no dot found, this is NOT a filename extension
      end--if
      numchhar = string.byte (strparanometer,numiindeks,numiindeks)
      if (numchhar==46) then
        break -- inner loop -- dot is here, do NOT store it
      end--if
      if ((lftestuc(numchhar)==false) and (lftestlc(numchhar)==false)) then
        numiindeks = 0 -- F**K
        break -- inner loop -- faulty value, this is NOT a filename extension
      end--if
      if (lftestlc(numchhar)) then
        numchhar = numchhar - 32
      end--if
      strsubu = string.char (numchhar) .. strsubu -- ueglstr
      numiindeks = numiindeks - 1 -- ONE-based counts down
    end--while -- inner loop
    if (numiindeks==0) then
      break -- this is NOT a filename extension
    end--if
    boogotcee = ((strsubu=="PNG") or (strsubu=="BMP") or (strsubu=="GIF") or (strsubu=="JPG") or (strsubu=="JPEG") or (strsubu=="SVG"))
    break -- finally
  end--while -- fake loop

  return boogotcee

end--function lftestfile

------------------------------------------------------------------------

-- Local function LFFILLNAME

-- Replace placeholder "\@" "\\@" by augmented name of the caller.

-- The caller name is submitted to us as a parameter thus we
-- do NOT access any constants and do NOT have to peek it either.

local function lffillname (strmessage,strcaller)

  local strhasill = ''
  local numstrloen = 0
  local numindfx = 1 -- ONE-based
  local numcjar = 0
  local numcjnext = 0

  numstrloen = string.len (strmessage)

  while (true) do
    if (numindfx>numstrloen) then
      break -- empty input is useless but cannot cause major harm
    end--if
    numcjar = string.byte (strmessage,numindfx,numindfx)
    numindfx = numindfx + 1
    numcjnext = 0
    if (numindfx<=numstrloen) then
      numcjnext = string.byte (strmessage,numindfx,numindfx)
    end--if
    if ((numcjar==92) and (numcjnext==64)) then
      strhasill = strhasill .. strcaller -- invalid input is caller's risk
      numindfx = numindfx + 1 -- skip 2 octet:s of the placeholder
    else
      strhasill = strhasill .. string.char (numcjar)
    end--if
  end--while

  return strhasill

end--function lffillname

------------------------------------------------------------------------

-- Local function LFKODEOSG

-- Transcode X-surrogates (without "\", thus for example "kacxo",
-- NOT "ka\cxo") to UTF-8 cxapeloj in a string (EO only).

-- Input  : * strsurr -- string (empty is useless but can't cause major harm)

-- Output : * strcxapeloj

-- We need const table "contabtransiltable".

-- This sub depends on "MATH FUNCTIONS"\"mathdiv"
-- and "MATH FUNCTIONS"\"mathmod".

local function lfkodeosg (strsurr)
  local varpeek = 0
  local strcxapeloj = ''
  local numinputl = 0
  local numininx = 0 -- ZERO-based source index
  local numknark = 0 -- current char (ZERO is NOT valid)
  local numknarp = 0 -- previous char (ZERO is NOT valid)
  local numlow = 0
  local numhaj = 0
  numinputl = string.len(strsurr)
  while (true) do
    if (numininx==numinputl) then
      break
    end--if
    numknark = string.byte(strsurr,(numininx+1),(numininx+1))
    numininx = numininx + 1
    numhaj = 0 -- pre-assume no translation
    if ((numknarp~=0) and ((numknark==88) or (numknark==120))) then -- got "x"
      varpeek = contabtransiltable[numknarp] -- UINT16 or nil
      if (varpeek~=nil) then
        numlow = mathmod (varpeek,256)
        numhaj = mathdiv (varpeek,256)
      end--if
    end--if
    if (numhaj~=0) then
      strcxapeloj = strcxapeloj .. string.char(numhaj,numlow)
      numknark = 0 -- invalidade current char
    else
      if (numknarp~=0) then -- add previous char only if valid
        strcxapeloj = strcxapeloj .. string.char(numknarp) -- add it
      end--if
    end--if
    numknarp = numknark -- copy to previous even if invalid
  end--while
  if (numknarp~=0) then -- add previous and last char only if valid
    strcxapeloj = strcxapeloj .. string.char(numknarp) -- add it
  end--if
  return strcxapeloj
end--function lfkodeosg

------------------------------------------------------------------------

---- MAIN EXPORTED FUNCTION ----

------------------------------------------------------------------------

function twoimage.ek (arxframent)

  -- general unknown type

  local vartmp = 0     -- variable without type multipurpose

  -- special type "args" AKA "arx"

  local arxsomons = 0  -- metaized "args" from our own or caller's "frame"

  -- general str

  local strpagenam  = '' -- from "{{PAGENAME}}" o "pagenameoverridetestonly"
  local strruangna  = '' -- "{{NAMESPACENUMBER}}" o "nsnumberoverridetestonly"
  local strsizes    = '' -- actually more than x and y
  local strtmp      = '' -- temp

  local strimagkk   = '' -- name left or one
  local strdesckk   = '' -- desc left or one
  local strimagll   = '' -- name right
  local strdescll   = '' -- desc right

  local strviserr   = '' -- visible error
  local strvisgud   = '' -- visible good output ie table
  local strinvkat   = '' -- invisible category part
  local strret      = '' -- final result string

  -- general num (no var for namespace)

  local numerr    = 0  -- 0 OK 1 inter 2 param 3 deskripsi 4 ns
  local numpindex = 0  -- number of anon params
  local numcase   = 0  -- decimal 97...101 for a) to e)
  local numsizxx  = 0
  local numsizyy  = 0
  local numtamp   = 0

  -- general boo

  local boonocat   = false  -- from "nocat=true"
  local booreduced = false  -- from "duon=1" "half=1"
  local booaldono  = false  -- "true" if ns = 102 (no num var exists)

  ---- GUARD AGAINST INTERNAL ERROR AGAIN ----

  -- later reporting of #E01 may NOT depend on uncommentable strings

  if (qbooguard) then
    numerr = 1 -- #E01 internal
  end--if

  ---- FILL IN ERROR MESSAGES AND TRANSCODE EO IF NEEDED ----

  -- placeholder "\@" "\\@" is replaced by augmented name of the caller
  -- from "constrkoll" in any case, for example 'sxablono "test"'
  -- or 'templat "test"'

  -- only for EO the X-substitution is subsequently performed

  if (numerr==0) then

    numtamp = 2 -- start with #E02
    numtump = 0 -- tolerance for holes
    while (true) do
      vartmp = contaberaroj[numtamp] -- risk of type "nil"
      if (type(vartmp)=="string") then -- number of messages is NOT hardcoded
        numtump = 0
        strtmp = lffillname (vartmp,constrkoll)
        if (constrpriv=="eo") then
          strtmp = lfkodeosg (strtmp)
        end--if
        contaberaroj[numtamp] = strtmp
      else
        numtump = numtump + 1 -- hole (we have limited tolerance for such)
      end--if
      if (numtump==4) then -- max 3 consecutive holes
        break
      end--if
      numtamp = numtamp + 1 -- TWO-based
    end--while

    if (constrpriv=="eo") then
      contabkatoj [1] = lfkodeosg (contabkatoj [1]) -- 4 tracking cat:s
      contabkatoj [2] = lfkodeosg (contabkatoj [2])
      contabkatoj [3] = lfkodeosg (contabkatoj [3])
      contabkatoj [4] = lfkodeosg (contabkatoj [4])
    end--if

  end--if

  ---- GET THE ARX (ONE OF TWO) ----

  -- must be seized independently on "numerr" even if we already suck

  -- give a f**k in possible anon params for now (would cause #E02)

  arxsomons = arxframent.args -- "args" from our own "frame"
  if (type(arxsomons)~="table") then
    arxsomons = {} -- guard against indexing error
    numerr = 1 -- #E01 internal
  end--if
  if (arxsomons['caller']=="true") then
    arxsomons = arxframent:getParent().args -- "args" from caller's "frame"
  end--if
  if (type(arxsomons)~="table") then
    arxsomons = {} -- guard against indexing error again
    numerr = 1 -- #E01 internal
  end--if

  ---- PROCESS 3 HIDDEN NAMED PARAMS ----

  -- this may override "mw.title.getCurrentTitle().text" and
  -- stipulate content in "strpagenam", missing is OK, empty is NOT valid

  -- bad "pagenameoverridetestonly=" can give #E01

  -- give a f**k in possible anon params for now (could otherwise cause #E02)

  strpagenam = ""
  if (numerr==0) then
    vartmp = arxsomons['pagenameoverridetestonly']
    if (type(vartmp)=="string") then
      numtamp = string.len(vartmp)
      if ((numtamp>=1) and (numtamp<=120)) then
        strpagenam = vartmp -- empty is not legal
      else
        numerr = 1 -- #E01 internal
      end--if
    end--if
  end--if

  strruangna = ""
  if (numerr==0) then
    vartmp = arxsomons['nsnumberoverridetestonly']
    if (type(vartmp)=="string") then
      numtamp = string.len(vartmp)
      if ((numtamp>=1) and (numtamp<=4)) then
        strruangna = vartmp -- empty is not legal but ignore crime
      end--if
    end--if
  end--if

  boonocat = (arxsomons['nocat']=='true') -- "arxsomons" must be a table !!!

  ---- SEIZE THE PAGENAME FROM MW AFTER OVERRIDE AND PROHIBIT EMPTY ----

  -- later reporting of #E01 may NOT depend on uncommentable strings

  -- must be 1...120 octet:s keep consistent with "pagenameoverridetestonly="

  if ((numerr==0) and (strpagenam=='')) then
    vartmp = mw.title.getCurrentTitle().text -- without namespace prefix
    if (type(vartmp)=="string") then -- this can leave bhnd "strpagenam" empty
      numtamp = string.len(vartmp)
      if ((numtamp>=1) and (numtamp<=120)) then
        strpagenam = vartmp -- pagename here (empty is NOT legal)
      else
        numerr = 1 -- #E01 internal
      end--if
    end--if
  end--if

  if (strpagenam=='') then
    numerr = 1 -- #E01 internal -- no other error number is possible so far
  end--if

  ---- WHINE IF YOU MUST #E01 ----

  -- reporting of this error #E01 may NOT depend on
  -- uncommentable strings such as "constrkoll" and "contaberaroj"

  -- do NOT use sub "lfbrewerror", report our name (NOT of template) and in EN

  if (numerr==1) then
    strtmp = '#E01 Internal error in module "mtwoimage".'
    strviserr = constrlaxhu .. constrelabg .. strtmp .. constrelaen .. constrlaxhu
  end--if

  ---- SEIZE THE NAMESPACE FROM MW AND CHECK IT ----

  -- assign "booaldono" on success or brew #E04 on failure

  if ((numerr==0) and (strruangna=='')) then
    vartmp = mw.title.getCurrentTitle().namespace -- this is a number
    if (type(vartmp)=="number") then -- this can leave bhnd "strruangna" empty
      if ((vartmp>=0) and (vartmp<=9999)) then
        strruangna = tostring(vartmp) -- empty is not legal but ignore crime
      end--if
    end--if
  end--if

  if (numerr==0) then
    booaldono = (strruangna=="102")
    if ((strruangna~="0") and (booaldono==false)) then
      numerr = 4 -- #E04 ns
    end--if
  end--if

  ---- PRELIMINARILY ANALYZE ANONYMOUS PARAMETERS ----

  -- this will catch holes, empty parameters, too long parameters,
  -- and wrong number of parameters, and give #E02 on a violation

  -- below on exit var "numpindex" will contain number of
  -- prevalidated anonymous params

  -- this depends on 3 constants:
  -- * contabparam[0] minimal number
  -- * contabparam[1] maximal number
  -- * contabparam[2] maximal length (default 160)

  if (numerr==0) then
    numpindex = 0 -- ZERO-based
    numtamp = contabparam[1] -- maximal number of params
    while (true) do
      vartmp = arxsomons [numpindex+1] -- can be "nil"
      if ((type(vartmp)~="string") or (numpindex>numtamp)) then
        break -- good or bad (can go one iteration too long)
      end--if
      numlong = string.len (vartmp)
      if ((numlong==0) or (numlong>contabparam[2])) then
        numerr = 2 -- #E02 param/RTFD
        break -- only bad here
      end--if
      numpindex = numpindex + 1 -- on exit has number of valid parameters
    end--while
    if ((numpindex<contabparam[0]) or (numpindex>numtamp)) then
      numerr = 2 -- #E02 param/RTFD
    end--if
  end--if

  ---- SEIZE 1...4 ANONYMOUS PARAMETERS ----

  -- here we assign "numcase" to "a)" to "e)" ie 97 to 101

  -- "lfchkparam" returns "true" if illegal and this gives #E03

  if (numerr==0) then
    while (true) do -- fake loop
      strimagkk = arxsomons [1] -- assign in any valid case
      if (lfchkparam(strimagkk)) then
        numerr = 3 -- #E03 fan och jaevlar
        break
      end--if
      if (numpindex==1) then
        numcase = 97 -- a) (1) image name
        break
      end--if
      if (numpindex==2) then -- b) or c)
        strtmp = arxsomons [2]
        if (lfchkparam(strtmp)) then
          numerr = 3 -- #E03 fan och jaevlar
          break
        end--if
        if (lftestfile(strtmp)) then -- c)
          numcase = 99 -- c) (2) two image names
          strimagll = strtmp
        else
          numcase = 98 -- b) (2) image name and description
          strdesckk = strtmp
        end--if
        break
      end--if (numpindex==2) then
      if (numpindex==3) then -- d)
        numcase = 100 -- d) (3) two image names and one description
        strimagll = arxsomons [2]
        strdesckk = arxsomons [3]
        if (lfchkparam(strimagll) or lfchkparam(strdesckk)) then
          numerr = 3 -- #E03 fan och jaevlar
          break
        end--if
      else
        numcase = 101 -- e) (4) image name, description, image name, description
        strdesckk = arxsomons [2]
        strimagll = arxsomons [3]
        strdescll = arxsomons [4]
        if (lfchkparam(strdesckk) or lfchkparam(strimagll) or lfchkparam(strdescll)) then
          numerr = 3 -- #E03 fan och jaevlar
          break
        end--if
      end--if (numpindex==3) else
      break -- finally
    end--while -- fake loop
  end--if (numerr==0) then

  ---- WHINE IF YOU MUST #E02...#E99 ----

  -- reporting of errors #E02...#E99 depends on uncommentable strings
  -- and name of the caller filled in from "constrkoll"

  if (numerr>1) then
    strviserr = lfbrewerror(numerr)
  end--if

  ---- SEIZE 1 NAMED PARAMETER ----

  -- this cannot cause any error but "arxsomons" must be a table !!!

  booreduced = false
  if ((arxsomons['duon']=='1') and (constrpriv=="eo")) then
    booreduced = true
  end--if
  if ((arxsomons['half']=='1') and (constrpriv=="id")) then
    booreduced = true
  end--if

  ---- REDUCE 5 CASES TO 3 BY MAGIC MAPPING ----

  if (numerr==0) then
    if (numcase==97) then
      strdesckk = strpagenam
      numcase = 98 -- a) becomes b) -- one image one description
    end--if
    if (numcase==99) then
      strdesckk = strpagenam
      numcase = 100 -- c) becomes d) -- two images one common description
    end--if
  end--if

  ---- RANDOMGENERATE THE SIZES ----

  if (numerr==0) then
    if (numcase==98) then
      if (booreduced) then
        numsizxx  = 160 -- one reduced, case b)
        numsizyy  = 160
      else
        numsizxx  = 240 -- one full, case b)
        numsizyy  = 240
      end--if
    else
      if (booreduced) then
        numsizxx  = 160 -- two reduced, cases d) e)
        numsizyy  = 120
      else
        numsizxx  = 240 -- two full, cases d) e)
        numsizyy  = 160
      end--if
    end--if
    strsizes = "|center|" .. tostring (numsizxx) .. "x" .. tostring (numsizyy) .. "px]]"
  end--if

  ---- BREW THE TABLE ----

  -- this depends on "contabhtml"

  -- [[File: (name) |center| (size) ]]
  --  "strsizes" begins with the left wall "|" and includes the final "]]"

  -- b) one image (two table rows each with one cell)
  -- d) two images with a common description (two table rows, the upper one
  --    with two cells and the lower one with "colspan=2")
  -- e) two images with two separate descriptions (2 table rows,
  --    each with 2 cells)

  if (numerr==0) then
    strvisgud = contabhtml[0] -- begin table
    if (numcase==98) then -- b)
      strvisgud = strvisgud .. '<tr>' .. contabhtml[1] .. '[[File:' .. strimagkk .. strsizes .. '</td></tr>'
      strvisgud = strvisgud .. '<tr>' .. contabhtml[2] .. strdesckk .. '</td></tr>'
    end--if
    if (numcase==100) then -- d)
      strvisgud = strvisgud .. '<tr>' .. contabhtml[1] .. '[[File:' .. strimagkk .. strsizes .. '</td>' .. contabhtml[1] .. '[[File:' .. strimagll .. strsizes .. '</td></tr>'
      strvisgud = strvisgud .. '<tr>' .. contabhtml[3] .. strdesckk .. '</td></tr>'
    end--if
    if (numcase==101) then -- e)
      strvisgud = strvisgud .. '<tr>' .. contabhtml[1] .. '[[File:' .. strimagkk .. strsizes .. '</td>' .. contabhtml[1] .. '[[File:' .. strimagll .. strsizes .. '</td></tr>'
      strvisgud = strvisgud .. '<tr>' .. contabhtml[2] .. strdesckk .. '</td>' .. contabhtml[2] .. strdescll .. '</td></tr>'
    end--if
    strvisgud = strvisgud .. contabhtml[4] -- close table
  end--if

  ---- BREW THE CAT PART ----

  -- this is done even for numerr<>0 but not for 1 !!!

  -- note that "constrkatp" is the cat prefix and includes the colon ":"

  if (boonocat==false) then
    if (numerr==0) then
      if (booaldono) then
        strinvkat = contabkatoj [2] -- aldo -- one of two cat:s
      else
        strinvkat = contabkatoj [1] -- lemma -- one of two cat:s
      end--if
      strinvkat = '[[' .. constrkatp .. strinvkat .. ']]'
    end--if
    if (numerr>=2) then
      strinvkat = '[[' .. constrkatp .. contabkatoj [3] .. ']][['.. constrkatp .. contabkatoj [4] .. ']]' -- both
    end--if
  end--if

  ---- RETURN THE JUNK STRING ----

  strret = strviserr .. strvisgud .. strinvkat
  return strret

end--function

  ---- RETURN THE JUNK LUA TABLE ----

return twoimage