Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.
The main server is currently down. We are running on a backup server, so editing and search functionality are temporarily disabled. Please check back in a few hours.

Module:InfoboxNeue: Difference between revisions

From GameBrew
No edit summary
No edit summary
Line 1: Line 1:
local InfoboxNeue = {}
--- Simple infobox module
local p = {}


local metatable = {}
--- Main function
local methodtable = {}
function p.infobox( frame )
 
local args
local libraryUtil = require( 'libraryUtil' )
if frame == mw.getCurrentFrame() then
local checkType = libraryUtil.checkType
args = frame:getParent().args
local checkTypeMulti = libraryUtil.checkTypeMulti
 
metatable.__index = methodtable
 
metatable.__tostring = function( self )
return tostring( self:renderInfobox() )
end
 
 
 
--- Helper function to restore underscore from space
--- so that it does not screw up the external link wikitext syntax
--- For some reason SMW property converts underscore into space
--- mw.uri.encode can't be used on full URL
local function restoreUnderscore( s )
return s:gsub( ' ', '%%5F' )
end
 
--- Helper function to format string to number with separators
--- It is usually use to re-format raw number from SMW into more readable format
local function formatNumber( s )
local lang = mw.getContentLanguage()
if s == nil then
return
end
if type( s ) ~= 'number' then
s = tonumber( s )
end
 
if type( s ) == 'number' then
return lang:formatNum( s )
end
 
return s
end
 
 
--- Put table values into a comma-separated list
---
--- @param data table
--- @return string
function methodtable.tableToCommaList( data )
if type( data ) == 'table' then
return table.concat( data, ', ' )
else
else
return data
args = frame
end
end
 
--- Show range if value1 and value2 are different
---
--- @param s1 string|nil
--- @param s2 string|nil
--- @return string|nil
function methodtable.formatRange( s1, s2, formatNum )
if s1 == nil and s2 == nil then
return
end
end
local infobox = mw.html.create('table')
        :addClass('infobox collapsible')
-- Toggle button
    local toggle_button = mw.html.create('button')
        :addClass('collapsible-toggle'):attr('type', 'button'):wikitext('Show/Hide'):done()
   
    infobox:node(toggle_button)


formatNum = formatNum or false;
-- Collapsible content
    local content = mw.html.create('div'):addClass('collapsible-content')
    infobox:node(content)


if formatNum then
--top infobox ads
if s1 then
local div = mw.html.create('div')
s1 = formatNumber( s1 )
div:attr('id', 'Ads-InfoboxTop')
end
infobox:node(div)
if s2 then
s2 = formatNumber( s2 )
end
end


if s1 and s2 and s1 ~= s2 then
-- Title
return s1 .. ' – ' .. s2
local title = args.title
end
if not title or title == '' then title = mw.title.getCurrentTitle().text end
 
infobox:tag('tr'):tag('th'):addClass('infobox-title'):attr('scope','col'):attr('colspan',2):wikitext(title)
return s1 or s2
end
-- Image
 
local image = args.image
--- Append unit to the value if exists
if image and image ~= '' then
---
if image:sub(1,2) ~= '[[' then
--- @param s string
if not image:find(':') then
--- @param unit string
image = 'File:' .. image
--- @return string|nil
end
function methodtable.addUnitIfExists( s, unit )
image = '[[' .. image .. '|' .. ('300px') .. ']]'
if s == nil then
return
end
 
return s .. ' ' .. unit
end
 
 
--- Shortcut to return the HTML of the infobox message component as string
---
--- @param data table {title, desc)
--- @return string html
function methodtable.renderMessage( self, data, noInsert )
checkType( 'Module:InfoboxNeue.renderMessage', 1, self, 'table' )
checkType( 'Module:InfoboxNeue.renderMessage', 2, data, 'table' )
checkType( 'Module:InfoboxNeue.renderMessage', 3, noInsert, 'boolean', true )
 
noInsert = noInsert or false
 
local item = self:renderSection( { content = self:renderItem( { data = data.title, desc = data.desc } ) }, noInsert )
 
if not noInsert then
table.insert( self.entries, item )
end
 
return item
end
 
 
--- Return the HTML of the infobox image component as string
---
--- @param filename string
--- @return string html
function methodtable.renderImage( self, filename )
checkType( 'Module:InfoboxNeue.renderImage', 1, self, 'table' )
 
