[rlplot] 13/23: Imported Upstream version 1.3

Andreas Tille tille at debian.org
Wed Jun 29 09:50:57 UTC 2016


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository rlplot.

commit 2f247a842232af5b72135008542a8ff20ab99a02
Author: Andreas Tille <tille at debian.org>
Date:   Wed Jun 29 11:43:56 2016 +0200

    Imported Upstream version 1.3
---
 Axes.cpp        |  108 ++--
 Export.cpp      |  315 ++++++----
 Fileio.cpp      |  116 +++-
 ODbuttons.cpp   |  133 ++++-
 Output.cpp      |   57 +-
 PlotObs.cpp     |  612 +++++++++++++++----
 PropertyDlg.cpp |  894 ++++++++++++++++++++--------
 QT_Spec.cpp     |  346 ++++++++---
 QT_Spec.h       |   28 +-
 RLPLOT.RC       |   14 +-
 TheDialog.cpp   |  292 +++++----
 TheDialog.h     |    6 +-
 UtilObj.cpp     |  319 ++++++++--
 Utils.cpp       |  164 +++++-
 Version.h       |    4 +-
 WinSpec.cpp     |  645 +++++++++++++-------
 WinSpec.h       |   15 +-
 menu.h          |   15 +-
 mfcalc.cpp      | 1769 ++++++++++++++++++++++++++++++++-----------------------
 mfcalc.y        |  713 +++++++++++++++-------
 no_gui.cpp      |   27 +-
 reports.cpp     | 1202 +++++++++++++++++++++++++++----------
 rlp_math.cpp    |  635 ++++++++++++++++++--
 rlplot.cpp      |  154 +++--
 rlplot.h        |  127 +++-
 rlplot.spec     |    9 +-
 spreadwi.cpp    |  397 +++++++------
 use_gui.cpp     |   79 ++-
 28 files changed, 6537 insertions(+), 2658 deletions(-)

diff --git a/Axes.cpp b/Axes.cpp
index 559fbc4..b4e13ae 100755
--- a/Axes.cpp
+++ b/Axes.cpp
@@ -1,4 +1,4 @@
-//Axes.cpp, Copyright 2000, 2001, 2002, 2003, 2004 R.Lackner
+//Axes.cpp, Copyright 2000-2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -269,7 +269,7 @@ GridLine3D:: DoPlot(anyOutput *o)
 	if(!gl2) gl2 = (POINT3D*)calloc(4, sizeof(POINT3D));
 	if(!gl3) gl3 = (POINT3D*)calloc(4, sizeof(POINT3D));
 	if(!ls) ls = (line_segment**)calloc(6, sizeof(line_segment*));
-	o->ActualSize(&rDims);
+	if(!(o->ActualSize(&rDims)))return;
 	Swap(rDims.left, rDims.right);	Swap(rDims.top, rDims.bottom);
 	if(gl1 && gl2 && gl3 && ls) {
 		for(i = 0; i < 6; i++) if(ls[i]) {
@@ -661,7 +661,7 @@ Tick::Command(int cmd, void *tmpl, anyOutput *o)
 		LabelDef->Style = TXS_NORMAL;
 		LabelDef->Mode = TXM_TRANSPARENT;
 		LabelDef->Font = FONT_HELVETICA;
-		LabelDef->text = tmpl && *((char*)tmpl) ? _strdup((char*)tmpl) : 0L;
+		LabelDef->text = tmpl && *((char*)tmpl) ? (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0) : 0L;
 		label = new Label(this, 0L, fix, fiy, LabelDef, LB_X_PARENT | LB_Y_PARENT);
 		if(LabelDef->text) free(LabelDef->text);
 		delete (LabelDef);
@@ -813,6 +813,7 @@ Axis::~Axis()
 	if(ssMITval) free(ssMITval);	ssMATval = ssMATlbl = ssMITval = 0L;
 	if(axisLabel) DeleteGO(axisLabel);	axisLabel = 0L;
 	if(mo) DelBitmapClass(mo);			mo = 0L;
+	if(atv) delete atv;					atv = 0L;
 }
 
 double
@@ -990,7 +991,7 @@ Axis::DoPlot(anyOutput *o)
 		memcpy(&tmp_axis, axis, sizeof(AxisDEF));
 		tmp_axis.loc[0].fx += dx;		tmp_axis.loc[1].fx += dx;
 		tmp_axis.loc[0].fy += dy;		tmp_axis.loc[1].fy += dy;
-		if(parent->Id == GO_PLOT3D && (axis->flags & AXIS_3D)) {
+		if(IsPlot3D(parent) && (axis->flags & AXIS_3D)) {
 			//set 3D information in scaleOut
 			cu1.fx = axis->loc[0].fx +dx;	cu1.fy = axis->loc[0].fy +dy;
 			cu1.fz = axis->loc[0].fz;		cu2.fx = axis->loc[1].fx +dx;
@@ -1160,44 +1161,6 @@ Axis::DoPlot(anyOutput *o)
 		if(Ticks[i]) Ticks[i]->DoPlot(si, csi, o);
 }
 
-void
-Axis::DoMark(anyOutput *o, bool mark)
-{
-	LineDEF mrkLine;
-	int x1, y1, x2, y2;
-	double minw = DefSize(SIZE_DATA_LINE);
-
-	if(axis->flags & AXIS_ANGULAR) {
-		if(mark) {
-			memcpy(&mrc, &rDims, sizeof(RECT));
-			IncrementMinMaxRect(&mrc, 6 + o->un2ix(axline.width));
-			mo = GetRectBitmap(&mrc, o);
-			memcpy(&mrkLine, &axline, sizeof(LineDEF));
-			mrkLine.width = axline.width < minw ? minw * 3.0 : axline.width *3.0;;
-			x1 = o->co2ix(axis->Center.fx) - o->un2ix(axis->Radius);
-			y1 = o->co2iy(axis->Center.fy) - o->un2iy(axis->Radius);
-			x2 = o->co2ix(axis->Center.fx) + o->un2ix(axis->Radius);
-			y2 = o->co2iy(axis->Center.fy) + o->un2iy(axis->Radius);
-			o->SetLine(&mrkLine);
-			o->oArc(x1, y1, x2, y2, 4);
-			mrkLine.color ^= 0x00ffffffL;
-			mrkLine.width = axline.width;
-			o->SetLine(&mrkLine);
-			o->oArc(x1, y1, x2, y2, 4);
-			o->UpdateRect(&mrc, false);
-			}
-		else RestoreRectBitmap(&mo, &mrc, o);
-		return;
-		}
-	if(mark){
-		memcpy(&mrc, &rDims, sizeof(RECT));
-		IncrementMinMaxRect(&mrc, 6 + o->un2ix(axline.width));
-		mo = GetRectBitmap(&mrc, o);
-		InvertLine(pts, 2, &axline, &rDims, o, mark);
-		}
-	else RestoreRectBitmap(&mo, &mrc, o);
-}
-
 bool
 Axis::Command(int cmd, void *tmpl, anyOutput *o)
 {
@@ -1209,6 +1172,7 @@ Axis::Command(int cmd, void *tmpl, anyOutput *o)
 
 	switch (cmd) {
 	case CMD_SCALE:
+		if(!Ticks && (axis->flags & 0x03) != AXIS_NOTICKS)CreateTicks();
 		scale = (scaleINFO*)tmpl;
 		lbdist.fx *= scale->sx.fy;			lbdist.fy *= scale->sy.fy;
 		tlbdist.fx *= scale->sx.fy;			tlbdist.fy *= scale->sy.fy;
@@ -1222,7 +1186,6 @@ Axis::Command(int cmd, void *tmpl, anyOutput *o)
 		axis->Center.fx *= scale->sx.fy;	axis->Center.fy *= scale->sy.fy;
 		axis->Radius *= scale->sy.fy;		tlbdef.iSize = 0;
 		if(axisLabel) axisLabel->Command(cmd, tmpl, o);
-		if(!Ticks && (axis->flags & 0x03) != AXIS_NOTICKS)CreateTicks();
 		if(Ticks) for(i = 0; i < NumTicks; i++) if(Ticks[i]) Ticks[i]->Command(cmd, tmpl, o);
 		return true;
 	case CMD_HIDE_MARK:
@@ -1411,9 +1374,9 @@ Axis::SetTick(long idx, double val, DWORD flags, char *txt)
 	Ticks[idx] = new Tick(this, data, val, flags);
 	if(!txt) {
 		WriteNatFloatToBuff(TmpTxt, val);
-		l = _strdup(TmpTxt+1);
+		l = (char*)memdup(TmpTxt+1, (int)strlen(TmpTxt+1)+1, 0);
 		}
-	else l = _strdup(txt);
+	else l = (char*)memdup(txt, (int)strlen(txt)+1, 0);
 	if(!gl_type) {
 		}
 	if(Ticks[idx]) {
@@ -1432,10 +1395,12 @@ void
 Axis::CreateTicks()
 {
 	int i, n, nstep;
-	char *format;
+	char *format, *tick_label;
 	double fVal, tmp;
 	DWORD flags;
 
+	if(axis->min == -HUGE_VAL || axis->min == HUGE_VAL) return;
+	if(axis->max == -HUGE_VAL || axis->max == HUGE_VAL) return;
 	Command(CMD_FLUSH, 0L, 0L);
 	if((axis->flags & 0xf000) == AXIS_LOG) {	//log-axis
 		if(axis->Start > defs.min4log) tmp = log10(axis->Start);
@@ -1470,6 +1435,27 @@ Axis::CreateTicks()
 			}
 		}
 	else {										//linear axis
+		if(atv && (nstep = atv->Count()) && (Ticks = (Tick**)calloc(nstep+1, sizeof(Tick*)))) {
+			for(NumTicks = i = n = 0; NumTicks < nstep && atv->GetItem(i, &tick_label, &fVal);	i++) {
+				SetTick(NumTicks, fVal, axis->flags, tick_label);
+				NumTicks++;		n += (int)strlen(tick_label);
+				}
+			type = type;
+#ifdef _WINDOWS
+			if(type == 1 && n > 40) {
+				tlbdef.RotBL = n >100 ? 90.0 : 45.0;		tlbdef.Align = TXA_HRIGHT | TXA_VCENTER;
+				tlbdist.fy = sizAxTick;						SetSize(SIZE_TLB_YDIST, tlbdist.fy);
+				Command(CMD_TLB_TXTDEF, &tlbdef, 0L);
+				}
+#else
+			if(type == 1 && n > 30) {
+				tlbdef.RotBL = n >70 ? 90.0 : 45.0;			tlbdef.Align = TXA_HRIGHT | TXA_VCENTER;
+				tlbdist.fy = sizAxTick;						SetSize(SIZE_TLB_YDIST, tlbdist.fy);
+				Command(CMD_TLB_TXTDEF, &tlbdef, 0L);
+				}
+#endif
+			return;
+			}
 		if((axis->flags & 0xf000) == AXIS_RECI) {
 			NiceStep(axis, 8);
 			format = GetNumFormat(floor(log10(axis->Step)));
@@ -1533,12 +1519,13 @@ Axis::ManuTicks(double sa, double st, int n, DWORD flags)
 bool
 Axis::GetValuePos(double val, double *fix, double *fiy, double *fiz, anyOutput *op)
 {
-	double tmp1 = 1.0;
+	double temp, tmp1 = 1.0;
 	int i;
 	bool bRet = true;
 	anyOutput *o;
 	fPOINT3D p1, p2;
 	lfPOINT fdp, fip;
+	AxisDEF caxis;
 
 	*fix = *fiy = *fiz = 0.0;
 	if(!op || !parent || (val < axis->min && val < axis->max) || 
@@ -1549,14 +1536,25 @@ Axis::GetValuePos(double val, double *fix, double *fiy, double *fiz, anyOutput *
 	if(axis->owner == this && scaleOut)	o = scaleOut;
 	else o = op;
 	if(axis->flags & AXIS_3D) {
-		p1.fx = GetSize(SIZE_XPOS);	p1.fy = GetSize(SIZE_YPOS);	p1.fz = GetSize(SIZE_ZPOS);
-		tmp1 = defs.cUnits == 1 ? 2.54 : defs.cUnits == 2 ? 1.0 : 25.4;
-		tmp1 /= op->VPscale;
-		switch(type) {
-		case 1: p1.fx += (tmp1 * (op->fx2fix(val)- op->Box1.Xmin)/op->hres);	break;
-		case 2: p1.fy += (tmp1 * (op->fy2fiy(val)- op->Box1.Ymax)/op->vres);	break;
-		case 3: p1.fz += (tmp1 * (op->fz2fiz(val)- op->Box1z.fx)/op->hres);	break;
-		default:	return false;
+		//Get a copy of the axis because GetAxisFac() modifies its contents
+		memcpy(&caxis, axis, sizeof(AxisDEF));
+		p1.fx = op->un2fix(axis->loc[1].fx - caxis.loc[0].fx);
+		p1.fy = op->un2fiy(axis->loc[1].fy - caxis.loc[0].fy);
+		p1.fz = op->un2fiz(axis->loc[1].fz - caxis.loc[0].fz);
+		tmp1 = sqrt(p1.fx*p1.fx + p1.fy*p1.fy + p1.fz*p1.fz);
+		p1.fx /= tmp1;		p1.fy /= tmp1;		p1.fz /= tmp1;
+		tmp1 = GetAxisFac(&caxis, tmp1, (type&0xf)-1);
+		temp = TransformValue(&caxis, val, true);
+		temp = (temp - caxis.min)*tmp1;
+		if(axis->flags & AXIS_INVERT) {
+			p1.fx = op->fix2un(op->un2fix(axis->loc[1].fx) - p1.fx*temp);
+			p1.fy = op->fiy2un(op->un2fiy(axis->loc[1].fy) - p1.fy*temp);
+			p1.fz = op->fix2un(op->un2fiz(axis->loc[1].fz) - p1.fz*temp);
+			}
+		else {
+			p1.fx = op->fix2un(p1.fx*temp+op->un2fix(axis->loc[0].fx));
+			p1.fy = op->fiy2un(p1.fy*temp+op->un2fiy(axis->loc[0].fy));
+			p1.fz = op->fix2un(p1.fz*temp+op->un2fiz(axis->loc[0].fz));
 			}
 		op->cvec2ivec(&p1, &p2);
 		*fix = p2.fx;	*fiy = p2.fy;	*fiz = p2.fz;
diff --git a/Export.cpp b/Export.cpp
index 7fd0ea2..b47b8ac 100755
--- a/Export.cpp
+++ b/Export.cpp
@@ -1,4 +1,4 @@
-//Export.cpp, Copyright (c) 2002-2006 R.Lackner
+//Export.cpp, Copyright (c) 2002-2007 R.Lackner
 //export graph files
 //
 //    This file is part of RLPlot.
@@ -108,7 +108,7 @@ ExportWMF::ExportWMF(GraphObj *g, char *FileName, float res, DWORD flags)
 	hPen = 0xffff, hBrush = 0xffff, hFont = 0xffff;
 	hres = vres = res;
 	go = g;
-	if(FileName)name = _strdup(FileName);
+	if(FileName)name = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
 	else name = 0L;
 	oFile = 0;
 	rec_size = 28;
@@ -239,7 +239,7 @@ ExportWMF::StartPage()
 		}
 	VPorg.fy = -un2fiy(go->GetSize(SIZE_GRECT_TOP));
 	VPorg.fx = -un2fix(go->GetSize(SIZE_GRECT_LEFT));
-	_write(oFile, &header, 18);
+	write(oFile, &header, 18);
 	return true;
 }
 
@@ -248,15 +248,15 @@ ExportWMF::EndPage()
 {
 	unsigned short end_token[3] = {3, 0, 0};
 
-	_write(oFile, &end_token, 6);
-	file_size = _lseek(oFile, 0L, SEEK_CUR);
-	_lseek(oFile, 0L, SEEK_SET);
+	write(oFile, &end_token, 6);
+	file_size = lseek(oFile, 0L, SEEK_CUR);
+	lseek(oFile, 0L, SEEK_SET);
 	header.mtSize0 = (file_size>>1)&0xffff;
 	header.mtSize1 = file_size>>17;
 	header.mtNoObj = maxGDIobj;
 	header.mtMaxRec = rec_size;
-	_write(oFile, &header, 18);
-	oFile = _close(oFile);
+	write(oFile, &header, 18);
+	oFile = close(oFile);
 	return true;
 }
 
@@ -367,7 +367,7 @@ ExportWMF::wmfCreateSolidBrush(DWORD color)
 {
 	wmfLogBrush lb = {7, 0x2fc, 0, color, 0};
 
-	_write(oFile, &lb, 14);
+	write(oFile, &lb, 14);
 	currGDIobj++;
 	maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
 	return currGDIobj-1;
@@ -385,7 +385,7 @@ ExportWMF::wmfCreateFontIndirect(short lfHeight, short lfWidth, short lfEscapeme
 		lfQuality, lfPitchAndFamily, "Arial"};
 
 	if(FaceName && FaceName[0]) rlp_strcpy(lf.face, 32, FaceName);
-	_write(oFile, &lf, 56);
+	write(oFile, &lf, 56);
 	currGDIobj++;
 	maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
 	return currGDIobj-1;
@@ -396,7 +396,7 @@ ExportWMF::wmfCreateSolidPen(DWORD color, unsigned short width)
 {
 	wmfLogPen lp = {8, 0x2fa, 0, width, color};
 
-	_write(oFile, &lp, 16);
+	write(oFile, &lp, 16);
 	currGDIobj++;
 	maxGDIobj = currGDIobj > maxGDIobj ? currGDIobj : maxGDIobj;
 	return currGDIobj-1;
@@ -418,7 +418,7 @@ ExportWMF::wmfEllipse(unsigned short ix1, unsigned short iy1, unsigned short ix2
 {
 	wmfRect rc = {7, 0x418, iy2, ix2, iy1, ix1};
 	
-	_write(oFile, &rc, 14);
+	write(oFile, &rc, 14);
 }
 
 void
@@ -428,11 +428,11 @@ ExportWMF::wmfPolyline(POINT *pts, unsigned short cp)
 	unsigned short v[2];
 	int i;
 
-	_write(oFile, &pl, 8);
+	write(oFile, &pl, 8);
 	for(i = 0; i < cp; i++) {
 		v[0] = (unsigned short)pts[i].x;
 		v[1] = (unsigned short)pts[i].y;
-		_write(oFile, &v, 4);
+		write(oFile, &v, 4);
 		}
 	if(pl.Size > rec_size) rec_size = pl.Size;
 }
@@ -444,11 +444,11 @@ ExportWMF::wmfPolygon(POINT *pts, unsigned short cp)
 	unsigned short v[2];
 	int i;
 
-	_write(oFile, &pl, 8);
+	write(oFile, &pl, 8);
 	for(i = 0; i < cp; i++) {
 		v[0] = (unsigned short)pts[i].x;
 		v[1] = (unsigned short)pts[i].y;
-		_write(oFile, &v, 4);
+		write(oFile, &v, 4);
 		}
 	if(pl.Size > rec_size) rec_size = pl.Size;
 }
@@ -458,7 +458,7 @@ ExportWMF::wmfRectangle(unsigned short ix1, unsigned short iy1, unsigned short i
 {
 	wmfRect rc = {7, 0x41B, iy2, ix2, iy1, ix1};
 	
-	_write(oFile, &rc, 14);
+	write(oFile, &rc, 14);
 }
 
 void
@@ -466,7 +466,7 @@ ExportWMF::wmfSelectObject(unsigned short o)
 {
 	wmfObjShort so  = {4, 0x12D, o};
 
-	_write(oFile, &so, 8);
+	write(oFile, &so, 8);
 }
 
 void
@@ -474,8 +474,8 @@ ExportWMF::wmfSetBkColor(DWORD col)
 {
 	wmfObjCol co = {5, 0x201};
 
-	_write(oFile, &co, 6);
-	_write(oFile, &col, 4);
+	write(oFile, &co, 6);
+	write(oFile, &col, 4);
 }
 
 void
@@ -484,9 +484,9 @@ ExportWMF::wmfSetBkMode(unsigned m)
 	wmfObjShort mo = {5, 0x102, m & 0xffff};
 	unsigned short p;
 
-	_write(oFile, &mo, 8);
+	write(oFile, &mo, 8);
 	p = m>>16;
-	_write(oFile, &p, 2);
+	write(oFile, &p, 2);
 }
 
 //cmSetMapMode()
@@ -498,9 +498,9 @@ ExportWMF::wmfSetTextAlign(unsigned a)
 	wmfObjShort ao = {5, 0x12E, a & 0xffff};
 	unsigned short p;
 
-	_write(oFile, &ao, 8);
+	write(oFile, &ao, 8);
 	p = a>>16;
-	_write(oFile, &p, 2);
+	write(oFile, &p, 2);
 }
 
 void
@@ -508,8 +508,8 @@ ExportWMF::wmfSetTextColor(DWORD col)
 {
 	wmfObjCol tc = {5, 0x209};
 
-	_write(oFile, &tc, 6);
-	_write(oFile, &col, 4);
+	write(oFile, &tc, 6);
+	write(oFile, &col, 4);
 }
 
 //cmSetWindowExt()
@@ -523,9 +523,9 @@ ExportWMF::wmfTextOut(unsigned short ix1, unsigned short iy1, char *txt, unsigne
 
 	le = cb &1 ? cb+1 : cb;
 	to.Size += le>>1;
-	_write(oFile, &to, 8);
-	_write(oFile, txt, le);
-	_write(oFile, &v, 4);	
+	write(oFile, &to, 8);
+	write(oFile, txt, le);
+	write(oFile, &v, 4);	
 	if(to.Size > rec_size) rec_size = to.Size;
 }
 
@@ -535,6 +535,8 @@ void DoExportWmf(GraphObj *g, char *FileName, float res, DWORD flags)
 {
 	ExportWMF *ex;
 	
+
+	InfoBox("The export of Windos metafile (*.wmf) is deprecated.\n\nThis feature will be removed in future\nversions of RLPlot!\n\n");
 	ex = new ExportWMF(g, FileName, res, flags);
 	if(ex->StartPage()) {
 		g->DoPlot(ex);
@@ -567,18 +569,20 @@ public:
 	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
 	bool oSolidLine(POINT *p);
 	bool oTextOut(int x, int y, char *txt, int cb);
+	bool oTextOutW(int x, int y, w_char *txt, int cb);
 	bool oPolygon(POINT *pts, int cp, char * nam = 0L);
 
 private:
-	int iLineWidth;
+	int iLineWidth, cb_out;
 	bool bUseGroupLine, bOutputPending;
 	GraphObj *go;
 	char *name, indent[80], output[120], tHatchStyle[80];
 	FILE *oFile;
 	DWORD flags;
 
+	bool com_TextOut(int x, int y, char *txt, int cb);
 	void Indent(bool ind);
-	void AddToOutput(char *txt);
+	void AddToOutput(char *txt, int len);
 	char *ColName(DWORD col);
 };
 
@@ -590,7 +594,7 @@ ExportSVG::ExportSVG(GraphObj *g, char *FileName, DWORD flg)
 	dFillCol = 0xffffffffL;
 	hres = vres = 1000.0f;
 	go = g;
-	if(FileName)name = _strdup(FileName);
+	if(FileName)name = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
 	else name = 0L;
 	oFile = 0L;
 	flags = flg;
@@ -739,7 +743,7 @@ ExportSVG::oCircle(int x1, int y1, int x2, int y2, char* nam)
 bool
 ExportSVG::oPolyline(POINT *pts, int cp, char *nam)
 {
-	int i;
+	int i, cb;
 	char tmptxt[40];
 
 	if(cp < 2) return false;
@@ -756,23 +760,27 @@ ExportSVG::oPolyline(POINT *pts, int cp, char *nam)
 	else {
 		if(cp == 2) return oSolidLine(pts);
 		bOutputPending = false;
-		sprintf(output, "<polyline points=\""); 
+		cb_out = sprintf(output, "<polyline points=\""); 
 		for(i = 0; i < cp; i++) {
-			sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
-			AddToOutput(tmptxt);
+			cb = sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
+			AddToOutput(tmptxt, cb);
 			}
-		i = (int)strlen(output);
-		if(i) output[i-1] = 0;
-		strcat(output, "\"");
+		if(cb_out) output[cb_out-1] = '"';
 		if(!bUseGroupLine) {
-			strcpy(tmptxt, " style = \"fill:none; ");
-			AddToOutput(tmptxt);
-			sprintf(tmptxt, "; stroke:%s; ", ColName(dLineCol));
-			AddToOutput(tmptxt);
-			sprintf(tmptxt, "stroke-width:%d\"/>",iLineWidth);
-			AddToOutput(tmptxt);
+			cb = rlp_strcpy(tmptxt, 120, " style = \"fill:none; ");
+			AddToOutput(tmptxt, cb);
+			cb = rlp_strcpy(tmptxt, 120, "; stroke:");
+			cb += rlp_strcpy(tmptxt+cb, 120-cb, ColName(dLineCol));
+			cb += rlp_strcpy(tmptxt+cb, 120-cb, "; ");
+			AddToOutput(tmptxt, cb);
+#ifdef USE_WIN_SECURE
+			cb = sprintf_s(tmptxt, 120, "stroke-width:%d\"/>",iLineWidth);
+#else
+			cb = sprintf(tmptxt, "stroke-width:%d\"/>",iLineWidth);
+#endif
+			AddToOutput(tmptxt, cb);
 			}
-		else strcat(output, "/>");
+		else AddToOutput("/>", 2);
 		fprintf(oFile, "%s%s\n", indent, output);
 		if(bOutputPending)Indent(false);
 		}
@@ -818,10 +826,10 @@ ExportSVG::oSolidLine(POINT *p)
 }
 
 bool
-ExportSVG::oTextOut(int x, int y, char *txt, int cb)
+ExportSVG::com_TextOut(int x, int y, char *txt, int cb)
 {
-	int i, j, h, ix, iy, dy;
-	char tmptxt[140], *nt;
+	int c, h, ix, iy, dy;
+	char tmptxt[120];
 
 	if(!txt || !txt[0]) return false;
 	else h = TxtSet.iSize;
@@ -839,70 +847,116 @@ ExportSVG::oTextOut(int x, int y, char *txt, int cb)
 		else if((TxtSet.Align & TXA_VBOTTOM) == TXA_VBOTTOM) dy = -un2iy(TxtSet.fSize*0.6);
 		else if((TxtSet.Align & TXA_VTOP) == TXA_VTOP) dy = -un2iy(TxtSet.fSize*0.2);
 		}
-	sprintf(output, "<text x=\"%d\" y=\"%d\" dy=\"%d\" ", ix, iy, dy);
+#ifdef USE_WIN_SECURE
+	cb_out = sprintf_s(output, 120, "<text x=\"%d\" y=\"%d\" dy=\"%d\" ", ix, iy, dy);
+#else
+	cb_out = sprintf(output, "<text x=\"%d\" y=\"%d\" dy=\"%d\" ", ix, iy, dy);
+#endif
 	if(fabs(TxtSet.RotBL) >.01 || fabs(TxtSet.RotCHAR) >.01) {
-		sprintf(tmptxt,"transform=\"rotate(%.0f,%d,%d)\" ", -TxtSet.RotBL, ix, iy);
-		strcat(output, tmptxt);
+#ifdef USE_WIN_SECURE
+		cb_out += sprintf_s(output+cb_out, 120-cb_out, "transform=\"rotate(%.0f,%d,%d)\" ", -TxtSet.RotBL, ix, iy);
+#else
+		cb_out += sprintf(output+cb_out,"transform=\"rotate(%.0f,%d,%d)\" ", -TxtSet.RotBL, ix, iy);
+#endif
 		}
-	strcpy(tmptxt, "style=\"font-family:");
+	c = rlp_strcpy(tmptxt, 140, "style=\"font-family:");
 	switch(TxtSet.Font) {
-	case FONT_TIMES:	strcat(tmptxt, "Times;");		break;
-	case FONT_COURIER:	strcat(tmptxt, "Courier;");		break;
-	default:			strcat(tmptxt, "Helvetica;");	break;
+	case FONT_TIMES:	c += rlp_strcpy(tmptxt+c, 120-c, "Times;");		break;
+	case FONT_COURIER:	c += rlp_strcpy(tmptxt+c, 120-c, "Courier;");	break;
+	default:			c += rlp_strcpy(tmptxt+c, 120-c, "Helvetica;");	break;
 		}
-	if(TxtSet.Style & TXS_ITALIC) strcat(tmptxt, " font-style:italic;");
-	if(TxtSet.Style & TXS_BOLD) strcat(tmptxt, " font-weight:bold;");
-	if(TxtSet.Style & TXS_UNDERLINE) strcat(tmptxt, " text-decoration:underline;");
-	AddToOutput(tmptxt);
-	sprintf(tmptxt, " fill:%s; stroke:%s; ", ColName(TxtSet.ColTxt),
-		ColName(TxtSet.ColTxt));
-	AddToOutput(tmptxt);
-	sprintf(tmptxt, "font-size:%d; text-anchor:%s \">", h, 
+	if(TxtSet.Style & TXS_ITALIC) c += rlp_strcpy(tmptxt+c, 120-c, " font-style:italic;");
+	if(TxtSet.Style & TXS_BOLD) c += rlp_strcpy(tmptxt+c, 120-c, " font-weight:bold;");
+	if(TxtSet.Style & TXS_UNDERLINE) c += rlp_strcpy(tmptxt+c, 120-c, " text-decoration:underline;");
+	AddToOutput(tmptxt, c);
+#ifdef USE_WIN_SECURE
+	c = sprintf_s(tmptxt, 120, " fill:%s; stroke:%s; ", ColName(TxtSet.ColTxt), ColName(TxtSet.ColTxt));
+#else
+	c = sprintf(tmptxt, " fill:%s; stroke:%s; ", ColName(TxtSet.ColTxt), ColName(TxtSet.ColTxt));
+#endif
+	AddToOutput(tmptxt, c);
+#ifdef USE_WIN_SECURE
+	c = sprintf(tmptxt, "font-size:%d; text-anchor:%s \">", h, 
+		(TxtSet.Align & TXA_HRIGHT) ? "end" : (TxtSet.Align & TXA_HCENTER) ? "middle":"start");
+#else
+	c = sprintf(tmptxt, "font-size:%d; text-anchor:%s \">", h, 
 		(TxtSet.Align & TXA_HRIGHT) ? "end" : (TxtSet.Align & TXA_HCENTER) ? "middle":"start");
-	AddToOutput(tmptxt);
-	if(TxtSet.Font == FONT_GREEK) {
-		for(i = j = 0; txt[i] && j < 4090; i++) {
-			switch(txt[i]) {
+#endif
+	AddToOutput(tmptxt, c);
+	if((strlen(indent)+strlen(txt)+cb_out) <110) cb_out += rlp_strcpy(output+cb_out, 120-cb_out, txt);
+	else {
+		fprintf(oFile, "%s%s\n", indent, output);
+		cb_out=rlp_strcpy(output, 120, txt);
+		}
+	if((strlen(indent) + cb_out) <104) 
+		fprintf(oFile, "%s%s</text>\n", indent, output);
+	else {
+		fprintf(oFile, "%s%s\n", indent, output);
+		fprintf(oFile, "</text>\n");
+		}
+	return true;
+}
+
+bool
+ExportSVG::oTextOut(int x, int y, char *txt, int cb)
+{
+	char *nt;
+
+	if(!txt || !txt[0]) return false;
+	nt = str2xml(txt, TxtSet.Font == FONT_GREEK);
+	return com_TextOut(x, y, nt, cb);
+}
+
+bool
+ExportSVG::oTextOutW(int x, int y, w_char *txt, int cb)
+{
+	int i, j;
+	wchar_t wc;
+	char c;
+
+	for(i = j = 0; txt[i]; i++) {
+		switch(txt[i]) {
 			case '"':
-				j += sprintf(TmpTxt+j, """);
+				j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, """);
 				break;
 			case '&':
-				j += sprintf(TmpTxt+j, "&");
+				j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "&");
 				break;
 			case '<':
-				j += sprintf(TmpTxt+j, "<");
+				j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, "<");
 				break;
 			case '>':
-				j += sprintf(TmpTxt+j, ">");
+				j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, ">");
 				break;
 			default:
-				if(txt[i] >= 'A' && txt[i] <= 'Z') j += sprintf(TmpTxt+j, "&#%d;", txt[i] - 'A' + 0x391);
-				else if(txt[i] >= 'a' && txt[i] <= 'z') j += sprintf(TmpTxt+j, "&#%d;", txt[i] - 'a' + 0x3B1);
-				else if(txt[i] > 31) TmpTxt[j++] = txt[i];
+				if(txt[i] > 255) {
+#ifdef USE_WIN_SECURE
+					j += sprintf_s(TmpTxt+j, TMP_TXT_SIZE-j, "&#%d;", txt[i]);
+#else
+					j += sprintf(TmpTxt+j, "&#%d;", txt[i]);
+#endif
+					}
+				else if(txt[i] > 127) {
+					c = (char)txt[i];
+					if(mbtowc(&wc, &c, 1) >0) 
+#ifdef USE_WIN_SECURE
+						j += sprintf_s(TmpTxt+j, TMP_TXT_SIZE-j, "&#%d;", ((unsigned short)wc));
+#else
+						j += sprintf(TmpTxt+j, "&#%d;", ((unsigned short)wc));
+#endif
+					}
+				else TmpTxt[j++] = (char)txt[i];
 				break;
-				}
 			}
-		nt = TmpTxt;
-		}
-	else nt = str2xml(txt);
-	if((strlen(indent)+strlen(nt)+strlen(output)) <110) strcat(output, nt);
-	else {
-		fprintf(oFile, "%s%s\n", indent, output);
-		strcpy(output, nt);
-		}
-	if((strlen(indent) + strlen(output)) <104) 
-		fprintf(oFile, "%s%s</text>\n", indent, output);
-	else {
-		fprintf(oFile, "%s%s\n", indent, output);
-		fprintf(oFile, "</text>\n");
 		}
-	return true;
+	TmpTxt[j++] = 0;
+	return com_TextOut(x, y, TmpTxt, j-1);
 }
 
 bool
 ExportSVG::oPolygon(POINT *pts, int cp, char *nam)
 {
-	int i;
+	int i, cb;
 	char tmptxt[40];
 
 	if(cp <3) return false;
@@ -911,21 +965,37 @@ ExportSVG::oPolygon(POINT *pts, int cp, char *nam)
 		Indent(true);
 		}
 	bOutputPending = false;
-	sprintf(output, "<polygon%s%s%s points=\"",
+#ifdef USE_WIN_SECURE
+	cb_out = sprintf_s(output, 120, "<polygon%s%s%s points=\"",
 		nam? " name=\"" : "", nam ? nam : "", nam ? "\"" : ""); 
+#else
+	cb_out = sprintf(output, "<polygon%s%s%s points=\"",
+		nam? " name=\"" : "", nam ? nam : "", nam ? "\"" : ""); 
+#endif
 	for(i = 0; i < cp; i++) {
-		sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
-		AddToOutput(tmptxt);
+#ifdef USE_WIN_SECURE
+		cb = sprintf_s(tmptxt, 40, "%d %d ", pts[i].x, pts[i].y);
+#else
+		cb = sprintf(tmptxt, "%d %d ", pts[i].x, pts[i].y);
+#endif
+		AddToOutput(tmptxt, cb);
 		}
-	i = (int)strlen(output);
-	if(i) output[i-1] = 0;
-	strcat(output, "\" ");
-	sprintf(tmptxt, "style=\"fill:%s; ", ColName(dFillCol));
-	AddToOutput(tmptxt);
-	sprintf(tmptxt, "stroke:%s; ", ColName(dLineCol));
-	AddToOutput(tmptxt);
-	sprintf(tmptxt, "stroke-width:%d\"/>",iLineWidth);
-	AddToOutput(tmptxt);
+	if(cb_out) output[cb_out-1] = '"';
+#ifdef USE_WIN_SECURE
+	cb = sprintf(tmptxt, "style=\"fill:%s; ", ColName(dFillCol));
+	AddToOutput(tmptxt, cb);
+	cb = sprintf(tmptxt, "stroke:%s; ", ColName(dLineCol));
+	AddToOutput(tmptxt, cb);
+	cb = sprintf(tmptxt, "stroke-width:%d\"/>",iLineWidth);
+	AddToOutput(tmptxt, cb);
+#else
+	cb = sprintf(tmptxt, "style=\"fill:%s; ", ColName(dFillCol));
+	AddToOutput(tmptxt, cb);
+	cb = sprintf(tmptxt, "stroke:%s; ", ColName(dLineCol));
+	AddToOutput(tmptxt, cb);
+	cb = sprintf(tmptxt, "stroke-width:%d\"/>",iLineWidth);
+	AddToOutput(tmptxt, cb);
+#endif
 	if(output)fprintf(oFile, "%s%s\n", indent, output);
 	if(bOutputPending)Indent(false);
 	if(hgo) {
@@ -953,16 +1023,21 @@ ExportSVG::Indent(bool ind)
 }
 
 void
-ExportSVG::AddToOutput(char *txt)
+ExportSVG::AddToOutput(char *txt, int len)
 {
-	if((strlen(txt) + strlen(output) + strlen(indent)) < 110)strcat(output, txt);
+	if(!txt || !txt[0]) return;
+	if(!len) len = (int)strlen(txt);
+	if((len + cb_out + strlen(indent)) < 110){
+		cb_out += rlp_strcpy(output+cb_out, 120, txt);
+		}
 	else {
 		fprintf(oFile, "%s%s\n", indent, output);
 		if(!bOutputPending) Indent(true);
 		bOutputPending = true;
-		strcpy(output, txt);
+		cb_out = rlp_strcpy(output, 120, txt);
 		}
 }
+
 char *
 ExportSVG::ColName(DWORD col)
 {
@@ -1001,7 +1076,7 @@ void DoExportSvg(GraphObj *g, char *FileName, DWORD flags)
 		g->DoPlot(ex);
 		ex->EndPage();
 		}
-	HideTextCursor();
+	HideTextCursor();	
 	delete(ex);
 }
 
@@ -1082,36 +1157,34 @@ ExportEPS::SetFill(FillDEF *fill)
 {
 	if(!fill) return false;
 	if((fill->type & 0xff) != FILL_NONE) {
-		if(!hgo) hgo = new HatchOut(this);
-		if(hgo) hgo->SetFill(fill);
+		if(!hgo) hgo = new HatchOut(this);		if(hgo) hgo->SetFill(fill);
 		}
 	else {
-		if(hgo) delete hgo;
-		hgo = 0L;
+		if(hgo) delete hgo;						hgo = 0L;
 		}
-	dFillCol = fill->color;
-	dFillCol2 = fill->color2;
+	dFillCol = fill->color;						dFillCol2 = fill->color2;
 	return true;
 }
 
 bool
 ExportEPS::SetTextSpec(TextDEF *set)
 {
+	int cb;
+
 	if(set->fSize > 0.0) {
-		if((set->Style & TXS_SUPER) || (set->Style & TXS_SUB))
-			set->iSize = un2iy(set->fSize * 0.71);
+		if((set->Style & TXS_SUPER) || (set->Style & TXS_SUB)) set->iSize = un2iy(set->fSize * 0.71);
 		else set->iSize = un2iy(set->fSize);
 		}
 	if(!set->iSize) return false;
 	anyOutput::SetTextSpec(set);
 	switch(TxtSet.Font) {
-	case FONT_TIMES:	sprintf(FontName, "(Times");		break;
-	case FONT_COURIER:	sprintf(FontName, "(Courier");		break;
-	default:			sprintf(FontName, "(Helvetica");	break;		//Helvetica
+	case FONT_TIMES:	cb = rlp_strcpy(FontName, 30, "(Times");		break;		//Serif
+	case FONT_COURIER:	cb = rlp_strcpy(FontName, 30, "(Courier");		break;		//fixed spaced
+	default:			cb = rlp_strcpy(FontName, 30, "(Helvetica");	break;		//Sans Serif	
 		}
-	if(TxtSet.Style & TXS_BOLD) strcat(FontName, "-Bold");
-	if(TxtSet.Style & TXS_ITALIC) strcat(FontName, "-Italic");
-	strcat(FontName, ")");	bFontChange = true;
+	if(TxtSet.Style & TXS_BOLD) cb += rlp_strcpy(FontName+cb, 30-cb, "-Bold");
+	if(TxtSet.Style & TXS_ITALIC) cb += rlp_strcpy(FontName+cb, 30-cb, "-Italic");
+	cb += rlp_strcpy(FontName+cb, 30-cb, ")");		bFontChange = true;
 	return true;
 }
 
diff --git a/Fileio.cpp b/Fileio.cpp
index 7fa8a37..055dd19 100755
--- a/Fileio.cpp
+++ b/Fileio.cpp
@@ -1,4 +1,4 @@
-//FileIO.cpp, Copyright (c) 2001-2006 R.Lackner
+//FileIO.cpp, Copyright (c) 2001-2007 R.Lackner
 //read/write graphic objects
 //
 //    This file is part of RLPlot.
@@ -239,7 +239,7 @@ static void WriteEscString(char *txt)
 			esc_str[j++] = '\\';	esc_str[j++] = 'n';
 			break;
 		default:	
-			if(txt[i] >= ' ') esc_str[j++] = txt[i];
+			if(((unsigned char*)txt)[i] >= ' ') esc_str[j++] = txt[i];
 			}
 		if(j > (esc_str_size -10)) esc_str = (char*)realloc(esc_str, (esc_str_size += 100));
 		if(j > lim && (l-i) > 3) {
@@ -899,6 +899,7 @@ bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste)
 	int i, id, lid;
 	unsigned int hv;
 	GraphObj *go;
+	scaleINFO sc_info;
 
 	LastOpenGO = 0L;
 	if(Notary || Cache) {
@@ -1004,6 +1005,7 @@ bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste)
 		case 967843:	go = new DefsRW(FILE_READ);			break;
 		case 66848:		go = new Func3D(FILE_READ);			break;
 		case 5001225:	go = new TextFrame(FILE_READ);		break;
+		case 4743132:	go = new NormQuant(FILE_READ);		break;
 		default:
 #ifdef USE_WIN_SECURE
 			sprintf_s(debug, 80, "Object %ld in file\n(Class = \"%s\")\nhash #%d\nis unknown.", id, tmp, hv);
@@ -1025,6 +1027,14 @@ bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste)
 	if((LastOpenGO = go = Notary->PopGO(lid))) {
 		go->Command(CMD_SET_DATAOBJ, 0L, 0L);
 		delete Notary;		Notary = 0L;
+		if(bPaste && go->Id == GO_GRAPH) {
+			sc_info.sx.fx = -((Graph*)go)->GRect.Xmin;				sc_info.sy.fx = -((Graph*)go)->GRect.Ymin;
+			sc_info.sx.fy = sc_info.sy.fy = sc_info.sz.fy = 1.0;	sc_info.sz.fx = 0.0;
+			go->Command(CMD_SCALE, &sc_info, 0L);
+			sc_info.sx.fy = sc_info.sy.fy = sc_info.sz.fy = 1.0/go->GetSize(SIZE_SCALE);
+			sc_info.sx.fx = sc_info.sy.fx = sc_info.sz.fx = 0.0;
+			go->Command(CMD_SCALE, &sc_info, 0L);
+			}
 		if(bPaste && root->Command(CMD_PASTE_OBJ, (void *)go, 0L)) {
 			// object accepted
 			}
@@ -2368,7 +2378,8 @@ PlotScatt::FileIO(int rw)
 		{"dLines", typOBJLST, &DropLines, &nPoints},
 		{"Labels", typOBJLST, &Labels, &nPoints},
 		{"x_info", typTEXT, &x_info, 0L},
-		{"y_info", typLAST | typTEXT, &y_info, 0L}};
+		{"y_info", typTEXT, &y_info, 0L},
+		{"DataDesc", typLAST | typTEXT, &data_desc, 0L}};
 	int i;
 
 	switch(rw) {
@@ -2489,6 +2500,7 @@ FreqDist::FileIO(int rw)
 		BarFill.hatch = &HatchLine;
 		memcpy(&BarLine, defs.GetOutLine(), sizeof(LineDEF));
 		curr_data=0L;		dirty = true;
+		dmin = HUGE_VAL, dmax = -HUGE_VAL;
 		if(name) {
 #ifdef USE_WIN_SECURE
 			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "freq. dist. (%s)", name);
@@ -2936,7 +2948,11 @@ Scatt3D::FileIO(int rw)
 		{"ssRefX", typTEXT, &ssRefX, 0L},
 		{"ssRefY", typTEXT, &ssRefY, 0L},
 		{"ssRefZ", typTEXT, &ssRefZ, 0L},
+		{"DataDesc", typTEXT, &data_desc, 0L},
 		{"hide", typNZINT, &hidden, 0L},
+		{"x_axis", typNZINT, &use_xaxis, 0L},
+		{"y_axis", typNZINT, &use_yaxis, 0L},
+		{"z_axis", typNZINT, &use_zaxis, 0L},
 		{"Line", typGOBJ, &Line, 0L},
 		{"Balls", typOBJLST, &Balls, &nBalls},
 		{"Columns", typOBJLST, &Columns, &nColumns},
@@ -3007,6 +3023,7 @@ Ribbon::FileIO(int rw)
 		{"ssRefX", typTEXT, &ssRefX, 0L},
 		{"ssRefY", typTEXT, &ssRefY, 0L},
 		{"ssRefZ", typTEXT, &ssRefZ, 0L},
+		{"DataDesc", typTEXT, &data_desc, 0L},
 		{"Line", typLINEDEF, &Line, 0L},
 		{"Fill", typFILLDEF, &Fill, 0L},
 		{"values", typFPLST3D, &values, &nVal},
@@ -3058,6 +3075,7 @@ Grid3D::FileIO(int rw)
 {
 	descIO Desc[] = {
 		{"Type", typNZINT, &type, 0L},
+		{"hide", typNZINT, &hidden, 0L},
 		{"Start", typPOINT3D, &start, 0L},
 		{"Step", typPOINT3D, &step, 0L},
 		{"Line", typLINEDEF, &Line, 0L},
@@ -3234,6 +3252,62 @@ FitFunc::FileIO(int rw)
 }
 
 bool
+NormQuant::FileIO(int rw)
+{
+	lfPOINT *dt;
+	long cnt;
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"nData", typINT, &nData, 0L},
+		{"Data", typFPLST, &dt, &cnt},
+		{"ssRef", typTEXT, &ssRef, 0L},
+		{"x_info", typTEXT, &x_info, 0L},
+		{"y_info", typLAST | typTEXT, &y_info, 0L}};
+	int i, j, l;
+
+	if(rw == FILE_WRITE) {
+		if(nData < 4) return false;
+		l = (nData >>1) +1;				cnt = l;
+		if(!(dt = (lfPOINT *)calloc(l, sizeof(lfPOINT))))return false;
+		for(i = j = 0; i < nData; i += 2, j++) {
+			dt[j].fx = src_data[i];		dt[j].fy = src_data[i+1];
+			}
+		}
+	else {
+		dt = 0L;		cnt = 0;
+		}
+	switch(rw) {
+	case INIT_VARS:
+		InitVarsGO(Desc);
+		sy = new Symbol(this, data, 0.0, 0.0, SYM_CIRCLE);
+		x_vals = y_vals = src_data = 0L;
+		if(name) {
+#ifdef USE_WIN_SECURE
+			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "normal quantiles (%s)", name);
+#else
+			i = sprintf(TmpTxt, "normal quantiles (%s)", name);
+#endif
+			free(name);		name = (char*)memdup(TmpTxt, i+1, 0);
+			}
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		if(dt && cnt > 1 && (src_data = (double*)malloc(nData*sizeof(double)))) {
+			for(i = j = 0, l = nData-1; i < nData; i += 2, j++) {
+				src_data[i] = dt[j].fx;		if(i < l) src_data[i+1] = dt[j].fy;
+				}
+			free(dt);
+			}
+		return true;
+	case FILE_WRITE:
+		ExecOutput(Notary->RegisterGO(this), "NormQuant", Desc);
+		free(dt);
+		return true;
+		}
+	return false;
+}
+
+bool
 GridLine::FileIO(int rw)
 {
 	descIO Desc[] = {
@@ -3418,13 +3492,11 @@ Axis::FileIO(int rw)
 		tlbdef.ColTxt = parent ? parent->GetColor(COL_AXIS) : defs.Color(COL_AXIS);
 		tlbdef.ColBg = parent ? parent->GetColor(COL_BG) : defs.Color(COL_AXIS);
 		tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;
-		tlbdef.fSize = DefSize(SIZE_TICK_LABELS);
-		tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
-		tlbdef.Style = TXS_NORMAL;
-		tlbdef.Mode = TXM_TRANSPARENT;
-		tlbdef.Font = FONT_HELVETICA;
-		tlbdef.text = 0L;	l_segs = 0L;	nl_segs = 0;
-		drawOut = scaleOut = 0L;			bModified = false;
+		tlbdef.fSize = DefSize(SIZE_TICK_LABELS);	tlbdef.Align = TXA_VCENTER | TXA_HCENTER;
+		tlbdef.Style = TXS_NORMAL;					tlbdef.Mode = TXM_TRANSPARENT;
+		tlbdef.Font = FONT_HELVETICA;				atv = 0L;
+		tlbdef.text = 0L;		l_segs = 0L;		nl_segs = 0;
+		drawOut = scaleOut = 0L;					bModified = false;
 		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
 		mo = 0L;
 		return true;
@@ -3467,6 +3539,7 @@ Plot3D::FileIO(int rw)
 {
 	fPOINT3D rot_vec, rot_ang;
 	descIO Desc[] = {
+		{"hide", typNZINT, &hidden, 0L},
 		{"xBounds", typLFPOINT, &xBounds, 0L},
 		{"yBounds", typLFPOINT, &yBounds, 0L},
 		{"zBounds", typLFPOINT, &zBounds, 0L},
@@ -3475,6 +3548,9 @@ Plot3D::FileIO(int rw)
 		{"Center", typPOINT3D, &rotC, 0L},
 		{"rot_vec", typPOINT3D, &rot_vec, 0L},
 		{"rot_ang", typPOINT3D, &rot_ang, 0L},
+		{"x_axis", typNZINT, &use_xaxis, 0L},
+		{"y_axis", typNZINT, &use_yaxis, 0L},
+		{"z_axis", typNZINT, &use_zaxis, 0L},
 		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
 		{"Plots", typLAST | typOBJLST, &plots, (long*)&nPlots}};
 	int i;
@@ -3499,6 +3575,7 @@ Plot3D::FileIO(int rw)
 		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
 		xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
 		xBounds.fy = yBounds.fy = zBounds.fy = -HUGE_VAL;
+		Sc_Plots = 0L;		nscp = 0;
 		if(name) {
 #ifdef USE_WIN_SECURE
 			i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "3D-root (%s)", name);
@@ -3538,6 +3615,7 @@ Func3D::FileIO(int rw)
 	fPOINT3D rot_vec, rot_ang;
 	descIO Desc[] = {
 		{"Type", typNZINT, &type, 0L},
+		{"hide", typNZINT, &hidden, 0L},
 		{"xBounds", typLFPOINT, &xBounds, 0L},
 		{"yBounds", typLFPOINT, &yBounds, 0L},
 		{"zBounds", typLFPOINT, &zBounds, 0L},
@@ -3546,6 +3624,9 @@ Func3D::FileIO(int rw)
 		{"Center", typPOINT3D, &rotC, 0L},
 		{"rot_vec", typPOINT3D, &rot_vec, 0L},
 		{"rot_ang", typPOINT3D, &rot_ang, 0L},
+		{"x_axis", typNZINT, &use_xaxis, 0L},
+		{"y_axis", typNZINT, &use_yaxis, 0L},
+		{"z_axis", typNZINT, &use_zaxis, 0L},
 		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
 		{"Plots", typOBJLST, &plots, (long*)&nPlots},
 		{"x1", typNZLFLOAT, &x1, 0L},
@@ -3614,6 +3695,7 @@ FitFunc3D::FileIO(int rw)
 	fPOINT3D rot_vec, rot_ang;
 	descIO Desc[] = {
 		{"Type", typNZINT, &type, 0L},
+		{"hide", typNZINT, &hidden, 0L},
 		{"ssXref", typTEXT, &ssXref, 0L},
 		{"ssYref", typTEXT, &ssYref, 0L},
 		{"ssZref", typTEXT, &ssZref, 0L},
@@ -3625,6 +3707,9 @@ FitFunc3D::FileIO(int rw)
 		{"Center", typPOINT3D, &rotC, 0L},
 		{"rot_vec", typPOINT3D, &rot_vec, 0L},
 		{"rot_ang", typPOINT3D, &rot_ang, 0L},
+		{"x_axis", typNZINT, &use_xaxis, 0L},
+		{"y_axis", typNZINT, &use_yaxis, 0L},
+		{"z_axis", typNZINT, &use_zaxis, 0L},
 		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
 		{"Plots", typOBJLST, &plots, (long*)&nPlots},
 		{"x1", typNZLFLOAT, &x1, 0L},
@@ -3821,7 +3906,7 @@ DefsRW::FileIO(int rw)
 {
 	descIO Desc[] = {
 		{"dUnits", typINT, &defs.dUnits, 0L},
-		{"cUnits", typINT, &defs.dUnits, 0L},
+		{"cUnits", typINT, &defs.cUnits, 0L},
 		{"dtHeight", typINT, &dlgtxtheight, 0L},
 		{"ss_txt", typLFLOAT, &defs.ss_txt, 0L},
 		{"fmt_date", typTEXT, &defs.fmt_date, 0L},
@@ -3838,6 +3923,15 @@ DefsRW::FileIO(int rw)
 	switch(rw) {
 	case FILE_READ:
 		ExecInput(Desc);
+		//check for plausibility
+		if(defs.ss_txt < 0.3 || defs.ss_txt > 3.0) defs.ss_txt = 0.9;
+		if(defs.dUnits < 0 || defs.dUnits > 2) defs.dUnits = 0;
+		defs.cUnits = defs.dUnits;
+#ifdef _WINDOWS
+		if(dlgtxtheight < 5 || dlgtxtheight > 60) dlgtxtheight = 16;
+#else
+		if(dlgtxtheight < 5 || dlgtxtheight > 60) dlgtxtheight = 10;
+#endif
 		return true;
 	case FILE_WRITE:
 		Notary = new notary();
diff --git a/ODbuttons.cpp b/ODbuttons.cpp
index 6d64b7d..1c81e4b 100755
--- a/ODbuttons.cpp
+++ b/ODbuttons.cpp
@@ -1,4 +1,4 @@
-//ODbuttons.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
+//ODbuttons.cpp, Copyright (c) 2001-2007 R.Lackner
 //Property dialogs for graphic objects
 //
 //    This file is part of RLPlot.
@@ -134,11 +134,12 @@ void OD_LineStyleTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 		pts[0].y = pts[1].y = pts[4].y = rec->top;
 		pts[1].x = pts[2].x = rec->right-1;
 		pts[2].y = pts[3].y = rec->bottom-1;
-		o->oPolyline(pts, 5);
-		Line.color = 0x00000000L;
-		o->SetLine(&Line);
-		o->SetFill(&Fill);
+		o->oPolyline(pts, 5);				Line.color = 0x00000000L;
+		o->SetLine(&Line);					o->SetFill(&Fill);
 		o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+		if(cmd == OD_DRAWSELECTED){
+			Fill.color = 0x000000ffL;		o->SetFill(&Fill);
+			}
 		np = 0;
 		switch(id) {
 		case 201:
@@ -210,26 +211,40 @@ void OD_LineStyleTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 				o->oSolidLine(pts);
 				pts[0].y++;		pts[1].y++;		pts[0].x = pts[1].x;	
 				}
-			o->oCircle(ix-3, rec->top + 7, ix+2, rec->top + 12);
+			o->oCircle(ix-3, rec->top + 9, ix+2, rec->top + 14);
 			o->oCircle(rec->left+11, iy-10, rec->left+16, iy -5);
 			o->oCircle(ix+3, rec->top + 27, ix+8, rec->top + 32);
 			o->oCircle(ix-5, iy+12, ix, iy + 17);
 			break;
+		case 212:
+			for(i = 2; i < (rec->bottom - rec->top - 18); i++) {
+				pts[1].x = ix + iround(pow(20.0, 1.0+((double)-i)/50.0) * -sin(((double)i)/4.0));
+				pts[1].y = iy + iround(pow(20.0, 1.0+((double)-i)/50.0) * -cos(((double)i)/4.0));
+				if(i>2)o->oSolidLine(pts);
+				pts[0].y = pts[1].y;		pts[0].x = pts[1].x;	
+				}
+			o->oCircle(ix-5, iy-4, ix, iy+1);			o->oCircle(ix-10, iy-17, ix-5, iy-12);
+#ifdef _WINDOWS
+			o->oCircle(ix-12, iy+9, ix-7, iy+4);		o->oCircle(ix+9, iy+7, ix+4, iy+2);
+#else
+			o->oCircle(ix-12, iy+9, ix-7, iy+4);		o->oCircle(ix+8, iy+6, ix+4, iy+2);
+#endif
+			break;
 			}
 		if(np) o->oPolyline(pts, np);
 		switch(id) {
 		case 201:	case 202:	case 203:	case 204:	case 205:
 		case 206:	case 207:	case 208:	case 209:
-			o->oCircle(ix-2, iy-2, ix+2, iy+2);
+			o->oCircle(ix-2, iy-2, ix+3, iy+3);
 #ifdef _WINDOWS
-			o->oCircle(rec->left+13, rec->bottom-13, rec->left+17, rec->bottom-17);
-			o->oCircle(rec->right-13, rec->top+13, rec->right-17, rec->top+17);
+			o->oCircle(rec->left+13, rec->bottom-13, rec->left+18, rec->bottom-18);
+			o->oCircle(rec->right-13, rec->top+13, rec->right-18, rec->top+18);
 #else
-			o->oCircle(rec->left+13, rec->bottom-14, rec->left+17, rec->bottom-16);
-			o->oCircle(rec->right-14, rec->top+13, rec->right-16, rec->top+17);
+			o->oCircle(rec->left+13, rec->bottom-14, rec->left+18, rec->bottom-18);
+			o->oCircle(rec->right-14, rec->top+13, rec->right-18, rec->top+18);
 #endif
 			break;
-		case 210:	case 211:
+		case 210:	case 211:	case 212:
 			break;
 			}
 		o->UpdateRect(rec, false);
@@ -740,8 +755,30 @@ void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 				pts[0].x++;		pts[1].x++;		pts[0].y = pts[1].y;	
 				}
 			break;
-		case 520:
-		case 521:
+		case 506:
+			o->SetLine(&bLine);
+			pts[0].x = rec->left +9;	pts[0].y = rec->bottom-5;	pts[1].x = pts[0].x+1;
+			for(i = 0; i < (rec->right - rec->left - 18); i++) {
+				r = ((double)(i+rec->left-ix+7))/8.0;
+				pts[1].y = pts[0].y - iround(exp(-r*r)*1.0+5.0);
+				pts[1].y = rec->bottom - iround(errf(r)*16.0+26.0);
+				if (i) o->oSolidLine(pts);
+				pts[0].x++;		pts[1].x++;		pts[0].y = pts[1].y;	
+				}
+			o->SetLine(&rLine);
+			pts[0].x = ix-2;	pts[1].x = pts[0].x+1;
+			for(i = 0; i < (rec->right - ix-5); i++) {
+				r = ((double)(i-9))/4.0;
+				pts[1].y = rec->bottom - iround(exp(-r*r)*17.0+7.0);
+				if (i) o->oSolidLine(pts);
+				pts[0].x++;		pts[1].x++;		pts[0].y = pts[1].y;	
+				}
+			o->SetFill(&FillG);			o->SetLine(&Line);
+			o->oCircle(ix, iy, ix+5, iy+5);
+			o->oCircle(ix-5, iy+8, ix, iy+13);
+			o->oCircle(ix+5, iy-10, ix+10, iy-5);
+			break;
+		case 520:		case 521:
 			if(id == 521) {
 				pts[0].x = rec->left+13;	pts[0].y = rec->bottom-12;
 				pts[1].x = rec->left+20;	pts[1].y = rec->top+18;
@@ -1321,7 +1358,7 @@ void OD_AxisTempl3D(int cmd, void *par, RECT *rec, anyOutput *o,
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Execute axis templates for new axis as owner drawn buttons
+// 2D Plot: Execute axis templates for new axis as owner drawn buttons
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 void OD_NewAxisTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 		void *data, int id)
@@ -1387,4 +1424,70 @@ void OD_NewAxisTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 		break;
 		}
 }
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// 3D Plot: Execute axis templates for new axis as owner drawn buttons
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void OD_NewAxisTempl3D(int cmd, void *par, RECT *rec, anyOutput *o,
+		void *data, int id)
+{
+	LineDEF Line = {0.0, 1.0, 0x0L, 0x0L};
+	FillDEF Fill = {FILL_NONE, 0x00ffffffL, 1.0, 0L};
+	POINT spts[24];
+	int i, ix, iy, edge;
+	DWORD col1, col2;
 
+	switch(cmd) {
+	case OD_DRAWNORMAL:
+	case OD_DRAWSELECTED:
+		Line.color = cmd == OD_DRAWSELECTED ? 0x00000000L : 0x00e8e8e8L;
+		Fill.color = cmd == OD_DRAWSELECTED ? 0x00ffffffL : 0x00e8e8e8L;
+		col1 = cmd == OD_DRAWSELECTED ? 0x008080c0L : 0x00c8c8c8L;
+		col2 = cmd == OD_DRAWSELECTED ? 0x0000ff00L : 0x0000c000L;
+		o->SetLine(&Line);
+		ix = (rec->right + rec->left)>>1;		iy = (rec->bottom + rec->top)>>1;
+		spts[0].x = spts[3].x = spts[4].x = rec->left;
+		spts[0].y = spts[1].y = spts[4].y = rec->top;
+		spts[1].x = spts[2].x = rec->right-1;	spts[2].y = spts[3].y = rec->bottom-1;
+		o->oPolyline(spts, 5);					Line.color = 0x00000000L;
+		o->SetLine(&Line);						o->SetFill(&Fill);
+		o->oRectangle(rec->left+3, rec->top+3, rec->right-3, rec->bottom-3);
+		spts[0].x = spts[6].x = spts[8].x = spts[13].x = spts[18].x = spts[19].x = rec->left+20;		
+		spts[0].y = spts[13].y = spts[18].y = rec->bottom-14;
+		spts[1].x = spts[2].x = spts[4].x = spts[5].x = spts[7].x = spts[21].x = rec->left+10;
+		spts[1].y = spts[2].y = spts[4].y = rec->bottom-10;
+		spts[3].x = spts[15].x = spts[16].x = spts[17].x = spts[20].x = spts[22].x = rec->right-20;				
+		spts[3].y = spts[15].y = spts[16].y = spts[2].y + 3;
+		spts[5].y = spts[7].y = spts[21].y = rec->top+12;
+		spts[6].y = spts[8].y = spts[19].y = rec->top+8;
+		spts[9].x = spts[10].x = spts[11].x = spts[12].x = spts[14].x = spts[23].x = rec->right-10;
+		spts[9].y = spts[10].y = spts[23].y = spts[8].y+3;
+		spts[11].y = spts[12].y = spts[14].y = spts[0].y+3;
+		spts[17].y = spts[20].y = spts[22].y = spts[7].y+3;
+		switch(id) {
+			case 201:		edge = 4;			break;
+			case 202:		edge = 16;			break;
+			case 203:		edge = 10;			break;
+			case 204:		edge = 18;			break;
+			case 205:		edge = 2;			break;
+			case 206:		edge = 14;			break;
+			case 207:		edge = 12;			break;
+			case 208:		edge = 0;			break;
+			case 209:		edge = 20;			break;
+			case 210:		edge = 22;			break;
+			case 211:		edge = 8;			break;
+			case 212:		edge = 6;			break;
+			default:		edge = -1;			break;
+			}
+		Line.color = col1;				o->SetLine(&Line);
+		if(true)for(i = 0; i < 24; i+= 2) {
+			if(i == edge){
+				Line.color = col2;		o->SetLine(&Line);
+				o->oSolidLine(spts+i);
+				Line.color = col1;		o->SetLine(&Line);
+				}
+			else o->oSolidLine(spts+i);
+			}
+		o->UpdateRect(rec, false);
+		break;
+		}
+}
diff --git a/Output.cpp b/Output.cpp
index 82e3083..2edb765 100755
--- a/Output.cpp
+++ b/Output.cpp
@@ -1,4 +1,4 @@
-//Output.cpp, Copyright (c) 2000-2006 R.Lackner
+//Output.cpp, Copyright (c) 2000-2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -56,7 +56,7 @@ anyOutput::anyOutput()
 	RLP.finc = 1.0f;
 	RLP.fp = 0.0f;
 	dPattern = 0xffffffffL;			//impossible (invisible)line pattern to start with
-	dBgCol = defs.Color(COL_BG);
+	dBgCol = defs.Color(COL_BG);	OC_type = OC_UNKNOWN;
 	MrkMode = MRK_NONE;				MrkRect = 0L;
 	VPorg.fx = VPorg.fy = 0.0;		VPscale = 1.0;
 	MenuHeight = 0;					cCursor = MC_ARROW;
@@ -96,6 +96,44 @@ anyOutput::SetRect(fRECT rec, int u, AxisDEF *x_ax, AxisDEF *y_ax)
 }
 
 void
+anyOutput::UseAxis(AxisDEF *ax, int type)
+{
+	AxisDEF *cax;
+
+	MrkMode = MRK_NONE;
+	if(!ax) return;
+	switch (type) {
+		case 1:			//x-axis
+			memcpy(cax = &xAxis, ax, sizeof(AxisDEF));
+			Box1.Xmin = co2fix(ax->loc[0].fx);
+			Box1.Xmax = co2fix(ax->loc[1].fx);
+			ddx = GetAxisFac(&xAxis, Box1.Xmax - Box1.Xmin, 0);
+			break;
+		case 2:			//y-axis
+			memcpy(cax = &yAxis, ax, sizeof(AxisDEF));
+			if(ax->flags & AXIS_3D) {
+				Box1.Ymax = co2fiy(ax->loc[0].fy);
+				Box1.Ymin = co2fiy(ax->loc[1].fy);
+				}
+			else {
+				Box1.Ymin = co2fiy(ax->loc[0].fy);
+				Box1.Ymax = co2fiy(ax->loc[1].fy);
+				}
+			ddy = GetAxisFac(&yAxis, Box1.Ymax - Box1.Ymin, 1);
+			break;
+		case 3:			//z-axis
+			memcpy(cax = &zAxis, ax, sizeof(AxisDEF));
+			Box1z.fx = un2fiz(ax->loc[0].fz);
+			Box1z.fy = un2fiz(ax->loc[1].fz);
+			ddz = GetAxisFac(&zAxis, Box1z.fy - Box1z.fx, 2);
+			break;
+		default:		//unnknown direction
+			return;
+		}
+	cax->owner = this;
+}
+
+void
 anyOutput::SetSpace(fPOINT3D *cub1, fPOINT3D *cub2, int u, double *rot, 
 	fPOINT3D *cent, AxisDEF *x_ax, AxisDEF *y_ax, AxisDEF *z_ax)
 {
@@ -637,12 +675,21 @@ anyOutput::oGetTextExtent(char *text, int cb, int *width, int *height)
 	default:				CharWidth = Helv_Char_Width;	break;
 		}
 	if(!cb && text) cb = (int)strlen(text);
-	for(i = w = 0; i < cb; i++) w += CharWidth[text[i]];
+	for(i = w = 0; i < cb; i++) w += ((unsigned)text[i] < 256 ? CharWidth[(unsigned)text[i]] : 35);
 	*width = iround(((double)w * (double)TxtSet.iSize)/52.0);
 	*height = TxtSet.iSize;
 	return true;
 }
 
+bool
+anyOutput::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
+{
+	if(cb < 1) for(cb = 0; text[cb]; cb++);
+	*width = (TxtSet.iSize * cb)>>1;
+	*height = TxtSet.iSize;
+	return true;
+}
+
 bool 
 anyOutput::oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam)
 {
@@ -1118,8 +1165,8 @@ HatchOut::IsInside(POINT p)
 {
 	long tmp1, tmp2, tmp3, tmp4;
 
-	if(p.x < DeskRect.left || p.x > DeskRect.right || p.y < DeskRect.top
-		|| p.y >DeskRect.bottom) return false;
+	if(out->OC_type != OC_HIMETRIC && (p.x < DeskRect.left || p.x > DeskRect.right || p.y < DeskRect.top
+		|| p.y >DeskRect.bottom)) return false;
 	switch(ho){
 	case HO_RECT:
 		if(p.x > HatchDef.rec.rec.left && p.x < HatchDef.rec.rec.right &&
diff --git a/PlotObs.cpp b/PlotObs.cpp
index 8a7fe3a..6119931 100755
--- a/PlotObs.cpp
+++ b/PlotObs.cpp
@@ -1,4 +1,4 @@
-//PlotObs.cpp, Copyright (c) 2001-2006 R.Lackner
+//PlotObs.cpp, Copyright (c) 2001-2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -51,8 +51,9 @@ Plot::Plot(GraphObj *par, DataObj *d):GraphObj(par, d)
 		pos = rlp_strcpy(name, nsize, (char*)"Plot");
 		add_int_to_buff(&name, &pos, &nsize, ++cPlots, true, 0);
 		}
-	use_xaxis = use_yaxis = 0;	hidden = 0;
-	x_info = y_info = z_info = 0L;
+	use_xaxis = use_yaxis = use_zaxis = 0;	hidden = 0;
+	x_info = y_info = z_info = data_desc = 0L;
+	x_tv = y_tv = 0L;
 }
 
 double
@@ -95,20 +96,17 @@ Plot::CheckBounds(double x, double y)
 bool
 Plot::UseAxis(int idx)
 {
-	double dx, dy;
-
 	if(CurrAxes && CurrAxes[idx]) {
-		dx = fabs(CurrAxes[idx]->GetSize(SIZE_XPOS+1) -
-			CurrAxes[idx]->GetSize(SIZE_XPOS));
-		dy = fabs(CurrAxes[idx]->GetSize(SIZE_YPOS+1) -
-			CurrAxes[idx]->GetSize(SIZE_YPOS));
-		if(dx > dy && idx != use_xaxis) {
+		switch(CurrAxes[idx]->type & 0xf) {
+		case 1:									// x-axis
 			Undo.ValInt(parent, &use_xaxis, 0L);
 			use_xaxis = idx;			return true;
-			}
-		else if(idx != use_yaxis) {
+		case 2:									// y-axis
 			Undo.ValInt(parent, &use_yaxis, 0L);
 			use_yaxis = idx;			return true;
+		case 3:									// z-axis
+			Undo.ValInt(parent, &use_zaxis, 0L);
+			use_zaxis = idx;			return true;
 			}
 		}
 	return false;
@@ -117,34 +115,20 @@ Plot::UseAxis(int idx)
 void
 Plot::ApplyAxes(anyOutput *o)
 {
-	AxisDEF x_axis, y_axis;
-	double dsp;
-	fRECT CurrRect;
-	
 	if(!o || !CurrAxes || !parent) return;
-	memcpy(&x_axis, &o->xAxis, sizeof(AxisDEF));
-	memcpy(&y_axis, &o->yAxis, sizeof(AxisDEF));
-	CurrRect.Xmin = (dsp = parent->GetSize(SIZE_GRECT_LEFT)) +
-		parent->GetSize(SIZE_DRECT_LEFT);
-	CurrRect.Xmax = dsp + parent->GetSize(SIZE_DRECT_RIGHT);
 	if(use_xaxis && CurrAxes[use_xaxis]) {
-		memcpy(&x_axis, CurrAxes[use_xaxis]->axis, sizeof(AxisDEF));
-		if(x_axis.flags & AXIS_DEFRECT) {
-			x_axis.loc[0].fx += dsp;	x_axis.loc[1].fx += dsp;
-			}
+		o->UseAxis(CurrAxes[use_xaxis]->axis, CurrAxes[use_xaxis]->type & 0xf);
 		}
 	else use_xaxis = 0;
-	CurrRect.Ymin = (dsp = parent->GetSize(SIZE_GRECT_TOP)) +
-		parent->GetSize(SIZE_DRECT_BOTTOM);
-	CurrRect.Ymax = dsp + parent->GetSize(SIZE_DRECT_TOP);
 	if(use_yaxis && CurrAxes[use_yaxis]) {
-		memcpy(&y_axis, CurrAxes[use_yaxis]->axis, sizeof(AxisDEF));
-		if(y_axis.flags & AXIS_DEFRECT) {
-			y_axis.loc[0].fy += dsp;	y_axis.loc[1].fy += dsp;
-			}
+		o->UseAxis(CurrAxes[use_yaxis]->axis, CurrAxes[use_yaxis]->type & 0xf);
 		}
 	else use_yaxis = 0;
-	o->SetRect(CurrRect, o->units, &x_axis, &y_axis);
+	if(use_zaxis && CurrAxes[use_zaxis]) {
+		o->UseAxis(CurrAxes[use_zaxis]->axis, CurrAxes[use_zaxis]->type & 0xf);
+		}
+	else use_zaxis = 0;
+	return;
 }
 
 void
@@ -175,10 +159,13 @@ DataObj *
 Plot::CreaCumData(char *xr, char *yr, int mode, double base)
 {
 	char **yranges;
-	int i, j, nc, nr, ir, ic, n;
+	int i, j, nc, nr, ir, ic, n, c_num, c_txt, c_datetime;
 	double value, old_val;
 	DataObj *CumData = 0L;
-	AccRange *ax = 0L, *ay = 0L;
+	anyResult ares;
+	AccRange *ax = 0L, **ayy = 0L;
+	TextValue *tv = 0L;
+	bool *validRows;
 
 	if(!xr || !yr || !mode || !data) return 0L;
 	if(!(CumData = new DataObj()))return 0L;
@@ -186,44 +173,92 @@ Plot::CreaCumData(char *xr, char *yr, int mode, double base)
 	if(!(ax = new AccRange(xr))) {
 		delete CumData;		CumData = 0L;	return 0L;
 		}
-	for(nr = 0, ax->GetFirst(&ic, &ir); ax->GetNext(&ic, &ir); )
-		if(data->GetValue(ir, ic, &value))nr++;
+	ax->DataTypes(data, &c_num, &c_txt, &c_datetime);
+	nr = ax->CountItems();
 	if(!(yranges = split(yr, '&', &nc))){
 		delete CumData;		delete ax;		return 0L;
 		}
-	if(CumData->Init(mode == 1 || mode == 2 ? nr : nr * 2, nc+2)){
-		// set x values as first column
-		for(i = n = 0, ax->GetFirst(&ic, &ir); ax->GetNext(&ic, &ir); i++) {
-			if(data->GetValue(ir, ic, &value)){
-				CumData->SetValue(n, 0, value);			CumData->SetValue(n++, 1, base);
+	if(x_tv) x_tv->Reset();		if(y_tv) y_tv->Reset();
+	j = mode == 1 || mode == 2 ? nr : nr * 2;
+	if(CumData->Init(j , nc+2) && (validRows = (bool*)calloc(j, sizeof(bool)))){
+		if(!c_num && (c_txt + c_datetime) > 0 ) {
+			if(x_tv) tv = x_tv;
+			else if(y_tv) tv = y_tv;
+			else tv = x_tv = new TextValue();
+			}
+		//setup all ranges
+		if(!(ayy = (AccRange**)calloc(nc, sizeof(AccRange*))))return 0L;
+		for(i = 0; i < nc; i++) {
+			if(yranges[i] && *yranges[i] && (ayy[i] = new AccRange(yranges[i]))) {
+				if(!ayy[i]->GetFirst(&ic, &ir)) return 0L;
 				}
 			}
-		if(mode == 3 || mode == 4) for(i = 1; i <= nr; i++) {			//complete polygon data
-			if(CumData->GetValue(nr-i, 0, &value)) CumData->SetValue(i-1+nr, 0, value);
-			}
-		//process all y-ranges
-		for (j = 2; j <= (nc+1); j++) if(ay = new AccRange(yranges[j-2])){
-			for(i = n = 0; i < nr; i++) {
-				if(CumData->GetValue(n, j-1, &value)) CumData->SetValue(n++, j, value);
-				}
-			for(i = n = 0, ay->GetFirst(&ic, &ir); ay->GetNext(&ic, &ir) && n < nr; i++) {
-				if(data->GetValue(ir, ic, &value) && CumData->GetValue(n, j, &old_val)){
-					switch (mode) {
-					case 1:	case 3:	value += old_val;			break;
-					case 2:	case 4: value = old_val -value;		break;
+		// set x values as first column
+		for(i = n = 0, ax->GetFirst(&ic, &ir); ax->GetNext(&ic, &ir); i++, n++) {
+			if(data->GetResult(&ares, ir, ic, false)) {
+				if(tv) {
+					switch(ares.type) {
+					case ET_TEXT:
+						value = tv->GetValue(ares.text);			break;
+					default:
+						TranslateResult(&ares);
+						value = tv->GetValue(ares.text);			break;
 						}
-					CumData->SetValue(n++, j, value);
+					CumData->SetValue(n, 0, value);		CumData->SetValue(n, 1, base);
 					}
+				else if(ares.type == ET_VALUE && ares.value > -HUGE_VAL && ares.value < HUGE_VAL) {
+					CumData->SetValue(n, 0, value = ares.value);	CumData->SetValue(n, 1, base);
+					}
+				else {
+					CumData->SetValue(n, 0, value = 0.0);	CumData->SetValue(n, 1, base);
+					}
+				if(mode == 3 || mode == 4){				//complete polygon data
+					CumData->SetValue((nr<<1)-i-1, 0, value);
+					}
+				for(j = 0; j < nc; j++) {
+					if(CumData->GetValue(n, j+1, &value)) CumData->SetValue(n, j+2, value);
+					if(ayy[j]->GetNext(&ic, &ir) && data->GetResult(&ares, ir, ic, false)){
+						if(ares.type == ET_VALUE && ares.value > -HUGE_VAL && ares.value < HUGE_VAL){
+							value = ares.value;		validRows[i] = true;
+							}
+						else value = 0.0;			old_val = 0.0;
+						CumData->GetValue(n, j+2, &old_val);
+						switch (mode) {
+						case 1:	case 3:	value += old_val;			break;
+						case 2:	case 4: value = old_val -value;		break;
+							}
+						CumData->SetValue(n, j+2, value);
+						}
+					if(mode == 3 || mode == 4)			//complete polygon data
+						if(CumData->GetValue(n, j+1, &value)){
+							if(validRows[n]) validRows[(nr<<1)-i-1] = true;
+							CumData->SetValue((nr<<1)-i-1, j+2, value);
+							}
+					}
+				}
+			else {
+				for(j = 0; j < nc; j++) ayy[j]->GetNext(&ic, &ir);
 				}
-			if(mode == 3 || mode == 4) for(i = 1; i <= nr; i++) {		//complete polygon data
-				if(CumData->GetValue(nr-i, j-1, &value)) CumData->SetValue(i-1+nr, j, value);
+			}
+		for(i = 0; i < nc; i++) delete ayy[i];		free(ayy);
+		for(i = 0; i < CumData->cRows; i++) {
+			if(!validRows[i]) {
+				CumData->cRows--;
+				for(j = 0; j < CumData->cCols; j++) {
+					if(CumData->etRows[i][j]) delete CumData->etRows[i][j];
+					}
+				free(CumData->etRows[i]);
+				for(j = i; j < CumData->cRows; j++) {
+					CumData->etRows[j] = CumData->etRows[j+1];
+					validRows[j] = validRows[j+1];
+					}
+				if(!validRows[i] && i < CumData->cRows) i--;
 				}
-			delete ay;		ay = 0L;
 			}
+		free(validRows);
 		}
 	for(i = 0; i < nc; i++) if(yranges[i]) free(yranges[i]);
-	if(ax) delete ax;	if(ay) delete ay;
-	free(yranges);
+	if(ax) delete ax;		free(yranges);
 	return CumData;
 }
 
@@ -281,9 +316,12 @@ PlotScatt::PlotScatt(int src):Plot(0L, 0L)
 PlotScatt::~PlotScatt()
 {
 	ForEach(FE_FLUSH, 0L, 0L);
-	if(name) free(name);		name=0L;
-	if(x_info) free(x_info);	x_info = 0L;
-	if(y_info) free(x_info);	y_info = 0L;
+	if(name) free(name);			name=0L;
+	if(x_info) free(x_info);		x_info = 0L;
+	if(y_info) free(x_info);		y_info = 0L;
+	if(data_desc) free(data_desc);	data_desc = 0L;
+	if(x_tv) delete(x_tv);			x_tv = 0L;
+	if(y_tv) delete(y_tv);			y_tv = 0L;
 	Undo.InvalidGO(this);
 }
 
@@ -470,6 +508,14 @@ PlotScatt::Command(int cmd, void *tmpl, anyOutput *o)
 			data = (DataObj *)tmpl;	
 			}
 		ForEach(cmd, tmpl, o);
+		if(cmd == CMD_AUTOSCALE) {
+			if(x_tv) {
+				Bounds.Xmin = 0.5;		Bounds.Xmax = ((double)x_tv->Count())+0.5;
+				}
+			if(y_tv) {
+				Bounds.Ymin = 0.5;		Bounds.Xmax = ((double)y_tv->Count())+0.5;
+				}
+			}
 		if(cmd == CMD_AUTOSCALE && parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH
 			&& Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) {
 			((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
@@ -684,6 +730,7 @@ xyStat::~xyStat()
 	if(name) free(name);					name=0L;
 	if(x_info) free(x_info);				x_info = 0L;
 	if(y_info) free(x_info);				y_info = 0L;
+	if(x_tv) delete(x_tv);					x_tv = 0;
 	Undo.InvalidGO(this);
 }
 
@@ -720,10 +767,11 @@ xyStat::Command(int cmd, void *tmpl, anyOutput *o)
 void
 xyStat::CreateData()
 {
-	int i, j, k, l, m, n, *ny;
-	double x, y, ss, d, lo, hi, **ay, *ax, *tay, *q1, *q2, *q3;
+	int i, j, k, l, m, n, *ny, c_num, c_txt, c_dattim;
+	double y, ss, d, lo, hi, **ay, *ax, *tay, *q1, *q2, *q3;
 	lfPOINT *xy;
 	AccRange *rX, *rY;
+	anyResult x_res, y_res;
 
 	if(!data || !xRange || !yRange || !xRange[0] || !yRange[0]) return;
 	if(!(rX = new AccRange(xRange)) || !(rY = new AccRange(yRange))) return;
@@ -733,6 +781,7 @@ xyStat::CreateData()
 		delete rX;	delete rY;
 		return;
 		}
+	if(x_tv) delete x_tv;					x_tv = 0L;
 	ny = (int*) calloc(m, sizeof(int));
 	ay = (double**) calloc(m, sizeof(double*));
 	ax = (double*) calloc(m, sizeof(double));
@@ -743,12 +792,27 @@ xyStat::CreateData()
 		delete rX;	delete rY;
 		return;
 		}
-	rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);
+	rX->DataTypes(data, &c_num, &c_txt, &c_dattim);
+	if(c_num < 5 && (c_txt + c_dattim) > 5) {
+		x_tv = new TextValue();	
+		}
+	rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);	dirty = true;
 	rX->GetNext(&i, &j);	rY->GetNext(&k, &l);	n=0;
 	do {
-		if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
-			xy[n].fx = x;		xy[n].fy = y;
-			n++;
+		if(data->GetResult(&x_res, j, i, false) && data->GetResult(&y_res, l, k, false) && y_res.type == ET_VALUE) {
+			xy[n].fy = y_res.value;
+			if(x_tv){ 
+				switch(x_res.type) {
+				case ET_TEXT:
+					xy[n++].fx = x_tv->GetValue(x_res.text);
+					break;
+				case ET_VALUE:	case ET_BOOL:	case ET_DATE:	case ET_TIME:	case ET_DATETIME:
+					TranslateResult(&x_res);
+					xy[n++].fx = x_tv->GetValue(x_res.text);
+					break;
+					}
+				}
+			else if(x_res.type == ET_VALUE) xy[n++].fx = x_res.value;
 			}
 		}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
 	delete rX;			delete rY;
@@ -871,6 +935,20 @@ FreqDist::FreqDist(GraphObj *par, DataObj *d):Plot(par, d)
 	Id = GO_FREQDIST;
 }
 
+FreqDist::FreqDist(GraphObj *par, DataObj *d, char* range, bool bOnce):Plot(par, d)
+{
+	FileIO(INIT_VARS);
+	if(range && range[0]) {
+		ssRef = (char*)memdup(range, (int)strlen(range)+1, 0);
+		plots = (GraphObj**)calloc(nPlots=3, sizeof(GraphObj*));
+		ProcData(-1);
+		if(bOnce && ssRef) {
+			free(ssRef);		ssRef = 0L;
+			}
+		}
+	Id = GO_FREQDIST;
+}
+
 FreqDist::FreqDist(int src):Plot(0L, 0L)
 {
 	FileIO(INIT_VARS);
@@ -892,6 +970,7 @@ FreqDist::~FreqDist()
 	if(name) free(name);					name=0L;
 	if(x_info) free(x_info);				x_info = 0L;
 	if(y_info) free(y_info);				y_info = 0L;
+	if(x_tv) delete x_tv;					x_tv = 0L;
 }
 
 void
@@ -977,8 +1056,11 @@ FreqDist::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_AUTOSCALE:
 		if(hidden) return false;
 		if(dirty){
-			Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+			Bounds.Xmin = HUGE_VAL;		Bounds.Ymin = 0;
 			Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+			if(dmax > dmin) {
+				Bounds.Xmin = dmin;		Bounds.Xmax = dmax;
+				}
 			}
 		else{
 			if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH && 
@@ -1020,48 +1102,85 @@ void
 FreqDist::ProcData(int sel)
 {
 	AccRange *ar;
-	int nv, i, j, r, c, ncl, *f_data, cb_f, size_fo, pos_fo;
-	double dmin = HUGE_VAL, dmax = -HUGE_VAL, min, max, sum, mean, sd, tmp, *s_data, *t_data, lstep;
+	int nv, i, j, r, c, ncl, *f_data, cb_f, size_fo, pos_fo, c_num, c_txt, c_dattim;
+	double min, max, sum, mean, sd, tmp, *s_data, *t_data, lstep;
 	double chi2, df, x, y;
 	anyResult *result;
+	bool bValid = false;
 	Bar **bars = 0L;
+	anyResult res;
 	TextDEF td;
 	char *fo, *fdesc = 0L, formula[500];
 
 	if(!parent || !data || !ssRef || !plots) return;
-	if(curr_data) delete(curr_data);
+	if(curr_data) delete(curr_data);		curr_data = 0L;
+	if(x_tv) delete x_tv;					x_tv = 0L;
 	if((curr_data = new DataObj()) && (ar = new AccRange(ssRef))) {
+		if(!y_info && (y_info = (char*)malloc(25*sizeof(char)))) rlp_strcpy(y_info, 25, "No. of observations");
+		dmin = HUGE_VAL, dmax = -HUGE_VAL;
+		ar->DataTypes(data, &c_num, &c_txt, &c_dattim);
+		if(c_num < 5 && (c_txt + c_dattim) > 5) {
+			x_tv = new TextValue();		dmin = 0.0;
+			}
 		//copy spreadsheet data into array
 		nv = ar->CountItems();			ar->GetFirst(&c, &r);
 		if(!(s_data = (double*)malloc(nv * sizeof(double))) 
 			|| !(t_data = (double*)malloc(nv * sizeof(double)))) {
 			delete(ar);					return;
 			}
-		for(sum = 0.0, nv = 0; ar->GetNext(&c, &r); ) if(data->GetValue(r, c, &tmp)) {
-			if(tmp > dmax) dmax = tmp;	if(tmp < dmin) dmin = tmp;
-			s_data[nv] = tmp;
-			switch (type & 0xff){
-			case 2:
-				if(tmp > 0.0) t_data[nv] = log(tmp);
-				else nv--;
-				break;
-			default:	t_data[nv] = tmp;		break;
+		for(sum = 0.0, nv = 0; ar->GetNext(&c, &r); ) if(data->GetResult(&res, r, c, false)) {
+			if(x_tv){
+				switch(res.type) {
+				case ET_TEXT:
+					if((tmp = x_tv->GetValue(res.text))> 0.0)bValid = true;
+					else bValid = false;				break;
+				case ET_VALUE:	case ET_DATE:	case ET_TIME:	case ET_DATETIME:	case ET_BOOL:
+					TranslateResult(&res);
+					if((tmp = x_tv->GetValue(res.text))> 0.0)bValid = true;
+					else bValid = false;				break;
+				default: 
+					bValid = false;						break;
+					}
+				}
+			else {
+				if(res.type == ET_VALUE) {
+					tmp = res.value;		bValid = true;
+					}
+				else bValid = false;
+				}
+			if(bValid) {
+				if(tmp > dmax) dmax = tmp;	if(tmp < dmin) dmin = tmp;
+				s_data[nv] = tmp;
+				switch (type & 0xff){
+				case 2:
+					if(tmp > 0.0) t_data[nv] = log(tmp);
+					else nv--;
+					break;
+				default:	t_data[nv] = tmp;		break;
+					}
+				nv++;
 				}
-			nv++;
+			}
+		delete(ar);
+		if(!nv || dmin >= dmax) {
+			free(s_data);		s_data = 0L;		free(t_data);		t_data = 0L;
+			return;
 			}
 		min = dmin;		max = dmax;
 		lstep = (max-min)/100.0;
-		delete(ar);
 		d_variance(nv, t_data, &mean, &sd);
 		sd = sqrt(sd/((double)(nv-1)));
 		step = fabs(step);
-		if(sel == -1) {
+		if(x_tv) {
+			start = 0.5;	step = 1.0;		max+= 0.5;
+			}
+		else if(sel == -1) {
 			start = min;	step = (max - min)/(step != 0.0 ? step : 7.0);
 			}
 		else if(sel == -2) {
 			min = start;
 			}
-		ncl = (int)(floor((max-start)/step));
+		ncl = (int)(floor((max-start)/step))+1;
 		if(plots[0] &&	(max > (Bounds.Xmax+step/2.0) || min < (Bounds.Xmin-step/2.0))) {
 			DeleteGO(plots[0]);		plots[0] = 0L;
 			}
@@ -1091,6 +1210,7 @@ FreqDist::ProcData(int sel)
 			plots[0]->SetSize(SIZE_BAR_LINE, BarLine.width);
 			}
 		if(plots[0]){
+			Bounds.Xmin = dmin;		Bounds.Xmax = dmax;
 			plots[0]->Command(CMD_SET_DATAOBJ, curr_data, 0L);
 			plots[0]->Command(CMD_AUTOSCALE, 0L, 0L);
 			}
@@ -1915,8 +2035,12 @@ BoxPlot::~BoxPlot()
 	if(curr_data) delete curr_data;		curr_data = 0L;
 	if(xRange) free(xRange);			xRange = 0L;
 	if(yRange) free(yRange);			yRange = 0L;
+	if(x_info) free(x_info);			x_info = 0L;
+	if(y_info) free(y_info);			y_info = 0L;
 	if(case_prefix) free(case_prefix);	case_prefix = 0L;
-	if(name) free(name);				name=0L;
+	if(name) free(name);				name = 0L;
+	if(x_tv) delete(x_tv);				x_tv = 0;
+	if(y_tv) delete(y_tv);				y_tv = 0;
 	Undo.InvalidGO(this);
 }
 
@@ -2069,6 +2193,9 @@ BoxPlot::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		dirty = false;
 		ForEach(cmd, tmpl, o);
+		if(x_tv) {
+			Bounds.Xmin = 0.5;		Bounds.Xmax = ((double)x_tv->Count())+0.5;
+			}
 		if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH
 			&& Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin){
 			((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
@@ -2076,10 +2203,12 @@ BoxPlot::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		return true;
 	case CMD_UPDATE:
-		if(Boxes) SavVarObs((GraphObj **)Boxes, nPoints, UNDO_CONTINUE);
-		if(Whiskers) SavVarObs((GraphObj **)Whiskers, nPoints, UNDO_CONTINUE);
-		if(Symbols) SavVarObs((GraphObj **)Symbols, nPoints, UNDO_CONTINUE);
-		if(Labels) SavVarObs((GraphObj **)Labels, nPoints, UNDO_CONTINUE); 
+		if(parent) {
+			if(Boxes) SavVarObs((GraphObj **)Boxes, nPoints, UNDO_CONTINUE);
+			if(Whiskers) SavVarObs((GraphObj **)Whiskers, nPoints, UNDO_CONTINUE);
+			if(Symbols) SavVarObs((GraphObj **)Symbols, nPoints, UNDO_CONTINUE);
+			if(Labels) SavVarObs((GraphObj **)Labels, nPoints, UNDO_CONTINUE); 
+			}
 		if(type && xRange && yRange) {		//Stat. - Plot ?
 			CreateData();
 			ForEach(CMD_SET_DATAOBJ, curr_data, o);
@@ -2189,10 +2318,11 @@ BoxPlot::ForEach(int cmd, void *tmpl, anyOutput *o)
 void
 BoxPlot::CreateData()
 {
-	int i, j, k, l, m, n, *ny;
-	double x, y, ss, d, lo, hi, **ay, *ax, *tay, *q1, *q2, *q3;
+	int i, j, k, l, m, n, *ny, c_num, c_txt, c_dattim;
+	double y, ss, d, lo, hi, **ay, *ax, *tay, *q1, *q2, *q3;
 	lfPOINT *xy;
 	AccRange *rX, *rY;
+	anyResult x_res, y_res;
 
 	if(curr_data) delete curr_data;			curr_data = 0L;
 	if(!data || !xRange || !yRange || !xRange[0] || !yRange[0]) return;
@@ -2202,6 +2332,7 @@ BoxPlot::CreateData()
 		delete rX;	delete rY;
 		return;
 		}
+	if(x_tv) delete x_tv;					x_tv = 0L;
 	ny = (int*) calloc(m, sizeof(int));
 	ay = (double**) calloc(m, sizeof(double*));
 	ax = (double*) calloc(m, sizeof(double));
@@ -2212,12 +2343,27 @@ BoxPlot::CreateData()
 		delete rX;	delete rY;
 		return;
 		}
+	rX->DataTypes(data, &c_num, &c_txt, &c_dattim);
+	if(c_num < 5 && (c_txt + c_dattim) > 5) {
+		x_tv = new TextValue();	
+		}
 	rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);
 	rX->GetNext(&i, &j);	rY->GetNext(&k, &l);	n=0;
 	do {
-		if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
-			xy[n].fx = x;		xy[n].fy = y;
-			n++;
+		if(data->GetResult(&x_res, j, i, false) && data->GetResult(&y_res, l, k, false) && y_res.type == ET_VALUE) {
+			xy[n].fy = y_res.value;
+			if(x_tv){ 
+				switch(x_res.type) {
+				case ET_TEXT:
+					xy[n++].fx = x_tv->GetValue(x_res.text);
+					break;
+				case ET_VALUE:	case ET_BOOL:	case ET_DATE:	case ET_TIME:	case ET_DATETIME:
+					TranslateResult(&x_res);
+					xy[n++].fx = x_tv->GetValue(x_res.text);
+					break;
+					}
+				}
+			else if(x_res.type == ET_VALUE) xy[n++].fx = x_res.value;
 			}
 		}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
 	delete rX;			delete rY;
@@ -2629,6 +2775,8 @@ StackBar::~StackBar()
 	if(ssXrange) free(ssXrange);	if(ssYrange) free(ssYrange);
 	if(CumData) delete CumData;		CumData = 0L;
 	if(name) free(name);			name=0L;
+	if(x_tv) delete x_tv;			x_tv = 0L;
+	if(y_tv) delete y_tv;			y_tv = 0L;
 	Undo.InvalidGO(this);
 }
 
@@ -2777,9 +2925,7 @@ StackBar::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		if(cum_data_mode){
 			if(CumData) delete CumData;
-			CumData = CreaCumData(ssXrange, ssYrange, cum_data_mode, StartVal);
-			if(cmd == CMD_SET_DATAOBJ) tmpl = CumData;
-			if(cmd == CMD_UPDATE && CumData) {
+			if(CumData = CreaCumData(ssXrange, ssYrange, cum_data_mode, StartVal)) {
 				if(Polygons) for(i = 0; i < numPG; i++)
 					if(Polygons[i]) Polygons[i]->Command(CMD_SET_DATAOBJ, CumData, o);
 				if(Lines) for(i = 0; i < numPL; i++)
@@ -2790,6 +2936,7 @@ StackBar::Command(int cmd, void *tmpl, anyOutput *o)
 					if(Boxes[i]) Boxes[i]->Command(CMD_SET_DATAOBJ, CumData, o);
 				}
 			}
+		if(cmd == CMD_SET_DATAOBJ) tmpl = (void*) CumData;
 		if(Polygons) for(i = 0; i < numPG; i++)
 			if(Polygons[i]) Polygons[i]->Command(cmd, tmpl, o);
 		if(Lines) for(i = 0; i < numPL; i++)
@@ -3186,27 +3333,28 @@ Scatt3D::~Scatt3D()
 	Undo.InvalidGO(this);
 	if(Balls) {
 		for(i = 0; i < nBalls; i++) if(Balls[i]) DeleteGO(Balls[i]);
-		free(Balls);		Balls = 0L;
+		free(Balls);					Balls = 0L;
 		}
 	if(Columns) {
 		for(i = 0; i < nColumns; i++) if(Columns[i]) DeleteGO(Columns[i]);
-		free(Columns);		Columns = 0L;
+		free(Columns);					Columns = 0L;
 		}
 	if(DropLines) {
 		for(i = 0; i < nDropLines; i++) if(DropLines[i]) DeleteGO(DropLines[i]);
-		free(DropLines);	DropLines = 0L;
+		free(DropLines);				DropLines = 0L;
 		}
 	if(Arrows) {
 		for(i = 0; i < nArrows; i++) if(Arrows[i]) DeleteGO(Arrows[i]);
-		free(Arrows);		Arrows = 0L;
+		free(Arrows);					Arrows = 0L;
 		}
 	if(Line) {
-		DeleteGO(Line);		Line = 0L;
+		DeleteGO(Line);					Line = 0L;
 		}
 	if(rib) {
-		DeleteGO(rib);      rib = 0L;
+		DeleteGO(rib);					 rib = 0L;
 		}
-	if(name) free(name);	name=0L;
+	if(name) free(name);				name=0L;
+	if(data_desc) free(data_desc);		data_desc = 0L;
 }
 
 double
@@ -3269,8 +3417,10 @@ Scatt3D::DoPlot(anyOutput *o)
 	long i;
 	RECT rc;
 
-	if(!o) return;
+	if(!o || !parent) return;
+	if(use_xaxis || use_yaxis || use_zaxis) ApplyAxes(o);
 	o->GetSize(&rc);
+	parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
 	rDims.left = rc.right;			rDims.right = rc.left;
 	rDims.top = rc.bottom;			rDims.bottom = rc.top;
 	if(Balls) {
@@ -3319,6 +3469,7 @@ Scatt3D::DoPlot(anyOutput *o)
 		UpdateMinMaxRect(&rDims, rib->rDims.right, rib->rDims.top);
 		UpdateMinMaxRect(&rDims, rib->rDims.left, rib->rDims.bottom);
 		}
+	if(use_xaxis || use_yaxis || use_zaxis)parent->Command(CMD_AXIS, 0L, o);
 	dirty = false;
 }
 
@@ -3377,6 +3528,8 @@ Scatt3D::Command(int cmd, void *tmpl, anyOutput *o)
 		if(Arrows) for(i = 0; i < nArrows; i++)
 			if(Arrows[i]) Arrows[i]->Command(cmd, tmpl, o);
 		return true;
+	case CMD_USEAXIS:
+		return UseAxis(*((int*)tmpl));
 	case CMD_LEGEND:
 		if(!tmpl) return false;
 		if(Balls) {
@@ -3541,8 +3694,9 @@ Ribbon::~Ribbon()
 		for(i = 0; i < nPlanes; i++) if(planes[i]) DeleteGO(planes[i]);
 		free(planes);		planes = 0L;
 		}
-	if(values) free(values);	values = 0L;	nVal = 0;
-	if(name) free(name);		name=0L;
+	if(values) free(values);		values = 0L;	nVal = 0;
+	if(name) free(name);			name=0L;
+	if(data_desc) free(data_desc);	data_desc = 0L;
 }
 
 double
@@ -3698,6 +3852,7 @@ Ribbon::CreateObs()
 		if(!ssRefX || !ssRefY) return;
 		if(z_width == 0.0) z_width = 1.0;	if(relwidth == 0.0) relwidth = 0.6;
 		if((rX = new AccRange(ssRefX)) && (rY = new AccRange(ssRefY))) {
+			if(!data_desc) data_desc = rY->RangeDesc(data, 1);
 			tmp = relwidth*z_width/2.0;
 			if(!(values = (fPOINT3D*)calloc(i = rX->CountItems(), sizeof(fPOINT3D)))){
 				delete rX;	delete rY;	return;
@@ -3705,17 +3860,18 @@ Ribbon::CreateObs()
 			if(!(planes = (Plane3D**)calloc(i-1, sizeof(Plane3D*)))){
 				free(values);	values = 0L;	delete rX;	delete rY;	return;
 				}
-			for(i = 0, rX->GetFirst(&cx, &rx), rY->GetFirst(&cy, &ry);
+			for(i = j = 0, rX->GetFirst(&cx, &rx), rY->GetFirst(&cy, &ry);
 				rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry); i++) {
 				if(data->GetValue(rx, cx, &fx) && data->GetValue(ry, cy, &fy)) {
 					values[i].fx = fx;	values[i].fy = fy;	values[i].fz = z_value;
 					pg[3].fx = pg[2].fx = fx;	pg[3].fy = pg[2].fy = fy;
 					pg[2].fz = z_value - tmp;	pg[3].fz = z_value +tmp;
-					if(i) {
+					if(j) {
 						pg[4].fx = pg[0].fx;	pg[4].fy = pg[0].fy; pg[4].fz = pg[0].fz;
 						planes[i-1] = new Plane3D(this, data, pg, 5);
 						if(planes[i-1]) planes[i-1]->Command(CMD_PG_FILL, &Fill, 0L);
 						}
+					j++;
 					pg[0].fx = pg[3].fx;	pg[0].fy = pg[3].fy; pg[0].fz = pg[3].fz;
 					pg[1].fx = pg[2].fx;	pg[1].fy = pg[2].fy; pg[1].fz = pg[2].fz;
 					}
@@ -3732,6 +3888,7 @@ Ribbon::CreateObs()
 			if(!(planes = (Plane3D**)calloc(i-1, sizeof(Plane3D*)))){
 				free(values);	values = 0L;	delete rX;	delete rY;	delete rZ;	return;
 				}
+			if(!data_desc) data_desc = rY->RangeDesc(data, 1);
 			for(i = 0, rX->GetFirst(&cx, &rx), rY->GetFirst(&cy, &ry), rZ->GetFirst(&cz, &rz);
 				rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry) && rZ->GetNext(&cz, &rz); i++) {
 				if(data->GetValue(rx, cx, &fx) && data->GetValue(ry, cy, &fy) &&
@@ -4258,13 +4415,20 @@ Function::Update(anyOutput *o, DWORD flags)
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Calculate and display a user defined function
+static char *lastFunc2D = 0L, *lastParam2D=0L;
 FitFunc::FitFunc(GraphObj *par, DataObj *d):Plot(par, d)
 {
 	FileIO(INIT_VARS);
-	x1 = 0.0;			x2 = 100.0;				xstep = 0.5;	dl = 0L;
-	cmdxy = (char*)malloc(20*sizeof(char));		parxy = (char*)malloc(20*sizeof(char));
-	if(cmdxy) rlp_strcpy(cmdxy, 20, "a+b*x^c");
-	if(parxy) rlp_strcpy(parxy, 20, "a=1; b=1; c=0.1;");
+	x1 = 0.0;			x2 = 100.0;					xstep = 0.5;		dl = 0L;
+	if(lastFunc2D && lastFunc2D[0] && lastParam2D && lastParam2D[0]) {
+		cmdxy = (char*)memdup(lastFunc2D, (int)strlen(lastFunc2D)+1, 0);
+		parxy = (char*)memdup(lastParam2D, (int)strlen(lastParam2D)+1, 0);
+		}
+	if(!cmdxy || !parxy) {
+		cmdxy = (char*)malloc(20*sizeof(char));		parxy = (char*)malloc(20*sizeof(char));
+		if(cmdxy) rlp_strcpy(cmdxy, 20, "a+b*x^c");
+		if(parxy) rlp_strcpy(parxy, 20, "a=1; b=1; c=0.1;");
+		}
 	Id = GO_FITFUNC;
 }
 
@@ -4277,7 +4441,6 @@ FitFunc::FitFunc(int src):Plot(0L, 0L)
 		}
 }
 
-
 FitFunc::~FitFunc()
 {
 	int i;
@@ -4366,6 +4529,17 @@ FitFunc::Command(int cmd, void *tmpl, anyOutput *o)
 			return true;
 			}
 		return false;
+	case CMD_ENDDIALOG:
+		if(!cmdxy || !parxy) return false;
+		if(i = (int)strlen(cmdxy)) {
+			if(lastFunc2D = (char*)realloc(lastFunc2D, i+2))
+				rlp_strcpy(lastFunc2D, i+1, cmdxy);
+			}
+		if(i = (int)strlen(parxy)) {
+			if(lastParam2D = (char*)realloc(lastParam2D, i+2))
+				rlp_strcpy(lastParam2D, i+1, parxy);
+			}
+		return true;
 	case CMD_SCALE:
 		if(dl) return dl->Command(cmd, tmpl, o);
 		if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
@@ -4453,6 +4627,131 @@ FitFunc::Command(int cmd, void *tmpl, anyOutput *o)
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// normal quantile plot and derivates
+NormQuant::NormQuant(GraphObj *par, DataObj *d, char* range)
+	:Plot(par, d)
+{
+	FileIO(INIT_VARS);
+	if(range && range[0]) ssRef = (char*)memdup(range, (int)strlen(range)+1, 0);
+	else ssRef = 0L;
+	Id = GO_NORMQUANT;
+}
+
+NormQuant::NormQuant(GraphObj *par, DataObj *d, double *val, int nval)
+	:Plot(par, d)
+{
+	FileIO(INIT_VARS);		ssRef = 0L;
+	if(val && nval) {
+		src_data = (double*)memdup(val, nval*sizeof(double), 0);
+		SortArray(nData = nval, src_data);		ProcessData();
+		}
+	Id = GO_NORMQUANT;
+}
+
+NormQuant::NormQuant(int src):Plot(0L, 0L)
+{
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		if(nData)SortArray(nData, src_data);	ProcessData();
+		}
+}
+
+NormQuant::~NormQuant()
+{
+	if(ssRef) free(ssRef);		ssRef = 0L;
+	if(x_info) free(x_info);	x_info = 0L;
+	if(y_info) free(y_info);	y_info = 0L;
+	if(x_vals) free(x_vals);	x_vals = 0L;
+	if(y_vals) free(y_vals);	y_vals = 0L;
+	if(src_data)free(src_data);	src_data = 0L;
+	if(sy)delete(sy);
+}
+
+void
+NormQuant::DoPlot(anyOutput *o)
+{
+	int i;
+
+	//draw symbols
+	if(sy && y_vals && src_data && y_vals && nValidData) {
+		sy->SetSize(SIZE_SYMBOL, defs.GetSize(SIZE_SYMBOL)/10.0);
+		for(i = 0; i < nValidData; i++) {
+			sy->SetSize(SIZE_XPOS, x_vals[i]);
+			sy->SetSize(SIZE_YPOS, y_vals[i]);
+			sy->DoPlot(o);
+			}
+		}
+}
+
+bool
+NormQuant::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	switch(cmd) {
+	case CMD_LEGEND:
+		if(sy) ((Legend*)tmpl)->HasSym(0L, sy, x_info ? x_info : (char*)"Data");
+		return true;
+	case CMD_SCALE:
+		return true;
+	case CMD_UPDATE:
+		return true;
+	case CMD_REDRAW:
+		if(parent) return parent->Command(cmd, tmpl, o);
+		break;
+	case CMD_SET_DATAOBJ:
+		Id = GO_NORMQUANT;
+		if(sy) sy->Command(cmd, tmpl, o);
+		data = (DataObj *)tmpl;
+		return true;
+		}
+	return false;
+}
+
+bool
+NormQuant::ProcessData()
+{
+	int i, r, c, n;
+	AccRange *rD;
+	double y, dtmp, sum;
+
+	if(data && ssRef && ssRef[0] && (rD = new AccRange(ssRef))) {
+		if((n = rD->CountItems()) && (src_data = (double*)realloc(src_data, n * sizeof(double)))){
+			for(nData = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
+				if(data->GetValue(r, c, &dtmp)) src_data[nData++] = dtmp;
+				}
+			if(nData)SortArray(nData, src_data);
+			}
+		if(y_info = (char*)malloc(20)){
+			rlp_strcpy(y_info, 20, "Normal quantiles");
+			}
+		x_info = rD->RangeDesc(data, 2);
+		delete rD;
+		}
+	if(src_data && nData) {
+		Bounds.Ymin = HUGE_VAL;			Bounds.Ymax = -HUGE_VAL;
+		x_vals = (double*)realloc(x_vals, nData * sizeof(double));
+		y_vals = (double*)realloc(y_vals, nData * sizeof(double));
+		for(n = i = 0, sum = dtmp = 1.0/((double)nData); i < (nData-1); i++ ) {
+			y = distinv(norm_dist, 0.0, 1.0, sum, 0.5);
+			if(y > -HUGE_VAL && y < HUGE_VAL) {
+				y_vals[n] = y;			x_vals[n] = src_data[i];
+				if(y < Bounds.Ymin) Bounds.Ymin = y;
+				if(y > Bounds.Ymax) Bounds.Ymax = y;
+				n++;
+				}
+			sum += dtmp;
+			}
+		Bounds.Xmax = src_data[nData-1];	Bounds.Xmin = src_data[0];
+		if(Bounds.Ymax <= Bounds.Ymin) {
+			Bounds.Ymin = -5.0;		Bounds.Ymax = 5.0;
+			}
+		nValidData = n;
+		return (n > 3);
+		}
+	return false;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // three dimensional graph
 Plot3D::Plot3D(GraphObj *par, DataObj *d, DWORD flags):Plot(par, d)
 {
@@ -4493,6 +4792,8 @@ Plot3D::~Plot3D()
 		free(Axes);
 		}
 	plots = 0L;		nPlots = nAxes = 0;
+	if(nscp > 0 && nscp <= nPlots && Sc_Plots) free(Sc_Plots);
+	nscp = 0;			Sc_Plots = 0L;
 	if(drag) DeleteGO(drag);	drag = 0L;
 	if(dispObs) free(dispObs);	dispObs = 0L;
 	free(RotDef);
@@ -4572,17 +4873,28 @@ Plot3D::DoPlot(anyOutput *o)
 
 	nObs = 0;
 	if(!parent || !o) return;
-	o->MouseCursor(MC_WAIT, true);
+	if(nscp > 0 && nscp <= nPlots && Sc_Plots) free(Sc_Plots);
+	nscp = 0;			Sc_Plots = 0L;		o->MouseCursor(MC_WAIT, true);
 	if(dirty) DoAutoscale();
 	if(Axes && nAxes >2) {		//if no axes then parent is another Plot3D ...
-		o->LightSource(32.0, 16.0);
+		o->LightSource(32.0, 16.0);						CurrAxes = Axes;
 		cu1.fx = cub1.fx;		cu1.fy = cub1.fy;		cu1.fz = cub1.fz;
 		cu2.fx = cub2.fx;		cu2.fy = cub2.fy;		cu2.fz = cub2.fz;
 		rc.fx = rotC.fx;		rc.fy = rotC.fy;		rc.fz = rotC.fz;
 		o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
 			Axes[1]->GetAxis(), Axes[2]->GetAxis());
+		if(nAxes >3) {									//DEBUG
+			nAxes = nAxes;
+			}
 		for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->DoPlot(o);
 		}
+	else if(IsPlot3D(parent)) {
+		if (use_xaxis || use_yaxis || use_zaxis)ApplyAxes(o);
+		parent->Command(CMD_REG_AXISPLOT, (void*)this, o);
+		}
+	else {
+		CurrAxes = 0L;
+		}
 	if(plots) for(i = 0; i < nPlots; i++) if(plots[i]){
 		if(plots[i]->Id >= GO_PLOT && plots[i]->Id < GO_GRAPH) {
 			if(((Plot*)plots[i])->hidden == 0) plots[i]->DoPlot(o);
@@ -4620,6 +4932,7 @@ Plot3D::DoPlot(anyOutput *o)
 			}
 		for (i = 1; i <= nObs; i++)	dispObs[i]->go->Command(CMD_REDRAW, 0L, o);
 		}
+	if(IsPlot3D(parent) && (use_xaxis || use_yaxis || use_zaxis))parent->Command(CMD_AXIS, 0L, o);
 	dirty = false;
 	o->MouseCursor(MC_ARROW, true);
 }
@@ -4667,6 +4980,35 @@ Plot3D::Command(int cmd, void *tmpl, anyOutput *o)
 			return true;
 			}
 		break;
+	case CMD_USEAXIS:
+		if(IsPlot3D(parent)) return UseAxis(*((int*)tmpl));
+		break;
+	case CMD_REG_AXISPLOT:	//notification: plot can handle its own axes
+		if(nscp > 0 && nscp <= nPlots && Sc_Plots)  {
+			for(i = 0; i < nscp; i++)
+				if(Sc_Plots[i] == (GraphObj*)tmpl) return true;
+			if(tmpPlots = (GraphObj**)realloc(Sc_Plots, (nscp+1)*sizeof(GraphObj*))){
+				tmpPlots[nscp++] = (GraphObj *)tmpl;
+				Sc_Plots = tmpPlots;
+				}
+			else {		//memory allocation error
+				nscp = 0;
+				Sc_Plots = 0L;
+				}
+			}
+		else {
+			if(Sc_Plots = (GraphObj **)calloc(1, sizeof(GraphObj*))){
+				Sc_Plots[0] = (GraphObj *)tmpl;
+				nscp = 1;
+				}
+			else nscp = 0;
+			}
+		return true;
+	case CMD_AXIS:			//one of the plots has changed scaling: reset
+		CurrAxes = Axes;
+		if(o) o->SetSpace(&cu1, &cu2, defs.cUnits, RotDef, &rc, Axes[0]->GetAxis(),
+			Axes[1]->GetAxis(), Axes[2]->GetAxis());
+		return true;
 	case CMD_HIDE_MARK:
 		if(!tmpl) return false;
 		//do all axes
@@ -4707,10 +5049,12 @@ Plot3D::Command(int cmd, void *tmpl, anyOutput *o)
 		if(IsPlot3D(parent)) return parent->Command(cmd, tmpl, o);
 		return dirty = true;
 	case CMD_ADDAXIS:
-		InfoBox("Add axis to 3D graph:\n\nThis feature is not yet implemented!");
+		if(AddAxis()){
+			if(parent) return parent->Command(CMD_REDRAW, tmpl, o);
+			}
 		return false;
 	case CMD_SET_GO3D:
-		if(IsPlot3D(parent)) return parent->Command(cmd, tmpl, o);
+		if(IsPlot3D(parent)) return parent->Command(CMD_REDRAW, 0L, o);
 		return AcceptObj((GraphObj *)tmpl);
 	case CMD_SETSCROLL:				case CMD_REDRAW:
 		if(parent) return parent->Command(cmd, tmpl, o);
@@ -5324,13 +5668,20 @@ Func3D::Update()
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // fit 3D function to data
+static char *lastFunc3D = 0L, *lastParam3D=0L;
 FitFunc3D::FitFunc3D(GraphObj *par, DataObj *d)
 	:Plot3D(par, d, 0x0L)
 {
 	FileIO(INIT_VARS);
-	cmdxy = (char*)malloc(20*sizeof(char));		param = (char*)malloc(20*sizeof(char));
-	if(cmdxy) rlp_strcpy(cmdxy, 20, (char*)"a+b*x^c");
-	if(param) rlp_strcpy(param, 20, (char*)"a=1; b=1; c=0.1;");
+	if(lastFunc3D && lastFunc3D[0] && lastParam3D && lastParam3D[0]) {
+		cmdxy = (char*)memdup(lastFunc3D, (int)strlen(lastFunc3D)+1, 0);
+		param = (char*)memdup(lastParam3D, (int)strlen(lastParam3D)+1, 0);
+		}
+	if(!cmdxy || !param) {
+		cmdxy = (char*)malloc(20*sizeof(char));		param = (char*)malloc(20*sizeof(char));
+		if(cmdxy) rlp_strcpy(cmdxy, 20, (char*)"a+b*x^c");
+		if(param) rlp_strcpy(param, 20, (char*)"a=1; b=1; c=0.1;");
+		}
 	Id = GO_FITFUNC3D;
 }
 
@@ -5360,7 +5711,20 @@ FitFunc3D::~FitFunc3D()
 bool
 FitFunc3D::Command(int cmd, void *tmpl, anyOutput *o)
 {
+	int i;
+
 	switch(cmd) {
+	case CMD_ENDDIALOG:
+		if(!cmdxy || !param) return false;
+		if(i = (int)strlen(cmdxy)) {
+			if(lastFunc3D = (char*)realloc(lastFunc3D, i+2))
+				rlp_strcpy(lastFunc3D, i+1, cmdxy);
+			}
+		if(i = (int)strlen(param)) {
+			if(lastParam3D = (char*)realloc(lastParam3D, i+2))
+				rlp_strcpy(lastParam3D, i+1, param);
+			}
+		return true;
 	case CMD_SET_DATAOBJ:
 		Plot3D::Command(cmd, tmpl, o);
 		if(gob && gda) gob->Command(cmd, gda, o);
diff --git a/PropertyDlg.cpp b/PropertyDlg.cpp
index 68ceff3..65c8e0e 100755
--- a/PropertyDlg.cpp
+++ b/PropertyDlg.cpp
@@ -1,4 +1,4 @@
-//PropertyDlg.cpp, Copyright (c) 2001-2006 R.Lackner
+//PropertyDlg.cpp, Copyright (c) 2001-2007 R.Lackner
 //Property dialogs for graphic objects
 //
 //    This file is part of RLPlot.
@@ -658,7 +658,8 @@ static char *LineDlg_DlgTmpl =
 	"208,209,,EXRADIO,ODBUTTON,10,87,70,25,25\n"
 	"209,210,,EXRADIO,ODBUTTON,10,112,70,25,25\n"
 	"210,211,,EXRADIO,ODBUTTON,10,37,95,25,25\n"
-	"211,,,EXRADIO,ODBUTTON,10,62,95,25,25\n"
+	"211,212,,EXRADIO,ODBUTTON,10,62,95,25,25\n"
+	"212,,,EXRADIO,ODBUTTON,10,87,95,25,25\n"
 	"300,301,,,LTEXT,5,15,30,80,9\n"
 	"301,302,,,EDTEXT,7,15,40,119,10\n"
 	"302,303,,,LTEXT,6,15,55,80,9\n"
@@ -698,8 +699,8 @@ DataLine::PropertyDlg()
 		LoopDlgWnd();
 		res = Dlg->GetResult();
 		switch (res) {
-		case 201:	case 202:	case 203:	case 204:	case 205:
-		case 206:	case 207:	case 208:	case 209:	case 210:	case 211:
+		case 201:	case 202:	case 203:	case 204:	case 205:	case 206:
+		case 207:	case 208:	case 209:	case 210:	case 211:	case 212:
 			if((tmpType & 0x0f) == (res-201)) res = 1;
 			else {
 				tmpType &= ~0x0f;	tmpType |= (res-201);
@@ -711,16 +712,13 @@ DataLine::PropertyDlg()
 	if(res == 1){						//OK pressed
 		Undo.SetDisp(cdisp);
 		if(ssXref && ssYref) {
-			if(Dlg->GetText(301, TmpTxt, TMP_TXT_SIZE) && strcmp(ssXref, TmpTxt)) {
-				cb = Undo.String(this, &ssXref, undo_flags);	undo_flags |= UNDO_CONTINUE;
-				if(ssXref = (char*)realloc(ssXref, (cb+=2))) rlp_strcpy(ssXref, cb, TmpTxt);
-				}
-			if(Dlg->GetText(303, TmpTxt, TMP_TXT_SIZE) && strcmp(ssYref, TmpTxt)) {
-				cb = Undo.String(this, &ssYref, undo_flags);	undo_flags |= UNDO_CONTINUE;
-				if(ssYref = (char*)realloc(ssYref, (cb+=2))) rlp_strcpy(ssYref, cb, TmpTxt);
+			TmpTxt[0] = 0;		Dlg->GetText(301, TmpTxt, TMP_TXT_SIZE); 
+			undo_flags = CheckNewString(&ssXref, ssXref, TmpTxt, this, undo_flags);
+			TmpTxt[0] = 0;	Dlg->GetText(303, TmpTxt, TMP_TXT_SIZE);
+			undo_flags = CheckNewString(&ssYref, ssYref, TmpTxt, this, undo_flags);
+			if(undo_flags & UNDO_CONTINUE) {
+				Command(CMD_UPDATE, 0L, cdisp);			parent->Command(CMD_MRK_DIRTY, 0L, cdisp);
 				}
-			if(undo_flags & UNDO_CONTINUE) Command(CMD_UPDATE, 0L, cdisp);
-			parent->Command(CMD_MRK_DIRTY, 0L, cdisp);
 			}
 		OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
 		if(cmpLineDEF(&LineDef, &newLine)) {
@@ -1120,6 +1118,7 @@ ErrorBar::PropertyDlg()
 			Dlg->Activate(307, true);	res = -1;	break;
 		case 1:								//accept for this object
 		case 2:								//   or all objects of plot
+			desc[0] = 0;
 			Undo.SetDisp(cdisp);			Dlg->GetText(307, desc, 80);
 			Dlg->GetValue(101, &n_sb);		Dlg->GetValue(104, &n_lw);
 			Dlg->GetColor(107, &n_col);		Dlg->GetValue(305, &n_err);
@@ -1132,20 +1131,7 @@ ErrorBar::PropertyDlg()
 		undo_flags = CheckNewFloat(&ferr, o_err, n_err, parent, undo_flags);
 		undo_flags = CheckNewLFPoint(&fPos, &o_pos, &n_pos, parent, undo_flags);
 		if(undo_flags & UNDO_CONTINUE) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
-		if(desc[0] && name && name[0] && strcmp(desc, name)) {
-			cb = Undo.String(this, &name, undo_flags);
-			name = (char*)realloc(name, (cb+=2));
-			rlp_strcpy(name, cb, desc);		undo_flags |= UNDO_CONTINUE;
-			}
-		else if(desc[0] && !name) {
-			cb = Undo.String(this, &name, undo_flags);
-			name = (char*)realloc(name, (cb+=2));
-			rlp_strcpy(name, cb, desc);		undo_flags |= UNDO_CONTINUE;
-			}
-		else if(!desc[0] && name && name[0]) {
-			Undo.String(this, &name, undo_flags);
-			name[0] = 0;			undo_flags |= UNDO_CONTINUE;
-			}
+		undo_flags = CheckNewString(&name, name, desc, this, undo_flags);
 		undo_flags = CheckNewFloat(&SizeBar, o_sb, n_sb, parent, undo_flags);
 		undo_flags = CheckNewFloat(&ErrLine.width, o_lw, n_lw, parent, undo_flags);
 		undo_flags = CheckNewDword(&ErrLine.color, ErrLine.color, n_col, parent, undo_flags);
@@ -1538,26 +1524,13 @@ Whisker::PropertyDlg()
 		case 2:								//   or all objects of plot
 			Undo.SetDisp(cdisp);			Dlg->GetValue(101, &n_size);
 			Dlg->GetValue(104, &n_lw);		Dlg->GetColor(107, &n_col);
-			Dlg->GetText(309, desc, 80);
+			desc[0] = 0;					Dlg->GetText(309, desc, 80);
 			break;
 			}
 		}while (res <0);
 	switch (res) {
 	case 1:				//new setting for current whisker
-		if(desc[0] && name && name[0] && strcmp(desc, name)) {
-			cb = Undo.String(this, &name, undo_flags);
-			name = (char*)realloc(name, (cb+=2));
-			rlp_strcpy(name, cb, desc);		undo_flags |= UNDO_CONTINUE;
-			}
-		else if(desc[0]) {
-			cb = Undo.String(this, &name, undo_flags);
-			name = (char*)realloc(name, (cb+=2));
-			rlp_strcpy(name, cb, desc);		undo_flags |= UNDO_CONTINUE;
-			}
-		else if(name && name[0]) {
-			Undo.String(this, &name, undo_flags);
-			name[0] = 0;					undo_flags |= UNDO_CONTINUE;
-			}
+		undo_flags = CheckNewString(&name, name, desc, this, undo_flags);
 		if(Dlg->GetValue(301, &tmpVal)) n_pos.fx = tmpVal;
 		else n_pos.fx = pos1.fx;
 		if(Dlg->GetValue(303, &tmpVal)) n_pos.fy = tmpVal;
@@ -2361,7 +2334,7 @@ Label::PropertyDlg()
 		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 90, 15, 15}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int cb, res, i, c_style, c_font;
+	int res, i, c_style, c_font;
 	bool RetVal = false, check;
 	double tmp;
 	DWORD undo_flags = 0x0;
@@ -2532,12 +2505,7 @@ Label::PropertyDlg()
 			pa->Command(CMD_SAVE_TICKS, 0L, 0L);			undo_flags |= UNDO_CONTINUE;
 			}
 		TmpTxt[0] = 0;		Dlg->GetText(106, TmpTxt, TMP_TXT_SIZE);
-		if(res == 1 && TextDef.text && TextDef.text[0] && strcmp(TextDef.text, TmpTxt)) {
-			Undo.String(this, &TextDef.text, undo_flags);
-			undo_flags |= UNDO_CONTINUE;			cb = (int)strlen(TmpTxt);
-			TextDef.text = (char*)realloc(TextDef.text, (cb+=2));
-			rlp_strcpy(TextDef.text, cb, TmpTxt);
-			}
+		if(res == 1) undo_flags = CheckNewString(&TextDef.text, TextDef.text, TmpTxt, this, undo_flags);
 		if(cmpTextDEF(&OldTxtDef, &NewTxtDef)){
 			if(NewTxtDef.ColTxt != TextDef.ColTxt) bBGvalid = false;
 			if (pa) pa->Command(CMD_TLB_TXTDEF, &NewTxtDef, 0L);
@@ -3348,6 +3316,7 @@ PlotScatt::PropertyDlg()
 		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) xRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
 		if(Dlg->GetText(103, TmpTxt, TMP_TXT_SIZE)) yRange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
 		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
+		data_desc = rY->RangeDesc(data, 1);
 		//Create graphic objects
 		rX->GetFirst(&i, &j);	rY->GetFirst(&k, &l);
 		rX->GetNext(&i, &j);	rY->GetNext(&k, &l);
@@ -3523,14 +3492,9 @@ xyStat::PropertyDlg()
 			sprintf(text1, "a1:a%d", height);			sprintf(text2, "b1:b%d", height);
 #endif
 			Bounds.Xmin = Bounds.Ymin = HUGE_VAL;		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
-			for(i= 0; i < height; i++) {
-				if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 1, &y))
-					CheckBounds(x, y);
-				}
 			if(type & 0x0001) {
 				if(nPoints >1 && (TheLine = new DataLine(this, curr_data, text1, text2)) &&
 					(TheLine->name = (char*)malloc(cb_mdesc+2))) rlp_strcpy(TheLine->name, cb_mdesc+2, mdesc);
-
 				}
 			if((type & 0x0002) && (Symbols = (Symbol**)calloc(nPoints, sizeof(Symbol*)))) {
 				for(i = 0; i < height; i++) {
@@ -3609,6 +3573,7 @@ xyStat::PropertyDlg()
 						}
 					}
 				}
+			Command(CMD_AUTOSCALE, 0L, 0L);
 			bRet = true;
 			}
 		}
@@ -4344,6 +4309,7 @@ PolarPlot::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Box plot properties dialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static int boxplot_mode_sel = 52;
 bool
 BoxPlot::PropertyDlg()
 {
@@ -4353,9 +4319,9 @@ BoxPlot::PropertyDlg()
 		{10, 50, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
 		{50, 60, 51, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
 		{51, 52, 0, 0x0L, LTEXT, (void*)"Data Source:", 10, 12, 40, 9},
-		{52, 53, 0, CHECKED | TOUCHEXIT, RADIO2, (void*)" user values", 60, 12, 50, 9},
+		{52, 53, 0, TOUCHEXIT, RADIO2, (void*)" user values", 60, 12, 50, 9},
 		{53, 0, 0, TOUCHEXIT, RADIO2, (void*)" statistical data", 60, 22, 60, 9},
-		{60, 61, 100, HIDDEN | ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
+		{60, 61, 100, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
 		{61, 0, 200, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
 		{100, 102, 0, 0x0L, LTEXT, (void*)"range for grouping variable (X data)", 10, 39, 140, 9},
 		{102, 103, 0, 0x0L, RANGEINPUT, TmpTxt+100, 10, 49, 165, 10},
@@ -4428,6 +4394,13 @@ BoxPlot::PropertyDlg()
 	ci_box = ci_err = 95.0;
 	if(!(Dlg = new DlgRoot(PlotDlg, data)))return false;
 	TmpTxt[0] = TmpTxt[100] = 0;
+	//restore previous style
+	if(boxplot_mode_sel == 53) {
+		Dlg->ShowItem(61, false);			Dlg->SetCheck(53, 0L, true);
+		}
+	else {
+		Dlg->SetCheck(52, 0L, true);		Dlg->ShowItem(60, false);
+		}
 	hDlg = CreateDlgWnd("Box and Whisker Plot", 50, 50, 370, 550, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -4437,6 +4410,7 @@ BoxPlot::PropertyDlg()
 			if(Dlg->GetCheck(10)) res=-1;
 			break;
 		case 52:	case 53:
+			boxplot_mode_sel = res;
 			if(res == 53) {
 				Dlg->ShowItem(60, true);	Dlg->ShowItem(61, false);
 				}
@@ -4513,6 +4487,10 @@ BoxPlot::PropertyDlg()
 		else if(Dlg->GetText(102, TmpTxt+100, 50) && TmpTxt[100] && Dlg->GetText(104, TmpTxt+200, 50) && TmpTxt[200]){
 			xRange = (char*)memdup(TmpTxt+100, ((int)strlen(TmpTxt+100))+2, 0);
 			yRange = (char*)memdup(TmpTxt+200, ((int)strlen(TmpTxt+200))+2, 0);
+			if((rX = new AccRange(xRange)) && (rY1 = new AccRange(yRange))) {
+				x_info = rX->RangeDesc(data, 2);		y_info = rY1->RangeDesc(data, 2);
+				delete rX;		delete rY1;		rX = rY1 = 0L;
+				}
 			if(Dlg->GetCheck(154)) type |= 0x0001;		if(Dlg->GetCheck(155)) type |= 0x0002;
 			if(Dlg->GetCheck(156)) type |= 0x0003;		if(Dlg->GetCheck(157)) type |= 0x0004;
 			if(Dlg->GetCheck(161)) type |= 0x0010;		if(Dlg->GetCheck(162)) type |= 0x0020;
@@ -4744,80 +4722,6 @@ DensDisp::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // create stacked bar or stacked polygon 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-int com_StackDlg(int res, DlgRoot *Dlg, AccRange **rX, int *nx, char ***rd, int *currYR,
-	AccRange **rY, bool *bContinue, int *ny, int *maxYR, bool *updateYR)
-{
-	char **tmprd;
-
-	switch (res) {
-		case 1:
-			if(rX && nx && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0] && 
-				(*rX = new AccRange(TmpTxt))) *nx = rX[0]->CountItems();
-			else if(nx) *nx = 0;
-			if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
-				if(rd[0][*currYR]) free(rd[0][*currYR]);
-				rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
-				}
-			break;
-		case 155:
-			res = -1;
-			*ny = 0;
-			if(rX) {
-				if(!(*currYR) && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
-					if(*rX = new AccRange(TmpTxt)){
-						*nx = rX[0]->CountItems();
-						delete *rX;						*rX = 0L;
-						}
-					}
-				if(!(*nx)) {
-					ErrorBox("X-range is empty\nor not valid!\n\nEnter a valid range\n"
-						"for common x-values.");
-					*bContinue = true;
-					break;
-					}
-				}
-			if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
-				if(*rY = new AccRange(TmpTxt)){
-					*ny = rY[0]->CountItems();
-					delete *rY;
-					*rY = 0L;
-					}
-				}
-			if(!(*ny)) {
-				ErrorBox("Y-range is empty\nor not valid!\n\nEnter a valid range\n"
-					"for y-values with the same\nsize as the x-range.");
-				*bContinue = true;
-				break;
-				}
-			if((*currYR)+1 > *maxYR) {
-				tmprd = (char**)realloc(*rd, sizeof(char*)*((*currYR)+2));
-				if(tmprd) *rd = tmprd;
-				else break;
-				*maxYR = (*currYR)+1;
-				rd[0][*currYR] = 0L;
-				rd[0][(*currYR)+1] = 0L;
-				}
-			if(rd[0][*currYR]) free(rd[0][*currYR]);
-			rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);	//store y-ranges
-			*updateYR = true;
-			(*currYR)++;
-			Dlg->SetText(154, rd[0][*currYR]);
-			Dlg->Activate(154, true);
-			break;
-		case 156:
-			if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE)){
-				if(rd[0][*currYR]) free(rd[0][*currYR]);
-				rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);;
-				}
-			else if(*currYR == *maxYR) (*maxYR)--;
-			(*currYR)--;
-			Dlg->SetText(154, rd[0][*currYR]);
-			*updateYR = true;
-			res = -1;
-			break;
-		}
-	return res;
-}
 
 static char *StackBar_DlgTmpl =
 		"1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
@@ -4854,10 +4758,11 @@ StackBar::PropertyDlg()
 	DlgInfo *StackBarDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, sc, j, res, currYR = 0, maxYR = 0, nx = 0, ny;
+	int i, sc, j, res, currYR = 0, maxYR = 0, nx = 0, ny, c_num, c_txt, c_datetime;
 	bool updateYR = true, bContinue = false, bSub, bRet = false, bHor;
 	char **rd = 0L, *rname;
 	AccRange *rX = 0L, *rY = 0L;
+	TextValue *tv = 0L;
 
 	if(!parent || !data) return false;
 	if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
@@ -4915,8 +4820,14 @@ StackBar::PropertyDlg()
 			if(i) TmpTxt[j++] = '&';
 			j+= rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, rd[i]);
 			}
-		if(Dlg->GetCheck(204)) y_info = rX->RangeDesc(data, 0);
-		else x_info = rX->RangeDesc(data, 0);
+		rX->DataTypes(data, &c_num, &c_txt, &c_datetime);
+		if(!c_num && (c_txt + c_datetime) > 0 ) tv = new TextValue();
+		if(Dlg->GetCheck(204)) {
+			y_info = rX->RangeDesc(data, 3);	y_tv = tv;
+			}
+		else {
+			x_info = rX->RangeDesc(data, 3);	x_tv = tv;
+			}
 		ssYrange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+1, 0);
 		if(Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)) ssXrange = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+1, 0);;
 		cum_data_mode = Dlg->GetCheck(200) ? 1 : 2;
@@ -4929,9 +4840,10 @@ StackBar::PropertyDlg()
 			numPlots = maxYR;
 			if(Boxes = (BoxPlot**)calloc(numPlots, sizeof(BoxPlot*))) 
 				for(i = sc = 0; i < (maxYR) && rd[i] && *rd[i]; i++) {
-					rY = new AccRange(rd[i]);				rname = rY->RangeDesc(data, 1);
-					if(Boxes[i]= new BoxPlot(this, CumData, Dlg->GetCheck(204)? 2:1, 0, i+1, i+2, rname)){
-					Boxes[i]->Command(CMD_UPDATE, 0L, 0L);			Boxes[i]->Command(CMD_AUTOSCALE, 0L, 0L);
+					rY = new AccRange(rd[i]);				rname = rY->RangeDesc(data, 3);
+					if(Boxes[i]= new BoxPlot(0L, CumData, Dlg->GetCheck(204)? 2:1, 0, i+1, i+2, rname)){
+					Boxes[i]->Command(CMD_UPDATE, 0L, 0L);	Boxes[i]->parent = this;
+					Boxes[i]->Command(CMD_AUTOSCALE, 0L, 0L);
 					Boxes[i]->Command(CMD_BOX_FILL, GetSchemeFill(&sc), 0L);
 					Boxes[i]->SetSize(SIZE_BOX, 60.0);
 					if(rname) free(rname);	delete rY;	rY = 0L;
@@ -4953,7 +4865,7 @@ StackBar::PropertyDlg()
 #else
 				sprintf(TmpTxt+20, "%c1:%c%d", 'c'+i, 'c'+i, nx*2);
 #endif
-				rY = new AccRange(rd[i]);				rname = rY->RangeDesc(data, 1);
+				rY = new AccRange(rd[i]);				rname = rY->RangeDesc(data, 3);
 				if(Dlg->GetCheck(204)) Polygons[i]=new DataPolygon(this,CumData,TmpTxt+20,TmpTxt, rname);
 				else Polygons[i] = new DataPolygon(this, CumData, TmpTxt, TmpTxt+20, rname);
 				if(Polygons[i]) {
@@ -5271,7 +5183,8 @@ static char *MultiLineDlg_Tmpl =
 	"2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
 	"3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
 	"10,11,100,ISPARENT | CHECKED,SHEET,1,5,10,140,100\n"
-	"11,20,300,ISPARENT,SHEET,2,5,10,140,100\n"
+	"11,12,300,ISPARENT,SHEET,2,5,10,140,100\n"
+	"12,20,200,ISPARENT,SHEET,15,5,10,140,100\n"
 	"20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
 	"100,101,,ISPARENT | CHECKED,GROUPBOX,3,12,30,128,75\n"
 	"101,102,,,LTEXT,0,25,39,60,8\n"
@@ -5282,7 +5195,17 @@ static char *MultiLineDlg_Tmpl =
 	"106,107,,,PUSHBUTTON,-9,60,87,35,12\n"
 	"107,108,,OWNDIALOG,COLBUTT,4,25,87,20,12\n"
 	"108,,,,LTEXT,12,47,90,30,9\n"
-	"300,301,,TOUCHEXIT, RADIO1,13,20,35,80,9\n"
+	"200,201,,CHECKED,CHECKBOX,16,25,35,80,9\n"
+	"201,202,,,SYMBUTT,17,25,70,10,10\n"
+	"202,203,,,SYMBUTT,18,37,70,10,10\n"
+	"203,204,,,SYMBUTT,19,49,70,10,10\n"
+	"204,205,,,SYMBUTT,20,61,70,10,10\n"
+	"205,206,,,SYMBUTT,21,73,70,10,10\n"
+	"206,207,,,SYMBUTT,22,85,70,10,10\n"
+	"207,208,,,SYMBUTT,23,97,70,10,10\n"
+	"208,209,,,SYMBUTT,24,109,70,10,10\n"
+	"209,,,CHECKED,CHECKBOX,25,25,50,80,9\n"
+	"300,301,,TOUCHEXIT,RADIO1,13,20,35,80,9\n"
 	"301,302,,ODEXIT,COLBUTT,4,105,35,20,10\n"
 	"302,303,,CHECKED | TOUCHEXIT, RADIO1,14,20,55,80,9\n"
 	"303,304,,ODEXIT,COLBUTT,4,25,70,10,10\n"
@@ -5299,8 +5222,10 @@ MultiLines::PropertyDlg()
 {
 	TabSHEET tab1 = {0, 25, 10, "Data"};
 	TabSHEET tab2 = {25, 60, 10, "Scheme"};
+	TabSHEET tab3 = {60, 97, 10, "Symbols"};
 	static DWORD colarr[] = {0x00000000L, 0x00ff0000L, 0x0000ff00L, 0x000000ffL,
 		0x00ff00ff, 0x00ffff00L, 0x0000ffff, 0x00c0c0c0};
+	Symbol *syms[8], **lsyms;
 	static DWORD defcol = 0x0L;
 	char x_txt[100], y_txt[100];
 	DlgInfo *StackBarDlg;
@@ -5308,17 +5233,24 @@ MultiLines::PropertyDlg()
 		(void*)&colarr[0], (void*)&colarr[1], (void*)&colarr[2], (void*)&colarr[3],
 		(void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6], (void*)&colarr[7],
 		(void*)"line color", (void*)" common color for lines:", (void*)" increment color scheme:",
-		(void*)0x000000ff};
+		(void*) &tab3, (void*)" draw symbols", (void*)&syms[0], (void*)&syms[1], (void*)&syms[2],
+		(void*)&syms[3], (void*)&syms[4], (void*)&syms[5], (void*)&syms[6], (void*)&syms[7],
+		(void*) " use line color for symbols"};
 	DlgRoot *Dlg;
 	void *hDlg;
 	char **rdx=0L, **rdy=0L;
 	DWORD *rdc = 0L, curr_col;
-	int i, j, res, currYR=0, maxYR=0, s1, s2;
+	int i, j, nd, res, currYR=0, maxYR=0, s1, s2, rx, ry, cx, cy;
+	double symsize, x, y;
 	bool updateYR = true, bContinue = false, bError, bRet = false;
 	AccRange *rX = 0L, *rY = 0L;
 	DataLine *dl;
 
 	if(!parent || !data) return false;
+	symsize = NiceValue(defs.GetSize(SIZE_SYMBOL)*.8);
+	for(i = 0; i < 8; i++) if(syms[i] = new Symbol(0L, data, 0.0, 0.0, i)) {
+		if(i != 2 && i != 3)syms[i]->SetSize(SIZE_SYMBOL, symsize);
+		}
 	if(!(StackBarDlg = CompileDialog(MultiLineDlg_Tmpl, dyndata)))return false;
 	if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
 		TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return false;
@@ -5466,14 +5398,37 @@ MultiLines::PropertyDlg()
 		}while (res < 0);
 
 	if(res == 1 && rdx && rdy && maxYR) {
-		maxYR++;
+		maxYR++;		rX = rY = 0L;
 		if(xyPlots=(PlotScatt**)calloc(maxYR, sizeof(PlotScatt*))) for(i = numXY = 0; i < maxYR; i++){
 			if(rdx[i] && rdy[i] && rdx[i][0] && rdy[i][0]) {
+				if(Dlg->GetCheck(200) && (rX = new AccRange(rdx[i])) && (rY = new AccRange(rdy[i]))) {
+					lsyms = (Symbol**)calloc(rX->CountItems()+1, sizeof(Symbol*));
+					symsize = syms[i &0x07]->GetSize(SIZE_SYMBOL);
+					for(nd = 0, rX->GetFirst(&cx, &rx), rY->GetFirst(&cy, &ry); rX->GetNext(&cx, &rx), rY->GetNext(&cy, &ry); ) {
+						if(data->GetValue(rx, cx, &x) && data->GetValue(ry, cy, &y)) {
+							lsyms[nd] = new Symbol(0L, data, x, y, syms[i &0x07]->type, cx, rx, cy, ry);
+							if(Dlg->GetCheck(209)) lsyms[nd]->SetColor(COL_SYM_LINE, Dlg->GetCheck(300) ? defcol : rdc[i & 0x07]);
+							else {
+								lsyms[nd]->SetColor(COL_SYM_LINE, syms[i &0x07]->GetColor(COL_SYM_LINE));
+								lsyms[nd]->SetColor(COL_SYM_FILL, syms[i &0x07]->GetColor(COL_SYM_FILL));
+								}
+							lsyms[nd]->SetSize(SIZE_SYMBOL, symsize);
+							nd++;
+							}
+						}
+					}
+				else {
+					nd = 0;		lsyms = 0L;
+					}
 				if(dl = new DataLine(this, data, rdx[i], rdy[i])) {
-					dl->SetColor(COL_DATA_LINE, Dlg->GetCheck(300) ? defcol : rdc[i]);
-					if(xyPlots[numXY] = new PlotScatt(this, data, 0, 0L, dl)) numXY++;
+					dl->SetColor(COL_DATA_LINE, Dlg->GetCheck(300) ? defcol : rdc[i & 0xf]);
+					if(xyPlots[numXY] = new PlotScatt(this, data, nd, lsyms, dl)) {
+						if(rY) xyPlots[numXY]->data_desc = rY->RangeDesc(data, 1);
+						numXY++;
+						}
 					else delete dl;
 					}
+				if(rX)delete rX;		if(rY)delete rY;		rX = rY = 0L;
 				}
 			}
 		if(numXY) bRet = true;
@@ -5488,7 +5443,12 @@ MultiLines::PropertyDlg()
 		for (i = 0; i < maxYR; i++)	if(rdy[i]) free(rdy[i]);
 		free(rdy);
 		}
+	for(i = 0; i < 8; i++) if(syms[i]) delete syms[i];
 	free(StackBarDlg);		if(rdc) free(rdc);
+	if(bRet) {
+		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;	Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
+		Command(CMD_AUTOSCALE, 0L, 0L);
+		}
 	return bRet;
 }
 
@@ -6016,7 +5976,7 @@ Scatt3D::PropertyDlg()
 			if(Dlg->GetText(105, text3, 100) && (rZ = new AccRange(text3))) n3 = rZ->CountItems();
 			if(n1 && n2 && n3){
 				if(c_flags == 0x2000 || c_flags == 0x4000) {
-					//no more but a ribbon ore surface
+					//no more but a ribbon or surface
 					}
 				else if(n1 == n2 && n2 == n3) {
 					//o.k., three ranges of equal size have been defined
@@ -6107,7 +6067,7 @@ Function::PropertyDlg()
 		{3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
 		{4, 5, 100, ISPARENT, SHEET, &tab1, 5, 10, 149, 110},
 		{5, 0, 500, ISPARENT | CHECKED, SHEET, &tab2, 5, 10, 149, 110},
-		{10, 0, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
+		{10, 600, 0, 0x0L, CHECKPIN, 0L, 5, 0, 12, 8},
 		{100, 101, 0, 0x0L, LTEXT, (void*)"plot user defined function", 10, 24, 100, 8},
 		{101, 102, 0, 0x0L, RTEXT, (void*)"where x=", 10, 40, 28, 8}, 
 		{102, 103, 0, 0x0L, EDVAL1, &x1, 38, 40, 25, 10},
@@ -6117,7 +6077,11 @@ Function::PropertyDlg()
 		{106, 107, 0, 0x0L, EDVAL1, &xstep, 119, 40, 25, 10},
 		{107, 200, 0, 0x0L, RTEXT, (void*)"y=", 10, 56, 10, 8}, 
 		{200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 54, 122, 40},
-		{500, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 25, 130, 100}};
+		{500, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 25, 130, 100},
+		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 45, 15, 15},
+		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 60, 15, 15},
+		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 75, 15, 15},
+		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 170, 90, 15, 15}};
 	DlgRoot *Dlg;
 	void *hDlg;
 	int res, undo_level = *Undo.pcb;
@@ -6144,11 +6108,14 @@ Function::PropertyDlg()
 		case 0:
 			if(Dlg->GetCheck(10)) res = -1;
 			break;
+		case 600:	case 601:	case 602:	case 603:
+			Undo.SetDisp(cdisp);
+			res = ExecDrawOrderButt(parent, this, res);
 			}
 		}while (res < 0);
 	Undo.SetDisp(cdisp);
-	while(*Undo.pcb > undo_level)	Undo.Pop(cdisp);
-	if(res == 1){						//OK pressed
+	if(res == 2) while(*Undo.pcb > undo_level)	Undo.Restore(true, cdisp);
+	else if(res == 1){					//OK pressed
 		if(bNew) {						//create function
 			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
 			Dlg->GetValue(102, &x1);		Dlg->GetValue(104, &x2);
@@ -6162,15 +6129,10 @@ Function::PropertyDlg()
 			undo_flags = CheckNewFloat(&x1, o_x1, n_x1, this, undo_flags);
 			undo_flags = CheckNewFloat(&x2, o_x2, n_x2, this, undo_flags);
 			undo_flags = CheckNewFloat(&xstep, o_xstep, n_xstep, this, undo_flags);
-			Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE);
-			if(cmdxy && strcmp(cmdxy, TmpTxt)) {
-				Undo.String(this, &cmdxy, undo_flags);
-				free(cmdxy);				undo_flags |= UNDO_CONTINUE;
-				cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
-				}
+			if(Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE))
+				undo_flags = CheckNewString(&cmdxy, cmdxy, TmpTxt, this, undo_flags);
 			if(undo_flags & UNDO_CONTINUE){
-				Update(0L, UNDO_CONTINUE);
-				Command(CMD_MRK_DIRTY, 0L, 0L);
+				Update(0L, UNDO_CONTINUE);		Command(CMD_MRK_DIRTY, 0L, 0L);
 				}
 			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
 			if(cmpLineDEF(&Line, &newLine)) {
@@ -6180,8 +6142,7 @@ Function::PropertyDlg()
 			bRet = (undo_flags & UNDO_CONTINUE) != 0;
 			}
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;
 	return bRet;
 }
 
@@ -6309,6 +6270,7 @@ FitFunc::PropertyDlg()
 					}
 				Dlg->GetValue(153, &conv);	Dlg->GetValue(155, &iter);
 				ReshapeFormula(&parxy);		ReshapeFormula(&cmdxy);
+				do_formula(data, 0L);		//clear any error condition
 				ares = do_formula(data, parxy);
 				if(ares->type != ET_VALUE) {
 					ErrorBox("Syntax Error in parameters.");
@@ -6383,14 +6345,12 @@ FitFunc::PropertyDlg()
 				}
 			xstep = (x2 - x1)/100.0;
 			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
-			dl->SetSize(SIZE_MIN_X, x1);		dl->SetSize(SIZE_MAX_X, x2);
-			dl->SetSize(SIZE_XSTEP, xstep);		dl->Command(CMD_SETFUNC, cmdxy, 0L);
-			dl->Command(CMD_SETPARAM, parxy, 0L);
-			dl->Command(CMD_SET_LINE, &Line, 0L);
-			dl->Command(CMD_AUTOSCALE, 0L, 0L);
-			CheckBounds(dl->Bounds.Xmin, dl->Bounds.Ymin);
+			dl->SetSize(SIZE_MIN_X, x1);			dl->SetSize(SIZE_MAX_X, x2);
+			dl->SetSize(SIZE_XSTEP, xstep);			dl->Command(CMD_SETFUNC, cmdxy, 0L);
+			dl->Command(CMD_SETPARAM, parxy, 0L);	dl->Command(CMD_SET_LINE, &Line, 0L);
+			dl->Command(CMD_AUTOSCALE, 0L, 0L);		CheckBounds(dl->Bounds.Xmin, dl->Bounds.Ymin);
 			CheckBounds(dl->Bounds.Xmax, dl->Bounds.Ymax);
-			bRet = true;
+			Command(CMD_ENDDIALOG, 0L, 0L);			bRet = true;
 			}
 		else {							//edit existing function
 			Dlg->GetValue(502, &n_x1);		Dlg->GetValue(504, &n_x2);
@@ -6404,18 +6364,8 @@ FitFunc::PropertyDlg()
 				dl->Command(CMD_SETPARAM, parxy, 0L);	dl->Command(CMD_SET_LINE, &Line, 0L);
 				dl->Update(0L, UNDO_CONTINUE);
 				}
-			if(o_parxy && parxy && strcmp(o_parxy, parxy)) {
-				tmp_char = parxy;	parxy = o_parxy;
-				Undo.String(this, &parxy, undo_flags);
-				free(parxy);	parxy = tmp_char;	undo_flags |= UNDO_CONTINUE;
-				o_parxy = 0L;
-				}
-			if(o_cmdxy && cmdxy && strcmp(o_cmdxy, cmdxy)) {
-				tmp_char = cmdxy;	cmdxy = o_cmdxy;
-				Undo.String(this, &cmdxy, undo_flags);
-				free(cmdxy);	cmdxy = tmp_char;	undo_flags |= UNDO_CONTINUE;
-				o_cmdxy = 0L;
-				}
+			undo_flags = CheckNewString(&parxy, o_parxy, parxy, this, undo_flags);
+			undo_flags = CheckNewString(&cmdxy, o_cmdxy, cmdxy, this, undo_flags);
 			if(undo_flags & UNDO_CONTINUE) {
 				Undo.ValInt(parent, (int*)&dirty, undo_flags);
 				Command(CMD_MRK_DIRTY, 0L, 0L);
@@ -6426,6 +6376,7 @@ FitFunc::PropertyDlg()
 				memcpy(&Line, &newLine, sizeof(LineDEF));
 				}
 			bRet = (undo_flags & UNDO_CONTINUE) != 0;
+			Command(CMD_ENDDIALOG, 0L, 0L);
 			}
 		}
 	CloseDlgWnd(hDlg);
@@ -6435,8 +6386,373 @@ FitFunc::PropertyDlg()
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Create a new normal qualntile plot
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *NormQuantDlg_Tmpl = 
+	"1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
+	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+	"100,101,,,LTEXT,2,10,30,60,8\n"
+	"101,,,LASTOBJ,RANGEINPUT,-15,20,40,100,10";
+
+bool
+NormQuant::PropertyDlg()
+{
+	TabSHEET tab1 = {0, 25, 10, "Data"};
+	DlgInfo *QuantDlg;
+	void *dyndata[] = {(void*)&tab1, (void*)"range for variables"};
+	DlgRoot *Dlg;
+	void *hDlg;
+	int res;
+	char *mrk;
+	bool bContinue = false, bRet = false;
+
+	if(!parent || !data) return false;
+	if(!(QuantDlg = CompileDialog(NormQuantDlg_Tmpl, dyndata))) return false;
+	if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
+	else UseRangeMark(data, 1, TmpTxt);
+	if(!(Dlg = new DlgRoot(QuantDlg, data)))return false;
+	hDlg = CreateDlgWnd("Normal Quantiles Plot", 50, 50, 420, 220, Dlg, 0x0L);
+	do {
+		LoopDlgWnd();
+		res = Dlg->GetResult();
+		switch (res) {
+		case 0:
+			if(bContinue) res = -1;
+			else if(Dlg->GetCheck(10)) res = -1;
+			break;
+		case -1:
+			bContinue = false;
+			break;
+			}
+		}while (res < 0);
+	if(res == 1 && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE)){
+		ssRef = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
+		bRet = ProcessData();
+		}
+	CloseDlgWnd(hDlg);	delete Dlg;	free(QuantDlg);
+	return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Create a three dimensional graph
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *AddAxis3D_Tmpl =
+		"1,2,,DEFAULT, PUSHBUTTON,-1,148,10,45,12\n"
+		"2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+		"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"4,5,50,TOUCHEXIT | ISPARENT,SHEET,1,5,10,130,148\n"
+		"5,6,200,ISPARENT | CHECKED,SHEET,2,5,10,130,148\n"
+		"6,20,300,ISPARENT,SHEET,3,5,10,130,148\n"
+		"20,,,NOSELECT,ODBUTTON,22,142,65,45,45\n"
+		"50,51,100,ISPARENT | CHECKED,GROUPBOX,4,10,30,120,36\n"
+		"51,120,,,CHECKBOX,5,17,37,80,8\n"
+		"100,101,,,RTEXT,6,10,51,35,8\n"
+		"101,102,,,EDVAL1,7,48,51,32,10\n"
+		"102,103,,,CTEXT,8,81,51,11,8\n"
+		"103,,,,EDVAL1,9,93,51,32,10\n"
+		"120,,121,ISPARENT | CHECKED,GROUPBOX,10,10,72,120,20\n"
+		"121,122,,,RTEXT,11,10,77,25,8\n"
+		"122,123,,,EDVAL1,12,37,77,25,10\n"
+		"123,124,,,LTEXT,-3,63,77,10,8\n"
+		"124,125,,,RTEXT,-11,73,77,25,8\n"
+		"125,130,,OWNDIALOG,COLBUTT,14,100,77,25,10\n"
+		"130,131,,ISPARENT | CHECKED,GROUPBOX,15,10,98,120,20\n"
+		"131,,,,EDTEXT,0,15,103,110,10\n"
+		"200,201,,,LTEXT,16,10,23,70,9\n"
+		"201,202,,CHECKED | EXRADIO,ODBUTTON,17,20,35,25,25\n"
+		"202,203,,EXRADIO,ODBUTTON,17,45,35,25,25\n"
+		"203,204,,EXRADIO,ODBUTTON,17,70,35,25,25\n"
+		"204,205,,EXRADIO,ODBUTTON,17,95,35,25,25\n"
+		"205,206,,EXRADIO,ODBUTTON,17,20,60,25,25\n"
+		"206,207,,EXRADIO,ODBUTTON,17,45,60,25,25\n"
+		"207,208,,EXRADIO,ODBUTTON,17,70,60,25,25\n"
+		"208,209,,EXRADIO,ODBUTTON,17,95,60,25,25\n"
+		"209,210,,EXRADIO,ODBUTTON,17,20,85,25,25\n"
+		"210,211,,EXRADIO,ODBUTTON,17,45,85,25,25\n"
+		"211,212,,EXRADIO,ODBUTTON,17,70,85,25,25\n"
+		"212,213,,EXRADIO,ODBUTTON,17,95,85,25,25\n"
+		"213,214,,,LTEXT,-12,20,120,70,9\n"
+		"214,215,,,LTEXT,-13,20,132,70,9\n"
+		"215,216,,,LTEXT,-14,20,144,70,9\n"
+		"216,217,250,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"217,218,260,HIDDEN | ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"218,,270,HIDDEN |ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"250,251,,,LTEXT,19,10,110,70,9\n"
+		"251,252,,,EDVAL1,0,58,120,32,10\n"
+		"252,253,,,LTEXT,-3,92,120,20,9\n"
+		"253,254,,,EDVAL1,0,43,132,32,10\n"
+		"254,255,,,CTEXT,-7,75,132,7,9\n"
+		"255,256,,,EDVAL1,0,82,132,32,10\n"
+		"256,257,,,LTEXT,-3,116,132,20,9\n"
+		"257,268,,,EDVAL1,0,58,144,32,10\n"
+		"260,261,,,LTEXT,20,10,110,70,9\n"
+		"261,262,,,EDVAL1,0,43,120,32,10\n"
+		"262,263,,,CTEXT,-7,75,120,7,9\n"
+		"263,264,,,EDVAL1,0,82,120,32,10\n"
+		"264,265,,,LTEXT,-3,116,120,20,9\n"
+		"265,266,,,EDVAL1,0,58,132,32,10\n"
+		"266,267,,,LTEXT,-3,92,132,20,9\n"
+		"267,268,,,EDVAL1,0,58,144,32,10\n"
+		"268,,,,LTEXT,-3,92,144,20,9\n"
+		"270,271,,,LTEXT,21,10,110,70,9\n"
+		"271,272,,,EDVAL1,0,58,120,32,10\n"
+		"272,273,,,LTEXT,-3,92,120,20,9\n"
+		"273,274,,,EDVAL1,0,58,132,32,10\n"
+		"274,275,,,LTEXT,-3,92,132,20,9\n"
+		"275,276,,,EDVAL1,0,43,144,32,10\n"
+		"276,277,,,CTEXT,-7,75,144,7,9\n"
+		"277,278,,,EDVAL1,0,82,144,32,10\n"
+		"278,,,,LTEXT,-3,116,144,20,9\n"
+		"300,,,LASTOBJ | NOSELECT,ODBUTTON,18,15,30,110,140";
+bool
+Plot3D::AddAxis()
+{
+	TabSHEET tab1 = {0, 25, 10, "Axis"};
+	TabSHEET tab2 = {25, 52, 10, "Style"};
+	TabSHEET tab3 = {52, 78, 10, "Plots"};
+	AxisDEF axis, ax_def[12], *caxdef;
+	double sizAxLine = DefSize(SIZE_AXIS_LINE);
+	DWORD colAxis = 0x0;
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)" scaling ", (void*)" automatic scaling",
+		(void*)"axis from", (void*)&axis.min, (void*)"to", (void*)&axis.max, (void*)" line ", (void*)"width",
+		(void*)&sizAxLine, (void*)0L, (void *)&colAxis, (void*)" axis label ", (void*)"select a template:",
+		(void*)(OD_NewAxisTempl3D), (void*)OD_axisplot, (void*)"y-axis at:", (void*)"x-axis at:", (void*)"z-axis at:",
+		(void*)(OD_AxisDesc3D)};
+	DlgInfo *NewAxisDlg;
+	DlgRoot *Dlg;
+	void *hDlg;
+	int i, j, res, currTempl = 201, ax_type = 2, tick_type = 2;
+	double tlb_dx, tlb_dy, lb_x, lb_y;
+	TextDEF label_def, tlbdef;
+	anyOutput *cdisp = Undo.cdisp;
+	Axis *the_new, **tmpAxes;
+	bool bAxis = false, bRet = false;
+	char **names;
+	GraphObj **somePlots;
+	Label *label;
+
+	if(!Axes || nAxes < 3 || !(NewAxisDlg = CompileDialog(AddAxis3D_Tmpl, dyndata))) return false;
+	lb_y = 0.0;		lb_x = DefSize(SIZE_AXIS_TICKS)*4.0;
+	tlb_dy = 0.0;	tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
+	tlbdef.ColTxt = colAxis;				tlbdef.ColBg = 0x00ffffffL;
+	tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;	tlbdef.fSize = DefSize(SIZE_TICK_LABELS);
+	tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+	tlbdef.Style = TXS_NORMAL;				tlbdef.Mode = TXM_TRANSPARENT;
+	tlbdef.Font = FONT_HELVETICA;			tlbdef.text = 0L;
+	if(!(names = (char**)calloc(nscp+2, sizeof(char*))))return false;
+	if(!(somePlots = (GraphObj**)calloc(nscp+2, sizeof(GraphObj*))))return false;
+	for(i = 0; i < 12; i++) {
+		ax_def[i].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK;
+		ax_def[i].owner = 0L;		ax_def[i].breaks = 0L;
+		ax_def[i].Center.fx = ax_def[i].Center.fy = ax_def[i].Radius = 0.0;
+		ax_def[i].nBreaks = 0L;
+		}
+	//y-axes
+	ax_def[0].min = ax_def[1].min = ax_def[2].min = ax_def[3].min = (caxdef = Axes[1]->GetAxis())->min;
+	ax_def[0].max = ax_def[1].max = ax_def[2].max = ax_def[3].max = caxdef->max;
+	ax_def[0].Start = ax_def[1].Start = ax_def[2].Start = ax_def[3].Start = caxdef->Start;
+	ax_def[0].Step = ax_def[1].Step = ax_def[2].Step = ax_def[3].Step = caxdef->Step;
+	ax_def[0].loc[0].fy  = ax_def[1].loc[0].fy = ax_def[2].loc[0].fy = ax_def[3].loc[0].fy = caxdef->loc[0].fy;
+	ax_def[0].loc[1].fy  = ax_def[1].loc[1].fy = ax_def[2].loc[1].fy = ax_def[3].loc[1].fy = caxdef->loc[1].fy;
+	ax_def[0].loc[0].fx = ax_def[0].loc[1].fx = ax_def[3].loc[0].fx = ax_def[3].loc[1].fx = cu1.fx;
+	ax_def[1].loc[0].fx = ax_def[1].loc[1].fx = ax_def[2].loc[0].fx = ax_def[2].loc[1].fx = cu2.fx;
+	ax_def[0].loc[0].fz = ax_def[0].loc[1].fz = ax_def[1].loc[0].fz = ax_def[1].loc[1].fz = cu2.fz;
+	ax_def[2].loc[0].fz = ax_def[2].loc[1].fz = ax_def[3].loc[0].fz = ax_def[3].loc[1].fz = cu1.fz;
+	ax_def[1].flags = ax_def[2].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
+	ax_def[0].flags = ax_def[3].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
+	//x-axes
+	ax_def[4].min = ax_def[6].min = ax_def[8].min = ax_def[10].min = (caxdef = Axes[0]->GetAxis())->min;
+	ax_def[4].max = ax_def[6].max = ax_def[8].max = ax_def[10].max = caxdef->max;
+	ax_def[4].Start = ax_def[6].Start = ax_def[8].Start = ax_def[10].Start = caxdef->Start;
+	ax_def[4].Step = ax_def[6].Step = ax_def[8].Step = ax_def[10].Step = caxdef->Step;
+	ax_def[4].loc[0].fx  = ax_def[6].loc[0].fx = ax_def[8].loc[0].fx = ax_def[10].loc[0].fx = caxdef->loc[0].fx;
+	ax_def[4].loc[1].fx  = ax_def[6].loc[1].fx = ax_def[8].loc[1].fx = ax_def[10].loc[1].fx = caxdef->loc[1].fx;
+	ax_def[4].loc[0].fy = ax_def[4].loc[1].fy = ax_def[6].loc[0].fy = ax_def[6].loc[1].fy = cu1.fy;
+	ax_def[8].loc[0].fy = ax_def[8].loc[1].fy = ax_def[10].loc[0].fy = ax_def[10].loc[1].fy = cu2.fy;
+	ax_def[4].loc[0].fz = ax_def[4].loc[1].fz = ax_def[8].loc[0].fz = ax_def[8].loc[1].fz = cu2.fz;
+	ax_def[6].loc[0].fz = ax_def[6].loc[1].fz = ax_def[10].loc[0].fz = ax_def[10].loc[1].fz = cu1.fz;
+	ax_def[4].flags = ax_def[6].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
+	ax_def[8].flags = ax_def[10].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
+	//z-axes
+	ax_def[5].min = ax_def[7].min = ax_def[9].min = ax_def[11].min = (caxdef = Axes[2]->GetAxis())->min;
+	ax_def[5].max = ax_def[7].max = ax_def[9].max = ax_def[11].max = caxdef->max;
+	ax_def[5].Start = ax_def[7].Start = ax_def[9].Start = ax_def[11].Start = caxdef->Start;
+	ax_def[5].Step = ax_def[7].Step = ax_def[9].Step = ax_def[11].Step = caxdef->Step;
+	ax_def[5].loc[0].fz  = ax_def[7].loc[0].fz = ax_def[9].loc[0].fz = ax_def[11].loc[0].fz = caxdef->loc[0].fz;
+	ax_def[5].loc[1].fz  = ax_def[7].loc[1].fz = ax_def[9].loc[1].fz = ax_def[11].loc[1].fz = caxdef->loc[1].fz;
+	ax_def[5].loc[0].fx = ax_def[5].loc[1].fx = ax_def[9].loc[0].fx = ax_def[9].loc[1].fx = cu2.fx;
+	ax_def[7].loc[0].fx = ax_def[7].loc[1].fx = ax_def[11].loc[0].fx = ax_def[11].loc[1].fx = cu1.fx;
+	ax_def[5].loc[0].fy = ax_def[5].loc[1].fy = ax_def[7].loc[0].fy = ax_def[7].loc[1].fy = cu1.fy;
+	ax_def[9].loc[0].fy = ax_def[9].loc[1].fy = ax_def[11].loc[0].fy = ax_def[11].loc[1].fy = cu2.fy;
+	ax_def[5].flags = ax_def[9].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_POSTICKS;
+	ax_def[7].flags = ax_def[11].flags = AXIS_3D | AXIS_DEFRECT | AXIS_AUTOTICK | AXIS_NEGTICKS;
+	//the default axis is the first
+	memcpy(&axis, &ax_def[0], sizeof(AxisDEF));
+	if(names[0] = (char*)malloc(10)) rlp_strcpy(names[0], 10, "[none]");
+	for(i = 0, j = 1; i < nscp; i++) {
+		if(Sc_Plots[i] && Sc_Plots[i]->name){
+			names[j] = (char*)memdup(Sc_Plots[i]->name, (int)strlen(Sc_Plots[i]->name)+1, 0);
+			somePlots[j++] = Sc_Plots[i];
+			}
+		}
+	OD_axisplot(OD_ACCEPT, 0L, 0L, 0L, names, 0);
+	if(!(Dlg = new DlgRoot(NewAxisDlg, data)))return false;
+	Dlg->SetValue(251, ax_def[0].loc[0].fx);		Dlg->SetValue(253, ax_def[0].loc[0].fy);
+	Dlg->SetValue(255, ax_def[0].loc[1].fy);		Dlg->SetValue(257, ax_def[0].loc[0].fz);
+	if(!nscp){						//must be root plot3d to link to plot
+		Dlg->ShowItem(6, false);
+		}
+	hDlg = CreateDlgWnd("Add Axis to 3D Plot", 50, 50, 400, 360, Dlg, 0x0L);
+	do{
+		LoopDlgWnd();
+		res = Dlg->GetResult();
+		switch (res){
+		case 4:											//the axis sheet
+			res = -1;
+			bAxis = true;
+			break;
+		//axis templates
+		case 201:	case 202:	case 203:	case 204:	case 205:	case 206:
+		case 207:	case 208:	case 209:	case 210:	case 211:	case 212:
+			i = currTempl-201;
+			switch(currTempl){
+				case 201:	case 202:	case 203:	case 204:		//prevoius is y-template
+					Dlg->GetValue(251, &axis.loc[0].fx);	Dlg->GetValue(253, &axis.loc[0].fy);
+					Dlg->GetValue(255, &axis.loc[1].fy);	Dlg->GetValue(257, &axis.loc[0].fz);
+					axis.loc[1].fx = axis.loc[0].fx;		axis.loc[1].fz = axis.loc[0].fz;
+					memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
+					break;
+				case 205:	case 207:	case 209:	case 211:		//prevoius is x-template
+					Dlg->GetValue(261, &axis.loc[0].fx);	Dlg->GetValue(263, &axis.loc[1].fx);
+					Dlg->GetValue(265, &axis.loc[0].fy);	Dlg->GetValue(267, &axis.loc[0].fz);
+					axis.loc[1].fy = axis.loc[0].fy;		axis.loc[1].fz = axis.loc[0].fz;
+					memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
+					break;
+				case 206:	case 208:	case 210:	case 212:		//previous is z-template
+					Dlg->GetValue(271, &axis.loc[0].fx);	Dlg->GetValue(273, &axis.loc[0].fy);
+					Dlg->GetValue(275, &axis.loc[0].fz);	Dlg->GetValue(277, &axis.loc[1].fz);
+					axis.loc[1].fx = axis.loc[0].fx;		axis.loc[1].fy = axis.loc[0].fy;
+					memcpy(&ax_def[i], &axis, sizeof(AxisDEF));
+					break;
+				}
+			i = res-201;
+			switch (res) {
+			case 201:	case 202:	case 203:	case 204:			//y-template
+				Dlg->ShowItem(216, true);		Dlg->ShowItem(217, false);
+				Dlg->ShowItem(218, false);
+				Dlg->SetValue(251, ax_def[i].loc[0].fx);	Dlg->SetValue(253, ax_def[i].loc[0].fy);
+				Dlg->SetValue(255, ax_def[i].loc[1].fy);	Dlg->SetValue(257, ax_def[i].loc[0].fz);
+				ax_type = tick_type = 2;	tlb_dy = 0.0;
+				if(res == 202 || res == 203){
+					tlb_dx = DefSize(SIZE_AXIS_TICKS)*2.0;
+					tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
+					}
+				else {
+					tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
+					tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+					}
+				break;
+			case 205:	case 207:	case 209:	case 211:			//x-template
+				Dlg->ShowItem(216, false);		Dlg->ShowItem(217, true);
+				Dlg->ShowItem(218, false);
+				Dlg->SetValue(261, ax_def[i].loc[0].fx);	Dlg->SetValue(263, ax_def[i].loc[1].fx);
+				Dlg->SetValue(265, ax_def[i].loc[0].fy);	Dlg->SetValue(267, ax_def[i].loc[0].fz);
+				ax_type = 1;	tick_type = 3; tlb_dx = 0;
+				if(res == 205 || res == 207){
+					tlb_dy = DefSize(SIZE_AXIS_TICKS)*2.0;
+					tlbdef.Align = TXA_VTOP | TXA_HCENTER;
+					}
+				else {
+					tlb_dy = -DefSize(SIZE_AXIS_TICKS)*2.0;
+					tlbdef.Align = TXA_VBOTTOM | TXA_HCENTER;
+					}
+				break;
+			case 206:	case 208:	case 210:	case 212:			//z-template
+				Dlg->ShowItem(216, false);		Dlg->ShowItem(217, false);
+				Dlg->ShowItem(218, true);
+				Dlg->SetValue(271, ax_def[i].loc[0].fx);	Dlg->SetValue(273, ax_def[i].loc[0].fy);
+				Dlg->SetValue(275, ax_def[i].loc[0].fz);	Dlg->SetValue(277, ax_def[i].loc[1].fz);
+				ax_type = 3;	tick_type = 2;	tlb_dy = 0;
+				if(res == 206 || res == 210){
+					tlb_dx = DefSize(SIZE_AXIS_TICKS)*2.0;
+					tlbdef.Align = TXA_VCENTER | TXA_HLEFT;
+					}
+				else {
+					tlb_dx = -DefSize(SIZE_AXIS_TICKS)*2.0;
+					tlbdef.Align = TXA_VCENTER | TXA_HRIGHT;
+					}
+				break;
+				}
+			memcpy(&axis, &ax_def[res-201], sizeof(AxisDEF));
+			currTempl = res;
+			Dlg->DoPlot(0L);
+			res = -1;
+			break;
+			}
+		}while (res < 0);
+	if(res == 1) {
+		Undo.SetDisp(cdisp);
+		Dlg->GetValue(122, &sizAxLine);				Dlg->GetColor(125, &colAxis);
+		Dlg->GetValue(101, &axis.min);				Dlg->GetValue(103, &axis.max);
+		axis.Start = axis.min;						axis.Center.fx = axis.Center.fy = 0.0;
+		axis.nBreaks = 0;			axis.breaks = 0L;		axis.Radius = 0.0;	
+		tlbdef.ColTxt =	colAxis;
+		label_def.ColTxt = colAxis;					label_def.ColBg = 0x00ffffffL;
+		label_def.fSize = DefSize(SIZE_TICK_LABELS)*1.2f;	label_def.RotBL = 0.0f;
+		label_def.RotCHAR = 0.0f;								label_def.iSize = 0;
+		label_def.Align = TXA_VTOP | TXA_HCENTER;		label_def.Mode = TXM_TRANSPARENT;
+		label_def.Style = TXS_NORMAL;	label_def.Font = FONT_HELVETICA;
+		if(Dlg->GetCheck(51)) axis.flags |= AXIS_AUTOSCALE;
+		if(the_new = new Axis(this, data, &axis, axis.flags)){
+			the_new->SetSize(SIZE_TLB_YDIST, tlb_dy);	the_new->SetSize(SIZE_TLB_XDIST, tlb_dx); 
+			the_new->SetSize(SIZE_AXIS_LINE, sizAxLine);
+			the_new->SetColor(COL_AXIS, colAxis);
+			the_new->Command(CMD_TLB_TXTDEF, (void*)&tlbdef, 0L);
+			the_new->SetSize(SIZE_LB_XDIST, lb_x);		the_new->SetSize(SIZE_LB_YDIST, lb_y);
+			the_new->type = ax_type;
+			the_new->Command(CMD_TICK_TYPE, &tick_type, 0L);
+			if(Dlg->GetText(131, TmpTxt, TMP_TXT_SIZE)) label_def.text = TmpTxt;
+			else label_def.text = 0L;
+			if(label = new Label(Axes[0], data, (axis.loc[0].fx + axis.loc[1].fx)/2.0,
+				(axis.loc[0].fy + axis.loc[1].fy)/2.0, &label_def, 
+				label_def.RotBL < 45.0 ? LB_Y_PARENT : LB_X_PARENT)){
+				label->SetSize(SIZE_LB_XDIST, lb_x);	label->SetSize(SIZE_LB_YDIST, lb_y); 
+				if(the_new->Command(CMD_DROP_LABEL, (void*)label, 0L)) label = 0L;
+				else DeleteGO(label);
+				}
+			for(i = 0; i < nAxes && Axes[i]; i++);
+			if(i < nAxes) {
+				Undo.SetGO(this, (GraphObj**)(&Axes[i]), the_new, 0L);
+				bRet = true;
+				}
+			else {
+				if(tmpAxes = (Axis**)calloc(nAxes+1, sizeof(Axis*))){
+					memcpy(tmpAxes, Axes, nAxes * sizeof(Axis*));
+					Undo.ListGOmoved((GraphObj**)Axes, (GraphObj**)tmpAxes, nAxes);
+					Undo.SetGO(this, (GraphObj**)(&tmpAxes[nAxes]), the_new, 0L);
+					free(Axes);			Axes = tmpAxes;
+					i = nAxes++;		bRet = true;
+					}
+				}
+			CurrAxes = Axes;
+			if(bRet) {
+				OD_axisplot(OD_ACCEPT, 0L, 0L, (anyOutput*) &res, 0L, 0);
+				if(res && i) somePlots[res]->Command(CMD_USEAXIS, &i, 0L);
+				}
+			}
+		}
+	CloseDlgWnd(hDlg);		delete Dlg;			free(NewAxisDlg);
+	if(names) {
+		for(j = 0; names[j]; j++) if(names[j]) free(names[j]);
+		free(names);
+		}
+	if(somePlots) free(somePlots);
+	return bRet;
+}
+
 static char *AddPlot3Dtmpl =
 		"1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
 		"2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
@@ -6536,17 +6852,17 @@ static char *Base25D_DlgTmpl =
 		"202,203,,,EDVAL1,9,65,45,25,10\n"
 		"203,204,,,RTEXT,10,48,57,13,8\n"
 		"204,,,,EDVAL1,11,65,57,25,10\n"
-		"300,301,,CHECKED, RADIO1,12,15,35,80,9\n"
-		"301,302,,OWNDIALOG | TOUCHEXIT,COLBUTT,13,110,35,20,10\n"
-		"302,303,,,RADIO1,14,15,55,80,9\n"
-		"303,304,,OWNDIALOG | TOUCHEXIT,COLBUTT,15,25,70,10,10\n"
-		"304,305,,OWNDIALOG | TOUCHEXIT,COLBUTT,16,37,70,10,10\n"
-		"305,306,,OWNDIALOG | TOUCHEXIT,COLBUTT,17,49,70,10,10\n"
-		"306,307,,OWNDIALOG | TOUCHEXIT,COLBUTT,18,61,70,10,10\n"
-		"307,308,,OWNDIALOG | TOUCHEXIT,COLBUTT,19,73,70,10,10\n"
-		"308,309,,OWNDIALOG | TOUCHEXIT,COLBUTT,20,85,70,10,10\n"
-		"309,310,,OWNDIALOG | TOUCHEXIT,COLBUTT,21,97,70,10,10\n"
-		"310,,,LASTOBJ | OWNDIALOG | TOUCHEXIT,COLBUTT,22,109,70,10,10";
+		"300,301,,,RADIO1,12,15,35,80,9\n"
+		"301,302,,ODEXIT,COLBUTT,13,110,35,20,10\n"
+		"302,303,,CHECKED,RADIO1,14,15,55,80,9\n"
+		"303,304,,ODEXIT,COLBUTT,15,25,70,10,10\n"
+		"304,305,,ODEXIT,COLBUTT,16,37,70,10,10\n"
+		"305,306,,ODEXIT,COLBUTT,17,49,70,10,10\n"
+		"306,307,,ODEXIT,COLBUTT,18,61,70,10,10\n"
+		"307,308,,ODEXIT,COLBUTT,19,73,70,10,10\n"
+		"308,309,,ODEXIT,COLBUTT,20,85,70,10,10\n"
+		"309,310,,ODEXIT,COLBUTT,21,97,70,10,10\n"
+		"310,,,LASTOBJ | ODEXIT,COLBUTT,22,109,70,10,10";
 bool
 Chart25D::PropertyDlg()
 {
@@ -6672,12 +6988,15 @@ Chart25D::PropertyDlg()
 							}while(rX->GetNext(&cx, &rx) && rY->GetNext(&cy, &ry));
 						if(ic) bRet = true;
 						}
-					delete(rY);		rY = 0L;
 					if(plot = new Scatt3D(this, data, cols, ic)){
 						if(bUseSch) plot->SetColor(COL_BAR_FILL, colarr[(i & 0x07)]);
 						else plot->SetColor(COL_BAR_FILL, defcol);
 						plots[nPlots++] = plot;
 						}
+					if(rY) {
+						plot->data_desc = rY->RangeDesc(data, 1);
+						delete(rY);		rY = 0L;
+						}
 					}
 				}
 			}
@@ -7046,12 +7365,8 @@ Func3D::PropertyDlg()
 			undo_flags = CheckNewFloat(&x1, o_x1, n_x1, this, undo_flags);
 			undo_flags = CheckNewFloat(&x2, o_x2, n_x2, this, undo_flags);
 			undo_flags = CheckNewFloat(&xstep, o_xstep, n_xstep, this, undo_flags);
-			Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE);
-			if(cmdxy && strcmp(cmdxy, TmpTxt)) {
-				Undo.String(this, &cmdxy, undo_flags);
-				if(cmdxy) free(cmdxy);		cmdxy = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
-				undo_flags |= UNDO_CONTINUE;
-				}
+			TmpTxt[0] = 0;	Dlg->GetText(200, TmpTxt, TMP_TXT_SIZE);
+			undo_flags = CheckNewString(&cmdxy, cmdxy, TmpTxt, this, undo_flags);
 //			if(undo_flags & UNDO_CONTINUE) Update(0L, UNDO_CONTINUE);
 			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
 			if(cmpLineDEF(&Line, &newLine)) {
@@ -7221,6 +7536,7 @@ FitFunc3D::PropertyDlg()
 					}
 				Dlg->GetValue(153, &conv);	Dlg->GetValue(155, &iter);
 				ReshapeFormula(&param);		ReshapeFormula(&cmdxy);
+				do_formula(data, 0L);		//clear any error condition
 				ares = do_formula(data, param);
 				if(ares->type != ET_VALUE) {
 					ErrorBox("Syntax Error in parameters.");
@@ -7312,6 +7628,7 @@ FitFunc3D::PropertyDlg()
 					}
 				else free(Balls);
 				}
+			if(bRet)Command(CMD_ENDDIALOG, 0L, 0L);
 			}
 		else {							//edit existing function
 			Dlg->GetValue(102, &x1);		Dlg->GetValue(104, &x2);
@@ -7577,11 +7894,8 @@ Tick::PropertyDlg()
 		if(label && label->Id == GO_LABEL) {
 			td = ((Label*)label)->GetTextDef();
 			if(!Dlg->GetText(203, TmpTxt, TMP_TXT_SIZE)) TmpTxt[0] = 0;
-			if(td->text && strcmp(td->text, TmpTxt)) {
-				Undo.String(this, &td->text, undo_flags);
-				undo_flags |= UNDO_CONTINUE;
+			if(undo_flags = CheckNewString(&td->text, td->text, TmpTxt, this, undo_flags))
 				label->Command(CMD_SETTEXT, TmpTxt, 0L);
-				}
 			}
 		if (undo_flags & UNDO_CONTINUE) bRet = true;
 		}
@@ -7818,6 +8132,20 @@ Axis::PropertyDlg()
 				}
 			}
 		}
+	else if(IsPlot3D(parent) && (res=((Plot3D*)parent)->nscp)){
+		scp = ((Plot3D*)parent)->Sc_Plots;
+		CurrAxes = ((Plot3D*)parent)->Axes;
+		if(!scp || !(names = (char**)calloc(res+2, sizeof(char*))) ||
+			!(somePlots = (GraphObj**)calloc(res+2, sizeof(GraphObj*))))
+			return false;
+		if(names[0] = (char*)malloc(15 * sizeof(char))) rlp_strcpy(names[0], 15, "[unchanged]");
+		for(i = 0, j = 1; i < res; i++) {
+			if(scp[i] && scp[i]->name){
+				names[j] = (char*)memdup(scp[i]->name, (int)strlen(scp[i]->name)+1, 0);
+				somePlots[j++] = scp[i];
+				}
+			}
+		}
 	else {
 		names = (char**)calloc(2, sizeof(char*));	names[0] = (char*)malloc(10*sizeof(char));
 		rlp_strcpy(names[0], 10, "n.a.");
@@ -7928,7 +8256,7 @@ Axis::PropertyDlg()
 	memcpy(&new_a, &old_a, sizeof(AxisDEF));
 	i = rlp_strcpy(TmpTxt, TMP_TXT_SIZE, type_txt);
 	rlp_strcpy(TmpTxt+i, TMP_TXT_SIZE-i, "xis properties");
-	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 436, 384, Dlg, 0x0L);
+	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 436, 390, Dlg, 0x0L);
 	switch(axis->flags & 0x70) {
 		case AXIS_LEFT: 
 		case AXIS_RIGHT:
@@ -8134,11 +8462,22 @@ Axis::PropertyDlg()
 		else if(Dlg->GetCheck(106)) new_a.flags |= AXIS_RIGHT;
 		else if(Dlg->GetCheck(107)) new_a.flags |= AXIS_TOP;
 		else if(Dlg->GetCheck(108)) new_a.flags |= AXIS_BOTTOM;
+		if((new_a.flags & AXIS_LOG)== AXIS_LOG && new_a.min < defs.min4log) {
+			switch(type & 0x0f) {
+			case 1:
+				new_a.min = parent->GetSize(SIZE_BOUNDS_XMIN);	break;
+			case 2:
+				new_a.min = parent->GetSize(SIZE_BOUNDS_YMIN);	break;
+			case 3:
+				new_a.min = parent->GetSize(SIZE_BOUNDS_ZMIN);	break;
+				}
+			}
 		if(cmpAxisDEF(&old_a, &new_a)) {
 			bChanged = true;
 			if(axis->flags != new_a.flags) parent->Command(CMD_MRK_DIRTY, 0L, 0L);
 			Undo.AxisDef(this, axis, undo_flags);
 			memcpy(axis, &new_a, sizeof(AxisDEF));	undo_flags |= UNDO_CONTINUE;
+			axis->Start = axis->min;
 			}
 		else if(new_a.breaks) free(new_a.breaks);
 		if(axis->nBreaks && Dlg->GetValue(406, &tmp))
@@ -8175,10 +8514,7 @@ Axis::PropertyDlg()
 		if(Dlg->GetText(131, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
 			if(old_Label && strcmp(old_Label,TmpTxt) && axisLabel->Id == GO_LABEL){
 				lb_def = ((Label*)axisLabel)->GetTextDef();
-				Undo.String(axisLabel, &lb_def->text, undo_flags);
-				if(lb_def->text) free(lb_def->text);
-				lb_def->text = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);
-				undo_flags |= UNDO_CONTINUE;
+				undo_flags = CheckNewString(&lb_def->text, old_Label, TmpTxt, this, undo_flags);
 				}
 			else if(!axisLabel) {
 				label_def.ColTxt = colAxis;				label_def.ColBg = 0x00ffffffL;
@@ -8335,7 +8671,7 @@ static char *GraphDlgTmpl =
 		"6,7,300,ISPARENT,SHEET,3,5,10,157,122\n"
 		"100,101,,,LTEXT,4,10,25,60,8\n"
 		"101,102,500,TOUCHEXIT | ISPARENT,SHEET,5,10,37,147,90\n"
-		"102,103,520,TOUCHEXIT | ISPARENT | CHECKED,SHEET,6,10,37,147,90\n"
+		"102,103,520,TOUCHEXIT | ISPARENT,SHEET,6,10,37,147,90\n"
 		"103,104,540,TOUCHEXIT | ISPARENT,SHEET,7,10,37,147,90\n"
 		"104,,560,TOUCHEXIT | ISPARENT,SHEET,8,10,37,147,90\n"
 		"200,201,,,LTEXT,9,10,35,60,8\n"
@@ -8362,7 +8698,7 @@ static char *GraphDlgTmpl =
 		"221,,,,LTEXT,-3,140,108,20,8\n"
 		"300,301,,,LTEXT,23,20,30,60,8\n"
 		"301,400,310,CHECKED | ISPARENT,GROUP,0,0,0,0,0\n"
-		"310,311,,TOUCHEXIT | CHECKED | ISRADIO,ODBUTTON,24,20,42,25,25\n"
+		"310,311,,EXRADIO,ODBUTTON,24,20,42,25,25\n"
 		"311,312,,EXRADIO,ODBUTTON,24,45,42,25,25\n"
 		"312,313,,EXRADIO,ODBUTTON,24,70,42,25,25\n"
 		"313,314,,EXRADIO,ODBUTTON,24,95,42,25,25\n"
@@ -8376,13 +8712,14 @@ static char *GraphDlgTmpl =
 		"410,411,,EXRADIO,ODBUTTON,30,20,42,25,25\n"
 		"411,412,,EXRADIO,ODBUTTON,30,45,42,25,25\n"
 		"412,,,EXRADIO, ODBUTTON,30,70,42,25,25\n"
-		"500,501,,EXRADIO | CHECKED,ODBUTTON,31,25,60,25,25\n"
+		"500,501,,EXRADIO,ODBUTTON,31,25,60,25,25\n"
 		"501,502,,EXRADIO,ODBUTTON,31,50,60,25,25\n"
 		"502,503,,EXRADIO,ODBUTTON,31,75,60,25,25\n"
 		"503,504,,EXRADIO,ODBUTTON,31,25,85,25,25\n"
 		"504,505,,EXRADIO,ODBUTTON,31,50,85,25,25\n"
-		"505,,,EXRADIO, ODBUTTON,31,75,85,25,25\n"
-		"520,521,,EXRADIO | CHECKED,ODBUTTON, 31, 20,50,25,25\n"
+		"505,506,,EXRADIO, ODBUTTON,31,75,85,25,25\n"
+		"506,,,EXRADIO, ODBUTTON,31,100,85,25,25\n"
+		"520,521,,EXRADIO,ODBUTTON, 31, 20,50,25,25\n"
 		"521,522,,EXRADIO,ODBUTTON,31,45,50,25,25\n"
 		"522,523,,EXRADIO,ODBUTTON,31,70,50,25,25\n"
 		"523,524,,EXRADIO,ODBUTTON,31,95,50,25,25\n"
@@ -8395,12 +8732,12 @@ static char *GraphDlgTmpl =
 		"530,531,,EXRADIO,ODBUTTON,31,20,100,25,25\n"
 		"531,532,,EXRADIO,ODBUTTON,31,45,100,25,25\n"
 		"532,,,EXRADIO,ODBUTTON,31,70,100,25,25\n"
-		"540,541,,EXRADIO | CHECKED,ODBUTTON,31,20,60,25,25\n"
+		"540,541,,EXRADIO,ODBUTTON,31,20,60,25,25\n"
 		"541,542,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
 		"542,543,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
 		"543,544,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
 		"544,,,TOUCHEXIT | ISRADIO,ODBUTTON, 31, 120,60,25,25\n"
-		"560,561,,EXRADIO | CHECKED,ODBUTTON, 31,20,60,25,25\n"
+		"560,561,,EXRADIO,ODBUTTON, 31,20,60,25,25\n"
 		"561,562,,EXRADIO,ODBUTTON,31,45,60,25,25\n"
 		"562,563,,EXRADIO,ODBUTTON,31,70,60,25,25\n"
 		"563,564,,EXRADIO,ODBUTTON,31,95,60,25,25\n"
@@ -8409,6 +8746,7 @@ static char *GraphDlgTmpl =
 		"566,567,,EXRADIO,ODBUTTON,31,45,85,25,25\n"
 		"567,,,LASTOBJ | EXRADIO, ODBUTTON, 31, 70,85,25,25";
 
+static int selSheet = 102, selPlt = 520, selAxis = 310;
 bool
 Graph::PropertyDlg()
 {
@@ -8431,7 +8769,7 @@ Graph::PropertyDlg()
 	DlgRoot *Dlg;
 	GraphObj *p;
 	void *hDlg;
-	int i, res, selPlt = 520, selAxis = 310;
+	int i, res;
 	bool bRet, bContinue;
 	fRECT rc1, rc2;
 
@@ -8443,6 +8781,36 @@ Graph::PropertyDlg()
 	if(parent->Id != GO_PAGE) {
 		Dlg->Activate(202, false);	Dlg->Activate(204, false);
 		}
+	//restore previous settitings
+	switch(selSheet) {
+		case 101:
+			if(selPlt >= 500 && selPlt <=506) Dlg->SetCheck(selPlt, 0L, true);
+			else Dlg->SetCheck(500, 0L, true);
+			Dlg->SetCheck(520, 0L, true);		Dlg->SetCheck(540, 0L, true);
+			Dlg->SetCheck(560, 0L, true);		break;
+		default:
+			if(selPlt >= 520 && selPlt <=532) Dlg->SetCheck(selPlt, 0L, true);
+			else Dlg->SetCheck(520, 0L, true);	selSheet = 102;
+			Dlg->SetCheck(500, 0L, true);		Dlg->SetCheck(540, 0L, true);
+			Dlg->SetCheck(560, 0L, true);		break;
+		case 103:
+			if(selPlt >= 540 && selPlt <=544) Dlg->SetCheck(selPlt, 0L, true);
+			else Dlg->SetCheck(540, 0L, true);
+			Dlg->SetCheck(520, 0L, true);		Dlg->SetCheck(500, 0L, true);
+			Dlg->SetCheck(560, 0L, true);		break;
+		case 104:
+			if(selPlt >= 560 && selPlt <=567) Dlg->SetCheck(selPlt, 0L, true);
+			else Dlg->SetCheck(560, 0L, true);
+			Dlg->ShowItem(301, false);	Dlg->ShowItem(400, true);
+			Dlg->SetCheck(520, 0L, true);		Dlg->SetCheck(540, 0L, true);
+			Dlg->SetCheck(500, 0L, true);		break;
+		}
+	Dlg->SetCheck(selSheet, 0L, true);
+	if(selAxis >= 310 && selAxis <= 314) Dlg->SetCheck(selAxis, 0L, true);
+	else Dlg->SetCheck(310, 0L, true);
+	if(selAxis >= 410 && selAxis <= 412) Dlg->SetCheck(selAxis, 0L, true);
+	else Dlg->SetCheck(410, 0L, true);
+	//display the dialog
 	hDlg = CreateDlgWnd("Create graph", 50, 50, 450, 300, Dlg, 0x0L);
 	bContinue = false;
 	do{
@@ -8457,24 +8825,24 @@ Graph::PropertyDlg()
 			bContinue = false;
 			break;
 		case 101:	//only y data
-			for(i = 500; i <= 505; i++) if(Dlg->GetCheck(i))selPlt = i;
+			for(i = 500; i <= 506; i++) if(Dlg->GetCheck(i))selPlt = i;
 			Dlg->ShowItem(301, true);	Dlg->ShowItem(400, false);
-			res = -1;
+			selSheet = res;				res = -1;
 			break;
 		case 102:	//xy data
 			for(i = 520; i <= 532; i++) if(Dlg->GetCheck(i))selPlt = i;
 			Dlg->ShowItem(301, true);	Dlg->ShowItem(400, false);
-			res = -1;
+			selSheet = res;				res = -1;
 			break;
 		case 103:	//x many y data
 			for(i = 540; i <= 544; i++) if(Dlg->GetCheck(i))selPlt = i;
 			Dlg->ShowItem(301, true);	Dlg->ShowItem(400, false);
-			res = -1;
+			selSheet = res;				res = -1;
 			break;
 		case 104:	//xyz data
 			for(i = 560; i <= 567; i++) if(Dlg->GetCheck(i))selPlt = i;
 			Dlg->ShowItem(301, false);	Dlg->ShowItem(400, true);
-			res = -1;
+			selSheet = res;				res = -1;
 			break;
 		case 310:	case 311:	case 312:	case 313:	case 314:
 			AxisTempl = res-310;
@@ -8497,7 +8865,7 @@ Graph::PropertyDlg()
 			res = -1;
 			break;
 		case 500:	case 501:	case 502:	case 503:
-		case 504:	case 505:
+		case 504:	case 505:	case 506:
 		case 520:	case 521:	case 522:	case 523:
 		case 524:	case 525:	case 526:	case 527:
 		case 528:	case 529:	case 530:	case 531:	case 532:
@@ -8554,6 +8922,7 @@ Graph::PropertyDlg()
 				else if(Dlg->GetCheck(503))p = new BarChart(this, data);
 				else if(Dlg->GetCheck(504))p = new GroupBars(this, data);
 				else if(Dlg->GetCheck(505))p = new FreqDist(this, data);
+				else if(Dlg->GetCheck(506))p = new NormQuant(this, data, 0L);
 				}
 			else if(Dlg->GetCheck(102)){
 				if(Dlg->GetCheck(524)) p = new BubblePlot(this, data);
@@ -8777,47 +9146,47 @@ Graph::Configure()
 }
 
 static char *AddAxisTmpl =
-		"1,2,,DEFAULT, PUSHBUTTON,-1,148,10,45,12\n"
-		"2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
-		"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
-		"4,5,50,TOUCHEXIT | ISPARENT,SHEET,1,5,10,130,130\n"
-		"5,6,200,ISPARENT | CHECKED,SHEET,2,5,10,130,130\n"
-		"6,,300,ISPARENT,SHEET,3,5,10,130,130\n"
-		"50,51,100,ISPARENT | CHECKED,GROUPBOX,4,10,30,120,36\n"
-		"51,120,,,CHECKBOX,5,17,37,80,8\n"
-		"100,101,,,RTEXT,6,10,51,35,8\n"
-		"101,102,,,EDVAL1,7,48,51,32,10\n"
-		"102,103,,,CTEXT,8,81,51,11,8\n"
-		"103,,,,EDVAL1,9,93,51,32,10\n"
-		"120,,121,ISPARENT | CHECKED,GROUPBOX,10,10,72,120,20\n"
-		"121,122,,,RTEXT,11,10,77,25,8\n"
-		"122,123,,,EDVAL1,12,37,77,25,10\n"
-		"123,124,,,LTEXT,-3,63,77,10,8\n"
-		"124,125,,,RTEXT,13,73,77,25,8\n"
-		"125,130,,OWNDIALOG,COLBUTT,14,100,77,25,10\n"
-		"130,131,,ISPARENT | CHECKED,GROUPBOX,15,10,98,120,20\n"
-		"131,,,,EDTEXT,0,15,103,110,10\n"
-		"200,201,,,LTEXT,16,10,30,70,9\n"
-		"201,202,,CHECKED | EXRADIO,ODBUTTON,17,20,42,25,25\n"
-		"202,203,,EXRADIO,ODBUTTON,17,45,42,25,25\n"
-		"203,204,,EXRADIO,ODBUTTON,17,70,42,25,25\n"
-		"204,205,,EXRADIO,ODBUTTON,17,95,42,25,25\n"
-		"205,206,,EXRADIO,ODBUTTON,17,20,67,25,25\n"
-		"206,207,,EXRADIO,ODBUTTON,17,45,67,25,25\n"
-		"207,208,,EXRADIO,ODBUTTON,17,70,67,25,25\n"
-		"208,210,,EXRADIO,ODBUTTON,17,95,67,25,25\n"
-		"210,,220,ISPARENT | CHECKED, GROUPBOX,18,10,97,120,35\n"
-		"220,221,,,RTEXT,-4,10,105,15,8\n"
-		"221,222,,,EDVAL1,19,27,105,35,10\n"
-		"222,223,,,LTEXT,-7,65,105,5,8\n"
-		"223,224,,,EDVAL1,20,71,105,35,10\n"
-		"224,225,,,LTEXT,-3,109,105,15,8\n"
-		"225,226,,,RTEXT,-5,10,117,15,8\n"
-		"226,227,,,EDVAL1,21,27,117,35,10\n"
-		"227,228,,,LTEXT,-7,65,117,5,8\n"
-		"228,229,,,EDVAL1,22,71,117,35,10\n"
-		"229,,,,LTEXT,-3,109,117,15,8\n"
-		"300,,,LASTOBJ | NOSELECT,ODBUTTON,23,15,30,110,140\n";
+	"1,2,,DEFAULT, PUSHBUTTON,-1,148,10,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,5,50,TOUCHEXIT | ISPARENT,SHEET,1,5,10,130,130\n"
+	"5,6,200,ISPARENT | CHECKED,SHEET,2,5,10,130,130\n"
+	"6,,300,ISPARENT,SHEET,3,5,10,130,130\n"
+	"50,51,100,ISPARENT | CHECKED,GROUPBOX,4,10,30,120,36\n"
+	"51,120,,,CHECKBOX,5,17,37,80,8\n"
+	"100,101,,,RTEXT,6,10,51,35,8\n"
+	"101,102,,,EDVAL1,7,48,51,32,10\n"
+	"102,103,,,CTEXT,8,81,51,11,8\n"
+	"103,,,,EDVAL1,9,93,51,32,10\n"
+	"120,,121,ISPARENT | CHECKED,GROUPBOX,10,10,72,120,20\n"
+	"121,122,,,RTEXT,11,10,77,25,8\n"
+	"122,123,,,EDVAL1,12,37,77,25,10\n"
+	"123,124,,,LTEXT,-3,63,77,10,8\n"
+	"124,125,,,RTEXT,-11,73,77,25,8\n"
+	"125,130,,OWNDIALOG,COLBUTT,14,100,77,25,10\n"
+	"130,131,,ISPARENT | CHECKED,GROUPBOX,15,10,98,120,20\n"
+	"131,,,,EDTEXT,0,15,103,110,10\n"
+	"200,201,,,LTEXT,16,10,30,70,9\n"
+	"201,202,,CHECKED | EXRADIO,ODBUTTON,17,20,42,25,25\n"
+	"202,203,,EXRADIO,ODBUTTON,17,45,42,25,25\n"
+	"203,204,,EXRADIO,ODBUTTON,17,70,42,25,25\n"
+	"204,205,,EXRADIO,ODBUTTON,17,95,42,25,25\n"
+	"205,206,,EXRADIO,ODBUTTON,17,20,67,25,25\n"
+	"206,207,,EXRADIO,ODBUTTON,17,45,67,25,25\n"
+	"207,208,,EXRADIO,ODBUTTON,17,70,67,25,25\n"
+	"208,210,,EXRADIO,ODBUTTON,17,95,67,25,25\n"
+	"210,,220,ISPARENT | CHECKED, GROUPBOX,18,10,97,120,35\n"
+	"220,221,,,RTEXT,-4,10,105,15,8\n"
+	"221,222,,,EDVAL1,19,27,105,35,10\n"
+	"222,223,,,LTEXT,-7,65,105,5,8\n"
+	"223,224,,,EDVAL1,20,71,105,35,10\n"
+	"224,225,,,LTEXT,-3,109,105,15,8\n"
+	"225,226,,,RTEXT,-5,10,117,15,8\n"
+	"226,227,,,EDVAL1,21,27,117,35,10\n"
+	"227,228,,,LTEXT,-7,65,117,5,8\n"
+	"228,229,,,EDVAL1,22,71,117,35,10\n"
+	"229,,,,LTEXT,-3,109,117,15,8\n"
+	"300,,,LASTOBJ | NOSELECT,ODBUTTON,23,15,30,110,140";
 
 bool
 Graph::AddAxis()
@@ -8830,10 +9199,10 @@ Graph::AddAxis()
 	DWORD colAxis = ColAX;
 	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)" scaling ", (void*)" automatic scaling",
 		(void*)"axis from", (void*)&y_axis.min, (void*)"to", (void*)&y_axis.max, (void*)" line ", (void*)"width",
-		(void*)&sizAxLine, (void*)"color", (void *)&colAxis, (void*)" axis label ", (void*)"select a template:",
+		(void*)&sizAxLine, (void*)0L, (void *)&colAxis, (void*)" axis label ", (void*)"select a template:",
 		(void*)(OD_NewAxisTempl), (void*)" placement ", (void*)&axis.loc[0].fx, (void*)&axis.loc[1].fx,
 		(void*)&axis.loc[0].fy, (void*)&axis.loc[1].fy,  (void*)OD_axisplot};
-	DlgInfo *NewAxisDlg = CompileDialog(AddAxisTmpl, dyndata);
+	DlgInfo *NewAxisDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
 	int i, j, res, currTempl = 201;
@@ -8848,6 +9217,7 @@ Graph::AddAxis()
 	GraphObj **somePlots;
 	Label *label;
 
+	if(!(NewAxisDlg = CompileDialog(AddAxisTmpl, dyndata)))return false;
 	if(!(names = (char**)calloc(nscp+2, sizeof(char*))))return false;
 	if(!(somePlots = (GraphObj**)calloc(nscp+2, sizeof(GraphObj*))))return false;
 	if(!Axes) Axes = (Axis**)calloc(2, sizeof(Axis*));
diff --git a/QT_Spec.cpp b/QT_Spec.cpp
index 8623c1c..dbee7a8 100755
--- a/QT_Spec.cpp
+++ b/QT_Spec.cpp
@@ -1,4 +1,4 @@
-//QT_Spec.cpp, Copyright (c) 2001-2006 R.Lackner
+//QT_Spec.cpp, Copyright (c) 2001-2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -46,7 +46,7 @@ extern Default defs;
 extern UndoObj Undo;
 
 QApplication *QAppl;
-QWidget *MainWidget =0L;
+QWidget *MainWidget =0L, *CurrWidget = 0L;
 POINT CurrWidgetPos = {0,0};
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -83,12 +83,24 @@ char *SaveDataAsName(char *oldname)
 // Get a new file name to store graph
 char *SaveGraphAsName(char *oldname)
 {
-	QString fileName = QFileDialog::getSaveFileName(oldname?oldname:defs.currPath,
-		"RLPlot files (*.rlp)", QAppl->focusWidget());
-	if(!fileName.isEmpty()){
-		strcpy(UserFileName, fileName);
-		defs.FileHistory(UserFileName);
-		return UserFileName;
+	QFileDialog qf(0,0,true);
+	QString filters("RLPlot files (*.rlp)");
+	int i, cb;
+	char *ext;
+
+	qf.setFilters(filters);				qf.setDir(defs.currPath);
+	qf.setSelection(oldname);			qf.setMode(QFileDialog::AnyFile);
+	if(qf.exec() == QDialog::Accepted) {
+		if(!qf.selectedFile().isEmpty()) {
+			cb = rlp_strcpy(UserFileName, 600, (char*)qf.selectedFile().ascii());
+			if(cb < 4 || UserFileName[cb-4] != '.'){
+				ext = (char*)qf.selectedFilter().ascii();
+				for(i = 0; ext[i] && ext[i] != '*'; i++);
+				rlp_strcpy(UserFileName+cb, 5, ext+i+1);
+				}
+			defs.FileHistory(UserFileName);
+			return UserFileName;
+			}
 		}
 	return 0L;
 }
@@ -209,7 +221,7 @@ void Qt_Box()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 anyOutput *oTxtCur = 0L;
 RECT rTxtCur, rCopyMark;
-bool bTxtCur = false;
+bool bTxtCur = false,  bSuspend = false;
 DWORD coTxtCur = 0x0L;
 TxtCurBlink *cTxtCur = 0L;
 POINT ptTxtCurLine[2];
@@ -230,9 +242,8 @@ void HideTextCursorObj(anyOutput *out)
 
 void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
 {
-	coTxtCur = color;
-	HideTextCursor();
-	oTxtCur = out;
+	coTxtCur = color;		HideTextCursor();
+	oTxtCur = out;			bSuspend = false;
 	memcpy(&rTxtCur, disp, sizeof(RECT));
 	ptTxtCurLine[0].x = rTxtCur.left;	ptTxtCurLine[0].y = rTxtCur.top;
 	ptTxtCurLine[1].x = rTxtCur.right;	ptTxtCurLine[1].y = rTxtCur.bottom;
@@ -264,21 +275,45 @@ void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
 	int i;
 
 	if(!out || !mrk || !nRec || !cTxtCur) return;
-	cTxtCur->oCopyMark = out;
+	cTxtCur->oCopyMark = out;	bSuspend = false;
 	rCopyMark.left = mrk[0].left;	rCopyMark.right = mrk[0].right;
 	rCopyMark.top = mrk[0].top;		rCopyMark.bottom = mrk[0].bottom;
 	for(i = 1; i < nRec; i++) {
 		UpdateMinMaxRect(&rCopyMark, mrk[i].left, mrk[i].top);
 		UpdateMinMaxRect(&rCopyMark, mrk[i].right, mrk[i].bottom);
 		}
+	if(cTxtCur->bmCopyMark) delete(cTxtCur->bmCopyMark);
 	cTxtCur->bmCopyMark = new BitMapQT(rCopyMark.right - rCopyMark.left+1, 
 		rCopyMark.bottom - rCopyMark.top+1, out->hres, out->vres);
 }
 
+void InvalidateOutput(anyOutput *o)
+{
+	if(!o || !cTxtCur) return;
+	if(o == cTxtCur->oCopyMark) {
+		cTxtCur->oCopyMark = 0L;
+		if(cTxtCur->bmCopyMark) delete cTxtCur->bmCopyMark;
+		cTxtCur->bmCopyMark = 0L;
+		}
+	if(o == oTxtCur) {
+		oTxtCur = 0L;	bTxtCur = false;
+		}
+}
+
+void SuspendAnimation(anyOutput *o, bool bSusp)
+{
+	if(!o || !cTxtCur) return;
+	if(!bSusp) bSuspend = false;
+	else {
+		if(o == cTxtCur->oCopyMark) bSuspend = bSusp;
+		if(o == oTxtCur) bSuspend = bSusp;
+		}
+}
+
 LineDEF liCopyMark1 = {0.0f, 1.0f, 0x00ffffffL, 0L};
 LineDEF liCopyMark2 = {0.0f, 6.0f, 0x0L, 0xf0f0f0f0L};
 
-TxtCurBlink::TxtCurBlink():QObject(MainWidget, 0)
+TxtCurBlink::TxtCurBlink():QObject(CurrWidget, 0)
 {
 	isVis = false;
 	oCopyMark = 0L;		bmCopyMark = 0L;
@@ -322,7 +357,7 @@ TxtCurBlink::showCopyMark()
 void
 TxtCurBlink::timerEvent(QTimerEvent *ev)
 {
-	showCopyMark();
+	if(bSuspend) return;		showCopyMark();
 	if(!oTxtCur || (ptTxtCurLine[0].x == ptTxtCurLine[1].x &&
 		ptTxtCurLine[0].y == ptTxtCurLine[1].y)) return;
 	count++;
@@ -666,6 +701,9 @@ void GetDesktopSize(int *width, int *height)
 	QWidget *d = QApplication::desktop();
 	*width = d->width();
 	*height = d->height();
+	if(*width < 800 || *height < 600){
+		*width = 800;		*height = 600;
+		}
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -683,26 +721,50 @@ DWORD SwapRB(DWORD col)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Common code for all QT output classes
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool com_TextOut(int x, int y, char *ctxt, TextDEF *TxtSet, QPainter *qP, anyOutput *o)
+bool com_QStringExt(QString txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP)
+{
+	QRect rc;
+
+	if(cb >0)txt.truncate(cb);
+	rc = qP->boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop, txt);
+	*width = rc.rRight() - rc.rLeft();
+	*height = TxtSet->iSize +2;
+	return true;
+}
+
+bool
+com_GetTextExtent(char  *txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP)
+{
+	if(!txt || !txt[0]) return com_QStringExt(QString("a"), width, height, 1, TxtSet, qP);
+	else return com_QStringExt(QString(txt), width, height, cb > 0 ? cb : (int)strlen(txt), TxtSet, qP);
+}
+
+bool
+com_GetTextExtentW(w_char  *txt, int *width, int *height, int cb, TextDEF *TxtSet, QPainter *qP)
+{
+	int i;
+	QString wtxt(0);
+
+	if(!txt || !txt[0]) return com_QStringExt(QString("a"), width, height, 1, TxtSet, qP);
+	for(i = 0; txt[i] && i < cb; i++) wtxt.append(QChar(txt[i]));
+	com_QStringExt(wtxt, width, height, cb, TxtSet, qP);
+}
+
+bool com_QStringOut(int x, int y, QString txt, TextDEF *TxtSet, QPainter *qP, anyOutput *o)
 {
 	int i, w, h, ix, iy;
 	QBrush oldBrush;
 	QPen oldPen, currPen;
 	QWMatrix xf, dxf;
-	QString txt(ctxt);
 
-	if(!ctxt || !ctxt[0] || !TxtSet || !qP || !o) return false;
-	if(TxtSet->Font==FONT_GREEK) {
-		txt.truncate(0);
-		for(i = 0; ctxt[i]; i++) {
-			if((ctxt[i] >= 'A' && ctxt[i] <= 'Z')) txt.append(QChar(ctxt[i] - 'A' + 0x391));
-			else if((ctxt[i] >= 'a' && ctxt[i] <= 'z')) txt.append(QChar(ctxt[i] - 'a' + 0x3B1));
-			else txt.append(QChar(ctxt[i]));
-			}
-		}
+	if(!TxtSet->iSize && TxtSet->fSize > 0.0) TxtSet->iSize = o->un2ix(TxtSet->fSize);
+	if(!TxtSet->iSize) return false;
+	if(TxtSet->Align & TXA_VCENTER) y += iround(TxtSet->iSize * 0.4);
+	else if(TxtSet->Align & TXA_VBOTTOM) y -= iround(TxtSet->iSize * 0.1);
+	else y += iround(TxtSet->iSize);
 	oldBrush = qP->brush();						dxf = qP->worldMatrix();
-	oldPen = currPen = qP->pen();
-	o->oGetTextExtent(ctxt, -1, &w, &h);		iy = y;
+	oldPen = currPen = qP->pen();				iy = y;
+	com_QStringExt(txt, &w, &h, -1, TxtSet, qP);
 	if(TxtSet->Align & TXA_HCENTER) ix = x - (w >> 1);
 	else if(TxtSet->Align & TXA_HRIGHT) ix = x - w;
 	else ix = x;
@@ -745,6 +807,33 @@ bool com_TextOut(int x, int y, char *ctxt, TextDEF *TxtSet, QPainter *qP, anyOut
 	return true;
 }
 
+bool com_TextOut(int x, int y, char *ctxt, TextDEF *TxtSet, QPainter *qP, anyOutput *o)
+{
+	int i, w, h, ix, iy;
+	QString txt(ctxt);
+
+	if(!ctxt || !ctxt[0] || !TxtSet || !qP || !o) return false;
+	if(TxtSet->Font==FONT_GREEK) {
+		txt.truncate(0);
+		for(i = 0; ctxt[i]; i++) {
+			if((ctxt[i] >= 'A' && ctxt[i] <= 'Z')) txt.append(QChar(ctxt[i] - 'A' + 0x391));
+			else if((ctxt[i] >= 'a' && ctxt[i] <= 'z')) txt.append(QChar(ctxt[i] - 'a' + 0x3B1));
+			else txt.append(QChar(ctxt[i]));
+			}
+		}
+	return com_QStringOut(x, y, txt, TxtSet, qP, o);
+}
+
+bool com_TextOutW(int x, int y, w_char *wtxt, TextDEF *TxtSet, QPainter *qP, anyOutput *o)
+{
+	int i;
+	QString txt(0);
+
+	if(!wtxt || !wtxt[0] || !TxtSet || !qP || !o) return false;
+	for(i = 0; wtxt[i]; i++) txt.append(QChar(wtxt[i]));
+	return com_QStringOut(x, y, txt, TxtSet, qP, o);
+}
+
 bool com_SetTextSpec(TextDEF *set, TextDEF *TxtSet, anyOutput *o, QFont qF, QPainter *qP)
 {
 	bool RetVal;
@@ -757,7 +846,7 @@ bool com_SetTextSpec(TextDEF *set, TextDEF *TxtSet, anyOutput *o, QFont qF, QPai
 		qF.setItalic((TxtSet->Style & TXS_ITALIC) ? true : false);
 		qF.setUnderline((TxtSet->Style &TXS_UNDERLINE) ? true : false);
 		if((TxtSet->Style & TXS_SUPER) || (TxtSet->Style & TXS_SUB))
-			 qF.setPointSize((int)(TxtSet->iSize*0.71));
+			qF.setPointSize((TxtSet->iSize > 1) ? (int)(TxtSet->iSize*0.71) : 1);
 		else qF.setPointSize((TxtSet->iSize > 2) ? TxtSet->iSize : 2);
 		switch(TxtSet->Font){
 		case FONT_HELVETICA:
@@ -1272,17 +1361,13 @@ BitMapQT::CopyBitmap(int x, int y, anyOutput* sr, int sx, int sy,
 bool
 BitMapQT::oGetTextExtent(char *text, int cb, int *width, int *height)
 {
-	if(!text || !text[0]){
-		QRect rc = qPainter.boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop, "A", 1);
-		*width = rc.rLeft();
-		}
-	else {
-		QRect rc = qPainter.boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop,
-		text, cb > 0 ? cb : strlen(text));
-		*width = rc.rRight() - rc.rLeft();
-		}
-	*height = TxtSet.iSize +2;
-	return true;
+	return com_GetTextExtent(text, width, height, cb, &TxtSet, &qPainter);
+}
+
+bool
+BitMapQT::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
+{
+	return com_GetTextExtentW(text, width, height, cb, &TxtSet, &qPainter);
 }
 
 bool
@@ -1374,13 +1459,17 @@ bool
 BitMapQT::oTextOut(int x, int y, char *txt, int cb)
 {
 	if(!txt || !txt[0]) return false;
-	if(TxtSet.Align & TXA_VCENTER) y += iround(TxtSet.iSize * 0.4);
-	else if(TxtSet.Align & TXA_VBOTTOM) y -= iround(TxtSet.iSize * 0.1);
-	else y += iround(TxtSet.iSize * 1.0);
 	return com_TextOut(x, y, txt, &TxtSet, &qPainter, this);
 }
 
 bool
+BitMapQT::oTextOutW(int x, int y, w_char *txt, int cb)
+{
+	if(!txt || !txt[0]) return false;
+	return com_TextOutW(x, y, txt, &TxtSet, &qPainter, this);
+}
+
+bool
 BitMapQT::oPolygon(POINT *pts, int cp, char *nam)
 {
 	int i;
@@ -1397,47 +1486,63 @@ BitMapQT::oPolygon(POINT *pts, int cp, char *nam)
 	if(hgo) hgo->oPolygon(pts, cp);
 }
 
-bool
-BitMapQT::oArc(int x1, int y1, int x2, int y2, int quads)
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The menu class
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RLPmenu::RLPmenu(QWidget *par, anyOutput *o, GraphObj *g)
+:QMenuBar(par, 0L)
 {
-	int i, j;
+	parent = par;		OutputClass = o;		BaseObj = g;
+	connect(this, SIGNAL(activated(int)), this, SLOT(doMenuItem(int)));
+}
 
-	if(x1 > x2) Swap(x1, x2);	if(y1 > y2) Swap(y1, y2);
-	switch(quads) {
-	case 1:	i = 270*16;		j = 90*16;	break;
-	case 2:	i = 180*16;		j = 180*16;	break;
-	case 3:	i = 90*16;		j = 270*16;	break;
-	case 4:	i = 0;			j = 360*16;	break;
-	default: return false;
+void
+RLPmenu::doMenuItem(int id)
+{
+	if(OutputClass) Undo.SetDisp(OutputClass);
+	if(parent && (parent->y() || parent->x())) {
+		CurrWidgetPos.x = parent->x();		CurrWidgetPos.y = parent->y();		CurrWidget = parent;
 		}
-	qPainter.drawArc(x1, y1, x2-x1, y2-y1, i, j);
-	return true;
+	if(BaseObj) switch(id) {
+	case CM_REPANOV:
+		rep_anova(BaseObj, BaseObj->data);				return;
+	case CM_REPKRUSKAL:
+		rep_kruskal(BaseObj, BaseObj->data);			return;
+	case CM_CORRELM:
+		rep_correl(BaseObj, BaseObj->data, 0);			return;
+	case CM_CORRELT:
+		rep_correl(BaseObj, BaseObj->data, 1);			return;
+	}
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // The display output class
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-OutputQT::OutputQT(GraphObj *g):BitMapQT(g, 0L)
+OutputQT::OutputQT(GraphObj *g):BitMapQT(g, QAppl->desktop())
 {
 	int w, h;
-	RLPwidget *rw;
 
 	HScroll = VScroll = 0L;
+	GetDesktopSize(&w, &h);
 	CreateNewWindow(BaseObj = g);
-	if(rw = (RLPwidget*)widget) {
-		rw->move(CurrWidgetPos.x+50, CurrWidgetPos.y+50);
-		rw->show();
-		rw->mempic = mempic;
-		rw->setBackgroundMode(QWidget::NoBackground);
+	if(widget) {
+		widget->setBackgroundMode(QWidget::NoBackground);
+		if(CurrWidgetPos.x >= ((w>>1)-100))CurrWidgetPos.x = CurrWidgetPos.y = 50;
+		widget->show();
+		widget->move(CurrWidgetPos.x+=50, CurrWidgetPos.y+=50);
+		if(widget->x() || widget->y()) {
+			CurrWidgetPos.x = widget->x();	CurrWidgetPos.y = widget->y();
+			}
 		}
 }
 
 OutputQT::OutputQT(DlgWidget *wi):BitMapQT(0L, wi)
 {
 	//assume fixed size (dialog) widget
-	widget = wi;
-	HScroll = VScroll = 0L;
-	BaseObj = 0L;
+	if(widget = wi) {
+		wi->move(CurrWidgetPos.x+50, CurrWidgetPos.y+50);
+		}
+	HScroll = VScroll = 0L;			BaseObj = 0L;
 	wi->OutputClass = this;
 	wi->mempic = mempic;
 	wi->setBackgroundMode(QWidget::NoBackground);
@@ -1462,7 +1567,7 @@ OutputQT::ActualSize(RECT *rc)
 		rc->left = rc->top = 0;
 		rc->bottom = widget->height() - MenuHeight-6;
 		rc->right = widget->width();
-		return true;
+		return (rc->right > 40 && rc->bottom > 40);
 		}
 	return false;
 }
@@ -1587,24 +1692,29 @@ OutputQT::MouseCursor(int cid, bool force)
 	QBitmap *bits, *mask;
 	bits = mask = 0L;
 
+	CurrWidget = widget;
 	switch(cid) {
 #ifdef Q_CHECK_PTR				//Qt version 3
 	case MC_ARROW:	widget->setCursor(QCursor(Qt::ArrowCursor));	break;
+	case MC_TXTFRM:
 	case MC_CROSS:	widget->setCursor(QCursor(Qt::CrossCursor));	break;
 	case MC_WAIT:	widget->setCursor(QCursor(Qt::WaitCursor));		break;
 	case MC_TEXT:	widget->setCursor(QCursor(Qt::IbeamCursor));	break;
 	case MC_NORTH:	widget->setCursor(QCursor(Qt::SizeVerCursor));	break;
 	case MC_NE:		widget->setCursor(QCursor(Qt::SizeBDiagCursor));break;
+	case MC_COLWIDTH:
 	case MC_EAST:	widget->setCursor(QCursor(Qt::SizeHorCursor));	break;
 	case MC_SE:		widget->setCursor(QCursor(Qt::SizeFDiagCursor));break;
 	case MC_SALL:	widget->setCursor(QCursor(Qt::SizeAllCursor));	break;
 #else							//Qt version 2
 	case MC_ARROW:	widget->setCursor(QCursor(ArrowCursor));	break;
+	case MC_TXTFRM:
 	case MC_CROSS:	widget->setCursor(QCursor(CrossCursor));	break;
 	case MC_WAIT:	widget->setCursor(QCursor(WaitCursor));		break;
 	case MC_TEXT:	widget->setCursor(QCursor(IbeamCursor));	break;
 	case MC_NORTH:	widget->setCursor(QCursor(SizeVerCursor));	break;
 	case MC_NE:		widget->setCursor(QCursor(SizeBDiagCursor));break;
+	case MC_COLWIDTH:
 	case MC_EAST:	widget->setCursor(QCursor(SizeHorCursor));	break;
 	case MC_SE:		widget->setCursor(QCursor(SizeFDiagCursor));break;
 	case MC_SALL:	widget->setCursor(QCursor(SizeAllCursor));	break;
@@ -1655,6 +1765,9 @@ OutputQT::SetScroll(bool isVert, int iMin, int iMax, int iPSize, int iPos)
 {
 	QScrollBar *sb;
 
+	if((CurrWidget = widget) && (widget->x() || widget->y())) {
+		CurrWidgetPos.x = widget->x();		CurrWidgetPos.y = widget->y();
+		}
 	if(isVert) {
 		if(!(sb = VScroll))return false;
 		}
@@ -1795,16 +1908,26 @@ OutputQT::SetMenu(int type)
 		graph->insertSeparator();
 		graph->insertItem("&Settings", widget, SLOT(cmDefaults()));
 
+		QPopupMenu *anov = new QPopupMenu(widget);
+		anov->insertItem("&One Way Anova", CM_REPANOV);
+		anov->insertItem("&Kruskal Wallis", CM_REPKRUSKAL);
+
+		QPopupMenu *corr = new QPopupMenu(widget);
+		corr->insertItem("Correlation &Matrix", CM_CORRELM);
+		corr->insertItem("Tiled &Plots", CM_CORRELT);
+
 		QPopupMenu *stats = new QPopupMenu(widget);
+		stats->insertItem("&Sample Stats", widget, SLOT(cmSmplStat()));
 		stats->insertItem("&Comp. Means", widget, SLOT(cmRepCmeans()));
-		stats->insertItem("&Anova", widget, SLOT(cmRepanov()));
+		stats->insertItem("&Anova", anov);
 		stats->insertItem("&Regression", widget, SLOT(cmRepregr()));
+		stats->insertItem("C&orrelations", corr);
 		stats->insertItem("&2x2 Table", widget, SLOT(cmReptwoway()));
 
 		QPopupMenu *about = new QPopupMenu(widget);
 		about->insertItem("&About ...", widget, SLOT(cmAbout()));
 
-		menu = new QMenuBar(widget);
+		menu = new RLPmenu(widget, this, BaseObj);
 		menu->insertItem("&File", file);			menu->insertItem("&Edit", edit);
 		menu->insertItem("&Statistics", stats);		menu->insertItem("&Graph", graph);
 		menu->insertItem("&?", about);
@@ -1876,7 +1999,7 @@ OutputQT::SetMenu(int type)
 		QPopupMenu *about = new QPopupMenu(widget);
 		about->insertItem("&About ...", widget, SLOT(cmAbout()));
 
-		menu = new QMenuBar(widget);
+		menu = new RLPmenu(widget, this, BaseObj);
 		menu->insertItem("&File", file);
 		menu->insertItem("&Edit", edit);
 		menu->insertItem("&Display", displ);
@@ -1946,7 +2069,7 @@ OutputQT::SetMenu(int type)
 		QPopupMenu *about = new QPopupMenu(widget);
 		about->insertItem("&About ...", widget, SLOT(cmAbout()));
 
-		menu = new QMenuBar(widget);
+		menu = new RLPmenu(widget, this, BaseObj);
 		menu->insertItem("&File", file);
 		menu->insertItem("&Edit", edit);
 		menu->insertItem("&Display", displ);
@@ -2007,6 +2130,7 @@ OutputQT::CreateNewWindow(GraphObj *g)
 	if(widget = new RLPwidget(0, 0, this, g)) {
 		widget->setCaption("OutputQT::CreateNewWindow");
 		widget->setGeometry(0, 0, (int)(w*.7f), (int)(h*.7f));
+		((RLPwidget*)widget)->mempic = mempic;
 		HScroll = ((RLPwidget*)widget)->HScroll;
 		VScroll = ((RLPwidget*)widget)->VScroll;
 		}
@@ -2038,6 +2162,7 @@ RLPwidget::RLPwidget(QWidget *par, const char *name, anyOutput *o, GraphObj *g)
 	if(!MainWidget) QAppl->setMainWidget(MainWidget = this);
 	setMouseTracking(true);
 	setFocusPolicy(StrongFocus);
+	setKeyCompression(true);
 }
 
 RLPwidget::~RLPwidget()
@@ -2406,15 +2531,15 @@ RLPwidget::cmtText()
 }
 
 void
-RLPwidget::cmRepCmeans()
+RLPwidget::cmSmplStat()
 {
-	if(BaseObj) rep_compmeans(BaseObj, BaseObj->data);
+	if(BaseObj) rep_samplestats(BaseObj, BaseObj->data);
 }
 
 void
-RLPwidget::cmRepanov()
+RLPwidget::cmRepCmeans()
 {
-	if(BaseObj) rep_anova(BaseObj, BaseObj->data);
+	if(BaseObj) rep_compmeans(BaseObj, BaseObj->data);
 }
 
 void
@@ -2443,6 +2568,7 @@ RLPwidget::paintEvent(QPaintEvent *range)
 void
 RLPwidget::resizeEvent(QResizeEvent *)
 {
+	CurrWidget = this;
 	HScroll->resize(width() -16, 16);
 	HScroll->move(0, height()-16);
 	VScroll->resize(16, height()-OutputClass->MenuHeight-16);
@@ -2478,6 +2604,7 @@ RLPwidget::mousePressEvent(QMouseEvent *e)
 	MouseEvent mev = {1, e->button() == Qt::LeftButton ? MOUSE_LBDOWN : -1, e->x(), e->y()};
 
 	HideTextCursor();			i = e->state();
+	CurrWidget = this;
 	if(i & Qt::ShiftButton) mev.StateFlags |= 0x08;
 	if(i & Qt::ControlButton) mev.StateFlags |= 0x10;
 	if (BaseObj)BaseObj->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
@@ -2513,6 +2640,8 @@ void
 RLPwidget::keyPressEvent(QKeyEvent *e)
 {
 	int i, c;
+	QChar qc;
+	w_char uc;
 
 	if(BaseObj) switch(c = e->key()) {
 		case Key_Prior:
@@ -2557,12 +2686,15 @@ RLPwidget::keyPressEvent(QKeyEvent *e)
 			BaseObj->Command(CMD_POS_LAST, 0L, OutputClass);
 			break;
 		default:
-			c = e->ascii();
-			if(c == 3) cmCopy();
-			else if(c == 22) cmPaste();
-			else if(c == 26) cmUndo();
-			else if(c >1 && c < 256)
-				BaseObj->Command(CMD_ADDCHAR, (void *)(& c), OutputClass);
+			QString kres = e->text();
+			for(i = 0; i < kres.length(); i++) {
+				qc = kres.at(i);	uc = qc.unicode();
+				if(uc == 3) cmCopy();
+				else if(uc == 22) cmPaste();
+				else if(uc == 26) cmUndo();
+				else if(uc > 255) BaseObj->Command(CMD_ADDCHARW, (void *)(&uc), OutputClass);
+				else BaseObj->Command(CMD_ADDCHAR, (void *)(&uc), OutputClass);
+				}
 			break;
 		}
 	e->accept();
@@ -2571,7 +2703,10 @@ RLPwidget::keyPressEvent(QKeyEvent *e)
 void
 RLPwidget::focusInEvent(QFocusEvent *e)
 {
-	CurrWidgetPos.x = x();			CurrWidgetPos.y = y();
+	if(x() || y()) {
+		CurrWidgetPos.x = x();			CurrWidgetPos.y = y();
+		}
+	CurrWidget = this;
 	if(BaseObj) {
 		if(BaseObj->Id == GO_GRAPH) CurrGraph = (Graph*)BaseObj;
 		}
@@ -2598,7 +2733,6 @@ RLPwidget::openHistoryFile(int idx)
 		}
 }
 
-
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Print and output EPS to file
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2765,6 +2899,9 @@ PrintQT::Eject()
 bool
 PrintQT::oGetTextExtent(char *text, int cb, int *width, int *height)
 {
+	return com_GetTextExtent(text, width, height, cb, &TxtSet, &qPainter);
+
+
 	if(!text || !text[0]){
 		QRect rc = qPainter.boundingRect(0, 0, 10000, 1000, Qt::AlignLeft | Qt::AlignTop, "A", 1);
 		*width = rc.rLeft();
@@ -2779,6 +2916,12 @@ PrintQT::oGetTextExtent(char *text, int cb, int *width, int *height)
 }
 
 bool
+PrintQT::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
+{
+	return com_GetTextExtentW(text, width, height, cb, &TxtSet, &qPainter);
+}
+
+bool
 PrintQT::oCircle(int x1, int y1, int x2, int y2, char* nam)
 {
 	qPainter.drawEllipse(x1, y1, x2-x1, y2-y1);
@@ -2821,15 +2964,17 @@ bool
 PrintQT::oTextOut(int x, int y, char *txt, int cb)
 {
 	if(!txt || !txt[0]) return false;
-	if(TxtSet.fSize > 0.0) TxtSet.iSize = un2ix(TxtSet.fSize);
-	if(!TxtSet.iSize) return false;
-	if(TxtSet.Align & TXA_VCENTER) y += iround(TxtSet.iSize * 0.4);
-	else if(TxtSet.Align & TXA_VBOTTOM) y -= iround(TxtSet.iSize * 0.1);
-	else y += iround(TxtSet.iSize * 1.0);
 	return com_TextOut(x, y, txt, &TxtSet, &qPainter, this);
 }
 
 bool
+PrintQT::oTextOutW(int x, int y, w_char *txt, int cb)
+{
+	if(!txt || !txt[0]) return false;
+	return com_TextOutW(x, y, txt, &TxtSet, &qPainter, this);
+}
+
+bool
 PrintQT::oPolygon(POINT *pts, int cp, char *nam)
 {
 	int i;
@@ -2847,12 +2992,6 @@ PrintQT::oPolygon(POINT *pts, int cp, char *nam)
 	return true;
 }
 
-bool
-PrintQT::oArc(int x1, int y1, int x2, int y2, int quads)
-{
-	return false;
-}
-
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Find a suitable www browser
 void FindBrowser()
@@ -2936,7 +3075,10 @@ DlgWidget::mousePressEvent(QMouseEvent *e)
 {
 	MouseEvent mev = {1, e->button() == Qt::LeftButton ? MOUSE_LBDOWN : -1, e->x(), e->y()};
 
-	HideTextCursor();
+	HideTextCursor();				CurrWidget = this;
+	if(x() || y()) {
+		CurrWidgetPos.x = x();		CurrWidgetPos.y = y();
+		}
 	if (dlg) dlg->Command(CMD_MOUSE_EVENT, (void *)&mev, OutputClass);
 }
 
@@ -2961,6 +3103,10 @@ DlgWidget::keyPressEvent(QKeyEvent *e)
 {
 	int c;
 
+	CurrWidget = this;
+	if(x() || y()) {
+		CurrWidgetPos.x = x();			CurrWidgetPos.y = y();
+		}
 	if(dlg) switch(c = e->key()) {
 		case Key_Left:
 			if(e->state() & ShiftButton) dlg->Command(CMD_SHIFTLEFT, 0L, OutputClass);
@@ -3008,7 +3154,10 @@ DlgWidget::keyPressEvent(QKeyEvent *e)
 void
 DlgWidget::focusInEvent(QFocusEvent *e)
 {
-	CurrWidgetPos.x = x();		CurrWidgetPos.y = y();
+	CurrWidget = this;
+	if(x() || y()) {
+		CurrWidgetPos.x = x();		CurrWidgetPos.y = y();
+		}
 }
 
 void
@@ -3047,6 +3196,8 @@ void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj
 	w->setCaption(title);
 	if(flags & 0x2) w->setFixedSize(width, height);
 	else w->setFixedSize(width-6, height-16);
+	o = new OutputQT(w);	o->units = defs.cUnits;
+	o->Erase(0x00e0e0e0L);	if(flags & 0x04) w->startTimer(100);
 	if(flags & 0x1) {
 		GetDesktopSize(&dw, &dh);
 		w->move((dw>>1) - ((w->width())>>1), (dh>>1) - ((w->height())>>1));
@@ -3060,8 +3211,6 @@ void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj
 			}
 		w->move(x, y);
 		}
-	o = new OutputQT(w);	o->units = defs.cUnits;
-	o->Erase(0x00e0e0e0L);	if(flags & 0x04) w->startTimer(100);
 	d->DoPlot(o);			w->show();
 	return w;
 }
@@ -3076,6 +3225,9 @@ void CloseDlgWnd(void *hDlg)
 	HideCopyMark();
 	if(hDlg) {
 		delete((DlgWidget*) hDlg);
+		if(CurrWidgetPos.x > 50 && CurrWidgetPos.y > 50) {
+			CurrWidgetPos.x -= 50;		CurrWidgetPos.y -= 50;
+			}
 		}
 }
 
diff --git a/QT_Spec.h b/QT_Spec.h
index ccb1f4c..ac260ae 100755
--- a/QT_Spec.h
+++ b/QT_Spec.h
@@ -1,4 +1,4 @@
-//QT_Spec.h, Copyright (c) 2001, 2002, 2003, 2004 R.Lackner
+//QT_Spec.h, Copyright (c) 2001-2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -110,6 +110,22 @@ private:
 #endif //RLP_PORT
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class RLPmenu:public QMenuBar {
+	Q_OBJECT
+public:
+	RLPmenu(QWidget *par, anyOutput *o, GraphObj *g);
+
+public slots:
+	void doMenuItem(int id);
+
+private:
+	anyOutput *OutputClass;
+	QWidget *parent;
+	GraphObj *BaseObj;
+
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // The Qt widget class implementet for RLPlot
 class RLPwidget:public QWidget {
 	Q_OBJECT
@@ -172,8 +188,8 @@ public slots:
 	void cmtEllipse();
 	void cmtArrow();
 	void cmtText();
+	void cmSmplStat();
 	void cmRepCmeans();
-	void cmRepanov();
 	void cmRepregr();
 	void cmReptwoway();
 	void cmFile1() {openHistoryFile(0);};
@@ -251,6 +267,7 @@ public:
 	bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
 		int sw, int sh, bool invert);
 	bool oGetTextExtent(char *text, int cb, int *width, int *height);
+	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
 	bool oGetPix(int x, int y, DWORD *col);
 	bool oDrawIcon(int type, int x, int y);
 	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
@@ -258,8 +275,8 @@ public:
 	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
 	bool oSolidLine(POINT *p);
 	bool oTextOut(int x, int y, char *txt, int cb);
+	bool oTextOutW(int x, int y, w_char *txt, int cb);
 	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
-	bool oArc(int x1, int y1, int x2, int y2, int quads);
 };
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -287,7 +304,7 @@ public:
 
 private:
 	GraphObj *BaseObj;
-	QMenuBar *menu;
+	RLPmenu *menu;
 };
 
 class PrintQT:public anyOutput{
@@ -305,13 +322,14 @@ public:
 	bool EndPage();
 	bool Eject();
 	bool oGetTextExtent(char *text, int cb, int *width, int *height);
+	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
 	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
 	bool oPolyline(POINT * pts, int cp, char *nam = 0L);
 	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
 	bool oSolidLine(POINT *p);
 	bool oTextOut(int x, int y, char *txt, int cb);
+	bool oTextOutW(int x, int y, w_char *txt, int cb);
 	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
-	bool oArc(int x1, int y1, int x2, int y2, int quads);
 
 private:
 	QPen qPen;
diff --git a/RLPLOT.RC b/RLPLOT.RC
index 76f54fd..4fd0459 100755
--- a/RLPLOT.RC
+++ b/RLPLOT.RC
@@ -135,10 +135,20 @@ BEGIN
     END
     POPUP "&Statistics"
     BEGIN
+    	MENUITEM "&Sample Stats"				CM_SMPLSTAT
     	MENUITEM "&Comp. Means"					CM_REPCMEANS
-    	MENUITEM "&Anova"						CM_REPANOV
+    	POPUP "&Anova"
+    	BEGIN
+    		MENUITEM "&One Way Anova"			CM_REPANOV
+    		MENUITEM "&Kruskal Wallis"			CM_REPKRUSKAL
+    	END
     	MENUITEM "&Regression"					CM_REPREGR
-    	MENUITEM "&2x2 Table"					CM_REPTWOWAY
+ 		POPUP "C&orrelations"
+		BEGIN
+			MENUITEM "Correlation &Matrix"		CM_CORRELM
+			MENUITEM "Tiled &Plots"				CM_CORRELT
+		END
+   	MENUITEM "&2x2 Table"					CM_REPTWOWAY
     END
     POPUP "&Graph"
     BEGIN
diff --git a/TheDialog.cpp b/TheDialog.cpp
index e3aeeba..341e24c 100755
--- a/TheDialog.cpp
+++ b/TheDialog.cpp
@@ -1,4 +1,4 @@
-//TheDialog.cpp, Copyright (c) 2001-2006 R.Lackner
+//TheDialog.cpp, Copyright (c) 2001-2007 R.Lackner
 //Operating system independent code for dialog boxes
 //
 //    This file is part of RLPlot.
@@ -65,7 +65,7 @@ DlgRoot::DlgRoot(DlgInfo *tmpl, DataObj *d)
 	DlgText.iSize = dlgtxtheight;		DlgText.ColBg = DlgBGcolor;
 	DlgText.fSize = defs.GetSize(SIZE_TEXT);
 	type = NONE;		Id = -2;		cContinue = 0;
-	bActive = false;	Result = -1;	c_go = CurrGO;
+	bActive = bRedraw = false;			Result = -1;	c_go = CurrGO;
 	CurrDisp = 0L;		oldFocus = DialogFocus;		DialogFocus = 0L;
 	oldDefault = DialogDefault;			oldTabStop = DialogTabStop;
 	data = d;			ParentOut = Undo.cdisp;
@@ -196,6 +196,7 @@ DlgRoot::~DlgRoot()
 	int i;
 
 	if(data) data->Command(CMD_ETRACC, 0L, 0L);
+	HideTextCursor();
 	if(dlg){
 		for (i = 0; dlg[i] && i < cDlgs; i++) {
 			//we need to delete each object using a cast on its proper type
@@ -413,7 +414,7 @@ DlgRoot::DoPlot(anyOutput *o)
 {
 	int i;
 
-	HideCopyMark();			mrk_item = 0L;
+	HideCopyMark();			mrk_item = 0L;			bRedraw = false;
 	if(tabstops) for(i = 0; i < cDlgs; tabstops[i++] = 0);
 	if(o)CurrDisp = o;		DialogDefault = 0L;
 	if(CurrDisp) {
@@ -545,7 +546,7 @@ DlgRoot::SetText(int id, char *txt)
 	int i;
 
 	i = FindIndex(id);
-	if(i && dlg[i] && dlg[i]->dialog->Command(CMD_SETTEXT, txt, CurrDisp)) DoPlot(CurrDisp);
+	if(i && dlg[i] && dlg[i]->dialog->Command(CMD_SETTEXT, txt, CurrDisp))bRedraw = true;
 	else return false;
 	return true;
 }
@@ -558,7 +559,7 @@ DlgRoot::SetValue(int id, double val)
 
 	i = FindIndex(id);
 	WriteNatFloatToBuff(tmp_txt, val);
-	if(i && dlg[i] && dlg[i]->dialog->Command(CMD_SETTEXT, tmp_txt+1, CurrDisp)) DoPlot(CurrDisp);
+	if(i && dlg[i] && dlg[i]->dialog->Command(CMD_SETTEXT, tmp_txt+1, CurrDisp))bRedraw = true;
 	else return false;
 	return true;
 }
@@ -593,9 +594,7 @@ DlgRoot::TextSize(int id, int size)
 
 	i = FindIndex(id);
 	if(size <= 0.001f) return false;
-	if(i && dlg[i]) {
-		dlg[i]->dialog->TextDef.iSize = size;
-		}
+	if(i && dlg[i]) dlg[i]->dialog->TextDef.iSize = size;
 	else return false;
 	return true;
 }
@@ -617,10 +616,10 @@ DlgRoot::GetResult()
 {
 	int ret;
 
-	if(Result >= 0 && ParentOut) Undo.SetDisp(ParentOut);
+	ret = Result;				Result = -1;
+	if(bRedraw)DoPlot(0L);
 	//return each result only once !
-	ret = Result;
-	Result = -1;
+	if(ret >= 0 && ParentOut) Undo.SetDisp(ParentOut);
 	return ret;
 }
 
@@ -642,7 +641,7 @@ DlgRoot::ForEach(int cmd, int start, anyOutput *o)
 	if(dlg && CurrDisp) {
 		next = start;
 		do {
-			if(dlg[next]->first) {
+			if(dlg[next] && dlg[next]->first) {
 				if(dlg[next]->flags && ISPARENT) {
 					if(dlg[next]->dialog) {
 						dlg[next]->dialog->Command(CMD_FLUSH, 0L, 0L);
@@ -668,7 +667,7 @@ DlgRoot::ForEach(int cmd, int start, anyOutput *o)
 				ForEach(cmd, FindIndex(dlg[next]->first), 0L);
 				}
 			//parent objects (groups) will channel command to children
-			if(dlg[next]->dialog && dlg[next]->dialog->parent == this && 
+			if(dlg[next] && dlg[next]->dialog && dlg[next]->dialog->parent == this && 
 				!(dlg[next]->dialog->flags & HIDDEN)) switch(cmd) {
 				case CMD_DOPLOT: 
 					dlg[next]->dialog->DoPlot(CurrDisp);
@@ -683,7 +682,7 @@ DlgRoot::ForEach(int cmd, int start, anyOutput *o)
 					dlg[next]->dialog->Select(mev->x, mev->y, CurrDisp);
 					break;
 				}
-			next = FindIndex(dlg[next]->next);
+			next = FindIndex(dlg[next] ? dlg[next]->next : 0);
 			}while(next && next < cDlgs);
 		}
 }
@@ -809,6 +808,9 @@ bool
 PushButton::Command(int cmd, void *tmpl, anyOutput *o)
 {
 	switch(cmd) {
+	case CMD_ENDDIALOG:
+		parent->Command(CMD_ENDDIALOG, (void *)this, o);
+		return true;
 	case CMD_ADDCHAR:
 		HideCopyMark();
 		if(parent && *((int*)tmpl) == 0x0d)		//return pressed
@@ -1819,12 +1821,12 @@ InputText::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_ADDCHAR:
 		if(Text && bActive && !(flags & NOEDIT)){
 			if(o) Undo.SetDisp(o);
-			if(flags & TOUCHEXIT) parent->Command(CMD_ENDDIALOG, (void *)this, o);
 			o->SetTextSpec(&TextDef);
 			switch(*((int*)tmpl)) {
 			case 8: return Text->Command(CMD_BACKSP, o, NULL);	//Backspace
 			default: return Text->AddChar(*((int*)tmpl), o, 0L);
 				}
+			if(flags & TOUCHEXIT) parent->Command(CMD_ENDDIALOG, (void *)this, o);
 			}
 		return false;
 	case CMD_SETTEXT:
@@ -2009,8 +2011,11 @@ RangeInput::Activate(int id, bool activate)
 InputValue::InputValue(tag_DlgObj *par, DlgInfo * desc, RECT rec, double *value)
 	:InputText(par, desc, rec, 0L)
 {
-	WriteNatFloatToBuff(TmpTxt, *value);
-	if(Text) Text->text = (char*)memdup(TmpTxt+1, (int)strlen(TmpTxt+1)+1, 0);
+	if(value) {
+		WriteNatFloatToBuff(TmpTxt, *value);
+		if(Text) Text->text = (char*)memdup(TmpTxt+1, (int)strlen(TmpTxt+1)+1, 0);
+		}
+	else if(Text) Text->SetText("");
 }
 
 InputValue::~InputValue()
@@ -2109,7 +2114,8 @@ TxtHSP::TxtHSP(tag_DlgObj *par, DlgInfo *desc, RECT rec, int *align)
 		}
 	d1[8].next = 0;			d1[8].flags |= LASTOBJ;
 	txt.ColTxt = 0x00808080L;	txt.ColBg = 0x00ffffff;
-	txt.fSize = 8.0;		txt.RotBL = txt.RotCHAR = 0.0;
+	txt.fSize = defs.GetSize(SIZE_TEXT)*2.0;		
+	txt.RotBL = txt.RotCHAR = 0.0;
 	txt.iSize = 0;			txt.Align = TXA_HCENTER | TXA_VCENTER;
 	txt.Style = TXS_NORMAL;	txt.Font = FONT_HELVETICA;
 	txt.Mode = TXM_TRANSPARENT;
@@ -2727,11 +2733,9 @@ TabSheet::DoPlot(anyOutput *o)
 	pts[2].y = pts[3].y = rctab.top;
 	pts[3].x = pts[4].x = rctab.right-1;
 	HideCopyMark();
-	Line.color = 0x00000000L;
-	Line.width = 0.0;
+	Line.color = 0x0L;				Line.width = 0.0;
 	Fill.color = bChecked ? DlgBGhigh : DlgBGcolor;
-	o->SetLine(&Line);
-	o->SetFill(&Fill);
+	o->SetLine(&Line);				o->SetFill(&Fill);
 	o->oPolygon(pts, 6);
 	if(bChecked) {
 		o->oRectangle(cr.left, rctab.bottom, cr.right, cr.bottom);
@@ -2745,6 +2749,10 @@ TabSheet::DoPlot(anyOutput *o)
 	o->oTextOut(rctab.right - 6, rctab.top + 3, Text, 0);
 #else
 	o->oTextOut(rctab.right - 6, rctab.top + 5, Text, 0);
+	if(bChecked) {
+		Line.color = 0x0L;			o->SetLine(&Line);
+		pts[0].y++;					o->oSolidLine(pts);
+		}
 #endif
 	Group::DoPlot(o);
 	o->UpdateRect(&cr, false);
@@ -3187,6 +3195,84 @@ LinePat::MBtrack(MouseEvent *mev, anyOutput *o)
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Common code for multiple range dialogs
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int com_StackDlg(int res, DlgRoot *Dlg, AccRange **rX, int *nx, char ***rd, int *currYR,
+	AccRange **rY, bool *bContinue, int *ny, int *maxYR, bool *updateYR)
+{
+	char **tmprd;
+
+	switch (res) {
+		case 1:
+			if(rX && nx && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0] && 
+				(*rX = new AccRange(TmpTxt))) *nx = rX[0]->CountItems();
+			else if(nx) *nx = 0;
+			if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
+				if(rd[0][*currYR]) free(rd[0][*currYR]);
+				rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);
+				}
+			break;
+		case 155:
+			res = -1;
+			*ny = 0;
+			if(rX) {
+				if(!(*currYR) && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
+					if(*rX = new AccRange(TmpTxt)){
+						*nx = rX[0]->CountItems();
+						delete *rX;						*rX = 0L;
+						}
+					}
+				if(!(*nx)) {
+					ErrorBox("X-range is empty\nor not valid!\n\nEnter a valid range\n"
+						"for common x-values.");
+					*bContinue = true;
+					break;
+					}
+				}
+			if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE) && TmpTxt[0]) {
+				if(*rY = new AccRange(TmpTxt)){
+					*ny = rY[0]->CountItems();
+					delete *rY;
+					*rY = 0L;
+					}
+				}
+			if(!(*ny)) {
+				ErrorBox("Y-range is empty\nor not valid!\n\nEnter a valid range\n"
+					"for y-values with the same\nsize as the x-range.");
+				*bContinue = true;
+				break;
+				}
+			if((*currYR)+1 > *maxYR) {
+				tmprd = (char**)realloc(*rd, sizeof(char*)*((*currYR)+2));
+				if(tmprd) *rd = tmprd;
+				else break;
+				*maxYR = (*currYR)+1;
+				rd[0][*currYR] = 0L;
+				rd[0][(*currYR)+1] = 0L;
+				}
+			if(rd[0][*currYR]) free(rd[0][*currYR]);
+			rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);	//store y-ranges
+			*updateYR = true;
+			(*currYR)++;
+			Dlg->SetText(154, rd[0][*currYR]);
+			Dlg->Activate(154, true);
+			break;
+		case 156:
+			if(Dlg->GetText(154, TmpTxt, TMP_TXT_SIZE)){
+				if(rd[0][*currYR]) free(rd[0][*currYR]);
+				rd[0][*currYR] = (char*)memdup(TmpTxt, ((int)strlen(TmpTxt))+2, 0);;
+				}
+			else if(*currYR == *maxYR) (*maxYR)--;
+			(*currYR)--;
+			Dlg->SetText(154, rd[0][*currYR]);
+			*updateYR = true;
+			res = -1;
+			break;
+		}
+	return res;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Dialog meta compiler
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 static char *std_text[] = {"OK", "Cancel", "", "x", "y", "z", "-", "Next >>", "<< Prev.",
@@ -3321,9 +3407,9 @@ bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 {
 	char *dst[] = {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10};
 	char *mrk, **ra =0L;;
-	int i, j, k, ranges=0;
-	bool success = false;
-	RECT vrc;
+	int i, j, ranges=0;
+	bool success = false, bErr=false;
+	RECT vrc, rrc;
 	AccRange *ar;
 	bool bRet = true;
 
@@ -3338,47 +3424,19 @@ bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 		case 1:
 			if(ranges > 1) {
 				for(i = 0; i < 11; i++) if(dst[i]) {
-#ifdef USE_WIN_SECURE
-					if(i < ranges) sprintf_s(dst[i], 100, "%s", ra[i]);
-					else {
-						j = sprintf_s(dst[i], 100, "%s%d:", Int2ColLabel(vrc.left, false), vrc.top+1);
-						sprintf_s(dst[i]+j, 100-j, "%s%d", Int2ColLabel(vrc.left, false), vrc.bottom+1);
-						}
-#else
-					if(i < ranges) sprintf(dst[i], "%s", ra[i]);
-					else {
-						j = sprintf(dst[i], "%s%d:", Int2ColLabel(vrc.left, false), vrc.top+1);
-						sprintf(dst[i]+j, "%s%d", Int2ColLabel(vrc.left, false), vrc.bottom+1);
-						}
-#endif
+					rlp_strcpy(dst[i], 100, i < ranges ? ra[i] : mkRangeRef(vrc.top, vrc.left, vrc.bottom, vrc.left));
 					}
 				success = true;
 				}
 			else if(vrc.top == vrc.bottom && (vrc.right - vrc.left) >2) {
-				for(i = 0; i < 11; i++) {
-					if(dst[i]){
-#ifdef USE_WIN_SECURE
-						j = sprintf_s(dst[i], 100, "%s%d:", Int2ColLabel(vrc.left, false), vrc.top+1+i);
-						sprintf_s(dst[i]+j, 100-j, "%s%d", Int2ColLabel(vrc.right, false), vrc.top+1+i);
-#else
-						j = sprintf(dst[i], "%s%d:", Int2ColLabel(vrc.left, false), vrc.top+1+i);
-						sprintf(dst[i]+j, "%s%d", Int2ColLabel(vrc.right, false), vrc.top+1+i);
-#endif
-						}
+				for(i = 0; i < 11; i++) if(dst[i]){
+					rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top+i, vrc.left, vrc.top+i, vrc.right));
 					}
 				success = true;
 				}
 			else if(vrc.right == vrc.left && (vrc.bottom - vrc.top) >2) {
-				for(i = 0; i < 11; i++) {
-					if(dst[i]){
-#ifdef USE_WIN_SECURE
-						j = sprintf_s(dst[i], 100, "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
-						sprintf_s(dst[i]+j, 100-j, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
-#else
-						j = sprintf(dst[i], "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
-						sprintf(dst[i]+j, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
-#endif
-						}
+				for(i = 0; i < 11; i++) if(dst[i]){
+					rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top, vrc.left+i, vrc.bottom, vrc.left+i));
 					}
 				success = true;
 				}
@@ -3387,46 +3445,44 @@ bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 			for(i = 0; i < 11; i++) if(dst[i]) *(dst[i]) = 0;
 			if(ranges == 1) {
 				for(i = 0, j = vrc.left; i < 11 && j <= vrc.right; i++, j++) if(dst[i]){
-#ifdef USE_WIN_SECURE
-					k = sprintf_s(dst[i], 100, "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
-					sprintf_s(dst[i]+k, 100-k, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
-#else
-					k = sprintf(dst[i], "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
-					sprintf(dst[i]+k, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
-#endif
+					rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top, vrc.left+i, vrc.bottom, vrc.left+i));
 					}
 				}
 			else if(ranges > 1) {
-				ar = new AccRange(ra[0]);	j = ar->CountItems();	delete ar;
-				for(i = 1; i < 11 && i < ranges; i++){
+				ar = new AccRange(ra[0]);		j = ar->CountItems();
+				ar->BoundRec(&rrc);				delete ar;
+				if(rrc.left == rrc.right)for(i = 1; i < 11 && i < ranges && !bErr; i++){
+					ar = new AccRange(ra[i]);	ar->BoundRec(&rrc);
+					if(rrc.left != rrc.right) bErr = true;
+					delete ar;
+					}
+				else if(rrc.top == rrc.bottom)for(i = 1; i < 11 && i < ranges && !bErr; i++){
+					ar = new AccRange(ra[i]);	ar->BoundRec(&rrc);
+					if(rrc.top != rrc.bottom) bErr = true;
+					delete ar;
+					}
+				else for(i = 1; i < 11 && i < ranges && !bErr; i++){
 					ar = new AccRange(ra[i]);
-					if(j != ar->CountItems()) {
-						InfoBox("Cannot resolve multiple ranges\nwith different sizes.\n\n"
-							"Please select ranges with equal size!");
-						i = 12;		bRet = false;
-						}
+					if(j != ar->CountItems()) bErr = true;
 					delete ar;
 					}
-				if(i < 12) for(i = 0; i < 11 && i < ranges; i++){
+				if(i < 12 && !bErr) for(i = 0; i < 11 && i < ranges; i++){
 					if(dst[i]) rlp_strcpy(dst[i], 100, ra[i]);
 					}
 				}
+			if(bErr) {
+				InfoBox("Cannot resolve multiple ranges\nwith different sizes.\n\n"
+					"Please select ranges with equal size!");
+				i = 12;		bRet = false;
+				}
 			success = true;
 			}
 		}
 	else {
 		vrc.left = vrc.top = 0;		vrc.right = vrc.bottom = 9;
 		}
-	if(!success) for(i = 0; i < 11; i++) {
- 		if(dst[i]){
-#ifdef USE_WIN_SECURE
-			j = sprintf_s(dst[i], 100, "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
-			sprintf_s(dst[i]+j, 100-j, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
-#else
-			j = sprintf(dst[i], "%s%d:", Int2ColLabel(vrc.left+i, false), vrc.top+1);
-			sprintf(dst[i]+j, "%s%d", Int2ColLabel(vrc.left+i, false), vrc.bottom+1);
-#endif
-			}
+	if(!success) for(i = 0; i < 11; i++) if(dst[i]){
+		rlp_strcpy(dst[i], 100, mkRangeRef(vrc.top, vrc.left+i, vrc.bottom, vrc.left+i));
 		}
 	if(ra) {
 		for(i = 0; i < ranges; i++) if(ra[i]) free(ra[i]);
@@ -3439,16 +3495,17 @@ bool UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Select color out of predefined palette
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *NewColorTmpl =
+	"1,2,,DEFAULT,PUSHBUTTON,-1,200,10,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,200,25,45,12\n"
+	"3,7,4,CHECKED | ISPARENT,GROUPBOX,1,200,55,45,40\n"
+	"4,5,,,LTEXT,0,210,60,45,8\n"
+	"5,6,,,LTEXT,0,210,70,45,8\n"
+	"6,,,,LTEXT,0,210,80,45,8\n"
+	"7,,8,CHECKED | ISPARENT,GROUP,0,0,0,0,0";
+
 DWORD GetNewColor(DWORD oldColor)
 {
-	char *NewColorTmpl =
-		"1, 2, 0, DEFAULT, PUSHBUTTON, -1, 200, 10, 45, 12\n"
-		"2, 3, 0, 0x0L, PUSHBUTTON, -2, 200, 25, 45, 12\n"
-		"3, 7, 4, CHECKED | ISPARENT, GROUPBOX, 1, 200, 55, 45, 40\n"
-		"4, 5, 0, 0x0L, LTEXT, 0, 210, 60, 45, 8\n"
-		"5, 6, 0, 0x0L, LTEXT, 0, 210, 70, 45, 8\n"
-		"6, 0, 0, 0x0L, LTEXT, 0, 210, 80, 45, 8\n"
-		"7, 0, 8, CHECKED | ISPARENT, GROUP, 0, 0, 0, 0, 0";
 	void *ptypes[] = {(void*)" RGB "};
 	DlgInfo *ColDlg = CompileDialog(NewColorTmpl, ptypes);
 	DWORD currcol, newcol, palette[230];
@@ -3729,26 +3786,30 @@ void GetNewFill(FillDEF *oldfill)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // execute layers dialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* LayerDlg_Tmpl =
+	"1,3,0,DEFAULT,PUSHBUTTON,-1,165,10,45,12\n"
+	"3,20,100,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"20,550,,,CHECKPIN,0,10,0,12,8\n"
+	"100,101,,TOUCHEXIT,TREEVIEW,1,10,15,100,70\n"
+	"101,102,,,EDTEXT,2, 120, 25, 90, 10\n"
+	"102,200,150,ISPARENT | CHECKED | HIDDEN,GROUP,0L,0,0,0,0\n"
+	"150,151,,TOUCHEXIT,RADIO1,3,120,35,40,9\n"
+	"151,,,TOUCHEXIT,RADIO1,4,160,35,40,9\n"
+	"200,500,,,LTEXT,5,10,5,110,9\n"
+	"500,501,600,ISPARENT | CHECKED | HIDDEN,GROUP,0,0,0,0,0\n"
+	"501,,,HIDDEN | TOUCHEXIT,TRASH,0,125,72,15,15\n"
+	"550,,,HIDDEN | TOUCHEXIT,CONFIG,0,140,72,15,15\n"
+	"600,601,,TOUCHEXIT, ODBUTTON,6,125,50,15,15\n"
+	"601,602,,TOUCHEXIT, ODBUTTON,6,145,50,15,15\n"
+	"602,603,,TOUCHEXIT, ODBUTTON,6,165,50,15,15\n"
+	"603,,,LASTOBJ | TOUCHEXIT, ODBUTTON,6,185,50,15,15";
+
 bool ShowLayers(GraphObj *root)
 {
 	char curr_name[50];
-	DlgInfo PageDlg[] = {
-		{1, 3, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 165, 10, 45, 12},
-		{3, 20, 100, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{20, 550, 0, 0x0L, CHECKPIN, 0L, 10, 0, 12, 8},
-		{100, 101, 0, TOUCHEXIT, TREEVIEW, (void*)root, 10, 15, 100, 70},
-		{101, 102, 0, 0x0L, EDTEXT, (void*)curr_name, 120, 25, 90, 10},
-		{102, 200, 150, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
-		{150, 151, 0, TOUCHEXIT, RADIO1, (void*)"hidden", 120, 35, 40, 9},
-		{151, 0, 0, TOUCHEXIT, RADIO1, (void*)"visible", 160, 35, 40, 9},
-		{200, 500, 0, 0x0L, LTEXT, (void*)"Layers:", 10, 5, 110, 9},
-		{500, 501, 600, ISPARENT | CHECKED | HIDDEN, GROUP, 0L, 0, 0, 0, 0},
-		{501, 0, 0, HIDDEN | TOUCHEXIT, TRASH, 0L, 125, 72, 15, 15},
-		{550, 0, 0, HIDDEN | TOUCHEXIT, CONFIG, 0L, 140, 72, 15, 15},
-		{600, 601, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 125, 50, 15, 15},
-		{601, 602, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 145, 50, 15, 15},
-		{602, 603, 0, TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 165, 50, 15, 15},
-		{603, 0, 0, LASTOBJ | TOUCHEXIT, ODBUTTON, (void*)OD_DrawOrder, 185, 50, 15, 15}};
+	void *dyndata[] = {(void*)root, (void*)curr_name, (void*)"hidden", (void*)"visible",
+		(void*)"Layers:", (void*)OD_DrawOrder};
+	DlgInfo *LayerDlg;
 	DlgRoot *Dlg;
 	void *hDlg;
 	int res, cl;
@@ -3756,9 +3817,9 @@ bool ShowLayers(GraphObj *root)
 	ObjTree *ot = 0L;
 	GraphObj *cgo = 0L;
 
-	if(!root) return false;
+	if(!root || !(LayerDlg = CompileDialog(LayerDlg_Tmpl, dyndata))) return false;
 	rlp_strcpy(curr_name, 50, "(root)");
-	if(!(Dlg = new DlgRoot(PageDlg, 0L)))return false;
+	if(!(Dlg = new DlgRoot(LayerDlg, 0L)))return false;
 	Dlg->ItemCmd(100, CMD_OBJTREE, &ot);
 	if(!ot) {
 		delete Dlg;			return false;
@@ -3834,8 +3895,7 @@ bool ShowLayers(GraphObj *root)
 			res = -1;
 			}
 		}while(res <0);
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;			free(LayerDlg);
 	return false;
 }
 
@@ -3904,7 +3964,7 @@ void RLPlotInfo()
 		{4, 5, 0, 0x0L, CTEXT, (void*)"scientific plotting program", 10, 30, 100, 8},
 		{5, 6, 0, 0x0L, CTEXT, (void*)"version "SZ_VERSION, 10, 38, 100, 8},
 		{6, 7, 0, HREF, CTEXT, (void*)"http://rlplot.sourceforge.net/", 5, 46, 110, 8},
-		{7, 8, 0, 0x0L, CTEXT, (void*)"Copyright (C) 2002-2006 R. Lackner", 5, 54, 110, 8},
+		{7, 8, 0, 0x0L, CTEXT, (void*)"Copyright (C) 2002-2007 R. Lackner", 5, 54, 110, 8},
 		{8, 9, 0, 0x0L, CTEXT, (void*)"reinhard.lackner at uibk.ac.at", 5, 62, 110, 9},
 		{9, 10, 0, 0x0L, CTEXT, (void*)"This is free software published", 5, 80, 110, 8},
 		{10, 11, 0, 0x0L, CTEXT, (void*)"under the GNU general public.", 5, 88, 110, 8},
@@ -3918,7 +3978,7 @@ void RLPlotInfo()
 		{4, 5, 0, 0x0L, CTEXT, (void*)"scientific plotting program", 10, 30, 100, 8},
 		{5, 6, 0, 0x0L, CTEXT, (void*)"version "SZ_VERSION, 10, 38, 100, 8},
 		{6, 7, 0, HREF, CTEXT, (void*)"http://rlplot.sourceforge.net/", 5, 46, 110, 8},
-		{7, 8, 0, 0x0L, CTEXT, (void*)"Copyright (C) 2002-2006 R. Lackner", 5, 54, 110, 8},
+		{7, 8, 0, 0x0L, CTEXT, (void*)"Copyright (C) 2002-2007 R. Lackner", 5, 54, 110, 8},
 		{8, 9, 0, 0x0L, CTEXT, (void*)"reinhard.lackner at uibk.ac.at", 5, 62, 110, 9},
 		{9, 10, 0, 0x0L, LTEXT, (void*)"powered by Trolltech\'s Qt", 35, 72, 80, 8},
 		{10, 11, 0, HREF, LTEXT, (void*)"http://www.trolltech.com", 35, 80, 80, 9},
@@ -4156,7 +4216,7 @@ bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go)
 				r1 = row;		c1 = col;
 				for( ; rF->GetNext(&col, &row); startval += stepval) {
 					if(formula[0] == '=') {
-						MoveFormula(d, formula, TmpTxt, col-c1, row-r1, -1, -1);
+						MoveFormula(d, formula, TmpTxt, TMP_TXT_SIZE, col-c1, row-r1, -1, -1);
 						d->SetText(row, col, TmpTxt);
 						}
 					else d->SetText(row, col, formula);
@@ -4869,7 +4929,7 @@ void OD_axisplot(int cmd, void *par, RECT *rec, anyOutput *o,
 		break;
 	case OD_ACCEPT:
 		if(data) names = (char**)data;
-		else Dlg->GetInt(110, &axisplot_sel);
+		else if(Dlg) Dlg->GetInt(110, &axisplot_sel);
 		if(o) *((int*)o) = axisplot_sel;
 		}
 }
diff --git a/TheDialog.h b/TheDialog.h
index ad8ac0e..aeed423 100755
--- a/TheDialog.h
+++ b/TheDialog.h
@@ -1,4 +1,4 @@
-//TheDialog.h, Copyright (c) 2001-2006 R.Lackner
+//TheDialog.h, Copyright (c) 2001-2007 R.Lackner
 //Definitions for TheDialog.cpp
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
@@ -141,7 +141,7 @@ private:
 	int cDlgs, Result, cContinue;
 	DataObj *data;
 	Dialog *oldFocus, *oldDefault, *oldTabStop;
-	bool bActive;
+	bool bActive, bRedraw;
 	GraphObj *c_go;
 	Dialog **tabstops, *mrk_item;
 	DlgTmpl **dlg;
@@ -536,6 +536,7 @@ private:
 //prototypes TheDialog.cpp
 bool UseRangeMark(DataObj *d, int type, char* =0L, char* =0L, char* =0L, char* =0L,
 	char* =0L, char* =0L, char* =0L, char* =0L, char* =0L, char* =0L, char* =0L);
+int com_StackDlg(int,DlgRoot*,AccRange**,int*,char***,int*,AccRange**,bool*,int*,int*,bool*);
 DlgInfo *CompileDialog(char* tmpl, void **ptypes);
 
 //prototypes ODbutton.cpp
@@ -552,3 +553,4 @@ void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int i
 void OD_AxisTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
 void OD_AxisTempl3D(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
 void OD_NewAxisTempl(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
+void OD_NewAxisTempl3D(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
diff --git a/UtilObj.cpp b/UtilObj.cpp
index 2b39e4f..1512ddb 100755
--- a/UtilObj.cpp
+++ b/UtilObj.cpp
@@ -1,4 +1,4 @@
-//UtilObj.cpp, (c) 2000-2006 by R. Lackner
+//UtilObj.cpp, (c) 2000-2007 by R. Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -232,13 +232,23 @@ EditText::Redraw(anyOutput *Out, bool display)
 		rc.left = loc.x;			rc.right = crb.x;
 		rc.top = loc.y+1;			rc.bottom = crb.y-2;
 		Out->oRectangle(loc.x, loc.y, crb.x-1, crb.y-1);
-		if((!text || !text[0]) && (type & 0xff) == ET_VALUE){
+		if(!text || !text[0]){
+			if((type & 0xff) == ET_VALUE){
 #ifdef USE_WIN_SECURE
-			sprintf_s(tmptxt, 500, "%g", Value);
+				sprintf_s(tmptxt, 500, "%g", Value);
 #else
-			sprintf(tmptxt, "%g", Value);
+				sprintf(tmptxt, "%g", Value);
 #endif
-			if(text = (char*)realloc(text, strlen(tmptxt)+2)) rlp_strcpy(text, 500, tmptxt);
+				}
+			else if((type & 0xff) == ET_BOOL) {
+#ifdef USE_WIN_SECURE
+				sprintf_s(tmptxt, 500, Value != 0.0 ? "true" : "false");
+#else
+				sprintf(tmptxt, Value != 0.0 ? "true" : "false");
+#endif
+				}
+			else tmptxt[0] = 0;
+			if(tmptxt[0] && (text = (char*)realloc(text, strlen(tmptxt)+2))) rlp_strcpy(text, 500, tmptxt);
 			CursorPos = 0;
 			}
 		if(ftext) free(ftext);		ftext = 0L;
@@ -1017,6 +1027,8 @@ typedef struct _tag_info {
 	int font, op;
 }tag_info;
 
+#define UC_TAG 100
+
 static tag_info tags[] = {
 	{"<i>", ~TXS_NORMAL, TXS_ITALIC, -1, 0},
 	{"</i>", ~TXS_ITALIC, TXS_NORMAL, -1, 0},
@@ -1075,7 +1087,7 @@ fmtText::StyleAt(int idx, TextDEF *txt_def, int *style, int *font)
 	if(!src || !split_text || (idx > (int)strlen(src))) return false;
 	memcpy(&td, txt_def, sizeof(TextDEF));
 	for(i = j = 0; i < n_split; i++) {
-		if((n=split_text[i].tag) >= 0  && SetTextDef(&td, n)) j += (int)strlen(tags[n].tag);
+		if((n=split_text[i].tag) >= 0 && n < UC_TAG && SetTextDef(&td, n)) j += (int)strlen(tags[n].tag);
 		if(j > idx) break;
 		if(split_text[i].txt && split_text[i].txt[0]) j += (int)strlen(split_text[i].txt);
 		if(j >= idx) break;
@@ -1111,26 +1123,70 @@ fmtText::leftTag(char *txt, int cb)
 	return -1;
 }
 
+int 
+fmtText::ucTag(char *txt, int cb, int *tl, int *ucc)
+{
+	int i, uc=0;
+
+	if(txt[cb] != '&' || txt[cb+1] != '#') return -1;
+	for(i = cb+2; txt[i] && txt[i] != ';'; i++) {
+		if(!isdigit(txt[i])) return -1;
+		}
+	if(txt[i] != ';') return -1;
+	i -= cb;
+#ifdef USE_WIN_SECURE
+	sscanf_s(txt+cb+2, "%d", &uc);
+#else
+	sscanf(txt+cb+2, "%d", &uc);
+#endif
+	if(tl) *tl = i+1;		if(ucc) *ucc = uc;
+	return UC_TAG;
+}
+
+int
+fmtText::ucLeft(char *txt, int cb, int *tl, int *ucc)
+{
+	int i, uc = 0;
+
+	for(i = 1; i < 6 && i < cb && txt[cb-i] != '#'; i++) {
+		if(!isdigit(txt[cb-i])) return -1;
+		}
+	if(txt[cb-i] != '#' || txt[cb-i-1] != '&') return -1;
+#ifdef USE_WIN_SECURE
+	sscanf_s(txt+cb-i+1, "%d", &uc);
+#else
+	sscanf(txt+cb-i+1, "%d", &uc);
+#endif
+	if(tl) *tl = i+1;			if(ucc) *ucc = uc;
+	return UC_TAG;
+}
+
 void
 fmtText::cur_right(int *pos)
 {
-	int n;
+	int n, tl;
 
 	if(!src || !pos || !src[*pos]) return;
 	if(src[*pos] == '<' && (n=rightTag(src, *pos)) >= 0) {
 		*pos += (int)strlen(tags[n].tag);
 		cur_right(pos);
 		}
+	else if(src[*pos] == '&' && (ucTag(src, *pos, &tl, 0L)== UC_TAG)){
+		*pos += tl;
+		}
 	else (*pos)++;
 }
 
 void 
 fmtText::cur_left(int *pos)
 {
-	int n;
+	int n, tl;
 
 	if(!src || !pos || !(*pos)) return;
 	(*pos)--;
+	if(src[*pos] == ';' && (n=ucLeft(src, *pos, &tl, 0L)) == UC_TAG) {
+		*pos -= tl;		return;
+		}
 	while (src[*pos] == '>' && (n=leftTag(src, *pos)) >= 0) {
 		*pos -= (int)strlen(tags[n].tag);
 		}
@@ -1148,9 +1204,19 @@ fmtText::oGetTextExtent(anyOutput *o, int *width, int *height, int cb)
 	if(!split_text) return o->oGetTextExtent(src, cb, width, height);
 	memcpy(&td1, &o->TxtSet, sizeof(TextDEF));	memcpy(&td2, &o->TxtSet, sizeof(TextDEF));
 	for(i = w = h = l = l1 = 0; i < n_split; i++){
-		if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) {
-			o->SetTextSpec(&td2);
-			l += (int)strlen(tags[n].tag);
+		if(split_text[i].tag == UC_TAG) {
+			o->oGetTextExtentW((w_char*)(&split_text[i].uc), 1, &w1, &h1);
+			w += w1;		h = h1 > h ? h1 : h;
+			l += split_text[i].uc_len;
+			}
+		else {
+			if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) {
+				o->SetTextSpec(&td2);
+				l += (int)strlen(tags[n].tag);
+				}
+			if(tags[n].font == -1 && tags[n].op > 0 && tags[n].op < 100) {
+				w += o->un2ix(td2.fSize/2.0);
+				}
 			}
 		if(split_text[i].txt && split_text[i].txt[0]){
 			l1 = l;		l += (int)strlen(split_text[i].txt);
@@ -1159,9 +1225,6 @@ fmtText::oGetTextExtent(anyOutput *o, int *width, int *height, int cb)
 			w += w1;	h = h1 > h ? h1 : h;
 			if (l >= cb) break;
 			}
-		if(tags[n].font == -1 && tags[n].op > 0 && tags[n].op < 100) {
-			w += o->un2ix(td2.fSize/2.0);
-			}
 		}
 	*width = w;			*height = h;		o->SetTextSpec(&td1);
 	return true;
@@ -1215,17 +1278,21 @@ fmtText::SetTextDef(TextDEF *td, int idx)
 bool
 fmtText::Parse()
 {
-	int i, li, j, n;
+	int i, li, j, n, tl, uc;
 	char *tmp;
 
 	if((flags & 0x01) || !src || !(tmp = (char*)memdup(src, (int)strlen(src)+1, 0))) return false;
 	for(i = li = 0; src[i]; i++) {
+		if(i-li == 1 && split_text) {
+			if(src[li] == '<' && (n=rightTag(src, li))>=0) i--;
+			else if(src[li] == '&' && (n=ucTag(src, li, &tl, &uc))>0) i--;
+			}
 		if(src[i] == '<' && (n=rightTag(src, i))>=0) {
 			if(split_text) {				//more tags in text
 				if(!(split_text = (fmt_txt_info *)realloc(split_text, (n_split+1)*sizeof(fmt_txt_info)))){
 					free(tmp);					return false;
 					}
-				for(j = li; j < i; j++) tmp[j-li]= src[j];	tmp[j-li]=0;
+				for(j = li; j < i; j++) tmp[j-li] = src[j];	tmp[j-li]=0;
 				split_text[n_split-1].txt = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
 				i += (int)strlen(tags[n].tag);	split_text[n_split].tag = n;
 				split_text[n_split++].txt = 0L;
@@ -1242,6 +1309,30 @@ fmtText::Parse()
 				}
 			li = i;							i--;
 			}
+		else if(src[i] == '&' && (n=ucTag(src, i, &tl, &uc))>0) {
+			if(split_text) {				//more tags in text
+				if(!(split_text = (fmt_txt_info *)realloc(split_text, (n_split+1)*sizeof(fmt_txt_info)))){
+					free(tmp);					return false;
+					}
+				for(j = li; j < i; j++) tmp[j-li] = src[j];	tmp[j-li]=0;
+				split_text[n_split-1].txt = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
+				i += tl;						split_text[n_split].tag = n;
+				split_text[n_split].uc = uc;	split_text[n_split].uc_len = tl;
+				split_text[n_split++].txt = 0L;
+				}
+			else {							//first tag of text
+				if(!(split_text = (fmt_txt_info *)calloc(2, sizeof(fmt_txt_info)))){
+					free(tmp);					return false;
+					}
+				for(j = 0; j < i; j++) tmp[j]= src[j];	tmp[j]=0;
+				split_text[0].tag = -1;		
+				split_text[0].txt = (char*)memdup(tmp, (int)strlen((char*)tmp)+1, 0);
+				i += tl;					split_text[1].tag = n;
+				split_text[1].uc = uc;		n_split = 2;
+				split_text[1].uc_len = tl;
+				}
+			li = i;
+			}
 		}
 	if(split_text && n_split && li < i && src[li]) 
 		split_text[n_split-1].txt = (char*)memdup(src+li, (int)strlen((char*)src+li)+1,0);
@@ -1316,6 +1407,7 @@ fmtText::DrawFormatted(anyOutput *o)
 	int i, n, x, y, x1, y1, w, h;
 	TextDEF td1, td2;
 	double si, csi, fx, fy;
+	w_char one_uc[2];
 
 	if(!o || !split_text) return;
 	memcpy(&td1, &o->TxtSet, sizeof(TextDEF));	memcpy(&td2, &o->TxtSet, sizeof(TextDEF));
@@ -1330,8 +1422,14 @@ fmtText::DrawFormatted(anyOutput *o)
 		}
 	x = iround(fx);			y = iround(fy);
 	td2.Align &= ~(TXA_HRIGHT | TXA_HCENTER);			o->SetTextSpec(&td2);
-	for(i = 0; i < n_split; i++) if(split_text[i].txt) {
-		if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) o->SetTextSpec(&td2);
+	for(i = 0; i < n_split; i++) if(split_text[i].txt || split_text[i].tag == UC_TAG) {
+		if(split_text[i].tag == UC_TAG) {
+			one_uc[0] = split_text[i].uc;	one_uc[1] = 0;
+			o->oGetTextExtentW(one_uc, 1, &w, &h);
+			if(!(o->oTextOutW(x, y, one_uc, 1))) o->oTextOut(x, y, "?", 1);
+			x = iround(fx += (w*csi));		y = iround(fy -= (w*si));
+			}
+		else if((n=split_text[i].tag) >= 0 && SetTextDef(&td2, n)) o->SetTextSpec(&td2);
 		else if(n >= 0 && tags[n].op) {
 			x1 = x + iround(o->un2fix(td2.fSize*0.25)*csi);
 			y1 = y - iround(o->un2fiy(td2.fSize*0.25)*si);
@@ -1366,7 +1464,7 @@ fmtText::DrawFormatted(anyOutput *o)
 				}
 			o->SetTextSpec(&td2);
 			}
-		if(split_text[i].txt){
+		if(split_text[i].txt && split_text[i].txt[0]){
 			o->oTextOut(x, y, split_text[i].txt, 0);
 			o->oGetTextExtent(split_text[i].txt, 0, &w, &h);
 			x = iround(fx += (w*csi));		y = iround(fy -= (w*si));
@@ -1380,6 +1478,98 @@ fmtText::EditMode(bool bEdit)
 	if(bEdit) flags |= 0x01;
 	else flags &= ~(0x01);
 }
+#undef UC_TAG
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// assign a value to a string
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+TextValue::TextValue()
+{
+	items = 0L;		nitems = 0;		next = inc = 1.0;
+}
+
+TextValue::TextValue(TextValItem **tvi, int ntvi)
+{
+	int i;
+
+	items = 0L;		nitems = 0;		next = inc = 1.0;
+	if(ntvi && (items = (TextValItem **)malloc(ntvi*sizeof(TextValItem*)))){
+		for(i = 0, nitems = ntvi; i < ntvi; i++) {
+			if(items[i] = (TextValItem*)memdup(tvi[i], sizeof(TextValItem), 0)){
+				if(tvi[i]->text) items[i]->text = (char*)memdup(tvi[i]->text, (int)strlen(tvi[i]->text)+1, 0);
+				}
+			}
+		nitems = ntvi;	if(items[nitems-1]) next = items[nitems-1]->val + inc;
+		}
+}
+
+TextValue::~TextValue()
+{
+	Reset();
+}
+
+double
+TextValue::GetValue(char *txt)
+{
+	unsigned int hv1, hv2;
+	int i;
+
+	if(!txt || !txt[0]) return 0.0;
+	hv1 = HashValue((unsigned char*)txt);
+	hv2 = Hash2((unsigned char*)txt);
+	if(items && nitems) for(i = 0; i < nitems; i++) {
+		if(items[i] && items[i]->hv1 == hv1 && items[i]->hv2 == hv2) return items[i]->val;
+		}
+	else if(!items &&(items = (TextValItem **)malloc(sizeof(TextValItem*)))) {
+		if(items[0] = (TextValItem*)calloc(1, sizeof(TextValItem))) {
+			items[0]->hv1 = hv1;		items[0]->hv2 = hv2;
+			items[0]->text = (char*)memdup(txt, (int)strlen(txt)+1, 0);
+			items[0]->val = next;		next += inc;
+			nitems = 1;					return (next-inc);
+			}
+		return 0.0;
+		}
+	else return 0.0;
+	if(items = (TextValItem **)realloc(items, (nitems+1)*sizeof(TextValItem*))){
+		if(items[nitems] = (TextValItem*)calloc(1, sizeof(TextValItem))) {
+			items[nitems]->hv1 = hv1;		items[nitems]->hv2 = hv2;
+			items[nitems]->text = (char*)memdup(txt, (int)strlen(txt)+1, 0);
+			items[nitems]->val = next;		next += inc;	nitems++;
+			return (next-inc);
+			}
+		}
+	return 0.0;
+}
+
+bool
+TextValue::GetItem(int idx, char **text, double *value)
+{
+	if(items && idx >=0 && idx < nitems) {
+		if(text) *text = items[idx]->text;
+		if(value) *value = items[idx]->val;
+		return true;
+		}
+	return false;
+}
+
+void
+TextValue::Reset()
+{
+	int i;
+
+	if(items) for(i = 0; i < nitems; i++){
+		if(items[i]->text) free(items[i]->text);
+		free(items[i]);
+		}
+	if(items && nitems) free(items);
+	next = inc = 1.0;	items = 0L;		nitems = 0;
+}
+
+TextValue *
+TextValue::Copy()
+{
+	return new TextValue(items, nitems);
+}
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // manage formats and style of a spreadsheet range
@@ -1475,7 +1665,7 @@ DataObj::DataObj()
 {
 	cRows = cCols = 0;
 	etRows = 0L;
-	ri = new RangeInfo(0, 1, 1, 1, 0L);
+	ri = new RangeInfo(0, 76, 19, 32, 0L);
 }
 
 DataObj::~DataObj()
@@ -1792,7 +1982,7 @@ notary::PushGO(unsigned int id, GraphObj *go)
 	if(!go) return true;
 	go->Id = id;
 	if(!goStack) {
-		goStack = (GraphObj ***)calloc(8192, sizeof(GraphObj **));
+		if(!(goStack = (GraphObj ***)calloc(8192, sizeof(GraphObj **))))return false;
 		goStack[0] = (GraphObj **)calloc(8192, sizeof(GraphObj *));
 		if(goStack && goStack[0]) {
 			goStack[0][0] = go;
@@ -1921,12 +2111,15 @@ AccRange::~AccRange()
 int
 AccRange::CountItems()
 {
-	int RetVal;
+	int RetVal, l;
 
 	RetVal = 0;
-	if(txt && Reset())	do {
-		RetVal += ((x2-x1+1)*(y2-y1+1));
-		} while((curridx < (int)strlen(txt)) && Parse(curridx));
+	if(txt && txt[0] && Reset()){
+		l = (int)strlen(txt);
+		do {
+			RetVal += ((x2-x1+1)*(y2-y1+1));
+			} while((curridx < l) && Parse(curridx));
+		}
 	return RetVal;
 }
 
@@ -1961,7 +2154,7 @@ bool
 AccRange::NextRow(int *y)
 {
 	if(cy <= y2) {
-		*y = cy;	cy++;	return true;
+		*y = cy;	cy++;	cx = x1;	return true;
 		}
 	else if(txt[curridx] && Parse(curridx)) return NextRow(y);
 	return false;
@@ -2014,7 +2207,7 @@ AccRange::Parse(int start)
 
 	i = start;
 	if(!txt) return false;
-	if(txt[i] == ';' || txt[i] == ',') i++;
+	while(txt[i] == ';' || txt[i] == ',') i++;
 	if(!txt[i]) return false;
 	step = x1 = y1 = x2 = y2 = 0;
 	v = &x1;
@@ -2077,20 +2270,36 @@ AccRange::Parse(int start)
 char *
 AccRange::RangeDesc(void *d, int style)
 {
-	anyResult res;
+	anyResult res, res1;
 	int cb;
 	char *desc;
 
 	if(!d || !txt || !Reset())return 0L;
-	((DataObj*)d)->GetResult(&res, y1, x1, false);
-	if(res.type == ET_TEXT) {
+	if(!((DataObj*)d)->GetResult(&res, y1, x1, false))return 0L;
+	if(style == 3) {
+		if(x1 == x2 && y1 > 0 && res.type == ET_TEXT) {
+			if(((DataObj*)d)->GetResult(&res1, 0, x1, false) && res1.type == ET_TEXT)
+				return (char*)memdup(res1.text, (int)strlen(res1.text)+1, 0);
+			}
+		if(y1 == y2 && x1 > 0 && res.type == ET_TEXT) {
+			if(((DataObj*)d)->GetResult(&res1, y1, 0, false) && res1.type == ET_TEXT)
+				return (char*)memdup(res1.text, (int)strlen(res1.text)+1, 0);
+			}
+		}
+	switch(res.type) {
+	case ET_TEXT:
+		if(res.text && res.text[0])
+			return (char*)memdup(res.text, (int)strlen(res.text)+1, 0);
+		else return 0L;
+	case ET_DATE:	case ET_DATETIME:	case ET_TIME:
+		TranslateResult(&res);
 		if(res.text && res.text[0])
 			return (char*)memdup(res.text, (int)strlen(res.text)+1, 0);
 		else return 0L;
 		}
 	if(!(desc = (char*)malloc(40*sizeof(char))))return 0L;
 	if(x1 == x2) {
-		if(style == 1) cb = rlp_strcpy(desc, 40, "Col. ");
+		if(style == 1 || style == 3) cb = rlp_strcpy(desc, 40, "Col. ");
 		else if(style == 2) cb = rlp_strcpy(desc, 40, "Column ");
 		else goto rdesc_err;
 		rlp_strcpy(desc+cb, 40-cb, Int2ColLabel(x1, true));
@@ -2109,6 +2318,29 @@ rdesc_err:
 	return 0L;
 }
 
+int 
+AccRange::DataTypes(void *d, int *numerical, int *strings, int *datetime)
+{
+	anyResult res;
+	int n, r, c, c_num, c_txt, c_dattim;
+
+	if(!d || !Reset()) return 0;
+	for(n = c_num = c_txt = c_dattim = 0, GetFirst(&c, &r); GetNext(&c, &r); n++) {
+		if(((DataObj*)d)->GetResult(&res, r, c, false)) {
+			switch(res.type) {
+			case ET_VALUE:		c_num++;		break;
+			case ET_TEXT:		c_txt++;		break;
+			case ET_DATE:		case ET_TIME:	case ET_DATETIME:		
+				c_dattim++;		break;
+				}
+			}
+		}
+	if(numerical) *numerical = c_num;
+	if(strings) *strings = c_txt;
+	if(datetime) *datetime = c_dattim;
+	return n;
+}
+
 //---------------------------------------------------------------------------
 // Use the Delauney triangulation to create a 3D mesh of dispersed data
 //---------------------------------------------------------------------------
@@ -2254,7 +2486,7 @@ Default::Default()
 	Fill_0.scale = Fill_1.scale = Fill_2.scale = 1.0;			//size = 100%
 	Fill_0.hatch = &FillLine_0;	Fill_1.hatch = &FillLine_1;	Fill_2.hatch = &FillLine_2;
 	Fill_0.color2 = Fill_1.color2 = Fill_2.color2 = 0x00ffffffL;	//white background
-	OutLine_0.width = .2;	OutLine_1.width = .1;	OutLine_2.width = 0.008;
+	OutLine_0.width = .2;	OutLine_1.width = .02;	OutLine_2.width = 0.008;
 	OutLine_0.patlength = 6.0;	OutLine_1.patlength = 0.6;	OutLine_2.patlength = 0.24;
 	OutLine_0.color = OutLine_1.color = OutLine_2.color = 0x00000000L;
 	OutLine_0.pattern = OutLine_1.pattern = OutLine_2.pattern = 0L;
@@ -2348,6 +2580,7 @@ Default::GetSize(int select)
 	case SIZE_CELLTEXT:				RetVal = 4.5*ss_txt;		break;
 	case SIZE_RRECT_RAD:			
 		return rrect_rad ? *rrect_rad : GetSize(SIZE_SYMBOL);
+	case SIZE_SCALE:				return 1.0;
 	default:	return 0.0;
 		}
 	switch(cUnits) {
@@ -2875,6 +3108,7 @@ UndoObj::KillDisp(anyOutput *o)
 {
 	int i, j, c_buf;
 
+	InvalidateOutput(o);			//kill text cursor and animated rectangle
 	if(o && buffers) {
 		for(i = 0, c_buf = -1; i < ndisp; i++) {
 			if(buffers[i] && buffers[i]->disp == o)	{
@@ -2961,9 +3195,8 @@ UndoObj::Restore(bool redraw, anyOutput*o)
 	if(!buff[idx]) return;
 	if(buff[idx]->zd.org.fx != cdisp->VPorg.fx ||
 		buff[idx]->zd.org.fy != cdisp->VPorg.fy || buff[idx]->zd.scale != cdisp->VPscale){
-		cdisp->VPorg.fx = buff[idx]->zd.org.fx;
-		cdisp->VPorg.fy = buff[idx]->zd.org.fy;
-		cdisp->VPscale = buff[idx]->zd.scale;
+		cdisp->VPorg.fx = buff[idx]->zd.org.fx;			cdisp->VPorg.fy = buff[idx]->zd.org.fy;
+		cdisp->VPscale = buff[idx]->zd.scale;			HideCopyMark();
 		if(cdisp->VPscale > 100.0) cdisp->VPscale = 100.0;
 		if(cdisp->VPscale < 0.05) cdisp->VPscale = 0.05;
 		if(buff[idx]->owner)
@@ -3073,8 +3306,9 @@ UndoObj::Restore(bool redraw, anyOutput*o)
 			memcpy(buff[idx]->loc, buff[idx]->data, sizeof(fRECT));
 			free(buff[idx]->data);								break;
 		case UNDO_STRING:
-			if(*(buff[idx]->loc) && buff[idx]->data) 
-				strcpy ((char*)(*buff[idx]->loc), (char*)(buff[idx]->data));
+			if(*(buff[idx]->loc) && buff[idx]->data)
+				rlp_strcpy ((char*)(*buff[idx]->loc), 100, (char*)(buff[idx]->data));
+			else if(*(buff[idx]->loc))((char*)*(buff[idx]->loc))[0] = 0;
 			if(buff[idx]->data) free(buff[idx]->data);
 			CurrGO = buff[idx]->owner;							break;
 		case UNDO_ROTDEF:
@@ -3337,7 +3571,8 @@ UndoObj::String(GraphObj *go, char **s, DWORD flags)
 	int iret;
 
 	if(s && *s &&  *(*s)){
-		ptr = strdup(*(s));		iret = (int)strlen(*(s));
+		iret = (int)strlen(*(s));
+		ptr = (char*)memdup(*(s), iret+1, 0);
 		}
 	else {
 		ptr = 0L;				iret = 0;
@@ -3397,8 +3632,10 @@ UndoObj::TextDef(GraphObj *go, TextDEF *td, DWORD flags)
 	TextDEF *ptr;
 
 	if(!(ptr = (TextDEF*) memdup(td, sizeof(TextDEF), 0))) return;
-	if(td->text) ptr->text = strdup(td->text);
-	if(0 > NewItem(UNDO_TEXTDEF, flags, go, ptr, (void**)td)) free(ptr);
+	if(td->text && td->text[0]) ptr->text = (char*)memdup(td->text, (int)strlen(td->text)+1, 0);
+	if(0 > NewItem(UNDO_TEXTDEF, flags, go, ptr, (void**)td)){
+		if(ptr->text) free(ptr->text);		free(ptr);
+		}
 }
 
 void
@@ -3459,7 +3696,7 @@ UndoObj::TextCell(EditText *et, anyOutput *o, char *text, int *cur, int *m1, int
 	if(o) {
 		o_save = cdisp;		SetDisp(o);
 		if(ptr = (EtBuff*) calloc(1, sizeof(EtBuff))) {
-			if(text && text[0]) ptr->txt = strdup(text);
+			if(text && text[0]) ptr->txt = (char*)memdup(text, (int)strlen(text)+1, 0);
 			ptr->cur = cur;			ptr->m1 = m1;		ptr->m2 = m2;
 			ptr->vcur = *cur;		ptr->vm1 = *m1;		ptr->vm2 = *m2;
 			ptr->row = et->row;		ptr->col = et->col;
diff --git a/Utils.cpp b/Utils.cpp
index 0a538db..66bea56 100755
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -1,4 +1,4 @@
-//Utils.cpp, Copyright (c) 2000-2006 R.Lackner
+//Utils.cpp, Copyright (c) 2000-2007 R.Lackner
 //Collection of utility functions and classes for RLPlot
 //
 //    This file is part of RLPlot.
@@ -89,7 +89,11 @@ void NiceAxis(AxisDEF *axis, int nTick)
 	HiVal = LoVal = Step * floor(axis->min/Step);
 	axis->max *=1.05f;
 	while(HiVal < axis->max) HiVal += Step;
-	axis->min = LoVal;
+	if((axis->flags & AXIS_LOG) == AXIS_LOG) {
+		if (LoVal > defs.min4log) axis->min = LoVal;
+		if ((LoVal + Step) > defs.min4log && (LoVal + Step) < axis->min) axis->min = LoVal+Step;
+		}
+	else axis->min = LoVal;
 	axis->max = HiVal;
 	axis->Start = axis->min;
 	axis->Step = Step;
@@ -126,8 +130,7 @@ double base4log(AxisDEF *axis, int direc)
 	case 2:		cmd = SIZE_BOUNDS_ZMIN;		break;
 	default:	return 1.0;
 		}
-	if(axis->min > defs.min4log) lv = axis->min;
-	else lv = ((GraphObj*)axis->owner)->GetSize(cmd);
+	lv = axis->min > defs.min4log ? axis->min : defs.min4log;
 	if(lv <= defs.min4log) return defs.min4log;
 	lv = log10(lv);
 	lv -= (Magn = floor(lv));
@@ -303,7 +306,7 @@ char *strreplace(char *needle, char *replace, char *haystack)
 	static size_t reslen = 0;
 	size_t i, j, k, l;
 
-	if(!needle || !needle[0] || !haystack || !haystack[0]) haystack;
+	if(!needle || !needle[0] || !haystack || !haystack[0]) return result;
 	if(!result) result = (char*)malloc(reslen = 100);
 	result[0] = 0;		l = strlen(needle);
 	for(i = j = k = 0; haystack[i]; i++, j=0) {
@@ -542,9 +545,31 @@ char *Int2ColLabel(int nr1, bool uc)
 	return RetTxt+i+1;
 }
 
+char *mkCellRef(int row, int col)
+{
+	static char RetTxt[20];
+
+#ifdef USE_WIN_SECURE
+	sprintf_s(RetTxt, 20, "%s%d", Int2ColLabel(col, false), row+1);
+#else
+	sprintf(RetTxt, "%s%d", Int2ColLabel(col, false), row+1);
+#endif
+	return RetTxt;
+}
+
+char *mkRangeRef(int r1, int c1, int r2, int c2)
+{
+	static char RetTxt[40];
+	int cb;
+
+	cb = rlp_strcpy(RetTxt, 20, mkCellRef(r1, c1)); 
+	RetTxt[cb++] = ':';
+	rlp_strcpy(RetTxt+cb, 40-cb, mkCellRef(r2, c2));
+	return RetTxt;
+}
 //convert strings to XML specifications
 //this offers a limited support for special characters
-char *str2xml(char *str)
+char *str2xml(char *str, bool bGreek)
 {
 	int i, j;
 	wchar_t wc;
@@ -565,7 +590,14 @@ char *str2xml(char *str)
 			j += rlp_strcpy(TmpTxt+j, TMP_TXT_SIZE-j, ">");
 			break;
 		default:
-			if((unsigned char)str[i] <= 127) TmpTxt[j++]=str[i];
+#ifdef USE_WIN_SECURE
+			if(bGreek && str[i] >= 'A' && str[i] <= 'Z') j += sprintf_s(TmpTxt+j, 20, "&#%d;", str[i] - 'A' + 0x391);
+			else if(bGreek && str[i] >= 'a' && str[i] <= 'z') j += sprintf_s(TmpTxt+j, 20, "&#%d;", str[i] - 'a' + 0x3B1);
+#else
+			if(bGreek && str[i] >= 'A' && str[i] <= 'Z') j += sprintf(TmpTxt+j, "&#%d;", str[i] - 'A' + 0x391);
+			else if(bGreek && str[i] >= 'a' && str[i] <= 'z') j += sprintf(TmpTxt+j, "&#%d;", str[i] - 'a' + 0x3B1);
+#endif
+			else if((unsigned char)str[i] <= 127) TmpTxt[j++]=str[i];
 			else {
 				if(mbtowc(&wc, str+i, 1) >0) 
 #ifdef USE_WIN_SECURE
@@ -610,7 +642,7 @@ char **split(char *str, char sep, int *nl)
 char *fit_num_rect(anyOutput *o, int max_width, char *num_str)
 {
 	int i, j, k, w, h, slen;
-	char mant[20], expo[20], fmt[10];
+	char mant[30], expo[30], fmt[20];
 	double num;
 
 	o->oGetTextExtent(num_str, slen = (int)strlen(num_str), &w, &h);
@@ -636,8 +668,8 @@ char *fit_num_rect(anyOutput *o, int max_width, char *num_str)
 #endif
 	if(k >0) do {
 #ifdef USE_WIN_SECURE
-		sprintf_s(fmt, 10, "%%.%dlf%s", k, expo);
-		slen = sprintf_s(num_str, 40, fmt, num);		//num_str is much longer than 40
+		sprintf_s(fmt, 20, "%%.%dlf%s", k, expo);
+		slen = sprintf_s(num_str, 60, fmt, num);		//num_str is much longer than 60
 #else
 		sprintf(fmt, "%%.%dlf%s", k, expo);
 		slen = sprintf(num_str, fmt, num);
@@ -939,6 +971,90 @@ void DrawBezier(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, in
 }
 
 //----------------------------------------------------------------------------
+// create a Bezier spline through data points
+static void ipol_curve(lfPOINT *p1, lfPOINT *p2, lfPOINT *p3, lfPOINT *cp1, lfPOINT *cp2)
+{
+	double dx, dy, l;
+	lfPOINT tHat;
+
+	tHat.fx = p3->fx - p1->fx;		tHat.fy = p3->fy - p1->fy;
+	l = sqrt(tHat.fx * tHat.fx + tHat.fy * tHat.fy);
+	tHat.fx /= l;					tHat.fy /= l;
+	cp1->fx = cp2->fx = p2->fx;		cp1->fy = cp2->fy = p2->fy;
+	dx = p3->fx - p2->fx;			dy = p3->fy - p2->fy;		l = sqrt(dx*dx + dy*dy)/3.0;
+	cp2->fx += (tHat.fx * l);		cp2->fy += (tHat.fy *l);
+	dx = p2->fx - p1->fx;			dy = p2->fy - p1->fy;		l = sqrt(dx*dx + dy*dy)/3.0;
+	cp1->fx -= (tHat.fx * l);		cp1->fy -= (tHat.fy *l);
+}
+
+static void mirr_vecvec(lfPOINT *a0, lfPOINT *a1, lfPOINT *v1)
+{
+	double dx, dy, as, ac, vs, vc, s, c, l;
+	lfPOINT sol1, sol2;
+
+	//mirror vector a0 -> v1 by rotation around vector a0 -> a1
+	dx = a1->fx - a0->fx;					dy = a1->fy - a0->fy;
+	l = sqrt(dx*dx + dy*dy);	as = dy/l;			ac = dx/l;
+	dx = v1->fx - a0->fx;					dy = v1->fy - a0->fy;
+	l = sqrt(dx*dx + dy*dy);	vs = dy/l;			vc = dx/l;
+	//calculate cw and ccw solution
+	s = sin((asin(as)-asin(vs))*2.0);		c = cos((acos(ac)-acos(vc))*2.0);
+	sol1.fx = dx * c + dy * s + a0->fx;		sol1.fy = dy * c - dx * s + a0->fy;
+	s = sin((asin(as)-asin(-vs))*2.0);		c = cos((acos(ac)-acos(-vc))*2.0);
+	sol2.fx = dx * c + dy * s + a0->fx;		sol2.fy = dy * c - dx * s + a0->fy;
+	//get better solution
+	dx = sol1.fx - a1->fx;					dy = sol1.fy - a1->fy;
+	l = sqrt(dx*dx + dy*dy);
+	dx = sol2.fx - a1->fx;					dy = sol2.fy - a1->fy;
+	if( l < sqrt(dx*dx + dy*dy)) {
+		v1->fx = sol1.fx;					v1->fy = sol1.fy;
+		}
+	else {
+		v1->fx = sol2.fx;					v1->fy = sol2.fy;
+		}
+}
+
+int mkCurve(lfPOINT *src, int n1, lfPOINT **dst, bool bClosed)
+{
+	int i, j, iret;
+
+	if(!src || n1 < 3) return 0;
+	if(!(*dst = (lfPOINT*)malloc((n1*3+2) * sizeof(lfPOINT))))return 0;
+	for(i = j = iret = 0; i < n1; i++, j += 3) {
+		(*dst)[j].fx = src[i].fx;		(*dst)[j].fy = src[i].fy;
+		if(i && i < (n1-1)){
+			ipol_curve(&src[i-1], &src[i], &src[i+1], *dst+j-1, *dst+j+1);
+			}
+		else if(i) {
+			iret = j+1;					break;
+			}
+		}
+	if(bClosed && iret >2) {
+		if((*dst)[j].fx != (*dst)[0].fx || (*dst)[j].fy != (*dst)[0].fy) {
+			j += 3;								iret += 3;
+			(*dst)[j].fx = (*dst)[0].fx;		(*dst)[j].fy = (*dst)[0].fy;	
+			}
+		if(j < 6) {
+			free(*dst);		*dst = 0L;				return 0;
+			}
+		ipol_curve(*dst+j-3, *dst+j, *dst+3, *dst+j-1, *dst+1);
+		ipol_curve(*dst+j-6, *dst+j-3, *dst+j, *dst+j-4, *dst+j-2);
+		}
+	else if(!bClosed && iret>3) {
+		(*dst)[1].fx = (*dst)[0].fx + (*dst)[3].fx - (*dst)[2].fx;
+		(*dst)[1].fy = (*dst)[0].fy + (*dst)[3].fy - (*dst)[2].fy;
+		mirr_vecvec(*dst, *dst+3, *dst+1);
+		(*dst)[j-1].fx = (*dst)[j].fx + (*dst)[j-3].fx - (*dst)[j-2].fx;
+		(*dst)[j-1].fy = (*dst)[j].fy + (*dst)[j-3].fy - (*dst)[j-2].fy;
+		mirr_vecvec(*dst+j, *dst+j-3, *dst+j-1);
+		}
+	else {
+		free(*dst);			*dst = 0L;				return 0;
+		}
+	return iret;
+}
+
+//----------------------------------------------------------------------------
 // create a circular polygon
 //use circular Bresenham's algorithm to draw arcs
 //Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
@@ -1253,6 +1369,7 @@ void DeleteGO(GraphObj *go)
 	case GO_FITFUNC3D:		delete((FitFunc3D*)go);		break;
 	case GO_BEZIER:			delete((Bezier*)go);		break;
 	case GO_TEXTFRAME:		delete((TextFrame*)go);		break;
+	case GO_NORMQUANT:		delete((NormQuant*)go);		break;
 	default:
 #ifdef USE_WIN_SECURE
 		sprintf_s(TmpTxt, TMP_TXT_SIZE, "Cannot delete Object\nwith Id %ld", go->Id);
@@ -1395,7 +1512,7 @@ bool FileExist(char *FileName)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 bool IsPlot3D(GraphObj *g)
 {
-	if(g && (g->Id == GO_PLOT3D || g->Id == GO_FUNC3D)) return true;
+	if(g && (g->Id == GO_PLOT3D || g->Id == GO_FUNC3D || g->Id == GO_FITFUNC3D)) return true;
 	return false;
 }
 
@@ -1561,6 +1678,31 @@ DWORD CheckNewLFPoint(lfPOINT *loc, lfPOINT *old_v, lfPOINT *new_v, GraphObj *pa
 	return flags;
 }
 
+DWORD CheckNewString(char **loc, char *s_old, char *s_new, GraphObj *par, DWORD flags)
+{
+	int ocb, ncb, cb;
+
+	if(s_old && s_new) {
+		if(!strcmp(s_old, s_new)) return flags;
+		ocb = (int)strlen(s_old);		ncb = (int)strlen(s_new);
+		cb = ncb > ocb ? ncb : ocb;
+		if(cb > ocb) {
+			*loc = (char*)realloc(*loc, cb * sizeof(char)+1);
+			}
+		Undo.String(par, loc, flags);	flags |= UNDO_CONTINUE;
+		if(*loc) rlp_strcpy(*loc, cb+1, s_new); 
+		}
+	else if(!s_old && s_new && s_new[0]) {
+		Undo.String(par, loc, flags);	flags |= UNDO_CONTINUE;
+		*loc = (char *)memdup(s_new, (int)strlen(s_new) +1, 0);
+		}
+	else if(s_old && s_old[0] && !s_new) {
+		Undo.String(par, loc, flags);	flags |= UNDO_CONTINUE;
+		if(*loc) *loc[0] = 0;
+		}
+	return flags;
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //execute clipping of 3D objects
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Version.h b/Version.h
index 95a98b5..2e349aa 100755
--- a/Version.h
+++ b/Version.h
@@ -1,4 +1,4 @@
-//RLPlot.h, Copyright (c) 2000-2006 R.Lackner
+//RLPlot.h, Copyright (c) 2000-2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -16,4 +16,4 @@
 //    along with RLPlot; if not, write to the Free Software
 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 //
-#define SZ_VERSION  "1.2"
+#define SZ_VERSION  "1.3"
diff --git a/WinSpec.cpp b/WinSpec.cpp
index e59c53b..a51b74b 100755
--- a/WinSpec.cpp
+++ b/WinSpec.cpp
@@ -1,4 +1,4 @@
-//WinSpec.cpp, Copyright (c) 2000-2006 R.Lackner
+//WinSpec.cpp, Copyright (c) 2000-2007 R.Lackner
 //the entire code of this module is highly specific to Windows!
 //
 //    This file is part of RLPlot.
@@ -19,6 +19,9 @@
 //
 #include <stdio.h>
 #include <math.h>
+#include <fcntl.h>				//file open flags
+#include <sys/stat.h>			//I/O flags
+#include <io.h>					//for read/write
 #include "rlplot.h"
 #include "WinSpec.h"
 #include "rlplot.rc"
@@ -30,7 +33,6 @@ extern int dlgtxtheight;
 HINSTANCE hInstance;
 HWND MainWnd = 0L;
 HACCEL accel;
-bool isWIN95 = false;
 extern tag_Units Units[];
 extern GraphObj *CurrGO;			//Selected Graphic Objects
 extern Graph *CurrGraph;
@@ -42,13 +44,11 @@ extern UndoObj Undo;
 
 const char name[] = "RLPLOT1";
 
-static unsigned int cf_rlpgraph = RegisterClipboardFormat("rlp_graph");
 static unsigned int cf_rlpobj = RegisterClipboardFormat("rlp_obj");
 static unsigned int cf_rlpxml = RegisterClipboardFormat("rlp_xml");
 
 long FAR PASCAL WndProc(HWND, UINT, UINT, LONG);
 PrintWin *Printer = 0L;
-
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // I/O File name dialogs
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -98,8 +98,10 @@ char *SaveDataAsName(char *oldname)
 char *SaveGraphAsName(char *oldname)
 {
 	static char szFile[500], szFileTitle[256];
-	static char szFilter[] = "RLPlot Graph (*.RLP)\0*.rlp\0";
+	static char szFilter[] = "RLPlot Graph (*.rlp)\0*.rlp\0";
 	OPENFILENAME ofn;
+	int i, j, cb;
+	char *ext;
 
 	szFile[0] = '\0';
 	if(oldname)rlp_strcpy(szFile, 500, oldname);
@@ -117,6 +119,16 @@ char *SaveGraphAsName(char *oldname)
 	ofn.lpstrTitle = "Save Graph As";
 
 	if(GetSaveFileName(&ofn)){
+		if(!(cb = (int)strlen(szFile)) || !szFile[0])return 0L;
+		if(cb < 4 || szFile[cb-4] != '.'){
+			for(i = j = 0; (j>>1) < (int)(ofn.nFilterIndex-1); i++) {
+				if(szFilter[i] == '\0') j++;
+				}
+			ext = szFilter+i;
+			for(i = 0; ext[i] && ext[i] != '*'; i++);
+			rlp_strcpy(szFile+cb, 5, ext+i+1);
+			}
+		defs.FileHistory(szFile);
 		defs.FileHistory(szFile);
 		return szFile;
 		}
@@ -128,7 +140,7 @@ char *SaveGraphAsName(char *oldname)
 char *OpenGraphName(char *oldname)
 {
 	static char szFile[500], szFileTitle[256];
-	static char szFilter[] = "RLPlot Graph (*.RLP)\0*.rlp\0";
+	static char szFilter[] = "RLPlot Graph (*.rlp)\0*.rlp\0";
 	OPENFILENAME ofn;
 
 	szFile[0] = '\0';
@@ -193,8 +205,10 @@ void OpenExportName(GraphObj *g, char *oldname)
 	static char szFile[500], szFileTitle[256];
 	static char szFilter[] = "Scalable Vector Graphics (*.svg)\0*.svg\0"
 		"Encapsulated Post Script (*.eps)\0*.eps\0"
-		"MSWindows MetaFile(*.wmf)\0*.wmf\0Tag Image File Format (*.tif)\0*.tif\0";
+		"Enhanced MetaFile(*.emf)\0*.emf\0Windows MetaFile(*.wmf)\0*.wmf\0"
+		"Tag Image File Format (*.tif)\0*.tif\0";
 	OPENFILENAME ofn;
+	WinCopyWMF *wmf;
 	int i;
 
 	szFile[0] = '\0';
@@ -219,8 +233,19 @@ void OpenExportName(GraphObj *g, char *oldname)
 		if(0==_stricmp(".svg", szFile+i-4)) {
 			DoExportSvg(g, szFile, 0L);
 			}
+		else if(0==_stricmp(".emf", szFile+i-4)) {
+			wmf = new WinCopyWMF(g, 0L, szFile);
+			if(wmf && wmf->StartPage()) {
+				g->DoPlot(wmf);		wmf->EndPage(); 	delete wmf;
+				}
+			else if(wmf) delete wmf;	g->Command(CMD_REDRAW, 0L, 0L);
+			}
 		else if(0==_stricmp(".wmf", szFile+i-4)) {
-			DoExportWmf(g, szFile, 600.0f, 0L);
+			wmf = new WinCopyWMF(g, szFile, 0L);
+			if(wmf && wmf->StartPage()) {
+				g->DoPlot(wmf);		wmf->EndPage(); 	delete wmf;
+				}
+			else if(wmf) delete wmf;	g->Command(CMD_REDRAW, 0L, 0L);
 			}
 		else if(0==_stricmp(".eps", szFile+i-4)) {
 			DoExportEps(g, szFile, 0L);
@@ -277,7 +302,7 @@ void Qt_Box()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 anyOutput *oTxtCur = 0L, *oCopyMark = 0L;
 RECT rTxtCur, rCopyMark;
-bool bTxtCur = false, bTxtCurIsVis = false;
+bool bTxtCur = false, bTxtCurIsVis = false, bSuspend = false;
 DWORD cTxtCur = 0x0L;
 HWND hwndTxtCur = 0L;
 int iTxtCurCount = 0;
@@ -302,9 +327,8 @@ void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
 {
 	HWND wnd = GetFocus();
 
-	cTxtCur = color;
-	HideTextCursor();
-	oTxtCur = out;
+	cTxtCur = color;			HideTextCursor();
+	oTxtCur = out;				bSuspend = false;
 	iTxtCurCount = -2;
 	memcpy(&rTxtCur, disp, sizeof(RECT));
 	ptTxtCurLine[0].x = rTxtCur.left;	ptTxtCurLine[0].y = rTxtCur.top;
@@ -317,6 +341,7 @@ void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
 void HideCopyMark()
 {
 	if(bmCopyMark && oCopyMark) {
+		bmCopyMark = 0L;
 		oCopyMark->UpdateRect(&rCopyMark, false);
 		delete bmCopyMark;
 		}
@@ -327,7 +352,7 @@ void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
 {
 	int i;
 
-	HideCopyMark();
+	HideCopyMark();			bSuspend = false;
 	if(!out || !mrk || !nRec) return;
 	oCopyMark = out;
 	rCopyMark.left = mrk[0].left;	rCopyMark.right = mrk[0].right;
@@ -340,6 +365,29 @@ void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec)
 		rCopyMark.bottom - rCopyMark.top, out->hres, out->vres);
 }
 
+void InvalidateOutput(anyOutput *o)
+{
+	if(!o) return;
+	if(o == oCopyMark) {
+		oCopyMark = 0L;
+		if(bmCopyMark) delete bmCopyMark;
+		bmCopyMark = 0L;
+		}
+	if(o == oTxtCur) {
+		oTxtCur = 0L;	bTxtCur = false;
+		}
+}
+
+void SuspendAnimation(anyOutput *o, bool bSusp)
+{
+	if(!o) return;
+	if(!bSusp) bSuspend = false;
+	else {
+		if(o == oCopyMark) bSuspend = bSusp;
+		if(o == oTxtCur) bSuspend = bSusp;
+		}
+}
+
 LineDEF liCopyMark1 = {0.0f, 1.0f, 0x00ffffffL, 0L};
 LineDEF liCopyMark2 = {0.0f, 6.0f, 0x0L, 0xf0f0f0f0L};
 
@@ -350,6 +398,7 @@ LRESULT FAR PASCAL TimerWndProc(HWND hwnd, UINT message, UINT wParam, LONG lPara
 
 	switch(message) {
 	case WM_TIMER:
+		if(bSuspend) return 0;
 		if(bmCopyMark && oCopyMark) {
 			bmCopyMark->CopyBitmap(0, 0, oCopyMark, rCopyMark.left, rCopyMark.top, 
 				rCopyMark.right - rCopyMark.left, rCopyMark.bottom - rCopyMark.top, false);
@@ -440,14 +489,10 @@ void TestClipboard(GraphObj *g)
 			(ptr = (unsigned char*) GlobalLock(hmem))) ProcMemData(g, ptr, true);
 		else if((hmem = GetClipboardData(cf_rlpobj)) &&
 			(ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr, true);
-		else if((hmem = GetClipboardData(cf_rlpgraph)) &&
-			(ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr, true);
 		}
 	else if(g->Id == GO_PAGE || g->Id == GO_GRAPH) {
 		if((hmem = GetClipboardData(cf_rlpobj)) &&
 			(ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr, true);
-		else if((hmem = GetClipboardData(cf_rlpgraph)) &&
-			(ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr, true);
 		}
 	else TestClipboard(g->parent);
 	if(hmem) GlobalUnlock(hmem);
@@ -503,8 +548,11 @@ void GetDesktopSize(int *width, int *height)
 	RECT rc;
 
 	GetClientRect(GetDesktopWindow(), &rc);
-	*width = rc.right;
-	*height = rc.bottom;
+	*width = rc.right - rc.left;
+	*height = rc.bottom - rc.top;
+	if(*width < 800 || *height < 600){
+		*width = 800;		*height = 600;
+		}
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -548,80 +596,119 @@ void noreflptr(long ref)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Common code for any Windows output class
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-bool com_oTextOut(int x, int y, char *txt, int cb, 
-	HFONT *hFont, HDC *dc, TextDEF *td, bool win95mode, anyOutput *o)
+bool com_oTextOutW(int x, int y, w_char *txt, int cb, HFONT *hFont, HDC *dc, 
+	TextDEF *td, anyOutput *o)
 {
 	XFORM xf;
-	WCHAR *uc;
-	int i, ix, iy, align;
+	int ix, iy, w, h, dtflags;
+	RECT dtrc;
+
 
 	if(!*hFont || !txt || !txt[0]) return false;
-	SelectObject(*dc, *hFont);
-	SetTextColor(*dc, td->ColTxt);
-	SetBkColor(*dc, td->ColBg);
-	align = ((td->Align & TXA_HRIGHT) ? TA_RIGHT : (td->Align &
-		TXA_HCENTER) ? TA_CENTER : TA_LEFT) | ((td->Align & TXA_VBOTTOM) ?
-		TA_BOTTOM : TA_TOP);
-	SetTextAlign(*dc, align);
-	SetBkMode(*dc, td->Mode ? TRANSPARENT : OPAQUE);
-	ix = iy = 0;
-	if(td->Style & TXS_SUB) {
-		if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy += o->un2iy(td->fSize*0.4);
-		else if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy += o->un2iy(td->fSize*0.2);
-		else if((td->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(td->fSize*.6);
-		}
-	else if(td->Style & TXS_SUPER) {
-		if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy -= o->un2iy(td->fSize*0.4);
-		else if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= o->un2iy(td->fSize*0.6);
-		else if((td->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(td->fSize*.0);
-		}
-	if(!win95mode && (fabs(td->RotBL) >.01 || fabs(td->RotCHAR) >.01)) {
+	if(cb < 1) cb = (int)wcslen(txt);
+	SelectObject(*dc, *hFont);				SetTextColor(*dc, td->ColTxt);
+	SetBkColor(*dc, td->ColBg);				SetBkMode(*dc, td->Mode ? TRANSPARENT : OPAQUE);
+	ix = iy = 0;							SetTextAlign(*dc, TA_LEFT | TA_TOP);
+	if(o->OC_type == OC_HIMETRIC) {
+		if(td->Style & TXS_SUB) {
+			if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy -= o->un2iy(td->fSize*0.4);
+			else if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= o->un2iy(td->fSize*0.2);
+			else if((td->Align & TXA_VTOP) == TXA_VTOP) iy -= o->un2iy(td->fSize*.6);
+			}
+		else if(td->Style & TXS_SUPER) {
+			if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy += o->un2iy(td->fSize*0.4);
+			else if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy += o->un2iy(td->fSize*0.6);
+			else if((td->Align & TXA_VTOP) == TXA_VTOP) iy -= o->un2iy(td->fSize*.0);
+			}
+		else {
+			if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy += td->iSize;
+			else if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy += (td->iSize>>1);
+			}
+		}
+	else {
+		if(td->Style & TXS_SUB) {
+			if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy += o->un2iy(td->fSize*0.4);
+			else if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy += o->un2iy(td->fSize*0.2);
+			else if((td->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(td->fSize*.6);
+			}
+		else if(td->Style & TXS_SUPER) {
+			if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy -= o->un2iy(td->fSize*0.4);
+			else if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= o->un2iy(td->fSize*0.6);
+			else if((td->Align & TXA_VTOP) == TXA_VTOP) iy += o->un2iy(td->fSize*.0);
+			}
+		else {
+			if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= td->iSize;
+			else if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy -= (td->iSize>>1);
+			}
+		}
+	dtflags = DT_NOCLIP | DT_NOPREFIX;
+	o->oGetTextExtentW(txt, cb, &w, &h);
+	if((td->Align & TXA_HCENTER) == TXA_HCENTER) {
+		dtrc.left = x+ix-(w>>1);	dtflags |= DT_CENTER;
+		}
+	else if((td->Align & TXA_HRIGHT) == TXA_HRIGHT) {
+		dtrc.left = x+ix-w;			dtflags |= DT_RIGHT;
+		}
+	else {
+		dtrc.left = x+ix;			dtflags |= DT_LEFT;
+		}
+	dtrc.top = iy + y;				dtrc.right = dtrc.left+w;		dtrc.bottom = dtrc.top+h;
+	if(fabs(td->RotBL) >.01 || fabs(td->RotCHAR) >.01) {
 		SetGraphicsMode(*dc, GM_ADVANCED);
-		xf.eM11 = xf.eM22 = (float)cos(td->RotBL *0.01745329252);
-		xf.eM12 = (float)-sin(td->RotBL *0.01745329252);
-		xf.eM21 = -xf.eM12;
-		xf.eDx = (float)x;
-		xf.eDy = (float)y;
-		SetWorldTransform(*dc, &xf);
-		if(td->Font==FONT_GREEK && (uc=(WCHAR *)calloc(strlen(txt)+1, sizeof(WCHAR)))) {
-			for(i = 0; txt[i]; i++) {
-				if((txt[i] >= 'A' && txt[i] <= 'Z')) uc[i] = txt[i] - 'A' + 0x391;
-				else if((txt[i] >= 'a' && txt[i] <= 'z')) uc[i] = txt[i] - 'a' + 0x3B1;
-				else uc[i] = txt[i];
-				}
-			TextOutW(*dc, ix, iy+((td->Align & TXA_VCENTER) ? - td->iSize/2 : 0), uc, 
-				(cb > 0) ? cb : (int)strlen(txt));
-			free(uc);
+		if(o->OC_type == OC_HIMETRIC) {
+			if((td->Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= (td->iSize<<1);
+			else if((td->Align & TXA_VCENTER) == TXA_VCENTER) iy -= (td->iSize);
+			xf.eM11 = (float)cos(td->RotBL *0.01745329252);
+			xf.eM12 = (float)sin(td->RotBL *0.01745329252);
+			xf.eM22 = (float)-cos(td->RotBL *0.01745329252);
+			xf.eM21 = xf.eM12;
 			}
 		else {
-			TextOut(*dc, ix, iy+((td->Align & TXA_VCENTER) ? - td->iSize/2 : 0), txt, 
-				(cb > 0) ? cb : (int)strlen(txt));
+			xf.eM11 = xf.eM22 = (float)cos(td->RotBL *0.01745329252);
+			xf.eM12 = (float)-sin(td->RotBL *0.01745329252);
+			xf.eM21 = -xf.eM12;
 			}
-//		DrawText(*dc, txt, (cb> 0)? cb : strlen(txt), 0L /*LPRECT*/, uFormat);
+		xf.eDx = (float)x;		xf.eDy = (float)y;			SetWorldTransform(*dc, &xf);
+		dtrc.left -= x;		dtrc.right -= x;
+		dtrc.top = iy;		dtrc.bottom = dtrc.top + h;
+		DrawTextW(*dc, txt, cb, &dtrc, dtflags);
 		ModifyWorldTransform(*dc, &xf, MWT_IDENTITY);
 		SetGraphicsMode(*dc, GM_COMPATIBLE);
 		return true;
 		}
 	else {
-		if(!win95mode && td->Font==FONT_GREEK && (uc=(WCHAR *)calloc(strlen(txt)+1, sizeof(WCHAR)))) {
-			for(i = 0; txt[i]; i++) {
-				if((txt[i] >= 'A' && txt[i] <= 'Z')) uc[i] = txt[i] - 'A' + 0x391;
-				else if((txt[i] >= 'a' && txt[i] <= 'z')) uc[i] = txt[i] - 'a' + 0x3B1;
-				else uc[i] = txt[i];
-				}
-			TextOutW(*dc, x+ix, iy + ((td->Align & TXA_VCENTER) ? y - td->iSize/2 : y), uc, 
-				(cb > 0) ? cb : (int)strlen(txt));
-			free(uc);
-			return true;
+		DrawTextW(*dc, txt, cb, &dtrc, DT_CENTER | DT_NOCLIP | DT_NOPREFIX);
+		return true;
+		}
+	return false;
+}
+
+bool com_oTextOut(int x, int y, char *atxt, int cb, HFONT *hFont, HDC *dc, TextDEF *td, anyOutput *o)
+{
+	unsigned char *utxt = (unsigned char*)atxt;
+	w_char *uc;
+	int i;
+
+	if(!*hFont || !atxt || !atxt[0]) return false;
+	if(cb < 1) cb = (int)strlen(atxt);
+	if(!(uc=(WCHAR *)calloc(cb+1, sizeof(WCHAR)))) return false;
+	if(td->Font==FONT_GREEK) {
+		for(i = 0; utxt[i]; i++) {
+			if((utxt[i] >= 'A' && utxt[i] <= 'Z')) uc[i] = utxt[i] - 'A' + 0x391;
+			else if((utxt[i] >= 'a' && utxt[i] <= 'z')) uc[i] = utxt[i] - 'a' + 0x3B1;
+			else uc[i] = utxt[i];
 			}
-		else if(TextOut(*dc, x+ix, iy + ((td->Align & TXA_VCENTER) ? y - td->iSize/2 : y), txt, 
-			(cb > 0) ? cb : (int)strlen(txt))) return true;
 		}
+	else {
+		for(i = 0; utxt[i]; i++) uc[i] = utxt[i];
+		}
+	com_oTextOutW(x, y, uc, cb, hFont, dc, td, o);
+	free(uc);
 	return false;
 }
 
 bool com_SetTextSpec(TextDEF *set, anyOutput *o, HFONT *hFont,	TextDEF *TxtSet, 
-	HDC *dc, bool win95mode)
+	HDC *dc)
 {	
 	bool IsModified, RetVal;
 	LOGFONT FontRec;
@@ -641,14 +728,8 @@ bool com_SetTextSpec(TextDEF *set, anyOutput *o, HFONT *hFont,	TextDEF *TxtSet,
 		else FontRec.lfHeight = TxtSet->iSize;
 		if(FontRec.lfHeight <2) FontRec.lfHeight = 2;
 		FontRec.lfWidth = 0;
-		if(win95mode) {				//Win 95, 98
-			FontRec.lfEscapement = iround(TxtSet->RotBL*10);		//text angle
-			FontRec.lfOrientation = iround(TxtSet->RotBL*10);		//base line angle
-			}
-		else {						//Win NT, 2000, XP
-			FontRec.lfEscapement = 0;		//text angle
-			FontRec.lfOrientation = 0;		//base line angle
-			}
+		FontRec.lfEscapement = 0;		//text angle
+		FontRec.lfOrientation = 0;		//base line angle
 		FontRec.lfWeight = (TxtSet->Style & TXS_BOLD) ? FW_BOLD : FW_NORMAL;
 		FontRec.lfItalic = (TxtSet->Style & TXS_ITALIC) ? TRUE : FALSE;
 		FontRec.lfUnderline = (TxtSet->Style & TXS_UNDERLINE) ? TRUE : FALSE;
@@ -683,30 +764,37 @@ bool com_SetTextSpec(TextDEF *set, anyOutput *o, HFONT *hFont,	TextDEF *TxtSet,
 	return RetVal;
 }
 
-bool com_Arc(HDC dc, int x1, int y1, int x2, int y2, int quads)
+bool com_oGetTextExtentW(w_char *text, int cb, int *width, int *height, HDC dc, TextDEF *TxtSet)
 {
-	int bx, by, ex, ey;
+	SIZE TextExtent;
+	double si, csi, d;
 
-	if(x1 > x2) Swap(x1, x2);	if(y1 > y2) Swap(y1, y2);
-	switch (quads) {
-	case 1:
-		bx = (x1+x2)>>1;	by = y2;
-		ex = x2;			ey = (y1 +y2)>>1;
-		break;
-	case 2:
-		bx = x1;	ex = x2;		by = ey = (y1 +y2)>>1;
-		break;
-	case 3:
-		bx = (x1+x2)>>1;	by = y1;
-		ex = x2;			ey = (y1 +y2)>>1;
-		break;
-	case 4:
-		bx = ex = x2;		by = ey = (y1 +y2)>>1;
-		break;
-	default: return false;
+	if(!text || !TxtSet) return false;
+	if(!GetTextExtentPoint32W(dc, text, cb ? cb : (int)wcslen(text), &TextExtent))return false;
+	if(fabs(TxtSet->RotBL) >0.01) {
+		si = fabs(sin(TxtSet->RotBL * 0.01745329252));	csi = fabs(cos(TxtSet->RotBL * 0.01745329252));
+		d = si > csi ? 1.0/si : 1.0/csi;
+		d = (TextExtent.cx * ((7.0 + d)/8.0));
+		TextExtent.cx = iround(d);
 		}
-	if(Arc(dc, x1, y1, x2, y2, bx, by, ex, ey)) return true;
-	return false;
+	*width = TextExtent.cx;					*height = TextExtent.cy;
+	return true;
+}
+
+bool com_oGetTextExtent(char *text, int cb, int *width, int *height, HDC dc, TextDEF *TxtSet)
+{
+	int i;
+	unsigned char *utext;
+	w_char *uc;
+	bool bRet;
+
+	if(!text || !TxtSet) return false;
+	if(!cb) cb = (int)strlen(text);
+	if(!(uc = (w_char *) malloc((cb+1)*sizeof(w_char))))return false;
+	for(i = 0, utext = (unsigned char*)text ; i <= cb; i++) uc[i] = utext[i];
+	bRet = com_oGetTextExtentW(uc, cb, width, height, dc, TxtSet);
+	free(uc);	
+	return bRet;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -864,7 +952,7 @@ BitMapWin::SetFill(FillDEF *fill)
 bool
 BitMapWin::SetTextSpec(TextDEF *set)
 {
-	return com_SetTextSpec(set, this, &hFont, &TxtSet, &memDC, isWIN95);
+	return com_SetTextSpec(set, this, &hFont, &TxtSet, &memDC);
 }
 
 bool
@@ -904,19 +992,13 @@ BitMapWin::CopyBitmap(int x, int y, anyOutput* sr, int sx, int sy,
 bool
 BitMapWin::oGetTextExtent(char *text, int cb, int *width, int *height)
 {
-	SIZE TextExtent;
-	double si, csi, d;
+	return com_oGetTextExtent(text, cb, width, height, memDC, &TxtSet);
+}
 
-	if(!text) return false;
-	if(!GetTextExtentPoint32(memDC, text, cb ? cb : (int)strlen(text), &TextExtent))return false;
-	if(fabs(TxtSet.RotBL) >0.01) {
-		si = fabs(sin(TxtSet.RotBL * 0.01745329252));	csi = fabs(cos(TxtSet.RotBL * 0.01745329252));
-		d = si > csi ? 1.0/si : 1.0/csi;
-		d = (TextExtent.cx * ((7.0 + d)/8.0));
-		TextExtent.cx = iround(d);
-		}
-	*width = TextExtent.cx;					*height = TextExtent.cy;
-	return true;
+bool
+BitMapWin::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
+{
+	return com_oGetTextExtentW(text, cb, width, height, memDC, &TxtSet);
 }
 
 bool
@@ -1004,7 +1086,13 @@ BitMapWin::oSolidLine(POINT *p)
 bool
 BitMapWin::oTextOut(int x, int y, char *txt, int cb)
 {
-	return com_oTextOut(x, y, txt, cb, &hFont, &memDC, &TxtSet, isWIN95, this);
+	return com_oTextOut(x, y, txt, cb, &hFont, &memDC, &TxtSet, this);
+}
+
+bool
+BitMapWin::oTextOutW(int x, int y, w_char *txt, int cb)
+{
+	return com_oTextOutW(x, y, txt, cb, &hFont, &memDC, &TxtSet, this);
 }
 
 bool
@@ -1018,12 +1106,6 @@ BitMapWin::oPolygon(POINT *pts, int cp, char *nam)
 	return false;
 }
 
-bool
-BitMapWin::oArc(int x1, int y1, int x2, int y2, int quads)
-{
-	return  com_Arc(memDC, x1, y1, x2, y2, quads);
-}
-
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Output to windows window
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1033,6 +1115,7 @@ OutputWin::OutputWin(GraphObj *g, HWND hw):BitMapWin(g, hw)
 	if(g) {
 		if(!hw) CreateNewWindow(g);
 		else hWnd = hw;
+		if(!MainWnd) MainWnd = hWnd;
 		}
 	else {							//its a dialog window
 		hWnd = hw;
@@ -1050,7 +1133,7 @@ OutputWin::~OutputWin()
 bool
 OutputWin::ActualSize(RECT *rc)
 {
-	if(GetClientRect(hWnd, rc)) return true;
+	if(GetClientRect(hWnd, rc)&& (rc->right-rc->left) > 40 && (rc->bottom - rc->top) > 40) return true;
 	return false;
 }
 
@@ -1176,12 +1259,14 @@ OutputWin::MouseCursor(int cid, bool force)
 	switch(cid) {
 	case MC_ARROW:
 		hoc = SetCursor(LoadCursor(NULL, IDC_ARROW));	break;
+	case MC_TXTFRM:
 	case MC_CROSS:	hoc = SetCursor(LoadCursor(NULL, IDC_CROSS));	break;
 	case MC_WAIT:
 		hoc = SetCursor(LoadCursor(NULL, IDC_WAIT));	break;
 	case MC_TEXT:	hoc = SetCursor(LoadCursor(NULL, IDC_IBEAM));	break;
 	case MC_NORTH:	hoc = SetCursor(LoadCursor(NULL, IDC_SIZENS));	break;
 	case MC_NE:		hoc = SetCursor(LoadCursor(NULL, IDC_SIZENESW));break;
+	case MC_COLWIDTH:
 	case MC_EAST:	hoc = SetCursor(LoadCursor(NULL, IDC_SIZEWE));	break;
 	case MC_SE:		hoc = SetCursor(LoadCursor(NULL, IDC_SIZENWSE));break;
 	case MC_SALL:	hoc = SetCursor(LoadCursor(NULL, IDC_SIZEALL));	break;	
@@ -1431,16 +1516,18 @@ OutputWin::CreateNewWindow(void *g)
 // Copy to Clipboard
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Create Windows Meta File for clipboard
-WinCopyWMF::WinCopyWMF(GraphObj *g)
+WinCopyWMF::WinCopyWMF(GraphObj *g, char *file_wmf, char *file_emf)
 {
-	DeskRect.left = DeskRect.top = 0;
-	DeskRect.right = DeskRect.bottom = 0x4fffffffL;
-	hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ffffffL);
+	HDC dc;
+	HWND hwndDesk;
+
+	DeskRect.left = DeskRect.top = 0;				DeskRect.right = DeskRect.bottom = 0x4fffffffL;
+	hPen = CreatePen(PS_SOLID, 1, dLineCol = 0x00ff0000L);
 	hBrush = CreateSolidBrush(dFillCol =dBgCol = 0x00ffffffL);
-	dPattern = 0L;
-	go = g;
-	hgo = 0L;
-	hres = vres = 1000.0;
+	dPattern = 0L;		go = g;			hgo = 0L;		bott_y = 0;
+	dc = GetDC(hwndDesk = GetDesktopWindow());
+	hres = (double)GetDeviceCaps(dc, LOGPIXELSX);	vres = (double)GetDeviceCaps(dc, LOGPIXELSY);
+	ReleaseDC(hwndDesk, dc);	wmf_file = file_wmf;	emf_file = file_emf;
 }
 
 WinCopyWMF::~WinCopyWMF()
@@ -1456,7 +1543,7 @@ WinCopyWMF::SetLine(LineDEF *lDef)
 {
 	int iw;
 	HPEN newPen;
-
+	
 	if(!hPen || lDef->width != LineWidth || lDef->width != LineWidth || 
 		lDef->pattern != dPattern || lDef->color != dLineCol) {
 		LineWidth = lDef->width;
@@ -1503,59 +1590,104 @@ WinCopyWMF::SetFill(FillDEF *fill)
 bool
 WinCopyWMF::SetTextSpec(TextDEF *set)
 {
-	return com_SetTextSpec(set, this, &hFont, &TxtSet, &hdc, true);
+	return com_SetTextSpec(set, this, &hFont, &TxtSet, &hdc);
+}
+
+bool
+WinCopyWMF::oGetTextExtent(char *text, int cb, int *width, int *height)
+{
+	return com_oGetTextExtent(text, cb, width, height, hdc, &TxtSet);
+}
+
+bool
+WinCopyWMF::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
+{
+	return com_oGetTextExtentW(text, cb, width, height, hdc, &TxtSet);
 }
 
 bool
 WinCopyWMF::StartPage()
 {
 	int w, h;
-
+	RECT rect;
+	double res;
 
 	if(!go) return false;
-	w = un2ix(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT));
-	h = un2iy(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP));
-	w++; h++;
-	if(!(hdc = CreateMetaFile(NULL))) return false;
-	if(hPen)SelectObject(hdc, hPen);
-	if(hBrush) SelectObject(hdc, hBrush);
-	VPorg.fy = -co2fiy(go->GetSize(SIZE_GRECT_TOP));
+	res = Units[defs.cUnits].convert;
+	w = iround(hres*res*(go->GetSize(SIZE_GRECT_RIGHT) - go->GetSize(SIZE_GRECT_LEFT)));
+	h = iround(vres*res*(go->GetSize(SIZE_GRECT_BOTTOM) - go->GetSize(SIZE_GRECT_TOP)));
+	rect.left = rect.top = 0;
+	rect.bottom = h+560;	rect.right = w+720;
+	if(!(hdc = CreateEnhMetaFile(0L, emf_file, &rect, "RLPlot")))return false;
+	if(SetMapMode(hdc, MM_HIMETRIC)) {
+		hres = vres = 2540.0;		OC_type = OC_HIMETRIC;	
+		bott_y = un2iy(go->GetSize(SIZE_GRECT_TOP) - go->GetSize(SIZE_GRECT_BOTTOM));
+		VPorg.fy = bott_y;
+		}
+	else return false;
+	if(hPen)SelectObject(hdc, hPen);	if(hBrush) SelectObject(hdc, hBrush);
 	VPorg.fx = -co2fix(go->GetSize(SIZE_GRECT_LEFT));
-	SetMapMode(hdc, MM_HIENGLISH); 
-	SetWindowExtEx(hdc, w, h, 0L);
-	SetWindowOrgEx(hdc, 0, 0, 0L);
 	return true;
 }
 
 bool
 WinCopyWMF::EndPage()
 {
-	HMETAFILE hmf;
-	HGLOBAL hGMem;
-	LPMETAFILEPICT pMFP;
-
-	hmf = CloseMetaFile(hdc);
-	hGMem = GlobalAlloc(GHND, sizeof(METAFILEPICT));
-	pMFP = (LPMETAFILEPICT)GlobalLock(hGMem);
-	pMFP->mm = MM_ANISOTROPIC;
-	pMFP->xExt = (long)(Box1.Xmax+Box1.Xmin);
-	pMFP->yExt = (long)(Box1.Ymax+Box1.Ymin);
-	pMFP->hMF = hmf;
-	GlobalUnlock(hGMem);
-	// We do not open the Clipboard because we are responding to WM_RENDERFORMAT
-	SetClipboardData(CF_METAFILEPICT, hGMem);
+	int iFile;
+	HENHMETAFILE hmf;
+	unsigned int cb;
+	unsigned char *buff;
+	HDC dc;
+
+	hmf = CloseEnhMetaFile(hdc);
+	if(emf_file);				// nothing more to do
+	else if(wmf_file) {
+		dc = GetDC(MainWnd);
+		cb = GetWinMetaFileBits(hmf, 0, 0L, MM_HIMETRIC, dc);
+		if(cb && (buff = (unsigned char*)malloc(cb+1))){
+#ifdef USE_WIN_SECURE
+			if(_sopen_s(&iFile, wmf_file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, 
+				0x40, S_IWRITE) || iFile < 0){
+				ErrorBox("Open failed for metafile");
+				free(buff);		 return false;
+				}
+#else
+			if(-1 ==(iFile = open(wmf_file, O_RDWR | O_BINARY | O_CREAT | O_TRUNC,
+				S_IWRITE | S_IREAD))){
+				ErrorBox("Open failed for metafile");
+				free(buff);		return false;
+				}
+#endif
+			if(cb = GetWinMetaFileBits(hmf, cb, buff, MM_HIMETRIC, dc)){
+#ifdef USE_WIN_SECURE
+				_write(iFile, buff, cb);
+				_close(iFile);
+#else
+				write(iFile, buff, cb);
+				close(iFile);
+#endif
+				}
+			free(buff);
+			}
+		ReleaseDC(MainWnd, dc);
+		}
+	else SetClipboardData(CF_ENHMETAFILE, hmf);
+	DeleteEnhMetaFile(hmf);
 	return true;
 }
 
 bool
-WinCopyWMF::oCircle(int x1, int y1, int x2, int y2, char* nam)
+WinCopyWMF::oCircle(int ix1, int iy1, int ix2, int iy2, char* nam)
 {
+	int x1=ix1, x2=ix2, y1, y2;
 	BOOL RetVal;
 	
+	y1 = bott_y - iy1;				y2 = bott_y - iy2;
+	if(x2 > x1) x2 = ix2 + 25;		else x1 = ix1 + 25;
+	if(y1 > y2) y2 -= 25;			else y1 -=25;
 	RetVal = Ellipse(hdc, x1, y1, x2, y2);
 	if(RetVal && hgo) return hgo->oCircle(x1, y1, x2, y2);
-	else if(RetVal) return true;
-	return false;
+	return RetVal != 0;
 }
 
 bool
@@ -1564,31 +1696,32 @@ WinCopyWMF::oPolyline(POINT * pts, int cp, char *nam)
 	int i;
 
 	if(cp < 1) return false;
+	for (i = 0; i < cp; i++) pts[i].y = bott_y - pts[i].y;
 	if (dPattern) {
 		for (i = 1; i < cp; i++) PatLine(pts[i-1], pts[i]);
 		return true;
 		}
-	else {
-		if(Polyline(hdc, pts, cp))return true;
-		else return false;
-		}
-	return false;
+	return (0 != Polyline(hdc, pts, cp));
 }
 
 bool
-WinCopyWMF::oRectangle(int x1, int y1, int x2, int y2, char *name)
+WinCopyWMF::oRectangle(int ix1, int iy1, int ix2, int iy2, char *name)
 {
+	int x1=ix1, x2=ix2, y1, y2;
 	BOOL RetVal;
 
+	y1 = bott_y - iy1;				y2 = bott_y - iy2;
+	if(x2 > x1) x2 = ix2 + 25;		else x1 = ix1 + 25;
+	if(y1 > y2) y2 -= 25;			else y1 -=25;
 	RetVal = Rectangle(hdc, x1, y1, x2, y2);
-	if(RetVal && hgo) return hgo->oRectangle(x1, y1, x2, y2, 0L);
-	else if (RetVal) return true;
-	return false;
+	if(RetVal && hgo) return hgo->oRectangle(ix1, iy1, ix2, iy2, 0L);
+	return RetVal != 0;
 }
 
 bool
 WinCopyWMF::oSolidLine(POINT *p)
 {
+	p[0].y = bott_y - p[0].y;		p[1].y = bott_y - p[1].y;
 	if(Polyline(hdc, p, 2)) return true;
 	return false;
 }
@@ -1596,24 +1729,30 @@ WinCopyWMF::oSolidLine(POINT *p)
 bool
 WinCopyWMF::oTextOut(int x, int y, char *txt, int cb)
 {
-	return com_oTextOut(x, y, txt, cb, &hFont, &hdc, &TxtSet, true, this);
+	y = bott_y - y;
+	return com_oTextOut(x, y, txt, cb, &hFont, &hdc, &TxtSet, this);
 }
 
 bool
-WinCopyWMF::oPolygon(POINT *pts, int cp, char *nam)
+WinCopyWMF::oTextOutW(int x, int y, w_char *txt, int cb)
 {
-	BOOL RetVal;
-
-	RetVal = Polygon(hdc, pts, cp);
-	if(RetVal && hgo) return hgo->oPolygon(pts, cp);
-	else if (RetVal) return true;
-	return false;
+	y = bott_y - y;
+	return com_oTextOutW(x, y, txt, cb, &hFont, &hdc, &TxtSet, this);
 }
 
 bool
-WinCopyWMF::oArc(int x1, int y1, int x2, int y2, int quads)
+WinCopyWMF::oPolygon(POINT *pts, int cp, char *nam)
 {
-	return  com_Arc(hdc, x1, y1, x2, y2, quads);
+	int i;
+	BOOL RetVal;
+
+	for (i = 0; i < cp; i++) pts[i].y = bott_y - pts[i].y;
+	RetVal = Polygon(hdc, pts, cp);
+	if(RetVal && hgo) {
+		for (i = 0; i < cp; i++) pts[i].y = - pts[i].y + bott_y ;
+		return hgo->oPolygon(pts, cp);
+		}
+	return (RetVal != 0);
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1729,7 +1868,19 @@ PrintWin::SetFill(FillDEF *fill)
 bool
 PrintWin::SetTextSpec(TextDEF *set)
 {
-	return com_SetTextSpec(set, this, &hFont, &TxtSet, &hDC, isWIN95);
+	return com_SetTextSpec(set, this, &hFont, &TxtSet, &hDC);
+}
+
+bool
+PrintWin::oGetTextExtent(char *text, int cb, int *width, int *height)
+{
+	return com_oGetTextExtent(text, cb, width, height, hDC, &TxtSet);
+}
+
+bool
+PrintWin::oGetTextExtentW(w_char *text, int cb, int *width, int *height)
+{
+	return com_oGetTextExtentW(text, cb, width, height, hDC, &TxtSet);
 }
 
 bool
@@ -1827,7 +1978,13 @@ PrintWin::oSolidLine(POINT *p)
 bool
 PrintWin::oTextOut(int x, int y, char *txt, int cb)
 {
-	return com_oTextOut(x, y, txt, cb, &hFont, &hDC, &TxtSet, isWIN95, this);
+	return com_oTextOut(x, y, txt, cb, &hFont, &hDC, &TxtSet, this);
+}
+
+bool
+PrintWin::oTextOutW(int x, int y, w_char *txt, int cb)
+{
+	return com_oTextOutW(x, y, txt, cb, &hFont, &hDC, &TxtSet, this);
 }
 
 bool
@@ -1841,21 +1998,13 @@ PrintWin::oPolygon(POINT *pts, int cp, char *nam)
 	return false;
 }
 
-bool
-PrintWin::oArc(int x1, int y1, int x2, int y2, int quads)
-{
-	return  com_Arc(hDC, x1, y1, x2, y2, quads);
-}
-
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Find a suitable www browser
 void FindBrowser()
 {
 	char text[600];
 	long size = 599;
-	HDC dc;
 	HKEY hdl;
-	HWND hwnd;
 	int i;
 
 	//find the default browser
@@ -1909,11 +2058,6 @@ void FindBrowser()
 	GetProfileString("intl", "sList", ".", text, 2);
 	if(text[0]) defs.ColSep[0] = text[0];
 	if(GetProfileInt("intl", "iMeasure", 0)) defs.dUnits = defs.cUnits = 2;
-	//test if windows95
-	dc = GetDC(hwnd = GetDesktopWindow());
-	isWIN95 = (0 == SetGraphicsMode(dc, GM_ADVANCED));
-	SetGraphicsMode(dc, GM_COMPATIBLE);
-	ReleaseDC(hwnd, dc);
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1925,6 +2069,8 @@ int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance,
 	WNDCLASS wndclass;
 	MSG	msg;
 	DefsRW *drw;
+	HWND hwnd;
+	HDC dc;
 
 	//OS dependent initialization
 	dlgtxtheight = 16;
@@ -1952,9 +2098,14 @@ int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInstance,
 	wndclass.lpszClassName = name;
 
 	RegisterClass(&wndclass);
-	ShowBanner(true);
-	InitTextCursor(true);
-	Printer = new PrintWin();
+	dc = GetDC(hwnd = GetDesktopWindow());
+	if(0 == SetGraphicsMode(dc, GM_ADVANCED)){
+		ErrorBox("RLPlot detected an\nold version of Windows which\nis no longer supported!\n");
+		return 1;
+		}
+	SetGraphicsMode(dc, GM_COMPATIBLE);
+	ReleaseDC(hwnd, dc);		ShowBanner(true);
+	InitTextCursor(true);		Printer = new PrintWin();
 	accel = LoadAccelerators(hInstance, MAKEINTRESOURCE(ACCELERATORS_1));
 	while(GetMessage(&msg, NULL, 0, 0)){
 		TranslateMessage(&msg);
@@ -2004,13 +2155,14 @@ void CopyData(GraphObj *g, unsigned int cf)
 		}
 }
 
-void CopyGraph(GraphObj *g, unsigned int cf)
+void CopyGraph(GraphObj *g, unsigned int cf, anyOutput *o)
 {
 	HGLOBAL hmem;
 	char *dt, *buf;
 	long cb;
 
 	if(!(dt = GraphToMem(g, &cb)))return;
+	if(o) ShowCopyMark(o, &g->rDims, 1);
 	if(hmem = GlobalAlloc(GMEM_MOVEABLE, cb+1)) {
 		if(buf = (char *)GlobalLock(hmem)) {
 			memcpy(buf, dt, cb);
@@ -2029,10 +2181,10 @@ void ScrollEvent(bool bVert, HWND hwnd, UINT type, GraphObj *g, OutputWin *w)
 
 	if(hwnd && g && w) {
 		cmd = bVert ? CMD_SETVPOS : CMD_SETHPOS;
-		LineStep = g->Id == GO_GRAPH ? 8 : 1;
 		si.fMask = SIF_ALL;
 		si.cbSize = sizeof(SCROLLINFO);
 		if(!(GetScrollInfo(hwnd, bVert ? SB_VERT : SB_HORZ, &si)))return;
+		LineStep = (g->Id == GO_GRAPH || g->Id == GO_PAGE) ? 16 : 1;
 		switch(type){
 		case SB_LINEUP:
 			pos = si.nPos - LineStep;
@@ -2090,7 +2242,8 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 {
 	static WinCopyWMF *CopyWMF = NULL;
 	static BitMapWin *CopyBMP = NULL;
-	static bool CtrlDown = false;
+	static bool CtrlDown = false, bAltKey = false;
+	static w_char uc_char;
 	PAINTSTRUCT ps;
 	OutputWin *w;
 	GraphObj *g;
@@ -2123,9 +2276,12 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		else if(message == WM_MOUSEMOVE)mev.Action = MOUSE_MOVE;
 		g->Command(CMD_MOUSE_EVENT, (void *)&mev, w);
 		break;
+	case 0x020A:				//WM_MOUSEWHEEL
+		ScrollEvent(true, hwnd, (int)wParam > 0 ? SB_LINEUP : SB_LINEDOWN, g, w);
+		return 0;
 	case WM_KEYDOWN:
+		cc = (wParam & 0xff);
 		if(g && w && (GetKeyState(VK_LCONTROL) || GetKeyState(VK_RCONTROL))){
-			cc = (wParam & 0xff);
 			if(cc == 0xbb || cc == 0x6b ) g->Command(CMD_ZOOM, &"+", w);
 			else if(cc == 0xbd || cc == 0x6d ) g->Command(CMD_ZOOM, &"-", w);
 			else break;
@@ -2134,8 +2290,36 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		break;
 	case WM_CHAR:
 		cc = (wParam & 0xff);
+		if(bAltKey && uc_char) {
+			if(uc_char >=255) {
+				g->Command(CMD_ADDCHARW, (void *)(& uc_char), w); 
+				uc_char = 0;	bAltKey = false;
+				return 0;
+				}
+			else cc = (int)uc_char;
+			uc_char = 0;	bAltKey = false;
+			}
 		g->Command(CMD_ADDCHAR, (void *)(& cc), w);
 		return 0;
+	case WM_SYSKEYDOWN:
+		if(wParam == VK_MENU) {
+			bAltKey = true;	uc_char = 0;
+			}
+		break;
+	case WM_SYSKEYUP:
+		if(wParam == VK_MENU) bAltKey = false;
+		if(bAltKey) {
+			cc = (wParam & 0xff);
+			if( cc >= 0x60 && cc <= 0x69) {
+				uc_char *= 10;	uc_char += (cc-0x60);
+				return 0;
+				}
+			else {
+				uc_char = 0;	bAltKey = false;
+				return 0;
+				}
+			}
+		break;
 	case WM_VSCROLL:		case WM_HSCROLL:
 		ScrollEvent(message == WM_VSCROLL, hwnd, wParam & 0xffff, g, w);
 		return 0;
@@ -2143,8 +2327,6 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 
 	switch(message) {
 	case WM_CREATE:
-		//assume that the first window created is the main window
-		if(!MainWnd) MainWnd = hwnd;
 		break;
 	case WM_SIZE:
 		if(g && w) g->Command(CMD_SETSCROLL, 0L, w);
@@ -2170,8 +2352,8 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		return 0;
 	case WM_RENDERFORMAT:
 		if(g && w) switch(wParam){
-			case CF_METAFILEPICT:
-				CopyWMF = new WinCopyWMF(copy_obj);
+			case CF_ENHMETAFILE:
+				CopyWMF = new WinCopyWMF(copy_obj, 0L, 0L);
 				if(CopyWMF && CopyWMF->StartPage()) {
 					copy_obj->DoPlot(CopyWMF);
 					CopyWMF->EndPage();
@@ -2192,7 +2374,7 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 				if(g->Id == GO_SPREADDATA) CopyData(g, wParam);
 				break;
 			default:
-				if(wParam == cf_rlpgraph) CopyGraph(copy_obj, wParam);
+//				if(wParam == cf_rlpgraph) CopyGraph(copy_obj, wParam, w);
 				if(wParam == cf_rlpxml) CopyData(g, wParam);
 				break;
 			}
@@ -2218,7 +2400,7 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 				}
 			g->Command(CMD_MOUSECURSOR, 0L, w);
 			return 0;
-		case CM_COPY:			case CM_CUT:
+		case CM_COPY:			case CM_CUT:		case CM_COPYGRAPH:
 			EmptyClip();
 			if(g->Id != GO_SPREADDATA && CurrGO && CurrGO->Id == GO_TEXTFRAME) {
 				if(CurrGO->Command(CMD_COPY, 0L, w))return 0;
@@ -2230,32 +2412,29 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 				SetClipboardData(cf_rlpxml, NULL);
 				}
 			else if(g->Id == GO_PAGE) {
-				SetClipboardData(CF_METAFILEPICT, NULL);
+				SetClipboardData(CF_ENHMETAFILE, NULL);
+				SetClipboardData(CF_BITMAP, NULL);
+				if(CurrGraph) {
+					CopyGraph(CurrGraph, cf_rlpobj, w);		copy_obj = CurrGraph;
+					}
+				}
+			else if(CurrGraph && CurrGraph->Id == GO_GRAPH){
+				SetClipboardData(CF_ENHMETAFILE, NULL);
+				SetClipboardData(CF_BITMAP, NULL);
+				CopyGraph(CurrGraph, cf_rlpobj, w);			copy_obj = CurrGraph;
+				}
+			else if(g->Id == GO_GRAPH){
+				SetClipboardData(CF_ENHMETAFILE, NULL);
 				SetClipboardData(CF_BITMAP, NULL);
-				SetClipboardData(cf_rlpgraph, NULL);
-				if(g->Id == GO_PAGE && CurrGraph) CopyGraph(CurrGraph, cf_rlpobj);
-				copy_obj = g;
+				CopyGraph(g, cf_rlpobj, w);					copy_obj = g;
 				}
 			CloseClipboard();
 			return 0;
 		case CM_UPDATE:
 			g->Command(CMD_UPDATE, 0L, w);
 			return 0;
-		case CM_COPYGRAPH:
-			EmptyClip();
-			if(CurrGO && CurrGO->Id == GO_TEXTFRAME) {
-				if(CurrGO->Command(CMD_COPY, 0L, w))return 0;
-				}
-			OpenClipboard(GetFocus());
-			SetClipboardData(CF_METAFILEPICT, NULL);
-			SetClipboardData(CF_BITMAP, NULL);
-			SetClipboardData(cf_rlpgraph, NULL);
-			if(g->Id == GO_PAGE && CurrGraph) CopyGraph(CurrGraph, cf_rlpobj);
-			copy_obj = g;
-			CloseClipboard();
-			return 0;
 		case CM_OPEN:
-			g->Command(CMD_OPEN, (void *)NULL, w);
+			g->Command(CMD_OPEN, 0L, w);
 			return 0;
 		case CM_FILE1:	case CM_FILE2:	case CM_FILE3:
 		case CM_FILE4:	case CM_FILE5:	case CM_FILE6:
@@ -2433,15 +2612,27 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		case CM_DELCOL:
 			g->Command(CMD_DELCOL, 0L, w);
 			return 0;
+		case CM_SMPLSTAT:
+			if(g->data) rep_samplestats(g, g->data);
+			return 0;
 		case CM_REPCMEANS:
 			if(g->data) rep_compmeans(g, g->data);
 			return 0;
 		case CM_REPANOV:
 			if(g->data) rep_anova(g, g->data);
 			return 0;
+		case CM_REPKRUSKAL:
+			if(g->data) rep_kruskal(g, g->data);
+			return 0;
 		case CM_REPREGR:
 			if(g->data) rep_regression(g, g->data);
 			return 0;
+		case CM_CORRELM:
+			if(g->data) rep_correl(g, g->data, 0);
+			return 0;
+		case CM_CORRELT:
+			if(g->data) rep_correl(g, g->data, 1);
+			return 0;
 		case CM_REPTWOWAY:
 			if(g->data) rep_twowaytable(g, g->data);
 			return 0;
diff --git a/WinSpec.h b/WinSpec.h
index 50a0c99..aaa60b8 100755
--- a/WinSpec.h
+++ b/WinSpec.h
@@ -38,6 +38,7 @@ public:
 	bool CopyBitmap(int x, int y, anyOutput* src, int sx, int sy,
 		int sw, int sh, bool invert);
 	bool oGetTextExtent(char *text, int cb, int *width, int *height);
+	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
 	bool oGetPix(int x, int y, DWORD *col);
 	bool oDrawIcon(int type, int x, int y);
 	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
@@ -45,8 +46,8 @@ public:
 	bool oRectangle(int x1, int y1, int x2, int y2, char* nam = 0L);
 	bool oSolidLine(POINT *p);
 	bool oTextOut(int x, int y, char *txt, int cb);
+	bool oTextOutW(int x, int y, w_char *txt, int cb);
 	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
-	bool oArc(int x1, int y1, int x2, int y2, int quads);
 };
 
 class OutputWin:public BitMapWin{
@@ -79,11 +80,13 @@ private:
 
 class WinCopyWMF:public anyOutput {
 public:
-	WinCopyWMF(GraphObj *g);
+	WinCopyWMF(GraphObj *g, char* file_wmf, char *file_emf);
 	~WinCopyWMF();
 	bool SetLine(LineDEF *lDef);
 	bool SetFill(FillDEF *fill);
 	bool SetTextSpec(TextDEF *set);
+	bool oGetTextExtent(char *text, int cb, int *width, int *height);
+	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
 	bool StartPage();
 	bool EndPage();
 	bool oCircle(int x1, int y1, int x2, int y2, char* nam = 0L);
@@ -91,16 +94,18 @@ public:
 	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
 	bool oSolidLine(POINT *p);
 	bool oTextOut(int x, int y, char *txt, int cb);
+	bool oTextOutW(int x, int y, w_char *txt, int cb);
 	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
-	bool oArc(int x1, int y1, int x2, int y2, int quads);
 
 private:
+	int bott_y;
 	GraphObj *go;
 	HDC hdc;
 	HPEN hPen;
 	HBRUSH hBrush;
 	HFONT hFont;
 	HatchOut *hgo;
+	char *wmf_file, *emf_file;
 };
 
 class PrintWin:public anyOutput{
@@ -110,6 +115,8 @@ public:
 	bool SetLine(LineDEF *lDef);
 	bool SetFill(FillDEF *fill);
 	bool SetTextSpec(TextDEF *set);
+	bool oGetTextExtent(char *text, int cb, int *width, int *height);
+	bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
 	bool StartPage();
 	bool EndPage();
 	bool Eject();
@@ -118,8 +125,8 @@ public:
 	bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L);
 	bool oSolidLine(POINT *p);
 	bool oTextOut(int x, int y, char *txt, int cb);
+	bool oTextOutW(int x, int y, w_char *txt, int cb);
 	bool oPolygon(POINT *pts, int cp, char *nam = 0L);
-	bool oArc(int x1, int y1, int x2, int y2, int quads);
 
 private:
 	HPEN hPen;
diff --git a/menu.h b/menu.h
index 8e02c7f..dd3e9e9 100755
--- a/menu.h
+++ b/menu.h
@@ -1,4 +1,4 @@
-//menu.h, (C) 2006 R.Lackner
+//menu.h, (C) 2006, 2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -92,8 +92,11 @@
 #define CM_SHPGUP      615
 #define CM_SHPGDOWN    616
 
-#define CM_REPCMEANS   650
-#define CM_REPANOV     651
-#define CM_REPREGR     652
-#define CM_REPTWOWAY   653
-
+#define CM_SMPLSTAT    650
+#define CM_REPCMEANS   651
+#define CM_REPANOV     652
+#define CM_REPKRUSKAL  653
+#define CM_REPREGR     654
+#define CM_CORRELM     655
+#define CM_CORRELT     656
+#define CM_REPTWOWAY   657
diff --git a/mfcalc.cpp b/mfcalc.cpp
index 9d20746..a7da92b 100644
--- a/mfcalc.cpp
+++ b/mfcalc.cpp
@@ -10,51 +10,60 @@
 #define	ARR	260
 #define	BLOCK	261
 #define	PBLOCK	262
-#define	PI	263
-#define	E	264
-#define	CLVAL	265
-#define	PSEP	266
-#define	IF	267
-#define	ELSE	268
-#define	BTRUE	269
-#define	BFALSE	270
-#define	DATE1	271
-#define	TIME1	272
-#define	DATETIME1	273
-#define	DIM	274
-#define	WHILE	275
-#define	VAR	276
-#define	FNCT	277
-#define	BFNCT	278
-#define	AFNCT	279
-#define	SFNCT	280
-#define	FUNC1	281
-#define	FUNC2	282
-#define	FUNC3	283
-#define	TXT	284
-#define	SRFUNC	285
-#define	YYFNC	286
-#define	FUNC4	287
-#define	YYFNC2	288
-#define	YYFNC3	289
-#define	CLAUSE	290
-#define	SER	291
-#define	COLR	292
-#define	COLC	293
-#define	AND	294
-#define	OR	295
-#define	EQ	296
-#define	NE	297
-#define	GT	298
-#define	GE	299
-#define	LT	300
-#define	LE	301
-#define	NEG	302
-#define	INC	303
-#define	DEC	304
-#define	PINC	305
-#define	PDEC	306
-#define	PDIM	307
+#define	IBLOCK	263
+#define	PI	264
+#define	E	265
+#define	CLVAL	266
+#define	PSEP	267
+#define	IF	268
+#define	ELSE	269
+#define	BTRUE	270
+#define	BFALSE	271
+#define	DATE1	272
+#define	TIME1	273
+#define	DATETIME1	274
+#define	DIM	275
+#define	WHILE	276
+#define	FOR	277
+#define	INARR	278
+#define	RANGEARR	279
+#define	RETURN	280
+#define	BREAK	281
+#define	VAR	282
+#define	FNCT	283
+#define	BFNCT	284
+#define	AFNCT	285
+#define	SFNCT	286
+#define	FUNC1	287
+#define	FUNC2	288
+#define	FUNC3	289
+#define	TXT	290
+#define	SRFUNC	291
+#define	YYFNC	292
+#define	FUNC4	293
+#define	YYFNC2	294
+#define	YYFNC3	295
+#define	ADDEQ	296
+#define	SUBEQ	297
+#define	MULEQ	298
+#define	DIVEQ	299
+#define	CLAUSE	300
+#define	SER	301
+#define	COLC	302
+#define	AND	303
+#define	OR	304
+#define	EQ	305
+#define	NE	306
+#define	GT	307
+#define	GE	308
+#define	LT	309
+#define	LE	310
+#define	NEG	311
+#define	INC	312
+#define	DEC	313
+#define	PINC	314
+#define	PDEC	315
+#define	PDIM	316
 
 
 /*
@@ -128,7 +137,8 @@ typedef struct{
 
 }YYSTYPE;
 
-static int yy_maxiter = 1000;
+static int yy_maxiter = 100000;		//maximum loop count
+static int block_res;			//result of eval()
 
 static symrec *putsym (unsigned int h_name, unsigned int h2_name, int sym_type);
 static symrec *getsym (unsigned int h_name, unsigned int h2_name, char *sym_name = 0L);
@@ -139,7 +149,7 @@ static double *PushArray(double *arr);
 static double *ReallocArray(double *arr, int size);
 static char *add_strings(char *st1, char *st2);
 static char *string_value(YYSTYPE *exp);
-static void eval(YYSTYPE *dst, YYSTYPE *sr);
+static int eval(YYSTYPE *dst, YYSTYPE *sr);
 static int range_array(YYSTYPE * res, char *range);
 static int range_array2(YYSTYPE *res1, YYSTYPE *res2);
 static void exec_clause(YYSTYPE *res);
@@ -148,9 +158,10 @@ static void yyerror(char *s);
 static void make_time(YYSTYPE *dst, double h, double m, double s);
 static int yylex(void);
 static double nop() {return 0.0;};
+static double for_loop(char *block1, char *block2);
 
 static char res_txt[1000];
-static anyResult line_res = {ET_UNKNOWN, 0.0, res_txt};
+static anyResult line_res = {ET_UNKNOWN, 0.0, res_txt, 0L, 0};
 static DataObj *curr_data;
 static char *last_error = 0L;		//error text
 static char *last_err_desc = 0L;	//short error description
@@ -170,23 +181,23 @@ static int parse_level = 0;		//count reentrances into parser
 
 
 
-#define	YYFINAL		269
+#define	YYFINAL		260
 #define	YYFLAG		-32768
-#define	YYNTBASE	69
+#define	YYNTBASE	78
 
-#define YYTRANSLATE(x) ((unsigned)(x) <= 307 ? yytranslate[x] : 76)
+#define YYTRANSLATE(x) ((unsigned)(x) <= 316 ? yytranslate[x] : 87)
 
 static const char yytranslate[] = {     0,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,    63,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    72,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,    65,
-    66,    53,    52,    37,    51,     2,    54,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,    68,    64,     2,
-    36,     2,    42,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    74,
+    75,    62,    61,    47,    60,     2,    63,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,    77,    73,     2,
+    42,     2,    51,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-    55,     2,    67,    56,     2,     2,     2,     2,     2,     2,
+    64,     2,    76,    65,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -205,98 +216,98 @@ static const char yytranslate[] = {     0,
      2,     2,     2,     2,     2,     1,     3,     4,     5,     6,
      7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
     17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-    27,    28,    29,    30,    31,    32,    33,    34,    35,    38,
-    39,    40,    41,    43,    44,    45,    46,    47,    48,    49,
-    50,    57,    58,    59,    60,    61,    62
+    27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+    37,    38,    39,    40,    41,    43,    44,    45,    46,    48,
+    49,    50,    52,    53,    54,    55,    56,    57,    58,    59,
+    66,    67,    68,    69,    70,    71
 };
 
 #if YYDEBUG != 0
 static const short yyprhs[] = {     0,
      0,     1,     4,     6,     8,    10,    13,    16,    19,    22,
-    25,    28,    30,    34,    38,    42,    47,    54,    61,    68,
-    75,    77,    81,    83,    85,    89,    93,    95,    99,   101,
-   106,   108,   110,   114,   118,   122,   126,   130,   134,   138,
-   142,   144,   146,   148,   150,   152,   154,   156,   158,   162,
-   166,   171,   176,   183,   192,   197,   202,   209,   216,   223,
-   230,   237,   244,   251,   258,   265,   274,   281,   290,   301,
-   308,   312,   317,   324,   331,   338,   345,   354,   363,   372,
-   381,   390,   399,   408,   417,   423,   431,   435,   439,   443,
-   447,   451,   454,   457,   460,   463,   467,   470,   474,   480,
-   485,   492,   498,   504,   508,   512,   518,   524,   530
+    25,    29,    35,    39,    43,    46,    48,    51,    53,    57,
+    61,    65,    70,    77,    84,    91,    98,   100,   102,   104,
+   108,   112,   114,   118,   120,   125,   127,   129,   133,   137,
+   141,   145,   149,   153,   157,   161,   163,   165,   167,   169,
+   171,   173,   175,   177,   179,   181,   183,   185,   187,   191,
+   195,   199,   203,   207,   211,   216,   221,   228,   237,   242,
+   247,   254,   261,   268,   275,   282,   289,   296,   303,   310,
+   319,   326,   335,   346,   353,   360,   364,   369,   376,   381,
+   390,   394,   398,   402,   406,   409,   412,   415,   418,   422,
+   425,   429,   435,   440,   447,   454,   461,   468,   475,   481,
+   485,   491,   497,   503
 };
 
 static const short yyrhs[] = {    -1,
-    69,    70,     0,    63,     0,    64,     0,    37,     0,    75,
-    63,     0,    75,    64,     0,    75,    37,     0,    71,    63,
-     0,    71,    64,     0,     1,    63,     0,     5,     0,    71,
-    52,    75,     0,    75,    52,    71,     0,    71,    52,    71,
-     0,    31,    65,    75,    66,     0,    31,    65,    75,    12,
-    71,    66,     0,    31,    65,    75,    12,    75,    66,     0,
-    31,    65,    75,    37,    71,    66,     0,    31,    65,    75,
-    37,    75,    66,     0,    71,     0,    22,    40,    22,     0,
-     6,     0,    75,     0,    73,    37,    73,     0,    73,    38,
-    75,     0,    72,     0,     3,    39,     3,     0,     4,     0,
-    24,    65,    75,    66,     0,    15,     0,    16,     0,    75,
-    43,    75,     0,    75,    44,    75,     0,    75,    45,    75,
-     0,    75,    46,    75,     0,    75,    47,    75,     0,    75,
-    48,    75,     0,    75,    49,    75,     0,    75,    50,    75,
-     0,     3,     0,    74,     0,    30,     0,    11,     0,     9,
-     0,    10,     0,    22,     0,     7,     0,    22,    36,    75,
-     0,    22,    36,    71,     0,    23,    65,    75,    66,     0,
-    25,    65,    73,    66,     0,    25,    65,    75,    12,    73,
-    66,     0,    25,    65,    75,    12,    75,    12,    75,    66,
-     0,    26,    65,    71,    66,     0,    26,    65,    75,    66,
-     0,    26,    65,    71,    12,    71,    66,     0,    26,    65,
-    75,    12,    71,    66,     0,    26,    65,    75,    12,    75,
-    66,     0,    26,    65,    71,    12,    75,    66,     0,    26,
-    65,    71,    37,    71,    66,     0,    26,    65,    75,    37,
-    71,    66,     0,    26,    65,    71,    37,    75,    66,     0,
-    26,    65,    75,    37,    75,    66,     0,    28,    65,    72,
-    12,    72,    66,     0,    28,    65,    72,    12,    72,    12,
-    72,    66,     0,    29,    65,    73,    12,    73,    66,     0,
-    29,    65,    73,    12,    73,    12,    72,    66,     0,    33,
-    65,    75,    12,    75,    12,    73,    12,    72,    66,     0,
-    27,    65,    73,    12,    72,    66,     0,    32,    65,    66,
-     0,    32,    65,    73,    66,     0,    34,    65,    75,    12,
-    75,    66,     0,    34,    65,    71,    12,    75,    66,     0,
-    34,    65,    75,    12,    71,    66,     0,    34,    65,    71,
-    12,    71,    66,     0,    35,    65,    71,    12,    71,    12,
-    71,    66,     0,    35,    65,    75,    12,    71,    12,    71,
-    66,     0,    35,    65,    71,    12,    75,    12,    71,    66,
-     0,    35,    65,    71,    12,    71,    12,    75,    66,     0,
-    35,    65,    75,    12,    75,    12,    71,    66,     0,    35,
-    65,    75,    12,    71,    12,    75,    66,     0,    35,    65,
-    71,    12,    75,    12,    75,    66,     0,    35,    65,    75,
-    12,    75,    12,    75,    66,     0,    13,    65,    75,    66,
-     7,     0,    13,    65,    75,    66,     7,    14,     7,     0,
-    21,     8,     7,     0,    75,    52,    75,     0,    75,    51,
-    75,     0,    75,    53,    75,     0,    75,    54,    75,     0,
-    22,    58,     0,    22,    59,     0,    58,    22,     0,    59,
-    22,     0,    75,    56,    75,     0,    51,    75,     0,    65,
-    73,    66,     0,    20,    22,    55,    75,    67,     0,    75,
-    55,    75,    67,     0,    75,    55,    75,    67,    36,    75,
-     0,     3,    40,     3,    40,     3,     0,     3,    68,     3,
-    68,     3,     0,     3,    40,     3,     0,     3,    68,     3,
-     0,    75,    42,    75,    41,    75,     0,    75,    42,     5,
-    41,     5,     0,    75,    42,     5,    41,    75,     0,    75,
-    42,    75,    41,     5,     0
+    78,    79,     0,    72,     0,    73,     0,    47,     0,    86,
+    72,     0,    86,    73,     0,    86,    47,     0,    80,    72,
+     0,    80,    73,     0,    14,     8,    84,     0,    14,     8,
+    84,    15,    84,     0,    23,     8,    84,     0,    22,     8,
+    84,     0,    26,     9,     0,    27,     0,     1,    72,     0,
+     5,     0,    80,    61,    86,     0,    86,    61,    80,     0,
+    80,    61,    80,     0,    37,    74,    86,    75,     0,    37,
+    74,    86,    13,    80,    75,     0,    37,    74,    86,    13,
+    86,    75,     0,    37,    74,    86,    47,    80,    75,     0,
+    37,    74,    86,    47,    86,    75,     0,    80,     0,     6,
+     0,    86,     0,    82,    47,    82,     0,    82,    48,    86,
+     0,    81,     0,     3,    49,     3,     0,     4,     0,    30,
+    74,    86,    75,     0,    16,     0,    17,     0,    86,    52,
+    86,     0,    86,    53,    86,     0,    86,    54,    86,     0,
+    86,    55,    86,     0,    86,    56,    86,     0,    86,    57,
+    86,     0,    86,    58,    86,     0,    86,    59,    86,     0,
+     7,     0,     9,     0,    86,     0,    80,     0,     3,     0,
+    25,     0,    83,     0,    36,     0,    12,     0,    10,     0,
+    11,     0,    28,     0,    84,     0,    28,    42,    86,     0,
+    28,    42,    80,     0,    28,    43,    86,     0,    28,    44,
+    86,     0,    28,    45,    86,     0,    28,    46,    86,     0,
+    29,    74,    86,    75,     0,    31,    74,    82,    75,     0,
+    31,    74,    86,    13,    82,    75,     0,    31,    74,    86,
+    13,    86,    13,    86,    75,     0,    32,    74,    80,    75,
+     0,    32,    74,    86,    75,     0,    32,    74,    80,    13,
+    80,    75,     0,    32,    74,    86,    13,    80,    75,     0,
+    32,    74,    86,    13,    86,    75,     0,    32,    74,    80,
+    13,    86,    75,     0,    32,    74,    80,    47,    80,    75,
+     0,    32,    74,    86,    47,    80,    75,     0,    32,    74,
+    80,    47,    86,    75,     0,    32,    74,    86,    47,    86,
+    75,     0,    34,    74,    85,    13,    85,    75,     0,    34,
+    74,    85,    13,    85,    13,    85,    75,     0,    35,    74,
+    82,    13,    82,    75,     0,    35,    74,    82,    13,    82,
+    13,    81,    75,     0,    39,    74,    86,    13,    86,    13,
+    82,    13,    81,    75,     0,    33,    74,    82,    13,    81,
+    75,     0,    33,    74,    82,    13,    25,    75,     0,    38,
+    74,    75,     0,    38,    74,    82,    75,     0,    40,    74,
+    85,    13,    85,    75,     0,    40,    74,    85,    75,     0,
+    41,    74,    85,    13,    85,    13,    85,    75,     0,    86,
+    61,    86,     0,    86,    60,    86,     0,    86,    62,    86,
+     0,    86,    63,    86,     0,    28,    67,     0,    28,    68,
+     0,    67,    28,     0,    68,    28,     0,    86,    65,    86,
+     0,    60,    86,     0,    74,    85,    75,     0,    21,    28,
+    64,    86,    76,     0,    86,    64,    86,    76,     0,    86,
+    64,    86,    76,    42,    86,     0,    86,    64,    86,    76,
+    43,    86,     0,    86,    64,    86,    76,    44,    86,     0,
+    86,    64,    86,    76,    45,    86,     0,    86,    64,    86,
+    76,    46,    86,     0,     3,    77,     3,    77,     3,     0,
+     3,    77,     3,     0,    86,    51,    86,    50,    86,     0,
+    86,    51,     5,    50,     5,     0,    86,    51,     5,    50,
+    86,     0,    86,    51,    86,    50,     5,     0
 };
 
 #endif
 
 #if YYDEBUG != 0
 static const short yyrline[] = { 0,
-   132,   133,   136,   136,   136,   137,   138,   139,   140,   141,
-   142,   145,   147,   148,   149,   150,   151,   152,   153,   154,
-   157,   159,   163,   164,   165,   166,   167,   168,   172,   173,
-   174,   175,   176,   177,   178,   179,   180,   181,   182,   183,
-   186,   187,   188,   189,   190,   191,   192,   193,   194,   195,
-   196,   197,   198,   200,   203,   204,   205,   206,   207,   208,
-   209,   210,   211,   212,   213,   214,   215,   216,   217,   218,
-   219,   220,   221,   222,   223,   224,   225,   226,   227,   228,
-   229,   230,   231,   232,   233,   234,   235,   239,   243,   247,
-   248,   250,   251,   252,   253,   254,   255,   256,   257,   259,
-   261,   263,   264,   265,   266,   267,   268,   269,   270
+   135,   136,   139,   139,   139,   140,   141,   142,   143,   144,
+   145,   147,   150,   151,   153,   154,   155,   158,   160,   161,
+   162,   163,   164,   165,   166,   167,   170,   174,   175,   176,
+   177,   178,   179,   183,   184,   185,   186,   187,   188,   189,
+   190,   191,   192,   193,   194,   197,   197,   199,   199,   201,
+   202,   203,   204,   205,   206,   207,   208,   209,   210,   211,
+   212,   213,   214,   215,   217,   218,   219,   221,   224,   225,
+   226,   227,   228,   229,   230,   231,   232,   233,   234,   235,
+   236,   237,   238,   239,   240,   241,   242,   243,   244,   245,
+   246,   250,   254,   255,   257,   258,   259,   260,   261,   262,
+   263,   264,   266,   268,   270,   273,   276,   279,   283,   284,
+   285,   286,   287,   288
 };
 #endif
 
@@ -304,390 +315,359 @@ static const short yyrline[] = { 0,
 #if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
 
 static const char * const yytname[] = {   "$","error","$undefined.","NUM","BOOLVAL",
-"STR","ARR","BLOCK","PBLOCK","PI","E","CLVAL","PSEP","IF","ELSE","BTRUE","BFALSE",
-"DATE1","TIME1","DATETIME1","DIM","WHILE","VAR","FNCT","BFNCT","AFNCT","SFNCT",
-"FUNC1","FUNC2","FUNC3","TXT","SRFUNC","YYFNC","FUNC4","YYFNC2","YYFNC3","'='",
-"','","CLAUSE","SER","COLR","COLC","'?'","AND","OR","EQ","NE","GT","GE","LT",
+"STR","ARR","BLOCK","PBLOCK","IBLOCK","PI","E","CLVAL","PSEP","IF","ELSE","BTRUE",
+"BFALSE","DATE1","TIME1","DATETIME1","DIM","WHILE","FOR","INARR","RANGEARR",
+"RETURN","BREAK","VAR","FNCT","BFNCT","AFNCT","SFNCT","FUNC1","FUNC2","FUNC3",
+"TXT","SRFUNC","YYFNC","FUNC4","YYFNC2","YYFNC3","'='","ADDEQ","SUBEQ","MULEQ",
+"DIVEQ","','","CLAUSE","SER","COLC","'?'","AND","OR","EQ","NE","GT","GE","LT",
 "LE","'-'","'+'","'*'","'/'","'['","'^'","NEG","INC","DEC","PINC","PDEC","PDIM",
 "'\\n'","';'","'('","')'","']'","':'","input","line","str_exp","range","arr",
-"bool","exp", NULL
+"bool","block","anyarg","exp", NULL
 };
 #endif
 
 static const short yyr1[] = {     0,
-    69,    69,    70,    70,    70,    70,    70,    70,    70,    70,
-    70,    71,    71,    71,    71,    71,    71,    71,    71,    71,
-    72,    72,    73,    73,    73,    73,    73,    73,    74,    74,
-    74,    74,    74,    74,    74,    74,    74,    74,    74,    74,
-    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
-    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
-    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
-    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
-    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
-    75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
-    75,    75,    75,    75,    75,    75,    75,    75,    75
+    78,    78,    79,    79,    79,    79,    79,    79,    79,    79,
+    79,    79,    79,    79,    79,    79,    79,    80,    80,    80,
+    80,    80,    80,    80,    80,    80,    81,    82,    82,    82,
+    82,    82,    82,    83,    83,    83,    83,    83,    83,    83,
+    83,    83,    83,    83,    83,    84,    84,    85,    85,    86,
+    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+    86,    86,    86,    86,    86,    86,    86,    86,    86,    86,
+    86,    86,    86,    86
 };
 
 static const short yyr2[] = {     0,
      0,     2,     1,     1,     1,     2,     2,     2,     2,     2,
-     2,     1,     3,     3,     3,     4,     6,     6,     6,     6,
-     1,     3,     1,     1,     3,     3,     1,     3,     1,     4,
-     1,     1,     3,     3,     3,     3,     3,     3,     3,     3,
+     3,     5,     3,     3,     2,     1,     2,     1,     3,     3,
+     3,     4,     6,     6,     6,     6,     1,     1,     1,     3,
+     3,     1,     3,     1,     4,     1,     1,     3,     3,     3,
+     3,     3,     3,     3,     3,     1,     1,     1,     1,     1,
      1,     1,     1,     1,     1,     1,     1,     1,     3,     3,
-     4,     4,     6,     8,     4,     4,     6,     6,     6,     6,
-     6,     6,     6,     6,     6,     8,     6,     8,    10,     6,
-     3,     4,     6,     6,     6,     6,     8,     8,     8,     8,
-     8,     8,     8,     8,     5,     7,     3,     3,     3,     3,
-     3,     2,     2,     2,     2,     3,     2,     3,     5,     4,
-     6,     5,     5,     3,     3,     5,     5,     5,     5
+     3,     3,     3,     3,     4,     4,     6,     8,     4,     4,
+     6,     6,     6,     6,     6,     6,     6,     6,     6,     8,
+     6,     8,    10,     6,     6,     3,     4,     6,     4,     8,
+     3,     3,     3,     3,     2,     2,     2,     2,     3,     2,
+     3,     5,     4,     6,     6,     6,     6,     6,     5,     3,
+     5,     5,     5,     5
 };
 
 static const short yydefact[] = {     1,
-     0,     0,    41,    29,    12,    48,    45,    46,    44,     0,
-    31,    32,     0,     0,    47,     0,     0,     0,     0,     0,
-     0,     0,    43,     0,     0,     0,     0,     0,     5,     0,
-     0,     0,     3,     4,     0,     2,     0,    42,     0,    11,
-     0,     0,     0,     0,     0,     0,    92,    93,     0,     0,
+     0,     0,    50,    34,    18,    46,    47,    55,    56,    54,
+     0,    36,    37,     0,     0,     0,    51,     0,    16,    57,
+     0,     0,     0,     0,     0,     0,     0,    53,     0,     0,
+     0,     0,     0,     5,     0,     0,     0,     3,     4,     0,
+     2,     0,    52,    58,     0,    17,     0,     0,     0,     0,
+     0,    15,     0,     0,     0,     0,     0,    95,    96,     0,
      0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-    97,    94,    95,    41,    23,    47,    21,    27,     0,    24,
-     0,     9,    10,     8,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,     0,     6,
-     7,   104,   105,     0,     0,    87,    50,    49,     0,     0,
-     0,    24,     0,     0,     0,     0,     0,     0,     0,    71,
-     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,    98,    15,    13,     0,     0,    33,    34,    35,    36,
-    37,    38,    39,    40,    89,    14,    88,    90,    91,     0,
-    96,     0,     0,     0,     0,    51,    30,    52,     0,     0,
-     0,    55,     0,     0,    56,     0,     0,     0,     0,     0,
-    16,    72,     0,     0,     0,     0,     0,    88,    28,    22,
-    25,    26,     0,     0,   100,   102,   103,    85,    99,     0,
-    24,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,     0,     0,   107,   108,   109,   106,     0,
-     0,    53,     0,    57,    60,    61,    63,    58,    59,    62,
-    64,    70,     0,    65,     0,    67,    17,    18,    19,    20,
-     0,    76,    74,    75,    73,     0,     0,     0,     0,   101,
-    86,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,     0,     0,    54,    66,    68,     0,    77,    80,    79,
-    83,    78,    82,    81,    84,     0,    69,     0,     0
+     0,   100,    97,    98,    49,     0,    48,     0,     9,    10,
+     8,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,     6,     7,   110,    11,
+     0,    14,    13,    60,    59,    61,    62,    63,    64,     0,
+     0,    50,    28,    27,    32,     0,    29,     0,     0,     0,
+    29,     0,     0,     0,    86,     0,     0,     0,     0,     0,
+   101,    21,    19,     0,     0,    38,    39,    40,    41,    42,
+    43,    44,    45,    92,    20,    91,    93,    94,     0,    99,
+     0,     0,     0,    65,    35,     0,     0,     0,    66,     0,
+     0,     0,    69,     0,     0,    70,     0,     0,     0,     0,
+     0,    22,    87,     0,     0,    89,     0,    91,     0,     0,
+   103,   109,    12,   102,    33,    30,    31,     0,    29,     0,
+     0,     0,     0,     0,     0,     0,     0,    51,     0,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,   112,
+   113,   114,   111,     0,     0,     0,     0,     0,    67,     0,
+    71,    74,    75,    77,    72,    73,    76,    78,    85,    84,
+     0,    79,     0,    81,    23,    24,    25,    26,     0,    88,
+     0,   104,   105,   106,   107,   108,     0,     0,     0,     0,
+     0,    68,    80,    82,     0,    90,     0,    83,     0,     0
 };
 
 static const short yydefgoto[] = {     1,
-    36,    67,    68,    69,    38,    70
+    41,   114,   115,   116,    43,    44,    76,    77
 };
 
 static const short yypact[] = {-32768,
-   242,   -55,    -3,-32768,-32768,-32768,-32768,-32768,-32768,   -52,
--32768,-32768,    -7,     9,    70,   -44,   -42,   -33,     4,     6,
-     7,    28,-32768,    31,    47,    52,    73,    95,-32768,   707,
-    41,    93,-32768,-32768,   369,-32768,    50,-32768,   822,-32768,
-   131,   158,   707,   112,   162,   426,-32768,-32768,   707,   707,
-   369,   426,   369,   483,   369,   707,   305,   707,   426,   426,
--32768,-32768,-32768,   -30,-32768,    65,   118,-32768,   -26,   363,
-   426,-32768,-32768,-32768,   540,   707,   707,   707,   707,   707,
-   707,   707,   707,   707,   426,   707,   707,   707,   707,-32768,
--32768,   159,   103,   871,   707,-32768,   118,   363,   896,   921,
-   -19,   135,    -6,   731,    54,   163,   363,    61,   757,-32768,
-    -4,   420,   -11,   477,    -9,   534,   707,   195,   181,   369,
-   707,-32768,-32768,    86,   165,  1272,   699,   699,   141,   141,
-   141,   141,   141,   141,    86,-32768,    86,    12,    12,   299,
--32768,   204,   210,   207,   845,-32768,-32768,-32768,   369,   426,
-   426,-32768,   426,   426,-32768,   483,   483,   369,   426,   426,
--32768,-32768,   707,   426,   426,   426,   426,    86,-32768,-32768,
-   182,  1287,   597,   654,   183,-32768,-32768,   209,-32768,    -2,
-   591,   -36,   946,   -27,   971,    38,   996,    43,  1021,   155,
-    -5,   -10,    67,  1046,    69,  1071,   648,    78,  1096,    79,
-  1121,    -8,   783,     2,   802,-32768,  1287,-32768,  1287,   707,
-   218,-32768,   707,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
--32768,-32768,   483,-32768,   483,-32768,-32768,-32768,-32768,-32768,
-   369,-32768,-32768,-32768,-32768,   426,   426,   426,   426,  1287,
--32768,  1146,   160,   161,    88,    80,  1171,    85,  1196,    91,
-  1221,   102,  1246,-32768,-32768,-32768,   483,-32768,-32768,-32768,
--32768,-32768,-32768,-32768,-32768,   164,-32768,   228,-32768
+   255,   -52,   -45,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+    27,-32768,-32768,    42,    67,    72,-32768,    94,-32768,    80,
+    43,    46,    47,    53,    62,    63,    65,-32768,    76,    77,
+    78,    81,    88,-32768,   724,    86,   121,-32768,-32768,   454,
+-32768,    40,-32768,-32768,   845,-32768,   105,    95,    90,    95,
+    95,-32768,   454,   724,   724,   724,   724,-32768,-32768,   724,
+   724,   400,   454,   400,   454,   400,   724,   327,   724,   454,
+   454,-32768,-32768,-32768,   104,    96,   391,   454,-32768,-32768,
+-32768,   562,   724,   724,   724,   724,   724,   724,   724,   724,
+   724,   454,   724,   724,   724,   724,-32768,-32768,    97,   160,
+   724,-32768,-32768,   104,   391,   445,   445,   445,   445,   894,
+   919,   -34,-32768,   104,-32768,   -26,   716,   -11,   145,    -8,
+   391,   163,     0,   748,-32768,    -2,   773,    -4,   164,   724,
+-32768,-32768,    79,   130,  1120,   496,   496,    70,    70,    70,
+    70,    70,    70,    79,-32768,    79,    34,    34,   320,-32768,
+   178,    95,   868,-32768,-32768,   180,   400,   724,-32768,   400,
+   454,   454,-32768,   454,   454,-32768,   508,   454,   400,   454,
+   454,-32768,-32768,   724,   454,-32768,   454,    79,   616,   670,
+   -17,-32768,-32768,-32768,-32768,   136,   445,    31,   801,   -44,
+   944,   -42,   969,   -37,   994,   -31,  1019,   110,   111,   391,
+    -3,    -6,   -24,  1044,    36,  1069,   826,   112,   175,-32768,
+   445,-32768,   445,   724,   724,   724,   724,   724,-32768,   724,
+-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+   454,-32768,   454,-32768,-32768,-32768,-32768,-32768,   400,-32768,
+   454,   445,   445,   445,   445,   445,  1094,   115,   116,    10,
+   118,-32768,-32768,-32768,   454,-32768,   119,-32768,   195,-32768
 };
 
 static const short yypgoto[] = {-32768,
--32768,    51,   -49,   -31,-32768,    -1
+-32768,    75,  -159,   -50,-32768,   -47,   -59,    -1
 };
 
 
-#define	YYLAST		1343
-
-
-static const short yytable[] = {    39,
-   164,   225,   166,   236,   106,   150,   223,    40,   118,    41,
-   120,   121,    43,   238,    44,    71,    45,   120,   121,   101,
-    49,   105,    50,   108,    71,   111,   120,   121,    61,   214,
-   151,    51,   120,   121,   120,   121,    41,    42,   216,   122,
-    71,    94,    71,    71,    98,    71,   148,    99,   100,   102,
-   104,    37,   107,    71,   109,   226,   112,   114,   116,   152,
-   224,   162,    62,   212,    42,   156,    88,    89,    52,   124,
-    53,    54,   158,   126,   127,   128,   129,   130,   131,   132,
-   133,   134,   135,   137,   138,   139,   140,   141,   171,    71,
-   120,   121,    55,   145,    71,    56,    97,   120,   121,   257,
-    46,    71,   103,   218,   119,    46,   190,   191,   220,   113,
-   115,    57,    72,    73,    63,   168,    58,   180,    71,   172,
-    71,   123,    47,    48,   120,   121,   192,    47,    48,    71,
-    71,    71,   227,    92,   229,   136,    71,    59,    86,    87,
-    88,    89,    71,   232,   234,   258,   149,   181,   183,   185,
-   260,   187,   189,    71,   107,   107,   262,   194,   196,    60,
-    93,   197,   199,   201,   203,   205,    95,   264,    96,    71,
-   143,   207,   209,   243,   157,   244,    75,    76,    77,    78,
-    79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
-    89,    84,   117,    86,    87,    88,    89,   169,   142,   245,
-   182,   184,   170,   186,   188,   173,   176,   266,   240,   193,
-   195,   242,   177,   178,   198,   200,   202,   204,   210,   121,
-   222,   107,   211,   107,   241,   255,   256,   269,     0,   267,
-     0,     0,     0,     0,   247,   249,   251,   253,     0,     0,
-     0,   268,     2,     0,     3,     4,     5,     0,     6,     0,
-     7,     8,     9,     0,    10,   107,    11,    12,     0,     0,
-     0,    13,    14,    15,    16,    17,    18,    19,    20,    21,
-    22,    23,    24,    25,    26,    27,    28,     0,    29,     0,
-     0,     0,     0,     0,     0,     0,   246,   248,   250,   252,
-     0,     0,    30,     0,     0,     0,     0,     0,     0,    31,
-    32,     0,     0,     0,    33,    34,    35,    64,     4,     5,
-    65,     6,     0,     7,     8,     9,     0,    10,     0,    11,
-    12,     0,     0,     0,    13,    14,    66,    16,    17,    18,
-    19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-    75,    76,    77,    78,    79,    80,    81,    82,    83,    84,
-   117,    86,    87,    88,    89,    30,     0,     0,     0,     0,
-     0,     0,    31,    32,     0,   175,     0,     0,     0,    35,
-   110,    64,     4,     5,    65,     6,     0,     7,     8,     9,
-     0,    10,     0,    11,    12,     0,     0,     0,    13,    14,
-    66,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-    25,    26,    27,    28,    75,    76,    77,    78,    79,    80,
-    81,    82,    83,    84,    85,    86,    87,    88,    89,    30,
-     0,     0,     0,     0,     0,     0,    31,    32,     3,     4,
-     5,   163,     6,    35,     7,     8,     9,     0,    10,     0,
-    11,    12,     0,     0,     0,    13,    14,    15,    16,    17,
+#define	YYLAST		1185
+
+
+static const short yytable[] = {    45,
+   100,   161,   102,   103,   167,   122,   233,   199,   175,   231,
+   128,   129,   169,   120,   156,   123,    78,   126,    78,    46,
+   157,   158,   255,    78,   214,   215,   216,   217,   218,    78,
+   221,    47,   223,    72,    48,   162,    78,   225,   157,   158,
+   157,   158,    47,   227,   157,   158,   157,   158,   159,    78,
+   235,   105,   106,   107,   108,   109,   157,   158,   110,   111,
+   117,   119,   121,   163,   121,   124,   121,   127,   234,    49,
+   176,   232,   173,   249,    50,    42,   133,   157,   158,    51,
+   135,   136,   137,   138,   139,   140,   141,   142,   143,   144,
+   146,   147,   148,   149,   150,   257,    78,    95,    96,   153,
+    78,     6,    52,     7,   183,   219,   186,    99,   201,   188,
+   237,    79,    80,    73,    75,   208,    60,   209,   202,    61,
+    62,    53,    54,    55,    56,    57,    63,   104,   178,    91,
+   130,    93,    94,    95,    96,    64,    65,   118,    66,    75,
+    93,    94,    95,    96,    75,    75,    58,    59,    74,    67,
+    68,    69,   132,   101,    70,   121,   187,   164,   189,   191,
+   193,    71,   195,   197,    78,   200,   145,   121,   204,   206,
+   131,   248,   207,   151,   152,   168,   177,   211,   213,   179,
+   182,   251,   185,   158,   229,   230,   240,   241,   250,   253,
+   254,   165,   256,   258,   260,    82,    83,    84,    85,    86,
+    87,    88,    89,    90,    91,    92,    93,    94,    95,    96,
+     0,     0,   242,   243,   244,   245,   246,     0,   247,   166,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,   200,     0,     0,     0,   190,   192,   121,   194,   196,
+     0,     0,    75,     0,   203,   205,     0,     0,     0,    75,
+     0,    75,     0,   200,   259,     2,     0,     3,     4,     5,
+     0,     6,     0,     7,     8,     9,    10,     0,    11,     0,
+    12,    13,     0,     0,     0,    14,    15,    16,     0,    17,
     18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-    28,    75,    76,    77,    78,    79,    80,    81,    82,    83,
-    84,   117,    86,    87,    88,    89,    30,     0,     0,     0,
-     0,     0,     0,    31,    32,     3,     4,     5,   165,     6,
-    35,     7,     8,     9,     0,    10,     0,    11,    12,     0,
-     0,     0,    13,    14,    66,    16,    17,    18,    19,    20,
-    21,    22,    23,    24,    25,    26,    27,    28,    75,    76,
-    77,    78,    79,    80,    81,    82,    83,    84,    85,    86,
-    87,    88,    89,    30,     0,     0,     0,     0,     0,     0,
-    31,    32,     3,     4,   125,   167,     6,    35,     7,     8,
-     9,     0,    10,     0,    11,    12,     0,     0,     0,    13,
-    14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-     0,    25,    26,    27,    28,    75,    76,    77,    78,    79,
-    80,    81,    82,    83,    84,    85,    86,    87,    88,    89,
-    30,     0,     0,     0,     0,     0,     0,    31,    32,     3,
-     4,   206,   213,     6,    35,     7,     8,     9,     0,    10,
-     0,    11,    12,     0,     0,     0,    13,    14,    15,    16,
-    17,    18,    19,    20,    21,    22,    23,     0,    25,    26,
-    27,    28,    75,    76,    77,    78,    79,    80,    81,    82,
-    83,    84,    85,    86,    87,    88,    89,    30,     0,     0,
-     0,     0,     0,     0,    31,    32,     3,     4,   208,   231,
-     6,    35,     7,     8,     9,     0,    10,     0,    11,    12,
-     0,     0,     0,    13,    14,    15,    16,    17,    18,    19,
-    20,    21,    22,    23,     0,    25,    26,    27,    28,    75,
-    76,    77,    78,    79,    80,    81,    82,    83,    84,   117,
-    86,    87,    88,    89,    30,     0,     0,     0,     0,     3,
-     4,    31,    32,     6,     0,     7,     8,     9,    35,    10,
-     0,    11,    12,     0,     0,     0,    13,    14,    15,    16,
-    17,    18,    19,    20,    21,    22,    23,     0,    25,    26,
-    27,    28,   153,    78,    79,    80,    81,    82,    83,    84,
-   117,    86,    87,    88,    89,     0,     0,    30,     0,     0,
-     0,     0,     0,     0,    31,    32,     0,   154,   159,     0,
-     0,    35,    75,    76,    77,    78,    79,    80,    81,    82,
-    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
-     0,     0,     0,   160,   237,     0,   155,     0,    75,    76,
-    77,    78,    79,    80,    81,    82,    83,    84,   117,    86,
-    87,    88,    89,   239,     0,     0,     0,     0,     0,     0,
-     0,     0,   161,     0,    75,    76,    77,    78,    79,    80,
-    81,    82,    83,    84,    85,    86,    87,    88,    89,     0,
-     0,     0,     0,    75,    76,    77,    78,    79,    80,    81,
-    82,    83,    84,    85,    86,    87,    88,    89,    74,     0,
-     0,     0,     0,    75,    76,    77,    78,    79,    80,    81,
-    82,    83,    84,    85,    86,    87,    88,    89,     0,     0,
-     0,     0,     0,     0,    90,    91,    75,    76,    77,    78,
-    79,    80,    81,    82,    83,    84,   117,    86,    87,    88,
-    89,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,   179,    75,    76,    77,    78,    79,    80,    81,    82,
-    83,    84,   117,    86,    87,    88,    89,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,   144,    75,    76,    77,
-    78,    79,    80,    81,    82,    83,    84,   117,    86,    87,
-    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,   146,    75,    76,    77,    78,    79,    80,    81,    82,
-    83,    84,   117,    86,    87,    88,    89,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,   147,    75,    76,    77,
-    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
-    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,   215,    75,    76,    77,    78,    79,    80,    81,    82,
-    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,   217,    75,    76,    77,
-    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
-    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,   219,    75,    76,    77,    78,    79,    80,    81,    82,
-    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,   221,    75,    76,    77,
-    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
-    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,   228,    75,    76,    77,    78,    79,    80,    81,    82,
-    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,   230,    75,    76,    77,
-    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
-    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,   233,    75,    76,    77,    78,    79,    80,    81,    82,
-    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,   235,    75,    76,    77,
-    78,    79,    80,    81,    82,    83,    84,   117,    86,    87,
-    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,   254,    75,    76,    77,    78,    79,    80,    81,    82,
-    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,   259,    75,    76,    77,
-    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
-    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,   261,    75,    76,    77,    78,    79,    80,    81,    82,
-    83,    84,    85,    86,    87,    88,    89,     0,     0,     0,
-     0,     0,     0,     0,     0,     0,   263,    75,    76,    77,
-    78,    79,    80,    81,    82,    83,    84,    85,    86,    87,
-    88,    89,     0,     0,     0,     0,     0,     0,     0,     0,
-     0,   265,   174,    75,    76,    77,    78,    79,    80,    81,
-    82,    83,    84,   117,    86,    87,    88,    89,    75,    76,
-    77,    78,    79,    80,    81,    82,    83,    84,   117,    86,
-    87,    88,    89
+    28,    29,    30,    31,    32,    33,     0,     0,     0,     0,
+     0,    34,     0,     0,     0,    75,     0,     0,     0,     0,
+     0,     0,     0,     0,    35,    75,     0,     0,     0,     0,
+     0,    36,    37,     0,     0,     0,    38,    39,    40,   112,
+     4,     5,   113,     6,     0,     7,     8,     9,    10,     0,
+     0,     0,    12,    13,     0,     0,     0,    14,     0,     0,
+     0,    17,     0,     0,    20,    21,    22,    23,    24,    25,
+    26,    27,    28,    29,    30,    31,    32,    33,     0,     0,
+    82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
+   130,    93,    94,    95,    96,     0,    35,     0,     0,     0,
+     0,     0,     0,    36,    37,   181,     0,     0,     0,     0,
+    40,   125,   112,     4,     5,   113,     6,     0,     7,     8,
+     9,    10,     0,     0,     0,    12,    13,     0,     0,     0,
+    14,     0,     0,     0,    17,     0,     0,    20,    21,    22,
+    23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
+    33,    82,    83,    84,    85,    86,    87,    88,    89,    90,
+    91,    92,    93,    94,    95,    96,     3,     4,     5,    35,
+     6,     0,     7,     8,     9,    10,    36,    37,     0,    12,
+    13,     0,     0,    40,    14,     0,     0,     0,    17,     0,
+     0,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+    29,    30,    31,    32,    33,    82,    83,    84,    85,    86,
+    87,    88,    89,    90,    91,   130,    93,    94,    95,    96,
+     3,     4,     5,    35,     6,     0,     7,     8,     9,    10,
+    36,    37,     0,    12,    13,     0,     0,    40,    14,     0,
+     0,     0,   198,     0,     0,    20,    21,    22,    23,    24,
+    25,    26,    27,    28,    29,    30,    31,    32,    33,    85,
+    86,    87,    88,    89,    90,    91,   130,    93,    94,    95,
+    96,     0,     0,     0,     3,     4,   134,    35,     6,     0,
+     7,     8,     9,    10,    36,    37,     0,    12,    13,     0,
+     0,    40,    14,     0,     0,     0,    17,     0,     0,    20,
+    21,    22,    23,    24,    25,    26,    27,    28,     0,    30,
+    31,    32,    33,     0,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     3,     4,
+   210,    35,     6,     0,     7,     8,     9,    10,    36,    37,
+     0,    12,    13,     0,     0,    40,    14,     0,     0,     0,
+    17,     0,     0,    20,    21,    22,    23,    24,    25,    26,
+    27,    28,     0,    30,    31,    32,    33,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,     0,     3,     4,   212,    35,     6,     0,     7,     8,
+     9,    10,    36,    37,     0,    12,    13,     0,     0,    40,
+    14,     0,     0,     0,    17,     0,     0,    20,    21,    22,
+    23,    24,    25,    26,    27,    28,     0,    30,    31,    32,
+    33,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,     3,     4,   160,    35,
+     6,     0,     7,     8,     9,    10,    36,    37,     0,    12,
+    13,     0,     0,    40,    14,     0,     0,     0,    17,     0,
+     0,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+   170,    30,    31,    32,    33,     0,    82,    83,    84,    85,
+    86,    87,    88,    89,    90,    91,    92,    93,    94,    95,
+    96,     0,     0,    35,     0,   174,     0,     0,     0,     0,
+    36,    37,     0,     0,   171,     0,     0,    40,    82,    83,
+    84,    85,    86,    87,    88,    89,    90,    91,   130,    93,
+    94,    95,    96,   220,     0,     0,     0,     0,     0,     0,
+     0,     0,   172,    82,    83,    84,    85,    86,    87,    88,
+    89,    90,    91,   130,    93,    94,    95,    96,   239,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,    82,    83,    84,    85,    86,    87,    88,    89,    90,
+    91,    92,    93,    94,    95,    96,     0,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,    82,    83,    84,    85,
+    86,    87,    88,    89,    90,    91,   130,    93,    94,    95,
+    96,    81,     0,     0,     0,    82,    83,    84,    85,    86,
+    87,    88,    89,    90,    91,    92,    93,    94,    95,    96,
+     0,     0,     0,     0,     0,     0,    97,    98,    82,    83,
+    84,    85,    86,    87,    88,    89,    90,    91,   130,    93,
+    94,    95,    96,     0,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,   184,    82,    83,    84,    85,    86,    87,
+    88,    89,    90,    91,   130,    93,    94,    95,    96,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,   154,    82,
+    83,    84,    85,    86,    87,    88,    89,    90,    91,   130,
+    93,    94,    95,    96,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,   155,    82,    83,    84,    85,    86,    87,
+    88,    89,    90,    91,    92,    93,    94,    95,    96,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,   222,    82,
+    83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
+    93,    94,    95,    96,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,   224,    82,    83,    84,    85,    86,    87,
+    88,    89,    90,    91,    92,    93,    94,    95,    96,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,   226,    82,
+    83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
+    93,    94,    95,    96,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,   228,    82,    83,    84,    85,    86,    87,
+    88,    89,    90,    91,    92,    93,    94,    95,    96,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,   236,    82,
+    83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
+    93,    94,    95,    96,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,   238,    82,    83,    84,    85,    86,    87,
+    88,    89,    90,    91,   130,    93,    94,    95,    96,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,   252,   180,
+    82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
+   130,    93,    94,    95,    96
 };
 
 static const short yycheck[] = {     1,
-    12,    12,    12,    12,    54,    12,    12,    63,    39,    40,
-    37,    38,    65,    12,    22,    52,     8,    37,    38,    51,
-    65,    53,    65,    55,    52,    57,    37,    38,    30,    66,
-    37,    65,    37,    38,    37,    38,    40,    68,    66,    66,
-    52,    43,    52,    52,    46,    52,    66,    49,    50,    51,
-    52,     1,    54,    52,    56,    66,    58,    59,    60,    66,
-    66,    66,    22,    66,    68,    12,    55,    56,    65,    71,
-    65,    65,    12,    75,    76,    77,    78,    79,    80,    81,
-    82,    83,    84,    85,    86,    87,    88,    89,   120,    52,
-    37,    38,    65,    95,    52,    65,    46,    37,    38,    12,
-    36,    52,    52,    66,    40,    36,   156,   157,    66,    59,
-    60,    65,    63,    64,    22,   117,    65,   149,    52,   121,
-    52,    71,    58,    59,    37,    38,   158,    58,    59,    52,
-    52,    52,    66,     3,    66,    85,    52,    65,    53,    54,
-    55,    56,    52,    66,    66,    66,    12,   149,   150,   151,
-    66,   153,   154,    52,   156,   157,    66,   159,   160,    65,
-     3,   163,   164,   165,   166,   167,    55,    66,     7,    52,
-    68,   173,   174,   223,    12,   225,    42,    43,    44,    45,
-    46,    47,    48,    49,    50,    51,    52,    53,    54,    55,
-    56,    51,    52,    53,    54,    55,    56,     3,    40,   231,
-   150,   151,    22,   153,   154,    41,     3,   257,   210,   159,
-   160,   213,     3,     7,   164,   165,   166,   167,    36,    38,
-    66,   223,    14,   225,     7,    66,    66,     0,    -1,    66,
-    -1,    -1,    -1,    -1,   236,   237,   238,   239,    -1,    -1,
-    -1,     0,     1,    -1,     3,     4,     5,    -1,     7,    -1,
-     9,    10,    11,    -1,    13,   257,    15,    16,    -1,    -1,
-    -1,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-    29,    30,    31,    32,    33,    34,    35,    -1,    37,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,   236,   237,   238,   239,
-    -1,    -1,    51,    -1,    -1,    -1,    -1,    -1,    -1,    58,
-    59,    -1,    -1,    -1,    63,    64,    65,     3,     4,     5,
-     6,     7,    -1,     9,    10,    11,    -1,    13,    -1,    15,
-    16,    -1,    -1,    -1,    20,    21,    22,    23,    24,    25,
+    48,    13,    50,    51,    13,    65,    13,   167,    13,    13,
+    70,    71,    13,    64,    49,    66,    61,    68,    61,    72,
+    47,    48,    13,    61,    42,    43,    44,    45,    46,    61,
+    75,    77,    75,    35,     8,    47,    61,    75,    47,    48,
+    47,    48,    77,    75,    47,    48,    47,    48,    75,    61,
+    75,    53,    54,    55,    56,    57,    47,    48,    60,    61,
+    62,    63,    64,    75,    66,    67,    68,    69,    75,    28,
+    75,    75,    75,   233,     8,     1,    78,    47,    48,     8,
+    82,    83,    84,    85,    86,    87,    88,    89,    90,    91,
+    92,    93,    94,    95,    96,   255,    61,    64,    65,   101,
+    61,     7,     9,     9,   152,    75,   157,     3,   168,   160,
+    75,    72,    73,    28,    40,   175,    74,   177,   169,    74,
+    74,    42,    43,    44,    45,    46,    74,    53,   130,    60,
+    61,    62,    63,    64,    65,    74,    74,    63,    74,    65,
+    62,    63,    64,    65,    70,    71,    67,    68,    28,    74,
+    74,    74,    78,    64,    74,   157,   158,    13,   160,   161,
+   162,    74,   164,   165,    61,   167,    92,   169,   170,   171,
+    75,   231,   174,    77,    15,    13,    13,   179,   180,    50,
+     3,   241,     3,    48,    75,    75,    75,    13,   239,    75,
+    75,    47,    75,    75,     0,    51,    52,    53,    54,    55,
+    56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
+    -1,    -1,   214,   215,   216,   217,   218,    -1,   220,    75,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,   233,    -1,    -1,    -1,   161,   162,   239,   164,   165,
+    -1,    -1,   168,    -1,   170,   171,    -1,    -1,    -1,   175,
+    -1,   177,    -1,   255,     0,     1,    -1,     3,     4,     5,
+    -1,     7,    -1,     9,    10,    11,    12,    -1,    14,    -1,
+    16,    17,    -1,    -1,    -1,    21,    22,    23,    -1,    25,
     26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
-    42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
-    52,    53,    54,    55,    56,    51,    -1,    -1,    -1,    -1,
-    -1,    -1,    58,    59,    -1,    67,    -1,    -1,    -1,    65,
-    66,     3,     4,     5,     6,     7,    -1,     9,    10,    11,
-    -1,    13,    -1,    15,    16,    -1,    -1,    -1,    20,    21,
-    22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
-    32,    33,    34,    35,    42,    43,    44,    45,    46,    47,
-    48,    49,    50,    51,    52,    53,    54,    55,    56,    51,
-    -1,    -1,    -1,    -1,    -1,    -1,    58,    59,     3,     4,
-     5,    12,     7,    65,     9,    10,    11,    -1,    13,    -1,
-    15,    16,    -1,    -1,    -1,    20,    21,    22,    23,    24,
-    25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-    35,    42,    43,    44,    45,    46,    47,    48,    49,    50,
-    51,    52,    53,    54,    55,    56,    51,    -1,    -1,    -1,
-    -1,    -1,    -1,    58,    59,     3,     4,     5,    12,     7,
-    65,     9,    10,    11,    -1,    13,    -1,    15,    16,    -1,
-    -1,    -1,    20,    21,    22,    23,    24,    25,    26,    27,
-    28,    29,    30,    31,    32,    33,    34,    35,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-    54,    55,    56,    51,    -1,    -1,    -1,    -1,    -1,    -1,
-    58,    59,     3,     4,     5,    12,     7,    65,     9,    10,
-    11,    -1,    13,    -1,    15,    16,    -1,    -1,    -1,    20,
-    21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-    -1,    32,    33,    34,    35,    42,    43,    44,    45,    46,
-    47,    48,    49,    50,    51,    52,    53,    54,    55,    56,
-    51,    -1,    -1,    -1,    -1,    -1,    -1,    58,    59,     3,
-     4,     5,    12,     7,    65,     9,    10,    11,    -1,    13,
-    -1,    15,    16,    -1,    -1,    -1,    20,    21,    22,    23,
-    24,    25,    26,    27,    28,    29,    30,    -1,    32,    33,
-    34,    35,    42,    43,    44,    45,    46,    47,    48,    49,
-    50,    51,    52,    53,    54,    55,    56,    51,    -1,    -1,
-    -1,    -1,    -1,    -1,    58,    59,     3,     4,     5,    12,
-     7,    65,     9,    10,    11,    -1,    13,    -1,    15,    16,
-    -1,    -1,    -1,    20,    21,    22,    23,    24,    25,    26,
-    27,    28,    29,    30,    -1,    32,    33,    34,    35,    42,
-    43,    44,    45,    46,    47,    48,    49,    50,    51,    52,
-    53,    54,    55,    56,    51,    -1,    -1,    -1,    -1,     3,
-     4,    58,    59,     7,    -1,     9,    10,    11,    65,    13,
-    -1,    15,    16,    -1,    -1,    -1,    20,    21,    22,    23,
-    24,    25,    26,    27,    28,    29,    30,    -1,    32,    33,
-    34,    35,    12,    45,    46,    47,    48,    49,    50,    51,
-    52,    53,    54,    55,    56,    -1,    -1,    51,    -1,    -1,
-    -1,    -1,    -1,    -1,    58,    59,    -1,    37,    12,    -1,
-    -1,    65,    42,    43,    44,    45,    46,    47,    48,    49,
-    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
-    -1,    -1,    -1,    37,    12,    -1,    66,    -1,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-    54,    55,    56,    12,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    -1,    66,    -1,    42,    43,    44,    45,    46,    47,
-    48,    49,    50,    51,    52,    53,    54,    55,    56,    -1,
-    -1,    -1,    -1,    42,    43,    44,    45,    46,    47,    48,
-    49,    50,    51,    52,    53,    54,    55,    56,    37,    -1,
-    -1,    -1,    -1,    42,    43,    44,    45,    46,    47,    48,
-    49,    50,    51,    52,    53,    54,    55,    56,    -1,    -1,
-    -1,    -1,    -1,    -1,    63,    64,    42,    43,    44,    45,
-    46,    47,    48,    49,    50,    51,    52,    53,    54,    55,
-    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    67,    42,    43,    44,    45,    46,    47,    48,    49,
-    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
-    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
-    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
-    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
-    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
-    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
-    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
-    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
-    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
-    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
-    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
-    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
-    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
-    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    66,    42,    43,    44,    45,    46,    47,    48,    49,
-    50,    51,    52,    53,    54,    55,    56,    -1,    -1,    -1,
-    -1,    -1,    -1,    -1,    -1,    -1,    66,    42,    43,    44,
-    45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-    55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-    -1,    66,    41,    42,    43,    44,    45,    46,    47,    48,
-    49,    50,    51,    52,    53,    54,    55,    56,    42,    43,
-    44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-    54,    55,    56
+    36,    37,    38,    39,    40,    41,    -1,    -1,    -1,    -1,
+    -1,    47,    -1,    -1,    -1,   231,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    60,   241,    -1,    -1,    -1,    -1,
+    -1,    67,    68,    -1,    -1,    -1,    72,    73,    74,     3,
+     4,     5,     6,     7,    -1,     9,    10,    11,    12,    -1,
+    -1,    -1,    16,    17,    -1,    -1,    -1,    21,    -1,    -1,
+    -1,    25,    -1,    -1,    28,    29,    30,    31,    32,    33,
+    34,    35,    36,    37,    38,    39,    40,    41,    -1,    -1,
+    51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
+    61,    62,    63,    64,    65,    -1,    60,    -1,    -1,    -1,
+    -1,    -1,    -1,    67,    68,    76,    -1,    -1,    -1,    -1,
+    74,    75,     3,     4,     5,     6,     7,    -1,     9,    10,
+    11,    12,    -1,    -1,    -1,    16,    17,    -1,    -1,    -1,
+    21,    -1,    -1,    -1,    25,    -1,    -1,    28,    29,    30,
+    31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
+    41,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+    60,    61,    62,    63,    64,    65,     3,     4,     5,    60,
+     7,    -1,     9,    10,    11,    12,    67,    68,    -1,    16,
+    17,    -1,    -1,    74,    21,    -1,    -1,    -1,    25,    -1,
+    -1,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+    37,    38,    39,    40,    41,    51,    52,    53,    54,    55,
+    56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
+     3,     4,     5,    60,     7,    -1,     9,    10,    11,    12,
+    67,    68,    -1,    16,    17,    -1,    -1,    74,    21,    -1,
+    -1,    -1,    25,    -1,    -1,    28,    29,    30,    31,    32,
+    33,    34,    35,    36,    37,    38,    39,    40,    41,    54,
+    55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
+    65,    -1,    -1,    -1,     3,     4,     5,    60,     7,    -1,
+     9,    10,    11,    12,    67,    68,    -1,    16,    17,    -1,
+    -1,    74,    21,    -1,    -1,    -1,    25,    -1,    -1,    28,
+    29,    30,    31,    32,    33,    34,    35,    36,    -1,    38,
+    39,    40,    41,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     3,     4,
+     5,    60,     7,    -1,     9,    10,    11,    12,    67,    68,
+    -1,    16,    17,    -1,    -1,    74,    21,    -1,    -1,    -1,
+    25,    -1,    -1,    28,    29,    30,    31,    32,    33,    34,
+    35,    36,    -1,    38,    39,    40,    41,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,     3,     4,     5,    60,     7,    -1,     9,    10,
+    11,    12,    67,    68,    -1,    16,    17,    -1,    -1,    74,
+    21,    -1,    -1,    -1,    25,    -1,    -1,    28,    29,    30,
+    31,    32,    33,    34,    35,    36,    -1,    38,    39,    40,
+    41,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,     3,     4,    13,    60,
+     7,    -1,     9,    10,    11,    12,    67,    68,    -1,    16,
+    17,    -1,    -1,    74,    21,    -1,    -1,    -1,    25,    -1,
+    -1,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+    13,    38,    39,    40,    41,    -1,    51,    52,    53,    54,
+    55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
+    65,    -1,    -1,    60,    -1,    13,    -1,    -1,    -1,    -1,
+    67,    68,    -1,    -1,    47,    -1,    -1,    74,    51,    52,
+    53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
+    63,    64,    65,    13,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    75,    51,    52,    53,    54,    55,    56,    57,
+    58,    59,    60,    61,    62,    63,    64,    65,    13,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    51,    52,    53,    54,    55,    56,    57,    58,    59,
+    60,    61,    62,    63,    64,    65,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    51,    52,    53,    54,
+    55,    56,    57,    58,    59,    60,    61,    62,    63,    64,
+    65,    47,    -1,    -1,    -1,    51,    52,    53,    54,    55,
+    56,    57,    58,    59,    60,    61,    62,    63,    64,    65,
+    -1,    -1,    -1,    -1,    -1,    -1,    72,    73,    51,    52,
+    53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
+    63,    64,    65,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    76,    51,    52,    53,    54,    55,    56,
+    57,    58,    59,    60,    61,    62,    63,    64,    65,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    75,    51,
+    52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
+    62,    63,    64,    65,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    75,    51,    52,    53,    54,    55,    56,
+    57,    58,    59,    60,    61,    62,    63,    64,    65,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    75,    51,
+    52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
+    62,    63,    64,    65,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    75,    51,    52,    53,    54,    55,    56,
+    57,    58,    59,    60,    61,    62,    63,    64,    65,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    75,    51,
+    52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
+    62,    63,    64,    65,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    75,    51,    52,    53,    54,    55,    56,
+    57,    58,    59,    60,    61,    62,    63,    64,    65,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    75,    51,
+    52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
+    62,    63,    64,    65,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    75,    51,    52,    53,    54,    55,    56,
+    57,    58,    59,    60,    61,    62,    63,    64,    65,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    75,    50,
+    51,    52,    53,    54,    55,    56,    57,    58,    59,    60,
+    61,    62,    63,    64,    65
 };
 /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
 
@@ -1018,7 +998,7 @@ yynewstate:
 #endif
 
       /* Get the current used size of the three stacks, in elements.  */
-      int size = (int)(yyssp - yyss) + 1;
+      int size = yyssp - yyss + 1;
 
 #ifdef yyoverflow
       /* Each stack pointer address is followed by the size of
@@ -1248,312 +1228,328 @@ case 10:
 {store_res(&yyvsp[-1]); return 0;;
     break;}
 case 11:
-{yyerrok;;
+{if(block_res = eval(&yyval, &yyvsp[-1]))return block_res; 
+				if(yyval.val != 0.0) if(block_res = eval(&yyval, &yyvsp[0]))return block_res;;
     break;}
 case 12:
-{;;
+{if(block_res = eval(&yyval, &yyvsp[-3])) return block_res; 
+				if(yyval.val != 0.0) {if(block_res = eval(&yyval, &yyvsp[-2])) return block_res;} 
+				else if(block_res = eval(&yyval, &yyvsp[0])) return block_res;;
     break;}
 case 13:
-{yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0])); yyval.type = STR;;
+{for_loop(yyvsp[-1].text, yyvsp[0].text);;
     break;}
 case 14:
-{yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text); yyval.type = STR;;
+{for(int i=0; i< yy_maxiter; i++){ if(block_res = eval(&yyval, &yyvsp[-1]))return block_res; 
+					if(yyval.val != 0.0){if(block_res = eval(&yyval, &yyvsp[0]))return block_res;} else break;};
     break;}
 case 15:
-{yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text); yyval.type = STR;;
+{if(block_res = eval(&yyval, &yyvsp[0]) == 1) return 1; else return 2;;
     break;}
 case 16:
-{((yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L)); yyval.type = STR;;
+{return 3;;
     break;}
 case 17:
-{((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
+{yyerrok;;
     break;}
 case 18:
-{((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
+{;;
     break;}
 case 19:
-{((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
+{yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0])); yyval.type = STR;;
     break;}
 case 20:
-{((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
+{yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text); yyval.type = STR;;
     break;}
 case 21:
-{;;
+{yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text); yyval.type = STR;;
     break;}
 case 22:
-{if(yyval.text = PushString("                                            ")) 
-					sprintf(yyval.text, "%s:%s", yyvsp[-2].tptr->name, yyvsp[0].tptr->name); yyval.type = STR;;
+{if(yyvsp[-3].tptr->fnctptr)((yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L)); yyval.type = STR;;
+    break;}
+case 23:
+{if(yyvsp[-5].tptr->fnctptr)((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
     break;}
 case 24:
-{if(!yyval.a_data) {yyval.a_data = PushArray((double*)malloc(sizeof(double))); yyval.a_count = 1; yyval.a_data[0] = yyval.val;};
+{if(yyvsp[-5].tptr->fnctptr)((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
     break;}
 case 25:
-{push(&yyval, &yyvsp[0]);yyval.type = ARR;;
+{if(yyvsp[-5].tptr->fnctptr)((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
     break;}
 case 26:
-{exec_clause(&yyval);yyval.type = ARR;;
+{if(yyvsp[-5].tptr->fnctptr)((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
     break;}
 case 27:
-{range_array(&yyval, yyvsp[0].text);yyval.type = ARR;;
+{;;
     break;}
 case 28:
-{if(yyvsp[-2].val < yyvsp[0].val && (yyval.a_data = PushArray((double*)malloc((int)(yyvsp[0].val-yyvsp[-2].val+2)*sizeof(double)))))
-					for(yyval.a_count=0; yyvsp[-2].val<=yyvsp[0].val; yyval.a_data[yyval.a_count++] = yyvsp[-2].val, yyvsp[-2].val += 1.0 ); yyval.type = ARR;;
+{;;
+    break;}
+case 29:
+{if(!yyval.a_data) {yyval.a_data = PushArray((double*)malloc(sizeof(double))); yyval.a_count = 1; yyval.a_data[0] = yyval.val;};
     break;}
 case 30:
-{yyval.val = ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)); yyval.type = BOOLVAL;;
+{push(&yyval, &yyvsp[0]);yyval.type = ARR;;
     break;}
 case 31:
-{yyval.val = 1.0; yyval.type = BOOLVAL;;
+{exec_clause(&yyval);yyval.type = ARR;;
     break;}
 case 32:
-{yyval.val = 0.0; yyval.type = BOOLVAL;;
+{range_array(&yyval, yyvsp[0].text);yyval.type = ARR;;
     break;}
 case 33:
-{yyval.val = ((yyvsp[-2].val != 0) && (yyvsp[0].val != 0))? 1 : 0; yyval.type = BOOLVAL;;
-    break;}
-case 34:
-{yyval.val = ((yyvsp[-2].val != 0) || (yyvsp[0].val != 0))? 1 : 0; yyval.type = BOOLVAL;;
+{if(yyvsp[-2].val < yyvsp[0].val && (yyval.a_data = PushArray((double*)malloc((int)(yyvsp[0].val-yyvsp[-2].val+2)*sizeof(double)))))
+					for(yyval.a_count=0; yyvsp[-2].val<=yyvsp[0].val; yyval.a_data[yyval.a_count++] = yyvsp[-2].val, yyvsp[-2].val += 1.0 ); yyval.type = ARR;;
     break;}
 case 35:
-{yyval.val = (yyvsp[-2].val == yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
+{yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)): 0.0; yyval.type = BOOLVAL;;
     break;}
 case 36:
-{yyval.val = (yyvsp[-2].val != yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
+{yyval.val = 1.0; yyval.type = BOOLVAL;;
     break;}
 case 37:
-{yyval.val = (yyvsp[-2].val > yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
+{yyval.val = 0.0; yyval.type = BOOLVAL;;
     break;}
 case 38:
-{yyval.val = (yyvsp[-2].val >= yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
+{yyval.val = ((yyvsp[-2].val != 0) && (yyvsp[0].val != 0))? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 39:
-{yyval.val = (yyvsp[-2].val < yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
+{yyval.val = ((yyvsp[-2].val != 0) || (yyvsp[0].val != 0))? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 40:
-{yyval.val = (yyvsp[-2].val <= yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
+{yyval.val = (yyvsp[-2].val == yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 41:
-{yyval.val = yyvsp[0].val; yyval.type = NUM;;
+{yyval.val = (yyvsp[-2].val != yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 42:
-{yyval.val = yyvsp[0].val; yyval.type = BOOLVAL;;
+{yyval.val = (yyvsp[-2].val > yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 43:
-{yyval.val = 0.0;;
+{yyval.val = (yyvsp[-2].val >= yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 44:
-{yyval.val = syntax_level ? syntax_level->clval : 0.0;  yyval.type = NUM;;
+{yyval.val = (yyvsp[-2].val < yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 45:
-{yyval.val = _PI; yyval.type = NUM;;
-    break;}
-case 46:
-{yyval.val = 2.71828182845905; yyval.type = NUM;;
-    break;}
-case 47:
-{yyvsp[0].tptr->GetValue(&yyval);;
-    break;}
-case 48:
-{eval(&yyvsp[0], &yyval);;
-    break;}
-case 49:
-{yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
+{yyval.val = (yyvsp[-2].val <= yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 50:
-{yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
+{yyval.val = yyvsp[0].val; yyval.type = NUM;;
     break;}
 case 51:
-{yyval.val = ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)); yyval.type = NUM;;
+{yyval.type = ARR;;
     break;}
 case 52:
-{yyval.val = ((yyvsp[-3].tptr->fnctptr)(proc_clause(&yyvsp[-1]))); yyval.type = NUM;;
+{yyval.val = yyvsp[0].val; yyval.type = BOOLVAL;;
     break;}
 case 53:
-{ if(!yyval.a_data){yyval.a_data=PushArray((double*)malloc(sizeof(double)));yyval.a_data[0]=yyvsp[-3].val;yyval.a_count=1;}
-		push(&yyval, &yyvsp[-1]);yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyval)); yyval.type = NUM;;
+{yyval.val = 0.0;;
     break;}
 case 54:
-{ yyval.a_data = PushArray((double*)malloc(3*sizeof(double)));
-		yyval.a_count = 3; yyval.a_data[0] = yyvsp[-5].val; yyval.a_data[1] = yyvsp[-3].val; yyval.a_data[2] = yyvsp[-1].val;	
-		yyval.val = ((yyvsp[-7].tptr->fnctptr)(&yyval)); yyval.type = NUM;;
+{yyval.val = syntax_level ? syntax_level->clval : 0.0;  yyval.type = NUM;;
     break;}
 case 55:
-{yyval.type = NUM; yyval.val = ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L));;
+{yyval.val = _PI; yyval.type = NUM;;
     break;}
 case 56:
-{yyval.type = NUM; yyvsp[-1].text = string_value(&yyvsp[-1]); yyval.val = ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L));;
+{yyval.val = 2.71828182845905; yyval.type = NUM;;
     break;}
 case 57:
-{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
+{if(yyvsp[0].tptr)yyvsp[0].tptr->GetValue(&yyval);;
     break;}
 case 58:
-{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
+{if(block_res = eval(&yyval, &yyvsp[0]))return block_res;;
     break;}
 case 59:
-{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
+{if(yyvsp[-2].tptr)yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
     break;}
 case 60:
-{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
+{if(yyvsp[-2].tptr)yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
     break;}
 case 61:
-{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
+{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val + yyvsp[0].val);};
     break;}
 case 62:
-{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
+{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val - yyvsp[0].val);};
     break;}
 case 63:
-{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
+{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyval.val * yyvsp[0].val);};
     break;}
 case 64:
-{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
+{if(yyvsp[-2].tptr){yyvsp[-2].tptr->GetValue(&yyval); yyvsp[-2].tptr->SetValue(yyvsp[0].val != 0.0 ? yyval.val / yyvsp[0].val :
+		(getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue());};
     break;}
 case 65:
-{range_array2(&yyvsp[-3], &yyvsp[-1]);yyval.val = ((*yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyvsp[-1], 0L)); yyval.type = NUM;;
+{yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)): 0.0; yyval.type = NUM;;
     break;}
 case 66:
-{range_array2(&yyvsp[-5], &yyvsp[-3]); yyval.val = ((*yyvsp[-7].tptr->fnctptr)(&yyvsp[-5], &yyvsp[-3], yyvsp[-1].text)); yyval.type = NUM;;
+{yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(proc_clause(&yyvsp[-1]))) : 0.0; yyval.type = NUM; yyval.a_data = 0L; yyval.a_count = 0; yyval.text = 0L;;
     break;}
 case 67:
-{yyval.val=((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), proc_clause(&yyvsp[-1]), 0L));;
+{ if(!yyval.a_data){yyval.a_data=PushArray((double*)malloc(sizeof(double)));yyval.a_data[0]=yyvsp[-3].val;yyval.a_count=1;}
+		push(&yyval, &yyvsp[-1]);yyval.val = yyvsp[-5].tptr->fnctptr ?((yyvsp[-5].tptr->fnctptr)(&yyval)):0.0; yyval.type = NUM;;
     break;}
 case 68:
-{yyval.val=((*yyvsp[-7].tptr->fnctptr)(proc_clause(&yyvsp[-5]), proc_clause(&yyvsp[-3]), yyvsp[-1].text));;
+{ yyval.a_data = PushArray((double*)malloc(3*sizeof(double)));
+		yyval.a_count = 3; yyval.a_data[0] = yyvsp[-5].val; yyval.a_data[1] = yyvsp[-3].val; yyval.a_data[2] = yyvsp[-1].val;	
+		yyval.val = yyvsp[-7].tptr->fnctptr ? ((yyvsp[-7].tptr->fnctptr)(&yyval)) : 0.0; yyval.type = NUM;;
     break;}
 case 69:
-{proc_clause(&yyvsp[-3]); yyval.val=(*yyvsp[-9].tptr->fnctptr)(yyvsp[-7].val, yyvsp[-5].val, &yyvsp[-3], &yyvsp[-1]); yyval.type = NUM;;
+{yyval.type = NUM; yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L)) : 0.0;;
     break;}
 case 70:
-{yyval.val = ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text));  yyval.type = NUM;;
+{yyval.type = NUM; yyvsp[-1].text = string_value(&yyvsp[-1]); yyval.val = yyvsp[-3].tptr->fnctptr ? ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L)) : 0.0;;
     break;}
 case 71:
-{(*yyvsp[-2].tptr->fnctptr)(&yyval, 0L);;
+{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
     break;}
 case 72:
-{(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1]);;
+{yyval.val = yyvsp[-5].tptr->fnctptr ?((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
     break;}
 case 73:
-{(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
+{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
     break;}
 case 74:
-{(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
+{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
     break;}
 case 75:
-{(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
+{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
     break;}
 case 76:
-{(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
+{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
     break;}
 case 77:
-{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
     break;}
 case 78:
-{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+{yyval.val = yyvsp[-5].tptr->fnctptr ? ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
     break;}
 case 79:
-{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+{range_array2(&yyvsp[-3], &yyvsp[-1]);yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyvsp[-1], 0L)) : 0.0; yyval.type = NUM;;
     break;}
 case 80:
-{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+{range_array2(&yyvsp[-5], &yyvsp[-3]); yyval.val = yyvsp[-7].tptr->fnctptr ? ((*yyvsp[-7].tptr->fnctptr)(&yyvsp[-5], &yyvsp[-3], yyvsp[-1].text)) : 0.0; yyval.type = NUM;;
     break;}
 case 81:
-{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+{yyval.val= yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), proc_clause(&yyvsp[-1]), 0L)) : 0.0;;
     break;}
 case 82:
-{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+{yyval.val=yyvsp[-7].tptr->fnctptr ? ((*yyvsp[-7].tptr->fnctptr)(proc_clause(&yyvsp[-5]), proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;;
     break;}
 case 83:
-{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+{proc_clause(&yyvsp[-3]); yyval.val=yyvsp[-9].tptr->fnctptr ? (*yyvsp[-9].tptr->fnctptr)(yyvsp[-7].val, yyvsp[-5].val, &yyvsp[-3], &yyvsp[-1]) : 0.0; yyval.type = NUM;;
     break;}
 case 84:
-{(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+{yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;;
     break;}
 case 85:
-{if(yyvsp[-2].val != 0.0)eval(&yyval, &yyvsp[0]);;
+{yyval.val = yyvsp[-5].tptr->fnctptr ? ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;;
     break;}
 case 86:
-{yyvsp[-4].val != 0.0 ? eval(&yyval, &yyvsp[-2]) : eval(&yyval, &yyvsp[0]);;
+{if(yyvsp[-2].tptr->fnctptr)(*yyvsp[-2].tptr->fnctptr)(&yyval, 0L);;
     break;}
 case 87:
-{for(int i=0; i< yy_maxiter; i++){
-					eval(&yyval, &yyvsp[-1]); 
-					if(yyval.val != 0.0)eval(&yyval, &yyvsp[0]);
-					else break;};
+{if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1]);;
     break;}
 case 88:
+{if(yyvsp[-5].tptr->fnctptr)(*yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 89:
+{if(yyvsp[-3].tptr->fnctptr)(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L);;
+    break;}
+case 90:
+{if(yyvsp[-7].tptr->fnctptr)(*yyvsp[-7].tptr->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);;
+    break;}
+case 91:
 {yyval.val = yyvsp[-2].val + yyvsp[0].val; yyval.type = NUM;
 				if(yyvsp[0].type == DATE1 || yyvsp[-2].type == DATE1) yyval.type = DATE1;
 				else if(yyvsp[0].type == TIME1 || yyvsp[-2].type == TIME1) yyval.type = TIME1;
 				else if(yyvsp[0].type == DATETIME1 || yyvsp[-2].type == DATETIME1) yyval.type = DATETIME1;;
     break;}
-case 89:
+case 92:
 {yyval.val = yyvsp[-2].val - yyvsp[0].val; yyval.type = NUM;
 				if(yyvsp[0].type == DATE1 || yyvsp[-2].type == DATE1) yyval.type = DATE1;
 				else if(yyvsp[0].type == TIME1 || yyvsp[-2].type == TIME1) yyval.type = TIME1;
 				else if(yyvsp[0].type == DATETIME1 || yyvsp[-2].type == DATETIME1) yyval.type = DATETIME1;;
     break;}
-case 90:
+case 93:
 {yyval.val = yyvsp[-2].val * yyvsp[0].val; yyval.type = NUM;;
     break;}
-case 91:
+case 94:
 {yyval.type = NUM; if(yyvsp[0].val != 0.0) yyval.val = yyvsp[-2].val / yyvsp[0].val;
 					else yyval.val = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue(); ;
     break;}
-case 92:
+case 95:
 {yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val+1.0); yyval.val -= 1.0; yyval.type = NUM;;
     break;}
-case 93:
+case 96:
 {yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val-1.0); yyval.val += 1.0; yyval.type = NUM;;
     break;}
-case 94:
+case 97:
 {yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val+1.0); yyval.type = NUM;;
     break;}
-case 95:
+case 98:
 {yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val-1.0); yyval.type = NUM;;
     break;}
-case 96:
+case 99:
 {yyval.val = (yyvsp[0].val >0 && yyvsp[0].val/2.0 == floor(yyvsp[0].val/2.0)) ? fabs(pow(yyvsp[-2].val,yyvsp[0].val) ): pow(yyvsp[-2].val, yyvsp[0].val); yyval.type = NUM;;
     break;}
-case 97:
+case 100:
 {yyval.val = -yyvsp[0].val; yyval.type = NUM;;
     break;}
-case 98:
+case 101:
 {memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;;
     break;}
-case 99:
+case 102:
 {yyval.a_data = PushArray((double*)calloc((int)yyvsp[-1].val, sizeof(double))); yyval.a_count=(int)(yyvsp[-1].val); 
 					yyval.type = ARR; yyvsp[-3].tptr->SetValue(&yyval,&yyval);;
     break;}
-case 100:
+case 103:
 {if(yyvsp[-3].a_data && yyvsp[-1].val >= 0.0 && yyvsp[-1].val < yyvsp[-3].a_count) yyval.val = yyvsp[-3].a_data[(int)yyvsp[-1].val];
 				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 101:
+case 104:
 {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] = yyvsp[0].val;
 				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 102:
-{make_time(&yyval, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val+1.0e-10);;
+case 105:
+{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
+				yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] += yyvsp[0].val;
+				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 103:
-{make_time(&yyval, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val+1.0e-10);;
+case 106:
+{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
+				yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] -= yyvsp[0].val;
+				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 104:
-{make_time(&yyval, yyvsp[-2].val, yyvsp[0].val, 1.0e-10);;
+case 107:
+{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
+				yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] *= yyvsp[0].val;
+				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
     break;}
-case 105:
+case 108:
+{if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count){ 
+				if(yyvsp[0].val != 0.0) yyval.val = yyvsp[-5].a_data[(int)yyvsp[-3].val] /= yyvsp[0].val;
+				else {yyval.val = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue();}}
+				else {yyval.val = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;;
+    break;}
+case 109:
+{make_time(&yyval, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val+1.0e-10);;
+    break;}
+case 110:
 {make_time(&yyval, yyvsp[-2].val, yyvsp[0].val, 1.0e-10);;
     break;}
-case 106:
+case 111:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
-case 107:
+case 112:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
-case 108:
+case 113:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
-case 109:
+case 114:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
 }
@@ -1845,7 +1841,7 @@ symrec::GetValue(void *re)
 				res->text = 0L;		break;
 			case ET_TEXT:
 				res->type = STR;	res->val = 0.0;
-				if(ares.text) res->text = PushString(text = strdup(ares.text));
+				if(ares.text) res->text = PushString(text = (char*)memdup(ares.text, (int)strlen(ares.text)+1, 0));
 				else res->text = 0L;	break;
 			default:
 				res->type = NUM;	res->val = var;
@@ -1859,15 +1855,19 @@ symrec::GetValue(void *re)
 		}
 	if(!isValid) NoInit();
 	if(a_data && a_count) {
+		if(text && text[0]) res->text = PushString(text);
+		else res->text = 0L;
 		res->a_data = a_data;	res->a_count = a_count;
 		res->val = 0.0;		res->type = ARR;
 		}
 	else if(text && text[0]) {
 		res->text = PushString(text);
-		res->val = var;		res->type = STR;
+		res->a_data = 0L;	res->a_count = 0;
+		res->val = 0.0;		res->type = STR;
 		}
 	else {
 		res->type = NUM;	res->val = var;
+		res->a_data = 0L;	res->a_count = 0;
 		res->text = 0L;
 		}
 }
@@ -1901,7 +1901,13 @@ symrec::SetValue(void* d, void* s)
 		else if(src->type == STR) curr_data->SetText(row, col, src->text);
 		else if(src->type == ARR || (src->a_data)) curr_data->SetText(row, col, "#ARRAY");
 		else if(src->type == VAR && src->tptr->type == TXT) curr_data->SetText(row, col, src->tptr->text);
-		else curr_data->SetValue(row, col, src->val);
+		else {
+			if(curr_data->SetValue(row, col, src->val))
+				switch(src->type) {
+				case BOOLVAL:
+					curr_data->etRows[row][col]->type = ET_BOOL;	break;
+				}
+			}
 		curr_data->Command(CMD_UPDATE, 0L, 0L);
 		}
 	isValid = true;
@@ -2003,7 +2009,7 @@ static void store_res(YYSTYPE *res)
 	if(last_err_desc) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
-		strcpy(res_txt, last_err_desc);
+		rlp_strcpy(res_txt, 1000, last_err_desc);
 		}
 	else if(res->type == NUM){
 		line_res.type = ET_VALUE;
@@ -2028,7 +2034,7 @@ static void store_res(YYSTYPE *res)
  	else if(res->type == STR) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
-		if(res->text) strcpy(res_txt, res->text);
+		if(res->text) rlp_strcpy(res_txt, 1000, res->text);
 		}
 	else if((res->type == ARR || (res->a_data)) && res->a_count == 1) {
 		line_res.type = ET_VALUE;
@@ -2041,12 +2047,14 @@ static void store_res(YYSTYPE *res)
 	else if(res->type == ARR || (res->a_data)) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
-		strcpy(res_txt, "#ARRAY");
+		line_res.a_data = res->a_data;
+		line_res.a_count = res->a_count;
+		rlp_strcpy(res_txt, 1000, "#ARRAY");
 		}
 	else if(res->tptr && res->tptr->type == TXT) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
-		if(res->tptr->text) strcpy(res_txt, res->tptr->text);
+		if(res->tptr->text) rlp_strcpy(res_txt, 1000, res->tptr->text);
 		}
 	else {
 		line_res.type = ET_VALUE;
@@ -2088,7 +2096,11 @@ static char *string_value(YYSTYPE *exp)
 		st1 = exp->tptr->text;
 		}
 	else {
+#ifdef USE_WIN_SECURE
+		sprintf_s(tmp, 50, "%g", exp->val);
+#else
 		sprintf(tmp,"%g", exp->val);
+#endif
 		st1 = tmp;
 		}
 	return PushString(st1);
@@ -2115,51 +2127,53 @@ static void pop_syntax()
 		}
 }
 
-static void eval(YYSTYPE *dst, YYSTYPE *sr) 
+static int eval(YYSTYPE *dst, YYSTYPE *sr) 
 {
 	char *s_buffer;
-	int s_buff_pos, s_yychar, s_yynerrs, length;
+	int s_buff_pos, s_yychar, s_yynerrs, length, parse_res;
 	anyResult *ar;
 
-	if(!sr || !sr->text) return;
-	parse_level++;
+	if(!sr || !sr->text || !sr->text[0]) return 1;
 	s_buffer = buffer;		s_buff_pos = buff_pos;
-	s_yychar = yychar;	s_yynerrs = yynerrs;
-	if (sr->text && (length=(int)strlen(sr->text)) && (buffer = (char*)malloc(length+2))) {
-		strcpy(buffer, sr->text);		buffer[length++] = ';';
-		buffer[length] = 0;		buff_pos = 0;
-		do {
-			yyparse();
-			}while(buff_pos < length);
-		free(buffer);		ar = &line_res;
+	s_yychar = yychar;		s_yynerrs = yynerrs;
+	if(!(length = (int)strlen(sr->text)))return 1;
+	parse_level++;
+	if(sr->text[length-1] == ';') buffer = sr->text;
+	else {
+		buffer = (char*)malloc(length+2);
+		rlp_strcpy(buffer, length+1, sr->text);
+		buffer[length++] = ';';		buffer[length] = 0;
+		}
+	if(buffer && buffer[0]){
+		buff_pos = 0;
+		while(!(parse_res = yyparse()) && buff_pos < length);
+		if(buffer != sr->text) free(buffer);
+		ar = &line_res;
 		buffer = s_buffer;		buff_pos = s_buff_pos;
-		yychar = s_yychar;	yynerrs = s_yynerrs;
+		yychar = s_yychar;		yynerrs = s_yynerrs;
 		}
-	else return;
-	yylval.a_data = 0L;	yylval.a_count = 0;
+	else return 1;
+	dst->a_data = ar->a_data;	dst->a_count = ar->a_count;
+	if(parse_res == 2) return 2;
+	else if(parse_res == 3 && sr->type == IBLOCK) return 3;
+	else if(parse_res == 1) return 1;
 	switch(ar->type) {
 	case ET_BOOL:
-		dst->type = BOOLVAL;
-		dst->val = ar->value;
-		dst->text = 0L;
-		break;
+		dst->type = BOOLVAL;	dst->val = ar->value;
+		dst->text = 0L;		break;
 	case ET_VALUE:
-		dst->type = NUM;
-		dst->val = ar->value;
-		dst->text = 0L;
-		break;
+		dst->type = NUM;	dst->val = ar->value;
+		dst->text = 0L;		break;
 	case ET_TEXT:
-		dst->type = STR;
-		dst->val = 0.0;
+		dst->type = STR;	dst->val = 0.0;
 		dst->text = PushString(ar->text);
 		break;
 	default:
-		dst->type = NUM;
-		dst->val = 0.0;
-		dst->text = 0L;
-		break;
+		dst->type = NUM;	dst->val = 0.0;
+		dst->text = 0L;		break;
 		}
 	parse_level--;
+	return 0;
 }
 
 // more functions
@@ -2532,7 +2546,7 @@ static double lognorminv(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3) {
-		sr->val = distinv(lognorm_dist, sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
+		sr->val = distinv(lognorm_dist, sr->a_data[1], sr->a_data[2], sr->a_data[0], exp(sr->a_data[1]));
 		}
 	else yyargserr("Wrong number of arguments\nin call to  lognorminv(p, mean, SD).");
 	return sr->val;
@@ -2662,12 +2676,23 @@ static double finv(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double ksdist(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = ks_dist((int)sr->a_data[0], sr->a_data[1]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  ksdist(n, D).");
+	return sr->val;
+}
+
 static double pearson(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 {
 	if(!sr1 || !sr2) return 0.0;
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_pearson(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		sr1->val = sr2->val = d_pearson(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
 		}
 	else yyargserr("Bad arguments in call to function\npearson(range1; range2 [;\"dest\"]).");
 	return sr1->val;
@@ -2678,7 +2703,7 @@ static double spearman(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	if(!sr1 || !sr2) return 0.0;
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_spearman(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		sr1->val = sr2->val = d_spearman(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
 		}
 	else yyargserr("Bad arguments in call to function\nspearman(range1; range2 [;\"dest\"]).");
 	return sr1->val;
@@ -2689,7 +2714,7 @@ static double kendall(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	if(!sr1 || !sr2) return 0.0;
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_kendall(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		sr1->val = sr2->val = d_kendall(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
 		}
 	else yyargserr("Bad arguments in call to function\nkendall(range1; range2 [;\"dest\"]).");
 	return sr1->val;
@@ -2762,6 +2787,34 @@ static double ftest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	return sr1->val;
 }
 
+static double p_tukey(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0;
+	if(sr->a_data && sr->a_count == 4){
+		sr->val = ptukey(sr->a_data[0], sr->a_data[3], sr->a_data[1], sr->a_data[2], 1, 0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = ptukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0);
+		}
+	else yyargserr("Wrong number of arguments\nin call to ptukey(q, nm, df[, nr = 1]).");
+	return sr->val;
+}
+
+static double q_tukey(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0;
+	if(sr->a_data && sr->a_count == 4){
+		sr->val = qtukey(sr->a_data[0], sr->a_data[3], sr->a_data[1], sr->a_data[2], 1, 0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = qtukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0);
+		}
+	else yyargserr("Wrong number of arguments\nin call to qtukey(p, nm, df[, nr = 1]).");
+	return sr->val;
+}
+
 static double fill(YYSTYPE *sr, char *dest)
 {
 	AccRange *ar;
@@ -2905,10 +2958,11 @@ static void ftime(YYSTYPE *dst, YYSTYPE *src)
 	dst->type = TIME1;		dst->val = src->val;
 }
 
-static void asort(YYSTYPE *dst, YYSTYPE *src)
+static void invert(YYSTYPE *dst, YYSTYPE *src)
 {
+	int i;
+
 	if(!dst || !src) return;
-	dst->type = ARR;
 	switch(src->a_count) {
 	case 0:
 		dst->a_data = PushArray((double*)malloc(sizeof(double)));
@@ -2921,46 +2975,70 @@ static void asort(YYSTYPE *dst, YYSTYPE *src)
 	default:
 		dst->a_data = PushArray((double*)memdup(src->a_data, src->a_count * sizeof(double), 0));
 		dst->a_count = src->a_count;
-		SortArray(dst->a_count, dst->a_data);
+		for(i = 0; i < src->a_count; i++) dst->a_data[i] = src->a_data[src->a_count-1-i];
 		}
 }
 
-static void _crank(YYSTYPE *dst, YYSTYPE *src)
+static void asort(YYSTYPE *dst, YYSTYPE *src)
 {
-	double tmp;
-
 	if(!dst || !src) return;
 	dst->type = ARR;
 	switch(src->a_count) {
-	case 0:	case 1:
+	case 0:
 		dst->a_data = PushArray((double*)malloc(sizeof(double)));
-		dst->a_count = 1;	dst->a_data[0] = dst->val = 1;
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->val;
+		break;
+	case 1:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->a_data[0];
 		break;
 	default:
 		dst->a_data = PushArray((double*)memdup(src->a_data, src->a_count * sizeof(double), 0));
 		dst->a_count = src->a_count;
-		crank(dst->a_count, dst->a_data, &tmp);
+		SortArray(dst->a_count, dst->a_data);
 		}
 }
 
+static void asort2(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char *fmt)
+{
+	int n;
+
+	res->val = 0.0;		res->type = NUM;
+	if(!sr1 || !sr2 || !sr1->a_data || !sr2->a_data) return;
+	n = sr1->a_count > sr2->a_count ? sr2->a_count : sr1->a_count;
+	res->val = (double)n;
+	if(n >1) SortArray2(n, sr1->a_data, sr2->a_data);
+	return;
+}
+
+static double _crank(YYSTYPE *src)
+{
+	double tmp = -1.0;
+
+	if(!src) return tmp;
+	tmp = 0.0;
+	if(src->a_data && src->a_count > 1.0)crank(src->a_count, src->a_data, &tmp);
+	return tmp;
+}
+
 static void ltrim(YYSTYPE *dst, YYSTYPE *src)
 {
 	if(!src || !dst || !src->text) return;
-	dst->text = PushString(str_ltrim(strdup(src->text)));
+	dst->text = PushString(str_ltrim(src->text));
 	dst->type = STR;	dst->val = 0.0;
 }
 
 static void rtrim(YYSTYPE *dst, YYSTYPE *src)
 {
 	if(!src || !dst || !src->text) return;
-	dst->text = PushString(str_rtrim(strdup(src->text)));
+	dst->text = PushString(str_rtrim(src->text));
 	dst->type = STR;	dst->val = 0.0;
 }
 
 static void trim(YYSTYPE *dst, YYSTYPE *src)
 {
 	if(!src || !dst || !src->text) return;
-	dst->text = PushString(str_trim(strdup(src->text)));
+	dst->text = PushString(str_trim(src->text));
 	dst->type = STR;	dst->val = 0.0;
 }
 
@@ -3063,6 +3141,59 @@ static void uc_word(YYSTYPE *dst, YYSTYPE *src)
 	else dst->text = 0L;
 }
 
+static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
+{
+	char *cmd = 0L;
+	int cmd_pos = 0, cmd_size, r, c;
+	AccRange *ar = 0L;
+	anyResult res, *eres;
+
+	if(!src1 || !src1->text || !src1->text[0]) return;
+	if((cmd =(char*)malloc((cmd_size = 1000) * sizeof(char))) && (ar = new AccRange(src1->text))) {
+		if(src2 && src2->text[0] && src2->text[0]) {
+			add_to_buff(&cmd, &cmd_pos, &cmd_size, src2->text, 0);
+			while(cmd_pos && cmd[cmd_pos-1] < 33) cmd_pos--;
+			if(cmd_pos && cmd[cmd_pos-1] != ';') cmd[cmd_pos++] = ';';
+			}
+		cmd[cmd_pos] = 0;
+		ar->GetFirst(&c, &r);	ar->GetNext(&c, &r);
+		do {
+			curr_data->GetResult(&res, r, c, false);
+			switch(res.type) {
+			case ET_VALUE:				//numerical value
+				if(res.value == -HUGE_VAL)
+					add_to_buff(&cmd, &cmd_pos, &cmd_size, "-inf", 4);
+				else if(res.value == HUGE_VAL)
+					add_to_buff(&cmd, &cmd_pos, &cmd_size, "inf", 3);
+				else add_dbl_to_buff(&cmd, &cmd_pos, &cmd_size, res.value, false);
+				break;
+			case ET_TEXT:					//text cell
+				if(res.text && res.text[0]) {
+					if(res.text[0] == res.text[1] && res.text[0] == '/') ar->NextRow(&r);
+					else add_to_buff(&cmd, &cmd_pos, &cmd_size, res.text, 0);
+					}
+				break;
+				}
+			}while(ar->GetNext(&c, &r));
+		eres = do_formula(curr_data, cmd);
+		switch(eres->type) {
+		case ET_BOOL:
+			dst->type = BOOLVAL;	dst->val = eres->value;
+			dst->text = 0L;				break;
+		case ET_VALUE:
+			dst->type = NUM;	dst->val = eres->value;
+			dst->text = 0L;				break;
+		case ET_TEXT:
+			dst->type = STR;	dst->val = 0.0;
+			dst->text = PushString(eres->text);	break;
+		default:
+			dst->type = NUM;	dst->val = 0.0;
+			dst->text = 0L;		break;
+			}
+		}
+	if(cmd) free(cmd);	if(ar) delete ar;
+}
+
 // Store strings in a list
 static char **str_list = 0L;
 static int n_str = 0;
@@ -3071,7 +3202,7 @@ static char *PushString(char *text)
 {
 	if(text && text[0]) {
 		if(str_list = (char**)realloc(str_list, sizeof(char*)*(n_str+1)))
-			str_list[n_str] = strdup(text);
+			str_list[n_str] = (char*)memdup(text, (int)strlen(text)+1, 0);
 		return str_list[n_str++];
 		}
 	return 0L;
@@ -3084,9 +3215,10 @@ static int n_arr = 0;
 static double *PushArray(double *arr)
 {
 	if(arr) {
-		if(arr_list = (double**)realloc(arr_list, sizeof(double*)*(n_arr+1)))
+		if(arr_list = (double**)realloc(arr_list, sizeof(double*)*(n_arr+1))){
 			arr_list[n_arr] = arr;
-		return arr_list[n_arr++];
+			return arr_list[n_arr++];
+			}
 		}
 	return 0L;
 }
@@ -3153,6 +3285,7 @@ void InitArithFuncs(DataObj *d)
 		double (*fnct)(double);
 		};
 	fdef fncts[] = {
+	INIT_SYM(AFNCT, "ptukey", p_tukey),		INIT_SYM(AFNCT, "qtukey", q_tukey),
 	INIT_SYM(YYFNC, "toupper", to_upper),		INIT_SYM(YYFNC, "tolower", to_lower),
 	INIT_SYM(YYFNC, "ucfirst", uc_first),		INIT_SYM(YYFNC, "ucword", uc_word),
 	INIT_SYM(SFNCT, "asc", asc),			INIT_SYM(YYFNC, "chr", chr),
@@ -3160,7 +3293,7 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(YYFNC2, "strpos",_strpos),		INIT_SYM(FUNC4, "classes", classes),
 	INIT_SYM(AFNCT, "rank", rank),			INIT_SYM(YYFNC, "ltrim", ltrim),
 	INIT_SYM(YYFNC, "rtrim", rtrim),		INIT_SYM(YYFNC, "trim", trim),
-	INIT_SYM(YYFNC, "asort", asort),		INIT_SYM(YYFNC, "crank", _crank),
+	INIT_SYM(YYFNC, "asort", asort),		INIT_SYM(AFNCT, "crank", _crank),
 	INIT_SYM(SRFUNC, "datestr", datestr),		INIT_SYM(SFNCT, "dateval", dateval),
 	INIT_SYM(BFNCT, "leapyear", leapyear),		INIT_SYM(YYFNC, "today", today),
 	INIT_SYM(YYFNC, "now", now),			INIT_SYM(FNCT, "year", year),
@@ -3172,7 +3305,7 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(FUNC1, "fill", fill),			INIT_SYM(FUNC2, "pearson", pearson),
 	INIT_SYM(FUNC2, "spearman", spearman),		INIT_SYM(FUNC2, "kendall", kendall),		
 	INIT_SYM(FUNC2, "correl", pearson),		INIT_SYM(FUNC2, "regression", regression),
-	INIT_SYM(FUNC2, "covar", covar),
+	INIT_SYM(FUNC2, "covar", covar),		INIT_SYM(YYFNC2, "exec", exec),
 	INIT_SYM(FUNC3, "utest", utest),		INIT_SYM(FUNC2, "ttest2", ttest2),
 	INIT_SYM(FUNC3, "ttest", ttest),		INIT_SYM(FUNC3, "ftest", ftest),
 	INIT_SYM(AFNCT, "variance", variance),		INIT_SYM(AFNCT, "stdev", stdev),
@@ -3183,24 +3316,21 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(AFNCT, "median", quartile2),		INIT_SYM(AFNCT, "quartile1", quartile1),
 	INIT_SYM(AFNCT, "quartile2",quartile2),		INIT_SYM(AFNCT, "quartile3", quartile3),
 	INIT_SYM(AFNCT, "gmean", gmean),		INIT_SYM(AFNCT, "hmean", hmean),
-	INIT_SYM(AFNCT, "tdist", tdist),		
-	INIT_SYM(AFNCT, "tfreq", tfreq),
-	INIT_SYM(AFNCT, "tinv", tinv),
+	INIT_SYM(AFNCT, "tdist", tdist),		INIT_SYM(AFNCT, "tfreq", tfreq),
+	INIT_SYM(AFNCT, "tinv", tinv),			INIT_SYM(YYFNC, "invert", invert),
 	INIT_SYM(AFNCT, "poisdist", poisdist),		INIT_SYM(AFNCT, "poisfreq", poisfreq),		
 	INIT_SYM(AFNCT, "expdist", expdist),		INIT_SYM(AFNCT, "expfreq", expfreq),		
-	INIT_SYM(AFNCT, "expinv", expinv),		
-	INIT_SYM(AFNCT, "fdist", fdist),
-	INIT_SYM(AFNCT, "ffreq", ffreq),
+	INIT_SYM(AFNCT, "expinv", expinv),		INIT_SYM(AFNCT, "fdist", fdist),
+	INIT_SYM(AFNCT, "ffreq", ffreq),		INIT_SYM(AFNCT, "ksdist", ksdist),
 	INIT_SYM(AFNCT, "finv", finv),			INIT_SYM(AFNCT, "gammp", _gammp),
 	INIT_SYM(AFNCT, "gammq", _gammq),		INIT_SYM(AFNCT, "beta", beta),
 	INIT_SYM(AFNCT, "betai", _betai),		INIT_SYM(AFNCT, "bincof", _bincof),
-	INIT_SYM(AFNCT, "binomdist",binomdist),
-	INIT_SYM(AFNCT, "binomfreq",binomfreq),
+	INIT_SYM(AFNCT, "binomdist",binomdist),		INIT_SYM(AFNCT, "binomfreq",binomfreq),
 	INIT_SYM(AFNCT, "normdist", normdist),
 	INIT_SYM(AFNCT, "norminv", norminv),		INIT_SYM(AFNCT, "normfreq", normfreq),
 	INIT_SYM(AFNCT, "lognormdist", lognormdist),	INIT_SYM(AFNCT, "lognormfreq", lognormfreq),
 	INIT_SYM(AFNCT, "lognorminv",lognorminv),	INIT_SYM(AFNCT, "chidist", chidist),
-	INIT_SYM(AFNCT, "chifreq", chifreq),
+	INIT_SYM(AFNCT, "chifreq", chifreq),		INIT_SYM(YYFNC2, "asort2", asort2),
 	INIT_SYM(AFNCT, "chiinv", chiinv),		INIT_SYM(SFNCT, "strlen", _strlen),
 	INIT_SYM(YYFNC, "eval", eval),			INIT_SYM(FNCT, "erf", errf),
 	INIT_SYM(FNCT, "erfc", errfc),			INIT_SYM(FNCT, "sign", sign),
@@ -3403,7 +3533,7 @@ static YYSTYPE *proc_clause(YYSTYPE *res)
 		if(!syntax_level) break;
 		syntax_level->clval = res->a_data[i];
 		yyparse();
-		if(line_res.type == ET_VALUE && line_res.value != 0.0) n_data[n++] = res->a_data[i];
+		if((line_res.type == ET_VALUE || line_res.type == ET_BOOL) && line_res.value != 0.0) n_data[n++] = res->a_data[i];
 		}
 	res->a_data = n_data;		res->a_count = n;
 	res->text=0L;
@@ -3515,16 +3645,28 @@ static int is_ttoken(unsigned int h_nam, unsigned int h2_nam)
 		if(h2_nam == 5220) return CLVAL;
 		break;
 	case 362:
-		if(h2_nam == 42878) return IF;
+		if(h2_nam == 42878) return (syntax_level->last_tok = IF);
 		break;
 	case 28421:
 		if(h2_nam == 82147317) return (syntax_level->last_tok = WHILE);
 		break;
+	case 1518:
+		if(h2_nam == 20654586) return (syntax_level->last_tok = FOR);
+		break;
+	case 370:
+		if(h2_nam == 46206) return INARR;
+		break;
 	case 1457:
 		if(h2_nam == 18357885) return DIM;
 		break;
+	case 108774:
+		if(h2_nam == 0x27d5d1fe) return (syntax_level->last_tok = RETURN);
+		break;
+	case 23583:
+		if(h2_nam == 0x954f67ff) return BREAK;
+		break;
 	case 6033:
-		if((h2_nam & 0x7fffffff) == 0x6371377d) return ELSE;
+		if((h2_nam & 0x7fffffff) == 0x6371377d) return (syntax_level->last_tok = ELSE);
 		break;
 	case 7097:
 		if((h2_nam & 0x7fffffff) == 0x550a2d65) return BTRUE;
@@ -3547,6 +3689,8 @@ static char *copy_block()
 		first[0] = '{';		last[0] = '}';	break;
 	case '(':
 		first[0] = '(';		last[0] = ')';	break;
+	default:
+		first[0] = '\0';	last[0] = ';';	break;
 		}
 	if(!(res = (char*)malloc(strlen(src)+2))) return 0L;
 	for(i = 1, level = mode = j = 0; src[i]; i++) {
@@ -3561,7 +3705,7 @@ static char *copy_block()
  			if(src[i] == last[level]) {
 				if(level) level--;
 				else {
-					res[j-1] = 0;	buff_pos += j;
+					res[j-1] = ';';	res[j] = 0;	buff_pos += j;
 					return res;
 					}
 				}
@@ -3577,25 +3721,103 @@ static char *copy_block()
 				}
 			}
 		}
+	res[j] = ';';	res[j+1] = 0;		buff_pos += j;
 	return res;
 }
 
 static symrec *curr_sym;
-static int yylex (void)
+static double for_loop(char *block1, char *block2)
+{
+	char *last_buffer, *bb1, *bb2, *bb3;
+	int i, a_count, last_buff_pos, cb1;
+	double *a_data;
+	YYSTYPE yyres, yysrc;
+	symrec *var;
+
+	if(!block1 || !block1[0]) return 0.0;
+	bb1 = bb2 = bb3 = 0L;		parse_level++;
+	cb1 = (int)strlen(block1);
+	last_buffer = buffer;		last_buff_pos = buff_pos;
+	buffer = block1;		buff_pos = 0;
+	//test for syntax 1
+	bb1 = copy_block();
+	if(buff_pos < cb1) bb2 = copy_block();
+	if(buff_pos < cb1) bb3 = copy_block();
+	if(bb1 && bb2 && bb3) {		//syntax 1 found !
+		yysrc.text = bb1;	if(bb1[0]) eval(&yyres, &yysrc);
+		for(i = 0; i < yy_maxiter; i++) {
+			yysrc.text = bb2;
+			if(bb2[0]) {
+				eval(&yyres, &yysrc);
+				if(yyres.type != NUM && yyres.type != BOOLVAL) yyres.val = 0.0;
+				}
+			else yyres.val = 1.0;
+			if(yyres.val != 0.0) {
+				if(block2 && block2[0]) {
+					yysrc.text = block2;
+					eval(&yyres, &yysrc);
+					}
+				yysrc.text = bb3;
+				eval(&yyres, &yysrc);
+				}
+			else break;		
+			}
+		if(i) last_error = 0L;
+		}
+	//test for syntax 2
+	else if(!bb2) {
+		buff_pos = 0;
+		if (VAR == yylex() && (var = curr_sym) && INARR == yylex() && buffer[buff_pos]){
+			yysrc.text = buffer + buff_pos;
+			eval(&yyres, &yysrc);
+			a_count = yyres.a_count;
+			a_data = yyres.a_data;
+			for(i = 0; i < a_count && i < yy_maxiter; i++) {
+				var->SetValue(a_data[i]);
+				if(block2 && block2[0]) {
+					yysrc.text = block2;
+					eval(&yyres, &yysrc);
+					}
+				}
+			last_error = 0;
+			}
+		else yyerror("parse error");
+		}
+	else yyerror("parse error");
+	if(bb1) free(bb1);	if(bb2) free(bb2);	if(bb3) free(bb3);
+	buffer = last_buffer;		buff_pos = last_buff_pos;
+	parse_level--;
+	return 0.0;
+}
+
+static int yylex()
 {
 	int i, c, tok;
 	unsigned int h_nam, h2_nam;
 	char tmp_txt[80], *block;
 	symrec *s;
 
+	memset(&yylval, 0, sizeof(YYSTYPE));
 	while((c = buffer[buff_pos++]) == ' ' || c == '\t');	//get first nonwhite char
 	if(!c) return 0;
+	//test for implicit block statement
+	if(syntax_level && (syntax_level->last_tok == PBLOCK 
+		|| syntax_level->last_tok == ELSE || syntax_level->last_tok == RETURN) && c != '{'){
+		buff_pos--;
+		if(block = copy_block()) {
+			yylval.text = PushString(block);
+			free(block);
+			}
+		syntax_level->last_tok = 0;
+		return yylval.type = IBLOCK;
+		}
 	//test for block statement
 	if(c == '{') {
 		if(block = copy_block()) {
 			yylval.text = PushString(block);
 			free(block);
 			}
+		syntax_level->last_tok = 0;
 		return yylval.type = BLOCK;
 		}
 	//test for '..' operator
@@ -3617,14 +3839,30 @@ static int yylex (void)
 				}
 			}
 		tmp_txt[i] = 0;
+#ifdef USE_WIN_SECURE
+		sscanf_s(tmp_txt, "%lf", &yylval.val);
+#else
 		sscanf(tmp_txt, "%lf", &yylval.val);
+#endif
 		return yylval.type = NUM;
 		}
 	//test for name or stringtoken
-	if(c > 31 && (isalpha(c) || c=='$')) {
- 		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$')); buff_pos++) {
+	if(c > 31 && (isalpha(c) || c=='$' || c =='_')) {
+ 		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$' || c == '_')); buff_pos++) {
 			tmp_txt[i++] = (char)c; 
 			}
+		while(buffer[buff_pos] == ' ' || buffer[buff_pos] == '\t') buff_pos++;
+		if(buffer[buff_pos] == ':' && !(syntax_level && syntax_level->last_tok == '?')){
+			tmp_txt[i++] = buffer[buff_pos++];
+			for(; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$')); buff_pos++) {
+				tmp_txt[i++] = (char)c; 
+				}
+			tmp_txt[i] = 0;
+			yylval.text = PushString(tmp_txt);
+			range_array(&yylval, yylval.text);
+			yylval.val = 0.0;
+			return yylval.type = RANGEARR;
+			}
 		tmp_txt[i] = 0;
 		h_nam = HashValue((unsigned char*)tmp_txt);
 		h2_nam = Hash2((unsigned char*)tmp_txt);
@@ -3636,8 +3874,7 @@ static int yylex (void)
 		if(!(s = getsym(h_nam, h2_nam, tmp_txt))){
 			s = putsym(h_nam, h2_nam, VAR);
 			s->SetName(tmp_txt);
-			}
-		
+			}	
 		curr_sym = yylval.tptr = s;	return s->type;
 		}
 	//test for string
@@ -3683,33 +3920,45 @@ static int yylex (void)
 		pop_syntax();
 		break;
 	case '(':
-		if(syntax_level->last_tok == WHILE){
+		if(syntax_level->last_tok == WHILE || syntax_level->last_tok == FOR
+			|| syntax_level->last_tok == IF){
 			if(block = copy_block()) {
 				yylval.text = PushString(block);
 				free(block);
 				}
-			return yylval.type = PBLOCK;
+			return yylval.type = syntax_level->last_tok = PBLOCK;
 			}
 		push_syntax();
+		if(syntax_level) syntax_level->last_tok = c;
+		break;
 	case '?':
 		if(syntax_level) syntax_level->last_tok = c;
 		break;
 	case ':':
 		if(syntax_level) {
-			if(syntax_level->last_tok == '(') return COLR;
-			else if(syntax_level->last_tok == '?') return COLC;
+			if(syntax_level->last_tok == '?') return COLC;
 			}
 		break;
 	case ';':
+		if(buff_pos <2)return yylex();
 		if(syntax_level) {
 			if(syntax_level->last_tok == '(') return PSEP;
+			else syntax_level->last_tok = 0;
 			}
 		break;
+	case '*':
+		if(buffer[buff_pos] == '=') tok = MULEQ;
+		break;
+	case '/':
+		if(buffer[buff_pos] == '=') tok = DIVEQ;
+		break;
 	case '+':
 		if(buffer[buff_pos] == '+') tok = INC;
+		else if(buffer[buff_pos] == '=') tok = ADDEQ;
 		break;
 	case '-':
 		if(buffer[buff_pos] == '-') tok = DEC;
+		else if(buffer[buff_pos] == '=') tok = SUBEQ;
 		break;
 		}
 	if(tok) {
@@ -3733,7 +3982,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	symrec *sx, *sy;
 	lfPOINT *new_points;
 	long npoints = 0;
-	int length, res_mode = 0;
+	int length, parse_res, res_mode = 0;
 
 	if(x1 < x2) step = fabs(step);
 	else step = -fabs(step);
@@ -3748,11 +3997,10 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 			pop_parser();
 			return false;
 			}
-		strcpy(buffer, param);	buffer[length++] = ';';
+		rlp_strcpy(buffer, length+1, param);
+		buffer[length++] = ';';
 		buffer[length] = 0;	buff_pos = 0;
-		do {
-			yyparse();
-			}while(buff_pos < length);
+		while(!(parse_res = yyparse()) && buff_pos < length);
 		free(buffer);		buffer = 0L;
 		}		
 	length = (int)strlen(expr);
@@ -3760,9 +4008,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	for(x = x1; step > 0.0 ? x <= x2 : x >= x2; x += step) {
 		if(sx){
 			sx->SetValue(x);	buff_pos = 0;
-			do {
-				yyparse();
-				}while(buff_pos < length);
+			while(!(parse_res = yyparse()) && buff_pos < length);
 			switch (res_mode) {
 			case 1:
 				y = sy->GetValue();	break;
@@ -3784,9 +4030,9 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	*pts = new_points;	*npts = npoints;
 	clear_table();
 	pop_parser();
-	if(curr_data) {
-		curr_data->Command(CMD_CLEAR_ERROR, 0L, 0L);
-		curr_data->Command(CMD_REDRAW, 0L, 0L);
+	if(d) {
+		d->Command(CMD_CLEAR_ERROR, 0L, 0L);
+		d->Command(CMD_REDRAW, 0L, 0L);
 		}
 	return true;
 }
@@ -3794,7 +4040,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double z2, double zstep, 
 	char *expr, char *param)
 {
-	int length, nr, nc, r, c, res_mode=0;
+	int length, parse_res, nr, nc, r, c, res_mode=0;
 	symrec *sx, *sz, *sy;
 	double x, y, z;
 
@@ -3807,11 +4053,10 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 			pop_parser();
 			return false;
 			}
-		strcpy(buffer, param);	buffer[length++] = ';';
+		rlp_strcpy(buffer, length+1, param);
+		buffer[length++] = ';';
 		buffer[length] = 0;	buff_pos = 0;
-		do {
-			yyparse();
-			}while(buff_pos < length);
+		while(!(parse_res = yyparse()) && buff_pos < length);
 		free(buffer);		buffer = 0L;
 		}		
 	length = (int)strlen(expr);		buffer = expr;
@@ -3821,9 +4066,7 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 	for(r = 0, x = x1; r < nr; r++, x += xstep) {
 		for(c = 0, z = z1; c < nc; c++, z+= zstep) {
 			sx->SetValue(x);	sz->SetValue(z);	buff_pos = 0;
-			do {
-				yyparse();
-				}while(buff_pos < length);
+			while(!(parse_res = yyparse()) && buff_pos < length);
 			switch (res_mode) {
 			case 1:
 				y = sy->GetValue();	break;
@@ -3848,13 +4091,15 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 
 anyResult *do_formula(DataObj *d, char *expr)
 {
-	int length;
+	int length, parse_res;
 	static anyResult ret, *pret = 0L;
 
 	if(d) curr_data = d;
 	ret.type = ET_ERROR;		ret.text = 0L;
+	ret.a_data = 0L;		ret.a_count = 0;
 	if(!expr || !expr[0]) {
 		if(!sym_table) InitArithFuncs(0L);
+		last_error = 0L;
 		return &ret;
 		}
 	push_parser();		//make code reentrant
@@ -3863,14 +4108,13 @@ anyResult *do_formula(DataObj *d, char *expr)
 		pop_parser();
 		return &ret;
 		}
-	strcpy(buffer, expr);	if(buffer[length-1] != ';') buffer[length++] = ';';
+	rlp_strcpy(buffer, length+1, expr);
+	if(buffer[length-1] != ';') buffer[length++] = ';';
 	buffer[length] = 0;	buff_pos = 0;
-	do {
-		yyparse();
-		}while(buff_pos < length);
+	while(!(parse_res= yyparse()) && buff_pos < length);
 	ret.type = ET_ERROR;		ret.text = 0L;
-	if(curr_data && last_error) {
-		if(!(strcmp(last_error, "parse error"))) curr_data->Command(CMD_ERROR, 0L, 0L);
+	if(parse_res == 1 && curr_data) {
+		if(last_error && (!(strcmp(last_error, "parse error")))) curr_data->Command(CMD_ERROR, 0L, 0L);
 		if(last_err_desc) pret = &line_res;
 		else pret = &ret;
 		}
@@ -3882,7 +4126,7 @@ anyResult *do_formula(DataObj *d, char *expr)
 	return pret;
 }
 
-bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
+bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int r0, int c0)
 {
 	int length, length2, tok, pos, i;
 	char *res, desc1[2], desc2[2];
@@ -3895,7 +4139,7 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 		pop_parser();
 		return false;
 		}
-	strcpy(buffer, of);	buffer[length++] = ';';
+	rlp_strcpy(buffer, length+1, of);	buffer[length++] = ';';
 	buffer[length] = 0;	buff_pos = pos = 0;
 	if(!(res = (char *)calloc(length2 = (length*2+10), sizeof(char))))return false;
 	length2--;
@@ -3918,7 +4162,7 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 			case YYFNC2:	case YYFNC3:
 				pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
 				break;
-			case COLR:			case COLC:
+			case COLC:
 				res[pos++] = ':';
 				break;
 			case PSEP:
@@ -3950,7 +4194,9 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 				else pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
 				break;
 			case STR:
-				pos += sprintf(res+pos, "\"%s\"", yylval.text && yylval.text[0] ? yylval.text : "");
+				pos += rlp_strcpy(res+pos, length2-pos, "\"");
+				pos += rlp_strcpy(res+pos, length2-pos, yylval.text);
+				pos += rlp_strcpy(res+pos, length2-pos, "\"");
 				break;
 			case SER:
 				res[pos++] = '.';	res[pos++] = '.';
@@ -4000,31 +4246,67 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 			case IF: 
 				res[pos++] = 'i';	res[pos++] = 'f';
 				break;
+			case ADDEQ: 
+				res[pos++] = '+';	res[pos++] = '=';
+				break;
+			case SUBEQ: 
+				res[pos++] = '-';	res[pos++] = '=';
+				break;
+			case MULEQ: 
+				res[pos++] = '*';	res[pos++] = '=';
+				break;
+			case DIVEQ: 
+				res[pos++] = '/';	res[pos++] = '=';
+				break;
 			case WHILE: 
 				pos += rlp_strcpy(res+pos, length2-pos, "while");
 				break;
+			case FOR: 
+				pos += rlp_strcpy(res+pos, length2-pos, "for");
+				break;
+			case INARR: 
+				pos += rlp_strcpy(res+pos, length2-pos, "in");
+				break;
 			case ELSE: 
 				pos += rlp_strcpy(res+pos, length2-pos, "else");
 				break;
+			case RETURN:
+				pos += rlp_strcpy(res+pos, length2-pos, " return");
+				break;
+			case BREAK:
+				pos += rlp_strcpy(res+pos, length2-pos, " break");
+				break;
+			case RANGEARR:
+				for(i = 0; yylval.text[i]; i++) if(yylval.text[i] == ':') {
+					yylval.text[i] = ';';	break;
+					}
+				MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
+				while(res[pos]) {
+					pos++;			if(res[pos] == ';') res[pos] = ':';
+					}
+				break;
 			case BLOCK:
-#ifdef USE_WIN_SECURE
-				pos += sprintf_s(res+pos, TMP_TXT_SIZE-pos, "{%s}", yylval.text && yylval.text[0] ? yylval.text : "");
-#else
-				pos += sprintf(res+pos, "{%s}", yylval.text && yylval.text[0] ? yylval.text : "");
-#endif
+				res[pos++] = '{';
+				MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
+				pos += (int)strlen(res+pos);
+				res[pos++] = '}';
+				break;
+			case IBLOCK:
+				MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
+				pos += (int)strlen(res+pos);
+				res[pos++] = ';';
 				break;
 			case PBLOCK:
-#ifdef USE_WIN_SECURE
-				pos += sprintf_s(res+pos, TMP_TXT_SIZE-pos, "(%s)", yylval.text && yylval.text[0] ? yylval.text : "");
-#else
-				pos += sprintf(res+pos, "(%s)", yylval.text && yylval.text[0] ? yylval.text : "");
-#endif
+				res[pos++] = '(';
+				MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
+				pos += (int)strlen(res+pos);
+				res[pos++] = ')';
 				break;
 			}
 		res[pos] = 0;
 		}while(buff_pos < length);
 	while((res[pos-1] == ';' || res[pos-1] == ' ') && pos > 0) { res[pos-1] = 0; pos--;} 
-	strcpy(nf, res);	free(res);
+	rlp_strcpy(nf, nfsize, res);	free(res);
 	free(buffer);		buffer = 0L;
 	clear_table();
 	pop_parser();
@@ -4035,7 +4317,7 @@ static char *txt_formula;	//function to fit
 static double **parval;		//pointers to parameter values
 static void fcurve(double x, double z, double **a, double *y, double dyda[], int ma)
 {
-	int i, length;
+	int i, length, parse_res;
 	double tmp, y1, y2;
 	symrec *symx, *symz, *sy=0L;
 
@@ -4049,7 +4331,7 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
 	symx->SetValue(x);	symz->SetValue(z);	
 	buffer = txt_formula;
 	buff_pos = 0;		length = (int)strlen(txt_formula);
-	do {	yyparse();	}while(buff_pos < length);
+	while(!(parse_res = yyparse()) && buff_pos < length);
 	if(sy = getsym(hn_y, h2_y)) *y = sy->GetValue();
 	else *y = line_res.value;
 	if(*y == HUGE_VAL || *y == -HUGE_VAL) {
@@ -4062,11 +4344,11 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
 			tmp = *parval[i];
 			*parval[i] = tmp*.995;
 			buff_pos = 0;
-			do {	yyparse();	}while(buff_pos < length);
+			while(!(parse_res = yyparse()) && buff_pos < length);
 			y1 = sy ? sy->GetValue() : line_res.value;
 			*parval[i] = tmp*1.005;
 			buff_pos = 0;
-			do {	yyparse();	}while(buff_pos < length);
+			while(!(parse_res = yyparse()) && buff_pos < length);
 			y2 = sy ? sy->GetValue() : line_res.value;
 			*parval[i] = tmp;
 			dyda[i] = (y2-y1)*100.0/tmp;
@@ -4081,7 +4363,8 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
 
 int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr, double conv, int maxiter, double *chi_2)
 {
-	int length, i, j, k, l, ndata, nparam, r1, r2, r3, c1, c2, c3, *lista, itst, itst1;
+	int length, i, j, k, l, ndata, nparam, r1, r2, r3, c1, c2, c3;
+	int *lista, itst, itst1, parse_res;
 	symrec *tab1, *tab2, *csr, **parsym;
 	AccRange *arx, *ary, *arz;
 	double *x, *y, *z, currx, curry, currz, alamda, chisq, ochisq;
@@ -4141,12 +4424,10 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 		free(y);	free(x);	delete arx;	delete ary;
 		return 0;
 		}
-	strcpy(buffer, *par);	buffer[length++] = ';';
+	rlp_strcpy(buffer, length, *par);	buffer[length++] = ';';
 	buffer[length] = 0;	buff_pos = 0;
 	tab1 = sym_table;
-	do {
-		yyparse();
-		}while(buff_pos < length);
+	while(!(parse_res = yyparse()) && buff_pos < length);
 	tab2 = sym_table;	free(buffer);	buffer =0L;
 	for(nparam = 0, csr=tab2; csr != tab1; nparam++, csr = csr->next);
 	parsym = (symrec**)malloc((nparam+1)*sizeof(symrec*));
@@ -4176,10 +4457,18 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 		if(k > 20) {
 			if(tmp_txt[j-1] == ' ') j--;
 			if(tmp_txt[j-1] == ';') j--;
+#ifdef USE_WIN_SECURE
+			l = sprintf_s(tmp_txt+j, 500-j, "\n");
+#else
 			l = sprintf(tmp_txt+j, "\n");
+#endif
 			j += l;		k = 0;
 			}
+#ifdef USE_WIN_SECURE
+		l += sprintf_s(tmp_txt+j, 500-j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue());
+#else
 		l += sprintf(tmp_txt+j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue());
+#endif
 		j += l;			k += l;
 		}
 	free(*par);
@@ -4187,9 +4476,7 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 	if(chi_2) *chi_2 = chisq;
 	//write back spreadsheet data if necessary
 	buffer = *par;	length = (int)strlen(buffer);
-	do {
-		yyparse();
-		}while(buff_pos < length);
+	while(!(parse_res = yyparse()) && buff_pos < length);
 	buffer = 0L;
 	free_dmatrix(alpha, 1, nparam, 1, nparam);
 	free_dmatrix(covar, 1, nparam, 1, nparam);
@@ -4198,10 +4485,12 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 	if(parval) free(parval);	if(parsym) free(parsym);
 	clear_table();
 	pop_parser();
-	if(curr_data){
-		curr_data->Command(CMD_CLEAR_ERROR, 0L, 0L);
-		curr_data->Command(CMD_REDRAW, 0L, 0L);
+	if(d){
+		d->Command(CMD_CLEAR_ERROR, 0L, 0L);
+		d->Command(CMD_REDRAW, 0L, 0L);
 		}
 	return itst < maxiter ? itst+1 : maxiter;
 }
 
+
+
diff --git a/mfcalc.y b/mfcalc.y
index e033364..1676c43 100755
--- a/mfcalc.y
+++ b/mfcalc.y
@@ -70,7 +70,8 @@ typedef struct{
 
 }YYSTYPE;
 
-static int yy_maxiter = 1000;
+static int yy_maxiter = 100000;		//maximum loop count
+static int block_res;			//result of eval()
 
 static symrec *putsym (unsigned int h_name, unsigned int h2_name, int sym_type);
 static symrec *getsym (unsigned int h_name, unsigned int h2_name, char *sym_name = 0L);
@@ -81,7 +82,7 @@ static double *PushArray(double *arr);
 static double *ReallocArray(double *arr, int size);
 static char *add_strings(char *st1, char *st2);
 static char *string_value(YYSTYPE *exp);
-static void eval(YYSTYPE *dst, YYSTYPE *sr);
+static int eval(YYSTYPE *dst, YYSTYPE *sr);
 static int range_array(YYSTYPE * res, char *range);
 static int range_array2(YYSTYPE *res1, YYSTYPE *res2);
 static void exec_clause(YYSTYPE *res);
@@ -90,9 +91,10 @@ static void yyerror(char *s);
 static void make_time(YYSTYPE *dst, double h, double m, double s);
 static int yylex(void);
 static double nop() {return 0.0;};
+static double for_loop(char *block1, char *block2);
 
 static char res_txt[1000];
-static anyResult line_res = {ET_UNKNOWN, 0.0, res_txt};
+static anyResult line_res = {ET_UNKNOWN, 0.0, res_txt, 0L, 0};
 static DataObj *curr_data;
 static char *last_error = 0L;		//error text
 static char *last_err_desc = 0L;	//short error description
@@ -104,17 +106,18 @@ static int parse_level = 0;		//count reentrances into parser
 #define MAX_PARSE 20			//maximum number of reentances 
 %}
 
-%token <val>  NUM BOOLVAL STR ARR BLOCK PBLOCK PI E CLVAL PSEP IF ELSE 
-%token <val>  BTRUE BFALSE DATE1 TIME1 DATETIME1 DIM WHILE
+%token <val>  NUM BOOLVAL STR ARR BLOCK PBLOCK IBLOCK PI E CLVAL PSEP IF ELSE 
+%token <val>  BTRUE BFALSE DATE1 TIME1 DATETIME1 DIM WHILE FOR INARR RANGEARR
+%token <val>  RETURN BREAK
 %token <tptr> VAR FNCT BFNCT AFNCT SFNCT FUNC1 FUNC2 FUNC3 TXT SRFUNC YYFNC
 %token <tptr> FUNC4 YYFNC2 YYFNC3
-%type  <val>  exp str_exp arr bool
+%type  <val>  exp str_exp arr bool block anyarg
 
-%right  '='
+%right  '=' ADDEQ SUBEQ MULEQ DIVEQ
 %left	','			/* list separator */
 %left	CLAUSE			/* clause (where) operator */
 %left	SER
-%right	COLR COLC		/* range sep., conditional sep. */
+%right	COLC			/* conditional sep. */
 %right	'?'			/* conditional assignment */
 %left	AND OR
 %left   EQ NE GT GE LT LE
@@ -139,6 +142,16 @@ line:	 '\n' | ';' | ','
 	| exp ','		{store_res(&yyvsp[-1]); return 0;}
 	| str_exp '\n'		{store_res(&yyvsp[-1]); return 0;}
 	| str_exp ';'		{store_res(&yyvsp[-1]); return 0;}
+	| IF PBLOCK block	{if(block_res = eval(&yyval, &yyvsp[-1]))return block_res; 
+				if(yyval.val != 0.0) if(block_res = eval(&yyval, &yyvsp[0]))return block_res;}
+	| IF PBLOCK block ELSE block {if(block_res = eval(&yyval, &yyvsp[-3])) return block_res; 
+				if(yyval.val != 0.0) {if(block_res = eval(&yyval, &yyvsp[-2])) return block_res;} 
+				else if(block_res = eval(&yyval, &yyvsp[0])) return block_res;}
+	| FOR PBLOCK block	{for_loop(yyvsp[-1].text, yyvsp[0].text);}
+	| WHILE PBLOCK block	{for(int i=0; i< yy_maxiter; i++){ if(block_res = eval(&yyval, &yyvsp[-1]))return block_res; 
+					if(yyval.val != 0.0){if(block_res = eval(&yyval, &yyvsp[0]))return block_res;} else break;}}
+	| RETURN IBLOCK		{if(block_res = eval(&yyval, &yyvsp[0]) == 1) return 1; else return 2;}
+	| BREAK			{return 3;}
 	| error '\n'		{yyerrok;}
 ;
 
@@ -147,30 +160,28 @@ str_exp:
 	|str_exp '+' exp	{yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0])); yyval.type = STR;}
 	|exp '+' str_exp	{yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text); yyval.type = STR;}
 	|str_exp '+' str_exp	{yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text); yyval.type = STR;}
-	|SRFUNC '(' exp ')'	{(($1->fnctptr)(&yyval, &yyvsp[-1], 0L)); yyval.type = STR;}
-	|SRFUNC '(' exp PSEP str_exp ')'	{(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
-	|SRFUNC '(' exp PSEP exp ')'		{(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
-	|SRFUNC '(' exp ',' str_exp ')'		{(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
-	|SRFUNC '(' exp ',' exp ')'		{(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
+	|SRFUNC '(' exp ')'	{if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-1], 0L)); yyval.type = STR;}
+	|SRFUNC '(' exp PSEP str_exp ')'	{if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
+	|SRFUNC '(' exp PSEP exp ')'		{if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
+	|SRFUNC '(' exp ',' str_exp ')'		{if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
+	|SRFUNC '(' exp ',' exp ')'		{if($1->fnctptr)(($1->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;}
 ;
 
 range:
 	str_exp			{;}
-	|VAR COLR VAR		{if(yyval.text = PushString("                                            ")) 
-					sprintf(yyval.text, "%s:%s", $1->name, $3->name); yyval.type = STR;}
 ;
 
-arr:	ARR
+arr:	ARR			{;}
 	|exp			{if(!yyval.a_data) {yyval.a_data = PushArray((double*)malloc(sizeof(double))); yyval.a_count = 1; yyval.a_data[0] = yyval.val;}}
 	|arr ',' arr		{push(&yyval, &yyvsp[0]);yyval.type = ARR;}
-	|arr CLAUSE exp		{exec_clause(&yyval);yyval.type = ARR;} 
+	|arr CLAUSE exp		{exec_clause(&yyval);yyval.type = ARR;}
 	|range			{range_array(&yyval, yyvsp[0].text);yyval.type = ARR;}
 	|NUM SER NUM		{if($1 < $3 && (yyval.a_data = PushArray((double*)malloc((int)($3-$1+2)*sizeof(double)))))
 					for(yyval.a_count=0; $1<=$3; yyval.a_data[yyval.a_count++] = $1, $1 += 1.0 ); yyval.type = ARR;}
 ;
 
 bool:	BOOLVAL
-	|BFNCT '(' exp ')'	{$$ = (($1->fnctptr)($3)); yyval.type = BOOLVAL;}
+	|BFNCT '(' exp ')'	{$$ = $1->fnctptr ? (($1->fnctptr)($3)): 0.0; yyval.type = BOOLVAL;}
 	|BTRUE			{$$ = 1.0; yyval.type = BOOLVAL;}
 	|BFALSE			{$$ = 0.0; yyval.type = BOOLVAL;}
 	|exp AND exp		{$$ = (($1 != 0) && ($3 != 0))? 1 : 0; yyval.type = BOOLVAL;}
@@ -183,59 +194,55 @@ bool:	BOOLVAL
 	|exp LE exp		{$$ = ($1 <= $3) ? 1 : 0; yyval.type = BOOLVAL;}
 ;
 
+block:	BLOCK | IBLOCK;
+
+anyarg: exp | str_exp;
+
 exp:	NUM				{$$ = $1; yyval.type = NUM;}
-    	|bool				{$$ = $1; yyval.type = BOOLVAL;}
+	|RANGEARR			{yyval.type = ARR;}
+  	|bool				{$$ = $1; yyval.type = BOOLVAL;}
         |TXT				{$$ = 0.0;}
 	|CLVAL				{$$ = syntax_level ? syntax_level->clval : 0.0;  yyval.type = NUM;}
 	|PI				{$$ = _PI; yyval.type = NUM;}
 	|E				{$$ = 2.71828182845905; yyval.type = NUM;}
-	|VAR				{$1->GetValue(&yyval);}
-	|BLOCK			{eval(&yyvsp[0], &yyval);}
-	|VAR '=' exp		{$1->SetValue(&yyval, &yyvsp[0]);}
-	|VAR '=' str_exp	{$1->SetValue(&yyval, &yyvsp[0]);}
-	|FNCT '(' exp ')'	{$$ = (($1->fnctptr)($3)); yyval.type = NUM;}
-	|AFNCT '(' arr ')'	{$$ = (($1->fnctptr)(proc_clause(&yyvsp[-1]))); yyval.type = NUM;}
+	|VAR				{if($1)$1->GetValue(&yyval);}
+	|block			{if(block_res = eval(&yyval, &yyvsp[0]))return block_res;}
+	|VAR '=' exp		{if($1)$1->SetValue(&yyval, &yyvsp[0]);}
+	|VAR '=' str_exp	{if($1)$1->SetValue(&yyval, &yyvsp[0]);}
+	|VAR ADDEQ exp		{if($1){$1->GetValue(&yyval); $1->SetValue(yyval.val + $3);}}
+	|VAR SUBEQ exp		{if($1){$1->GetValue(&yyval); $1->SetValue(yyval.val - $3);}}
+	|VAR MULEQ exp		{if($1){$1->GetValue(&yyval); $1->SetValue(yyval.val * $3);}}
+	|VAR DIVEQ exp		{if($1){$1->GetValue(&yyval); $1->SetValue($3 != 0.0 ? yyval.val / $3 :
+		(getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue());}}
+	|FNCT '(' exp ')'	{$$ = $1->fnctptr ? (($1->fnctptr)($3)): 0.0; yyval.type = NUM;}
+	|AFNCT '(' arr ')'	{$$ = $1->fnctptr ? (($1->fnctptr)(proc_clause(&yyvsp[-1]))) : 0.0; yyval.type = NUM; yyval.a_data = 0L; yyval.a_count = 0; yyval.text = 0L;}
 	|AFNCT '(' exp PSEP arr ')' { if(!yyval.a_data){yyval.a_data=PushArray((double*)malloc(sizeof(double)));yyval.a_data[0]=$3;yyval.a_count=1;}
-		push(&yyval, &yyvsp[-1]);$$ = (($1->fnctptr)(&yyval)); yyval.type = NUM;}
+		push(&yyval, &yyvsp[-1]);$$ = $1->fnctptr ?(($1->fnctptr)(&yyval)):0.0; yyval.type = NUM;}
 	|AFNCT '(' exp PSEP exp PSEP exp ')' { yyval.a_data = PushArray((double*)malloc(3*sizeof(double)));
 		yyval.a_count = 3; yyval.a_data[0] = $3; yyval.a_data[1] = $5; yyval.a_data[2] = $7;	
-		$$ = (($1->fnctptr)(&yyval)); yyval.type = NUM;}
-	|SFNCT '(' str_exp ')'	{yyval.type = NUM; $$ = (($1->fnctptr)(&yyvsp[-1], &yyval, 0L));}
-	|SFNCT '(' exp ')'	{yyval.type = NUM; yyvsp[-1].text = string_value(&yyvsp[-1]); $$ = (($1->fnctptr)(&yyvsp[-1], &yyval, 0L));}
-	|SFNCT '(' str_exp PSEP str_exp ')' {$$ = (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;}
-	|SFNCT '(' exp PSEP str_exp ')' {$$ = (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;}
-	|SFNCT '(' exp PSEP exp ')' {$$ = (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;}
-	|SFNCT '(' str_exp PSEP exp ')' {$$ = (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;}
-	|SFNCT '(' str_exp ',' str_exp ')' {$$ = (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;}
-	|SFNCT '(' exp ',' str_exp ')' {$$ = (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;}
-	|SFNCT '(' str_exp ',' exp ')' {$$ = (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;}
-	|SFNCT '(' exp ',' exp ')' {$$ = (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;}
-	|FUNC2 '(' range PSEP range ')' {range_array2(&yyvsp[-3], &yyvsp[-1]);$$ = ((*$1->fnctptr)(&yyvsp[-3], &yyvsp[-1], 0L)); yyval.type = NUM;}
-	|FUNC2 '(' range PSEP range PSEP range ')' {range_array2(&yyvsp[-5], &yyvsp[-3]); $$ = ((*$1->fnctptr)(&yyvsp[-5], &yyvsp[-3], yyvsp[-1].text)); yyval.type = NUM;}
-	|FUNC3 '(' arr PSEP arr ')'	{$$=((*$1->fnctptr)(proc_clause(&yyvsp[-3]), proc_clause(&yyvsp[-1]), 0L));}
-	|FUNC3 '(' arr PSEP arr PSEP range ')' {$$=((*$1->fnctptr)(proc_clause(&yyvsp[-5]), proc_clause(&yyvsp[-3]), yyvsp[-1].text));}
-	|FUNC4 '(' exp PSEP exp PSEP arr PSEP range ')' {proc_clause(&yyvsp[-3]); $$=(*$1->fnctptr)($3, $5, &yyvsp[-3], &yyvsp[-1]); yyval.type = NUM;}
-	|FUNC1 '(' arr PSEP range ')' {$$ = ((*$1->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text));  yyval.type = NUM;}
-	|YYFNC '(' ')'		{(*$1->fnctptr)(&yyval, 0L);}
-	|YYFNC '(' arr ')'	{(*$1->fnctptr)(&yyval, &yyvsp[-1]);}
-	|YYFNC2 '(' exp PSEP exp ')'	{(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);}
-	|YYFNC2 '(' str_exp PSEP exp ')'	{(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);}
-	|YYFNC2 '(' exp PSEP str_exp ')'	{(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);}
-	|YYFNC2 '(' str_exp PSEP str_exp ')'	{(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);}
-	|YYFNC3 '(' str_exp PSEP str_exp PSEP str_exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
-	|YYFNC3 '(' exp PSEP str_exp PSEP str_exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
-	|YYFNC3 '(' str_exp PSEP exp PSEP str_exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
-	|YYFNC3 '(' str_exp PSEP str_exp PSEP exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
-	|YYFNC3 '(' exp PSEP exp PSEP str_exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
-	|YYFNC3 '(' exp PSEP str_exp PSEP exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
-	|YYFNC3 '(' str_exp PSEP exp PSEP exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
-	|YYFNC3 '(' exp PSEP exp PSEP exp')'	{(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
-	|IF '(' exp ')' BLOCK	{if($3 != 0.0)eval(&yyval, &yyvsp[0]);}
-	|IF '(' exp ')' BLOCK ELSE BLOCK	{$3 != 0.0 ? eval(&yyval, &yyvsp[-2]) : eval(&yyval, &yyvsp[0]);}
-	|WHILE PBLOCK BLOCK	{for(int i=0; i< yy_maxiter; i++){
-					eval(&yyval, &yyvsp[-1]); 
-					if(yyval.val != 0.0)eval(&yyval, &yyvsp[0]);
-					else break;}}
+		$$ = $1->fnctptr ? (($1->fnctptr)(&yyval)) : 0.0; yyval.type = NUM;}
+	|SFNCT '(' str_exp ')'	{yyval.type = NUM; $$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-1], &yyval, 0L)) : 0.0;}
+	|SFNCT '(' exp ')'	{yyval.type = NUM; yyvsp[-1].text = string_value(&yyvsp[-1]); $$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-1], &yyval, 0L)) : 0.0;}
+	|SFNCT '(' str_exp PSEP str_exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
+	|SFNCT '(' exp PSEP str_exp ')' {$$ = $1->fnctptr ?(($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
+	|SFNCT '(' exp PSEP exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
+	|SFNCT '(' str_exp PSEP exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
+	|SFNCT '(' str_exp ',' str_exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
+	|SFNCT '(' exp ',' str_exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
+	|SFNCT '(' str_exp ',' exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
+	|SFNCT '(' exp ',' exp ')' {$$ = $1->fnctptr ? (($1->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
+	|FUNC2 '(' anyarg PSEP anyarg ')' {range_array2(&yyvsp[-3], &yyvsp[-1]);$$ = $1->fnctptr ? ((*$1->fnctptr)(&yyvsp[-3], &yyvsp[-1], 0L)) : 0.0; yyval.type = NUM;}
+	|FUNC2 '(' anyarg PSEP anyarg PSEP anyarg ')' {range_array2(&yyvsp[-5], &yyvsp[-3]); $$ = $1->fnctptr ? ((*$1->fnctptr)(&yyvsp[-5], &yyvsp[-3], yyvsp[-1].text)) : 0.0; yyval.type = NUM;}
+	|FUNC3 '(' arr PSEP arr ')'	{$$= $1->fnctptr ? ((*$1->fnctptr)(proc_clause(&yyvsp[-3]), proc_clause(&yyvsp[-1]), 0L)) : 0.0;}
+	|FUNC3 '(' arr PSEP arr PSEP range ')' {$$=$1->fnctptr ? ((*$1->fnctptr)(proc_clause(&yyvsp[-5]), proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;}
+	|FUNC4 '(' exp PSEP exp PSEP arr PSEP range ')' {proc_clause(&yyvsp[-3]); $$=$1->fnctptr ? (*$1->fnctptr)($3, $5, &yyvsp[-3], &yyvsp[-1]) : 0.0; yyval.type = NUM;}
+	|FUNC1 '(' arr PSEP range ')' {$$ = $1->fnctptr ? ((*$1->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;}
+	|FUNC1 '(' arr PSEP RANGEARR ')' {$$ = $1->fnctptr ? ((*$1->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text)) : 0.0;  yyval.type = NUM;}
+	|YYFNC '(' ')'		{if($1->fnctptr)(*$1->fnctptr)(&yyval, 0L);}
+	|YYFNC '(' arr ')'	{if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-1]);}
+	|YYFNC2 '(' anyarg PSEP anyarg ')' {if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-3], &yyvsp[-1]);}
+	|YYFNC2 '(' anyarg ')' {if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-1], 0L);}
+	|YYFNC3 '(' anyarg PSEP anyarg PSEP anyarg')'	{if($1->fnctptr)(*$1->fnctptr)(&yyval, &yyvsp[-5], &yyvsp[-3], &yyvsp[-1]);}
 	|exp '+' exp		{$$ = $1 + $3; yyval.type = NUM;
 				if(yyvsp[0].type == DATE1 || yyvsp[-2].type == DATE1) yyval.type = DATE1;
 				else if(yyvsp[0].type == TIME1 || yyvsp[-2].type == TIME1) yyval.type = TIME1;
@@ -253,16 +260,27 @@ exp:	NUM				{$$ = $1; yyval.type = NUM;}
 	|DEC VAR %prec PDEC	{$$=$2->GetValue(); $2->SetValue($$-1.0); yyval.type = NUM;}
 	|exp '^' exp		{$$ = ($3 >0 && $3/2.0 == floor($3/2.0)) ? fabs(pow($1,$3) ): pow($1, $3); yyval.type = NUM;}
 	|'-' exp  %prec NEG	{$$ = -$2; yyval.type = NUM;}
-	|'(' arr ')'		{memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;}
+	|'(' anyarg ')'		{memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;}
 	|DIM VAR %prec PDIM '[' exp ']'	{yyval.a_data = PushArray((double*)calloc((int)$4, sizeof(double))); yyval.a_count=(int)($4); 
 					yyval.type = ARR; $2->SetValue(&yyval,&yyval);}
 	|exp '[' exp ']'	{if(yyvsp[-3].a_data && yyvsp[-1].val >= 0.0 && yyvsp[-1].val < yyvsp[-3].a_count) $$ = yyvsp[-3].a_data[(int)yyvsp[-1].val];
 				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
 	|exp '[' exp ']' '=' exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) $$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] = $6;
 				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
-	|NUM COLR NUM COLR NUM	{make_time(&yyval, $1, $3, $5+1.0e-10);}
+	|exp '[' exp ']' ADDEQ exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
+				$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] += $6;
+				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
+	|exp '[' exp ']' SUBEQ exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
+				$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] -= $6;
+				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
+	|exp '[' exp ']' MULEQ exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count) 
+				$$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] *= $6;
+				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
+	|exp '[' exp ']' DIVEQ exp {if(yyvsp[-5].a_data && yyvsp[-3].val >= 0.0 && yyvsp[-3].val < yyvsp[-5].a_count){ 
+				if($6 != 0.0) $$ = yyvsp[-5].a_data[(int)yyvsp[-3].val] /= $6;
+				else {$$ = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue();}}
+				else {$$ = 0.0; last_err_desc = "#INDEX";} yyval.type = NUM;}
 	|NUM ':' NUM ':' NUM	{make_time(&yyval, $1, $3, $5+1.0e-10);}
-	|NUM COLR NUM 		{make_time(&yyval, $1, $3, 1.0e-10);}
 	|NUM ':' NUM 		{make_time(&yyval, $1, $3, 1.0e-10);}
 	|exp '?' exp COLC exp	{memcpy(&yyval, $1 != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE))}
 	|exp '?' STR COLC STR	{memcpy(&yyval, $1 != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE))}
@@ -336,7 +354,7 @@ symrec::GetValue(void *re)
 				res->text = 0L;		break;
 			case ET_TEXT:
 				res->type = STR;	res->val = 0.0;
-				if(ares.text) res->text = PushString(text = strdup(ares.text));
+				if(ares.text) res->text = PushString(text = (char*)memdup(ares.text, (int)strlen(ares.text)+1, 0));
 				else res->text = 0L;	break;
 			default:
 				res->type = NUM;	res->val = var;
@@ -350,15 +368,19 @@ symrec::GetValue(void *re)
 		}
 	if(!isValid) NoInit();
 	if(a_data && a_count) {
+		if(text && text[0]) res->text = PushString(text);
+		else res->text = 0L;
 		res->a_data = a_data;	res->a_count = a_count;
 		res->val = 0.0;		res->type = ARR;
 		}
 	else if(text && text[0]) {
 		res->text = PushString(text);
-		res->val = var;		res->type = STR;
+		res->a_data = 0L;	res->a_count = 0;
+		res->val = 0.0;		res->type = STR;
 		}
 	else {
 		res->type = NUM;	res->val = var;
+		res->a_data = 0L;	res->a_count = 0;
 		res->text = 0L;
 		}
 }
@@ -392,7 +414,13 @@ symrec::SetValue(void* d, void* s)
 		else if(src->type == STR) curr_data->SetText(row, col, src->text);
 		else if(src->type == ARR || (src->a_data)) curr_data->SetText(row, col, "#ARRAY");
 		else if(src->type == VAR && src->tptr->type == TXT) curr_data->SetText(row, col, src->tptr->text);
-		else curr_data->SetValue(row, col, src->val);
+		else {
+			if(curr_data->SetValue(row, col, src->val))
+				switch(src->type) {
+				case BOOLVAL:
+					curr_data->etRows[row][col]->type = ET_BOOL;	break;
+				}
+			}
 		curr_data->Command(CMD_UPDATE, 0L, 0L);
 		}
 	isValid = true;
@@ -494,7 +522,7 @@ static void store_res(YYSTYPE *res)
 	if(last_err_desc) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
-		strcpy(res_txt, last_err_desc);
+		rlp_strcpy(res_txt, 1000, last_err_desc);
 		}
 	else if(res->type == NUM){
 		line_res.type = ET_VALUE;
@@ -519,7 +547,7 @@ static void store_res(YYSTYPE *res)
  	else if(res->type == STR) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
-		if(res->text) strcpy(res_txt, res->text);
+		if(res->text) rlp_strcpy(res_txt, 1000, res->text);
 		}
 	else if((res->type == ARR || (res->a_data)) && res->a_count == 1) {
 		line_res.type = ET_VALUE;
@@ -532,12 +560,14 @@ static void store_res(YYSTYPE *res)
 	else if(res->type == ARR || (res->a_data)) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
-		strcpy(res_txt, "#ARRAY");
+		line_res.a_data = res->a_data;
+		line_res.a_count = res->a_count;
+		rlp_strcpy(res_txt, 1000, "#ARRAY");
 		}
 	else if(res->tptr && res->tptr->type == TXT) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
-		if(res->tptr->text) strcpy(res_txt, res->tptr->text);
+		if(res->tptr->text) rlp_strcpy(res_txt, 1000, res->tptr->text);
 		}
 	else {
 		line_res.type = ET_VALUE;
@@ -579,7 +609,11 @@ static char *string_value(YYSTYPE *exp)
 		st1 = exp->tptr->text;
 		}
 	else {
+#ifdef USE_WIN_SECURE
+		sprintf_s(tmp, 50, "%g", exp->val);
+#else
 		sprintf(tmp,"%g", exp->val);
+#endif
 		st1 = tmp;
 		}
 	return PushString(st1);
@@ -606,51 +640,53 @@ static void pop_syntax()
 		}
 }
 
-static void eval(YYSTYPE *dst, YYSTYPE *sr) 
+static int eval(YYSTYPE *dst, YYSTYPE *sr) 
 {
 	char *s_buffer;
-	int s_buff_pos, s_yychar, s_yynerrs, length;
+	int s_buff_pos, s_yychar, s_yynerrs, length, parse_res;
 	anyResult *ar;
 
-	if(!sr || !sr->text) return;
-	parse_level++;
+	if(!sr || !sr->text || !sr->text[0]) return 1;
 	s_buffer = buffer;		s_buff_pos = buff_pos;
-	s_yychar = yychar;	s_yynerrs = yynerrs;
-	if (sr->text && (length=(int)strlen(sr->text)) && (buffer = (char*)malloc(length+2))) {
-		strcpy(buffer, sr->text);		buffer[length++] = ';';
-		buffer[length] = 0;		buff_pos = 0;
-		do {
-			yyparse();
-			}while(buff_pos < length);
-		free(buffer);		ar = &line_res;
+	s_yychar = yychar;		s_yynerrs = yynerrs;
+	if(!(length = (int)strlen(sr->text)))return 1;
+	parse_level++;
+	if(sr->text[length-1] == ';') buffer = sr->text;
+	else {
+		buffer = (char*)malloc(length+2);
+		rlp_strcpy(buffer, length+1, sr->text);
+		buffer[length++] = ';';		buffer[length] = 0;
+		}
+	if(buffer && buffer[0]){
+		buff_pos = 0;
+		while(!(parse_res = yyparse()) && buff_pos < length);
+		if(buffer != sr->text) free(buffer);
+		ar = &line_res;
 		buffer = s_buffer;		buff_pos = s_buff_pos;
-		yychar = s_yychar;	yynerrs = s_yynerrs;
+		yychar = s_yychar;		yynerrs = s_yynerrs;
 		}
-	else return;
-	yylval.a_data = 0L;	yylval.a_count = 0;
+	else return 1;
+	dst->a_data = ar->a_data;	dst->a_count = ar->a_count;
+	if(parse_res == 2) return 2;
+	else if(parse_res == 3 && sr->type == IBLOCK) return 3;
+	else if(parse_res == 1) return 1;
 	switch(ar->type) {
 	case ET_BOOL:
-		dst->type = BOOLVAL;
-		dst->val = ar->value;
-		dst->text = 0L;
-		break;
+		dst->type = BOOLVAL;	dst->val = ar->value;
+		dst->text = 0L;		break;
 	case ET_VALUE:
-		dst->type = NUM;
-		dst->val = ar->value;
-		dst->text = 0L;
-		break;
+		dst->type = NUM;	dst->val = ar->value;
+		dst->text = 0L;		break;
 	case ET_TEXT:
-		dst->type = STR;
-		dst->val = 0.0;
+		dst->type = STR;	dst->val = 0.0;
 		dst->text = PushString(ar->text);
 		break;
 	default:
-		dst->type = NUM;
-		dst->val = 0.0;
-		dst->text = 0L;
-		break;
+		dst->type = NUM;	dst->val = 0.0;
+		dst->text = 0L;		break;
 		}
 	parse_level--;
+	return 0;
 }
 
 // more functions
@@ -1023,7 +1059,7 @@ static double lognorminv(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3) {
-		sr->val = distinv(lognorm_dist, sr->a_data[1], sr->a_data[2], sr->a_data[0], sr->a_data[1]);
+		sr->val = distinv(lognorm_dist, sr->a_data[1], sr->a_data[2], sr->a_data[0], exp(sr->a_data[1]));
 		}
 	else yyargserr("Wrong number of arguments\nin call to  lognorminv(p, mean, SD).");
 	return sr->val;
@@ -1153,12 +1189,23 @@ static double finv(YYSTYPE *sr)
 	return sr->val;
 }
 
+static double ksdist(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = ks_dist((int)sr->a_data[0], sr->a_data[1]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  ksdist(n, D).");
+	return sr->val;
+}
+
 static double pearson(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 {
 	if(!sr1 || !sr2) return 0.0;
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_pearson(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		sr1->val = sr2->val = d_pearson(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
 		}
 	else yyargserr("Bad arguments in call to function\npearson(range1; range2 [;\"dest\"]).");
 	return sr1->val;
@@ -1169,7 +1216,7 @@ static double spearman(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	if(!sr1 || !sr2) return 0.0;
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_spearman(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		sr1->val = sr2->val = d_spearman(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
 		}
 	else yyargserr("Bad arguments in call to function\nspearman(range1; range2 [;\"dest\"]).");
 	return sr1->val;
@@ -1180,7 +1227,7 @@ static double kendall(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	if(!sr1 || !sr2) return 0.0;
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
-		sr1->val = sr2->val = d_kendall(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		sr1->val = sr2->val = d_kendall(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data, 0L);
 		}
 	else yyargserr("Bad arguments in call to function\nkendall(range1; range2 [;\"dest\"]).");
 	return sr1->val;
@@ -1253,6 +1300,34 @@ static double ftest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	return sr1->val;
 }
 
+static double p_tukey(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0;
+	if(sr->a_data && sr->a_count == 4){
+		sr->val = ptukey(sr->a_data[0], sr->a_data[3], sr->a_data[1], sr->a_data[2], 1, 0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = ptukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0);
+		}
+	else yyargserr("Wrong number of arguments\nin call to ptukey(q, nm, df[, nr = 1]).");
+	return sr->val;
+}
+
+static double q_tukey(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0;
+	if(sr->a_data && sr->a_count == 4){
+		sr->val = qtukey(sr->a_data[0], sr->a_data[3], sr->a_data[1], sr->a_data[2], 1, 0);
+		}
+	else if(sr->a_data && sr->a_count == 3){
+		sr->val = qtukey(sr->a_data[0], 1.0, sr->a_data[1], sr->a_data[2], 1, 0);
+		}
+	else yyargserr("Wrong number of arguments\nin call to qtukey(p, nm, df[, nr = 1]).");
+	return sr->val;
+}
+
 static double fill(YYSTYPE *sr, char *dest)
 {
 	AccRange *ar;
@@ -1396,10 +1471,11 @@ static void ftime(YYSTYPE *dst, YYSTYPE *src)
 	dst->type = TIME1;		dst->val = src->val;
 }
 
-static void asort(YYSTYPE *dst, YYSTYPE *src)
+static void invert(YYSTYPE *dst, YYSTYPE *src)
 {
+	int i;
+
 	if(!dst || !src) return;
-	dst->type = ARR;
 	switch(src->a_count) {
 	case 0:
 		dst->a_data = PushArray((double*)malloc(sizeof(double)));
@@ -1412,46 +1488,70 @@ static void asort(YYSTYPE *dst, YYSTYPE *src)
 	default:
 		dst->a_data = PushArray((double*)memdup(src->a_data, src->a_count * sizeof(double), 0));
 		dst->a_count = src->a_count;
-		SortArray(dst->a_count, dst->a_data);
+		for(i = 0; i < src->a_count; i++) dst->a_data[i] = src->a_data[src->a_count-1-i];
 		}
 }
 
-static void _crank(YYSTYPE *dst, YYSTYPE *src)
+static void asort(YYSTYPE *dst, YYSTYPE *src)
 {
-	double tmp;
-
 	if(!dst || !src) return;
 	dst->type = ARR;
 	switch(src->a_count) {
-	case 0:	case 1:
+	case 0:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->val;
+		break;
+	case 1:
 		dst->a_data = PushArray((double*)malloc(sizeof(double)));
-		dst->a_count = 1;	dst->a_data[0] = dst->val = 1;
+		dst->a_count = 1;	dst->a_data[0] = dst->val = src->a_data[0];
 		break;
 	default:
 		dst->a_data = PushArray((double*)memdup(src->a_data, src->a_count * sizeof(double), 0));
 		dst->a_count = src->a_count;
-		crank(dst->a_count, dst->a_data, &tmp);
+		SortArray(dst->a_count, dst->a_data);
 		}
 }
 
+static void asort2(YYSTYPE *res, YYSTYPE *sr1, YYSTYPE *sr2, char *fmt)
+{
+	int n;
+
+	res->val = 0.0;		res->type = NUM;
+	if(!sr1 || !sr2 || !sr1->a_data || !sr2->a_data) return;
+	n = sr1->a_count > sr2->a_count ? sr2->a_count : sr1->a_count;
+	res->val = (double)n;
+	if(n >1) SortArray2(n, sr1->a_data, sr2->a_data);
+	return;
+}
+
+static double _crank(YYSTYPE *src)
+{
+	double tmp = -1.0;
+
+	if(!src) return tmp;
+	tmp = 0.0;
+	if(src->a_data && src->a_count > 1.0)crank(src->a_count, src->a_data, &tmp);
+	return tmp;
+}
+
 static void ltrim(YYSTYPE *dst, YYSTYPE *src)
 {
 	if(!src || !dst || !src->text) return;
-	dst->text = PushString(str_ltrim(strdup(src->text)));
+	dst->text = PushString(str_ltrim(src->text));
 	dst->type = STR;	dst->val = 0.0;
 }
 
 static void rtrim(YYSTYPE *dst, YYSTYPE *src)
 {
 	if(!src || !dst || !src->text) return;
-	dst->text = PushString(str_rtrim(strdup(src->text)));
+	dst->text = PushString(str_rtrim(src->text));
 	dst->type = STR;	dst->val = 0.0;
 }
 
 static void trim(YYSTYPE *dst, YYSTYPE *src)
 {
 	if(!src || !dst || !src->text) return;
-	dst->text = PushString(str_trim(strdup(src->text)));
+	dst->text = PushString(str_trim(src->text));
 	dst->type = STR;	dst->val = 0.0;
 }
 
@@ -1554,6 +1654,59 @@ static void uc_word(YYSTYPE *dst, YYSTYPE *src)
 	else dst->text = 0L;
 }
 
+static void exec(YYSTYPE *dst, YYSTYPE *src1, YYSTYPE *src2)
+{
+	char *cmd = 0L;
+	int cmd_pos = 0, cmd_size, r, c;
+	AccRange *ar = 0L;
+	anyResult res, *eres;
+
+	if(!src1 || !src1->text || !src1->text[0]) return;
+	if((cmd =(char*)malloc((cmd_size = 1000) * sizeof(char))) && (ar = new AccRange(src1->text))) {
+		if(src2 && src2->text[0] && src2->text[0]) {
+			add_to_buff(&cmd, &cmd_pos, &cmd_size, src2->text, 0);
+			while(cmd_pos && cmd[cmd_pos-1] < 33) cmd_pos--;
+			if(cmd_pos && cmd[cmd_pos-1] != ';') cmd[cmd_pos++] = ';';
+			}
+		cmd[cmd_pos] = 0;
+		ar->GetFirst(&c, &r);	ar->GetNext(&c, &r);
+		do {
+			curr_data->GetResult(&res, r, c, false);
+			switch(res.type) {
+			case ET_VALUE:				//numerical value
+				if(res.value == -HUGE_VAL)
+					add_to_buff(&cmd, &cmd_pos, &cmd_size, "-inf", 4);
+				else if(res.value == HUGE_VAL)
+					add_to_buff(&cmd, &cmd_pos, &cmd_size, "inf", 3);
+				else add_dbl_to_buff(&cmd, &cmd_pos, &cmd_size, res.value, false);
+				break;
+			case ET_TEXT:					//text cell
+				if(res.text && res.text[0]) {
+					if(res.text[0] == res.text[1] && res.text[0] == '/') ar->NextRow(&r);
+					else add_to_buff(&cmd, &cmd_pos, &cmd_size, res.text, 0);
+					}
+				break;
+				}
+			}while(ar->GetNext(&c, &r));
+		eres = do_formula(curr_data, cmd);
+		switch(eres->type) {
+		case ET_BOOL:
+			dst->type = BOOLVAL;	dst->val = eres->value;
+			dst->text = 0L;				break;
+		case ET_VALUE:
+			dst->type = NUM;	dst->val = eres->value;
+			dst->text = 0L;				break;
+		case ET_TEXT:
+			dst->type = STR;	dst->val = 0.0;
+			dst->text = PushString(eres->text);	break;
+		default:
+			dst->type = NUM;	dst->val = 0.0;
+			dst->text = 0L;		break;
+			}
+		}
+	if(cmd) free(cmd);	if(ar) delete ar;
+}
+
 // Store strings in a list
 static char **str_list = 0L;
 static int n_str = 0;
@@ -1562,7 +1715,7 @@ static char *PushString(char *text)
 {
 	if(text && text[0]) {
 		if(str_list = (char**)realloc(str_list, sizeof(char*)*(n_str+1)))
-			str_list[n_str] = strdup(text);
+			str_list[n_str] = (char*)memdup(text, (int)strlen(text)+1, 0);
 		return str_list[n_str++];
 		}
 	return 0L;
@@ -1575,9 +1728,10 @@ static int n_arr = 0;
 static double *PushArray(double *arr)
 {
 	if(arr) {
-		if(arr_list = (double**)realloc(arr_list, sizeof(double*)*(n_arr+1)))
+		if(arr_list = (double**)realloc(arr_list, sizeof(double*)*(n_arr+1))){
 			arr_list[n_arr] = arr;
-		return arr_list[n_arr++];
+			return arr_list[n_arr++];
+			}
 		}
 	return 0L;
 }
@@ -1644,6 +1798,7 @@ void InitArithFuncs(DataObj *d)
 		double (*fnct)(double);
 		};
 	fdef fncts[] = {
+	INIT_SYM(AFNCT, "ptukey", p_tukey),		INIT_SYM(AFNCT, "qtukey", q_tukey),
 	INIT_SYM(YYFNC, "toupper", to_upper),		INIT_SYM(YYFNC, "tolower", to_lower),
 	INIT_SYM(YYFNC, "ucfirst", uc_first),		INIT_SYM(YYFNC, "ucword", uc_word),
 	INIT_SYM(SFNCT, "asc", asc),			INIT_SYM(YYFNC, "chr", chr),
@@ -1651,7 +1806,7 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(YYFNC2, "strpos",_strpos),		INIT_SYM(FUNC4, "classes", classes),
 	INIT_SYM(AFNCT, "rank", rank),			INIT_SYM(YYFNC, "ltrim", ltrim),
 	INIT_SYM(YYFNC, "rtrim", rtrim),		INIT_SYM(YYFNC, "trim", trim),
-	INIT_SYM(YYFNC, "asort", asort),		INIT_SYM(YYFNC, "crank", _crank),
+	INIT_SYM(YYFNC, "asort", asort),		INIT_SYM(AFNCT, "crank", _crank),
 	INIT_SYM(SRFUNC, "datestr", datestr),		INIT_SYM(SFNCT, "dateval", dateval),
 	INIT_SYM(BFNCT, "leapyear", leapyear),		INIT_SYM(YYFNC, "today", today),
 	INIT_SYM(YYFNC, "now", now),			INIT_SYM(FNCT, "year", year),
@@ -1663,7 +1818,7 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(FUNC1, "fill", fill),			INIT_SYM(FUNC2, "pearson", pearson),
 	INIT_SYM(FUNC2, "spearman", spearman),		INIT_SYM(FUNC2, "kendall", kendall),		
 	INIT_SYM(FUNC2, "correl", pearson),		INIT_SYM(FUNC2, "regression", regression),
-	INIT_SYM(FUNC2, "covar", covar),
+	INIT_SYM(FUNC2, "covar", covar),		INIT_SYM(YYFNC2, "exec", exec),
 	INIT_SYM(FUNC3, "utest", utest),		INIT_SYM(FUNC2, "ttest2", ttest2),
 	INIT_SYM(FUNC3, "ttest", ttest),		INIT_SYM(FUNC3, "ftest", ftest),
 	INIT_SYM(AFNCT, "variance", variance),		INIT_SYM(AFNCT, "stdev", stdev),
@@ -1674,24 +1829,21 @@ void InitArithFuncs(DataObj *d)
 	INIT_SYM(AFNCT, "median", quartile2),		INIT_SYM(AFNCT, "quartile1", quartile1),
 	INIT_SYM(AFNCT, "quartile2",quartile2),		INIT_SYM(AFNCT, "quartile3", quartile3),
 	INIT_SYM(AFNCT, "gmean", gmean),		INIT_SYM(AFNCT, "hmean", hmean),
-	INIT_SYM(AFNCT, "tdist", tdist),		
-	INIT_SYM(AFNCT, "tfreq", tfreq),
-	INIT_SYM(AFNCT, "tinv", tinv),
+	INIT_SYM(AFNCT, "tdist", tdist),		INIT_SYM(AFNCT, "tfreq", tfreq),
+	INIT_SYM(AFNCT, "tinv", tinv),			INIT_SYM(YYFNC, "invert", invert),
 	INIT_SYM(AFNCT, "poisdist", poisdist),		INIT_SYM(AFNCT, "poisfreq", poisfreq),		
 	INIT_SYM(AFNCT, "expdist", expdist),		INIT_SYM(AFNCT, "expfreq", expfreq),		
-	INIT_SYM(AFNCT, "expinv", expinv),		
-	INIT_SYM(AFNCT, "fdist", fdist),
-	INIT_SYM(AFNCT, "ffreq", ffreq),
+	INIT_SYM(AFNCT, "expinv", expinv),		INIT_SYM(AFNCT, "fdist", fdist),
+	INIT_SYM(AFNCT, "ffreq", ffreq),		INIT_SYM(AFNCT, "ksdist", ksdist),
 	INIT_SYM(AFNCT, "finv", finv),			INIT_SYM(AFNCT, "gammp", _gammp),
 	INIT_SYM(AFNCT, "gammq", _gammq),		INIT_SYM(AFNCT, "beta", beta),
 	INIT_SYM(AFNCT, "betai", _betai),		INIT_SYM(AFNCT, "bincof", _bincof),
-	INIT_SYM(AFNCT, "binomdist",binomdist),
-	INIT_SYM(AFNCT, "binomfreq",binomfreq),
+	INIT_SYM(AFNCT, "binomdist",binomdist),		INIT_SYM(AFNCT, "binomfreq",binomfreq),
 	INIT_SYM(AFNCT, "normdist", normdist),
 	INIT_SYM(AFNCT, "norminv", norminv),		INIT_SYM(AFNCT, "normfreq", normfreq),
 	INIT_SYM(AFNCT, "lognormdist", lognormdist),	INIT_SYM(AFNCT, "lognormfreq", lognormfreq),
 	INIT_SYM(AFNCT, "lognorminv",lognorminv),	INIT_SYM(AFNCT, "chidist", chidist),
-	INIT_SYM(AFNCT, "chifreq", chifreq),
+	INIT_SYM(AFNCT, "chifreq", chifreq),		INIT_SYM(YYFNC2, "asort2", asort2),
 	INIT_SYM(AFNCT, "chiinv", chiinv),		INIT_SYM(SFNCT, "strlen", _strlen),
 	INIT_SYM(YYFNC, "eval", eval),			INIT_SYM(FNCT, "erf", errf),
 	INIT_SYM(FNCT, "erfc", errfc),			INIT_SYM(FNCT, "sign", sign),
@@ -1894,7 +2046,7 @@ static YYSTYPE *proc_clause(YYSTYPE *res)
 		if(!syntax_level) break;
 		syntax_level->clval = res->a_data[i];
 		yyparse();
-		if(line_res.type == ET_VALUE && line_res.value != 0.0) n_data[n++] = res->a_data[i];
+		if((line_res.type == ET_VALUE || line_res.type == ET_BOOL) && line_res.value != 0.0) n_data[n++] = res->a_data[i];
 		}
 	res->a_data = n_data;		res->a_count = n;
 	res->text=0L;
@@ -2006,16 +2158,28 @@ static int is_ttoken(unsigned int h_nam, unsigned int h2_nam)
 		if(h2_nam == 5220) return CLVAL;
 		break;
 	case 362:
-		if(h2_nam == 42878) return IF;
+		if(h2_nam == 42878) return (syntax_level->last_tok = IF);
 		break;
 	case 28421:
 		if(h2_nam == 82147317) return (syntax_level->last_tok = WHILE);
 		break;
+	case 1518:
+		if(h2_nam == 20654586) return (syntax_level->last_tok = FOR);
+		break;
+	case 370:
+		if(h2_nam == 46206) return INARR;
+		break;
 	case 1457:
 		if(h2_nam == 18357885) return DIM;
 		break;
+	case 108774:
+		if(h2_nam == 0x27d5d1fe) return (syntax_level->last_tok = RETURN);
+		break;
+	case 23583:
+		if(h2_nam == 0x954f67ff) return BREAK;
+		break;
 	case 6033:
-		if((h2_nam & 0x7fffffff) == 0x6371377d) return ELSE;
+		if((h2_nam & 0x7fffffff) == 0x6371377d) return (syntax_level->last_tok = ELSE);
 		break;
 	case 7097:
 		if((h2_nam & 0x7fffffff) == 0x550a2d65) return BTRUE;
@@ -2038,6 +2202,8 @@ static char *copy_block()
 		first[0] = '{';		last[0] = '}';	break;
 	case '(':
 		first[0] = '(';		last[0] = ')';	break;
+	default:
+		first[0] = '\0';	last[0] = ';';	break;
 		}
 	if(!(res = (char*)malloc(strlen(src)+2))) return 0L;
 	for(i = 1, level = mode = j = 0; src[i]; i++) {
@@ -2052,7 +2218,7 @@ static char *copy_block()
  			if(src[i] == last[level]) {
 				if(level) level--;
 				else {
-					res[j-1] = 0;	buff_pos += j;
+					res[j-1] = ';';	res[j] = 0;	buff_pos += j;
 					return res;
 					}
 				}
@@ -2068,25 +2234,103 @@ static char *copy_block()
 				}
 			}
 		}
+	res[j] = ';';	res[j+1] = 0;		buff_pos += j;
 	return res;
 }
 
 static symrec *curr_sym;
-static int yylex (void)
+static double for_loop(char *block1, char *block2)
+{
+	char *last_buffer, *bb1, *bb2, *bb3;
+	int i, a_count, last_buff_pos, cb1;
+	double *a_data;
+	YYSTYPE yyres, yysrc;
+	symrec *var;
+
+	if(!block1 || !block1[0]) return 0.0;
+	bb1 = bb2 = bb3 = 0L;		parse_level++;
+	cb1 = (int)strlen(block1);
+	last_buffer = buffer;		last_buff_pos = buff_pos;
+	buffer = block1;		buff_pos = 0;
+	//test for syntax 1
+	bb1 = copy_block();
+	if(buff_pos < cb1) bb2 = copy_block();
+	if(buff_pos < cb1) bb3 = copy_block();
+	if(bb1 && bb2 && bb3) {		//syntax 1 found !
+		yysrc.text = bb1;	if(bb1[0]) eval(&yyres, &yysrc);
+		for(i = 0; i < yy_maxiter; i++) {
+			yysrc.text = bb2;
+			if(bb2[0]) {
+				eval(&yyres, &yysrc);
+				if(yyres.type != NUM && yyres.type != BOOLVAL) yyres.val = 0.0;
+				}
+			else yyres.val = 1.0;
+			if(yyres.val != 0.0) {
+				if(block2 && block2[0]) {
+					yysrc.text = block2;
+					eval(&yyres, &yysrc);
+					}
+				yysrc.text = bb3;
+				eval(&yyres, &yysrc);
+				}
+			else break;		
+			}
+		if(i) last_error = 0L;
+		}
+	//test for syntax 2
+	else if(!bb2) {
+		buff_pos = 0;
+		if (VAR == yylex() && (var = curr_sym) && INARR == yylex() && buffer[buff_pos]){
+			yysrc.text = buffer + buff_pos;
+			eval(&yyres, &yysrc);
+			a_count = yyres.a_count;
+			a_data = yyres.a_data;
+			for(i = 0; i < a_count && i < yy_maxiter; i++) {
+				var->SetValue(a_data[i]);
+				if(block2 && block2[0]) {
+					yysrc.text = block2;
+					eval(&yyres, &yysrc);
+					}
+				}
+			last_error = 0;
+			}
+		else yyerror("parse error");
+		}
+	else yyerror("parse error");
+	if(bb1) free(bb1);	if(bb2) free(bb2);	if(bb3) free(bb3);
+	buffer = last_buffer;		buff_pos = last_buff_pos;
+	parse_level--;
+	return 0.0;
+}
+
+static int yylex()
 {
 	int i, c, tok;
 	unsigned int h_nam, h2_nam;
 	char tmp_txt[80], *block;
 	symrec *s;
 
+	memset(&yylval, 0, sizeof(YYSTYPE));
 	while((c = buffer[buff_pos++]) == ' ' || c == '\t');	//get first nonwhite char
 	if(!c) return 0;
+	//test for implicit block statement
+	if(syntax_level && (syntax_level->last_tok == PBLOCK 
+		|| syntax_level->last_tok == ELSE || syntax_level->last_tok == RETURN) && c != '{'){
+		buff_pos--;
+		if(block = copy_block()) {
+			yylval.text = PushString(block);
+			free(block);
+			}
+		syntax_level->last_tok = 0;
+		return yylval.type = IBLOCK;
+		}
 	//test for block statement
 	if(c == '{') {
 		if(block = copy_block()) {
 			yylval.text = PushString(block);
 			free(block);
 			}
+		syntax_level->last_tok = 0;
 		return yylval.type = BLOCK;
 		}
 	//test for '..' operator
@@ -2108,14 +2352,30 @@ static int yylex (void)
 				}
 			}
 		tmp_txt[i] = 0;
+#ifdef USE_WIN_SECURE
+		sscanf_s(tmp_txt, "%lf", &yylval.val);
+#else
 		sscanf(tmp_txt, "%lf", &yylval.val);
+#endif
 		return yylval.type = NUM;
 		}
 	//test for name or stringtoken
-	if(c > 31 && (isalpha(c) || c=='$')) {
- 		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$')); buff_pos++) {
+	if(c > 31 && (isalpha(c) || c=='$' || c =='_')) {
+ 		for(buff_pos--, i = 0; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$' || c == '_')); buff_pos++) {
 			tmp_txt[i++] = (char)c; 
 			}
+		while(buffer[buff_pos] == ' ' || buffer[buff_pos] == '\t') buff_pos++;
+		if(buffer[buff_pos] == ':' && !(syntax_level && syntax_level->last_tok == '?')){
+			tmp_txt[i++] = buffer[buff_pos++];
+			for(; i < 79 && ((c = buffer[buff_pos]) && c > 31 && (isalnum(c) || c == '$')); buff_pos++) {
+				tmp_txt[i++] = (char)c; 
+				}
+			tmp_txt[i] = 0;
+			yylval.text = PushString(tmp_txt);
+			range_array(&yylval, yylval.text);
+			yylval.val = 0.0;
+			return yylval.type = RANGEARR;
+			}
 		tmp_txt[i] = 0;
 		h_nam = HashValue((unsigned char*)tmp_txt);
 		h2_nam = Hash2((unsigned char*)tmp_txt);
@@ -2127,8 +2387,7 @@ static int yylex (void)
 		if(!(s = getsym(h_nam, h2_nam, tmp_txt))){
 			s = putsym(h_nam, h2_nam, VAR);
 			s->SetName(tmp_txt);
-			}
-		
+			}	
 		curr_sym = yylval.tptr = s;	return s->type;
 		}
 	//test for string
@@ -2174,33 +2433,45 @@ static int yylex (void)
 		pop_syntax();
 		break;
 	case '(':
-		if(syntax_level->last_tok == WHILE){
+		if(syntax_level->last_tok == WHILE || syntax_level->last_tok == FOR
+			|| syntax_level->last_tok == IF){
 			if(block = copy_block()) {
 				yylval.text = PushString(block);
 				free(block);
 				}
-			return yylval.type = PBLOCK;
+			return yylval.type = syntax_level->last_tok = PBLOCK;
 			}
 		push_syntax();
+		if(syntax_level) syntax_level->last_tok = c;
+		break;
 	case '?':
 		if(syntax_level) syntax_level->last_tok = c;
 		break;
 	case ':':
 		if(syntax_level) {
-			if(syntax_level->last_tok == '(') return COLR;
-			else if(syntax_level->last_tok == '?') return COLC;
+			if(syntax_level->last_tok == '?') return COLC;
 			}
 		break;
 	case ';':
+		if(buff_pos <2)return yylex();
 		if(syntax_level) {
 			if(syntax_level->last_tok == '(') return PSEP;
+			else syntax_level->last_tok = 0;
 			}
 		break;
+	case '*':
+		if(buffer[buff_pos] == '=') tok = MULEQ;
+		break;
+	case '/':
+		if(buffer[buff_pos] == '=') tok = DIVEQ;
+		break;
 	case '+':
 		if(buffer[buff_pos] == '+') tok = INC;
+		else if(buffer[buff_pos] == '=') tok = ADDEQ;
 		break;
 	case '-':
 		if(buffer[buff_pos] == '-') tok = DEC;
+		else if(buffer[buff_pos] == '=') tok = SUBEQ;
 		break;
 		}
 	if(tok) {
@@ -2224,7 +2495,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	symrec *sx, *sy;
 	lfPOINT *new_points;
 	long npoints = 0;
-	int length, res_mode = 0;
+	int length, parse_res, res_mode = 0;
 
 	if(x1 < x2) step = fabs(step);
 	else step = -fabs(step);
@@ -2239,11 +2510,10 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 			pop_parser();
 			return false;
 			}
-		strcpy(buffer, param);	buffer[length++] = ';';
+		rlp_strcpy(buffer, length+1, param);
+		buffer[length++] = ';';
 		buffer[length] = 0;	buff_pos = 0;
-		do {
-			yyparse();
-			}while(buff_pos < length);
+		while(!(parse_res = yyparse()) && buff_pos < length);
 		free(buffer);		buffer = 0L;
 		}		
 	length = (int)strlen(expr);
@@ -2251,9 +2521,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	for(x = x1; step > 0.0 ? x <= x2 : x >= x2; x += step) {
 		if(sx){
 			sx->SetValue(x);	buff_pos = 0;
-			do {
-				yyparse();
-				}while(buff_pos < length);
+			while(!(parse_res = yyparse()) && buff_pos < length);
 			switch (res_mode) {
 			case 1:
 				y = sy->GetValue();	break;
@@ -2275,9 +2543,9 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	*pts = new_points;	*npts = npoints;
 	clear_table();
 	pop_parser();
-	if(curr_data) {
-		curr_data->Command(CMD_CLEAR_ERROR, 0L, 0L);
-		curr_data->Command(CMD_REDRAW, 0L, 0L);
+	if(d) {
+		d->Command(CMD_CLEAR_ERROR, 0L, 0L);
+		d->Command(CMD_REDRAW, 0L, 0L);
 		}
 	return true;
 }
@@ -2285,7 +2553,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double z2, double zstep, 
 	char *expr, char *param)
 {
-	int length, nr, nc, r, c, res_mode=0;
+	int length, parse_res, nr, nc, r, c, res_mode=0;
 	symrec *sx, *sz, *sy;
 	double x, y, z;
 
@@ -2298,11 +2566,10 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 			pop_parser();
 			return false;
 			}
-		strcpy(buffer, param);	buffer[length++] = ';';
+		rlp_strcpy(buffer, length+1, param);
+		buffer[length++] = ';';
 		buffer[length] = 0;	buff_pos = 0;
-		do {
-			yyparse();
-			}while(buff_pos < length);
+		while(!(parse_res = yyparse()) && buff_pos < length);
 		free(buffer);		buffer = 0L;
 		}		
 	length = (int)strlen(expr);		buffer = expr;
@@ -2312,9 +2579,7 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 	for(r = 0, x = x1; r < nr; r++, x += xstep) {
 		for(c = 0, z = z1; c < nc; c++, z+= zstep) {
 			sx->SetValue(x);	sz->SetValue(z);	buff_pos = 0;
-			do {
-				yyparse();
-				}while(buff_pos < length);
+			while(!(parse_res = yyparse()) && buff_pos < length);
 			switch (res_mode) {
 			case 1:
 				y = sy->GetValue();	break;
@@ -2339,13 +2604,15 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 
 anyResult *do_formula(DataObj *d, char *expr)
 {
-	int length;
+	int length, parse_res;
 	static anyResult ret, *pret = 0L;
 
 	if(d) curr_data = d;
 	ret.type = ET_ERROR;		ret.text = 0L;
+	ret.a_data = 0L;		ret.a_count = 0;
 	if(!expr || !expr[0]) {
 		if(!sym_table) InitArithFuncs(0L);
+		last_error = 0L;
 		return &ret;
 		}
 	push_parser();		//make code reentrant
@@ -2354,14 +2621,13 @@ anyResult *do_formula(DataObj *d, char *expr)
 		pop_parser();
 		return &ret;
 		}
-	strcpy(buffer, expr);	if(buffer[length-1] != ';') buffer[length++] = ';';
+	rlp_strcpy(buffer, length+1, expr);
+	if(buffer[length-1] != ';') buffer[length++] = ';';
 	buffer[length] = 0;	buff_pos = 0;
-	do {
-		yyparse();
-		}while(buff_pos < length);
+	while(!(parse_res= yyparse()) && buff_pos < length);
 	ret.type = ET_ERROR;		ret.text = 0L;
-	if(curr_data && last_error) {
-		if(!(strcmp(last_error, "parse error"))) curr_data->Command(CMD_ERROR, 0L, 0L);
+	if(parse_res == 1 && curr_data) {
+		if(last_error && (!(strcmp(last_error, "parse error")))) curr_data->Command(CMD_ERROR, 0L, 0L);
 		if(last_err_desc) pret = &line_res;
 		else pret = &ret;
 		}
@@ -2373,7 +2639,7 @@ anyResult *do_formula(DataObj *d, char *expr)
 	return pret;
 }
 
-bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
+bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int r0, int c0)
 {
 	int length, length2, tok, pos, i;
 	char *res, desc1[2], desc2[2];
@@ -2386,7 +2652,7 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 		pop_parser();
 		return false;
 		}
-	strcpy(buffer, of);	buffer[length++] = ';';
+	rlp_strcpy(buffer, length+1, of);	buffer[length++] = ';';
 	buffer[length] = 0;	buff_pos = pos = 0;
 	if(!(res = (char *)calloc(length2 = (length*2+10), sizeof(char))))return false;
 	length2--;
@@ -2409,7 +2675,7 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 			case YYFNC2:	case YYFNC3:
 				pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
 				break;
-			case COLR:			case COLC:
+			case COLC:
 				res[pos++] = ':';
 				break;
 			case PSEP:
@@ -2441,7 +2707,9 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 				else pos += rlp_strcpy(res+pos, length2-pos, curr_sym->name);
 				break;
 			case STR:
-				pos += sprintf(res+pos, "\"%s\"", yylval.text && yylval.text[0] ? yylval.text : "");
+				pos += rlp_strcpy(res+pos, length2-pos, "\"");
+				pos += rlp_strcpy(res+pos, length2-pos, yylval.text);
+				pos += rlp_strcpy(res+pos, length2-pos, "\"");
 				break;
 			case SER:
 				res[pos++] = '.';	res[pos++] = '.';
@@ -2491,31 +2759,67 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 			case IF: 
 				res[pos++] = 'i';	res[pos++] = 'f';
 				break;
+			case ADDEQ: 
+				res[pos++] = '+';	res[pos++] = '=';
+				break;
+			case SUBEQ: 
+				res[pos++] = '-';	res[pos++] = '=';
+				break;
+			case MULEQ: 
+				res[pos++] = '*';	res[pos++] = '=';
+				break;
+			case DIVEQ: 
+				res[pos++] = '/';	res[pos++] = '=';
+				break;
 			case WHILE: 
 				pos += rlp_strcpy(res+pos, length2-pos, "while");
 				break;
+			case FOR: 
+				pos += rlp_strcpy(res+pos, length2-pos, "for");
+				break;
+			case INARR: 
+				pos += rlp_strcpy(res+pos, length2-pos, "in");
+				break;
 			case ELSE: 
 				pos += rlp_strcpy(res+pos, length2-pos, "else");
 				break;
+			case RETURN:
+				pos += rlp_strcpy(res+pos, length2-pos, " return");
+				break;
+			case BREAK:
+				pos += rlp_strcpy(res+pos, length2-pos, " break");
+				break;
+			case RANGEARR:
+				for(i = 0; yylval.text[i]; i++) if(yylval.text[i] == ':') {
+					yylval.text[i] = ';';	break;
+					}
+				MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
+				while(res[pos]) {
+					pos++;			if(res[pos] == ';') res[pos] = ':';
+					}
+				break;
 			case BLOCK:
-#ifdef USE_WIN_SECURE
-				pos += sprintf_s(res+pos, TMP_TXT_SIZE-pos, "{%s}", yylval.text && yylval.text[0] ? yylval.text : "");
-#else
-				pos += sprintf(res+pos, "{%s}", yylval.text && yylval.text[0] ? yylval.text : "");
-#endif
+				res[pos++] = '{';
+				MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
+				pos += (int)strlen(res+pos);
+				res[pos++] = '}';
+				break;
+			case IBLOCK:
+				MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
+				pos += (int)strlen(res+pos);
+				res[pos++] = ';';
 				break;
 			case PBLOCK:
-#ifdef USE_WIN_SECURE
-				pos += sprintf_s(res+pos, TMP_TXT_SIZE-pos, "(%s)", yylval.text && yylval.text[0] ? yylval.text : "");
-#else
-				pos += sprintf(res+pos, "(%s)", yylval.text && yylval.text[0] ? yylval.text : "");
-#endif
+				res[pos++] = '(';
+				MoveFormula(d, yylval.text, res+pos, nfsize-pos-2, dx, dy, r0, c0);
+				pos += (int)strlen(res+pos);
+				res[pos++] = ')';
 				break;
 			}
 		res[pos] = 0;
 		}while(buff_pos < length);
 	while((res[pos-1] == ';' || res[pos-1] == ' ') && pos > 0) { res[pos-1] = 0; pos--;} 
-	strcpy(nf, res);	free(res);
+	rlp_strcpy(nf, nfsize, res);	free(res);
 	free(buffer);		buffer = 0L;
 	clear_table();
 	pop_parser();
@@ -2526,7 +2830,7 @@ static char *txt_formula;	//function to fit
 static double **parval;		//pointers to parameter values
 static void fcurve(double x, double z, double **a, double *y, double dyda[], int ma)
 {
-	int i, length;
+	int i, length, parse_res;
 	double tmp, y1, y2;
 	symrec *symx, *symz, *sy=0L;
 
@@ -2540,7 +2844,7 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
 	symx->SetValue(x);	symz->SetValue(z);	
 	buffer = txt_formula;
 	buff_pos = 0;		length = (int)strlen(txt_formula);
-	do {	yyparse();	}while(buff_pos < length);
+	while(!(parse_res = yyparse()) && buff_pos < length);
 	if(sy = getsym(hn_y, h2_y)) *y = sy->GetValue();
 	else *y = line_res.value;
 	if(*y == HUGE_VAL || *y == -HUGE_VAL) {
@@ -2553,11 +2857,11 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
 			tmp = *parval[i];
 			*parval[i] = tmp*.995;
 			buff_pos = 0;
-			do {	yyparse();	}while(buff_pos < length);
+			while(!(parse_res = yyparse()) && buff_pos < length);
 			y1 = sy ? sy->GetValue() : line_res.value;
 			*parval[i] = tmp*1.005;
 			buff_pos = 0;
-			do {	yyparse();	}while(buff_pos < length);
+			while(!(parse_res = yyparse()) && buff_pos < length);
 			y2 = sy ? sy->GetValue() : line_res.value;
 			*parval[i] = tmp;
 			dyda[i] = (y2-y1)*100.0/tmp;
@@ -2572,7 +2876,8 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
 
 int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr, double conv, int maxiter, double *chi_2)
 {
-	int length, i, j, k, l, ndata, nparam, r1, r2, r3, c1, c2, c3, *lista, itst, itst1;
+	int length, i, j, k, l, ndata, nparam, r1, r2, r3, c1, c2, c3;
+	int *lista, itst, itst1, parse_res;
 	symrec *tab1, *tab2, *csr, **parsym;
 	AccRange *arx, *ary, *arz;
 	double *x, *y, *z, currx, curry, currz, alamda, chisq, ochisq;
@@ -2632,12 +2937,10 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 		free(y);	free(x);	delete arx;	delete ary;
 		return 0;
 		}
-	strcpy(buffer, *par);	buffer[length++] = ';';
+	rlp_strcpy(buffer, length, *par);	buffer[length++] = ';';
 	buffer[length] = 0;	buff_pos = 0;
 	tab1 = sym_table;
-	do {
-		yyparse();
-		}while(buff_pos < length);
+	while(!(parse_res = yyparse()) && buff_pos < length);
 	tab2 = sym_table;	free(buffer);	buffer =0L;
 	for(nparam = 0, csr=tab2; csr != tab1; nparam++, csr = csr->next);
 	parsym = (symrec**)malloc((nparam+1)*sizeof(symrec*));
@@ -2667,10 +2970,18 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 		if(k > 20) {
 			if(tmp_txt[j-1] == ' ') j--;
 			if(tmp_txt[j-1] == ';') j--;
+#ifdef USE_WIN_SECURE
+			l = sprintf_s(tmp_txt+j, 500-j, "\n");
+#else
 			l = sprintf(tmp_txt+j, "\n");
+#endif
 			j += l;		k = 0;
 			}
+#ifdef USE_WIN_SECURE
+		l += sprintf_s(tmp_txt+j, 500-j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue());
+#else
 		l += sprintf(tmp_txt+j, "%s%s=%g;", j && k ? " " : "", parsym[i]->name, parsym[i]->GetValue());
+#endif
 		j += l;			k += l;
 		}
 	free(*par);
@@ -2678,9 +2989,7 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 	if(chi_2) *chi_2 = chisq;
 	//write back spreadsheet data if necessary
 	buffer = *par;	length = (int)strlen(buffer);
-	do {
-		yyparse();
-		}while(buff_pos < length);
+	while(!(parse_res = yyparse()) && buff_pos < length);
 	buffer = 0L;
 	free_dmatrix(alpha, 1, nparam, 1, nparam);
 	free_dmatrix(covar, 1, nparam, 1, nparam);
@@ -2689,10 +2998,12 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 	if(parval) free(parval);	if(parsym) free(parsym);
 	clear_table();
 	pop_parser();
-	if(curr_data){
-		curr_data->Command(CMD_CLEAR_ERROR, 0L, 0L);
-		curr_data->Command(CMD_REDRAW, 0L, 0L);
+	if(d){
+		d->Command(CMD_CLEAR_ERROR, 0L, 0L);
+		d->Command(CMD_REDRAW, 0L, 0L);
 		}
 	return itst < maxiter ? itst+1 : maxiter;
 }
 
+
+
diff --git a/no_gui.cpp b/no_gui.cpp
index eee8d1d..2195534 100755
--- a/no_gui.cpp
+++ b/no_gui.cpp
@@ -1,4 +1,4 @@
-//no_gui.cpp, Copyright 2000-2006 R.Lackner
+//no_gui.cpp, Copyright 2000-2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -420,6 +420,16 @@ bool FitFunc::PropertyDlg()
 	return false;
 }
 
+bool NormQuant::PropertyDlg()
+{
+	return false;
+}
+
+bool Plot3D::AddAxis()
+{
+	return false;
+}
+
 bool Plot3D::PropertyDlg()
 {
 	return false;
@@ -465,6 +475,11 @@ bool Tick::PropertyDlg()
 	return false;
 }
 
+void
+Axis::DoMark(anyOutput *o, bool mark)
+{
+}
+
 bool Axis::PropertyDlg()
 {
 	return false;
@@ -538,6 +553,16 @@ void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color)
 	return;
 }
 
+void InvalidateOutput(anyOutput *o)
+{
+	return;
+}
+
+void SuspendAnimation(anyOutput *o, bool bSusp)
+{
+	return;
+}
+
 anyOutput *NewDispClass(GraphObj *g)
 {
 	return 0L;
diff --git a/reports.cpp b/reports.cpp
index ab73a4d..42e8b9c 100755
--- a/reports.cpp
+++ b/reports.cpp
@@ -1,4 +1,4 @@
-//reports.cpp, Copyright (c) 2006 R.Lackner
+//reports.cpp, Copyright (c) 2006, 2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -48,7 +48,7 @@ static char SymLineStr[40];
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 static void rep_init()
 {
-	curr_id = 1;
+	curr_id = 1;		defs.cUnits = defs.dUnits;
 	txtdef1.ColTxt = txtdef2.ColTxt = 0x0L;
 	txtdef1.ColBg = txtdef2.ColBg = 0x00ffffffL;
 	txtdef1.fSize = defs.GetSize(SIZE_TEXT);
@@ -99,6 +99,40 @@ static char* mk_label(double x, double y, bool moveable, int align, TextDEF *td,
 	add_to_buff(&res, &pos, &csize, "\"\n", 2);
 	return res;
 }
+static void rep_DrawText(GraphObj *parent, double x, double y, bool moveable, int align, TextDEF *td, char*text)
+{
+	char *txt_obj;
+
+	if(txt_obj = mk_label(x, y,	false, align, td, text)) {
+		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
+		free(txt_obj);
+		}
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// draw a rectangle
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char* mk_rect(double x1, double y1, double x2, double y2, DWORD lcol, DWORD fcol)
+{
+	int csize, pos = 0;
+	char *res;
+
+	if(!(res = (char*)malloc(csize = 1000)))return 0L;
+	res[pos++] = '\n';				res[pos++] = '[';
+	add_int_to_buff(&res, &pos, &csize, curr_id++, false, 0);
+	add_to_buff(&res, &pos, &csize, "=rectangle]\np1=", 0);
+	add_dbl_to_buff(&res, &pos, &csize, x1, true);
+	add_dbl_to_buff(&res, &pos, &csize, y1, true);
+	add_to_buff(&res, &pos, &csize, "\np2=", 0);
+	add_dbl_to_buff(&res, &pos, &csize, x2, true);
+	add_dbl_to_buff(&res, &pos, &csize, y2, true);
+	add_to_buff(&res, &pos, &csize, "\nLine= 0 1", 0);
+	add_hex_to_buff(&res, &pos, &csize, lcol, true);
+	add_to_buff(&res, &pos, &csize, " 0x0\nFillLine= 0 1 0x0 0x0\nFill= 0", 0);
+	add_hex_to_buff(&res, &pos, &csize, fcol, true);
+	add_to_buff(&res, &pos, &csize, " 1 0x0 0x00ffffff\n", 0);
+	return res;
+}
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // print values to string
@@ -127,35 +161,25 @@ static int dbl_to_str2(char *dest, int size, char* fmt, double val1, double val2
 static void mk_header(Page *page, char* desc)
 {
 	time_t ti = time(0L);
-	char *txt_obj, label[80];
+	char label[80];
 	double rpos;
 	int cb;
 
 	if(!page) return;
 	rpos = page->GetSize(SIZE_GRECT_RIGHT) - txtdef1.fSize*5.0;
-	if(txt_obj = mk_label(txtdef1.fSize*5.0, page->GetSize(SIZE_GRECT_TOP)+txtdef2.fSize*6.0,
-		false, TXA_HLEFT, &txtdef2, desc)) {
-		OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(page, txtdef1.fSize*5.0, page->GetSize(SIZE_GRECT_TOP)+txtdef2.fSize*6.0,
+		false, TXA_HLEFT, &txtdef2, desc); 
 #ifdef USE_WIN_SECURE
 	ctime_s(label, 32, &ti);
 #else
 	rlp_strcpy(label, 25, ctime(&ti));
 #endif
 	label[24] = 0;
-	if(txt_obj = mk_label(rpos, page->GetSize(SIZE_GRECT_TOP)+txtdef1.fSize*5.0,
-		false, TXA_HRIGHT, &txtdef1, label)) {
-		OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
-	cb = rlp_strcpy(label, 80, "RLPlot ");
-	cb += rlp_strcpy(label+cb, 80-cb, SZ_VERSION);
-	if(txt_obj = mk_label(rpos, page->GetSize(SIZE_GRECT_BOTTOM)-txtdef1.fSize*6.0,
-		false, TXA_HRIGHT, &txtdef1, label)) {
-		OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(page, rpos, page->GetSize(SIZE_GRECT_TOP)+txtdef1.fSize*5.0,
+		false, TXA_HRIGHT, &txtdef1, label);
+	cb = rlp_strcpy(label, 80, "RLPlot ");		cb += rlp_strcpy(label+cb, 80-cb, SZ_VERSION);
+	rep_DrawText(page, rpos, page->GetSize(SIZE_GRECT_BOTTOM)-txtdef1.fSize*6.0,
+		false, TXA_HRIGHT, &txtdef1, label);
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -189,17 +213,16 @@ static double mk_mean_report(GraphObj *parent, double x, double y, double *da, i
 {
 	static char *mean_fmts[] = {"Mean = %g", "Std.Dev. = %g", "N = %g", "Std.Err. = %g", 0L,
 		"Kurtosis = %g", "Skewness = %g"};
-	char *txt_obj, desc[80];
+	char desc[80];
 	int i, cb;
 	double v, t, res[10];
 
-	cb = rlp_strcpy(desc, 20, "<b>");				cb += rlp_strcpy(desc+cb, 20-cb, name);
-	cb += rlp_strcpy(desc+cb, 20-cb, ":</b>");
-	if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, desc)) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);								y += linsp1;
+	if(name && name[0]) {
+		cb = rlp_strcpy(desc, 40, "<b>");			cb += rlp_strcpy(desc+cb, 40-cb, name);
+		cb += rlp_strcpy(desc+cb, 40-cb, ":</b>");
+		rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
+		y += linsp1;		x += (txtdef1.fSize*3.0);
 		}
-	x += (txtdef1.fSize*3.0);
 	cb = dbl_to_str1(desc, 80, "%g%%%% C.I. = %%g", ci*100.0);
 	mean_fmts[4] = (char*)malloc(cb+2);
 	rlp_strcpy(mean_fmts[4], cb+1, desc);			t = distinv(t_dist, n-1, 1, 1.0-ci, 2.0);
@@ -209,11 +232,8 @@ static double mk_mean_report(GraphObj *parent, double x, double y, double *da, i
 	res[6] = d_skew(n, da);
 	for(i = 0; i < 7; i++) {
 		dbl_to_str1(desc, 80, mean_fmts[i], res[i]);
-		if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, desc)) {
-			OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-			free(txt_obj);							y += linsp1/1.2;
-			}
-		if(i == 2) y += linsp1/3.6;
+		rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
+		y += (i==2 ? linsp1/0.9 : linsp1/1.2);
 		}
 	free(mean_fmts[4]);								mean_fmts[4] = 0L;
 	return y;
@@ -225,18 +245,17 @@ static double mk_mean_report(GraphObj *parent, double x, double y, double *da, i
 static double mk_median_report(GraphObj *parent, double x, double y, double *da, int n, double ci, char *name)
 {
 	static char *mean_fmts[] = {"Median = %g", "25%% = %g", "75%% = %g", "N = %g", "Min. = %g", "Max. = %g" };
-	char *txt_obj, desc[80];
+	char desc[80];
 	int i, cb;
 	double res[6];
 
 	if(!da || !parent || !n) return y;
-	cb = rlp_strcpy(desc, 20, "<b>");				cb += rlp_strcpy(desc+cb, 20-cb, name);
-	cb += rlp_strcpy(desc+cb, 20-cb, ":</b>");
-	if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, desc)) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);								y += linsp1;
+	if(name && name[0]) {
+		cb = rlp_strcpy(desc, 40, "<b>");			cb += rlp_strcpy(desc+cb, 40-cb, name);
+		cb += rlp_strcpy(desc+cb, 40-cb, ":</b>");
+		rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
+		y += linsp1; x += (txtdef1.fSize*3.0);
 		}
-	x += (txtdef1.fSize*3.0);
 	d_quartile(n, da, &res[1], &res[0], &res[2]);
 	res[4] = res[5] = *da;
 	for(i = 1; i < n; i++) {
@@ -245,10 +264,8 @@ static double mk_median_report(GraphObj *parent, double x, double y, double *da,
 	res[3] = (double)n;
 	for(i = 0; i < 6; i++) {
 		dbl_to_str1(desc, 80, mean_fmts[i], res[i]);
-		if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, desc)) {
-			OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-			free(txt_obj);							y += linsp1/1.2;
-			}
+		rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, desc);
+		y += linsp1/1.2;
 		}
 	return y;
 }
@@ -264,7 +281,6 @@ static void mk_table(GraphObj *parent, double x, double y, int type, double **dd
 	char *cfmt[8];
 	int i, j, nl, nc[8];
 	double posc[8], cinc;
-	char *txt_obj;
 
 #ifdef _WINDOWS
 	cinc = txtdef1.fSize;
@@ -284,42 +300,27 @@ static void mk_table(GraphObj *parent, double x, double y, int type, double **dd
 	default: return;
 		}
 	if(type == 1 || type == 2) {
-		if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, rheaders[0])) {
-			OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-			free(txt_obj);
-			}
+		rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, rheaders[0]);
 		for(i = 0; i < 5; i++) {
-			if(txt_obj = mk_label(posc[i], y, false, TXA_HRIGHT, &txtdef1, cheaders[i])) {
-				OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-				free(txt_obj);
-				}
+			rep_DrawText(parent, posc[i], y, false, TXA_HRIGHT, &txtdef1, cheaders[i]);
 			if(i) posc[i] += linsp1;
 			}
-		mk_hr(parent, x, posc[4], y + linsp1);
-		y += linsp2;
+		mk_hr(parent, x, posc[4], y + linsp1);			y += linsp2;
 		}
 	for(i = 0; i < nl; i++) {
-		if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, rheaders[i+1])) {
-			OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-			free(txt_obj);
-			}
+		rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, rheaders[i+1]);
 		for(j = 0; j < nc[i]; j++) {
-			if(j == 4 && dda[i][j] > 0.0 && dda[i][j] < 0.0001)
-				rlp_strcpy(TmpTxt, 10, "< 0.0001");
+			if(j == 4 && dda[i][j] > 0.0 && dda[i][j] < 0.0001) rlp_strcpy(TmpTxt, 10, "< 0.0001");
 #ifdef USE_WIN_SECURE
 			else sprintf_s(TmpTxt, 20, cfmt[j], dda[i][j]);
 #else
 			else sprintf(TmpTxt, cfmt[j], dda[i][j]);
 #endif
-			if(txt_obj = mk_label(posc[j], y, false, TXA_HRIGHT, &txtdef1, TmpTxt)) {
-				OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-				free(txt_obj);
-				}
+			rep_DrawText(parent, posc[j], y, false, TXA_HRIGHT, &txtdef1, TmpTxt);
 			}
 		if(i < (nl-2)) y += linsp1;
 		else {
-			mk_hr(parent, x, posc[4], y + linsp1);
-			y += linsp2;
+			mk_hr(parent, x, posc[4], y + linsp1);		y += linsp2;
 			}
 		}
 }
@@ -346,8 +347,7 @@ static char* mk_boxplot(double *x, double *y, double *by1, double *by2, double *
 		add_to_buff(&res, &pos, &csize,"\nLow=", 5);
 		add_dbl_to_buff(&res, &pos, &csize, x ? x[i] : (double)(i+1), true);
 		add_dbl_to_buff(&res, &pos, &csize, by1[i], true);
-		add_to_buff(&res, &pos, &csize,"\nSize= 60\n", 10);
-		add_to_buff(&res, &pos, &csize, "\nName= \"", 8);
+		add_to_buff(&res, &pos, &csize,"\nSize= 60\nName= \"", 17);
 		add_to_buff(&res, &pos, &csize, b_nam, 0);
 		add_to_buff(&res, &pos, &csize, "\"\n", 2);
 		}
@@ -409,21 +409,21 @@ static char* mk_boxplot(double *x, double *y, double *by1, double *by2, double *
 		add_int_to_buff(&res,&pos,&csize, first_b, false, 0);	add_to_buff(&res,&pos,&csize, ",", 1);
 		if(i && (i%16)== 0 && first_b < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n   ", 4);
 		}
-	while(res[pos-1] == ',' || res[pos-1] < 33) pos --;		add_to_buff(&res, &pos, &csize, "}\n", 2);
+	while(res[pos-1] == ',' || res[pos-1] < 33) pos --;		add_to_buff(&res, &pos, &csize, "}", 2);
 	add_to_buff(&res,&pos,&csize, "\nWhiskers=(", 0);		add_int_to_buff(&res,&pos,&csize, n, false, 0);
 	add_to_buff(&res,&pos,&csize, "){", 2);
 	for(i = 0; i < n; i++, first_w++) {
 		add_int_to_buff(&res,&pos,&csize, first_w, false, 0);	add_to_buff(&res,&pos,&csize, ",", 1);
 		if(i && (i%16)== 0 && first_b < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n   ", 4);
 		}
-	while(res[pos-1] == ',' || res[pos-1] < 33) pos --;		add_to_buff(&res, &pos, &csize, "}\n", 2);
+	while(res[pos-1] == ',' || res[pos-1] < 33) pos --;		add_to_buff(&res, &pos, &csize, "}", 2);
 	add_to_buff(&res,&pos,&csize, "\nSymbols=(", 10);		add_int_to_buff(&res,&pos,&csize, n, false, 0);
 	add_to_buff(&res,&pos,&csize, "){", 2);
 	for(i = 0; i < n; i++, first_s++) {
 		add_int_to_buff(&res,&pos,&csize, first_s, false, 0);	add_to_buff(&res,&pos,&csize, ",", 1);
 		if(i && (i%16)== 0 && first_s < (curr_id-2)) add_to_buff(&res, &pos, &csize, "\n   ", 4);
 		}
-	while(res[pos-1] == ',' || res[pos-1] < 33) pos --;		add_to_buff(&res, &pos, &csize, "}\n", 2);
+	while(res[pos-1] == ',' || res[pos-1] < 33) pos --;		add_to_buff(&res, &pos, &csize, "}", 2);
 	add_to_buff(&res,&pos,&csize, "\nLabels=(", 9);			add_int_to_buff(&res,&pos,&csize, n, false, 0);
 	add_to_buff(&res,&pos,&csize, "){", 2);
 	for(i = 0; i < n; i++, first_l++) {
@@ -457,10 +457,6 @@ static char* mk_scatt(double *x, double *y, double *ss, int *ny, int n, char *s_
 		add_to_buff(&res, &pos, &csize, "\n", 1);
 		add_to_buff(&res, &pos, &csize, SymLineStr, cbSymLineStr);
 		add_to_buff(&res, &pos, &csize, "FillCol= 0x00ffffff\n", 20);
-		if(s_nam) {
-			add_to_buff(&res, &pos, &csize, "Name=\"", 6);
-			add_to_buff(&res, &pos, &csize, s_nam, 0);	add_to_buff(&res, &pos, &csize, "\"\n", 2);
-			}
 		}
 	if(ss && ny) {
 		for(i = 0; i < n && res; i++) {
@@ -531,57 +527,69 @@ static char* mk_scatt(double *x, double *y, double *ss, int *ny, int n, char *s_
 		add_to_buff(&res,&pos,&csize, "y_info= \"", 9);		add_to_buff(&res,&pos,&csize, y_desc, 0);
 		add_to_buff(&res,&pos,&csize, "\"\n", 2);
 		}
+	if(s_nam && s_nam[0]) {
+		add_to_buff(&res, &pos, &csize, "DataDesc=\"", 10);
+		add_to_buff(&res, &pos, &csize, s_nam, 0);			add_to_buff(&res, &pos, &csize, "\"\n", 2);
+		}
 	return res;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // one way anova
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-static char *AnovaDlg_Tmpl = 
-	"1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
-	"2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
-	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
-	"4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
-	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
-	"100,101,,,LTEXT,2,10,30,60,8\n"
-	"101,102,,,RANGEINPUT,-15,20,40,100,10\n"
-	"102,103,,CHECKED,RADIO1,3,10,55,60,9\n"
-	"103,,,LASTOBJ,RADIO1,4,10,65,60,9";
-void
-rep_anova(GraphObj *parent, DataObj *data)
+static char *AnovaDlg_Tmpl =
+	"1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
+	"3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"10,20,152,ISPARENT | CHECKED, SHEET,1,5,10,140,70\n"
+	"20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+	"152,153,,ISPARENT | CHECKED,GROUPBOX,2,12,30,128,45\n"
+	"153,154,,,LTEXT,0,25,35,60,8\n"
+	"154,155,,,RANGEINPUT,0,25,45,100,10\n"
+	"155,156,0,,PUSHBUTTON,-8,95,57,30,12\n"
+	"156,,,LASTOBJ,PUSHBUTTON,-9,60,57,35,12";
+
+void rep_anova(GraphObj *parent, DataObj *data)
 {
 	TabSHEET tab1 = {0, 45, 10, "Anova Input"};
 	DlgInfo *AnovaDlg;
-	void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables",
-		(void*)"variables arranged in columns", (void*)"    -\"-           -\"-      in rows"};
+	void *dyndata[] = {(void*)&tab1, (void*)" select one range for every variable "};
 	DlgRoot *Dlg;
 	void *hDlg;
 	double **cols = 0L, tmp, *csums=0L, mtot, *css=0L, ssa, ssw, sst;
 	double **res_tab = 0L;
-	int i, j, res, nr, nc, ntot, *ncols = 0L;;
-	bool bContinue = false;
+	int i, j, n, c, r, res, nc, ntot, currYR = 0, maxYR=0, ny, *ncols = 0L;;
+	bool bContinue = false, updateYR = true;
+	anyResult ares;
 	AccRange *rD =0L;
-	char *mrk, *txt_obj;
-	RECT rec;
+	char **rd = 0L, **names, *txt_obj;
 	Graph *graph;
 	Page *page;
 
 	if(!parent || !data) return;
+	if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+		TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return;
 	if(!(AnovaDlg = CompileDialog(AnovaDlg_Tmpl, dyndata))) return;
-	if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
-	else {
-		data->ValueRec(&rec);
-#ifdef USE_WIN_SECURE
-		i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s%d", Int2ColLabel(rec.left,false), rec.top + 1);
-		sprintf_s(TmpTxt+i, TMP_TXT_SIZE-i, ":%s%d", Int2ColLabel(rec.right, false), rec.bottom+1);
-#else
-		i = sprintf(TmpTxt,"%s%d", Int2ColLabel(rec.left,false), rec.top + 1);
-		sprintf(TmpTxt+i, ":%s%d", Int2ColLabel(rec.right, false), rec.bottom+1);
-#endif
+	if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+		for(i=j=0; i <= 1000; i +=100) if(TmpTxt[i]) 
+			rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);	 maxYR = j-1;
 		}
+	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return;
 	if(!(Dlg = new DlgRoot(AnovaDlg, data)))return;
-	hDlg = CreateDlgWnd("One Way Anova", 50, 50, 420, 220, Dlg, 0x0L);
+	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+	hDlg = CreateDlgWnd("Single-Classification Anova", 50, 50, 420, 200, Dlg, 0x0L);
 	do {
+		if(updateYR) {
+			if(currYR >0) Dlg->ShowItem(156, true);
+			else Dlg->ShowItem(156, false);
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "variable # %d/%d", currYR+1, maxYR+1);
+#else
+			sprintf(TmpTxt,"variable # %d/%d", currYR+1, maxYR+1);
+#endif
+			Dlg->SetText(153, TmpTxt);
+			updateYR = false;
+			}
 		LoopDlgWnd();
 		res = Dlg->GetResult();
 		switch (res) {
@@ -592,90 +600,422 @@ rep_anova(GraphObj *parent, DataObj *data)
 		case -1:
 			bContinue = false;
 			break;
+		case 155:		case 156:
+			res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
+				&rD, &bContinue, &ny, &maxYR, &updateYR);
+			break;
 			}
 		}while (res < 0);
-	if(res == 1 && Dlg->GetText(101, TmpTxt, TMP_TXT_SIZE) &&(rD = new AccRange(TmpTxt))
-		&& rD->BoundRec(&rec) && (res_tab = (double**)calloc(3, sizeof(double*)))
+	if(res == 1 && (res_tab = (double**)calloc(3, sizeof(double*)))
 		&& (res_tab[0] = (double*) malloc(5*sizeof(double)))
 		&& (res_tab[1] = (double*) malloc(5*sizeof(double)))
-		&& (res_tab[2] = (double*) malloc(5*sizeof(double)))) {
-		rep_init();
-		if(Dlg->GetCheck(102)) {
-			nr = rec.bottom - rec.top +1;		nc = rec.right - rec.left +1;
-			if((cols = (double**)malloc(nc * sizeof(double*))) && (ncols = (int*)malloc(nc * sizeof(int)))) {
-				for(i = rec.left; i <= rec.right; i++) {
-					ncols[i-rec.left] = 0;	cols[i-rec.left] = (double*)malloc(nr * sizeof(double));
-					if(cols[i-rec.left]) for(j = rec.top; j <= rec.bottom; j++) {
-						if(data->GetValue(j, i, &tmp)) cols[i-rec.left][ncols[i-rec.left]++] = tmp;
+		&& (res_tab[2] = (double*) malloc(5*sizeof(double)))
+		&& (cols = (double**)calloc(maxYR+1, sizeof(double*)))
+		&& (names = (char**)calloc(maxYR+1, sizeof(char*)))
+		&& (ncols = (int*)calloc(maxYR+1, sizeof(int)))
+		&& (csums = (double*)calloc(maxYR+1, sizeof(double)))
+		&& (css = (double*)calloc(maxYR+1, sizeof(double)))) {
+		rep_init();		if(rD) delete rD;		rD = 0L;
+		dBounds.Ymin = HUGE_VAL;		dBounds.Ymax = -HUGE_VAL;
+		// get data into two dimensional array
+		for(nc = maxYR+1, i = ntot = 0, mtot = 0.0; i < nc; i++) {
+			if((rD = new AccRange(rd[i])) && (n = rD->CountItems()) && (cols[i] = (double*)malloc(n*sizeof(double)))) {
+				names[i] = rD->RangeDesc(data, 1);
+				for(n = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
+					if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE) {
+						if(ares.value < dBounds.Ymin) dBounds.Ymin = ares.value;
+						if(ares.value > dBounds.Ymax) dBounds.Ymax = ares.value;
+						cols[i][n] = ares.value;		csums[i] += cols[i][n++];
 						}
 					}
+				ncols[i] = n;		ntot += n;		mtot += csums[i];
+				if(ncols[i]) csums[i] /= ((double)ncols[i]);
+				delete(rD);			rD = 0L;
+				}
+			if(!names[i] && (names[i] = (char*)malloc(20*sizeof(char)))){
+#ifdef USE_WIN_SECURE
+				sprintf_s(names[i], 20, "Group %d", i+1);
+#else
+				sprintf(names[i], "Group %d", i+1);
+#endif
 				}
 			}
-		else {
-			nr = rec.right - rec.left +1;		nc = rec.bottom - rec.top +1;
-			if((cols = (double**)malloc(nc * sizeof(double*))) && (ncols = (int*)malloc(nc * sizeof(int)))) {
-				for(i = rec.top; i <= rec.bottom; i++) {
-					ncols[i-rec.top] = 0;	cols[i-rec.top] = (double*)malloc(nr * sizeof(double));
-					if(cols[i-rec.top]) for(j = rec.left; j <= rec.right; j++) {
-						if(data->GetValue(i, j, &tmp)) cols[i-rec.top][ncols[i-rec.top]++] = tmp;
-						}
+		// check for unique names
+		for(i = 0; i < (nc-1); i++) for(j = i+1; j < nc; j++) {
+			if(!strcmp(names[i], names[j])) {
+				names[i] = (char*) realloc(names[i], 20 *sizeof(char));
+				names[j] = (char*) realloc(names[j], 20 *sizeof(char));
+#ifdef USE_WIN_SECURE
+				sprintf_s(names[i], 20, "Group %d", i+1);	sprintf_s(names[j], 20, "Group %d", j+1);
+#else
+				sprintf(names[i], "Group %d", i+1);			sprintf(names[j], "Group %d", j+1);
+#endif
+				}
+			}
+		dBounds.Xmin = 0.5;				dBounds.Xmax = ((double)nc)+0.5;
+		if(ntot) mtot /= ((double)ntot);
+		for(i = 0; i < nc; i++) {
+			for(j = 0, css[i] = 0.0; j < ncols[i]; j++) {
+				tmp = cols[i][j] - csums[i];	css[i] += (tmp*tmp);
+				}
+			}
+		for(i = 0, ssa = ssw = sst = 0.0;  i < nc; i++) {
+			tmp =(csums[i] - mtot);		ssa += (tmp*tmp) * ((double)ncols[i]);
+			ssw += css[i];
+			}
+		sst = ssa + ssw;
+		res_tab[0][0] = nc - 1;				res_tab[1][0] = ntot - nc;
+		res_tab[2][0] = ntot -1;			res_tab[0][1] = ssa;
+		res_tab[1][1] = ssw;				res_tab[2][1] = sst;
+		res_tab[0][2] = ssa/res_tab[0][0];	res_tab[1][2] = ssw/res_tab[1][0];
+		res_tab[0][3] = res_tab[0][2]/res_tab[1][2];
+		res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[1][0]);
+		page = new Page(parent, data);
+		mk_header(page, "<b>Single-Classification ANOVA</b>");
+		if((graph = new Graph(parent, data, 0L)) && (txt_obj = mk_scatt(0L, csums, css, ncols, nc, "Mean", "Groups", "Means <u>+</u> S.D."))){
+			OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+			if(LastOpenGO && LastOpenGO->Id == GO_PLOTSCATT) {
+				if(((PlotScatt*)LastOpenGO)->x_tv = new TextValue()){
+					for(i = 0; i < nc; i++) ((PlotScatt*)LastOpenGO)->x_tv->GetValue(names[i]);
 					}
 				}
+			free(txt_obj);								graph->moveable = 0;
+			graph->GRect.Xmin += (txtdef1.fSize*5.0);	graph->GRect.Xmax += (txtdef1.fSize*5.0);
+			graph->GRect.Ymin += (txtdef1.fSize*10.0);	graph->GRect.Ymax += (txtdef1.fSize*10.0);
+			page->Command(CMD_DROP_GRAPH, graph, 0L);
+			}
+		mk_table(page, graph->GRect.Xmin, graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0, 1, res_tab);
+		parent->Command(CMD_DROP_GRAPH, page, 0L);
+		for(i = 0; i < nc; i++){
+			if(cols[i]) free(cols[i]);		if(names[i]) free(names[i]);
 			}
-		if(cols && nr >1 && nc >1 && (csums = (double*)malloc(nc *sizeof(double)))
-			&& (css = (double*)malloc(nc *sizeof(double)))) {
-			dBounds.Ymin = HUGE_VAL;		dBounds.Ymax = -HUGE_VAL;
-			for(i = ntot = 0, mtot = 0.0; i < nc; i++) {
-				for(j = 0, csums[i] = 0.0; j < ncols[i]; j++) {
-					csums[i] += cols[i][j];
-					if(dBounds.Ymin > cols[i][j]) dBounds.Ymin = cols[i][j];
-					if(dBounds.Ymax < cols[i][j]) dBounds.Ymax = cols[i][j];
+		for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
+		free(cols);			free(ncols);			free(names);
+		free(res_tab);		free(css);				free(csums);
+		}
+	if(rD) delete rD;		CloseDlgWnd(hDlg);
+	delete Dlg;				free(AnovaDlg);
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Kruskal-Wallis Test for Differences of Location
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *RepKruskal_DlgTmpl =
+	"1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
+	"3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"10,20,152,ISPARENT | CHECKED, SHEET,1,5,10,140,70\n"
+	"20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+	"152,153,,ISPARENT | CHECKED,GROUPBOX,2,12,30,128,45\n"
+	"153,154,,,LTEXT,0,25,35,60,8\n"
+	"154,155,,,RANGEINPUT,0,25,45,100,10\n"
+	"155,156,0,,PUSHBUTTON,-8,95,57,30,12\n"
+	"156,,,LASTOBJ,PUSHBUTTON,-9,60,57,35,12";
+
+void rep_kruskal(GraphObj *parent, DataObj *data)
+{
+	TabSHEET tab1 = {0, 25, 10, "Data"};
+	
+	void *dyndata[] = {(void*)&tab1, (void*)" select one range for every variable "};
+	DlgInfo *KruskalDlg;
+	DlgRoot *Dlg;
+	void *hDlg;
+	int i, j, n, c, r, nt, res, currYR = 0, maxYR = 0, ny, nr, *nvals;
+	bool updateYR = true, bContinue = false;
+	double h, h1, p, **vals, *x, *y, *by1, *by2, *wy1, *wy2, *ranks, *ridx, *rsums, th, cy, cx[10];
+	char **rd = 0L, **names, *txt_obj;
+	char *headings[] = {"<i>Groups</i>", "<i>N</i>", "<i>Median</i>", "<i>25% - 75%</i>",
+		"<i>Range</i>","<i>Rank Sums</i>"};
+	scaleINFO scale = {{0.0, 1.0}, {0.0, 1.0}, {0.0, 1.0}};
+	AccRange *rV1 = 0L;
+	anyResult ares;
+	Page *page;
+	Graph *graph;
+
+	if(!parent || !data) return;
+	if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+		TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return;
+	if(!(KruskalDlg = CompileDialog(RepKruskal_DlgTmpl, dyndata))) return;
+	if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+		for(i=j=0; i <= 1000; i +=100) if(TmpTxt[i]) 
+			rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);	 maxYR = j-1;
+		}
+	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return;
+	if(!(Dlg = new DlgRoot(KruskalDlg, data))) return;
+	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+	hDlg = CreateDlgWnd("Kruskal-Wallis Nonparametric Anova", 50, 50, 420, 200, Dlg, 0x0L);
+	do {
+		if(updateYR) {
+			if(currYR >0) Dlg->ShowItem(156, true);
+			else Dlg->ShowItem(156, false);
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "variable # %d/%d", currYR+1, maxYR+1);
+#else
+			sprintf(TmpTxt,"variable # %d/%d", currYR+1, maxYR+1);
+#endif
+			Dlg->SetText(153, TmpTxt);
+			updateYR = false;
+			}
+		LoopDlgWnd();
+		res = Dlg->GetResult();
+		switch(res) {
+		case 0:
+			if(bContinue || Dlg->GetCheck(20)) res = -1;
+			break;
+		case -1:
+			bContinue = false;
+			break;
+		case 155:		case 156:
+			res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
+				&rV1, &bContinue, &ny, &maxYR, &updateYR);
+			break;
+			}
+		}while (res < 0);
+	if(res == 1 && (vals = (double**)calloc(sizeof(double*), maxYR+1)) && (nvals = (int*)calloc(sizeof(int), maxYR+1))
+		&& (names = (char**)calloc(maxYR+1, sizeof(char*))) && (x = (double*)calloc(maxYR+1, sizeof(double)))
+		&& (y = (double*)calloc(maxYR+1, sizeof(double))) && (by1 = (double*)calloc(maxYR+1, sizeof(double)))
+		&& (by2 = (double*)calloc(maxYR+1, sizeof(double))) && (wy1 = (double*)calloc(maxYR+1, sizeof(double)))
+		&& (wy2 = (double*)calloc(maxYR+1, sizeof(double)))
+		&& (rsums = (double*)calloc(maxYR+1, sizeof(double)))) {
+		maxYR++;	rep_init();		page = new Page(parent, data);
+		dBounds.Xmin = 0.5;			dBounds.Xmax = (double)maxYR+0.3;
+		if(rV1) delete rV1;			rV1 = 0L;	ranks = ridx = 0L;
+		cy = txtdef1.fSize*10.0;
+		mk_header(page, "<b>Kruskal-Wallis Test for Differences of Location</b>");
+		dBounds.Ymin = HUGE_VAL;	dBounds.Ymax = -HUGE_VAL;
+		// get data into two dimensional array
+		for(nr = maxYR, i = nt = 0; i < nr; i++) {
+			x [i] = y[i] = by1[i] = by2[i] = wy1[i] = wy2[i] = 0.0;		nvals[i] = 0;
+			if((rV1 = new AccRange(rd[i])) && (n = rV1->CountItems()) && (vals[i] = (double*)malloc(n*sizeof(double)))) {
+				names[i] = rV1->RangeDesc(data, 1);
+				for(n = 0, rV1->GetFirst(&c, &r); rV1->GetNext(&c, &r); ) {
+					if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE) {
+						if(!n) wy1[i] = wy2[i] = ares.value;
+						else {
+							if(ares.value < wy1[i]) wy1[i] = ares.value;
+							if(ares.value > wy2[i]) wy2[i] = ares.value;
+							}
+						if(ares.value < dBounds.Ymin) dBounds.Ymin = ares.value;
+						if(ares.value > dBounds.Ymax) dBounds.Ymax = ares.value;
+						vals[i][n] = ares.value;		n++;
+						}
 					}
-				mtot += csums[i];			ntot += ncols[i];
-				if(ncols[i]) csums[i] /= ((double)ncols[i]);
+				nvals[i] = n;	nt += n;	delete rV1;		rV1 = 0;
 				}
-			dBounds.Xmin = 0.5;				dBounds.Xmax = nc;
-			if(ntot) mtot /= ((double)ntot);
-			for(i = 0; i < nc; i++) {
-				for(j = 0, css[i] = 0.0; j < ncols[i]; j++) {
-					tmp = cols[i][j] - csums[i];	css[i] += (tmp*tmp);
+			if(!names[i] && (names[i] = (char*)malloc(20*sizeof(char)))){
+#ifdef USE_WIN_SECURE
+				sprintf_s(names[i], 20, "Group %d", i+1);
+#else
+				sprintf(names[i], "Group %d", i+1);
+#endif
+				}
+			}
+		// rank sums
+		if(nt && (ranks=(double*)malloc(nt*sizeof(double))) && (ridx=(double*)malloc(nt*sizeof(double)))) {
+			for(i = n = 0; i < nr; i++) {
+				for(j = 0; j < nvals[i]; j++) {
+					ridx[n] = (double)(i);	ranks[n] = vals[i][j];	n++;
 					}
 				}
-			for(i = 0, ssa = ssw = sst = 0.0;  i < nc; i++) {
-				tmp =(csums[i] - mtot);		ssa += (tmp*tmp) * ((double)ncols[i]);
-				ssw += css[i];
+			SortArray2(n, ranks, ridx);			crank(n, ranks, &th);
+			for(i = 0; i < n; i++) rsums[(int)ridx[i]] += ranks[i];
+			//statistics on range sums
+			for(i = 0, h = 0.0; i < nr; i++) h += rsums[i]*rsums[i]/((double)nvals[i]);
+			h = h * 12.0/(((double)n)*((double)(n+1))) - 3.0*((double)n+1);
+			h1 = h  / (1.0 - th/(((double)(n-1)) * ((double)n)* ((double)(n+1))));
+			}
+		else h = h1 = -1.0;
+		// check for unique names
+		for(i = 0; i < (nr-1); i++) for(j = i+1; j < nr; j++) {
+			if(!strcmp(names[i], names[j])) {
+				names[i] = (char*) realloc(names[i], 20 *sizeof(char));
+				names[j] = (char*) realloc(names[j], 20 *sizeof(char));
+#ifdef USE_WIN_SECURE
+				sprintf_s(names[i], 20, "Group %d", i+1);	sprintf_s(names[j], 20, "Group %d", j+1);
+#else
+				sprintf(names[i], "Group %d", i+1);			sprintf(names[j], "Group %d", j+1);
+#endif
 				}
-			sst = ssa + ssw;
-			res_tab[0][0] = nc - 1;				res_tab[1][0] = ntot - nc;
-			res_tab[2][0] = ntot -1;			res_tab[0][1] = ssa;
-			res_tab[1][1] = ssw;				res_tab[2][1] = sst;
-			res_tab[0][2] = ssa/res_tab[0][0];	res_tab[1][2] = ssw/res_tab[1][0];
-			res_tab[0][3] = res_tab[0][2]/res_tab[1][2];
-			res_tab[0][4] = f_dist(res_tab[0][3], res_tab[0][0], res_tab[1][0]);
-			page = new Page(parent, data);
-			mk_header(page, "<b>One Way ANOVA</b>");
-			if((graph = new Graph(parent, data, 0L)) && (txt_obj = mk_scatt(0L, csums, css, ncols, nc, "Mean", 0L, "Means <u>+</u> S.D."))){
-				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
-				free(txt_obj);								graph->moveable = 0;
-				graph->GRect.Xmin += (txtdef1.fSize*5.0);	graph->GRect.Xmax += (txtdef1.fSize*5.0);
-				graph->GRect.Ymin += (txtdef1.fSize*10.0);	graph->GRect.Ymax += (txtdef1.fSize*10.0);
-				page->Command(CMD_DROP_GRAPH, graph, 0L);
+			}
+		// simple group statistics
+		for(i = 0; i < nr; i++) {
+			x[i] = (double)(i+1);		d_quartile(nvals[i], vals[i], by1+i, y+i, by2+i);
+			}
+		// create boxplot
+		if((graph = new Graph(parent, data, 0L)) && (txt_obj = mk_boxplot(x, y, by1, by2, wy1, wy2,
+			nvals, nr,"Median","25-75%","Min./Max."))){
+			scale.sx.fx = (txtdef1.fSize*5.0);			scale.sy.fx = (txtdef1.fSize*10.0);
+			OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+			if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
+				if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
+					for(i = 0; i < nr; i++) ((BoxPlot*)LastOpenGO)->x_tv->GetValue(names[i]);
+					}
+				if(((BoxPlot*)LastOpenGO)->x_info = (char*)malloc(20*sizeof(char)))
+					rlp_strcpy(((BoxPlot*)LastOpenGO)->x_info, 20, "Groups");
+				if(((BoxPlot*)LastOpenGO)->y_info = (char*)malloc(20*sizeof(char)))
+					rlp_strcpy(((BoxPlot*)LastOpenGO)->y_info, 20, "Location");
 				}
-			mk_table(page, graph->GRect.Xmin, graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0,
-				1, res_tab);
-			parent->Command(CMD_DROP_GRAPH, page, 0L);
+			free(txt_obj);		graph->Command(CMD_SCALE, &scale, 0L);
+			cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef1.fSize*2.0;
+			page->Command(CMD_DROP_GRAPH, graph, 0L);
+			}
+		parent->Command(CMD_DROP_GRAPH, page, 0L);
+		//report statistics
+		cx[0] = txtdef1.fSize*5.0;				cx[1] = cx[0] + linsp1*5.0;
+		cx[2] = cx[1] + linsp1*2.5;		cx[3] = cx[2] + linsp1*4.0;
+		cx[4] = cx[3] + linsp1*5.0;		cx[5] = cx[4] + linsp1*7.0;
+		cx[6] = cx[5] + linsp1*8.0;
+		rep_DrawText(page, cx[0], cy, false, TXA_HLEFT, &txtdef1, "<b>Test Statistics:</b>");
+		cy += linsp2;			p = chi_dist(h,(double)(nr-1), 0.0);
+		dbl_to_str2(TmpTxt, 100, p < 0.0001 ?(char*)"H = %.2lf, P < 0.0001" : (char*)"H = %.2lf, P = %.4lf", h, p);
+		rep_DrawText(page, cx[1], cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+		cy += linsp1;			p = chi_dist(h1,(double)(nr-1), 0.0);
+		dbl_to_str2(TmpTxt, 100, p < 0.0001 ?(char*)"H(corr.) = %.2lf, P < 0.0001" : (char*)"H(corr.) = %.2lf, P = %.4lf", h1, p);
+		if(th >= 1.0) {
+			rep_DrawText(page, cx[1], cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+			cy += linsp1;
+			}
+		cy += linsp2;
+		// create summary table
+		rep_DrawText(page, cx[0], cy, false, TXA_HLEFT, &txtdef1, "<b>Summary:</b>");
+		for(i = 0, cy += linsp2; i < 6; i++) {				//column headers
+			c = (i == 3 || i == 4) ? TXA_HCENTER : TXA_HRIGHT;
+			rep_DrawText(page, cx[i+1], cy, false, c, &txtdef1, headings[i]);
+			}
+		mk_hr(page, cx[0], cx[6]+txtdef1.fSize*2.0, cy +linsp1);
+		for(i = 0, cy += linsp2; i < nr; i++, cy += linsp1) {
+			for(j = 0; j < 6; j++) {
+				switch(j) {
+				default:	rlp_strcpy(TmpTxt, 20, names[i]);						break;
+				case 1:		dbl_to_str1(TmpTxt, 20, "%.0lf", (double)nvals[i]);		break;
+				case 2:		dbl_to_str1(TmpTxt, 20, "%g", y[i]);					break;
+				case 3:		dbl_to_str2(TmpTxt, 20, "%g - %g", by1[i], by2[i]);		break;
+				case 4:		dbl_to_str2(TmpTxt, 20, "%g - %g", wy1[i], wy2[i]);		break;
+				case 5:		dbl_to_str1(TmpTxt, 20, "%g", rsums[i]);				break;
+					}
+				c = (j == 3 || j == 4) ? TXA_HCENTER : TXA_HRIGHT;
+				rep_DrawText(page, cx[j+1], cy, false, c, &txtdef1,TmpTxt);
+				}
+			}
+		mk_hr(page, cx[0], cx[6]+txtdef1.fSize*2.0, cy+txtdef1.fSize*0.2);
+		for(i= 0; i< nr; i++) {
+			if(vals[i]) free(vals[i]);	if(names[i]) free(names[i]);
 			}
+		free(vals);				free(nvals);		free(names);
+		free(x);				free(y);			free(by1);
+		free(by2);				free(wy1);			free(wy2);
+		free(rsums);
 		}
-	if(cols) {
-		for(i = 0; i < nc; i++) if(cols[i]) free(cols[i]);
-		free(cols);
+	CloseDlgWnd(hDlg);
+	delete Dlg;
+	if(rd) {
+		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
+		free(rd);
 		}
-	if(res_tab) {
-		for(i = 0; i < 3; i++) if(res_tab[i]) free(res_tab[i]);
-		free(res_tab);
+	if(ranks)free(ranks);	if(ridx)free(ridx);
+	if(rV1) delete rV1;		free(KruskalDlg);
+	return;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// simple sample statistics
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *SmplStatDlg_Tmpl = 
+	"1,2,,DEFAULT,PUSHBUTTON,-1,148,10,45,12\n"
+	"2,3,,,PUSHBUTTON,-2,148,25,45,12\n"
+	"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+	"4,10,100,ISPARENT | CHECKED,SHEET,1,5,10,130,80\n"
+	"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+	"100,101,,,LTEXT,2,10,30,60,8\n"
+	"101,,,LASTOBJ,RANGEINPUT,-15,20,40,100,10";
+void rep_samplestats(GraphObj *parent, DataObj *data)
+{
+	TabSHEET tab1 = {0, 40, 10, "Input Data"};
+	DlgInfo *SmplStatDlg;
+	void *dyndata[] = {(void*)&tab1, (void*)"rectangular range for variables"};
+	DlgRoot *Dlg;
+	void *hDlg;
+	int res, nr, nc, ntot, cb;
+	double val, *src_data, cx, cy, ksprob, ksd, sww, swp, mean, sd;
+	bool bContinue = false;
+	AccRange *rD =0L;
+	char *mrk, *x_info, *y_info;
+	RECT rec;
+	Plot *plot;
+	Graph *graph;
+	Page *page;
+
+	if(!parent || !data) return;
+	if(!(SmplStatDlg = CompileDialog(SmplStatDlg_Tmpl, dyndata))) return;
+	if(data->Command(CMD_GETMARK, &mrk, 0L))rlp_strcpy(TmpTxt, TMP_TXT_SIZE, mrk);
+	else {
+		data->ValueRec(&rec);
+		rlp_strcpy(TmpTxt, 100, mkRangeRef(rec.top, rec.left, rec.bottom, rec.right));
 		}
-	if(rD) delete rD;	if(ncols) free(ncols);	if(csums) free(csums);
-	if(css) free(css);	CloseDlgWnd(hDlg);	delete Dlg;	free(AnovaDlg);
+	if(!(Dlg = new DlgRoot(SmplStatDlg, data)))return;
+	hDlg = CreateDlgWnd("Sample Statistics", 50, 50, 420, 220, Dlg, 0x0L);
+	do {
+		LoopDlgWnd();
+		res = Dlg->GetResult();
+		switch (res) {
+		case 0:
+			if(bContinue) res = -1;
+			else if(Dlg->GetCheck(10)) res = -1;
+			break;
+		case -1:
+			bContinue = false;
+			break;
+			}
+		}while (res < 0);
+	if(res == 1 && Dlg->GetText(101, TmpTxt+200, TMP_TXT_SIZE) &&(rD = new AccRange(TmpTxt+200))
+		&& rD->BoundRec(&rec) && (ntot = rD->CountItems()) && (src_data = (double*)malloc(ntot*sizeof(double)))){
+		rep_init();
+		x_info = rD->RangeDesc(data, 2);
+		if(y_info = (char*)malloc(20)) rlp_strcpy(y_info, 20, "Normal quantiles");
+		page = new Page(parent, data);
+		cb = rlp_strcpy(TmpTxt, 100, "<b>Sample Statistics for \"");
+		if(x_info && x_info[0])	cb += rlp_strcpy(TmpTxt+cb, 100-cb, x_info);
+		else cb += rlp_strcpy(TmpTxt+cb, 100-cb, TmpTxt+200);
+		rlp_strcpy(TmpTxt+cb,100-cb, "\"</b>");		mk_header(page, TmpTxt);
+		for(ntot = 0, rD->GetFirst(&nc, &nr); rD->GetNext(&nc, &nr); ) {
+			if(data->GetValue(nr, nc, &val)) src_data[ntot++] = val;
+			}
+		if(ntot > 5 && (graph = new Graph(page, data, 0L))) {
+			if(plot = new NormQuant(page, data, src_data, ntot)) {
+				plot->x_info = x_info;		plot->y_info = y_info;
+				}
+			if(!(graph->Command(CMD_DROP_PLOT, (void *)plot, 0L))) {
+				delete plot;	plot =0L;
+				}
+			graph->moveable = 0;							graph->GRect.Xmin += (txtdef1.fSize*5.0);	
+			graph->GRect.Xmax += (txtdef1.fSize*5.0);		graph->GRect.Ymin += (txtdef1.fSize*10.0);
+			graph->GRect.Ymax += (txtdef1.fSize*10.0);		page->Command(CMD_DROP_GRAPH, graph, 0L);
+			}
+		cy = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef1.fSize*3;
+		rep_DrawText(page, graph->GRect.Xmin, cy, false, TXA_HLEFT, &txtdef1, "<b>Descriptive Statistics:</b>");
+		cy += txtdef1.fSize*1.5;			cx = graph->GetSize(SIZE_GRECT_LEFT)+txtdef1.fSize*25.0;
+		mk_median_report(page, cx, cy, src_data, ntot, .95, 0L);
+		cx = graph->GetSize(SIZE_GRECT_LEFT)+txtdef1.fSize*2.0;
+		cy = mk_mean_report(page, cx, cy, src_data, ntot, .95, 0L);
+		//data are sorted by the mk_median_report();
+		d_variance(ntot, src_data, &mean, &sd);
+		sd = sqrt(sd/((double)(ntot-1)));
+		KolSmir(ntot, src_data, norm_dist, mean, sd, true, &ksd, &ksprob);
+		cy += txtdef1.fSize*1.5;			cx = graph->GRect.Xmin;
+		rep_DrawText(page, cx , cy, false, TXA_HLEFT, &txtdef1, "<b>Test for Normal Distribution:</b>");
+		cy += linsp1;						cx += (txtdef1.fSize*2.0);
+		cb = dbl_to_str1(TmpTxt, 100, "Kolmogorov-Smirnov D = %.4lf, P ", ksd);
+		dbl_to_str1(TmpTxt+cb, 100-cb, ksprob >= 0.0001 ? (char*)"= %.4lf" : (char*)"< 0.0001", ksprob);
+		rep_DrawText(page, cx , cy, false, TXA_HLEFT, &txtdef1,TmpTxt);			cy += linsp1/1.2;
+		swilk1(ntot, src_data, norm_dist, 0.0, 1.0, true, &sww, &swp);
+		if(sww >= 0.0 && swp >= 0.0 && (cb = dbl_to_str1(TmpTxt, 100, "Shapiro-Wilk W = %.4lf, P ", sww))
+			&& (dbl_to_str1(TmpTxt+cb, 100-cb, swp >= 0.0001 ? (char*)"= %.4lf" : (char*)"< 0.0001", swp))){
+			rep_DrawText(page, cx , cy, false, TXA_HLEFT, &txtdef1,TmpTxt);		cy += linsp1/1.2;
+			}
+		parent->Command(CMD_DROP_GRAPH, page, 0L);
+		delete rD;	free(src_data);
+		}
+	CloseDlgWnd(hDlg);	delete Dlg;		free(SmplStatDlg);
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -683,71 +1023,40 @@ rep_anova(GraphObj *parent, DataObj *data)
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 static double mk_regr_summary(GraphObj *parent, double x, double y, double *dres, double ci, int n)
 {
-	char *txt_obj;
 	char *fmts[] = {"slope = %g", "intercept = %g", "observations = %g", "r<sup> 2</sup> = %g", "r = %g"};
 	char *ci_fmt = "%g  -  %g";
 	char lbl[80];
 	double z, s;
 	double x1 = x + txtdef1.fSize*3.0;
-	double x2 = x + txtdef1.fSize*20.0;
+	double x2 = x + txtdef1.fSize*25.0;
 #ifdef _WINDOWS
 	double hrw = txtdef1.fSize*38.0;
 #else
 	double hrw = txtdef1.fSize*1.3*38.0;
 #endif
 
-	if(txt_obj = mk_label(x, y, false, TXA_HLEFT, &txtdef1, "<b>Regression:</b>")) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(parent, x, y, false, TXA_HLEFT, &txtdef1, "<b>Regression:</b>");
 	dbl_to_str1(lbl, 80, "%g%% C.I.", ci);
-	if(txt_obj = mk_label(x2, y, false, TXA_HCENTER, &txtdef1, lbl)) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
 	mk_hr(parent, x, x+hrw, y+txtdef1.fSize*1.2);
 	y += linsp1*1.5;		dbl_to_str1(lbl, 80, fmts[0], dres[0]);
-	if(txt_obj = mk_label(x1, y, false, TXA_HLEFT, &txtdef1, lbl)) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
 	dbl_to_str2(lbl, 80, ci_fmt, dres[0]-dres[10], dres[0]+dres[10]);
-	if(txt_obj = mk_label(x2, y, false, TXA_HCENTER, &txtdef1, lbl)) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
 	y += linsp1;		dbl_to_str1(lbl, 80, fmts[1], dres[1]);
-	if(txt_obj = mk_label(x1, y, false, TXA_HLEFT, &txtdef1, lbl)) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
 	dbl_to_str2(lbl, 80, ci_fmt, dres[1]-dres[11], dres[1]+dres[11]);
-	if(txt_obj = mk_label(x2, y, false, TXA_HCENTER, &txtdef1, lbl)) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
 	y += linsp1;		dbl_to_str1(lbl, 80, fmts[2], (double)n);
-	if(txt_obj = mk_label(x1, y, false, TXA_HLEFT, &txtdef1, lbl)) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
 	y += linsp1;		dbl_to_str1(lbl, 80, fmts[3], dres[12]);
-	if(txt_obj = mk_label(x1, y, false, TXA_HLEFT, &txtdef1, lbl)) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
 	y += linsp1;		dbl_to_str1(lbl, 80, fmts[4], sqrt(dres[12]));
-	if(txt_obj = mk_label(x1, y, false, TXA_HLEFT, &txtdef1, lbl)) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(parent, x1, y, false, TXA_HLEFT, &txtdef1, lbl);
 	z = 0.5 * log((1.0+sqrt(dres[12])+_PREC)/(1.0-sqrt(dres[12])+_PREC));	//Fishers z-transform
 	s = distinv(t_dist, 1.0E+10, 1.0, (100-ci)/100.0, 2.0)/sqrt((double)(n-3));	
 	dbl_to_str2(lbl, 80, ci_fmt, tanh(z-s), tanh(z+s));
-	if(txt_obj = mk_label(x2, y, false, TXA_HCENTER, &txtdef1, lbl)) {
-		OpenGraph(parent, 0L, (unsigned char*)txt_obj, false);
-		free(txt_obj);
-		}
+	rep_DrawText(parent, x2, y, false, TXA_HCENTER, &txtdef1, lbl);
 	mk_hr(parent, x, x+hrw, y+txtdef1.fSize*1.2);
 	return y + linsp1*3.0;
 }
@@ -763,8 +1072,8 @@ static char *RegrDlg_Tmpl =
 	"102,103,,,LTEXT,3,10,55,60,8\n"
 	"103,104,,,RANGEINPUT,-16,20,65,100,10\n"
 	"104,105,,,LTEXT,4,10,80,60,8\n"
-	"105,106,,,EDVAL1,5,70,80,25,10\n"
-	"106,107,,,LTEXT,-10,97,80,60,8\n"
+	"105,106,,,EDVAL1,5,74,80,25,10\n"
+	"106,107,,,LTEXT,-10,101,80,60,8\n"
 	"107,,,LASTOBJ,CHECKBOX,6,10,95,100,8";
 
 void
@@ -929,11 +1238,8 @@ rep_regression(GraphObj *parent, DataObj *data)
 			if(!bParZ) sprintf(TmpTxt, "y = %g %c %g * x",dres[1],(dres[0] < 0.0 ? '-' : '+'), fabs(dres[0]));
 			else sprintf(TmpTxt, "y = %g * x", fabs(dres[0]));
 #endif
-			if(txt_obj = mk_label((graph->GetSize(SIZE_DRECT_LEFT) + graph->GetSize(SIZE_DRECT_RIGHT))/2.0,
-				graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize/2.0, true, TXA_HCENTER, &txtdef1, TmpTxt)) {
-				OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
-				free(txt_obj);
-				}
+			rep_DrawText(graph, (graph->GetSize(SIZE_DRECT_LEFT) + graph->GetSize(SIZE_DRECT_RIGHT))/2.0,
+				graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize/2.0, true, TXA_HCENTER, &txtdef1, TmpTxt);
 			page = new Page(parent, data);					page->Command(CMD_DROP_GRAPH, graph, 0L);
 			graph->moveable = 0;
 			graph->GRect.Xmin += (txtdef1.fSize*5.0);		graph->GRect.Xmax += (txtdef1.fSize*5.0);
@@ -948,11 +1254,8 @@ rep_regression(GraphObj *parent, DataObj *data)
 			c_y = graph->GetSize(SIZE_GRECT_BOTTOM)+txtdef2.fSize*3.0;
 			c_x = graph->GRect.Xmin;
 			c_y = mk_regr_summary(page, c_x, c_y, dres, ci, n);
-			if(txt_obj = mk_label(c_x, c_y, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>")) {
-				OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
-				free(txt_obj);						c_y += txtdef1.fSize*1.5;
-				}
-			mk_table(page, c_x, c_y, 2, res_tab);
+			rep_DrawText(page, c_x, c_y, false, TXA_HLEFT, &txtdef1, "<b>Anova:</b>");
+			c_y += txtdef1.fSize*1.5;			mk_table(page, c_x, c_y, 2, res_tab);
 			parent->Command(CMD_DROP_GRAPH, page, 0L);
 			}
 		}
@@ -965,6 +1268,293 @@ rep_regression(GraphObj *parent, DataObj *data)
 	if(x) free(x);				if(y) free(y);
 	if(rX) delete rX;			if(rY) delete rY;		free(RegrDlg);
 }
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Correlation reports
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *RepCorrel_DlgTmpl =
+		"1,2,,DEFAULT,PUSHBUTTON,-1,158,10,45,12\n"
+		"2,3,,,PUSHBUTTON,-2,158,25,45,12\n"
+		"3,,10,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"10,11,152,ISPARENT | CHECKED, SHEET,1,5,10,140,70\n"
+		"11,20,200,ISPARENT | TOUCHEXIT,SHEET,2,5,10,140,70\n"
+		"20,21,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+		"21,22,,CHECKED,CHECKBOX,7,25,85,130,9\n"
+		"22,23,,,LTEXT,8,35,95,50,9\n"
+		"23,24,,,EDVAL1,9,87,95,30,10\n"
+		"24,,,,LTEXT,-10,120,95,10,9\n"
+		"152,153,,ISPARENT | CHECKED,GROUPBOX,3,12,30,128,45\n"
+		"153,154,,,LTEXT,0,25,35,60,8\n"
+		"154,155,,,RANGEINPUT,0,25,45,100,10\n"
+		"155,156,0,,PUSHBUTTON,-8,95,57,30,12\n"
+		"156,,,,PUSHBUTTON,-9,60,57,35,12\n"
+		"200,201,,TOUCHEXIT,RADIO1,4,25,30,60,8\n"
+		"201,202,,TOUCHEXIT,RADIO1,5,25,45,60,8\n"
+		"202,,,TOUCHEXIT,RADIO1,6,25,60,60,8\n"
+		"300,,,LASTOBJ,NONE,0,0,0,0,0";
+static int use_corr = 2;
+static double use_ci = 95.0;
+
+void rep_correl(GraphObj *parent, DataObj *data, int style)
+{
+	TabSHEET tab1 = {0, 25, 10, "Data"};
+	TabSHEET tab2 = {25, 57, 10, "Method"};
+	
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, 
+		(void*)" select one range for every variable ", (void*)" Pearsons product moment",
+		(void*)" Spearmans rank correlation", (void*)" Kendalls Tau", (void*)" highlight significant correlations,",
+		(void*)"sigificance level", (void*)&use_ci};
+	DlgInfo *CorrelDlg;
+	DlgRoot *Dlg;
+	void *hDlg;
+	int i, j, res, nr, currYR = 0, maxYR = 0, ny, corr;
+	int r1, c1, r2, c2, n, cb;
+	bool updateYR = true, bContinue = false, bMtab = false, bHiLite;
+	double lmarg, line_inc, *v1, *v2, val1, val2, cx, cy, r,dn, p, sf, ra[20], cl;
+	char **rd = 0L, *txt_obj, *info1, *info2;
+	scaleINFO scale = {{0.0, 0.14}, {0.0, 0.14}, {0.0, 0.14}};
+	AccRange *rV1 = 0L, *rV2 = 0L;
+	TextDEF mtext;
+	Plot *plot;
+	Graph *graph;
+	Page *page;
+
+	if(!parent || !data) return;
+	info1 = info2 = 0L;
+	if(!UseRangeMark(data, 2, TmpTxt, TmpTxt+100, TmpTxt+200, TmpTxt+300, TmpTxt+400,
+		TmpTxt+500, TmpTxt+600, TmpTxt+700, TmpTxt+800, TmpTxt+900, TmpTxt+1000)) return;
+	if(!(CorrelDlg = CompileDialog(RepCorrel_DlgTmpl, dyndata))) return;
+	if(TmpTxt[0] && TmpTxt[100] && (rd = (char**)calloc(12, sizeof(char*)))) {
+		for(i=j=0; i <= 1000; i +=100) if(TmpTxt[i]) 
+			rd[j++] = (char*)memdup(TmpTxt+i, ((int)strlen(TmpTxt+i))+2, 0);	 maxYR = j-1;
+		}
+	if(!rd && !(rd = (char**)calloc(1, sizeof(char*))))return;
+	if(!(Dlg = new DlgRoot(CorrelDlg, data))) return;
+	if(rd && rd[currYR] &&  *(rd[currYR])) Dlg->SetText(154, rd[currYR]);
+	switch(use_corr) {
+	case 1:			Dlg->SetCheck(200, 0L, true);			corr = 1;			break;
+	default:		Dlg->SetCheck(201, 0L, true);			corr = 2;			break;
+	case 3:			Dlg->SetCheck(202, 0L, true);			corr = 3;			break;
+		}
+	hDlg = CreateDlgWnd(style? (char*)"Create Tiled Correlation Plots" : 
+		(char*)"Create a Correlation Matrix", 50, 50, 420, 252, Dlg, 0x0L);
+	do {
+		if(updateYR) {
+			if(currYR >0) Dlg->ShowItem(156, true);
+			else Dlg->ShowItem(156, false);
+#ifdef USE_WIN_SECURE
+			sprintf_s(TmpTxt, TMP_TXT_SIZE, "variable # %d/%d", currYR+1, maxYR+1);
+#else
+			sprintf(TmpTxt,"variable # %d/%d", currYR+1, maxYR+1);
+#endif
+			Dlg->SetText(153, TmpTxt);
+			updateYR = false;
+			}
+		LoopDlgWnd();
+		res = Dlg->GetResult();
+		switch(res) {
+		case 0:
+			if(bContinue || Dlg->GetCheck(20)) res = -1;
+			break;
+		case -1:
+			bContinue = false;
+			break;
+		case 11:					//select correlation method
+			bMtab = true;	res =-1;	break;
+		case 200:					//select pearson
+		case 201:					//select spearman
+		case 202:					//select kendall
+			corr = res-199;		res =-1;	break;
+		case 1:
+			if(!bMtab) {
+				Dlg->SetCheck(11, 0L, true);
+				bMtab = true;	res = -1;	
+				break;
+				}
+		case 155:		case 156:
+			res = com_StackDlg(res, Dlg, 0L, 0L, &rd, &currYR,
+				&rV1, &bContinue, &ny, &maxYR, &updateYR);
+			break;
+			}
+		}while (res < 0);
+
+	if(res ==1) {
+		if(bHiLite = Dlg->GetCheck(21)) {
+			Dlg->GetValue(23, &use_ci);		cl = 1.0 - use_ci/100.0;
+			}
+		maxYR++;	rep_init();		page = new Page(parent, data);
+		if(rV1) delete rV1;			rV1 = 0L;		use_corr = corr;
+		switch(corr) {
+		case 1:
+			mk_header(page, "<b>Pearsons product moment correlations</b>");
+			break;
+		case 2:
+			mk_header(page, "<b>Spearmans rank correlations</b>");
+			break;
+		case 3:
+			mk_header(page, "<b>Kendalls non parametric correlations</b>");
+			break;
+		default:
+			mk_header(page, "<b>### Correlation Error ###</b>");
+			break;
+			}
+		memcpy(&mtext, &txtdef1, sizeof(TextDEF));
+		if(style == 0) {
+			lmarg = txtdef1.fSize*12.0;
+			cy = txtdef1.fSize*13.0;	cx = txtdef1.fSize*6.0;
+			line_inc = linsp1;
+			sf = (page->GetSize(SIZE_GRECT_RIGHT)-lmarg-linsp1)/(cx *(double)maxYR);
+			if(sf< 1.0) {
+				cx *= sf;		line_inc *= sf;		lmarg *= sf;
+				mtext.fSize *= sf;		mtext.iSize = 0;
+				}
+			}
+		else {
+			lmarg = txtdef1.fSize*8.0;
+			cy = txtdef1.fSize*13.0;
+			cx = (page->GetSize(SIZE_GRECT_RIGHT)-txtdef1.fSize*3.0-lmarg)/maxYR;
+			switch(defs.cUnits) {
+			default:
+				scale.sx.fy = scale.sy.fy = scale.sz.fy = cx/165.0;			break;
+			case 1:
+				scale.sx.fy = scale.sy.fy = scale.sz.fy = cx/16.50;			break;
+			case 2:
+				scale.sx.fy = scale.sy.fy = scale.sz.fy = cx/6.49606;		break;
+				}
+			line_inc = cx/1.44;
+			}
+		for(nr = maxYR, i = 0; i < nr; i++) for(j = 0; j < nr; j++) {
+			if(i == 0 &&(rV1 = new AccRange(rd[j]))) {	//first row
+				if(info1 = rV1->RangeDesc(data, style == 0 || nr > 5 ? 1 : 2)) {
+					if(style == 0)
+						rep_DrawText(page, lmarg+cx*j, cy-txtdef1.fSize*2.0, false, TXA_HCENTER, &mtext, info1);
+					else if(style == 1)
+						rep_DrawText(page, lmarg+cx*j+cx/2.0, cy-txtdef1.fSize*2.0, false, TXA_HCENTER, &mtext, info1);
+					free(info1);	info1 = 0L;
+					}
+				delete rV1;			rV1 = 0L;
+				}
+			if(j == 0 &&(rV1 = new AccRange(rd[i]))) {	//first column
+				if(info1 = rV1->RangeDesc(data, 1)) {
+					if(style == 0) 
+						rep_DrawText(page, lmarg-cx/2.0-txtdef1.fSize, cy+line_inc, false, TXA_HRIGHT, &mtext, info1);
+					else if(style == 1)
+						rep_DrawText(page, lmarg-txtdef1.fSize, cy+line_inc/2.0-mtext.fSize/2.0, false, TXA_HRIGHT, &mtext, info1);
+					free(info1);	info1 = 0L;
+					}
+				delete rV1;			rV1 = 0L;
+				}
+			if(i == j) {					//self correlation: do something else ...
+				if(style == 0) {			//correlation matrix
+					rep_DrawText(page, lmarg+cx*j, cy+line_inc, false, TXA_HCENTER, &mtext, "---");
+					}
+				else if(style = 1) {		//tiled plots
+					graph = new Graph(parent, data, 0L);
+					scale.sx.fx = lmarg+cx*j;			scale.sy.fx = cy;
+					if(plot = new FreqDist(graph, data, rd[i], true)){
+						if(rV1 = new AccRange(rd[i])){
+							plot->x_info = rV1->RangeDesc(data, 2);
+							delete rV1;		rV1 = 0L;
+							}
+						if(!(graph->Command(CMD_DROP_PLOT, plot, 0L))) delete(plot);
+						}
+					graph->Command(CMD_SCALE, &scale, 0L);
+					page->Command(CMD_DROP_GRAPH, graph, 0L);
+					}
+				}
+			else {
+				rV1 = new AccRange(rd[i]);	rV2 = new AccRange(rd[j]);
+				v1 = (double*)malloc((rV1->CountItems()+1) * sizeof(double));
+				v2 = (double*)malloc((rV2->CountItems()+1) * sizeof(double));
+				dBounds.Xmin = dBounds.Ymin = HUGE_VAL;		dBounds.Xmax = dBounds.Ymax = -HUGE_VAL;
+				rV1->GetFirst(&c1, &r1);	rV2->GetFirst(&c2, &r2);
+				//copy values into arrays
+				for(n = 0; rV1->GetNext(&c1, &r1) && rV2->GetNext(&c2, &r2); ) {
+					if(data->GetValue(r1, c1, &val1) && data->GetValue(r2, c2, &val2)) {
+						if(dBounds.Xmin > val1) dBounds.Xmin = val1;
+						if(dBounds.Xmax < val1) dBounds.Xmax = val1;
+						if(dBounds.Ymin > val2) dBounds.Ymin = val2;
+						if(dBounds.Ymax < val2) dBounds.Ymax = val2;
+						v1[n] = val1;	v2[n] = val2;	n++;
+						}
+					}
+				//do correlation
+				dn = n;			r = 0.0;
+				if(n) switch(corr) {
+				case 1:
+					d_pearson(v1, v2, n, 0L, 0L, ra);
+					r = ra[0];	p = ra[2];	dn = ra[3];
+					break;
+				case 2:
+					d_spearman(v1, v2, n, 0L, 0L, ra);
+					r = ra[3];	p = ra[4];	dn = ra[5];
+					break;
+				case 3:
+					d_kendall(v1, v2, n, 0L, 0L, ra);
+					r = ra[0];	p = ra[2];	dn = ra[3];
+					break;
+				default:
+					r = 0.0;	dn = 0.0;	p = 1.0;			break;
+					}
+				//process result
+				if(style == 0) {			//correlation matrix
+					if(bHiLite && p < cl && (txt_obj = mk_rect(lmarg+cx*j-cx/2.1, cy-line_inc/4.0, lmarg+cx*j+cx/2.1, 
+						cy+line_inc*3.25, 0x0000ffffL, 0x0080ffffL))) {
+						OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
+						free(txt_obj);
+						}
+					dbl_to_str1(TmpTxt, 80, "%g", r);
+					rep_DrawText(page, lmarg+cx*j, cy, false, TXA_HCENTER, &mtext, TmpTxt);
+					dbl_to_str1(TmpTxt, 80, "n = %g", dn);
+					rep_DrawText(page, lmarg+cx*j, cy+line_inc, false, TXA_HCENTER, &mtext, TmpTxt);
+					dbl_to_str1(TmpTxt, 80, p < 0.001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p);
+					rep_DrawText(page, lmarg+cx*j, cy+line_inc*2.0, false, TXA_HCENTER, &mtext, TmpTxt);
+					if(j == (nr-1)) cy += (line_inc*4.0);
+					}
+				else if(style = 1) {		//tiled plots
+					graph = new Graph(parent, data, 0L);
+					scale.sx.fx = lmarg+cx*j;			scale.sy.fx = cy;
+					info1 = rV1->RangeDesc(data, 2);	info2 = rV2->RangeDesc(data, 2);
+					if(txt_obj = mk_scatt(v1, v2, 0L, 0L, n, "Data", info1, info2)){
+						OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+						free(txt_obj);
+						}
+					if(info1) free(info1);				if(info2) free(info2);
+					info1 = info2 = 0L;
+					if(bHiLite && p < cl) {
+						graph->SetColor(COL_GRECT, 0x0000ffffL);	graph->SetColor(COL_DRECT, 0x00c0ffffL);
+						}
+					switch(corr) {
+					case 1:
+						cb = dbl_to_str2(TmpTxt, 80, "r = %.4lf, n = %g, ", r, dn);				break;
+					case 2:
+						cb = dbl_to_str2(TmpTxt, 80, "r<sub>S</sub> = %.4lf, n = %g, ", r, dn);	break;
+					case 3:
+						cb = dbl_to_str2(TmpTxt, 80, "r<sub>K</sub> = %.4lf, n = %g, ", r, dn);	break;
+					default:
+						TmpTxt[0] = 0;		cb = 0;		break;
+						}
+					dbl_to_str1(TmpTxt+cb, 80, p < 0.001 ? (char*)"P < 0.0001" : (char*)"P = %.4lf", p);
+					rep_DrawText(graph, graph->GetSize(SIZE_DRECT_LEFT)+txtdef1.fSize, 
+						graph->GetSize(SIZE_DRECT_TOP)+txtdef1.fSize, false, TXA_HLEFT, &txtdef1, TmpTxt);
+					if(LastOpenGO)LastOpenGO->SetColor(COL_TEXT, 0x00cb0000L);
+					graph->Command(CMD_SCALE, &scale, 0L);
+					page->Command(CMD_DROP_GRAPH, graph, 0L);
+					if(j == (nr-1)) cy += line_inc;
+					}
+				free(v1);		free(v2);
+				if(rV1)delete rV1;		if(rV2)delete rV2;		rV1 = rV2 = 0L;
+				}
+			}
+		parent->Command(CMD_DROP_GRAPH, page, 0L);
+		}
+	CloseDlgWnd(hDlg);
+	delete Dlg;
+	if(rd) {
+		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
+		free(rd);
+		}
+	if(rV2) delete rV2;		if(rV1) delete rV1;		free(CorrelDlg);
+}
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // 2x2 table
@@ -1004,25 +1594,30 @@ void rep_twowaytable(GraphObj *parent, DataObj *data)
 		(void*)"Group B", (void*)"A + B", (void*)"C1+C2", (void*)"Fisher's exact:"};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, level, res;
+	int i, r, c, level, res, wcc;
 	int v_idx[] = {101,102,400,103,104,401,402,403,404};
-	double v[9], chi2, p, dn, pf;
+	double tmp, v[9], chi2, p, dn, pf, pfa[128];
+	char *rng;
+	AccRange *ar;
 
 	if(!parent || !data) return;
 	if(!(twDlg = CompileDialog(twDlg_Tmpl, dyndata))) return;
 	if(!(Dlg = new DlgRoot(twDlg, data)))return;
 	for(i = 400; i < 405; i++) Dlg->Activate(i, false);
-	level = 0;
-	if (!level) {
-		Dlg->ShowItem(2, false);		Dlg->ShowItem(4, false);	
-		Dlg->ShowItem(5, false);	
-		hDlg = CreateDlgWnd("2x2 Table", 50, 50, 450, 200, Dlg, 0);
-		ResizeDlgWnd(hDlg, 370, 150);
-		}
-	else {
-		Dlg->ShowItem(3, false);
-		hDlg = CreateDlgWnd("2x2 Table", 50, 50, 450, 200, Dlg, 0);
+	if(data->Command(CMD_GETMARK, &rng, 0L) && rng && rng[0] && (ar = new AccRange(rng)) && ar->GetFirst(&c, &r)) {
+		for(i = 0; i < 4 && ar->GetNext(&c, &r); ) {
+			if(data->GetValue(r, c, &tmp)) {
+				Dlg->SetValue(101+i, tmp);				i++;
+				}
+			}
+		delete ar;
+		if(i == 4) Dlg->ItemCmd(600, CMD_ENDDIALOG, 0L);
 		}
+	level = wcc = 0;
+	Dlg->ShowItem(2, false);		Dlg->ShowItem(4, false);	
+	Dlg->ShowItem(5, false);	
+	hDlg = CreateDlgWnd("2x2 Table", 50, 50, 450, 200, Dlg, 0);
+	ResizeDlgWnd(hDlg, 370, 150);
 	do {
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -1043,21 +1638,37 @@ void rep_twowaytable(GraphObj *parent, DataObj *data)
 				v[2] = v[0] + v[1];				v[5] = v[3] + v[4];
 				v[6] = v[0] + v[3];				v[7] = v[1] + v[4];
 				v[8] = v[6] + v[7];				chi2 = v[0]*v[4]-v[1]*v[3];
-				if(v[2] < 32.0 && v[5] < 32.0 && v[6] < 32.0 && v[7] < 32.0) {
+				for(i = wcc = 0; i < 9; i++) {
+					dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "%g", v[i]);
+					Dlg->SetText(v_idx[i], TmpTxt);
+					}
+				if(v[8] < 128.0) do {
 					pf = factrl((int)v[2])/factrl((int)v[0])*factrl((int)v[5])/factrl((int)v[1])
 						*factrl((int)v[6])/factrl((int)v[3])*factrl((int)v[7])/factrl((int)v[4]);
 					pf /= factrl((int)v[8]);
-					dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "P = %g", pf);
+					pfa[wcc++] = pf;
+					//worse case correction
+					//RR Sokal & FJ Rohlf: Biometry, 3rd ed., pp. 734 ff.
+					if((v[0]*v[4]- v[1]*v[3]) < 0.0) {
+						v[0]-=1.0;	v[4]-=1.0;	v[1]+=1.0;	v[3]+=1.0;
+						}
+					else if((v[0]*v[4]- v[1]*v[3]) > 0.0) {
+						v[0]+=1.0;	v[4]+=1.0;	v[1]-=1.0;	v[3]-=1.0;
+						}
+					else break;
+					}while(v[0]>=0.0 && v[1]>=0.0 && v[3]>=0.0 && v[4]>=0.0 && wcc < 128);
+				if(wcc){
+					for(i = 1, pf = pfa[0]; i < wcc; i++){
+						pf += pfa[i];
+						}
+					if(pf > 1.0) pf = 1.0;
+					dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "P(one sided) = %.4lf", pf);
 					Dlg->SetText(410, pf >= 0.001 ? TmpTxt : (char*)"P < 0.001");
 					}
 				else Dlg->SetText(410, "- - -");
 				dn = (v[2]*v[5]*v[6]*v[7]);
 				chi2 = dn > 0.0  ? (chi2*chi2*v[8])/dn : 0.0;
 				p = chi_dist(chi2, 1.0, 1.0);
-				for(i = 0; i < 9; i++) {
-					dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "%g", v[i]);
-					Dlg->SetText(v_idx[i], TmpTxt);
-					}
 				dbl_to_str1(TmpTxt, TMP_TXT_SIZE, "Chi2 = %g", chi2);
 				Dlg->SetText(407, TmpTxt);
 				if(p >= 0.001) {
@@ -1075,7 +1686,7 @@ void rep_twowaytable(GraphObj *parent, DataObj *data)
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// compare means of two groups
+// compare means / medians of two groups
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 void rep_compmeans(GraphObj *parent, DataObj *data)
 {
@@ -1087,14 +1698,15 @@ void rep_compmeans(GraphObj *parent, DataObj *data)
 		(void*)&ci, (void*)" "};
 	char *ttest[] = {"Student's t = %g", "P = %g", "P(corr.) = %g"};
 	char *utest[] = {"Mann-Whitney U = %g", "z = %g", "P = %g", "z(corr.) = %g", "P(corr.) = %g"};
-	char g1_nam[20], g2_nam[20], *c_name;
+	char g1_nam[30], g2_nam[30], *c_name;
 	DlgRoot *Dlg;
 	void *hDlg;
 	int i, j, res, n1, n2, r, c, *ny;
 	bool bContinue = false;
-	double *d1, *d2, *rs, dtmp, cx, cy, min1,max1, min2, max2;
+	double *d1, *d2, dtmp, *rs, cx, cy, min1,max1, min2, max2;
 	scaleINFO scale = {{0.0, 0.9}, {0.0, 0.9}, {0.0, 0.9}};
 	char *txt_obj;
+	anyResult ares;
 	AccRange *rD;
 	Graph *graph;
 	Page *page;
@@ -1122,36 +1734,39 @@ void rep_compmeans(GraphObj *parent, DataObj *data)
 			min1 = min2 = dBounds.Ymin = HUGE_VAL;		max1 = max2 = dBounds.Ymax = -HUGE_VAL;
 			if(Dlg->GetText(101,TmpTxt,TMP_TXT_SIZE)&&(rD=new AccRange(TmpTxt))&&(n1=rD->CountItems())&&(d1=(double*)malloc(n1*sizeof(double)))){
 				if(c_name = rD->RangeDesc(data, 2)) {
-					rlp_strcpy(g1_nam, 20, c_name);		g1_nam[0] = toupper(g1_nam[0]);
+					rlp_strcpy(g1_nam, 30, c_name);		g1_nam[0] = toupper(g1_nam[0]);
 					free(c_name);
 					}
-				else rlp_strcpy(g1_nam, 20, "Group 1");
+				else rlp_strcpy(g1_nam, 30, "Group 1");
 				for(n1 = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
-					if(data->GetValue(r, c, &dtmp)){
-						if(dBounds.Ymin > dtmp) dBounds.Ymin = dtmp;
-						if(dBounds.Ymax < dtmp) dBounds.Ymax = dtmp;
-						if(min1 > dtmp) min1 = dtmp;		if(max1 < dtmp) max1 = dtmp;
-						d1[n1++] = dtmp;
+					if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE){
+						if(dBounds.Ymin > ares.value) dBounds.Ymin = ares.value;
+						if(dBounds.Ymax < ares.value) dBounds.Ymax = ares.value;
+						if(min1 > ares.value) min1 = ares.value;		if(max1 < ares.value) max1 = ares.value;
+						d1[n1++] = ares.value;
 						}
 					}
 				delete rD;
 				}
-			if(Dlg->GetText(103,TmpTxt,TMP_TXT_SIZE)&&(rD=new AccRange(TmpTxt))&&(n2=rD->CountItems())&&(d2=(double*)malloc(n1*sizeof(double)))){
+			if(Dlg->GetText(103,TmpTxt,TMP_TXT_SIZE)&&(rD=new AccRange(TmpTxt))&&(n2=rD->CountItems())&&(d2=(double*)malloc(n2*sizeof(double)))){
 				if(c_name = rD->RangeDesc(data, 2)) {
-					rlp_strcpy(g2_nam, 20, c_name);		g2_nam[0] = toupper(g2_nam[0]);
+					rlp_strcpy(g2_nam, 30, c_name);		g2_nam[0] = toupper(g2_nam[0]);
 					free(c_name);
 					}
-				else rlp_strcpy(g2_nam, 20, "Group 2");
+				else rlp_strcpy(g2_nam, 30, "Group 2");
 				for(n2 = 0, rD->GetFirst(&c, &r); rD->GetNext(&c, &r); ) {
-					if(data->GetValue(r, c, &dtmp)){
-						if(dBounds.Ymin > dtmp) dBounds.Ymin = dtmp;
-						if(dBounds.Ymax < dtmp) dBounds.Ymax = dtmp;
-						if(min2 > dtmp) min2 = dtmp;		if(max2 < dtmp) max2 = dtmp;
-						d2[n2++] = dtmp;
+					if(data->GetResult(&ares, r, c, false) && ares.type == ET_VALUE){
+						if(dBounds.Ymin > ares.value) dBounds.Ymin = ares.value;
+						if(dBounds.Ymax < ares.value) dBounds.Ymax = ares.value;
+						if(min2 > ares.value) min2 = ares.value;		if(max2 < ares.value) max2 = ares.value;
+						d2[n2++] = ares.value;
 						}
 					}
 				delete rD;
 				}
+			if(g1_nam[0] && g2_nam[0] && 0==strcmp(g1_nam, g2_nam)) {
+				rlp_strcpy(g1_nam, 30, "Group 1");		rlp_strcpy(g2_nam, 30, "Group 2");
+				}
 			if(!d1 || !d2 || n1 < 2 || n2 < 2) {
 				InfoBox("Insufficient data to calculate means!");
 				bContinue = true;
@@ -1182,25 +1797,24 @@ void rep_compmeans(GraphObj *parent, DataObj *data)
 			graph->DRect.Xmin *= 0.8;					graph->moveable = 0;
 			graph->DRect.Xmax = graph->GRect.Xmax - (txtdef1.fSize*2.0);
 			OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
-			free(txt_obj);								graph->Command(CMD_SCALE, &scale, 0L);
+			if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
+				if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
+					((BoxPlot*)LastOpenGO)->x_tv->GetValue(g1_nam);
+					((BoxPlot*)LastOpenGO)->x_tv->GetValue(g2_nam);
+					}
+				}
+			free(txt_obj);						graph->Command(CMD_SCALE, &scale, 0L);
 			cx = graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0;
 			cy = mk_mean_report(page, cx, graph->GetSize(SIZE_GRECT_TOP), d1, n1, ci, g1_nam);
 			cy = mk_mean_report(page, cx, cy + txtdef1.fSize, d2, n2, ci, g2_nam);
 			cy += linsp1;
-			if(txt_obj = mk_label(graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, 
-				&txtdef1, "<b>t-Test:</b>")) {
-				OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
-				free(txt_obj);								cy += linsp1;
-				}
-			d_ttest(d1, d2, n1, n2, 0L, 0L, rs+15);
+			rep_DrawText(page, graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, "<b>t-Test:</b>");
+			cy += linsp1;						d_ttest(d1, d2, n1, n2, 0L, 0L, rs+15);
 			for(i = 0; i < 3; i++) {
 				switch(i) {
-					case 0:
-						dtmp = rs[24];			break;
-					case 1:
-						dtmp = rs[21];			break;
-					case 2:
-						dtmp = rs[23];			break;
+					case 0:			dtmp = rs[24];			break;
+					case 1:			dtmp = rs[21];			break;
+					case 2:			dtmp = rs[23];			break;
 					}
 #ifdef USE_WIN_SECURE
 				j = sprintf_s(TmpTxt, 80, ttest[i], dtmp);
@@ -1211,10 +1825,8 @@ void rep_compmeans(GraphObj *parent, DataObj *data)
 					while(TmpTxt[j] != '=' && j) j--;
 					rlp_strcpy(TmpTxt+j, 10, "< 0.0001");
 					}
-				if(txt_obj = mk_label(cx+(txtdef1.fSize*3.0), cy, false, TXA_HLEFT, &txtdef1, TmpTxt)) {
-					OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
-					free(txt_obj);							cy += linsp1/1.2;
-					}
+				rep_DrawText(page, cx+(txtdef1.fSize*3.0), cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+				cy += linsp1/1.2;
 				}
 			page->Command(CMD_DROP_GRAPH, graph, 0L);
 			}
@@ -1229,28 +1841,25 @@ void rep_compmeans(GraphObj *parent, DataObj *data)
 			graph->DRect.Xmin *= 0.8;					graph->moveable = 0;
 			graph->DRect.Xmax = graph->GRect.Xmax - (txtdef1.fSize*2.0);
 			OpenGraph(graph, 0L, (unsigned char*)txt_obj, false);
+			if(LastOpenGO && LastOpenGO->Id == GO_BOXPLOT) {
+				if(((BoxPlot*)LastOpenGO)->x_tv = new TextValue()){
+					((BoxPlot*)LastOpenGO)->x_tv->GetValue(g1_nam);
+					((BoxPlot*)LastOpenGO)->x_tv->GetValue(g2_nam);
+					}
+				}
 			free(txt_obj);								graph->Command(CMD_SCALE, &scale, 0L);
 			cy = mk_median_report(page, cx, graph->GetSize(SIZE_GRECT_TOP), d1, n1, .95, g1_nam);
 			cy = mk_median_report(page, cx, cy + txtdef1.fSize, d2, n2, .95, g2_nam);
 			cy += linsp1;
-			if(txt_obj = mk_label(graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, 
-				&txtdef1, "<b>u-Test:</b>")) {
-				OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
-				free(txt_obj);								cy += linsp1;
-				}
-			d_utest(d1, d2, n1, n2, 0L, 0L, rs+15);
+			rep_DrawText(page, graph->GetSize(SIZE_GRECT_RIGHT)+txtdef1.fSize*3.0, cy, false, TXA_HLEFT, &txtdef1, "<b>u-Test:</b>");
+			cy += linsp1;			d_utest(d1, d2, n1, n2, 0L, 0L, rs+15);
 			for(i = 0; i < 5; i++) {
 				switch(i) {
-					case 0:
-						dtmp = rs[17];			break;
-					case 1:
-						dtmp = rs[18];			break;
-					case 2:
-						dtmp = rs[21];			break;
-					case 3:
-						dtmp = rs[22];			break;
-					case 4:
-						dtmp = rs[23];			break;
+					case 0:			dtmp = rs[17];			break;
+					case 1:			dtmp = rs[18];			break;
+					case 2:			dtmp = rs[21];			break;
+					case 3:			dtmp = rs[22];			break;
+					case 4:			dtmp = rs[23];			break;
 					}
 #ifdef USE_WIN_SECURE
 				j = sprintf_s(TmpTxt, 80, utest[i], dtmp);
@@ -1261,15 +1870,14 @@ void rep_compmeans(GraphObj *parent, DataObj *data)
 					while(TmpTxt[j] != '=' && j) j--;
 					rlp_strcpy(TmpTxt+j, 10, "< 0.0001");
 					}
-				if(txt_obj = mk_label(cx+(txtdef1.fSize*3.0), cy, false, TXA_HLEFT, &txtdef1, TmpTxt)) {
-					OpenGraph(page, 0L, (unsigned char*)txt_obj, false);
-					free(txt_obj);							cy += linsp1/1.2;
-					}
+				rep_DrawText(page, cx+(txtdef1.fSize*3.0), cy, false, TXA_HLEFT, &txtdef1, TmpTxt);
+				cy += linsp1/1.2;
 				}
 			page->Command(CMD_DROP_GRAPH, graph, 0L);
 			}
-		parent->Command(CMD_DROP_GRAPH, page, 0L);	free(rs);
+		parent->Command(CMD_DROP_GRAPH, page, 0L);	
+		free(rs);			free(ny);
 		}
-	CloseDlgWnd(hDlg);		delete Dlg;
-	free(MeanDlg);			if(d1) free(d1);	if(d2) free(d2);
+	CloseDlgWnd(hDlg);		delete Dlg;				free(MeanDlg);
+	if(d1) free(d1);		if(d2) free(d2);
 }
diff --git a/rlp_math.cpp b/rlp_math.cpp
index 0f6d86f..80b1def 100755
--- a/rlp_math.cpp
+++ b/rlp_math.cpp
@@ -1,4 +1,4 @@
-//rlp_math.cpp, Copyright (c) 2004-2006 R.Lackner
+//rlp_math.cpp, Copyright (c) 2004-2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -230,7 +230,7 @@ bool Check_MRQerror()
 
 //---------------------------------------------------------------------------
 //Use heap sort to sort elements of an float array
-//W.H. pres, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1988/1989)
+//W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1988/1989)
 //Numerical Recipes in C, Cambridge University Press, ISBN 0-521-35465-X
 // p. 245
 void SortArray(int n, double *vals)
@@ -685,6 +685,206 @@ double f_freq(double x, double df1, double df2)
 	return exp(a-b+c+d);
 }
 
+// Shapiro-Wilk W test and its significance level
+// Algorithm AS 394, 1995, Appl. Statist. 44(4), 547-551
+//
+static int do_swilk(double (*func)(double, double, double), double p1, double p2, 
+	double *x, int n, int n1, int n2, double *a, double *w, double *pw)
+{
+
+//initialized data
+const static double z90 = 1.2816;		//tinv(0.2, inf)
+const static double z95 = 1.6449;		//tinv(0.1, inf)
+const static double z99 = 2.3263;		//tinv(.05, inf)
+const static double zm = 1.7509;		//(z90 + z95 + z99)/3
+const static double zss = 0.56268;
+const static double bf1 = 0.8378;
+const static double xx90 = 0.556;
+const static double xx95 = 0.622;
+const static double sqrth = 0.70711;	//sqrt(0.5)
+const static double smal = 1.0e-19;		//small value
+const static double pi6 = 1.909859;
+const static double stqr = 1.047198;	//pi / 3
+
+//polynomial coefficients
+static double g[2] = {-2.273, 0.459};
+static double c1[6] = {0.0, 0.221157, -0.147981, -2.07119, 4.434685, -2.706056};
+static double c2[6] = {0.0, 0.042981, -0.293762, -1.752461, 5.682633, -3.582633};
+static double c3[4] = {0.544, -0.39978, 0.025054, -6.714e-4};
+static double c4[4] = {1.3822, -0.77857, 0.062767, -0.0020322};
+static double c5[4] = {-1.5861, -0.31082, -0.083751, 0.0038915};
+static double c6[3] = {-0.4803, -0.082676, 0.0030302};
+static double c7[2] = {0.164, 0.533};
+static double c8[2] = {0.1736, 0.315};
+static double c9[2] = {0.256, -0.00635};
+
+	//local variables
+	int i, j, ncens, i1, nn2;
+	double zbar, ssassx, summ2, ssumm2, gamma, delta, range;
+	double a1, a2, an, bf, ld, m, s, sa, xi, sx, xx, y, w1;
+	double fac, asa, an25, ssa, z90f, sax, zfm, z95f, zsd, z99f, rsn, ssx, xsx;
+
+	//parameter adjustment
+	--a;
+
+	*pw = 1.0;
+	if(*w >= 0.0) *w = 1.0;
+	an = (double)(n);			nn2 = n>>1;
+	if(n2 < nn2) return 3;
+	if(n < 3) return 1;
+	// calculate coefficients a[]
+	if(true) {
+		if(n == 3) a[1] = sqrth;
+		else {
+			for(i = 1, summ2 = 0.0, an25 = an + 0.25; i <= n2; ++i) {
+				a[i] = distinv(func, p1, p2, (i-0.375)/an25, 0);
+				summ2 += (a[i] * a[i]);
+				}
+			summ2 *= 2.0;			ssumm2 = sqrt(summ2);
+			rsn = 1.0 / sqrt(an);	a1 = devlpl(c1, 6, rsn) -a[1]/ssumm2;
+			//normalize a[]
+			if(n > 5) {
+				i1 = 3;
+				a2 = -a[2] / ssumm2 + devlpl(c2, 6, rsn);
+				fac = sqrt((summ2 - 2.0*a[1]*a[1] - 2.0*a[2]*a[2])
+					/ (1.0 - 2.0*a1*a1 - 2.0*a2*a2));
+				a[2] = a2;
+				}
+			else {
+				i1 = 2;
+				fac = sqrt((summ2 -2.0*a[1]*a[1]) / (1.0 - 2.0*a1*a1));
+				}
+			a[1] = a1;
+			for(i = i1; i <= nn2; ++i) a[i] /= -fac;
+			} 
+		}
+	if(n1 < 3) return 1;
+	ncens = n - n1;
+	if(ncens < 0 || (ncens > 0 && n < 20)) return 4;
+	delta = (double)ncens / an;
+	if(delta > 0.8) return 5;
+	//if w input as negative, calculate significance level of -w
+	if(*w < 0.0) { 
+		w1 = 1.0 + *w;
+		goto sw_prob;
+		}
+	//check for zero range
+	if((range = x[n1-1] -x[0]) < smal) return 6;
+	//check for sort order
+	xx = x[0]/range;	sx = xx;	sa = -a[1];		j = n -1;
+	for(i = 1; i < n1; --j) {
+		xi = x[i] / range;			sx += xi;			++i;
+		if(i != j) sa += i > j ? a[i < j ? i : j] : -a[i < j ? i : j];
+		xx = xi;
+		}
+	//calculate w statistic as squared correlation between data and coefficients
+	sa /= n1;		sx /= n1;		ssa = ssx = sax = 0.0;		j = n -1;
+	for(i = 0; i < n1; ++i, --j) {
+		if(i > j) asa = a[1+j] - sa;
+		else if(i < j) asa = -a[1+i] - sa;
+		else asa = -sa;
+		xsx = x[i] / range - sx;		ssa += asa * asa;
+		ssx += xsx * xsx;				sax += asa * xsx;
+		}
+	ssassx = sqrt(ssa * ssx);
+	w1 = (ssassx - sax) * (ssassx + sax) / (ssa * ssx);
+sw_prob:
+	*w = 1.0 - w1;			//reduce rounding errors
+	if(n == 3) {
+		*pw = pi6 * (asin(sqrt(*w)) - stqr);
+		return 0;
+		}
+	y = log(w1);
+	xx = log(an);
+	if(n <= 11) {
+		gamma = devlpl(g, 2, an);
+		if(y >= gamma) {
+			*pw = smal;		return 0;
+			}
+		y = -log(gamma - y);		m = devlpl(c3, 4, an);
+		s = exp(devlpl(c4, 4, an));
+		}
+	else {					//n >= 12
+		m = devlpl(c5, 4, xx);		s = exp(devlpl(c6, 3, xx));
+		}
+	//Censoring by proportion  NCENS/N
+	if(ncens > 0) {
+		ld = -log(delta);			bf = 1.0 + xx * bf1;
+		z90f = z90 + bf * pow(devlpl(c7, 2, pow(xx90, xx)), ld);
+		z95f = z95 + bf * pow(devlpl(c8, 2, pow(xx95, xx)), ld);
+		z99f = z99 + bf * pow(devlpl(c9, 2, xx), ld);
+		//Regress z90f ... z99f on normal deviates z90 ... z99
+		//   to get pseudo-mean and pseudo-sd of z as the slope and intercept 
+		zfm = (z90f + z95f + z99f)/3.0;
+		zsd = (z90 * (z90f - zfm) + z95 * (z95f - zfm) + z99 * (z99f - zfm)) / zss;
+		zbar = zfm - zsd * zm;		m += zbar * s;		s *= zsd;
+		}
+	*pw = 1.0 - norm_dist(y, m, s);
+	return 0;
+}
+
+void swilk1(int n, double *v0, double (*func)(double, double, double), double p1, double p2, 
+	bool bsorted, double *w, double *p)
+{
+	double *v, *a;
+
+	if(!n || !w || !p) return;			*w = *p = 1.0;
+	if(!(a = (double*)malloc(n *sizeof(double)))) return;
+	if(!bsorted && (v = (double*)memdup(v0, n*sizeof(double), 0)))SortArray(n, v);
+	else if(bsorted) v = v0;
+	else return;
+	if(do_swilk(func, p1, p2, v, n, n, n>>1, a, w, p)){
+		//an error occured
+		*w = *p = -1.0;
+		}
+	free(a);	if(v != v0) free(v);
+}
+
+//Kolmogorov-Smirnov's test and distribution of D
+// (1) Miller L. (1956) Journal of the American Statistical Association.  51: 111-121
+// (2) Mises R. (1964) Mathematical Theory of Probability and Statistics (New York: Academic Press)
+//     Chapters IX(C) and IX(E)
+// (3) Press W.H., Flannery B.P.,Teukolsky S.A., Vetterling W.T. (1988/1989)
+//     Numerical Recipes in C, Cambridge University Press, ISBN 0-521-35465-X, pp. 490 ff.
+//
+double ks_dist(int n, double d)
+{
+	double j, jn, sum, las, q, r, s, dn = (double)n;
+
+	las = floor(dn - dn * d);
+	for (j = sum = 0.0; j <= las; j += 1.0) {
+		jn = j / dn;							q = gammln(dn+1) - gammln(j+1) - gammln(dn-j+1.0);
+		r = (dn - j) * log( 1 - d - jn );		s = (j - 1.0) * log( d + jn );
+		sum += exp(q + r + s);
+		}
+	return(d*sum);
+}
+
+void KolSmir(int n, double *v0, double (*func)(double, double, double), double p1, double p2, 
+	bool bsorted, double *d, double *p)
+{
+	int i;
+	double *v, *dev, *x, ff, dt, dt1, dt2;
+	double dn = (double)n, f0 = 0.0;
+
+	if(!n || !d || !p) return;			*d = *p = 0.0;
+	if(!(dev = (double*)malloc(n*sizeof(double)))) return;
+	if(!(x = (double*)malloc(n*sizeof(double)))){
+		free(dev);						return;
+		}
+	if(!bsorted && (v = (double*)memdup(v0, n*sizeof(double), 0)))SortArray(n, v);
+	else if(bsorted) v = v0;
+	else return;
+	for(i = 0, *d = 0.0; i < n; i++) {
+		x[i] = (double)(i+1)/dn;		ff = (*func)(v[i], p1, p2); 
+		dt1 = fabs(f0-ff);				dt2 = fabs(dev[i] = (f0 = x[i])-ff);
+		dt = dt1 > dt2 ? dt1 : dt2;		if(dt > *d) *d = dt;
+		}
+	free(dev);	free(x);
+	*p = ks_dist(n, *d);
+	if(v != v0) free(v);
+}
+
 //---------------------------------------------------------------------------
 // Inverse of statitistical functions:
 // funcd supplies the function value fn and the derivative df of the function sf at x
@@ -698,10 +898,9 @@ void funcd(double x, double *fn, double *df, double (*sf)(double, double, double
 	else if(sf == chi_dist) *df = -chi_freq(x, df1);
 	else if(sf == t_dist) *df = -2.0 * t_freq(x, df1);
 	else if(sf == f_dist) *df = -1.0 * f_freq(x, df1, df2);
-//	if(true){
+	else if(sf == lognorm_dist) *df = lognorm_freq(x, df1, df2);
 	else {
-		y1 = (sf)(x * 0.995, df1, df2);
-		y2 = (sf)(x * 1.005, df1, df2);
+		y1 = (sf)(x * 0.995, df1, df2);		y2 = (sf)(x * 1.005, df1, df2);
 		*df = (y2-y1)*100.0/x;
 		}
 	*fn = *fn - p;
@@ -711,19 +910,19 @@ void funcd(double x, double *fn, double *df, double (*sf)(double, double, double
 double distinv(double (*sf)(double, double, double), double df1, double df2, double p, double x0)
 {
 	int i, j;
-	double df, dx, f, rtn;
+	double df, df0, adf, dx, f, rtn;
 
-	for(j = 0, rtn = dx = x0; j < 100; j++) {
-		for( i= 0; i < 100; i++) {
+	for(j = 0, rtn = dx = x0; j < 200; j++) {
+		for(i = 0, df0 = 0.0; i < 20; i++) {
 			funcd(rtn, &f, &df, sf, df1, df2, p);
-			if(fabs(df) > 1.0e-12) break;
-			rtn += (dx = dx/2.0);
-			if(i >= 99) return HUGE_VAL;
+			if((adf=fabs(df)) > 1.0e-12 || df0 > adf) break;
+			rtn += (dx = dx/2.0);				df0 = adf;
+			if(i >= 19) return HUGE_VAL;
 			}
-		dx = f/df*(0.01*(double)(100-j));					rtn -= dx;
-		if(fabs(dx) < _PREC && j > 3) return rtn; 
+		dx = f/df*(0.01*(double)(100-j));		rtn -= dx;
+		if(fabs(dx) < _PREC && j > 3)return rtn; 
 		}
-	return rtn;
+	return HUGE_VAL;
 }
 
 //---------------------------------------------------------------------------
@@ -842,14 +1041,7 @@ double d_skew(int n, double *v)
 {
 	double sum, avg, sd, tmp, dn = n;
 	int i;
-//	double x, skew;
-
-//	sd = sqrt(d_variance(n, v, &avg, 0L));
-//	for(i = 0, skew = 0.0; i < n; i++){
-//		x = (v[i]-avg)/sd;
-//		skew += (x*x*x - skew)/((double)(i+1));
-//		}
-//	return skew;
+
 	for(i = 0, avg = 0.0; i < n; i++) avg += ((v[i]-avg)/((double)(i+1)));
 	for(i = 0, sum = 0.0; i < n; i++) sum += (tmp = v[i]-avg) * tmp;
 	for(i = 0, sd = sqrt(sum/(dn-1.0)), sum=0.0; i < n; i++) sum += ((tmp = (v[i]-avg)/sd)*tmp*tmp);
@@ -886,13 +1078,14 @@ double d_classes(DataObj *d, double start, double step, double *v, int nv, char
 //    Numerical Rcipies in C. The Art of Scientific Computing, 
 //    Cambridge University Press, ISBN 0-521-35465, pp. 503 ff.
 // (2) B. Gough (2000), linear.c, gsl-1.7 the GNU scientific library
-double d_pearson(double *x, double *y, int n, char *dest, DataObj *data)
+double d_pearson(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
 {
 	int j, r, c;
 	double yt, xt, t, df, res[4];
 	double syy=0.0, sxy=0.0, sxx=0.0, ay=0.0, ax=0.0;
 	AccRange *rD;
 
+
 	for(j = 0;	j < n; j++) {				// find means
 		ax += (x[j] - ax) / (j+1);			ay += (y[j] - ay) / (j+1);
 		}
@@ -902,7 +1095,7 @@ double d_pearson(double *x, double *y, int n, char *dest, DataObj *data)
 		sxy += (xt*yt-sxy) / (j+1);
 		}
 	res[0] = sxy/sqrt(sxx*syy);				//pearsons r
-	if(dest) {
+	if(dest || ra) {
 		res[1] = 0.5 * log((1.0+res[0]+_PREC)/(1.0-res[0]+_PREC));	//Fishers z-transform
 		df = n-2;
 		t = res[0]*sqrt(df/((1.0-res[0]+_PREC)*(1.0+res[0]+_PREC)));	//Student's t
@@ -917,6 +1110,9 @@ double d_pearson(double *x, double *y, int n, char *dest, DataObj *data)
 		data->Command(CMD_UPDATE, 0L, 0L);
 		delete rD;
 		}
+	if (ra){
+		memcpy(ra, res, 4 * sizeof(double));
+		}
 	return res[0];
 }
 
@@ -968,35 +1164,40 @@ void crank(int n, double *w0, double *s)
 }
 
 //the actual rank correlation
-double d_spearman(double *x, double *y, int n, char *dest, DataObj *data)
+double d_spearman(double *sx, double *sy, int n, char *dest, DataObj *data, double *ra)
 {
 	int j, r, c;
-	double vard, t, sg, sf, fac, en3n, en, df, aved, tmp;
+	double *x, *y, vard, t, sg, sf, fac, en3n, en, df, aved, tmp;
 	double res[6];
 	AccRange *rD;
 
-	SortArray2(n, x, y);		crank(n, x, &sf);
-	SortArray2(n, y, x);		crank(n, y, &sg);
+	if(!(x = (double*)memdup(sx, n*sizeof(double), 0)) 
+		|| !(y = (double*)memdup(sy, n*sizeof(double), 0)))return 0.0;
+	SortArray2(n, x, y);			crank(n, x, &sf);
+	SortArray2(n, y, x);			crank(n, y, &sg);
 	for(j = 0, res[0] = 0.0; j < n; j++) res[0] += ((tmp = (x[j]-y[j]))*tmp);
 	en = n;						en3n = en*en*en -en;
 	aved = en3n/6.0 - (sf+sg)/12.0;
 	fac = (1.0-sf/en3n)*(1.0-sg/en3n);
-	vard = ((en-1.0)*en*en*((en+1.0)*(en+1.0))/36.0)*fac;
 	vard = ((en-1.0)*en*en*((tmp = (en+1.0))*tmp)/36.0)*fac;
 	res[1] = (res[0]-aved)/sqrt(vard);
 	res[2] = errfc(fabs(res[1])/_SQRT2);
 	res[3] = (1.0-(6.0/en3n)*(res[0]+0.5*(sf+sg)))/fac;
 	t = res[3]*sqrt((en-2.0)/((res[3]+1.0)*(1.0-res[3])));
-	df = en-2.0;
+	df = en-2.0;	res[5] = (double)n;
     res[4] = betai(0.5*df, 0.5, df/(df+t*t));
 	if((dest) && (data) && (rD = new AccRange(dest))) {
-		rD->GetFirst(&c, &r);	res[5] = n;
+		rD->GetFirst(&c, &r);
 		for(j = 0; j < 6 && rD->GetNext(&c, &r); j++) {
 			data->SetValue(r, c, res[j]);
 			}
 		data->Command(CMD_UPDATE, 0L, 0L);
 		delete rD;
 		}
+	if(ra) {
+		memcpy(ra, res, 6 * sizeof(double));
+		}
+	free(x);						free(y);
 	return res[3];
 }
 
@@ -1006,7 +1207,7 @@ double d_spearman(double *x, double *y, int n, char *dest, DataObj *data)
 //    Numerical Recipies in C. The Art of Scientific Computing, 
 //    Cambridge University Press, ISBN 0-521-35465, pp. 510 ff.
 
-double d_kendall(double *x, double *y, int n, char *dest, DataObj *data)
+double d_kendall(double *x, double *y, int n, char *dest, DataObj *data, double *ra)
 {
 	int j, k, n1, n2, is, r, c;
 	double aa, a1, a2, sv, res[4];
@@ -1026,16 +1227,20 @@ double d_kendall(double *x, double *y, int n, char *dest, DataObj *data)
 			}
 		}
 	res[0] = ((double)is)/(sqrt((double)n1) * sqrt((double)n2));
+	sv = (4.0 * ((double)n) + 10.0)/(9.0*((double)n)*((double)(n-1)));
+	res[1] = res[0]/sqrt(sv);	res[2] = errfc(fabs(res[1])/_SQRT2);
+	res[3] = n;			
 	if((dest) && (data) && (rD = new AccRange(dest))) {
-		sv = (4.0 * ((double)n) + 10.0)/(9.0*((double)n)*((double)(n-1)));
-		res[1] = res[0]/sqrt(sv);	res[2] = errfc(fabs(res[1])/_SQRT2);
-		res[3] = n;			rD->GetFirst(&c, &r);
+		rD->GetFirst(&c, &r);
 		for(j = 0; j < 4 && rD->GetNext(&c, &r); j++) {
 			data->SetValue(r, c, res[j]);
 			}
 		data->Command(CMD_UPDATE, 0L, 0L);
 		delete rD;
 		}
+	if (ra){
+		memcpy(ra, res, 4 * sizeof(double));
+		}
 	return res[0];
 }
 
@@ -1246,9 +1451,367 @@ double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 		}
 	return p;
 }
+//---------------------------------------------------------------------------
+// Modules from the R-project
+//
+//---------------------------------------------------------------------------
+#define M_1_SQRT_2PI	0.398942280401432677939946059934	/* 1/sqrt(2pi) */
+#define M_LN2 log(2.0)
+/*
+ *  Copyright (C) 1998       Ross Ihaka
+ *  Copyright (C) 2000--2005 The R Development Core Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *  DESCRIPTION
+ *    Computes the probability that the maximum of rr studentized
+ *    ranges, each based on cc means and with df degrees of freedom
+ *    for the standard error, is less than q.
+ *    The algorithm is based on that of the reference.
+ *
+ *  REFERENCE
+ *    Copenhaver, Margaret Diponzio & Holland, Burt S.
+ *    Multiple comparisons of simple effects in
+ *    the two-way analysis of variance with fixed effects.
+ *    Journal of Statistical Computation and Simulation,
+ *    Vol.30, pp.1-15, 1988.
+ */
+
+double wprob(double w, double rr, double cc)
+{
+/*  wprob() :
+
+	This function calculates probability integral of Hartley's
+	form of the range.
+
+	w     = value of range
+	rr    = no. of rows or groups
+	cc    = no. of columns or treatments
+	ir    = error flag = 1 if pr_w probability > 1
+	pr_w = returned probability integral from (0, w)
+
+	program will not terminate if ir is raised.
+
+	bb = upper limit of legendre integration
+	iMax = maximum acceptable value of integral
+	nleg = order of legendre quadrature
+	ihalf = int ((nleg + 1) / 2)
+	wlar = value of range above which wincr1 intervals are used to
+	       calculate second part of integral,
+	       else wincr2 intervals are used.
+	C1, C2, C3 = values which are used as cutoffs for terminating
+           or modifying a calculation.
+	xleg = legendre 12-point nodes
+	aleg = legendre 12-point coefficients
+ */
+#define nleg	12
+#define ihalf	6
+
+    /* looks like this is suboptimal for double precision.
+       (see how C1-C3 are used) <MM> */
+    /* const double iMax  = 1.; not used if = 1*/
+    const static double C1 = -30.0, C2 = -50.0, C3 = 60.;
+    const static double bb = 8.0, wlar = 3.0, wincr1 = 2.0, wincr2 = 3.;
+    const static double xleg[ihalf] = {	0.981560634246719250690549090149,
+	0.904117256370474856678465866119,	0.769902674194304687036893833213,
+	0.587317954286617447296702418941,	0.367831498998180193752691536644,
+	0.125233408511468915472441369464};
+    const static double aleg[ihalf] = {	0.047175336386511827194615961485,
+	0.106939325995318430960254718194,	0.160078328543346226334652529543,
+	0.203167426723065921749064455810,	0.233492536538354808760849898925,
+	0.249147045813402785000562436043};
+    double a, ac, pr_w, b, binc, blb, bub, c, cc1, einsum, elsum,
+		pminus, pplus, qexpo, qsqz, rinsum, wi, wincr, xx;
+    int j, jj;
+
+    qsqz = w * 0.5;
+
+    // if w >= 16 then the integral lower bound (occurs for c=20)
+    // is 0.99999999999995 so return a value of 1
+	if (qsqz >= bb)	return 1.0;
+
+	// find (f(w/2) - 1) ^ cc
+    // (first term in integral of hartley's form). 
+	pr_w = 2.0 * norm_dist(qsqz, 0.0, 1.0) -1.0;
+    // if pr_w ^ cc < 2e-22 then set pr_w = 0 
+    if (pr_w >= exp(C2 / cc)) pr_w = pow(pr_w, cc);
+    else pr_w = 0.0;
+    // if w is large then the second component of the
+    // integral is small, so fewer intervals are needed.
+    if (w > wlar) wincr = wincr1;
+    else wincr = wincr2;
+
+    /* find the integral of second term of hartley's form */
+    /* for the integral of the range for equal-length */
+    /* intervals using legendre quadrature.  limits of */
+    /* integration are from (w/2, 8).  two or three */
+    /* equal-length intervals are used. */
+    /* blb and bub are lower and upper limits of integration. */
+    blb = qsqz;			    binc = (bb - qsqz) / wincr;
+    bub = blb + binc;	    einsum = 0.0;
+
+    // integrate over each interval
+    cc1 = cc - 1.0;
+    for (wi = 1; wi <= wincr; wi++) {
+		elsum = 0.0;		a = 0.5 * (bub + blb);
+		// legendre quadrature with order = nleg
+		b = 0.5 * (bub - blb);
+		for (jj = 1; jj <= nleg; jj++) {
+			if (ihalf < jj) {
+				j = (nleg - jj) + 1;		xx = xleg[j-1];
+				}
+			else {
+				j = jj;						xx = -xleg[j-1];
+				}
+			c = b * xx;					    ac = a + c;
+			// if exp(-qexpo/2) < 9e-14, then doesn't contribute to integral
+			if ((qexpo = ac * ac) > C3) break;
+			pplus = 2.0 * norm_dist(ac, 0.0, 1.0);    pminus= 2.0 * norm_dist(ac, w, 1.0);
+			// if rinsum ^ (cc-1) < 9e-14, then doesn't contribute to integral
+			rinsum = (pplus * 0.5) - (pminus * 0.5);
+			if (rinsum >= exp(C1 / cc1)) {
+				rinsum = (aleg[j-1] * exp(-(0.5 * qexpo))) * pow(rinsum, cc1);
+				elsum += rinsum;
+				}
+			}
+		elsum *= (((2.0 * b) * cc) * M_1_SQRT_2PI);
+		einsum += elsum;		blb = bub;			bub += binc;
+		}
+	// if pr_w ^ rr < 9e-14, then return 0 */
+	pr_w = einsum + pr_w;
+	if (pr_w <= exp(C1 / rr))return 0.;
+    pr_w = pow(pr_w, rr);
+ 	return pr_w < 1.0 ? pr_w : 1.0;
+}
+
+double ptukey(double q, double rr, double cc, double df, int lower_tail, int log_p)
+{
+/* 	q = value of studentized range
+	rr = no. of rows or groups
+	cc = no. of columns or treatments
+	df = degrees of freedom of error term
+	ir[0] = error flag = 1 if wprob probability > 1
+	ir[1] = error flag = 1 if qprob probability > 1
+
+	All references in wprob to Abramowitz and Stegun
+	are from the following reference:
+		Abramowitz, Milton and Stegun, Irene A.
+		Handbook of Mathematical Functions.
+		New York:  Dover publications, Inc. (1970).
+	All constants taken from this text are given to 25 significant digits.
+
+	nlegq = order of legendre quadrature
+	ihalfq = int ((nlegq + 1) / 2)
+	eps = max. allowable value of integral
+	eps1 & eps2 = values below which there is no contribution to integral.
+
+	d.f. <= dhaf:	integral is divided into ulen1 length intervals.  else
+	d.f. <= dquar:	integral is divided into ulen2 length intervals.  else
+	d.f. <= deigh:	integral is divided into ulen3 length intervals.  else
+	d.f. <= dlarg:	integral is divided into ulen4 length intervals.
+
+	d.f. > dlarg:	the range is used to calculate integral.
+
+	xlegq = legendre 16-point nodes
+	alegq = legendre 16-point coefficients
+
+	The coefficients and nodes for the legendre quadrature used in
+	qprob and wprob were calculated using the algorithms found in:
+		Stroud, A. H. and Secrest, D.,	Gaussian Quadrature Formulas.
+		Englewood Cliffs, New Jersey:  Prentice-Hall, Inc, 1966.
+
+	All values matched the tables (provided in same reference)
+	to 30 significant digits.
+
+	f(x) = .5 + erf(x / sqrt(2)) / 2      for x > 0
+	f(x) = erfc( -x / sqrt(2)) / 2	      for x < 0
+	where f(x) is standard normal c. d. f.
+
+	if degrees of freedom large, approximate integral with range distribution.
+ */
+#define nlegq	16
+#define ihalfq	8
+
+/*  const double eps = 1.0; not used if = 1 */
+    const static double eps1 = -30.0, eps2 = 1.0e-14;
+    const static double dhaf  = 100.0, dquar = 800.0, deigh = 5000.0, dlarg = 25000.0;
+    const static double ulen1 = 1.0, ulen2 = 0.5, ulen3 = 0.25, ulen4 = 0.125;
+    const static double xlegq[ihalfq] = { 0.989400934991649932596154173450,
+	0.944575023073232576077988415535, 0.865631202387831743880467897712,
+	0.755404408355003033895101194847, 0.617876244402643748446671764049,
+	0.458016777657227386342419442984, 0.281603550779258913230460501460,
+	0.950125098376374401853193354250e-1};
+    const static double alegq[ihalfq] = {0.271524594117540948517805724560e-1,
+	0.622535239386478928628438369944e-1, 0.951585116824927848099251076022e-1,
+	0.124628971255533872052476282192, 0.149595988816576732081501730547,
+	0.169156519395002538189312079030, 0.182603415044923588866763667969,
+	0.189450610455068496285396723208};
+    double ans, f2, f21, f2lf, ff4, otsum, qsqz, rotsum, t1, twa1, ulen, wprb;
+    int i, j, jj;
+
+    if (df > dlarg)	return wprob(q, rr, cc);
+    f2 = df * 0.5;								// calculate leading constant
+    f2lf = ((f2 * log(df)) - (df * M_LN2)) - gammln(f2);
+    f21 = f2 - 1.0;
+    // integral is divided into unit, half-unit, quarter-unit, or eighth-unit length intervals 
+	//    depending on the value of the degrees of freedom.
+    ff4 = df * 0.25;
+    if	    (df <= dhaf)	ulen = ulen1;
+    else if (df <= dquar)	ulen = ulen2;
+    else if (df <= deigh)	ulen = ulen3;
+    else					ulen = ulen4;
+    f2lf += log(ulen);
+    for (i = 1, ans = 0.0; i <= 50; i++) {		// integrate over each subinterval
+		otsum = 0.0;
+		// legendre quadrature with order = nlegq, nodes (stored in xlegq) are symmetric around zero.
+		twa1 = (2 * i - 1) * ulen;
+		for (jj = 1; jj <= nlegq; jj++) {
+			if (ihalfq < jj) {
+				j = jj - ihalfq - 1;
+				t1 = (f2lf + (f21 * log(twa1 + (xlegq[j] * ulen)))) - (((xlegq[j] * ulen) + twa1) * ff4);
+				} 
+			else {
+				j = jj - 1;
+				t1 = (f2lf + (f21 * log(twa1 - (xlegq[j] * ulen)))) + (((xlegq[j] * ulen) - twa1) * ff4);
+				}
+			if (t1 >= eps1) {			// if exp(t1) < 9e-14, then doesn't contribute to integral 
+				if (ihalfq < jj) qsqz = q * sqrt(((xlegq[j] * ulen) + twa1) * 0.5);
+				else qsqz = q * sqrt(((-(xlegq[j] * ulen)) + twa1) * 0.5);
+				wprb = wprob(qsqz, rr, cc);		// call wprob to find integral of range portion
+				rotsum = (wprb * alegq[j]) * exp(t1);			otsum += rotsum;
+				}
+			}									// end legendre integral for interval i
+		// If integral for interval i < 1e-14, then stop. However, in order to avoid small area 
+		//    under left tail, at least  1 / ulen  intervals are calculated.
+		if (i * ulen >= 1.0 && otsum <= eps2) break;
+		ans += otsum;							//end of interval i 
+		}
+	return ans > 1.0 ? 1.0 : ans;
+ }
+
+ /*
+ *  Copyright (C) 1998 	     Ross Ihaka
+ *  Copyright (C) 2000--2005 The R Development Core Team
+ *  based in part on AS70 (C) 1974 Royal Statistical Society
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ *  DESCRIPTION
+ *	Computes the quantiles of the maximum of rr studentized
+ *	ranges, each based on cc means and with df degrees of freedom
+ *	for the standard error, is less than q.
+ *	The algorithm is based on that of the reference.
+ *
+ *  REFERENCE
+ *	Copenhaver, Margaret Diponzio & Holland, Burt S., Multiple comparisons of simple
+ *	effects in the two-way analysis of variance with fixed effects.
+ *	Journal of Statistical Computation and Simulation, Vol.30, pp.1-15, 1988.
+ */
+
+/* qinv() :
+ *	this function finds percentage point of the studentized range
+ *	which is used as initial estimate for the secant method.
+ *	function is adapted from portion of algorithm as 70
+ *	from applied statistics (1974) ,vol. 23, no. 1
+ *	by odeh, r. e. and evans, j. o.
+ *	  p = percentage point
+ *	  c = no. of columns or treatments
+ *	  v = degrees of freedom
+ *	  qinv = returned initial estimate
+ *	vmax is cutoff above which degrees of freedom
+ *	is treated as infinity.
+ */
+
+static double qinv(double p, double c, double v)
+{
+    const static double p0 = 0.322232421088, q0 = 0.993484626060e-01;
+    const static double p1 = -1.0, q1 = 0.588581570495;
+    const static double p2 = -0.342242088547, q2 = 0.531103462366;
+    const static double p3 = -0.204231210125, q3 = 0.103537752850;
+    const static double p4 = -0.453642210148e-04, q4 = 0.38560700634e-02;
+    const static double c1 = 0.8832, c2 = 0.2368, c3 = 1.214, c4 = 1.208, c5 = 1.4142;
+    const static double vmax = 120.0;
+    double ps, q, t, yi;
+
+    ps = 0.5 - 0.5 * p;
+    yi = sqrt (log (1.0 / (ps * ps)));
+    t = yi + (((( yi * p4 + p3) * yi + p2) * yi + p1) * yi + p0)
+	   / (((( yi * q4 + q3) * yi + q2) * yi + q1) * yi + q0);
+    if (v < vmax) t += (t * t * t + t) / v / 4.0;
+    q = c1 - c2 * t;
+    if (v < vmax) q += -c3 / v + c4 * t / v;
+    return t * (q * log (c - 1.0) + c5);
+}
+
+/*
+ *  Copenhaver, Margaret Diponzio & Holland, Burt S.
+ *  Multiple comparisons of simple effects in
+ *  the two-way analysis of variance with fixed effects.
+ *  Journal of Statistical Computation and Simulation,
+ *  Vol.30, pp.1-15, 1988.
+ *
+ *  Uses the secant method to find critical values.
+ *
+ *  p = confidence level (1 - alpha)
+ *  rr = no. of rows or groups
+ *  cc = no. of columns or treatments
+ *  df = degrees of freedom of error term
+ *
+ */
+double qtukey(double p, double rr, double cc, double df, int lower_tail, int log_p)
+{
+    const int maxiter = 50;
+    double ans = HUGE_VAL, valx0, valx1, x0, x1;
+    int iter;
+
+    // df must be > 1 ; there must be at least two values 
+	if(p >= 1.0 || df < 2 || rr < 1 || cc < 2) return HUGE_VAL;
+	if(p < 0.0) p = 0.0;
+    x0 = qinv(p, cc, df);									// Initial value
+    valx0 = ptukey(x0, rr, cc, df, true, false) - p;		// Find prob(value < x0)
+    // Find the second iterate and prob(value < x1). If the first iterate has probability value 
+    // exceeding p then second iterate is 1 less than first iterate; otherwise it is 1 greater.
+	x1 = valx0 > 0.0 ? (x1 = x0 > 1.0 ? x0-1.0 : 0.0) : (x0 + 1.0);
+    valx1 = ptukey(x1, rr, cc, df, true, false) - p;
+    for(iter=1; iter < maxiter ; iter++) {					// Iterate
+		ans = x1 - ((valx1 * (x1 - x0)) / (valx1 - valx0));
+		valx0 = valx1;		x0 = x1;
+		if (ans < 0.0) {									// New iterate must be >= 0
+			ans = 0.0;			valx1 = -p;
+			}
+		valx1 = ptukey(ans, rr, cc, df, true, false) - p;	//  Find prob(value < new iterate)
+		x1 = ans;
+		if (fabs(x1 - x0) < _PREC)	return ans;				// Convergence ?
+		}
+    //The process did not converge in 'maxiter' iterations 
+    return ans;
+}
+//---------------------------------------------------------------------------
+// END Modules from the R-project
+
 
 //---------------------------------------------------------------------------
-// Calendar, Date- and time functions
+// Calendar, Date- and Time functions
 // The following characters are used as format specifiers in a format string,
 //    all other characters are either ignored or copyied to the output
 //
diff --git a/rlplot.cpp b/rlplot.cpp
index 5084b18..aa95e1e 100755
--- a/rlplot.cpp
+++ b/rlplot.cpp
@@ -223,7 +223,6 @@ Symbol::DoPlot(anyOutput *target)
 	POINT pts[5];
 	FillDEF cf;
 
-	if(size <= 0.001) return;
 	atype = (type  & 0xfff);
 	memcpy(&cf, &SymFill, sizeof(FillDEF));
 	if(atype == SYM_CIRCLEF || atype == SYM_RECTF || atype == SYM_TRIAUF ||
@@ -240,22 +239,23 @@ Symbol::DoPlot(anyOutput *target)
 	default:
 	case SYM_CIRCLE:		//circle
 	case SYM_CIRCLEF:		//filled circle
-		rx = target->un2ix(size/2.0);		ry = target->un2iy(size/2.0); 
+		rx = target->un2ix(size/2.0);		ry = target->un2iy(size/2.0);
+		if(rx < 5) rx = 1;					if(ry < 5) ry = 1;
 		target->SetFill(&cf);
 		target->oCircle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
 		rx--;ry--;			//smaller marking rectangle
 		break;
 	case SYM_RECT:			//rectange (square)
 	case SYM_RECTF:			//filled rectangle
-		rx = target->un2ix(size/2.25676);
-		ry = target->un2iy(size/2.25676);
+		rx = target->un2ix(size/2.25676);	ry = target->un2iy(size/2.25676);
+		if(rx < 5) rx = 1;					if(ry < 5) ry = 1;
 		target->SetFill(&cf);
 		target->oRectangle(ix-rx, iy-ry, ix+rx+1, iy+ry+1, name);
 		break;
 	case SYM_TRIAU:			//triangles up and down, open or closed
 	case SYM_TRIAUF:	case SYM_TRIAD:		case SYM_TRIADF:
-		rx = target->un2ix(size/1.48503);
-		ry = target->un2iy(size/1.48503);
+		rx = target->un2ix(size/1.48503);	ry = target->un2iy(size/1.48503);
+		if(rx < 5) rx = 1;					if(ry < 5) ry = 1;
 		target->SetFill(&cf);
 		pts[0].x = pts[3].x = ix - rx;		pts[1].x = ix;		pts[2].x = ix+rx;
 		if(atype == SYM_TRIAU || atype == SYM_TRIAUF) {		//patch by anonymous
@@ -270,8 +270,8 @@ Symbol::DoPlot(anyOutput *target)
 		rx--; ry--;
 		break;
 	case SYM_DIAMOND:	case SYM_DIAMONDF:
-		rx = target->un2ix(size/1.59588f);
-		ry = target->un2iy(size/1.59588f);
+		rx = target->un2ix(size/1.59588f);	ry = target->un2iy(size/1.59588f);
+		if(rx < 5) rx = 1;					if(ry < 5) ry = 1;
 		target->SetFill(&cf);
 		pts[0].x = pts[2].x = pts[4].x = ix;		
 		pts[0].y = pts[4].y = iy -ry;
@@ -283,8 +283,8 @@ Symbol::DoPlot(anyOutput *target)
 	case SYM_STAR:			//star is a combination of + and x symbols
 	case SYM_PLUS:			//draw a + sign
 	case SYM_HLINE:		case SYM_VLINE:
-		rx = target->un2ix(size/2.0f);
-		ry = target->un2iy(size/2.0f);
+		rx = target->un2ix(size/2.0f);		ry = target->un2iy(size/2.0f);
+		if(rx < 5) rx = 1;					if(ry < 5) ry = 1;
 		pts[0].x = pts[1].x = ix;
 		pts[0].y = iy - ry;					pts[1].y = iy + ry +1;
 		if(type != SYM_HLINE) target->oPolyline(pts, 2);
@@ -295,8 +295,8 @@ Symbol::DoPlot(anyOutput *target)
 		if(atype == SYM_HLINE){ ry = 2; break;}
 		if(atype == SYM_PLUS) break;		//continue with x symbol for star
 	case SYM_CROSS:			//draw a x symbol
-		rx = target->un2ix(size/2.5);
-		ry = target->un2iy(size/2.5);
+		rx = target->un2ix(size/2.5);		ry = target->un2iy(size/2.5);
+		if(rx < 5) rx = 1;					if(ry < 5) ry = 1;
 		pts[0].x = ix - rx;					pts[1].x = ix + rx;
 		pts[0].y = iy - ry;					pts[1].y = iy + ry;
 		target->oPolyline(pts, 2);
@@ -1034,8 +1034,10 @@ DataLine::DoPlot(anyOutput *target)
 	if (nPntSet >= nPnt) nPntSet = nPnt-1;
 	if(mo) DelBitmapClass(mo);		mo = 0L;
 	if(pts) free(pts);				pts = 0L;
-	if((type & 0xff) == 9 || (type & 0xff) == 10) //splines
+	if((type & 0xff) == 9 || (type & 0xff) == 10)	//splines
 		pts = (POINT *)malloc(sizeof(POINT)*1000);
+	else if((type & 0xff) == 11)					// curve
+		pts = (POINT *) malloc(sizeof(POINT)* (nPntSet+2)*192);
 	else if(type & 0xff) pts = (POINT *)malloc(sizeof(POINT)*(nPntSet+2)*2);
 	else pts = (POINT *)malloc(sizeof(POINT)*(nPntSet+2));
 	if(!pts) return;
@@ -1137,6 +1139,9 @@ DataLine::DoPlot(anyOutput *target)
 	case 9:		case 10:
 		DrawSpline(target);
 		break;
+	case 11:
+		DrawCurve(target);
+		break;
 		}
 	if(cp < 2) return;
 	if(isPolygon) {			//for mark polygon only !!
@@ -1307,13 +1312,33 @@ DataLine::LineData(lfPOINT *val, long nval)
 		}
 	else if(!Undo.busy) Undo.DataMem(this, (void**)&Values, nPnt * sizeof(lfPOINT), &nPnt, UNDO_CONTINUE);
 	memcpy(Values, val, nval * sizeof(lfPOINT));
-	if(pts) free(pts);			pts = 0L;				dirty = true;			
+	if(pts) free(pts);			pts = 0L;					dirty = true;			
 	free(val);					nPnt = nval;				nPntSet = nPnt-1;
 }
 
 void
 DataLine::DrawCurve(anyOutput *target)
 {
+	lfPOINT *sdata, *bdata;
+	POINT *tmppts;
+	int i, j, n;
+
+	if(!(sdata = (lfPOINT *)malloc(nPnt * sizeof(lfPOINT))))return;
+	sdata[0].fx = Values[0].fx;				sdata[0].fy = Values[0].fy;
+	for(i = j = 1; i < nPnt; i++) {
+		if(Values[i].fx != sdata[j-1].fx || Values[i].fy != sdata[j-1].fy) {
+			sdata[j].fx = Values[i].fx;		sdata[j++].fy = Values[i].fy;
+			}
+		}
+	n = mkCurve(sdata, j, &bdata, false);
+	if(!(tmppts = (POINT*)malloc((n+2)*sizeof(POINT))))return;
+	for(i = 0; i < n; i++){
+		tmppts[i].x = target->fx2ix(bdata[i].fx);	tmppts[i].y = target->fy2iy(bdata[i].fy);
+		}
+	for(i = cp = 0; i< (n-2); i += 3) {
+		DrawBezier(&cp, pts, tmppts[i], tmppts[i+1], tmppts[i+2], tmppts[i+3], 0);
+		}
+	if(bdata) free(bdata);	free(sdata);
 }
 
 void
@@ -3881,7 +3906,7 @@ Plane3D::DoPlot(anyOutput *o)
 
 	if(ipl) delete ipl;		ipl = 0L;
 	if(pts) free(pts);		pts = 0L;
-	o->ActualSize(&rDims);
+	if(!(o->ActualSize(&rDims)))return;
 	rDims.left = rDims.right;	rDims.top = rDims.bottom;
 	rDims.right = rDims.bottom = 0;
 	if((pts = (fPOINT3D*)malloc(sizeof(fPOINT3D)*ndt))){
@@ -3923,7 +3948,10 @@ Plane3D::Command(int cmd, void *tmpl, anyOutput *o)
 		return true;
 	case CMD_LEGEND:
 		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
-		((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
+		if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH) {
+			((Legend*)tmpl)->HasFill(&Line, &Fill, ((Plot*)parent)->data_desc);
+			}
+		else ((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
 		break;
 	case CMD_MRK_DIRTY:
 		if(parent) return parent->Command(cmd, tmpl, o);
@@ -4193,7 +4221,10 @@ Brick::Command(int cmd, void *tmpl, anyOutput *o)
 		return true;
 	case CMD_LEGEND:
 		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
-		((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
+		if(parent && parent->Id > GO_PLOT && parent->Id < GO_GRAPH) {
+			((Legend*)tmpl)->HasFill(&Line, &Fill, ((Plot*)parent)->data_desc);
+			}
+		else ((Legend*)tmpl)->HasFill(&Line, &Fill, 0L);
 		break;
 	case CMD_BAR_FILL:
 		if(tmpl) {
@@ -5323,7 +5354,7 @@ Label::Command(int cmd, void *tmpl, anyOutput *o)
 			return true;
 			}
 		return false;
-	case CMD_ADDCHAR:
+	case CMD_ADDCHAR:	case CMD_ADDCHARW:
 		SetModified();
 		if(tmpl && 8 != *((int*)tmpl)) return AddChar(*((int*)tmpl), o);
 		//value 8 == backspace
@@ -6463,6 +6494,7 @@ void
 TextFrame::AddChar(anyOutput *o, unsigned char c)
 {
 	int i, j, h, w, maxw;
+	bool brd;
 
 	if(cur_pos.y >= nlines) return;
 	if(!lines || !lines[cur_pos.y]) return;
@@ -6489,8 +6521,12 @@ TextFrame::AddChar(anyOutput *o, unsigned char c)
 				}
 			}
 		fmt_txt.SetText(0L, (char*)lines[cur_pos.y], &j, &j);
-		fmt_txt.oGetTextExtent(o, &w, &h, i);
-		if(w >= maxw || c == '\n' || (c == ' ' && w >=(maxw>>1))) {
+		fmt_txt.oGetTextExtent(o, &w, &h, i);				brd = false;
+		if(cur_pos.x > 2 && (c == '>' || c == ';')) {
+			if(c == '>' && fmt_txt.leftTag((char*)lines[cur_pos.y],cur_pos.x-1) >= 0) brd =true;
+			if(c == ';' && fmt_txt.ucLeft((char*)lines[cur_pos.y],cur_pos.x-1, 0L, 0L) > 0) brd =true;
+			}
+		if(brd || w >= maxw || c == '\n' || (c == ' ' && w >=(maxw>>1))) {
 			c_char = lines[cur_pos.y][cur_pos.x];			lines[cur_pos.y][cur_pos.x] = 0x01;
 			if(!c_char) lines[cur_pos.y][cur_pos.x+1] = 0x00; 
 			lines2text();	Undo.TextBuffer(this, &csize, &cpos, &text, 0L, o);		text2lines(o);
@@ -8493,6 +8529,10 @@ Legend::HasSym(LineDEF *ld, GraphObj *sy, char *desc)
 	else if(sy->name && sy->name[0]) {
 		ns->name = (char*)memdup(sy->name,(int)strlen(sy->name)+1, 0); 
 		}
+	else if(sy->parent && sy->parent->Id < GO_GRAPH && sy->parent->Id >= GO_PLOT) {
+		if(((Plot*)(sy->parent))->data_desc) ns->name = (char*)memdup(((Plot*)(sy->parent))->data_desc,
+			(int)strlen(((Plot*)(sy->parent))->data_desc)+1, 0);
+		}
 	else if(sy->parent && sy->parent->name && sy->parent->name[0]) {
 		ns->name = (char*)memdup(sy->parent->name,(int)strlen(sy->parent->name)+1, 0); 
 		}
@@ -8599,11 +8639,24 @@ Graph::GetColor(int select)
 	switch(select & 0xfff) {
 	case COL_AXIS:		return ColAX;
 	case COL_BG:		return ColDR;
+	case COL_DRECT:		return ColDR;
+	case COL_GRECT:		return ColGR;
 		}
 	if(parent) return parent->GetColor(select);
 	else return defs.Color(select);
 }
 
+bool
+Graph::SetColor(int select, DWORD col)
+{
+	switch(select) {
+	case COL_DRECT:
+		ColDR = col;		return true;
+	case COL_GRECT:
+		ColGR = col;		return true;
+		}
+	return false;
+}
 
 void
 Graph::DoPlot(anyOutput *target)
@@ -8616,6 +8669,8 @@ Graph::DoPlot(anyOutput *target)
 	rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = -1;
 	CurrAxes = Axes;
 	if(data) do_formula(data, 0L);			//init mfcalc
+	//every graph needs axes!
+	if(type == GT_STANDARD && !NumAxes) CreateAxes(AxisTempl);
 	//verify ownership of axes
 	if(Axes) for (i = 0; i < NumAxes; i++){
 		if(Axes[i] && (ax = Axes[i]->GetAxis()))
@@ -8636,12 +8691,6 @@ Graph::DoPlot(anyOutput *target)
 		Disp->VPorg.fy = (double)Disp->MenuHeight;
 		Disp->CheckMenu(ToolMode, true);
 		OwnDisp = true;						defs.SetDisp(Disp);
-		if(GRect.Xmin > 0.0001 || GRect.Xmin < -0.0001) {
-			GRect.Xmax -= GRect.Xmin;	GRect.Xmin = 0.0;
-			}
-		if(GRect.Ymin > 0.0001 || GRect.Ymin < -0.0001) {
-			GRect.Ymax -= GRect.Ymin;	GRect.Ymin = 0.0;
-			}
 		bModified = false;			//first graph is not modified!
 		Undo.SetDisp(Disp);
 		}
@@ -8839,14 +8888,13 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		return false;
 	case CMD_REDRAW:
 		if(!CurrDisp) {
-			DoPlot(CurrDisp);
-			return true;
+			DoPlot(CurrDisp);			return true;
 			}
+		if(Disp)CurrDisp = Disp;
 		if(parent && (parent->Id == GO_PAGE || parent->Id == GO_GRAPH)) return parent->Command(cmd, tmpl, o);
 		if(CurrDisp && CurrDisp->Erase(ColBG)) CurrDisp->StartPage();
 		CurrDisp->MrkMode = MRK_NONE;			DoPlot(CurrDisp);
-		if(CurrDisp) CurrDisp->EndPage();
-		if(CurrGO == this) CurrGO = 0L;
+		if(CurrDisp) CurrDisp->EndPage();		if(CurrGO == this) CurrGO = 0L;
 		if(CurrGO && CurrGO == CurrLabel && CurrLabel->Id == GO_LABEL)
 			CurrDisp->ShowMark(CurrLabel, MRK_GODRAW);
 		return true;
@@ -8856,9 +8904,10 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		if(o)o->MouseCursor(PasteObj ? MC_PASTE : MC_ARROW, false);	
 		return true;
 	case CMD_AXIS:			//one of the plots has changed scaling: reset
+		CurrAxes = Axes;
 		if(o)o->SetRect(CurrRect, units, &x_axis, &y_axis);
 		return true;
-	case CMD_REG_AXISPLOT:	//notification: plot can hnadle its own axes
+	case CMD_REG_AXISPLOT:	//notification: plot can handle its own axes
 		if(nscp > 0 && nscp <= NumPlots && Sc_Plots)  {
 			for(i = 0; i < nscp; i++)
 				if(Sc_Plots[i] == (GraphObj*)tmpl) return true;
@@ -9019,6 +9068,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		default:
 			o->MouseCursor(MC_ARROW, true);			break;
 			}
+		if((ToolMode & 0x0f) != TM_TEXT) HideTextCursor();
 		return Command(CMD_REDRAW, 0L, CurrDisp);
 	case CMD_ADDPLOT:
 		Undo.SetDisp(o ? o : CurrDisp);
@@ -9048,10 +9098,11 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		return false;
 	case CMD_MRK_DIRTY:
 		return (dirty = true);
-	case CMD_CURRLEFT:	case CMD_CURRIGHT:	case CMD_ADDCHAR:
+	case CMD_CURRLEFT:	case CMD_CURRIGHT:	case CMD_ADDCHAR:	case CMD_ADDCHARW:
 	case CMD_BACKSP:	case CMD_POS_FIRST:	case CMD_POS_LAST:
 		defs.SetDisp(o);
 		if(tmpl && *((int*)tmpl) == 27) {			//Escape
+			HideCopyMark();
 			if(CurrGO && CurrGO->Id == GO_TEXTFRAME) {
 				CurrGO->DoMark(o, false);				o->MrkMode = MRK_NONE;
 				CurrGO = 0L;
@@ -9188,7 +9239,6 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 					}
 				NiceAxis(&x_axis, 4);				NiceAxis(&y_axis, 4);
 				NumPlots = 1;
-				if(type == GT_STANDARD && !NumAxes) CreateAxes(AxisTempl);
 				dirty = false;
 				return true;
 				}
@@ -9255,7 +9305,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		else if(mev->Action == MOUSE_LBDOWN){
 			if(CurrGO && CurrGO->Id == GO_TEXTFRAME && CurrGO->Command(cmd, tmpl, o)) return true;
-			CurrGO = 0L;
+			CurrGO = 0L;					SuspendAnimation(o, true);
 			if((ToolMode & 0xff) == TM_STANDARD || (ToolMode & 0xff) == TM_ZOOMIN){
 				rc_mrk.left = mev->x;		rc_mrk.top = mev->y;
 				}
@@ -9291,8 +9341,8 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 			if(CurrGO == this) CurrGO = 0L;
 			return false;
 		case MOUSE_LBUP:
-			Undo.SetDisp(o);
-			if(Id == GO_GRAPH){
+			Undo.SetDisp(o);		SuspendAnimation(o, false);
+			if(Id == GO_GRAPH && parent && parent->Id == GO_SPREADDATA){
 				CurrGO = TrackGO = 0L;
 				CurrGraph = this;
 				}
@@ -9303,7 +9353,9 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 				if(Axes[i] && Axes[i]->Command(cmd, tmpl,o)) return true;
 			//do all plots
 			if(Plots)for(i = NumPlots-1; i>=0; i--)
-				if(Plots[i] && Plots[i]->Command(cmd, tmpl,o)) return true;
+				if(Plots[i] && Plots[i]->Command(cmd, tmpl,o)){
+					if(Id == GO_GRAPH)CurrGraph = this;		return true;
+					}
 			if(frm_d && frm_d->Command(cmd, tmpl, o)) return true;
 			if(frm_g && frm_g->Command(cmd, tmpl, o)) return true;
 			if(mev->Action == MOUSE_MOVE && ToolMode == TM_STANDARD &&
@@ -9314,7 +9366,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		break;
 	case CMD_SETSCROLL:
 		if(o) {
-			o->ActualSize(&rc);
+			if(!(o->ActualSize(&rc)))return false;
 			i = o->un2iy(GRect.Ymax);
 			o->SetScroll(true, -(i>>3), i+(i>>3), (rc.bottom -rc.top)>>1, - iround(o->VPorg.fy));
 			i = o->un2ix(GRect.Xmax);
@@ -9360,6 +9412,7 @@ Graph::DefSize(int select)
 	case SIZE_BOUNDS_XMAX:		return Bounds.Xmax;
 	case SIZE_BOUNDS_YMIN:		return Bounds.Ymin;
 	case SIZE_BOUNDS_YMAX:		return Bounds.Ymax;
+	case SIZE_SCALE:			return scale > 0.0 ? scale : 1.0;
 	case SIZE_BOUNDS_LEFT:		return x_axis.flags & AXIS_INVERT ? x_axis.max : x_axis.min;
 	case SIZE_BOUNDS_RIGHT:		return x_axis.flags & AXIS_INVERT ? x_axis.min : x_axis.max;
 	case SIZE_BOUNDS_TOP:		return y_axis.flags & AXIS_INVERT ? y_axis.min : y_axis.max;
@@ -9730,29 +9783,34 @@ Graph::CreateAxes(int templ)
 		NumAxes = 2;
 		break;
 		}
+	if(Plots[0] && Plots[0]->Id >= GO_PLOT && Plots[0]->Id < GO_GRAPH && NumAxes > 1) {
+		if(((Plot*)Plots[0])->x_tv) if(Axes[0])Axes[0]->atv = ((Plot*)Plots[0])->x_tv->Copy();
+		if(((Plot*)Plots[0])->y_tv) if(Axes[1])Axes[1]->atv = ((Plot*)Plots[0])->y_tv->Copy();
+		}
 }
 
 bool
 Graph::DoScale(scaleINFO* sc, anyOutput *o)
 {
 	int i;
-	double x0, y0, z0;
+	scaleINFO sc0;
 
-	if(sc->sy.fy > 0.0) {
-		scale = scale > 0.0 ? scale * sc->sy.fy : sc->sy.fy;
-		}
-	else return false;
+	if(sc->sy.fy <= 0.0) return false;
 	GRect.Xmax = sc->sx.fx + GRect.Xmax* sc->sx.fy;
 	GRect.Xmin = sc->sx.fx + GRect.Xmin * sc->sx.fy;
 	GRect.Ymax = sc->sy.fx + GRect.Ymax * sc->sy.fy;
 	GRect.Ymin = sc->sy.fx + GRect.Ymin * sc->sy.fy;
 	DRect.Xmax *= sc->sx.fy;	DRect.Xmin *= sc->sx.fy;
 	DRect.Ymax *= sc->sy.fy;	DRect.Ymin *= sc->sy.fy;
-	x0 = sc->sx.fx;		y0 = sc->sy.fx;		z0= sc->sz.fx;
-	sc->sx.fx = sc->sy.fx = sc->sz.fx = 0.0;	sc->sx.fy = sc->sz.fy = sc->sy.fy;
-	if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->Command(CMD_SCALE, sc, o);
-	if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]) Plots[i]->Command(CMD_SCALE, sc, o);
-	sc->sx.fx = x0;		sc->sy.fx = y0;		sc->sz.fx = z0;
+	if(sc->sx.fy == 1.0 && sc->sx.fy  == sc->sy.fy && sc->sx.fy == sc->sz.fy) return true;
+	memcpy(&sc0, sc, sizeof(scaleINFO));
+	sc0.sx.fx = sc0.sy.fx = sc0.sz.fx = 0.0;	sc0.sx.fy = sc0.sz.fy = sc->sy.fy;
+	if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) Axes[i]->Command(CMD_SCALE, &sc0, o);
+	if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]){
+		if(Plots[i]->Id == GO_GRAPH || Plots[i]->Id == GO_PAGE) Plots[i]->Command(CMD_SCALE, sc, o);
+		else Plots[i]->Command(CMD_SCALE, &sc0, o);
+		}
+	scale = scale > 0.0 ? scale * sc->sy.fy : sc->sy.fy;
 	return true;
 }
 
diff --git a/rlplot.h b/rlplot.h
index 25ac873..70d1971 100755
--- a/rlplot.h
+++ b/rlplot.h
@@ -1,4 +1,4 @@
-//RLPlot.h, Copyright (c) 2000-2006 R.Lackner
+//RLPlot.h, Copyright (c) 2000-2007 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -29,27 +29,22 @@ inline int iround(double a) {return a < 0.0 ?(int)(a-0.499) : (int)(a+0.499);}
 #define _SQRT2	1.4142135623730950488016887242096980785696718753769
 
 #ifdef _WINDOWS					//platform is windows
-#pragma warning( disable : 4996 )
+#pragma warning( disable : 4997 )
 #include <windows.h>
 #if _MSC_VER >= 1400
 #define USE_WIN_SECURE
 #endif
-#define w_char unsigned short
+#define w_char WCHAR
 #define _SBINC	1				//scrollbox extra space/line
 #define _TXH	4.0				//graph text default size in mm
 
 #else							//platform is *nix
 #include <sys/types.h>
 #define DWORD u_int32_t
-#define w_char unsigned short
+#define w_char wchar_t
 #define _SBINC	8				//scrollbox extra space/line
 #define _TXH	3.0				//graph text default size in mm
 #define RLP_PORT	4321		//clipboard server
-#define _strdup	strdup
-#define _open	open
-#define _write	write
-#define _close	close
-#define _lseek	lseek
 
 typedef struct tagPOINT { // pt 
     long x; 
@@ -86,13 +81,13 @@ enum {SIZE_MINE, SIZE_SYMBOL, SIZE_SYM_LINE, SIZE_DATA_LINE, SIZE_TEXT,
 	SIZE_A, SIZE_B, SIZE_MX, SIZE_MY, SIZE_MIN_Z, SIZE_MAX_Z, SIZE_MIN_X, SIZE_MAX_X,
 	SIZE_MIN_Y, SIZE_MAX_Y, SIZE_TICK_ANGLE, SIZE_RRECT_RAD, SIZE_XCENT, SIZE_YCENT,
 	SIZE_ZCENT, SIZE_DRADIUS, SIZE_CURSORPOS, SIZE_CURSOR_XMIN, SIZE_CURSOR_YMIN,
-	SIZE_CURSOR_XMAX, SIZE_CURSOR_YMAX, SIZE_XSTEP, SIZE_LSPC};
+	SIZE_CURSOR_XMAX, SIZE_CURSOR_YMAX, SIZE_XSTEP, SIZE_LSPC, SIZE_SCALE};
 enum {COL_SYM_LINE, COL_SYM_FILL, COL_DATA_LINE, COL_TEXT, COL_BG,
 	COL_AXIS, COL_BAR_LINE, COL_BAR_FILL, COL_ERROR_LINE, COL_BUBBLE_LINE, 
 	COL_BUBBLE_FILLLINE, COL_BUBBLE_FILL, COL_ARROW, COL_WHISKER, COL_BOX_LINE,
 	COL_DRECT, COL_GRECT, COL_GRECTLINE, COL_POLYLINE, COL_POLYGON};
 enum {MRK_NONE, MRK_INVERT, MRK_GODRAW, MRK_SSB_DRAW};
-enum {CMD_NONE, CMD_ADDCHAR, CMD_SETFOCUS, CMD_KILLFOCUS, CMD_DELETE,
+enum {CMD_NONE, CMD_ADDCHAR, CMD_ADDCHARW, CMD_SETFOCUS, CMD_KILLFOCUS, CMD_DELETE,
 	CMD_BACKSP, CMD_CURRLEFT, CMD_CURRIGHT, CMD_CURRUP, CMD_CURRDOWN,
 	CMD_SHIFTLEFT, CMD_SHIFTRIGHT, CMD_SHIFTUP, CMD_SHIFTDOWN,
 	CMD_NEWGRAPH, CMD_DELGRAPH, CMD_DELOBJ, CMD_DROP_PLOT, CMD_DROP_GRAPH, CMD_OPEN,
@@ -144,8 +139,9 @@ enum {GO_UNKNOWN, GO_AXIS, GO_TICK, GO_GRIDLINE, GO_SYMBOL, GO_BUBBLE, GO_BAR,
 	GO_BOXPLOT, GO_DENSDISP, GO_STACKBAR, GO_STACKPG, GO_WATERFALL, GO_POLARPLOT,
 	GO_PIECHART, GO_RINGCHART, GO_GROUP, GO_STARCHART, GO_SCATT3D, GO_PLOT3D,
 	GO_RIBBON, GO_LIMITS, GO_FUNCTION, GO_FITFUNC, GO_FREQDIST, GO_GRID3D, GO_FUNC3D,
-	GO_XYSTAT, GO_FITFUNC3D,
+	GO_XYSTAT, GO_FITFUNC3D, GO_NORMQUANT,
 	GO_GRAPH = 0x200, GO_PAGE, GO_SPREADDATA = 0x300, GO_DEFRW};
+enum {OC_UNKNOWN, OC_HIMETRIC};
 enum {FILL_NONE, FILL_HLINES, FILL_VLINES, FILL_HVCROSS, FILL_DLINEU, FILL_DLINED,
 	FILL_DCROSS, FILL_STIPPLE1, FILL_STIPPLE2, FILL_STIPPLE3, FILL_STIPPLE4, 
 	FILL_STIPPLE5, FILL_ZIGZAG, FILL_COMBS, FILL_BRICKH, FILL_BRICKV, FILL_BRICKDU, 
@@ -161,7 +157,7 @@ enum {TM_STANDARD, TM_DRAW, TM_POLYLINE, TM_POLYGON, TM_RECTANGLE, TM_ELLIPSE,
 	TM_PASTE=0x200};
 enum {MC_LAST, MC_ARROW, MC_CROSS, MC_TEXT, MC_WAIT, MC_MOVE, MC_NORTH,
 	MC_NE, MC_EAST, MC_SE, MC_SALL, MC_ZOOM, MC_PASTE, MC_DRAWPEN, MC_DRAWREC, 
-	MC_DRAWRREC, MC_DRAWELLY};
+	MC_DRAWRREC, MC_DRAWELLY, MC_TXTFRM, MC_COLWIDTH};
 enum {FILE_ERROR, FILE_READ, FILE_WRITE, INIT_VARS, SAVE_VARS};
 enum {ARROW_NOCAP, ARROW_LINE, ARROW_TRIANGLE, ARROW_UNITS = 0x100};
 enum {MENU_NONE, MENU_SPREAD, MENU_GRAPH, MENU_PAGE};
@@ -333,6 +329,8 @@ typedef struct {
 	int type;
 	double value;
 	char *text;
+	double *a_data;
+	int a_count;
 	} anyResult;
 
 //the AccRange class allows to access data objects with a 'a1:b1' style
@@ -348,6 +346,7 @@ public:
 	bool IsInRange(int x, int y);
 	bool BoundRec(RECT *rec);
 	char *RangeDesc(void *d, int style);	//d points to a DataObj class
+	int DataTypes(void *d, int *numerical, int *strings, int *datetime);
 
 private:
 	char *txt;
@@ -391,6 +390,7 @@ class anyOutput{
 public:
 	int units;							//use units mm, inch ...
 	int MrkMode;						//existing mark on screen
+	int OC_type;						//specify display, printer clipboard ...
 	void *MrkRect;						//pointer to e.g. the marked rectangle
 	fRECT Box1;							//User drawing rectangle
 	lfPOINT Box1z;						// add 3D to Box1
@@ -420,6 +420,7 @@ public:
 
 	anyOutput();
 	void SetRect(fRECT rec, int units, AxisDEF *x_ax, AxisDEF *y_ax);
+	void UseAxis(AxisDEF *ax, int type);
 	void SetSpace(fPOINT3D*,fPOINT3D*,int,double*,fPOINT3D*,AxisDEF*,AxisDEF*,AxisDEF*);
 	void LightSource(double x, double y);
 	DWORD VecColor(double *plane_vec, DWORD col1, DWORD col2);
@@ -474,14 +475,15 @@ public:
 	virtual bool oGetPix(int x, int y, DWORD *col){return false;};
 	virtual bool oDrawIcon(int type, int x, int y) {return false;};
 	virtual bool oGetTextExtent(char *text, int cb, int *width, int *height);
+	virtual bool oGetTextExtentW(w_char *text, int cb, int *width, int *height);
 	virtual bool oCircle(int x1, int y1, int x2, int y2, char *nam = 0L){return false;};
 	virtual bool oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam = 0L);
 	virtual bool oPolyline(POINT * pts, int cp, char *nam = 0L){return false;};
 	virtual bool oRectangle(int x1, int y1, int x2, int y2, char *nam = 0L){return false;};
 	virtual bool oSolidLine(POINT *p){return false;};
 	virtual bool oTextOut(int x, int y, char *txt, int cb){return false;};
+	virtual bool oTextOutW(int x, int y, w_char *txt, int cb){return false;};
 	virtual bool oPolygon(POINT *pts, int cp, char *nam = 0L){return false;};
-	virtual bool oArc(int x1, int y1, int x2, int y2, int quads){return false;};
 };
 
 enum {ET_UNKNOWN, ET_VALUE, ET_TEXT, ET_FORMULA, ET_ERROR, ET_BOOL, 
@@ -533,7 +535,7 @@ private:
 class fmtText {
 
 typedef struct _fmt_txt_info {
-	int tag;
+	int tag, uc, uc_len;
 	char *txt;
 }fmt_txt_info;
 
@@ -544,6 +546,8 @@ public:
 	bool StyleAt(int idx,  TextDEF *txt_def, int *style, int *font);
 	int rightTag(char *txt, int cb);
 	int leftTag(char *txt, int cb);
+	int ucTag(char *txt, int cb, int *tl, int *ucc);
+	int ucLeft(char *txt, int cb, int *tl, int *ucc);
 	void cur_right(int *pos);
 	void cur_left(int *pos);
 	bool oGetTextExtent(anyOutput *o, int *width, int *height, int cb);
@@ -564,6 +568,30 @@ private:
 	fmt_txt_info *split_text;
 };
 
+class TextValue {
+
+typedef struct _TxtValItem {
+	unsigned int hv1, hv2;
+	char *text;
+	double val;
+}TextValItem;
+
+public:
+	TextValue();
+	TextValue(TextValItem **tvi, int ntvi);
+	~TextValue();
+	double GetValue(char* txt);
+	bool GetItem(int idx, char **text, double *value);
+	void Reset();
+	TextValue *Copy();
+	int Count() {return nitems;};
+
+private:
+	TextValItem **items;
+	int nitems;
+	double next, inc;
+};
+
 class RangeInfo {
 public:
 	int col_width, row_height, first_width;
@@ -577,6 +605,8 @@ public:
 	int GetWidth(int col);
 	int GetHeight(int row);
 	int GetFirstWidth();
+	int Type(){return r_type;};
+	RangeInfo *Next(){return ri_next;};
 
 private:
 	int r_type;		// 0 default
@@ -588,18 +618,19 @@ private:
 
 class DataObj{
 public:
-	int cRows, cCols;
+	int cRows, cCols, c_disp, r_disp;
 	RangeInfo *ri;
 	EditText ***etRows;
 
 	DataObj();
 	~DataObj();
 	virtual bool Init(int nRows, int nCols);
+	virtual bool mpos2dpos(POINT *mp, POINT *dp, bool can_scroll){return false;};
 	virtual bool SetValue(int row, int col, double val);
 	virtual bool SetText(int row, int col, char *txt);
 	virtual bool GetValue(int row, int col, double *v);
 	virtual bool GetText(int row, int col, char *txt, int len, bool bTranslate = true);
-	char ** GetTextPtr(int row, int col);
+	char **GetTextPtr(int row, int col);
 	virtual bool GetResult(anyResult *r, int row, int col, bool use_last = false);
 	virtual bool GetSize(int *width, int *height);
 	virtual bool isEmpty(int row, int col);
@@ -1642,10 +1673,12 @@ class Plot:public GraphObj{
 public:
 	fRECT Bounds;					//contains minima and maxima for x and y
 	bool dirty;						//rescale before redraw;
-	int use_xaxis, use_yaxis;		//this plot uses its own axes
+	int use_xaxis, use_yaxis, use_zaxis;		//this plot uses its own axes
 	lfPOINT xBounds, yBounds, zBounds;	//like Bounds but in 3D space
 	int hidden;						//plot (layer) is not visible
 	char *x_info, *y_info, *z_info;	//descriptor used e.g. for axis label or legend
+	char *data_desc;				//descriptor for data, used for legend etc
+	TextValue *x_tv, *y_tv;			//TextValue object for ordinal axes
 
 	Plot(GraphObj *par, DataObj *d);
 	virtual double GetSize(int select);
@@ -1727,6 +1760,7 @@ public:
 class FreqDist:public Plot {
 public:
 	FreqDist(GraphObj *par, DataObj *d);
+	FreqDist(GraphObj *par, DataObj *d, char* range, bool bOnce);
 	FreqDist(int src);
 	~FreqDist();
 	void DoPlot(anyOutput *o);
@@ -1736,7 +1770,7 @@ public:
 	bool FileIO(int rw);
 
 private:
-	double start, step;
+	double dmin, dmax, start, step;
 	long nPlots;
 	char *ssRef;
 	LineDEF BarLine, HatchLine;
@@ -2108,6 +2142,27 @@ private:
 	Function *dl;
 };
 
+class NormQuant:public Plot{
+public:
+	NormQuant(GraphObj *par, DataObj *d, char* range);
+	NormQuant(GraphObj *par, DataObj *d, double *data, int ndata);
+	NormQuant(int src);
+	~NormQuant();
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	bool FileIO(int rw);
+
+private:
+	char *ssRef;
+	int nData, nValidData;
+	double *x_vals, *y_vals, *src_data;
+	Symbol *sy;
+
+	bool ProcessData();
+};
+
+	
 class GridLine:public GraphObj{
 public:
 	DWORD flags;
@@ -2183,6 +2238,7 @@ class Axis:public GraphObj{
 public:
 	AxisDEF *axis;
 	LineDEF axline;
+	TextValue *atv;
 
 	Axis(GraphObj *par, DataObj *d, AxisDEF *ax, DWORD flags);
 	Axis(int src);
@@ -2242,9 +2298,10 @@ class Plot3D:public Plot{
 public:
 	long nPlots, nAxes;
 	Axis **Axes;
-	GraphObj **plots;
+	GraphObj **plots, **Sc_Plots;
 	double *RotDef;
 	fPOINT3D cub1, cub2, rotC;
+	int nscp;
 
 	Plot3D(GraphObj *par, DataObj *d, DWORD flags);
 	Plot3D(int src);
@@ -2266,6 +2323,7 @@ public:
 	bool AcceptObj(GraphObj *go);
 	void SortObj();
 	bool Rotate(double dx, double dy, double dz, anyOutput *o, bool accept);
+	bool AddAxis();
 
 private:
 	long nObs, nmaxObs;
@@ -2368,6 +2426,7 @@ public:
 	double GetSize(int select);
 	bool SetSize(int select, double value);
 	DWORD GetColor(int select);
+	bool SetColor(int select, DWORD col);
 	virtual void DoPlot(anyOutput *o);
 	virtual bool Command(int cmd, void *tmpl, anyOutput *o);
 	bool PropertyDlg();
@@ -2641,6 +2700,8 @@ void HideTextCursorObj(anyOutput *out);
 void ShowTextCursor(anyOutput *out, RECT *disp, DWORD color);
 void HideCopyMark();
 void ShowCopyMark(anyOutput *out, RECT *mrk, int nRec);
+void InvalidateOutput(anyOutput *o);
+void SuspendAnimation(anyOutput *o, bool bSusp);
 void InitTextCursor(bool init);
 void EmptyClip();
 void CopyText(char *txt, int len);
@@ -2710,7 +2771,9 @@ bool Txt2Flt(char *txt, double *val);
 void RmTrail(char *txt);
 double NiceValue(double fv);
 char *Int2ColLabel(int nr, bool uc);
-char *str2xml(char *str);
+char *mkCellRef(int row, int col);
+char *mkRangeRef(int r1, int c1, int r2, int c2);
+char *str2xml(char *str, bool bGreek);
 char **split(char *str, char sep, int *nl);
 char *fit_num_rect(anyOutput *o, int max_width, char *num_str);
 void add_to_buff(char** dest, int *pos, int *csize, char *txt, int len);
@@ -2727,6 +2790,7 @@ bool IsInPolygon(POINT *p, POINT *pts, int cp);
 bool OverlapRect(RECT *rc1, RECT *rc2);
 void AddToPolygon(long *cp, POINT *pts, POINT *np);
 void DrawBezier(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, int depth=0);
+int mkCurve(lfPOINT *src, int n1, lfPOINT **dst, bool bClosed);
 POINT *MakeArc(int ix, int iy, int r, int qad, long *npts);
 void InvertPolygon(POINT*, int, LineDEF*, FillDEF*, RECT*, anyOutput*, bool);
 void InvertLine(POINT*, int, LineDEF*, RECT*, anyOutput*, bool);
@@ -2757,6 +2821,7 @@ DWORD CheckNewFloat(double *loc, double old_v, double new_v, GraphObj *par, DWOR
 DWORD CheckNewInt(int *loc, int old_v, int new_v, GraphObj *par, DWORD flags);
 DWORD CheckNewDword(DWORD *loc, DWORD old_v, DWORD new_v, GraphObj *par, DWORD flags);
 DWORD CheckNewLFPoint(lfPOINT *loc, lfPOINT *old_v, lfPOINT *new_v, GraphObj *par, DWORD flags);
+DWORD CheckNewString(char **loc, char *s_old, char *s_new, GraphObj *par, DWORD flags);
 void clip_line_sphere(GraphObj *par, POINT3D **li, int r, int cx, int cy, int cz);
 void clip_line_plane(GraphObj *par, POINT3D **li, POINT3D *pg, int np, double *vec);
 void clip_sphline_sphere(GraphObj *par, POINT3D *lim1, POINT3D *lim2, POINT3D *cent, 
@@ -2780,7 +2845,7 @@ bool do_xyfunc(DataObj *, double, double, double, char *, lfPOINT **, long *, ch
 bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double z2, double zstep, 
 	char *expr, char *param);
 anyResult *do_formula(DataObj *, char *);
-bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0);
+bool MoveFormula(DataObj *d, char *of, char *nf, int nfsize, int dx, int dy, int r0, int c0);
 int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr, 
 	double conv, int maxiter, double *chi_2);
 
@@ -2791,6 +2856,7 @@ bool mrqmin(double *, double *, double *, int, double **, int, int *, int, doubl
 	void (*funcs)(double, double, double **, double *, double *, int), double *);
 bool Check_MRQerror();
 void SortArray(int n, double *vals);
+void SortArray2(int n, double *a1, double *a2);
 void SortFpArray(int n, lfPOINT *vals);
 void spline(lfPOINT *v, int n, double *y2);
 double gammln(double x);
@@ -2817,6 +2883,11 @@ double t_freq(double t, double df);
 double pois_dist(double x, double m, double);
 double f_dist(double f, double df1, double df2);
 double f_freq(double f, double df1, double df2);
+double ks_dist(int n, double d);
+void swilk1(int n, double *v0, double (*func)(double, double, double), double p1, double p2, 
+	bool bsorted, double *w, double *p);
+void KolSmir(int n, double *v0, double (*func)(double, double, double),
+	double p1, double p2, bool bsorted, double *d, double *p);
 double distinv(double (*sf)(double, double, double), double df1, double df2, double p, double x0);
 void d_quartile(int n, double *v, double *q1, double *q2, double *q3);
 double d_variance(int n, double *v, double *mean = 0L, double *ss = 0L);
@@ -2826,17 +2897,20 @@ double d_skew(int n, double *v);
 double d_gmean(int n, double *v);
 double d_hmean(int n, double *v);
 double d_classes(DataObj *d, double start, double step, double *v, int nv, char *range);
-double d_pearson(double *x, double *y, int n, char *dest, DataObj *data);
+double d_pearson(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
 double d_rank(int n, double *v, double v1);
 void crank(int n, double *w0, double *s);
-double d_spearman(double *x, double *y, int n, char *dest, DataObj *data);
-double d_kendall(double *x, double *y, int n, char *dest, DataObj *data);
+double d_spearman(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
+double d_kendall(double *x, double *y, int n, char *dest, DataObj *data, double *ra);
 double d_regression(double *x, double *y, int n, char *dest, DataObj *data);
 double d_covar(double *x, double *y, int n, char *dest, DataObj *data);
 double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results);
 double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data, double *results);
 double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data);
 double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data);
+double wprob(double w, double rr, double cc);
+double ptukey(double q, double rr, double cc, double df, int lower_tail, int log_p);
+double qtukey(double p, double rr, double cc, double df, int lower_tail, int log_p);
 bool date_value(char *desc, char *fmt, double *value);
 char *value_date(double dv, char *fmt);
 double now_today();
@@ -2846,7 +2920,10 @@ Ribbon *SurfTria(GraphObj *parent, DataObj *data, char *text1, char *text2, char
 
 //prototypes reports.cpp
 void rep_anova(GraphObj *parent, DataObj *data);
+void rep_kruskal(GraphObj *parent, DataObj *data);
+void rep_samplestats(GraphObj *parent, DataObj *data);
 void rep_regression(GraphObj *parent, DataObj *data);
 void rep_twowaytable(GraphObj *parent, DataObj *data);
 void rep_compmeans(GraphObj *parent, DataObj *data);
+void rep_correl(GraphObj *parent, DataObj *data, int style);
 
diff --git a/rlplot.spec b/rlplot.spec
index 88e95c3..b63355e 100755
--- a/rlplot.spec
+++ b/rlplot.spec
@@ -1,5 +1,5 @@
 Name:      rlplot
-Version:   1.2
+Version:   1.3
 Release:   1
 Summary:   A plotting program to create high quality graphs from data.
 License:   GPL
@@ -16,7 +16,7 @@ graphs of your choice. The Graphs are displayed as you get them (WYSIWIG).
 Double click any element of the graph (or a single click with the right
 mouse button) to modify its properties. RLPlot is a cross platform
 development for Linux and Windows. Exported file formats include
-Scalable Vector Graphics (SVG), Windows Metafile (WMF), Encapsulated
+Scalable Vector Graphics (SVG), Encapsulated
 Postscript (EPS). 
 
 %prep
@@ -41,6 +41,9 @@ rm -rf "$RPM_BUILD_ROOT"
 %{_bindir}/exprlp
 
 %changelog
+* Sun Feb 25 2007 Reinhard Lackner
+- release 1.3
+
 * Thu Oct 19 2006 Reinhard Lackner
 - release 1.2
 
@@ -63,3 +66,5 @@ rm -rf "$RPM_BUILD_ROOT"
 - initial
 
 
+
+
diff --git a/spreadwi.cpp b/spreadwi.cpp
index 72a5740..776d74b 100755
--- a/spreadwi.cpp
+++ b/spreadwi.cpp
@@ -178,7 +178,6 @@ SpreadWin::SpreadWin(GraphObj *par, DataObj *Data):GraphObj(par, Data)
 	else if(d &&  d->ri) {
 		d->ri->SetHeight(19);	d->ri->SetDefWidth(76);	d->ri->SetFirstWidth(32);
 		}
-	cButtons = rButtons = 0L;
 	Id = GO_SPREADDATA;
 	is_modified = bDoColWidth = false;
 }
@@ -209,7 +208,7 @@ SpreadWin::~SpreadWin()
 void
 SpreadWin::DoPlot(anyOutput *o)
 {
-	o->ActualSize(&currRC);
+	if(!(o->ActualSize(&currRC)))return;
 	o->StartPage();
 	d->Command(CMD_DOPLOT, (void*)this, o);
 	o->EndPage();
@@ -222,7 +221,7 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 	Graph *g2;
 	int i, j, k;
 	MouseEvent *mev;
-	POINT p1;
+	POINT p1, p2;
 
 	if(d) {
 		if(!o) o = w;
@@ -248,6 +247,7 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 					w->UpdateRect(&urc, false);
 					}
 				}
+			else return false;
 			return true;
 		case CMD_CAN_CLOSE:
 			HideTextCursor();
@@ -327,7 +327,8 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			if((Name = SaveDataAsName(filename)) && Name[0]){
 				if(o) o->FileHistory();
 				if(Name && d->WriteData(Name)) {
-					if(filename) free(filename);		filename = _strdup(Name);
+					if(filename) free(filename);
+					filename = (char*)memdup(Name, (int)strlen(Name)+1, 0);
 					}
 				else return false;
 				}
@@ -337,19 +338,20 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			if(!Command(CMD_CAN_CLOSE, 0L, o)) return false;
 			if(IsRlpFile((char*)tmpl)) return OpenGraph(this, (char*)tmpl, 0L, false);
 			else if(d->ReadData((char*)tmpl, 0L, FF_UNKNOWN)){
-				if(filename) free(filename);			filename = _strdup((char*)tmpl);
+				if(filename) free(filename);
+				filename = (char*)memdup(tmpl, (int)strlen((char*)tmpl)+1, 0);
 				return Command(CMD_SETSCROLL, 0L, w);
 				}
 			return false;
 		case CMD_OPEN:
 			if(!Command(CMD_CAN_CLOSE, 0L, o)) return false;
-			Undo.KillDisp(o);
-			Undo.SetDisp(o);
+			Undo.KillDisp(o);		Undo.SetDisp(o);
 			if((Name = OpenDataName(filename)) && Name[0]){
 				if(o) o->FileHistory();
 				if(IsRlpFile(Name)) return OpenGraph(this, Name, 0L, false);
 				else if(d->ReadData(Name, 0L, FF_UNKNOWN)){
-					if(filename) free(filename);		filename = _strdup(Name);
+					if(filename) free(filename);
+					filename = (char*)memdup(Name, (int)strlen(Name)+1, 0);
 					return Command(CMD_SETSCROLL, 0L, w);
 					}
 				}
@@ -361,18 +363,19 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			if(o && cButtons && rButtons && (mev = (MouseEvent*)tmpl) && mev->y > o->MenuHeight) {
 				for(i = 0; cButtons[i]; i++){
 					if(bDoColWidth) {
-						o->MouseCursor(MC_EAST, false);
+						o->MouseCursor(MC_COLWIDTH, false);
 						}
 					else if(mev->x > cButtons[i]->rDims.left && mev->x < cButtons[i]->rDims.right+2){
 						if(mev->x > cButtons[i]->rDims.right-4) {
-							o->MouseCursor(MC_EAST, false);
 							switch(mev->Action) {
 							case MOUSE_LBDOWN:
 								CurrCol = i;					line[0].x = line[1].x = mev->x;
 								line[0].y = o->MenuHeight;		line[1].y = currRC.bottom;
 								d->Command(CMD_TOOLMODE, tmpl, o);
+								o->MouseCursor(MC_COLWIDTH, false);
 								return bDoColWidth = true;
 								}
+							o->MouseCursor(MC_COLWIDTH, false);
 							}
 						else o->MouseCursor(MC_ARROW, false);
 						return false;
@@ -398,11 +401,7 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 						bDoColWidth = false;
 						k = line[0].x - cButtons[CurrCol]->rDims.left;
 						if(abs(k - cButtons[CurrCol]->rDims.right + cButtons[CurrCol]->rDims.left)>3) {
-#ifdef USE_WIN_SECURE
-							sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s1:%s1", Int2ColLabel(CurrCol + ssOrg.x, false), Int2ColLabel(CurrCol + ssOrg.x, false));
-#else
-							sprintf(TmpTxt, "%s1:%s1", Int2ColLabel(CurrCol + ssOrg.x, false), Int2ColLabel(CurrCol + ssOrg.x, false));
-#endif
+							rlp_strcpy(TmpTxt, 40, mkRangeRef(0, CurrCol + ssOrg.x, 0, CurrCol + ssOrg.x));
 							d->ri = new RangeInfo(1, TmpTxt, d->ri);
 							d->ri->SetWidth(k >=20 ? k : 20);
 							}
@@ -415,20 +414,25 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			else o->MouseCursor(MC_ARROW, false);
 			return false;
 		case CMD_MOUSE_EVENT:
-			if(!tmpl) return false;
+			if(!(mev =(MouseEvent*)tmpl)) return false;
 			if(bDoColWidth)return Command(CMD_COL_MOUSE, tmpl, o);
-			if((mev = (MouseEvent*)tmpl)->y < o->MenuHeight) o->MouseCursor(MC_ARROW, false); 
+			p1.x = mev->x;		p1.y = mev->y;
+			if(mev->y < o->MenuHeight) o->MouseCursor(MC_ARROW, false);
 			else if(o && cButtons && rButtons) {
 				if(mev->x < d->ri->GetFirstWidth() && mev->y < (o->MenuHeight + d->ri->GetHeight(-1)) && aButton) {
 					aButton->Command(cmd, tmpl, o);
 					}
 				else if(mev->x < d->ri->GetFirstWidth() && rButtons) {
-					i = (mev->y - o->MenuHeight - d->ri->GetHeight(-1))/d->ri->GetHeight(-1);
-					if(rButtons[i]) rButtons[i]->Command(cmd, tmpl, o);
+					if(!(d->mpos2dpos(&p1, &p2, false)))return false;
+					p2.x -= ssOrg.x;		p2.y -= ssOrg.y;
+					if (p2.y < 0 || p2.y >= (d->r_disp-1)) return false;
+					if(rButtons[p2.y]) rButtons[p2.y]->Command(cmd, tmpl, o);
 					}
 				else if(mev->y < (o->MenuHeight + d->ri->GetHeight(-1)) && cButtons) {
-					i = (mev->x - d->ri->GetFirstWidth())/d->ri->GetWidth(-1);
-					if(cButtons[i]) cButtons[i]->Command(cmd, tmpl, o);
+					if(!(d->mpos2dpos(&p1, &p2, false)))return false;
+					p2.x -= ssOrg.x;		p2.y -= ssOrg.y;
+					if (p2.x < 0 || p2.x >= (d->c_disp-1)) return false;
+					if(cButtons[p2.x]) cButtons[p2.x]->Command(cmd, tmpl, o);
 					}
 				else if(o->MrkMode == MRK_SSB_DRAW) o->HideMark();
 				}
@@ -454,7 +458,7 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			if(o)o->MouseCursor(MC_ARROW, false);	
 			return true;
 		case CMD_SETSCROLL:
-			HideTextCursor();						o->ActualSize(&currRC);
+			HideTextCursor();						if(!(o->ActualSize(&currRC)))return false;
 			k = (currRC.bottom-currRC.top)/d->ri->GetHeight(-1);
 			d->GetSize(&i, &j);
 			o->SetScroll(true, 0, j, k, ssOrg.y);	k = (currRC.right-currRC.left)/d->ri->GetWidth(-1);
@@ -529,7 +533,7 @@ SpreadWin::ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cp)
 	ButtText.Align = TXA_HCENTER | TXA_VCENTER;
 	w->GetSize(&rc);
 	if(!cButtons) {
-		c = ((rc.right/CellWidth)<<2) +1;
+		c = d->c_disp;		if(c < 40 || c > 200) d->c_disp = c = 40;
 		cButtons = (ssButton **)calloc(c, sizeof(ssButton*));
 		for(i = 0, cx = FirstWidth; i < (c-1); i++) {
 			cw = d->ri->GetWidth(i+ssOrg.x);
@@ -545,7 +549,7 @@ SpreadWin::ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cp)
 			}
 		}
 	if(!rButtons) {
- 		c = (rc.bottom/CellHeight)+1;
+ 		c = d->r_disp;			if(c < 60 || c > 300) d->c_disp = c = 60;
 		rButtons = (ssButton**)calloc(c, sizeof(ssButton*));
 		for(i = 0; i < (c-1); i++) rButtons[i] = 
 			new ssButton(this, 0, i*CellHeight+CellHeight+w->MenuHeight, 
@@ -777,7 +781,7 @@ SpreadWin::PrintData(anyOutput *o)
 				o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
 				tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
 #ifdef USE_WIN_SECURE
-				ctime_s(TmpTxt, 24, &ti);
+				ctime_s(TmpTxt, 50, &ti);	TmpTxt[24] = 0;
 #else
 				sprintf(TmpTxt, "%s", ctime(&ti));	TmpTxt[24] = 0;
 #endif
@@ -801,7 +805,7 @@ SpreadWin::PrintData(anyOutput *o)
 	o->oTextOut(rc.right-margin.right, rc.bottom-(margin.bottom>>1), TmpTxt, 0);
 	tdp.Align = TXA_HCENTER | TXA_VCENTER; o->SetTextSpec(&tdp);
 #ifdef USE_WIN_SECURE
-	ctime_s(TmpTxt, 24, &ti);
+	ctime_s(TmpTxt, 50, &ti);	TmpTxt[24] = 0;
 #else
 	sprintf(TmpTxt, "%s", ctime(&ti));	TmpTxt[24] = 0;
 #endif
@@ -870,7 +874,7 @@ public:
 	bool MemList(unsigned char **ptr, int type);
 
 private:
-	int CellHeight, CellWidth, FirstWidth, r_disp, c_disp, mrk_offs;
+	int CellHeight, CellWidth, FirstWidth, mrk_offs;
 	RECT cp_src_rec;			//bounding rectangle for copy range
 	bool bActive, new_mark, bCopyCut, bUpdate, isRowMark, isColMark;
 	POINT currpos, currpos2;
@@ -887,9 +891,9 @@ private:
 SpreadData::SpreadData(GraphObj *par)
 {
 	Disp = 0L;	m_range = 0L;	c_range = 0L;	w = 0L;		err_msg=last_err=rlw_file =  0L;
-	g_parent = par;		CellWidth = CellHeight = FirstWidth = 0;
-	et_racc = 0L;
-	currpos.x = currpos.y = r_disp = c_disp = mrk_offs = 0;
+	g_parent = par;		CellWidth = 76;		CellHeight = 19;	FirstWidth = 32;
+	et_racc = 0L;	currpos.x = currpos.y = mrk_offs = 0;
+	r_disp = 60;	c_disp = 40;
 	bActive = bCopyCut = bUpdate = isRowMark = isColMark = false;
 	cp_src_rec.left = cp_src_rec.right = cp_src_rec.top = cp_src_rec.bottom = 0;
 	if(defs.IniFile && FileExist(defs.IniFile)) {
@@ -913,17 +917,21 @@ SpreadData::Init(int nRows, int nCols)
 {
 	int i, j;
 	RECT rc;
+	RangeInfo *o_ri;
 
 	cRows = nRows;	cCols = nCols;				currpos.x = currpos.y = 0;
 	new_mark = bCopyCut = false;				if(w && m_range) HideMark(true);
+	while(ri->Type()) {
+		o_ri = ri;		ri = ri->Next();		delete(o_ri);
+		}
 	if(!Disp) {
 		Disp = new SpreadWin(g_parent, this);
 		w = Disp->w;
 		if(w) {
 			CellWidth = w->un2ix(defs.GetSize(SIZE_CELLWIDTH));
 			CellHeight = w->un2iy(defs.GetSize(SIZE_CELLTEXT)/defs.ss_txt) + 2;
-			FirstWidth = 32;
-			w->GetSize(&rc);
+			if(CellHeight < 12)CellHeight = 19;		if(CellWidth < 40)CellWidth = 76;
+			FirstWidth = 32;						w->GetSize(&rc);
 			r_disp = (rc.bottom-rc.top)/CellHeight;
 			c_disp = (rc.right-rc.left)/CellWidth+1;
 			}
@@ -968,28 +976,30 @@ SpreadData::mpos2dpos(POINT *mp, POINT *dp, bool can_scroll)
 	dp->y = (mp->y - w->MenuHeight - CellHeight)/CellHeight + Disp->ssOrg.y;
 	dp->x = Disp->ssOrg.x;
 	for(mx = mp->x - ri->GetFirstWidth() - ri->GetWidth(dp->x); mx > 0; dp->x++, mx -= ri->GetWidth(dp->x));
-	if(can_scroll && dp->x < cCols && mp->x < (ri->GetFirstWidth()+10) && mp->x > ri->GetFirstWidth() && Disp->ssOrg.x >0) {
-		Disp->ssOrg.x -= 1;
-		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
-		Disp->Command(CMD_SETSCROLL, 0L, w);
-		}
-	if(can_scroll && mp->y < (w->MenuHeight + CellHeight+9) && mp->y > (w->MenuHeight + CellHeight) && Disp->ssOrg.y >0) {
-		Disp->ssOrg.y -= 1;
-		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
-		Disp->Command(CMD_SETSCROLL, 0L, w);
-		}
-	if(can_scroll && mp->x > (Disp->currRC.right-w->MenuHeight-10) && Disp->ssOrg.x < (cCols-2)) {
-		Disp->ssOrg.x += 1;
-		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
-		Disp->Command(CMD_SETSCROLL, 0L, w);
-		}
-	if(can_scroll && mp->y > (Disp->currRC.bottom-10) && Disp->ssOrg.y < (cRows-5)) {
-		Disp->ssOrg.y += 1;
-		do {
-			mp->y -= CellHeight;
-		} while(mp->y > (Disp->currRC.bottom-CellHeight));
-		if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
-		Disp->Command(CMD_SETSCROLL, 0L, w);			CurrText = 0L;
+	if(can_scroll) {
+		if(dp->x < cCols && mp->x < (ri->GetFirstWidth()+10) && mp->x > ri->GetFirstWidth() && Disp->ssOrg.x >0) {
+			Disp->ssOrg.x -= 1;
+			if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
+			Disp->Command(CMD_SETSCROLL, 0L, w);
+			}
+		if(mp->y < (w->MenuHeight + CellHeight+9) && mp->y > (w->MenuHeight + CellHeight) && Disp->ssOrg.y >0) {
+			Disp->ssOrg.y -= 1;
+			if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
+			Disp->Command(CMD_SETSCROLL, 0L, w);
+			}
+		if(mp->x > (Disp->currRC.right-w->MenuHeight-10) && Disp->ssOrg.x < (cCols-2)) {
+			Disp->ssOrg.x += 1;
+			if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
+			Disp->Command(CMD_SETSCROLL, 0L, w);
+			}
+		if(mp->y > (Disp->currRC.bottom-10) && Disp->ssOrg.y < (cRows-5)) {
+			Disp->ssOrg.y += 1;
+			do {
+				mp->y -= CellHeight;
+			} while(mp->y > (Disp->currRC.bottom-CellHeight));
+			if(CurrText) CurrText->Update(2, w, mp);		CurrText = 0L;
+			Disp->Command(CMD_SETSCROLL, 0L, w);			CurrText = 0L;
+			}
 		}
 	if(dp->y >= cRows) dp->y = cRows-1;					if(dp->x >= cCols) dp->x = cCols-1;
 	return true;
@@ -1004,7 +1014,7 @@ SpreadData::Select(POINT *p)
 		if(CurrText->isFormula() && CurrText->hasMark()) et_racc = CurrText;
 		return true;
 		}
-	mpos2dpos(p, &currpos, false);
+	if(!(mpos2dpos(p, &currpos, false)))return false;
 	if(currpos.y < cRows && currpos.x < cCols && currpos.y >= 0 && currpos.x >= 0) {
 		if(etRows[currpos.y][currpos.x]) {
 			if(etRows[currpos.y][currpos.x] == CurrText) CurrText->Update(1, w, p);
@@ -1115,7 +1125,8 @@ SpreadData::WriteData(char *FileName)
 		MemList(&buff, FF_RLW);
 		if(buff){
 			if(rlw_file != FileName) {
-				if(rlw_file) free(rlw_file);		rlw_file = _strdup(FileName);
+				if(rlw_file) free(rlw_file);
+				rlw_file = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
 				}
 			if(fprintf(File, "%s", buff) <= 0) bErr = true;
 			free(buff);					fclose(File);
@@ -1171,11 +1182,12 @@ SpreadData::ReadData(char *FileName, unsigned char *buffer, int type)
 			0 == strcmp(".rlw", FileName+strlen(FileName)-4) ||
 			0 == strcmp(".RLW", FileName+strlen(FileName)-4) ||
 			IsXmlFile(FileName)){
+			Disp->Command(CMD_DELGRAPH, 0L, w);
 			if(ReadXML(FileName, buffer, type, 0L)){
 				if(0 == strcmp(".rlw", FileName+strlen(FileName)-4) ||
 					0 == strcmp(".RLW", FileName+strlen(FileName)-4)) {
-					if(rlw_file)	free(rlw_file);
-					rlw_file = _strdup(FileName);
+					if(rlw_file) free(rlw_file);
+					rlw_file = (char*)memdup(FileName, (int)strlen(FileName)+1, 0);
 					}
 				return true;
 				}
@@ -1375,7 +1387,7 @@ SpreadData::DeleteCols()
 						etRows[i][j-dc]->type = ET_VALUE;
 						break;
 					case ET_FORMULA:
-						MoveFormula(this, etRows[i][j]->text, TmpTxt, -dc, 0, -1, c0);
+						MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, -dc, 0, -1, c0);
 						etRows[i][j-dc]->SetText(TmpTxt);	etRows[i][j]->type = ET_FORMULA;
 						break;
 						}
@@ -1391,11 +1403,11 @@ SpreadData::DeleteCols()
 				}
 			}
 		cCols -= dc;
-		MoveFormula(this, m_range, TmpTxt, -dc, 0, -1, c0+1);		free(m_range);
+		MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, -dc, 0, -1, c0+1);		free(m_range);
 		m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);	nc--;
 		for(i = 0; i < c0; i++) for(j = 0; j < c0; j++) {
 			if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
-				MoveFormula(this, etRows[i][j]->text, TmpTxt, -dc, 0, -1, c0);
+				MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, -dc, 0, -1, c0);
 				etRows[i][j]->SetText(TmpTxt);			etRows[i][j]->type = ET_FORMULA;
 				}
 			}
@@ -1452,7 +1464,7 @@ SpreadData::InsertCols()
 						etRows[i][j]->type = ET_VALUE;
 						break;
 					case ET_FORMULA:
-						MoveFormula(this, etRows[i][j-dc]->text, TmpTxt, dc, 0, -1, c0);
+						MoveFormula(this, etRows[i][j-dc]->text, TmpTxt, TMP_TXT_SIZE, dc, 0, -1, c0);
 						etRows[i][j]->SetText(TmpTxt);	etRows[i][j]->type = ET_FORMULA;
 						break;
 						}
@@ -1460,11 +1472,11 @@ SpreadData::InsertCols()
 					}
 				}
 			}
-		MoveFormula(this, m_range, TmpTxt, dc, 0, -1, c0);		free(m_range);
+		MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, dc, 0, -1, c0);		free(m_range);
 		m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);	nc--;
 		for(i = 0; i < c0; i++) for(j = 0; j < c0; j++) {
 			if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
-				MoveFormula(this, etRows[i][j]->text, TmpTxt, dc, 0, -1, c0);
+				MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, dc, 0, -1, c0);
 				etRows[i][j]->SetText(TmpTxt);			etRows[i][j]->type = ET_FORMULA;
 				}
 			}
@@ -1521,7 +1533,7 @@ SpreadData::DeleteRows()
 						etRows[i-dr][j]->type = ET_VALUE;
 						break;
 					case ET_FORMULA:
-						MoveFormula(this, etRows[i][j]->text, TmpTxt, 0, -dr, r0, -1);
+						MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, 0, -dr, r0, -1);
 						etRows[i-dr][j]->SetText(TmpTxt);	etRows[i-dr][j]->type = ET_FORMULA;
 						break;
 						}
@@ -1535,11 +1547,11 @@ SpreadData::DeleteRows()
 				}
 			}
 		cRows -= dr;
-		MoveFormula(this, m_range, TmpTxt, 0, -dr, r0+1, -1);		free(m_range);
+		MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, 0, -dr, r0+1, -1);		free(m_range);
 		m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);	nr--;
 		for(i = 0; i < r0; i++) for(j = 0; j < cCols; j++) {
 			if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
-				MoveFormula(this, etRows[i][j]->text, TmpTxt, 0, -dr, r0, -1);
+				MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, 0, -dr, r0, -1);
 				etRows[i][j]->SetText(TmpTxt);			etRows[i][j]->type = ET_FORMULA;
 				}
 			}
@@ -1598,7 +1610,7 @@ SpreadData::InsertRows()
 						etRows[i][j]->type = ET_VALUE;
 						break;
 					case ET_FORMULA:
-						MoveFormula(this, etRows[i-dr][j]->text, TmpTxt, 0, dr, r0, -1);
+						MoveFormula(this, etRows[i-dr][j]->text, TmpTxt, TMP_TXT_SIZE, 0, dr, r0, -1);
 						etRows[i][j]->SetText(TmpTxt);	etRows[i][j]->type = ET_FORMULA;
 						break;
 						}
@@ -1606,11 +1618,11 @@ SpreadData::InsertRows()
 					}
 				}
 			}
-		MoveFormula(this, m_range, TmpTxt, 0, dr, r0, -1);		free(m_range);
+		MoveFormula(this, m_range, TmpTxt, TMP_TXT_SIZE, 0, dr, r0, -1);		free(m_range);
 		m_range = (char*)memdup(TmpTxt, (int)strlen(TmpTxt)+1, 0);	nr--;
 		for(i = 0; i < r0; i++) for(j = 0; j < cCols; j++) {
 			if(etRows && etRows[i] && etRows[i][j] && etRows[i][j]->type == ET_FORMULA) {
-				MoveFormula(this, etRows[i][j]->text, TmpTxt, 0, dr, r0, -1);
+				MoveFormula(this, etRows[i][j]->text, TmpTxt, TMP_TXT_SIZE, 0, dr, r0, -1);
 				etRows[i][j]->SetText(TmpTxt);			etRows[i][j]->type = ET_FORMULA;
 				}
 			}
@@ -1637,12 +1649,13 @@ SpreadData::DoPlot(anyOutput *o)
 	AccRange *ar;
 
 	if(!w || !Disp) return;
-	w->Erase(0x00e8e8e8L);					w->ActualSize(&rc);
+	w->Erase(0x00e8e8e8L);					if(!(w->ActualSize(&rc)))return;
 	w->SetTextSpec(&ssText);				et_racc = 0L;
 	r_disp = (rc.bottom-rc.top)/CellHeight;
-	for(c = Disp->ssOrg.x, j=rc.left, c_disp = 1; c < cCols && j <= rc.right; c++, c_disp++) {
+	for(c = Disp->ssOrg.x, j=rc.left, c_disp = 1; c < cCols && j <= (rc.right-rc.left) && c_disp < cCols; c++, c_disp++) {
 		j += ri->GetWidth(c);
 		}
+	if(j >= (rc.right-rc.left))c_disp--;
 	Disp->ShowGrid(CellWidth, CellHeight, FirstWidth, &currpos);
 	rc.top = w->MenuHeight;					rc.bottom = rc.top + CellHeight;
 	for(i = 0; i <= (cRows - Disp->ssOrg.y) && i <= r_disp; i++) {
@@ -1682,7 +1695,8 @@ SpreadData::DoPlot(anyOutput *o)
 		delete (ar);
 		}
 	if(c_range) InitCopy(0, 0L, w);			//move animated rectangle
-	w->ActualSize(&rc);		rc.bottom += CellHeight;		w->UpdateRect(&rc, false);
+	if(!(w->ActualSize(&rc))) return;		
+	rc.bottom += CellHeight;		w->UpdateRect(&rc, false);
 	if(err_msg && (!last_err || strcmp(err_msg,last_err))) {
 		ErrorBox(last_err = err_msg);
 		}
@@ -1751,7 +1765,7 @@ SpreadData::PasteRange(int cmd, char *txt)
 bool
 SpreadData::InitCopy(int cmd, void *tmpl, anyOutput *o)
 {
-	int i, r, c;
+	int r, c;
 	AccRange *ar;
 	RECT rc_band, rcCopy;
 	bool bRet = false;
@@ -1772,14 +1786,9 @@ SpreadData::InitCopy(int cmd, void *tmpl, anyOutput *o)
 		else if (CurrText) {
 			if(CurrText->hasMark()) return CurrText->Command(CMD_COPY, o, 0L);
 			else {
-				if(m_range) free(m_range);	m_range=0L;
-#ifdef USE_WIN_SECURE
-				i = sprintf_s(TmpTxt, TMP_TXT_SIZE, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
-#else
-				i = sprintf(TmpTxt, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
-#endif
-				m_range = (char*)malloc(i*2+2);				rlp_strcpy(m_range, i+1, TmpTxt);
-				rlp_strcpy(m_range +i, i, TmpTxt);			DoPlot(o);
+				if(m_range = (char*)realloc(m_range, 40*sizeof(char)))
+					rlp_strcpy(m_range, 40, mkRangeRef(currpos.y, currpos.x, currpos.y, currpos.x));
+				DoPlot(o);
 				return InitCopy(cmd, tmpl, o);
 				}
 			}
@@ -1840,6 +1849,7 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 	static int move_cr = CMD_CURRDOWN;
 	MouseEvent *mev;
 	POINT p, cp;
+	RECT rc;
 	
 	if(!o) o = w;
 	switch(cmd) {
@@ -1847,7 +1857,7 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 		mev = (MouseEvent *) tmpl;
 		p.x = mev->x;				p.y = mev->y;
 		if((mev->StateFlags & 1) || mev->Action == MOUSE_LBUP || p.y < (w->MenuHeight+CellHeight)) {
-			mpos2dpos(&p, &cp, (mev->StateFlags & 1) == 1);
+			if(!(mpos2dpos(&p, &cp, (mev->StateFlags & 1) == 1))) return false;
 			if(cp.y >= cRows || cp.x >= cCols || cp.y < 0 || cp.x < 0) return false;
 			}
 		else cp.x = cp.y = 0;
@@ -1879,27 +1889,19 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 				if(!et_racc && !m_range && CurrText) {
 					CurrText->Update(2, w, &p);		 CurrText = 0L;	
 					}
+				if(mrk_offs && m_range && m_range[0]){
+					mrk_offs = rlp_strcpy(TmpTxt, mrk_offs+1, m_range);
+					}
+				else mrk_offs = 0;
 				if(p.x < FirstWidth || p.y < (w->MenuHeight+CellHeight)) {
-#ifdef USE_WIN_SECURE
-					i = sprintf_s(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(p.x < FirstWidth ? 0 : currpos.x, false),
-						p.y < (w->MenuHeight+CellHeight) ? 0 : currpos.y+1);
-					sprintf_s(TmpTxt+mrk_offs+i, TMP_TXT_SIZE - mrk_offs-i, "%s%d", Int2ColLabel(p.x < FirstWidth ? cCols-1 : cp.x, false), 
-						p.y < (w->MenuHeight+CellHeight) ? cRows : cp.y+1);
-#else
-					i = sprintf(TmpTxt+mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(p.x < FirstWidth ? 0 : currpos.x, false),
-						p.y < (w->MenuHeight+CellHeight) ? 0 : currpos.y+1);
-					sprintf(TmpTxt+mrk_offs+i, "%s%d", Int2ColLabel(p.x < FirstWidth ? cCols-1 : cp.x, false), 
-						p.y < (w->MenuHeight+CellHeight) ? cRows : cp.y+1);
-#endif
+					if(mrk_offs && TmpTxt[mrk_offs-1] != ';')TmpTxt[mrk_offs++] = ';';
+					rlp_strcpy(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, mkRangeRef(
+						p.y < (w->MenuHeight+CellHeight) ? 0 : currpos.y, p.x < FirstWidth ? 0 : currpos.x,
+						p.y < (w->MenuHeight+CellHeight) ? cRows : cp.y, p.x < FirstWidth ? cCols-1 : cp.x));
 					}
 				else {
-#ifdef USE_WIN_SECURE
-					i = sprintf_s(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(currpos.x, false), currpos.y+1);
-					sprintf_s(TmpTxt+mrk_offs+i, TMP_TXT_SIZE - mrk_offs-i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
-#else
-					i = sprintf(TmpTxt+mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(currpos.x, false), currpos.y+1);
-					sprintf(TmpTxt+mrk_offs+i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
-#endif
+					if(mrk_offs && TmpTxt[mrk_offs-1] != ';')TmpTxt[mrk_offs++] = ';';
+					rlp_strcpy(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, mkRangeRef(currpos.y, currpos.x, cp.y, cp.x));
 					}
 				if(!CurrText || et_racc)MarkRange(TmpTxt, &cp);
 				return true;
@@ -1926,15 +1928,13 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 					if(p.y < (w->MenuHeight+CellHeight)) {
 						currpos.y = 0;	cp.y = cRows-1;
 						}
-#ifdef USE_WIN_SECURE
-					i = sprintf_s(TmpTxt+mrk_offs, TMP_TXT_SIZE-mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(currpos.x, false), currpos.y+1);
-					sprintf_s(TmpTxt+mrk_offs+i, TMP_TXT_SIZE-mrk_offs-i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
-#else
-					i = sprintf(TmpTxt+mrk_offs, "%s%s%d:", mrk_offs? ";" : "", Int2ColLabel(currpos.x, false), currpos.y+1);
-					sprintf(TmpTxt+mrk_offs+i, "%s%d", Int2ColLabel(cp.x, false), cp.y+1);
-#endif
-					MarkRange(TmpTxt);
-					currpos2.x = cp.x;		currpos2.y = cp.y + 1;
+					if(mrk_offs && m_range && m_range[0]){
+						mrk_offs = rlp_strcpy(TmpTxt, mrk_offs+1, m_range);
+						}
+					else mrk_offs = 0;
+					if(mrk_offs && TmpTxt[mrk_offs-1] != ';')TmpTxt[mrk_offs++] = ';';
+					rlp_strcpy(TmpTxt+mrk_offs, TMP_TXT_SIZE - mrk_offs, mkRangeRef(currpos.y, currpos.x, cp.y, cp.x));
+					MarkRange(TmpTxt);			currpos2.x = cp.x;		currpos2.y = cp.y + 1;
 					}
 				else if((m_range) && !new_mark) HideMark(false);
 				if(et_racc && !et_racc->isInRect(&p)) {
@@ -1943,14 +1943,9 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 						CurrText->Command(CMD_ADDTXT, o, (DataObj*) m_range);
 						}
 					else {
-						if(!m_range) m_range = (char*)malloc(20);
-#ifdef USE_WIN_SECURE
-						sprintf_s(m_range, 20, "%s%d%", Int2ColLabel(currpos.x, false), currpos.y+1);
-#else
-						sprintf(m_range, "%s%d%", Int2ColLabel(currpos.x, false), currpos.y+1);
-#endif
+						m_range = (char*)realloc(m_range, 40*sizeof(char));
+						rlp_strcpy(m_range, 40, mkCellRef(currpos.y, currpos.x));
 						CurrText->Command(CMD_ADDTXT, o, (DataObj*) m_range);
-						free(m_range);	m_range = 0L;
 						}
 					}
 				else if(m_range) {
@@ -2059,8 +2054,7 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 		currpos2.y ++;
 		if(currpos2.y >= cRows) currpos2.y --;		if(currpos2.y < 0) currpos2.y ++;
 		//mark rectangular range
-		i = sprintf(TmpTxt, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
-		sprintf(TmpTxt+i, "%s%d", Int2ColLabel(currpos2.x, false), currpos2.y+1);
+		rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
 		MarkRange(TmpTxt);							HideTextCursor();
 		break;
 	case CMD_SHIFTRIGHT:	case CMD_SHIFTLEFT:
@@ -2075,8 +2069,7 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 		else currpos2.x ++;
 		if(currpos2.x >= cCols) currpos2.x --;		if(currpos2.x < 0) currpos2.x ++;
 		//mark rectangular range
-		i = sprintf(TmpTxt, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
-		sprintf(TmpTxt+i, "%s%d", Int2ColLabel(currpos2.x, false), currpos2.y+1);
+		rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
 		MarkRange(TmpTxt);							HideTextCursor();
 		break;
 	case CMD_SHPGUP:
@@ -2085,8 +2078,7 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 			if(Disp->ssOrg.y < 0) Disp->ssOrg.y = 0;
 			Disp->Command(CMD_SETSCROLL, 0L, w);
 			currpos2.y -= r_disp;					if(currpos2.y < 0) currpos2.y = 0;
-			i = sprintf(TmpTxt, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
-			sprintf(TmpTxt+i, "%s%d", Int2ColLabel(currpos2.x, false), currpos2.y+1);
+			rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
 			MarkRange(TmpTxt);							HideTextCursor();
 			}
 		break;
@@ -2098,13 +2090,12 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 		if(currpos2.y < (cRows-1)) {
 			currpos2.y += r_disp;					if(currpos2.y >= cRows) currpos2.y = cRows-1;
 			//mark rectangular range
-			i = sprintf(TmpTxt, "%s%d:", Int2ColLabel(currpos.x, false), currpos.y+1);
-			sprintf(TmpTxt+i, "%s%d", Int2ColLabel(currpos2.x, false), currpos2.y+1);
+			rlp_strcpy(TmpTxt, 40, mkRangeRef(currpos.y, currpos.x, currpos2.y, currpos2.x));
 			MarkRange(TmpTxt);							HideTextCursor();
 			}
 		break;
 	case CMD_CURRIGHT:		case CMD_CURRDOWN:
-		move_cr = cmd;
+		move_cr = cmd;		w->ActualSize(&rc);
 	case CMD_CURRLEFT:		case CMD_CURRUP:	case CMD_POS_FIRST:		case CMD_POS_LAST:
 		if(cmd == CMD_CURRUP && Disp->ssOrg.y && CurrText && currpos.y == Disp->ssOrg.y) {
 			Disp->ssOrg.y --;		currpos.y --;
@@ -2121,9 +2112,9 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 				}
 			DoPlot(o);		return false;
 			}
-		if(cmd == CMD_CURRIGHT && c_disp > 3 && (currpos.x-Disp->ssOrg.x) >= (c_disp-3)) {
+		if(CurrText && cmd == CMD_CURRIGHT && c_disp > 3 && ((currpos.x-Disp->ssOrg.x) >= (c_disp-1) || CurrText->GetRX() >= (rc.right-rc.left-10))) {
 			Disp->ssOrg.x ++;		currpos.y ++;			DoPlot(o);
-			if(CurrText) CurrText->Command(CMD_POS_FIRST, o, this);
+			CurrText->Command(CMD_POS_FIRST, o, this);
 			}
 		if(cmd == CMD_CURRDOWN && r_disp > 3 && (currpos.y-Disp->ssOrg.y) >= (r_disp-3)) {
 			Disp->ssOrg.y ++;		currpos.y ++;			DoPlot(o);
@@ -2249,8 +2240,8 @@ SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flag
 		if(!(XMLcache = new ReadCache())) return false;
 		if(! XMLcache->Open(file)) {
 			delete XMLcache;
-			sprintf(TmpTxt, "Error open file\n\"%s\"", file);
-			ErrorBox(TmpTxt);
+			i = rlp_strcpy(TmpTxt, 40, "Error open file\n\"");		i = rlp_strcpy(TmpTxt+i, 200, file);
+			rlp_strcpy(TmpTxt+i, 2, "\"");							ErrorBox(TmpTxt);
 			return false;
 			}
 		bUndo_done = true;
@@ -2294,13 +2285,20 @@ SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flag
 				}while(TmpTxt[i-1] > 31 && TmpTxt[i-1] != '>');
 			TmpTxt[i] = 0;
 			row = col = 0;
-			if(TmpTxt[17] = '=' && TmpTxt[13] == 'r') {
-				strcpy(TmpTxt, TmpTxt+19);
+			if(TmpTxt[17] == '=' && TmpTxt[13] == 'r') {
+#ifdef USE_WIN_SECURE
+				sscanf_s(TmpTxt+19, "%d", &row);
+#else
+				sscanf(TmpTxt+19, "%d", &row);
+#endif
 				}
 			else break;
-			sscanf(TmpTxt, "%d", &row);
-			for(i = 0; TmpTxt[i] && TmpTxt[i] != '='; i++);
+			for(i = 20; TmpTxt[i] && TmpTxt[i] != '='; i++);
+#ifdef USE_WIN_SECURE
+			sscanf_s(TmpTxt+i+2, "%d", &col);
+#else
 			sscanf(TmpTxt+i+2, "%d", &col);
+#endif
 			if(row && col) {
 				AddCols(col);		AddRows(row);
 				}
@@ -2351,15 +2349,18 @@ SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flag
 				for(i = 1; i < 6; TmpTxt[i++] = XMLcache->Getc());
 				TmpTxt[i] = 0;
 				if(bContinue =(0 == strcmp("<text>", TmpTxt))) {
-					for(i = 0; i < 1023 && ('<' != (TmpTxt[i] =XMLcache->Getc())); i++);
-					TmpTxt[i] = 0;
+					for(i = 0; i < 1023; i++) {
+						if(!(TmpTxt[i] =XMLcache->Getc())) break;
+						if(i >1 && TmpTxt[i-2] == '<' && TmpTxt[i-1] == '/' && TmpTxt[i] == 't') break;
+						}
+					i -=2;		TmpTxt[i] = 0;
 					//xml indices start at 1:1 !
 					row += currpos.y-1;	col += currpos.x-1;
 					if(row >= cRows)AddRows(row+1);
 					if(col >= cCols)AddCols(col+1);
 					if(i && etRows[row] && etRows[row][col]) {
 						if(TmpTxt[0] == '=') {
-							MoveFormula(this, TmpTxt, TmpTxt, currpos.x-mov.x, currpos.y-mov.y, -1, -1);
+							MoveFormula(this, TmpTxt, TmpTxt, TMP_TXT_SIZE, currpos.x-mov.x, currpos.y-mov.y, -1, -1);
 							}
 						etRows[row][col]->SetText(TmpTxt);
 						etRows[row][col]->Update(20, 0L, &pt);
@@ -2389,7 +2390,9 @@ SpreadData::ReadTSV(char *file, unsigned char *buffer, int type)
 		if(!(TSVcache = new ReadCache())) return false;
 		if(! TSVcache->Open(file)) {
 			delete TSVcache;
-			sprintf(TmpTxt, "Error open file\n\"%s\"", file);
+			i = rlp_strcpy(TmpTxt, 200, "Error open file\n\"");
+			i += rlp_strcpy(TmpTxt+i, 200-i, file);
+			i += rlp_strcpy(TmpTxt+i, 200-i, "\"\n");
 			ErrorBox(TmpTxt);
 			return false;
 			}
@@ -2442,20 +2445,25 @@ TSVError:
 	return bRet;
 }
 
+static void sylk_cell_ref(char** ptr, int *cbd, int *size, char *first, char* trail, int row, int col)
+{
+	if(first && first[0]) add_to_buff(ptr, cbd, size, first, 0);
+	add_to_buff(ptr, cbd, size, "Y", 1);	add_int_to_buff(ptr, cbd, size, row+1, false, 0);
+	add_to_buff(ptr, cbd, size, ";X", 2);	add_int_to_buff(ptr, cbd, size, col+1, false, 0);
+	if(trail && trail[0]) add_to_buff(ptr, cbd, size, trail, 0);
+}
+
 bool 
 SpreadData::MemList(unsigned char **ptr, int type)
 {
-	int i, j, k, nc, nl, cb = 0; 
-	long cbd = 0, size;
-	char tmptxt[8000];
-	*ptr = (unsigned char *)malloc(size = 10000);
-	unsigned char *tmpptr;
+	int i, j, nc, nl; 
+	int cbd = 0, size;
 	bool bLimit = true;
 	AccRange *ar;
 	anyResult res;
 	RECT rcCopy;
 
-	if(!(*ptr))return false;
+	if(!(*ptr = (unsigned char *)malloc(size = 10000)))return false;
 	if (c_range &&  c_range[0]) {
 		ar = new AccRange(c_range);			ar->BoundRec(&rcCopy);
 		if(bCopyCut) Undo.DataObject(Disp, w, this, &rcCopy, 0L);
@@ -2466,34 +2474,45 @@ SpreadData::MemList(unsigned char **ptr, int type)
 		}
 	if(rcCopy.left < 0) rcCopy.left = 0;	if(rcCopy.right >= cCols) rcCopy.right = cCols-1;
 	if(rcCopy.top < 0) rcCopy.top = 0;		if(rcCopy.bottom >= cRows) rcCopy.bottom = cRows-1;
-	if(type == FF_SYLK) cbd = sprintf((char*)*ptr, "ID;PWXL;N;E\r\n"
-		"P;Pdd/mm/yyyy\r\nP;Phh:mm:ss\r\nP;Pdd/mm/yyyy hh:mm:ss\r\n");
+	if(type == FF_SYLK) cbd = rlp_strcpy((char*)*ptr, size, "ID;PWXL;N;E\n"
+		"P;Pdd/mm/yyyy\nP;Phh:mm:ss\nP;Pdd/mm/yyyy hh:mm:ss\n");
 	else if(type == FF_XML) {
-		cbd = sprintf((char*)*ptr, "<?xml version=\"1.0\"?><!DOCTYPE spreadsheet-snippet>"
-		"<spreadsheet-snippet rows=\"%d\" columns=\"%d\" >\n", cRows, cCols);
+		cbd = rlp_strcpy((char*)*ptr, 100, "<?xml version=\"1.0\"?><!DOCTYPE spreadsheet-snippet>"
+			"<spreadsheet-snippet rows=\"");
+		add_int_to_buff((char**)ptr, &cbd, &size, cRows, false, 0);
+		add_to_buff((char**)ptr, &cbd, &size, "\" columns=\"", 11);
+		add_int_to_buff((char**)ptr, &cbd, &size, cCols, false, 0);
+		add_to_buff((char**)ptr, &cbd, &size, "\">\n", 3);
 		if(rcCopy.left || rcCopy.top || rcCopy.bottom || rcCopy.right){
-			cbd += sprintf((char*)*ptr+cbd, " <pos1 row=\"%d\" "
-				"column=\"%d\"></pos1>\n", rcCopy.top, rcCopy.left);
-			cbd += sprintf((char*)*ptr+cbd, " <pos2 row=\"%d\" "
-				"column=\"%d\"></pos2>\n", rcCopy.bottom, rcCopy.right);
+			add_to_buff((char**)ptr, &cbd, &size, " <pos1 row=\"", 12);
+			add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.top, false, 0);
+			add_to_buff((char**)ptr, &cbd, &size, "\" column=\"", 10);
+			add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.left, false, 0);
+			add_to_buff((char**)ptr, &cbd, &size, "\"></pos1>\n <pos2 row=\"", 22);
+			add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.bottom, false, 0);
+			add_to_buff((char**)ptr, &cbd, &size, "\" column=\"", 10);
+			add_int_to_buff((char**)ptr, &cbd, &size, rcCopy.right, false, 0);
+			add_to_buff((char**)ptr, &cbd, &size, "\"></pos2>\n", 10);
 			}
 		}
 	else if(type == FF_RLW) {
-		cbd = sprintf((char*)*ptr, "<?xml version=\"1.0\"?><!DOCTYPE RLPlot-workbook>\n"
-		"<RLPlot-data rows=\"%d\" columns=\"%d\" >\n", cRows, cCols);
+		cbd = rlp_strcpy((char*)*ptr, size, "<?xml version=\"1.0\"?><!DOCTYPE RLPlot-workbook>\n<RLPlot-data rows=\"");
+		add_int_to_buff((char**)ptr, &cbd, &size, cRows, false, 0);
+		add_to_buff((char**)ptr, &cbd, &size, "\" columns=\"", 11);
+		add_int_to_buff((char**)ptr, &cbd, &size, cCols, false, 0);
+		add_to_buff((char**)ptr, &cbd, &size, "\">\n", 3);
 		}
 	for(nl =0, i = rcCopy.top; i <= rcCopy.bottom; i++, nl++) {
-		for(nc = 0, j = rcCopy.left; j <= rcCopy.right; cb = 0, j++, nc++) {
+		for(nc = 0, j = rcCopy.left; j <= rcCopy.right; j++, nc++) {
 			switch (type) {
 			case FF_TSV:
-				if(nl || nc) cb = sprintf(tmptxt,"%s", nc ? "\t" : "\n");
+				if(nl || nc) add_to_buff((char**)ptr, &cbd, &size, nc ? (char*)"\t" : (char*)"\n", 1);
 				if(etRows[i] && etRows[i][j]){
 					if((ar && ar->IsInRange(j,i)) || !ar) {
 						etRows[i][j]->GetResult(&res, false);
 						TranslateResult(&res);
-						cb += sprintf(tmptxt+cb, "%s", res.text);
+						add_to_buff((char**)ptr, &cbd, &size, res.text, 0);
 						}
-					tmptxt[cb] = 0;
 					}
 				break;
 			case FF_SYLK:
@@ -2502,64 +2521,62 @@ SpreadData::MemList(unsigned char **ptr, int type)
 					TranslateResult(&res);
 					switch(res.type) {
 					case ET_VALUE:	case ET_BOOL:
-						cb = sprintf(tmptxt, "C;Y%d;X%d;K", nl+1, nc+1);
-						cb += sprintf(tmptxt+cb, "%s\r\n", res.text);
+						sylk_cell_ref((char**) ptr, &cbd, &size, "C;", ";K", nl, nc);
+						add_to_buff((char**)ptr, &cbd, &size, res.text, 0);
 						break;
 					case ET_DATE:
-						cb = sprintf(tmptxt, "F;P0;FG0G;Y%d;X%d\r\n", nl+1, nc+1);
-						cb += sprintf(tmptxt+cb, "C;K%g\r\n", res.value+1.0);
+						sylk_cell_ref((char**) ptr, &cbd, &size, "F;P0;FG0G;", "\nC;K", nl, nc);
+						add_dbl_to_buff((char**)ptr, &cbd, &size, res.value+1, false);
 						break;
 					case ET_DATETIME:
-						cb = sprintf(tmptxt, "F;P2;FG0G;Y%d;X%d\r\n", nl+1, nc+1);
-						cb += sprintf(tmptxt+cb, "C;K%g\r\n", res.value+1.0);
+						sylk_cell_ref((char**) ptr, &cbd, &size, "F;P2;FG0G;", "\nC;K", nl, nc);
+						add_dbl_to_buff((char**)ptr, &cbd, &size, res.value+1, false);
 						break;
 					case ET_TIME:
-						cb = sprintf(tmptxt, "F;P1;FG0G;Y%d;X%d\r\n", nl+1, nc+1);
-						cb += sprintf(tmptxt+cb, "C;K%g\r\n", res.value-floor(res.value));
+						sylk_cell_ref((char**) ptr, &cbd, &size, "F;P1;FG0G;", "\nC;K", nl, nc);
+						add_dbl_to_buff((char**)ptr, &cbd, &size, res.value, false);
 						break;
 					case ET_TEXT:
-						cb = sprintf(tmptxt, "C;Y%d;X%d;K", nl+1, nc+1);
-						cb += sprintf(tmptxt+cb, "\"%s\"\r\n", res.text);
+						sylk_cell_ref((char**) ptr, &cbd, &size, "C;", ";K\"", nl, nc);
+						add_to_buff((char**)ptr, &cbd, &size, res.text, 0);
+						add_to_buff((char**)ptr, &cbd, &size, "\"", 1);
 						break;
 						}
+					add_to_buff((char**)ptr, &cbd, &size, "\n", 1);
 					if(bCopyCut) etRows[i][j]->SetText("");
 					}
 				break;
 			case FF_RLW:	case FF_XML:
 				if(etRows[i] && etRows[i][j] && etRows[i][j]->text && ((ar && ar->IsInRange(j,i)) || !ar)
 					&& etRows[i][j]->text[0]){
-					cb = sprintf(tmptxt, " <cell row=\"%d\" column=\"%d\" >\n", nl+1, nc+1);
-					cb += sprintf(tmptxt+cb, "  <text>");
-					for(k = 0; k < 7880 && (etRows[i][j]->text[k]); k++) 
-						tmptxt[cb++] = etRows[i][j]->text[k];
-					cb += sprintf(tmptxt+cb, "</text>\n </cell>\n");
+					add_to_buff((char**)ptr, &cbd, &size, " <cell row=\"", 12);
+					add_int_to_buff((char**)ptr, &cbd, &size, nl+1, false, 0);
+					add_to_buff((char**)ptr, &cbd, &size, "\" column=\"", 10);
+					add_int_to_buff((char**)ptr, &cbd, &size, nc+1, false, 0);
+					add_to_buff((char**)ptr, &cbd, &size, "\">\n  <text>", 11);
+					add_to_buff((char**)ptr, &cbd, &size, etRows[i][j]->text, 0);
+					add_to_buff((char**)ptr, &cbd, &size, "</text>\n </cell>\n", 17);
 					if(bCopyCut) etRows[i][j]->SetText("");
 					}
 				break;
 				}
-			if((cbd+cb+100) > size){
-				if(tmpptr = (unsigned char*)realloc(*ptr, size+10000)) {
-					*ptr = tmpptr;					size += 10000;
-					}
-				else return true;	//not all but something on clipboard
-				}
-			memcpy(*ptr+cbd, tmptxt, cb+1);
-			cbd += cb;
 			}
-		if(type == FF_SYLK) {
-			if(!bLimit) {
-				cbd += sprintf((char*)*ptr+cbd, "C;Y%d;X1;K\"long strings were"
-				" truncated to 256 characters due to limitations of the SYLK format!\"\n", i+2);
-				}
-			sprintf((char*)*ptr+cbd, "E\n");
+		}
+	if(type == FF_SYLK) {
+		if(!bLimit) {
+			add_to_buff((char**)ptr, &cbd, &size, "C;Y", 3);
+			add_int_to_buff((char**)ptr, &cbd, &size, i+2, false, 0);
+			add_to_buff((char**)ptr, &cbd, &size, ";X1;K\"long strings were"
+			" truncated to 256 characters due to limitations of the SYLK format!\"\n", 92);
 			}
-		else if(type == FF_TSV) sprintf((char*)*ptr+cbd,"\n");
+		add_to_buff((char**)ptr, &cbd, &size, "E\n", 2);
 		}
-	if(type == FF_XML) sprintf((char*)*ptr+cbd,"</spreadsheet-snippet>\n");
+	else if(type == FF_TSV) add_to_buff((char**)ptr, &cbd, &size, "\n", 1);
+	else if(type == FF_XML) add_to_buff((char**)ptr, &cbd, &size, "</spreadsheet-snippet>\n", 23);
 	else if(type == FF_RLW){
 		Disp->Command(CMD_WRITE_GRAPHS, ptr, (anyOutput*)&cbd);
-		sprintf((char*)*ptr+cbd,"</RLPlot-data>\n");
 		//note: cbd may be greater than size !
+		add_to_buff((char**)ptr, &cbd, &size, "</RLPlot-data>\n", 15);
 		}
 	if(ar) delete ar;
 	if(bCopyCut && type == FF_XML || type == FF_SYLK || type == FF_RLW){
diff --git a/use_gui.cpp b/use_gui.cpp
index 30dce9a..b78b780 100755
--- a/use_gui.cpp
+++ b/use_gui.cpp
@@ -962,21 +962,41 @@ Label::AddChar(int ci, anyOutput *o)
 		if(!parent->Command(CMD_MUTATE, golist, o)) DeleteGO(golist[1]);
 		return false;
 		}
-	if(ci < 254 && ci > 31) c = (char)ci;
+	if(TextDef.text && TextDef.text[0]) i = (int)strlen(TextDef.text);
+	else i = 0;		if(CursorPos > i)CursorPos = i;
+	if(ci > 254) {
+		Undo.String(this, &TextDef.text, 0L);
+		Undo.ValInt(this, &CursorPos, UNDO_CONTINUE);
+		txt1 = (char*)malloc((i+12)*sizeof(char));
+		if(txt1) {
+			if(j=CursorPos) k = rlp_strcpy(txt1, CursorPos+1, TextDef.text);
+			else k = 0;
+#ifdef USE_WIN_SECURE
+			k += sprintf_s(txt1+k, i+12-k, "&#%d;",ci);
+#else
+			k += sprintf(txt1+k, "&#%d;",ci);
+#endif
+			CursorPos = k;
+			k += rlp_strcpy(txt1+k, i+12-k, TextDef.text+j);
+			if(TextDef.text) free(TextDef.text);
+			TextDef.text = txt1;			RedrawEdit(o);
+			}
+		return true;
+		}
+	else if( ci > 31) c = (char)ci;
 	else return false;
 	if(!TextDef.text || CursorPos < 10 || c == ' ') {
 		Undo.String(this, &TextDef.text, 0L);
 		Undo.ValInt(this, &CursorPos, UNDO_CONTINUE);
 		}
-	if(TextDef.text) txt1 = (char*)calloc((i = (int)strlen(TextDef.text))+2, sizeof(char));
-	else txt1 = (char*)calloc((i = 0)+2, sizeof(char));
+	txt1 = (char*)malloc((i+4)* sizeof(char));
 	if(txt1) {
-		for(j = k = 0; j< i && j < CursorPos; txt1[k++] = TextDef.text[j++]);
-		txt1[k++] = c;
-		for(; j< i; txt1[k++] = TextDef.text[j++]);
+		if(j=CursorPos) k = rlp_strcpy(txt1, CursorPos+1, TextDef.text);
+		else k = 0;			txt1[k++] = c;
+		k += rlp_strcpy(txt1+k, i+12-k, TextDef.text+j);
 		if(TextDef.text) free(TextDef.text);
-		TextDef.text = txt1;
-		CursorPos++;		RedrawEdit(o);
+		TextDef.text = txt1;	txt1[k] = 0;
+		CursorPos++;			RedrawEdit(o);
 		}
 	return true;
 }
@@ -1066,6 +1086,40 @@ TextFrame::CalcCursorPos(int x, int y, anyOutput *o)
 	else cur_pos.x = i;
 }
 
+void
+Axis::DoMark(anyOutput *o, bool mark)
+{
+	LineDEF mrkLine;
+	double minw = DefSize(SIZE_DATA_LINE);
+	POINT *arc;
+	long narc = 0;
+
+	if(axis->flags & AXIS_ANGULAR) {
+		if(mark) {
+			o->GetSize(&mrc);						mo = GetRectBitmap(&mrc, o);
+			memcpy(&mrkLine, &axline, sizeof(LineDEF));
+			mrkLine.width = axline.width < minw ? minw * 3.0 : axline.width *3.0;
+			o->SetLine(&mrkLine);
+			if(arc = MakeArc(pts[0].x, pts[0].y, pts[1].x, 0x0f, &narc)) {
+				o->oPolyline(arc, (int)narc, 0L);
+				mrkLine.color ^= 0x00ffffffL;		mrkLine.width = axline.width;
+				o->SetLine(&mrkLine);				o->oPolyline(arc, (int)narc, 0L);
+				free(arc);
+				}
+			o->UpdateRect(&mrc, false);
+			}
+		else RestoreRectBitmap(&mo, &mrc, o);
+		return;
+		}
+	if(mark){
+		memcpy(&mrc, &rDims, sizeof(RECT));
+		IncrementMinMaxRect(&mrc, 6 + o->un2ix(axline.width));
+		mo = GetRectBitmap(&mrc, o);
+		InvertLine(pts, 2, &axline, &rDims, o, mark);
+		}
+	else RestoreRectBitmap(&mo, &mrc, o);
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Graphs are graphic objects containing plots, axes, and drawn objects
 bool
@@ -1082,7 +1136,7 @@ Graph::ExecTool(MouseEvent *mev)
 	double x, y;
 
 	if(!mev || !CurrDisp) return false;
-	td = 0L;
+	td = 0L;	if(mev->Action == MOUSE_LBUP) SuspendAnimation(CurrDisp, false);
 	if(ToolMode & TM_MOVE) switch (mev->Action) {
 		case MOUSE_LBDOWN:
 			pl.x = pc.x = mev->x;				pl.y = pc.y = mev->y;
@@ -1450,7 +1504,7 @@ Graph::ExecTool(MouseEvent *mev)
 			return true;
 		case MOUSE_MOVE:
 			if(mev->StateFlags &1) {
-				CurrDisp->MouseCursor(MC_CROSS, false);
+				CurrDisp->MouseCursor(MC_TXTFRM, false);
 				if(rcUpd.left != rcUpd.right && rcUpd.top != rcUpd.bottom)
 					CurrDisp->UpdateRect(&rcUpd, false);
 				line[0].x = line[4].x = pl.x;	line[0].y = line[4].y = pl.y;
@@ -1582,6 +1636,7 @@ Graph::DoZoom(char *z)
 	Graph *cg;
 
 	if(!z) return false;
+	HideCopyMark();
 	if(0==strcmp("fit", z)) {
 		if(CurrGraph) cg = CurrGraph;
 		else cg = this;
@@ -1591,7 +1646,7 @@ Graph::DoZoom(char *z)
 		rc_mrk.top = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_TOP))-4 
 			- iround(CurrDisp->MenuHeight);
 		rc_mrk.bottom = CurrDisp->un2ix(cg->GetSize(SIZE_GRECT_BOTTOM))+4;
-		CurrDisp->ActualSize(&cw);
+		if(!(CurrDisp->ActualSize(&cw)))return false;
 		f1 = (double)(cw.bottom - cw.top)/(double)(rc_mrk.bottom - rc_mrk.top);
 		f2 = ((double)(cw.right - cw.left)/(double)(rc_mrk.right - rc_mrk.left));
 		fac = f1 < f2 ? f1 : f2;
@@ -1624,7 +1679,7 @@ Graph::DoZoom(char *z)
 				ToolMode = TM_STANDARD;		Command(CMD_TOOLMODE, &ToolMode, CurrDisp);
 				return false;
 				}
-			CurrDisp->ActualSize(&cw);
+			if(!(CurrDisp->ActualSize(&cw)))return false;
 			fac = (double)(cw.bottom - cw.top)/(double)(rc_mrk.bottom - rc_mrk.top);
 			fac += ((double)(cw.right - cw.left)/(double)(rc_mrk.right - rc_mrk.left));
 			fac /= 2.0;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/rlplot.git



More information about the debian-science-commits mailing list