মডিউল:উদ্ধৃতি: সংশোধিত সংস্করণের মধ্যে পার্থক্য

বিষয়বস্তু বিয়োগ হয়েছে বিষয়বস্তু যোগ হয়েছে
Jayantanth (আলোচনা | অবদান)
১ টি সংশোধন
Reverted to revision 1479141 by Aftab1995. (TW)
৩৭ নং লাইন:
end
return false;
end
 
--[[
Categorize and emit an error message when the citation contains one or more deprecated parameters. Because deprecated parameters (currently |day=, |month=,
|coauthor=, and |coauthors=) aren't related to each other and because these parameters may be concatenated into the variables used by |date= and |author#= (and aliases)
details of which parameter caused the error message are not provided. Only one error message is emitted regarless of the number of deprecated parameters in the citation.
]]
function deprecated_parameter()
if true ~= Page_in_deprecated_cat then -- if we haven't been here before then set a
Page_in_deprecated_cat=true; -- sticky flag so that if there are more than one deprecated parameter the category is added only once
table.insert( z.message_tail, { seterror( 'deprecated_params', {error_message}, true ) } ); -- add error message
end
end
 
-- Populates numbered arguments in a message string using an argument table.
function substitute( msg, args )
-- return args and tostring( mw.message.newRawMessage( msg, args ) ) or msg;
return args and mw.message.newRawMessage( msg, args ):plain() or msg;
end
 
--[[
Apply kerning to open the space between the quote mark provided by the Module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value.
This function will positive kern either single or double quotes:
"'Unkerned title with leading and trailing single quote marks'"
" 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example)
]]
function kern_quotes (str)
local left='<span style="padding-left:0.2em;">%1</span>'; -- spacing to use when title contains leading single or double quote mark
local right='<span style="padding-right:0.2em;">%1</span>'; -- spacing to use when title contains trailing single or double quote mark
if str:match ("^[\"\'][^\']") then
str = string.gsub( str, "^[\"\']", left, 1 ); -- replace (captured) leading single or double quote with left-side <span>
end
if str:match ("[^\'][\"\']$") then
str = string.gsub( str, "[\"\']$", right, 1 ); -- replace (captured) trailing single or double quote with right-side <span>
end
return str;
end
 
১৩৭ ⟶ ১০৫ নং লাইন:
end
 
-- Checks that parameter name is valid using the whitelist
--[[
Looks for a parameter's name in the whitelist.
 
Parameters in the whitelist can have three values:
true - active, supported parameters
false - deprecated, supported parameters
nil - unsupported parameters
]]
function validate( name )
local name = tostring( name );
local state = whitelist.basic_arguments[ name ];
-- Normal arguments
if whitelist.basic_arguments[ name ] then
-- Normal arguments
if true == state then return true; end -- valid actively supported parameter
end
if false == state then
deprecated_parameter (); -- parameter is deprecated but still supported
-- Arguments with numbers in them
return true;
name = name:gsub( "%d+", "#" );
end
if whitelist.numbered_arguments[ name ] then
return true;
-- Arguments with numbers in them
end
name = name:gsub( "%d+", "#" ); -- replace digit(s) with # (last25 becomes last#
state = whitelist.numbered_arguments[ name ];
if true == state then-- returnNot true;found, end --argument valid activelynot supported parameter.
return false
if false == state then
deprecated_parameter (); -- parameter is deprecated but still supported
return true;
end
return false; -- Not supported because not found or name is set to nil
end
 
২৬৩ ⟶ ২১৯ নং লাইন:
 