local hasPlaceholderImage = false
 
if type( filename ) ~= 'string' and self.config.displayPlaceholder == true then
hasPlaceholderImage = true
filename = self.config.placeholderImage
-- Add tracking category for infoboxes using placeholder image
table.insert( self.categories,
string.format( '[[Category:%s]]', t( 'category_infobox_using_placeholder_image' ) )
)
end
 
if type( filename ) ~= 'string' then
return ''
end
 
local parts = mw.text.split( filename, ':', true )
if #parts > 1 then
table.remove( parts, 1 )
filename = table.concat( parts, ':' )
end
 
local html = mw.html.create( 'div' )
:addClass( 'infobox__image' )
:wikitext( mw.ustring.format( '[[File:%s|400px]]', filename ) )
 
if hasPlaceholderImage == true then
local icon = mw.html.create( 'span' ):addClass( 'citizen-ui-icon mw-ui-icon-wikimedia-upload' )
-- TODO: Point the Upload link to a specific file name
html:tag( 'div' ):addClass( 'infobox__image-upload' )
:wikitext( mw.ustring.format( '[[%s|%s]]', 'Special:UploadWizard', tostring( icon ) .. t( 'label_upload_image' ) ) )
end
 
local item = tostring( html )
 
table.insert( self.entries, item )
 
return item
end
 
 
--- Return the HTML of the infobox indicator component as string
---
--- @param data table {data, desc, class)
--- @return string html
function methodtable.renderIndicator( self, data )
checkType( 'Module:InfoboxNeue.renderIndicator', 1, self, 'table' )
checkType( 'Module:InfoboxNeue.renderIndicator', 2, data, 'table' )
 
if data == nil or data[ 'data' ] == nil or data[ 'data' ] == '' then return '' end
 
local html = mw.html.create( 'div' ):addClass( 'infobox__indicator' )
html:wikitext(
self:renderItem(
{
[ 'data' ] = data[ 'data' ],
[ 'desc' ] = data[ 'desc' ] or nil,
row = true,
spacebetween = true
}
)
)
 
if data[ 'class' ] then html:addClass( data[ 'class' ] ) end
 
local item = tostring( html )
 
table.insert( self.entries, item )
 
return item
end
 
 
--- Return the HTML of the infobox header component as string
---
--- @param data table {title, subtitle, badge)
--- @return string html
function methodtable.renderHeader( self, data )
checkType( 'Module:InfoboxNeue.renderHeader', 1, self, 'table' )
checkTypeMulti( 'Module:InfoboxNeue.renderHeader', 2, data, { 'table', 'string' } )
 
if type( data ) == 'string' then
data = {
title = data
}
end
 
if data == nil or data[ 'title' ] == nil then return '' end
 
local html = mw.html.create( 'div' ):addClass( 'infobox__header' )
 
if data[ 'badge' ] then
html:tag( 'div' )
:addClass( 'infobox__item infobox__badge' )
:wikitext( data[ 'badge' ] )
end
 
local titleItem = mw.html.create( 'div' ):addClass( 'infobox__item' )
 
titleItem:tag( 'div' )
:addClass( 'infobox__title' )
:wikitext( data[ 'title' ] )
 
if data[ 'subtitle' ] then
titleItem:tag( 'div' )
-- Subtitle is always data
:addClass( 'infobox__subtitle infobox__data' )
:wikitext( data[ 'subtitle' ] )
end
 
html:node( titleItem )
 
local item = tostring( html )
 
table.insert( self.entries, item )
 
return item
end
 
 
--- Wrap the HTML into an infobox section
---
--- @param data table {title, subtitle, content, border, col, class}
--- @param noInsert boolean whether to insert this section into the internal table table
--- @return string html
function methodtable.renderSection( self, data, noInsert )
checkType( 'Module:InfoboxNeue.renderSection', 1, self, 'table' )
checkType( 'Module:InfoboxNeue.renderSection', 2, data, 'table' )
checkType( 'Module:InfoboxNeue.renderSection', 3, noInsert, 'boolean', true )
 
noInsert = noInsert or false
 
if type( data.content ) == 'table' then
data.content = table.concat( data.content )
end
 
if data == nil or data[ 'content' ] == nil or data[ 'content' ] == '' then return '' end
 
