Vés al contingut

Mòdul:Chart/proves

De la Viquipèdia, l'enciclopèdia lliure
Icona de documentació de mòdul Documentació del mòdul [ mostra ] [ modifica el codi ] [ mostra l'historial ] [ refresca ]

Mòdul Chart (codi · ús · discussió · proves · 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]


per a

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]
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 $1 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,9
    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,9
    Creences

  • Església catòlica: 78,7
  • Altres cristians: 10,4
  • Altres/sense religió: 10,9
  • Anotació

    Títol
    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
    tooltip 1
    tooltip 2
    tooltip 3
    10
    20
    30
    40
    50
    60
    Abans
    Durant
    Després
    Post mortem

  • Poma
  • Plàtan
  • Taronja
  • Passant el cursor del ratolí per sobre de $1 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
    tooltip 1
    tooltip 2
    tooltip 3
    10
    20
    30
    40
    50
    60
    Abans
    Durant
    Després
    Post mortem

  • Poma
  • Plàtan
  • Taronja
  • Passant el cursor del ratolí per sobre de $1 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%)

  • 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%)
  • --<syntaxhighlight lang="lua">
    local SDebug = {}
    local p = {}
    
    -- Required modules --
    local DefColors = require "Module:Plotter/DefaultColors"
    local SA = require "Module:SimpleArgs"
    local BrewerColors = require "Module:BrewerColors"
    local ChartColors = require "Module:ChartColors"
    local CFCM = require "Module:ComplForColorModules"
    local MC = require "Module:XCols"
    local yesno = require "Module:Yesno"
    local TNTT = require "Module:TNTTools"
    local NTO = require "Module:NumTableOrder"
    local sd = require "Module:SimpleDebug"
    
    -- For tanslation go to :commons:Data:I18n/Chart.tab --
    
    local TS_BarChart = 'BarChart'
    local TS_PieChart = 'PieChart'
    
    local ArgL = {
    	Width =				'Width',
    	UnitsPrefix =		'UnitsPrefix',
    	UnitsSuffix =		'UnitsSuffix',
    	
    	Delimiter =			'Delimiter',
    	MouseOverTooltip =	'MouseOverTooltip',
    	PercDecim =			'PercDecim',
    	Title =				'Title',
    	TitleBackground =	'TitleBackground',
    	Subtit =			'Subtit',
    	SubtitBackground =	'SubtitBackground',
    	HideGroupLegends =	'HideGroupLegends',
    	LegendColumns =		'LegendColumns',
    	LegendTitle =		'LegendTitle',
    	Note =				'Note',
    	Align =				'Align',
    
    	Slices =			'Slices',
    	Slice =				'Slice',
    	Radius =			'Radius',
    	ColorPalette =		'ColorPalette',
    	Percent =			'Percent',
    	LegendNumbers =		'LegendNumbers',
    	SliceNumbers =		'SliceNumbers',
    
    	--main
    	Colors =			'Colors',
    	GroupNames =		'GroupNames',
    	DataTooltipMode =	'DataTooltipMode',
    	Stack =				'Stack',
    	Group =				'Group',
    	XLegend =			'XLegend',
    	--extract
    	Height =			'Height',
    	Links =				'Links',
    	DefColor =			'DefColor',
    	YTicks =			'YTicks',
    	ScalePerGroup =		'ScalePerGroup',
    	XText2Lines =		'XText2Lines',
    	InPercent =			'InPercent',
    	HideGridY =			'HideGridY',
    	WallColor =			'WallColor',
    	--tooltip
    	Tooltip =			'Tooltip',
    	AccumulateTooltip =	'AccumulateTooltip',
    	ColTooltip =		'ColTooltip',
    	XTooltip =			'XTooltip',
    	LegendTooltip =		'LegendTooltip',
    	TooltipSep =		'TooltipSep',
    	MeanLabel =			'MeanLabel',
    	OrderLabel =		'OrderLabel',
    	SumLabel =			'SumLabel',
    	DifLabel =			'DifLabel',
    	AllLabel =			'AllLabel',
    }	
    local Opt = {
    	basic =	"basic",
    	num =	"num",
    	perc =	"perc",
    	order =	"order",
    	mean =	"mean",
    	meandif ="meandif",
    	list =	"list",
    	sum =	"sum",
    	dif =	"dif",
    	x =		"x",
    	gr =	"gr",
    	abs =	"abs",
    	rel =	"rel",
    	all =	"all",
    	prior =	"prior",
    	next =	"next",
    }
    local Msg = {
    	--DefaultShow
    	Mean =	"Mean",
    	Order = "Order",
    	Sum =	"Sum",
    	Dif =	"Dif",
    	All =	"All",
    	--MouseOver
    	Pie =		"Pie",
    	Tooltip =	"Tooltip",
    	Cols =		"Cols",
    	X =			"X",
    	Legend =	"Legend",
    	--Other
    	Quali =		"Quali",
    	SemiQ =		"SemiQ",
    	And =		"And",
    	Tt_abs =	"Tt_abs",
    	Tt_rel =	"Tt_rel",
    	Total =		"Total",
    }		
    local Err = {
    	InvalTooltip =					"InvalTooltip",
    	SliceWithNotNumber =			"SliceWithNotNumber",
    	NoSlices =						"NoSlices",
    	RequiredValForS =				"RequiredValForS",
    	KWNumAndGroupNumNotMatched =	"KWNumAndGroupNumNotMatched",
    	IncompatibleSettings =			"IncompatibleSettings",
    	NotHaveSameNumber =				"NotHaveSameNumber",
    	InvalLegendNumber =				"InvalLegendNumber",
    	ExpectedNumForKW =				"ExpectedNumForKW",
    	EmptyTooltip =					"EmptyTooltip",
    	InvalTooltip1Group =			"InvalTooltip1Group",
    	LookAtHelp =					"LookAtHelp",
    	AnyGroupIsRequired =			"AnyGroupIsRequired",
    	Selected2LinesButNoSpaces =		"Selected2LinesButNoSpaces",
    	SetDataTooltipModeAndCustomDataTooltipMode = "SetDataTooltipModeAndCustomDataTooltipMode",
    	InvalDataTooltipMode =			"InvalDataTooltipMode",
    	InvalDataTooltipMode2Need =		"InvalDataTooltipMode2Need",
    }
    
    local i18n = {
    	["BarChart"] = "bar chart",
    	["PieChart"] = "pie chart",
    	["Arg"] = {
    		["Gral"] = {
    			[ArgL.Width] =				"width",
    			[ArgL.UnitsPrefix] =		"units prefix",
    			[ArgL.UnitsSuffix] =		"units suffix",
    			[ArgL.Delimiter] =			"delimiter",
    			[ArgL.MouseOverTooltip] =	"tooltip info",
    			[ArgL.PercDecim] =			"percent decimals",
    			[ArgL.Title] =				"title",
    			[ArgL.TitleBackground] =	"title background",
    			[ArgL.Subtit] =				"subtitle",
    			[ArgL.SubtitBackground] =	"subtitle background",
    			[ArgL.HideGroupLegends] =	"hide group legends",
    			[ArgL.LegendColumns] =		"legend columns",
    			[ArgL.LegendTitle] =		"legend title",
    			[ArgL.Note] =				"note",
    			[ArgL.Align] =				"align",
    		},	
    		["PC"] = { --Pie Chart
    			[ArgL.ColorPalette] =		"color palette",
    			[ArgL.LegendNumbers] =		"numbers in legend",
    			[ArgL.Percent] =			"percent",
    			[ArgL.Radius] =				"radius",
    			[ArgL.Slice] =				"slice",
    			[ArgL.Slices] =				"slices",
    			[ArgL.SliceNumbers] =		"numbers in slices",
    		},	
    		["BC"] = { --Bar Chart
    			[ArgL.Height] =				"height",
    			[ArgL.Group] =				"group",
    			[ArgL.GroupNames] =			"group names",
    			[ArgL.Links] =				"links",
    			[ArgL.Colors] =				"colors",
    			[ArgL.Stack] =				"stack",
    			[ArgL.XLegend] =			"x legends",
    			[ArgL.YTicks] =				"y tick marks",
    			[ArgL.ScalePerGroup] =		"scale per group",
    			[ArgL.XText2Lines] =		"x text in 2 lines",
    			[ArgL.InPercent] =			"in percent",
    			[ArgL.HideGridY] =			"hide grid y",
    			[ArgL.WallColor] =			"wall color",
    			[ArgL.Tooltip] =			"tooltip",
    			[ArgL.DataTooltipMode] =	"data tooltip mode",
    			[ArgL.AccumulateTooltip] =	"tooltip value accumulation",
    			[ArgL.ColTooltip] =			"column tooltip",
    			[ArgL.XTooltip] =			"x tooltip",
    			[ArgL.LegendTooltip] =		"legend tooltip",
    			[ArgL.TooltipSep] =			"tooltip separator",
    			[ArgL.MeanLabel] =			"mean label",
    			[ArgL.OrderLabel] =			"order label",
    			[ArgL.SumLabel] =			"sum label",
    			[ArgL.DifLabel] =			"difference label",
    			[ArgL.AllLabel] =			"all label",
    		},	
    	},	
    	["Opt"] = {
    		[Opt.basic] =	"basic",
    		[Opt.num] =		"num",
    		[Opt.perc] =	"perc",
    		[Opt.order] =	"order",
    		[Opt.mean] =	"mean",
    		[Opt.meandif] =	"meandif",
    		[Opt.list] =	"list",
    		[Opt.sum] =		"sum",
    		[Opt.dif] =		"dif",
    		[Opt.x] =		"x",
    		[Opt.gr] =		"gr",
    		[Opt.abs] =		"abs",
    		[Opt.rel] =		"rel",
    		[Opt.all] =		"all",
    		[Opt.prior] =	"prior",
    		[Opt.next] =	"next",
    	},
    	["Msg"] = {
    		["DefShow"] = {
    			[Msg.Mean] =	"x&#772;",
    			[Msg.Order] =	"Order",
    			[Msg.Sum] =		"∑",
    			[Msg.Dif] =		"∆",
    			[Msg.All] =		"All",
    		},	
    		["MouseOver"] = {
    			[Msg.Pie] =		"Moving the mouse cursor over the pie appears data tooltip",
    			[Msg.Tooltip] =	"Moving the mouse cursor above $1 appears data tooltip",
    			[Msg.Cols] =	"the columns",
    			[Msg.X] =		"the X-axis text",
    			[Msg.Legend] =	"the legend text",
    		},	
    		[Msg.Quali] =	"quali",
    		[Msg.SemiQ] =	"semiq",
    		[Msg.And] =		"and",
    		[Msg.Tt_abs] =	"abs.:",
    		[Msg.Tt_rel] =	"rel.:",
    		[Msg.Total] =	"Total",
    	},
    	["Error"] = {
    		--Common--
    		[Err.InvalTooltip] =					"Incorrect value for \"$1\": $2. Only \"$3\" are valid",
    		--PieChart--
    		[Err.SliceWithNotNumber] =				"Sector $1: \"$2\", the first element (\"$3\") should be a number",
    		[Err.NoSlices] =						"No sector found: a graph can not be drawn",
    		--BarChart--
    		[Err.RequiredValForS] =					"Values must be provided for $1",
    		[Err.KWNumAndGroupNumNotMatched] =		"$1 should contain the same item number as the group number, but contains $2 items and there are $2 groups",
    		[Err.IncompatibleSettings] =			"Bad assignment: $1 and $2 are not supported",
    		[Err.NotHaveSameNumber] =				"$1 $2 does not have the same number of values as $3 1",
    		[Err.InvalLegendNumber] =				"Incorrect name of $1. It should be exactly $2",
    		[Err.ExpectedNumForKW] =				"A numeric index was expected for key $1 instead of $2",
    		[Err.EmptyTooltip] =					"No value for \"$1\" of \"$2\". Valid \"$3\"",
    		[Err.InvalTooltip1Group] =				"When there is only one group, it is not allowed to assign options to \"$1\"",
    		[Err.LookAtHelp] =						"Incorrect value for \"$1\": $2. See template help for this option",
    		[Err.AnyGroupIsRequired] =				"Any group is required",
    		[Err.Selected2LinesButNoSpaces] =		"Two lines are selected for the legends of the X values, but there is no legend with two words",
    		[Err.SetDataTooltipModeAndCustomDataTooltipMode] = "For automated tooltip mode of data, you have assigned values for $1 and $2",
    		[Err.InvalDataTooltipMode] =			"Invalid automated tooltip mode of data ($1): $2",
    		[Err.InvalDataTooltipMode2Need] =		"$1: Two parameters are required (for X and Y) and there are $2",
    	},
    }	
    i18n = SA.loadI18n ('Chart', i18n)
    
    
    local function I18nArgLabG (S)
    	return i18n["Arg"]["Gral"][S]
    end
    
    local function I18nArgLabP (S)
    	return i18n["Arg"]["PC"][S]
    end
    
    local function I18nArgLabB (S)
    	return i18n["Arg"]["BC"][S]
    end
    
    local function I18nArgOpt (S)
    	return i18n["Opt"][S]
    end
    
    local function I18nStrDS (S)
    	return i18n["Msg"]["DefShow"][S]
    end
    
    local function I18nStrMO (S)
    	return i18n["Msg"]["MouseOver"][S]
    end
    
    local function I18nStr (S)
    	return i18n["Msg"][S]
    end
    
    local function I18nError (S, ...)
    	return SA.I18nStrParams (i18n["Error"][S], ...)
    end
    
    -- 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.MultiColX (true, '100%', false, nil, LegendColumns, Show)
    		table.insert (tab, SShow)
    		table.insert (tab, '</div>')
    	end
    end --createLegends
    
    local function OkWord (wd, tab)
    	if type(tab) == 'table' then
    		return (wd == tab[1]) or (wd == tab[2])
    	else	
    		return (wd == tab)
    	end	
    end	
    
    local function getbasicArgs (args)
    	align = SA.HAlign_Par(args, I18nArgLabG(ArgL.Align), '')
    	Title = SA.Str_Par (args, I18nArgLabG(ArgL.Title), '')
    	TitleBackground = SA.Str_Par (args, I18nArgLabG(ArgL.TitleBackground), '')
    	Subtit = SA.Str_Par (args, I18nArgLabG(ArgL.Subtit), '')
    	SubtitBackground = SA.Str_Par (args, I18nArgLabG(ArgL.SubtitBackground), '')
    	LegendColumns = SA.PosInt_Par (args, I18nArgLabG(ArgL.LegendColumns), 1)
    	LegendTitle = SA.Str_Par (args, I18nArgLabG(ArgL.LegendTitle), '')
    	HideGroupLegends = not SA.NulOrWhitespace_Par (args, I18nArgLabG(ArgL.HideGroupLegends))
    	Note = SA.Str_Par (args, I18nArgLabG(ArgL.Note), '')
    	PercDecim = SA.ZeroOrPosInt_Par (args, I18nArgLabG(ArgL.PercDecim), 100)
    	MouseOverTooltip = SA.Bool_Par (args, I18nArgLabG(ArgL.MouseOverTooltip), false) 
    	delimiter = SA.Str_Par (args, I18nArgLabG(ArgL.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 = SA.GetArgs (frame)
    	if NArgs == 0 then return end
    	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 I18nError(Err.SliceWithNotNumber, tostring(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 = SA.Str_Par (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
    						I18nError(Err.InvalTooltip, SA.ConcatParams  (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 (SA.Str_Par (args,I18nArgLabG(ArgL.UnitsPrefix),''), '_', ' ')
    		suffix = replaceH (SA.Str_Par (args,I18nArgLabG(ArgL.UnitsSuffix),''), '_', ' ')
    		radius = SA.PosInt_Par (args, I18nArgLabP(ArgL.Radius), 100, 40, 400)
    		width = SA.PosInt_Par (args, I18nArgLabG(ArgL.Width), radius * 2, radius * 2, 1000) 
    		local percent = SA.Bool_Par (args, I18nArgLabP(ArgL.Percent))
    		LegendNumbers = GetAndCheckNumber (I18nArgLabP(ArgL.LegendNumbers))
    		SliceNumbers = GetAndCheckNumber (I18nArgLabP(ArgL.SliceNumbers))
    		if (#LegendNumbers == 0) and (#SliceNumbers == 0) then
    			InsertNP (LegendNumbers, percent)
    			InsertNP (SliceNumbers, percent)
    		end
    		
    		--Add slices mode 1
    		local i = 0
    		local slicesStr = SA.Str_Par (args,I18nArgLabP(ArgL.Slices),'') 
    		for slice in mw.ustring.gmatch (slicesStr, "%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
    			local S = I18nArgLabP(ArgL.Slice)
    			function ForKw0 (Str)
    				return mw.ustring.match (k, '^'..Str..'%s+(%d+)$')
    			end	
    			function ForKw (idx)
    				return ForKw0 (S[idx])
    			end	
    			if type(S) == 'table' then
    				ind = ForKw(1) or ForKw(2)	
    			else	
    				ind = ForKw0 (S)
    			end	
    			if ind then addSlice (tonumber (ind), v) end
    		end
    		
    		local ColorPalette = SA.Str_Par (args, I18nArgLabP(ArgL.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 
    		I18nError(Err.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, I18nStrMO (Msg.Pie))
    	end
    	AddPerhapsNote (res)
    	addRes ('</div>') -- close containing div
    	AppendResAtChartEnd (res)
    	return frame:preprocess (table.concat (res, '\n'))
    end --pieChart
    
    -------------------------------------------------------------------------------
    
    function barChart (frame)
    	local args,NArgs = SA.GetArgs (frame)
    	if NArgs == 0 then return end
    	local res = {}
    	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, NumXValues
    	local scaleWidth
    	local YSep = 0
    	local InPercent = false 
    	local XText2Lines = false
    	local HideGridY = false 
    	local DataTooltipMode = ''
    	
    	local Tt_N = { --Tolltip
    		--SIMPLE
    		Basic = 1,
    		Num = 2,
    		Perc = 3,
    		Order = 4,
    		Mean = 5,
    		MeanDif = 6,
    		List = 7,
    		Sum = 8,
    		Dif = 9,
    		--to middle/end
    		Abs = 10,
    		Rel = 11,
    		All = 12,
    		X = 13,
    		Gr = 14,
    		--to end
    		Prior = 15,
    		Next = 16,
    		--COMPOST
    		Perc_x = 17,
    		Perc_gr = 18,
    		Perc_abs = 19,
    		Perc_rel = 20,
    		Perc_all = 21,
    		Sum_prior = 22,
    		Sum_next = 23,
    		Sum_x = 24,
    		Sum_gr = 25,
    		Sum_x_prior = 26,
    		Sum_x_next = 27,
    		Sum_gr_prior = 28,
    		Sum_gr_next = 29,
    		MeanDif_x = 30,
    		MeanDif_gr = 31,
    		Dif_prior = 32,
    		Dif_next = 33,
    		Dif_x = 34,
    		Dif_gr = 35,
    		Dif_x_prior = 36,
    		Dif_x_next = 37,
    		Dif_gr_prior = 38,
    		Dif_gr_next = 39,
    	}
    	local function SumArr (A1, A2)
    		if (type(A1) == 'string') and (type(A2) == 'string') then
    			return A1..'_'..A2
    		else	
    			local A = {}
    			if (type(A1) == 'table') and (type(A2) == 'table') then
    				for k, v in ipairs (A1) do
    					for kk, vv in ipairs (A2) do
    						table.insert(A, v..'_'..vv)
    					end
    				end	
    			elseif type(A1) == 'table' then
    				for k, v in ipairs (A1) do
    					table.insert(A, v..'_'..A2)
    				end	
    			elseif type(A2) == 'table' then
    				for k, v in ipairs (A2) do
    					table.insert(A, A1..'_'..v)
    				end	
    			end	
    			return A
    		end
    	end
    	local RS_Tt_Perc = I18nArgOpt (Opt.perc)
    	local RS_Tt_X = I18nArgOpt (Opt.x)
    	local RS_Tt_Gr = I18nArgOpt (Opt.gr)
    	local RS_Tt_Abs = I18nArgOpt (Opt.abs)
    	local RS_Tt_Rel = I18nArgOpt (Opt.rel)
    	local RS_Tt_All = I18nArgOpt (Opt.all)
    	local Tt_A = {
    		Basic = I18nArgOpt (Opt.basic),
    		Num = I18nArgOpt (Opt.num),
    		Perc = RS_Tt_Perc,
    		Order = I18nArgOpt (Opt.order),
    		Mean = I18nArgOpt (Opt.mean),
    		MeanDif = I18nArgOpt (Opt.meandif),
    		List = I18nArgOpt (Opt.list),
    		Sum = I18nArgOpt (Opt.sum),
    		Dif = I18nArgOpt (Opt.dif),
    		Abs = RS_Tt_Abs,
    		Rel = RS_Tt_Rel,
    		All = RS_Tt_All,
    		X = RS_Tt_X,
    		Gr = RS_Tt_Gr,
    		Prior = I18nArgOpt (Opt.prior),
    		Next = I18nArgOpt (Opt.next),
    		Perc_x = SumArr (RS_Tt_Perc, RS_Tt_X),
    		Perc_gr = SumArr (RS_Tt_Perc, RS_Tt_Gr),
    		Perc_abs = SumArr (RS_Tt_Perc, RS_Tt_Abs),
    		Perc_rel = SumArr (RS_Tt_Perc, RS_Tt_Rel),
    		Perc_all = SumArr (RS_Tt_Perc, RS_Tt_All),
    		}
    	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_meandif = 'meandif'
    	local RS_mean = 'mean'
    	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 DefaultShow = {
    		Mean = I18nStrDS (Msg.Mean), --'x&#772;'
    		Order = I18nStrDS (Msg.Order), --'x&#772;'
    		Sum = I18nStrDS (Msg.Sum)..' ', --'∑'
    		Dif = I18nStrDS (Msg.Dif)..' ', --'∆'
    		All = I18nStrDS (Msg.All)..' ', --'All'
    		}
    	local RS_dif_ = RS_dif..'_' 
    	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_meandif_ = RS_meandif..'_'
    	local RS_meandif_x = RS_meandif_..RS_x	
    	local RS_meandif_gr = RS_meandif_..RS_gr		
    	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 IdxFromTabTrans1 (Str, TtA)
    			local Idx = 0
    			local Found = false
    			for I, A in ipairs(TtA) do
    				if type(A) == 'table' then
    					for J, W in ipairs(A) do
    						if W == Str then
    							Idx = I
    							Found = true
    							break
    						end	
    					end	
    					if Found then
    						break
    					end
    				else
    					if A == Str then
    						Idx = I
    						break
    					end	
    				end	
    			end	
    			return Idx
    		end	--IdxFromTabTrans1
    
    		function IdxFromTabTrans2 (Str, TtA, AChar)
    			local Idx = 0
    			local Found = false
    			local Pos, Len = 0, 0
    			local StrEnd = ''
    			local WW = ''
    			for I, A in ipairs(TtA) do
    				if type(A) == 'table' then
    					for J, W in ipairs(A) do
    						Pos = string.find (Str, W..AChar)
    						if Pos == 1 then
    							Idx = I
    							WW = W
    							Found = true
    							break
    						end
    					end	
    					if Found then
    						break
    					end
    				else
    					Pos = string.find (Str, A..AChar)
    					if Pos == 1 then
    						WW = A
    						Found = true
    						break
    					end
    				end			
    			end	
    			if Found then
    				StrEnd = string.sub (Str, string.len(WW)+2)
    			end	
    			return Idx, StrEnd, WW
    		end	--IdxFromTabTrans2
    
    		function NumOrPerc0 (kw, m, what, whatCode, Pattern, PatternCode, Tooltip)
    
    			function MessError ()
    				return what..':['..table.concat(Pattern,'/')..']'
    			end	
    			if #Pattern ~= #PatternCode then error ('Debug error') end
    			if m == '' then
    				I18nError(Err.EmptyTooltip, what, kw, MessError())
    			else	
    				local SubPar = {}
    				local SubCode = {}
    				SubPar = mw.text.split (m, ',')
    				IsValid = true
    				for n, o in ipairs(SubPar) do
    					Idx = IdxFromTabTrans1 (o, Pattern)
    					if Idx == 0 then
    						I18nError(Err.InvalTooltip, kw, o, MessError())
    					else
    						table.insert (SubCode, PatternCode[Idx])
    					end
    				end
    				local W = {}
    				table.insert (W, whatCode)
    				table.insert (W, SubCode)
    				table.insert (Tooltip, W)
    			end	
    		end --NumOrPerc0
    		
    		function ErrorPattern(Pattern)
    			return '['..table.concat(Pattern,'/')..']'
    		end	
    		local PatternNumPerc = {Tt_A.Num, Tt_A.Perc}
    		local PatternNumPercCode = {Tt_N.Num, Tt_N.Perc}
    		local PatternNumPercOrd = {Tt_A.Num, Tt_A.Perc, Tt_A.Order}
    		local PatternNumPercOrdCode = {Tt_N.Num, Tt_N.Perc, Tt_N.Order}
    		function ErrorPatternNumPerc ()
    			return ErrorPattern (PatternNumPerc)
    		end
    		function ErrorPatternNumPercOrd ()
    			return ErrorPattern (PatternNumPercOrd)
    		end
    		local PatternPriorNext = {Tt_A.Prior, Tt_A.Next}
    		local PatternPriorNextCode = {Tt_N.Prior, Tt_N.Next}
    		local function ErrorPatternPriorNext ()
    			return ErrorPattern (PatternPriorNext)
    		end
    		local PatternGrX = {Tt_A.Gr, Tt_A.X}
    		local function ErrorPatternGrX ()
    			return ErrorPattern (PatternGrX)
    		end
    
    		function ExtractAndCheckcolTt (kw, v, Tooltip)
    			local PatternNumPercs = {Tt_A.Num, Tt_A.Perc_abs, Tt_A.Perc_rel}
    			local PatternNumPercsCode = {Tt_N.Num, Tt_N.Perc_abs, Tt_N.Perc_rel}
    			function NumOrPerc (NParam, m, what, whatCode)
    				local tab = {}
    				local tabCode = {}
    				if NParam == 3 then
    					tab = PatternNumPercs
    					tabCode = PatternNumPercsCode
    				else--if NParam == 2 then
    					tab = PatternNumPerc
    					tabCode = PatternNumPercCode
    				end
    				NumOrPerc0 (kw, m, what, whatCode, tab, tabCode, Tooltip)
    			end
    			function Add (RS_Ini_, TtArr, TtCode, m, NParam)
    				local whatCode = ''
    				function ErrorPNand ()
    					local tab = {}
    					if RS_Ini_ == RS_sum_ then
    						tab = ErrorPatternNumPerc ()
    					else
    						tab = ErrorPattern (PatternNumPercs)
    					end
    					return ErrorPatternPriorNext()..':'..tab
    				end
    				function AddEndPosNext (S, SCode, m2)
    					Idx, m2, SFound = IdxFromTabTrans2 (m2, {Tt_A.Prior,Tt_A.Next}, ':') 
    					if Idx == 0 then
    						I18nError(Err.InvalTooltip, kw, m, S..ErrorPNand (NParam))
    					else
    						if Idx == 1 then	
    							if TtCode == Tt_N.Sum then
    								whatCode = Tt_N.Sum_prior
    							elseif TtCode == Tt_N.Dif then
    								whatCode = Tt_N.Dif_prior
    							elseif TtCode == Tt_N.Sum_x then
    								whatCode = Tt_N.Sum_x_prior
    							elseif TtCode == Tt_N.Dif_x then
    								whatCode = Tt_N.Dif_x_prior
    							elseif TtCode == Tt_N.Sum_gr then
    								whatCode = Tt_N.Sum_gr_prior
    							elseif TtCode == Tt_N.Dif_gr then
    								whatCode = Tt_N.Dif_gr_prior
    							end
    						elseif Idx == 2 then
    							if TtCode == Tt_N.Sum then
    								whatCode = Tt_N.Sum_next
    							elseif TtCode == Tt_N.Dif then
    								whatCode = Tt_N.Dif_next
    							elseif TtCode == Tt_N.Sum_x then
    								whatCode = Tt_N.Sum_x_next
    							elseif TtCode == Tt_N.Dif_x then
    								whatCode = Tt_N.Dif_x_next
    							elseif TtCode == Tt_N.Sum_gr then
    								whatCode = Tt_N.Sum_gr_next
    							elseif TtCode == Tt_N.Dif_gr then
    								whatCode = Tt_N.Dif_gr_next
    							end
    						end	
    						NumOrPerc (NParam, m2, S..SFound, whatCode)
    					end
    				end	--AddEndPosNext
    				Idx, m2, SFound = IdxFromTabTrans2 (m, TtArr, '_')
    				if Idx == 1 then
    					if NumGroups == 1 then
    						AddEndPosNext (SFound..'_', m2, TtCode)
    					else
    						Idx, m2, SFound2 = IdxFromTabTrans2 (m2, {Tt_A.Gr,Tt_A.X}, '_')
    						if Idx == 0 then
    							I18nError(Err.InvalTooltip, kw, m, SFound..'_'..ErrorPatternGrX()..'_'..ErrorPNand (NParam))
    						else 
    							if Idx == 1 then
    								if TtCode == Tt_N.Sum then
    									whatCode = Tt_N.Sum_gr
    								elseif TtCode == Tt_N.Dif then
    									whatCode = Tt_N.Dif_gr
    								end	
    							elseif Idx == 2 then
    								if TtCode == Tt_N.Sum then
    									whatCode = Tt_N.Sum_x
    								elseif TtCode == Tt_N.Dif then
    									whatCode = Tt_N.Dif_x
    								end	
    							end
    							AddEndPosNext (SFound..'_'..SFound2, m2, whatCode)
    						end
    					end	
    				end	
    			end --Add
    			function AddMd (m, S)
    				Idx, m2, SFound = IdxFromTabTrans2 (m, {Tt_A.Gr,Tt_A.X}, ':')
    				if Idx == 0 then
    					I18nError(Err.InvalTooltip, kw, m, S..'_'..ErrorPatternGrX()..':'..ErrorPatternNumPerc())
    				else
    					if Idx == 1 then
    						whatCode = Tt_N.MeanDif_gr
    					elseif Idx == 2 then
    						whatCode = Tt_N.MeanDif_x
    					end
    					NumOrPerc (2, m2, S..'_'..SFound, whatCode)
    				end	
    			end --AddMd
    			local STooltip = v or ''
    			local IsValid = false
    			if STooltip ~= '' then
    				local Wds = mw.text.split (STooltip, ' ')
    				local Usual = {Tt_A.Num, Tt_A.Perc_x, Tt_A.Perc_gr, Tt_A.Perc_all,}
    				local UsualCode = {Tt_N.Num, Tt_N.Perc_x, Tt_N.Perc_gr, Tt_N.Perc_all,}
    				local SumDif = {Tt_A.Sum, Tt_A.Dif} 
    				local SumDifCode = {Tt_N.Sum, Tt_N.Dif}  
    				local MdSumDif = {Tt_A.MeanDif, Tt_A.Sum, Tt_A.Dif} 
    				local MdSumDifCode = {Tt_N.MeanDif, Tt_N.Sum, Tt_N.Dif}  
    				for l, m in ipairs(Wds) do
    					if NumGroups == 1 then
    						Idx1, m1, SFound1 = IdxFromTabTrans2 (m, {Tt_A.Basic,Tt_A.MeanDif}, ':')
    						if Idx1 == 1 then
    							local tab = {Tt_A.Num, Tt_A.Perc, Tt_A.Order}
    							local tabCode = {Tt_N.Num, Tt_N.Perc, Tt_N.Order}
    							NumOrPerc0 (kw, m1, SFound1, Tt_N.Basic, tab, tabCode, Tooltip)
    						elseif Idx1 == 2 then
    							local tab = {Tt_A.Num, Tt_A.Perc}
    							local tabCode = {Tt_N.Num, Tt_N.Perc}
    							NumOrPerc0 (kw, m1, SFound1, Tt_N.MeanDif, tab, tabCode, Tooltip)
    						else	
    							Idx2, m2, SFound2 = IdxFromTabTrans2 (m, SumDif, '_')
    							if Idx2 == 0 then
    								I18nError(Err.LookAtHelp, kw, m)
    							else
    								Add (SFound2..'_', SumDif[Idx2], SumDifCode[Idx2], m2, 2)
    							end
    						end
    					else	
    						Idx = IdxFromTabTrans1 (m, Usual)
    						if Idx == 0 then
    							Idx2, m2, SFound2 = IdxFromTabTrans2 (m, {Tt_A.Order}, ':')
    							if Idx2 == 1 then
    								local tab = {Tt_A.X, Tt_A.Gr, Tt_A.All}
    								local tabCode = {Tt_N.X, Tt_N.Gr, Tt_N.All}
    								NumOrPerc0 (kw, m2, SFound2, Tt_N.Order, tab, tabCode, Tooltip)
    							else	
    								Idx3, m3, SFound3 = IdxFromTabTrans2 (m, MdSumDif, '_')		
    								if Idx3 == 0 then	
    									I18nError(Err.LookAtHelp, kw, m)
    								elseif Idx3 == 1 then	
    									AddMd (m3, SFound3)
    								else  
    									Add (SFound3..'_', MdSumDif[Idx3], MdSumDifCode[Idx3], m3, 2)
    								end
    							end	
    						else	
    							table.insert (Tooltip, UsualCode[Idx])
    						end
    					end		
    				end
    			end	
    		end --ExtractAndCheckcolTt
    		
    		function ExtractAndCheckXorLegTt (kw, v, Tooltip)
    			local STooltip = v or ''
    			local IsValid = false
    			function NumOrPerc3 (m, what, whatCode)
    				NumOrPerc0 (kw, m, what, whatCode, PatternNumPercOrd, PatternNumPercOrdCode, Tooltip)
    			end
    			function NumOrPerc2 (m, what, whatCode)
    				NumOrPerc0 (kw, m, what, whatCode, PatternNumPerc, PatternNumPercCode, Tooltip)
    			end
    			function Add (RS_Ini_, TtArr, TtCode, m)
    				Idx, m2, SFound = IdxFromTabTrans2 (m, TtArr, '_')
    				if Idx == 1 then
    					Idx, m2, SFound2 = IdxFromTabTrans2 (m2, {Tt_A.Prior, Tt_A.Next}, ':')
    					if Idx == 0 then
    						I18nError(Err.InvalTooltip, kw, m, RS_Ini_..ErrorPatternPriorNext())
    					else
    						local whatCode = ''
    						if Idx == 1 then
    							if TtCode == Tt_N.Sum then
    								whatCode = Tt_N.Sum_prior
    							elseif TtCode == Tt_N.Dif then
    								whatCode = Tt_N.Dif_prior
    							end
    						elseif Idx == 2 then
    							if TtCode == Tt_N.Sum then
    								whatCode = Tt_N.Sum_next
    							elseif TtCode == Tt_N.Dif then
    								whatCode = Tt_N.Dif_next
    							end
    						end
    						NumOrPerc2 (m2, SFound..'_'..SFound2, whatCode)
    					end	
    				end	
    			end
    			--BEGIN
    			if STooltip ~= '' then
    				if NumGroups == 1 then
    					I18nError(Err.InvalTooltip1Group, kw)
    				else
    					local Wds = mw.text.split (STooltip, ' ')
    					local Headers = {Tt_A.Basic, Tt_A.Mean, Tt_A.List, }
    					local HeadersCode = {Tt_N.Basic, Tt_N.Mean, Tt_N.List, }
    					local SumDif = {Tt_A.Sum, Tt_A.Dif} 
    					local SumDifCode = {Tt_N.Sum, Tt_N.Dif}  
    					for l, m in ipairs(Wds) do
    						Idx, m2, SFound = IdxFromTabTrans2 (m, Headers, ':')
    						if Idx > 0 then
    							if Idx == 1 then --Tt_N.Basic
    								NumOrPerc3 (m2, SFound, HeadersCode[Idx])
    							else
    								NumOrPerc2 (m2, SFound, HeadersCode[Idx])
    							end	
    						else
    							Idx2, m2, SFound2 = IdxFromTabTrans2 (m, SumDif, '_')
    							if Idx2 == 0 then
    								I18nError(Err.InvalTooltip, kw, m, 'Algo')
    								  --'['..RS_basic..'/'..RS_mean..'/'..RS_sum_..ErrorPatternPriorNext()..'/'..RS_dif_..ErrorPatternPriorNext()..'/'..RS_list..']:'..ErrorPatternNumPerc()), 0)
    							else
    								Add (SFound2..'_', MdSumDif[Idx2], MdSumDifCode[Idx2], m2, 2)
    							end
    						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 ForKw0 (Str)
    				return (Str == key and 0) or key:match (Str.."%s+(%d+)")	
    			end	
    			function ForKw (idx)
    				return ForKw0 (keyword[idx])	
    			end	
    			if type(keyword) == 'table' then
    				IdxForParams = ForKw(1) or ForKw(2)	
    			else	
    				IdxForParams = ForKw0(keyword)
    			end	
    			if not IdxForParams then 
    				return false
    			else
    				IdxForParams = tonumber (IdxForParams) or I18nError(Err.ExpectedNumForKW, SA.ConcatParams (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
    					SA.CheckSIsNum (s, I18nArgLabB(ArgL.Group))
    					s = tonumber (s)
    				end
    				table.insert (IdxForParams == 0 and tab or tab[IdxForParams], s)
    			end
    		end	
    		
    		--BEGIN extractParams
    		getbasicArgs (args)
    		width = SA.PosInt_Par (args, I18nArgLabG(ArgL.Width), 500, 200, 1000)
    		height = SA.PosInt_Par (args, I18nArgLabB(ArgL.Height), 350, 150, 750)
    		stack = SA.Bool_Par (args, I18nArgLabB(ArgL.Stack), false) 
    		yticks = SA.Int_Par (args, I18nArgLabB(ArgL.YTicks), -1, -1, 40)
    		ScalePerGroup = SA.Bool_Par (args, I18nArgLabB(ArgL.ScalePerGroup), false)
    		DefColor = 'blue'
    		accumulateTooltip = SA.Bool_Par (args, I18nArgLabB(ArgL.AccumulateTooltip), false)
    		TooltipSep = SA.Str_Par (args, I18nArgLabB(ArgL.TooltipSep), ':')
    		DefaultShow.Mean = SA.Str_Par (args, I18nArgLabB(ArgL.MeanLabel), DefaultShow.Mean)
    		DefaultShow.Order = SA.Str_Par (args, I18nArgLabB(ArgL.OrderLabel), DefaultShow.Order)
    		DefaultShow.Sum = SA.Str_Par (args, I18nArgLabB(ArgL.SumLabel), DefaultShow.Sum)
    		DefaultShow.Dif = SA.Str_Par (args, I18nArgLabB(ArgL.DifLabel), DefaultShow.Dif)
    		DefaultShow.All = SA.Str_Par (args, I18nArgLabB(ArgL.AllLabel), DefaultShow.All)
    		XText2Lines = SA.Bool_Par (args, I18nArgLabB(ArgL.XText2Lines), false)
    		InPercent = SA.Bool_Par (args, I18nArgLabB(ArgL.InPercent), false)
    		HideGridY = SA.Bool_Par (args, I18nArgLabB(ArgL.HideGridY), false)
    		WallColor = SA.Str_Par (args, I18nArgLabB(ArgL.WallColor), '')
    		for k, v in pairs (args) do
    			if OkWord (k, I18nArgLabB(ArgL.ColTooltip)) then 
    				ExtractAndCheckcolTt (k, v, colTooltip)
    			elseif OkWord (k, I18nArgLabB(ArgL.XTooltip)) then 
    				ExtractAndCheckXorLegTt (k, v, xTooltip)
    			elseif OkWord (k, I18nArgLabB(ArgL.LegendTooltip)) then 
    				ExtractAndCheckXorLegTt (k, v, legendTooltip)
    			elseif OkWord (k, I18nArgLabB(ArgL.XLegend)) then 
    				Test0 (v, xlegends)
    			elseif OkWord (k, I18nArgLabB(ArgL.Colors)) then 
    				Test0 (v, colors)
    			elseif OkWord (k, I18nArgLabG(ArgL.UnitsPrefix)) then 
    				Test0 (v, unitsPrefix)
    			elseif OkWord (k, I18nArgLabG(ArgL.UnitsSuffix)) then 
    				Test0 (v, unitsSuffix)
    			elseif OkWord (k, I18nArgLabB(ArgL.GroupNames)) then
    				Test0 (v, GroupNames)
    			elseif IsOk2 (k, I18nArgLabB(ArgL.Group)) then
    				InsertH (v, values, true)
    			elseif IsOk2 (k, I18nArgLabB(ArgL.Tooltip)) then
    				InsertH (v, tooltips, false)
    			elseif IsOk2 (k, I18nArgLabB(ArgL.Links)) then
    				InsertH (v, links, false)
    			end
    		end
    		DataTooltipMode = SA.Str_Par (args, I18nArgLabB(ArgL.DataTooltipMode), '')
    	end --extractParams
    
    	local PercentByCell = {}
    	function ValuesFromType ()
    		if InPercent then
    			return PercentByCell
    		else
    			return values
    		end	
    	end	
    
    	local SumAll = 0
    	local SumSeries = {}
    	local SumGroups = {}
    	local OrdAll = {}
    	local OrdSeries = {}
    	local OrdGroups = {}
    	local OrdSumSeries = {}
    	local OrdSumGroups = {}
    	
    	function calcSumsOrder ()
    		function OrderOfTempTab (Tab)
    			local res = {}
    			Tab, res = NTO.SortAnSetOrder (Tab, true, true, OnDupliValue)
    			return res
    		end
    		function ArrayToMatrix (A, ANumber)
    			local res = {}
    			local temp = {}
    			local Count = 0
    			local N = #A / ANumber
    			for I, V in ipairs (A) do
    				Count = Count + 1
    				table.insert (temp, V)
    				if Count == N then
    					Count = 0
    					table.insert (res, temp)
    					temp = {}
    				end	
    			end	
    			return res
    		end	--ArrayToMatrix
    		--BEGIN--
    		--Sum--
    		local sum = 0
    		for i = 1, NumXValues 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, NumXValues 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, NumXValues do
    					table.insert (giPerc, (100*values[gi][i])/SumSeries[i])
    				end
    				table.insert (PercentByCell, giPerc)
    				giPerc = {}
    			end	
    		end	
    		--Order--
    		OrdSumSeries = OrderOfTempTab(SumSeries)
    		OrdSumGroups = OrderOfTempTab(SumGroups)
    		local temp = {}
    		local OnDupliValue = 3
    		local res = {}
    		for i = 1, NumXValues do
    			temp = {}
    			for gi = 1, NumGroups do
    				table.insert(temp, values[gi][i])
    			end
    			table.insert(OrdSeries, OrderOfTempTab(temp))
    		end	
    		for gi = 1, NumGroups do
    			temp = {}
    			for i = 1, NumXValues do
    				table.insert(temp, values[gi][i])
    			end
    			table.insert (OrdGroups, OrderOfTempTab(temp))
    		end	
    		temp = {}
    		for gi = 1, NumGroups do
    			for i = 1, NumXValues do
    				table.insert(temp, values[gi][i])
    			end
    		end	
    		local tab = OrderOfTempTab(temp)
    		OrdAll = ArrayToMatrix (tab, NumGroups)
    	end --calcSumsOrder
    
    	local ValScales = {}
    	local ValScalesPG = {}
    	local NumNotches = 0
    	local NumNotchesPG = {}
    	local XSep = 0
    	
    	function validate()
    		
    		function ValiDataTooltipMode()
    			local ValWds = {}
    			local ValSemiQ = {}
    			function AddFor (Axis)
    				ValWds = {}
    				local S_Quali = I18nStr (Msg.Quali)
    				if type(S_Quali) == 'table' then
    					for k, v in ipairs(S_Quali) do
    						table.insert (ValWds, Axis..v)
    					end	
    				else
    					table.insert (ValWds, Axis..S_Quali)
    				end	
    				local S_SemiQ = I18nStr (Msg.SemiQ)
    				if type(S_SemiQ) == 'table' then
    					for k, v in ipairs(S_SemiQ) do
    						table.insert (ValWds, Axis..v)
    						table.insert (ValSemiQ, v)
    					end	
    				else
    					table.insert (ValWds, Axis..S_SemiQ)
    					table.insert (ValSemiQ, S_SemiQ)
    				end	
    				--[[]
    				local S_Quali = I18nStr (Msg.Quali)[1]
    				local S_SemiQ = I18nStr (Msg.SemiQ)[1]
    				table.insert (ValWds, Axis..S_Quali)
    				table.insert (ValWds, Axis..S_SemiQ)
    				table.insert (ValSemiQ, S_SemiQ)
    				if WithTrans then
    					local S_Quali = I18nStr (Msg.Quali)
    					local S_SemiQ = I18nStr (Msg.SemiQ)
    					table.insert (ValWds, Axis..S_Quali)
    					table.insert (ValWds, Axis..S_SemiQ)
    					table.insert (ValSemiQ, S_SemiQ)
    				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)
    				I18nError (RS, SA.ConcatParams (I18nArgLabB(ArgL.DataTooltipMode)), S1)
    			end	
    			if (DataTooltipMode ~= '') and ((#colTooltip ~= 0) or (#xTooltip ~= 0) or (#legendTooltip ~= 0)) then
    				if #colTooltip > 0 then
    					table.insert (SArr, I18nStrMO (Msg.Cols))
    				end	
    				if #xTooltip > 0 then
    					table.insert (SArr, I18nStrMO (Msg.X))
    				end	
    				if #legendTooltip > 0 then
    					table.insert (SArr, I18nStrMO (Msg.Legend))
    				end
    				local S = SArr[1]
    				if #SArr > 1 then
    					if #SArr > 2 then
    						S = S..', '..SArr[2]..' '..I18nStr (Msg.And)..' '..SArr[3]
    					else	
    						S = S..' '..I18nStr (Msg.And)..' '..ValWds[2]
    					end	
    				end	
    				I18nError(Err.SetDataTooltipModeAndCustomDataTooltipMode, SA.ConcatParams (I18nArgLabB(ArgL.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 (Err.InvalDataTooltipMode, s) 
    					end	
    				end
    				if FoundN ~= 2 then
    					errorH (Err.InvalDataTooltipMode2Need, tostring(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
    				I18nError(Err.RequiredValForS, SA.ConcatParams (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
    				I18nError(Err.KWNumAndGroupNumNotMatched, SA.ConcatParams (kws), tostring(#tab), tostring(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
    			I18nError(Err.AnyGroupIsRequired)
    		end	
    		NumXValues = #values[1]
    		NumAllValues = NumGroups * NumXValues
    		YSep = 32
    		if XText2Lines then
    			YSep = 50
    			local FoundH = false
    			for i = 1, NumXValues do
    				if string.find(xlegends[i],' ') ~= nil then
    					FoundH = true
    					break
    				end	
    			end	
    			if not FoundH then
    				I18nError(Err.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
    		calcSumsOrder()
    		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 (I18nArgLabG(ArgL.UnitsPrefix), unitsPrefix, true, true)
    		fill (unitsPrefix)
    		asGroups (I18nArgLabG(ArgL.UnitsSuffix), unitsSuffix, true, true)
    		fill (unitsSuffix)
    		asGroups (I18nArgLabB(ArgL.Colors), colors, true, true)
    		if #GroupNames == 0 then
    			table.insert (GroupNames, '')
    		end	
    		asGroups (I18nArgLabB(ArgL.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
    			I18nError(Err.IncompatibleSettings, SA.ConcatParams (I18nArgLabB(ArgL.Stack)), SA.ConcatParams (I18nArgLabB(ArgL.ScalePerGroup)))
    		end
    		for gi = 2, NumGroups do
    			if #values[gi] ~= NumXValues then 
    				I18nError(Err.NotHaveSameNumber, SA.ConcatParams (I18nArgLabB(ArgL.Group)), tostring(gi), SA.ConcatParams (I18nArgLabB(ArgL.Group)))
    			end
    		end
    		if #xlegends ~= NumXValues then 
    			I18nError(Err.InvalLegendNumber, SA.ConcatParams (I18nArgLabB(ArgL.XLegend)),  tostring(NumXValues))
    		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 < NumXValues 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 < NumXValues 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 AddS2b (Idx, S)
    		AString = AString..' &nbsp;'..S
    	end
    	function SumFrom (tab, Num, Sum, ALabel)
    		AString = ''
    		for l, m in ipairs(tab) do
    			local S = ''
    			if m == Tt_N.Num then
    				S = PrepNum(Num)
    			elseif m == Tt_N.Perc then
    				S = Mult100 (Num/Sum,NDecOfVal(Sum))
    			end
    			AddS2 (l, S)
    		end
    		table.insert (ATooltipLines, ALabel..' '..AString)
    	end	--SumFrom
    	
    	function PrepMeanNum (Mean, NVals)
    		return PrepNum (round (Mean, NDecOfVal(NVals)))
    	end
    	
    	function PrepMeanPerc (Mean, Z)
    		return DefaultShow.Dif..' '..NumToPercSign0 (Mean/(SumAll/Z), SumAll)
    	end
    	
    	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 (DefaultShow.Sum..'(%s & '..CharForSum(IsPrior)..'%s)', groupName, xlegend)
            end	
            function ALabelGr (IsPrior)
            	return string.format (DefaultShow.Sum..'(%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 == Tt_N.Num then
    					S = PrepNum(val)
    				elseif m == Tt_N.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=NumXValues, 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;'..DefaultShow.Sum..' '..Arg, '', val/sum, NDecOfVal(sum))
    			end
    		end
    		
    		local ExistsAbsRel = false
    		function SIfAbsAndRel (IsAbs)
    			if ExistsAbsRel then
    				if IsAbs then
    					return I18nStr (Msg.Tt_abs)
    				else
    					return I18nStr (Msg.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 == Tt_N.Perc_abs then
    					ExistsAbs = true
    				elseif m == Tt_N.Perc_rel then
    					ExistsRel = true
    				end
    			end
    			return ExistsAbs and ExistsRel
    		end
    		
    		function AddSSpc (AS, What, Order)
    			if AS ~= '' then
    				AS = AS..'&emsp;'
    			end
    			return AS..What..' '..Order	
    		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] == Tt_N.Basic then
    		   				SumAndOrPerc (k[2]) 
    		  			elseif k[1] == Tt_N.Order then
    						AString = DefaultShow.Order..TooltipSep
    						local S = ''
    						for l, m in ipairs(k[2]) do
    							local Order = 0
    							local W = ''
    							if m == Tt_N.All then
    								S = AddSSpc (S, DefaultShow.All, OrdAll[gi][i])
    							elseif m == Tt_N.X then
    								S = AddSSpc (S, xlegend, OrdSeries[i][gi])
    							elseif m == Tt_N.Gr then
    								S = AddSSpc (S, groupName, OrdGroups[gi][i])
    							end		
    						end
    						table.insert (ATooltipLines, AString..' '..S)
    		   			elseif (k[1] == Tt_N.Sum_x_prior) or (k[1] == Tt_N.Sum_prior) then
    						SumFromPriorX (k[2], gi, i) 
     		  			elseif (k[1] == Tt_N.Sum_x_next) or (k[1] == Tt_N.Sum_next) then
    						SumFromNextX (k[2], gi, i) 
     					elseif k[1] == Tt_N.Sum_gr_prior then
    			 			SumFromPriorGr (k[2], gi, i)
    		  			elseif k[1] == Tt_N.Sum_gr_next then
    		 				SumFromNextGr (k[2], gi, i)
    		   			elseif (k[1] == Tt_N.MeanDif_x) or (k[1] == Tt_N.MeanDif) then
    						AString = DefaultShow.Mean..'('..xlegend..')'..TooltipSep
    						for l, m in ipairs(k[2]) do
    							local S = DefaultShow.Mean..TooltipSep
    							local Mean = val/SumSeries[i]
    							if m == Tt_N.Num then
    								S = PrepMeanNum (Mean, SumSeries[i])
    							elseif m == Tt_N.Perc then
    								S = PrepMeanPerc (Mean, SumSeries[i])
    							end
    							AddS2 (l, S)
    						end
    						table.insert (ATooltipLines, AString)
     		  			elseif k[1] == Tt_N.MeanDif_gr then
    						AString = DefaultShow.Mean..'('..groupName..')'..TooltipSep
    						for l, m in ipairs(k[2]) do
    							local S = DefaultShow.Mean..TooltipSep
    							local Mean = val/SumGroups[gi]
    							if m == Tt_N.Num then
    								S = PrepMeanNum (Mean, SumGroups[gi])
    							elseif m == Tt_N.Perc then
    								S = PrepMeanPerc (Mean, SumGroups[gi])
    							end
    							AddS2 (l, S)
    						end
    						table.insert (ATooltipLines, AString)
    		 			elseif (k[1] == Tt_N.Dif_x_prior) or (k[1] == Tt_N.Dif_prior) then 
    		 				if i > 1 then
    							AString = DefaultShow.Dif..XPrior..TooltipSep
    							ExistsAbsRel = TestAbsRel (k[2])
    							for l, m in ipairs(k[2]) do
    								local S = ''
    								if m == Tt_N.Num then
    									S = PrepNum(val-values[gi][i-1])
    								elseif (m == Tt_N.Perc_abs) or (m == Tt_N.Perc) then
    									S = DifPriorX (true)
    								elseif m == Tt_N.Perc_rel then
    									S = DifPriorX (false)
    								end
    								AddS3 (l, #k[2], S)
    							end
    							table.insert (ATooltipLines, AString)
    						end	
    		  			elseif (k[1] == Tt_N.Dif_x_next) or (k[1] == Tt_N.Dif_next) then
    		  				if i < NumXValues then
    							AString = DefaultShow.Dif..XNext..TooltipSep
    							ExistsAbsRel = TestAbsRel (k[2])
    							for l, m in ipairs(k[2]) do
    								local S = ''
    								if m == Tt_N.Num then
    									S = PrepNum(val-values[gi][i+1])
    								elseif (m == Tt_N.Perc_abs) or (m == Tt_N.Perc) then
    									S = DifNextX (true)
    								elseif m == Tt_N.Perc_rel then
    									S = DifNextX (false)
    								end
    								AddS3 (l, #k[2], S)
    							end
    							table.insert (ATooltipLines, AString)
    						end	
    		  			elseif k[1] == Tt_N.Dif_gr_prior then
    		  				if gi > 1 then
    							AString = DefaultShow.Dif..GPrior..TooltipSep
    							ExistsAbsRel = TestAbsRel (k[2])
    							for l, m in ipairs(k[2]) do
    								local S = ''
    								if m == Tt_N.Num then
    									S = PrepNum(val-values[gi-1][i])
    								elseif m == Tt_N.Perc_abs then
    									S = DifPriorGr (true)
    								elseif m == Tt_N.Perc_rel then
    									S = DifPriorGr (false)
    								end
    								AddS3 (l, #k[2], S)
    							end
    							table.insert (ATooltipLines, AString)
    						end	
    		  			elseif k[1] == Tt_N.Dif_gr_next then
    		  				if gi < NumGroups then
    							AString = DefaultShow.Dif..GNext..TooltipSep
    							ExistsAbsRel = TestAbsRel (k[2])
    							for l, m in ipairs(k[2]) do
    								local S = ''
    								if m == Tt_N.Num then
    									S = PrepNum(val-values[gi+1][i])
    								elseif m == Tt_N.Perc_abs then
    									S = DifNextGr (true)
    								elseif m == Tt_N.Perc_rel then
    									S = DifNextGr (false)
    								end
    								AddS3 (l, #k[2], S)
    							end
    							table.insert (ATooltipLines, AString)
    						end	
    					end	
    	 			else	
    		  			if k == Tt_N.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 == Tt_N.Perc_all then 
    						AddPercOfSum (I18nStr (Msg.Total), SumAll) 
    					elseif k == Tt_N.Perc_x then 
    		 				AddPercOfSum (groupName, SumGroups[gi]) 
    					elseif k == Tt_N.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 / NumXValues)
    		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] == Tt_N.Basic then
    					AString = xlegends[i]..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == Tt_N.Num then
    							S = PrepNum(val)
    						elseif m == Tt_N.Perc then
    							S = Mult100 (val/SumAll,NDecOfVal(SumAll))
    						elseif m == Tt_N.Order then
    							S = OrdSumSeries[i]
    						end
    						AddS3 (l, S)
    					end
    					table.insert (ATooltipLines, AString)
    				elseif k[1] == Tt_N.Mean then
    					AString = DefaultShow.Mean..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = DefaultShow.Mean..TooltipSep
    						local Mean = val/NumXValues
    						if m == Tt_N.Num then
    							S = PrepMeanNum (Mean, NumXValues)
    						elseif m == Tt_N.Perc then
    							S = PrepMeanPerc (Mean, NumXValues)
    						end
    						AddS2b (l, S)
    					end
    					table.insert (ATooltipLines, AString)
    				elseif k[1] == Tt_N.Sum_prior then
    					AString = DefaultShow.Sum..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] == Tt_N.Sum_next then
    					AString = DefaultShow.Sum..CharForSum(false)..xlegends[i]..TooltipSep
    					local sum = 0
    					for l = NumXValues, i, -1 do
    						sum = sum + SumSeries[l] 
    					end
    					SumFrom (k[2], sum, SumAll, AString) 
    				elseif (k[1] == Tt_N.Dif_prior) and (i > 1) then
    					AString = DefaultShow.Dif..XPrior..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == Tt_N.Num then
    							S = PrepNum(val-SumSeries[i-1])
    						elseif m == Tt_N.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] == Tt_N.Dif_next) and (i < NumXValues) then
    					AString = DefaultShow.Dif..XNext..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == Tt_N.Num then
    							S = PrepNum(val-SumSeries[i+1])
    						elseif m == Tt_N.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] == Tt_N.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 == Tt_N.Num then
    								S = PrepNum(values[gi][i])
    							elseif m == Tt_N.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, NumXValues 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] == Tt_N.Basic then
    					AString = groupName..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == Tt_N.Num then
    							S = PrepNum(val)
    						elseif m == Tt_N.Perc then
    							S = Mult100 (val/SumAll,NDecOfVal(SumAll))
    						elseif m == Tt_N.Order then
    							S = OrdSumGroups[gi]
    						end
    						AddS2 (l, S)
    					end
    					table.insert (ATooltipLines, AString)
    				elseif k[1] == Tt_N.Mean then
    					AString = DefaultShow.Mean..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = DefaultShow.Mean..TooltipSep
    						local Mean = val/NumGroups
    						if m == Tt_N.Num then
    							S = PrepMeanNum (Mean, NumGroups)
    						elseif m == Tt_N.Perc then
    							S = PrepMeanPerc (Mean, NumGroups)
    						end
    						AddS2 (l, S)
    					end
    					table.insert (ATooltipLines, AString)
    				elseif k[1] == Tt_N.Sum_prior then
    					AString = DefaultShow.Sum..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] == Tt_N.Sum_next then
    					AString = DefaultShow.Sum..CharForSum(false)..groupName..TooltipSep
    					local sum = 0
    					for l = NumXValues, i, -1 do
    						sum = sum + SumGroups[l] 
    					end
    					SumFrom (k[2], sum, SumAll, AString) 
    				elseif (k[1] == Tt_N.Dif_prior) and (gi > 1) then
    					AString = DefaultShow.Dif..GPrior..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == Tt_N.Num then
    							S = PrepNum(val-SumGroups[gi-1])
    						elseif m == Tt_N.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] == Tt_N.Dif_next) and (gi < NumGroups) then
    					AString = DefaultShow.Dif..GNext..TooltipSep
    					for l, m in ipairs(k[2]) do
    						local S = ''
    						if m == Tt_N.Num then
    							S = PrepNum(val-SumGroups[gi+1])
    						elseif m == Tt_N.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] == Tt_N.List then
    					NDec = NDecOfVal(SumGroups[gi])
    					for i = 1, NumXValues do
    						AString = xlegends[i]..TooltipSep
    						for l, m in ipairs(k[2]) do
    							local S = ''
    							if m == Tt_N.Num then
    								S = PrepNum(values[gi][i])
    							elseif m == Tt_N.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, I18nStrMO (Msg.Cols))
    			end	
    			if #xTooltip > 0 then
    				table.insert (SArr, I18nStrMO (Msg.X))
    			end	
    			if #legendTooltip > 0 then
    				table.insert (SArr, I18nStrMO (Msg.Legend))
    			end
    			if #SArr > 0 then
    				local S = SArr[1]
    				if #SArr > 1 then
    					if #SArr > 2 then
    						S = S..', '..SArr[2]..' '..I18nStr (Msg.And)..' '..SArr[3]
    					else	
    						S = S..' '..I18nStr (Msg.And)..' '..SArr[2]
    					end	
    				end	
    				AddMouseOverMess (res, I18nStrMO (Msg.Tooltip, 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 {
    	[i18n["BarChart"]] = barChart,
    	['bar chart'] = barChart,
    	[i18n["PieChart"]] = pieChart,
        ['pie chart'] = pieChart,
    }
    --</syntaxhighlight>