Modulo:msngtbllin

El Vikivortaro
 MODULO
Memtesto disponeblas sur la paĝo Ŝablono:montablng.

--[===[

MODULE "MSNGTBLLIN" (single tabelo kun lingvoj)

"eo.wiktionary.org/wiki/Modulo:msngtbllin" <!--2024-Jan-20-->
"id.wiktionary.org/wiki/Modul:msngtbllin"

Purpose: brews a table with info about one language

Utilo: generas tabelon kun informoj pri unu lingvo

Manfaat: membuat tabel dengan informasi tentang satu bahasa

Syfte: skapar en tabell med information kring ett spraak

Used by templates / Uzata far sxablonoj /
Digunakan oleh templat / Anvaent av mallar:
- "montablng" (EO) / "mpltabbah" (ID)

Required submodules / Bezonataj submoduloj / Submodul yang diperlukan:
* "loaddata-tbllingvoj" T78 in turn requiring template "tbllingvoj" (EO)
* "loaddata-tblbahasa" T78 in turn requiring template "tblbahasa" (ID)

Incoming: * 2 parameters
            * anonymous obligatory parameter
              * string with 2 or 3 char:s -- language access code
            * named obligatory parameter
              * "infsel=" control string for lines -- 6 digits (boolean
                 options: "0" do not show | "1" show and query |
                 value "2" NOT available here)
                * "d07" "tln" top lng cat
                * "d07" "kap" cat
                * "d08" "vor" cat
                * "d08" "mal" cat
                * "d09" "apx" appendix
                * "d09" "ind" index

Returned: * one big string

This module is unbreakable (when called with correct module name
and function name). Every imaginable input from the caller and
from the imported module "loaddata-tbllingvoj" will output either
a useful result or at least the string "Grava eraro".

Cxi tiu modulo estas nerompebla (kiam vokita kun gxustaj nomo de modulo
kaj nomo de funkcio). Cxiu imagebla enigo de la vokanto kaj
de la importata modulo "loaddata-tbllingvoj" eldonos aux
utilan rezulton aux almenaux signocxenon "Grava eraro".

The table we brew consists of LINES. Those are ROWS (horizontal) here in
"msngtbllin" whereas they are COLUMNS (vertical) in "mkomtbllin", with
essentially same content.

Note that the parameter "infsel=" (control string with 6 char:s) has
almost same function in both "mkomtbllin" and "msngtbllin", but some of
the values are tristate in "mkomtbllin", whereas all are boolean here in
"msngtbllin", and querying is always on.

It is possible to control whether to show link to appendix page in "d09"
or not. This is provided for consistency with "mkomtbllin", but since
this module "msngtbllin" is supposed to be called from exactly those
appendix pages (via "montablng" or "mpltabbah"), this subparameter will
usually be false ie "0".

Line numbering in the source table:
- numbering starts from ZERO
- /cy/ does not count (it has theoretically index "-1")
- note that there is no comma between /cy/ and /c0/

Structure of a line in the source table with 1+11 values
for 1+11 lines in the generated table:
- /cy/ : y-index marker (2 or 3 digits)
- /c0/ : name of the language in the site language
         * EO: usually AJ lowercase, alternatively SB uppercase begin
         * ID: without "bahasa " and begins with uppercase letter
- /c1/ : QID (for example "Q5432") "Q" + 2...8 digits, earliest digit
         "1"..."9", further digits "0"..."9"
- /c2/ : name of the language in the language itself
         ("propralingve")
- /c3/ : constructed and antique status (digit "0"..."3")
- c4 : ISO 639-1:2002 2-letter code (only lowercase)
- c5 : ISO 639-3:2007 3-letter code (only lowercase)
- c6 : wiki access code, itself usually same as /cy/, but may be different
       and longer up to 10 char:s, for example "zh-min-nan", leave it "-"
       here if code is same or unknown, use "??" if code belongs to
       other language ("als.pedia.org")
- c7 : wiki availability code (2 digits "0"..."2" ie "00"..."22"),
       "-" causes reddish background and no info about availability
- c8 : name of ipedia article, base principle usually
       followed (there are some exceptions):
       - EO: core word usually AJ name with uppercased begin
             followed by " lingvo", no "la" article
       - ID: prefixed by "Bahasa " and core word begins with uppercase letter
- c9 : category with our site language ("eo" or "id") in other tionary
       (with category NS prefix, but without language prefix, without "]]"
       or other nonsense, can be absurdly long
       "Rummad:Wikeriadur:Distagaduriou' a vank en indonezeg" has 52
       octet:s and even worse 2 apo:s)
- ca : number of pages in that category, apo:s ("16'384") are
       tolerable (this cannot be peeked automatically)
Note that /cy/ and /c0/ are ultimately obligatory, the remaining
ones are only highly desirable.

Overall structure of the generated destination table:
* title cell "colspan=2" with fixed string (big, bold, no link)
* body part
  * 14 rows per 2 cells with info
     or
  * one single cell "colspan=2" with lagom
    error "constrnekl" "Nekotata lingvokodo"
* bottom cell "colspan=2" with update/purge link (depends on pagename)
  and link to source table (fixed) and link to complete table (fixed)

Structure of the right column in the destination table with 14 rows:
- d00 : - incoming language access code (bold) only if valid and found
        # adjust background for "eo" only
- d01 : - name of the language in the site language with link to the
          lemma page (name literally peeked from /c0/ in the source table,
          must be available and valid, link augmented by "lfinsertultim"
          according to control string "contabpages[0]")
- d02 : - QID (for example "Q5432")
- d03 : - name of the language in the language itself
          (literally peeked from /c1/ in the source table)
- d04 : - constructed and antique status (expanded from digit "0"..."3"
          peeked from "c2" in the source table)
        # adjust background to greenish or grey if applicable
- d05 : - "ISO 639-1:2002" 2-letter language code
          (literally peeked from "c3" in the source table)
- d06 : - "ISO 639-3:2007" 3-letter language code
          (literally peeked from "c4" in the source table)
- d07 : - ? link to the "tln" top lng category in own tionary if
            desired, no page count here
        - ? EOL (only if both cat:s are desired)
        - ? link to the "kap" category in own tionary with all words in
            the language (constructed from constant string "constrkatq"
            (category namespace prefix without ":") and /c0/ augmented by
            "lfinsertultim" according to control string "contabpages[6]")
          - ? EOL (if complaint below exists)
          - ? complaint about not existing if applicable
          - ? EOL (if the "parent" link to the "kap" category is present)
          - ? number of pages (queried) or "??" if querying does not work
        # adjust background to reddish if the category (one of two)
          does not exist
        ! depends on variables "bootlnsow" and "bootlnexp" and "bookapsow"
          and "bookapexp" and includes expensive querying (2), column
          can be completely hidden by "bood07"
- d08 : - ? link to the "vor" category in own tionary with all dictionaries in
            the language (constructed from constant string "constrkatq"
            (category namespace prefix without ":") and /c0/ augmented by
            "lfinsertultim" according to control string "contabpages[3]"), no
            page count here
        - ? EOL (only if both cat:s are desired)
        - ? link to the "mal" template cat
          - ? EOL (if complaint below exists)
          - ? complaint about not existing if applicable
          - ? EOL (if the "parent" link to the "mal" template cat is present)
          - ? number of pages (queried) or "??" if querying does not work
        # adjust background to reddish if the category (one of two)
          does not exist
        ! depends on variables "boovorsow" and "boovorexp" and "boomalsow"
          and "boomalexp" and includes expensive querying (2), column
          can be completely hidden by "bood08"
- d09 : - link to the appendix page (constructed from constant string
          "constrapxq" (appendix namespace prefix without ":") and /c0/
          augmented by "lfinsertultim" according to control string
          "contabpages[1]") controlled by "booapxsow"
        - EOL (only if both pages are desired)
        - link to the index page in own tionary with
          the language (constructed from constant string "constrindq"
          (index namespace prefix without ":") and /c0/ augmented by
          "lfinsertultim" according to control string "contabpages[2]")
        # adjust background to reddish if at least one of them does not exist
        ! depends on variables "booapxsow" and "booapxexp" and "booindsow"
          and "booindexp" and includes expensive querying (1), column
          can be completely hidden by "bood09"
- d10 : - quasi-external link to wikipedia in the language concerned
          (constructed from "c5" and "c6" and /cy/, irrespective availability)
        - EOL (if note below exists)
        - note about bad availability if applicable
        # adjust background to grey according to bad availability
        ! no expensive querying here
- d11 : - quasi-external link to tionary in the language concerned
          (constructed from "c5" and "c6" and /cy/, irrespective availability)
        - EOL (if note below exists)
        - note about bad availability if applicable
        # adjust background to grey according to bad availability
        ! no expensive querying here
        & special rule ie blocking for own site language
- d12 : - quasi-external link to the article in own ipedia about the language
          (article name constructed from "c7", or alternatively if "c7" is
          not available then it is guessed using "lfinsertultim" from /c0/
          and "contabpages[7]" and " (??)" is added)
        # adjust background to reddish if "c7" is not available
        ! no expensive querying here
- d13 : - quasi-external link to EO or ID category in the tionary in the
          language concerned (peeked from "c8" in the source table)
        - EOL (if number of articles below exists)
        - number of articles (peeked from "c9" in the source table)
        # adjust background to reddish if "c8" or "c9" is not available
        ! no expensive querying here
        & special rule ie blocking for own site language

Expensive querying: !!!FIXME!!!
There are 6 expensive queries (2 cat:s plus appendix plus index, one cat
costs 2 bucks ("ifexist" and "pagesincategory") per page, appendix and index
cost one buck per page) per language and thus per table row. This is a big
problem in "mkomtbllin" but here in "msngtbllin" it is no problem at all.

Error handling (here in "msngtbllin" we are much stricter than
"mkomtbllin" is and do NOT show broken stuff, and do NOT use red
background, but reddish background is still applied when appropriate):
- "xbooerr" is assigned to true if argument supplied from the caller is
  bad, or neither the requested language nor our own language could be
  peeked, or the peeked complete line contains syntax errors,
  output is minimal with huge error "Grava eraro" then, no big table
  (replace the output string if we already began to brew the table)
- #E10 language code appears to be valid but
  is not found while our own code works, big table with lagom  !!!FIXME!!!
  error "Nekotata lingvokodo"
- if there are too many elements in a line then we ignore the
  superfluous ones (we do not count them in advance)
- if there are too few elements (but at least one ie /c0/) in a line
  then we show "-" (not "=") and adjust the background color in
  cells not getting any content
- if /c0/ is not available then "xbooerr" is assigned to true and "Grava eraro"
- if "mw.title.getCurrentTitle().prefixedText" does not reveal our
  pagename (needed for purge link) then we don't whine but use a bad
  default "Special:Recent changes" instead

]===]

local exporttable = {}

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