local html = mw.html.create( 'div' ):addClass( 'infobox__section' )
 
if data[ 'title' ] then
local header = html:tag( 'div' ):addClass( 'infobox__sectionHeader' )
header:tag( 'div' )
:addClass( 'infobox__sectionTitle' )
:wikitext( data[ 'title' ] )
if data[ 'subtitle' ] then
header:tag( 'div' )
:addClass( 'infobox__sectionSubtitle' )
:wikitext( data[ 'subtitle' ] )
end
end
end
local imgcell = infobox:tag('tr'):tag('td'):addClass('infobox-image')
 
:attr('colspan',2):wikitext(image)
local content = html:tag( 'div' )
local caption = args.imagecaption
content:addClass( 'infobox__sectionContent')
if caption and caption ~= '' then
:wikitext( data[ 'content' ] )
imgcell:wikitext("<br />''" .. caption .. "''")
 
if data[ 'border' ] == false then html:addClass( 'infobox__section--noborder' ) end
if data[ 'col' ] then content:addClass( 'infobox__grid--cols-' .. data[ 'col' ] ) end
if data[ 'class' ] then html:addClass( data[ 'class' ] ) end
 
local item = tostring( html )
 
if not noInsert then
table.insert( self.entries, item )
end
 
return item
end
 
 
--- Return the HTML of the infobox link button component as string
---
--- @param data table {label, link, page}
--- @return string html
function methodtable.renderLinkButton( self, data )
checkType( 'Module:InfoboxNeue.renderLinkButton', 1, self, 'table' )
checkType( 'Module:InfoboxNeue.renderLinkButton', 2, data, 'table' )
 
if data == nil or data[ 'label' ] == nil or ( data[ 'link' ] == nil and data[ 'page' ] == nil ) then return '' end
 
--- Render multiple linkButton when link is a table
if type( data[ 'link' ] ) == 'table' then
local htmls = {}
 
for i, url in ipairs( data[ 'link' ] ) do
table.insert( htmls,
self:renderLinkButton( {
label = mw.ustring.format( '%s %d', data[ 'label' ], i ),
link = url
} )
)
end
end
return table.concat( htmls )
end
end
-- Description
          local description = args.description
          if not description or description == '' then description = mw.title.getCurrentTitle().text end


local html = mw.html.create( 'div' ):addClass( 'infobox__linkButton' )
-- Rows
 
for i = 1, 30 do
if data[ 'link' ] then
local header = args['header' .. i]; if header == '' then header = nil end
html:wikitext( mw.ustring.format( '[%s %s]', restoreUnderscore( data[ 'link' ] ), data[ 'label' ] ) )
local label = args['label' .. i]; if label == '' then label = nil end
elseif data[ 'page' ] then
local data = args['data' .. i]; if data == '' then data = nil end
html:wikitext( mw.ustring.format( '[[%s|%s]]', data[ 'page' ], data[ 'label' ] ) )
end
if header then
 
infobox:tag('tr')
return tostring( html )
:tag('th'):addClass('infobox-header'):attr('scope','col'):attr('colspan',2):wikitext(header)
end
 
--- Return the HTML of the infobox footer component as string
---
--- @param data table {content, button}
--- @return string html
function methodtable.renderFooter( self, data )
checkType( 'Module:InfoboxNeue.renderFooter', 1, self, 'table' )
checkType( 'Module:InfoboxNeue.renderFooter', 2, data, 'table' )
 