--[[
Formats a PMC and checks for embargoed articles. The embargo parameter takes a date for a value. If the embargo date is in the futue
Format PMID and do simple error checking. PMIDs are sequential numbers beginning at 1 and counting up. This code checks the PMID to see that it
the PMC identifier will not be linked to the article. If the embargo specifies a date in the past, or if it is empty or omitted, then
contains only digits and is less than test_limit; the value in local variable test_limit will need to be updated periodically as more PMIDs are issued.
the PMC identifier is linked to the article through the link at cfg.id_handlers['PMC'].link.
 
The {{citation/core}} version of {{cite journal}} links the citation title (if url parameter is empty) when embargo date is in the past
or when embargo parameter is missing or empty. That behavior is inconsistent with the behavior of other identifiers used in CS1 and is
not supported here.
]]
function pmidpmc(id, embargo)
local handler = cfg.id_handlers['PMC'];
local test_limit = 30000000; -- update this value as PMIDs approach
local handler = cfg.id_handlers['PMID'];
local text;
local err_cat = ''; -- presume that PMID is valid
if id:match("[^%d]") then -- if PMID has anything but digits
err_cat = ' ' .. seterror( 'bad_pmid' ); -- set an error message
else -- PMID is only digits
local id_num = tonumber(id); -- convert id to a number for range testing
if 1 > id_num or test_limit < id_num then -- if PMID is outside test limit boundaries
err_cat = ' ' .. seterror( 'bad_pmid' ); -- set an error message
end
end
return externallinkid({link = handler.link, label = handler.label,
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) .. err_cat;
end
 
--[[
Determines if a PMC identifier's online version is embargoed. Compares the date in |embargo= against today's date. If embargo date is
in the future, returns true; otherwse, returns false because the embargo has expired or |embargo= not set in this cite.
]]
function is_embargoed(embargo)
if is_set(embargo) then
local lang = mw.getContentLanguage();
২৯৪ ⟶ ২৩৭ নং লাইন:
good1, embargo_date = pcall( lang.formatDate, lang, 'U', embargo );
good2, todays_date = pcall( lang.formatDate, lang, 'U' );
 
if good1 and good2 and tonumber( embargo_date ) >=< tonumber( todays_date ) then --isif embargo date is in the future?past then
text = externallinkid({link = handler.link, label = handler.label, --ok to link to article
return true; -- still embargoed
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
else
text="[[" .. handler.link .. "|" .. handler.label .. "]]:" .. handler.separator .. id; --still embargoed so no external link
end
end
return false; -- embargo expired or |embargo= not set
end
 
--[[
Formats a PMC and checks for embargoed articles. The embargo parameter takes a date for a value. If the embargo date is in the future
the PMC identifier will not be linked to the article. If the embargo specifies a date in the past, or if it is empty or omitted, then
the PMC identifier is linked to the article through the link at cfg.id_handlers['PMC'].prefix.
]]
function pmc(id, embargo)
local handler = cfg.id_handlers['PMC'];
local text;
 
if is_embargoed(embargo) then
text="[[" .. handler.link .. "|" .. handler.label .. "]]:" .. handler.separator .. id; --still embargoed so no external link
else
text = externallinkid({link = handler.link, label = handler.label, --no embargo date, ok to link to article
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
end
return text;
end
 
৩২৭ ⟶ ২৫৭ নং লাইন:
local text;
if is_set(inactive) then
text = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id;
local inactive_year = inactive:match("%d%d%d%d") or ''; -- try to get the year portion from the inactive date
table.insert( z.error_categories, "".. selectyear(inactive) .. " থেকে নিষ্ক্রিয় ডিওআইসহ পাতা" );
text = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id;
inactive = " (" .. cfg.messages['inactive'] .. " " .. inactive .. ")"
if is_set(inactive_year) then
else
table.insert( z.error_categories, "Pages with DOIs inactive since " .. inactive_year );
text = externallinkid({link = handler.link, label = handler.label,
else
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
table.insert( z.error_categories, "Pages with inactive DOIs" ); -- when inactive doesn't contain a recognizable year
inactive = ""
end
end
inactive = " (" .. cfg.messages['inactive'] .. " " .. inactive .. ")"
if ( string.sub(id,1,3) ~= "10." ) then
else
cat = seterror( 'bad_doi' );
text = externallinkid({link = handler.link, label = handler.label,
end
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
return text .. inactive =.. ""cat
end
 
if nil == id:match("^10%.[^%s–]-[^%.,]$") then -- doi must begin with '10.', must not contain spaces or endashes, and must not end with period or comma
cat = ' ' .. seterror( 'bad_doi' );
end
return text .. inactive .. cat
end
 
৩৮৩ ⟶ ৩০৭ নং লাইন:
]]
function issn(id)
local clean_issn;
local issn_copy = id; -- save a copy of unadulterated issn; use this version for display if issn does not validate
local handler = cfg.id_handlers['ISSN'];
local temp = 0;
local text;
local valid_issn = true;
 
id=id:gsub( "[%s-–]", "" ); -- strip spaces, hyphens, and ndashes from the issn
clean_issn=string.sub( id, 1, 4 ) .. "-" .. string.sub( id, 5 ); -- make a copy with a hyphen after 4 digits; use this version for display if issn validates
 
if 8 ~= id:len() or nil == id:match( "^%d*X?$" ) then -- validate the issn: 8 didgits long, containing only 0-9 or X in the last position
valid_issn=false; -- wrong length or improper character
else
valid_issnid =is_valid_isxn( { id:byte(1, 8) }; -- validatetable of individual issnbytes
for i, v in ipairs( id ) do -- loop through all of the byte an calculate the checksum
if v == string.byte( "X" ) then -- if checkdigit is X
temp = temp + 10*( 9 - i ); -- it represents 10 decimal
else
temp = temp + tonumber( string.char(v) )*(9-i);
end
end
valid_issn = temp % 11 == 0; -- checksum must be zero for valid issn
end
 
if true == valid_issn then
id = string.sub( id, 1, 4 ) .. "-" .. string.sub( id, 5 )clean_issn; -- if valid, displayuse correctlythe formattedcleaned-up version for the display
else
id = issn_copy; -- if not valid, use the show the invalid issn with error message
৪১২ ⟶ ৩৪৭ নং লাইন:
end
 
--[[
This function sets default title types (equivalent to the citation including |type=<default value>) for those citations that have defaults.
Also handles the special case where it is desireable to omit the title type from the rendered citation (|type=none).
]]
function set_titletype(cite_class, title_type)
if is_set(title_type) then
if "none" == title_type then
title_type = ""; -- if |type=none then type parameter not displayed
end
return title_type; -- if |type= has been set to any other value use that value
end
 
if "podcast" == cite_class then -- if this citation is cite podcast
return "Podcast"; -- display podcast annotation
 
elseif "pressrelease" == cite_class then -- if this citation is cite press release
return "Press release"; -- display press release annotation
 
elseif "techreport" == cite_class then -- if this citation is cite techreport
return "Technical report"; -- display techreport annotation
elseif "thesis" == cite_class then -- if this citation is cite thesis (degree option handled after this function returns)
return "Thesis"; -- display simple thesis annotation (without |degree= modification)
end
end
 
-- returns a number according to the month in a date: 1 for January, etc. Capitalization and spelling must be correct. If not a valid month, returns 0
function get_month_number (month)
local long_months = {['January']=1, ['February']=2, ['March']=3, ['April']=4, ['May']=5, ['June']=6, ['July']=7, ['August']=8, ['September']=9, ['October']=10, ['November']=11, ['December']=12};
local short_months = {['Jan']=1, ['Feb']=2, ['Mar']=3, ['Apr']=4, ['May']=5, ['Jun']=6, ['Jul']=7, ['Aug']=8, ['Sep']=9, ['Oct']=10, ['Nov']=11, ['Dec']=12};
local temp;
temp=long_months[month];
if temp then return temp; end -- if month is the long-form name
temp=short_months[month];
if temp then return temp; end -- if month is the short-form name
return 0; -- misspelled, improper case, or not a month name
end
 
-- returns a number according to the sequence of seasons in a year: 1 for Winter, etc. Capitalization and spelling must be correct. If not a valid season, returns 0
function get_season_number (season)
local season_list = {['Winter']=1, ['Spring']=2, ['Summer']=3, ['Fall']=4, ['Autumn']=4}
local temp;
temp=season_list[season];
if temp then return temp; end -- if season is a valid name return its number
return 0; -- misspelled, improper case, or not a season name
end
 
--[[
Determines whether an URL string is valid
Returns true if day is less than or equal to the number of days in month; else returns false.
 
Assumes Julian calendar prior to year 1582 and Gregorian calendar thereafter. Accounts for Julian calendar leap years before 1582 and Gregorian leap years after 1582.
Where the two calendars overlap (1582 to approximately 1923) dates are assumed to be Gregorian.
]]
function is_valid_date (year, month, day)
local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
local month_length;
if (2==month) then -- if February
month_length = 28; -- then 28 days unless
if 1582 > tonumber(year) then -- Julian calendar
if 0==(year%4) then
month_length = 29;
end
else -- Gregorian calendar
if (0==(year%4) and (0~=(year%100) or 0==(year%400))) then -- is a leap year?
month_length = 29; -- if leap year then 29 days in February
end
end
else
month_length=days_in_month[month];
end
 
if tonumber (day) > month_length then
return false;
end
return true;
end
 
--[[
Check a pair of months or seasons to see if both are valid members of a month or season pair.
 
Month pairs are expected to be left to right, earliest to latest in time. Similarly, seasons are also left to right, earliest to latest in time. There is
an oddity with seasons. Winter is assigned a value of 1, spring 2, ..., fall and autumn 4. Because winter can follow fall/autumn at the end of a calender year, a special test
is made to see if |date=Fall-Winter yyyy (4-1) is the date.
]]
 
function is_valid_month_season_range(range_start, range_end)
local range_start_number = get_month_number (range_start);
if 0 == range_start_number then -- is this a month range?
local range_start_number = get_season_number (range_start); -- not a month; is it a season? get start season number
local range_end_number = get_season_number (range_end); -- get end season number
 
if 0 ~= range_start_number then -- is start of range a season?
if range_start_number < range_end_number then -- range_start is a season
return true; -- return true when range_end is also a season and follows start season; else false
end
if 4 == range_start_number and 1 == range_end_number then -- special case when range is Fall-Winter or Autumn-Winter
return true;
end
end
return false; -- range_start is not a month or a season; or range_start is a season and range_end is not; or improper season sequence
end
 
local range_end_number = get_month_number (range_end); -- get end month number
if range_start_number < range_end_number then -- range_start is a month; does range_start precede range_end?
return true; -- if yes, return true
end
return false; -- range_start month number is greater than or equal to range end number; or range end isn't a month
end
 
--[[
Check date format to see that it is one of the formats approved by MOS:DATE: MMMM D, YYYY; D MMMM YYYY; MMMM YYYY; YYYY-MM-DD; YYYY.
Additionally, check the date to see that it is a real date: no 31 in 30-day months; no 29 February when not a leap year. Months, both long-form and three
character abbreviations, and seasons must be spelled correctly.
 
If the date fails the fomat tests, this function returns false but does not return values for anchor_year and COinS_date. When this happens, the date parameter is
used in the COinS metadata and the CITEREF identifier gets its year from the year parameter if present.
 
Inputs:
date_string - date string from date-holding parameters (date, year, accessdate, embargo, archivedate, etc)
 
Returns:
false if date string is not a real date; else
true, anchor_year, COinS_date
anchor_year can be used in CITEREF anchors
COinS_date is date_string without anchor_year disambiguator if any
]]
function check_date (date_string)
local year;
local month=0; -- assume that month and day are not used; if either is zero then final year/month/day validation is not necessary
local day=0;
local day2=0; -- second day in a day range
local anchor_year;
local coins_date;
 
if date_string:match("^%d%d%d%d%-%d%d%-%d%d$") then -- Year-initial numerical year month day format
year, month, day=string.match(date_string, "(%d%d%d%d)%-(%d%d)%-(%d%d)");
month=tonumber(month);
if 12 < month or 1 > month or 1583 > tonumber(year) then return false; end -- month number not valid or not Gregorian calendar
anchor_year = year;
 
elseif date_string:match("^%a+ +[1-9]%d?, +[1-9]%d%d%d%a?$") then -- month-initial: month day, year
month, day, anchor_year, year=string.match(date_string, "(%a+)%s*(%d%d?),%s*((%d%d%d%d)%a?)");
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
elseif date_string:match("^%a+ +[1-9]%d?–[1-9]%d?, +[1-9]%d%d%d%a?$") then -- month-initial day range: month day–day, year; days are separated by endash
month, day, day2, anchor_year, year=string.match(date_string, "(%a+) +(%d%d?)–(%d%d?), +((%d%d%d%d)%a?)");
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
 
elseif date_string:match("^[1-9]%d? +%a+ +[1-9]%d%d%d%a?$") then -- day-initial: day month year
day, month, anchor_year, year=string.match(date_string, "(%d%d*)%s*(%a+)%s*((%d%d%d%d)%a?)");
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
 
elseif date_string:match("^[1-9]%d?–[1-9]%d? +%a+ +[1-9]%d%d%d%a?$") then -- day-range-initial: day–day month year; days are separated by endash
day, day2, month, anchor_year, year=string.match(date_string, "(%d%d?)–(%d%d?) +(%a+) +((%d%d%d%d)%a?)");
if tonumber(day) >= tonumber(day2) then return false; end -- date range order is left to right: earlier to later; dates may not be the same;
month = get_month_number (month);
if 0 == month then return false; end -- return false if month text isn't one of the twelve months
 
elseif mw.ustring.match (date_string, "^%a+–%a+ +[1-9]%d%d%d%a?$") then -- month/season range year; months separated by endash
local month2
month, month2, anchor_year, year=mw.ustring.match (date_string, "(%a+)[%-/–](%a+)%s*((%d%d%d%d)%a?)");
if false == is_valid_month_season_range(month, month2) then
return false;
end
elseif date_string:match("^%a+ +%d%d%d%d%a?$") then -- month/season year
month, anchor_year, year=string.match(date_string, "(%a+)%s*((%d%d%d%d)%a?)");
if 0 == get_month_number (month) then -- if month text isn't one of the twelve months, might be a season
if 0 == get_season_number (month) then -- not a month, is it a season?
return false; -- return false not a month or one of the five seasons
end
end
 
elseif date_string:match("^[1-9]%d%d%d?%a?$") then -- year; here accept either YYY or YYYY
anchor_year, year=string.match(date_string, "((%d%d%d%d?)%a?)");
 
else
return false; -- date format not one of the MOS:DATE approved formats
end
 
if 0~=month and 0~=day then -- check year month day dates for validity
if 0~=day2 then -- If there is a second day (d–d Mmm YYYY or Mmm d–d, YYYY) test the second date
if false==is_valid_date(year,month,day2) then
return false; -- second date in date range string is not a real date return false; unset anchor_year and coins_date
end -- if second date range string is valid, fall through to test the first date range
end
if false==is_valid_date(year,month,day) then
return false; -- date string is not a real date return false; unset anchor_year and coins_date
end
end
 
coins_date= mw.ustring.gsub( date_string, "–", "-" ); -- if here, then date_string is valid; set coins_date and replace any ndash with a hyphen
return true, anchor_year, coins_date; -- format is good and date string represents a real date
end
 
--[[
Cycle the date-holding parameters in passed table date_parameters_list through check_date() to check compliance with MOS:DATE. For all valid dates, check_date() returns
true and values for anchor_year (used in CITEREF identifiers) and COinS_date (used in the COinS metadata). The |date= parameter test is unique. This function only
accepts anchor_year and COinS_date results from the |date= parameter test and |date= is the only date-holding parameter that is allowed to contain the no-date keywords
"n.d." or "nd" (without quotes).
 
Unlike most error messages created in this module, only one error message is created by this function. Because all of the date holding parameters are processed serially,
a single error message is created as the dates are tested.
]]
 
function dates(date_parameters_list)
local anchor_year; -- will return as nil if the date being tested is not |date=
local COinS_date; -- will return as nil if the date being tested is not |date=
local error_message ="";
local good_date=false;
for k, v in pairs(date_parameters_list) do -- for each date-holding parameter in the list
if is_set(v) then -- if the parameter has a value
if v:match("^c%. [1-9]%d%d%d?%a?$") then -- special case for c. year or with or without CITEREF disambiguator - only |date= and |year=
if 'date'==k then
good_date, anchor_year, COinS_date = true, v:match("((c%. [1-9]d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter
elseif 'year'==k then
good_date = true;
end
elseif 'year'==k then -- if the parameter is |year= (but not c. year)
if v:match("^[1-9]%d%d%d?%a?$") then -- year with or without CITEREF disambiguator
good_date = true;
end
elseif 'date'==k then -- if the parameter is |date=
if v:match("n%.d%.%a?") then -- if |date=n.d. with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v:match("((n%.d%.)%a?)"); --"n.d."; no error when date parameter is set to no date
elseif v:match("nd%a?$") then -- if |date=nd with or without a CITEREF disambiguator
good_date, anchor_year, COinS_date = true, v:match("((nd)%a?)"); --"nd"; no error when date parameter is set to no date
else
good_date, anchor_year, COinS_date = check_date (v); -- go test the date
end
else -- any other date-holding parameter
good_date = check_date (v); -- go test the date
end
if false==good_date then -- assemble one error message so we don't add the tracking category multiple times
if is_set(error_message) then -- once we've added the first portion of the error message ...
error_message=error_message .. ", "; -- ... add a comma space separator
end
error_message=error_message .. "&#124;" .. k .. "="; -- add the failed parameter
end
end
end
if is_set(error_message) then
table.insert( z.message_tail, { seterror( 'bad_date', {error_message}, true ) } ); -- add this error message
end
 
return anchor_year, COinS_date; -- and done
end
 
--[[
Determines whether a URL string is valid
 
At present the only check is whether the string appears to
৬৮৪ ⟶ ৩৬৫ নং লাইন:
function cleanisbn( isbn_str )
return isbn_str:gsub( "[^-0-9X]", "" );
end
 
--[[
ISBN-10 and ISSN validator code calculates checksum across all isbn/issn digits including the check digit. ISBN-13 is checked in checkisbn().
If the number is valid the result will be 0. Before calling this function, issbn/issn must be checked for length and stripped of dashes,
spaces and other non-isxn characters.
]]
function is_valid_isxn (isxn_str, len)
local temp = 0;
isxn_str = { isxn_str:byte(1, len) }; -- make a table of bytes
len = len+1; -- adjust to be a loop counter
for i, v in ipairs( isxn_str ) do -- loop through all of the bytes and calculate the checksum
if v == string.byte( "X" ) then -- if checkdigit is X
temp = temp + 10*( len - i ); -- it represents 10 decimal
else
temp = temp + tonumber( string.char(v) )*(len-i);
end
end
return temp % 11 == 0; -- returns true if calculation result is zero
end
 
-- Determines whether an ISBN string is valid
function checkisbn( isbn_str )
isbn_str = cleanisbn( isbn_str ):gsub( "-", "" );
if nil ~= isbn_str:match("[^%s-0-9X]") then return false; end -- fail if isbn_str contains anything but digits, hyphens, or the uppercase X
local len = isbn_str:len();
isbn_str = isbn_str:gsub( "-", "" ):gsub( " ", "" ); -- remove hyphens and spaces
local len = isbn_str:len();
if len ~= 10 and len ~= 13 then
return false;
end
 
local temp = 0;
if len == 10 then
if len == 10 then
if isbn_str:match( "^%d*X?$" ) == nil then return false; end
return is_valid_isxn( isbn_str = { isbn_str:byte(1, 10len) };
for i, v in ipairs( isbn_str ) do
else
if v == string.byte( "X" ) then
local temp = 0;
temp = temp + 10*( 11 - i );
if isbn_str:match( "^97[89]%d*$" ) == nil then return false; end -- isbn13 begins with 978 or 979
else
isbn_str = { isbn_str:byte(1, len) };
temp = temp + tonumber( string.char(v) )*(11-i);
for i, v in ipairs( isbn_str ) do
end
temp = temp + (3 - 2*(i % 2)) * tonumber( string.char(v) );
end
return temp % 1011 == 0;
else
end
if isbn_str:match( "^%d*$" ) == nil then return false; end
isbn_str = { isbn_str:byte(1, len) };
for i, v in ipairs( isbn_str ) do
temp = temp + (3 - 2*(i % 2)) * tonumber( string.char(v) );
end
return temp % 10 == 0;
end
end
 
৮৪৬ ⟶ ৫১৫ নং লাইন:
return str;
end
 
--[[
Return the year portion of a date string, if possible.
Returns empty string if the argument can not be interpreted
as a year.
]]
function selectyear( str )
-- Is the input a simple number?
local num = tonumber( str );
if num ~= nil and num > 0 and num < 2100 and num == math.floor(num) then
return str;
else
-- Use formatDate to interpret more complicated formats
local lang = mw.getContentLanguage();
local good, result;
good, result = pcall( lang.formatDate, lang, 'Y', str );
if good then
return result;
else
-- extract year if the date uses seasons
str=string.lower (str);
local seasons={"winter", "spring", "summer", "fall", "autumn"};
local date_string_split=mw.text.split (str, "[%s%-/–]"); -- split date string into parts; white space, hyphen, forward slash, and ndash are allowed separators
local has_season=false;
for n,season_value in ipairs(seasons) do -- for each season ...
for n,split_value in ipairs(date_string_split) do -- ... loop through date string values
if split_value == season_value then -- does the split value match the season value?
if has_season==false then -- found one. if this one is the first we've found ...
has_season=true; -- ... remember that we found a season
end
elseif has_season==true then -- if split_value isn't a season, and we've previously found a season ...
num = tonumber( split_value ); -- ... convert current split value to a number if we can
if num ~= nil and num > 0 and num < 2100 and num == math.floor(num) then -- if it's a suitable number
return tostring( num ); -- return it as a string
end -- if num
end -- if string.find
end -- for split value loop
end -- season value loop
end -- if good
end -- if num
end -- selectyear
 
-- Attempts to convert names to initials.
৯৮২ ⟶ ৬৯৩ নং লাইন:
elseif k == 'PMC' then
table.insert( new_list, {handler.label, pmc( v, options.Embargo ) } );
elseif k == 'PMID' then
table.insert( new_list, {handler.label, pmid( v ) } );
elseif k == 'ISSN' then
table.insert( new_list, {handler.label, issn( v ) } );
৯৯৭ ⟶ ৭০৬ নং লাইন:
end
function comp( a, b ) -- used in following table.sort()
return a[1] < b[1];
end
১,১৪৭ ⟶ ৮৫৬ নং লাইন:
 
--[[
This is the main function doingfoing the majority of the citation
formatting.
]]
১,১৮৯ ⟶ ৮৯৮ নং লাইন:
local TransChapter = A['TransChapter'];
local TitleType = A['TitleType'];
local Degree = A['Degree'];
local Docket = A['Docket'];
local ArchiveURL = A['ArchiveURL'];
local URL = A['URL']
১,১৯৯ ⟶ ৯০৬ নং লাইন:
local ConferenceURLorigin = A:ORIGIN('ConferenceURL');
local Periodical = A['Periodical'];
if ( config.CitationClass == "encyclopaedia" ) then
if not is_set(Chapter) then
if not is_set(Title) then
Title = Periodical;
Periodical = '';
else
Chapter = Title
TransChapter = TransTitle
Title = '';
TransTitle = '';
end
end
end
 
local Series = A['Series'];
--[[
Parameter remapping for cite encyclopedia:
When the citation has these parameters:
|encyclopedia and |title then map |title to |article and |encyclopedia to |title
|encyclopedia and |article then map |encyclopedia to |title
|encyclopedia then map |encyclopedia to |title
 
|trans_title maps to |trans_chapter when |title is re-mapped
 
All other combinations of |encyclopedia, |title, and |article are not modified
]]
if ( config.CitationClass == "encyclopaedia" ) then
if is_set(Periodical) then -- Periodical is set when |encyclopedia is set
if is_set(Title) then
if not is_set(Chapter) then
Chapter = Title; -- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title
TransChapter = TransTitle;
Title = Periodical;
Periodical = ''; -- redundant so unset
TransTitle = ''; -- redundant so unset
end
else -- |title not set
Title = Periodical; -- |encyclopedia set and |article set or not set so map |encyclopedia to |title
Periodical = ''; -- redundant so unset
end
end
end
 
local Series = A['Series'];
local Volume = A['Volume'];
local Issue = A['Issue'];
১,২৭৪ ⟶ ৯৬৭ নং লাইন:
local DoiBroken = A['DoiBroken'];
local ID = A['ID'];
-- Special case for cite techreport.
local ID = A['ID'];
if (config.CitationClass == "techreport") then -- special case for cite techreport
if is_set(Issue) then -- cite techreport uses 'number', which other citations aliase to 'issue'
if not is_set(ID) then -- can we use ID for the "number"?
ID = Issue; -- yes, use it
Issue = ""; -- unset Issue so that "number" isn't duplicated in the rendered citation or COinS metadata
else -- can't use ID so emit error message
ID = ID .. " " .. seterror('redundant_parameters', '<code>&#124;id=</code> and <code>&#124;number=</code>');
end
end
end
local ASINTLD = A['ASINTLD'];
local IgnoreISBN = A['IgnoreISBN'];
১,৩১৭ ⟶ ৯৯৭ নং লাইন:
end
 
-- At this point fields may be nil if they weren't specified in the template use. We can use that fact.
local anchor_year; -- used in the CITEREF identifier
local COinS_date; -- used in the COinS metadata
 
-- legacy: promote concatenation of |day=, |month=, and |year= to Date if Date not set; or, promote PublicationDate to Date if neither Date nor Year are set.
if not is_set(Date) then
Date = Year; -- promote Year to Date
Year = nil; -- make nil so Year as empty string isn't used for CITEREF
if is_set(Date) then
local Month = A['Month'];
if is_set(Month) then
Date = Month .. " " .. Date;
local Day = A['Day']
if is_set(Day) then Date = Day .. " " .. Date end
end
elseif is_set(PublicationDate) then -- use PublicationDate when |date= and |year= are not set
Date = PublicationDate; -- promonte PublicationDate to Date
PublicationDate = ''; -- unset, no longer needed
end
end
 
if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation
 
-- Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates.
-- TODO: 2013-10-27: AirDate is nil when dates() is called because it hasn't been set yet. Move the call to dates() or set AirDate earlier.
anchor_year, COinS_date = dates({['accessdate']=AccessDate, ['airdate']=AirDate, ['archivedate']=ArchiveDate, ['date']=Date, ['doi_brokendate']=DoiBroken,
['embargo']=Embargo, ['laydate']=LayDate, ['publicationdate']=PublicationDate, ['year']=Year});
 
-- At this point fields may be nil if they weren't specified in the template use. We can use that fact.
 
--Account for the oddity that is {{cite journal}} with |pmc= set and |url= not set
if config.CitationClass == "journal" and not is_set(URL) and is_set(ID_list['PMC']) then
if not is_embargoed(Embargo) then
URL=cfg.id_handlers['PMC'].prefix .. ID_list['PMC']; -- set url to be the same as the PMC external link if not embargoed
URLorigin = cfg.id_handlers['PMC'].parameters[1]; -- set URLorigin to parameter name for use in error message if citation is missing a |title=
end
end
 
-- Account for the oddity that is {{cite conference}}, before generation of COinS data.
if is_set(BookTitle) then
১,৩৯৯ ⟶ ১,০৪৪ নং লাইন:
['Title'] = Title,
['PublicationPlace'] = PublicationPlace,
['Date'] = first_set(Date, Year, PublicationDate),
['Date'] = first_set(COinS_date, Date), -- COinS_date has correctly formatted date if Date is valid; any reason to keep Date here? Should we be including invalid dates in metadata?
['Series'] = Series,
['Volume'] = Volume,
১,৪৯৬ ⟶ ১,১৪১ নং লাইন:
end
end
if not is_set(Date) then
Date = Year;
if is_set(Date) then
local Month = A['Month'];
if is_set(Month) then
Date = Month .. " " .. Date;
local Day = A['Day']
if is_set(Day) then Date = Day .. " " .. Date end
end
end
end
if inArray(PublicationDate, {Date, Year}) then PublicationDate = ''; end
if not is_set(Date) and is_set(PublicationDate) then
Date = PublicationDate;
PublicationDate = '';
end
 
-- Captures the value for Date prior to adding parens or other textual transformations
local DateIn = Date;
if not is_set(URL) and
১,৫০৩ ⟶ ১,১৬৯ নং লাইন:
not is_set(TranscriptURL) then
-- Test if cite web oris cite podcast |url= iscalled missingwithout orgiving emptya URL
if inArray( config.CitationClass, {== "web","podcast"} ) then
table.insert( z.message_tail, { seterror( 'cite_web_url', {}, true ) } );
end
-- Test if accessdate is given without giving a URL
১,৫৪৯ ⟶ ১,২১৫ নং লাইন:
TransChapter = wrap( 'trans-italic-title', TransChapter );
else
Chapter = kern_quotes (Chapter); -- if necessary, separate chapter title's leading and trailing quote marks from Module provided quote marks
Chapter = wrap( 'quoted-title', Chapter );
TransChapter = wrap( 'trans-quoted-title', TransChapter );
১,৫৯৭ ⟶ ১,২৬২ নং লাইন:
if is_set(Periodical) then
Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from Module provided quote marks
Title = wrap( 'quoted-title', Title );
TransTitle = wrap( 'trans-quoted-title', TransTitle );
elseif inArray(config.CitationClass, {"web","news","pressrelease","conference","podcast"}) and
not is_set(Chapter) then
Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from Module provided quote marks
Title = wrap( 'quoted-title', Title );
TransTitle = wrap( 'trans-quoted-title', TransTitle );
১,৬৬৯ ⟶ ১,৩৩২ নং লাইন:
if is_set(Pages) then
if is_set(Periodical) and
not inArray(config.CitationClass, {"encyclopaedia","web","book","news","podcast"}) then
Pages = ": " .. Pages;
elseif tonumber(Pages) ~= nil then
১,৬৭৯ ⟶ ১,৩৪২ নং লাইন:
else
if is_set(Periodical) and
not inArray(config.CitationClass, {"encyclopaedia","web","book","news","podcast"}) then
Page = ": " .. Page;
else
১,৭১৭ ⟶ ১,৩৮০ নং লাইন:
]]
if is_set (Language) then
-- local name = mw.language.fetchLanguageName( Language:lower(), "en" ); -- experiment: this seems to return correct ISO 639-1 language names
local name = cfg.iso639_1[Language:lower()]; -- get the language name if Language parameter has a valid iso 639-1 code
if nil == name then
Language=" " .. wrap( 'language', Language ); -- no match, use parameter's value
else
if 0 == this_page.namespace and 'enbn' ~= Language:lower() then --found a match; is this page main / article space and English not the language?
Language=" " .. wrap( 'language', name .. '[[Category:Articles with ' .. name .. '-language externalভাষার বহিঃসংযোগের সাথে linksনিবন্ধসমূহ]]' ); -- in main space and not English: categorize
else
Language=" " .. wrap( 'language', name ); --not in mainspace or language is English so don't categorize
১,৭৩২ ⟶ ১,৩৯৪ নং লাইন:
end
 
Others = is_set(Others) and (sepc .. " " .. Others) or "";
TitleType = is_set(TitleType) and (" (" .. TitleType .. ")") or "";
 
TitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or "";
-- handle type parameter for those CS1 citations that have default values
 
if inArray(config.CitationClass, {"podcast","pressrelease","techreport","thesis"}) then
TitleType = set_titletype (config.CitationClass, TitleType);
if is_set(Degree) and "Thesis" == TitleType then -- special case for cite thesis
TitleType = Degree .. " thesis";
end
end
 
if is_set(TitleType) then -- if type parameter is specified
TitleType = " (" .. TitleType .. ")"; -- display it in parentheses
end
 
TitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or "";
Edition = is_set(Edition) and (" " .. wrap( 'edition', Edition )) or "";
Issue = is_set(Issue) and (" (" .. Issue .. ")") or "";
১,৭৮৫ ⟶ ১,৪৩৪ নং লাইন:
if is_set(ID) then ID = sepc .." ".. ID; end
if "thesis" == config.CitationClass and is_set(Docket) then
ID = sepc .." Docket ".. Docket .. ID;
end
 
ID_list = buildidlist( ID_list, {DoiBroken = DoiBroken, ASINTLD = ASINTLD, IgnoreISBN = IgnoreISBN, Embargo=Embargo} );
১,৮৫৯ ⟶ ১,৫০৪ নং লাইন:
local Publisher;
if is_set(Periodical) and
not inArray(config.CitationClass, {"encyclopaedia","web","pressrelease","podcast"}) then
if is_set(PublisherName) then
if is_set(PublicationPlace) then
১,৯০৬ ⟶ ১,৫৫১ নং লাইন:
end
end
 
--[[
Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that
the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided).
]]
if "speech" == config.CitationClass then -- cite speech only
TitleNote = " (Speech)"; -- annotate the citation
if is_set (Periodical) then -- if Periodical, perhaps because of an included |website= or |journal= parameter
if is_set (Conference) then -- and if |event= is set
Conference = Conference .. sepc .. " "; -- then add appropriate punctuation to the end of the Conference variable before rendering
end
end
end
 
-- Piece all bits together at last. Here, all should be non-nil.
২,০১৭ ⟶ ১,৬৪৯ নং লাইন:
 
-- Now enclose the whole thing in a <span/> element
if not is_set(Year) then
if is_set(DateIn) then
Year = selectyear( DateIn );
elseif is_set(PublicationDate) then
Year = selectyear( PublicationDate );
end
end
local options = {};
২,০৪০ ⟶ ১,৬৮০ নং লাইন:
end
end
names[ #names + 1 ] = first_set(Year, anchor_year); -- Year first for legacy citations
id = anchorid(names)
end