Модуль:Enumeration

Материал из Указатель частей и соединений РККА 1941-1945
Перейти к:навигация, поиск

Для документации этого модуля может быть создана страница Модуль:Enumeration/doc

local p = {}
local global = mw.ext.luaglobal
local tools = require( 'Module:Tools' )
local ref = require( 'Module:Ref' )
local report = require( 'Module:Report' )
local lexer = require( 'Module:Lexer' )
local dataOut = mw.loadData( 'Module:DataOut' )
local cargo = mw.ext.cargo

local TYPE_DIV = '2'
local TYPE_SUBDIV = '3'
local TYPE_SUBCORP = '5'


report.space = ' '

--[[
таблица enum
-- --ид вики-страницы (в принципе, он есть, но нужен короткий код «перечень+часть»)--
-- --ид раздела «перечень+разделы»--
-- en = номер перечня - char(?)
-- chap = метка раздела - varchar(16)
-- porno = порно (int)
-- unit = объект (наименование вч) - varchar(300)
-- type = тип объекта (корпус с корпусными частями, корпусная часть, дивизия с составом, часть из состава дивизии, обычная отдельная часть, подразделение обычной части) — char
-- father = порно родителя (для корпусных и дивизионных частей и для подразделений) — int
-- add = флаг наличия допфактов? — Boolean
-- sa_battle = флаг собственных боевых дат (обычно отсутствует для дивизионных частей) — Boolean
-- group = номер группировки внутри дивизии (и настоящей, и мнимой) — char
-- refs = все сноски? text(2048)

таблица enum_add
-- en+chap+porno = связь (ид вики-страницы + порно) перечень-метка-порно
-- what = тип факта (строка в ??? символов)
-- sec_unit = наименование связанной вч — varchar(300)
-- start+stop = дата факта — для фактов типа «экв» и «в составе» нужны диапазоны дат date+date

таблица enum_battle
-- en+chap+porno = связь (ид вики-страницы + порно)
-- start+stop = начальная дата
-- конечная дата

--]]

local function enumLink( eNumb, toc, label )
	local descr = toc[label]
	local part = descr.part
	if part then
		part = ' (часть ' .. part .. ')'
	end
	return 'РККА:Перечень № ' .. eNumb .. ( part or '' ) .. '#enum-' .. label
end

function p.Header( frame )
	local args = tools.checkargs( frame:getParent().args, {
				true, true, -- номер перечня и метка раздела
				true, -- признак фиктивного заголовка
			} )
	local eN = args[1]
	local toc = require( 'Module:EnumTOC/' .. eN )
	local myLabel = mw.text.trim( args[2] )
	local myDescr = toc[myLabel]
	local pager = tonumber( mw.title.getCurrentTitle().subpageText )
	if pager then
		pager = '.' .. string.sub( '0' .. pager, -2, -1 )
	end
	local fiction = args[3]
	assert( not fiction or fiction == '-', 'Ошибка в признаке фиктивного заголовка' )

	local out = {}

	-- можно и для остальных так проверять первый заголовок
	if not	global.get( 'enum-page' ) then
		table.insert( out, frame:callParserFunction{ name = '#seo', args = { '',
				description = 'Перечень № ' .. eN .. '. ' .. ( toc.short or 'Состав действуюшей армии в период Великой отечественной войны' ) .. '.',
				keywords = 'перечни, действующая армия, Великая Отечественная война, боевой состав',
			}
		} )
		if pager then
			table.insert( out, '[[Категория:Перечни (формирование БД)|' 
				.. string.sub( '0' .. eN, -2, -1) .. pager .. ']]<div class=show-disambig>' )
		else
			table.insert( out, '[[Категория:Перечни|' 
				.. string.sub( '0' .. eN, -2, -1).. ']]<div>' )
		end
	end

	if not myDescr.up then
		table.insert( out, '<div class=enum-toc><div class=enum-toc-header>Оглавление</div>' )
		table.insert( out, require( 'Module:EnumTOC' ).makeTOC( eN ) )
		table.insert( out, '</div>' )
	end

	if not fiction then
		if myDescr.up and toc[myDescr.up].part ~= myDescr.part and not myDescr.left
		or myDescr.left and toc[myDescr.left].part ~= myDescr.part then
			-- первый заголовок текущей части, надо выводить оглавление вышестоящих
			-- оно не может быть пустым (это точно не уровень перечня), раз есть верхний или левый элемент
			-- Все они точно в другой части

			local label = myDescr.up

			local outPos = #out+1
			repeat
				local descr = toc[label]
				local outline = { '<div class="enum-toc-' .. descr.level .. '">' }
				if descr.left then
					table.insert( outline, '<span class=enum-left-link>[[' .. enumLink( eN, toc, descr.left )
						.. '|<i class="fa fa-caret-square-o-left></i>]] </span>' )
				end
				table.insert( outline, '[[' .. enumLink( eN, toc, label ) .. '|' )
				if descr[1] ~= '' then
					table.insert( outline, '<span class=enum-numb>' .. descr[1] .. ' </span>' )
				end
				table.insert( outline, '<span class=enum-name>' .. descr[2] .. ' </span>]]' )
				if descr.right then
					table.insert( outline, '<span class=enum-right-link> [[' .. enumLink( eN, toc, descr.right )
						.. '|<i class="fa fa-caret-square-o-right></i>]]</span>' )
				end
				table.insert( outline, '</div>\n' )
				table.insert( out, outPos, table.concat( outline ) )
				label = descr.up
			until not label
			table.insert( out, outPos, '<div class=enum-path>' )
			table.insert( out, '</div>' )
	--		GLOBAL_enum = eN
		elseif myDescr.up and toc[myDescr.up].down ~= myLabel then
			table.insert( out, '<div class=enum-end></div>' )
		end



		table.insert( out, '<div id="enum-' .. myLabel .. '" class="enum-header enum-toc-' .. myDescr.level .. '">' )
		if myDescr.left then
			table.insert( out, '<span class=enum-path-left-link>[[' .. enumLink( eN, toc, myDescr.left )
				.. '|<i class="fa fa-caret-square-o-left></i>]] </span>' )
		end
		if myDescr[1] ~= '' then
			table.insert( out, '<span class=enum-numb>' .. myDescr[1] .. ' </span>' )
		end
		table.insert( out, '<span class=enum-name>' .. myDescr[2] .. ' </span>' )
		if myDescr.right then
			table.insert( out, '<span class=enum-path-right-link> [[' .. enumLink( eN, toc, myDescr.right )
				.. '|<i class="fa fa-caret-square-o-right></i>]]</span>' )
		end
		table.insert( out, '</div>' )
	end
	global.set( 'enum-page', { eN, myLabel .. ( pager or '' ), 0, 0, pager } )
	return table.concat( out )