if data == nil then return '' end
 
    -- Checks if an input is of type 'table' or 'string' and if it is not empty
    local function isNonEmpty( input )
        return ( type( input ) == 'table' and next( input ) ~= nil ) or ( type( input ) == 'string' and #input > 0 )
    end
 
local hasContent = isNonEmpty( data[ 'content' ] )
local hasButton = isNonEmpty( data[ 'button' ] ) and isNonEmpty( data[ 'button' ][ 'content' ] ) and isNonEmpty( data[ 'button' ][ 'label' ] )
 
if not hasContent and not hasButton then return '' end
 
local html = mw.html.create( 'div' ):addClass( 'infobox__footer' )
 
if hasContent then
local content = data[ 'content' ]
if type( content ) == 'table' then content = table.concat( content ) end
 
        html:addClass( 'infobox__footer--has-content')
        html:tag( 'div' )
            :addClass( 'infobox__section' )
            :wikitext( content )
end
 
if hasButton then
    html:addClass( 'infobox__footer--has-button')
local buttonData = data[ 'button' ];
local button = html:tag( 'div' ):addClass( 'infobox__button' )
local label = button:tag( 'div' ):addClass( 'infobox__buttonLabel' )
 
if buttonData[ 'icon' ] ~= nil then
label:wikitext( mw.ustring.format( '[[File:%s|16px|link=]]%s', buttonData[ 'icon' ], buttonData[ 'label' ] ) )
else
label:wikitext( buttonData[ 'label' ] )
end
 
if buttonData[ 'type' ] == 'link' then
button:tag( 'div' )
:addClass( 'infobox__buttonLink' )
:wikitext( buttonData[ 'content' ] )
elseif buttonData[ 'type' ] == 'popup' then
button:tag( 'div' )
:addClass( 'infobox__buttonCard' )
:wikitext( buttonData[ 'content' ] )
end
end
end
if data then
 
if label then
local item = tostring( html )
infobox:tag('tr')
 
:tag('th'):attr('scope','row'):addClass('infobox-label'):wikitext(label):done()
table.insert( self.entries, item )
:tag('td'):addClass('infobox-data'):wikitext(data)
 
else
return item
infobox:tag('tr')
end
:tag('td'):addClass('infobox-data'):attr('colspan',2)
 
:css('text-align','center'):wikitext(data)
 
--- Return the HTML of the infobox footer button component as string
---
--- @param data table {icon, label, type, content}
--- @return string html
function methodtable.renderFooterButton( self, data )
checkType( 'Module:InfoboxNeue.renderFooterButton', 1, self, 'table' )
checkType( 'Module:InfoboxNeue.renderFooterButton', 2, data, 'table' )
 
if data == nil then return '' end
 
return self:renderFooter( { button = data } )
end
 
 
--- Return the HTML of the infobox item component as string
---
--- @param data table {label, data, desc, tooltip, icon, row, spacebetween, colspan)
--- @param content string|number|nil optional
--- @return string html
function methodtable.renderItem( self, data, content )
checkType( 'Module:InfoboxNeue.renderItem', 1, self, 'table' )
checkTypeMulti( 'Module:InfoboxNeue.renderItem', 2, data, { 'table', 'string' } )
checkTypeMulti( 'Module:InfoboxNeue.renderItem', 3, content, { 'string', 'number', 'nil' } )
 
-- The arguments are not passed as a table
-- Allows to call this as box:renderItem( 'Label', 'Data' )
if content ~= nil then
data = {
label = data,
data = content
}
end
 
if data == nil or data[ 'data' ] == nil or data[ 'data' ] == '' then return '' end
 
if self.config.removeEmpty == true and data[ 'data' ] == self.config.emptyString then
return ''
end
 
local html = mw.html.create( 'div' ):addClass( 'infobox__item' )
 
if data[ 'tooltip' ] then html:attr( 'title', data[ 'tooltip' ] ) end
if data[ 'row' ] == true then html:addClass( 'infobox__grid--row' ) end
if data[ 'spacebetween' ] == true then html:addClass( 'infobox__grid--space-between' ) end
if data[ 'colspan' ] then html:addClass( 'infobox__grid--col-span-' .. data[ 'colspan' ] ) end
 
local textWrapper = html
 
if data[ 'link' ] then
html:addClass( 'infobox__itemButton' )
html:tag( 'div' )
:addClass( 'infobox__itemButtonLink' )
:wikitext( mw.ustring.format( '[%s]', data[ 'link' ] ) )
elseif data[ 'page' ] then
html:addClass( 'infobox__itemButton' )
html:tag( 'div' )
:addClass( 'infobox__itemButtonLink' )
:wikitext( mw.ustring.format( '[[%s]]', data[ 'link' ] ) )
end
 
if data[ 'icon' ] then
html:addClass( 'infobox__item--hasIcon' )
html:tag( 'div' )
:addClass( 'infobox__icon' )
:wikitext( mw.ustring.format( '[[File:%s|16px|link=]]', data[ 'icon' ] ) )
-- Create wrapper for text to align with icon
textWrapper = html:tag( 'div' ):addClass( 'infobox__text' )
end
 
local dataOrder = { 'label', 'data', 'desc' }
 
for _, key in ipairs( dataOrder ) do
if data[ key ] then
if type( data[ key ] ) == 'table' then
data[ key ] = table.concat( data[ key ], ', ' )
end
end
textWrapper:tag( 'div' )
:addClass( 'infobox__' .. key )
:wikitext( data[ key ] )
end
end
-- Add arrow indicator as affordnance
if data[ 'link' ] or data[ 'page' ] then
html:tag( 'div' ):addClass( 'infobox__itemButtonArrow citizen-ui-icon mw-ui-icon-wikimedia-collapse' )
end
return tostring( html )
end
--- Wrap the infobox HTML
---
--- @param innerHtml string inner html of the infobox
--- @param snippetText string text used in snippet in mobile view
--- @return string html infobox html with templatestyles
function methodtable.renderInfobox( self, innerHtml, snippetText )
checkType( 'Module:InfoboxNeue.renderInfobox', 1, self, 'table' )
checkTypeMulti( 'Module:InfoboxNeue.renderInfobox', 2, innerHtml, { 'table', 'string', 'nil' } )
checkType( 'Module:InfoboxNeue.renderInfobox', 3, snippetText, 'string', true )
innerHtml = innerHtml or self.entries
if type( innerHtml ) == 'table' then
innerHtml = table.concat( self.entries )
end
local function renderSnippet()
if snippetText == nil then snippetText = mw.title.getCurrentTitle().text end
local html = mw.html.create( 'div' )
html
:addClass( 'infobox__snippet mw-collapsible-toggle' )
:attr( 'role', 'button' )
:attr( 'aria-owns', 'infobox__content' )
:tag( 'div' )
:addClass( 'citizen-ui-icon mw-ui-icon-wikimedia-collapse' )
:done()
:tag( 'div' )
:addClass( 'infobox__data' )
:wikitext( mw.ustring.format( '%s:', t( 'label_quick_facts' ) ) )
:done()
:tag( 'div' )
:addClass( 'infobox__desc' )
:wikitext( snippetText )
return tostring( html )
end
local html = mw.html.create( 'div' )
html
:addClass( 'infobox floatright mw-collapsible' )
:wikitext( renderSnippet() )
:tag( 'div' )
:addClass( 'infobox__content mw-collapsible-content' )
:attr( 'id', 'infobox__content' )
:wikitext( innerHtml )
return tostring( html ) .. mw.getCurrentFrame():extensionTag{
name = 'templatestyles', args = { src = 'Module:InfoboxNeue/styles.css' }
} .. table.concat( self.categories )
end
--- Just an accessor for the class method
function methodtable.showDescIfDiff( s1, s2 )
return InfoboxNeue.showDescIfDiff( s1, s2 )
end
--- Format text to show comparison as desc text if two strings are different
---
--- @param s1 string|nil base
--- @param s2 string|nil comparsion
--- @return string|nil html
function InfoboxNeue.showDescIfDiff( s1, s2 )
    if s1 == nil or s2 == nil or s1 == s2 then return s1 end
    return mw.ustring.format( '%s <span class="infobox__desc">(%s)</span>', s1, s2 )
end
--- New Instance
---
--- @return table InfoboxNeue
function InfoboxNeue.new( self, config )
local baseConfig = {
-- Flag to discard empty rows
removeEmpty = false,
-- Optional string which is valued as empty
emptyString = nil,
-- Display a placeholder image if addImage does not find an image
displayPlaceholder = true,
-- Placeholder Image
placeholderImage = 'Platzhalter.webp',
}
for k, v in pairs( config or {} ) do
baseConfig[ k ] = v
end
    local instance = {
categories = {},
config = baseConfig,
entries = {}
}
    setmetatable( instance, metatable )
    return instance
end
--- Create an Infobox from args
---
--- @param frame table
--- @return string
function InfoboxNeue.fromArgs( frame )
local instance = InfoboxNeue:new()
local args = require( 'Module:Arguments' ).getArgs( frame )
local sections = {
{ content = {}, col = args[ 'col' ] or 2 }
}
local sectionMap = { default = 1 }
local currentSection
if args[ 'image' ] then
instance:renderImage( args[ 'image' ] )
end
if args[ 'indicator' ] then
instance:renderIndicator( {
data = args[ 'indicator' ],
desc = args[ 'indicatorDesc' ],
class = args[ 'indicatorClass' ]
} )
end
if args[ 'title' ] then
instance:renderHeader( {
title = args[ 'title' ],
subtitle = args[ 'subtitle' ],
} )
end
for i = 1, 50, 1 do
if args[ 'section' .. i ] then
currentSection = args[ 'section' .. i ]
table.insert( sections, {
title = currentSection,
subtitle = args[ 'section-subtitle' .. i ],
col = args[ 'section-col' .. i ] or args[ 'col' ] or 2,
content = {}
} )
sectionMap[ currentSection ] = #sections
end
if args[ 'label' .. i ] and args[ 'content' .. i ] then
table.insert( sections[ sectionMap[ ( currentSection or 'default' ) ] ].content, instance:renderItem( args[ 'label' .. i ], args[ 'content' .. i ] ) )
end
end
end
end
 
for _, section in ipairs( sections ) do
-- Below
instance:renderSection( {
local below = args.below
title = section.title,
if below and below ~= '' then
subtitle = section.subtitle,
infobox:tag('tr'):tag('td'):addClass('infobox-below'):attr('colspan',2):wikitext(below)
col = section.col,
content = section.content,
} )
end
end
 
return instance:renderInfobox( nil, args[ 'snippet' ] )
return infobox
end
end
 
 
return p
return InfoboxNeue

Revision as of 02:22, 23 July 2024

Documentation for this module may be created at Module:InfoboxNeue/doc

--- Simple infobox module
local p = {}

--- Main function
function p.infobox( frame )
	local args
	if frame == mw.getCurrentFrame() then
		args = frame:getParent().args
	else
		args = frame
	end
 
	local infobox = mw.html.create('table')
        :addClass('infobox collapsible')
 
-- Toggle button
    local toggle_button = mw.html.create('button')
        :addClass('collapsible-toggle'):attr('type', 'button'):wikitext('Show/Hide'):done()
    
    infobox:node(toggle_button)

-- Collapsible content
    local content = mw.html.create('div'):addClass('collapsible-content')
    infobox:node(content)

--top infobox ads
local div = mw.html.create('div')
div:attr('id', 'Ads-InfoboxTop')
infobox:node(div)

	-- Title
	local title = args.title
	if not title or title == '' then title = mw.title.getCurrentTitle().text end
	infobox:tag('tr'):tag('th'):addClass('infobox-title'):attr('scope','col'):attr('colspan',2):wikitext(title)
 
	-- Image
	local image = args.image
	if image and image ~= '' then
		if image:sub(1,2) ~= '[[' then
			if not image:find(':') then
				image = 'File:' .. image	
			end
			image = '[[' .. image .. '|' .. ('300px') .. ']]'
		end
		local imgcell = infobox:tag('tr'):tag('td'):addClass('infobox-image')
			:attr('colspan',2):wikitext(image)
		local caption = args.imagecaption
		if caption and caption ~= '' then
			imgcell:wikitext("<br />''" .. caption .. "''")
		end
	end
	-- Description
           local description = args.description
           if not description or description == '' then description = mw.title.getCurrentTitle().text end

	-- Rows
	for i = 1, 30 do
		local header = args['header' .. i]; if header == '' then header = nil end
		local label = args['label' .. i]; if label == '' then label = nil end
		local data = args['data' .. i]; if data == '' then data = nil end
 
		if header then
			infobox:tag('tr')
				:tag('th'):addClass('infobox-header'):attr('scope','col'):attr('colspan',2):wikitext(header)
		end
		if data then
			if label then
				infobox:tag('tr')
					:tag('th'):attr('scope','row'):addClass('infobox-label'):wikitext(label):done()
					:tag('td'):addClass('infobox-data'):wikitext(data)
			else
				infobox:tag('tr')
					:tag('td'):addClass('infobox-data'):attr('colspan',2)
						:css('text-align','center'):wikitext(data)
			end
		end
	end
 
	-- Below
	local below = args.below
	if below and below ~= '' then
		infobox:tag('tr'):tag('td'):addClass('infobox-below'):attr('colspan',2):wikitext(below)
	end
 
	return infobox
end
 
return p

Advertising: