Mòdul:Chart/proves

De Viquipèdia
Salta a la navegació Salta a la cerca
Icona de documentació de mòdul Documentació del mòdul [ mostra ] [ modifica el codi ] [ mostra l'historial ] [ refresca ]

Mòdul Chart (codi · ús · discussió · tests · casos prova | subpàgines · enllaços)

A continuació es mostra la documentació transclosa de la subpàgina /ús. [salta a la caixa de codi]


Compte, no funcionen el missatge emergent de les llegendes en mode Mòdul.

dif_x_prior:num,perc_abs sum_gr_prior:num,perc sum_gr_next:num,perc sum_x_prior:num,perc sum_x_next:num,perc num perc_x perc_gr perc_all dif_gr_prior:num,perc_abs dif_gr_next:num,perc_abs dif_x_prior:num,perc_abs dif_x_next:num,perc_abs sum_prior:num,perc sum_next:num,perc

Evolució del pes a Crackcity
Determinació de l'IMC segons els Servei Sanitari de la Salut de Llunyland[a]
Transparent.png
Transparent.png
Transparent.png
Transparent.png
Transparent.png
Transparent.png
Transparent.png
Transparent.png
Transparent.png
Transparent.png
Transparent.png
Transparent.png
50
100
150
200
250
300
1970
1990
2010
  • Normal/baix (<25)
  • Sobrepès (25-30)
  • Obesitat (30-40)
  • Mòrbida (>40)
  • Passant el cursor del ratolí per sobre de les columnes, el text de l'eix X i el text de la llegenda apareix informació emergent de les dades

    1. Com tothom sap, és un país molt llunyà

    Religions
    Subtítol
    Església catòlica: 78,7Altres cristians: 10,4Altres/sense religió: 10,9Circle frame.svg
    Creences
  • Església catòlica: 78,7
  • Altres cristians: 10,4
  • Altres/sense religió: 10,9
  • Passant el cursor del ratolí per sobre del pastís apareix informació emergent de les dades

    Anotació

    Religions
    Subtítol
    Església catòlica: 78,7Altres cristians: 10,4Altres/sense religió: 10,9Circle frame.svg
    Creences
  • Església catòlica: 78,7
  • Altres cristians: 10,4
  • Altres/sense religió: 10,9
  • Anotació

    Títol
    Transparent.png
    Transparent.png
    Transparent.png
    Transparent.png
    10
    20
    30
    40
    50
    60
    Abans
    Durant

  • Poma
  • Plàtan
  • Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

    Títol de llibre
    Transparent.png
    Transparent.png
    Transparent.png
    Transparent.png
    tooltip 1
    tooltip 2
    tooltip 3
    Transparent.png
    Transparent.png
    Transparent.png
    Transparent.png
    Transparent.png
    10
    20
    30
    40
    50
    60
    Abans
    Durant
    Després
    Post mortem

  • Poma
  • Plàtan
  • Taronja
  • Passant el cursor del ratolí per sobre de les columnes apareix informació emergent de les dades

    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.



    Títol
    Transparent.png
    Transparent.png
    Transparent.png
    Transparent.png
    tooltip 1
    tooltip 2
    tooltip 3
    Transparent.png
    Transparent.png
    Transparent.png
    Transparent.png
    Transparent.png
    10
    20
    30
    40
    50
    60
    Abans
    Durant
    Després
    Post mortem
  • Poma
  • Plàtan
  • Taronja
  • Passant el cursor del ratolí per sobre de les columnes apareix informació emergent de les dades



    Títol
    1: 1 Unitats (0,2%)7: 7 Unitats (1,5%)8: 8 Unitats (1,7%)9: 9 Unitats (1,9%)10: 10 Unitats (2,1%)11: 11 Unitats (2,3%)12: 12 Unitats (2,5%)13: 13 Unitats (2,7%)14: 14 Unitats (2,9%)15: 15 Unitats (3,2%)16: 16 Unitats (3,4%)17: 17 Unitats (3,6%)18: 18 Unitats (3,8%)19: 19 Unitats (4%)20: 20 Unitats (4,2%)21: 21 Unitats (4,4%)22: 22 Unitats (4,6%)23: 23 Unitats (4,8%)24: 24 Unitats (5%)25: 25 Unitats (5,3%)26: 26 Unitats (5,5%)27: 27 Unitats (5,7%)28: 28 Unitats (5,9%)29: 29 Unitats (6,1%)30: 30 Unitats (6,3%)31: 31 Unitats (6,5%)Circle frame.svg

  • 1: 1 Unitats (0,2%)
  • 7: 7 Unitats (1,5%)
  • 8: 8 Unitats (1,7%)
  • 9: 9 Unitats (1,9%)
  • 10: 10 Unitats (2,1%)
  • 11: 11 Unitats (2,3%)
  • 12: 12 Unitats (2,5%)
  • 13: 13 Unitats (2,7%)
  • 14: 14 Unitats (2,9%)
  • 15: 15 Unitats (3,2%)
  • 16: 16 Unitats (3,4%)
  • 17: 17 Unitats (3,6%)
  • 18: 18 Unitats (3,8%)
  • 19: 19 Unitats (4%)
  • 20: 20 Unitats (4,2%)
  • 21: 21 Unitats (4,4%)
  • 22: 22 Unitats (4,6%)
  • 23: 23 Unitats (4,8%)
  • 24: 24 Unitats (5%)
  • 25: 25 Unitats (5,3%)
  • 26: 26 Unitats (5,5%)
  • 27: 27 Unitats (5,7%)
  • 28: 28 Unitats (5,9%)
  • 29: 29 Unitats (6,1%)
  • 30: 30 Unitats (6,3%)
  • 31: 31 Unitats (6,5%)
  •                                                          --<source lang=lua>
    local SDebug = {}
    local p = {}
    
    -- Required modules
    local DefColors = require "Module:Plotter/DefaultColors"
    local SArgs = require "Module:SimpleArgs"
    local BrewerColors = require "Module:BrewerColors"
    local ChartColors = require "Module:ChartColors"
    local CFCM = require "Module:ComplForColorModules"
    local MC = require "Module:Multicol"
    local yesno = require('Module:Yesno')
    local AlignString = require('Module:AlignString')
    
    --BEGIN OF REQUIRED TRANSLATION--
    -- keywords used for languages: they are the names of the actual parameters of the templatea
    
    local WithTrans = true -- = two languages 
    local keywords = {
    	barChart =			{'bar chart',				''},
    	pieChart =			{'pie chart',				''},
    	
      --basic
    	width = 			{'width',					'amplada'},
    	delimiter = 		{'delimiter',				'delimitador'},
    	MouseOverTooltip =	{'tooltip info',			'info emergent'},
    	unitsPrefix =		{'units prefix',			'unitat com prefix'},
    	unitsSuffix =		{'units suffix',			'unitat com sufix'},
    	PercDecim =			{'percent decimals',		'decimals del percentatge'},
    	Title = 			{'title',					'títol'},
    	TitleBackground =	{'title background',		'fons del títol'},
    	Subtit =			{'subtitle',				'subtítol'},
    	SubtitBackground =	{'subtitle background',		'fons del subtítol'},
    	HideGroupLegends =	{'hide group legends',		'amaga la llegenda'},
    	LegendColumns = 	{'legend columns',			'columnes de la llegenda'},
    	LegendTitle =		{'legend title',			'títol de la llegenda'},
    	Note =				{'note',					'nota'},
    	align = 			{'align',					'alineació'},
    	
      --barChart
    	height =			{'height',					'alçada'},
    	group = 			{'group',					'grup'},
    	GroupNames =		{'group names',				'noms dels grups'},
    	links = 			{'links',					'enllaços'},
    	colors =			{'colors',					'colors'},
    	DefColor =			{'default color',			'color predeterminat'}, --not used
    	stack = 			{'stack',					'apilat'},
    	xlegend =			{'x legends',				'llegendes de x'},
    	yticks =			{'y tick marks',			'marques y'},
    	ScalePerGroup = 	{'scale per group',			'escala per grup'},
    	XText2Lines =		{'x text in 2 lines',		'text x en 2 línies'},
    	InPercent =			{'in percent',				'en percentatge'},
    	HideGridY =			{'hide grid y', 			'amaga la graella y'},
    	WallColor = 		{'wall color',				'color de paret'},
    	--tooltip
    	tooltip =			{'tooltip',					'text emergent'},
    	DataTooltipMode =	{'data tooltip mode',		'mode emergent de dades'},
    	accumulateTooltip = {'tooltip value accumulation',''}, --obsolet
    	colTooltip =		{'column tooltip',			'emergent de columnes'},
    	xTooltip =			{'x tooltip',				'emergent de x'},
    	legendTooltip = 	{'legend tooltip',			'emergent de llegenda'},
    	TooltipSep =		{'tooltip separator',		'separador emergent'},
    	
      --pieChart
    	slices =			{'slices',					'sectors'},
    	slice = 			{'slice',					'sector'},
    	radius =			{'radius',					'radi'},
    	ColorPalette =		{'color palette',			'paleta de colors'},
    	percent =			{'percent',					'percentatge'}, --obsolet
    	LegendNumbers =		{'numbers in legend',		'números en llegenda'},
    	SliceNumbers =		{'numbers in slices',		'números en sectors'},
    }	
    local Quali =	{'quali',	'quali'} -- Qualitative
    local SemiQ =	{'semiq',	'semiq'} -- Semi-quantitative
    	
    --Error messages:
    local RS_SliceWithNotNumber = 'Sector %d: "%s", el primer element ("%s") hauria de ser un número'
    local RS_NoSlices = "no s'ha trobat cap sector: no es pot dibuixar gràfic"
    local RS_RequiredValForS = "ha de subministrar-se valors per a %s"
    local RS_KWNumAndGroupNumNotMatched = "%s hauria de contenir el mateix nombre d'elements que el nombre de grups, però en conté %d elements i aquí hi han %d grups"
    local RS_IncompatibleSettings = 'Assignació incorrecte: no són compatibles %s i %s.'
    local RS_NotHaveSameNumber = '%s %d no té el mateix nombre de valors que %s 1'
    local RS_InvalLegendNumber = 'Nombre incorrecte de %s. Hauria de ser exactament %d'
    local RS_ExpectedNumForKW = "S'esperava un índex numèric per a la clau %s en lloc de %s"
    local RS_EmptyTooltip = 'Sense valor per a "%s" de "%s". Són vàlids "%s"'
    local RS_InvalValueFor = 'Valor incorrecte per a "%s": %s. '
    local RS_InvalTooltip = RS_InvalValueFor..'Només són vàlids "%s"'
    local RS_InvalTooltip1Group = "Quan només hi ha un grup no s'admès assignar opcions a "..'"%s"' 
    local RS_InvalTooltipMore1Group = "Quan hi ha més d'un grup no s'admès "..'"%s" per a "%s"' 
    local RS_LookAtHelp = RS_InvalValueFor.."Mireu l'ajuda de la plantilla per aquesta opció"
    local RS_Any_Group_IsRequired = 'Cal assignar algun grup'
    --local RS_Any_Group_IsRequired = 'Any group is required'
    local RS_Selected2LinesButNoSpaces = 'Hi ha seleccionat dues línies per les llegendes dels valors X, però no hi ha cap llegenda amb dues paraules'
    --local RS_Selected2LinesButNoSpaces = 'Two lines are selected for the legends of the X values, but there is no legend with two words'
    local RS_SetDataTooltipModeAndCustomDataTooltipMode = 'Del mode automatitzat de text emergent de dades, heu assignat valors per a %s i per %s'
    --local RS_SetDataTooltipModeAndCustomDataTooltipMode = 'For automated tooltip mode of data, you have assigned values for %s and %s'
    local RS_InvalDataTooltipMode = 'Mode automatitzat de text emergent de dades (%s) incorrecte: %s'
    --local RS_InvalDataTooltipMode = 'Invalid automated tooltip mode of data (%s): %s'
    local RS_InvalDataTooltipMode2Need = "A %s: Són necessaris dos paràmetres (per X i Y) i n'hi han %d"
    --local RS_InvalDataTooltipMode2Need = "%s: Two parameters are required (for X and Y) and there are %d"
    --Other messages:
    local RS_MouseOverPie = "Passant el cursor del ratolí per sobre del pastís apareix informació emergent de les dades"
    --Moving the mouse cursor over pie tooltips with complementary information appear
    local RS_MouseOverTooltip = "Passant el cursor del ratolí per sobre de %s apareix informació emergent de les dades"
    --Moving the mouse cursor over %s tooltips with complementary information appear
    local RS_MouseOverCols = 'les columnes'
    local RS_MouseOverX = "el text de l'eix X"
    local RS_MouseOverLegend = 'el text de la llegenda'
    local RS_And = 'i'
    
    local RS_Tt_abs = 'abs.:'
    local RS_Tt_rel = 'rel.:'
    local RS_Total = 'Total'
    --END OF REQUIRED TRANSLATION--
    
    -- Variables
    local delimiter = ':'
    local HideGroupLegends = false
    local LegendColumns = 1
    local LegendTitle = ''
    local align = ''
    local Title = ''
    local TitleBackground = ''
    local Subtit = ''
    local SubtitBackground = ''
    local prefix = ''
    local suffix = ''
    local TooltipSep = ':'
    local PercDecim = 100
    local MouseOverTooltip = false
    local colors = {}
    
    local function roundup (x) -- returns the next round number: eg., for 30 to 39.999 will return 40, for 3000 to 3999.99 wil return 4000. for 10 - 14.999 will return 15.
    	local ordermag = 10 ^ math.floor (math.log10 (x))
    	local normalized = x /  ordermag
    	local top = normalized >= 1.5 and  (math.floor (normalized + 1)) or 1.5
    	return ordermag * top, top, ordermag
    end
    
    local function round(num, PercDecimimalPlaces)
    	local mult = 10^(PercDecimimalPlaces or 0)
    	return math.floor(num * mult + 0.5) / mult
    end
    
    local function fnum (num)
    	return mw.getContentLanguage():formatNum (tonumber (num) or 0)
    end	
    
    local function Mult100 (AValue,NDec)
    	return fnum(round(AValue*100,NDec))..'%'
    end
    	
    local function nulOrWhitespace (s)
    	return (not s) or (mw.text.trim (s) == '')
    end
    
    local function NonBreak (s)
    	return string.gsub (s, ' ', '&#160;')
    end
    
    local function NonBreakArr (ATooltipLines)
    	for k = 1, #ATooltipLines do
    		ATooltipLines[k] = NonBreak (ATooltipLines[k])
    	end	
    end
    
    local MarginsForText = 'margin-left:0.5em; margin-right:0.5em; margin-top:0.4em; margin-bottom:0.4em; '
    
    local function createLegends (tab, legends, AddedLegends, cols, Tooltips)
    	if #legends > 1 and not HideGroupLegends then
    		local WithTooltips = table.getn(Tooltips) > 0
    		table.insert (tab, '<div style="width:auto; text-align:left; '..MarginsForText..'">') 
    		if LegendTitle ~= '' then
    			table.insert (tab, '<div align="left"><b>'..LegendTitle..'</b></div>')
    		end	
    		local Show = {}
    		local WithAddedLegends = AddedLegends ~= nil
    		for gi=1, #legends do
    			STooltip = ''
    			if WithTooltips then
    				STooltip = Tooltips[gi]
    			end	
    			local WLegend = legends[gi]
    			if WithAddedLegends then
    				WLegend = WLegend..' '..AddedLegends[gi]
    			end	
    			table.insert (Show, CFCM.LegendColor(cols[gi],WLegend,STooltip))
    		end
    		local SShow = MC.MultiCol (LegendColumns, Show, #legends, 1, false)
    		table.insert (tab, SShow)
    		table.insert (tab, '</div>')
    	end
    end --createLegends
    
    local function OkWord (wd, tab)
    	if WithTrans then
    		return (wd == tab[1]) or (wd == tab[2])
    	else	
    		return (wd == tab[1])
    	end	
    end	
    
    local function getbasicArgs (args)
    	align = AlignString (SArgs.GetStrFromArgs(args, keywords.align), '')
    	Title = SArgs.GetStrFromArgs (args, keywords.Title)
    	TitleBackground = SArgs.GetStrFromArgs (args, keywords.TitleBackground)
    	Subtit = SArgs.GetStrFromArgs (args, keywords.Subtit)
    	SubtitBackground = SArgs.GetStrFromArgs (args, keywords.SubtitBackground)
    	LegendColumns = SArgs.GetIntFromArgs (args, keywords.LegendColumns, 1)
    	LegendTitle = SArgs.GetStrFromArgs (args, keywords.LegendTitle)
    	HideGroupLegends = not SArgs.NulOrWhitespaceFromArgs (args, keywords.HideGroupLegends)
    	Note = SArgs.GetStrFromArgs (args, keywords.Note)
    	PercDecim = SArgs.GetZeroOrPosIntFromArgs (args, keywords.PercDecim, 100)
    	MouseOverTooltip = SArgs.GetBoolFromArgs (args, keywords.MouseOverTooltip, false) 
    	delimiter = SArgs.GetStrFromArgs (args, keywords.delimiter, ':')
    end --getbasicArgs
    
    local function AddPerhapsTitle (res, width)
    	if Title ~= '' then
    		table.insert (res, '<div style="width:100%; padding:0.2em">')
    		--table.insert (res, '<div style="width:'..(width-10)..'; padding:0.2em">')
    		table.insert (res, '<table style="width:100%;">')
    		local STB = ''
    		if TitleBackground ~= '' then
    			STB = 'background:'..TitleBackground..'; ' 	
    		end	
    		table.insert (res, '<tr><td style="'..STB..'font-size:120%; text-align:center; padding:0.3em"><b>'..Title..'</b></td></tr>')
    		if Subtit ~= '' then
    			local SSTB = ''
    			if SubtitBackground ~= '' then
    				SSTB = 'background:'..SubtitBackground..'; ' 	
    			end	
    			table.insert (res, '<tr><td style="'..SSTB..'valign=top; text-align:center; padding:0.2em">'..Subtit..'</td></tr>')
    		end
    		table.insert (res, '</table>')
    		table.insert (res, '</div>')
    	end
    end --AddPerhapsTitle	
    
    local function AddMouseOverMess (res, S)
    	table.insert (res, '<p style="width:auto; font-size:93%; line-height:105%; valign=top; text-align:center; '..MarginsForText..'">'..S..'</p>')
    end
    
    local function AddPerhapsNote (res)
    	if Note ~= '' then
    		table.insert (res, '<p style="width:auto; '..MarginsForText..'valign=top; text-align:left; ">'..Note..'</p>')
    	end
    end	
    
    local function PrepNum (AValue)
    	local SSuffix = suffix
    	if (suffix ~= '') and (suffix ~= ' ') then
    		SSuffix = '&thinsp;'..suffix
    	end	
        return mw.ustring.gsub(prefix..fnum(AValue)..SSuffix, '_', ' ')
    end
    
    local function NDecOfVal (tot)
    	if PercDecim == 0 then
    		return 0
    	elseif PercDecim == 1 then
    		return 1
    	else	
    		if tot > PercDecim then
    			return 1
    		else
    			return 0
    		end	
    	end	
    end	--NDecOfVal
    		
    local function ColorsFromPalette (Palette, Num)
    	local AColors = {}
    	ColorName, IsInv = CFCM.ColorNameInvFromS0 (Palette)
    	AColors = BrewerColors.GetColors (ColorName, IsInv, Num, false)
    	if table.getn(AColors) == 0 then
    		ColorName, IsInv, StartN = ChartColors.ColorNameInvStartFromS (Palette)
    		AColors = ChartColors.GetColors (ColorName, IsInv, StartN, Num, true)
    	end	
    	return AColors
    end --ColorsFromPalette
    		
    local function AppendResAtChartBegin (res, width)
    	if align ~= '' then
    		if align == 'center' then
    			table.insert (res, '<div class="center">')
    		end
    		local Al = ''
    		if align == 'left' then
    			Al = 'tleft'
    		elseif align == 'center' then
    			Al = 'tnone'
    		elseif align == 'right' then
    			Al = 'tright'
    		end	
    		table.insert (res, '<div class="thumb '..Al..'>')
    		table.insert (res, '<div class="thumbinner" style="align:center; width:'..(width+8)..'px">')
    		table.insert (res, '<div class="noresize" style="align:center; width:'..width..'px">')
    	end
    end --AppendResAtChartBegin	
    
    local function AppendResAtChartEnd (res)
    	if align ~= '' then
    		table.insert (res, '</div></div></div>')
    		if align == 'center' then
    			table.insert (res, '</div>')
    		end
    	end	
    end --AppendResAtChartEnd	
    	
    -------------------------------------------------------------------------------
    
    function pieChart (frame)
    	local args,Nargs = SArgs.GetArgs (frame)
    	local res, imslices = {}, {}
    	local radius
    	local width
    	local values, names, AddedToName, legends, links = {}, {}, {}, {}, {}
    	local lang = mw.getContentLanguage()
    	
    	function replaceH (s, subst, with)
    		return mw.ustring.gsub (s, subst, with)
    	end --replaceH
    
    	function analyzeParams()
    		getbasicArgs (args)
    		local PaletteRequired = false
    		
    		function addSlice (i, slice)
    			local value, name, color, link = unpack (mw.text.split (slice, '%s*'..delimiter..'%s*'))
    			values[i] = tonumber (lang:parseFormattedNumber (value))
    				or error (string.format(RS_SliceWithNotNumber, i, value or '', sliceStr))
    			colors[i] = not nulOrWhitespace (color) and color or 0
    			if colors[i] == 0 then
    				PaletteRequired = true
    			end
    			names[i] = name or ''
    			local PosSep = string.find (names[i], '%-%-')
    			if PosSep == nil then
    				table.insert (AddedToName, '')
    			else	
    				table.insert (AddedToName, string.sub (names[i],PosSep+2))
    				names[i] = string.sub (names[i], 1, PosSep-1)
    			end	
    			links[i] = link
    		end --addSlice
    		
    		local NP = {'n','p'}
    		local LegendNumbers, SliceNumbers = {}, {}
    		function GetAndCheckNumber (tab)
    			local S = SArgs.GetStrFromArgs (args, tab, '')
    			local Numbers = {}
    			if S ~= '' then
    				local Wds = mw.text.split (S, ' ')
    				for l, m in ipairs(Wds) do
    					IsValid = (m == NP[1]) or (m == NP[2])
     					if IsValid then
    						table.insert (Numbers, m)
    					else
    						error(string.format(RS_InvalTooltip, SArgs.Concat2Params (tab), m, table.concat(NP,', ')))
    					end	
    				end
    			end	
    			return Numbers
    		end --GetAndCheckNumber
    		function InsertNP (tab, Two)
    			table.insert (tab, NP[1])
    			if Two then
    				table.insert (tab, NP[2])
    			end	
    		end
    		
    		prefix = replaceH (SArgs.GetStrFromArgs (args, keywords.unitsPrefix), '_', ' ')
    		suffix = replaceH (SArgs.GetStrFromArgs (args, keywords.unitsSuffix), '_', ' ')
    		radius = SArgs.GetPosIntFromArgs (args, keywords.radius, 100, 40, 400)
    		width = SArgs.GetIntFromArgs (args, keywords.width, radius * 2, radius * 2, 1000) 
    		local percent = SArgs.GetBoolFromArgs (args, keywords.percent)
    		LegendNumbers = GetAndCheckNumber (keywords.LegendNumbers)
    		SliceNumbers = GetAndCheckNumber (keywords.SliceNumbers)
    		if (#LegendNumbers == 0) and (#SliceNumbers == 0) then
    			InsertNP (LegendNumbers, percent)
    			InsertNP (SliceNumbers, percent)
    		end
    		
    		--Add slices mode 1
    		local i = 0
    		local slicesStr = SArgs.GetStrFromArgs (args, keywords.slices) 
    		for slice in mw.ustring.gmatch (slicesStr or '', "%b()") do
    			i = i + 1
    			addSlice (i, mw.ustring.match (slice, '^%(%s*(.-)%s*%)$'))
    		end
    		--Add slices mode 2
    		for k, v in pairs(args) do 
    			local ind = 0
    			function ForKw (idx)
    				return mw.ustring.match (k, '^'..keywords.slice[idx]..'%s+(%d+)$')
    			end	
    			if WithTrans then
    				ind = ForKw(1) or ForKw(2)	
    			else	
    				ind = ForKw(1)
    			end	
    			if ind then addSlice (tonumber (ind), v) end
    		end
    		
    		local ColorPalette = SArgs.GetStrFromArgs (args, keywords.ColorPalette, '')
    		if PaletteRequired then 
    			if ColorPalette == '' then
    				for i = 1, #colors do
    					if colors[i] == 0 then
    						colors[i] = DefColors[i * 2]
    					end	
    				end
    			else
    				local AColors = ColorsFromPalette (ColorPalette, #colors)
    				for i = 1, #colors do
    					if colors[i] == 0 then
    						colors[i] = AColors[i]
    					end	
    				end
    			end
    		end
    		
    		local sum = 0
    		for _, val in ipairs (values) do 
    			sum = sum + val 
    		end
    		local NDOV = NDecOfVal(sum)
    		for i, value in ipairs (values) do
    			--local NP = {'n','p'}
    			local addNum = prefix..lang:formatNum (value)..suffix
    			local addPer = Mult100 (value/sum, NDOV)
    			
    			legends[i] = names[i]
    			if AddedToName[i] ~= '' then
    				legends[i] = legends[i]..' '..AddedToName[i]
    			end	
    			for j, what in ipairs (LegendNumbers) do
    				local S = ''
    				if what == NP[1] then
    					S = addNum
    				else
    					S = addPer
    				end
    				if j == 1 then 
    					legends[i] = legends[i]..': '..S
    				else
    					legends[i] = legends[i]..' ('..S..')'
    				end
    			end
    			if not links[i] then
    				local SS = ''
    				for j, what in ipairs (SliceNumbers) do
    					local S = ''
    					if what == NP[1] then
    						S = addNum
    					else
    						S = addPer
    					end
    					if j == 1 then 
    						SS = names[i]..': '..S
    					else
    						SS = SS..' ('..S..')'
    					end
    				end
    				links[i] = string.format('[[#noSuchAnchor|%s]]', SS)				
    			end	
    		end
    	end --analyzeParams
    
    	function addRes (...)
    		for _, v in pairs ({ ... }) do
    			table.insert (res, v)
    		end
    	end
    
    	function createSlices()
    	
    		function drawSlice (i, q, start)
    			local color = colors[i]
    			local angle = start * 2 * math.pi
    			local sin, cos = math.abs (math.sin (angle)), math.abs (math.cos (angle))
    			local wsin, wcos = sin * radius, cos * radius
    			local s1, s2, w1, w2, w3, w4, width, border
    			local style
    			if q == 1 then
    				border = 'left'
    				w1, w2, w3, w4 = 0, 0, wsin, wcos
    				s1, s2 = 'bottom', 'left'
    			elseif q == 2 then
    				border = 'bottom'
    				w1, w2, w3, w4 = 0, wcos, wsin, 0
    				s1, s2 = 'bottom', 'right'
    			elseif q == 3 then
    				border = 'right'
    				w1, w2, w3, w4 = wsin, wcos, 0, 0
    				s1, s2 = 'top', 'right'
    			else
    				border = 'top'
    				w1, w2, w3, w4 = wsin, 0, 0, wcos
    				s1, s2 = 'top', 'left'
    			end
    			local style = string.format ('border:solid transparent;position:absolute;%s:%spx;%s:%spx;width:%spx;height:%spx', s1, radius, s2, radius, radius, radius)
    			if start <=  (q - 1) * 0.25 then
    				style = string.format ('%s;border:0;background-color:%s', style, color)
    			else
    				style = string.format ('%s;border-width:%spx %spx %spx %spx;border-%s-color:%s', style, w1, w2, w3, w4, border, color)
    			end
    			addRes (mw.text.tag ('div', { style = style }, ''))
    		end --drawSlice
    
    		function coordsOfAngle (angle)
    			return  (100 + math.floor (100 * math.cos (angle)))..' '.. (100 - math.floor (100 * math.sin (angle)))
    		end
    	
    		-- BEGIN createSlices 
    		local sum, start = 0, 0
    		for _, value in ipairs (values) do sum = sum + value end
    		for i, value in ipairs(values) do
    			local poly = { 'poly 100 100' }
    			local startC, endC =  start / sum,  (start + value) / sum
    			local startQ, endQ = math.floor (startC * 4 + 1), math.floor (endC * 4 + 1)
    			for q = startQ, math.min (endQ, 4) do drawSlice (i, q, startC) end
    			for angle = startC * 2 * math.pi, endC * 2 * math.pi, 0.02 do
    				table.insert (poly,  coordsOfAngle (angle))
    			end
    			table.insert (poly, coordsOfAngle (endC * 2 * math.pi)..' 100 100 '..links[i])
    			table.insert (imslices, table.concat (poly, ' '))
    			start = start + values[i]
    		end
    	end --createSlices
    	
    	function createImageMap()
    		addRes ('{{#tag:imagemap|', 'Image:Circle frame.svg{{!}}'.. (radius * 2)..'px')
    		addRes (unpack (imslices))
    		addRes ('desc none', '}}')
    	end
    
    	--BEGIN pieChart
    	analyzeParams()
    	if #values == 0 then error (RS_NoSlices) end
    	AppendResAtChartBegin (res, width)
    	
    	addRes (mw.text.tag ('div', { class = 'chart noresize', style = string.format ('align:center; margin-top:0.1em; margin-bottom:0.3em; max-width:%spx;', width) }))
    	AddPerhapsTitle (res, width)
    	--addRes (mw.text.tag ('div', { class = 'chart noresize', style = string.format ('left:%spx; margin-top:0.5em;max-width:%spx;', math.floor((width/2)-radius), radius * 2) }))
    	addRes (mw.text.tag ('div', { style = string.format ('position:relative;left:%spx; min-width:%spx;min-height:%spx;max-width:%spx;overflow:hidden;', math.floor((width/2)-radius), radius * 2, radius * 2, radius * 2) }))
    	--addRes (mw.text.tag ('div', { style = string.format ('position:relative;min-width:%spx;min-height:%spx;max-width:%spx;overflow:hidden;', radius * 2, radius * 2, radius * 2) }))
    	createSlices()
    	addRes (mw.text.tag ('div', { style = string.format ('position:absolute;min-width:%spx;min-height:%spx;overflow:hidden;', radius * 2, radius * 2) }))
    	createImageMap()
    	addRes ('</div>') -- close "position:relative" div that contains slices and imagemap.
    	addRes ('</div>') -- close "position:relative" div that contains slices and imagemap.
    	
    	local Tooltips = {}
    	createLegends (res, legends, nil, colors, Tooltips) -- legends
    	if MouseOverTooltip then
    		AddMouseOverMess (res, RS_MouseOverPie)
    	end
    	AddPerhapsNote (res)
    	addRes ('</div>') -- close containing div
    	AppendResAtChartEnd (res)
    	return frame:preprocess (table.concat (res, '\n'))
    end --pieChart
    
    -------------------------------------------------------------------------------
    
    function barChart (frame)
    	local res = {}
    	local args,Nargs = SArgs.GetArgs (frame)
    	local values, xlegends, tooltips, yscales = {}, {}, {}, {} ,{}, {}
    	local GroupNames, AddedToGroup, unitsSuffix, unitsPrefix, links = {}, {}, {}, {}, {}
    	local width, height, yticks, stack = 500, 350, -1, false
    	local chartWidth, chartHeight, DefColor, ScalePerGroup, accumulateTooltip
    	local IncTop = 5
    	
    	local colTooltip = {}
    	local xTooltip = {}
    	local legendTooltip = {}
    
    	local NumGroups, NumValues
    	local scaleWidth
    	local YSep = 0
    	local InPercent = false 
    	local XText2Lines = false
    	local HideGridY = false 
    	local DataTooltipMode = ''
    	
    	local RS_num = 'num'
    	local RS_perc = 'perc' --percentage
    	local RS_prior = 'prior'
    	local RS_next = 'next'
    	local RS_gr = 'gr' --group
    	local RS_x = 'x' --axes
    	local RS_basic = 'basic'
    	local RS_list = 'list'
    	local RS_sum_ = 'sum_' 
    	local RS_dif_ = 'dif_'
    	local RS_abs = 'abs' --absolute
    	local RS_rel = 'rel' --relative
    	local RS_all = 'all'
    	local RS_sum_to_show = '∑ ' --with space
    	local RS_dif_to_show = '∆ ' --with space
    	
    	local RS_perc_ = RS_perc..'_'
    	local RS_perc_abs = RS_perc_..RS_abs
    	local RS_perc_rel = RS_perc_..RS_rel
    	local RS_perc_x = RS_perc_..RS_x
    	local RS_perc_gr = RS_perc_..RS_gr
    	local RS_perc_all = RS_perc_..RS_all
    	local RS_gr_ = RS_gr..'_'
    	local RS_x_ = RS_x..'_'
    	local RS_sum_prior = RS_sum_..RS_prior		
    	local RS_sum_x_prior = RS_sum_..RS_x_..RS_prior		
    	local RS_sum_gr_prior = RS_sum_..RS_gr_..RS_prior		
    	local RS_sum_next = RS_sum_..RS_next		
    	local RS_sum_x_next = RS_sum_..RS_x_..RS_next		
    	local RS_sum_gr_next = RS_sum_..RS_gr_..RS_next		
    	local RS_dif_prior = RS_dif_..RS_prior
    	local RS_dif_next = RS_dif_..RS_next	
    	local RS_dif_x_prior = RS_dif_..RS_x_..RS_prior		
    	local RS_dif_gr_prior = RS_dif_..RS_gr_..RS_prior		
    	local RS_dif_x_next = RS_dif_..RS_x_..RS_next		
    	local RS_dif_gr_next = RS_dif_..RS_gr_..RS_next		
    
    	-- Accessory functions --
    	
    	function AddAny (ATooltipLines, ALabel, Arg, SValue)
    		if ALabel ~= '' then
    			local LabelHere = ''
    			if not nulOrWhitespace(Arg) then
    				LabelHere = string.format(ALabel,Arg)
    			else
    				LabelHere = ALabel
    			end	
    			SValue = LabelHere..TooltipSep..' '..SValue
    		end
    		table.insert (ATooltipLines, SValue)
    	end --AddAny
    
    	function AddPercS (ATooltipLines, ALabel, Arg, SValue)
            AddAny (ATooltipLines, ALabel, Arg, SValue)
    	end
    	
    	function AddPerc (ATooltipLines, ALabel, Arg, AValue, NDec)
    		AddPercS (ATooltipLines, ALabel, Arg, Mult100(AValue,NDec))
    	end
    	
    	function NumToPercSign0 (AValue, NVals)
    		if AValue == 1 then 
    			return '0'
    		elseif AValue > 1 then
    			return '+'..Mult100(AValue-1,NDecOfVal(NVals))
    		else
    			return '-'..Mult100(1-AValue,NDecOfVal(NVals))
    		end	
    	end	--NumToPercSign0
    
    	function NumToPercSign (ATooltipLines, ALabel, Arg, AValue, NVals)
    		local S = NumToPercSign0 (AValue, NVals)
    		AddPercS (ATooltipLines, ALabel, Arg, S)
    	end	--NumToPercSign
    	
    	function GetPrefixSuffix (gi)
    		prefix = unitsPrefix[gi]
    		suffix = unitsSuffix[gi]
    	end	
    	
    	-- Main functions --
    
    	function extractParams()
    		function NumOrPerc0 (kw, m, what, Pattern, Tooltip)
    			function MessError ()
    				return what..':['..table.concat(Pattern,'/')..']'
    			end	
    			if m == '' then
    				error(string.format(RS_EmptyTooltip, what, kw, MessError()))
    			else	
    				local SubPar = {}
    				SubPar = mw.text.split (m, ',')
    				IsValid = true
    				for n, o in ipairs(SubPar) do
    					local Found = false
    					for p, q in ipairs(Pattern) do
    						if o == q then
    							Found = true
    							break
    						end
    					end
    					if not Found then
    						error(string.format(RS_InvalTooltip, kw, o, MessError()))
    					end	
    				end
    				local W = {}
    				table.insert (W, what)
    				table.insert (W, SubPar)
    				table.insert (Tooltip, W)
    			end	
    		end --NumOrPerc0
    		
    		function ErrorPattern(Pattern)
    			return '['..table.concat(Pattern,'/')..']'
    		end	
    		local PatternNumPerc = {RS_num, RS_perc}
    		function ErrorPatternNumPerc ()
    			return ErrorPattern (PatternNumPerc)
    		end
    		local PatternPriorNext = {RS_prior, RS_next}
    		local function ErrorPatternPriorNext ()
    			return ErrorPattern (PatternPriorNext)
    		end
    		local PatternGrX = {RS_gr, RS_x}
    		local function ErrorPatternGrX ()
    			return ErrorPattern (PatternGrX)
    		end
    		
    		function ExtractAndCheckcolTt (kw, v, Tooltip)
    			local PatternNumPercs = {RS_num, RS_perc_abs, RS_perc_rel}
    			function NumOrPerc (NParam, m, what)
    				local tab = {}
    				if NParam == 3 then
    					tab = PatternNumPercs
    				else--if NParam == 2 then
    					tab = PatternNumPerc
    				end
    				NumOrPerc0 (kw, m, what, tab, Tooltip)
    			end
    			local Found = false
    			function Add (RS_Ini_, m, NParam)
    				function ErrorPNand ()
    					local tab = {}
    					if RS_Ini_ == RS_sum_ then
    						tab = ErrorPatternNumPerc ()
    					else
    						tab = ErrorPattern (PatternNumPercs)
    					end
    					return ErrorPatternPriorNext()..':'..tab
    				end
    				function AddEndPosNext (S, m2)
    					PosPrior = string.find (m2, RS_prior..':')
    					PosNext = string.find (m2, RS_next..':')
    					if PosPrior == 1 then
    						m2 = string.sub(m2, string.len(RS_prior)+2)
    						NumOrPerc (NParam, m2, S..RS_prior)
    						Found = true
    					elseif PosNext == 1 then
    						m2 = string.sub(m2, string.len(RS_next)+2)
    						NumOrPerc (NParam, m2, S..RS_next)
    						Found = true
    					else
    						error(string.format(RS_InvalTooltip, kw, m, S..ErrorPNand (NParam)))
    					end
    				end	
    				local Pos = string.find (m, RS_Ini_)
    				if Pos == 1 then
    					local m2 = string.sub(m, string.len(RS_Ini_)+1)
    					if NumGroups == 1 then
    						AddEndPosNext (RS_Ini_, m2)
    					else
    						PosGr = string.find (m2, RS_gr_)
    						PosX = string.find (m2, RS_x_)
    						if (PosGr == nil) and (PosX == nil) then
    							error (string.format(RS_InvalTooltip, kw, m, RS_Ini_..ErrorPatternGrX()..'_'..ErrorPNand (NParam)))
    						else
    							local S = RS_Ini_
    							if PosGr ~= nil then
    								S = S..RS_gr_
    								m2 = string.sub(m2, string.len(RS_gr_)+1)
    							else
    								S = S..RS_x_
    								m2 = string.sub(m2, string.len(RS_x_)+1)
    							end
    							AddEndPosNext (S, m2)
    						end
    					end	
    				end	
    			end --Add
    			local STooltip = v or ''
    			local IsValid = false
    			if STooltip ~= '' then
    				local Usual = {RS_num, RS_perc_x, RS_perc_gr, RS_perc_all,}
    				local Wds = mw.text.split (STooltip, ' ')
    				for l, m in ipairs(Wds) do
    					Found = false
    					if NumGroups == 1 then
    						local Pos = string.find (m, RS_basic..':')
    						if Pos == 1 then
    							if NumGroups == 1 then
    								local m2 = string.sub(m, string.len(RS_basic)+2) 
    								NumOrPerc (2, m2, RS_basic)
    								Found = true
    							else	
    								error(string.format(RS_InvalTooltipMore1Group, m, kw))
    							end	
    						end	
    						if not Found then
    							Add (RS_sum_, m, 2)
    						end	
    						if not Found then
    							Add (RS_dif_, m, 2)
    						end
    						if not Found then
    							error(string.format(RS_InvalTooltip, kw, m, 
    								'['..RS_basic..'/'..RS_sum_..ErrorPatternPriorNext()..'/'..RS_dif_..ErrorPatternPriorNext()))
    						end
    					else
    						if not Found then
    							for n, o in ipairs(Usual) do
    								if m == o then
    									if (m ~= RS_num) and (NumGroups == 1) then
    										error(string.format(RS_InvalTooltipMore1Group, m, kw))
    									else	
    										table.insert (Tooltip, m)
    										Found = true
    										break
    									end	
    								end
    							end
    						end
    						if not Found then
    							Add (RS_sum_, m, 2)
    						end	
    						if not Found then
    							Add (RS_dif_, m, 3)
    						end
    						if not Found then
    							error(string.format(RS_LookAtHelp, kw, m))
    						end
    					end		
    				end
    			end	
    		end --ExtractAndCheckcolTt
    		
    		function ExtractAndCheckXorLegTt (kw, v, Tooltip)
    			local STooltip = v or ''
    			local Headers = {RS_list, RS_basic}
    			local IsValid = false
    			function NumOrPerc2 (m, what)
    				NumOrPerc0 (kw, m, what, PatternNumPerc, Tooltip)
    			end
    			local Found = false
    			function Add (RS_Ini_, m)
    				local PosDif = string.find (m, RS_Ini_)
    				if PosDif == 1 then
    					local m2 = string.sub(m, string.len(RS_Ini_)+1)
    					PosPrior = string.find (m2, RS_prior..':')
    					PosNext = string.find (m2, RS_next..':')
    					if PosPrior == 1 then
    						m2 = string.sub(m2, string.len(RS_prior)+2)
    						NumOrPerc2 (m2, RS_Ini_..RS_prior)
    						Found = true
    					elseif PosNext == 1 then
    						m2 = string.sub(m2, string.len(RS_next)+2)
    						NumOrPerc2 (m2, RS_Ini_..RS_next)
    						Found = true
    					else
    						error(string.format(RS_InvalTooltip, kw, m, RS_Ini_..ErrorPatternPriorNext()))
    					end
    				end	
    			end
    			--BEGIN
    			if STooltip ~= '' then
    				if NumGroups == 1 then
    					error (string.format(RS_InvalTooltip1Group, kw))
    				else
    					local Wds = mw.text.split (STooltip, ' ')
    					for l, m in ipairs(Wds) do
    						Found = false
    						for n, o in ipairs(Headers) do
    							local PosHeader = string.find (m, o..':')
    							if PosHeader == 1 then
    								m = string.sub(m, string.len(o)+2)
    								NumOrPerc2 (m, o)
    								Found = true
    								break
    							end
    						end	
    						if not Found then
    							Add (RS_sum_, m)
    						end	
    						if not Found then
    							Add (RS_dif_, m)
    						end	
    						if not Found then
    							error(string.format(RS_InvalTooltip, kw, m, 
    							  '['..RS_basic..'/'..RS_sum_..ErrorPatternPriorNext()..'/'..RS_dif_..ErrorPatternPriorNext()..'/'..RS_list..']:'..ErrorPatternNumPerc()))
    						end
    					end
    				end	
    			end
    		end --ExtractAndCheckXorLegTt
    		
    		function SDelimiter (S)
    			local D = delimiter
    			if string.find (S,'\t') ~= nil then
    				D = '\t'	
    			end
    			return '%s*'..D..'%s*'
    		end
    		
    		function Test0 (val, tab)
    			for s in mw.text.gsplit (val, SDelimiter(val)) do
    				table.insert (tab, s)
    			end
    		end	
    		
    		local IdxForParams = false
    		function IsOk2 (key, keyword)
    			function ForKw (idx)
    				return (keyword[idx] == key and 0) or key:match (keyword[idx].."%s+(%d+)")	
    			end	
    			if WithTrans then
    				IdxForParams = ForKw(1) or ForKw(2)	
    			else	
    				IdxForParams = ForKw(1)
    			end	
    			if not IdxForParams then 
    				return false
    			else
    				IdxForParams = tonumber (IdxForParams) or error(string.format(RS_ExpectedNumForKW, SArgs.Concat2Params(keyword), key))
    				return true
    			end	
    		end
    		function InsertH (val, tab, NumRequired)
    			if IdxForParams > 0 then 
    				tab[IdxForParams] = {} 
    			end
    			for s in mw.text.gsplit (val, SDelimiter(val)) do
    				if NumRequired then
    					SArgs.CheckSIsNumber (s, keywords.group)
    				end
    				table.insert (IdxForParams == 0 and tab or tab[IdxForParams], s)
    			end
    		end	
    		
    		--BEGIN extractParams
    		getbasicArgs (args)
    		width = SArgs.GetIntFromArgs (args, keywords.width, 500, 200, 1000)
    		height = SArgs.GetIntFromArgs (args, keywords.height, 350, 150, 750)
    		stack = SArgs.GetBoolFromArgs (args, keywords.stack, false) 
    		yticks = SArgs.GetIntFromArgs (args, keywords.yticks, -1, -1, 40)
    		ScalePerGroup = SArgs.GetBoolFromArgs (args, keywords.ScalePerGroup, false)
    		DefColor = SArgs.GetStrFromArgs (args, keywords.DefColor, 'blue')	
    		accumulateTooltip = SArgs.GetBoolFromArgs (args, keywords.accumulateTooltip, false)
    		TooltipSep = SArgs.GetStrFromArgs (args, keywords.TooltipSep, ':')
    		XText2Lines = SArgs.GetBoolFromArgs (args, keywords.XText2Lines, false)
    		InPercent = SArgs.GetBoolFromArgs (args, keywords.InPercent, false)
    		HideGridY = SArgs.GetBoolFromArgs (args, keywords.HideGridY, false)
    		WallColor = SArgs.GetStrFromArgs (args, keywords.WallColor, '')
    		for k, v in pairs (args) do
    			if OkWord (k, keywords.colTooltip) then 
    				ExtractAndCheckcolTt (k, v, colTooltip)
    			elseif OkWord (k, keywords.xTooltip) then 
    				ExtractAndCheckXorLegTt (k, v, xTooltip)
    			elseif OkWord (k, keywords.legendTooltip) then 
    				ExtractAndCheckXorLegTt (k, v, legendTooltip)
    			elseif OkWord (k, keywords.xlegend) then 
    				Test0 (v, xlegends)
    			elseif OkWord (k, keywords.colors) then 
    				Test0 (v, colors)
    			elseif OkWord (k, keywords.unitsPrefix) then 
    				Test0 (v, unitsPrefix)
    			elseif OkWord (k, keywords.unitsSuffix) then 
    				Test0 (v, unitsSuffix)
    			elseif OkWord (k, keywords.GroupNames) then
    				Test0 (v, GroupNames)
    			elseif IsOk2 (k, keywords.group) then
    				InsertH (v, values, true)
    			elseif IsOk2 (k, keywords.tooltip) then
    				InsertH (v, tooltips, false)
    			elseif IsOk2 (k, keywords.links) then
    				InsertH (v, links, false)
    			end
    		end
    		DataTooltipMode = SArgs.GetStrFromArgs (args, keywords.DataTooltipMode, '')
    	end --extractParams
    
    	local PercentByCell = {}
    	function ValuesFromType ()
    		if InPercent then
    			return PercentByCell
    		else
    			return values
    		end	
    	end	
    
    	local SumAll = 0
    	local SumSeries = {}
    	local SumGroups = {}
    	function calcSums ()
    		local sum = 0
    		for i = 1, NumValues do
    			for gi = 1, NumGroups do
    				sum = sum + values[gi][i]
    			end
    			table.insert (SumSeries, sum)
    			SumAll = SumAll + sum
    			sum = 0
    		end	
    		sum = 0
    		for gi = 1, NumGroups do
    			for i = 1, NumValues do
    				sum = sum + values[gi][i]
    			end
    			table.insert (SumGroups, sum)
    			sum = 0
    		end	
    		local giPerc = {}
    		if NumGroups == 1 then
    		else	
    			for gi = 1, NumGroups do
    				for i = 1, NumValues do
    					table.insert (giPerc, (100*values[gi][i])/SumSeries[i])
    				end
    				table.insert (PercentByCell, giPerc)
    				giPerc = {}
    			end	
    		end	
    	end --calcSums
    
    	local ValScales = {}
    	local ValScalesPG = {}
    	local NumNotches = 0
    	local NumNotchesPG = {}
    	local XSep = 0
    	
    	function validate()
    		function ValiDataTooltipMode()
    			local ValWds = {}
    			local ValSemiQ = {}
    			function AddFor (Axis)
    				ValWds = {}
    				table.insert (ValWds, Axis..Quali[1])
    				table.insert (ValWds, Axis..SemiQ[1])
    				table.insert (ValSemiQ, SemiQ[1])
    				if WithTrans then
    					table.insert (ValWds, Axis..Quali[2])
    					table.insert (ValWds, Axis..SemiQ[2])
    					table.insert (ValSemiQ, SemiQ[2])
    				end	
    			end	
    			function TestFor (s)
    				Found = false
    				s = string.sub (s, 2)
    				for i, w in ipairs(ValSemiQ) do
    					if w == s then
    						Found = true
    						break
    					end	
    				end	
    				return Found
    			end	
    			function errorH (RS, S1)
    				error (string.format(RS, SArgs.Concat2Params(keywords.DataTooltipMode), S1)) 
    			end	
    			if (DataTooltipMode ~= '') and ((#colTooltip ~= 0) or (#xTooltip ~= 0) or (#legendTooltip ~= 0)) then
    				if #colTooltip > 0 then
    					table.insert (SArr, RS_MouseOverCols)
    				end	
    				if #xTooltip > 0 then
    					table.insert (SArr, RS_MouseOverX)
    				end	
    				if #legendTooltip > 0 then
    					table.insert (SArr, RS_MouseOverLegend)
    				end
    				local S = SArr[1]
    				if #SArr > 1 then
    					if #SArr > 2 then
    						S = S..', '..SArr[2]..' '..RS_And..' '..SArr[3]
    					else	
    						S = S..' '..RS_And..' '..ValWds[2]
    					end	
    				end	
    				error (string.format(RS_SetDataTooltipModeAndCustomDataTooltipMode, SArgs.Concat2Params(keywords.DataTooltipMode), S))
    			elseif (DataTooltipMode == '') and (#colTooltip == 0) and (#xTooltip == 0) and (#legendTooltip == 0) then
    				
    			elseif DataTooltipMode ~= '' then
    				local Found = false
    				local FoundN = 0
    				for s in mw.text.gsplit (DataTooltipMode, ' ') do
    					Found = false
    					FoundN = FoundN + 1
    					if FoundN == 1 then
    						AddFor ('x')
    					else
    						AddFor ('y')
    					end	
    					for i, w in ipairs(ValWds) do
    						if w == s then
    							if FoundN == 1 then
    								IsXSemiQ = TestFor (s)
    							else
    								IsYSemiQ = TestFor (s)
    							end
    							Found = true
    							break
    						end	
    					end	
    					if not Found then
    						errorH (RS_InvalDataTooltipMode, s) 
    					end	
    				end
    				if FoundN ~= 2 then
    					errorH (RS_InvalDataTooltipMode2Need, FoundN) 
    				else
    					if IsXSemiQ and IsYSemiQ then
    						SEnd = 'XY'
    					elseif IsXSemiQ then
    						SEnd = 'X-'
    					elseif IsYSemiQ then	
    						SEnd = '-Y'
    					else	
    						SEnd = '--'
    					end	
    				end	
    			end	
    		end	
    		function asGroups (kws, tab, toDuplicate, emptyOK)
    			if #tab == 0 and not emptyOK then
    				error (string.format(RS_RequiredValForS, SArgs.Concat2Params(kws)))
    			end
    			if #tab == 1 and toDuplicate then
    				for i = 2, NumGroups do 
    					tab[i] = tab[1] 
    				end
    			end
    			if #tab > 0 and #tab ~= NumGroups then
    				error  (string.format(RS_KWNumAndGroupNumNotMatched, SArgs.Concat2Params(kws), #tab, NumGroups))
    			end
    		end --asGroups
    		function fill (tab)
    			if #tab == 0 then
    				for gi = 1, NumGroups do
    					table.insert (tab, '')
    				end	
    			end	
    		end	
    
    		function calcHeightLimits() -- if limits were passed by user, use them, otherwise calculate. for "stack" there's only one limet.
    			local sums = {}
    			local Vals = ValuesFromType()
    			if stack then
    				for _, group in pairs (Vals) do
    					for i, val in ipairs (group) do 
    						sums[i] = (sums[i] or 0) + val 
    					end
    				end
    				local sum = math.max (unpack (sums))
    				for i = 1, #values do 
    					yscales[i] = sum 
    				end
    			else
    				for i, group in ipairs (Vals) do 
    					yscales[i] = math.max (unpack (group)) 
    				end
    			end
    			for i, scale in ipairs (yscales) do 
    				yscales[i] = roundup (scale * 0.9999) 
    			end
    			if not ScalePerGroup then 
    				for i = 1, #values do 
    					yscales[i] = math.max (unpack (yscales)) 
    				end
    			end
    		end --calcHeightLimits
    	
    		function GetValScales()
    			function ScaleInGroup(gi)
    				local yscale = yscales[gi]
    				local VScales = {}
    				local _, top, ordermag = roundup (yscale * 0.999)
    				local NNotches = yticks >= 0 and yticks or
    						(top <= 1.5 and top * 4
    						or top < 4  and top * 2
    						or top)
    				for i = 1, NNotches do
    					table.insert (VScales, i / NNotches * yscale)
    				end	
    				return NNotches, VScales
    			end	
    			if ScalePerGroup then
    				for gi = 1, NumGroups do
    					local NN, VS = ScaleInGroup (gi)
    					table.insert (NumNotchesPG, NN)
    					table.insert (ValScalesPG, VS)
    				end	
    			else
    				NumNotches, ValScales = ScaleInGroup (1)
    			end	
    		end --GetValScales
    		
    		-- do all sorts of validation here, so we can assume all params are good from now on.
    		-- among other things, replace numerical values with mw.language:parseFormattedNumber() result
    
    		ValiDataTooltipMode()
    		NumGroups = #values
    		if NumGroups == 0 then
    			error (RS_Any_Group_IsRequired)
    		end	
    		NumValues = #values[1]
    		YSep = 32
    		if XText2Lines then
    			YSep = 50
    			local FoundH = false
    			for i = 1, NumValues do
    				if string.find(xlegends[i],' ') ~= nil then
    					FoundH = true
    					break
    				end	
    			end	
    			if not FoundH then
    				error (RS_Selected2LinesButNoSpaces)
    			end	
    		end	
    		chartHeight = height - YSep
    		
    		if table.getn(colors) == 0 then 
    			if NumGroups == 1 then
    		        DefColor = DefColor or 'blue'
    		        colors[1] = colors[1] or DefColor
    			else	
    				colors = ChartColors.GetColors ('plotter', false, 1, #values, false)
    			end	
    		elseif (table.getn(colors) == 1) and (NumGroups > 1) then
    			colors = ColorsFromPalette (colors[1], #values)
    		end
    		calcSums()
    		calcHeightLimits()
    		GetValScales ()
    		
    		local ZLen = 0
    		if InPercent then
    			ZLen = 4
    		else
    			if ScalePerGroup then
    				for gi = 1, NumGroups do
    					for i = 1, NumNotchesPG[gi] do
    						ZLen = math.max (ZLen, string.len(tostring(ValScalesPG[gi][i])))
    					end	
    				end	
    			else	
    				for i = 1, NumNotches do
    					ZLen = math.max (ZLen, string.len(tostring(ValScales[i])))
    				end	
    			end	
    		end
    		XSep = (ZLen * 7)+ (math.floor(ZLen/3)*3) + 14
    		scaleWidth = (ScalePerGroup and XSep * NumGroups) or XSep
    		
    		local ChartMargin = 0
    		chartWidth = width - (scaleWidth + ChartMargin*2)
    		asGroups (keywords.unitsPrefix, unitsPrefix, true, true)
    		fill (unitsPrefix)
    		asGroups (keywords.unitsSuffix, unitsSuffix, true, true)
    		fill (unitsSuffix)
    		asGroups (keywords.colors, colors, true, true)
    		if #GroupNames == 0 then
    			table.insert (GroupNames, '')
    		end	
    		asGroups (keywords.GroupNames, GroupNames, false, false)
    		local PosSep
    		for gi = 1, NumGroups do
    			PosSep = string.find (GroupNames[gi], '%-%-')
    			if PosSep == nil then
    				table.insert (AddedToGroup, '')
    			else	
    				table.insert (AddedToGroup, string.sub (GroupNames[gi],PosSep+2))
    				GroupNames[gi] = string.sub (GroupNames[gi], 1, PosSep-1)
    			end	
    		end	
    		if stack and ScalePerGroup then
    			error (string.format(RS_IncompatibleSettings, SArgs.Concat2Params(keyword.stack), SArgs.Concat2Params(keyword.ScalePerGroup)))
    		end
    		for gi = 2, NumGroups do
    			if #values[gi] ~= NumValues then 
    				error (string.format(RS_NotHaveSameNumber, SArgs.Concat2Params(keywords.group), gi, SArgs.Concat2Params(keywords.group))) 
    			end
    		end
    		if #xlegends ~= NumValues then 
    			error (string.format(RS_InvalLegendNumber, SArgs.Concat2Params(keywords.xlegend),  NumValues))
    		end
    	end --validate
    	
    	local XPrior = ''
    	local XNext = ''
    	function GetXPriorNext (i)
    		if i > 1 then
    			XPrior = not nulOrWhitespace (xlegends[i-1]) and xlegends[i-1] or ''
    		end	
    		if i < NumValues then
    			XNext = not nulOrWhitespace (xlegends[i+1]) and xlegends[i+1] or ''
    		end	
    	end	
    	
    	local GPrior = ''
    	local GNext = ''
    	function GPriorNext (gi)
    			if gi > 1 then
    				GPrior = GroupNames[gi-1]
    			end	
    			if gi < NumValues then
    				GNext = GroupNames[gi+1]
    			end	
    	end --GPriorNext
    	
    	-- Next are used for GetColTooltip, GetXTooltip, GetLegendTooltip --
    	local AString = '' 
    	local ATooltipLines = {}
    	function CharForSum (IsPrior)
    		if IsPrior then
    			return '≤'
    		else
    			return '≥'
    		end	
    	end	
    	function AddS2 (Idx, S)
    		if Idx == 2 then
    			S = '('..S..')'
    		end
    		AString = AString..' '..S
    	end
    	function SumFrom (tab, Num, Sum, ALabel)
    		AString = ''
    		for l, m in ipairs(tab) do
    			local S = ''
    			if m == RS_num then
    				S = PrepNum(Num)
    			elseif m == RS_perc then
    				S = Mult100 (Num/Sum,NDecOfVal(Sum))
    			end
    			AddS2 (l, S)
    		end
    		table.insert (ATooltipLines, ALabel..' '..AString)
    	end	--SumFrom
    	
    	function GetColTooltip (gi, i, val)
    		if tooltips and tooltips[gi] and not nulOrWhitespace (tooltips[gi][i]) then return tooltips[gi][i], true end
    		local groupName = not nulOrWhitespace (GroupNames[gi]) and GroupNames[gi] or ''
    		GetXPriorNext (i)
    		local xlegend = not nulOrWhitespace (xlegends[i]) and xlegends[i] or ''
    		ATooltipLines = {} 
    		
            function ALabelX (IsPrior)
            	return string.format (RS_sum_to_show..'(%s & '..CharForSum(IsPrior)..'%s)', groupName, xlegend)
            end	
            function ALabelGr (IsPrior)
            	return string.format (RS_sum_to_show..'(%s & '..CharForSum(IsPrior)..'%s)', xlegend, groupName)
            end	
            
    		function AddS3 (Idx, Total, S)
    			if Idx == 1 then
    				AString = AString..' '..S
    			elseif Idx == 2 then
    				S = '('..S
    				if Total == 2 then
    					S = S..')'
    				end	
    				AString = AString..' '..S
    			elseif Idx == 3 then
    				AString = AString..', '..S..')'
    			end
    		end
    		
    		function SumAndOrPerc (tab)
    			AString = ''
    			for l, m in ipairs(tab) do
    				local S = ''
    				if m == RS_num then
    					S = PrepNum(val)
    				elseif m == RS_perc then
    					S = Mult100 (val/SumAll,NDecOfVal(SumAll))
    				end
    				AddS2 (l, S)
    			end
    			table.insert (ATooltipLines, xlegend..TooltipSep..' '..AString)
    		end	
    			
    		function SumFromPriorX (tab, gi, i)
                local sum = 0
                for j=1, i do
                    sum = sum + values[gi][j] 
                end
    			SumFrom (tab, sum, SumGroups[gi], ALabelX(true)) 
            end
            function SumFromPriorGr (tab, gi, i)
                local sum = 0
                for j=1, gi do
                    sum = sum + values[j][i] 
                end
    			SumFrom (tab, sum, SumSeries[i], ALabelGr(true)) 
            end
            function SumFromNextX (tab, gi, i)
                local sum = 0
                for j=NumValues, i, -1 do
                    sum = sum + values[gi][j] 
                end
    			SumFrom (tab, sum, SumGroups[gi], ALabelX(false))
            end
            function SumFromNextGr (tab, gi, i)
                local sum = 0
                for j=NumGroups, gi, -1 do
                    sum = sum + values[j][i] 
                end
    			SumFrom (tab, sum, SumSeries[i], ALabelGr(false)) 
            end
            
    		function AddPercOfSum (Arg, sum)
    			if sum > 0 then -- sum should always be > 0
    				AddPerc (ATooltipLines, '% /&thinsp;'..RS_sum_to_show..' '..Arg, '', val/sum, NDecOfVal(sum))
    			end
    		end
    		
    		local ExistsAbsRel = false
    		function SIfAbsAndRel (IsAbs)
    			if ExistsAbsRel then
    				if IsAbs then
    					return RS_Tt_abs
    				else
    					return RS_Tt_rel
    				end
    			else
    				return ''
    			end
    		end
    		function DifPriorX (IsAbs)
    			local S = SIfAbsAndRel (IsAbs)
    			if IsAbs then
    				S = S..NumToPercSign0 (val/values[gi][i-1],
    					math.max(val,values[gi][i-1]))
    			else
    				S = S..NumToPercSign0 ((val/SumSeries[i]) / (values[gi][i-1]/SumSeries[i-1]), 
    					math.max(SumSeries[i],SumSeries[i-1]))
    			end
    			return S
    		end
    		function DifNextX (IsAbs)
    			local S = SIfAbsAndRel (IsAbs)
    			if IsAbs then
    				S = S..NumToPercSign0 (val/values[gi][i+1],
    					math.max(val,values[gi][i+1]))
    			else
    				S = S..NumToPercSign0 ((val/SumSeries[i]) / (values[gi][i+1]/SumSeries[i+1]), 
    					math.max(SumSeries[i],SumSeries[i+1]))
    			end
    			return S
    		end
    		function DifPriorGr (IsAbs)
    			local S = SIfAbsAndRel (IsAbs)
    			if IsAbs then
    				S = S..NumToPercSign0 (val/values[gi-1][i],
    					math.max(val,values[gi-1][i]))
    			else
    				S = S..NumToPercSign0 ((val/SumGroups[gi]) / (values[gi-1][i]/SumGroups[gi-1]), 
    					math.max(SumGroups[gi],SumGroups[gi-1]))
    			end
    			return S
    		end
    		function DifNextGr (IsAbs)
    			local S = SIfAbsAndRel (IsAbs)
    			if IsAbs then
    				S = S..NumToPercSign0 (val/values[gi+1][i],
    					math.max(val,values[gi+1][i]))
    			else
    				S = S..NumToPercSign0 ((val/SumGroups[gi]) / (values[gi+1][i]/SumGroups[gi+1]), 
    					math.max(SumGroups[gi],SumGroups[gi+1]))
    			end
    			return S
    		end
    		
    		function TestAbsRel (tab)
    			ExistsAbs = false
    			ExistsRel = false
    			for l, m in ipairs(tab) do
    				if m == RS_perc_abs then
    					ExistsAbs = true
    				elseif m == RS_perc_rel then
    					ExistsRel = true
    				end
    			end
    			return ExistsAbs and ExistsRel
    		end
    		
    		GetPrefixSuffix (gi)
    		GPriorNext (gi)
    		if #colTooltip == 0 then
    			if NumGroups == 1 then
    			    table.insert (ATooltipLines, xlegend..TooltipSep..' '..PrepNum(val))
    			else
    				if stack then
    	        		AString = groupName..', '..xlegend..' '..PrepNum(val)
    	        		table.insert (ATooltipLines, AString)
    	        		if gi > 1 then
    		        		SumFromPriorGr ({RS_num}, gi, i)
    		        	end	
    	        	else
    	        		table.insert (ATooltipLines, groupName..', '..xlegend..TooltipSep..' '..PrepNum(val))
    	        	end	
    			end	
    		else	
    	 		for j, k in ipairs(colTooltip) do
    	 			if type(k)=='table' then
    		   			if k[1] == RS_basic then
    		   				SumAndOrPerc (k[2]) 
    		   			elseif (k[1] == RS_sum_x_prior) or (k[1] == RS_sum_prior) then
    						SumFromPriorX (k[2], gi, i) 
     		  			elseif (k[1] == RS_sum_x_next) or (k[1] == RS_sum_next) then
    						SumFromNextX (k[2], gi, i) 
     					elseif k[1] == RS_sum_gr_prior then
    			 			SumFromPriorGr (k[2], gi, i)
    		  			elseif k[1] == RS_sum_gr_next then
    		 				SumFromNextGr (k[2], gi, i)
    		 			elseif (k[1] == RS_dif_x_prior) or (k[1] == RS_dif_prior) then 
    		 				if i > 1 then
    							AString = RS_dif_to_show..XPrior..TooltipSep
    							ExistsAbsRel = TestAbsRel (k[2])
    							for l, m in ipairs(k[2]) do
    								local S = ''
    								if m == RS_num then
    									S = PrepNum(val-values[gi][i-1])
    								elseif (m == RS_perc_abs) or (m == RS_perc) then
    									S = DifPriorX (true)
    								elseif m == RS_perc_rel then
    									S = DifPriorX (false)
    								end
    								AddS3 (l, #k[2], S)
    							end
    							table.insert (ATooltipLines, AString)
    						end	
    		  			elseif (k[1] == RS_dif_x_next) or (k[1] == RS_dif_next) then
    		  				if i < NumValues then
    							AString = RS_dif_to_show..XNext..TooltipSep
    							ExistsAbsRel = TestAbsRel (k[2])
    							for l, m in ipairs(k[2]) do
    								local S = ''
    								if m == RS_num then
    									S = PrepNum(val-values[gi][i+1])
    								elseif (m == RS_perc_abs) or (m == RS_perc) then
    									S = DifNextX (true)
    								elseif m == RS_perc_rel then
    									S = DifNextX (false)
    								end
    								AddS3 (l, #k[2], S)
    							end
    							table.insert (ATooltipLines, AString)
    						end	
    		  			elseif k[1] == RS_dif_gr_prior then
    		  				if gi > 1 then
    							AString = RS_dif_to_show..GPrior..TooltipSep
    							ExistsAbsRel = TestAbsRel (k[2])
    							for l, m in ipairs(k[2]) do
    								local S = ''
    								if m == RS_num then
    									S = PrepNum(val-values[gi-1][i])
    								elseif m == RS_perc_abs then
    									S = DifPriorGr (true)
    								elseif m == RS_perc_rel then
    									S = DifPriorGr (false)
    								end
    								AddS3 (l, #k[2], S)
    							end
    							table.insert (ATooltipLines, AString)
    						end	
    		  			elseif k[1] == RS_dif_gr_next then
    		  				if gi < NumGroups then
    							AString = RS_dif_to_show..GNext..TooltipSep
    							ExistsAbsRel = TestAbsRel (k[2])
    							for l, m in ipairs(k[2]) do
    								local S = ''
    								if m == RS_num then
    									S = PrepNum(val-values[gi+1][i])
    								elseif m == RS_perc_abs then
    									S = DifNextGr (true)
    								elseif m == RS_perc_rel then
    									S = DifNextGr (false)
    								end
    								AddS3 (l, #k[2], S)
    							end
    							table.insert (ATooltipLines, AString)
    						end	
    					end	
    	 			else	
    		  			if k == RS_num then
    		  				if NumGroups > 1 then
    			        		AString = groupName..', '..xlegend
    			        		table.insert (ATooltipLines, AString)
    			        		AString = PrepNum(val)
    			        		table.insert (ATooltipLines, AString)
    			        	else
    			        		table.insert (ATooltipLines, xlegend..TooltipSep..' '..PrepNum(val))
    			        	end	
    		  			elseif k == RS_perc_all then 
    						AddPercOfSum (RS_Total, SumAll) 
    					elseif k == RS_perc_x then 
    		 				AddPercOfSum (groupName, SumGroups[gi]) 
    					elseif k == RS_perc_gr then 
    						AddPercOfSum (xlegend, SumSeries[i]) 
    					end
    				end	
    			end
    		end	
    		--[[
    		for k = 1, #ATooltipLines do
    			ATooltipLines[k] = NonBreak (ATooltipLines[k])
    		end	
    		--]]
    		local ASS = table.concat(ATooltipLines,"&#10;")
    		return ASS, false
    	end --GetColTooltip
    
    	function calcHeights (gi, i, val)
    		local barHeight = math.floor (val / yscales[gi] * chartHeight + 0.5) -- add half to make it "round" instead of "trunc"
    		local top, base = chartHeight - barHeight, 0
    		local Vals = ValuesFromType()
    		if stack then
    			local rawbase = 0
    			for j = 1, gi - 1 do 
    				rawbase = rawbase + Vals[j][i] 
    			end -- sum the "i" value of all the groups below our group, gi.
    			base = math.floor (chartHeight * rawbase / yscales[gi]) -- normally, and especially if it's "stack", all the yscales must be equal.
    		end
    		return barHeight, top - base
    	end --calcHeights
    
    	function groupBounds (i)
    		local setWidth = math.floor (chartWidth / NumValues)
    		local setOffset =  (i - 1) * setWidth
    		return setOffset, setWidth
    	end
    
    	function calcx (gi, i)
    		local setOffset, setWidth = groupBounds (i)
    		if stack or NumGroups == 1 then
    			local barWidth = math.min (38, math.floor (0.8 * setWidth))
    			return setOffset + (setWidth - barWidth) / 2, barWidth
    		end
    		setWidth = 0.85 * setWidth
    		local barWidth = math.floor (0.75 * setWidth / NumGroups)
    		local left = setOffset + math.floor ( (gi - 1) / NumGroups * setWidth)
    		return left, barWidth
    	end --calcx
    
    	function drawbar (gi, i, val, ttval)
    		--if val == '0' then return end -- do not show single line (borders....) if value is 0, or rather, '0'. see talkpage
    		--local color, tooltip, custom = colors[gi] or DefColor or 'blue', GetColTooltip (gi, i, ttval or val)
    		local color, tooltip, custom = colors[gi] or DefColor or 'blue', GetColTooltip (gi, i, values[gi][i])
    		local left, barWidth = calcx (gi, i)
    		local barHeight, top = calcHeights (gi, i, val)
    		if barHeight == 0 then
    			return
    		end
    
    		-- borders so it shows up when printing
    		local style = string.format("position:absolute;left:%spx;top:%spx;height:%spx;min-width:%spx;max-width:%spx;background-color:%s;-webkit-print-color-adjust:exact;border:1px solid %s;border-bottom:none;overflow:hidden;",
    						left, top+IncTop, barHeight-1, barWidth-2, barWidth-2, color, color)
    		local S = ''			
    		local link = links[gi] and links[gi][i] or ''
    		if not nulOrWhitespace (link) then
    	        img = mw.ustring.format( '[[File:Transparent.png|1000px|link=%s|%s]]', link, custom and tooltip or '' ) or ''
    	        S = mw.text.tag( 'div', { style = style, title = tooltip, }, img ) 
    		elseif tooltip ~= '' then
    			S = '<div style="'..style..'"><span title="'..tooltip..'">[[File:Transparent.png|1000px]]</span></div>'
    		else	
    			S = '<div style="'..style..'">[[File:Transparent.png|1000px]]</div>'
    		end	
    		table.insert (res, S)
    	end --drawbar
    	
    	function drawWallAndYGrid()
    		if WallColor ~= '' then
    			local WallStr = string.format ('<div style="position:absolute; max-height:%spx; max-width:%spx; top:%spx; left:%spx; background-color:%s;"><span>[[File:Transparent.png|1000px|link=]]</span></div>',
    					chartHeight, chartWidth, IncTop, scaleWidth - XSep, WallColor)			
    			table.insert (res, WallStr)
    		end	
    		function drawSingle()
    			local lineStyleStr = 'position:absolute;height=1px;min-width:%spx;top:%spx;left:%spx;border:1px dotted %s;'
    			for i = 1, NumNotches do
    				local y = chartHeight - calcHeights (1, 1, ValScales[i])
    				local div = mw.text.tag ('div', { style = string.format (lineStyleStr, chartWidth-4, y + IncTop, (scaleWidth - XSep) + 2, 'Silver') }, '')
    				table.insert (res, div)
    			end
    		end --drawSingle
    		for gi = 1, NumGroups do
    			drawSingle()
    		end
    	end--drawWallAndYGrid
    	
    	function drawYScale()
    		function drawSingle (gi, color, width, yticks, single)
    			local valStyleStr =
    				single and 'position:absolute;height=20px;text-align:right;vertical-align:middle;width:%spx;top:%spx;padding:0 2px'
    				or 'position:absolute;height=20px;text-align:right;vertical-align:middle;width:%spx;top:%spx;left:3px;background-color:%s;color:white;font-weight:bold;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;padding:0 2px'
    			local notchStyleStr = 'position:absolute;height=1px;min-width:5px;top:%spx;left:%spx;border:1px solid %s;'
    			local SS = {}
    			local NN = (ScalePerGroup and NumNotchesPG[gi]) or NumNotches
    			for i = 1, NN do
    				local val = (ScalePerGroup and ValScalesPG[gi][i]) or ValScales[i]
    				-- table.insert (SS, val)
    				local y = chartHeight - calcHeights (gi, i, val)
    				local temp = mw.getContentLanguage():formatNum (tonumber(val) or 0)
    				if InPercent then
    					temp = temp..'%'
    				end	
    				-- table.insert (SS, temp..'='..y)
    				local div = mw.text.tag ('div', { style = string.format (valStyleStr, width - 10, (y - 10) + IncTop, color) }, temp)
    				table.insert (res, div)
    				div = mw.text.tag ('div', { style = string.format (notchStyleStr, y + IncTop, width - 4, color) }, '')
    				table.insert (res, div)
    			end
    			-- error (table.concat(SS, ' - '))
    		end --drawSingle
    
    		if ScalePerGroup then
    			local colWidth = XSep
    			local colStyle = "position:absolute;height:%spx;min-width:%spx;left:%spx;border-right:1px solid %s;color:%s"
    			for gi = 1, NumGroups do
    				local left =  (gi - 1) * colWidth
    				local color = colors[gi] or DefColor
    				table.insert (res, mw.text.tag ('div', { style = string.format (colStyle, chartHeight, colWidth, left, color, color) }))
    				drawSingle (gi, color, colWidth, yticks)
    				table.insert (res, '</div>')
    			end
    		else
    			drawSingle (1, 'black', scaleWidth, yticks, true)
    		end
    	end --drawYScale
    
    	function drawXlegends()
    		
    		function GetXTooltip(i)
    			ATooltipLines = {}
    			GetXPriorNext (i)
    			local val = SumSeries[i]
    	 		for j, k in ipairs(xTooltip) do	
    				if k[1] == RS_basic then
    					AString = xlegends[i]..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == RS_num then
    							S = PrepNum(val)
    						elseif m == RS_perc then
    							S = Mult100 (val/SumAll,NDecOfVal(SumAll))
    						end
    						AddS2 (l, S)
    					end
    					table.insert (ATooltipLines, AString)
    				elseif k[1] == RS_sum_prior then
    					AString = RS_sum_to_show..CharForSum(true)..xlegends[i]..TooltipSep
    					local sum = 0
    					for l = 1, i do
    						sum = sum + SumSeries[l] 
    					end
    					SumFrom (k[2], sum, SumAll, AString) 
    				elseif k[1] == RS_sum_next then
    					AString = RS_sum_to_show..CharForSum(false)..xlegends[i]..TooltipSep
    					local sum = 0
    					for l = NumValues, i, -1 do
    						sum = sum + SumSeries[l] 
    					end
    					SumFrom (k[2], sum, SumAll, AString) 
    				elseif (k[1] == RS_dif_prior) and (i > 1) then
    					AString = RS_dif_to_show..XPrior..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == RS_num then
    							S = PrepNum(val-SumSeries[i-1])
    						elseif m == RS_perc then
    							S = NumToPercSign0 (val/SumSeries[i-1],math.max(val,SumSeries[i-1]))
    						end
    						AddS2 (l, S)
    					end
    					table.insert (ATooltipLines, AString)
    				elseif (k[1] == RS_dif_next) and (i < NumValues) then
    					AString = RS_dif_to_show..XNext..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == RS_num then
    							S = PrepNum(val-SumSeries[i+1])
    						elseif m == RS_perc then
    							S = NumToPercSign0 (val/SumSeries[i+1],math.max(val,SumSeries[i+1]))
    						end
    						AddS2 (l, S)
    					end
    					table.insert (ATooltipLines, AString)
    				elseif k[1] == RS_list then
    					NDec = NDecOfVal(SumSeries[i])
    					for gi = 1, NumGroups do
    						AString = GroupNames[gi]..TooltipSep
    						for l, m in ipairs(k[2]) do
    							local S = ''
    							if m == RS_num then
    								S = PrepNum(values[gi][i])
    							elseif m == RS_perc then
    								S = Mult100(PercentByCell[gi][i],NDec)
    							end
    							AddS2 (l, S)
    						end
    						table.insert (ATooltipLines, AString)
    					end	
    				end
    			end
    			for k = 1, #ATooltipLines do
    				ATooltipLines[k] = NonBreak (ATooltipLines[k])
    			end	
    			NonBreakArr (ATooltipLines)
    			local ASS = table.concat(ATooltipLines,"&#10;")
    			return ASS, false
    		end --GetXTooltip
    		
    		local setOffset, setWidth
    		local legendDivStyleFormat = "position:absolute;left:%spx;top:10px;min-width:%spx;max-width:%spx;text-align:center;vertical-align:top;"
    		local tickDivstyleFormat = "position:absolute;left:%spx;height:10px;width:1px;border-left:1px solid black;"
    		for i = 1, NumValues do
    			if not nulOrWhitespace (xlegends[i]) then
    				setOffset, setWidth = groupBounds (i)
    				-- setWidth = 0.85 * setWidth
    				table.insert (res,  mw.text.tag ('div', { style = string.format (legendDivStyleFormat, setOffset + 5, setWidth - 10, setWidth - 10) }, CFCM.TextWithTooltip(xlegends[i],GetXTooltip(i)) or ''))
    				table.insert (res, mw.text.tag ('div', { style = string.format (tickDivstyleFormat, setOffset + setWidth / 2) }, ''))
    			end
    		end
    	end --drawXlegends
    	
    	function drawChart()
    		
    		function GetLegendTooltip (gi)
    			GetPrefixSuffix (gi)
    			GPriorNext (gi)
    			local groupName = GroupNames[gi]
    			ATooltipLines = {}
    			function NumToPercSignH (idx, AValue, Arg, NVals)
    				local ALabel = legendTooltipLabel[idx] or ''
    				NumToPercSign (ATooltipLines, ALabel, Arg, AValue, NVals)
    			end	
    			local val = SumGroups[gi]
    	 		for j, k in ipairs(legendTooltip) do		
    				if k[1] == RS_basic then
    					AString = groupName..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == RS_num then
    							S = PrepNum(val)
    						elseif m == RS_perc then
    							S = Mult100 (val/SumAll,NDecOfVal(SumAll))
    						end
    						AddS2 (l, S)
    					end
    					table.insert (ATooltipLines, AString)
    				elseif k[1] == RS_sum_prior then
    					AString = RS_sum_to_show..CharForSum(true)..groupName..TooltipSep
    					local sum = 0
    					for l = 1, i do
    						sum = sum + SumGroups[l] 
    					end
    					SumFrom (k[2], sum, SumAll, AString) 
    				elseif k[1] == RS_sum_next then
    					AString = RS_sum_to_show..CharForSum(false)..groupName..TooltipSep
    					local sum = 0
    					for l = NumValues, i, -1 do
    						sum = sum + SumGroups[l] 
    					end
    					SumFrom (k[2], sum, SumAll, AString) 
    				elseif (k[1] == RS_dif_prior) and (gi > 1) then
    					AString = RS_dif_to_show..GPrior..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == RS_num then
    							S = PrepNum(val-SumGroups[gi-1])
    						elseif m == RS_perc then
    							S = NumToPercSign0 (val/SumGroups[gi-1],math.max(val,SumGroups[gi-1]))
    						end
    						AddS2 (l, S)
    					end
    					table.insert (ATooltipLines, AString)
    				elseif (k[1] == RS_dif_next) and (gi < NumGroups) then
    					AString = RS_dif_to_show..GNext..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == RS_num then
    							S = PrepNum(val-SumGroups[gi+1])
    						elseif m == RS_perc then
    							S = NumToPercSign0 (val/SumGroups[gi+1],math.max(val,SumGroups[gi+1]))
    						end
    						AddS2 (l, S)
    					end
    					table.insert (ATooltipLines, AString)
    				elseif k[1] == RS_list then
    					NDec = NDecOfVal(SumGroups[gi])
    					for i = 1, NumValues do
    						AString = xlegends[i]..TooltipSep
    						for l, m in ipairs(k[2]) do
    							local S = ''
    							if m == RS_num then
    								S = PrepNum(values[gi][i])
    							elseif m == RS_perc then
    								S = Mult100(values[gi][i]/SumGroups[gi],NDec)
    							end
    							AddS2 (l, S)
    						end
    						table.insert (ATooltipLines, AString)
    					end	
    				end
    			end	
    			NonBreakArr (ATooltipLines)
    			local ASS = table.concat(ATooltipLines,"&#10;")
    			return ASS
    		end --GetLegendTooltip
    
    	-- BEGIN drawChart() --	
    		table.insert (res, mw.text.tag ('div', { class = 'chart noresize', style = string.format ('margin-top:0.1em; margin-bottom:0.3em; max-width:%spx;', width) }))
    		AddPerhapsTitle (res, width)
    		table.insert (res, mw.text.tag ('div', { style = string.format("position:relative;min-height:%spx;min-width:%spx;max-width:%spx;", height, width, width) }))
    
    		local chartHeightH = chartHeight + IncTop
    		table.insert (res, mw.text.tag ('div', { style = string.format("float:right;position:relative;min-height:%spx;min-width:%spx;max-width:%spx;border-left:1px black solid;border-bottom:1px black solid;", chartHeightH, chartWidth, chartWidth) }))
    		if not (ScalePerGroup or HideGridY) then
    			drawWallAndYGrid()
    		end
    		local acum = stack and accumulateTooltip and {}
    		local Vals = ValuesFromType()
    		for gi, group in pairs (Vals) do
    			for i, val in ipairs (group) do
    				if acum then 
    					acum[i] =  (acum[i] or 0) + val 
    					if val ~= 0 then
    						drawbar (gi, i, val, acum and acum[i])
    					end	
    				else
    					drawbar (gi, i, val, acum and acum[i])
    				end
    			end
    		end
    		table.insert (res, '</div>')
    		table.insert (res, mw.text.tag ('div', { style = string.format("position:absolute;height:%spx;min-width:%spx;max-width:%spx;", chartHeightH, scaleWidth, scaleWidth, scaleWidth) }))
    		drawYScale()
    		table.insert (res, '</div>')
    		table.insert (res, mw.text.tag ('div', { style = string.format ("position:absolute;top:%spx;left:%spx;width:%spx;", chartHeightH, scaleWidth, chartWidth) }))
    		drawXlegends()
    		table.insert (res, '</div>')
    		table.insert (res, '</div>')
    		local Tooltips = {}
    		if table.getn(legendTooltip) > 0 then
    			for gi = 1, NumGroups do
    				table.insert (Tooltips, GetLegendTooltip(gi))
    			end	
    		end	
    		createLegends (res, GroupNames, AddedToGroup, colors, Tooltips)
    		if MouseOverTooltip then
    			local SArr = {}
    			if (#colTooltip > 0) or tooltips then
    				table.insert (SArr, RS_MouseOverCols)
    			end	
    			if #xTooltip > 0 then
    				table.insert (SArr, RS_MouseOverX)
    			end	
    			if #legendTooltip > 0 then
    				table.insert (SArr, RS_MouseOverLegend)
    			end
    			if #SArr > 0 then
    				local S = SArr[1]
    				if #SArr > 1 then
    					if #SArr > 2 then
    						S = S..', '..SArr[2]..' '..RS_And..' '..SArr[3]
    					else	
    						S = S..' '..RS_And..' '..SArr[2]
    					end	
    				end	
    				AddMouseOverMess (res, string.format (RS_MouseOverTooltip, S))
    			end	
    		end
    		AddPerhapsNote (res)
    		table.insert (res, '</div>')
    	end --drawChart
    
    	---- BEGIN ----
    	extractParams()
    	validate()
    	AppendResAtChartBegin (res, width)
    	drawChart()
    	AppendResAtChartEnd (res)
    	local Debug = false
    	if Debug then
    		return '<pre>'..table.concat (res, "\n")..'</pre>'
    	else	
    	--return SDebug..table.concat (res, "\n")
    	return table.concat (res, "\n")
    	end
    end --barChart
    
    return {
    	['bar-chart'] = barChart,
    	[keywords.barChart[1]] = barChart,
    	[keywords.pieChart[1]] = pieChart,
    }
    --</source>