Module:SBIR
From Defense Knowledge
Documentation for this module may be created at Module:SBIR/doc
local p = {}
-- Helper function to build an address string
local function getFullAddress(item)
local fields = {"address1", "address2", "city", "state", "zip"}
local addressParts = {}
for _, key in ipairs(fields) do
local value = item[key]
if value and value ~= "" then
table.insert(addressParts, value)
end
end
return next(addressParts) and table.concat(addressParts, ", ") or "N/A"
end
-- Function to format large numbers into shortened notation
function formatLargeNumber(num)
-- Check if the input is a valid number
if not tonumber(num) then
return tostring(num) -- Return as is if not a number
end
local absNumber = math.abs(num)
local suffix = ""
local formattedNumber = num
if absNumber >= 1e9 then
formattedNumber = num / 1e9
suffix = " Billion"
elseif absNumber >= 1e6 then
formattedNumber = num / 1e6
suffix = " Million"
elseif absNumber >= 1e3 then
formattedNumber = num / 1e3
suffix = " Thousand"
end
-- Round to one decimal place
formattedNumber = string.format("%.1f", formattedNumber)
-- Handle edge cases for negative numbers
return formattedNumber .. suffix
end
-- Helper function to get company details
local function getCompanyDetails(item)
local fields = {
{"uei", "UEI"},
{"hubzone_owned", "HUBzone Owned"},
{"socially_economically_disadvantaged", "SED Owned"},
{"woman_owned", "Woman Owned"}
}
local companyDetails = {}
for _, field in ipairs(fields) do
local key, label = field[1], field[2]
local value = item[key]
if value and value ~= "" and value ~= "No" and value ~= "Unavailable" then
table.insert(companyDetails, label .. ": " .. value)
end
end
return next(companyDetails) and table.concat(companyDetails, "\n") or "N/A"
end
-- Helper function to get company details
local function getAwardDetails(item)
local html = mw.html.create()
local card = html:tag('div'):addClass('card rounded-0')
local badges = {
{"agency", "Agency"},
{"branch", "Branch"},
{"program", "Program"},
{"phase", "Phase"},
{"topic_code", "Topic"}
}
local details = {
{"number_employees", "Employees"},
{"proposal_award_date", "Award Date"},
{"contract", "Contract"},
{"contract_end_date", "Contract Ends"},
}
local solicitation = {
{"solicitation_number", "Solicitation"},
{"solicitation_year", "Solicitation Year"},
}
local keywords = {
{"research_area_keywords", "Keywords"}
}
card:tag('h4')
:addClass('card-header')
:wikitext(item['award_title'] .. ' - ' .. item['award_year'])
local tagline = card:tag('div')
:addClass('card-tagline p-3')
for _, field in ipairs(badges) do
local key, label = field[1], field[2]
local value = item[key]
if value and value ~= "" and value ~= "No" and value ~= "Unavailable" then
tagline:tag('span')
:addClass('badge badge-secondary')
:attr('title', label)
:wikitext(value)
end
end
card:tag('div')
:addClass('h1 px-3 py-2')
:wikitext(formatLargeNumber(item['award_amount']))
for _, field in ipairs(keywords) do
local key, label = field[1], field[2]
local value = item[key]
if value and value ~= "" and value ~= "No" and value ~= "Unavailable" then
tagline:tag('span')
:addClass('badge badge-secondary')
:attr('title', label)
:wikitext(value)
end
end
for _, field in ipairs(details) do
local key, label = field[1], field[2]
local value = item[key]
if value and value ~= "" and value ~= "No" and value ~= "Unavailable" then
card:tag('div')
:addClass('card-body py-1')
:wikitext(label .. ": " .. value)
end
end
card:tag('div')
:addClass('card-body')
:wikitext(item['abstract'])
card:tag('div')
:addClass('card-body')
:wikitext('Solicitation: ' .. item['solicitation_number'] .. '(' .. item['solicitation_year'] .. ')' )
local out = tostring(html)
return out
end
function p.check(frame)
local page = mw.title.getCurrentTitle().text
local results = mw.ext.externalData.getWebData {
url = 'https://api.www.sbir.gov/public/api/firm?name=' .. page,
format = 'JSON',
['cache seconds'] = 86400
}
local html = mw.html.create()
local wrapper = html:tag('div')
:addClass('d-flex flex-wrap gap-3 mb-3')
local card = ''
if type(results) == "table" or #results > 0 then
-- Add data rows
for _, item in ipairs(results) do
local awards = item.number_awards or 0
out = string.format(
'%d %s',
awards, frame:preprocess('{{plural: ' .. awards .. '|award|awards}}')
)
end
card = wrapper:tag('div')
:addClass('card rounded-0')
card:tag('h4')
:addClass('card-header')
:wikitext('SBIR')
card:tag('div')
:addClass('card-body')
:wikitext(out)
card = wrapper:tag('div')
:addClass('card rounded-0')
card:tag('h4')
:addClass('card-header')
:wikitext('Address')
card:tag('div')
:addClass('card-body')
:wikitext(getFullAddress(results))
card = wrapper:tag('div')
:addClass('card rounded-0')
card:tag('h4')
:addClass('card-header')
:wikitext('Details')
card:tag('div')
:addClass('card-body')
:wikitext(getCompanyDetails(results))
local awards = mw.ext.externalData.getWebData {
url = 'https://api.www.sbir.gov/public/api/awards?firm=' .. page,
format = 'JSON',
['cache seconds'] = 86400
}
if type(awards) == "table" or #awards > 0 then
for _, award in ipairs(awards) do
html:tag('div')
:addClass('mb-3')
:wikitext(getAwardDetails(award))
end
end
end
return tostring(html) .. '__NOTOC__'
end
function p.byKeyword(frame)
local agency = frame.args[1]
local apiUrl = 'https://api.www.sbir.gov/public/api/awards?agency=' .. agency
local awards = mw.ext.externalData.getWebData {
url = apiUrl,
format = 'JSON',
data = {
json = '__json'
},
['cache seconds'] = 86400
}
local html = mw.html.create()
local awardsTable = html:tag('table')
:attr('id', 'sbirtable')
local row = ''
for _, award in ipairs(awards.json) do
local link = 'https://www.sbir.gov/awards/' .. award['award_link']
local title = string.format('[' .. link .. ' %s]'
, award['award_title'] or ''
)
local firm = string.format('[%s %s] (%s)'
, award['company_url'] or 'https://www.sbir.gov/portfolio'
, award['firm'] or ''
, award['number_employees'] or ''
)
local amount = '$' .. formatLargeNumber(award['award_amount'])
row = awardsTable:tag('tr')
row:tag('td')
:wikitext(award['contract'])
row:tag('td')
:wikitext(title)
row:tag('td')
:wikitext(amount)
row:tag('td')
:wikitext(firm)
row:tag('td')
:wikitext(award['program'])
row:tag('td')
:wikitext(award['phase'])
row:tag('td')
:wikitext(award['topic_code'])
row:tag('td')
:wikitext(award['proposal_award_date'])
row:tag('td')
:wikitext(award['contract_end_date'])
row:tag('td')
:wikitext(award['agency'])
row:tag('td')
:wikitext(award['branch'])
row:tag('td')
:wikitext(award['research_area_keywords'])
end
return html
end
-- Helper
local function extractUniqueValues(data)
local uniqueItems = {} -- Table to store unique items
local seenItems = {} -- Table to track already seen items
-- Iterate through each table in the input data
for _, tableEntry in ipairs(data) do
local listString = tableEntry.list
if listString then
-- Split the comma-separated string into individual items
for item in mw.text.gsplit(listString, ",%s*") do
-- Trim whitespace and check if the item is already seen
local trimmedItem = mw.text.trim(item)
if trimmedItem ~= "" and not seenItems[trimmedItem] then
table.insert(uniqueItems, '<div>' .. trimmedItem .. '</div>')
seenItems[trimmedItem] = true
end
end
end
end
table.sort(uniqueItems)
return uniqueItems
end
function p.getKeywords(frame)
local agency = frame.args[1]
local apiUrl = 'https://api.www.sbir.gov/public/api/awards?agency=' .. agency
local keywords = mw.ext.externalData.getWebData {
url = apiUrl,
format = 'JSON',
data = {
list = 'research_area_keywords'
},
['cache seconds'] = 86400
}
local list = extractUniqueValues(keywords)
return table.concat(list, "\n")
end
function p.getFromMongo(frame)
local keyword = frame.args[1]
-- local query = '{ "Abstract": { "$regex": "' .. keyword .. '" } }'
local query = '{ "Agency": "' .. keyword .. '" }'
local keywords = mw.ext.externalData.getExternalData {
source = 'samdb',
from = 'sbir',
limit = 1000,
['find query'] = query,
format = 'JSON',
data = {
title = 'Award Title',
amount = 'Award Amount',
agency = 'Agency',
branch = 'Branch',
topic = 'Topic Code',
phase = 'Phase',
program = 'Program',
company = 'Company',
website = 'Company Website',
award_date = 'Proposal Award Date',
contract = 'Contract',
contract_end = 'Contract End Date',
abstract = 'Abstract'
},
['cache seconds'] = 86400
}
local html = mw.html.create()
local awardsTable = html:tag('table')
:attr('id', 'sbirtable')
local row = ''
for _, award in ipairs(keywords) do
local amount = '$' .. formatLargeNumber(award['amount'])
local firm = string.format('[%s %s]'
, award['website']
, award['company']
)
row = awardsTable:tag('tr')
row:tag('td')
:wikitext(award['contract'])
row:tag('td')
:wikitext(award['title'])
row:tag('td')
:wikitext(amount)
row:tag('td')
:wikitext(firm)
row:tag('td')
:wikitext(award['program'])
row:tag('td')
:wikitext(award['phase'])
row:tag('td')
:wikitext(award['topic'])
row:tag('td')
:wikitext(award['award_date'])
row:tag('td')
:wikitext(award['contract_end'])
row:tag('td')
:wikitext(award['agency'])
row:tag('td')
:wikitext(award['branch'])
row:tag('td')
:wikitext(award['abstract'])
end
return html
end
return p