---- CONSTANTS [O] ----

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

  -- constant strings EO vs ID

  local constrpriv = "eo"                            -- EO (privileged site language)
  -- local constrpriv = "id"                            -- ID (privileged site language)
  local constringvoj = "Modulo:loaddata-tbllingvoj"  -- EO
  -- local constringvoj = "Modul:loaddata-tblbahasa"    -- ID
  local constrkatq = "Kategorio"             -- EO (used only via "lfykattlaenk")
  -- local constrkatq = "Kategori"              -- ID
  local constrindq = "Indekso"               -- EO (used only via "lfyapxindlaenk")
  -- local constrindq = "Indeks"                -- ID
  local constrapxq = "Aldono"                -- EO (used only via "lfyapxindlaenk")
  -- local constrapxq = "Lampiran"              -- ID

  -- constant table -- ban list -- add obviously invalid access codes (2-letter or 3-letter) only

  -- length of the list is NOT stored anywhere, the processing stops
  -- when type "nil" is encountered, used by "lfivalidatelnkoadv" only

  -- controversial codes (sh sr hr), (zh cmn)
  -- "en.wiktionary.org/wiki/Wiktionary:Language_treatment" excluded languages
  -- "en.wikipedia.org/wiki/Spurious_languages"
  -- "iso639-3.sil.org/code/art" only valid in ISO 639-2
  -- "iso639-3.sil.org/code/gem" only valid in ISO 639-2 and 639-5, "collective"
  -- "iso639-3.sil.org/code/zxx" "No linguistic content"

  local contabisbanned = {}
  contabisbanned = {'by','dc','ll','jp','art','deu','eng','epo','fra','gem','ger','ido','lat','por','rus','spa','swe','tup','zxx'} -- 1...19

  -- background colour translation for
  -- lng status "d04" sub "lfhintegertocol6d"

  local contabwarnlng = {}
  contabwarnlng [0] = '?'      -- default (yellow) -> ordinary lang
  contabwarnlng [1] = 'D0FFD8' -- greenish -> semiconlang
  contabwarnlng [2] = 'A0FFC0' -- more greenish, but still not green -> conlang
  contabwarnlng [3] = 'D0D0D0' -- grey -> dead lang

  -- background colour translation for
  -- wiki availability "d10" & "d11" sub "lfhintegertocol6d"

  local contabwarnwik = {}
  contabwarnwik [0] = 'B0B0B0' -- darker grey -> dead domain
  contabwarnwik [1] = 'D0D0D0' -- grey -> closed wiki
  contabwarnwik [2] = '?'      -- default (yellow) -> good wiki

  -- text for lng status "d04"

  local contabd04ap = {}
  contabd04ap = {'ne planita','parte planita','planita','antikva'}  -- EO (index 1...4, no spaces)
  -- contabd04ap = {'tidak buatan','agak buatan','buatan','kuno'}      -- ID (index 1...4, no spaces)

  -- text for wiki availability "d10" & "d11"

  local contabd10d11w = {}
  contabd10d11w = {'fermita aux malplena','nedisponebla'}  -- EO
  -- contabd10d11w = {'tertutup atau kosong','tidak ada'}     -- ID

  -- surrogate transcoding table (only needed for EO)

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

  -- surrogate transcoding table (only needed for SV)

  local contabtranslutsv = {}
  contabtranslutsv['AA'] = 0xC385 -- Aring
  contabtranslutsv['Aa'] = 0xC385 -- Aring
  contabtranslutsv['aa'] = 0xC3A5 -- aring
  contabtranslutsv['AE'] = 0xC384
  contabtranslutsv['Ae'] = 0xC384
  contabtranslutsv['ae'] = 0xC3A4
  contabtranslutsv['EE'] = 0xC389 -- rarely used
  contabtranslutsv['Ee'] = 0xC389 -- rarely used
  contabtranslutsv['ee'] = 0xC3A9 -- rarely used
  contabtranslutsv['OE'] = 0xC396
  contabtranslutsv['Oe'] = 0xC396
  contabtranslutsv['oe'] = 0xC3B6

  -- constant strings (generic & misc)

  local constrfrco = '2020E0'                                      -- table frame color (blue)
  local constrbkco = 'FFFFD0'                                      -- default cell background color (light yellow)
  local constrbord = 'border:0.25em solid #' .. constrfrco .. ';'  -- to be used inside "style" element
  local constrtdbg = '<td style="' .. constrbord .. 'text-align:center;padding:0.4em;">'              -- colspan NO color NO
  local constrtdcs = '<td style="' .. constrbord .. 'text-align:center;padding:0.4em;" colspan="2">'  -- colspan YES color NO (komp NO sng YES)
  local constrtddf = '<td style="' .. constrbord .. 'text-align:center;padding:0.4em;background:#'    -- colspan NO color YES
  local constrtdfd = ';">'                              -- part of HTML table code after HEX color
  local constrtden = '</td>'
  local constrkros = '&nbsp;#&nbsp;#&nbsp;'             -- lagom -> huge circumfix
  local constremibg = '<span class="error">'            -- minimal whining begin
  local constremien = '</span>'                         -- minimal whining end
  local constrelabg = '<span class="error"><b>'         -- lagom whining begin
  local constrelaen = '</b></span>'                     -- lagom whining end
  local constrehubg = constrkros .. constrelabg         -- huge whining begin
  local constrehuen = constrelaen .. constrkros         -- huge whining end

  -- constant strings EO vs ID (depends on above "generic & misc" section)

  local constrfate = constrehubg .. 'Grava eraro' .. constrehuen                     -- EO (huge)
  -- local constrfate = constrehubg .. 'Kesalahan jahat' .. constrehuen                 -- ID (huge)
  local constrnekl = constrelabg .. 'Nekonata lingvokodo' .. constrelaen             -- EO (lagom)
  -- local constrnekl = constrelabg .. 'Kode bahasa yang tidak dikenal' .. constrelaen  -- ID (lagom)

  local constrtop = '<big><b>Informoj pri lingvo</b></big>'  -- EO (komp NO sng YES)
  -- local constrtop = '<big><b>Informasi bahasa</b></big>'     -- ID (komp NO sng YES)

  -- uncommentable EO vs ID constant table (titles for the table)

  -- * see "lfbrewtitsel" and note that contabmisc[0] is needed too
  -- * note that we can have 2 items in one cell but the non-bold title part
  --   "kvanto" cannot be doubled and must be shared if needed !!!FIXME!!!

  local contabdestit = {}
  contabdestit[00] = 'Alira lingva kodo'                                             -- EO
  -- contabdestit[00] = 'Kode akses bahasa'                                             -- ID
  contabdestit[01] = 'Nomo de la lingvo en EO kaj kapvorta pagxo'                    -- EO (complete title bold)
  -- contabdestit[01] = 'Nama bahasa dalam ID dan halaman lema'                         -- ID (complete title bold)
  contabdestit[02] = 'Vikidatumeja pagxo'                                            -- EO
  -- contabdestit[02] = 'Halaman wikidata'                                              -- ID
  contabdestit[03] = 'Lingvonomo propralingve'                                       -- EO
  -- contabdestit[03] = 'Nama bahasa dalam bahasa itu'                                  -- ID
  contabdestit[04] = 'Planlingva kaj antikva statuso'                                -- EO
  -- contabdestit[04] = 'Status buatan dan kuno'                                        -- ID
  contabdestit[05] = 'ISO 639-1:2002 2-litera kodo'            -- EO
  -- contabdestit[05] = 'ISO 639-1:2002 kode 2 huruf'             -- ID
  contabdestit[06] = 'ISO 639-3:2007 3-litera kodo'            -- EO
  -- contabdestit[06] = 'ISO 639-3:2007 kode 3 huruf'             -- ID
  contabdestit[07] = 'Cxefa kategorio%Kapvorta kategorio#kvanto da pagxoj'           -- EO  (colu can be hidden)
  -- contabdestit[07] = 'Kategori utama%Kategori lema#jumlah halaman'                   -- ID  (colu can be hidden)
  contabdestit[08] = 'Vortara kategorio%Sxablona kategorio#kvanto da pagxoj'         -- EO  (colu can be hidden)
  -- contabdestit[08] = 'Kategori kamus%Kategori templat#jumlah halaman'                -- ID  (colu can be hidden)
  contabdestit[09] = 'Aldono%Indekso'                                                -- EO  (colu can be hidden)
  -- contabdestit[09] = 'Lampiran%Indeks'                                               -- ID  (colu can be hidden)
  contabdestit[10] = 'Vikipedio en la lingvo'                                               -- EO
  -- contabdestit[10] = 'Wikipedia dalam bahasa itu'                                           -- ID
  contabdestit[11] = 'Vikivortaro en la lingvo'                                             -- EO
  -- contabdestit[11] = 'Wikikamus dalam bahasa itu'                                           -- ID
  contabdestit[12] = 'Artikolo pri la lingvo en EO vikipedio'                               -- EO
  -- contabdestit[12] = 'Artikel tentang bahasa itu dalam wikipedia ID'                        -- ID
  contabdestit[13] = 'Kategorio pri EO en vikivortaro en la lingvo#kvanto da pagxoj'        -- EO
  -- contabdestit[13] = 'Kategori tentang ID dalam wikikamus dalam bahasa itu#jumlah halaman'  -- ID

  -- uncommentable EO vs ID constant strings and tables (misc)

  local contabmisc = {}
  contabmisc[0] = "kaj"          -- EO coordinator "&"
  -- contabmisc[0] = "dan"          -- ID coordinator "&"
  contabmisc[1] = "ne ekzistas"  -- EO status of category pages lng kap vor
  -- contabmisc[1] = "tidak ada"    -- ID status of category pages lng kap vor

  -- uncommentable EO vs ID constant table (pagenames to be constructed)

  -- syntax of the insertion and discarding magic string:
  -- "@" followed by 2 uppercase letters and 2 hex numbers
  -- otherwise the hit is not expanded, but copied as-is instead
  -- 2 letters select the insertable item from table supplied by the caller
  -- 2 hex numbers control discarding left and right (0...15 char:s)

  -- insertable items defined:
  -- * LK lng code (for example "da" or "io" or "grc")
  -- * LN lng name native (for example "dana" or "Ido")
  -- * LU lng name uppercased (for example "Dana" or "Ido")

  -- see "lfinsertultim" and "tabstuff" and use space here and avoid "_"

  local contabpages = {}
  contabpages[0] = "@LN00"                  -- EO lemma page in NS ZERO
  -- contabpages[0] = "bahasa @LN00"           -- ID lemma page in NS ZERO
  contabpages[1] = "@LU00"                  -- EO appendix-NS page
  -- contabpages[1] = "Bahasa @LN00"           -- ID appendix-NS page
  contabpages[2] = "@LU00"                  -- EO index-NS page
  -- contabpages[2] = "Bahasa @LN00"           -- ID index-NS page
  contabpages[3] = "Vortaro (@LN00)"        -- EO "vor" dict cat
  -- contabpages[3] = "Kamus bahasa @LN00"     -- ID "vor" dict cat
  contabpages[4] = "Sxablonaro -@LK00-"     -- EO "mal" template cat "Kategorio:Sxablonaro -ja-"
  -- contabpages[4] = "Templat bahasa @LN00"   -- ID "mal" template cat "Kategori:Templat bahasa Jepang"
  contabpages[5] = "@LU00"                  -- EO "tln" top lng cat
  -- contabpages[5] = "Bahasa @LN00"           -- ID "tln" top lng cat
  contabpages[6] = "Kapvorto (@LN00)"       -- EO "kap" lemma cat
  -- contabpages[6] = "Kata bahasa @LN00"      -- ID "kap" lemma cat
  contabpages[7] = "@LU00 lingvo"           -- EO ipedia page guessing
  -- contabpages[7] = "Bahasa @LN00"           -- ID ipedia page guessing

  local constrjlnkpu = 'gxisdatigo'                                    -- EO (no dot "." here) (komp NO sng YES)
  -- local constrjlnkpu = 'pemutakhiran'                                  -- ID (no dot "." here) (komp NO sng YES)
  local constrjsumbr = "[[%C5%9Cablono:tbllingvoj|fonta tabelo]]"      -- EO (no dot "." here) (komp NO sng YES)
  -- local constrjsumbr = "[[Templat:tblbahasa|tabel sumber]]"            -- ID (no dot "." here) (komp NO sng YES)
  local constrjkompl = "[[Aldono:Listo kun lingvoj|kompleta tabelo]]"  -- EO (komp NO sng YES)
  -- local constrjkompl = "[[Lampiran:Daftar bahasa|tabel lengkap]]"      -- ID (komp NO sng YES)

  -- integers "num"

  -- limits for single items

  local connummaaxc0nlen = 44   -- safe values 16 ... 96  -- eval "nummaxc0n"
  local connummaaxc2nlen = 68   -- safe values 16 ... 96  -- eval "nummaxc2n" (for ex "ae" "lad" are very long)
  local connummaxc8catlen = 100 -- safe values 64 ... 256 -- eval "nummaxkal"

  -- constants to control behaviour from source AKA semi-hardcoded parameters

  local conbookodlng  = false  -- "true" to allow long codes like "zh-min-nan"
  local conboomiddig  = false  -- "true" to allow middle digit "s7a"

  local conboofree = false -- cost for "lfwifexist", into qtcostquery[1] (komp true sng false)
  local connumcatstyle = 0 -- category style: 0 raw | 1 "Ka:" | 2 <br> (komp 1 sng 0)

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

---- SPECIAL STUFF OUTSIDE MAIN [B] ----

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

---- SPECIAL VAR:S ----

local qtcostquery = {}   -- for IfExists and PagesInCategory with 5 elements
local qtbunch = {}       -- bunch strings here for "lfhoptconcat"
local qstrret = ''       -- declare here if "lfhoptconcat" used
local qldingvoj = {}     -- type "table" and nested
local qbooguard = false  -- only for the guard test, pass to other var ASAP

---- GUARD AGAINST INTERNAL ERROR AND IMPORT ONE VIA LOADDATA ----

qbooguard = (type(constrpriv)~='string') or (type(constringvoj)~='string') or (type(constrkatq)~='string') or (type(constrapxq)~='string')
if (not qbooguard) then
  qldingvoj = mw.loadData(constringvoj) -- can crash here
  qbooguard = (type(qldingvoj)~='table') -- seems to be always false
end--if

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

---- MATH FUNCTIONS [E] ----

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

local function mathisintrange (numinpuut, numzjmin, numzjmax)
  local numclean = 0
  local booisclean = false
  numclean = math.floor (numinpuut) -- no transcendental
  numclean = math.max (numclean,numzjmin) -- not below minimum
  numclean = math.min (numclean,numzjmax) -- no trillions
  booisclean = (numclean==numinpuut)
  return booisclean
end--function mathisintrange

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

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

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

-- Local function MATHBITWRIT

-- Write bit selected by ZERO-based index assigning it to "1" or "0".

-- Depends on functions :
-- [E] mathdiv mathmod

local function mathbitwrit (numinkoming, numbityndex, boowrite)
  local numpatched = 0
  local numcountup = 0
  local numweight = 1 -- single bit value 1 -> 2 -> 4 -> 8 ...
  local boosinglebit = false
  while true do
    if ((numinkoming==0) and (numcountup>numbityndex)) then
      break -- we have run out of bits on BOTH possible sources
    end--if
    if (numcountup==numbityndex) then
      boosinglebit = boowrite -- overwrite bit
    else
      boosinglebit = (mathmod(numinkoming,2)==1) -- pick bit
    end--if
    numinkoming = mathdiv(numinkoming,2) -- shift right
    if (boosinglebit) then
      numpatched = numpatched + numweight -- add one bit rtl only if true
    end--if
    numcountup = numcountup + 1 -- count up here until we run out of bits
    numweight = numweight * 2
  end--while
  return numpatched
end--function mathbitwrit

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

---- SOME FUNCTIONS [?] ----

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

local function lfcountchr (strqq,numascii) -- count occurrences of char in str
  local numrezalt = 0
  local numciar = 0
  local numukuran = 0
  local numindxe = 0 -- ZERO-based
  numukuran = string.len(strqq)
  while true do
    if (numindxe==numukuran) then
      break
    end--if
    numciar = string.byte(strqq,(numindxe+1),(numindxe+1))
    if (numciar==numascii) then
      numrezalt = numrezalt + 1
    end--if
    numindxe = numindxe + 1
  end--while
  return numrezalt
end--function lfcountchr

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

-- Local function LFCOUNTNDG

-- Count occurrences of non-digits in string.

-- Tolerable char:s that do not count are:
-- - digits "0"..."9"
-- - space
-- - apo

local function lfcountndg (strzzz)
  local numjrezalt = 0
  local numcair = 0
  local numjukuran = 0
  local numjindxe = 0 -- ZERO-based
  numjukuran = string.len(strzzz)
  while true do
    if (numjindxe==numjukuran) then
      break
    end--if
    numcair = string.byte(strzzz,(numjindxe+1),(numjindxe+1))
    if (((numcair<48) or (numcair>57)) and (numcair~=32) and (numcair~=39)) then
      numjrezalt = numjrezalt + 1
    end--if
    numjindxe = numjindxe + 1
  end--while
  return numjrezalt
end--function lfcountndg

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

-- Local function LFREMOVENONDI

-- Remove non-digits from a string, return "0" if no digits available.

local function lfremovenondi (strmess)
  local strnumautnum = ''
  local numcchhrr = 0
  local numwukur = 0
  local numwindxe = 0 -- ZERO-based
  numwukur = string.len(strmess)
  while true do
    if (numwindxe==numwukur) then
      break
    end--if
    numcchhrr = string.byte(strmess,(numwindxe+1),(numwindxe+1))
    if ((numcchhrr>47) and (numcchhrr<58)) then
      strnumautnum = strnumautnum .. string.char(numcchhrr) -- cpy digits only
    end--if
    numwindxe = numwindxe + 1
  end--while
  if (strnumautnum=='') then
    strnumautnum = '0' -- result CANNOT be empty, always a valid number
  end--if
  return strnumautnum
end--function lfremovenondi

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

---- NUMBER CONVERSION FUNCTIONS [N] ----

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

-- Local function LFDEC1DIGIT

-- Convert 1 decimal ASCII digit to integer 0...9 (255 if invalid).

local function lfdec1digit (num1digit)
  num1digit = num1digit - 48 -- may become invalid
  if ((num1digit<0) or (num1digit>9)) then
    num1digit = 255 -- report ERROR on invalid input digit
  end--if
  return num1digit
end--function lfdec1digit

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

-- Local function LFDEC1DIGLM

-- Convert 1 digit decimal to UINT8 with inclusive upper limit.

local function lfdec1diglm (num1dygyt,num1lim)
  num1dygyt = num1dygyt - 48 -- may become invalid
  if ((num1dygyt<0) or (num1dygyt>num1lim)) then
    num1dygyt = 255
  end--if
  return num1dygyt
end--function lfdec1diglm

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

local function lfonehextoint (numdigit)
  local numresult = 255
  if ((numdigit>47) and (numdigit<58)) then
    numresult = numdigit-48
  end--if
  if ((numdigit>64) and (numdigit<71)) then
    numresult = numdigit-55
  end--if
  return numresult
end--function lfonehextoint

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

-- Local function LFNUMTO2DIGIT

-- Convert integer 0...99 to decimal ASCII string always 2 digits "00"..."99".

-- Depends on functions :
-- [E] mathisintrange mathdiv mathmod

local function lfnumto2digit (numzerotoninetynine)
  local strtwodig = '??' -- always 2 digits
  if (mathisintrange(numzerotoninetynine,0,99)) then
    strtwodig = tostring(mathdiv(numzerotoninetynine,10)) .. tostring(mathmod(numzerotoninetynine,10))
  end--if
  return strtwodig
end--function lfnumto2digit

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

-- Local function LFNUMTODECBUN

-- Convert non-negative integer to decimal string with bunching.

-- Depends on functions :
-- [E] mathdiv mathmod

local function lfnumtodecbun (numnomoriin)
  local strnomorut = ''
  local numindeex = 0
  local numcaar = 0
  numnomoriin = math.floor (numnomoriin) -- transcendental numbers suck
  if (numnomoriin<0) then
    numnomoriin = 0 -- negative numbers suck
  end--if
  while true do
    numcaar = mathmod(numnomoriin,10) + 48 -- get digit moving right to left
    numnomoriin = mathdiv(numnomoriin,10)
    if (numindeex==3) then
      strnomorut = "'" .. strnomorut -- ueglstr apo
      numindeex = 0
    end--if
    strnomorut = string.char(numcaar) .. strnomorut -- ueglstr digit
    numindeex = numindeex + 1
    if (numnomoriin==0) then
      break
    end--if
  end--while
  return strnomorut
end--function lfnumtodecbun

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

---- LOW LEVEL STRING FUNCTIONS [G] ----

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

-- test whether char is an ASCII digit "0"..."9", return boolean

local function lfgtestnum (numkaad)
  local boodigit = false
  boodigit = ((numkaad>=48) and (numkaad<=57))
  return boodigit
end--function lfgtestnum

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

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

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

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

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

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

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

---- UTF8 FUNCTIONS [U] ----

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

-- Local function LFULNUTF8CHAR

-- Evaluate length of a single UTF8 char in octet:s.

-- Input  : * numbgoctet  -- beginning octet of a UTF8 char

-- Output : * numlen1234x -- number 1...4 or ZERO if invalid

-- Does NOT thoroughly check the validity, looks at 1 octet only.

local function lfulnutf8char (numbgoctet)
  local numlen1234x = 0
    if (numbgoctet<128) then
      numlen1234x = 1 -- $00...$7F -- ANSI/ASCII
    end--if
    if ((numbgoctet>=194) and (numbgoctet<=223)) then
      numlen1234x = 2 -- $C2 to $DF
    end--if
    if ((numbgoctet>=224) and (numbgoctet<=239)) then
      numlen1234x = 3 -- $E0 to $EF
    end--if
    if ((numbgoctet>=240) and (numbgoctet<=244)) then
      numlen1234x = 4 -- $F0 to $F4
    end--if
  return numlen1234x
end--function lfulnutf8char

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

-- Local function LFCASEREST

-- Adjust case of a single letter (restricted), only ASCII
-- plus a very limited set of 2-octet UTF8 letters. (this is REST)

-- Input  : * strucinrsut : single unicode letter (1 or 2 octet:s)
--          * booupcas    : for desired uppercase "true" and for
--                          lowercase "false"
--          * numselset   : 0 ASCII -- 2 eo -- 5 sv (value 255 NOT here)

-- Output : * strucinrsut (same var) : special value "ZZ" on failure

-- Depends on functions : (this is REST)
-- [U] lfulnutf8char
-- [G] lfgtestuc lfgtestlc
-- [E] mathdiv mathmod mathbitwrit

-- Unknown non-ASCII input strictly returns "ZZ"

-- Defined sets:
-- 2: 2 x 6 uppercase and lowercase -eo- (CX GX HX JX SX UX cx gx hx jx sx ux)
--    upper CX $0108 GX $011C HX $0124 JX $0134 SX $015C UX $016C lower +1
-- 5: 2 x 4 uppercase and lowercase -sv- (AA AE OE EE aa ae oe ee)
--    upper AE $00C4 AA $00C5 EE $00C9 OE $00D6 lower +$20

local function lfcaserest (strucinrsut, booupcas, numselset)

  local numlaengdn = 0 -- length from "string.len"
  local numchaerr = 0 -- UINT8 beginning char
  local numchaess = 0 -- UINT8 later char (BIG ENDIAN, lower value here up)
  local numchareel = 0 -- UINT8 code relative to beginning of block $00...$FF
  local numdeta = 0 -- SINT8 +32 or -32 or +1 or -1 or ZERO
  local numtheemp = 0

  local boowantlowr = false
  local booiisuppr = false
  local booiislowr = false
  local boovalid = false -- preASSume guilt

  booupcas = not (not booupcas)
  boowantlowr = (not booupcas)

  while true do -- upper fake loop (this is REST)

    numlaengdn = string.len (strucinrsut)
    if ((numlaengdn<1) or (numlaengdn>2)) then -- only 1 or 2 accepted
      break -- bad string length
    end--if
    numchaerr = string.byte (strucinrsut,1,1)
    if ((lfulnutf8char(numchaerr))~=numlaengdn) then
      break -- mismatch with length
    end--if

    if (numlaengdn==1) then
      booiisuppr = lfgtestuc(numchaerr)
      booiislowr = lfgtestlc(numchaerr)
      if (booiisuppr and boowantlowr) then
        numdeta = 32 -- ASCII UPPER->lower
      end--if
      if (booiislowr and booupcas) then
        numdeta = -32 -- ASCII lower->UPPER
      end--if
      boovalid = true
      break -- success with ASCII, almost done
    end--if

    numchaess = string.byte (strucinrsut,2,2) -- only $80 to $BF
    numchareel = (mathmod(numchaerr,4)*64) + (numchaess-128) -- 4 times 64

    if ((numselset==2) and ((numchaerr==196) or (numchaerr==197))) then -- eo
      numtheemp = mathbitwrit (numchareel,0,false) -- bad way to do AND $FE
      if ((numtheemp==8) or (numtheemp==28) or (numtheemp==36) or (numtheemp==52) or (numtheemp==92) or (numtheemp==108)) then
        booiisuppr = (numtheemp==numchareel) -- UC below and even
        booiislowr = not booiisuppr
        if (booiisuppr and boowantlowr) then
          numdeta = 1 -- UPPER->lower
        end--if
        if (booiislowr and booupcas) then
          numdeta = -1 -- lower->UPPER
        end--if
        boovalid = true
        break -- success with -eo-, almost done
      end--if
    end--if ((numselset==2) and ...

    if ((numselset==5) and (numchaerr==195)) then -- sv
      numtheemp = mathbitwrit (numchareel,5,false) -- bad way to do AND $DF
      if ((numtheemp==196) or (numtheemp==197) or (numtheemp==201) or (numtheemp==214)) then
        booiisuppr = (numtheemp==numchareel) -- UC below and bit is ZERO
        booiislowr = not booiisuppr
        if (booiisuppr and boowantlowr) then
          numdeta = 32 -- UPPER->lower
        end--if
        if (booiislowr and booupcas) then
          numdeta = -32 -- lower->UPPER
        end--if
        boovalid = true
        break -- success with -sv-, almost done
      end--if
    end--if ((numselset==5) and ...

    break -- finally to join mark -- unknown non-ASCII char is a fact :-(
  end--while -- upper fake loop -- join mark (this is REST)

  while true do -- lower fake loop (this is REST)

    if (not boovalid) then
      strucinrsut = "ZZ" -- unknown non-ASCII char
      break -- helvete
    end--if

    if (numdeta==0) then
      break -- nothing to do
    end--if

    if (numlaengdn==1) then
      strucinrsut = string.char (numchaerr + numdeta) -- no risk of carry here
      break -- done
    end--if

    strucinrsut = string.char (numchaerr) .. string.char (numchaess + numdeta)

    break -- finally to join mark
  end--while -- lower fake loop -- join mark (this is REST)

  return strucinrsut -- same var for input and output

end--function lfcaserest

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

-- Local function LFUCASESTR

-- Adjust case of beginning letter or of all letters in a word or group
-- of words to upper or lower, with limited and adjustable unicode support.

-- Input  : * strenigo  : word or group of words (may be empty)
--          * boouprcas : "true" for uppercase and "false" for lowercase
--          * boodooall : "true" to adjust all letters, "false" only beginning
--          * numslsaet : 0 ASCII -- 2 eo -- 5 sv

-- Depends on functions : (restricted LFCASEREST)
-- [U] lfulnutf8char lfcaserest
-- [G] lfgtestuc lfgtestlc
-- [E] mathdiv mathmod mathbitwrit

local function lfucasestr (strenigo, boouprcas, boodooall, numslsaet)

  local numlein = 0
  local numposi = 1 -- octet position ONE-based
  local numcut = 0 -- length of an UTF8 char
  local bootryadj = false -- try to adjust single char
  local strte7mp = ''
  local strelygo = ''

  boouprcas = not (not boouprcas)
  boodooall = not (not boodooall)
  numlein = string.len (strenigo)

  while true do
    if (numposi>numlein) then
      break -- done
    end--if
    bootryadj = (boodooall or (numposi==1))
    numcut = lfulnutf8char(string.byte(strenigo,numposi,numposi))
    if ((numcut==0) or ((numposi+numcut-1)>numlein)) then
      numcut = 1 -- skip ie copy one faulty octet
      bootryadj = false
    end--if
    strte7mp = string.sub (strenigo,numposi,(numposi+numcut-1)) -- 1...4 oct
    if (bootryadj) then
      strte7mp = lfcaserest(strte7mp,boouprcas,numslsaet) -- (restricted LFCASEREST)
    end--if
    strelygo = strelygo .. strte7mp -- this can be slow
    numposi = numposi + numcut -- done 1...4 octet:s
  end--while

  return strelygo

end--function lfucasestr

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

---- HIGH LEVEL STRING FUNCTIONS [I] ----

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

-- Local function LFISPACUNDR

-- Spaces to underscores or vice-versa.

-- Incoming boolean "true" for output underscores and "false" for spaces.

local function lfispacundr (strxxin, boounderlig)
  local numleang = 0
  local numandex = 0 -- ZERO-based
  local numcxarr = 0
  local strkatrol = ''
  numleang = string.len (strxxin)
  while true do -- genuine loop
    if (numandex==numleang) then
      break
    end--if
    numcxarr = string.byte (strxxin,(numandex+1),(numandex+1))
    if ((numcxarr==32) or (numcxarr==95)) then
      if (boounderlig) then
        numcxarr = 95
      else
        numcxarr = 32
      end--if
    end--if
    strkatrol = strkatrol .. string.char (numcxarr)
    numandex = numandex + 1
  end--while
  return strkatrol
end--function lfispacundr

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

-- Local function LFIVALIDATESTR

-- Validate string according to a huge bunch of criteria.

-- Input  : - stryn : string
--          - varalt : alternative valid string (for example "??" or "-")
--                     that can "jump over" all other checks, note that empty
--                     string can be used here, use type "nil" if none defined
--          - nummyn : minimal length
--          - nummex : maximal length
--          - numapo : apo rules
--                     0 : no restrictions
--                     1 : leading and trailing and multiple apo:s prohibited
--                         (no-wiki-bolding-policy)
--                     2 : apo:s totally prohibited
--          - numpoz : positive list of tolerable char:s
--                     0 : none
--                     1 : only ASCII digits and maybe
--                         apo:s (see also "numapo" above)
--                     2 : only ASCII uppercase letters
--                     3 : only ASCII lowercase letters

-- Output : - booisvalid : true if string is valid

local function lfivalidatestr (stryn,varalt,nummyn,nummex,numapo,numpoz)
  local booisvalid = true -- for the caller
  local numlencx = 0
  local numynx = 0
  local numcxar = 0
  local numcxur = 0
  local vartnp = 0
  while true do -- fake loop
    if (type(varalt)=="string") then
      if (stryn==varalt) then
        break -- to join mark -- string is valid
      end--if
    end--if
    numlencx = string.len(stryn)
    if ((numlencx<nummyn) or (numlencx>nummex)) then
      booisvalid = false
      break -- to join mark -- string is faulty
    end--if
    if (numlencx==0) then
      break -- to join mark -- string is empty but valid
    end--if
    if (numapo==1) then
      numcxar = string.byte(stryn,1,1)
      numcxur = string.byte(stryn,numlencx,numlencx)
      vartnp = string.find(stryn, "''", 1, true) -- plain text search for apo
      if ((numcxar==39) or (numcxur==39) or vartnp) then
        booisvalid = false
        break -- to join mark -- string is faulty
      end--if
    end--if (numapo==1) then
    if ((numpoz~=0) or (numapo==2)) then
      numynx = 0 -- ZERO-based index
      while true do
        if (numynx==numlencx) then
          break -- done search, all OK
        end--if
        numcxar = string.byte(stryn,(numynx+1),(numynx+1))
        if ((numapo==2) and (numcxar==39)) then
          booisvalid = false
          break -- abort search, crime detected (apo)
        end--if
        if ((numpoz==1) and (numcxar~=39)) then
          if ((numcxar<48) or (numcxar>57)) then
            booisvalid = false
            break -- abort search, crime detected (non-digit)
          end--if
        end--if
        if (numpoz==2) then
          if ((numcxar<65) or (numcxar>90)) then
            booisvalid = false
            break -- abort search, crime detected (non-uppercase)
          end--if
        end--if
        if (numpoz==3) then
          if ((numcxar<97) or (numcxar>122)) then
            booisvalid = false
            break -- abort search, crime detected (non-lowercase)
          end--if
        end--if
        numynx = numynx + 1 -- ZERO-based index
      end--while
    end--if ((numpoz~=0) or (numapo==2)) then
    break -- finally to join mark
  end--while -- fake loop -- join mark
  return booisvalid
end--function lfivalidatestr

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

-- Local function LFIVALIDATEQUACK

-- Validate a Q-item.

-- Input  : * strqynq -- string

-- Output : * booqisvalid -- true if string is valid

-- Depends on functions :
-- [G] lfgtestnum

-- Criteria:
-- * length totally 3...9 chars ("Q" plus 2...8 digits)
-- * zeroth char "Q"
-- * then "1"..."9"
-- * subsequent chars (1...7 left) "0"..."9"

local function lfivalidatequack (strqynq)
  local booqisvalid = false -- preASSume guilt
  local numlendx = 0
  local numuinx = 0
  local numcyaar = 0
  while true do -- fake loop
    numlendx = string.len(strqynq)
    if ((numlendx<3) or (numlendx>9)) then
      break -- to join mark -- string is faulty, length
    end--if
    if (string.byte(strqynq,1,1)~=81) then
      break -- to join mark -- string is faulty, no "Q"
    end--if
    if (string.byte(strqynq,2,2)==48) then
      break -- to join mark -- string is faulty, ZERO "0" prohibited here
    end--if
    numuinx = 1 -- ZERO-based -- skip "Q"
    booqisvalid = true -- preASSume innocence
    while true do
      if (numuinx>=numlendx) then
        break -- done search, all OK
      end--if
      numcyaar = string.byte(strqynq,(numuinx+1),(numuinx+1))
      if (not lfgtestnum(numcyaar)) then
        booqisvalid = false -- guilty, no number
        break -- abort search
      end--if
      numuinx = numuinx + 1 -- ZERO-based
    end--while
    break -- finally to join mark
  end--while -- fake loop -- join mark
  return booqisvalid
end--function lfivalidatequack

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

-- Local function LFIVALIDATELNKOADV

-- Advanced test whether a string (intended to be a language code) is valid
-- containing only 2 or 3 lowercase letters, or 2...10 char:s and with some
-- dashes, or maybe a digit in middle position or maybe instead equals to "-"
-- or "??" and maybe additionally is not included on the ban list.

-- Input  : * strqooq -- string (empty is useless and returns
--                       "true" ie "bad" but cannot cause any major harm)
--          * booyesdsh -- "true" to allow special code dash "-"
--          * booyesqst -- "true" to allow special code doublequest "??"
--          * booloonkg -- "true" to allow long codes such as "zh-min-nan"
--          * boodigit -- "true" to allow digit in middle position
--          * boonoban -- (inverted) "true" to skip test against ban table

-- Output : * booisvaladv -- true if string is valid

-- Depends on functions :
-- [G] lfgtestnum lfgtestlc

-- Depends on constants :
-- * table "contabisbanned"

-- Incoming empty string is safe but type "nil" is NOT.

-- Digit is tolerable only ("and" applies):
-- * if boodigit is "true"
-- * if length is 3 char:s
-- * in middle position

-- Dashes are tolerable (except in special code "-") only ("and" applies):
-- * if length is at least 4 char:s (if this is permitted at all)
-- * in inner positions
-- * NOT adjacent
-- * maximally TWO totally
-- There may be maximally 3 adjacent letters, this makes at least ONE dash
-- obligatory for length 4...7, and TWO dashes for length 8...10.

local function lfivalidatelnkoadv (strqooq, booyesdsh, booyesqst, booloonkg, boodigit, boonoban)

  local varomongkosong = 0 -- for check against the ban list
  local numchiiar = 0
  local numukurran = 0
  local numindeex = 0 -- ZERO-based -- two loops
  local numadjlet = 0 -- number of adjacent letters (max 3)
  local numadjdsh = 0 -- number of adjacent dashes (max 1)
  local numtotdsh = 0 -- total number of dashes (max 2)
  local booislclc = false
  local booisdigi = false
  local booisdash = false
  local booisvaladv = true -- preASSume innocence -- later final verdict here

  while true do -- fake (outer) loop

    if (strqooq=="-") then
      booisvaladv = booyesdsh
      break -- to join mark -- good or bad
    end--if
    if (strqooq=="??") then
      booisvaladv = booyesqst
      break -- to join mark -- good or bad
    end--if
    numukurran = string.len (strqooq)
    if ((numukurran<2) or (numukurran>10)) then
      booisvaladv = false
      break -- to join mark -- evil
    end--if
    if (not booloonkg and (numukurran>3)) then
      booisvaladv = false
      break -- to join mark -- evil
    end--if

    numindeex = 0
    while true do -- inner genuine loop over char:s
      if (numindeex>=numukurran) then
        break -- done -- good
      end--if
      numchiiar = string.byte (strqooq,(numindeex+1),(numindeex+1))
      booisdash = (numchiiar==45)
      booisdigi = lfgtestnum(numchiiar)
      booislclc = lfgtestlc(numchiiar)
      if (not (booislclc or booisdigi or booisdash)) then
        booisvaladv = false
        break -- to join mark -- inherently bad char
      end--if
      if (booislclc) then
        numadjlet = numadjlet + 1
      else
        numadjlet = 0
      end--if
      if (booisdigi and ((numukurran~=3) or (numindeex~=1) or (not boodigit))) then
        booisvaladv = false
        break -- to join mark -- illegal digit
      end--if
      if (booisdash) then
        if ((numukurran<4) or (numindeex==0) or ((numindeex+1)==numukurran)) then
          booisvaladv = false
          break -- to join mark -- illegal dash
        end--if
        numadjdsh = numadjdsh + 1
        numtotdsh = numtotdsh + 1 -- total
      else
        numadjdsh = 0 -- do NOT zeroize the total !!!
      end--if
      if ((numadjlet>3) or (numadjdsh>1) or (numtotdsh>2)) then
        booisvaladv = false
        break -- to join mark -- evil
      end--if
      numindeex = numindeex + 1 -- ZERO-based
    end--while -- inner genuine loop over char:s

    if (not boonoban) then -- if "yesban" then
      numindeex = 0
      while true do -- lower inner genuine loop
        varomongkosong = contabisbanned[numindeex+1] -- number of elem unknown
        if (type(varomongkosong)~='string') then
          break -- abort inner loop (then outer fake loop) due to end of table
        end--if
        numukurran = string.len (varomongkosong)
        if ((numukurran<2) or (numukurran>3)) then
          break -- abort inner loop (then outer fake loop) due to faulty table
        end--if
        if (strqooq==varomongkosong) then
          booisvaladv = false
          break -- abort inner loop (then outer fake loop) due to violation
        end--if
        numindeex = numindeex + 1 -- ZERO-based
      end--while -- lower inner genuine loop
    end--if (not boonoban) then

    break -- finally to join mark
  end--while -- fake loop -- join mark

  return booisvaladv

end--function lfivalidatelnkoadv

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

-- Local function LFIVALIUMDCTLSTR

-- Validate control string against restrictive pattern (dec).

-- Input  : * strresdpat -- restrictive pattern (max 200 char:s)
--          * strctldstr -- incoming suspect

-- Output : * numbadpos -- bad position, or 254 wrong length, or 255 success

-- Depends on functions :
-- [N] lfdec1digit

-- Content of restrictive pattern:
-- * "."                           -- skip check
-- * "-" and "?"                   -- must match literally
-- * digit "1"..."9" ("0" invalid) -- inclusive upper limit (min ZERO)

local function lfivaliumdctlstr (strresdpat, strctldstr)

  local numlenresdpat = 0
  local numldninkom = 0
  local numcomperindex = 0 -- ZERO-based
  local numead2 = 0
  local numead3 = 0
  local numbadpos = 254 -- preASSume guilt (len differ or too long or ...)
  local booddaan = false

  numlenresdpat = string.len(strresdpat)
  numldninkom = string.len(strctldstr)
  if ((numlenresdpat<=200) and (numlenresdpat==numldninkom)) then
    while true do
      if (numcomperindex==numlenresdpat) then
        numbadpos = 255
        break -- success
      end--if
      numead2 = string.byte(strresdpat,(numcomperindex+1),(numcomperindex+1)) -- rest
      numead3 = string.byte(strctldstr,(numcomperindex+1),(numcomperindex+1)) -- susp
      booddaan = false
      if ((numead2==45) or (numead2==63)) then
        if (numead2~=numead3) then
          numbadpos = numcomperindex
          break -- "-" and "?" must match literally
        end--if
        booddaan = true -- position OK
      end--if
      if (numead2==46) then -- skip for dot "."
        booddaan = true -- position OK
      end--if
      if (not booddaan) then
        numead2 = lfdec1digit(numead2) -- rest
        if (numead2>9) then -- limit defined or bad ??
          numbadpos = 254
          break -- bad restrictive pattern
        else
          numead3 = lfdec1digit(numead3) -- susp
          if (numead3>numead2) then
            numbadpos = numcomperindex
            break -- value limit violation
          end--if
        end--if (numead2>9) else
      end--if (not booddaan) then
      numcomperindex = numcomperindex + 1
    end--while
  end--if ((numlenresdpat<=200) and (numlenresdpat==numldninkom)) then

  return numbadpos

end--function lfivaliumdctlstr

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

---- HIGH LEVEL FUNCTIONS [H] ----

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

-- Local function LFHOPTCONCAT

-- PURPOSE: workaround poor memory management in LUA during string
--          concatenations, add incoming string to "qstrret"

-- IN  : parameter "varincom" either string or type "nil"

-- CHG : qtbunch (table), qstrret (string)

-- NOTE: the thing needs to be initialized by <<local qstrret = ''>>
--       and <<local qtbunch = {}>>

-- NOTE: the thing needs to be flushed by "lfhoptconcat (nil)" before
--       using "qstrret"

-- NOTE: if the "qstrret" string has to be changed directly
--       (by concatenation or replace), then either "lfhoptconcat (nil)"
--       (flush) or "qtbunch = {}" (discard) must be done before !!!

-- Depends on upvalues :
-- * qtbunch qstrret

local function lfhoptconcat (varincom)
  if (type(varincom)=="string") then
    if (#qtbunch>20) then
      qstrret = qstrret .. table.concat (qtbunch) .. varincom
      qtbunch = {}
    else
      table.insert (qtbunch, varincom) -- ONE-based numbering
    end--if
  end--if
  if ((varincom==nil) and (#qtbunch>0)) then
    qstrret = qstrret .. table.concat (qtbunch)
    qtbunch = {}
  end--if
end--function lfhoptconcat

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

-- Local function LFINSERTULTIM

-- Insert selected extra strings into a given string at given positions
-- with optional discarding if the insertable item is empty. Discarding
-- is protected from access out of range by clamping the distances.

-- Input  : * strmdata -- main data string with control cod (syntax see below)
--          * tabinseert -- not-string element is safe and has same effect as
--                          empty string, still explicit type "nil" or empty
--                          string "" are preferred
-- Output : * strhazil

-- syntax of the insertion and discarding magic string:
-- "@" followed by 2 uppercase letters and 2 hex numbers
-- otherwise the hit is not expanded, but copied as-is instead
-- 2 letters select the insertable item from table supplied by the caller
-- 2 hex numbers control discarding left and right (0...15 char:s)

-- Empty item in "tabinseert" is legal and results in discarding if some of
-- the control numbers is non-ZERO. Left discarding is practically performed
-- on "strhazil" whereas right discarding on "strmdata" and "numdatainx".

-- If uppercasing or other adjustment is needed then the caller must take
-- care of it in the form of 2 or more separate items provided in the table
-- with separate names.

-- Depends on functions :
-- [G] lfgtestuc
-- [N] lfonehextoint

local function lfinsertultim (strmdata,tabinseert)

  local varduahuruf = 0
  local strhazil = ''
  local numdatalen = 0
  local numdatainx = 0 -- src index
  local numdataoct = 0 -- maybe @
  local numdataodt = 0 -- UC
  local numdataoet = 0 -- UC
  local numammlef = 0 -- hex and discard left
  local numammrig = 0 -- hex and discard right
  local boogotmagic = false

  numdatalen = string.len(strmdata)
  numdatainx = 1 -- ONE-based

  while true do -- genuine loop, "numdatainx" is the counter
    if (numdatainx>numdatalen) then -- beware of risk of overflow below
      break -- done (ZERO iterations possible)
    end--if
    boogotmagic = false
    numdataoct = string.byte(strmdata,numdatainx,numdatainx)
    numdatainx = numdatainx + 1
    while true do -- fake loop
      if ((numdataoct~=64) or ((numdatainx+3)>numdatalen)) then
        break -- no hit here
      end--if
      numdataodt = string.byte(strmdata, numdatainx   , numdatainx   )
      numdataoet = string.byte(strmdata,(numdatainx+1),(numdatainx+1))
      if (not (lfgtestuc(numdataodt)) or (not lfgtestuc(numdataoet))) then
        break -- no hit here
      end--if
      numammlef = string.byte(strmdata,(numdatainx+2),(numdatainx+2))
      numammrig = string.byte(strmdata,(numdatainx+3),(numdatainx+3))
      numammlef = lfonehextoint (numammlef)
      numammrig = lfonehextoint (numammrig)
      boogotmagic = ((numammlef~=255) and (numammrig~=255))
      break
    end--while -- fake loop -- join mark
    if (boogotmagic) then
      numdatainx = numdatainx + 4 -- consumed 5 char:s, cannot overflow here
      varduahuruf = string.char (numdataodt,numdataoet)
      varduahuruf = tabinseert[varduahuruf] -- risk of type "nil"
      if (type(varduahuruf)~='string') then
        varduahuruf = '' -- type "nil" or invalid type gives empty string
      end--if
      if (varduahuruf=='') then
        numdataoct = string.len(strhazil) - numammlef -- this can underflow
        if (numdataoct<=0) then
          strhazil = ''
        else
          strhazil = string.sub(strhazil,1,numdataoct) -- discard left
        end--if
        numdatainx = numdatainx + numammrig -- discard right this can overflow
      else
        strhazil = strhazil .. varduahuruf -- insert / expand
      end--if
    else
      strhazil = strhazil .. string.char(numdataoct) -- copy char as-is
    end--if (boogotmagic) else
  end--while

  return strhazil

end--function lfinsertultim

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

-- Local function LFIKODEOSG

-- Transcode eo X-surrogates to cxapeloj in a single string (eo only).

-- Input  : * streosurr -- ANSI string (empty is useless but cannot
--                                      cause major harm)

-- Output : * strutf8eo -- UTF8 string

-- Depends on functions :
-- [E] mathdiv mathmod

-- Depends on constants :
-- * table "contabtransluteo" inherently holy

-- To be called ONLY from "lfhfillsurrstrtab".

-- * the "x" in a surr pair is case insensitive,
--   for example both "kacxo" and "kacXo" give same result
-- * avoid "\", thus for example "ka\cxo" would get converted but the "\" kept
-- * double "x" (both case insensitive) prevents conversion and becomes
--   reduced to single "x", for example "kacxxo" becomes "kacxo"

local function lfikodeosg (streosurr)

  local vareopeek = 0
  local strutf8eo = ''
  local numeoinplen = 0
  local numinpinx = 0 -- ZERO-based source index
  local numknar0k = 0 -- current char
  local numknaf1x = 0 -- next char (ZERO is NOT valid)
  local numknaf2x = 0 -- post next char (ZERO is NOT valid)
  local boonext1x = false
  local boonext2x = false
  local boosudahdone = false

  numeoinplen = string.len(streosurr)

  while true do

    if (numinpinx>=numeoinplen) then
      break
    end--if

    numknar0k = string.byte(streosurr,(numinpinx+1),(numinpinx+1))
    numknaf1x = 0 -- preASSume no char
    numknaf2x = 0 -- preASSume no char
    if ((numinpinx+1)<numeoinplen) then
      numknaf1x = string.byte(streosurr,(numinpinx+2),(numinpinx+2))
    end--if
    if ((numinpinx+2)<numeoinplen) then
      numknaf2x = string.byte(streosurr,(numinpinx+3),(numinpinx+3))
    end--if

    boonext1x = ((numknaf1x==88) or (numknaf1x==120)) -- case insensitive
    boonext2x = ((numknaf2x==88) or (numknaf2x==120)) -- case insensitive
    boosudahdone = false
    if (boonext1x and boonext2x) then -- got "xx"
      strutf8eo = strutf8eo .. string.char(numknar0k,numknaf1x) -- keep one "x" only
      numinpinx = numinpinx + 3 -- eaten 3 written 2
      boosudahdone = true
    end--if
    if (boonext1x and (not boonext2x)) then -- got yes-"x" and no-"x"
      vareopeek = contabtransluteo[numknar0k] -- UINT16 or type "nil"
      if (type(vareopeek)=='number') then
        strutf8eo = strutf8eo .. string.char(mathdiv(vareopeek,256),mathmod(vareopeek,256)) -- add UTF8 char
        numinpinx = numinpinx + 2 -- eaten 2 written 2
        boosudahdone = true
      end--if
    end--if
    if (not boosudahdone) then
      strutf8eo = strutf8eo .. string.char(numknar0k) -- copy char
      numinpinx = numinpinx + 1 -- eaten 1 written 1
    end--if

  end--while

  return strutf8eo

end--function lfikodeosg

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

-- Local function LFIKODSVSG

-- Transcode sv blackslash-surrogates in a single string (sv only).

-- Input  : * strsvsurr -- ANSI string (empty is useless but cannot
--                                      cause major harm)

-- Output : * strutf8sv -- UTF8 string

-- Depends on functions :
-- [E] mathdiv mathmod

-- Depends on constants :
-- * table "contabtranslutsv" inherently holy

-- To be called ONLY from "lfhfillsurrstrtab".

-- * the latter letter in a surr triple is case insensitive,
--   for example both "\AEgare" and "\Aegare" give same result

local function lfikodsvsg (strsvsurr)

  local varsvpeek = 0
  local strutf8sv = ''
  local strsvdouble = ''
  local numsvinplen = 0
  local numinpinx = 0 -- ZERO-based source index
  local numsvonechar = 0 -- current char

  numsvinplen = string.len(strsvsurr)

  while true do

    if (numinpinx>=numsvinplen) then
      break
    end--if

    numsvonechar = string.byte(strsvsurr,(numinpinx+1),(numinpinx+1))
    strsvdouble = '' -- preASSume no dblchar
    if ((numsvonechar==92) and ((numinpinx+2)<numsvinplen)) then
      strsvdouble = string.sub(strsvsurr,(numinpinx+2),(numinpinx+3))
    end--if

    varsvpeek = contabtranslutsv[strsvdouble] -- UINT16 or type "nil"
    if (type(varsvpeek)=='number') then
      strutf8sv = strutf8sv .. string.char(mathdiv(varsvpeek,256),mathmod(varsvpeek,256)) -- add UTF8 char
      numinpinx = numinpinx + 3 -- eaten 3 written 2
    else
      strutf8sv = strutf8sv .. string.char(numsvonechar) -- copy char
      numinpinx = numinpinx + 1 -- eaten 1 written 1
    end--if

  end--while

  return strutf8sv

end--function lfikodsvsg

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

-- Local function LFHFILLSURRSTRTAB

-- Process (fill in, transcode surr) either a single string, or all string
-- items in a table using any type of keys/indexes (such as a holy number
-- sequence and non-numeric ones). Items with a non-string value are kept
-- as-is. For filling in own name, and converting eo and sv surrogates
-- (via 3 separate sub:s).

-- Input  : * varinkommen -- type "string" or "table"
--          * varfyllo -- string, or type "nil" if no filling-in desired
--          * strlingkod -- "eo" or "sv" to convert surrogates, anything
--                          else (preferably type "nil") to skip this

-- Depends on functions :
-- [I] lfifillname (only if filling-in desired)
-- [I] lfikodeosg (only if converting of eo X-surrogates desired)
-- [I] lfikodsvsg (only if converting of sv blackslash-surrogates desired)
-- [E] mathdiv mathmod (via "lfikodeosg" and "lfikodsvsg")

-- Depends on constants :
-- * table "contabtransluteo" inherently holy (via "lfikodeosg")
-- * table "contabtranslutsv" inherently holy (via "lfikodsvsg")

local function lfhfillsurrstrtab (varinkommen, varfyllo, strlingkod)

  local varkey = 0 -- variable without type
  local varele = 0 -- variable without type
  local varutmatning = 0
  local boodone = false

  if (type(varinkommen)=='string') then
    if (type(varfyllo)=='string') then
      varinkommen = lfifillname (varinkommen,varfyllo) -- fill-in
    end--if
    if (strlingkod=='eo') then
      varinkommen = lfikodeosg (varinkommen) -- surr
    end--if
    if (strlingkod=='sv') then
      varinkommen = lfikodsvsg (varinkommen) -- surr
    end--if
    varutmatning = varinkommen -- copy, risk for no change
    boodone = true
  end--if

  if (type(varinkommen)=='table') then
    varutmatning = {} -- brew new table
    varkey = next (varinkommen) -- try to pick 0:th (in no order) key/index
    while true do
      if (varkey==nil) then
        break -- empty table or end reached
      end--if
      varele = varinkommen[varkey] -- pick element of unknown type
      if (type(varele)=='string') then
        varele = lfhfillsurrstrtab (varele, varfyllo, strlingkod) -- RECURSION
      end--if
      varutmatning[varkey] = varele -- write at same place in dest table
      varkey = next (varinkommen, varkey) -- try to pick next key/index
    end--while
    boodone = true
  end--if

  if (not boodone) then
    varutmatning = varinkommen -- copy as-is whatever it is
  end--if

  return varutmatning

end--function lfhfillsurrstrtab

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

---- MEDIAWIKI INTERACTION FUNCTIONS [W]

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

-- Local function LFWIFEXIST

-- Tight-fisted check whether a wiki page exists. The caller must use "pcall".

-- Input  : * strpgname    -- fullpagename (default NS 0, not template NS 10)

-- Output : * boomemangada -- "true" on success

-- Depends on upvalues :
-- * heterogeneous table "qtcostquery" with 5 elements

-- Extra colon is tolerable for non-NS-ZERO and non-template-NS-10 pages
-- such as "{{msgnw::Help:TOC}}" and returns ...":Help:TOC"... if the
-- page does not exist.

local function lfwifexist (strpgname)
  local boomemangada = false
  local arxxx = 0
  local metaa = 0
  if (qtcostquery[1]) then
    arxxx = qtcostquery[0] -- trick below does NOT work with substitution
    boomemangada = ( '&#91;&#91;:' .. strpgname .. '&#93;&#93;' ~= arxxx:preprocess ('{{msgnw::' .. strpgname .. '}}') )
    qtcostquery[4] = qtcostquery[4] + 1 -- free counter
  else
    metaa = mw.title.new (strpgname) -- 1 param
    boomemangada = metaa.exists -- expensive here
    qtcostquery[3] = qtcostquery[3] + 1 -- expensive counter
  end--if
  return boomemangada
end--function lfwifexist

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

-- Local function LFWKATROL

-- Peek summary of a category. The caller must use "pcall".

-- Input  : * strcatname           -- without prefix

-- Output : * numpages, numsubcats -- 2 values, value -1 for unknown

-- Depends on upvalues :
-- * heterogeneous table "qtcostquery" with 5 elements

local function lfwkatrol (strcatname)
  local metab = 0
  local numpages = -1
  local numsubcats = -1
  metab = mw.site.stats.pagesInCategory ( strcatname, "*" ) -- expensive here
  qtcostquery[2] = qtcostquery[2] + 1 -- expensive counter
  if (type(metab)=="table") then -- risk of type "number" or "nil"
    numpages = metab.pages
    numsubcats = metab.subcats
    if (numpages<0) then
      numpages = -1 -- YES MediaWiki is stupid
    end--if
    if (numsubcats<0) then
      numsubcats = -1 -- YES MediaWiki is stupid
    end--if
  end--if
  return numpages, numsubcats
end--function lfwkatrol

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

---- SOME FUNCTIONS [?] ----

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

-- Local function LFINUMBERINKAT

local function lfinumberinkat (numjumlahorminone)
  local strnothing = '' -- "(16'384 pages)" or "(?? pages)"
  if (numjumlahorminone<0) then -- expected type integer, value -1 for unknown
    strnothing = '(??'
  else
    strnothing = '(' .. lfnumtodecbun(numjumlahorminone) -- ZERO is valid
  end--if
  strnothing = strnothing .. ' pages)'
  return strnothing
end--function lfinumberinkat

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

-- Local function LFHINTEGERTOCOL6D

-- Output : * varfromtable -- 6 hex quasi-digits, maybe copied from
--                            "strdefault", or "=" if index bad

-- Depends on constants :
-- * tables "contabwarnlng" and "contabwarnwik" both ZERO-based

local function lfhintegertocol6d (numkoloindex,bootype,strdefault)
  local varfromtable = 0
  if (bootype) then
    varfromtable = contabwarnwik[numkoloindex]
  else
    varfromtable = contabwarnlng[numkoloindex]
  end--if
  if (type(varfromtable)~='string') then
    varfromtable = "=" -- index bad
  end--if
  if (varfromtable=="?") then
    varfromtable = strdefault
  end--if
  return varfromtable
end--function lfhintegertocol6d

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

-- Local function LFAVAILNT

-- Translate number 2...0 to text with "br".

-- Depends on constants :
-- * table "contabd10d11w" with 2 strings at indexes ONE and TWO

local function lfavailnt (numalb)
  local strnote = '' -- preASSume no extra complaint
  if (numalb==1) then
    strnote = '<br>(' .. contabd10d11w[1] .. ')' -- closed or empty
  end--if
  if (numalb==0) then
    strnote = '<br>(' .. contabd10d11w[2] .. ')' -- inaccessible
  end--if
  return strnote
end--function lfavailnt

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

-- Local function LFIBREWURL

-- Brew an external link [] to a different wiki.

-- Input  : * straxk : wiki access code (2...10 char:s), "??" for invalid
--          * bootip : type (false -> ipedia | true -> tionary)
--          * varpage : pagename string (article, or category with
--                      prefix) or type "nil"

-- Depends on functions :
-- [I] lfispacundr

-- Here we replace spaces in URL by underscores, no further encoding
-- is performed.

-- No link if wiki access code is "??", only plain text instead.

local function lfibrewurl (straxk,bootip,varpage)

  local strurlkita = ''
  local strsite = ''
  local boolinkvalid = false
  local boohavepage = false

  if (bootip) then
    strsite = 'tionary'
  else
    strsite = 'ipedia'
  end--if
  boolinkvalid = (straxk~='??')
  boohavepage = (type(varpage)=='string')

  if (boolinkvalid) then
    strurlkita = '[http://' .. straxk .. '.wik' .. strsite .. '.org'
    if (boohavepage) then -- string (article or category with prefix) or nil
      strurlkita = strurlkita .. '/wiki/' .. lfispacundr(varpage,true) -- replace in URL
    end--if
    strurlkita = strurlkita .. ' ' -- separation space
  end--if
  strurlkita = strurlkita .. straxk .. '.' .. strsite .. '...' -- visible text
  if (boohavepage) then -- string (article or category with prefix) or nil
    strurlkita = strurlkita .. '<br>/' .. varpage -- do NOT replace here
  end--if
  if (boolinkvalid) then
    strurlkita = strurlkita .. ']' -- done
  end--if

  return strurlkita

end--function lfibrewurl

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

-- Local function LFBREWTITSEL

-- Brew content of title cell (for column or row) from index
-- number and two booleans.

-- Input  : * numindxe -- index number of column (ZERO-based)
--          * bootopp, boobotm

-- Depends on functions :
-- [N] lfnumto2digit

-- Depends on constants :
-- * table "contabdestit"
-- * contabmisc[0] (translated coordinator "and")

-- * (begin of bold) is always added at the very beginning
-- * (end of bold) is added at the very end if no "#" is present
-- * "#" is expanded to (end of bold) + EOL + word "and" + EOL
-- * maximally ONE "#" is permitted
-- * "%" is border between 2 selectable items, it is expanded to
--   (end of bold) + EOL + word "and" + EOL + (begin of bold) only
--   if both items are active
-- * maximally ONE "%" is permitted

-- An entry in the table "contabdestit" is NOT supposed to contain
-- "<b>" (even less triple-apo "'''"), nor "</b>" at end nor "<br>".

local function lfbrewtitsel (numindxe, bootopp, boobotm)

  local strraw = ''
  local strdesc = ''
  local strandkajdan = ''
  local numlimiit = 0
  local numoindex = 1 -- ONE-based
  local numpycker = 0
  local numfragmm = 0 -- NOT relevant if both "bootopp" and "boobotm" are true
  local booslutbold = false
  local bootakeit = false

  strandkajdan = "<br>" .. contabmisc[0] .. "<br>" -- for both % and #
  strraw = contabdestit[numindxe]
  strdesc = '<b>'
  numlimiit = string.len (strraw)

  while true do
    if (numoindex>numlimiit) then
      break
    end--if
    bootakeit = true
    numpycker = string.byte(strraw,numoindex,numoindex)
    numoindex = numoindex + 1
    if (numpycker==35) then -- 35 is "#"
      strdesc = strdesc .. "</b>" .. strandkajdan -- no (begin of bold) !!!
      booslutbold = true
      bootakeit = false
      numfragmm = 2 -- following text taken unconditionally
    end--if
    if (numpycker==37) then -- 37 is "%"
      if (bootopp and boobotm) then
        strdesc = strdesc .. "</b>" .. strandkajdan .. "<b>"
      end--if
      numfragmm = numfragmm + 1
      bootakeit = false
    end--if
    if ((numfragmm==0) and (not bootopp)) then
      bootakeit = false
    end--if
    if ((numfragmm==1) and (not boobotm)) then
      bootakeit = false
    end--if
    if (bootakeit) then
      strdesc = strdesc .. string.char(numpycker)
    end--if
  end--while

  if (not booslutbold) then
    strdesc = strdesc .. '</b>' -- add "</b>" only if it is not yet in
  end--if
  strdesc = strdesc .. '<br>(d' .. lfnumto2digit (numindxe) .. ')'

  return strdesc

end--function lfbrewtitsel

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

---- VERY HIGH LEVEL FUNCTIONS [Y]

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

-- Local function LFYKATTLAENK

-- Brew link to category possibly saving screen space and
-- optionally check existence and content.

-- Input  : * strkattnamn            -- without prefix

-- Output : * booisbiru, strlikatter -- 2 values

-- Depends on functions :
-- [W] lfwifexist lfwkatrol
-- [I] lfinumberinkat

-- Depends on upvalues :
-- * heterogeneous table "qtcostquery" with 5 elements

-- Depends on constants :
-- * constrkatq (ns prefix NOT ending with colon)
-- * contabmisc[1] (statement "does not exist")
-- * connumcatstyle (0 raw | 1 "Ka:" | 2 <br>)

local function lfykattlaenk (strkattnamn,boocheckdabl)
  local strfullcatname = ''
  local strlikatter = ''
  local straltprefix = ''
  local numjumlah = 0
  local booisbiru = true -- preASSume innocence
  strfullcatname = constrkatq .. ':' .. strkattnamn
  if (connumcatstyle==0) then
    strlikatter = "[[:" .. strfullcatname .. "]]" -- raw
  else
    if (connumcatstyle==1) then
      straltprefix = string.sub (constrkatq,1,2) .. ':' -- "Ca:" or "Ka:"
    else
      straltprefix = constrkatq .. ':<br>' -- "Category:" + EOL
    end--if
    strlikatter = "[[:" .. strfullcatname .. "|" .. straltprefix .. strkattnamn.. "]]"
  end--if
  if (boocheckdabl) then
    booisbiru = lfwifexist (strfullcatname)
    if (not booisbiru) then -- incidents reported here but counted by caller
      strlikatter = strlikatter .. '<br>(' .. contabmisc[1] .. ')' -- "does not exist"
    end--if
    numjumlah = lfwkatrol (strkattnamn) -- discard 1 of 2 results, can be -1
    strlikatter = strlikatter .. '<br>' .. lfinumberinkat(numjumlah) -- can be -1
  end--if
  return booisbiru,strlikatter
end--function lfykattlaenk

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

-- Local function LFYAPXINDLAENK

-- Brew link to appendix or index page and optionally check existence.

-- Input  : * strapxindnamn           -- without prefix

-- Output : * booitisblue, strailiink -- 2 values

-- Depends on functions :
-- [W] lfwifexist

-- Depends on upvalues :
-- * heterogeneous table "qtcostquery" with 5 elements

-- Depends on constants :
-- * constrapxq and constrindq (ns prefixes NOT ending with colon)
-- * contabmisc[1] (statement "does not exist")

local function lfyapxindlaenk (strapxindnamn,bootypetrueind,boocekexx)
  local strfullcainame = ''
  local strailiink = ''
  local booitisblue = true -- preASSume innocence
  if (bootypetrueind) then
    strfullcainame = constrindq .. ':' .. strapxindnamn -- "Index:" prefix
  else
    strfullcainame = constrapxq .. ':' .. strapxindnamn -- "Appendix:" prefix
  end--if
  strailiink = '[[' .. strfullcainame .. ']]'
  if (boocekexx) then
    booitisblue = lfwifexist (strfullcainame)
    if (not booitisblue) then -- incidents reported here but counted by caller
      strailiink = strailiink .. '<br>(' .. contabmisc[1] .. ')' -- "does not exist"
    end--if
  end--if
  return booitisblue,strailiink
end--function lfyapxindlaenk

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

---- VARIABLES [R] ----

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

function exporttable.ek (arxframent)

  -- general unknown type "var"

  local vartmp = 0     -- variable without type multipurpose

  -- special type "args" AKA "arx"

  local arxourown = 0  -- metaized "args" from our own "frame" (NOT caller's)

  -- general "tab"

  local tab78ysubt = {}  -- all langcodes
  local tabc0toca  = {}  -- one langcode
  local tabstuff   = {}  -- double-letter indexes for "lfinsertultim"

  -- general "str"

  local striywo   = "" -- incoming parameter with langcode is the y-index word
  local strinfsel = "" -- incoming parameter with 6 digi, converted into 9 boo
  local strtmp    = "" -- temp
  local strtpm    = "" -- temp other
  local strbkn    = "" -- HTML HEX color (6 digits)
  local strt3d    = "" -- HTML "td" element concatenated from 3 parts
  local strtblc0  = "" -- src column 0 (this is NOT the y-index word) (obliga)
  local strtblc1  = "" -- src column 1 (nice to have) Q-item
  local strtblc2  = "" -- src column 2 (nice to have) propralingve
  local strtblc3  = "" -- src column 3 (nice to have) 1 digit
  local strtblc4  = "" -- src column 4 (nice to have) 2 letters
  local strtblc5  = "" -- src column 5 (nice to have) 3 letters
  local strtblc6  = ""
  local strtblc7  = ""
  local strtblc8  = ""
  local strtblc9  = ""
  local strtblca  = ""
  local strdeste  = "" -- destinat table element with both "td" HTML elements
  local strpurge  = "" -- purge quasi-external link complete with "[" and "]"

  -- general "num"

  local numc7pedi = 0    -- ipedia code "0"..."2"
  local numc7tion = 0    -- tionary code "0"..."2"

  local numafstbfcl = 0  -- string length aftr stripping RLLR before clamping
  local numafstbfkp = 0  -- string length aftr stripping RLLR before clamping

  local numerr    = 0    -- #E01 internal
  local numoct    = 0    -- !!!FIXME!!! localize
  local numtamp   = 0    -- !!!FIXME!!! localize

  -- general "boo"

  local boohavtbl  = false  -- have table on OK or #E10
  local booerr     = false  -- fatal error flag (huge error, no table)
  local bootimp    = false  -- !!!FIXME!!! localize

  -- from arxourown "boo"

  local bootlnsow  = false  -- f "infsel=" d07 above show "tln" top lng cat
  local bookapsow  = false  -- f "infsel=" d07 below show "kap"
  local bood07     = false

  local boovorsow  = false  -- f "infsel=" d08 above show "vor"
  local boomalsow  = false  -- f "infsel=" d08 below show "mal"
  local bood08     = false

  local booapxsow  = false  -- f "infsel=" d09
  local booindsow  = false  -- f "infsel=" d09
  local bood09     = false

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

---- MAIN [Z] ----

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

  qtcostquery[0] = arxframent -- constant
  qtcostquery[1] = conboofree -- constant
  qtcostquery[2] = 0          -- counter expensive PagesInCategory
  qtcostquery[3] = 0          -- counter expensive IfExists
  qtcostquery[4] = 0          -- counter free IfExists

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

  ---- SEIZE ONE ANON AND OBLIGATORY PARAMETER ----

  -- in arxourown[1] expecting lang code (2 or 3 lowercase letters,
  -- everythig else is criminal but this can be changed easily)

  -- result in "striywo" will be later used as index for T78 but
  -- also displayed in right column in row /d00/

  arxourown = arxframent.args -- "args" from our own "frame"

  if ((arxourown[1]==nil) or (arxourown[2])) then
    numerr = 8 -- #E08 need one obligatory anon param, NOT more
  else
    striywo = arxourown[1] -- y-index word (langcode)
    if (not lfivalidatelnkoadv(striywo,false,false,conbookodlng,conboomiddig,false)) then
      numerr = 9 -- #E09 obviously invalid langcode
    end--if
  end--if

  ---- SEIZE ONE NAMED AND OBLIGATORY PARAMETER ----

  -- obligatory 6 digits about 6 items in 3 columns into 9
  -- boolean:s (all preassigned to "false")

  -- in "infsel=" expecting 6 decimal digits, value "2" NOT accepted here

  if (numerr==0) then
    do -- scope
      local varselinf = 0
      local numsilur = 0
      while true do
        varselinf = arxourown['infsel'] -- 6 digits: tln kap vor mal apx ind
        if (type(varselinf)~='string') then
          numerr = 11 -- #E11 named param "infsel=" missing
          break
        end--if
        strinfsel = varselinf
        numsilur = lfivaliumdctlstr ('111111',strinfsel) -- less than 255 bad
        if (numsilur~=255) then
          numerr = 12 -- #E12 named param "infsel=" invalid
          break
        end--if
        numsilur = lfdec1digit(string.byte(strinfsel,1,1)) -- "tln"
        bootlnsow = (numsilur~=0) -- show tln in d07
        numsilur = lfdec1digit(string.byte(strinfsel,2,2)) -- "kap"
        bookapsow = (numsilur~=0) -- show kap in d07
        bood07 = bootlnsow or bookapsow
        numsilur = lfdec1digit(string.byte(strinfsel,3,3)) -- "vor"
        boovorsow = (numsilur~=0) -- show vor in d08
        numsilur = lfdec1digit(string.byte(strinfsel,4,4)) -- "mal"
        boomalsow = (numsilur~=0) -- show mal in d08
        bood08 = boovorsow or boomalsow
        numsilur = lfdec1digit(string.byte(strinfsel,5,5)) -- "apx"
        booapxsow = (numsilur~=0) -- show apx
        numsilur = lfdec1digit(string.byte(strinfsel,6,6)) -- "ind"
        booindsow = (numsilur~=0) -- show ind
        bood09 = booapxsow or booindsow
        break -- finally to join mark
      end--while -- fake loop -- join mark
    end--do scope
  end--if

  ---- PROCESS MESSAGES, FILL IN NEVER, SURR ONLY IF NEEDED ----

  -- no placeholder "\@" "\\@" yet

  if (numerr==0) then
    constrjlnkpu  = lfhfillsurrstrtab (constrjlnkpu, nil, constrpriv)  -- "gxisdatigo"
    contabd10d11w = lfhfillsurrstrtab (contabd10d11w, nil, constrpriv) -- 1,2 -- "fermita aux malplena"
    contabdestit  = lfhfillsurrstrtab (contabdestit, nil, constrpriv)  -- 0...13 -- table headings
    contabpages   = lfhfillsurrstrtab (contabpages, nil, constrpriv)   -- 0...8 -- "Sxablonaro -@LK00-"
  end--if

  ---- SEIZE THE PAGENAME (NEEDED FOR PURGE LINK) AND BREW THE PURGE LINK ----

  -- here we do NOT use the usual function "lfibrewurl" due to
  -- insurmountable differences in the link form

  -- we need "constrjlnkpu" with one word (komp "constrlnkpu" sng "constrjlnkpu")

  if (numerr==0) then

    strtpm = "Special:Recent changes" -- bad default

    vartmp = mw.title.getCurrentTitle().prefixedText -- with namespace prefix
    if (type(vartmp)=="string") then
      if (string.len(vartmp)~=0) then
        strtpm = vartmp -- pagename here (otherwise "Special:Recent changes")
      end--if
    end--if

    strtpm = lfispacundr(strtpm,true) -- replace spaces by underscores in URL
    strtpm = 'http://' .. constrpriv .. '.wiktionary.org/wiki/' .. strtpm .. '?action=purge'
    strpurge = '[' .. strtpm .. ' ' .. constrjlnkpu .. ']' -- visible one word

  end--if

  ---- PICK ONE SUBTABLE T78 ----

  while true do -- fake loop

    if (numerr~=0) then
      break -- to join mark
    end--if
    num2statcode = qldingvoj[2]
    if (type(num2statcode)~='number') then -- important check
      numerr = 2 -- #E02 malica
      break -- to join mark
    end--if
    if (num2statcode~=0) then
      if (mathisintrange(num2statcode,2,79)) then
        numerr = 3 -- #E03 nombrigita
      else
        numerr = 2 -- #E02 malica
      end--if
      break -- to join mark
    end--if
    tab78ysubt = qldingvoj['T78']
    if (type(tab78ysubt)~='table') then -- important check
      numerr = 2 -- #E02 malica
      break -- to join mark
    end--if

    break -- finally to join mark
  end--while -- fake loop -- join mark

  ---- DO SOMETHING ----        !!!FIXME!!!

  if (numerr==0) then
    tabc0toca = tab78ysubt[striywo]
    if (type(tabc0toca)~='table') then
      numerr = 10 -- #E10 unknown langcode
    end--if
  end--if

  -- if "striywo" fails
  --   if own code works then
  --     xboonotfnd = true -- lagom error (since at least our own code found)
  --   else
  --     xbooerr = true -- huge error (since our own code NOT found either)
  --   endif
  -- endif

  ---- BEGIN OUTPUT TABLE (1+14+1 ROWS) AND BREW TOP CELL "COLSPAN=2" ----

  -- using constants "constrtdcs" and "constrtden" for
  -- "<td"...">" (with <<colspan="2">>) and "</td>"

  -- table "sng" must use <<float:right;>> and margins different from "komp"

  -- here we start using "lfhoptconcat", the thing has been initialized
  -- by <<local qstrret = ''>> and <<local qtbunch = {}>>

  boohavtbl = (numerr==0) or (numerr==10) -- OK or #E10

  if (boohavtbl) then -- OK or #E10
    lfhoptconcat ('<table style="' .. constrbord .. 'float:right;margin:0 0 1em 1em;border-collapse:collapse;">')
    lfhoptconcat ('<tr>' .. constrtdcs .. constrtop .. constrtden .. '</tr>')
  end--if

  ---- BOTHER WITH UNKNOWN LANGUAGE CODE ----

  -- using constants "constrtdcs" and "constrtden" for
  -- "<td"...">" (with <<colspan="2">>) and "</td>"

  if (numerr==10) then -- #E10 unknown langcode
    lfhoptconcat ('<tr>' .. constrtdcs .. constrnekl .. constrtden .. '</tr>')
  end--if

  ---- MAIN BLOCK ----

  -- from above we receive "striywo" (from the caller,
  -- this is /cy/) and "tabc0toca"

  -- using function "lfbrewtitsel" for every table row /d00/ ... /d13/

  while true do -- fake loop

    if (numerr~=0) then -- skip main block also for #E10
      break -- to join mark
    end--if

    booerr = (numerr~=0)  -- !!!FIXME!!!

    -- begin /d00/ -- our access code
    strtpm = '<tr>' .. constrtdbg .. lfbrewtitsel (0,true,true) .. constrtden
    lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
    strbkn = constrbkco -- color code without "#" cross
    if (striywo=="eo") then
      strbkn = '90FF90' -- green decoration
    end--if
    strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
    lfhoptconcat (strt3d .. '<b>' .. striywo .. '</b>' .. constrtden .. '</tr>')
    -- done /d00/

    -- begin /c0/ -- lingvonomo in site language
    strtblc0 = tabc0toca[0] or ''
    if (not lfivalidatestr(strtblc0,nil,2,connummaaxc0nlen,0,0)) then
      booerr = true -- /c0/ faulty
      break -- to join mark -- no table and huge error
    end--if
    -- done /c0/ -- ultimately obligatory -- even "-" is bad here

    -- crucial task
    tabstuff["LK"] = striywo -- for "lfinsertultim" -- this is /cy/
    tabstuff["LN"] = strtblc0 -- for "lfinsertultim"
    tabstuff["LU"] = lfucasestr(strtblc0,true,false,2) -- lang name uppercase

    -- begin /d01/ -- lemma page
    lfhoptconcat ('<tr>')
    strtpm = constrtdbg .. lfbrewtitsel (1,true,true) .. constrtden
    lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
    strtpm = lfinsertultim(contabpages[0],tabstuff) -- augment and maybe uc
    strdeste = '[[' .. strtpm .. '|' .. strtblc0 .. ']]' -- wl to lem page
    strt3d = constrtddf .. constrbkco .. constrtdfd -- long "td" eleme
    lfhoptconcat (strt3d .. strdeste .. constrtden) -- here "strdeste" used
    lfhoptconcat ('</tr>')
    -- done /d01/

        -- begin /c1/ -- Q-item
        strtblc1 = tabc0toca[1] or ''
        if (strtblc1~="-") then
          if (not lfivalidatequack(strtblc1)) then
            booerr = true -- /c1/ faulty
            break -- to join mark -- no table and huge error
          end--if
        end--if
        -- done /c1/

        -- begin /d02/ -- Q-item
        lfhoptconcat ('<tr>')
        strtpm = constrtdbg .. lfbrewtitsel (2,true,true) .. constrtden
        lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
        strbkn = constrbkco -- color code without "#" cross
        if (strtblc1=="-") then -- nice to have, do not abort
          strbkn = 'FFD8D8' -- reddish if no "lang in the lang"
        else
          strtblc1 = '[[d:' .. strtblc1 .. '|' .. strtblc1 .. ']]'
        end--if
        strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
        lfhoptconcat (strt3d .. strtblc1 .. constrtden) -- no "strdeste" here c1
        lfhoptconcat ('</tr>')
        -- done /d02/

        -- begin "c2" -- name of lang propralingve -- nice to have
        strtblc2 = tabc0toca[2] or '' -- submodule cares about RLLR
        if (not lfivalidatestr(strtblc2,"-",2,connummaaxc2nlen,0,0)) then
          booerr = true -- /c2/ is faulty ("-" tolerable here)
          break -- to join mark -- no table and huge error
        end--if
        -- done "c2"

        -- begin dest "d03" -- name of lang propralingve
        lfhoptconcat ('<tr>')
        strtpm = constrtdbg .. lfbrewtitsel (3,true,true) .. constrtden
        lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
        strbkn = constrbkco -- color code without "#" cross
        if (strtblc2=="-") then -- nice to have, do not abort
          strbkn = 'FFD8D8' -- reddish if no propralingve
        end--if
        strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
        lfhoptconcat (strt3d .. strtblc2 .. constrtden) -- no "strdeste" here c1
        lfhoptconcat ('</tr>') -- done "d03"

        -- begin "c3" -- constructed and antique status
        strtblc3 = tabc0toca[3] or ''
        -- done "c3"

        -- begin "d04" -- constructed and antique status
        strtpm = '<tr>' .. constrtdbg .. lfbrewtitsel (4,true,true) .. constrtden
        lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
        if (strtblc3=="-") then -- nice to have, do not abort
          strbkn = 'FFD8D8' -- reddish if missing
          strdeste = "-"
        else
          numtamp = string.len(strtblc3) -- must be "0" ... "3"
          if (numtamp~=1) then
            numoct = 255 -- invalid
          else
            numoct = lfdec1diglm(string.byte(strtblc3,1,1),3) -- 0...3 or 255
          end--if
          strbkn = lfhintegertocol6d(numoct,false,constrbkco) -- preASSume light yellow (default color)
          if (strbkn=="=") then
            booerr = true -- "c3" is faulty
            break -- to join mark -- no table and huge error
          else
            strdeste = contabd04ap[numoct+1] -- "contabd04ap" is ONE-based
            strdeste = strdeste .. ' (' .. string.char(numoct+48) .. ')'
          end--if
        end--if (strtblc3=="-") else
        strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
        lfhoptconcat (strt3d .. strdeste .. constrtden .. '</tr>')
        -- done "d04"

        -- begin "c4"
        strtblc4 = tabc0toca[4] or ''
        if (strtblc4=="--") then
          bootimp = false -- 2 valid alternative values "-" and "--" exist
        else
          bootimp = (not lfivalidatestr(strtblc4,"-",2,2,2,3))
        end--if
        if (bootimp) then
          booerr = true -- "c4" is faulty
          break -- to join mark -- no table and huge error
        end--if
        -- done "c4"

        lfhoptconcat ('<tr>') -- begin "d05"
        strtpm = constrtdbg .. lfbrewtitsel (5,true,true) .. constrtden
        lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
        strbkn = constrbkco -- color code without "#" cross
        if (strtblc4=="-") then -- nice to have ("-" is reddish, "--" is NOT)
          strbkn = 'FFD8D8' -- reddish if no ISO 639-1:2002 code
        end--if
        strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
        lfhoptconcat (strt3d .. strtblc4 .. constrtden) -- no "strdeste" here c3
        lfhoptconcat ('</tr>') -- done "d05"

        -- begin "c5"
        strtblc5 = tabc0toca[5] or ''
        if (strtblc5=="---") then
          bootimp = false -- 2 valid alternative values "-" and "---" exist
        else
          bootimp = (not lfivalidatestr(strtblc5,"-",3,3,2,3))
        end--if
        if (bootimp) then
          booerr = true -- "c5" is faulty
          break -- to join mark -- no table and huge error
        end--if
        -- done "c5"

        -- begin "d06" -- 3-letter code
        lfhoptconcat ('<tr>')
        strtpm = constrtdbg .. lfbrewtitsel (6,true,true) .. constrtden
        lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
        strbkn = constrbkco -- color code without "#" cross
        if (strtblc5=="-") then -- nice to have ("-" is reddish, "---" is NOT)
          strbkn = 'FFD8D8' -- reddish if no ISO 639-3:2007 code
        end--if
        strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
        lfhoptconcat (strt3d .. strtblc5 .. constrtden) -- no "strdeste" here c4
        lfhoptconcat ('</tr>')
        -- done "d06"

        -- begin "d07" -- "tln" + "kap" (!!! can be hidden !!!)
        if (bood07) then
          lfhoptconcat ('<tr>')
          strtpm = constrtdbg .. lfbrewtitsel (7,bootlnsow,bookapsow) .. constrtden
          lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
          strbkn = constrbkco -- color code without "#" cross
            strdeste = '' -- crucial
            if (bootlnsow) then
              strtmp = lfinsertultim(contabpages[5],tabstuff) -- augm maybe uc
              bootimp,strdeste = lfykattlaenk (strtmp,true) -- "tln"
            end--if (bootlnsow) then
            if (bootlnsow and bookapsow) then
              strdeste = strdeste .. '<br>'
            end--if
            if (bookapsow) then
              strtmp = lfinsertultim(contabpages[6],tabstuff) -- augm maybe uc
              bootimp,strtmp = lfykattlaenk (strtmp,true) -- "kap"
              strdeste = strdeste .. strtmp
              if (not bootimp) then
                strbkn = 'FFD8D8' -- reddish if "kap" kat does not exist
              end--if
            end--if (bookapsow) then
          strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
          lfhoptconcat (strt3d .. strdeste .. constrtden)
          lfhoptconcat ('</tr>')
        end--if (bood07) then
        -- done "d07"

        -- begin "d08" -- "vor" + "mal" (!!! can be hidden !!!)
        if (bood08) then
          lfhoptconcat ('<tr>')
          strtpm = constrtdbg .. lfbrewtitsel (8,boovorsow,boomalsow) .. constrtden
          lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
          strbkn = constrbkco -- color code without "#" cross
            strdeste = '' -- crucial
            if (boovorsow) then
              strtmp = lfinsertultim(contabpages[3],tabstuff) -- augm maybe uc
              bootimp,strdeste = lfykattlaenk (strtmp,true) -- "vor"
            end--if (boovorsow) then
            if (boovorsow and boomalsow) then
              strdeste = strdeste .. '<br>'
            end--if
            if (boomalsow) then
              strtmp = lfinsertultim(contabpages[4],tabstuff) -- augm maybe uc
              bootimp,strtmp = lfykattlaenk (strtmp,true) -- "mal"
              strdeste = strdeste .. strtmp
              if (not bootimp) then
                strbkn = 'FFD8D8' -- reddish if "mal" kat does not exist
              end--if
            end--if (boomalsow) then
          strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
          lfhoptconcat (strt3d .. strdeste .. constrtden)
          lfhoptconcat ('</tr>')
        end--if (bood08) then
        -- done "d08"

        -- begin "d09" -- Appendix + Index (!!! can be hidden !!!)
        if (bood09) then
          lfhoptconcat ('<tr>')
          strtpm = constrtdbg .. lfbrewtitsel (9,booapxsow,booindsow) .. constrtden
          lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
          strbkn = constrbkco -- color code without "#" cross
            strdeste = '' -- crucial
            if (booapxsow) then
              strtmp = lfinsertultim(contabpages[1],tabstuff) -- augm maybe uc
              bootimp,strdeste = lfyapxindlaenk (strtmp,false,true) -- "apx"
            end--if (booapxsow) then
            if (booapxsow and booindsow) then
              strdeste = strdeste .. '<br>'
            end--if
            if (booindsow) then
              strtmp = lfinsertultim(contabpages[2],tabstuff) -- augm maybe uc
              bootimp,strtmp = lfyapxindlaenk (strtmp,true,true) -- "ind"
              strdeste = strdeste .. strtmp
              if (not bootimp) then
                strbkn = 'FFD8D8' -- reddish if "ind" page does not exist
              end--if
            end--if (booindsow) then
          strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
          lfhoptconcat (strt3d .. strdeste .. constrtden)
          lfhoptconcat ('</tr>')
        end--if (bood09) then
        -- done "d09"

        -- begin /c6/ -- wiki access code
        strtblc6 = tabc0toca[6] or ''
        if (strtblc6=="-") then -- nice to have, long codes permitted, "??" permitted
          strtblc6 = striywo -- copy access code from /cy/
        else
          if (not lfivalidatelnkoadv(strtblc6,false,true,true,false,false)) then -- function returns true if valid
            booerr = true -- "c6" is faulty
            break -- to join mark -- no table and huge error
          end--if
        end--if
        -- done /c6/

        -- begin "c7" -- wiki availability code
        strtblc7 = tabc0toca[7] or ''
        if (strtblc7~="-") then -- nice to have
          numtamp = string.len(strtblc7) -- length
          if (numtamp==2) then
            numc7pedi = string.byte(strtblc7,1,1) -- availability code
            numc7tion = string.byte(strtblc7,2,2) -- availability code
            numc7pedi = lfdec1diglm (numc7pedi,2) -- 0...2 or 255 if invalid
            numc7tion = lfdec1diglm (numc7tion,2) -- 0...2 or 255 if invalid
            if ((numc7pedi==255) or (numc7tion==255)) then
              booerr = true -- /c7/ is faulty
              break -- to join mark -- no table and huge error
            end--if
          else
            booerr = true -- /c7/ is faulty
            break -- to join mark -- no table and huge error
          end--if
        end--if
        -- done "c7"

        -- begin "d10" -- other ipedia main page
        strtpm = '<tr>' .. constrtdbg .. lfbrewtitsel (10,true,true) .. constrtden
        lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
        strbkn = lfhintegertocol6d(numc7pedi,true,constrbkco) -- preASSume light yellow (default color)
        strdeste = lfibrewurl(strtblc6,false,nil) .. lfavailnt(numc7pedi)
        strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
        lfhoptconcat (strt3d .. strdeste .. constrtden .. '</tr>')
        -- done "d10"

        -- begin "d11" -- other tionary main page
        strtpm = '<tr>' .. constrtdbg .. lfbrewtitsel (11,true,true) .. constrtden
        lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
        if (strtblc6==constrpriv) then
          strbkn = constrbkco -- color code without "#" cross -- light yellow (default color)
          strdeste = ':-)' -- reserved for "d11" cell
        else
          strbkn = lfhintegertocol6d(numc7tion,true,constrbkco) -- preASSume light yellow (default color)
          strdeste = lfibrewurl (strtblc6,true,nil) .. lfavailnt(numc7tion)
        end--if
        strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
        lfhoptconcat (strt3d .. strdeste .. constrtden .. '</tr>')
        -- done "d11"

        -- begin "c8" -- article in own wikipedia
        strtblc8 = tabc0toca[8] or ''
        if (not lfivalidatestr(strtblc8,"-",2,32,0,0)) then
          booerr = true -- "c8" is faulty
          break -- to join mark -- no table and huge error
        end--if -- done "c8"

        -- begin "d12" -- article in own wikipedia
        strtpm = '<tr>' .. constrtdbg .. lfbrewtitsel (12,true,true) .. constrtden
        lfhoptconcat (strtpm) -- "lfbrewtitsel" does not add "<td"...">" "</td>"
        strbkn = constrbkco -- color code without "#" cross
            strtmp = strtblc8 -- name of wp article, BEWARE: may contain space
            bootimp = false
            if (strtmp=="-") then
              bootimp = true -- this is semi-evil, we have to guess
              strtmp = lfinsertultim(contabpages[7],tabstuff) -- augment and maybe uc
            end--if
            strdeste = lfibrewurl (constrpriv,false,strtmp) -- own ipedia article
            if (bootimp) then
              strbkn = 'FFD8D8' -- reddish if we had to guess
              strdeste = strdeste .. ' (??)' -- tagg the quess
            end--if
        strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
        lfhoptconcat (strt3d .. strdeste .. constrtden .. '</tr>')
        -- done "d12"

        -- begin "c9" -- cat in other tionary
        strtblc9 = tabc0toca[9] or '' -- submodule cares about RLLR
        numafstbfcl = string.len(strtblc9)
        -- done "c9"

        -- begin /ca/ -- number of lemmas in that cat
        strtblca = tabc0toca[10] or ''
        numafstbfkp = string.len(strtblca)
        -- done /ca/

    -- begin /d13/ -- cat in other tionary with number of lemmas
    do -- scope
      local strta13mp = ''
      local numtaamp  = 0
      local numtuump  = 0
      local boolocerx = false -- local error flag
      local boolocery = false -- other local error flag
      lfhoptconcat ('<tr>')
        strta13mp = constrtdbg .. lfbrewtitsel (13,true,true) .. constrtden
        lfhoptconcat (strta13mp) -- "lfbrewtitsel" not add "<td"...">" "</td>"
        strbkn = constrbkco -- color code without "#" cross
        boolocerx = false
        boolocery = false
        if (strtblc9~="-") then -- do NOT evaluate evilness of "-" in "c9"
          if ((numafstbfcl<8) or (numafstbfcl>connummaxc8catlen)) then -- "c9" bad
            boolocerx = true -- length out of range
          else
            numtaamp = lfcountchr(strtblc9,58)
            if ((numtaamp==0) or (numtaamp>2)) then -- "c9" bad
              boolocerx = true -- bad number of colons, ONE or TWO required
            end--if
          end--if
        end--if
        if (strtblca~="-") then -- do NOT evaluate evilness of "-" in /ca/
          if (numafstbfkp>8) then -- /ca/ bad
            boolocery = true -- length out of range (no minimum)
          else
            if (lfcountndg(strtblca)~=0) then -- /ca/ bad
              boolocery = true -- faulty char:s, a number is expected
            end--if
          end--if
        end--if
        if (boolocerx or boolocery) then
          booerr = true -- "c9" or /ca/ is faulty
          break -- to join mark -- no table and huge error
        else
          if (strtblc9=='-') then
            strbkn = 'FFD8D8' -- reddish if no category
            strdeste = '-'
          else
            strdeste = lfibrewurl (strtblc6,true,strtblc9) .. '<br>' -- other tionary cat
            if (strtblca=="-") then
              strdeste = strdeste .. lfinumberinkat(-1) -- NOT count as error
            else
              numtuump = tonumber(lfremovenondi(strtblca)) -- apo:s tolerable
              strdeste = strdeste .. lfinumberinkat(numtuump) -- apo:s added
            end--if (strtblca=='-') else
          end--if (strtblc9=='-') else
        end--if (boolocerx or boolocery) else
      strt3d = constrtddf .. strbkn .. constrtdfd -- long "td" eleme
      lfhoptconcat (strt3d .. strdeste .. constrtden) -- here "strdeste" used
      lfhoptconcat ('</tr>')
    end--do scope
    -- done /d13/

    break -- finally to join mark
  end--while -- fake loop -- join mark

  --- BREW THE BOTTOM CELL "COLSPAN=2" ----

  -- using constants "constrtdcs" and "constrtden" for
  -- "<td"...">" (with <<colspan="2">>) and "</td>"

  -- update/purge link (depends on pagename)
  -- link to source table (fixed) (template namespace)
  -- link to complete table (fixed) (appendix namespace)

  if (boohavtbl) then -- OK or #E10
    lfhoptconcat ('<tr>' .. constrtdcs .. strpurge .. '<br>' .. constrjsumbr .. '<br>' .. constrjkompl .. constrtden .. '</tr>')
  end--if

  ---- CLOSE THE OUTPUT TABLE, FINALIZE STRING, WHINE IF NEEDED ----

  if (boohavtbl) then -- OK or #E10
    lfhoptconcat ('</table>')
    lfhoptconcat (nil) -- crucial to finalize "qstrret"
  else
    qtbunch = {} -- crucial to discard
    qstrret = constrfate -- fatal error -- replace content of the string
  end--if

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

  return qstrret

end--function

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

return exporttable