local convert = require('মডিউল:সংখ্যা রূপান্তরকারী').convert; local horizontal_timeline = {};  local getArgs = require('Module:Arguments').getArgs local builder = mw.html.create()  local function defaultInvokeFunc(funcName) 	return function (frame) 		args = getArgs(frame, {                        trim = true,                        removeBlanks = true,                        parentFirst = true                     })          local from = getNotNilValue(tonumber(args['from']))         local to =  getNotNilValue(tonumber(args['to']))          if not from or not to or from == to then             return ("from and to cannot be nil or equal.")         else         	return horizontal_timeline[funcName](args)         end 	end end  horizontal_timeline.showTimeLine = defaultInvokeFunc('_showTimeLine') function horizontal_timeline._showTimeLine(args)     local wdth = getNotNilValue(args['width'], '100%' )     local bordr = getNotNilValue(args['border'], '1px solid rgb(170, 170, 170)' )     local bgCol = getNotNilValue(args['plot-color'], args['plot-colour'], 'transparent')     local mrgn = getNotNilValue(args['margin'], '1em')      local div_root = builder         :tag('div')         :cssText('float:left;border:'..bordr .. ';width:'..wdth)      local cntnt = div_root         :tag('div')         :cssText('text-align:left; padding:1em; font-size:95%; margin:' ..mrgn.. '; background:'..bgCol)                 local rowNums = affixNums(args, 'row') -- Gets numbers for row1, row2, etc. with nil arguments removed.     for _, num in ipairs(rowNums) do         local rowType = args['row' .. num] -- Gets args.rowtype1, args.rowtype2, etc. with nil arguments removed.         if rowType == 'scale' then             cntnt:wikitext(horizontal_timeline.scaleRow(args))         elseif rowType == 'note' then             cntnt:wikitext(horizontal_timeline.noteRow(num, args))         elseif rowType == 'timeline' then             cntnt:wikitext(horizontal_timeline.timelineRow(num, args))         else             cntnt:wikitext(rowType)         end     end     if args.caption then         cntnt:tag('div')             :cssText('clear:both; text-align:center')             :wikitext(args.caption)             :done()     end     return tostring(div_root) .. "" end  horizontal_timeline.showOneRow = defaultInvokeFunc('_showOneRow') function horizontal_timeline._showOneRow(args)     local rowNums = affixNums(args, 'row') -- Gets numbers for row1, row2, etc. with nil arguments removed.     for _, num in ipairs(rowNums) do         local rowType = args['row' .. num] -- Gets args.rowtype1, args.rowtype2, etc. with nil arguments removed.         if rowType == 'scale' then             return horizontal_timeline.scaleRow(args)         elseif rowType == 'note' then             return horizontal_timeline.noteRow(num, args)         elseif rowType == 'timeline' then             return horizontal_timeline.timelineRow(num, args)         else             return wikitext(rowType)         end     end     return "?" end  function horizontal_timeline.timelineRow(num, args)     local root = mw.html.create()          local from = getNotNilValue(tonumber(args['from']))     local to =  getNotNilValue(tonumber(args['to']))          local style    = getNotNilValue(args['row' .. num .. '-style'], )     local hght     = getNotNilValue (args['row' .. num .. '-height'], 									 args[style .. '-height'], 									 '2.5em')     local bordrTop = getNotNilValue (args['row' .. num .. '-bordertop'], 									 args[style .. '-bordertop'], 									 'none')     local bordrBtm = getNotNilValue (args['row' .. num .. '-borderbottom'], 									 args[style .. '-borderbottom'], 									 'none')     local txtTop   = getNotNilValue (args['row' .. num .. '-texttop'], 									 args[style .. '-texttop'], 									 '0em')     local colr     = getNotNilValue (args['row' .. num .. '-colour'],     	                             args['row' .. num .. '-color'],     	                             args[style .. '-colour'],     	                             args[style .. '-color'],     	                             'transparent') 	local barborder = getNotNilValue (args['bar-border'], '1px solid #000') 	                                  if bordrTop ~= 'none' then     	bordrTop = 'border-top:' .. bordrTop .. ';'     else     	bordrTop =  	end 	 	if bordrBtm ~= 'none' then     	bordrBtm = 'border-bottom:' .. bordrBtm .. ';'     else     	bordrBtm = 	end      local p = root          :tag('div')             :cssText("clear:both;width:100%; padding:0px; height:".. hght)             :cssText(bordrTop.. bordrBtm .. "background-color:"..colr)      local rowDat = affixNums(args, 'row'..num..'%-', '%-[a-zA-Z]*')     local lastTo = from     local firstNode = true     for _, vals in ipairs(rowDat) do      	local styleL    = getNotNilValue(args['row' .. num .. '-'.. vals ..  '-style'], style)          --These vars should be initialized every iteration. Do not move outside of loop         local bar_to = tonumber(getNotNilValue(args['row' .. num .. '-'.. vals .. '-to'],                                         args[styleL .. '-to'],                                         args[style.. '-'.. vals .. '-to'], to  ) )         local bar_fontsize =getNotNilValue(args['row' .. num .. '-'.. vals .. '-fontsize'],         								args[styleL .. '-fontsize'],                                         args[style..'-'.. vals .. '-fontsize'], '0.9em' )         local bar_bordr= getNotNilValue(args['row' .. num .. '-'.. vals .. '-border'],         								args[styleL .. '-border'],                                         args[style..'-'.. vals .. '-border'],                                         'none')         local bar_txtTop= getNotNilValue(args['row' .. num .. '-'.. vals .. '-texttop'],         								args[styleL .. '-texttop'],                                         args[style..'-'.. vals .. '-texttop'], txtTop )         local bar_text = getNotNilValue(args['row' .. num .. '-'.. vals .. '-text'],         								args[styleL .. '-text'],                                         args[style..'-'.. vals .. '-text'], )         local bar_colour = getNotNilValue(args['row' .. num .. '-'.. vals .. '-colour'],                                         args['row' .. num .. '-'.. vals .. '-color'],                                         args[styleL .. '-boxcolour'],                                         args[styleL .. '-boxcolor'],                                         args[style..'-'.. vals .. '-colour'],                                         args[style..'-'.. vals .. '-color'],                                         'transparent' )                                                  if from < to then             if bar_to > to then bar_to = to end             if lastTo < from then lastTo = from end         else             if bar_to < to then bar_to = to end             if lastTo > from then lastTo = from end     	end          local width =( (bar_to-lastTo)*100 / (to-from) ) --math.abs          if width > 0 and width <= 100 then             if bar_bordr == 'none' then                 if firstNode then -- for first box both left and right border needed                     bar_bordr = barborder .. "; border-left:" .. barborder                     firstNode = false                 else                     bar_bordr = barborder     	        end 		    end             p:tag('div')                 :cssText("float:left; height:100%; text-align:center; overflow: hidden; background-color:"..bar_colour)                 :cssText("width:"..width .."%")                     :tag('div')                     :cssText("-moz-box-sizing: border-box; -webkit-box-sizing: border-box;box-sizing: border-box;")                     :cssText("float:right; height:100%; width:100%; border-right:"..bar_bordr)                         :tag('div')                             :cssText('position: relative; top:'..bar_txtTop .. '; font-size:'.. bar_fontsize)                             :wikitext(bar_text)                         :done()                     :done()                 :done()         end          lastTo = bar_to     end     return tostring(root) end  function horizontal_timeline.noteRow(num, args)     local root = mw.html.create()          local from = getNotNilValue(tonumber(args['from']))     local to =  getNotNilValue(tonumber(args['to']))          local hght = getNotNilValue(args['row' .. num .. '-height'], '2.5em')      local p = root          :tag('div')             :cssText("width:100%; position:relative; left:-0.2em; top:0.8em; clear:both; height:".. hght)      local rowDat = affixNums(args, 'row'..num..'%-', '%-at')     if not rowDat then         return ("Please specify location for note at "..'row' .. num .. '-'.. vals .. '-at'.." parameter.")     end     for _, vals in ipairs(rowDat) do         local note_at   =args['row' .. num .. '-'.. vals .. '-at'] --will never be nil as it is what is used to receive rowDat         local note_text =getNotNilValue(args['row' .. num .. '-'.. vals .. '-text'],  )         local note_shift=getNotNilValue(args['row' .. num .. '-'.. vals .. '-shift'], '0em' )         local note_lift =getNotNilValue(args['row' .. num .. '-'.. vals .. '-lift'], '0em' )         local note_arrow=getNotNilValue(args['row' .. num .. '-'.. vals .. '-arrow'], '↓' )  		local note_sft = 100*(note_at - from) / (to-from)                  p:tag('div')             :cssText("position:absolute; top:0px; width:100%")                 :tag('div')                     :cssText("margin-left:".. note_sft .."%; margin-top:0; position:relative")                     :tag('span')                         :cssText("position:relative; top:0.25em; left:-1.5px")                         :wikitext(note_arrow)                         :done()                     :tag('span')                         :cssText("font-size:smaller; position:relative; line-height:3px; overflow:visible")                         :cssText("left:"..note_shift.."; top:"..note_lift.."; z-index:".. (1000- tonumber(num)))                         :wikitext(note_text)                         :done()                     :done()                 :done()             :done()     end     return tostring(root) end  function horizontal_timeline.scaleRow(args) 	local from = getNotNilValue(tonumber(args['from']))     local to =  getNotNilValue(tonumber(args['to']))     local inc = getNotNilValue( tonumber(args['inc']), (math.floor( (from - to) / 5 ) * -1) )     local negativeFmt = getNotNilValue(args['axis-negativeFmt'], '−%s')     local positiveFmt = getNotNilValue(args['axis-positiveFmt'], '%s')     local zeroFmt     = getNotNilValue(args['axis-zeroFmt'], '%s')     local nudge       = getNotNilValue(args['axis-nudge'], '-1.8em')      local wdth = math.abs ( (100 * inc) / (from - to) )     local root = mw.html.create()      local p = root         :wikitext("")         :tag('div')             :attr('id', 'Scale')             :cssText('clear:both;position:relative;top:-1.4em;left:-0.2em;width:100%;padding:0;height:2.5em')                  for var=from, to, inc do         if from < to then             if var+inc > to then wdth = 0 end         else             if var+inc < to then wdth = 0 end         end                  local lbl         if var < 0 then             lbl = string.format( negativeFmt, math.abs(var) )         elseif var > 0 then             lbl = string.format( positiveFmt, math.abs(var) )         else             lbl = string.format( zeroFmt, math.abs(var) )         end          local markr = getNotNilValue(args['axis-marker-'..lbl], '│')  		lbl = getNotNilValue(args['axis-'..lbl], lbl) 		         p:tag('div')             :cssText('float:left;overflow:visible;width:'.. wdth .. '%')             :wikitext(markr)             :tag('div')                 :cssText('font-size:86%; position:relative; left:'..nudge..'; overflow:visible; white-space:nowrap')                 :wikitext(convert('bn',lbl))                 :done()         :done()     end     p:done()     return tostring(root) end  --Returns the first non nil value from the list of parameters. function getNotNilValue(...)     for _,v in pairs(arg) do --Do not use ipairs. Will stop at first nil         if v then return v end     end     return nil end  function affixNums(t, prefix, suffix)     prefix = prefix or      suffix = suffix or ''          local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$'     local nums = {}     for k, v in pairs(t) do         if type(k) == 'string' then                         local num = mw.ustring.match(k, pattern)             if num then                 nums[#nums + 1] = tonumber(num)             end         end     end     table.sort(nums)     return nums end  return horizontal_timeline