Модуль:BallotМодуль для шаблона {{Результат выборов арбитров}}
Псст… не хочешь глянуть в предпросмотре на local p = {}
local trim = mw.text.trim
local green90, green85, green80, green75, green70 = "#d5fdf4", "#d3fcf3", "#b6f4e7", "#9aebd9", "#7fe3cd"
local red90, red85, red80, red75, red70 = "#fee7e6", "#ffe9e8", "#fbd3d2", "#f8bfbd", "#f4a8a6"
local yellow90, yellow85, yellow80, yellow75, yellow70 = "#fef6e7", "#fff7e8", "#fff1d4", "#ffeac0", "#ffe5ac"
--[[
Процесс работы:
1) Устанавливается список кандидатов
1.1) Список кандидатов ищется на разных страницах
1.2) В случае ошибок сообщения о них передаются в таблице и потом группируются
2) Устанавливается список избирателей
2.1) нужна заранее подготовленная таблица к выборам, без неё нет автоматической проверки критериев
2.1.1) если вообще нет такой таблицы, пропускать всех так // правка MBH авторства IKhitron
2.2) принимаются команды с комментариями от бюрократов о необходимости учесть кого-то, кого нет в списке избирателей
BUG - необходимо переписать, чтобы была возможность указать по одному пользователю много разных частичных ограничений
3) Установление списка голосов
3.1) vote_listing, грабит страницы с голосами при помощи pooling
3.2) compute переписывает голоса в таблицу допущенных, добавляя в таблицу err списки исключённых
3.3) сортировка кандидатов согласно ВП:ВАК
TODO - сделать строку серой, пока не перейдена граница 20 голосов
3.4) формируется итоговая таблица
3.4.1) записывается заранее заданная шапка
3.4.2) на основании valid_votes функция line_format записывает строки
3.4.3) сообщения об ошибках группируются и записываются самые важные вместе с подвалом таблицы
TODO - необходимо компактно отображать ещё больше информации
3.5) выдаётся итоговый результат
Таблицы
candidatrue[candidate] - (ключ - ник кандидата, значение true/nil в зависимости от того, есть ли о нём запись)
candidates[N] - (без ключа, содержит ники кандидатов)
err[N] - (без ключа, {тип ошибки текстом; группа ошибки; серьёзность ошибки: 1 - критическая, 2 - серьёзная, 3 - мелкая, 4 - не ошибка; текст ошибки})
vote_table[candidate] = votes[voter] {{nick,bool_pro,bool_contra,time}, }
exceptions[user] = {is_exception,in_general,allow,prevent,comment,candidate} --старая форма
exceptions[user] = { {is_exception,in_general,allow,prevent,comment,candidate}, ...}
--]]
-- local mw = mw or {} -- для уменьшения количества ошибок от локального дебаггера
-- local frame -- frame из p.open_vote, чтобы не волноваться о доступе из любой функции
-- вызов функцией не переданного в неё аргумента приводит к [[Замыкание (программирование)|замыканию]], которое тут не нужно
local monthlang = {"января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря"}
local month_to_num = {["января"]=1,["февраля"]=2,["марта"]=3,["апреля"]=4,["мая"]=5,["июня"]=6,
["июля"]=7,["августа"]=8,["сентября"]=9,["октября"]=10,["ноября"]=11,["декабря"]=12,["-"]=""}
local table_start, table_end = '<table class="wikitable sortable" width=33%><tr style="text-align:center"><th class="headerSortDown">#</th><th>Кандидат</th><th>+</th><th>−</th><th>Δ</th><th>Σ</th><th>%</th></tr>', "</table>"
local err_start, err_end = '<tr class="sortbottom" style="text-align:center"><td colspan="7"><div class="mw-collapsible mw-collapsed"><strong style="display:block;text-align:left">Дополнительная информация</strong><div class="mw-collapsible-content">','</div></td></tr>'
local err_type = {["no data"] ="Нет данных:", ["clash"] ="Расхождения:", ["vot_ers"] ="Исключения:"}
-- функция для проверки, содержит ли массив запрашиваемое значение
local function is_in_list ( var, list )
for i=1, #list do
if var == list[i] then
return true
end
end
return false
end
-- функция для подсчёта элементов в массиве
local function n_list (tab)
if type(tab) ~= "table" then
return 0
end
local i = 0
for k,v in pairs(tab) do
i = i + 1
end
return i
end
-- граббинг данных со страниц с голосами
local function pooling (content, plus, votes)
if not content or #content < 2 then return end
votes = votes or {}
for line in string.gmatch(content, "[^\n]+") do
--при моментальном переголосовании в течении минуты модуль не может определить позднейший голос
local user, nick, h, m, d, mon, y = string.match(line, "^#%s%[%[user:(.-)|(.-)%]]%s(%d%d):(%d%d),%s(.-)%s(.-)%s(.-)%s%(UTC%)")
if user then
local date = os.time{year=y, month=month_to_num[mon], day=d, hour=h, min=m}
votes[user] = votes[user] or {}
table.insert(votes[user], {
nick, -- user == voter == nick
plus, -- pro
not plus, -- contra
date}) -- date
end
end
return votes
end
-- =p.dress("Кандидат",true,false,"причина")
local function dress (candidate,pro,contra,comm)
return "<span style='font-size:90%' class='ts-comment-commentedText' title='" .. candidate .. (comm and " (" or "") .. (comm or "") .. (comm and ")" or "") .. "'>" .. (pro and "+" or (contra and "−" or "?")) .. "</span>"
end
-- TODO подсчёт результатов на заданную дату
-- отмены голосов бюрократами будут вневременные и не повлияют на динамику
local function compute (err,vote_table,electoratrue,exceptions,has_page,date)
if not vote_table then return nil end
date = date or os.time()
local valid_votes = {}
for candidate, votes in pairs(vote_table) do
valid_votes[candidate] = valid_votes[candidate] or {}
-- mw.log("== " .. candidate .. " ==")
for voter, vote in pairs(votes) do
err[votes] = err[votes] or {}
err[votes][candidate] = err[votes][candidate] or {}
err[votes][candidate]["change"] = #vote - 1
valid_votes[candidate][voter] = valid_votes[candidate][voter] or {}
local min_date, pro, contra = 0, false, false
-- local max_date = 17179869184
table.sort(vote,function(a,b) return a[4]>b[4] end)
pro, contra, timestamp = vote[1][2], vote[1][3], vote[1][4]
if #vote ~= 1 then
table.insert(err,{"vot_ers",voter,"<small><i>change: </i></small>",dress(candidate,false,false,#vote)})
end
--[[ for i,subvote in ipairs(vote) do
-- subvote[N] {nick,bool_pro,bool_contra,time}
if subvote[1] ~= voter then
table.insert(err,{"clash",candidate,voter,"(" .. subvote[1] .. ")"})
break
end
if #vote == 1 then
pro, contra = subvote[2], subvote[3]
elseif subvote[4] > min_date then
table.insert(err,{"vot_ers",voter,"<small><i>change: </i></small>",dress(candidate,false,false,#vote)})
pro, contra, v_date, change = subvote[2], subvote[3], subvote[4], true
end
end
--]]
if has_page and not electoratrue[voter] then
table.insert(err,{"vot_ers",voter,"<small><i>[[Special:Contributions/"..voter.."|activity]]: </i></small>",dress(candidate,pro,contra)})
end
valid_votes[candidate][voter] = {electoratrue[voter] or not has_page or false, pro, contra, timestamp}
if exceptions[voter] and type(exceptions[voter]) == "table" then
for _, ex in ipairs(exceptions[voter]) do
-- убрал проверку ex[1], т.к. он пока всегда true
if ex[2] or ex[7] == candidate then
if ex[3] then
valid_votes[candidate][voter][1] = true
table.insert(err,{"vot_ers",voter,"<small><i>allowed: </i></small>",dress(candidate,pro,contra,ex[5] and ex[6] or nil)})
elseif ex[4] then
-- mw.log(voter .. " - " .. candidate)
valid_votes[candidate][voter][1] = false
table.insert(err,{"vot_ers",voter,"<small><i>restricted: </i></small>",dress(candidate,pro,contra,ex[5] and ex[6] or nil)})
end
end
end
end
-- exceptions[voter] {{is_exception,in_general,allow,prevent,bool_comment,comment,candidate}, ...}
-- err[N] {txt_type; txt_group; txt_subgroup; txt_comment}
-- valid_votes[candidate][voter]{[1]= bool_valid, [2]=bool_pro, [3]=bool_contra}
end
end
return err, valid_votes
end
local function reform (err, valid_votes)
local pre_result, pre_sort = {},{}
for candidate, votes in pairs(valid_votes) do
local count_sup,count_opp = 0,0
for voter, vote in pairs(votes) do
if vote[1] and vote[2] then
count_sup = count_sup + 1
elseif vote[1] and vote[3] then
count_opp = count_opp + 1
else
-- mw.log(candidate .. ">" .. voter .. ">("..tostring(vote[1])..","..tostring(vote[2])..","..tostring(vote[3])..")")
end
end
local count_tot = count_sup + count_opp
local percent = count_tot == 0 and 0 or (count_sup * 100 / count_tot)
pre_result[candidate] = {count_sup,count_opp,count_tot,percent}
-- сортировка по голосам за, но те кто набирает процент - выше
local sort_index
-- mw.log(candidate .. " - " .. percent .. "(" .. tostring(percent > (200/3)).. ")")
if percent >= (200/3) then
sort_index = 1000000 + 1000 * count_sup - count_opp
else
sort_index = 100 * (100/3 + percent) + count_sup
end
-- mw.log(sort_index)
table.insert(pre_sort,{candidate, sort_index})
end
-- mw.logObject(pre_sort)
table.sort(pre_sort, function(a,b) return (a[2] == b[2]) and (a[1] < b[1]) or (a[2]>b[2]) end)
return err, pre_result, pre_sort
end
-- valid_votes[candidate][voter]{[1]= bool_valid, [2]=bool_pro, [3]=bool_contra}
-- line_format(i, cand[1], pre_result[cand[1]], arb_page))
local function line_format (i, candidate, c_res, arb_page)
local count_sup,count_opp,count_tot,percent = c_res[1], c_res[2], c_res[3], c_res[4]
local passing = percent > 66.66
local second = percent >= 50
-- нужны даты голосования и автоматический вывод то одних, то других ссылок
local main_arb_page = string.gsub( arb_page, "%/Голосование", "")
local isNew = mw.title.new(arb_page.."/Голоса"):getContent(), pathname
if isNew then pathname = "/Голоса" else pathname = "/*" end
local tr = mw.html.create( 'tr' )
tr :css( 'background', passing and '#cfc;' or (second and '#ffc;' or '#fcc;') )
:tag( 'td' ):css('text-align','right'):wikitext( (passing and '' or '<small>') .. i .. (passing and '' or '</small>')):done()
:tag( 'td' ):css('text-align','center'):css('white-space','nowrap'):wikitext( table.concat{"[[".. arb_page .. pathname .."#", candidate, '|', candidate, "]] ([[", main_arb_page,"#", candidate,"|обс.]])"}):done()
:tag( 'td' ):css('text-align','right'):wikitext( count_sup ):done()
:tag( 'td' ):css('text-align','right'):wikitext( count_opp ):done()
:tag( 'td' ):css('text-align','right'):wikitext( count_sup-count_opp*2 ):done()
:tag( 'td' ):css('text-align','right'):wikitext( count_tot ):done()
:tag( 'td' ):css('text-align','right'):wikitext( (string.gsub( mw.ustring.format("%.2f %%", percent), "%.", ","))):done()
return tostring( tr )
end
local function vote_listing (err,vote_table,arb_page,candidate)
local pattern = "\n#[^#*:][^\n]+"; -- подсчёт нумерованных списков
local pagepointer_sup=mw.title.new(arb_page .. '/+/' .. candidate, '')
local pagepointer_opp=mw.title.new(arb_page .. '/-/' .. candidate, '')
local text_sup=pagepointer_sup.getContent(pagepointer_sup)
local text_opp=pagepointer_opp.getContent(pagepointer_opp)
local votes = {}
votes = pooling(text_sup, true, votes)
local pro_votes = n_list(votes)
-- mw.log(candidate .. " + " .. pro_votes)
votes = pooling(text_opp, false, votes)
local opp_votes = 1+ n_list(votes) - pro_votes
-- mw.log(candidate .. " - " .. opp_votes)
local votes = votes or {} -- хак для отображения пустой таблицы
if not votes then return err, vote_table end
vote_table[candidate] = votes
err[votes] = err[votes] or {}
err[votes][candidate] = err[votes][candidate] or {}
err[votes][candidate]["raw_pro"] = pro_votes
err[votes][candidate]["raw_opp"] = opp_votes
return err, vote_table
end
-- для сложения таблиц кандидатов
local vlist={}
function vlist.__add (tru1,tru2)
if not tru1 or not tru2
or type(tru1) ~= "table" or type(tru2) ~= "table"
then return end
local tru_list = {}
for key,bool in pairs(tru1) do
tru_list[key] = bool
end
for key,bool in pairs(tru2) do
tru_list[key] = bool
end
return tru_list
end
local nomination = function(page)
local nomination_page_text = page:getContent() or ""
local block_pattern = "%{%{ВАРБ:строка|кандидат=([^\n]*)\n|номинатор=([^\n]*)\n|согласие=([^\n]*)\n|отказ=([^\n]*)\n|бюрократ=([^\n]*)\n|отказ бюрократа=([^\n]*)\n%}%}"
local old_block_pattern = "%{%{ВАРБ:старая строка|1=([^\n]*)|2=([^\n]*)|3=([^\n]*)|4=([^\n]*)|5=([^\n]*)%}%}"
local candidates, candidatrue = {}, {}
setmetatable(candidatrue,vlist)
for candidate, submitter, consent, refusal, admission, non_admission in nomination_page_text:gmatch(block_pattern) do
candidate = trim(candidate)
if consent:find("(UTC)") and admission:find("(UTC)") then
candidatrue[candidate] = true
table.insert(candidates, candidate)
end
end
for consent_type, nominee, nominator, consent, admission in nomination_page_text:gmatch(old_block_pattern) do
nominee = trim(nominee)
if consent_type=="+" and admission:find("(UTC)") then
candidatrue[nominee] = true
table.insert(candidates, nominee)
end
end
return candidates, candidatrue
end
local function line_processor(raw_text_candid,patt_string,patt_candid,patt_candid_end,position)
local candidates, candidatrue = {}, {}
setmetatable(candidatrue,vlist)
for line in raw_text_candid:gmatch("[^\n]+") do
if string.match( line, patt_string ) then
local candidate_text = string.match( line, patt_candid)
local pos0, pos1 = string.find(candidate_text,patt_candid_end)
local candidate = string.sub(candidate_text, position, pos0 - 1)
if candidate ~= "" and candidatrue[candidate] ~= true then
candidatrue[candidate] = true
table.insert(candidates, candidate)
end
end
end
return candidates, candidatrue
end
-- =p.caret({},"Википедия:Выборы арбитров/Лето 2021/Голосование/Исключения")
local caret = function (err, page)
local raw_text = mw.title.new(page):getContent() or ""
if #raw_text < 2 then
table.insert(err,{"no data","bureaucrat panel","",'[['.. page ..'|/Исключения]]'})
return err, {}
end
local content, exceptions = false, {}
for line in raw_text:gmatch("[^\n]+") do
if content then
-- TODO exceptions[voter] {{is_exception,in_general,allow,prevent,bool_comment,comment,candidate}, ... }
-- "*" true true true false ""
-- "*" true false false true "отказался" "Candid"
local line_data = string.match( line, "%*%s(.+)")
local _,n = line_data:gsub("|","")
if n == 0 then
local voter_nick = mw.text.trim(line_data)
-- mw.log("0 " .. voter_nick)
exceptions[voter_nick] = exceptions[voter_nick] or {}
table.insert(exceptions[voter_nick],{true,true,true,false})
elseif n == 1 then
local voter, comment = mw.ustring.match(line_data,"([^|]+)|([^|]+)")
voter = mw.text.trim(voter)
comment = mw.text.trim(comment)
-- mw.log("1 " .. voter .. " - " .. comment)
exceptions[voter] = exceptions[voter] or {}
table.insert(exceptions[voter],{true,true,false,true,true,comment})
elseif n == 2 then
local voter, candidate, comment = mw.ustring.match(line_data,"([^|]+)%s?|%s?([^|]+)|([^|]+)")
voter = mw.text.trim(voter)
candidate = mw.text.trim(candidate)
comment = mw.text.trim(comment)
-- mw.log("1 " .. voter .. " - " .. comment .. " - " .. candidate)
exceptions[voter] = exceptions[voter] or {}
table.insert(exceptions[voter],{true,false,false,true,true,comment,candidate})
else
table.insert(err,{"clash","bureaucrat panel","",line_data})
end
elseif string.match( line, ".*</noinclude>" ) then
content = true
end
end
-- mw.logObject(exceptions)
return err, exceptions
end
-- =p.exclamat(mw.title.new("Википедия:Выборы арбитров/Лето 2021/Голосование/!"))
local function exclamat (page)
return line_processor(page:getContent() or "","====.+}}","====.+}}","{{",8)
end
-- =p.ampersan(mw.title.new("Википедия:Выборы арбитров/Лето 2021/Голосование/&"))
local function ampersan (page)
return line_processor(page:getContent() or "","%|[^|]+%|%|%[%[.*","%|[^|]+%|%|%[%[","||%[%[",2)
end
-- =p.allvotes(mw.title.new("Википедия:Выборы арбитров/Лето 2021/Голосование/Голоса"))
local function allvotes (page)
return line_processor(page:getContent() or "","%*%s%[%[#[^|]+|[^%]]+%]%]","%*%s%[%[#[^|]+|[^%]]+%]%]","|",6)
end
-- =p.w_quarry(mw.title.new("Википедия:Выборы арбитров/Лето 2021/Избиратели"))
local function w_quarry (page)
local electorate, electoratrue = line_processor(page:getContent() or "","|[^|]+||%d+||%d+||%d+","^|[^|]+||","||",2)
if not electorate[1] then
local raw_text = page:getContent()
-- TODO сообщение об ошибке
if not raw_text then return {}, {} end
for line in raw_text:gmatch("[^\n]+") do
if line ~= "" and electoratrue[line] ~= true then
electoratrue[line] = true
table.insert(electorate, line)
end
end
end
-- mw.logObject(electoratrue)
-- mw.logObject(electorate)
return electorate, electoratrue
end
-- =p.elec_listing({},"Википедия:Выборы арбитров/Лето 2021/Голосование")
-- =p.elec_listing({},"Шаблон:Результат выборов арбитров")
local function elec_listing (err, arb_page)
local page_1, page_2, _ = mw.ustring.match(arb_page,"([^/]+)/([^/]+)/([^/]+)")
local page_name, has_page
if not page_1 then
page_name = table.concat({page_1 or arb_page,"Избиратели"},"/")
else
page_name = table.concat({page_1,page_2,"Избиратели"},"/")
end
local page = mw.title.new(page_name)
local electorate, electoratrue = w_quarry (page)
if not electorate[1] then
table.insert(err,{"no data","elec","","[[" .. page_name .. "|/Избиратели]]"})
has_page = false
else
has_page = true
end
return err, electoratrue, has_page
end
local function merge(candidates,err,candidatrue,mark,candidates_merge)
for key,bool in pairs(candidatrue) do
if not is_in_list(key,candidates_merge) then
table.insert(err,{"no data",mark,"",key})
elseif not is_in_list(key,candidates) then
table.insert(candidates,key)
end
end
return candidates,err
end
-- =p.cand_listing("","Википедия:Выборы арбитров/Лето 2021/Голосование")
local function cand_listing (err, arb_page)
local candidates, candidatrue = {}, {}
local nom_page = string.gsub( arb_page, "%/Голосование", "/Выдвижение")
-- local pagep_candid_excl = mw.title.new(arb_page .. '/!')
-- local pagep_candid_ampe = mw.title.new(arb_page .. '/&')
local pagep_candid_allvotes = mw.title.new(arb_page .. '/Голоса')
local pagep_candid_nom = mw.title.new(nom_page)
-- local candidates_excl, candidatrue_excl = exclamat(pagep_candid_excl)
-- local candidates_ampe, candidatrue_ampe = ampersan(pagep_candid_ampe)
local candidates_allvotes, candidatrue_allvotes = allvotes(pagep_candid_allvotes)
local candidates_nom, candidatrue_nom = nomination(pagep_candid_nom)
-- if not candidates_excl[1] then
-- table.insert(err,{"no data","service page","",'[['.. tostring(pagep_candid_excl) ..'|/!]]'}) end
-- if not candidates_ampe[1] then
-- table.insert(err,{"no data","allpages changes","",'[['.. tostring(pagep_candid_ampe) ..'|/&]]'}) end
-- if not candidates_allvotes[1] then
-- table.insert(err,{"no data","all votes","",'[['.. tostring(pagep_candid_allvotes) ..'|/Голоса]]'}) end
if not candidates_nom[1] then
table.insert(err,{"no data","nomination","",'[['.. tostring(pagep_candid_nom) ..'|/Выдвижение]]'}) end
candidatrue = candidatrue_allvotes + candidatrue_nom
local err_spec = {}
-- candidates,err_spec = merge(candidates,err_spec,candidatrue,"service page",candidates_excl)
-- candidates,err_spec = merge(candidates,err_spec,candidatrue,"allpages changes",candidates_ampe)
candidates,err_spec = merge(candidates,err_spec,candidatrue,"all votes",candidates_allvotes)
candidates,err_spec = merge(candidates,err_spec,candidatrue,"all votes",candidates_nom)
-- TODO нужна более чёткая проверка наличия расхождений
if not candidates[1] then
for _, er in ipairs(err_spec) do
table.insert(err,er)
end
end
return err, candidates
end
-- todo - сообщения об ошибках, исключение голосов
-- функция для работы через {{Результат выборов арбитров}}
-- =p.open_vote(mw.getCurrentFrame():newChild{title="Википедия:Выборы арбитров/Лето 2021/Голосование",args={"Википедия:Выборы арбитров/Лето 2021/Голосование"}})
function p.open_vote(frame)
local parent = frame:getParent()
local args = parent.args
local ch_args = frame.args --для отладки
local arb_page = ch_args[1] or mw.title.getCurrentTitle().fullText
local return_json = (ch_args[2] == "json")
-- модуль работает на старых страницах, путь приводится к одному формату таким образом
arb_page = string.gsub( arb_page, "%/Голосование%/Предитоги", "/Голосование")
arb_page = string.gsub( arb_page, "%/Голосование%/Предытоги", "/Голосование")
arb_page = string.gsub( arb_page, "%/Форум", "/Голосование")
arb_page = string.gsub( arb_page, "%d%d%d%d ?%d?$", "%0/Голосование")
local err, vote_table = {}, {}
local candidates, electoratrue, exceptions, valid_votes, pre_result, pre_sort
err, candidates = cand_listing (err, arb_page)
err, electoratrue, has_page = elec_listing (err, arb_page)
err, exceptions = caret(err, arb_page .. "/Исключения")
local result = {}
table.insert(result, table_start)
if #candidates > 0 then
for _, candidate in ipairs(candidates) do
err, vote_table = vote_listing (err,vote_table,arb_page,candidate)
end
-- TODO function under construction
err, valid_votes = compute (err,vote_table,electoratrue,exceptions,has_page) --,date
-- mw.logObject(err)
if return_json then
return mw.text.jsonEncode(valid_votes)
end
err, pre_result, pre_sort = reform (err, valid_votes)
-- TODO новая функция - недоделки
for i, cand in ipairs(pre_sort) do
table.insert(result, line_format(i, cand[1], pre_result[cand[1]], arb_page))
end
--mw.logObject(pre_result)
--]]
else
table.insert(err,{"no data","elec","","Отсутствуют кандидаты"})
end
local err_notice = {}
for i, err in ipairs(err) do
err_notice[err[1]] = err_notice[err[1]] or {} -- err type
err_notice[err[1]][err[2]] = err_notice[err[1]][err[2]] or {} -- err group
err_notice[err[1]][err[2]][err[3]] = err_notice[err[1]][err[2]][err[3]] or {} -- err subgroup
table.insert(err_notice[err[1]][err[2]][err[3]],err[4]) -- err messaage
end
local err_mass = {}
for e_type, gr_errs in pairs(err_notice) do
table.insert(err_mass,err_type[e_type])
for e_group, subgr_errs in pairs(gr_errs) do
table.insert(err_mass,e_group)
for e_subgr,e_msgs in pairs(subgr_errs) do
table.insert(err_mass,e_subgr)
for i, e_msg in ipairs(e_msgs) do
table.insert(err_mass,e_msg)
end
end
end
end
-- mw.logObject(err_mass)
if type(err_mass) == "table" and err_mass[1] then
table.insert(err_mass,1,err_start)
table.insert(err_mass,err_end)
table.insert(result,table.concat(err_mass," "))
end
table.insert(result, table_end)
return table.concat(result)
end
return p
|
Index:
pl ar de en es fr it arz nl ja pt ceb sv uk vi war zh ru af ast az bg zh-min-nan bn be ca cs cy da et el eo eu fa gl ko hi hr id he ka la lv lt hu mk ms min no nn ce uz kk ro simple sk sl sr sh fi ta tt th tg azb tr ur zh-yue hy my ace als am an hyw ban bjn map-bms ba be-tarask bcl bpy bar bs br cv nv eml hif fo fy ga gd gu hak ha hsb io ig ilo ia ie os is jv kn ht ku ckb ky mrj lb lij li lmo mai mg ml zh-classical mr xmf mzn cdo mn nap new ne frr oc mhr or as pa pnb ps pms nds crh qu sa sah sco sq scn si sd szl su sw tl shn te bug vec vo wa wuu yi yo diq bat-smg zu lad kbd ang smn ab roa-rup frp arc gn av ay bh bi bo bxr cbk-zam co za dag ary se pdc dv dsb myv ext fur gv gag inh ki glk gan guw xal haw rw kbp pam csb kw km kv koi kg gom ks gcr lo lbe ltg lez nia ln jbo lg mt mi tw mwl mdf mnw nqo fj nah na nds-nl nrm nov om pi pag pap pfl pcd krc kaa ksh rm rue sm sat sc trv stq nso sn cu so srn kab roa-tara tet tpi to chr tum tk tyv udm ug vep fiu-vro vls wo xh zea ty ak bm ch ny ee ff got iu ik kl mad cr pih ami pwn pnt dz rmy rn sg st tn ss ti din chy ts kcg ve
Portal di Ensiklopedia Dunia