Модуль:CargoObjectDump

Материал из Справочника наблюдателя
Перейти к:навигация, поиск

(i)      Описание модуля[]

Документация отсутствует!


local p = {}

local global = mw.ext.luaglobal
local cargo = mw.ext.cargo;
local Geobase = global.get( 'Geobase' )
local Fields = global.get( 'Fields' )
local Region = global.get( 'RegionCode' )
local GeoParam = global.get( 'GeoParam' )

global.strict( true )

local function collectObjects( ctg )
	local basename = mw.title.getCurrentTitle().baseText
	local collectPage = mw.title.new( basename .. '/Сборка' )
	local bases, subs = {}, {}
	if collectPage.id ~= 0 then
		local content = mw.text.trim( collectPage:getContent() or '' )
		content = mw.text.split( content, '[\t\f ]*[\r\n]+[\t\f ]*' )
		for _, val in pairs( content ) do
			if val ~= '' then
				local z = mw.ustring.sub( val, 1, 1 )
				if val == '/' then
					subs[#subs+1] = ''
				elseif z == '/' then
					subs[#subs+1] = val
				elseif z == ':' then
					bases[#bases+1] = basename .. val
				else
					bases[#bases+1] = val
				end
			end
		end
	end

	if #bases == 0 then
		bases = { basename }
	end
	if ctg then
		subs = { '/' .. ctg }
	elseif #subs == 0 then
		subs = { '/УИК', '/Власти', '/Сервисы' }
	end

	local basesCounter, subsCounter = 1, 0
	return function ()
				subsCounter = subsCounter + 1
				if subsCounter > #subs then
					basesCounter = basesCounter + 1
					if basesCounter > #bases then
						return nil
					end
					subsCounter = 1
				end
				return bases[basesCounter] .. subs[subsCounter] -- , mw.ustring.sub( subs[subsCounter], 2, -1 )
			end,
		bases --- еще надо понять, что мы хотим
end


local function normUIK (numbUIK)
	return string.gsub ( '' .. numbUIK, '^0*([0-9]+)[%-/]?([0-9]*)$', '%1%2' )
end

local prec_color = { '#CCC', '#3366BB', '#ff9900', 'red' }

local function showAddr ( row, prefix, alt )
	local addr, org, lat, lon, prec, show =
		row[prefix..'_addr'], row[prefix..'_org'], row[prefix..'_geo__lat'],
		row[prefix..'_geo__lon'], tonumber( row[prefix..'_geo_p'] ), row[prefix..'_geo_s']
	local result = addr
	if ( addr or '' ) == '' then
		return ''
	end
	if org ~= '' then
		result = result .. ' — ' .. org
	end
	if alt then
		result = result .. ' <span style="color:#746963; font-style:italic">(' .. alt .. ')</span>'
	end
	local marker
	if prec > 4 then
		marker = 'pin'
		prec = prec - 4
	else
		marker = 'marker-alt'
	end
	result = result .. '&nbsp;[http://m.nablawiki.ru/?' .. GeoParam
		.. '&addressSpecial=' .. mw.uri.encode( addr, 'PATH' )
	if ( lat or 0 ) ~= 0 then
		result = result .. '&latlon=' .. lat .. ',' .. lon
		prec = prec_color[ prec ]
	else
		prec = 'red'
	end
	result = result .. ' <span class="fas fa-map-' .. marker .. '" style="color:' .. prec
		.. '" title="на карте"></span>]'
	return result
end

local function compositeAddr ( row )
	local addr, org = row['room_addr'], row['room_org']
	local addrO, orgO = row['office_addr'], row['office_org']
	if ( addrO or '' ) == '' then
		return showAddr( row, 'room' )
	end
	if addr ~= addrO then
		return showAddr( row, 'room' ) .. '<br><span style="color:#746963; font-style:italic">'
			.. showAddr( row, 'office' ) .. '</span>'
	end
	if org == orgO then
		return showAddr( row, 'room' )
	end
	return showAddr( row, 'room', orgO )
end

local function compositePhone( row )
	local room, offi = row.room_phone, row.office_phone
	if room == offi then
		return room
	end
	return room .. '<br><span style="color:#746963; font-style:italic">' .. offi .. '</span>'
end

local tabC = {
	['номер']           = { 'style="width:4en;"',
							'УИK',
							'style="text-align:center; font-weight:bold;"',
							function ( row )
								local s = row.number
								if s == '' then
									return ''
								else
									local txt = '[https://www.wikiuiki.org/ik/' .. Region .. '-uik-' .. normUIK (s) .. ' ' .. s .. ']';
									if (row.gas or '') ~= '' then
										txt = txt .. ' [' .. row.gas .. ' <sup><span style="color:red">§</span></sup>]';
									end
									if row.temp ~= '' then
										txt = '{{подсказка|<i>' .. txt .. '</i>|временный участок}}'
									end
									return txt
								end
							end,
						  },
	['мо']              = { '',
							'МО',
							'style="font-size:83%; line-height:95%;"',
							'mun',
						  },
	['округ']           = { 'style="width:3en;"',
							'<small>округ</small>',
							'style="text-align:center;"',
							'district',
						  },
	['коиб']            = { 'style="width:2en;"',
							'<small>KОИБ</small>',
							'style="text-align:center;"',
							'koib',
						  },
--      ['временный']       = { 'style="width:2en;"',
--                              '<small>{{подсказка|вр.|участок, созданный для временно пребывающих}}</small>',
--								'style="text-align:center;"',
--                            },
	['численность']     = { 'style="width:4en;"',
							'изб.',
							'style="text-align:right;"',
							'quantity',
						  },
	['прг']             = { '',
							'{{подсказка|ПPГ|число членов комиссии с правом решающего голоса}}',
							'style="text-align:center;"',
							'members',
						  },
	['адрес']           = { 'class=unsortable',
							'адрес помещения',
							'style="font-size:92%; line-height:95%;"',
							function ( row )
								return showAddr( row, 'room' )
							end
						  },
	['адреса']          = { 'class=unsortable',
							'адрес помещения, <i>адрес офиса</i>',
							'style="font-size:92%; line-height:95%;"',
							compositeAddr,
						  },
	['телефон']         = { 'class=unsortable',
							'телефон',
							'',
							'room_phone',
						  },
	['телефоны']        = { 'class=unsortable',
							'телефоны',
							'',
							compositePhone,
						  },
	['адрес офиса']     = { 'class=unsortable',
							'адрес офиса',
							'style="font-size:92%; line-height:95%;"',
							function ( row )
								return showAddr( row, 'office' )
							end
						  },
	['телефон офиса']   = { 'class=unsortable',
							'тел. офиса',
							'',
							'office_phone',
						  },
	['границы']         = { 'class=unsortable',
							'границы избирательного участка',
							'style="font-size:83%; line-height:95%;"',
							'border',
						  },
	['тип']             = { 'style="width:3en; border-right:0px;"',
							' ',
							'style="font-size:83%; line-height:95%;"',
							'label',
						  },
	['наименование']    = { '',
							'наименование органа',
							'',
							'name',
						  },
--	['метка']           = { '',
--							'сокр.',
--						  },
	['сайты']           = { 'class=unsortable',
							'сайты',
							'style="font-size:83%; line-height:95%;"',
							'site',
						  },
	['примечание']      = { 'class=unsortable',
							'примечание',
							'style="font-size:83%; line-height:95%;"',
							'addendum',
						  },
	['#явка']           = { '',
							'явка',
							'',
							'x_turnout',
						  },
	['#досрочно']       = { '',
							'доср.',
							'',
							'x_before',
						  },
	['#дома']           = { '',
							'дома',
							'',
							'x_home',
						  },
	['#власть']         = { '',
							'власть',
							'',
							'x_loyal',
						  },
	['#явка%']          = { '',
							'явка',
							'',
							function ( row )
								if (row.quantity or 0) ~= 0 then
									return string.format('%4.1f', tonumber (row.x_turnout) / tonumber (row.quantity) * 100) .. '%'
								else
									return ''
								end
							end,
						  },
	['#досрочно%']      = { '',
							'доср.',
							'',
							function ( row )
								if (row.quantity or 0) ~= 0 then
									return string.format('%4.1f', tonumber (row.x_before) / tonumber (row.quantity) * 100) .. '%'
								else
									return ''
								end
							end,
						  },
	['#дома%']          = { '',
							'дома',
							'',
							function ( row )
								if (row.quantity or 0) ~= 0 then
									return string.format('%4.1f', tonumber (row.x_home) / tonumber (row.quantity) * 100) .. '%'
								else
									return ''
								end
							end,
						  },
	['#власть%']        = { '',
							'власть',
							'',
							function ( row )
								if (row.quantity or 0) ~= 0 then
									return string.format('%4.1f', tonumber (row.x_loyal) / tonumber (row.quantity) * 100) .. '%'
								else
									return ''
								end
							end,
						  },
}


function p.tab( frame )
--[=[
	Может вызываться на странице с объектами или на сторонней странице
	Родную страницу распознаем либо по наличию глобальных Fields либо Geobase
	Типы и метки надо объединить(?):
	ИКМО(поселение) — ТИК/ИКМО(район) — ГИК — ИКСРФ
	ОВД — МО МВД — ГорОВД — (Г)УВД СРФ
	Адм поселения — района — города — субъекта
	---
	Параметры:
	* категория=текст (по умолчанию УИК, иначе ищем страницу «/текст»)
	* список полей (при пустом берем Fields, при пустом Fields берем умолчание для предусмотренных категорий, иначе только наименование)
--]=]


	local args = frame:getParent().args
	local ctg = args['категория'] or 'УИК'
	local list = mw.text.trim( mw.ustring.lower( args[1] or '' ) )
	if list == '' then
		if  true then -- not next( Fields )  then
			if ctg == 'УИК' then
				list = { 'номер', 'округ', 'адрес', 'телефон' ,'границы' }
			elseif ctg == 'Власти' or ctg == 'Сервисы' then
				list = { 'тип', 'наименование', 'адрес', 'телефон', 'сайты', 'примечание' }
			else
				list = { 'тип', 'наименование', 'адрес', 'телефон', 'сайты', 'примечание' }
			end
		end
	else
		list = mw.text.split( list, '[\t\r\n\f ]*,[\t\r\n\f ]*' )
	end

	local result = { { '' }, '<table class="wikitable sortable>', { '' } }
	local editInfo = {}
	local nopageInfo = {}
--	result[#result+1] = '<caption style="font-size:80%; line-height:110%; text-align:right;">'
--		.. 'Сведения об объектах вносятся '
--		.. ' [{{fullurl:' .. mw.title.getCurrentTitle().text .. '/' .. ctg
--		.. '|action=edit&editintro=Избирательные_кампании/Объекты/' .. ctg .. '/editnotice'
--		.. '}} здесь]. '
--		.. 'Скачать [//www.nablawiki.ru/images/ArticleToFile/{{urlencode:{{BASEPAGENAME}} - '
--		.. ctg .. '.csv|PATH}} файл в формате csv]'
--		.. '([[Как работать с таблицей объектов в формате csv|?]])</caption><tr>'
	result[#result+1] = '<tr>'
	for _, col in ipairs( list ) do
		local z = tabC[col]
		if z then
			z = '<th ' .. z[1] .. '>' .. z[2] .. '</th>'
		else
			z = '<th style="background-color:red">' .. col .. '</th>'
		end
		result[#result+1] = z
	end
	result[#result+1] = '</tr>'

	local wasPages
--	local collectObjects = collectObjects( ctg ) -- переопределили на собственно итератор
	for finam in collectObjects( ctg ) do
		wasPages = true
		local pid = mw.title.new( finam ).id
		local tmp = cargo.query( 'ObjectsPage', '_pageID,geobase,geoparam,region',
			{ where = '_pageID=' .. pid } )
		if #tmp == 0 then
			nopageInfo[#nopageInfo+1] = frame:preprocess(
				'{{Доделать|доделать|header=Страница «'
				.. finam .. '» еще не создана.'
				.. '|Чтобы создать страницу и увидеть инструкцию по ее наполнению, нажмите ['
				.. '{{fullurl:' .. finam
				.. '|action=edit&preload=Избирательные_кампании/Объекты/' .. ctg .. '/pattern'
				.. '&editintro=Избирательные_кампании/Объекты/' .. ctg .. '/editnotice'
				.. '}} сюда]}}[[Категория:Незаполненная таблица]]' )
		else
			local shortname = mw.ustring.match( finam, ':([^:]+)/[^/]+$' )
			if Fields or not shortname then
				shortname = 'здесь'
			end
			editInfo[#editInfo+1] = '[' .. tostring( mw.uri.fullUrl( finam, { 
					action = 'edit',
					editintro = 'Избирательные_кампании/Объекты/' .. ctg .. '/editnotice',
				} ) )
				.. ' ' .. shortname .. ']'
				
			tmp = tmp[1]
			Geobase = tmp.geobase
			GeoParam = tmp.geoparam
			Region = tmp.region

			local cQuery = cargo.query( 'Objects',
				'_pageID, number, mun, gas, district, koib, temp, quantity, members, room_addr, room_org, '
					.. 'room_geo__lat, room_geo__lon, room_geo_s, room_geo_p,room_phone, '
					.. 'office_addr, office_org, office_geo__lat, office_geo__lon, office_geo_p, office_geo_s, '
					.. 'office_phone, border, addendum, x_turnout, x_before, x_home, x_loyal, '
					.. 'name, site, label',
				{
					where = '_pageID=' .. pid,
					limit = 1000,
				}
			)

			for _, row in ipairs( cQuery ) do
				result[#result+1] = '<tr>'
				for _, col in ipairs( list ) do
					local z = tabC[col]
					result[#result+1] = '<td ' .. z[3] .. '>'
					if type( z[4] ) == 'function' then
						result[#result+1] = z[4](row) .. '</td>'
					else
						result[#result+1] = mw.text.decode( row[z[4]] ) .. '</td>'
					end
				end
				result[#result+1] = '</tr>'
			end
		end
	end
	if not wasPages then
		return 'Нет ничего!'
	end
	result[1] = table.concat( nopageInfo, '\n' )
	if Fields then
		result[3] = '<caption style="font-size:80%; line-height:110%; text-align:right;">'
			.. 'Скачать [//www.nablawiki.ru/images/ArticleToFile/{{urlencode:{{BASEPAGENAME}} - '
			.. ctg .. '.csv|PATH}} файл в формате csv]'
			.. '([[Как работать с таблицей объектов в формате csv|?]])</caption>'
	else
		result[3] = '<caption style="font-size:80%; line-height:110%; text-align:right;">'
			..'Редактирование сведений об объектах: ' 
			.. table.concat (editInfo, ' &bull; ') .. '</caption>'
	end
	
	result[#result+1] = '</table>'

	return frame:preprocess( table.concat(result) )
end


local icoName = {
	['ИК']          = 'ik';
	['ТИК']         = 'tik';
	['ИКМО']        = 'ikmo';
	['полиция']     = 'ovd';
	['прокуратура'] = 'proc';
	['СК']          = 'ck';
	['суд']         = 'sud2';
	['адм']         = 'adm2';
}


local function dQ (s)
	return mw.ustring.gsub ( mw.text.decode( s ), '"', '""')
end

local function bQ (s)
	return mw.ustring.gsub (s, '"', '\\"')
end


local function pointName( row )
	if (row.number or '') ~= '' then
		return 'УИК ' .. bQ( row.number )
	else
		return bQ( row.name )
	end
end
local function pointAddr( row )
	if row.room_org == '' then
		return bQ( row.room_addr )
	else
		return bQ( row.room_addr .. ' — ' .. row.room_org )
	end
end
local function pointIcon( row )
	if (row.number or '') ~= '' then
		local numb = mw.ustring.sub ('0000' .. normUIK (row.number),-4)
		return 'http://www.nablawiki.ru/images/NablaIcons/E/' .. string.sub (numb,1,1) .. '/uik' .. numb .. '-e.png'
	else
		local icon =icoName[row.label]
		if icon then
			return 'http://www.nablawiki.ru/images/NablaIcons/E/gov/' .. icon .. '-e.png'
		else
			return ''
		end
	end
end


function p.kml( frame )
	local result = {}
	for finam in collectObjects() do
		local pid = mw.title.new( finam ).id
		if pid ~= 0 then
			local cQuery = cargo.query( 'Objects',
				'_pageID, number, mun, gas, district, koib, temp, quantity, members, room_addr, room_org, '
					.. 'room_geo__lat, room_geo__lon, room_geo_s, room_geo_p,room_phone, '
					.. 'office_addr, office_org, office_geo__lat, office_geo__lon, office_geo_p, office_geo_s, '
					.. 'office_phone, border, addendum, x_turnout, x_before, x_home, x_loyal, '
					.. 'name, site, label',
				{
					where = '_pageID=' .. pid,
					limit = 1000,
				}
			)
			if #cQuery ~= 0 then
				result[#result+1] = [[
    <Folder>
      <name>]] .. finam .. [[</name>
      <description>Информация для выборов</description>]]
				for _,row in ipairs( cQuery ) do
					result[#result+1] = '      <Placemark>'
					result[#result+1] = '        <name>' .. pointName( row ) .. '</name>'
					result[#result+1] = '        <description>' .. pointAddr( row ) .. '</description>'
					result[#result+1] = [[
        <Point>
          <coordinates>]] .. row.room_geo__lon .. ',' .. row.room_geo__lat .. [[</coordinates>
        </Point>
        <Style>
          <IconStyle>
            <Icon>
              <href>]] .. pointIcon( row ) .. [[</href>
            </Icon>
            <hotSpot x="11" y="0" xunits="pixels" yunits="pixels" />
          </IconStyle>
        </Style>
      </Placemark>]]
				end
				result[#result+1] = '    </Folder>'
			end
		end
	end
	return table.concat( result, '\n' )
end


function p.gpx( frame )
	local result = {}
	for finam in collectObjects() do
		local pid = mw.title.new( finam ).id
		if pid ~= 0 then
			local cQuery = cargo.query( 'Objects',
				'_pageID, number, mun, gas, district, koib, temp, quantity, members, room_addr, room_org, '
					.. 'room_geo__lat, room_geo__lon, room_geo_s, room_geo_p,room_phone, '
					.. 'office_addr, office_org, office_geo__lat, office_geo__lon, office_geo_p, office_geo_s, '
					.. 'office_phone, border, addendum, x_turnout, x_before, x_home, x_loyal, '
					.. 'name, site, label',
				{
					where = '_pageID=' .. pid,
					limit = 1000,
				}
			)
			if #cQuery ~= 0 then
				for _,row in ipairs( cQuery ) do
					result[#result+1] = '  <wpt lat="' .. row.room_geo__lat .. '" lon="' .. row.room_geo__lon .. '">'
					result[#result+1] = '    <name>' .. pointName( row ) .. '</name>'
					result[#result+1] = '    <desc>' .. pointAddr( row ) .. '</desc>'
			--		result[#result+1] = '    <cmt>' .. pointAddr( row ) .. '</cmt>'
					result[#result+1] = '  </wpt>'
				end
			end
		end
	end
	return table.concat( result, '\n' )
end

function p.json( frame )
	local result = {}
	for finam in collectObjects() do
		local pid = mw.title.new( finam ).id
		if pid ~= 0 then
			local cQuery = cargo.query( 'Objects',
				'_pageID, number, mun, gas, district, koib, temp, quantity, members, room_addr, room_org, '
					.. 'room_geo__lat, room_geo__lon, room_geo_s, room_geo_p,room_phone, '
					.. 'office_addr, office_org, office_geo__lat, office_geo__lon, office_geo_p, office_geo_s, '
					.. 'office_phone, border, addendum, x_turnout, x_before, x_home, x_loyal, '
					.. 'name, site, label',
				{
					where = '_pageID=' .. pid,
					limit = 1000,
				}
			)
			if #cQuery ~= 0 then
				for _,row in ipairs( cQuery ) do
					local outside = ''
					if row.room_geo_s ~= 0 then
						outside = ', "outside": 1'
					end
					result[#result+1] = [[
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": []] .. row.room_geo__lon .. ',' .. row.room_geo__lat .. [[]
      },
      "properties": {]]
				-- show --
				result[#result+1] = '        "name": "' .. pointName( row ) .. '",'
				result[#result+1] = '        "description": "' .. pointAddr( row ) .. '",'
				result[#result+1] = '        "icon": {'
				result[#result+1] = '          "iconUrl": "' .. pointIcon( row ) .. '",'
				result[#result+1] = [[
          "iconSize": [39, 30],
          "iconAnchor": [11, 30],
          "popupAnchor": [9, -30]
        }]] .. outside .. [[
      }
    },]]
				end
			end
		end
	end
	return table.concat( result, '\n' )
end

function p.csv( frame )
	local paname = mw.title.getCurrentTitle().text
	local pid = mw.title.new( paname ).id
	if pid == 0 then
		return nil
	end
	local cQuery = cargo.query( 'Objects',
		'_pageID, number, mun, gas, district, koib, temp, quantity, members, room_addr, room_org, '
			.. 'room_geo__lat, room_geo__lon, room_geo_s, room_geo_p,room_phone, '
			.. 'office_addr, office_org, office_geo__lat, office_geo__lon, office_geo_p, office_geo_s, '
			.. 'office_phone, border, addendum, x_turnout, x_before, x_home, x_loyal, '
			.. 'name, site, label',
		{
			where = '_pageID=' .. pid,
			limit = 1000,
		}
	)
	if #cQuery == 0 then
		return nil
	end
	
	local fieldsSeq = {
		label           = { 10,  'тип' }, 
		number          = { 20,  'номер' },  
		gas				= { 30,  'ГАС' },  
		temp			= { 40,  'временный' },  
		name			= { 50,  'наименование' },  
		mun				= { 60,  'МО' },  
		district		= { 70,  'округ' },  
		koib			= { 80,  'КОИБ' },  
		members			= { 90,  'ПРГ' },  
		room_addr		= { 100, 'адрес (дом)' }, 
		room_org		= { 110, 'адрес (орг)' }, 
		room_geo__lat	= { 120, 'адрес (широта)' },
		room_geo__lon	= { 130, 'адрес (долгота)' }, 
		room_geo_p		= { 140, 'адрес (точность)' },
		room_geo_s		= { 150, 'адрес (показ)' }, 
		room_phone		= { 160, 'телефон' },
		office_addr		= { 170, 'адрес офиса (дом)' }, 
		office_org		= { 180, 'адрес офиса (орг)' },  
		office_geo__lat	= { 190, 'адрес офиса (широта)' }, 
		office_geo__lon = { 200, 'адрес офиса (долгота)' },  
		office_geo_p	= { 210, 'адрес офиса (точность)' }, 
		office_geo_s	= { 220, 'адрес офиса (показ)' },  
		office_phone	= { 230, 'телефон офиса' }, 
		border			= { 240, 'границы' }, 
		quantity		= { 250, 'численность' }, 
		x_turnout		= { 260, '#явка' }, 
		x_before		= { 270, '#досрочно' }, 
		x_home			= { 280, '#дома' }, 
		x_loyal			= { 290, '#власть' }, 
		site			= { 300, 'сайты' }, 
		addendum		= { 310, 'примечание' }, 
	}

	local columns, xc = {}, {}
	for _,row in ipairs( cQuery ) do
		row._pageID = nil
		for col, value in pairs( row ) do
			if (value or '') ~= '' and not xc[col] then
				xc [col] = true
				columns[#columns+1] = col
			end
		end
	end
	table.sort( columns, function ( a, b )
			return fieldsSeq[a][1] < fieldsSeq[b][1]
		end )
	

--	local result = { table.concat( columns, ',' ) }
	local x = {}
	for i, col in ipairs( columns ) do
		x[i] = fieldsSeq[col][2]
	end
	local result = { '"' .. table.concat( x, '","' ) .. '"' }
	for _, row in ipairs( cQuery ) do
		x = {}
		for i, col in ipairs( columns ) do
			x[i] = dQ( row[col] or '' )
		end
		result[#result+1] = '"' .. table.concat( x, '","' ) .. '"'
	end

	return table.concat( result, '\n' )
end

function p.Collect( frame )
	local fn = mw.text.trim( frame:getParent().args[1] or '' )
	local base = mw.title.getCurrentTitle().baseText
	if fn == '-:' then
		fn = mw.ustring.gsub( base, ':[^:]+$', '' )
	end
	local subp = mw.title.getCurrentTitle().subpageText
	if fn == '' then
		fn = base
	end
	return frame:callParserFunction( '#a2f', 'Избирательные кампании/Объекты/Данные kml/pattern',  fn, fn .. '.kml'  )
		.. frame:callParserFunction( '#a2f', 'Избирательные кампании/Объекты/Данные gpx/pattern',  fn, fn .. '.gpx'  )
		.. frame:callParserFunction( '#a2f', 'Избирательные кампании/Объекты/Данные json/pattern', fn, fn .. '.json' )
		.. frame:callParserFunction( '#a2f', 'Избирательные кампании/Объекты/Данные csv/pattern',  mw.title.getCurrentTitle().text, base .. ' - ' .. subp .. '.csv' )
end
return p