end


local gender1 = { ['м'] = '', ['ж'] = 'а', ['с'] = 'о', ['х'] = 'и', }
local gender2 = { ['м'] = 'ся', ['ж'] = 'ась', ['с'] = 'ось', ['х'] = 'ись', }
local gender3 = { ['м'] = '', ['ж'] = 'а', ['с'] = 'о', ['х'] = 'ы', }


local mLength = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }

local function parseDate( txt )
	if txt == '' then
		return ''
	end
	local res = mw.text.split( txt, '.', true )
	assert( #res <= 3, 'Кривая дата' )
	local d, m, y = res[#res-2], res[#res-1], res[#res]
	y = tonumber( y )
	assert( y, 'это не дата' )
	if y < 100 then
		y = y+1900
	end
	assert(  y >= 1939 and y <= 1946, 'недопустимый номер года' )
	res = tostring( y )
	if m then
		m = tonumber( m )
		assert( m >= 1 and m <= 12, 'недопустимый номер месяца' )
		res = res .. '-' .. string.sub( '0' .. m, -2, -1 )
		if d then
			d = tonumber( d )
			assert( d >= 1 and d <= mLength[m] and ( m ~= 2 or d ~= 29 or y % 4 == 0 ), 'недопустимое число в месяце' )
			res = res .. '-' .. string.sub( '0' .. d, -2, -1 )
		end
	end
	return res
end


local function parseSingleInterval( str, hard )
	local dates = mw.text.split( str, '%s*%-%s*' )
	assert( #dates == 2, 'Нет диапазона дат' )
	local start = parseDate( dates[1] )
	assert( start, 'Плохая дата ' .. dates[1] )
	local finish = parseDate( dates[2] )
	assert( finish, 'Плохая дата ' .. dates[2] )
	if start == '' or finish == '' then
		assert( not hard, 'Должны быть заданы обе границы интервала дат' )
	else
		assert( start <= finish, 'Извращенный диапазон дат' )
	end
	return start, finish
end

local function parseMultiInterval( str, hard )
	local diaps = mw.text.split( mw.text.trim( str ), '%s*[,;]%s*' )
	local res = {}
	for _, diap in ipairs( diaps ) do
		local start, finish = parseSingleInterval( diap, hard )
		table.insert( res, { start, finish } )
	end
	return res
end

local function concat( tab )
	assert( type( tab ) == 'table' and #tab ~= 0 )
	if #tab == 1 then
		return tab[1]
	end
	return table.concat( tab, ', ', 1, #tab - 1 ) .. ' и ' .. 	tab[#tab]
end


--[[
en			Integer				номер перечня
chap		String(size=16)		метка раздела
porno		Integer
unit		String(size=300)	наименование части (соединения)
type		String(size=1)		тип объекта ("0" — обычная часть; "1" — подразделение обычной части; "2" — дивизия; "3" — часть из состава дивизии; "4" — корпус; "5" — корпусная часть)
top			Integer				porno родителя
ext			Boolean				наличие дополнительной информации
battle		Boolean				наличие собственного боевого периода
unitgroup	String(size=1)		группировка частей внутри дивизии
ref			Text(size=2048)		сноска
ref_battle	Text(size=2048)		сноска к боевому периоду
--]]
--[[
en			Integer				номер перечня
chap		String(size=16)		метка раздела
porno		Integer
event		Integer				тип расширенной информации (всё надо пронумеровать)
unit		String(size=300)	наименование части (соединения), связанной по данному событию
start		Date				начало периода события (или дата события)
stop		Date				конец периода события (или пусто, если событие мгновенное)
ref			Text(size=2048)		сноска
--]]


local function unitPrint( data_enum, data_ext, data_battle, dictionary, nameHL  )

	local lowNameHL = {}
	if type( nameHL ) == 'string' then
		lowNameHL = { [mw.ustring.lower( nameHL )] = true }
	elseif type( nameHL ) == 'table' then
		for _, u in ipairs( nameHL ) do
			lowNameHL[mw.ustring.lower( u )] = true
		end
	end

	local function markHL( unit, str )
		if lowNameHL[mw.ustring.lower( unit )] then
			return '<span class=enum-highlight>' .. ( str or  unit ) .. '</span>'
		end
		return str or unit
	end

	local function unitLink( unit, text, parents )
		if text or not parents then
			return '[[' .. unit .. '|' .. markHL( unit, text ) .. ']]'
		end
		local body = unit
		local shorted, parent, generation, foreign
		repeat
			local  el
			shorted, el = string.match( body, '^(.-)%s+(%b())$' )
			if shorted then
				body = shorted
				el = mw.text.trim( string.sub( el, 2, -2 ) )
				if dataOut.generation[el] then
					generation = ' (' .. el .. ')'
				elseif dataOut.foreigner[el] then
					foreign =  ' (' .. el .. ')'
				else
					parent = el
				end
			end
		until not shorted

		if parent then
			local stored = {}
			parent = string.gsub( parent, '%b()', function( a )
					table.insert( stored, a )
					return '&' .. string.char( 96 + #stored )
				end )
			local parts = mw.text.split( parent, '%s*,%s*' )
			for i, part in ipairs( parts ) do
				part = --[[report.bigfuller( ( ]] string.gsub( part, '&(.)', function ( u )
						return stored[string.byte( u ) - 96]
					end ) --[[ ) ) ]]
				if ( parents[i].unit or '' ) ~= '' then
					parts[i] = '[[' .. parents[i].unit .. '|' .. markHL( parents[i].unit, part ) .. ']]'
				end
			end
--			parent = ' (' .. string.gsub( table.concat( parts, ', ' ), ' формирования%)', '%)' ) .. ')'
			parent = ' (' .. table.concat( parts, ', ' ) .. ')'
		end

		return '[[' .. unit .. '|' .. markHL( unit, body .. ( foreign or '' ) ) .. ']]' .. ( parent or '' ) .. ( generation or '' )
	end

--	local function dmy( arr, field )
--		local d=arr[field]
--		if string.sub( d, 5, 5 ) == '-' then -- данные из базы
--			d = tools.dmy( d )
--			local prec = arr[field .. '__precision']
--			if prec == 2 then
--				d = string.sub( d, 4, 10 )
--			elseif prec == 3 then
--				d = string.sub( d, 7, 10 )
--			end
--		end
--		return string.rep( '&#x2007;', #d-10 ) .. d
--	end
	local function dmy( arr, field )
		local d=arr[field]
		d = tools.dmy( d )
		local prec = arr[field .. '__precision'] -- если из базы
		if prec == '2' then
			d = string.sub( d, 4, 10 )
		elseif prec == '3' then
			d = string.sub( d, 7, 10 )
		end
		return d
	end

	local function diap2text( tree )
		local diapsPrint = {}
		for _, diap in ipairs( tree ) do
			local txt
			if diap.start == '' then
				txt = 'до ' .. dmy( diap, 'stop' )
			elseif diap.stop == '' then
				txt = 'с ' .. dmy( diap, 'start' )
			else
				txt = 'с ' .. dmy( diap, 'start' ) .. ' до ' .. dmy( diap, 'stop' )
			end
			table.insert( diapsPrint, txt )
		end
		return concat( diapsPrint )
	end


	local enumDecode = mw.loadData( 'Module:EnumDecode' )



	local function printEvent( gender, rows, i, j )
		local dsc = enumDecode[rows[i].event]
		local unitStr, unitref
		if j ~= i then
			local units = {}
			for k = i, j do
				local txt = unitLink( rows[k].unit,
					lexer.declension( rows[k].unit, dsc[2] ) or ('<span class=err> ¿ ' .. rows[k].unit .. ' ? </span>' ) )
				if ( rows[k].ref or '' ) ~= '' then
					ref.refStart()
					txt = txt .. ref.use( rows[k].ref )
				end
				table.insert( units, txt )
			end
			unitStr = ' ' .. concat( units)
		else
			if ( rows[i].unit or '' ) ~= '' then
				unitStr = ' ' .. unitLink( rows[i].unit,
					lexer.declension( rows[i].unit, dsc[2] ) or ('<span class=err> ¿ ' .. rows[i].unit .. ' ? </span>' ) )
			end
			if ( rows[i].ref or '' ) ~= '' then
				ref.refStart()
				unitref = ref.use( rows[i].ref )
			end
		end
		assert( dsc[2] or not unitStr )
		local text = string.gsub( dsc[1], '[S%d]',
				{ ['1'] = gender1[gender], ['2'] = gender2[gender], ['3'] = gender3[gender], S = dmy( rows[i], 'start' ) } )
			.. ( unitStr or '' )
		if ( rows[i].start or '' ) ~= '' and not string.find( dsc[1], 'S', 1, true ) then
			text = text .. ' ' .. dmy( rows[i], 'start' )
		end
		return text .. ( unitref or '' ) .. '. '
	end


	local data_extT = {}
	for _, ext in ipairs( data_ext ) do
		ext.event = tonumber( ext.event )
		data_extT[ext.chap] = data_extT[ext.chap] or {}
		data_extT[ext.chap][ext.porno] = data_extT[ext.chap][ext.porno] or {}
		data_extT[ext.chap][ext.porno][enumDecode[ext.event].group] = data_extT[ext.chap][ext.porno][enumDecode[ext.event].group] or {}
		table.insert( data_extT[ext.chap][ext.porno][enumDecode[ext.event].group], ext )
	end
	local data_batT = {}
	for _, dia in ipairs( data_battle ) do
		data_batT[dia.chap] = data_batT[dia.chap] or {}
		data_batT[dia.chap][dia.porno] = data_batT[dia.chap][dia.porno] or {}
		table.insert( data_batT[dia.chap][dia.porno], dia )
	end


	local rowCnt = 1
	local enumrow = data_enum[1]
	local out = {}
	local nextrow
	local lastChapA, lastChap = {}
	local eN, toc
	while enumrow do
		if nameHL then -- запрос со страницы формирования, надо печатать заголовки
			local chap = string.match( enumrow.chap, '^(.+)%.' )
			if chap ~= lastChap then
				if lastChap then
					table.insert( out, '<div class=enum-end></div>' )
				end
				local chapA = mw.text.split( chap, '_' )
				local diff = 0
				repeat
					diff = diff + 1
				until chapA[diff] ~= lastChapA[diff]
				if diff == 1 then
					eN = tonumber( string.sub( chapA[1], 2, 3 ) )
					toc = require( 'Module:EnumTOC/' .. eN )
				end
				lastChapA, lastChap = chapA, chap
				chap = table.concat( lastChapA, '_', 1, diff )
				table.insert( out, '<div class=enum-path-on-unitpage>' )
				for i = diff, #lastChapA do
					local descr = toc[chap]
--					mw.log( chap )
					table.insert( out, '<div class="enum-toc-' .. descr.level .. '">'
						.. '[[' .. enumLink( eN, toc, chap ) .. '|' )
					if descr[1] ~= '' then
						table.insert( out, '<span class=enum-numb>' .. descr[1] .. ' </span>' )
					end
					table.insert( out, '<span class=enum-name>' .. descr[2] .. ' </span>]]' )
					if descr.ref then
						ref.refStart()
						table.insert( out, ref.use( descr.ref ) )
						ref.refReturn()
					end
					table.insert( out, '</div>' )
					chap = chap .. '_' .. ( chapA[i+1] or 'ы' )
				end
				table.insert( out, '</div>' )
			end
		end

		local uniclass
		if ( enumrow.top or '' ) == '' then
			uniclass = 'unit'
		else
			uniclass = 'subu'
		end

		local _, _, gender = lexer.declension( enumrow.unit, 1 )
		local extA = data_extT[enumrow.chap] or {}
		extA = extA[enumrow.porno] or {}

		local printedName
		if extA.show then
			printedName = extA.show[1].ref
		end

		table.insert( out, '<div class=enum-' .. uniclass .. 'row-wrapper><div class=enum-' .. uniclass .. '-wrapper><div class=enum-' .. uniclass .. '>'
			.. unitLink( enumrow.unit, printedName, extA.parentlink ) )
		if ( enumrow.ref or '' ) ~= '' then
			ref.refStart()
			table.insert( out, ref.use( enumrow.ref ) )
		end
--		if extA.parentlink then
--			for _, link in ipairs( extA.parentlink ) do
--				table.insert( out, ' <span class=enum-parentlink>' .. unitLink( link.unit, '<i class="fa fa-external-link"></i>'  ) .. '</span>' )
--			end
--		end
		table.insert( out, '</div>' )

		if extA.add then
			table.insert( out, '<div class=enum-add>' .. extA.add[1].ref .. '</div>' )
		end

		if extA.syn then
			local synonims = {}
			for _, syn in ipairs( extA.syn ) do
				local syntext
				if syn.start == '' then
					if syn.stop == '' then
--						syntext = 'он' .. gender1[gender] .. ' же'
						syntext = ''
					else
--						syntext = 'до ' .. dmy( syn, 'stop' ) .. ' именовал' .. gender2[gender]
						syntext = 'до ' .. dmy( syn, 'stop' ) .. ' — '
					end
				elseif syn.stop == '' then
--					syntext = 'c ' .. dmy( syn, 'start' ) .. ' именовал' .. gender2[gender]
					syntext = 'c ' .. dmy( syn, 'start' ) .. ' — '
				else
--					syntext = 'в период c ' .. dmy( syn, 'start' ) .. ' до ' .. dmy( syn, 'stop' ) .. ' именовал' .. gender2[gender]
					syntext = 'в период c ' .. dmy( syn, 'start' ) .. ' до ' .. dmy( syn, 'stop' ) .. ' — '
				end
				table.insert( synonims,  '<i>' .. syntext .. '</i>' .. unitLink( syn.unit ) )
			end
			table.insert( out, '<div class=enum-syn>[' .. table.concat( synonims, ', ' ) .. ']</div>' )
		end

		if enumrow.type == TYPE_DIV then
			-- состав
			local subarr = {}
			local subCnt = rowCnt
			repeat
				subCnt = subCnt + 1
				local subrow = data_enum[subCnt]
				if not subrow or subrow.type ~= TYPE_SUBDIV then
--					table.insert( out, mw.dumpObject( subrow ) )
					break
				end
				local subExtA = data_extT[subrow.chap] or {}
				subExtA = subExtA[subrow.porno] or {}
--				assert( dictionary[subrow.unit] )
				if ( subrow.unitgroup or '' ) ~= '' then
					-- группа
					local subdia = subExtA.set
					local nextGrow = data_enum[subCnt+1]
--					assert( nextGrow, 'не след. за ' .. subrow.unit )
--					assert( nextGrow.chap == subrow.chap and data_extT[nextGrow.chap], '++ не след. за ' .. subrow.unit .. '\n' .. mw.dumpObject(data_enum) )
					local nextGdia = data_extT[nextGrow.chap] or {}
					nextGdia = nextGdia[nextGrow.porno] or {}   --- nextrow.chap = subrow.chap
					nextGdia = nextGdia.set
					if not subdia --[[ aka and not nextGdia ]] or subdia[1].start == nextGdia[1].start then
						-- группа без раскладки по датам
						local commontext
						subrow.printtext = dictionary[subrow.unit] or report.shorter( subrow.unit )
						subrow.num, commontext = string.match( subrow.printtext, '^(%d+)[ \160](.+)$' )
						local i = subCnt + 1
						while nextGrow.unitgroup == subrow.unitgroup do
							nextGrow.printtext = dictionary[nextGrow.unit] or report.shorter( nextGrow.unit )
							if commontext then
								nextGrow.num = string.match( nextGrow.printtext, '^(%d+) ' .. commontext .. '$' )
								if not nextGrow.num then
									commontext = nil
								end
							end
							i = i + 1
							nextGrow = data_enum[i] or {}
						end
						local printtext
						if commontext then
							printtext = subrow.num
						else
							printtext = subrow.printtext
						end
						printtext = unitLink( subrow.unit, printtext )
						if ( subrow.ref or '' ) ~= '' then
							ref.refStart()
							printtext = printtext .. ref.use( subrow.ref )
						end
						local group = {}
						nextGrow = data_enum[subCnt+1]
						i = subCnt+1
						while nextGrow.unitgroup == subrow.unitgroup do
							local printtext
							if commontext then
								printtext = nextGrow.num
							else
								printtext = nextGrow.printtext
							end
							printtext = unitLink( nextGrow.unit, printtext )
							if ( nextGrow.ref or '' ) ~= '' then
								ref.refStart()
								printtext = printtext .. ref.use( nextGrow.ref )
							end
							table.insert( group, printtext )
							i = i + 1
							nextGrow = data_enum[i] or {}
						end
						printtext = printtext .. ' (' .. table.concat( group, ', ' ) .. ')'
						if commontext then
							printtext = printtext .. ' ' .. commontext
						end
						if subExtA.set then
							printtext = printtext .. ' — <i>' .. diap2text( subExtA.set ) .. '</i>'
						end

						table.insert( subarr, printtext )
						subCnt = i - 1

--						table.insert( subarr, 'GROUP-SYN' )
					else
						-- группа с раскладкой по датам — всегда ровно два элемента
--						assert( group[1].limits[1][1] == group[2].limits[1][2] and group[1].limits[1][2] == '' and group[2].limits[1][1] == '' -- А (до ххх — B)
--							or  group[1].limits[1][2] == group[2].limits[1][1] and group[1].limits[1][1] == '' and group[2].limits[1][2] == '' -- А (с ххх — В)
--							or  group[1].limits[1][2] == group[2].limits[1][1] and group[1].limits[2][1] == group[2].limits[1][2]
--								and group[1].limits[1][1] == '' and group[1].limits[2][2] == '', 'Неприемлемая группировка сроков' ) -- А (с ххх до ууу — В)
						local printtext = unitLink( subrow.unit, dictionary[subrow.unit] or report.shorter( subrow.unit ) )
						if ( subrow.ref or '' ) ~= '' then
							ref.refStart()
							printtext = printtext .. ref.use( subrow.ref )
						end
						printtext = printtext .. ' (<i>' .. diap2text( nextGdia ) .. '</i> — '
						printtext = printtext .. unitLink( nextGrow.unit, dictionary[nextGrow.unit] or report.shorter( nextGrow.unit ) )
						if ( nextGrow.ref or '' ) ~= '' then
							ref.refStart()
							printtext = printtext .. ref.use( nextGrow.ref )
						end
						printtext = printtext .. ')'
						table.insert( subarr, printtext )
						subCnt = subCnt + 1


--						table.insert( subarr, 'GROUP-SEQ' )
--						while subrow.unitgroup == nextGrow.unitgroup do
--							subCnt = subCnt + 1
--							subrow = data_enum[subCnt] or {}
--						end
--						subCnt = subCnt - 1
					end
				else
					-- не группа
					local text = unitLink( subrow.unit, dictionary[subrow.unit] or report.shorter( subrow.unit ) )
					if subExtA.set then
						text = text .. ' — <i>' .. diap2text( subExtA.set ) .. '</i>'
					end
					if ( subrow.ref or '' ) ~= '' then
						ref.refStart()
						text = text .. ref.use( subrow.ref )
					end
					table.insert( subarr, text )
				end
			until false
			nextrow = subCnt
			table.insert( out, '<div class=enum-set-wrapper>' )
			table.insert( out, table.concat( subarr, ', ' ) )
			table.insert( out, '</div>' )
		else
			nextrow = rowCnt + 1
		end
		table.insert( out, '</div>' )

		if extA.c or extA.num then
			table.insert( out, '<div class=enum-create-wrapper>' )
			if extA.c then
				table.insert( out, '<div class=phone-marker><i class="fa fa-check-circle"></i></div>' )
				local i = 1
				while i <= #extA.c do
					local extc = extA.c[i]
					local unit = extc.unit
					if ( unit or '' ) == '' then
						table.insert( out, printEvent( gender, extA.c, i, i ) )
						i = i + 1
					else
						local j = i + 1
						local extn = extA.c[j]
						while extn and extc.event == extn.event and extc.start == extn.start do
							j = j + 1
							extn = extA.c[j]
						end
						table.insert( out, printEvent( gender, extA.c, i, j - 1 ) )
						i = j
					end
				end
			end
			if extA.num then
				table.insert( out, 'Новая нумерация частям дивизии присвоена ' .. dmy( extA.num[1], 'start' ) .. '. ' )
			end
		else
			table.insert( out, '<div class="enum-create-wrapper empty-wrapper">' )
		end
		table.insert( out, '</div>' )

		table.insert( out, '<div class=enum-time-wrapper>' )
		local diabat = data_batT[enumrow.chap] or {}
		diabat = diabat[enumrow.porno]
		if diabat then
			table.insert( out, '<div class=phone-marker>[[Файл:History swords.png|12px|link=]]</div>' )
			for _, dia in ipairs( diabat ) do
				local d1, d2 = dmy( dia, 'start' ), dmy( dia, 'stop' )
				table.insert( out,
					'<span class=date-field>' .. string.rep( '&#x2007;&#x2007;', (10-#d1)/3 ) .. d1 .. '</span>-'
					.. '<span class=date-field>' .. string.rep( '&#x2007;&#x2007;', (10-#d2)/3 ) .. d2 .. '</span> ' )
			end
			if ( enumrow.ref_battle or '' ) ~= '' then
				ref.refStart()
				table.insert( out, ref.use( enumrow.ref_battle ) )
			end
		end
		table.insert( out, '</div>' )

		if extA.d then
			table.insert( out, '<div class=enum-death-wrapper>' )
			table.insert( out, '<div class=phone-marker><i class="fa fa-times-circle"></i></div>' )
			local i = 1
			while i <= #extA.d do
				local extc = extA.d[i]
				local unit = extc.unit
				if ( unit or '' ) == '' then
					table.insert( out, printEvent( gender, extA.d, i, i ) )
					i = i + 1
				else
					local j = i + 1
					local extn = extA.d[j]
					while extn and extc.event == extn.event and extc.start == extn.start do
						j = j + 1
						extn = extA.d[j]
					end
					table.insert( out, printEvent( gender, extA.d, i, j - 1 ) )
					i = j
				end
			end
		else
			table.insert( out, '<div class="enum-death-wrapper empty-wrapper">' )
		end
		table.insert( out, '</div>' )
		table.insert( out, '</div>' )
		rowCnt = nextrow
		enumrow = data_enum[rowCnt]
	end
	if nameHL then
		table.insert( out, '<div class=enum-end></div>' )
	end
	return table.concat( out )
end


local function unitrow( args, subunit )
	local enumEncode = mw.loadData( 'Module:EnumEncode' )
	local dictionary = {}
	local title
	local function unitfuller( str, badAbbr, parents )
		local clear = string.match( str, '^(.-)%s*!$' )
		if not clear then
			clear = str
		else -- эксперимент, инверсия смысла «!»
			parents = nil
		end
		local show, tilda = string.match( clear, '^([^~]-)%s*~%s*(.*)$' )
		if show then
			if tilda == '' then
				tilda = title
			end
			clear = show .. ' (' .. tilda .. ')'
		else
			show = clear
		end
		local name = report.bigfuller( clear, badAbbr, parents )
--		dictionary[name] = show
		return name
	end

--	local uniclass
--	if subunit then
--		uniclass = 'subu'
--	else
--		uniclass = 'unit'
--	end
	local eN, label, porno, lastUp, pager = unpack( global.get( 'enum-page' ) )
	porno = porno+1
	local locno = 0
	local data_enum, data_ext, data_battle = {}, {}, {}
	local parents = {}
	title = unitfuller( args[1], nil, parents )
	data_enum[1] = {
--		en        = eN,
		chap      = label,
		porno     = porno,
		unit      = title,
		ref       = args['сноска'],
		unitgroup = nil,
	}
	if subunit then
		data_enum[1].top = lastUp
		data_enum[1].type = TYPE_SUBCORP
	else
		lastUp = porno
	end

	if next( parents ) then
		data_enum[1].ext = true
		for _, parent in ipairs( parents ) do
			locno = locno + 1
			table.insert( data_ext, {
					chap   = label,
					porno  = porno,
					locno  = locno,
					event  = enumEncode.parentlink,
					unit   = parent,
				} )
		end
	end

	if args['название'] then
		data_enum[1].ext = true
		locno = locno + 1
		table.insert( data_ext, {
--					en     = eN,
				chap   = label,
				porno  = porno,
				locno  = locno,
				event  = enumEncode.show,
				ref    = args['название'],
			} )
	end


	if args['синоним'] then
		data_enum[1].ext = true
		local syns = mw.text.split( args['синоним'], '%s*&%s*' )
		for _, syn in ipairs( syns ) do
			local el = mw.text.split( syn, '%s*;%s*' )
			assert( #el == 3, 'Ошибка в описании альтернативного наименования (' .. syn .. ')' )
			local code = enumEncode[el[1]]
			assert( code, 'Неизвестный описатель альтернативного наименования' )
			local start, finish = parseSingleInterval( el[2] )
			locno = locno + 1
			table.insert( data_ext, {
--					en     = eN,
					chap   = label,
					porno  = porno,
					locno  = locno,
					event  = code,
					unit   = unitfuller( el[3] ),
					start  = start,
					stop   = finish,
					ref    = args['сноска/синоним'],
				} )

		end
	end

	if args['дополнение'] then
		data_enum[1].ext = true
		local code = enumEncode['прицеп']
		locno = locno + 1
		table.insert( data_ext, {
				chap   = label,
				porno  = porno,
				locno  = locno,
				event  = code,
				ref    = args['дополнение'],
			} )
	end

	if args['нумерация'] then
		data_enum[1].ext = true
		local date = parseDate( args['нумерация'] )
		assert( date ~= '' )
		locno = locno + 1
		table.insert( data_ext, {
--				en     = eN,
				chap   = label,
				porno  = porno,
				locno  = locno,
				event  = enumEncode['*|нумерация'],
				start  = date,
		} )
	end

	if args['создание'] then
		data_enum[1].ext = true
		local creating = mw.text.split( args['создание'], '%s*;%s*' )
		assert( #creating == 3, 'Непонятная структура описателя создания' )
		local date = parseDate( creating[3] )
		local way  = mw.ustring.lower( creating[1] )
		local n
		way, n = mw.ustring.gsub( way, '([ае]н)[аоы]? из', '%1 из' )
		if n == 0 then
			way, n = mw.ustring.gsub( way, '([ае]н)[аоы]? на базе', '%1 на базе' )
		end
		if n == 0 then
			way, n = mw.ustring.gsub( way, '(ят)[аоы]? из', '%1 из' )
		end
		if n == 0 then
			way, n = mw.ustring.gsub( way, '(ыл)[аои]? из', '%1 из' )
		end
		assert( enumEncode['+|' .. way], '	неведомый способ создания: «' .. way .. '»' )
		way = enumEncode['+|' .. way]
		local multisource = mw.text.split( creating[2], '%s*%+%s*' )
		for _, monosource in ipairs( multisource ) do
			locno = locno + 1
			table.insert( data_ext, {
--					en     = eN,
					chap   = label,
					porno  = porno,
					locno  = locno,
					unit   = unitfuller( monosource ),
					event  = way,
					start  = date,
					ref    = args['сноска/создание'],
			} )
		end
	end

	if args['судьба'] then
		data_enum[1].ext = true
		local deaths = mw.text.split( args['судьба'], '%s*&%s*' )
		for _, deathPart in ipairs( deaths ) do
			local death = mw.text.split( deathPart, '%s*;%s*' )
			local date = parseDate( death[3] )
			local way  = mw.ustring.lower( death[1] )
			way = string.gsub( way, ' во$', ' в' )
			local n
			way, n = mw.ustring.gsub( way, '^([^ ]+[ае]н)[аоы]? ', '%1 ' )
			if n == 0 then
				way, n = mw.ustring.gsub( way, '(расформирован)[аоы]?', '%1' )
			end
			if n == 0 then
				way, n = mw.ustring.gsub( way, '(шл)[аои]? ', '%1 ' )
			end
			assert( enumEncode['-|' .. way], '	неведомая судьба: «' .. way .. '»' )
			way = enumEncode['-|' .. way]
			if ( death[2] or '' ) ~= '' then
				local multitarget = mw.text.split( death[2], '%s*%+%s*' )
				for _, monotarget in ipairs( multitarget ) do
					locno = locno + 1
					table.insert( data_ext, {
	--						en     = eN,
							chap   = label,
							porno  = porno,
							locno  = locno,
							unit   = unitfuller( monotarget ),
							event  = way,
							start  = date,
							ref    = args['сноска/судьба'],
					} )
				end
			else
				locno = locno + 1
				table.insert( data_ext, {
	--					en     = eN,
						chap   = label,
						porno  = porno,
						locno  = locno,
						unit   = nil,
						event  = way,
						start  = date,
						ref    = args['сноска/судьба'],
				} )
			end
		end
	end


	if args['период'] then
		data_enum[1].battle = true
		local intervals = parseMultiInterval( args['период'], true )
		for _, inter in ipairs( intervals ) do
			table.insert( data_battle, {
--					en     = eN,
					chap   = label,
					porno  = porno,
					start  = inter[1],
					stop   = inter[2],
			} )
		end
		data_enum[1].ref_battle = args['сноска/период']
	end

	if args['состав'] then
		data_enum[1].type = TYPE_DIV
		local hiddenRef = {}
		local children = string.gsub( args['состав'], '%{([^}]+)%}', function ( str )
				table.insert( hiddenRef, mw.text.trim( str ) )
				return '{' .. #hiddenRef .. '}'
			end )
		local hiddenDiap = {}
		children = string.gsub( children, '%[([^%]]+)%]', function ( str )
				table.insert( hiddenDiap, mw.text.trim( str ) )
				return '[' .. #hiddenDiap .. ']'
			end )
		children = mw.text.split( children, '%s*,%s*' )
		local group
		local groupMarker = 64 -- string.code( 'A' ) - 1
		for _, child in ipairs( children ) do
			local a, reference = string.match( child, '^([^*]+)%*%s*(.+)$' )
			if a then
				child = mw.text.trim( a )
			end
			local obra, childN, tail = string.match( child, '^(%(?)%s*([^[%*]+)(.*)$' )
			assert( obra )
			if obra == '(' then
				assert( not group, 'Вложенные скобки ' .. child )
				group = {}
				groupMarker = groupMarker + 1
			end
			childN = mw.text.trim( childN )
			local childD, cbra = nil, ''
			local limits
			if tail ~= '' then
				childD, cbra = string.match( tail, '^%[([^%]]+)%]%s*(%)?)$' )
				assert( childD )
			elseif group and cbra == '' then
				if string.sub( childN, -1 ) == ')' then
					local _, o = string.gsub( childN, '%(', function () end )
					local _, c = string.gsub( childN, '%)', function () end )
					if c == o + 1 then
						cbra  = ')'
						childN = mw.text.trim( string.sub( childN, 1, -2 ) )
					end
				end
			end
			if childD then
				childD = hiddenDiap[tonumber( childD )]
				limits = parseMultiInterval( childD )
			end
			if reference then
				reference = string.gsub( reference, '%{([^%}]+)%}', function ( str )
						return hiddenRef[tonumber( str )]
					end )
			end
--			childN = unitfuller( childN, { ['минд'] = 'минометный дивизион' } )
			childN = unitfuller( childN, mw.loadData('Module:Redata').BadEnum )
--			dictionary[full], childN = childN, full
--			mw.log( obra .. ' | ' .. childN .. ' | ' .. tail .. ' | ' .. ( childD or '' ) .. ' | ' .. cbra )
			assert ( obra == '' or cbra == '' )
			if group then
				table.insert( group, { name = childN, diap = childD, limits = limits, ref = reference } )
				if cbra ~= '' then
					assert( group and #group > 1 )
					local seq = group[1].diap ~= group[2].diap
					if seq then
						assert( #group == 2 )
						-- ( 71 гв. обс [-05.05.1943, 14.11.1944-], 71 гв. орс [05.05.1943-14.11.1944] )
						assert( group[1].limits[1][1] == group[2].limits[1][2] and group[1].limits[1][2] == '' and group[2].limits[1][1] == '' -- А (до ххх — B)
							or  group[1].limits[1][2] == group[2].limits[1][1] and group[1].limits[1][1] == '' and group[2].limits[1][2] == '' -- А (с ххх — В)
							or  group[1].limits[1][2] == group[2].limits[1][1] and group[1].limits[2][1] == group[2].limits[1][2]
								and group[1].limits[1][1] == '' and group[1].limits[2][2] == '', 'Неприемлемая группировка сроков' ) -- А (с ххх до ууу — В)
					end
					for _, u in ipairs( group ) do
						porno = porno + 1
						locno = 0
						table.insert( data_enum, {
--								en        = eN,
								chap      = label,
								porno     = porno,
								unit      = u.name,
								type      = TYPE_SUBDIV,
								top       = lastUp,
								unitgroup = string.char( groupMarker ),
								ref       = u.ref,
						} )
						if u.diap then
							data_enum[#data_enum].ext = true
							for _, v in ipairs( u.limits ) do
								locno = locno + 1
								table.insert( data_ext, {
--										en     = eN,
										chap   = label,
										porno  = porno,
										locno  = locno,
										event  = enumEncode['*|в составе дивизии'],
										start  = v[1],
										stop   = v[2],
								} )
							end
						end
					end
					group = nil
				end
			else
				porno = porno + 1
				locno = 0
				table.insert( data_enum, {
--						en        = eN,
						chap      = label,
						porno     = porno,
						unit      = childN,
						type      = TYPE_SUBDIV,
						top       = lastUp,
						ref       = reference,
				} )
				if childD then
					for _, v in ipairs( limits ) do
						data_enum[#data_enum].ext = true
						locno = locno + 1
						table.insert( data_ext, {
--								en     = eN,
								chap   = label,
								porno  = porno,
								locno  = locno,
								event  = enumEncode['*|в составе дивизии'],
								start  = v[1],
								stop   = v[2],
						} )
					end
				end
			end
		end -- for ipairs(состав)
	end -- if args[состав]
	local z = ''
	if pager then
		local frame = mw.getCurrentFrame()
		for _, u in ipairs( data_enum ) do
	--		z = z .. frame:expandTemplate{ title = 'Таблица строк перечня', args = u }
			u._table = 'enum'
			u[1] = ''
			z = z .. frame:callParserFunction( '#cargo_store', u )
		end
		for _, u in ipairs( data_ext ) do
	--		z = z .. frame:expandTemplate{ title = 'Таблица расширенной информации перечня', args = u }
			u._table = 'enum_ext'
			u[1] = ''
			z = z .. frame:callParserFunction( '#cargo_store', u )
		end
		for _, u in ipairs( data_battle ) do
	--		z = z .. frame:expandTemplate{ title = 'Таблица боевых периодов', args = u }
			u._table = 'enum_battle'
			u[1] = ''
			z = z .. frame:callParserFunction( '#cargo_store', u )
		end
	end
	global.set( 'enum-page', { eN, label, porno, lastUp, pager } )
	return unitPrint( data_enum, data_ext, data_battle, dictionary )
end

function p.unitQuery( name ) -- запрос из модулей Page и Disambigution
	-- основные упоминания
	-- упоминания в расширениях
	-- родители всех упоминаний
	-- дети основных упоминаний и упоминаний как синонимов

	-- 1. собираем основные упоминания (M:[name] = A)
	-- 2. собираем упоминания в расширениях (X:[name] = B)
	-- 3. собираем недостающие элементы основной таблицы (M:(B[syn]-A) = C)
	-- 4. нам нужны родители (M:(A+B) = D)
	-- 5. Нам нужны дети (M:(A+C) = E)
	-- 6. Собираем недостающие расширения (X:(A+C+D+E))
	local function makeWhere( tab, fieldV, fieldN )
		local where = {}
		for _, u in pairs( tab ) do
			table.insert( where, 'chap="' .. u.chap .. '" AND ' .. ( fieldN or 'porno' ) .. '=' .. u[fieldV or 'porno'] )
		end
		return '( ' .. table.concat( where, ' OR ' ) .. ' )'
	end

	local where
	if type( name ) == 'table' then
		where = '( unit="' .. table.concat( name, '" OR unit="' ) .. '" )'
	else
		where = 'unit="' .. name .. '"'
	end
	local queryA = cargo.query(
		'enum',
		'chap, porno, unit, type, top, ext, battle, unitgroup, ref, ref_battle, CONCAT(chap, ":", porno)=idx',
		{
			where = where,
			orderBy = 'chap, porno',
		} )
	local need_main = {}
	local recieved_main = {}
	local need_children = {}
	local requery = {}
	for _, row in ipairs( queryA ) do
		recieved_main[row.idx] = row
		need_children[row.idx] = row
	end
	local orRecieved = ''
	if next( recieved_main ) then
		orRecieved = ' OR event=1 AND ' .. makeWhere( recieved_main )
	end
	local queryB = cargo.query(
		'enum_ext',
		'chap, porno, locno, event, unit, start, stop, ref, CONCAT(chap, ":", porno)=idx',
		{
			where = where .. orRecieved,
			orderBy = 'chap, porno, locno',
		} )
	for _, row in ipairs( queryB ) do
		if not recieved_main[row.idx] then
			table.insert( need_main, row )
			if row.event == '1' then
				need_children[row.idx] = row
			end
		else
			table.insert( requery, row.unit )
		end
	end
	if #requery ~= 0 then
		local queryAplus = cargo.query(
			'enum',
			'chap, porno, unit, type, top, ext, battle, unitgroup, ref, ref_battle, CONCAT(chap, ":", porno)=idx',
			{
				where = '( unit="' .. table.concat( requery, '" OR unit="' ) .. '" )',
				orderBy = 'chap, porno',
			} )
		for _, row in ipairs( queryAplus ) do
			if not recieved_main[row.idx] then
				table.insert( queryA, row )
				recieved_main[row.idx] = row
				need_children[row.idx] = row
			end
		end
	end

	if next( need_main ) then
		local queryC = cargo.query(
			'enum',
			'chap, porno, unit, type, top, ext, battle, unitgroup, ref, ref_battle, CONCAT(chap, ":", porno)=idx',
			{
				where = makeWhere( need_main ),
				orderBy = 'chap, porno',
			} )
		for _, row in ipairs( queryC ) do
			recieved_main[row.idx] = row
			table.insert( queryA, row )
		end
	end

	if #queryA == 0 then
		return nil
	end

	-- queryA — массив записей основной таблицы   =p.unitQuery('284 бомбардировочная авиационная дивизия')
	need_main = {}
	for _, row in ipairs( queryA ) do
		if row.top ~= '' and not recieved_main[row.chap..':'..row.top] then
			table.insert( need_main, 'chap="' .. row.chap .. '" AND porno=' .. row.top )
		end
		if row.unitgroup ~= '' then
			table.insert( need_main, 'chap="' .. row.chap .. '" AND top=' .. row.top .. ' AND  unitgroup="' .. row.unitgroup .. '"' )
		end -- чревато дубликатами
	end
	for _, row in pairs( need_children ) do
		table.insert( need_main, 'chap="' .. row.chap .. '" AND top=' .. row.porno )
	end

	if #need_main ~= 0 then
		local queryD = cargo.query(
			'enum',
			'chap, porno, unit, type, top, ext, battle, unitgroup, ref, ref_battle, CONCAT(chap, ":", porno)=idx',
			{
				where = table.concat( need_main, ' OR ' ),
				orderBy = 'chap, porno',
			} )
		for _, row in ipairs( queryD ) do
			if not recieved_main[row.idx] then
				recieved_main[row.idx] = row -- а так мы дубликаты побороли
				table.insert( queryA, row )
			end
		end
	end

	table.sort( queryA, function ( a, b )
			return a.chap < b.chap or ( a.chap == b.chap and tonumber( a.porno ) < tonumber( b.porno ) )
		end )

	local i = 1
	while i < #queryA do
		if queryA[i].idx == queryA[i+1].idx then
			table.remove( queryA, i )
		else
			i = i + 1
		end
	end

--	local need_ext = {}
--	for _, row in ipairs( queryA ) do
--		table.insert( need_ext, 'chap="' .. row.chap .. '" AND porno=' .. row.porno )
--	end
--	if #need_ext ~= 0 then
	local queryE = cargo.query(
		'enum_ext',
		'chap, porno, event, unit, start, stop, ref, CONCAT(chap, ":", porno)=idx, start__precision, stop__precision',
		{
			where = makeWhere( queryA ),
			orderBy = 'chap, porno, locno',
		} )
--	for _, row in ipairs( queryE ) do
--		if not recieved_ext[row.idx] then
--			table.insert( queryB, row )
--		end
--	end
--	end

	local queryF = cargo.query(
		'enum_battle',
		'chap, porno, start, stop, start__precision, stop__precision',
		{
			where = makeWhere( queryA ),
			orderBy = 'chap, porno, start',
		} )

	if #queryA == 0 then
		return nil
	end
	return unitPrint( queryA, queryE, queryF, {}, name )

--[====[
	local queryB = cargo.query(
		'enum_ext',
		'chap, porno, locno, event, unit, start, stop, ref, CONCAT(chap, ":", porno)=idx',
		{
			where = where,
			orderBy = 'chap, porno, locno',
		} )
	for _, row in ipairs( queryB ) do
		if not recieved_main[row.idx] then
			table.insert( need_main, row )
		end
		recieved_ext[row.idx] = row
		if row.event == '1' then
			need_children[row.idx] = row
		end
	end
	if next( need_main ) then
		local queryC = cargo.query(
			'enum',
			'chap, porno, unit, type, top, ext, battle, unitgroup, ref, ref_battle, CONCAT(chap, ":", porno)=idx',
			{
				where = makeWhere( need_main ),
				orderBy = 'chap, porno',
			} )
		for _, row in ipairs( queryC ) do
			recieved_main[row.idx] = row
			table.insert( queryA, row )
		end
	end
	-- queryA — массив записей основной таблицы   =p.unitQuery('284 бомбардировочная авиационная дивизия')
	need_main = {}
	for _, row in ipairs( queryA ) do
		if row.top ~= '' and not recieved_main[row.chap..':'..row.top] then
			table.insert( need_main, 'chap="' .. row.chap .. '" AND porno=' .. row.top )
		end
		if row.unitgroup ~= '' then
			table.insert( need_main, 'chap="' .. row.chap .. '" AND top=' .. row.top .. ' AND  unitgroup="' .. row.unitgroup .. '"' )
		end -- чревато жубликатами
	end
	for _, row in pairs( need_children ) do
		table.insert( need_main, 'chap="' .. row.chap .. '" AND top=' .. row.porno )
	end

	if #need_main ~= 0 then
		local queryD = cargo.query(
			'enum',
			'chap, porno, unit, type, top, ext, battle, unitgroup, ref, ref_battle, CONCAT(chap, ":", porno)=idx',
			{
				where = table.concat( need_main, ' OR ' ),
				orderBy = 'chap, porno',
			} )
		for _, row in ipairs( queryD ) do
			if not recieved_main[row.idx] then
				recieved_main[row.idx] = row
				table.insert( queryA, row )
			end
		end
	end

	table.sort( queryA, function ( a, b )
			return a.chap < b.chap or ( a.chap == b.chap and tonumber( a.porno ) < tonumber( b.porno ) )
		end )

	local need_ext = {}
	for _, row in ipairs( queryA ) do
		if not recieved_ext[row.idx] then
			table.insert( need_ext, 'chap="' .. row.chap .. '" AND porno=' .. row.porno )
		end
	end
	if #need_ext ~= 0 then
		local queryE = cargo.query(
			'enum_ext',
			'chap, porno, event, unit, start, stop, ref, CONCAT(chap, ":", porno)=idx',
			{
				where = table.concat( need_ext, ' OR ' ),
				orderBy = 'chap, porno, locno',
			} )
		for _, row in ipairs( queryE ) do
			if not recieved_ext[row.idx] then
				table.insert( queryB, row )
			end
		end
	end

	local queryF = cargo.query(
		'enum_battle',
		'chap, porno, start, stop',
		{
			where = makeWhere( queryA ),
			orderBy = 'chap, porno, start',
		} )

	if #queryA == 0 then
		return nil
	end
	return unitPrint( queryA, queryB, queryF, {}, name )
--]====]
end

function p.UnitQuery( frame )
	return p.unitQuery( frame.args.unit )
end


function p.Unit( frame )
	local args = tools.checkargs( frame:getParent().args, {
			true, ['сноска'] = true, ['синоним'] = true,
			['дополнение'] = true, ['название'] = true,
			['состав'] = true, -- ['сноска/состав'] = true,
			['создание'] = true, ['сноска/создание'] = true,
			['нумерация'] = true,
			['судьба'] = true, ['сноска/судьба'] = true,
			['период'] = true, ['сноска/период'] = true,
		} )
	return ref.refReturn( unitrow( args ) )
end

function p.Subunit( frame )
	local args = tools.checkargs( frame:getParent().args, {
			true, ['сноска'] = true, ['синоним'] = true,
			['дополнение'] = true,
			['создание'] = true, ['сноска/создание'] = true,
			['судьба'] = true, ['сноска/судьба'] = true,
			['период'] = true, ['сноска/период'] = true,
		} )
	return ref.refReturn( unitrow( args, true ) )
end

function p.End( frame )
	local args = tools.checkargs( frame:getParent().args, {
			true
		} )
	local pager = tonumber( mw.title.getCurrentTitle().subpageText )
	if pager or not args[1] then
		ref.refStart()
		return '<div class=enum-end></div>' .. ref.refOut() .. '</div>'
	end
end

return p