[rlplot] 05/23: Imported Upstream version 1.1

Andreas Tille tille at debian.org
Wed Jun 29 09:50:55 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 4dc4177dfb02f5c866b363b20f0cc632a7ea917a
Author: Andreas Tille <tille at debian.org>
Date:   Wed Jun 29 11:43:54 2016 +0200

    Imported Upstream version 1.1
---
 Export.cpp      |  121 ++--
 Fileio.cpp      |  184 ++++--
 ODbuttons.cpp   |   26 +-
 Output.cpp      |   84 ++-
 PlotObs.cpp     |  178 ++++--
 PropertyDlg.cpp | 1419 +++++++++++++++++++++++++++++---------------
 QT_Spec.cpp     |  688 ++++++++++++---------
 QT_Spec.h       |   79 ++-
 RLPLOT.RC       |   74 +--
 TheDialog.cpp   |  224 ++++++-
 TheDialog.h     |   12 +-
 UtilObj.cpp     |  285 +++++----
 Utils.cpp       |  140 ++++-
 Version.h       |    4 +-
 WinSpec.cpp     |   73 ++-
 exprlp.cpp      |   17 +-
 mfcalc.cpp      | 1773 ++++++++++++++++++++++++++++++++++++++-----------------
 mfcalc.y        | 1037 +++++++++++++++++++++++---------
 resource.h      |   86 ---
 rlp_math.cpp    |  729 +++++++++++++++++++++--
 rlplot.cpp      | 1617 ++++++++++++++++++++++++++++++++++----------------
 rlplot.h        |  144 ++++-
 rlplot.spec     |   13 +-
 spreadwi.cpp    |  501 +++++++++-------
 24 files changed, 6663 insertions(+), 2845 deletions(-)

diff --git a/Export.cpp b/Export.cpp
index 7b4b7f5..86107e6 100755
--- a/Export.cpp
+++ b/Export.cpp
@@ -1,4 +1,4 @@
-//Export.cpp, Copyright (c) 2002, 2003, 2004 R.Lackner
+//Export.cpp, Copyright (c) 2002-2006 R.Lackner
 //export graph files
 //
 //    This file is part of RLPlot.
@@ -33,6 +33,7 @@
 	#include <unistd.h>
 #endif
 
+extern char TmpTxt[];
 extern Default defs;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -240,7 +241,6 @@ ExportWMF::EndPage()
 	unsigned short end_token[3] = {3, 0, 0};
 
 	write(oFile, &end_token, 6);
-//	file_size = tell(oFile);
 	file_size = lseek(oFile, 0L, SEEK_CUR);
 	lseek(oFile, 0L, SEEK_SET);
 	header.mtSize0 = (file_size>>1)&0xffff;
@@ -636,7 +636,11 @@ ExportSVG::SetFill(FillDEF *fill)
 bool
 ExportSVG::SetTextSpec(TextDEF *set)
 {
-	if(!set->iSize && set->fSize > 0.0f) set->iSize = un2iy(set->fSize);
+	if(set->fSize > 0.0) {
+		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;
 	return anyOutput::SetTextSpec(set);
 }
@@ -799,7 +803,7 @@ ExportSVG::oSolidLine(POINT *p)
 bool
 ExportSVG::oTextOut(int x, int y, char *txt, int cb)
 {
-	int i, h, ix, iy;
+	int i, j, h, ix, iy, dy;
 	char tmptxt[140], *nt;
 
 	if(!txt || !txt[0]) return false;
@@ -807,19 +811,18 @@ ExportSVG::oTextOut(int x, int y, char *txt, int cb)
 	if(TxtSet.Align & TXA_VCENTER) iy = y + h/3;
 	else if(TxtSet.Align & TXA_VBOTTOM) iy = y;
 	else iy = y + iround(h * 0.8);
-	ix = x;
-	if((TxtSet.Style & TXS_SUB) || (TxtSet.Style & TXS_SUPER)) h = iround((double)TxtSet.iSize * 0.8);
+	ix = x;		dy = 0;
 	if(TxtSet.Style & TXS_SUB) {
-		if((TxtSet.Align & TXA_VCENTER) == TXA_VCENTER) iy +=un2iy(TxtSet.fSize*0.4);
-		else if((TxtSet.Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy += un2iy(TxtSet.fSize*0.2);
-		else if((TxtSet.Align & TXA_VTOP) == TXA_VTOP) iy += un2iy(TxtSet.fSize*.6);
+		if((TxtSet.Align & TXA_VCENTER) == TXA_VCENTER) dy = un2iy(TxtSet.fSize*0.4);
+		else if((TxtSet.Align & TXA_VBOTTOM) == TXA_VBOTTOM) dy = un2iy(TxtSet.fSize*0.2);
+		else if((TxtSet.Align & TXA_VTOP) == TXA_VTOP) dy = un2iy(TxtSet.fSize*.6);
 		}
 	else if(TxtSet.Style & TXS_SUPER) {
-		if((TxtSet.Align & TXA_VCENTER) == TXA_VCENTER) iy -= un2iy(TxtSet.fSize*0.4);
-		else if((TxtSet.Align & TXA_VBOTTOM) == TXA_VBOTTOM) iy -= un2iy(TxtSet.fSize*0.6);
-		else if((TxtSet.Align & TXA_VTOP) == TXA_VTOP) iy -= un2iy(TxtSet.fSize*0.2);
+		if((TxtSet.Align & TXA_VCENTER) == TXA_VCENTER) dy = -un2iy(TxtSet.fSize*0.4);
+		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\" ", ix, iy);
+	sprintf(output, "<text x=\"%d\" y=\"%d\" dy=\"%d\" ", ix, iy, dy);
 	if(fabs(TxtSet.RotBL) >.01 || fabs(TxtSet.RotCHAR) >.01) {
 		sprintf(tmptxt,"transform=\"rotate(%.0f,%d,%d)\" ", -TxtSet.RotBL, ix, iy);
 		strcat(output, tmptxt);
@@ -840,14 +843,31 @@ ExportSVG::oTextOut(int x, int y, char *txt, int cb)
 	sprintf(tmptxt, "font-size:%d; text-anchor:%s \">", h, 
 		(TxtSet.Align & TXA_HRIGHT) ? "end" : (TxtSet.Align & TXA_HCENTER) ? "middle":"start");
 	AddToOutput(tmptxt);
-	nt = str2xml(txt);
-	if((TxtSet.Style & TXS_SUB) || (TxtSet.Style & TXS_SUPER)) {
-		for(i = strlen(nt)+6, nt[i+1]=0; i > 5; i--) {
-			nt[i] = nt[i-6];
+	if(TxtSet.Font == FONT_GREEK) {
+		for(i = j = 0; txt[i] && j < 4090; i++) {
+			switch(txt[i]) {
+			case '"':
+				j += sprintf(TmpTxt+j, """);
+				break;
+			case '&':
+				j += sprintf(TmpTxt+j, "&");
+				break;
+			case '<':
+				j += sprintf(TmpTxt+j, "<");
+				break;
+			case '>':
+				j += sprintf(TmpTxt+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];
+				break;
+				}
 			}
-		nt[0] = '&';		nt[1] = 'n';		nt[2] = 'b';
-		nt[3] = 's';		nt[4] = 'p';		nt[5] = ';';
+		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);
@@ -997,9 +1017,10 @@ private:
 	fRECT SolLines[2000];
 	int nSolLines;
 	GraphObj *go;
-	char *name;
+	char *name, FontName[30];
 	FILE *oFile;
 	DWORD CurrCol;
+	bool bFontChange;
 
 	float ix2eps(int x);
 	float iy2eps(int y);
@@ -1010,16 +1031,11 @@ private:
 
 ExportEPS::ExportEPS(GraphObj *g, char *FileName, DWORD flags)
 {
-	hgo =0L;
-	nSolLines = 0;
-	DeskRect.left = DeskRect.top = 0;
+	hgo =0L;		nSolLines = 0;			DeskRect.left = DeskRect.top = 0;
 	DeskRect.right = DeskRect.bottom = 0x4fffffff;
-	dFillCol = 0xffffffffL;
-	hres = vres = 720.0f;
-	go = g;
-	if(FileName)name = strdup(FileName);
-	else name = 0L;
-	oFile = 0L;
+	dFillCol = 0xffffffffL;					hres = vres = 720.0f;
+	go = g;			bFontChange = false;	oFile = 0L;
+	if(FileName)name = strdup(FileName);	else name = 0L;
 }
 
 ExportEPS::~ExportEPS()
@@ -1064,15 +1080,12 @@ ExportEPS::SetFill(FillDEF *fill)
 bool
 ExportEPS::SetTextSpec(TextDEF *set)
 {
-	char FontName[30];
-
-	if(!set->iSize && set->fSize > 0.0f) set->iSize = un2iy(set->fSize);
-	if(!set->iSize) return false;
-	if(set->iSize == TxtSet.iSize && set->Style == TxtSet.Style && 
-		set->Font == TxtSet.Font){
-		anyOutput::SetTextSpec(set);
-		return true;
+	if(set->fSize > 0.0) {
+		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;
@@ -1081,8 +1094,7 @@ ExportEPS::SetTextSpec(TextDEF *set)
 		}
 	if(TxtSet.Style & TXS_BOLD) strcat(FontName, "-Bold");
 	if(TxtSet.Style & TXS_ITALIC) strcat(FontName, "-Italic");
-	strcat(FontName, ")");
-	fprintf(oFile, "\n%s findfont %d scalefont setfont ", FontName, TxtSet.iSize/10);
+	strcat(FontName, ")");	bFontChange = true;
 	return true;
 }
 
@@ -1224,27 +1236,46 @@ bool
 ExportEPS::oTextOut(int x, int y, char *txt, int cb)
 {
 	int h, ix, iy, w;
-	float fx, fy;
+	float fx, fy, lw;
 
-	FlushSolLines();
+	FlushSolLines();	if(!txt || !txt[0]) return true;
 	oGetTextExtent(txt, cb, &w, &h);
+	if(bFontChange)	{
+		fprintf(oFile, "\n%s findfont %d scalefont setfont ", FontName, TxtSet.iSize/10);
+		bFontChange = false;
+		}
 	if(TxtSet.Align & TXA_VCENTER) iy = y + h/3;
 	else if(TxtSet.Align & TXA_VBOTTOM) iy = y;
 	else iy = y + iround(h*.8);
 	if(TxtSet.Align & TXA_HRIGHT) ix = x-w;
 	else if(TxtSet.Align & TXA_HCENTER) ix = x-w/2;
-	else ix = x;
+	else ix = x;			lw = (float)(iy-y)/150.0f;
 	fprintf(oFile,"\n");
 	if(fabs(TxtSet.RotBL) >.01 || fabs(TxtSet.RotCHAR) >.01) {
+		if(TxtSet.Style & TXS_SUB) iy += un2iy(TxtSet.fSize*0.6);
+		else if(TxtSet.Style & TXS_SUPER) iy -= un2iy(TxtSet.fSize*.2);
 		fprintf(oFile, "gsave %.1f %.1f translate %f rotate %.1f %.1f moveto\n",
 			ix2eps(x), iy2eps(y), TxtSet.RotBL, (float)(ix-x)/10.0f, (float)(iy-y)/-10.0f);
-		if(CurrCol != TxtSet.ColTxt) fprintf(oFile, "%s ", col2eps(CurrCol = TxtSet.ColTxt));
-		fprintf(oFile, "(%s) show grestore ", txt);
+		fprintf(oFile, "%s ", col2eps(CurrCol = TxtSet.ColTxt));
+		fprintf(oFile, "(%s) show ", txt);
+		if(TxtSet.Style & TXS_UNDERLINE) {
+			fprintf(oFile, "\ncurrentpoint %.1f exch pop moveto", (float)(iy-y)/-10.0f - lw*1.2);
+			fprintf(oFile, " 0 %.1f lineto %s %.1f setlinewidth stroke ", (float)(iy-y)/-10.0f -lw*1.2,
+				col2eps(TxtSet.ColTxt), lw);
+			}
+		fprintf(oFile, "grestore\n");
 		}
 	else {
+		if(TxtSet.Style & TXS_SUB) iy += un2iy(TxtSet.fSize*0.6);
+		else if(TxtSet.Style & TXS_SUPER) iy -= un2iy(TxtSet.fSize*.2);
 		fx = ix2eps(ix);			fy = iy2eps(iy);
-		if(CurrCol != TxtSet.ColTxt) fprintf(oFile, "%s ", col2eps(CurrCol = TxtSet.ColTxt));
+		fprintf(oFile, "%s ", col2eps(CurrCol = TxtSet.ColTxt));
 		fprintf(oFile,"%.1f %.1f moveto (%s) show ", fx, fy, txt);
+		if(TxtSet.Style & TXS_UNDERLINE) {
+			fprintf(oFile, "\ncurrentpoint %.1f exch pop moveto", fy - lw*1.2);
+			fprintf(oFile, " %.1f %.1f lineto %s %.1f setlinewidth stroke\n", fx, fy - lw*1.2, 
+				col2eps(TxtSet.ColTxt), lw);
+			}
 		}
 	return true;
 }
diff --git a/Fileio.cpp b/Fileio.cpp
index e022eb8..edfb6f6 100755
--- a/Fileio.cpp
+++ b/Fileio.cpp
@@ -1,4 +1,4 @@
-//FileIO.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
+//FileIO.cpp, Copyright (c) 2001-2006 R.Lackner
 //read/write graphic objects
 //
 //    This file is part of RLPlot.
@@ -211,7 +211,7 @@ int WriteEscString(char *txt, char *buff, int cb)
 
 	if(!txt || !txt[0]) return 0;
 	l = strlen(txt);
-	if((l+10) > esc_str_size) esc_str = (char*)realloc(esc_str, esc_str_size = (l+10));
+	if((l+10) > esc_str_size) esc_str = (char*)realloc(esc_str, esc_str_size = (l+100));
 	j = 0;	esc_str[j++] = '"';
 	for(i = 0; txt[i]; i++) {
 		switch(txt[i]) {
@@ -219,8 +219,8 @@ int WriteEscString(char *txt, char *buff, int cb)
 		case '\n':	j += sprintf(esc_str+j, "\\n");		break;
 		default:	esc_str[j++] = txt[i];
 			}
-		if(j > esc_str_size -2) esc_str = (char*)realloc(esc_str, (esc_str_size += 20));
-		if(j > lim) {
+		if(j > (esc_str_size -10)) esc_str = (char*)realloc(esc_str, (esc_str_size += 100));
+		if(j > lim && (l-i) > 5) {
 			j += sprintf(esc_str+j, "\"\n   \"");
 			lim += 60;
 			}
@@ -806,7 +806,7 @@ void UpdGOfromMem(GraphObj *go, unsigned char *buff)
 	delete Cache;		Cache = 0L;
 }
 
-bool OpenGraph(GraphObj *root, char *name, unsigned char *mem)
+bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste)
 {
 	unsigned char c, tmp[80];
 	char debug[80];
@@ -857,10 +857,10 @@ bool OpenGraph(GraphObj *root, char *name, unsigned char *mem)
 		hv = HashValue(tmp);
 		switch(hv) {
 		case 3895:		go = new Axis(FILE_READ);			break;
-		case 7496002:	go = new Bar(FILE_READ);			break;
+		case 886:		go = new Bar(FILE_READ);			break;
 		case 81384:		go = new Symbol(FILE_READ);			break;
 		case 62229:		go = new Bubble(FILE_READ);			break;
-		case 7892802:	go = new Box(FILE_READ);			break;
+		case 948:		go = new Box(FILE_READ);			break;
 		case 15411:		go = new Arrow(FILE_READ);			break;
 		case 1052406:	go = new ErrorBar(FILE_READ);		break;
 		case 324566:	go = new Whisker(FILE_READ);		break;
@@ -872,7 +872,8 @@ bool OpenGraph(GraphObj *root, char *name, unsigned char *mem)
 		case 61662266:	go = new DataPolygon(FILE_READ);	break;
 		case 435228:	go = new segment(FILE_READ);		break;
 		case 1741325:	go = new polyline(FILE_READ);		break;
-		case 435258:	go = new polygon(FILE_READ);		break;
+		case 435258:	go = new polygon(FILE_READ);		break;
+		case 92534:		go = new Bezier(FILE_READ);			break;
 		case 6888037:	go = new rectangle(FILE_READ);		break;
 		case 1780087:	go = new roundrec(FILE_READ);		break;
 		case 78813:		go = new Sphere(FILE_READ);			break;
@@ -930,12 +931,9 @@ bool OpenGraph(GraphObj *root, char *name, unsigned char *mem)
 	if((go = Notary->PopGO(lid))) {
 		go->Command(CMD_SET_DATAOBJ, 0L, 0L);
 		delete Notary;		Notary = 0L;
-		if(root->Id == GO_PAGE) {
-			if(go->Id == GO_PAGE){
-				if(!(root->parent->Command(CMD_DROP_GRAPH,(void *)go, 0L))) DeleteGO(go);
-				}
-			else if(!(root->Command(CMD_DROP_GRAPH, (void *)go, 0L))) DeleteGO(go);
-			}
+		if(bPaste && root->Command(CMD_PASTE_OBJ, (void *)go, 0L)) {
+			// object accepted
+			}
 		else if(!(root->Command(CMD_DROP_GRAPH, (void *)go, 0L))){
 			DeleteGO(go);	go = 0L;
 			}
@@ -1522,7 +1520,8 @@ ErrorBar::FileIO(int rw)
 		{"Pos", typLFPOINT, &fPos, 0L},
 		{"Err", typLFLOAT, &ferr, 0L},
 		{"Size", typLFLOAT, &SizeBar, 0L},
-		{"Line", typLAST | typLINEDEF, &ErrLine, 0L}};
+		{"Line", typLINEDEF, &ErrLine, 0L},
+		{"Desc", typLAST | typTEXT, &name, 0L}};
 
 	switch(rw) {
 	case SAVE_VARS:
@@ -1532,6 +1531,8 @@ ErrorBar::FileIO(int rw)
 		SizeBar = defs.GetSize(SIZE_ERRBAR);
 		ErrLine.width = defs.GetSize(SIZE_ERRBAR_LINE);
 		ErrLine.color = defs.Color(COL_SYM_LINE);
+		mo = 0L;
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
 		return true;
 	case FILE_READ:
 		return ExecInput(Desc);
@@ -1619,7 +1620,8 @@ Whisker::FileIO(int rw)
 		{"High", typLFPOINT, &pos1, 0L},
 		{"Low", typLFPOINT, &pos2, 0L},
 		{"Size", typLFLOAT, &size, 0L},
-		{"Line", typLAST | typLINEDEF, &LineDef, 0L}};
+		{"Line", typLINEDEF, &LineDef, 0L},
+		{"Desc", typLAST | typTEXT, &name, 0L}};
 
 	switch(rw) {
 	case SAVE_VARS:
@@ -1629,6 +1631,8 @@ Whisker::FileIO(int rw)
 		size = defs.GetSize(SIZE_WHISKER);
 		LineDef.width = defs.GetSize(SIZE_WHISKER_LINE);
 		LineDef.color = defs.Color(COL_WHISKER);
+		mo = 0L;
+		mrc.left = mrc.right = mrc.top = mrc.bottom = 0;
 		return true;
 	case FILE_READ:
 		return ExecInput(Desc);
@@ -1999,7 +2003,32 @@ polyline::FileIO(int rw)
 			type == 1 ? (char*)"polygon" : (char*)"polyline", Desc);
 		}
 	return false;
-}
+}
+
+bool
+Bezier::FileIO(int rw)
+{
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"moveable", typNZINT, &moveable, 0L},
+		{"Data", typFPLST, &Values, &nPoints},
+		{"Line", typLINEDEF, &pgLine, 0L},
+		{"FillLine", typLINEDEF, &pgFillLine, 0L},
+		{"Fill", typLAST | typFILLDEF, &pgFill, 0L}};
+	
+	switch(rw) {
+	case INIT_VARS:
+		//assume that all initialization is done by polyline::FileIO(int rw)
+		return true;
+	case FILE_READ:
+		ExecInput(Desc);
+		pgFill.hatch = &pgFillLine;
+		return true;
+	case FILE_WRITE:
+		return ExecOutput(Notary->RegisterGO(this), "bezier", Desc);
+		}
+	return false;
+}
 
 bool
 rectangle::FileIO(int rw)
@@ -2120,7 +2149,7 @@ Legend::FileIO(int rw)
 		D_Rect.Xmax = d*1.3;		D_Rect.Ymax = d*0.4;
 		F_Rect.Ymin = 0.0;			F_Rect.Xmin = d*0.2;
 		F_Rect.Xmax = d*1.3;		F_Rect.Ymax = d*0.4;
-		to = 0L;
+		to = 0L;					hasLine = false;
 		trc.left = trc.right = trc.top = trc.bottom = 0;
 		if(!name) name=strdup("Legend");
 		return true;
@@ -2528,6 +2557,7 @@ DensDisp::FileIO(int rw)
 {
 	descIO Desc[] = {
 		{"Type", typNZINT, &type, 0L},
+		{"hide", typNZINT, &hidden, 0L},
 		{"Bounds", typFRECT, &Bounds, 0L},
 		{"xRange", typTEXT, &xRange, 0L},
 		{"yRange", typTEXT, &yRange, 0L},
@@ -2570,6 +2600,7 @@ StackBar::FileIO(int rw)
 {
 	descIO Desc[] = {
 		{"Bounds", typFRECT, &Bounds, 0L},
+		{"hide", typNZINT, &hidden, 0L},
 		{"x_axis", typNZINT, &use_xaxis, 0L},
 		{"y_axis", typNZINT, &use_yaxis, 0L},
 		{"cumData", typNZINT, &cum_data_mode, 0L},
@@ -2622,6 +2653,7 @@ PieChart::FileIO(int rw)
 	descIO Desc[] = {
 		{"ssRefA", typTEXT, &ssRefA, 0L},
 		{"ssRefR", typTEXT, &ssRefR, 0L},
+		{"hide", typNZINT, &hidden, 0L},
 		{"CtDef", typLFPOINT, &CtDef, 0L},
 		{"FacRad", typLFLOAT, &FacRad, 0L},
 		{"Segs", typLAST | typOBJLST, &Segments, (long*)&nPts}};
@@ -2664,6 +2696,7 @@ GoGroup::FileIO(int rw)
 {
 	descIO Desc[] = {
 		{"Pos", typNZLFPOINT, &fPos, 0L},
+		{"hide", typNZINT, &hidden, 0L},
 		{"Items", typLAST | typOBJLST, &Objects, (long*)&nObs}};
 	int i;
 
@@ -2704,6 +2737,7 @@ Scatt3D::FileIO(int rw)
 		{"ssRefX", typTEXT, &ssRefX, 0L},
 		{"ssRefY", typTEXT, &ssRefY, 0L},
 		{"ssRefZ", typTEXT, &ssRefZ, 0L},
+		{"hide", typNZINT, &hidden, 0L},
 		{"Line", typGOBJ, &Line, 0L},
 		{"Balls", typOBJLST, &Balls, &nBalls},
 		{"Columns", typOBJLST, &Columns, &nColumns},
@@ -2763,6 +2797,7 @@ Ribbon::FileIO(int rw)
 {
 	descIO Desc[] = {
 		{"Type", typNZINT, &type, 0L},
+		{"hide", typNZINT, &hidden, 0L},
 		{"z-pos", typNZLFLOAT, &z_value},
 		{"z-width", typNZLFLOAT, &z_width},
 		{"relwidth", typNZLFLOAT, &relwidth},
@@ -2884,6 +2919,7 @@ bool
 Function::FileIO(int rw)
 {
 	descIO Desc[] = {
+		{"hide", typNZINT, &hidden, 0L},
 		{"x1", typNZLFLOAT, &x1, 0L},
 		{"x2", typNZLFLOAT, &x2, 0L},
 		{"xstep", typNZLFLOAT, &xstep, 0L},
@@ -2930,6 +2966,7 @@ bool
 FitFunc::FileIO(int rw)
 {
 	descIO Desc[] = {
+		{"hide", typNZINT, &hidden, 0L},
 		{"ssXref", typTEXT, &ssXref, 0L},
 		{"ssYref", typTEXT, &ssYref, 0L},
 		{"x1", typNZLFLOAT, &x1, 0L},
@@ -2940,7 +2977,7 @@ FitFunc::FileIO(int rw)
 		{"maxiter", typNZINT, &maxiter, 0L},
 		{"Line", typLINEDEF, &Line, 0L},
 		{"f_xy", typTEXT, &cmdxy, 0L},
-		{"p_xy", typTEXT, &parxy, 0L},
+		{"p_xy", typTEXT, &parxy, 0L},
 		{"Symbols", typLAST | typOBJLST, &Symbols, &nPoints}};
 	int i;
 
@@ -3199,7 +3236,6 @@ bool
 Plot3D::FileIO(int rw)
 {
 	fPOINT3D rot_vec, rot_ang;
-	//DEBUG: must initialize rot_vec, rot_ang in case they are not present in file
 	descIO Desc[] = {
 		{"xBounds", typLFPOINT, &xBounds, 0L},
 		{"yBounds", typLFPOINT, &yBounds, 0L},
@@ -3238,7 +3274,9 @@ Plot3D::FileIO(int rw)
 			free(name);		name=strdup(TmpTxt);
 			}
 		return true;
-	case FILE_READ:
+	case FILE_READ:
+		rot_vec.fx = 0.919384;	rot_vec.fy = 0.389104;	rot_vec.fz = -0.057709;
+		rot_ang.fx = 0.327146;	rot_ang.fy = 0.944974;	rot_ang.fz = 0.055026;
 		ExecInput(Desc);
 		RotDef[0] = rot_vec.fx;	RotDef[1] = rot_vec.fy;	RotDef[2] = rot_vec.fz;
 		RotDef[3] = rot_ang.fx;	RotDef[4] = rot_ang.fy;	RotDef[5] = rot_ang.fz;
@@ -3264,7 +3302,6 @@ bool
 Func3D::FileIO(int rw)
 {
 	fPOINT3D rot_vec, rot_ang;
-	//DEBUG: must initialize rot_vec, rot_ang in case they are not present in file
 	descIO Desc[] = {
 		{"Type", typNZINT, &type, 0L},
 		{"xBounds", typLFPOINT, &xBounds, 0L},
@@ -3283,7 +3320,6 @@ Func3D::FileIO(int rw)
 		{"z1", typNZLFLOAT, &x1, 0L},
 		{"z2", typNZLFLOAT, &x2, 0L},
 		{"zstep", typNZLFLOAT, &xstep, 0L},
-		{"g_idx", typNZINT, &g_idx, 0L},
 		{"Line", typLINEDEF, &Line, 0L},
 		{"Fill", typFILLDEF, &Fill, 0L},
 		{"f_xz", typTEXT, &cmdxy, 0L},
@@ -3297,7 +3333,7 @@ Func3D::FileIO(int rw)
 		x1 = -20.0;		x2 = 20.0;	xstep = 2.0;
 		z1 = -20.0;		z2 = 20.0;	zstep = 2.0;
 		gda = 0L;		gob = 0L;
-		g_idx = 0;		param = cmdxy = 0L;
+		param = cmdxy = 0L;
 		Line.width = defs.GetSize(SIZE_HAIRLINE);
 		Line.patlength = defs.GetSize(SIZE_PATLENGTH);
 		Line.color = Line.pattern = 0x0L;
@@ -3311,6 +3347,8 @@ Func3D::FileIO(int rw)
 			}
 		return true;
 	case FILE_READ:
+		rot_vec.fx = 0.919384;	rot_vec.fy = 0.389104;	rot_vec.fz = -0.057709;
+		rot_ang.fx = 0.327146;	rot_ang.fy = 0.944974;	rot_ang.fz = 0.055026;
 		ExecInput(Desc);
 		RotDef[0] = rot_vec.fx;	RotDef[1] = rot_vec.fy;	RotDef[2] = rot_vec.fz;
 		RotDef[3] = rot_ang.fx;	RotDef[4] = rot_ang.fy;	RotDef[5] = rot_ang.fz;
@@ -3326,6 +3364,83 @@ Func3D::FileIO(int rw)
 		}
 	return false;
 }
+
+void
+FitFunc3D::RegGO(void *n)
+{
+}
+
+bool
+FitFunc3D::FileIO(int rw)
+{
+	fPOINT3D rot_vec, rot_ang;
+	descIO Desc[] = {
+		{"Type", typNZINT, &type, 0L},
+		{"ssXref", typTEXT, &ssXref, 0L},
+		{"ssYref", typTEXT, &ssYref, 0L},
+		{"ssZref", typTEXT, &ssZref, 0L},
+		{"xBounds", typLFPOINT, &xBounds, 0L},
+		{"yBounds", typLFPOINT, &yBounds, 0L},
+		{"zBounds", typLFPOINT, &zBounds, 0L},
+		{"Corner1", typPOINT3D, &cub1, 0L},
+		{"Corner2", typPOINT3D, &cub2, 0L},
+		{"Center", typPOINT3D, &rotC, 0L},
+		{"rot_vec", typPOINT3D, &rot_vec, 0L},
+		{"rot_ang", typPOINT3D, &rot_ang, 0L},
+		{"Axes", typOBJLST, &Axes, (long*)&nAxes},
+		{"Plots", typOBJLST, &plots, (long*)&nPlots},
+		{"x1", typNZLFLOAT, &x1, 0L},
+		{"x2", typNZLFLOAT, &x2, 0L},
+		{"xstep", typNZLFLOAT, &xstep, 0L},
+		{"z1", typNZLFLOAT, &x1, 0L},
+		{"z2", typNZLFLOAT, &x2, 0L},
+		{"zstep", typNZLFLOAT, &xstep, 0L},
+		{"maxiter", typNZINT, &maxiter, 0L},
+		{"Line", typLINEDEF, &Line, 0L},
+		{"Fill", typFILLDEF, &Fill, 0L},
+		{"f_xz", typTEXT, &cmdxy, 0L},
+		{"param", typLAST | typTEXT, &param, 0L}};
+	int i;
+
+	switch(rw) {
+	case SAVE_VARS:
+		return SaveVarGO(Desc);
+	case INIT_VARS:
+		x1 = -20.0;		x2 = 20.0;	xstep = 2.0;
+		z1 = -20.0;		z2 = 20.0;	zstep = 2.0;
+		gda = 0L;		gob = 0L;
+		conv = 1.0e-15;	maxiter = 100;
+		param = cmdxy = ssXref = ssYref = ssZref = 0L;
+		Line.width = defs.GetSize(SIZE_HAIRLINE);
+		Line.patlength = defs.GetSize(SIZE_PATLENGTH);
+		Line.color = Line.pattern = 0x0L;
+		Fill.color = 0x00c0c0c0;
+		Fill.color2 = 0x00ffffff;
+		Fill.hatch = 0L;
+		Fill.type = FILL_LIGHT3D;
+		if(name) {
+			sprintf(TmpTxt, "FitFunc3D (Plot %d)", cPlots);
+			free(name);		name=strdup(TmpTxt);
+			}
+		return true;
+	case FILE_READ:
+		rot_vec.fx = 0.919384;	rot_vec.fy = 0.389104;	rot_vec.fz = -0.057709;
+		rot_ang.fx = 0.327146;	rot_ang.fy = 0.944974;	rot_ang.fz = 0.055026;
+		ExecInput(Desc);
+		RotDef[0] = rot_vec.fx;	RotDef[1] = rot_vec.fy;	RotDef[2] = rot_vec.fz;
+		RotDef[3] = rot_ang.fx;	RotDef[4] = rot_ang.fy;	RotDef[5] = rot_ang.fz;
+		return true;
+	case FILE_WRITE:
+		rot_vec.fx = RotDef[0];	rot_vec.fy = RotDef[1];	rot_vec.fz = RotDef[2];
+		rot_ang.fx = RotDef[3];	rot_ang.fy = RotDef[4];	rot_ang.fz = RotDef[5];
+		//do all plots
+		for(i = 0; plots && i< nPlots; i++) if(plots[i]) plots[i]->FileIO(rw);
+		//do all axes
+		if(Axes) for(i = 0; i< nAxes; i++) if(Axes[i]) Axes[i]->FileIO(rw);
+		ExecOutput(Notary->RegisterGO(this), "FitFunc3D", Desc);
+		}
+	return false;
+}
 
 void
 Graph::RegGO(void *n)
@@ -3365,10 +3480,8 @@ Graph::FileIO(int rw)
 	ixax = iyax = -1;
 	switch(rw) {
 	case INIT_VARS:
-		InitVarsGO(Desc);
-		units = defs.cUnits = defs.dUnits;
-		OwnDisp = false;
-		dirty = true;
+		InitVarsGO(Desc);			units = defs.cUnits = defs.dUnits;
+		OwnDisp = false;			dirty = true;
 		GRect.Ymin = defs.GetSize(SIZE_GRECT_TOP);		GRect.Ymax = defs.GetSize(SIZE_GRECT_BOTTOM);
 		GRect.Xmin = defs.GetSize(SIZE_GRECT_LEFT);		GRect.Xmax = defs.GetSize(SIZE_GRECT_RIGHT);
 		DRect.Ymin = defs.GetSize(SIZE_DRECT_TOP);		DRect.Ymax = defs.GetSize(SIZE_DRECT_BOTTOM);
@@ -3376,16 +3489,14 @@ Graph::FileIO(int rw)
 		ColGR = defs.Color(COL_GRECT);					ColGRL = defs.Color(COL_GRECTLINE);
 		ColDR = defs.Color(COL_DRECT);					ColBG = defs.Color(COL_BG);
 		ColAX = defs.Color(COL_AXIS);
-		x_axis.max = y_axis.max = 1.0;
-		x_axis.owner = y_axis.owner = (void *)this;
+		x_axis.max = y_axis.max = 1.0;					x_axis.owner = y_axis.owner = (void *)this;
 		rcDim.left = rcDim.right = rcDim.top = rcDim.bottom = 0;
 		rcUpd.left = rcUpd.right = rcUpd.top = rcUpd.bottom = 0;
 		CurrGO = 0L;		Disp = 0L;			Sc_Plots = 0L;
 		AxisTempl = 0;		nscp = 0;			CurrDisp = 0L;
-		ToolMode = TM_STANDARD;
-		zoom_def = 0L;			tl_pts = 0L;			tl_nPts = 0;
-		tickstyle = zoom_level = 0;
-		frm_g = frm_d = 0L;		filename = 0L;
+		ToolMode = TM_STANDARD;					zoom_def = 0L;
+		tl_pts = 0L;		tl_nPts = 0;		tickstyle = zoom_level = 0;
+		frm_g = frm_d = 0L;	PasteObj = 0L;		filename = 0L;
 		rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = -1;
 		return true;
 	case FILE_READ:
@@ -3469,7 +3580,10 @@ DefsRW::FileIO(int rw)
 		{"dUnits", typINT, &defs.dUnits, 0L},
 		{"cUnits", typINT, &defs.dUnits, 0L},
 		{"dtHeight", typINT, &dlgtxtheight, 0L},
-		{"ss_txt", typLFLOAT, &defs.ss_txt, 0L},
+		{"ss_txt", typLFLOAT, &defs.ss_txt, 0L},
+		{"fmt_date", typTEXT, &defs.fmt_date, 0L},
+		{"fmt_datetime", typTEXT, &defs.fmt_datetime, 0L},
+		{"fmt_time", typTEXT, &defs.fmt_time, 0L},
 		{"File1", typTEXT, &defs.File1, 0L},
 		{"File2", typTEXT, &defs.File2, 0L},
 		{"File3", typTEXT, &defs.File3, 0L},
diff --git a/ODbuttons.cpp b/ODbuttons.cpp
index 7a22b70..e328796 100755
--- a/ODbuttons.cpp
+++ b/ODbuttons.cpp
@@ -1,4 +1,4 @@
-//ODbuttons.cpp, Copyright (c) 2001, 2002, 2003, 2004 R.Lackner
+//ODbuttons.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
 //Property dialogs for graphic objects
 //
 //    This file is part of RLPlot.
@@ -27,6 +27,7 @@
 
 extern int ODtickstyle;
 extern int AxisTempl3D;
+extern Default defs;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Common code to modify drawing order in any dialog
@@ -650,7 +651,7 @@ void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 		iy = (rec->top +rec->bottom)>>1;
 		switch(id) {
 		case 560:	case 561:	case 562:	case 563:	case 564:		//3D axes
-		case 565:
+		case 565:	case 566:
 			OD_AxisTempl3D(cmd, par, rec, o, data, 410+AxisTempl3D);
 			break;
 		default:
@@ -859,7 +860,7 @@ void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 			memcpy(&otd, &o->TxtSet, sizeof(TextDEF));
 			td.Align = TXA_HLEFT | TXA_VCENTER;
 			td.Style = TXS_BOLD;	td.Mode = TXM_TRANSPARENT;
-			td.fSize = 7.0;			td.iSize = 0;
+			td.fSize = defs.GetSize(SIZE_TEXT)*1.75;			td.iSize = 0;
 			td.ColTxt = cmd == OD_DRAWSELECTED ? 0x0000f0f0L : 0x00c00000;
 			o->SetTextSpec(&td);
 			o->oTextOut(ix-2, iy+3, "?", 0);
@@ -1081,7 +1082,7 @@ void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 			pts[4].x = pts[0].x;		pts[4].y = pts[0].y;
 			o->oPolygon(pts, 5, 0L);
 			break;
-		case 565:
+		case 565:	case 566:
 			o->SetLine(&rLine);
 			pts[0].x = ix-16;			pts[0].y = iy-2;
 			pts[1].x = ix+4;			pts[1].y = iy+6;
@@ -1100,11 +1101,20 @@ void OD_PlotTempl(int cmd, void *par, RECT *rec, anyOutput *o,
 			memcpy(&td, &o->TxtSet, sizeof(TextDEF));
 			memcpy(&otd, &o->TxtSet, sizeof(TextDEF));
 			td.Align = TXA_HCENTER | TXA_VTOP;
-			td.Style = TXS_NORMAL;
 			td.Mode = TXM_TRANSPARENT;
-			td.ColTxt = 0x00c00000L;
-			o->SetTextSpec(&td);
-			o->oTextOut(ix, iy+4, "f(x,z)", 0);
+			if(id == 565) {
+				td.Style = TXS_NORMAL;
+				td.ColTxt = 0x00c00000L;
+				o->SetTextSpec(&td);
+				o->oTextOut(ix, iy+4, "f(x,z)", 0);
+				}
+			else {
+				td.Style = TXS_BOLD;
+				td.fSize = defs.GetSize(SIZE_TEXT)*1.75;			td.iSize = 0;
+				td.ColTxt = cmd == OD_DRAWSELECTED ? 0x0000cb00L : 0x00cb00c0L;
+				o->SetTextSpec(&td);
+				o->oTextOut(ix-10, iy-6, "?", 0);
+				}
 			o->SetTextSpec(&otd);
 			break;
 			}
diff --git a/Output.cpp b/Output.cpp
index 54d6576..6ee7048 100755
--- a/Output.cpp
+++ b/Output.cpp
@@ -1,4 +1,4 @@
-//Output.cpp, Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 R.Lackner
+//Output.cpp, Copyright (c) 2000-2006 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -407,6 +407,7 @@ anyOutput::HideMark()
 					}
 				else CurrGraph->Command(CMD_REDRAW, 0L, this);
 				}
+			else ((GraphObj*)MrkRect)->DoMark(this, false);
 			return true;
 		case MRK_SSB_DRAW:
 			MrkMode = MRK_NONE;
@@ -639,7 +640,7 @@ anyOutput::oGetTextExtent(char *text, int cb, int *width, int *height)
 		}
 	if(!cb && text) cb = strlen(text);
 	for(i = w = 0; i < cb; i++) w += CharWidth[text[i]];
-	*width = (w * TxtSet.iSize)>>6;
+	*width = iround(((double)w * (double)TxtSet.iSize)/52.0);
 	*height = TxtSet.iSize;
 	return true;
 }
@@ -825,7 +826,7 @@ HatchOut::oSphere(int cx, int cy, int r, POINT *pts, int cp, char *nam)
 	v[0] = 0.0;		v[1] = 1.0;		v[2] = 0.0;
 	for (i = 0; i < 3; i++) for(j = 0, vec[i] = 0.0; j < 3; j++)
 		vec[i] += (light_vec[i][j] * v[j]);
-	circ_grad.cx = cx - iround(vec[0]*((double)r));
+	circ_grad.cx = cx + iround(vec[0]*((double)r));
 	circ_grad.cy = cy - iround(vec[2]*((double)r));
 	circ_grad.r = r;
 	if(pts && cp) return oPolygon(pts, cp, nam);
@@ -924,12 +925,14 @@ HatchOut::DoHatch()
 	case FILL_WAVES1:		Arcs(FILL_WAVES1);				break;
 	case FILL_SCALES:		Arcs(FILL_SCALES);				break;
 	case FILL_SHINGLES:		Arcs(FILL_SHINGLES);			break;
-	case FILL_WAVES2:		Waves2();						break;
+	case FILL_WAVES2:		Waves2(0);						break;
 	case FILL_HERRING:		Herringbone();					break;
 	case FILL_CIRCLES:		Circles();						break;
 	case FILL_GRASS:		Grass();						break;
 	case FILL_FOAM:			Foam();							break;
 	case FILL_RECS:			Recs();							break;
+	case FILL_HASH:			Hash();							break;
+	case FILL_WATER:		Waves2(1);						break;
 	case FILL_LIGHT3D:		CircGrad();						break;
 		}
 
@@ -1504,7 +1507,7 @@ HatchOut::Arcs(int type)
 		iy = iround(ybase*.8);			ix = iround(xbase*.8);
 		}
 	if(iy < 2) iy = 2;				if(ix < 2) ix = 2;
-	UseRect.right += ix;		UseRect.top -= 2*iy;	UseRect.bottom += 2*iy;
+	UseRect.right += ix;		UseRect.top -= (iy<<1);	UseRect.bottom += (iy<<1);
 	for(i = UseRect.top, level = 0; i < UseRect.bottom; i+= iy, level++) {
 		if(type == FILL_WAVES1) {
 			HatchArc(UseRect.left, i, ix, 0, true);
@@ -1528,26 +1531,45 @@ HatchOut::Arcs(int type)
 }
 
 void
-HatchOut::Waves2()					//hatch using sine waves
+HatchOut::Waves2(int type)					//hatch using sine waves
 {
-	int i, j, y, ix, yinc, *pts;
+	int i, j, level, y, ix, yinc, *pts;
 	POINT Line[2];
 	double dtmp;
 
-	if(3>(yinc = iround(ybase*.8)))yinc = 3;	if(14>(ix = iround(xbase*2.5)))ix = 14;
+	if(3>(yinc = iround(type?ybase*.8 : ybase*1.2)))yinc = 3;	
+	if(type == 0 && 14>(ix = iround(xbase*2.5)))ix = 14;
+	else if(type == 1 && 7>(ix = iround(xbase*1.2)))ix = 7;
 	if(!(pts = (int *)malloc(ix * sizeof(int))))return;
 	for(i = 0; i < ix; i++) {
 		dtmp = sin(6.283185307/((double)ix/(double)i));
+		if(type == 1) dtmp /= 2.0;
 		pts[i] = dtmp > 0.0 ? iround(0.3*ybase*dtmp) : iround(0.3*ybase*dtmp);
 		}
-	for(y = UseRect.top; y <= UseRect.bottom + yinc; y += yinc){
-		Line[0].x = UseRect.left;		Line[1].x = UseRect.left+1;
-		Line[0].y = y;					Line[1].y = y+pts[1];
-		for(j = 2; Line[0].x < UseRect.right+1; j++) {
+	UseRect.bottom += yinc;					UseRect.right++;
+	for(y = UseRect.top, level = 0; y <= UseRect.bottom; y += yinc, level++){
+		Line[0].x = UseRect.left;			Line[1].x = UseRect.left+1;
+		Line[0].y = y;						Line[1].y = y+pts[1];
+		if(type == 0) for(j = 2; Line[0].x < UseRect.right; j++) {
 			HatchLine(Line[0], Line[1]);
 			Line[0].x = Line[1].x;			Line[1].x++;
 			Line[0].y = Line[1].y;			Line[1].y = y + pts[j%ix];
 			}
+		else if(type == 1) {
+			if(level & 1) {
+				Line[0].x += (ix + (ix>>1));		Line[1].x = Line[0].x +1;
+				}
+			for(j = 2; Line[0].x < UseRect.right; j++){
+				HatchLine(Line[0], Line[1]);
+				Line[0].x = Line[1].x;
+				Line[0].y = Line[1].y;				Line[1].y = y + pts[j%ix];
+				if((j-1) % ix) Line[1].x++;
+				else {
+					HatchLine(Line[0], Line[1]);
+					Line[1].x += (ix << 1);			Line[0].x = Line[1].x -1;
+					}
+				}
+			}
 		}
 	free(pts);
 }
@@ -1660,13 +1682,49 @@ HatchOut::Recs()
 }
 
 void
+HatchOut::Hash()
+{
+	int i, dh, dw, cx, cy, xinc, yinc;
+	double xsize, ysize, mix, miy;
+	long idum = -1;
+	POINT Line[5];
+
+	xsize = xbase * 0.9;						ysize = ybase * 0.9;
+	xinc = iround(xsize * 3.3);					yinc = iround(ysize * 2.2);
+	mix = xbase *.5;							miy = ybase *.5;
+	dw = iround(xbase > 5 ? xbase/2.0 : 2.0);	dh = iround(ybase > 5 ? xbase/2.0 : 2.0);
+	if(xsize < 2.0) xsize = 2.0;		if(ysize < 2.0) ysize = 2.0;
+	IncrementMinMaxRect(&UseRect, (int)xsize);
+	for(i = 0, cy = UseRect.top; cy < UseRect.bottom; i++, cy += yinc) {
+		for(cx = (i & 1) ? UseRect.left:UseRect.left+xinc/2; cx < UseRect.right; cx += xinc) { 
+			Line[0].x = Line[1].x = cx;
+			Line[0].y = cy - iround(ran2(&idum) * ysize + miy);
+			Line[1].y = cy + iround(ran2(&idum) * ysize + miy);
+			HatchLine(Line[0], Line[1]);
+			Line[0].x = Line[1].x = cx + dw;
+			Line[0].y = cy - iround(ran2(&idum) * ysize + miy);
+			Line[1].y = cy + iround(ran2(&idum) * ysize + miy);
+			HatchLine(Line[0], Line[1]);
+			Line[0].y = Line[1].y = cy;
+			Line[0].x = cx - iround(ran2(&idum) * xsize + mix);
+			Line[1].x = cx + iround(ran2(&idum) * xsize + mix);
+			HatchLine(Line[0], Line[1]);
+			Line[0].y = Line[1].y = cy + dh;
+			Line[0].x = cx - iround(ran2(&idum) * xsize + mix);
+			Line[1].x = cx + iround(ran2(&idum) * xsize + mix);
+			HatchLine(Line[0], Line[1]);
+			}
+		}
+}
+
+void
 HatchOut::CircGrad()
 {
 	int i;
 	double f;
 	LineDEF ld = {0.0, 1.0, 0x0, 0x0};
 
-	for(i = 1; i < this->circ_grad.r; i++) {
+	for(i = 1; i < circ_grad.r; i++) {
 		f = (((double)i)/((double)circ_grad.r));
 		f = f*f;
 		ld.color = IpolCol(dFillCol, dFillCol2, f);
diff --git a/PlotObs.cpp b/PlotObs.cpp
index 2af0276..9a8324b 100755
--- a/PlotObs.cpp
+++ b/PlotObs.cpp
@@ -1,4 +1,4 @@
-//PlotObs.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
+//PlotObs.cpp, Copyright (c) 2001-2006 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -422,6 +422,8 @@ PlotScatt::Command(int cmd, void *tmpl, anyOutput *o)
 			if(TheLine && TheLine->Id == GO_DATAPOLYGON) TheLine->Command(cmd, tmpl, o);
 			}
 		else if(TheLine) TheLine->Command(cmd, tmpl, o);
+		if(Errors) for (i = 0; i < nPoints; i++)
+			if(Errors[i]) Errors[i]->Command(cmd, tmpl, o);
 		break;
 	case CMD_MRK_DIRTY:
 		dirty = true;
@@ -488,7 +490,7 @@ PlotScatt::Command(int cmd, void *tmpl, anyOutput *o)
 		if(DropLines) for(i = 0; i < nPoints; i++)
 			if(DropLines[i]) DropLines[i]->Command(cmd, tmpl, o);
 		return true;
-	case CMD_ERR_TYPE:		case CMD_WHISKER_STYLE:
+	case CMD_ERR_TYPE:		case CMD_WHISKER_STYLE:		case CMD_ERRDESC:
 		if(Errors) for(i = 0; i < nPoints; i++) {
 			if(Errors[i]) Errors[i]->Command(cmd, tmpl, o);
 			}
@@ -803,12 +805,7 @@ xyStat::CreateData()
 			switch(type & 0x1f00) {
 			case 0x0100:	case 0x0200:	case 0x1000:	//SD, SEM, conf. int.
 				if(ny[i] > 1) {
-					y = d_amean(ny[i], ay[i]);
-					for(k = 0, ss = 0.0; k < (ny[i]); k++) {
-						ss += ((d=ay[i][k]-y)*d);
-						ny[i] = ny[i];
-						}
-					ss = ss/(double)(ny[i]-1);
+					ss = d_variance(ny[i], ay[i], &y);
 					switch(type & 0x1f00) {
 					case 0x0100:
 						curr_data->SetValue(i, 2, sqrt(ss));
@@ -1082,7 +1079,7 @@ FreqDist::ProcData(int sel)
 			cb += sprintf(fo+cb,"f_xy=\"A=%g; SD=%g; M=%g\\n", nv*step, sd, mean);
 			cb += sprintf(fo+cb,"ex=(x-M)/SD; ex=-0.5*ex*ex\\n");
 			cb += sprintf(fo+cb,"y=(A/(SD*2.5066283))*exp(ex)\\n\"\n");
-			OpenGraph(this, 0L, (unsigned char *)fo);
+			OpenGraph(this, 0L, (unsigned char *)fo, false);
 			free(fo);
 			}
 		}
@@ -1662,12 +1659,10 @@ PolarPlot::Command(int cmd, void *tmpl, anyOutput *o)
 			return ReplaceGO(&Axes[i], tmpPlots);
 			}
 		break;
-	case CMD_SETSCROLL:
-	case CMD_REDRAW:
+	case CMD_SETSCROLL:		case CMD_REDRAW:
 		if(parent) return parent->Command(cmd, tmpl, o);
 		return false;
-	case CMD_DELOBJ_CONT:
-	case CMD_DELOBJ:
+	case CMD_DELOBJ_CONT:	case CMD_DELOBJ:
 		if(Plots && nPlots) for(i = 0; i < nPlots; i++) if(tmpl == (void*)Plots[i]) {
 			Undo.DeleteGO((GraphObj**)(&Plots[i]), cmd == CMD_DELOBJ_CONT ? UNDO_CONTINUE : 0L, o);
 			if(parent)parent->Command(CMD_REDRAW, NULL, o);
@@ -1735,12 +1730,10 @@ BoxPlot::BoxPlot(GraphObj *par, DataObj *dt, int mode, int c1, int c2, int c3):P
 		Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
 		Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
 		if(Boxes = (Box**)calloc(nr, sizeof(Box*))) for(i = 0; i < nr; i++) {
-			if(mode == 1) Boxes[i] = new Box(this, data, fp, fp, 0, c1, i, c2, i, c1, i, c3, i);
-			else Boxes[i] = new Box(this, data, fp, fp, 0, c2, i, c1, i, c3, i, c1, i);
-			if(Boxes[i]) Boxes[i]->Command(CMD_AUTOSCALE, 0L, 0L);
+			if(mode == 1) Boxes[i] = new Box(this, data, fp, fp, BAR_RELWIDTH, c1, i, c2, i, c1, i, c3, i);
+			else Boxes[i] = new Box(this, data, fp, fp, BAR_RELWIDTH, c2, i, c1, i, c3, i, c1, i);
 			}
 		}
-	BoxDist.fx = BoxDist.fy = GetSize(mode == 2  ? SIZE_BOXMINY : SIZE_BOXMINX);
 }
 
 BoxPlot::~BoxPlot()
@@ -1882,7 +1875,6 @@ BoxPlot::Command(int cmd, void *tmpl, anyOutput *o)
 		return false;
 	case CMD_LEGEND:
 		if(((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
-		if(Boxes) for (i = 0; i < nPoints; i++)	if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
 		if(Symbols) {
 			if(TheLine && TheLine->Id == GO_DATALINE) {
 				for (i = 0; i < nPoints && i < 100; i++)
@@ -1895,6 +1887,8 @@ BoxPlot::Command(int cmd, void *tmpl, anyOutput *o)
 			if(TheLine && TheLine->Id == GO_DATAPOLYGON) TheLine->Command(cmd, tmpl, o);
 			}
 		else if(TheLine) TheLine->Command(cmd, tmpl, o);
+		if(Boxes) for (i = 0; i < nPoints; i++)	if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
+		if(Whiskers) for (i = 0; i < nPoints; i++)	if(Whiskers[i]) Whiskers[i]->Command(cmd, tmpl, o);
 		break;
 	case CMD_SET_DATAOBJ:
 		Id = GO_BOXPLOT;		data = (DataObj *)tmpl;		dirty = true;
@@ -1975,7 +1969,7 @@ BoxPlot::Command(int cmd, void *tmpl, anyOutput *o)
 		if(Boxes) for (i = 0; i < nPoints; i++)
 			if(Boxes[i]) Boxes[i]->Command(cmd, tmpl, o);
 		return true;
-	case CMD_WHISKER_STYLE:
+	case CMD_WHISKER_STYLE:		case CMD_ERRDESC:
 		if(Whiskers) for (i = 0; i < nPoints; i++)
 			if(Whiskers[i]) Whiskers[i]->Command(cmd, tmpl, o);
 		return true;
@@ -2129,12 +2123,7 @@ BoxPlot::CreateData()
 			|| (type & 0x0f0f) == 0x0201 || (type & 0x0f0f) == 0x0501) for(i = 0; i < j; i++) {
 			// set SD, SE, Conf. Intervall
 			if(ny[i] > 1) {
-				y = d_amean(ny[i], ay[i]);
-				for(k = 0, ss = 0.0; k < (ny[i]); k++) {
-					ss += ((d=ay[i][k]-y)*d);
-					ny[i] = ny[i];
-					}
-				ss = sqrt(ss/(double)(ny[i]-1));
+				ss = sqrt(d_variance(ny[i], ay[i], &y));
 				}
 			else {
 				y = *ay[i];		ss = 0.0;
@@ -2483,8 +2472,7 @@ StackBar::SetSize(int select, double value)
 		if(xyPlots) for(i = 0; i < numXY; i++)
 			if(xyPlots[i]) xyPlots[i]->SetSize(select, value);
 		return true;
-	case SIZE_BOX:
-	case SIZE_BOX_LINE:
+	case SIZE_BOX:		case SIZE_BOX_LINE:
 		if(Boxes) for(i = 0; i < numPlots; i++) 
 			if(Boxes[i]) Boxes[i]->SetSize(select, value);
 		return true;
@@ -3709,7 +3697,7 @@ Grid3D::DoPlot(anyOutput *o)
 {
 	int i;
 
-	if(!lines && !planes) CreateObs();
+	if(!lines && !planes) CreateObs(false);
 	if(lines) for(i = 0; i < nLines; i++) if(lines[i]) lines[i]->DoPlot(o);
 	if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->DoPlot(o);
 	dirty = false;
@@ -3752,6 +3740,8 @@ Grid3D::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_LEGEND:
 		if(!hidden) ((Legend*)tmpl)->HasFill(&Line, planes ? &Fill : 0L);
 		break;
+	case CMD_CONFIG:
+		return Configure();
 	case CMD_MRK_DIRTY:
 		dirty = true;
 	case CMD_SET_GO3D:		case CMD_SETSCROLL:		case CMD_REDRAW:
@@ -3766,7 +3756,7 @@ Grid3D::Command(int cmd, void *tmpl, anyOutput *o)
 		if(planes) for(i = 0; i < nPlanes; i++) if(planes[i]) planes[i]->Command(cmd, tmpl, o);
 		return dirty = true;
 	case CMD_AUTOSCALE:
-		if(!lines && !planes) CreateObs();
+		if(!lines && !planes) CreateObs(false);
 		if(dirty) {
 			Bounds.Xmin = Bounds.Ymin = HUGE_VAL;	Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
 			xBounds.fx = yBounds.fx = zBounds.fx = HUGE_VAL;
@@ -3800,7 +3790,7 @@ Grid3D::Command(int cmd, void *tmpl, anyOutput *o)
 }
 
 void
-Grid3D::CreateObs()
+Grid3D::CreateObs(bool set_undo)
 {
 	int i, ir, ic, idx, w, h;
 	fPOINT3D *vec;
@@ -3866,6 +3856,10 @@ Grid3D::CreateObs()
 		SetSize(SIZE_SYM_LINE, Line.width);		SetColor(COL_POLYLINE, Line.color);
 		free(vec);
 		}
+	if(set_undo) {
+		if(planes && nPlanes)Undo.StoreListGO(parent, (GraphObj***)&planes, &nPlanes, UNDO_CONTINUE);
+		if(lines && nLines)Undo.StoreListGO(parent, (GraphObj***)&lines, &nLines, UNDO_CONTINUE);
+		}
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -4044,21 +4038,10 @@ Function::Update(anyOutput *o, DWORD flags)
 // Calculate and display a user defined function
 FitFunc::FitFunc(GraphObj *par, DataObj *d):Plot(par, d)
 {
-	int width, height;
-
 	FileIO(INIT_VARS);
 	x1 = 0.0;			x2 = 100.0;			xstep = 0.5;	dl = 0L;
 	cmdxy = strdup("a+b*x^c");
 	parxy = strdup("a=1; b=1; c=0.1;");
-	data->GetSize(&width, &height);
-	if(!ssXref) {
-		sprintf(TmpTxt, "a1:a%d", height);
-		ssXref = strdup(TmpTxt);
-		}
-	if(!ssYref) {
-		sprintf(TmpTxt, "b1:b%d", height);
-		ssYref = strdup(TmpTxt);
-		}
 	Id = GO_FITFUNC;
 }
 
@@ -4126,7 +4109,18 @@ FitFunc::DoPlot(anyOutput *o)
 
 	if(!data || x1 >= x2) return;
 	dirty = false;
-	if(dl && o) dl->DoPlot(o);
+	if(!dl && (dl = new Function(this, data))) {
+		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->Update(o, UNDO_CONTINUE);
+		}
+	if(dl && o) {
+		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->DoPlot(o);
+		}
 	if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->DoPlot(o);
 }
 
@@ -4166,8 +4160,16 @@ FitFunc::Command(int cmd, void *tmpl, anyOutput *o)
 		return false;
 	case CMD_AUTOSCALE:
 		if(dirty) {
-			if(dl) dl->Command(cmd, tmpl, o);
-			memcpy(&Bounds, &dl->Bounds, sizeof(fRECT));
+			if(!dl && (dl = new Function(this, data))) {
+				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->Update(o, UNDO_CONTINUE);
+				}
+			if(dl) {
+				dl->Command(cmd, tmpl, o);
+				memcpy(&Bounds, &dl->Bounds, sizeof(fRECT));
+				}
 			if(Symbols) for(i = 0; i < nPoints; i++) if(Symbols[i])Symbols[i]->Command(cmd, tmpl, o);
 			dirty = false;
 			}
@@ -4177,6 +4179,7 @@ FitFunc::Command(int cmd, void *tmpl, anyOutput *o)
 			SavVarObs((GraphObj**)Symbols, nPoints, UNDO_CONTINUE);
 			for(i = 0; i < nPoints; i++) if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
 			}
+		Undo.String(this, &parxy, UNDO_CONTINUE);
 		do_fitfunc(data, ssXref, ssYref, 0L, &parxy, cmdxy, conv, maxiter, &chi2);
 		if(!dl) dl = new Function(this, data);
 		if(dl){
@@ -4189,9 +4192,11 @@ FitFunc::Command(int cmd, void *tmpl, anyOutput *o)
 		if(parent) parent->Command(CMD_MRK_DIRTY, 0L, o);
 		return true;
 	case CMD_DELOBJ:
-		if(parent && tmpl && tmpl == dl) return parent->Command(CMD_DELOBJ, this, o);
+		if(!parent) return false;
+		if(tmpl && tmpl == dl) return parent->Command(CMD_DELOBJ, this, o);
+		else if(DeleteGOL((GraphObj***)&Symbols,nPoints,(GraphObj*)tmpl,o)) return parent->Command(CMD_REDRAW,0L,o);
 		else if(dl) return dl->Command(cmd, tmpl, o);
-		break;
+		return false;
 	case CMD_MRK_DIRTY:
 		dirty = true;
 		if(dl){
@@ -5040,6 +5045,7 @@ Func3D::Command(int cmd, void *tmpl, anyOutput *o)
 		return true;
 	case CMD_UPDATE:
 		return Update();
+		break;
 		}
 	return Plot3D::Command(cmd, tmpl, o);
 }
@@ -5073,3 +5079,83 @@ Func3D::Update()
 		}
 	return false;
 }
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// fit 3D function to data
+FitFunc3D::FitFunc3D(GraphObj *par, DataObj *d)
+	:Plot3D(par, d, 0x0L)
+{
+	FileIO(INIT_VARS);
+	cmdxy = strdup("a+b*x^c");
+	param = strdup("a=1; b=1; c=0.1;");
+	Id = GO_FITFUNC3D;
+}
+
+FitFunc3D::FitFunc3D(int src):Plot3D(0)
+{
+	int i;
+
+	FileIO(INIT_VARS);
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		//now set parent in all children
+		if(Axes) for(i = 0; i < nAxes; i++)
+			if(Axes[i]) Axes[i]->parent = this;
+		if(plots) for(i = 0; i < nPlots; i++)
+			if(plots[i]) plots[i]->parent = this;
+		}
+}
+
+FitFunc3D::~FitFunc3D()
+{
+	if(param) free(param);		param = 0L;
+	if(cmdxy) free(cmdxy);		cmdxy = 0L;
+	if(gda) delete(gda);		gda = 0L;
+	if(name) free(name);		name=0L;
+}
+
+bool
+FitFunc3D::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	switch(cmd) {
+	case CMD_SET_DATAOBJ:
+		Plot3D::Command(cmd, tmpl, o);
+		if(gob && gda) gob->Command(cmd, gda, o);
+		Id = GO_FITFUNC3D;
+		return true;
+	case CMD_UPDATE:
+		return Update();
+		break;
+		}
+	return Plot3D::Command(cmd, tmpl, o);
+}
+
+bool
+FitFunc3D::Update()
+{
+	if(cmdxy) {
+		dirty = true;
+		if(xstep == 0.0) xstep = 1.0;	if(zstep == 0.0) zstep = 1.0;
+		if(!gda) gda = new DataObj();
+		if(gda && do_func3D(gda, x1, x2, xstep, z1, z2, zstep, cmdxy, param)) {
+			if(gob = new Grid3D(this, gda, type, x1, xstep, z1, zstep)) {
+				gob->Command(CMD_SET_LINE, &Line, 0L);
+				gob->Command(CMD_SYM_FILL, &Fill, 0L);
+				if(!plots && (plots = (GraphObj**)calloc(3, sizeof(GraphObj*)))) {
+					nPlots = 1;				plots[0] = (Plot *)gob;
+					if(parent->Id == GO_GRAPH) CreateAxes();
+					return dirty = parent->Command(CMD_REDRAW, 0L, 0L);
+					}
+				else if(plots && nPlots && plots[0]->Id == GO_GRID3D) {
+					Undo.DeleteGO(&plots[0], UNDO_CONTINUE, 0L);
+					Undo.SetGO(this, &plots[0], gob, UNDO_CONTINUE);
+					return true;
+					}
+				else {
+					DeleteGO(gob);		gob=0L;
+					}
+				}
+			}
+		}
+	return false;
+}
diff --git a/PropertyDlg.cpp b/PropertyDlg.cpp
index 73d8eac..4d0147e 100755
--- a/PropertyDlg.cpp
+++ b/PropertyDlg.cpp
@@ -1,4 +1,4 @@
-//PropertyDlg.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
+//PropertyDlg.cpp, Copyright (c) 2001-2006 R.Lackner
 //Property dialogs for graphic objects
 //
 //    This file is part of RLPlot.
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include <time.h>
 #include "TheDialog.h"
 
 extern tag_Units Units[];
@@ -1013,7 +1014,7 @@ ErrorBar::PropertyDlg()
 		{4, 0, 5, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
 		{5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 100},
 		{6, 7, 200, ISPARENT, SHEET, &tab2, 5, 10, 90, 100},
-		{7, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 90, 100},
+		{7, 0, 300, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 90, 100},
 		{100, 101, 0, 0x0L, RTEXT, (void*)"cap width", 15, 40, 28, 8},
 		{101, 102, 0, 0x0L, EDVAL1, &SizeBar, 46, 40, 25, 10},
 		{102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 40, 20, 8},
@@ -1023,12 +1024,14 @@ ErrorBar::PropertyDlg()
 		{106, 107, 0, 0x0L, RTEXT, (void*)"line color", 15, 70, 28, 8},
 		{107, 0, 0, OWNDIALOG, COLBUTTON, (void *)ErrLine.color, 46, 70, 25, 10},
 		{200, 0, 500, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 15, 40, 28, 8},
-		{301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 46, 40, 35, 10},
-		{302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 15, 55, 28, 8},
-		{303, 304, 0, 0x0L, EDVAL1, &fPos.fy, 46, 55, 35, 10},
-		{304, 305, 0, 0x0L, RTEXT, (void*)"error", 15, 70, 28, 8},
-		{305, 0, 0, 0x0L, EDVAL1, &ferr, 46, 70, 35, 10},
+		{300, 301, 0, 0x0L, RTEXT, (void*)"x-value", 15, 30, 28, 8},
+		{301, 302, 0, 0x0L, EDVAL1, &fPos.fx, 46, 30, 35, 10},
+		{302, 303, 0, 0x0L, RTEXT, (void*)"y-value", 15, 45, 28, 8},
+		{303, 304, 0, 0x0L, EDVAL1, &fPos.fy, 46, 45, 35, 10},
+		{304, 305, 0, 0x0L, RTEXT, (void*)"error", 15, 60, 28, 8},
+		{305, 306, 0, 0x0L, EDVAL1, &ferr, 46, 60, 35, 10},
+		{306, 307, 0, 0x0L, LTEXT, (void*)"description:", 10, 80, 70, 8},
+		{307, 0, 0, 0x0L, EDTEXT, (void*)name, 10, 90, 80, 10},
 		{500, 501, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 12, 40, 25, 25},
 		{501, 502, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 37, 40, 25, 25},
 		{502, 503, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_ErrBarTempl), 62, 40, 25, 25},
@@ -1043,8 +1046,10 @@ ErrorBar::PropertyDlg()
 	DWORD n_col, undo_flags = 0L;
 	anyOutput *cdisp = Undo.cdisp;
 	bool bRet = false;
+	char desc[80];
 
 	if(!parent) return false;
+	desc[0] = 0;
 	if(!(Dlg = new DlgRoot(ErrDlg)))return false;
 	Dlg->SetCheck(500 + (type & 0x7), 0L, true);
 	if(!(Dlg->GetValue(101, &o_sb))) o_sb = SizeBar;
@@ -1062,12 +1067,12 @@ ErrorBar::PropertyDlg()
 		switch (res) {
 		case 500:	case 501:	case 502:
 		case 503:	case 504:	case 505:
-			tmpType = res-500;
-			res = -1;
-			break;
+			tmpType = res-500;			res = -1;	break;
+		case 7:								//edit tab
+			Dlg->Activate(307, true);	res = -1;	break;
 		case 1:								//accept for this object
 		case 2:								//   or all objects of plot
-			Undo.SetDisp(cdisp);
+			Undo.SetDisp(cdisp);			Dlg->GetText(307, desc);
 			Dlg->GetValue(101, &n_sb);		Dlg->GetValue(104, &n_lw);
 			Dlg->GetColor(107, &n_col);		Dlg->GetValue(305, &n_err);
 			Dlg->GetValue(301, &n_pos.fx);	Dlg->GetValue(303, &n_pos.fy);
@@ -1076,6 +1081,20 @@ ErrorBar::PropertyDlg()
 		}while (res <0);
 	switch (res) {
 	case 1:				//new setting for current error bar only
+		if(desc[0] && name && name[0] && strcmp(desc, name)) {
+			Undo.String(this, &name, undo_flags);
+			name = (char*)realloc(name, strlen(desc)+2);
+			strcpy(name, desc);		undo_flags |= UNDO_CONTINUE;
+			}
+		else if(desc[0]) {
+			Undo.String(this, &name, undo_flags);
+			name = (char*)realloc(name, strlen(desc)+2);
+			strcpy(name, 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 = 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);
@@ -1086,6 +1105,7 @@ ErrorBar::PropertyDlg()
 		break;
 	case 2:				//new settings to all error bars of plot
 		parent->Command(CMD_SAVE_ERRS, 0L, 0L);
+		if(desc[0] || name) parent->Command(CMD_ERRDESC, desc, 0L);
 		parent->SetSize(SIZE_ERRBAR, n_sb);
 		parent->SetSize(SIZE_ERRBAR_LINE, n_lw);
 		parent->SetColor(COL_ERROR_LINE, n_col);
@@ -1388,41 +1408,49 @@ Box::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Whisker properties dialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *WhiskerDlgTmpl =
+		"1,2,,DEFAULT,PUSHBUTTON,1,100,10,64,12\n"
+		"2,3,,,PUSHBUTTON,2,100,25,64,12\n"
+		"3,4,,,PUSHBUTTON,-2, 100, 40, 64, 12\n"
+		"4,,5,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"5,6,100,ISPARENT | CHECKED,SHEET,3, 5, 10, 90, 100\n"
+		"6,7,500,ISPARENT,SHEET,4,5,10,90,100\n"
+		"7,,300,ISPARENT,SHEET,5,5,10,90,100\n"
+		"100,101,,,RTEXT,6,15,40,28,8\n"
+		"101,102,,,EDVAL1,7,46,40,25,10\n"
+		"102,103,,,LTEXT,-3,73,40,20,8\n"
+		"103,104,,,RTEXT,8,15,55,28,8\n"
+		"104,105,,,EDVAL1,9,46,55,25,10\n"
+		"105,106,,,LTEXT,-3,73,55,20,8\n"
+		"106,107,,,RTEXT,10,15,70,28,8\n"
+		"107,,,OWNDIALOG,COLBUTT,11,46,70,25,10\n"
+		"300,301,,,RTEXT,12,15,30,28,8\n"
+		"301,302,,,EDVAL1,13,46,30,35,10\n"
+		"302,303,,,RTEXT,-5,15,42,28,8\n"
+		"303,304,,,EDVAL1,14,46,42,35,10\n"
+		"304,305,,,RTEXT,15,15,55,28,8\n"
+		"305,306,,,EDVAL1,16,46,55,35,10\n"
+		"306,307,,,RTEXT,-5,15,67,28,8\n"
+		"307,308,,,EDVAL1,17,46,67,35,10\n"
+		"308,309,,,LTEXT,18,10,85,70,8\n"
+		"309,,,,EDTEXT,19,10,95,80,10\n"
+		"500,501,,EXRADIO,ODBUTTON,20,32,40,18,18\n"
+		"501,502,,EXRADIO,ODBUTTON,20,14,40,18,18\n"
+		"502,503,,EXRADIO,ODBUTTON,20,50,40,18,18\n"
+		"503,504,,EXRADIO,ODBUTTON,20,68,40,18,18\n"
+		"504,,,LASTOBJ,LTEXT,21,14,30,30,9";
 bool
 Whisker::PropertyDlg()
 {
 	TabSHEET tab1 = {0, 38, 10, "Whisker"};
 	TabSHEET tab2 = {65, 90, 10, "Edit"};
 	TabSHEET tab3 = {38, 65, 10, "Style"};
-	DlgInfo ErrDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"Apply to WHISKER", 100, 10, 64, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Apply to PLOT", 100, 25, 64, 12},
-		{3, 4, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 100, 40, 64, 12},
-		{4, 0, 5, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
-		{5, 6, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 90, 100},
-		{6, 7, 500, ISPARENT, SHEET, &tab3, 5, 10, 90, 100},
-		{7, 0, 300, ISPARENT, SHEET, &tab2, 5, 10, 90, 100},
-		{100, 101, 0, 0x0L, RTEXT, (void*)"cap width", 15, 40, 28, 8},
-		{101, 102, 0, 0x0L, EDVAL1, &size, 46, 40, 25, 10},
-		{102, 103, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 40, 20, 8},
-		{103, 104, 0, 0x0L, RTEXT, (void*)"line width", 15, 55, 28, 8},
-		{104, 105, 0, 0x0L, EDVAL1, &LineDef.width, 46, 55, 25, 10},
-		{105, 106, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 73, 55, 20, 8},
-		{106, 107, 0, 0x0L, RTEXT, (void*)"line color", 15, 70, 28, 8},
-		{107, 0, 0, OWNDIALOG, COLBUTTON, (void *)LineDef.color, 46, 70, 25, 10},
-		{300, 301, 0, 0x0L, RTEXT, (void*)"point 1 x", 15, 40, 28, 8},
-		{301, 302, 0, 0x0L, EDVAL1, &pos1.fx, 46, 40, 35, 10},
-		{302, 303, 0, 0x0L, RTEXT, (void*)"y", 15, 52, 28, 8},
-		{303, 304, 0, 0x0L, EDVAL1, &pos1.fy, 46, 52, 35, 10},
-		{304, 305, 0, 0x0L, RTEXT, (void*)"point 2 x", 15, 70, 28, 8},
-		{305, 306, 0, 0x0L, EDVAL1, &pos2.fx, 46, 70, 35, 10},
-		{306, 307, 0, 0x0L, RTEXT, (void*)"y", 15, 82, 28, 8},
-		{307, 0, 0, 0x0L, EDVAL1, &pos2.fy, 46, 82, 35, 10},
-		{500, 501, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_WhiskerTempl),32,40,18,18},
-		{501, 502, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_WhiskerTempl), 14, 40, 18, 18},
-		{502, 503, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_WhiskerTempl), 50, 40, 18, 18},
-		{503, 504, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_WhiskerTempl), 68, 40, 18, 18},
-		{504, 0, 0, LASTOBJ, LTEXT, (void*)"select style:", 14, 30, 30, 9}};
+	void *dyndata[] = {(void*)"Apply to WHISKER", (void*)"Apply to PLOT", (void*)&tab1,
+		(void*)&tab3, (void*)&tab2, (void*)"cap width", (void*)&size, (void*)"line width",
+		(void*)&LineDef.width, (void*)"line color", (void *)&LineDef.color, (void*)"point 1 x",
+		(void*)&pos1.fx, (void*)&pos1.fy, (void*)"point 2 x", (void*)&pos2.fx, (void*)&pos2.fy,
+		(void*)"description:", (void*)name, (void*)(OD_WhiskerTempl), (void*)"select style:"};
+	DlgInfo *ErrDlg = CompileDialog(WhiskerDlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
 	int res, tmp_type;
@@ -1431,9 +1459,10 @@ Whisker::PropertyDlg()
 	lfPOINT n_pos;
 	double tmpVal, o_size, n_size, o_lw, n_lw;
 	bool bRet = false;
+	char desc[80];
 
 	if(!parent) return false;
-	tmp_type = type;
+	desc[0] = 0;	tmp_type = type;
 	Dlg = new DlgRoot(ErrDlg);
 	Dlg->SetCheck(500 + (tmp_type & 0x03), 0L, true);
 	Dlg->GetValue(101, &o_size);		Dlg->GetValue(104, &o_lw);
@@ -1451,11 +1480,26 @@ 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);
 			break;
 			}
 		}while (res <0);
 	switch (res) {
 	case 1:				//new setting for current whisker
+		if(desc[0] && name && name[0] && strcmp(desc, name)) {
+			Undo.String(this, &name, undo_flags);
+			name = (char*)realloc(name, strlen(desc)+2);
+			strcpy(name, desc);		undo_flags |= UNDO_CONTINUE;
+			}
+		else if(desc[0]) {
+			Undo.String(this, &name, undo_flags);
+			name = (char*)realloc(name, strlen(desc)+2);
+			strcpy(name, desc);		undo_flags |= UNDO_CONTINUE;
+			}
+		else if(name && name[0]) {
+			Undo.String(this, &name, undo_flags);
+			name[0] = 0;			undo_flags |= UNDO_CONTINUE;
+			}
 		if(Dlg->GetValue(301, &tmpVal)) n_pos.fx = tmpVal;
 		else n_pos.fx = pos1.fx;
 		if(Dlg->GetValue(303, &tmpVal)) n_pos.fy = tmpVal;
@@ -1474,8 +1518,9 @@ Whisker::PropertyDlg()
 		break;
 	case 2:				//new settings to all whiskers of plot
 		if(o_size == n_size && type == tmp_type && o_lw == n_lw 
-			&& n_col == LineDef.color) break;
+			&& n_col == LineDef.color && !desc[0] && !name) break;
 		parent->Command(CMD_SAVE_ERRS, 0L, 0L);
+		if(desc[0] || name) parent->Command(CMD_ERRDESC, desc, 0L);
 		parent->SetSize(SIZE_WHISKER, n_size);
 		parent->SetSize(SIZE_WHISKER_LINE, n_lw);
 		parent->SetColor(COL_WHISKER, n_col);
@@ -1483,8 +1528,7 @@ Whisker::PropertyDlg()
 		bRet = true;
 		break;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;		free(ErrDlg);
 	return bRet;
 }
 
@@ -1812,6 +1856,7 @@ Plane3D::PropertyDlg()
 	double o_lsize, n_lsize, o_rbw, n_rbw, o_rbz, n_rbz;
 
 	if(!parent) return false;
+	if(parent->Id == GO_GRID3D) return parent->PropertyDlg();
 	memcpy(&newFill, &Fill, sizeof(FillDEF));
 	if(parent->Id == GO_RIBBON && parent->type == 1) {
 		rb_width = parent->GetSize(SIZE_CELLWIDTH) *100.0;
@@ -2125,6 +2170,7 @@ Line3D::PropertyDlg()
 	anyOutput *cdisp = Undo.cdisp;
 
 	if(!parent) return false;
+	if(parent->Id == GO_GRID3D) return parent->PropertyDlg();
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
 	if(!(Dlg = new DlgRoot(LineDlg)))return false;
 	sprintf(TmpTxt, "Line of %s", parent->name);
@@ -2954,10 +3000,10 @@ PlotScatt::PropertyDlg()
 		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 140, 10, 45, 12},
 		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 140, 25, 45, 12},
 		{3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
-		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 131, 100},
+		{4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 131, 100},
 		{5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 131, 100},
-		{6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 131, 100},
-		{7, 10, 400, ISPARENT, SHEET, &tab4, 5, 10, 131, 100},
+		{6, 7, 300, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 131, 100},
+		{7, 10, 400, TOUCHEXIT | ISPARENT, SHEET, &tab4, 5, 10, 131, 100},
 		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
 		{100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 30, 60, 8},
 		{101, 102, 0, 0x0L, RANGEINPUT, text1, 20, 40, 100, 10},
@@ -2993,7 +3039,7 @@ PlotScatt::PropertyDlg()
 	DlgRoot *Dlg;
 	void *hDlg;
 	int c, i, j, k, l, i1, j1, k1, l1, m, n, o, p, ic;
-	int ErrType = 0, res, width, height, BarType;
+	int ErrType = 0, res, BarType;
 	double x, y, e;
 	lfPOINT fp1, fp2;
 	bool bRet = false, bLayout = false, bContinue = false;
@@ -3003,24 +3049,18 @@ PlotScatt::PropertyDlg()
 
 	if(!parent || !data) return false;
 	if(Id == GO_BARCHART) return CreateBarChart();
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);		sprintf(text2, "b1:b%d", height);
-	sprintf(text3, "c1:c%d", height);		sprintf(text4, "b1:b%d", height);
+	UseRangeMark(data, 1, text1, text2, text3, text4);
 	rX = rY = rE = rL = 0L;
 	if(!(Dlg = new DlgRoot(XYDlg)))return false;
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);
-	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
-	Dlg->ItemCmd(304, CMD_SET_DATAOBJ, data);
-	Dlg->ItemCmd(402, CMD_SET_DATAOBJ, data);
+	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);			Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
+	Dlg->ItemCmd(304, CMD_SET_DATAOBJ, data);			Dlg->ItemCmd(402, CMD_SET_DATAOBJ, data);
 #ifdef _WINDOWS
 	for(i = 104; i <= 107; i++) Dlg->TextSize(i, 12);
 #else
 	for(i = 104; i <= 107; i++) Dlg->TextSize(i, 10);
 #endif
-	if(DefSel & 0x01)Dlg->SetCheck(200, 0L, true);
-	if(DefSel & 0x02)Dlg->SetCheck(250, 0L, true);
-	if(DefSel & 0x04)Dlg->SetCheck(255, 0L, true);
-	if(DefSel & 0x08)Dlg->SetCheck(256, 0L, true);
+	if(DefSel & 0x01)Dlg->SetCheck(200, 0L, true);		if(DefSel & 0x02)Dlg->SetCheck(250, 0L, true);
+	if(DefSel & 0x04)Dlg->SetCheck(255, 0L, true);		if(DefSel & 0x08)Dlg->SetCheck(256, 0L, true);
 	hDlg = CreateDlgWnd("XY Plot properties", 50, 50, 388, 260, Dlg, 0x0L);
 	do {
 		LoopDlgWnd();
@@ -3039,10 +3079,14 @@ PlotScatt::PropertyDlg()
 			Dlg->SetCheck(301, 0L, true);
 			res = -1;
 			break;
+		case 4:								// the data tab sheet
+			Dlg->Activate(101, true);	res = -1;				break;
 		case 5:								// the layout tab sheet
-			bLayout = true;
-			res = -1;
-			break;
+			bLayout = true;				res = -1;				break;
+		case 6:								// the error tab sheet
+			Dlg->Activate(304, true);	res = -1;				break;
+		case 7:								// the label tab sheet
+			Dlg->Activate(402, true);	res = -1;				break;
 		case 1:								// OK
 			if(rX) delete rX;	if(rY) delete rY; if(rE) delete rE;
 			rX = rY = rE = 0L;						// check x-range
@@ -3230,12 +3274,12 @@ xyStat::PropertyDlg()
 	int i, res, width, height;
 	double x, y, e, f, dx, dy;
 	lfPOINT fp1, fp2;
+	char errdesc[40];
 	TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), defs.GetSize(SIZE_TEXT), 0.0f, 0.0f, 0,
 		TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
 
 	if(!parent || !data) return false;
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);		sprintf(text2, "b1:b%d", height);
+	UseRangeMark(data, 1, text1, text2);
 	if(!(Dlg = new DlgRoot(StatDlg)))return false;
 	Dlg->ItemCmd(102, CMD_SET_DATAOBJ, data);
 	Dlg->ItemCmd(104, CMD_SET_DATAOBJ, data);
@@ -3268,8 +3312,8 @@ xyStat::PropertyDlg()
 		if(Dlg->GetText(404, TmpTxt) && TmpTxt[0]) case_prefix = strdup(TmpTxt);
 		CreateData();
 		if(type && curr_data) {
-			data->GetSize(&width, &height);			nPoints = height;
-			sprintf(text1, "a1:a%d", height);		sprintf(text2, "b1:b%d", height);
+			curr_data->GetSize(&width, &height);		nPoints = height;
+			sprintf(text1, "a1:a%d", height);			sprintf(text2, "b1:b%d", height);
 			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))
@@ -3291,12 +3335,24 @@ xyStat::PropertyDlg()
 						Bars[i] = new Bar(this, curr_data, x, y, BAR_VERTB | BAR_RELWIDTH, 0, i, 1, i);
 					}
 				}
-			if(type & 0x1f00) Errors = (ErrorBar**)calloc(nPoints, sizeof(ErrorBar*));
+			if(type & 0x1f00) {
+				Errors = (ErrorBar**)calloc(nPoints, sizeof(ErrorBar*));
+				switch(type & 0x1f00) {
+				case 0x0100:	strcpy(errdesc, "Std. Dev.");			break;
+				case 0x0200:	strcpy(errdesc, "Std. Err.");			break;
+				case 0x0400:	strcpy(errdesc, "25, 75% Perc.");		break;
+				case 0x0800:	strcpy(errdesc, "Min./Max.");			break;
+				case 0x1000:	sprintf(errdesc, "'%g%% CI", ci);		break;
+				default:		strcpy(errdesc, "error");
+					}
+				}
 			if((type & 0x1300) && Errors) {
 				for(i = 0; i < height; i++) {
 					if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 1, &y)
-						&& curr_data->GetValue(i, 2, &e))
+						&& curr_data->GetValue(i, 2, &e)) {
 						Errors[i]= new ErrorBar(this, curr_data, x, y, e, 0, 0, i, 1, i, 2, i);
+						if(Errors[i]) Errors[i]->Command(CMD_ERRDESC, errdesc, 0L);
+						}
 					}
 				}
 			if((type & 0x0c00) && Errors) {
@@ -3304,6 +3360,7 @@ xyStat::PropertyDlg()
 					if(curr_data->GetValue(i, 0, &x) && curr_data->GetValue(i, 2, &e) && curr_data->GetValue(i, 3, &f)){
 						fp1.fx = fp2.fx = x;	fp1.fy = e;		fp2.fy = f;
 						Errors[i]= (ErrorBar*)new Whisker(this, curr_data, fp1, fp2, 0, 0, i, 2, i, 0, i, 3, i);
+						if(Errors[i]) Errors[i]->Command(CMD_ERRDESC, errdesc, 0L);
 						}
 					}
 				}
@@ -3318,7 +3375,7 @@ xyStat::PropertyDlg()
 					dx = -dy;
 					}
 				for(i = 0; i < height; i++) {
-					if(curr_data->GetValue(i, 0, &x) && curr_data->GetText(i, 5, TmpTxt, TMP_TXT_SIZE)){
+					if(curr_data->GetValue(i, 0, &x) && curr_data->GetText(i, 5, TmpTxt, TMP_TXT_SIZE, false)){
 						if((type & 0x2000) && curr_data->GetValue(i, 4, &y)) 
 							Labels[i] = new Label(this, curr_data, x, y, &lbdef, 
 							LB_X_DATA | LB_Y_DATA, 0, i, 4, i, 5, i);
@@ -3450,7 +3507,7 @@ Regression::PropertyDlg()
 		{214, 0, 0, LASTOBJ, RADIO1, (void*)"y = sqrt(y)", 82, 64, 30, 8}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int c, i, j, k, l, ic, res, width, height, n;
+	int c, i, j, k, l, ic, res, n;
 	double x, y;
 	AccRange *rX, *rY;
 	bool bRet = false, bContinue = false, dValid;
@@ -3458,9 +3515,7 @@ Regression::PropertyDlg()
 
 	if(!parent || !data) return false;
 	rX = rY = 0L;
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);
-	sprintf(text2, "b1:b%d", height);
+	UseRangeMark(data, 1, text1, text2);
 	if(!(Dlg = new DlgRoot(RegDlg)))return false;
 	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Linear regression analysis step 1/2", 50, 50, 380, 225, Dlg, 0x0L);
@@ -3617,7 +3672,7 @@ BubblePlot::PropertyDlg()
 		{412, 0, 0, LASTOBJ, RADIO1, (void*)"area", 40, 105, 45, 8}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, j, k, l, m, n, ic, res, width, height, BubbleType;
+	int i, j, k, l, m, n, ic, res, BubbleType;
 	double x, y, s;
 	double tmp;
 	bool bRetVal = false, bFillChanged, bContinue = false;
@@ -3625,10 +3680,7 @@ BubblePlot::PropertyDlg()
 	LineDEF ShowFillLine ={0.2f, 1.0f, 0x0L, 0x0L};
 
 	if(!parent || !data) return false;
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);
-	sprintf(text2, "b1:b%d", height);
-	sprintf(text3, "c1:c%d", height);
+	UseRangeMark(data, 1, text1, text2, text3);
 	memcpy(&ShowFill, &BubbleFill, sizeof(FillDEF));
 	if(BubbleFill.hatch) memcpy(&ShowFillLine, BubbleFill.hatch, sizeof(LineDEF));
 	ShowFill.hatch = &ShowFillLine;
@@ -3896,7 +3948,7 @@ PolarPlot::PropertyDlg()
 		{213, 0, 0, LASTOBJ, RANGEINPUT, (void*)text2, 20, 92, 100, 10}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, width, height, i, j, k, l, n, ic, cType = 200;
+	int res, i, j, k, l, n, ic, cType = 200;
 	double x, y;
 	bool bRet = false, bType = false;
 	AccRange *rX = 0L, *rY = 0L;
@@ -3910,9 +3962,7 @@ PolarPlot::PropertyDlg()
 	frad = (parent->GetSize(SIZE_DRECT_BOTTOM) - parent->GetSize(SIZE_DRECT_TOP))/2.0f;
 	fcx = parent->GetSize(SIZE_GRECT_LEFT) + parent->GetSize(SIZE_DRECT_LEFT)*1.5 + frad;
 	fcy = parent->GetSize(SIZE_GRECT_TOP) + parent->GetSize(SIZE_DRECT_TOP) + frad;
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);
-	sprintf(text2, "b1:b%d", height);
+	UseRangeMark(data, 1, text1, text2);
 	tlbdef.ColTxt = defs.Color(COL_AXIS);
 	tlbdef.ColBg = 0x00ffffffL;
 	tlbdef.RotBL = tlbdef.RotCHAR = 0.0f;
@@ -4113,6 +4163,7 @@ BoxPlot::PropertyDlg()
 	bool bRet = false;
 	int i, j, k, k1, l, l1, n, ic, c, res, width, height;
 	double x, y1, y2, dx, dy;
+	char errdesc[40];
 	lfPOINT fp1, fp2;
 	TextDEF lbdef = {defs.Color(COL_TEXT), defs.Color(COL_BG), defs.GetSize(SIZE_TEXT), 0.0f, 0.0f, 0,
 		TXA_HLEFT | TXA_VBOTTOM, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, TmpTxt};
@@ -4120,10 +4171,7 @@ BoxPlot::PropertyDlg()
 	int it_racc[] = {102, 104, 202, 253, 263, 273, 275, 283, 285};
 
 	if(!parent || !data) return false;
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);		sprintf(text2, "b1:b%d", height);
-	sprintf(text3, "c1:c%d", height);		sprintf(text4, "d1:d%d", height);
-	sprintf(text5, "e1:e%d", height);		sprintf(text6, "f1:f%d", height);
+	UseRangeMark(data, 1, text1, text2, text3, text4, text5, text6);
 	ci_box = ci_err = 95.0;
 	if(!(Dlg = new DlgRoot(PlotDlg)))return false;
 	for(i=0; i < 9; i++) Dlg->ItemCmd(it_racc[i], CMD_SET_DATAOBJ, data);
@@ -4253,11 +4301,20 @@ BoxPlot::PropertyDlg()
 					bRet = true;
 					}
 				if(nPoints > 0 && (type & 0x0f00) && (Whiskers = (Whisker**)calloc(nPoints, sizeof(Whisker*)))) {
+					switch(type & 0x1f00) {
+					case 0x0100:	strcpy(errdesc, "Std. Dev.");			break;
+					case 0x0200:	strcpy(errdesc, "Std. Err.");			break;
+					case 0x0300:	strcpy(errdesc, "25, 75% Perc.");		break;
+					case 0x0400:	strcpy(errdesc, "Min./Max.");			break;
+					case 0x0500:	sprintf(errdesc, "'%g%% CI", ci_err);	break;
+					default:		strcpy(errdesc, "error");
+						}
 					for(i = 0; i < height; i++) {
 						if(curr_data->GetValue(i, 0, &x) &&	curr_data->GetValue(i, 4, &y1)
 							&&	curr_data->GetValue(i, 5, &y2)) {
 							fp1.fy = y1;	fp2.fy = y2;		fp1.fx = fp2.fx = x;
 							Whiskers[i] = new Whisker(this, curr_data, fp1, fp2, 0, 0, i, 4, i, 0, i, 5, i);
+							if(Whiskers[i]) Whiskers[i]->Command(CMD_ERRDESC, errdesc, 0L);
 							}
 						}
 					bRet = true;
@@ -4323,16 +4380,14 @@ DensDisp::PropertyDlg()
 		{203, 0, 0, TOUCHEXIT | LASTOBJ, RADIO1, 0L, 25, 96, 60, 9}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int n, res, width, height, align = 0;
+	int n, res, align = 0;
 	bool bRet = false, bContinue = false, bVert;
 	AccRange *rX = 0L, *rY = 0L;
 
 	if(!parent || !data) return false;
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)defs.GetOutLine(), 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)defs.GetFill(), 0);
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);
-	sprintf(text2, "b1:b%d", height);
+	UseRangeMark(data, 1, text1, text2);
 	if(!(Dlg = new DlgRoot(PlotDlg)))return false;
 	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("Density profile", 50, 50, 420, 260, Dlg, 0x0L);
@@ -4572,6 +4627,7 @@ StackBar::PropertyDlg()
 					Boxes[i]->Command(CMD_UPDATE, 0L, 0L);
 					Boxes[i]->Command(CMD_AUTOSCALE, 0L, 0L);
 					Boxes[i]->Command(CMD_BOX_FILL, GetSchemeFill(&sc), 0L);
+					Boxes[i]->SetSize(SIZE_BOX, 60.0);
 					}
 				}
 			}
@@ -5067,6 +5123,47 @@ MultiLines::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Pie and ring chart properties
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *PieDlgTmpl = 
+		"1,2,,DEFAULT,PUSHBUTTON,-1,130,10,45,12\n"
+		"2,3,,,PUSHBUTTON,-2,130,25,45,12\n"
+		"3,,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"4,5,100,ISPARENT | CHECKED,SHEET,1,5,10,120,103\n"
+		"5,6,200,ISPARENT,SHEET,2,5,10,120,103\n"
+		"6,10,300,ISPARENT,SHEET,3,5,10,120,103\n"
+		"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+		"100,101,,,LTEXT,4,10,25,60,8\n"
+		"101,105,,,RANGEINPUT,5,15,35,100,10\n"
+		"105,106,500,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"106,107,600,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"107,108,,,EDVAL1,6,58,59,30,10\n"
+		"108,,,,LTEXT,-3,89,59,15,8\n" 
+		"200,,,,LTEXT,7,15,30,60,8\n"
+		"201,202,,,RTEXT,-4,2,42,20,8\n"
+		"202,204,,,EDVAL1,8,23,42,30,10\n"
+		"204,205,,,RTEXT,-5,47,42,20,8\n"
+		"205,206,,,EDVAL1,9,68,42,30,10\n"
+		"206,207,,,LTEXT,-3,99,42,15,8\n" 
+		"207,208,,,RTEXT,10,27,58,20,8\n"
+		"208,209,,,EDVAL1,11,48,58,30,10\n"
+		"209,210,,,LTEXT,12,79,58,15,8\n" 
+		"210,211,400,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"211,212,410,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"212,,,,LTEXT,13,15,80,30,8\n"
+		"300,,,NOSELECT,ODBUTTON,14,20,35,80,60\n"
+		"400,401,,EXRADIO | CHECKED,ODBUTTON,15,40,75,30,30\n"
+		"401,,,EXRADIO,ODBUTTON,15,70,75,30,30\n"
+		"410,411,,EXRADIO | CHECKED,ODBUTTON,15,40,75,30,30\n"
+		"411,,,EXRADIO,ODBUTTON,15,70,75,30,30\n"
+		"500,501,,CHECKED,RADIO1,16,10,59,20,8\n"
+		"501,502,,,RADIO1,17,10,71,40,8\n"
+		"502,503,,,RANGEINPUT,18,15,82,100,10\n"
+		"503,504,,,LTEXT,19,15,94,10,8\n"
+		"504,505,,,EDVAL1,20,42,94,25,10\n"
+		"505,,,,LTEXT,21,70,94,15,8\n"
+		"600,601,,,RTEXT,22,8,59,45,8\n"
+		"601,602,,,RTEXT,23,8,74,45,8\n"
+		"602,603,,,EDVAL1,24,58,74,30,10\n"
+		"603,,,LASTOBJ,LTEXT,-3,89,74,15,8";
 bool
 PieChart::PropertyDlg()
 {
@@ -5075,50 +5172,16 @@ PieChart::PropertyDlg()
 	TabSHEET tab3 = {55, 90, 10, "Scheme"};
 	double fcx =10.0, fcy = 20.0, frad=40.0, firad = 30.0;
 	char txt2[80];
-	DlgInfo PieDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 130, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 130, 25, 45, 12},
-		{3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
-		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 120, 103},
-		{5, 6, 200, ISPARENT, SHEET, &tab2, 5, 10, 120, 103},
-		{6, 10, 300, ISPARENT, SHEET, &tab3, 5, 10, 120, 103},
-		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
-		{100, 101, 0, 0x0L, LTEXT, (void*)"spread sheet range for values", 10, 25, 60, 8},
-		{101, 105, 0, 0x0L, RANGEINPUT, TmpTxt, 15, 35, 100, 10},
-		{105, 106, 500, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{106, 107, 600, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{107, 108, 0, 0x0L, EDVAL1, &frad, 58, 59, 30, 10},
-		{108, 0, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 89, 59, 15, 8}, 
-		{200, 201, 0, 0x0L, LTEXT, (void*)"position of center:", 15, 30, 60, 8},
-		{201, 202, 0, 0x0L, RTEXT, (void*)"x", 2, 42, 20, 8},
-		{202, 204, 0, 0x0L, EDVAL1, &fcx, 23, 42, 30, 10},
-		{204, 205, 0, 0x0L, RTEXT, (void*)"y", 47, 42, 20, 8},
-		{205, 206, 0, 0x0L, EDVAL1, &fcy, 68, 42, 30, 10},
-		{206, 207, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 99, 42, 15, 8}, 
-		{207, 208, 0, 0x0L, RTEXT, (void*)"start angle", 27, 58, 20, 8},
-		{208, 209, 0, 0x0L, EDVAL1, &CtDef.fx, 48, 58, 30, 10},
-		{209, 210, 0, 0x0L, LTEXT, (void*)"degree", 79, 58, 15, 8}, 
-		{210, 211, 400, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{211, 212, 410, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{212, 0, 0, 0x0L, LTEXT, (void*)"style:", 15, 80, 30, 8},
-		{300, 0, 0, NOSELECT, ODBUTTON, (void*)(OD_scheme), 20, 35, 80, 60},
-		{400, 401, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PieTempl, 40, 75, 30, 30},
-		{401, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PieTempl, 70, 75, 30, 30},
-		{410, 411, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PieTempl, 40, 75, 30, 30},
-		{411, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PieTempl, 70, 75, 30, 30},
-		{500, 501, 0, CHECKED, RADIO1, (void*)"fixed radius", 10, 59, 20, 8},
-		{501, 502, 0, 0x0L, RADIO1, (void*)"pick radii from spreadsheet range", 10, 71, 40, 8},
-		{502, 503, 0, 0x0L, RANGEINPUT, TmpTxt+100, 15, 82, 100, 10},
-		{503, 504, 0, 0x0L, LTEXT, (void*)"x  factor", 15, 94, 10, 8},
-		{504, 505, 0, 0x0L, EDVAL1, &FacRad, 42, 94, 25, 10},
-		{505, 0, 0, 0x0L, LTEXT, &txt2, 70, 94, 15, 8},
-		{600, 601, 0, 0x0L, RTEXT, (void*)"outer radius", 8, 59, 45, 8},
-		{601, 602, 0, 0x0L, RTEXT, (void*)"inner radius", 8, 74, 45, 8},
-		{602, 603, 0, 0x0L, EDVAL1, &firad, 58, 74, 30, 10},
-		{603, 0, 0, LASTOBJ, LTEXT, (void *) Units[defs.cUnits].display, 89, 74, 15, 8}};
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"spread sheet range for values",
+		(void*)TmpTxt, (void*)&frad, (void*)"position of center:", (void*)&fcx, (void*)&fcy,
+		(void*)"start angle", (void*)&CtDef.fx, (void*)"degree", (void*)"style:", (void*)(OD_scheme),
+		(void*)(OD_PieTempl), (void*)"fixed radius", (void*)"pick radii from spreadsheet range",
+		(void*)(TmpTxt+100), (void*)"x  factor", (void*)&FacRad, (void*)&txt2, (void*)"outer radius",
+		(void*)"inner radius", (void*)&firad};
+	DlgInfo *PieDlg = CompileDialog(PieDlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, ix, iy, rix, riy, ny, res, width, height, cf;
+	int i, ix, iy, rix, riy, ny, res, cf;
 	bool bRet = false, bContinue = false;
 	double sum = 0.0, dang1, dang2;
 	double fv;
@@ -5126,9 +5189,7 @@ PieChart::PropertyDlg()
 	AccRange *rY = 0L, *rR = 0L;
 
 	if(!parent || !data) return false;
-	data->GetSize(&width, &height);
-	sprintf(TmpTxt, "a1:a%d", height);
-	sprintf(TmpTxt+100, "b1:b%d", height);
+	UseRangeMark(data, 1, TmpTxt, TmpTxt+100);
 	sprintf(txt2, "= [%s]", Units[defs.cUnits].display);
 	frad = (parent->GetSize(SIZE_DRECT_BOTTOM) - parent->GetSize(SIZE_DRECT_TOP))/2.0;
 	fcx = parent->GetSize(SIZE_GRECT_LEFT) + (parent->GetSize(SIZE_DRECT_LEFT))/2.0 + frad;
@@ -5222,8 +5283,7 @@ PieChart::PropertyDlg()
 		bRet = true;
 		}
 	if(rY) delete rY;		if(rR) delete rR;
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;				free(PieDlg);
 	return bRet;
 }
 
@@ -5359,8 +5419,155 @@ StarChart::PropertyDlg()
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Grid3D represents a surface in space
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+Grid3D::PropertyDlg()
+{
+	return Configure();
+}
+
+bool
+Grid3D::Configure()
+{
+	TabSHEET tab1 = {0, 37, 10, "Function"};
+	TabSHEET tab2 = {37, 65, 10, "Style"};
+	FillDEF newFill;
+	DlgInfo GridDlg[] = {
+		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 155, 10, 50, 12},
+		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 155, 25, 50, 12},
+		{3, 0, 300, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+		{300, 301, 500, HIDDEN | CHECKED, GROUPBOX, (void*)" grid lines ", 10, 10, 140, 100},
+		{301, 305, 400, HIDDEN | CHECKED, GROUPBOX, (void*)" surface ", 10, 10, 140, 100},
+		{305, 306, 0, TOUCHEXIT, RADIO1, (void*) " grid lines", 155, 45, 50, 10},
+		{306, 0, 0, TOUCHEXIT, RADIO1, (void*) " surface", 155, 57, 50, 10},
+		{400, 401, 0, 0x0L, RTEXT, (void*)"grid line width", 38, 20, 40, 8},
+		{401, 402, 0, 0x0L, EDVAL1, &Line.width, 80, 20, 25, 10},
+		{402, 403, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 20, 20, 8},
+		{403, 404, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 32, 40, 8},
+		{404, 405, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 80, 32, 25, 10},
+		{405, 406, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 44, 40, 8},
+		{406, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 44, 25, 10},
+		{500, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, 15, 130, 100}};
+	DlgRoot *Dlg;
+	void *hDlg;
+	int res, new_type, undo_level = *Undo.pcb;
+	bool bRet = false;
+	double tmp;
+	DWORD new_col;
+	LineDEF newLine;
+	anyOutput *cdisp = Undo.cdisp;
+
+	if(!parent) return false;
+	memcpy(&newFill, &Fill, sizeof(FillDEF));
+	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+	if(!(Dlg = new DlgRoot(GridDlg))) return false;
+	if(!type) {
+		Dlg->ShowItem(300, true);	Dlg->SetCheck(305, 0L, true);
+		}
+	else {
+		Dlg->ShowItem(301, true);	Dlg->SetCheck(306, 0L, true);
+		}
+	if(parent->name) sprintf(TmpTxt, "Grid of %s", parent->name);
+	else strcpy(TmpTxt, "3D Grid");
+	hDlg = CreateDlgWnd(TmpTxt, 50, 50, 426, 260, Dlg, 0x0L);
+	do{
+		LoopDlgWnd();
+		res = Dlg->GetResult();
+		switch (res) {
+		case 305:		case 306:
+			if(Dlg->GetCheck(305)) {
+				Dlg->ShowItem(300, true);	Dlg->ShowItem(301, false);
+				}
+			else {
+				Dlg->ShowItem(300, false);	Dlg->ShowItem(301, true);
+				}
+			Dlg->Command(CMD_REDRAW, 0L, 0L);
+			res = -1;
+			break;
+			}
+		}while (res < 0);
+	Undo.SetDisp(cdisp);
+	while(*Undo.pcb > undo_level)	Undo.Pop(cdisp);
+	if(res == 1) {
+		if(Dlg->GetCheck(305) && type == 0) {
+			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
+			if(cmpLineDEF(&Line, &newLine)) {
+				Command(CMD_SET_LINE, &newLine, 0L);
+				bRet = true;
+				}
+			}
+		else if(Dlg->GetCheck(306) && type == 1) {
+			Dlg->GetValue(401, &tmp);			Dlg->GetColor(404, &new_col);
+			if(planes && (cmpFillDEF(&Fill, &newFill) || tmp != Line.width || new_col != Line.color)) {
+				Command(CMD_SAVE_SYMBOLS, 0L, 0L);
+				Command(CMD_SYM_FILL, &newFill, 0L);
+				if(tmp != Line.width) SetSize(SIZE_SYM_LINE, tmp);
+				if(new_col != Line.color) SetColor(COL_POLYLINE, new_col);
+				bRet = true;
+				}
+			}
+		else {
+			Undo.ValInt(parent, &type, 0L);
+			Undo.Line(this, &Line, UNDO_CONTINUE);	Undo.Fill(this, &Fill, UNDO_CONTINUE);
+			if(Dlg->GetCheck(305)) {
+				new_type = 0;
+				OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+				}
+			else {
+				new_type = 1;
+				memcpy(&Fill, &newFill, sizeof(FillDEF));
+				Dlg->GetValue(401, &Line.width);
+				Dlg->GetColor(404, &Line.color);
+				Line.pattern = 0L;
+				Line.patlength = 1;
+				}
+			if(planes && nPlanes) Undo.DropListGO(parent, (GraphObj***)&planes, &nPlanes, UNDO_CONTINUE);
+			if(lines && nLines) Undo.DropListGO(parent, (GraphObj***)&lines, &nLines, UNDO_CONTINUE);
+			Undo.VoidPtr(parent, (void**)&planes, 0L, 0L, UNDO_CONTINUE);
+			Undo.VoidPtr(parent, (void**)&lines, 0L, 0L, UNDO_CONTINUE);
+			type = new_type;
+			CreateObs(true);
+			bRet = true;
+			}
+		}
+	CloseDlgWnd(hDlg);
+	delete Dlg;
+	return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Scatt3D is a layer representing most simple 3D plots
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *Dlg3DTmpl = 
+		"1,2,,DEFAULT,PUSHBUTTON,-1,142,10,45,12\n"
+		"2,3,,,PUSHBUTTON,-2,142,25,45,12\n"
+		"3,50,4,ISPARENT | CHECKED,GROUP,0,0,0,0,0\n"
+		"4,5,100,TOUCHEXIT | ISPARENT | CHECKED, SHEET,1,5,10,131,100\n"
+		"5,6,200,TOUCHEXIT | ISPARENT, SHEET,2,5,10,131,100\n"
+		"6,10,400, TOUCHEXIT | ISPARENT, SHEET,3,5,10,131,100\n"
+		"10,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+		"50,60,,NOSELECT, ODBUTTON,4,142,65,45,45\n"
+		"60,61,,,ICON,5,10,114,20,20\n"
+		"61,62,,,LTEXT,6,30,116,100,6\n"
+		"62,,,,LTEXT,7,30,122,100,6\n"
+		"100,101,,,LTEXT,8,10,30,60,8\n"
+		"101,102,,,RANGEINPUT,9,20,40,100,10\n"
+		"102,103,,,LTEXT,10,10,55,60,8\n"
+		"103,104,,,RANGEINPUT,11,20,65,100,10\n"
+		"104,105,,,LTEXT,12,10,80,60,8\n"
+		"105,,,,RANGEINPUT,13,20,90,100,10\n"
+		"200,201,,,LTEXT,14,25,30,60,8\n"
+		"201,202,,,CHECKBOX,15,30,55,60,8\n"
+		"202,203,,TOUCHEXIT,CHECKBOX,16,30,65,60,8\n"
+		"203,204,,TOUCHEXIT,CHECKBOX,17,30,45,60,8\n"
+		"204,205,,TOUCHEXIT,CHECKBOX,18,30,75,60,8\n"
+		"205,,,TOUCHEXIT,CHECKBOX,19,30,85,60,8\n"
+		"400,410,,,LTEXT,20,20,30,60,8\n"
+		"410,411,,EXRADIO,ODBUTTON,21,20,42,25,25\n"
+		"411,412,,EXRADIO,ODBUTTON,21,45,42,25,25\n"
+		"412,,,LASTOBJ | EXRADIO,ODBUTTON,21,70,42,25,25";
+
 bool
 Scatt3D::PropertyDlg()
 {
@@ -5369,37 +5576,16 @@ Scatt3D::PropertyDlg()
 	TabSHEET tab3 = {50, 75, 10, "Axes"};
 	char text1[100], text2[100], text3[100];
 	int icon = ICO_INFO;
-	DlgInfo Dlg3D[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 142, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 142, 25, 45, 12},
-		{3, 50, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
-		{4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 131, 100},
-		{5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 131, 100},
-		{6, 10, 400, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 131, 100},
-		{10, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
-		{50, 60, 0, NOSELECT, ODBUTTON, (void*)(OD_AxisDesc3D), 142, 65, 45, 45},
-		{60, 61, 0, 0x0L, ICON, (void*)&icon, 10, 114, 20, 20},
-		{61, 62, 0, 0x0L, LTEXT, (void*)"Use [arrow keys], [shift]+[arrow key],", 30, 116, 100, 6},
-		{62, 0, 0, 0x0L, LTEXT, (void*)"and [r], [R], [l] or [L] to rotate graph.", 30, 122, 100, 6},
-		{100, 101, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 30, 60, 8},
-		{101, 102, 0, 0x0L, RANGEINPUT, text1, 20, 40, 100, 10},
-		{102, 103, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 55, 60, 8},
-		{103, 104, 0, 0x0L, RANGEINPUT, text2, 20, 65, 100, 10},
-		{104, 105, 0, 0x0L, LTEXT, (void*)"range for Z Data", 10, 80, 60, 8},
-		{105, 0, 0, 0x0L, RANGEINPUT, text3, 20, 90, 100, 10},
-		{200, 201, 0, 0x0L, LTEXT, (void*)"select style:", 25, 30, 60, 8},
-		{201, 202, 0, 0x0L, CHECKBOX, (void*)" balls", 30, 55, 60, 8},
-		{202, 203, 0, TOUCHEXIT, CHECKBOX, (void*)" columns", 30, 65, 60, 8},
-		{203, 204, 0, TOUCHEXIT, CHECKBOX, (void*)" line", 30, 45, 60, 8},
-		{204, 205, 0, TOUCHEXIT, CHECKBOX, (void*)" drop lines", 30, 75, 60, 8},
-		{205, 0, 0, TOUCHEXIT, CHECKBOX, (void*)" arrows", 30, 85, 60, 8},
-		{400, 410, 0, 0x0L, LTEXT, (void*)"select template:", 20, 30, 60, 8},
-		{410, 411, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 20, 42, 25, 25},
-		{411, 412, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 45, 42, 25, 25},
-		{412, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 70, 42, 25, 25}};
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)(OD_AxisDesc3D), (void*)&icon,
+		(void*)"Use [arrow keys], [shift]+[arrow key],", (void*)"and [r], [R], [l] or [L] to rotate graph.",
+		(void*)"range for X Data", (void*)text1, (void*)"range for Y Data", (void*)text2,
+		(void*)"range for Z Data", (void*)text3, (void*)"select style:", (void*)" balls", (void*)" columns",
+		(void*)" line", (void*)" drop lines", (void*)" arrows", (void*)"select template:", 
+		(void*)(OD_AxisTempl3D)};
+	DlgInfo *Dlg3D = CompileDialog(Dlg3DTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, width, height, n1, n2, n3, ic = 0;
+	int res, n1, n2, n3, ic = 0;
 	int i, j, k, l, m, n, i2, j2, k2, l2, m2;
 	double x, y, z, bar_w, bar_d, rad;
 	bool bRet = false, bContinue = false;
@@ -5407,13 +5593,10 @@ Scatt3D::PropertyDlg()
 	fPOINT3D pos1, pos2;
 
 	if(!data || !parent)return false;
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);		sprintf(text2, "b1:b%d", height);
-	sprintf(text3, "c1:c%d", height);
+	UseRangeMark(data, 1, text1, text2, text3);
 	if(!(Dlg = new DlgRoot(Dlg3D)))return false;
 	Dlg->SetCheck(410 + AxisTempl3D, 0L, true);
-	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);
-	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
+	Dlg->ItemCmd(101, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(103, CMD_SET_DATAOBJ, data);
 	Dlg->ItemCmd(105, CMD_SET_DATAOBJ, data);
 	for(i = 0; i < 5; i++) Dlg->SetCheck(201+i, 0L, (c_flags & (1<<i))!=0);
 	if(c_flags == 0x2000) {
@@ -5537,9 +5720,8 @@ Scatt3D::PropertyDlg()
 			" data triplets!");
 		bRet = true;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
-	if(rX) delete rX;	if(rY) delete rY;	if(rZ) delete rZ;
+	CloseDlgWnd(hDlg);		delete Dlg;			free(Dlg3D);
+	if(rX) delete rX;		if(rY) delete rY;	if(rZ) delete rZ;
 	return bRet;
 }
 
@@ -5666,9 +5848,9 @@ FitFunc::PropertyDlg()
 		{155, 200, 0, 0x0L, EDVAL1, &iter, 119, 118, 25, 10},
 		{200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 84, 122, 30},
 		{400, 401, 0, 0x0L, LTEXT, (void*)"range for X Data", 10, 30, 60, 8},
-		{401, 402, 0, 0x0L, RANGEINPUT, (void*)ssXref, 20, 40, 100, 10},
+		{401, 402, 0, 0x0L, RANGEINPUT, (void*)text1, 20, 40, 100, 10},
 		{402, 403, 0, 0x0L, LTEXT, (void*)"range for Y Data", 10, 55, 60, 8},
-		{403, 404, 0, 0x0L, RANGEINPUT, (void*)ssYref, 20, 65, 100, 10},
+		{403, 404, 0, 0x0L, RANGEINPUT, (void*)text2, 20, 65, 100, 10},
 		{404, 405, 0, CHECKED, CHECKBOX, (void*)"draw symbols", 20, 95, 60, 8},
 		{405, 0, 0, HIDDEN, LTEXT, 0L, 20, 95, 60, 8},
 		{500, 550, 501, CHECKED, GROUP, 0L, 0, 0, 0, 0},
@@ -5689,10 +5871,12 @@ FitFunc::PropertyDlg()
 	AccRange *rX, *rY;
 	char *o_cmdxy, *o_parxy, *tmp_char;
 	anyOutput *cdisp = Undo.cdisp;
+	anyResult *ares;
 
 	if(!parent || !data) return false;
 	if(!(o_cmdxy = strdup(cmdxy))) return false;
 	if(!(o_parxy = strdup(parxy))) return false;
+	UseRangeMark(data, 1, text1, text2);
 	iter = (double)maxiter;
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
 	if(!(Dlg = new DlgRoot(FuncDlg))) return false;
@@ -5748,6 +5932,18 @@ FitFunc::PropertyDlg()
 					}
 				Dlg->GetValue(153, &conv);	Dlg->GetValue(155, &iter);
 				ReshapeFormula(&parxy);		ReshapeFormula(&cmdxy);
+				ares = do_formula(data, parxy);
+				if(ares->type != ET_VALUE) {
+					ErrorBox("Syntax Error in parameters.");
+					bContinue = true;	res = -1;
+					break;
+					}
+				ares = do_formula(data, cmdxy);
+				if(ares->type != ET_VALUE) {
+					ErrorBox("Syntax Error in formula.");
+					bContinue = true;	res = -1;
+					break;
+					}
 				i = do_fitfunc(data, text1, text2, 0L, &parxy, cmdxy, conv, (int)iter, &chi2);
 				Dlg->SetText(102, parxy);
 				if(i >1 || res == 7) {
@@ -5834,14 +6030,6 @@ FitFunc::PropertyDlg()
 				Undo.ValInt(parent, (int*)&dirty, undo_flags);
 				Command(CMD_MRK_DIRTY, 0L, 0L);
 				}
-//			Dlg->GetText(200, TmpTxt);
-//			if(cmdxy && strcmp(cmdxy, TmpTxt)) {
-//				Undo.String(this, &cmdxy, undo_flags);
-//				free(cmdxy);	cmdxy = strdup(TmpTxt); undo_flags |= UNDO_CONTINUE;
-//				}
-//			if(undo_flags & UNDO_CONTINUE) Update(0L, UNDO_CONTINUE);
-//			cmdxy = strdup(TmpTxt);
-//			bRet = Update(0L, 0L);
 			OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&newLine, 0);
 			if(cmpLineDEF(&Line, &newLine)) {
 				Undo.Line(parent, &Line, undo_flags);	undo_flags |= UNDO_CONTINUE;
@@ -5859,19 +6047,22 @@ FitFunc::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Create a three dimensional graph
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *AddPlot3Dtmpl =
+		"1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
+		"2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
+		"3,,560,ISPARENT | CHECKED,GROUPBOX,1,5,10,140,70\n"
+		"560,561,,EXRADIO | CHECKED,ODBUTTON,2,12,20,25,25\n"
+		"561,562,,EXRADIO,ODBUTTON,2,37,20,25,25\n"
+		"562,563,,EXRADIO,ODBUTTON,2,62,20,25,25\n"
+		"563,564,,EXRADIO,ODBUTTON,2,87,20,25,25\n"
+		"564,565,,EXRADIO,ODBUTTON,2,112,20,25,25\n"
+		"565,,,LASTOBJ | EXRADIO,ODBUTTON,2,12,45,25,25";
+
 bool
 Plot3D::AddPlot(int family)
 {
-	DlgInfo PlotsDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
-		{3, 0, 560, ISPARENT | CHECKED, GROUPBOX, (void *)"  select template  ", 5, 10, 140, 70},
-		{560, 561, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 12, 20, 25, 25},
-		{561, 562, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 37, 20, 25, 25},
-		{562, 563, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 62, 20, 25, 25},
-		{563, 564, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 87, 20, 25, 25},
-		{564, 565, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 112, 20, 25, 25},
-		{565, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 12, 45, 25, 25}};
+	void *dyndata[] = {(void *)"  select template  ", (void*)(OD_PlotTempl)};
+	DlgInfo *PlotsDlg = CompileDialog(AddPlot3Dtmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
 	int res, cSel = 560;
@@ -5887,26 +6078,27 @@ Plot3D::AddPlot(int family)
 		case 560:	case 561:	case 562:	case 563:	case 564:	case 565:
 			if(res == cSel) res = 1;
 			else {
-				cSel = res;
-				res = -1;
+				cSel = res;		res = -1;
 				}
 			break;
 			}
 		}while (res < 0);
 	if(res == 1){						//OK pressed
-		if(Dlg->GetCheck(560)) p = new Scatt3D(this, data, 0x01);
-		else if(Dlg->GetCheck(561)) p = new Scatt3D(this, data, 0x02);
-		else if(Dlg->GetCheck(562)) p = new Scatt3D(this, data, 0x04);
-		else if(Dlg->GetCheck(563)) p = new BubblePlot3D(this, data);
-		else if(Dlg->GetCheck(564)) p = new Scatt3D(this, data, 0x2000);
-		else if(Dlg->GetCheck(565)) p = new Func3D(this, data);
+		switch (cSel) {
+		case 560:		p = new Scatt3D(this, data, 0x01);			break;
+		case 561:		p = new Scatt3D(this, data, 0x02);			break;
+		case 562:		p = new Scatt3D(this, data, 0x04);			break;
+		case 563:		p = new BubblePlot3D(this, data);			break;
+		case 564:		p = new Scatt3D(this, data, 0x2000);		break;
+		case 565:		p = new Func3D(this, data);					break;
+		default:		p = 0L;										break;
+			}
 		if(p && p->PropertyDlg()) {
 			if(!(bRet = Command(CMD_DROP_PLOT, p, (anyOutput *)NULL))) delete p;
 			}
 		else if(p) delete p;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;		free(PlotsDlg);
 	return bRet;
 }
 
@@ -5927,8 +6119,39 @@ Plot3D::PropertyDlg()
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Create a 2.5 dimensional chart
+// Create a 2.5 dimensional bar chart
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *Base25D_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,100,ISPARENT | CHECKED,SHEET,1,5,10,140,100\n"
+		"11,12,200,ISPARENT,SHEET,2,5,10,140,100\n"
+		"12,20,300,ISPARENT,SHEET,3,5,10,140,100\n"
+		"20,,,CHECKED,CHECKPIN,0,5,0,12,8\n"
+		"100,101,,,LTEXT,4,15,30,60,8\n"
+		"101,152,,,RANGEINPUT,5,25,40,100,10\n"
+		"152,153,,ISPARENT | CHECKED,GROUPBOX,6,12,60,128,45\n"
+		"153,154,,,LTEXT,0,25,65,60,8\n"
+		"154,155,,,RANGEINPUT,0,25,75,100,10\n"
+		"155,156,,,PUSHBUTTON,-8,95,87,30,12\n"
+		"156,,,,PUSHBUTTON,-9,60,87,35,12\n"
+		"200,201,,,LTEXT,7,20,35,80,8\n"
+		"201,202,,,RTEXT,8,48,45,13,8\n"
+		"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";
 bool
 Chart25D::PropertyDlg()
 {
@@ -5940,38 +6163,13 @@ Chart25D::PropertyDlg()
 	static DWORD defcol = 0x00ffffffL;
 	char text1[100];
 	double start_z = 1.0;
-	DlgInfo Bar3D_Dlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 158, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 158, 25, 45, 12},
-		{3, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
-		{10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 140, 100},
-		{11, 12, 200, ISPARENT, SHEET, &tab2, 5, 10, 140, 100},
-		{12, 20, 300, ISPARENT, SHEET, &tab3, 5, 10, 140, 100},
-		{20, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
-		{100, 101, 0, 0x0L, LTEXT, (void*)"range for common x values", 15, 30, 60, 8},
-		{101, 152, 0, 0x0L, RANGEINPUT, text1, 25, 40, 100, 10},
-		{152, 153, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for y values ", 12, 60, 128, 45},
-		{153, 154, 0, 0x0L, LTEXT, 0L, 25, 65, 60, 8},
-		{154, 155, 0, 0x0L, RANGEINPUT, 0L, 25, 75, 100, 10},
-		{155, 156, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 95, 87, 30, 12},
-		{156, 0, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 60, 87, 35, 12},
-		{200, 201, 0, 0x0L, LTEXT, (void*)"distances:", 20, 35, 80, 8},
-		{201, 202, 0, 0x0L, RTEXT, (void*)"start z =", 48, 45, 13, 8},
-		{202, 203, 0, 0x0L, EDVAL1, &start_z, 65, 45, 25, 10},
-		{203, 204, 0, 0x0L, RTEXT, (void*)"step =", 48, 57, 13, 8},
-		{204, 0, 0, 0x0L, EDVAL1, &dspm.fz, 65, 57, 25, 10},
-		{300, 301, 0, CHECKED, RADIO1, (void*)" common color for columns:", 15, 35, 80, 9},
-		{301, 302, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)defcol, 110, 35, 20, 10},
-		{302, 303, 0, 0x0L, RADIO1, (void*)" increment color scheme:", 15, 55, 80, 9},
-		{303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[0], 25, 70, 10, 10},
-		{304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[1], 37, 70, 10, 10},
-		{305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[2], 49, 70, 10, 10},
-		{306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[3], 61, 70, 10, 10},
-		{307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[4], 73, 70, 10, 10},
-		{308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[5], 85, 70, 10, 10},
-		{309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[6], 97, 70, 10, 10},
-		{310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[7], 109, 70, 10, 10},
-		{500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
+		(void*)text1, (void*)" ranges for y values ", (void*)"distances:", (void*)"start z =", 
+		(void*)&start_z, (void*)"step =", (void*)&dspm.fz, (void*)" common color for columns:",
+		(void*)&defcol, (void*)" increment color scheme:", (void*)&colarr[0], (void*)&colarr[1],
+		(void*)&colarr[2], (void*)&colarr[3], (void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6],
+		(void*)&colarr[7]};
+	DlgInfo *Bar3D_Dlg = CompileDialog(Base25D_DlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
 	int i, ic, res, width, height, currYR=0, maxYR=0, nx=0, ny, rx, cx, ry, cy, oax;
@@ -6086,10 +6284,8 @@ Chart25D::PropertyDlg()
 		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
 		free(rd);
 		}
-	if(rX) delete rX;		if(rY) delete rY;
-	if(bRet) {
-		Command(CMD_MRK_DIRTY, 0L, 0L);
-		}
+	if(rX) delete rX;		if(rY) delete rY;		free(Bar3D_Dlg);
+	if(bRet) Command(CMD_MRK_DIRTY, 0L, 0L);
 	return bRet;
 }
 
@@ -6107,38 +6303,13 @@ Ribbon25D::PropertyDlg()
 	static DWORD defcol = 0x00ffffffL;
 	char text1[100];
 	double start_z = 1.0;
-	DlgInfo Bar3D_Dlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 158, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 158, 25, 45, 12},
-		{3, 0, 10, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
-		{10, 11, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 140, 100},
-		{11, 12, 200, ISPARENT, SHEET, &tab2, 5, 10, 140, 100},
-		{12, 20, 300, ISPARENT, SHEET, &tab3, 5, 10, 140, 100},
-		{20, 0, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
-		{100, 101, 0, 0x0L, LTEXT, (void*)"range for common x values", 15, 30, 60, 8},
-		{101, 152, 0, 0x0L, RANGEINPUT, text1, 25, 40, 100, 10},
-		{152, 153, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" ranges for y values ", 12, 60, 128, 45},
-		{153, 154, 0, 0x0L, LTEXT, 0L, 25, 65, 60, 8},
-		{154, 155, 0, 0x0L, RANGEINPUT, 0L, 25, 75, 100, 10},
-		{155, 156, 0, 0x0L, PUSHBUTTON, (void*)"Next >>", 95, 87, 30, 12},
-		{156, 0, 0, 0x0L, PUSHBUTTON, (void*)"<< Prev.", 60, 87, 35, 12},
-		{200, 201, 0, 0x0L, LTEXT, (void*)"distances:", 20, 35, 80, 8},
-		{201, 202, 0, 0x0L, RTEXT, (void*)"start z =", 48, 45, 13, 8},
-		{202, 203, 0, 0x0L, EDVAL1, &start_z, 65, 45, 25, 10},
-		{203, 204, 0, 0x0L, RTEXT, (void*)"step =", 48, 57, 13, 8},
-		{204, 0, 0, 0x0L, EDVAL1, &dspm.fz, 65, 57, 25, 10},
-		{300, 301, 0, CHECKED, RADIO1, (void*)" common color for ribbons:", 15, 35, 80, 9},
-		{301, 302, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)defcol, 110, 35, 20, 10},
-		{302, 303, 0, 0x0L, RADIO1, (void*)" increment color scheme:", 15, 55, 80, 9},
-		{303, 304, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[0], 25, 70, 10, 10},
-		{304, 305, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[1], 37, 70, 10, 10},
-		{305, 306, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[2], 49, 70, 10, 10},
-		{306, 307, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[3], 61, 70, 10, 10},
-		{307, 308, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[4], 73, 70, 10, 10},
-		{308, 309, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[5], 85, 70, 10, 10},
-		{309, 310, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[6], 97, 70, 10, 10},
-		{310, 0, 0, OWNDIALOG | TOUCHEXIT, COLBUTTON, (void*)colarr[7], 109, 70, 10, 10},
-		{500, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"range for common x values",
+		(void*)text1, (void*)" ranges for y values ", (void*)"distances:", (void*)"start z =", 
+		(void*)&start_z, (void*)"step =", (void*)&dspm.fz, (void*)" common color for ribbons:",
+		(void*)&defcol, (void*)" increment color scheme:", (void*)&colarr[0], (void*)&colarr[1],
+		(void*)&colarr[2], (void*)&colarr[3], (void*)&colarr[4], (void*)&colarr[5], (void*)&colarr[6],
+		(void*)&colarr[7]};
+	DlgInfo *Bar3D_Dlg = CompileDialog(Base25D_DlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
 	int i, res, width, height, currYR=0, maxYR=0, nx=0, ny, oax;
@@ -6232,10 +6403,8 @@ Ribbon25D::PropertyDlg()
 		for (i = 0; i < maxYR; i++)	if(rd[i]) free(rd[i]);
 		free(rd);
 		}
-	if(rX) delete rX;		if(rY) delete rY;
-	if(bRet) {
-		Command(CMD_MRK_DIRTY, 0L, 0L);
-		}
+	if(rX) delete rX;		if(rY) delete rY;		free(Bar3D_Dlg);
+	if(bRet) Command(CMD_MRK_DIRTY, 0L, 0L);
 	return bRet;
 }
 
@@ -6276,7 +6445,7 @@ BubblePlot3D::PropertyDlg()
 		{412, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 70, 42, 25, 25}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int i, res, width, height, count;
+	int i, res, count;
 	int cx, rx, cy, ry, cz, rz, cr, rr, s_type = 5;
 	bool bRet = false;
 	double fx, fy, fz, fr;
@@ -6286,9 +6455,7 @@ BubblePlot3D::PropertyDlg()
 	int etracc[] = {101, 103, 105, 151};
 
 	if(!data || !parent)return false;
-	data->GetSize(&width, &height);
-	sprintf(text1, "a1:a%d", height);		sprintf(text2, "b1:b%d", height);
-	sprintf(text3, "c1:c%d", height);		sprintf(text4, "d1:d%d", height);
+	UseRangeMark(data, 1, text1, text2, text3, text4);
 	if(!(Dlg = new DlgRoot(BubDlg3D)))return false;
 	for(i = 0; i < 4; i++) Dlg->ItemCmd(etracc[i], CMD_SET_DATAOBJ, data);
 	rX = rY = rZ = rR = 0L;
@@ -6337,7 +6504,7 @@ BubblePlot3D::PropertyDlg()
 					}
 				}
 			sc_plot = new Scatt3D(this, data, Balls, count);
-			if(parent->Id == GO_PLOT3D || parent->Id == GO_FUNC3D) {
+			if(parent->Id == GO_PLOT3D || parent->Id == GO_FUNC3D || parent->Id == GO_FITFUNC3D) {
 				if(!(parent->Command(CMD_DROP_PLOT, sc_plot, 0L))) delete(sc_plot);
 				bRet = true;
 				}
@@ -6456,6 +6623,7 @@ Func3D::PropertyDlg()
 			Dlg->GetValue(108, &z1);		Dlg->GetValue(109, &z2);
 			Dlg->GetValue(110, &zstep);		type = Dlg->GetCheck(305) ? 0 : 1;
 			if(Dlg->GetText(200, TmpTxt)) {
+				if(cmdxy) free(cmdxy);
 				cmdxy = strdup(TmpTxt);		ReshapeFormula(&cmdxy);
 				bRet = Update();
 				}
@@ -6486,6 +6654,247 @@ Func3D::PropertyDlg()
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Fit data to a 3D function
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool
+FitFunc3D::PropertyDlg()
+{
+	TabSHEET tab1 = {0, 22, 10, "Data"};
+	TabSHEET tab2 = {22, 59, 10, "Function"};
+	TabSHEET tab3 = {59, 87, 10, "Style"};
+	char text1[100], text2[100], text3[100];
+	FillDEF newFill;
+	double iter;
+//	bool bNew = (dl == 0L);
+	bool bNew = true;
+	DlgInfo FuncDlg[] = {
+		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 160, 10, 45, 12},
+		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 160, 25, 45, 12},
+		{3, 10, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
+		{4, 5, 400, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 149, 134},
+		{5, 6, 100, ISPARENT, SHEET, &tab2, 5, 10, 149, 134},
+		{6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 149, 134},
+		{7, 0, 0, 0x0L, PUSHBUTTON, (void*)"Fit", 160, 132, 45, 12},
+		{10, 50, 0, CHECKED, CHECKPIN, 0L, 5, 0, 12, 8},
+		{50, 0, 0, NOSELECT, ODBUTTON, (void*)(OD_AxisDesc3D), 160, 65, 45, 45},
+		{100, 101, 0, 0x0L, LTEXT, (void*)"fit function by nonlinear regression", 10, 24, 100, 8},
+		{101, 102, 0, 0x0L, LTEXT, (void*)"parameters and initial values:", 10, 34, 100, 8},
+		{102, 150, 0, 0x0L, TEXTBOX, (void*)param, 22, 44, 122, 30},
+		{150, 151, 0, 0x0L, LTEXT, (void*)"function, y=f(x,z):", 10, 77, 10, 8}, 
+		{151, 152, 0, 0x0L, RTEXT, (void*)"y=", 10, 91, 10, 8}, 
+		{152, 153, 0, 0x0L, RTEXT, (void*)"converg.:", 20, 128, 26, 8}, 
+		{153, 154, 0, 0x0L, EDVAL1, &conv, 46, 128, 25, 10},
+		{154, 155, 0, 0x0L, RTEXT, (void*)"iterations:", 72, 128, 47, 8}, 
+		{155, 200, 0, 0x0L, EDVAL1, &iter, 119, 128, 25, 10},
+		{200, 0, 0, 0x0L, TEXTBOX, (void*)cmdxy, 22, 89, 122, 30},
+		{300, 301, 550, CHECKED, GROUPBOX, (void*)" grid ", 10, 40, 140, 100},
+		{301, 305, 350, HIDDEN | CHECKED, GROUPBOX, (void*)" surface ", 10, 40, 140, 100},
+		{305, 306, 0, CHECKED | TOUCHEXIT, RADIO1, (void*) " grid lines", 15, 25, 50, 10},
+		{306, 0, 0, TOUCHEXIT, RADIO1, (void*) " surface", 85, 25, 50, 10},
+		{350, 351, 0, 0x0L, RTEXT, (void*)"grid line width", 38, 50, 40, 8},
+		{351, 352, 0, 0x0L, EDVAL1, &Line.width, 80, 50, 25, 10},
+		{352, 353, 0, 0x0L, LTEXT, (void*)Units[defs.cUnits].display, 107, 50, 20, 8},
+		{353, 354, 0, 0x0L, RTEXT, (void*)"grid line color", 38, 62, 40, 8},
+		{354, 355, 0, OWNDIALOG, COLBUTTON, (void *)Line.color, 80, 62, 25, 10},
+		{355, 356, 0, 0x0L, RTEXT,(void*)"plane color" , 38, 74, 40, 8},
+		{356, 0, 0, OWNDIALOG, SHADE3D, &newFill, 80, 74, 25, 10},
+		{400, 401, 0, 0x0L, LTEXT, (void*)"range for X data", 10, 30, 60, 8},
+		{401, 402, 0, 0x0L, RANGEINPUT, (void*)text1, 20, 40, 100, 10},
+		{402, 403, 0, 0x0L, LTEXT, (void*)"range for Y data", 10, 55, 60, 8},
+		{403, 404, 0, 0x0L, RANGEINPUT, (void*)text2, 20, 65, 100, 10},
+		{404, 405, 0, 0x0L, LTEXT, (void*)"range for Z data", 10, 80, 60, 8},
+		{405, 406, 0, 0x0L, RANGEINPUT, (void*)text3, 20, 90, 100, 10},
+		{406, 407, 0, CHECKED, CHECKBOX, (void*)"draw symbols", 20, 110, 60, 8},
+		{407, 0, 0, HIDDEN, LTEXT, 0L, 20, 110, 60, 8},
+		{500, 550, 501, CHECKED, GROUP, 0L, 0, 0, 0, 0},
+		{501, 502, 0, 0x0L, RTEXT, (void*)"plot x=", 10, 30, 28, 8}, 
+		{502, 503, 0, 0x0L, EDVAL1, &x1, 38, 30, 25, 10},
+		{503, 504, 0, 0x0L, RTEXT, (void*)"until", 61, 30, 17, 8}, 
+		{504, 505, 0, 0x0L, EDVAL1, &x2, 78, 30, 25, 10},
+		{505, 506, 0, 0x0L, RTEXT, (void*)"step", 102, 30, 17, 8}, 
+		{506, 0, 0, 0x0L, EDVAL1, &xstep, 119, 30, 25, 10},
+		{550, 0, 0, LASTOBJ | NOSELECT, ODBUTTON, (void*)OD_linedef, 15, bNew ? 45:45, 130, 100}};
+	DlgRoot *Dlg;
+	void *hDlg;
+	int res, undo_level = *Undo.pcb, i, j, k, l, m, n, ns = 0;
+	bool bRet = false, bContinue = false;
+	DWORD undo_flags = 0L;
+	LineDEF newLine;
+	double x, y, z, o_x1, n_x1, o_x2, n_x2, o_xstep, n_xstep, n_chi2=chi2, rad;
+	AccRange *rX, *rY, *rZ;
+	char *o_cmdxy, *o_param;
+	anyOutput *cdisp = Undo.cdisp;
+	anyResult *ares;
+	Sphere **Balls;
+
+	if(!parent || !data) return false;
+	UseRangeMark(data, 1, text1, text2, text3);
+	if(!(o_cmdxy = strdup(cmdxy))) return false;
+	if(!(o_param = strdup(param))) return false;
+	rX = rY = rZ = 0L;			iter = (double)maxiter;
+	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+	memcpy(&newFill, &Fill, sizeof(FillDEF));
+	memcpy(&newLine, &Line, sizeof(LineDEF));
+	if(!(Dlg = new DlgRoot(FuncDlg))) return false;
+	if(!bNew){
+		Dlg->ShowItem(10, false);		Dlg->Activate(401, false);
+		Dlg->Activate(403, false);		Dlg->Activate(405, false);		
+		Dlg->SetCheck(6, 0L, true);
+		Dlg->SetCheck(4, 0L, false);	Dlg->ShowItem(404, false);
+		if(chi2 > 0.0) {
+			sprintf(TmpTxt, "Chi 2 = %g", chi2);
+			Dlg->SetText(405,TmpTxt);	Dlg->ShowItem(405, true);
+			}
+		}
+	else {
+		Dlg->ItemCmd(401, CMD_SET_DATAOBJ, data);	Dlg->ItemCmd(403, CMD_SET_DATAOBJ, data);
+		Dlg->ItemCmd(405, CMD_SET_DATAOBJ, data);	Dlg->ShowItem(500, false);
+		}
+	Dlg->GetValue(502, &o_x1);		n_x1 = o_x1;
+	Dlg->GetValue(504, &o_x2);		n_x2 = o_x2;
+	Dlg->GetValue(506, &o_xstep);	n_xstep = o_xstep;
+	hDlg = CreateDlgWnd("Fit Function to Data in 3D Space", 50, 50, 426, 320, Dlg, 0x0L);
+	if(bNew) Dlg->SetCheck(4, 0L, true);
+	do{
+		LoopDlgWnd();
+		res = Dlg->GetResult();
+		switch (res) {
+		case 0:
+			if(Dlg->GetCheck(10)) res = -1;
+			if(bContinue) res = -1;
+			bContinue = false;
+			break;
+		case 305:		case 306:
+			if(Dlg->GetCheck(305)) {
+				Dlg->ShowItem(300, true);	Dlg->ShowItem(301, false);
+				}
+			else {
+				Dlg->ShowItem(300, false);	Dlg->ShowItem(301, true);
+				}
+			Dlg->DoPlot(0L);
+			res = -1;
+			break;
+		case 1:
+			if(!bNew){
+				if(Dlg->GetText(102, TmpTxt) && param) {
+					free(param);	param = strdup(TmpTxt);
+					}
+				if(Dlg->GetText(200, TmpTxt) && cmdxy) {
+					free(cmdxy);	cmdxy = strdup(TmpTxt);
+					}
+				ReshapeFormula(&param);		ReshapeFormula(&cmdxy);
+				dirty = true;
+				break;
+				}
+		case 7:								//Start: do nonlinear regression
+			Undo.SetDisp(cdisp);
+			if(!Dlg->GetText(401, text1) || !Dlg->GetText(403, text2) || !Dlg->GetText(405, text3)) {
+				Dlg->SetCheck(4, 0L, true);			bContinue = true;
+				InfoBox("Invalid or missing range");
+				res = -1;
+				}
+			else if(Dlg->GetCheck(5)) {		//  the function tab must be shown
+				if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_WAIT, true);
+				if(Dlg->GetText(102, TmpTxt) && param) {
+					free(param);	param = strdup(TmpTxt);
+					}
+				if(Dlg->GetText(200, TmpTxt) && cmdxy) {
+					free(cmdxy);	cmdxy = strdup(TmpTxt);
+					}
+				Dlg->GetValue(153, &conv);	Dlg->GetValue(155, &iter);
+				ReshapeFormula(&param);		ReshapeFormula(&cmdxy);
+				ares = do_formula(data, param);
+				if(ares->type != ET_VALUE) {
+					ErrorBox("Syntax Error in parameters.");
+					bContinue = true;	res = -1;
+					break;
+					}
+				ares = do_formula(data, cmdxy);
+				if(ares->type != ET_VALUE) {
+					ErrorBox("Syntax Error in formula.");
+					bContinue = true;	res = -1;
+					break;
+					}
+				i = do_fitfunc(data, text1, text2, text3, &param, cmdxy, conv, (int)iter, &chi2);
+				Dlg->SetText(102, param);
+				if(i >1 || res == 7) {
+					sprintf(TmpTxt, "The Levenberg-Marquart algorithm\nexited after %d iterations.\n\nChi2 = %g", i, chi2);
+					InfoBox(TmpTxt);
+					}
+				bContinue = true;
+				if(res == 7) res = -1;
+				if(Dlg->CurrDisp) Dlg->CurrDisp->MouseCursor(MC_ARROW, true);
+				}
+			else {							//diplay function tab first
+				Dlg->SetCheck(5, 0L, true);
+				res = -1;
+				}
+			break;
+			}
+		}while (res < 0);
+	Undo.SetDisp(cdisp);
+	while(*Undo.pcb > undo_level)	Undo.Pop(cdisp);
+	if(res == 1 && (rX=new AccRange(text1)) && (rY=new AccRange(text2)) && (rZ=new AccRange(text3))){
+		//OK pressed
+		if(bNew) {						//create function
+			if(Dlg->GetCheck(305)) {
+				type = 0;
+				OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&Line, 0);
+				}
+			else {
+				type = 1;
+				memcpy(&Fill, &newFill, sizeof(FillDEF));
+				Dlg->GetValue(401, &Line.width);
+				Dlg->GetColor(404, &Line.color);
+				Line.pattern = 0L;			Line.patlength = 1;
+				}
+			rX->GetFirst(&i, &j);		rX->GetNext(&i, &j);
+			rY->GetFirst(&k, &l);		rY->GetNext(&k, &l);
+			rZ->GetFirst(&m, &n);		rZ->GetNext(&m, &n);
+			do {
+				if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && data->GetValue(n, m, &z))
+					CheckBounds3D(x,y,z);
+				}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
+			x1 = xBounds.fx;		x2 = xBounds.fy;		xstep = (x2-x1)/10.0;
+			z1 = zBounds.fx;		z2 = zBounds.fy;		zstep = (z2-z1)/10.0;
+			if(Dlg->GetText(102, TmpTxt)) {
+				if(param) free(param);	param = strdup(TmpTxt);		ReshapeFormula(&param);
+				}
+			if(Dlg->GetText(200, TmpTxt)) {
+				if(cmdxy) free(cmdxy);	cmdxy = strdup(TmpTxt);		ReshapeFormula(&cmdxy);
+				}
+			if((bRet = Update()) && gob && nPlots == 1 && (Balls=(Sphere**)calloc(rX->CountItems(), sizeof(Sphere*)))) {
+				rX->GetFirst(&i, &j);		rX->GetNext(&i, &j);
+				rY->GetFirst(&k, &l);		rY->GetNext(&k, &l);
+				rZ->GetFirst(&m, &n);		rZ->GetNext(&m, &n);
+				rad = defs.GetSize(SIZE_SYMBOL);
+				do {
+					if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y) && data->GetValue(n, m, &z)) {
+						Balls[ns++] = new Sphere(this, data, 0, x, y, z, rad, i, j, k, l, m, n);
+						}
+					}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l) && rZ->GetNext(&m, &n));
+				if(ns) {
+					plots[1] = (GraphObj*) new Scatt3D(this, data, Balls, ns);
+					nPlots = 2;
+					}
+				else free(Balls);
+				}
+			}
+		else {							//edit existing function
+			Dlg->GetValue(102, &x1);		Dlg->GetValue(104, &x2);
+			Dlg->GetValue(106, &xstep);
+			Dlg->GetValue(108, &z1);		Dlg->GetValue(109, &z2);
+			Dlg->GetValue(110, &zstep);		type = Dlg->GetCheck(305) ? 0 : 1;
+			InfoBox("Not Implemented");
+			}
+		}
+	if(rX) delete(rX);		if(rY) delete(rY);		if(rZ) delete(rZ);
+	CloseDlgWnd(hDlg);
+	delete Dlg;
+	return bRet;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Grid line properties
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 bool
@@ -6764,28 +7173,35 @@ Tick::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Axis properties dialog
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *ssTickTmpl =
+		"1,2,,DEFAULT, PUSHBUTTON,-1,113,10,45,12\n"
+		"2,3,,, PUSHBUTTON,-2,113,25,45,12\n"
+		"3,4,,, LTEXT,1,5,10,100,9\n"
+		"4,5,,TOUCHEXIT,RANGEINPUT,4,10,20,90,10\n"
+		"5,6,,, LTEXT,2,5, 32, 100, 9\n"
+		"6,7,,TOUCHEXIT,RANGEINPUT,5,10,42,90,10\n"
+		"7, 8,,,LTEXT,3, 5, 54, 80, 8\n"
+		"8,,,LASTOBJ | TOUCHEXIT,RANGEINPUT,6,10,64,90,10";
+
 bool
 Axis::ssTicks()
 {
-	DlgInfo TickDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 113, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 113, 25, 45, 12},
-		{3, 4, 0, 0x0L, LTEXT, (void*)"range for major tick VALUES:", 5, 10, 100, 9},
-		{4, 5, 0, 0x0L, EDTEXT, (void*)ssMATval, 10, 20, 90, 10},
-		{5, 6, 0, 0x0L, LTEXT, (void*)"range for major tick LABELS:", 5, 32, 100, 9},
-		{6, 7, 0, 0x0L, EDTEXT, (void*)ssMATlbl, 10, 42, 90, 10},
-		{7, 8, 0, 0x0L, LTEXT, (void*)"minor tick VALUES:", 5, 54, 80, 8},
-		{8, 0, 0, LASTOBJ, EDTEXT, (void*)ssMITval, 10, 64, 90, 10}};
+	void *dyndata[] ={(void*)"range for major tick VALUES:", (void*)"range for major tick LABELS:",
+		(void*)"minor tick VALUES:", (void*)ssMATval, (void*)ssMATlbl, (void*)ssMITval};
+	DlgInfo *TickDlg = CompileDialog(ssTickTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
 	int res, n, n1, n2, n3;
-	bool bRet = false, bContinue = false;
+	bool bRet = false, bContinue = true;
 	AccRange *rT, *rL, *rMT;
 
 	if(!data) return false;
 	n = n1 = n2 = n3 = 0;			rT = rL = rMT = 0L;
 	if(!(Dlg = new DlgRoot(TickDlg)))return false;
+	Dlg->ItemCmd(4, CMD_SET_DATAOBJ, data);		Dlg->ItemCmd(6, CMD_SET_DATAOBJ, data);
+	Dlg->ItemCmd(8, CMD_SET_DATAOBJ, data);
 	hDlg = CreateDlgWnd("choose ticks from spreadsheet", 50, 50, 330, 190, Dlg, 0x0L);
+	Dlg->Activate(4, true);
 	do{
 		LoopDlgWnd();
 		res = Dlg->GetResult();
@@ -6793,9 +7209,9 @@ Axis::ssTicks()
 		case 0:								// focus lost
 			if(bContinue) res = -1;
 			break;
-		case -1:
-			bContinue = false;
-			break;
+		case 4:		case 6:		case 8:
+			bContinue = true;
+			res = -1;			break;
 		case 1:
 			if(rT) delete rT;		if(rL) delete rL;		if(rMT) delete rMT;
 			n = n1 = n2 = n3 = 0;	rT = rL = rMT = 0L;
@@ -6829,7 +7245,7 @@ Axis::ssTicks()
 		bRet = true;
 		}
 	CloseDlgWnd(hDlg);
-	delete Dlg;
+	delete Dlg;			free(TickDlg);
 	if(rT) delete rT;	if(rL) delete rL;	if(rMT) delete rMT;
 	return bRet;
 }
@@ -7386,27 +7802,30 @@ Axis::PropertyDlg()
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Graph dialogs
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *AddPlotTmpl =
+		"1,2,,DEFAULT,PUSHBUTTON,-1,150,10,45,12\n"
+		"2,3,,,PUSHBUTTON,-2,150,25,45,12\n"
+		"3,,520,ISPARENT | CHECKED,GROUPBOX,1,5,10,135,95\n"
+		"520,521,,EXRADIO | CHECKED,ODBUTTON,2,10,20,25,25\n"
+		"521,522,,EXRADIO,ODBUTTON,2,35,20,25,25\n"
+		"522,523,,EXRADIO,ODBUTTON,2,60,20,25,25\n"
+		"523,524,,EXRADIO,ODBUTTON,2,85,20,25,25\n"
+		"524,525,,EXRADIO,ODBUTTON,2,110,20,25,25\n"
+		"525,526,,EXRADIO,ODBUTTON,2,10,45,25,25\n"
+		"526,528,,EXRADIO,ODBUTTON,2,35,45,25,25\n"
+		"528,529,,EXRADIO,ODBUTTON,2,60,45,25,25\n"
+		"529,530,,EXRADIO,ODBUTTON,2,85,45,25,25\n"
+		"530,531,,EXRADIO,ODBUTTON,2,110,45,25,25\n"
+		"531,532,,EXRADIO,ODBUTTON,2,10,70,25,25\n"
+		"532,540,,EXRADIO,ODBUTTON,2,35,70,25,25\n"
+		"540,541,,EXRADIO,ODBUTTON,2,60,70,25,25\n"
+		"541,,,LASTOBJ | EXRADIO,ODBUTTON, 2, 85,70,25,25";
+
 bool
 Graph::AddPlot(int family)
 {
-	DlgInfo GraphDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
-		{3, 0, 520, ISPARENT | CHECKED, GROUPBOX, (void *)"  select template  ", 5, 10, 135, 95},
-		{520, 521, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 10, 20, 25, 25},
-		{521, 522, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 35, 20, 25, 25},
-		{522, 523, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 60, 20, 25, 25},
-		{523, 524, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 85, 20, 25, 25},
-		{524, 525, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 110, 20, 25, 25},
-		{525, 526, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 10, 45, 25, 25},
-		{526, 528, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 35, 45, 25, 25},
-		{528, 529, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 60, 45, 25, 25},
-		{529, 530, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 85, 45, 25, 25},
-		{530, 531, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 110, 45, 25, 25},
-		{531, 532, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 10, 70, 25, 25},
-		{532, 540, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 35, 70, 25, 25},
-		{540, 541, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 60, 70, 25, 25},
-		{541, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 85, 70, 25, 25}};
+	void *dyndata[] = {(void *)"  select template  ",(void*)OD_PlotTempl};
+	DlgInfo *GraphDlg = CompileDialog(AddPlotTmpl, dyndata);
 	DlgRoot *Dlg;
 	void *hDlg;
 	int i, res, cSel = 520;
@@ -7465,11 +7884,92 @@ Graph::AddPlot(int family)
 			}
 		else if(p) delete p;
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;		free(GraphDlg);
 	return bRet;
 }
 
+static char *GraphDlgTmpl = 
+		"1,2,,DEFAULT, PUSHBUTTON, -1, 170,10,45,12\n"
+		"2,3,,,PUSHBUTTON, -2, 170,25,45,12\n"
+		"3,0,4,ISPARENT | CHECKED,GROUP, 0, 138,40,55,12\n"
+		"4,5,100,ISPARENT | CHECKED,SHEET, 1, 5,10,157,122\n"
+		"5,6,200,ISPARENT,SHEET, 2, 5,10,157,122\n"
+		"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"
+		"103,104,540,TOUCHEXIT | ISPARENT,SHEET, 7, 10,37,147,90\n"
+		"104,0,560, TOUCHEXIT | ISPARENT,SHEET, 8, 10,37,147,90\n"
+		"200,201,,,LTEXT, 9, 10,35,60,8\n"
+		"201,202,,,RTEXT, 10, 5,47,58,8\n"
+		"202,203,,,EDVAL1, 11, 64,47,30,10\n"
+		"203,204,,,RTEXT, -5, 95,47,10,8\n"
+		"204,205,,,EDVAL1, 12, 107,47,30,10\n"
+		"205,206,,,LTEXT, -3, 140,47,20,8\n"
+		"206,207,,,RTEXT, 13, 5,59,58,8\n"
+		"207,208,,,EDVAL1, 14, 64,59,30,10\n"
+		"208,209,,,RTEXT, -5, 95,59,10,8\n"
+		"209,210,,,EDVAL1, 15, 107,59,30,10\n"
+		"210,211,,,LTEXT, -3, 140,59,20,8\n"
+		"211,212,,,LTEXT, 16, 10,84,60,8\n"
+		"212,213,,,RTEXT, 17, 5,96,58,8\n"
+		"213,214,,,EDVAL1, 18, 64,96,30,10\n"
+		"214,215,,,RTEXT, -5, 95,96,10,8\n"
+		"215,216,,,EDVAL1, 19, 107,96,30,10\n"
+		"216,217,,,LTEXT, -3, 140,96,20,8\n"
+		"217,218,,,RTEXT, 20, 5,108,58,8\n"
+		"218,219,,,EDVAL1, 21, 64,108,30,10\n"
+		"219,220,,,RTEXT, -5, 95,108,10,8\n"
+		"220,221,,,EDVAL1, 22, 107,108,30,10\n"
+		"221,,,,LTEXT, -3, 140,108,20,8\n"
+		"300,301,,,LTEXT, 23, 20,30,60,8\n"
+		"301,400,310,CHECKED | ISPARENT, GROUP, 0L, 0,0,0,0\n"
+		"310,311,,TOUCHEXIT | CHECKED | ISRADIO, 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"
+		"314,315,,EXRADIO, ODBUTTON, 24, 120,42,25,25\n"
+		"315,316,,CHECKED | TOUCHEXIT, RADIO1, 25, 12,85,40,8\n"
+		"316,317,,TOUCHEXIT, RADIO1, 26, 12,93,40,8\n"
+		"317,318,,TOUCHEXIT, RADIO1, 27, 12,101,40,8\n"
+		"318,319,,TOUCHEXIT, CHECKBOX, 28, 80,85,40,8\n"
+		"319,,,TOUCHEXIT, CHECKBOX, 29, 80,93,40,8\n"
+		"400,,410,HIDDEN | CHECKED | ISPARENT, GROUP, 0L, 0,0,0,0\n"
+		"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"
+		"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"
+		"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"
+		"524,525,,EXRADIO, ODBUTTON, 31, 120,50,25,25\n"
+		"525,526,,EXRADIO, ODBUTTON, 31, 20,75,25,25\n"
+		"526,527,,EXRADIO, ODBUTTON, 31, 45,75,25,25\n"
+		"527,528,,EXRADIO, ODBUTTON, 31, 70,75,25,25\n"
+		"528,529,,EXRADIO, ODBUTTON, 31, 95,75,25,25\n"
+		"529,530,,EXRADIO, ODBUTTON, 31, 120,75,25,25\n"
+		"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"
+		"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"
+		"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"
+		"564,565,,EXRADIO, ODBUTTON, 31, 120,60,25,25\n"
+		"565,566,,EXRADIO, ODBUTTON, 31, 20,85,25,25\n"
+		"566,,,LASTOBJ | EXRADIO, ODBUTTON, 31, 45,85,25,25";
+
 bool
 Graph::PropertyDlg()
 {
@@ -7480,86 +7980,15 @@ Graph::PropertyDlg()
 	TabSHEET tab_B = {27, 65, 10, "XY values"};
 	TabSHEET tab_C = {65, 104, 10, "X, many Y"};
 	TabSHEET tab_D = {104, 147, 10, "XYZ values"};
-	DlgInfo GraphDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 170, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 170, 25, 45, 12},
-		{3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 138, 40, 55, 12},
-		{4, 5, 100, ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 157, 122},
-		{5, 6, 200, ISPARENT, SHEET, &tab2, 5, 10, 157, 122},
-		{6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 157, 122},
-		{100, 101, 0, 0x0L, LTEXT, (void*)"arrangement of data: select plot", 10, 25, 60, 8},
-		{101, 102, 500, TOUCHEXIT | ISPARENT, SHEET, &tab_A, 10, 37, 147, 90},
-		{102, 103, 520, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab_B, 10, 37, 147, 90},
-		{103, 104, 540, TOUCHEXIT | ISPARENT, SHEET, &tab_C, 10, 37, 147, 90},
-		{104, 0, 560, TOUCHEXIT | ISPARENT, SHEET, &tab_D, 10, 37, 147, 90},
-		{200, 201, 0, 0x0L, LTEXT, (void*)"bounding rectangle (relative to page)", 10, 35, 60, 8},
-		{201, 202, 0, 0x0L, RTEXT, (void*)"upper left corner x", 5, 47, 58, 8},
-		{202, 203, 0, 0x0L, EDVAL1, &GRect.Xmin, 64, 47, 30, 10},
-		{203, 204, 0, 0x0L, RTEXT, (void*)"y", 95, 47, 10, 8},
-		{204, 205, 0, 0x0L, EDVAL1, &GRect.Ymin, 107, 47, 30, 10},
-		{205, 206, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 47, 20, 8},
-		{206, 207, 0, 0x0L, RTEXT, (void*)"lower right x", 5, 59, 58, 8},
-		{207, 208, 0, 0x0L, EDVAL1, &GRect.Xmax, 64, 59, 30, 10},
-		{208, 209, 0, 0x0L, RTEXT, (void*)"y", 95, 59, 10, 8},
-		{209, 210, 0, 0x0L, EDVAL1, &GRect.Ymax, 107, 59, 30, 10},
-		{210, 211, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 59, 20, 8},
-		{211, 212, 0, 0x0L, LTEXT, (void*)"plotting rectangle (relative to bounding rectangle)", 10, 84, 60, 8},
-		{212, 213, 0, 0x0L, RTEXT, (void*)"upper left corner x", 5, 96, 58, 8},
-		{213, 214, 0, 0x0L, EDVAL1, &DRect.Xmin, 64, 96, 30, 10},
-		{214, 215, 0, 0x0L, RTEXT, (void*)"y", 95, 96, 10, 8},
-		{215, 216, 0, 0x0L, EDVAL1, &DRect.Ymin, 107, 96, 30, 10},
-		{216, 217, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 96, 20, 8},
-		{217, 218, 0, 0x0L, RTEXT, (void*)"lower right x", 5, 108, 58, 8},
-		{218, 219, 0, 0x0L, EDVAL1, &DRect.Xmax, 64, 108, 30, 10},
-		{219, 220, 0, 0x0L, RTEXT, (void*)"y", 95, 108, 10, 8},
-		{220, 221, 0, 0x0L, EDVAL1, &DRect.Ymax, 107, 108, 30, 10},
-		{221, 0, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 140, 108, 20, 8},
-		{300, 301, 0, 0x0L, LTEXT, (void*)"select template:", 20, 30, 60, 8},
-		{301, 400, 310, CHECKED | ISPARENT, GROUP, 0L, 0, 0, 0, 0,},
-		{310, 311, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl), 20, 42, 25, 25},
-		{311, 312, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl), 45, 42, 25, 25},
-		{312, 313, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl), 70, 42, 25, 25},
-		{313, 314, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl), 95, 42, 25, 25},
-		{314, 315, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl), 120, 42, 25, 25},
-		{315, 316, 0, CHECKED | TOUCHEXIT, RADIO1, (void*)"ticks outside", 12, 85, 40, 8},
-		{316, 317, 0, TOUCHEXIT, RADIO1, (void*)"ticks inside", 12, 93, 40, 8},
-		{317, 318, 0, TOUCHEXIT, RADIO1, (void*)"ticks symmetrical", 12, 101, 40, 8},
-		{318, 319, 0, TOUCHEXIT, CHECKBOX, (void*)"horizontal grid lines", 80, 85, 40, 8},
-		{319, 0, 0, TOUCHEXIT, CHECKBOX, (void*)"vertical grid lines", 80, 93, 40, 8},
-		{400, 0, 410, HIDDEN | CHECKED | ISPARENT, GROUP, 0L, 0, 0, 0, 0,},
-		{410, 411, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 20, 42, 25, 25},
-		{411, 412, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 45, 42, 25, 25},
-		{412, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_AxisTempl3D), 70, 42, 25, 25},
-		{500, 501, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 25, 60, 25, 25},
-		{501, 502, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 50, 60, 25, 25},
-		{502, 503, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 75, 60, 25, 25},
-		{503, 504, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 25, 85, 25, 25},
-		{504, 505, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 50, 85, 25, 25},
-		{505, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 75, 85, 25, 25},
-		{520, 521, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 20, 50, 25, 25},
-		{521, 522, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 45, 50, 25, 25},
-		{522, 523, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 70, 50, 25, 25},
-		{523, 524, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 95, 50, 25, 25},
-		{524, 525, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 120, 50, 25, 25},
-		{525, 526, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 20, 75, 25, 25},
-		{526, 527, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 45, 75, 25, 25},
-		{527, 528, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 70, 75, 25, 25},
-		{528, 529, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 95, 75, 25, 25},
-		{529, 530, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 120, 75, 25, 25},
-		{530, 531, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 20, 100, 25, 25},
-		{531, 532, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 45, 100, 25, 25},
-		{532, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 70, 100, 25, 25},
-		{540, 541, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 20, 60, 25, 25},
-		{541, 542, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 45, 60, 25, 25},
-		{542, 543, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 70, 60, 25, 25},
-		{543, 544, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 95, 60, 25, 25},
-		{544, 0, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 120, 60, 25, 25},
-		{560, 561, 0, TOUCHEXIT | CHECKED | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 20, 60, 25, 25},
-		{561, 562, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 45, 60, 25, 25},
-		{562, 563, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 70, 60, 25, 25},
-		{563, 564, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 95, 60, 25, 25},
-		{564, 565, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 120, 60, 25, 25},
-		{565, 0, 0, LASTOBJ | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)OD_PlotTempl, 20, 85, 25, 25}};
+	void *dyndata[] = {(void*)&tab1, (void*)&tab2, (void*)&tab3, (void*)"arrangement of data: select plot",
+		(void*)&tab_A, (void*)&tab_B, (void*)&tab_C, (void*)&tab_D, (void*)"bounding rectangle (relative to page)",
+		(void*)"upper left corner x", (void*)&GRect.Xmin, (void*)&GRect.Ymin, (void*)"lower right x",
+		(void*)&GRect.Xmax, (void*)&GRect.Ymax, (void*)"plotting rectangle (relative to bounding rectangle)",
+		(void*)"upper left corner x", (void*)&DRect.Xmin, (void*)&DRect.Ymin, (void*)"lower right x",
+		(void*)&DRect.Xmax, (void*)&DRect.Ymax, (void*)"select template:", (void*)(OD_AxisTempl),
+		(void*)"ticks outside", (void*)"ticks inside", (void*)"ticks symmetrical", (void*)"horizontal grid lines",
+		(void*)"vertical grid lines", (void*)(OD_AxisTempl3D), (void*)(OD_PlotTempl)};
+	DlgInfo *GraphDlg = CompileDialog(GraphDlgTmpl, dyndata);
 	DlgRoot *Dlg;
 	GraphObj *p;
 	void *hDlg;
@@ -7636,7 +8065,7 @@ Graph::PropertyDlg()
 		case 540:	case 541:	case 542:	case 543:
 		case 544:
 		case 560:	case 561:	case 562:	case 563:
-		case 564:	case 565:
+		case 564:	case 565:	case 566:
 			if(res != selPlt) {
 				selPlt = res;
 				res = -1;
@@ -7716,6 +8145,7 @@ Graph::PropertyDlg()
 				else if(Dlg->GetCheck(563)) p = new BubblePlot3D(this, data);
 				else if(Dlg->GetCheck(564)) p = new Plot3D(this, data, 0x2000);
 				else if(Dlg->GetCheck(565)) p = new Func3D(this, data);
+				else if(Dlg->GetCheck(566)) p = new FitFunc3D(this, data);
 				}
 			if(p && p->PropertyDlg()) {
 				if(!Command(CMD_DROP_PLOT, p, 0L)) DeleteGO(p);
@@ -7735,8 +8165,7 @@ Graph::PropertyDlg()
 		}while(res <0);
 	if(!bRet) parent->Command(CMD_DELOBJ, this, NULL);
 	else Command(CMD_SET_DATAOBJ, (void*)data, 0L);
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;		free(GraphDlg);
 	return bRet;
 }
 
@@ -7908,6 +8337,49 @@ Graph::Configure()
 	return bRet;
 }
 
+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";
+
 bool
 Graph::AddAxis()
 {
@@ -7917,49 +8389,12 @@ Graph::AddAxis()
 	AxisDEF axis;
 	double sizAxLine = defs.GetSize(SIZE_AXIS_LINE);
 	DWORD colAxis = ColAX;
-	DlgInfo NewAxisDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 148, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 148, 25, 45, 12},
-		{3, 0, 4, ISPARENT | CHECKED, GROUP, NULL, 138, 40, 55, 12},
-		{4, 5, 50, TOUCHEXIT | ISPARENT, SHEET, &tab1, 5, 10, 130, 130},
-		{5, 6, 200, ISPARENT | CHECKED, SHEET, &tab2, 5, 10, 130, 130},
-		{6, 0, 300, ISPARENT, SHEET, &tab3, 5, 10, 130, 130},
-		{50, 51, 100, ISPARENT | CHECKED, GROUPBOX, (void*)" scaling ", 10, 30, 120, 36},
-		{51, 120, 0, 0x0L, CHECKBOX, (void*)" automatic scaling", 17, 37, 80, 8},
-		{100, 101, 0, 0x0L, RTEXT, (void*)"axis from", 10, 51, 35, 8},
-		{101, 102, 0, 0x0L, EDVAL1, &y_axis.min, 48, 51, 32, 10},
-		{102, 103, 0, 0x0L, CTEXT, (void*)"to", 81, 51, 11, 8},
-		{103, 0, 0, 0x0L, EDVAL1, &y_axis.max, 93, 51, 32, 10},
-		{120, 0, 121, ISPARENT | CHECKED, GROUPBOX, (void*)" line ", 10, 72, 120, 20},
-		{121, 122, 0, 0x0L, RTEXT, (void*)"width", 10, 77, 25, 8},
-		{122, 123, 0, 0x0L, EDVAL1, &sizAxLine, 37, 77, 25, 10},
-		{123, 124, 0, 0x0L, LTEXT, (void *) Units[defs.cUnits].display, 63, 77, 10, 8},
-		{124, 125, 0, 0x0L, RTEXT, (void*)"color", 73, 77, 25, 8},
-		{125, 130, 0, OWNDIALOG, COLBUTTON, (void *)colAxis, 100, 77, 25, 10},
-		{130, 131, 0, ISPARENT | CHECKED, GROUPBOX, (void*)" axis label ", 10, 98, 120, 20},
-		{131, 0, 0, 0x0L, EDTEXT, (void*)0L, 15, 103, 110, 10},
-		{200, 201, 0, 0x0L, LTEXT, (void*)"select a template:", 10, 30, 70, 9},
-		{201, 202, 0, CHECKED | TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 20, 42, 25, 25},
-		{202, 203, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 45, 42, 25, 25},
-		{203, 204, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 70, 42, 25, 25},
-		{204, 205, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 95, 42, 25, 25},
-		{205, 206, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 20, 67, 25, 25},
-		{206, 207, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 45, 67, 25, 25},
-		{207, 208, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 70, 67, 25, 25},
-		{208, 210, 0, TOUCHEXIT | ISRADIO, ODBUTTON, (void*)(OD_NewAxisTempl), 95, 67, 25, 25},
-		{210, 0, 220, ISPARENT | CHECKED, GROUPBOX, (void*)" placement ", 10, 97, 120, 35},
-		{220, 221, 0, 0x0L, RTEXT, (void*)"x", 10, 105, 15, 8},
-		{221, 222, 0, 0x0L, EDVAL1, &axis.loc[0].fx, 27, 105, 35, 10},
-		{222, 223, 0, 0x0L, LTEXT, (void*)"-", 65, 105, 5, 8},
-		{223, 224, 0, 0x0L, EDVAL1, &axis.loc[1].fx, 71, 105, 35, 10},
-		{224, 225, 0, 0x0L, LTEXT, (void*)Units[units].display, 109, 105, 15, 8},
-		{225, 226, 0, 0x0L, RTEXT, (void*)"y", 10, 117, 15, 8},
-		{226, 227, 0, 0x0L, EDVAL1, &axis.loc[0].fy, 27, 117, 35, 10},
-		{227, 228, 0, 0x0L, LTEXT, (void*)"-", 65, 117, 5, 8},
-		{228, 229, 0, 0x0L, EDVAL1, &axis.loc[1].fy, 71, 117, 35, 10},
-		{229, 0, 0, 0x0L, LTEXT, (void*)Units[units].display, 109, 117, 15, 8},
-		{300, 0, 0, NOSELECT, ODBUTTON, (void*)OD_axisplot, 15, 30, 110, 140},
-		{400, 0, 0, LASTOBJ, NONE, 0L, 0, 0, 0, 0}};
+	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*)(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);
 	DlgRoot *Dlg;
 	void *hDlg;
 	int i, j, res, currTempl = 201;
@@ -8138,8 +8573,7 @@ Graph::AddAxis()
 				}
 			}
 		}
-	CloseDlgWnd(hDlg);
-	delete Dlg;
+	CloseDlgWnd(hDlg);		delete Dlg;			free(NewAxisDlg);
 	if(names) {
 		for(j = 0; names[j]; j++) if(names[j]) free(names[j]);
 		free(names);
@@ -8201,24 +8635,41 @@ Page::Configure()
 bool
 Default::PropertyDlg()
 {
-	TabSHEET tab1 = {0, 25, 10, "Line"};
-	TabSHEET tab2 = {25, 60, 10, "Shapes"};
-	TabSHEET tab3 = {60, 93, 10, "Dialogs"};
-	TabSHEET tab4 = {93, 128, 10, "Internat."};
+	TabSHEET tab1 = {0, 22, 10, "Line"};
+	TabSHEET tab2 = {22, 52, 10, "Shapes"};
+	TabSHEET tab3 = {52, 82, 10, "Dialogs"};
+	TabSHEET tab4 = {82, 116, 10, "Internat."};
+	TabSHEET tab5 = {116, 155, 10, "Date/Time"};
 	double ts =  dlgtxtheight;
+	time_t ti = time(0L);
+	char dt_info[50], date_info[50], datetime_info[50], time_info[50];
 	DlgInfo DefsDlg[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 150, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 150, 25, 45, 12},
+		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 180, 10, 40, 12},
+		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 180, 25, 40, 12},
 		{3, 0, 4, ISPARENT | CHECKED, GROUP, 0L, 0, 0, 0, 0},
-		{4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 139, 120},
-		{5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 139, 120},
-		{6, 7, 300, ISPARENT, SHEET, &tab3, 5, 10, 139, 120},
-		{7, 0, 400, ISPARENT, SHEET, &tab4, 5, 10, 139, 120},
+		{4, 5, 100, TOUCHEXIT | ISPARENT | CHECKED, SHEET, &tab1, 5, 10, 170, 130},
+		{5, 6, 200, TOUCHEXIT | ISPARENT, SHEET, &tab2, 5, 10, 170, 130},
+		{6, 7, 300, TOUCHEXIT | ISPARENT, SHEET, &tab3, 5, 10, 170, 130},
+		{7, 8, 400, TOUCHEXIT | ISPARENT, SHEET, &tab4, 5, 10, 170, 130},
+		{8, 0, 350, TOUCHEXIT | ISPARENT, SHEET, &tab5, 5, 10, 170, 130},
 		{100, 0, 0, NOSELECT, ODBUTTON, (void*)OD_linedef, 10, 38, 130, 100},
 		{200, 0, 0, NOSELECT, ODBUTTON, (void*)OD_filldef, 25, 40, 90, 50},
 		{300, 301, 0, 0x0L, RTEXT, (void*)"text size", 20, 30, 38, 8},
 		{301, 302, 0, 0x0L, EDVAL1, (void*)&ts, 60, 30, 20, 10},
 		{302, 0, 0, 0x0L, LTEXT, (void*)"pixel", 82, 30, 20, 8},
+		{350, 351, 0, 0x0L, LTEXT, (void*)dt_info, 10, 30, 120, 8},
+		{351, 352, 0, 0x0L, LTEXT, (void*)"date format:", 10, 43, 70, 8},
+		{352, 353, 0, 0x0L, EDTEXT, (void*)defs.fmt_date, 10, 53, 60, 10},
+		{353, 354, 0, 0x0L, LTEXT, (void*)date_info, 80, 54, 40, 10}, 
+		{354, 355, 0, 0x0L, LTEXT, (void*)"date + time format:", 10, 65, 70, 8},
+		{355, 356, 0, 0x0L, EDTEXT, (void*)defs.fmt_datetime, 10, 75, 60, 10},
+		{356, 357, 0, 0x0L, LTEXT, (void*)datetime_info, 80, 76, 40, 10}, 
+		{357, 358, 0, 0x0L, LTEXT, (void*)"time format:", 10, 87, 70, 8},
+		{358, 359, 0, 0x0L, EDTEXT, (void*)defs.fmt_time, 10, 97, 60, 10},
+		{359, 360, 0, 0x0L, LTEXT, (void*)time_info, 80, 98, 40, 10}, 
+		{360, 361, 0, 0x0L, LTEXT, (void*)"For further information about formats see", 10, 119, 140, 8},
+		{361, 362, 0, HREF | TOUCHEXIT, LTEXT, (void*)"http://rlplot.sourceforge.net/Docs/functions/datetime.html", 10, 127, 140, 8},
+		{362, 0, 0, 0x0L, PUSHBUTTON, (void*)"Test", 130, 107, 40, 12},
 		{400, 401, 0, 0x0L, LTEXT, (void*)"edit country specific information", 20, 30, 100, 8},
 		{401, 402, 0, 0x0L, RTEXT, (void*)"decimal point", 45, 45, 40, 8},
 		{402, 403, 0, 0x0L, EDTEXT, (void*)DecPoint, 90, 45, 10, 10},
@@ -8231,27 +8682,61 @@ Default::PropertyDlg()
 		{422, 0, 0, LASTOBJ, RADIO1, (void*)Units[2].display, 75, 91, 20, 8}};
 	DlgRoot *Dlg;
 	void *hDlg;
-	int res, tmpUnits = cUnits;
-	bool bRet = false;
+	int i, res, tmpUnits = cUnits;
+	bool bRet = false, bContinue = false;
+	double dt;
 	LineDEF LineDef;
 	FillDEF FillDef;
 
 	OD_linedef(OD_SETLINE, 0L, 0L, 0L, (void *)GetLine(), 0);
 	OD_filldef(OD_SETLINE, 0L, 0L, 0L, (void *)GetOutLine(), 0);
 	OD_filldef(OD_SETFILL, 0L, 0L, 0L, (void *)GetFill(), 0);
+	sprintf(dt_info, "today is %s", ctime(&ti));
+	dt_info[33] = 0;
+	date_value(dt_info+13, "x z H:M:S Y", &dt);
+	strcpy(date_info, value_date(dt, defs.fmt_date));
+	strcpy(datetime_info, value_date(dt, defs.fmt_datetime));
+	strcpy(time_info, value_date(dt, defs.fmt_time));
 	Dlg = new DlgRoot(DefsDlg);
 	switch(dUnits) {
 	case 1:		Dlg->SetCheck(421, 0L, true);	break;
 	case 2:		Dlg->SetCheck(422, 0L, true);	break;
 	default:	Dlg->SetCheck(420, 0L, true);	break;
 		}
-	hDlg = CreateDlgWnd("Edit Global Preferences", 50, 50, 410, 300, Dlg, 0x0L);
+#ifdef _WINDOWS
+	for(i = 360; i <= 361; i++) Dlg->TextSize(i, 12);
+#else
+	for(i = 360; i <= 361; i++) Dlg->TextSize(i, 10);
+#endif
+	hDlg = CreateDlgWnd("Edit Global Preferences", 50, 50, 460, 316, Dlg, 0x0L);
 	do{
 		LoopDlgWnd();
 		res = Dlg->GetResult();
 		switch(res) {
-		case 4:	case 5:
-			res = -1;
+		case 0:
+			if(bContinue) res = -1;
+			break;
+		case 362:			//update date/time display
+			ti = time(0L);
+			sprintf(dt_info, "today is %s", ctime(&ti));
+			dt_info[33] = 0;										Dlg->SetText(350, dt_info);
+			date_value(dt_info+13, "x z H:M:S Y", &dt);
+			if(!(Dlg->GetText(352, date_info))) strcpy(date_info, defs.fmt_date);
+			strcpy(date_info, value_date(dt, date_info));			Dlg->SetText(353, date_info);
+			if(!(Dlg->GetText(355, datetime_info))) strcpy(datetime_info, defs.fmt_datetime);
+			strcpy(datetime_info, value_date(dt, datetime_info));	Dlg->SetText(356, datetime_info);
+			if(!(Dlg->GetText(358, time_info))) strcpy(time_info, defs.fmt_time);
+			strcpy(time_info, value_date(dt, time_info));			Dlg->SetText(359, time_info);
+			bContinue = false;		res = -1;
+			break;
+		case 361:			//call browser
+			bContinue = true;		res = -1;
+			break;
+		case 4:		case 5:		case 6:		case 7:
+			bContinue = false;		res = -1;
+			break;
+		case 8:
+			bContinue = true;		res = -1;
 			break;
 		case 1:
 			if(Dlg->GetCheck(421)) dUnits = 1;
@@ -8262,7 +8747,6 @@ Default::PropertyDlg()
 	if(res == 1) {
 		if(Dlg->GetText(402, TmpTxt))	DecPoint[0] = TmpTxt[0];
 		if(Dlg->GetText(404, TmpTxt))	ColSep[0] = TmpTxt[0];
-		bRet = true;
 		OD_linedef(OD_GETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
 		SetLine(tmpUnits, &LineDef, 0);
 		OD_filldef(OD_GETLINE, 0L, 0L, 0L, (void *)&LineDef, 0);
@@ -8270,6 +8754,19 @@ Default::PropertyDlg()
 		OD_filldef(OD_GETFILL, 0L, 0L, 0L, (void *)&FillDef, 0);
 		SetFill(tmpUnits, &FillDef);
 		Dlg->GetInt(301, &dlgtxtheight);
+		if(Dlg->GetText(352, date_info) && date_info[0] && strcmp(date_info, defs.fmt_date)) {
+			if(defs.fmt_date) free(defs.fmt_date);
+			defs.fmt_date = strdup(date_info);
+			}
+		if(Dlg->GetText(355, datetime_info) && datetime_info[0] && strcmp(datetime_info, defs.fmt_datetime)) {
+			if(defs.fmt_datetime) free(defs.fmt_datetime);
+			defs.fmt_datetime = strdup(datetime_info);
+			}
+		if(Dlg->GetText(358, time_info) && time_info[0] && strcmp(time_info, defs.fmt_time)) {
+			if(defs.fmt_time) free(defs.fmt_time);
+			defs.fmt_time = strdup(time_info);
+			}
+		bRet = true;
 		}
 	CloseDlgWnd(hDlg);
 	delete Dlg;
diff --git a/QT_Spec.cpp b/QT_Spec.cpp
index 221de54..b9314ca 100755
--- a/QT_Spec.cpp
+++ b/QT_Spec.cpp
@@ -1,4 +1,4 @@
-//QT_Spec.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
+//QT_Spec.cpp, Copyright (c) 2001-2006 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -27,7 +27,8 @@
 #include <qcstring.h>
 #include <qclipboard.h>
 #include <qbuffer.h>
-#include <qbitmap.h>
+#include <qbitmap.h>
+#include <qtextstream.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -71,39 +72,58 @@ POINT CurrWidgetPos = {0,0};
 #define CM_PRINT       517
 #define CM_EXPORT      518
 #define CM_DELOBJ      519
-#define CM_DEFAULTS    520
-#define CM_COPY        521
-#define CM_PASTE       522
-#define CM_UPDATE      523
-#define CM_ADDAXIS     524
-#define CM_UNDO        525
-#define CM_ZOOMIN      526
-#define CM_ZOOMOUT     527
-#define CM_ZOOMFIT     528
-#define CM_FILE1       529
-#define CM_FILE2       530
-#define CM_FILE3       531
-#define CM_FILE4       532
-#define CM_FILE5       533
-#define CM_FILE6       534
-#define CM_FILLRANGE   535
-#define CM_CUT         536
-#define CM_LEGEND      537
-#define CM_LAYERS      538
-#define CM_INSROW      539
-#define CM_INSCOL      540
-#define CM_DELROW      541
-#define CM_DELCOL      542
+#define CM_DEFAULTS    522
+#define CM_COPY        523
+#define CM_PASTE       524
+#define CM_UPDATE      525
+#define CM_ADDAXIS     526
+#define CM_UNDO        527
+#define CM_ZOOMIN      528
+#define CM_ZOOMOUT     529
+#define CM_ZOOMFIT     530
+#define CM_FILE1       531
+#define CM_FILE2       532
+#define CM_FILE3       533
+#define CM_FILE4       534
+#define CM_FILE5       535
+#define CM_FILE6       536
+#define CM_FILLRANGE   537
+#define CM_CUT         538
+#define CM_LEGEND      539
+#define CM_LAYERS      540
+#define CM_INSROW      541
+#define CM_INSCOL      542
+#define CM_DELROW      543
+#define CM_DELCOL      544
+#define CM_SAVEDATA    545
 
-#define CM_T_STANDARD  560
-#define CM_T_DRAW      561
-#define CM_T_POLYLINE  562
-#define CM_T_POLYGON   563
-#define CM_T_RECTANGLE 564
-#define CM_T_ROUNDREC  565
-#define CM_T_ELLIPSE   566
-#define CM_T_ARROW     567
-#define CM_T_TEXT      568
+#define CM_T_STANDARD  550
+#define CM_T_DRAW      551
+#define CM_T_POLYLINE  552
+#define CM_T_POLYGON   553
+#define CM_T_RECTANGLE 554
+#define CM_T_ROUNDREC  555
+#define CM_T_ELLIPSE   556
+#define CM_T_ARROW     557
+#define CM_T_TEXT      558
+
+#define CM_DELKEY      600
+#define CM_LEFTARRKEY  601
+#define CM_RIGHTARRKEY 602
+#define CM_UPARRKEY    603
+#define CM_DOWNARRKEY  604
+#define CM_TAB         605
+#define CM_SHTAB       606
+#define CM_PGUP        607
+#define CM_PGDOWN      608
+#define CM_POS_FIRST   609
+#define CM_POS_LAST    610
+#define CM_SHLEFT      611
+#define CM_SHRIGHT     612
+#define CM_SHUP        613
+#define CM_SHDOWN      614
+#define CM_SHPGUP      615
+#define CM_SHPGDOWN    616
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Exute a file open dialog for the different situations
@@ -111,15 +131,23 @@ POINT CurrWidgetPos = {0,0};
 static char UserFileName[600];
 // Get a new file name to store data in
 char *SaveDataAsName(char *oldname)
-{
-	QString fileName = QFileDialog::getSaveFileName(oldname?oldname:defs.currPath,
-		"RLPlot workbook (*.rlw)\ndata files (*.csv)\ntab separated (*.tsv)\nXML (*.xml)", QAppl->focusWidget());
-	if(!fileName.isEmpty()){
-		strcpy(UserFileName, fileName);
-		defs.FileHistory(UserFileName);
-		return UserFileName;
-		}
-	return 0L;
+{
+	QFileDialog qf(0,0,true);
+	QString filters("RLPlot workbook (*.rlw);;data files (*.csv);;"
+		"tab separated (*.tsv);;XML (*.xml)");
+
+	qf.setFilters(filters);				qf.setDir(defs.currPath);
+	qf.setSelection(oldname);			qf.setMode(QFileDialog::AnyFile);
+	if(qf.exec() == QDialog::Accepted) {
+//		InfoBox((char*)qf.selectedFilter().ascii());
+//		InfoBox((char*)qf.selectedFile().ascii());
+		if(!qf.selectedFile().isEmpty()) {
+			strcpy(UserFileName, (char*)qf.selectedFile().ascii());
+			defs.FileHistory(UserFileName);
+			return UserFileName;
+			}
+		}
+	return 0L;
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -376,238 +404,281 @@ TxtCurBlink::timerEvent(QTimerEvent *ev)
 			}
 		}
 }
-
-#define MIME_KSPREAD "application/x-kspread-snippet"
-#define MIME_RLPLOT "application/x-rlplot-snippet"
-#define MIME_RLPGRAPH "application/x-rlplot-graph"
-#define MIME_RLPOBJ "application/x-rlplot-object"
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Clipboard support
-// based on KDEs KSpread source: kspread_table.cc
-// copyright (C) 1998, 1999 Torben Weis
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-KSpreadTextDrag::KSpreadTextDrag(QWidget *dragSource, const char *name )
-	:QTextDrag(dragSource, name)
-{
-	go = 0L;
-}
-
-KSpreadTextDrag::~KSpreadTextDrag()
-{
-}
-
-bool
-KSpreadTextDrag::provides(const char *mimeType)
-{
-	if(0 == strcmp(mimeType, "text/plain")) return true;
-	if(0 == strcmp(mimeType, MIME_RLPLOT)) return true;
-	if(0 == strcmp(mimeType, selectionMimeType())) return true;
-	return false;
-}
-
-QByteArray
-KSpreadTextDrag::encodedData(const char *mime) const
-{
-	static QByteArray b;
-	char *ptr = 0L;
-	long cb;
-
-	if(!go || go->Id != GO_SPREADDATA) return 0L;
-	if(0 == strcmp(mime, MIME_RLPLOT)) {
-		go->Command(CMD_COPY_XML, &ptr, 0L);
-		}
-	else if(0 == strcmp(mime, "text/plain")) {
-		go->Command(CMD_COPY_TSV, &ptr, 0L);
-		}
-	else if(0 == strcmp(mime, selectionMimeType())){
-		go->Command(CMD_COPY_XML, &ptr, 0L);
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Clipboard support: the clipboard server uses sockets
+// code based on Qt example code
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#define MIME_KSPREAD "application/x-kspread-snippet"
+
+#ifdef RLP_PORT
+static RLPserver *rlpsrv = 0L;
+
+ReadCB::ReadCB(QObject *parent, const char *name, GraphObj *g):QSocket(parent, name)
+{
+	par = parent;	DestGO = g;		res= 0L;	level = 0;	format = 0L;
+	connect(this, SIGNAL(connected()), SLOT(isConnected()));
+	connect(this, SIGNAL(readyRead()), SLOT(receiveData()));
+	connect(this, SIGNAL(connectionClosed()), SLOT(endData()));
+	connect(this, SIGNAL(error(int)), SLOT(isError(int)));
+	connectToHost("localhost", RLP_PORT);
+}
+
+ReadCB::~ReadCB()
+{
+	if(res) delete res;			res= 0L;
+	if(format) free(format);	format = 0L;
+}
+
+void
+ReadCB::isConnected()
+{
+	QTextStream ts(this);
+	ts << "enum formats\n";
+	res = new QString();
+}
+
+void
+ReadCB::receiveData()
+{
+	char *line;
+
+	QTextStream ts(this);
+	if(!level) while(canReadLine()){
+		QString s = ts.readLine();
+		if(DestGO && (DestGO->Id == GO_SPREADDATA || DestGO->Id == GO_PAGE || DestGO->Id == GO_GRAPH)) {
+			if(s == "text/xml" || s == "text/rlp-graph" || s == "text/rlp-page") {
+				while(bytesAvailable()) getch();
+				format = strdup(s.ascii());				level = 1;
+				ts << "get " << s << "\n";
+				}
+			}
 		}
-	else return 0L;
-	if(!ptr) ptr = (char*)calloc(cb = 4, 1);
-	else cb = strlen(ptr)+1;
-	if(ptr && b.resize(cb)) {
-		memcpy(b.data(), ptr, cb);
-		free (ptr);
-		return (b);
-		}
-	return 0L;
-}
-
-bool
-KSpreadTextDrag::canDecode(QMimeSource *e)
-{
-	if(e->provides(selectionMimeType())) return true;
-	return false;
-}
-
-const char *
-KSpreadTextDrag::format(int i) const
-{
-	static const char *fmt;
-
-	switch(i) {
-	case 0:	case 1:
-		fmt = "text/plain";
-		return fmt;
-	case 2:
-	case 3:	case 4:
-		return selectionMimeType();
-	default:
-		return 0L;
-		}
-}
-
-const char *
-KSpreadTextDrag::selectionMimeType()
-{
-	return(MIME_RLPLOT);
-}
-
-RLPGraphDrag::RLPGraphDrag(QWidget *dragSource, const char *name)
-	:QTextDrag(dragSource, name)
-{
-	go1 = go2 = 0L;
-}
-
-RLPGraphDrag::~RLPGraphDrag()
-{
-}
-
-bool
-RLPGraphDrag::provides(const char *mimeType)
-{
-	if(go1 && 0 == strcmp(mimeType, MIME_RLPGRAPH)) return true;
-	if(go2 && 0 == strcmp(mimeType, MIME_RLPOBJ)) return true;
-	return false;
-}
-
-void
-RLPGraphDrag::setGraphData(GraphObj *g)
-{
-	go1 = g;
-	if(CurrGraph && CurrGraph != g) go2 = CurrGraph;
-	else go2 = 0L;
-}
-
-QByteArray
-RLPGraphDrag::encodedData(const char* mime) const
-{
-	static QByteArray b;
-	char *ptr = 0L;
-	long cb;
-
-	if(0 == strcmp(mime, "text/plain")) return 0L;
-	else if(go1 && 0 == strcmp(mime, MIME_RLPGRAPH)) ptr = GraphToMem(go1, &cb);
-	else if(go2 && 0 == strcmp(mime, MIME_RLPOBJ)) ptr = GraphToMem(go2, &cb);
-	else return 0L;
-	if(ptr && b.resize(cb+1)) {
-		memcpy(b.data(), ptr, cb+1);
-		free (ptr);
-		return (b);
-		}
-	return 0L;
-}
-
-const char*
-RLPGraphDrag::format(int i) const
-{
-	switch(i) {
-	case 0:		return("text/plain");
-	case 1:		return MIME_RLPGRAPH;
-	case 2:		return MIME_RLPOBJ;
-	default:	return 0L;
-		}
-}
-
-bool
-RLPGraphDrag::canDecode(QMimeSource *e)
-{
-	if(e->provides(MIME_RLPGRAPH)) return true;
-	if(e->provides(MIME_RLPOBJ)) return true;
-	return false;
-}
-
-const char*
-RLPGraphDrag::selectionMimeType()
-{
-	return(MIME_RLPGRAPH);
-}
-
+	else while(canReadLine()) {
+		res->append(ts.readLine());
+		res->append("\n");
+		}
+}
+
+void
+ReadCB::endData()
+{
+	receiveData();
+	if(res && res->length() > 5 && DestGO && DestGO->Id == GO_SPREADDATA) {
+		if(strcmp(format, "text/xml") == 0) DestGO->Command(CMD_PASTE_XML, (void*)res->ascii(), 0L);
+		if(strcmp(format, "text/rlp-graph") == 0) OpenGraph(DestGO, 0L, (unsigned char*)res->ascii(), true);
+		if(strcmp(format, "text/rlp-page") == 0) OpenGraph(DestGO, 0L, (unsigned char*)res->ascii(), true);
+		}
+	else if(res && res->length() > 5 && DestGO && (DestGO->Id == GO_PAGE || DestGO->Id == GO_GRAPH)) {
+		if(strcmp(format, "text/rlp-graph") == 0) OpenGraph(DestGO, 0L, (unsigned char*)res->ascii(), true);
+		if(strcmp(format, "text/rlp-page") == 0) OpenGraph(DestGO, 0L, (unsigned char*)res->ascii(), true);
+		}
+	if(res) delete res;		res= 0L;
+	delete this;
+}
+
+void
+ReadCB::isError(int)
+{
+	QClipboard *cb;
+	QDragObject *mime;
+
+	if((cb = QAppl->clipboard()) && (mime = (QDragObject *)cb->data())) {
+		if(DestGO && DestGO->Id == GO_SPREADDATA) {
+			if(mime->provides(MIME_KSPREAD)){
+				QByteArray b = mime->encodedData(MIME_KSPREAD);
+				if(b) DestGO->Command(CMD_PASTE_XML, (void*)b.data(), 0L);
+				delete this;	return;
+				}
+			else if(mime->provides("text/plain")){
+				ProcMemData(DestGO, (unsigned char*)cb->text().latin1(), true);
+				delete this;	return;
+				}
+			}
+		}
+	delete this;
+}
+
+RLPsock::RLPsock(int sock, QObject *parent, const char *name, GraphObj *g):QSocket(parent, name)
+{
+	par = parent;	SourceGO = g;
+	connect(this, SIGNAL(readyRead()), SLOT(readClient()));
+	connect(this, SIGNAL(connectionClosed()), SLOT(deleteLater()));
+	setSocket(sock);
+}
+
+void
+RLPsock::readClient()
+{
+	char *ptr = 0L;
+	const char *cmd;
+
+	//allow only connetions from local host
+	/*
+	if(peerAddress().toString() != "127.0.0.1") {close(); return;}
+	*/
+	QTextStream ts(this);
+	while(canReadLine()) {
+		QString str = ts.readLine();
+		cmd = str.ascii();
+		if(strcmp(cmd, "close") == 0) {
+			close();
+			if(rlpsrv && par) delete par;
+			return;
+			}
+		else if(strcmp(cmd, "exit") == 0) {
+			close();
+			if(rlpsrv && par) delete par;
+			return;
+			}
+		else if(strcmp(cmd, "enum formats") == 0) {
+			if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
+				ts << "text/xml\n";
+				if(((RLPserver*)par)->GetTXT()) ts << "text/plain\n";
+				}
+			else if(SourceGO && SourceGO->Id == GO_GRAPH) ts << "text/rlp-graph\n";
+			else if(SourceGO && SourceGO->Id == GO_PAGE) ts << "text/rlp-page\n";
+			else close();
+			}
+		else if(strcmp(cmd, "get text/xml") == 0) {
+			if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
+				if(ptr = ((RLPserver*)par)->GetXML()) ts << ptr;
+				}
+			close();
+			}
+		else if(strcmp(cmd, "get text/rlp-graph") == 0 || strcmp(cmd, "get text/rlp-page") == 0) {
+			if(SourceGO && (SourceGO->Id == GO_GRAPH || SourceGO->Id == GO_PAGE)) {
+				if(ptr = ((RLPserver*)par)->GetRLP()) ts << ptr;
+				}
+			close();
+			}
+		else if(strcmp(cmd, "get text/plain") == 0) {
+			if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
+				if(ptr = ((RLPserver*)par)->GetTXT()) ts << ptr;
+				}
+			close();
+			}
+		else close();
+		}
+}
+
+
+RLPserver::RLPserver(QObject* parent, GraphObj *g):QServerSocket(RLP_PORT, 4, parent)
+{
+	text_xml = text_rlp = text_plain = 0L;
+	SetGO(g);
+}
+
+RLPserver::~RLPserver()
+{
+	rlpsrv = 0L;
+	HideCopyMark();
+	if(text_xml) free(text_xml);		text_xml =  0L;
+	if(text_rlp) free(text_rlp);		text_rlp =  0L;
+	if(text_plain) free(text_plain);	text_plain = 0L;
+}
+
+void 
+RLPserver::SetGO(GraphObj *g)
+{
+	QClipboard *cb;
+
+	SourceGO = g;
+	if(text_xml) free(text_xml);		text_xml =  0L;
+	if(text_rlp) free(text_rlp);		text_rlp =  0L;
+	if(text_plain) free(text_plain);	text_plain = 0L;
+	if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
+		SourceGO->Command(CMD_COPY_TSV, &text_plain, 0L);
+		if(text_plain && text_plain[0]){
+			cb = QAppl->clipboard();
+			cb->clear();
+#ifdef Q_CHECK_PTR				//n.a. in Qt version 2
+			cb->setText(text_plain, QClipboard::Clipboard);
+			cb->setText(text_plain, QClipboard::Selection);
+#else
+			cb->setText(text_plain);
+#endif
+			}
+		}
+}
+
+char *
+RLPserver::GetXML()
+{
+	if(SourceGO && SourceGO->Id == GO_SPREADDATA) {
+		if(!text_xml) SourceGO->Command(CMD_COPY_XML, &text_xml, 0L);
+		return text_xml;
+		}
+	return 0L;
+}
+
+char *
+RLPserver::GetRLP()
+{
+	long cb;
+
+	if(SourceGO && (SourceGO->Id == GO_GRAPH || SourceGO->Id == GO_PAGE)) {
+		text_rlp = GraphToMem(SourceGO, &cb);
+		return text_rlp;
+		}
+	return 0L;
+}
+
+#endif //RLP_PORT
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Process paste command: check for clipboard contents
 void TestClipboard(GraphObj *g)
-{
-
-	QClipboard *cb;
-	QDragObject *mime;
-
-	if(!(cb = QAppl->clipboard()))return;
-	if(!(mime = (QDragObject *)cb->data()))return;
-	if(g->Id == GO_SPREADDATA) {
-		if(mime->provides(MIME_RLPLOT)){
-			QByteArray b = mime->encodedData(MIME_RLPLOT);
-			if(b) g->Command(CMD_PASTE_XML, (void*)b.data(), 0L);
-			return;
-			}
-		else if(mime->provides(MIME_KSPREAD)){
-			QByteArray b = mime->encodedData(MIME_KSPREAD);
-			if(b) g->Command(CMD_PASTE_XML, (void*)b.data(), 0L);
-			return;
-			}
-		else if(QByteArray b = mime->encodedData(MIME_RLPOBJ)){
-			OpenGraph(g, 0L, (unsigned char*)b.data());
-			return;
-			}
-		else if(QByteArray b = mime->encodedData(MIME_RLPGRAPH)){
-			OpenGraph(g, 0L, (unsigned char*)b.data());
-			return;
-			}
-		else if(mime->provides("text/plain")){
-			QString _text = cb->text();
-			ProcMemData(g, (unsigned char*)_text.latin1(), true);
-			return;
-			}
-		}
-	else if(g->Id == GO_PAGE){
-		if(QByteArray b = mime->encodedData(MIME_RLPOBJ)){
-			OpenGraph(g, 0L, (unsigned char*)b.data());
-			return;
-			}
-		else if(QByteArray b = mime->encodedData(MIME_RLPGRAPH)){
-			OpenGraph(g, 0L, (unsigned char*)b.data());
-			return;
-			}
-		}
-	else if(g->Id == GO_GRAPH)TestClipboard(g->parent);
+{
+	if(!g) return;
+#ifdef RLP_PORT
+	if(rlpsrv && rlpsrv->SourceGO) {
+		if(rlpsrv->SourceGO->Id == GO_GRAPH || rlpsrv->SourceGO->Id == GO_PAGE)
+			OpenGraph(g, 0L, (unsigned char*)rlpsrv->GetRLP(), true);
+		else if(rlpsrv->SourceGO->Id == GO_SPREADDATA && g->Id == GO_SPREADDATA)
+			g->Command(CMD_PASTE_XML, (void*)rlpsrv->GetXML(), 0L);
+		}
+	else new ReadCB(0, 0, g);
+#endif //RLP_PORT
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Copy spreadsheet or graph to clipboard
 void CopyData(GraphObj *g)
-{
-	EmptyClip();
-	KSpreadTextDrag *kd = new KSpreadTextDrag(0L);
-	kd->setText(QString("RLPlot snippet"));
-	kd->setSpreadData(g);
-#ifdef Q_CHECK_PTR				//n.a. in Qt version 2
-	if(QAppl->clipboard()->supportsSelection())
-		QAppl->clipboard()->setSelectionMode(TRUE);
-#endif
-	QAppl->clipboard()->setData(kd);
+{
+	HideCopyMark();
+	QAppl->clipboard()->clear();
+#ifdef RLP_PORT
+	if(rlpsrv) {
+		if(rlpsrv->ok()) rlpsrv->SetGO(g);
+		else {
+			delete rlpsrv;
+			rlpsrv = new RLPserver(0, g);
+			}
+		}
+	else rlpsrv = new RLPserver(0, g);
+#endif //RLP_PORT
 }
 
 void CopyGraph(GraphObj *g)
-{
-	EmptyClip();
-	RLPGraphDrag *gd = new RLPGraphDrag(0L);
-	gd->setText(QString("RLPlot graph"));
-	gd->setGraphData(g);
-	//no support for X11 clipboard possible
-	QAppl->clipboard()->setData(gd);
+{
+	CopyData(g);
 }
 
 void EmptyClip()
-{
+{
+#ifdef RLP_PORT
+	if(rlpsrv) {
+		delete(rlpsrv);			rlpsrv = 0;
+		}
+	else { 
+		QSocket *socket = new QSocket(0);
+		socket->connectToHost("localhost", RLP_PORT);
+		QTextStream os(socket);
+		os << "close\n";
+		socket->close();
+		}
+#endif //RLP_PORT
 	HideCopyMark();
 	QAppl->clipboard()->clear();
 }
@@ -615,17 +686,14 @@ void EmptyClip()
 void CopyText(char *txt, int len)
 {
 	QClipboard *cb;
-	char tmp_txt[90];
 
-	if(!(cb = QAppl->clipboard()) || !txt || !txt[0])return;
+	if(!(cb = QAppl->clipboard()) || !txt || !txt[0]) return;
 	EmptyClip();
-	if(!len) len = strlen(txt);
-	memcpy(tmp_txt, txt, len);		tmp_txt[len] = 0;
 #ifdef Q_CHECK_PTR				//n.a. in Qt version 2
-	cb->setText(tmp_txt, QClipboard::Clipboard);
-	cb->setText(tmp_txt, QClipboard::Selection);
+	cb->setText(txt, QClipboard::Clipboard);
+	cb->setText(txt, QClipboard::Selection);
 #else
-	cb->setText(tmp_txt);
+	cb->setText(txt);
 #endif
 }
 
@@ -1488,7 +1556,40 @@ unsigned char zoom_mask[] =	{	//zoom cursor mask
 	0xf0, 0x1f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf4, 0x7e,
 	0x7c, 0x7c, 0xfc, 0x7e, 0xf8, 0x3f, 0xf8, 0x3f,
 	0xf0, 0x1f, 0xe0, 0x0f, 0x80, 0x03, 0x00, 0x00};
-
+
+unsigned char paste_bits[] = {	//paste cursor bitmap
+	0x04, 0x00,	0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
+	0xc4, 0x7f, 0x20, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f,
+	0x20, 0x80, 0x20, 0x80, 0x20, 0x80, 0x20, 0x80,
+	0x20, 0x80, 0x20, 0x80, 0xc0, 0x7f, 0x00, 0x00};
+
+unsigned char paste_mask[] = {	//paste cursor mask
+	0x04, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x04, 0x00,
+	0xc4, 0x7f, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff,
+	0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0xe0, 0xff,
+	0xe0, 0xff, 0xe0, 0xff, 0xc0, 0x7f, 0x00, 0x00};
+
+//display 16x16 cursor data: developers utility
+/*
+void disp_bm(unsigned char *tb)
+{
+	char txt[512];
+	unsigned char currbyte;
+	int i, j, pos;
+
+	for(i = pos = 0; i < 32; i++) {
+		currbyte = tb[i];
+		for (j = 0; j < 8; j++) {
+			if(currbyte & 0x01) pos += sprintf(txt+pos, "1");
+			else pos += sprintf(txt+pos, "0");
+			currbyte >>= 1;
+			}
+		if(i & 1)pos += sprintf(txt+pos, "\n");
+		}
+	InfoBox(txt);
+}
+*/
+
 void
 OutputQT::MouseCursor(int cid, bool force)
 {
@@ -1496,6 +1597,7 @@ OutputQT::MouseCursor(int cid, bool force)
 	if(cid == MC_LAST) cid = cCursor;
 	QBitmap cb(16, 16, hand_bits, TRUE);	QBitmap cm(16, 16, hand_mask, TRUE);
 	QBitmap zb(16, 16, zoom_bits, TRUE);	QBitmap zm(16, 16, zoom_mask, TRUE);
+	QBitmap pb(16, 16, paste_bits, TRUE);	QBitmap pm(16, 16, paste_mask, TRUE);
 	switch(cid) {
 #ifdef Q_CHECK_PTR				//Qt version 3
 	case MC_ARROW:	widget->setCursor(QCursor(Qt::ArrowCursor));	break;
@@ -1519,11 +1621,14 @@ OutputQT::MouseCursor(int cid, bool force)
 	case MC_SALL:	widget->setCursor(QCursor(SizeAllCursor));	break;
 #endif
 	case MC_MOVE:
-		widget->setCursor(QCursor(cb, cm));
+		widget->setCursor(QCursor(cb, cm, 7, 7));
 		break;
 	case MC_ZOOM:
-		widget->setCursor(QCursor(zb, zm));
+		widget->setCursor(QCursor(zb, zm, 7, 7));
 		break;
+	case MC_PASTE:
+		widget->setCursor(QCursor(pb, pm, 2, 2));
+		break;
 	default:	return;
 		}
 	cCursor = cid;
@@ -1628,11 +1733,12 @@ OutputQT::SetMenu(int type)
 	if(type == MENU_SPREAD){
 		QPopupMenu *file = new QPopupMenu(widget);
 		file->insertItem("&Open", widget, SLOT(cmOpen()));
+		file->insertItem("&Save", widget, SLOT(cmSaveData()));
 		file->insertItem("Save &as", widget, SLOT(cmSaveDataAs()));
 		file->insertSeparator();
 		file->insertItem("&Print", widget, SLOT(cmPrint()));
 		file->insertSeparator();
-		file->insertItem("E&xit", widget, SLOT(cmExit()));
+		file->insertItem("E&xit", widget, SLOT(cmExitRLP()));
 		file->insertSeparator();
 		file->insertItem("n.a.", widget, SLOT(cmFile1()), 0, CM_FILE1);
 		file->insertItem("n.a.", widget, SLOT(cmFile2()), 0, CM_FILE2);
@@ -1910,11 +2016,7 @@ RLPwidget::RLPwidget(QWidget *par, const char *name, anyOutput *o, GraphObj *g)
 RLPwidget::~RLPwidget()
 {
 	if(OutputClass)((OutputQT*)OutputClass)->widget = 0L;
-	OutputClass = 0L;
-	if(BaseObj){
-		BaseObj->Command(CMD_CAN_DELETE, 0L, 0L);
-		BaseObj = 0L;
-		}
+	OutputClass = 0L;	BaseObj = 0L;
 }
 
 //public slots: menu items, events
@@ -1943,6 +2045,12 @@ RLPwidget::cmOpen()
 	if(BaseObj)BaseObj->Command(CMD_OPEN, (void *)NULL, OutputClass);
 }
 
+void
+RLPwidget::cmSaveData()
+{
+	if(BaseObj)BaseObj->Command(CMD_SAVEDATA, (void *)NULL, OutputClass);
+}
+
 void
 RLPwidget::cmSaveDataAs()
 {
@@ -1952,14 +2060,19 @@ RLPwidget::cmSaveDataAs()
 void
 RLPwidget::cmExit()
 {
-	if(BaseObj) {
-		if(BaseObj->Command(CMD_CAN_CLOSE, 0L, 0L)){
-			BaseObj = 0L;
-			delete this;
-			}
+	if(BaseObj && BaseObj->Command(CMD_CAN_CLOSE, 0L, 0L)){
+		if(BaseObj->parent) BaseObj->parent->Command(CMD_DELOBJ, BaseObj, 0L);
 		}
-	else delete(this);
 }
+
+void
+RLPwidget::cmExitRLP()
+{
+	if(BaseObj) {
+		if(!BaseObj->Command(CMD_CAN_CLOSE, 0L, 0L)) return;
+		}
+	QAppl->exit(0);
+}
 
 void
 RLPwidget::cmNewGraph()
@@ -2033,7 +2146,7 @@ RLPwidget::cmPaste()
 	if(BaseObj) {
 		OutputClass->MouseCursor(MC_WAIT, true);
 		TestClipboard(BaseObj);
-		OutputClass->MouseCursor(MC_ARROW, true);
+		BaseObj->Command(CMD_MOUSECURSOR, 0L, OutputClass);
 		}
 }
 
@@ -2130,7 +2243,7 @@ RLPwidget::cmPrint()
 void
 RLPwidget::cmExport()
 {
-	OpenExportName(BaseObj, "hello.svg");
+	OpenExportName(BaseObj, 0L);
 	BaseObj->DoPlot(0L);
 }
 
@@ -2286,8 +2399,7 @@ RLPwidget::closeEvent(QCloseEvent *e)
 	if(BaseObj){
 		if(BaseObj->Command(CMD_CAN_CLOSE, 0L, 0L)) {
 			if(OutputClass)((OutputQT*)OutputClass)->widget = 0L;
-			OutputClass = 0L;
-			BaseObj = 0L;
+			OutputClass = 0L;			BaseObj = 0L;
 			e->accept();
 			}
 		}
@@ -2706,10 +2818,6 @@ int main (int argc, char **argv)
 			drw->FileIO(FILE_WRITE);		delete drw;
 			}
 		}
-	SpreadMain(false);
-	InitTextCursor(false);
-	if(WWWbrowser) free(WWWbrowser);
-	if(LoadFile) free(LoadFile);
 	return 0;
 }
 
diff --git a/QT_Spec.h b/QT_Spec.h
index 0f4b425..2340a85 100755
--- a/QT_Spec.h
+++ b/QT_Spec.h
@@ -47,41 +47,70 @@ private:
 };
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// based on KDEs KSpread source: kspread_table.h
-// copyright (C) 1998, 1999 Torben Weis
-class KSpreadTextDrag:public QTextDrag {
+//use sockets for to exchange clipboard data
+#ifdef RLP_PORT
+
+#include <qsocket.h>
+#include <qserversocket.h>
+
+class ReadCB:public QSocket {
 	Q_OBJECT
 public:
-	KSpreadTextDrag(QWidget *dragSource = 0L, const char *name = 0L);
-	virtual ~KSpreadTextDrag();
-	virtual bool provides(const char *mimeType);
-	void setSpreadData(GraphObj *g) {go = g;};
-	virtual QByteArray encodedData(const char* mime) const;
-	virtual const char* format(int i) const;
-	static bool canDecode(QMimeSource *e);
-	static const char* selectionMimeType();
+	ReadCB(QObject *parent=0, const char *name=0, GraphObj *g=0);
+	~ReadCB();
 
-protected:
-	GraphObj *go;
+private slots:
+	void isConnected();
+	void receiveData();
+	void endData();
+	void isError(int);
+
+private:
+	int level;
+	char *format;
+	QObject *par;
+	GraphObj *DestGO;
+	QString *res;
 };
 
-class RLPGraphDrag:public QTextDrag {
+class RLPsock:public QSocket {
 	Q_OBJECT
 public:
-	RLPGraphDrag(QWidget *dragSource = 0L, const char *name = 0L);
-	virtual ~RLPGraphDrag();
-	virtual bool provides(const char *mimeType);
-	void setGraphData(GraphObj *g);
-	virtual QByteArray encodedData(const char* mime) const;
-	virtual const char* format(int i) const;
-	static bool canDecode(QMimeSource *e);
-	static const char* selectionMimeType();
+	RLPsock(int sock, QObject *parent=0, const char *name=0, GraphObj *g=0);
 
-protected:
-	GraphObj *go1, *go2;
+private slots:
+	void readClient();
+
+private:
+	QObject *par;
+	GraphObj *SourceGO;
 };
 
+class RLPserver:public QServerSocket {
+	Q_OBJECT
+public:
+	GraphObj *SourceGO;
+
+	RLPserver(QObject* parent=0, GraphObj *g=0);
+	~RLPserver();
+	void newConnection(int socket){new RLPsock(socket, this, 0, SourceGO);};
+
+	void SetGO(GraphObj *g);
+	char *GetXML();
+	char *GetRLP();
+	char *GetTXT() {return text_plain; };
+
+signals:
+	void newConnect(RLPsock *);
+
+private:
+	char *text_xml, *text_rlp, *text_plain;
+};
+
+#endif //RLP_PORT
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// The Qt widget class implementet for RLPlot
 class RLPwidget:public QWidget {
 	Q_OBJECT
 
@@ -96,8 +125,10 @@ public slots:
 	void hScrollEvent(int pos);
 	void vScrollEvent(int pos);
 	void cmOpen();
+	void cmSaveData();
 	void cmSaveDataAs();
 	void cmExit();
+	void cmExitRLP();
 	void cmNewGraph();
 	void cmNewPage();
 	void cmDelGraph();
diff --git a/RLPLOT.RC b/RLPLOT.RC
index 2be39ca..9c502ec 100755
--- a/RLPLOT.RC
+++ b/RLPLOT.RC
@@ -1,4 +1,4 @@
-//RLPlot.RC, (C)2000, 2001, 2002, 2003, 2004, 2005 R.Lackner
+//RLPlot.RC, (C)2000-2006 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -36,39 +36,40 @@
 #define CM_PRINT       517
 #define CM_EXPORT      518
 #define CM_DELOBJ      519
-#define CM_DEFAULTS    520
-#define CM_COPY        521
-#define CM_PASTE       522
-#define CM_UPDATE      523
-#define CM_ADDAXIS     524
-#define CM_UNDO        525
-#define CM_ZOOMIN      526
-#define CM_ZOOMOUT     527
-#define CM_ZOOMFIT     528
-#define CM_FILE1       529
-#define CM_FILE2       530
-#define CM_FILE3       531
-#define CM_FILE4       532
-#define CM_FILE5       533
-#define CM_FILE6       534
-#define CM_FILLRANGE   535
-#define CM_CUT         536
-#define CM_LEGEND      537
-#define CM_LAYERS      538
-#define CM_INSROW      539
-#define CM_INSCOL      540
-#define CM_DELROW      541
-#define CM_DELCOL      542
+#define CM_DEFAULTS    522
+#define CM_COPY        523
+#define CM_PASTE       524
+#define CM_UPDATE      525
+#define CM_ADDAXIS     526
+#define CM_UNDO        527
+#define CM_ZOOMIN      528
+#define CM_ZOOMOUT     529
+#define CM_ZOOMFIT     530
+#define CM_FILE1       531
+#define CM_FILE2       532
+#define CM_FILE3       533
+#define CM_FILE4       534
+#define CM_FILE5       535
+#define CM_FILE6       536
+#define CM_FILLRANGE   537
+#define CM_CUT         538
+#define CM_LEGEND      539
+#define CM_LAYERS      540
+#define CM_INSROW      541
+#define CM_INSCOL      542
+#define CM_DELROW      543
+#define CM_DELCOL      544
+#define CM_SAVEDATA    545
 
-#define CM_T_STANDARD  560
-#define CM_T_DRAW      561
-#define CM_T_POLYLINE  562
-#define CM_T_POLYGON   563
-#define CM_T_RECTANGLE 564
-#define CM_T_ROUNDREC  565
-#define CM_T_ELLIPSE   566
-#define CM_T_ARROW     567
-#define CM_T_TEXT      568
+#define CM_T_STANDARD  550
+#define CM_T_DRAW      551
+#define CM_T_POLYLINE  552
+#define CM_T_POLYGON   553
+#define CM_T_RECTANGLE 554
+#define CM_T_ROUNDREC  555
+#define CM_T_ELLIPSE   556
+#define CM_T_ARROW     557
+#define CM_T_TEXT      558
 
 #define CM_DELKEY      600
 #define CM_LEFTARRKEY  601
@@ -112,7 +113,7 @@ BEGIN
         MENUITEM "&Print",                      CM_PRINT
         MENUITEM "&Export",                     CM_EXPORT
         MENUITEM SEPARATOR
-        MENUITEM "E&xit",                       CM_EXIT
+        MENUITEM "&Close",                      CM_EXIT
     END
     POPUP "&Edit"
     BEGIN
@@ -174,7 +175,8 @@ BEGIN
     POPUP "&File"
     BEGIN
         MENUITEM "&Open",                       CM_OPEN
-        MENUITEM "&Save as",                    CM_SAVEDATAAS
+        MENUITEM "&Save",						CM_SAVEDATA
+        MENUITEM "Save &as",                    CM_SAVEDATAAS
         MENUITEM SEPARATOR
         MENUITEM "&Print",                      CM_PRINT
         MENUITEM SEPARATOR
@@ -226,7 +228,7 @@ BEGIN
         MENUITEM "&Print",                      CM_PRINT
         MENUITEM "&Export",                     CM_EXPORT
         MENUITEM SEPARATOR
-        MENUITEM "E&xit",                       CM_EXIT
+        MENUITEM "&Close",                      CM_EXIT
     END
     POPUP "&Edit"
     BEGIN
diff --git a/TheDialog.cpp b/TheDialog.cpp
index d6721ee..5e07427 100755
--- a/TheDialog.cpp
+++ b/TheDialog.cpp
@@ -1,4 +1,4 @@
-//TheDialog.cpp, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
+//TheDialog.cpp, Copyright (c) 2001-2006 R.Lackner
 //Operating system independent code for dialog boxes
 //
 //    This file is part of RLPlot.
@@ -42,7 +42,7 @@ static int ybase = 2;
 int dlgtxtheight = 10;
 static unsigned long DlgBGcolor = 0x00e0e0e0L;
 static unsigned long DlgBGhigh = 0x00e8e8e8L;
-TextDEF DlgText = {0x00000000L, 0x00ffffffL, 4.0, 0.0f, 0.0f, 0, 
+TextDEF DlgText = {0x00000000L, 0x00ffffffL, 4.0, 0.0, 0.0, 0, 
 	TXA_HLEFT | TXA_VTOP, TXM_TRANSPARENT, TXS_NORMAL, FONT_HELVETICA, 0L}; 
 
 //prototypes: WinSpec.cpp
@@ -63,6 +63,7 @@ DlgRoot::DlgRoot(DlgInfo *tmpl)
 
 	dlg = 0L;			flags = 0L;		tabstops = 0L;
 	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;
 	CurrDisp = 0L;		oldFocus = DialogFocus;		DialogFocus = 0L;
@@ -98,6 +99,9 @@ DlgRoot::DlgRoot(DlgInfo *tmpl)
 				case COLBUTTON:
 					dlg[i]->dialog = new ColorButton(this, &tmpl[i],rc, (unsigned long)tmpl[i].ptype);
 					break;
+				case COLBUTT:
+					dlg[i]->dialog = new ColorButton(this, &tmpl[i],rc, (DWORD *)tmpl[i].ptype);
+					break;
 				case FILLBUTTON:
 					dlg[i]->dialog = new FillButton(this, &tmpl[i],rc, (FillDEF *)tmpl[i].ptype);
 					break;
@@ -202,6 +206,7 @@ DlgRoot::~DlgRoot()
 				case TEXTBOX:		delete((TextBox*)dlg[i]->dialog);			break;
 				case ARROWBUTT:		delete((ArrowButton*)dlg[i]->dialog);		break;
 				case COLBUTTON:		delete((ColorButton*)dlg[i]->dialog);		break;
+				case COLBUTT:		delete((ColorButton*)dlg[i]->dialog);		break;
 				case FILLBUTTON:	delete((FillButton*)dlg[i]->dialog);		break;
 				case SHADE3D:		delete((Shade3D*)dlg[i]->dialog);			break;
 				case LINEBUTT:		delete((LineButton*)dlg[i]->dialog);		break;
@@ -461,7 +466,7 @@ DlgRoot::GetColor(int id, DWORD *color)
 	int i;
 
 	i = FindIndex(id);
-	if(i && dlg[i]) return dlg[i]->dialog->GetColor(id, color);
+	if(i && dlg[i] && dlg[i]->dialog) return dlg[i]->dialog->GetColor(id, color);
 	return false;
 }
 
@@ -621,8 +626,13 @@ DlgRoot::ForEach(int cmd, int start, anyOutput *o)
 						dlg[next]->dialog->Command(CMD_FLUSH, 0L, 0L);
 						//if j equals cDlgs we are caught in a circular reference
 						for(j = 0, i = dlg[next]->first; i && j < cDlgs; j++) {
-							dlg[next]->dialog->Command(CMD_ADDCHILD, (void*)dlg[i = FindIndex(i)]->dialog, 0L);
-							if(i) i = dlg[i]->next;
+							if(i = FindIndex(i)) {
+								dlg[next]->dialog->Command(CMD_ADDCHILD, (void*)dlg[i]->dialog, 0L);
+								i = dlg[i]->next;
+								}
+							else{
+								i=i;
+								}
 							}
 						}
 					else return;	//error bad structured template
@@ -1007,6 +1017,12 @@ ColorButton::ColorButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, unsigned lon
 	col = color;
 }
 
+ColorButton::ColorButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, DWORD *color)
+	:Dialog(par, desc, rec)
+{
+	col = *color;
+}
+
 void
 ColorButton::DoPlot(anyOutput *o)
 {
@@ -1692,15 +1708,17 @@ bool
 Text::Select(int x, int y, anyOutput *o)
 {
 	if(WWWbrowser && WWWbrowser[0] && txt && (flags & HREF) && IsInRect(&cr, x, y)) {
+		o->MouseCursor(MC_WAIT, false);
 		sprintf(TmpTxt, "%s %s", WWWbrowser, txt);
-		if(parent)parent->Command(CMD_CONTINUE, 0L, o);
+		if(parent && (flags & TOUCHEXIT))parent->Command(CMD_ENDDIALOG, 0L, o);
+		else if(parent)parent->Command(CMD_CONTINUE, 0L, o);
 #ifdef _WINDOWS
 		WinExec(TmpTxt, SW_SHOWMAXIMIZED); 
 #else
 		strcat(TmpTxt, " &");
 		system(TmpTxt);
 #endif
-		if(parent)parent->Command(CMD_ENDDIALOG, 0L, o);
+		o->MouseCursor(MC_ARROW, false);
 		return true;
 		}
 	return false;
@@ -1926,7 +1944,10 @@ RangeInput::Select(int x, int y, anyOutput *o)
 
 	bRes = InputText::Select(x, y, o);
 	if(bRes && data) {
-		if(DialogFocus == this) data->Command(CMD_ETRACC, Text, 0L);
+		if(DialogFocus == this){
+			data->Command(CMD_ETRACC, Text, 0L);
+			if(Text) Text->Update(1, o, 0L); 
+			}
 		else data->Command(CMD_ETRACC, 0L, 0L);
 		}
 	return bRes;
@@ -3115,28 +3136,171 @@ LinePat::MBtrack(MouseEvent *mev, anyOutput *o)
 		}
 }
 
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Dialog meta compiler
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+static char *std_text[] = {"OK", "Cancel", "", "x", "y", "z", "-", "Next >>", "<< Prev."};
+
+DlgInfo *CompileDialog(char* tmpl, void **ptypes)
+{
+	char **lines, **fields, **flags;
+	int i, j, nlines, nfields, nflags;
+	unsigned int hv;
+	DlgInfo *Dlg;
+
+	std_text[2] = Units[defs.cUnits].display;
+	lines = split(tmpl, '\n', &nlines);
+	if(!lines || nlines <1 ||(!(Dlg = (DlgInfo*)malloc(nlines*sizeof(DlgInfo))))) return 0L;
+	for(i = 0; i < nlines; i++) if(lines[i] && lines[i][0]){
+		if(fields = split(lines[i], ',', &nfields)) {
+			if(nfields == 10) {
+				Dlg[i].id = Dlg[i].next = Dlg[i].first = 0;
+				sscanf(fields[0], "%d", &Dlg[i].id);		sscanf(fields[1], "%d", &Dlg[i].next);
+				sscanf(fields[2], "%d", &Dlg[i].first);		Dlg[i].flags = 0L;
+				if(flags = split(fields[3], '|', &nflags)) {
+					for(j = 0; j < nflags; j++){
+						hv = HashValue((unsigned char *)str_trim(flags[j]));
+						switch(hv) {
+						case 196904:		Dlg[i].flags |= CHECKED;		break;
+						case 4444568:		Dlg[i].flags |= TOUCHEXIT;		break;
+						case 284491160:		Dlg[i].flags |= TOUCHSELEXIT;	break;
+						case 235859:		Dlg[i].flags |= ISRADIO;		break;
+						case 942268:		Dlg[i].flags |= ISPARENT;		break;
+						case 4220131:		Dlg[i].flags |= OWNDIALOG;		break;
+						case 198260:		Dlg[i].flags |= DEFAULT;		break;
+						case 54530:			Dlg[i].flags |= HIDDEN;			break;
+						case 1011472:		Dlg[i].flags |= NOSELECT;		break;
+						case 3546:			Dlg[i].flags |= HREF;			break;
+						case 62296:			Dlg[i].flags |= NOEDIT;			break;
+						case 231330:		Dlg[i].flags |= LASTOBJ;		break;
+						case 224595:		Dlg[i].flags |= EXRADIO;		break;
+							}
+						free(flags[j]);
+						}
+					free(flags);
+					}
+				hv = HashValue((unsigned char *)str_trim(fields[4]));
+				switch(hv) {
+				case 17108522:		Dlg[i].type = PUSHBUTTON;	break;
+				case 3252180:		Dlg[i].type = ARROWBUTT;	break;
+				case 3296810:		Dlg[i].type = COLBUTTON;	break;
+				case 206036:		Dlg[i].type = COLBUTT;		break;
+				case 13602346:		Dlg[i].type = FILLBUTTON;	break;
+				case 261312:		Dlg[i].type = SHADE3D;		break;
+				case 948692:		Dlg[i].type = LINEBUTT;		break;
+				case 282068:		Dlg[i].type = SYMBUTT;		break;
+				case 3403091:		Dlg[i].type = FILLRADIO;	break;
+				case 1130835:		Dlg[i].type = SYMRADIO;		break;
+				case 787668:		Dlg[i].type = CHECKBOX;		break;
+				case 62812:			Dlg[i].type = RADIO0;		break;
+				case 62813:			Dlg[i].type = RADIO1;		break;
+				case 62814:			Dlg[i].type = RADIO2;		break;
+				case 15460:			Dlg[i].type = LTEXT;		break;
+				case 16996:			Dlg[i].type = RTEXT;		break;
+				case 13156:			Dlg[i].type = CTEXT;		break;
+				case 51300:			Dlg[i].type = EDTEXT;		break;
+				case 16235656:		Dlg[i].type = RANGEINPUT;	break;
+				case 51281:			Dlg[i].type = EDVAL1;		break;
+				case 14534481:		Dlg[i].type = INCDECVAL1;	break;
+				case 229196:		Dlg[i].type = HSCROLL;		break;
+				case 286540:		Dlg[i].type = VSCROLL;		break;
+				case 71804:			Dlg[i].type = TXTHSP;		break;
+				case 3418:			Dlg[i].type = ICON;			break;
+				case 14196:			Dlg[i].type = GROUP;		break;
+				case 909332:		Dlg[i].type = GROUPBOX;		break;
+				case 16408:			Dlg[i].type = SHEET;		break;
+				case 970282:		Dlg[i].type = ODBUTTON;		break;
+				case 957537:		Dlg[i].type = LISTBOX1;		break;
+				case 1108443:		Dlg[i].type = TREEVIEW;		break;
+				case 237304:		Dlg[i].type = LINEPAT;		break;
+				case 269332:		Dlg[i].type = TEXTBOX;		break;
+				case 787858:		Dlg[i].type = CHECKPIN;		break;
+				case 17284:			Dlg[i].type = TRASH;		break;
+				case 51627:			Dlg[i].type = CONFIG;		break;
+				default:			Dlg[i].type = NONE;			break;
+					}
+				sscanf(fields[5], "%d", &j);
+				if(j < 0) Dlg[i].ptype = (void*)std_text[(-j)-1];
+				else if(j > 0) Dlg[i].ptype = ptypes[j-1];
+				else Dlg[i].ptype = (void*)0L;
+				sscanf(fields[6], "%d", &Dlg[i].x);		sscanf(fields[7], "%d", &Dlg[i].y);
+				sscanf(fields[8], "%d", &Dlg[i].w);		sscanf(fields[9], "%d", &Dlg[i].h);
+				}
+			for(j = 0; j < nfields; j++)free(fields[j]);
+			free(fields);
+			}
+		free(lines[i]);
+		}
+	free(lines);
+	return Dlg;
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Use marked ranges as default for dialog ranges
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+void UseRangeMark(DataObj *d, int type, char *r0, char *r1, char *r2, char *r3,
+	char *r4, char *r5, char *r6, char *r7, char *r8, char *r9, char *r10)
+{
+	char *dst[] = {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10};
+	char *mrk, **ra =0L;;
+	int i, ranges=0;
+	bool success = false;
+	RECT vrc;
+	AccRange *ar;
+
+	if(d && type) {
+		d->ValueRec(&vrc);
+		if(d->Command(CMD_GETMARK, &mrk, 0L)) {
+			ra = split(mrk, ';', &ranges);
+			ar = new AccRange(mrk);			ar->BoundRec(&vrc);			delete ar;
+			}
+		switch(type) {
+		case 1:
+			if(ranges > 1) {
+				for(i = 0; i < 11; i++) if(dst[i]) {
+					if(i < ranges) sprintf(dst[i], "%s", ra[i]);
+					else sprintf(dst[i], "%c%d:%c%d", 'a'+i+vrc.left, vrc.top+1, 'a'+i+vrc.left, vrc.bottom+1);
+					}
+				success = true;
+				}
+			break;
+			}
+		}
+	else {
+		vrc.left = vrc.top = 0;		vrc.right = vrc.bottom = 9;
+		}
+	if(!success) for(i = 0; i < 11; i++) {
+		if(dst[i])sprintf(dst[i], "%c%d:%c%d", 'a'+i+vrc.left, vrc.top+1, 'a'+i+vrc.left, vrc.bottom+1);
+		}
+	if(ra) {
+		for(i = 0; i < ranges; i++) if(ra[i]) free(ra[i]);
+		free(ra);
+		}
+}
+
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Select color out of predefined palette
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 DWORD GetNewColor(DWORD oldColor)
 {
-	DlgInfo *ColDlg, ColDlgTmpl[] = {
-		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 200, 10, 45, 12},
-		{2, 3, 0, 0x0L, PUSHBUTTON, (void*)"Cancel", 200, 25, 45, 12},
-		{3, 7, 4, CHECKED | ISPARENT, GROUPBOX, (void*)" RGB ", 200, 55, 45, 40},
-		{4, 5, 0, 0x0L, LTEXT, (void*)0L, 210, 60, 45, 8},
-		{5, 6, 0, 0x0L, LTEXT, (void*)0L, 210, 70, 45, 8},
-		{6, 0, 0, 0x0L, LTEXT, (void*)0L, 210, 80, 45, 8},
-		{7, 0, 8, CHECKED | ISPARENT, GROUP, 0L, 0, 0, 0, 0}};
+	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;
 	int ilevels[] = {0x0, 0x40, 0x80, 0xc0, 0xe0, 0xff};
 	int i, ir, ig, ib, col, row, res;
 	DlgRoot *Dlg;
 	void *hDlg;
 
-	if(!(ColDlg = (DlgInfo *)malloc(230 * sizeof(DlgInfo))))return oldColor;
-	memcpy(ColDlg, ColDlgTmpl, 14 * sizeof(DlgInfo));
+	if(!(ColDlg = (DlgInfo *)realloc(ColDlg, 230 * sizeof(DlgInfo))))return oldColor;
 	for(ir=row=col=0, i= 7; ir<6; ir++) for(ig=0; ig<6; ig++) for(ib=0; ib<6; ib++) {
 		ColDlg[i].id = i+1;					ColDlg[i].next = i+2;
 		ColDlg[i].type = COLBUTTON;			ColDlg[i].first = 0;
@@ -3232,7 +3396,7 @@ void ConfShade(FillDEF *oldfill)
 		}
 	hDlg = CreateDlgWnd("Shade and Fill Color", 50, 50, 300, 180, Dlg, 0x0L);
 	bRedraw = true;
-	o = Dlg->GetOutputClass();			o->LightSource(8.0, -16.0);
+	o = Dlg->GetOutputClass();			o->LightSource(32.0, 16.0);
 	rc_prev.left =240;					rc_prev.right = 280;
 	rc_prev.top = 100;					rc_prev.bottom = 140;
 	do {
@@ -3281,7 +3445,8 @@ void GetNewFill(FillDEF *oldfill)
 	FILL_DCROSS, FILL_STIPPLE1, FILL_STIPPLE2, FILL_STIPPLE3, FILL_STIPPLE4, 
 	FILL_STIPPLE5, FILL_ZIGZAG, FILL_COMBS, FILL_BRICKH, FILL_BRICKV, FILL_BRICKDU, 
 	FILL_BRICKDD, FILL_TEXTURE1, FILL_TEXTURE2, FILL_WAVES1, FILL_SCALES, FILL_SHINGLES, 
-	FILL_WAVES2, FILL_HERRING, FILL_CIRCLES, FILL_GRASS, FILL_FOAM, FILL_RECS};
+	FILL_WAVES2, FILL_HERRING, FILL_CIRCLES, FILL_GRASS, FILL_FOAM, FILL_RECS, FILL_HASH,
+	FILL_WATER};
 	double fscale;
 	DlgInfo FillDlgBase[] = {
 		{1, 2, 0, DEFAULT, PUSHBUTTON, (void*)"OK", 170, 10, 45, 12},
@@ -3478,7 +3643,8 @@ bool ShowLayers(GraphObj *root)
 				else {
 					Dlg->ShowItem(500, false);			Dlg->ShowItem(501, false);
 					}
-				if(cgo->Id == GO_GRAPH || cgo->Id == GO_PAGE || cgo->Id == GO_POLARPLOT){
+				if(cgo->Id == GO_GRAPH || cgo->Id == GO_PAGE || cgo->Id == GO_POLARPLOT
+					|| cgo->Id == GO_GRID3D){
 					Dlg->ShowItem(550, true);
 					if(res == 550) if(cgo->Command(CMD_CONFIG, 0L, 0L))
 						cgo->Command(CMD_REDRAW, 0L, 0L);
@@ -3520,6 +3686,7 @@ void ShowBanner(bool show)
 		{5, 0, 0, LASTOBJ, LTEXT, (void*)"... is loading", 45, 25, 50, 9}};
 	DlgRoot *Dlg;
 	void *hDlg;
+	bool init = true;
 	int res, cnt = 5;
 
 	if(!show) return;
@@ -3533,8 +3700,6 @@ void ShowBanner(bool show)
 	Dlg->TextFont(3, FONT_TIMES);
 	Dlg->SetColor(3, 0x00ff0000L);
 	hDlg = CreateDlgWnd("RLPlot", 50, 50, 200, 80, Dlg, 0x7L);
-	FindBrowser();
-	SpreadMain(true);
 	ShowDlgWnd(hDlg);
 	do{
 		LoopDlgWnd();
@@ -3542,9 +3707,14 @@ void ShowBanner(bool show)
 		switch (res) {
 		case 0:						//loose focus: get it again
 			ShowDlgWnd(hDlg);
-			res = -1;
+			cnt = 5;		res = -1;
 			break;
 		case -2:					//Timer event
+			if(init) {
+				init = false;
+				FindBrowser();		SpreadMain(true);
+				ShowDlgWnd(hDlg);	cnt = 4;
+				}
 			if((cnt--) <=0) res = 1;
 			break;
 			}
@@ -3567,7 +3737,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-2005 R. Lackner", 5, 54, 110, 8},
+		{7, 8, 0, 0x0L, CTEXT, (void*)"Copyright (C) 2002-2006 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},
@@ -3581,7 +3751,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-2005 R. Lackner", 5, 54, 110, 8},
+		{7, 8, 0, 0x0L, CTEXT, (void*)"Copyright (C) 2002-2006 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},
@@ -3724,7 +3894,7 @@ bool FillSsRange(DataObj *d, char **range, GraphObj *msg_go)
 	double startval = 1.0, stepval = 1.0;
 	static char *formula = 0L;
 	if(!formula && CurrText && CurrText->isFormula()) {
-		if(CurrText->GetText(TmpTxt,TMP_TXT_SIZE)) formula = strdup(TmpTxt);
+		if(CurrText->GetText(TmpTxt,TMP_TXT_SIZE, false)) formula = strdup(TmpTxt);
 		}
 	if(!formula) formula = strdup("=a1");
 	DlgInfo RangeDlg[] = {
diff --git a/TheDialog.h b/TheDialog.h
index e41ffcf..d3ac27d 100755
--- a/TheDialog.h
+++ b/TheDialog.h
@@ -1,4 +1,4 @@
-//TheDialog.h, Copyright (c) 2001, 2002, 2003, 2004, 2005 R.Lackner
+//TheDialog.h, Copyright (c) 2001-2006 R.Lackner
 //Definitions for TheDialog.cpp
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //
@@ -37,7 +37,7 @@ typedef struct {
 } TabSHEET;
 
 //types of dialogs
-enum {NONE, PUSHBUTTON, ARROWBUTT, COLBUTTON, FILLBUTTON, SHADE3D, LINEBUTT, SYMBUTT,
+enum {NONE, PUSHBUTTON, ARROWBUTT, COLBUTTON, COLBUTT, FILLBUTTON, SHADE3D, LINEBUTT, SYMBUTT,
 	FILLRADIO, SYMRADIO, CHECKBOX, RADIO0, RADIO1, RADIO2, LTEXT, RTEXT, CTEXT, EDTEXT, 
 	RANGEINPUT, EDVAL1, INCDECVAL1, HSCROLL, VSCROLL, TXTHSP, ICON, GROUP, 
 	GROUPBOX, SHEET, ODBUTTON, LISTBOX1, TREEVIEW, LINEPAT, TEXTBOX, CHECKPIN, TRASH,
@@ -57,6 +57,8 @@ enum {NONE, PUSHBUTTON, ARROWBUTT, COLBUTTON, FILLBUTTON, SHADE3D, LINEBUTT, SYM
 #define NOEDIT       0x00000400L
 #define LASTOBJ      0x00100000L
 
+#define EXRADIO      TOUCHEXIT|ISRADIO
+
 //owner draw button commands
 enum {OD_CREATE, OD_DELETE, OD_DRAWNORMAL, OD_DRAWSELECTED, OD_SELECT, OD_MBTRACK,
 	OD_SETLINE, OD_GETLINE, OD_SETFILL, OD_GETFILL, OD_ACCEPT};
@@ -180,6 +182,7 @@ private:
 class ColorButton:public Dialog {
 public:
 	ColorButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, unsigned long color);
+	ColorButton(tag_DlgObj *par, DlgInfo * desc, RECT rec, DWORD *color);
 	void DoPlot(anyOutput *o);
 	bool Select(int x, int y, anyOutput *o);
 	bool GetColor(int id, DWORD *color) {*color = col; return true;};
@@ -524,6 +527,11 @@ private:
 	DWORD *pPattern;
 };
 
+//prototypes TheDialog.cpp
+void 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);
+DlgInfo *CompileDialog(char* tmpl, void **ptypes);
+
 //prototypes ODbutton.cpp
 void OD_DrawOrder(int cmd, void *par, RECT *rec, anyOutput *o, void *data, int id);
 int ExecDrawOrderButt(GraphObj *parent, GraphObj *obj, int id);
diff --git a/UtilObj.cpp b/UtilObj.cpp
index 7950b37..0913bb5 100755
--- a/UtilObj.cpp
+++ b/UtilObj.cpp
@@ -1,4 +1,4 @@
-//UtilObj.cpp, (c)2000, 2001, 2002, 2003, 2004, 2005 by R. Lackner
+//UtilObj.cpp, (c) 2000-2006 by R. Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include <ctype.h>
 
 #include <fcntl.h>				//file open flags
 #include <sys/stat.h>			//I/O flags
@@ -81,7 +82,7 @@ EditText::~EditText()
 	HideCopyMark();
 	if(CurrText == this)	CurrText = 0L;
 	if(text) free(text);	text = 0L;
-	if(ftext) free(ftext);	ftext = 0L;
+//	if(ftext) free(ftext);	ftext = 0L;
 }
 
 bool
@@ -168,11 +169,12 @@ EditText::Update(int select, anyOutput *Out, POINT *MousePos)
 				}
 			break;
 		case 2:							//inactive spreadsheet cell
-			if((type & 0xff) == ET_FORMULA) Align = TXA_VCENTER | TXA_HRIGHT;
+			if(CurrText == this) {
+				FindType();
+				}
 			if(crb.x > rb.x) {
 				crb.x = rb.x;	crb.y = rb.y;
 				}
-			if(CurrText == this) FindType();
 			bgLine = &ETbgnn; bgFill = &ETfbnn; TextCol = 0x00000000L;
 			if(Out) Redraw(Out, true);
 			break;
@@ -194,18 +196,18 @@ EditText::Redraw(anyOutput *Out, bool display)
 {
 	RECT rc;
 	POINT MyPos;
-	char *txt, tmptxt[80];
+	char *txt, tmptxt[500];
 	int w, h, o_crbx;
 	bool b_clip = false;
 	anyOutput *opc;
-	anyResult *fmres;
+	anyResult cres;
 
 	if(!parent && disp) Out = disp;
 	if(loc.x <1 || rb.x < 1 || loc.y <1 || rb.y <1) return false;
 	o_crbx = crb.x;			crb.x = rb.x;				crb.y = rb.y;
 	if (Out) {
 		if (m1 >m2) Swap(m1, m2);
-		if(((type & 0xff) == ET_UNKNOWN) && text && text[0]) FindType();
+		if(((type & 0xff) == ET_UNKNOWN) && text && text[0] && (bgLine == &ETbgnn || bgLine == &ETbgmn)) FindType();
 		Out->TxtSet.Align = Align;		Out->TxtSet.ColTxt = TextCol;
 		Out->TxtSet.ColBg = bgLine->color;
 		if(text && text[0]) {
@@ -227,42 +229,35 @@ EditText::Redraw(anyOutput *Out, bool display)
 			}
 		if(ftext) free(ftext);		ftext = 0L;
 		if(text && text[0]){
-			if((type & 0xff) == ET_FORMULA && (bgLine == &ETbgnn || bgLine == &ETbgmn)) {
+			if(bgLine == &ETbgnn || bgLine == &ETbgmn) {
 				Out->TxtSet.Align = TXA_HLEFT | TXA_VCENTER;
-				if(type & ET_CIRCULAR) strcpy (tmptxt, "#CIRC.");
-				else if((fmres = do_formula((DataObj*)parent, text+1)) && fmres->type != ET_ERROR) {
-					b_clip = false;
-					if(fmres->type == ET_VALUE) {
-						sprintf(tmptxt, "%g", Value = fmres->value);
-						fit_num_rect(Out, rb.x - loc.x, tmptxt);
-						Out->TxtSet.Align = TXA_HRIGHT | TXA_VCENTER;
-						}
-					else if(fmres->type == ET_TEXT) {
-						if(ftext) free (ftext);		ftext = 0L;
-						if(fmres->text) ftext = strdup(fmres->text);
-						if(fmres->text && strlen(fmres->text)<sizeof(tmptxt)) strcpy(tmptxt, fmres->text);
-						else if(fmres->text) sprintf(tmptxt,"#SIZE");
-						else tmptxt[0] = 0;
-						}
-					else strcpy(tmptxt, "#VALUE");
-					}
-				else sprintf(tmptxt, "#ERROR");
-				txt = tmptxt;
-				}
-			else if((type &0xff) == ET_VALUE) {
-				Out->oGetTextExtent(text, strlen(text), &w, &h);
-				if(w >= (rb.x - loc.x-8) && (bgLine == &ETbgnn || bgLine == &ETbgmn)) {
-					sprintf(tmptxt, "%g", Value);
+				GetResult(&cres, false);				TranslateResult(&cres);
+				Value = cres.value;
+				switch (cres.type) {
+				case ET_VALUE:
+					Out->TxtSet.Align = TXA_HRIGHT | TXA_VCENTER;
+					b_clip = false;				strcpy(tmptxt, cres.text);
 					fit_num_rect(Out, rb.x - loc.x, tmptxt);
-					txt = tmptxt;		b_clip = false;
-					}
-				else txt = text;
-				}
-			else if((type & 0xff) == ET_TEXT) {
-				if(text && text[0] == '\'' && (bgLine == &ETbgnn || bgLine == &ETbgmn)) {
-					txt = text+1;
+					Int2Nat(tmptxt);			break;
+				case ET_BOOL:	case ET_DATE:	case ET_TIME:	case ET_DATETIME:
+				case ET_TEXT:
+					Out->TxtSet.Align = cres.type == ET_TEXT ? 
+						TXA_HLEFT | TXA_VCENTER : TXA_HRIGHT | TXA_VCENTER;
+					if(ftext) free (ftext);		ftext = 0L;
+					if(cres.text) ftext = strdup(cres.text);
+					if(cres.text && strlen(cres.text)<sizeof(tmptxt)) 
+						strcpy(tmptxt, cres.text[0] != '\'' ? cres.text : cres.text +1);
+					else if(cres.text) sprintf(tmptxt,"#SIZE");
+					else tmptxt[0] = 0;			
+					Out->oGetTextExtent(tmptxt, strlen(tmptxt), &w, &h);
+					b_clip = (crb.x - loc.x) < (w+(h>>1)) ? true : false;
+					break;
+				case ET_ERROR:
+					strcpy(tmptxt, "#ERROR");	break;
+				default: 
+					strcpy(tmptxt, "#VALUE");	break;
 					}
-				else txt = text;
+				txt = tmptxt;
 				}
 			else txt = text;
 			MyPos.y = (loc.y+rb.y)>>1;
@@ -459,16 +454,18 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 				}
 			return false;
 		case CMD_ADDTXT:
-			if(data_obj && *((char*)data_obj) && text && 
+			if((tag1 = (char*)data_obj) && *tag1 && text && 
 				(type == ET_TEXT || type == ET_UNKNOWN || type == ET_FORMULA)){
 				if(hasMark()) Command(CMD_DELETE, 0L, 0L);
 				else Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
 				if(m1 > -1 && m2 > -1) Command(CMD_DELETE, 0L, 0L);
+				for(k = 0; tag1[k] && tag1[k] == text[k]; k++);
+				if(tag1[k]!=';') k = 0;
 				for(i = 0; i < CursorPos && text[i]; i++) TmpTxt[i] = text[i];
-				j = i + sprintf(TmpTxt+i, "%s", (char*)data_obj);
+				j = i + sprintf(TmpTxt+i, "%s", tag1+k);
 				if(text[i]) sprintf(TmpTxt+j, "%s", text+i);
 				if(text = (char*)realloc(text, strlen(TmpTxt)+2)) strcpy(text, TmpTxt);
-				CursorPos += strlen((char*)data_obj);
+				CursorPos += strlen(tag1+k);
 				Out->Focus();
 				Update(1, Out, 0L);
 				}
@@ -484,9 +481,6 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 			CursorPos--;						//continue as if delete
 		case CMD_DELETE:
 			if(!text) return false;
-			if(parent) {
-				((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' ? this : 0L, 0L);
-				}
 			if(cmd == CMD_DELETE) Undo.TextCell(this, Out, text, &CursorPos, &m1, &m2, parent, 0L);
 			if(parent) {
 				((DataObj*)parent)->Command(CMD_MRK_DIRTY, 0L, 0L);
@@ -512,6 +506,9 @@ EditText::Command(int cmd, anyOutput *Out, void *data_obj)
 					}
 				if(Out)Redraw(Out, (bRet = true));
 				}
+			if(parent) {
+				((DataObj*)parent)->Command(CMD_ETRACC, text[0] == '=' ? this : 0L, 0L);
+				}
 			if(Out)Out->TextCursor(text, MyPos, (POINT *) NULL, &CursorPos,
 				scroll_et == this ? scroll_dist : scroll_dist=0);
 			return bRet;
@@ -734,7 +731,8 @@ EditText::GetValue(double *v)
 		return false;
 		}
 	if(CurrText == this && !(type & ET_BUSY)) FindType();
-	if((type & 0xff) == ET_VALUE){
+	if((type & 0xff) == ET_VALUE || (type & 0xff) == ET_BOOL || (type & 0xff) == ET_DATE 
+		|| (type & 0xff) == ET_TIME || (type & 0xff) == ET_DATETIME){
 		*v = Value;			return true;
 		}
 	if((type & 0xff) == ET_FORMULA && text && text[0]){
@@ -757,15 +755,30 @@ EditText::GetValue(double *v)
 }
 
 bool
-EditText::GetText(char *tx, int size)
+EditText::GetText(char *tx, int size, bool bTranslate)
 {
-	char *t;
+	char *t = 0L;
+	static char tmp_txt[40];
+	anyResult res;
 
-	if(text && text[0]) {
+	if((type & 0xff) == ET_TEXT && text && text[0]) {
 		if(text[0] =='\'' && text[1]) t = text + 1;
 		else t = text;
 		}
-	else t = 0L;
+	else if(bTranslate) {
+		GetResult(&res, false);					TranslateResult(&res);
+		switch (res.type) {
+		case ET_VALUE:
+			strcpy(tmp_txt, res.text);			t = tmp_txt;
+			Int2Nat(tmp_txt);					break;
+		case ET_BOOL:		case ET_DATE:		case ET_TIME:	
+		case ET_DATETIME:	case ET_TEXT:
+			t = res.text;						break;
+		default:
+			t = 0L;								break;
+			}
+		}
+	else if(text && text[0]) t = (text[0] =='\'' && text[1]) ? text+1 : text;
 	if(t) {
 		if((int)strlen(t) < size) strcpy(tx, t);
 		else {
@@ -773,9 +786,9 @@ EditText::GetText(char *tx, int size)
 			}
 		return true;
 		}
-	if((type & 0xff) == ET_VALUE) {
+	else if((type & 0xff) == ET_VALUE) {
 		if(text = (char*)realloc(text, 20)) sprintf(text, "%g", Value);
-		if(text && text[0]) return(GetText(tx, size));
+		if(text && text[0]) return(GetText(tx, size, false));
 		}
 	return false;
 }
@@ -796,8 +809,9 @@ EditText::GetResult(anyResult *r, bool use_last)
 		return true;
 		}
     if((type & 0xff) == ET_UNKNOWN) FindType();
-	if((type & 0xff) == ET_VALUE) {
-		r->text = 0L;	r->value = Value;		r->type = ET_VALUE;
+	if((type & 0xff) == ET_VALUE || (type & 0xff) == ET_BOOL || (type & 0xff) == ET_DATE 
+		|| (type & 0xff) == ET_TIME || (type & 0xff) == ET_DATETIME){
+		r->text = 0L;	r->value = Value;		r->type = (type & 0xff);
 		return true;
 		}
 	if((type & 0xff) == ET_TEXT) {
@@ -818,8 +832,10 @@ EditText::GetResult(anyResult *r, bool use_last)
 			type |= ET_BUSY;
 			if(res = do_formula((DataObj*)parent, text+1)) {
 				if(res->type == ET_VALUE) Value = res->value;
-				else Value = 0.0;
-				type &= ~ET_BUSY;
+				else if(res->type == ET_ERROR) {
+					res->text = "#ERROR";	res->type = ET_TEXT;
+					}
+				else Value = 0.0;	type &= ~ET_BUSY;
 				memcpy(r, res, sizeof(anyResult));
 				return true;
 				}
@@ -854,43 +870,6 @@ EditText::SetText(char *t)
 	return false;
 }
 
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// return the ASCII reprentation of value of text if applicable. If not return
-//    the text with double quotes: comma separated file syntax.
-bool
-EditText::GetItem(char *dest, int size)
-{
-	char tmp[50];
-	int i;
-
-	if(!text || !text[0] || !dest || size < 3) return false;
-	if((type & 0xff) == ET_UNKNOWN) FindType();
-	if(CurrText == this) FindType();
-	//its a value
-	if((type & 0xff) == ET_VALUE){
-		if(text && strlen(text) < (sizeof(tmp)-1)){
-			strcpy(tmp, text);
-			if(defs.DecPoint[0] != '.') {
-				for(i = 0; tmp[i]; i++) 
-					if(tmp[i] == defs.DecPoint[0]) tmp[i]='.';
-				}
-			}
-		else {
-			sprintf(tmp, "%f", Value);			RmTrail(tmp);
-			}
-		for(i = 0; i < (size-1) && tmp[i]; i++) dest[i] = tmp[i];
-		dest[i] = 0;
-		}
-	//else its a string
-	else {
-		dest[0] = '"';
-		for(i = 1; i < (size-2) && text[i-1]; i++) dest[i] = text[i-1];
-		dest[i++] = '"';
-		dest[i] = 0;
-		}
-	return true;
-}
-
 void
 EditText::SetRec(RECT *rc)
 {
@@ -903,7 +882,8 @@ bool
 EditText::isValue()
 {
 	if((type & 0xff)==ET_UNKNOWN) FindType();
-	return (type == ET_VALUE || type == ET_FORMULA);
+	return (type == ET_VALUE || type == ET_FORMULA || type == ET_BOOL
+		|| type == ET_DATE || type == ET_TIME || type == ET_DATETIME);
 }
 
 bool
@@ -916,25 +896,59 @@ EditText::isFormula()
 void
 EditText::FindType()
 {
-	if(text && text[0] == '=') {
+	int i, c1, c2, c3, c4;
+
+	if(!text || !text[0]) {
 		Align = TXA_VCENTER | TXA_HRIGHT;
-		type = ET_FORMULA;
+		if ((type && 0xff) == ET_VALUE) type = ET_VALUE;
+		else type = ET_UNKNOWN;
+		return;
 		}
-	else if(text && (Txt2Flt(text, &Value))) {
+	if(text[0] == '=') {
 		Align = TXA_VCENTER | TXA_HRIGHT;
-		type = ET_VALUE;
-		}
-	else if (text && text[0]) {
-		Align = TXA_VCENTER | TXA_HLEFT;
-		type = ET_TEXT;
+		type = ET_FORMULA;
 		}
-	else if ((type && 0xff) == ET_VALUE) {
-		Align = TXA_VCENTER | TXA_HRIGHT;
-		type = ET_VALUE;
+	else if(isdigit(text[0]) || text[0] == '.' || text[0] == defs.DecPoint[0]) {
+		for(i = c1 = c2 = c3 = c4 = 0; text[i]; i++) {
+			switch(text[i]) {
+			case '.':		c1++;		break;
+			case '-':		c2++;		break;
+			case '/':		c3++;		break;
+			case ':':		c4++;		break;
+				}
+			}
+		if(c1 < 2 && c2 < 2 && !c3  && !c4 && Txt2Flt(text, &Value)) {
+			Align = TXA_VCENTER | TXA_HRIGHT;
+			type = ET_VALUE;
+			}
+		else if((c1 == 2 || c2 == 2 || c3 == 2) && date_value(text, 0L, &Value)) {
+			Align = TXA_VCENTER | TXA_HRIGHT;
+			type = c4 == 2 ? ET_DATETIME : ET_DATE;
+			}
+		else if((c4 == 1 || c4 == 2) && date_value(text, "H:M:S", &Value)) {
+			Align = TXA_VCENTER | TXA_HRIGHT;
+			type = ET_TIME;
+			}
+		else {
+			Align = TXA_VCENTER | TXA_HLEFT;
+			type = ET_TEXT;
+			}
 		}
 	else {
-		Align = TXA_VCENTER | TXA_HRIGHT;
-		type = ET_UNKNOWN;
+		if(0 == strcmp(text, "true")) {
+			Value = 1.0;
+			Align = TXA_VCENTER | TXA_HRIGHT;
+			type = ET_BOOL;
+			}
+		else if(0 == strcmp(text, "false")) {
+			Value = 0.0;
+			Align = TXA_VCENTER | TXA_HRIGHT;
+			type = ET_BOOL;
+			}
+		else {
+			Align = TXA_VCENTER | TXA_HLEFT;
+			type = ET_TEXT;
+			}
 		}
 }
 
@@ -1353,10 +1367,10 @@ DataObj::GetValue(int row, int col, double *v)
 }
 
 bool
-DataObj::GetText(int row, int col, char *txt, int len)
+DataObj::GetText(int row, int col, char *txt, int len, bool bTranslate)
 {
 	if(row < 0 || row >= cRows || col < 0 || col >= cCols) return false;
-	if(txt && etRows[row][col]) return etRows[row][col]->GetText(txt, len);
+	if(txt && etRows[row][col]) return etRows[row][col]->GetText(txt, len, bTranslate);
 	return false;
 }
 
@@ -1398,6 +1412,37 @@ DataObj::FlushData()
 	etRows = 0L;
 }
 
+bool
+DataObj::ValueRec(RECT *rc)
+{
+	int r, c;
+	double val;
+
+	if(etRows && rc){
+		rc->left = cCols;	rc->right = 0;
+		rc->bottom = 0;		rc->top = cRows;
+		for(r = 0; r < cRows; r++) if(etRows[r]) {
+			for (c = 0; c< cCols; c++) {
+				if(etRows[r][c] && etRows[r][c]->GetValue(&val)) {
+					if(c < rc->left) rc->left =  c;
+					if(c > rc->right) rc->right =  c;
+					else c = rc->right;
+					if(r > rc->bottom) rc->bottom =  r;
+					else c = rc->right;
+					if(r < rc->top) rc->top =  r;
+					}
+				}
+			}
+		if(rc->right < rc->left) rc->right = rc->left < cCols ? rc->left : rc->left = 0;
+		if(rc->bottom < rc->top) rc->bottom = rc->top < cRows ? rc->top : rc->top = 0;
+		if(!rc->bottom && !rc->top && !rc->right && !rc->left) {
+			rc->right = cCols-1;	rc->bottom = cRows-1;
+			}
+		return true;
+		}
+	return false;
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Store Data Object as strings: less memory required than with DataObj
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1876,6 +1921,9 @@ Default::Default()
 	axis_color = 0x0L;	
 	svgAttr = svgScript = currPath = IniFile = 0L;
 	File1 = File2 = File3 = File4 = File5 = File6 = 0L;
+	fmt_date = strdup("Z.V.Y");
+	fmt_time = strdup("H:M:S");
+	fmt_datetime = strdup("Z.V.Y H:M:S");
 }
 
 Default::~Default()
@@ -1889,6 +1937,8 @@ Default::~Default()
 	if(File1) free(File1);			if(File2) free(File2);
 	if(File3) free(File3);			if(File4) free(File4);
 	if(File5) free(File5);			if(File6) free(File6);
+	if(fmt_date) free(fmt_date);	if(fmt_time) free(fmt_time);
+	if(fmt_datetime) free(fmt_datetime);
 }
 
 void
@@ -2128,7 +2178,8 @@ Default::FileHistory(char *path)
 	char **history[] = {&File1, &File2, &File3, &File4, &File5, &File6};
 	int i;
 
-	if(path && (tmp_path=strdup(path))){
+	if(path && (tmp_path=(char*)malloc(strlen(path)+10))){
+		strcpy(tmp_path, path);
 		for(i=strlen(path); i > 0 && tmp_path[i] != '/' && tmp_path[i] != '\\'; i--);
 		tmp_path[i] = 0;
 		if(currPath) free(currPath);
@@ -2584,7 +2635,7 @@ UndoObj::Restore(bool redraw, anyOutput*o)
 			if((ul = (UndoList *)(buff[idx]->data)) && (ul->array)){
 				gol = (GraphObj**)(*(ul->loc_arr));
 				if(gol) for (i = 0; i < *(ul->loc_count); i++) if(gol[i]) ::DeleteGO(gol[i]);
-				*(ul->loc_count) = ul->count;				free(gol);
+				*(ul->loc_count) = ul->count;				if(gol) free(gol);
 				*(ul->loc_arr) = ul->array;					free(ul);
 				}
 			break;
@@ -2729,7 +2780,7 @@ UndoObj::DeleteGO(GraphObj **go, DWORD flags, anyOutput *o)
 		SetDisp(o);					 o->HideMark();
 		}
 	if(CurrGO == *go) CurrGO = 0L;
-	if((*go)->Id == GO_POLYLINE || (*go)->Id == GO_POLYGON){
+	if((*go)->Id == GO_POLYLINE || (*go)->Id == GO_POLYGON || (*go)->Id == GO_BEZIER){
 		if(CurrHandle && CurrHandle->parent==*go) {
 			if((*go)->Command(CMD_DELOBJ, CurrHandle, 0l)) return;
 			}
@@ -2780,7 +2831,7 @@ UndoObj::DropListGO(GraphObj *parent, GraphObj ***go, long *count, DWORD flags)
 	UndoList *ul;
 
 	if(ul = (UndoList *)malloc(sizeof(UndoList))) {
-		if(ul->array = memdup(*go, *count * sizeof(GraphObj*), 0)){
+		if(ul->array = *go) {
 			ul->loc_arr = (void **)go;		*go = 0L;
 			ul->count = *count;				*count = 0;
 			ul->loc_count = count;
@@ -2826,10 +2877,10 @@ UndoObj::Point(GraphObj *parent, POINT *pt, anyOutput * o, DWORD flags)
 }
 
 void 
-UndoObj::VoidPtr(GraphObj *parent, void **pptr, void *ptr, anyOutput * o, DWORD flags)
+UndoObj::VoidPtr(GraphObj *parent, void **pptr, void *ptr, anyOutput *o, DWORD flags)
 {
 	if(o) SetDisp(o);
-	if(0 > NewItem(UNDO_VOIDPTR, flags, parent, ptr, pptr)) free(ptr);
+	NewItem(UNDO_VOIDPTR, flags, parent, ptr, pptr);
 }
 
 void
@@ -3147,7 +3198,7 @@ UndoObj::RestoreConf(UndoInfo *inf)
 	//   of the tree finalizing undo.
 	if(!inf->data) return;
 	if(!(proc = new UndoUtil(inf->owner, (GraphObj*)inf->loc))) return; 
-	OpenGraph(proc, 0L, (unsigned char *)inf->data);
+	OpenGraph(proc, 0L, (unsigned char *)inf->data, false);
 	if(proc->res) for(i = 0; i < UNDO_RING_SIZE; i++) {
 		if(buff[i] && buff[i]->owner == (GraphObj*)inf->loc) FreeInfo(&buff[i]);
 		if(buff[i] && buff[i]->cmd == UNDO_OBJCONF){
diff --git a/Utils.cpp b/Utils.cpp
index a3bc6da..9d2b6dd 100755
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -1,4 +1,4 @@
-//Utils.cpp, Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 R.Lackner
+//Utils.cpp, Copyright (c) 2000-2006 R.Lackner
 //Collection of utility functions and classes for RLPlot
 //
 //    This file is part of RLPlot.
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <errno.h>
 #include "rlplot.h"
 
 extern GraphObj *CurrGO;			//Selected Graphic Objects
@@ -245,6 +246,28 @@ double GetAxisFac(AxisDEF *axis, double delta, int direc)
 //----------------------------------------------------------------------------
 // Text utility functions: internationalization and formats
 //----------------------------------------------------------------------------
+//remove leading/trailing whitespace
+char *str_ltrim(char *str) {
+	int i, j;
+
+	if(!str || !str[0]) return str;
+	for(i = 0; str[i] && str[i] <= ' '; i++);
+	for(j = 0; str[i]; str[j++] = str[i++]);
+	str[j++] = '\0';	return str;
+	}
+
+char *str_rtrim(char *str) {
+	int i;
+
+	i = strlen(str);
+	while(i > 0 && str[i-1] <= ' ') str[--i] = '\0';
+	return str;
+}
+
+char *str_trim(char *str) {
+	str = str_ltrim(str);			return str_rtrim(str);
+}
+
 // restyle formula
 void ReshapeFormula(char **text)
 {
@@ -264,6 +287,34 @@ void ReshapeFormula(char **text)
 		}
 }
 
+//translate anyResult to output format
+void TranslateResult(anyResult *res)
+{
+	static char tr_text[80];
+
+	switch (res->type) {
+	case ET_VALUE:
+		sprintf(tr_text, "%g", res->value);
+		res->text = tr_text;				return;
+	case ET_BOOL:
+		sprintf(tr_text, "%s", ((int)res->value) ? "true" : "false"); 
+		res->text = tr_text;				return;
+	case ET_DATE:
+		sprintf(tr_text, "%s", value_date(res->value, defs.fmt_date)); 
+		res->text = tr_text;				return;
+	case ET_TIME:
+		sprintf(tr_text, "%s", value_date(res->value, defs.fmt_time)); 
+		res->text = tr_text;				return;
+	case ET_DATETIME:
+		sprintf(tr_text, "%s", value_date(res->value, defs.fmt_datetime)); 
+		res->text = tr_text;				return;
+	case ET_TEXT:
+		if(res->text && res->text[0])		return;
+		}
+	if(!(res->text)) res->text="";
+}
+
+//remove invalid tag combinations from string
 void CleanTags(char *txt, int *i1, int *i2, int *i3)
 {
 	char *no_tags[] = {"<b></b>", "</b><b>", "<b><b>", "</b></b>",
@@ -627,8 +678,7 @@ void AddToPolygon(long *cp, POINT *pts, POINT *np)
 		if(np->y == pts[i-1].y) return;
 		if((np->y > pts[i-1].y && pts[i-1].y > pts[i-2].y) ||
 			(np->y < pts[i-1].y && pts[i-1].y < pts[i-2].y)) {
-			pts[i-1].x = np->x;
-			pts[i-1].y = np->y;
+			pts[i-1].x = np->x;		pts[i-1].y = np->y;
 			return;
 			}
 		}
@@ -636,8 +686,7 @@ void AddToPolygon(long *cp, POINT *pts, POINT *np)
 		if(np->x == pts[i-1].x) return;
 		if((np->x > pts[i-1].x && pts[i-1].x > pts[i-2].x) ||
 			(np->x < pts[i-1].x && pts[i-1].x < pts[i-2].x)) {
-			pts[i-1].x = np->x;
-			pts[i-1].y = np->y;
+			pts[i-1].x = np->x;		pts[i-1].y = np->y;
 			return;
 			}
 		}
@@ -648,20 +697,61 @@ void AddToPolygon(long *cp, POINT *pts, POINT *np)
 			(pts[i-1].x - pts[i-2].x))/(pts[i-1].y - pts[i-2].y)) : 0;
 		iy = (pts[i-1].x != pts[i-2].x) ? (pts[i-2].y + ((np->x - pts[i-2].x) * 
 			(pts[i-1].y - pts[i-2].y))/(pts[i-1].x - pts[i-2].x)) : 0;
-		if((ix && ix == np->x) || (iy && iy == np->y)) {
-			pts[i-1].x = np->x;
-			pts[i-1].y = np->y;
+		if((ix && ix == np->x) && (iy && iy == np->y)) {
+			pts[i-1].x = np->x;		pts[i-1].y = np->y;
 			return;
 			}
 		}
 	//not explained by extrapolation, accept new point
-	pts[i].x = np->x;
-	pts[i].y = np->y;
+	pts[i].x = np->x;				pts[i].y = np->y;
 	*cp = i+1;
 	return;
 }
 
 //----------------------------------------------------------------------------
+// create a Bezier polygon
+void DrawBezier(long *cp, POINT *pts, POINT p0, POINT p1, POINT p2, POINT p3, int depth)
+{
+#define MIN_SEG 11
+#define MAX_DEPTH 5
+	int i;
+	POINT np, p01, p12, p23, p012, p123, p0123;
+	POINT *ap[] = {&p0, &p1, &p2, &p3};
+
+	depth ++;
+	if(depth > MAX_DEPTH) {
+		for(i= 0; i < 4; i++) {
+			np.x = (*ap[i]).x >> 2;		np.y = (*ap[i]).y >> 2;
+			AddToPolygon(cp, pts, &np);
+			}
+		return;
+		}
+	else if(depth == 1) for(i=0; i < 4; i++) {
+		(*ap[i]).x <<= 2;			(*ap[i]).y <<= 2;
+		}
+	p01.x = (p0.x + p1.x) >> 1;				p01.y = (p0.y + p1.y) >> 1;
+	p12.x = (p1.x + p2.x) >> 1;				p12.y = (p1.y + p2.y) >> 1;
+	p23.x = (p2.x + p3.x) >> 1;				p23.y = (p2.y + p3.y) >> 1;
+	p012.x = (p01.x + p12.x) >> 1;			p012.y = (p01.y + p12.y) >> 1;
+	p123.x = (p12.x + p23.x) >> 1;			p123.y = (p12.y + p23.y) >> 1;
+	p0123.x = (p012.x + p123.x) >> 1;		p0123.y = (p012.y + p123.y) >> 1;
+	if(abs(p0.x - p0123.x)> MIN_SEG || abs(p0.y - p0123.y)> MIN_SEG) {
+		DrawBezier(cp, pts, p0, p01, p012, p0123, depth);		//recursion: refine
+		}
+	else {
+		DrawBezier(cp, pts, p0, p01, p012, p0123, MAX_DEPTH);	//recursion: store data
+		}
+	if(abs(p3.x - p0123.x)> MIN_SEG || abs(p3.y - p0123.y)> MIN_SEG) {
+		DrawBezier(cp, pts, p0123, p123, p23, p3, depth);		//recursion: refine
+		}
+	else {
+		DrawBezier(cp, pts, p0123, p123, p23, p3, MAX_DEPTH);	//recursion: store data
+		}
+#undef MAX_DEPTH
+#undef MIN_SEG
+}
+
+//----------------------------------------------------------------------------
 // create a circular polygon
 //use circular Bresenham's algorithm to draw arcs
 //Ref: C. Montani, R. Scopigno (1990) "Speres-To-Voxel Conversion", in:
@@ -975,6 +1065,8 @@ void DeleteGO(GraphObj *go)
 	case GO_GRID3D:			delete((Grid3D*)go);		break;
 	case GO_FUNC3D:			delete((Func3D*)go);		break;
 	case GO_XYSTAT:			delete((xyStat*)go);		break;
+	case GO_FITFUNC3D:		delete((FitFunc3D*)go);		break;
+	case GO_BEZIER:			delete((Bezier*)go);		break;
 	default:
 		sprintf(TmpTxt, "Cannot delete Object\nwith Id %ld", go->Id);
 		ErrorBox(TmpTxt);
@@ -1078,7 +1170,11 @@ bool FileExist(char *FileName)
 {
 	FILE *TheFile;
 
-	if(0L ==(TheFile = fopen(FileName, "r"))) return false;
+
+	if(0L ==(TheFile = fopen(FileName, "r"))) {
+		if(errno == ENOENT) return false;
+		return true;
+		}
 	fclose(TheFile);
 	return true;
 }
@@ -1137,17 +1233,31 @@ bool ReplaceGO(GraphObj **oldobj, GraphObj **newobj)
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 //calculate a 'unique' hash value for a string
+//Ref: Corman T.H., Leiserson C.E. & Rivest R.L. (1990) Hash Functions.
+//   in: Introduction to Algorithms (MIT Press & McGraw-Hill)
+//   ISBN 0-262-03141-8 and ISBN 0-07-013143-0, pp. 226ff
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 unsigned int HashValue(unsigned char *str)
 {
-	unsigned int i = 0, ret=0;
+	unsigned int i = 0, ret = 0;
 
-	if(!str) return 0;
+	if(!str || !str[0]) return 0;
 	do {
 		if(str[i] > 32) ret = ((str[i]-32) + (ret <<2));
 		i++;
 		}while(str[i]);
-	if(i < 4) memcpy(&ret, str, i);
+	return ret;
+}
+
+unsigned int Hash2(unsigned char * str)
+{
+	unsigned int i = 0, ret = 0, c;
+
+	if(!str) return 0;
+	do {
+		c = str[i++];
+		ret = ((ret * c)<<2) | c;
+		}while(str[i]);
 	return ret;
 }
 
@@ -1532,7 +1642,6 @@ double *ppg_vec = 0L;
 //Ref: P.S. Heckbert (1990) "Digital Line Drawing", in: Graphic Gems
 //   (A.S. Glassner, ed.); Academic Press, Inc.,
 //   ISBN 0-12-286165-5
-// void AddToPolygon(long *cp, POINT *pts, POINT *np);
 bool IsOnLine(POINT *p1, POINT *p2, int x, int y)
 {
 	int d, ax, ay, sx, sy, dx, dy;
@@ -1570,7 +1679,6 @@ bool IsOnLine(POINT *p1, POINT *p2, int x, int y)
 //Ref: P.S. Heckbert (1990) "Digital Line Drawing", in: Graphic Gems
 //   (A.S. Glassner, ed.); Academic Press, Inc.,
 //   ISBN 0-12-286165-5
-// void AddToPolygon(long *cp, POINT *pts, POINT *np);
 bool ShadowPolygon(POINT *p1, POINT *p2, POINT *tp, int ntp, POINT *pts, long *cp, POINT *lim)
 {
 	int d, ax, ay, sx, sy, dx, dy;
diff --git a/Version.h b/Version.h
index aca17f5..ecd91f5 100755
--- a/Version.h
+++ b/Version.h
@@ -1,4 +1,4 @@
-//RLPlot.h, Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 R.Lackner
+//RLPlot.h, Copyright (c) 2000-2006 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.0"
+#define SZ_VERSION  "1.1"
diff --git a/WinSpec.cpp b/WinSpec.cpp
index ff11d6e..9e9de14 100755
--- a/WinSpec.cpp
+++ b/WinSpec.cpp
@@ -1,4 +1,4 @@
-//WinSpec.cpp, Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 R.Lackner
+//WinSpec.cpp, Copyright (c) 2000-2006 R.Lackner
 //the entire code of this module is highly specific to Windows!
 //
 //    This file is part of RLPlot.
@@ -427,15 +427,15 @@ void TestClipboard(GraphObj *g)
 		else if((hmem = GetClipboardData(CF_TEXT)) &&
 			(ptr = (unsigned char*) GlobalLock(hmem))) ProcMemData(g, ptr, true);
 		else if((hmem = GetClipboardData(cf_rlpobj)) &&
-			(ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr);
+			(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);
+			(ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr, true);
 		}
 	else if(g->Id == GO_PAGE) {
 		if((hmem = GetClipboardData(cf_rlpobj)) &&
-			(ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr);
+			(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);
+			(ptr = (unsigned char*) GlobalLock(hmem))) OpenGraph(g, 0L, ptr, true);
 		}
 	else if(g->Id == GO_GRAPH) TestClipboard(g->parent);
 	if(hmem) GlobalUnlock(hmem);
@@ -1037,6 +1037,39 @@ unsigned char zoom_mask[] =	{	//zoom cursor mask
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
+unsigned char paste_bits[] =	{	//paste cursor bitmap
+	0x20, 0x00, 0x20, 0x00, 0xf8, 0x00, 0x20, 0x00,
+	0x23, 0xfe, 0x07, 0xff, 0x07, 0xff, 0x07, 0xff,
+	0x07, 0xff, 0x07, 0xff, 0x07, 0xff, 0x07, 0xff,
+	0x07, 0xff, 0x07, 0xff, 0x03, 0xfe, 0x00, 0x00};
+
+unsigned char paste_mask[] =	{	//paste cursor mask
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xfc, 0x05, 0xfd, 0x05, 0xfd, 0xf9,
+	0xfc, 0x01, 0xfc, 0x01, 0xfc, 0x01, 0xfc, 0x01,
+	0xfc, 0x01, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xff};
+
+//display 16x16 cursor data: developers utility
+/*
+void disp_bm(unsigned char *tb)
+{
+	char txt[512];
+	unsigned char currbyte;
+	int i, j, pos;
+
+	for(i = pos = 0; i < 32; i++) {
+		currbyte = tb[i];
+		for (j = 0; j < 8; j++) {
+			if(currbyte & 0x80) pos += sprintf(txt+pos, "1");
+			else pos += sprintf(txt+pos, "0");
+			currbyte <<= 1;
+			}
+		if(i & 1) pos += sprintf(txt+pos, "\n");
+		}
+	InfoBox(txt);
+}
+*/
+
 void
 OutputWin::MouseCursor(int cid, bool force)
 {
@@ -1057,11 +1090,15 @@ OutputWin::MouseCursor(int cid, bool force)
 	case MC_SE:		hoc = SetCursor(LoadCursor(NULL, IDC_SIZENWSE));break;
 	case MC_SALL:	hoc = SetCursor(LoadCursor(NULL, IDC_SIZEALL));	break;	
 	case MC_MOVE:
-		hc = CreateCursor(hInstance, 8, 8, 16, 16, hand_mask, hand_bits);
+		hc = CreateCursor(hInstance, 7, 7, 16, 16, hand_mask, hand_bits);
 		hoc = SetCursor(hc);
 		break;
 	case MC_ZOOM:
-		hc = CreateCursor(hInstance, 8, 8, 16, 16, zoom_mask, zoom_bits);
+		hc = CreateCursor(hInstance, 7, 7, 16, 16, zoom_mask, zoom_bits);
+		hoc = SetCursor(hc);
+		break;
+	case MC_PASTE:
+		hc = CreateCursor(hInstance, 2, 2, 16, 16, paste_mask, paste_bits);
 		hoc = SetCursor(hc);
 		break;
 	default:	return;
@@ -1257,14 +1294,20 @@ OutputWin::FileHistory()
 void
 OutputWin::CreateNewWindow(void *g)
 {
+	RECT ClientRect;
+
 	hWnd = CreateWindow(name, "RLPlot",
 		WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
 		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
 		CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
 	SetWindowLong(hWnd, 0, (long)g);		// g is the parent graphic obj
 	SetWindowLong(hWnd, GWL_USERDATA, (long)this);
-	ShowWindow(hWnd, SW_SHOW);
+	if(BitMapWin::Erase(0x00cbcbcb)) {
+		GetClientRect(hWnd, &ClientRect);
+		InvalidateRect(hWnd, &ClientRect, FALSE);
+		}
 	UpdateWindow(hWnd);
+	ShowWindow(hWnd, SW_SHOW);
 }
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2047,8 +2090,8 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		case CM_PASTE:
 			w->MouseCursor(MC_WAIT, true);
 			if(g->Id == GO_SPREADDATA || g->Id == GO_PAGE ||
-				g->Id == GO_GRAPH)TestClipboard(g);
-			w->MouseCursor(MC_ARROW, true);
+				g->Id == GO_GRAPH) TestClipboard(g);
+			g->Command(CMD_MOUSECURSOR, 0L, w);
 			return 0;
 		case CM_COPY:			case CM_CUT:
 			EmptyClip();
@@ -2127,6 +2170,9 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		case CM_DELGRAPH:
 			g->Command(CMD_DELGRAPH, 0L, w);
 			return 0;
+		case CM_SAVEDATA:
+			g->Command(CMD_SAVEDATA, 0L, w);
+			return 0;
 		case CM_SAVEDATAAS:
 			g->Command(CMD_SAVEDATAAS, 0L, w);
 			return 0;
@@ -2145,7 +2191,7 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 			SaveGraphAs(g);
 			return 0;
 		case CM_EXPORT:
-			OpenExportName(g, "hello.svg");
+			OpenExportName(g, 0L);
 			g->DoPlot(w);
 			return 0;
 		case CM_PRINT:
@@ -2257,8 +2303,7 @@ long FAR PASCAL WndProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
 		return 0;
 	case WM_CLOSE:
 		if(g && g->Command(CMD_CAN_CLOSE, 0L, 0L)) {
-			SetWindowLong(hwnd, 0, 0L);
-			SetWindowLong(hwnd, GWL_USERDATA, 0L);
+			SetWindowLong(hwnd, 0, 0L);		SetWindowLong(hwnd, GWL_USERDATA, 0L);
 			w->go = 0L;
 			DestroyWindow(hwnd);
 			}
@@ -2399,7 +2444,6 @@ void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj
 	if(hDlg && w && w->Erase(0x00e0e0e0L)) {
 		SetWindowLong(hDlg, GWL_USERDATA, (long)w);
 		SetWindowLong(hDlg, 0, (long)d);
-		ShowWindow(hDlg, SW_SHOW);
 		if(flags & 0x01) {					//center on screen
 			GetWindowRect(hDlg, &BoxRec);
 			GetClientRect(GetDesktopWindow(), &DeskRect);
@@ -2410,6 +2454,7 @@ void *CreateDlgWnd(char *title, int x, int y, int width, int height, tag_DlgObj
 			}
 		if(flags & 0x04)			SetTimer(hDlg, 1, 100, 0L);
 		UpdateWindow(hDlg);			d->DoPlot(w);
+		ShowWindow(hDlg, SW_SHOW);
 		}
 	else {
 		if(w) delete (w);			return 0L;
diff --git a/exprlp.cpp b/exprlp.cpp
index fbccddb..5a291a9 100755
--- a/exprlp.cpp
+++ b/exprlp.cpp
@@ -260,6 +260,16 @@ bool StarChart::PropertyDlg()
 bool Function::PropertyDlg()
 {
 	return false;
+}
+
+bool Grid3D::PropertyDlg()
+{
+	return false;
+}
+
+bool Grid3D::Configure()
+{
+	return false;
 }
 
 bool Scatt3D::PropertyDlg()
@@ -297,6 +307,11 @@ bool Func3D::PropertyDlg()
 	return false;
 }
 
+bool FitFunc3D::PropertyDlg()
+{
+	return false;
+}
+
 bool BubblePlot3D::PropertyDlg()
 {
 	return false;
@@ -410,7 +425,7 @@ ExpRoot::ExpRoot(char *file1, char *file2):GraphObj(0L, 0L)
 	if(file2 && strcmp("-", file2)) name2 = file2;
 	else name2 = 0L;
 	go = 0L;
-	OpenGraph(this, name1, 0L);
+	OpenGraph(this, name1, 0L, false);
 	if(bDelete && name1 && name1[0]) unlink(name1);
 }
 
diff --git a/mfcalc.cpp b/mfcalc.cpp
old mode 100644
new mode 100755
index 9144a14..2e3360c
--- a/mfcalc.cpp
+++ b/mfcalc.cpp
@@ -5,42 +5,56 @@
 #define YYBISON 1  /* Identify Bison output.  */
 
 #define	NUM	257
-#define	STR	258
-#define	ARR	259
-#define	BLOCK	260
-#define	PI	261
-#define	E	262
-#define	CLVAL	263
-#define	PSEP	264
-#define	IF	265
-#define	ELSE	266
-#define	VAR	267
-#define	FNCT	268
-#define	AFNCT	269
-#define	SFNCT	270
-#define	FUNC2	271
-#define	TXT	272
-#define	CLAUSE	273
-#define	SER	274
-#define	COLR	275
-#define	COLC	276
-#define	AND	277
-#define	OR	278
-#define	EQ	279
-#define	NE	280
-#define	GT	281
-#define	GE	282
-#define	LT	283
-#define	LE	284
-#define	NEG	285
-#define	INC	286
-#define	DEC	287
-#define	PINC	288
-#define	PDEC	289
+#define	BOOLVAL	258
+#define	STR	259
+#define	ARR	260
+#define	BLOCK	261
+#define	PI	262
+#define	E	263
+#define	CLVAL	264
+#define	PSEP	265
+#define	IF	266
+#define	ELSE	267
+#define	BTRUE	268
+#define	BFALSE	269
+#define	DATE1	270
+#define	TIME1	271
+#define	DATETIME1	272
+#define	DIM	273
+#define	VAR	274
+#define	FNCT	275
+#define	BFNCT	276
+#define	AFNCT	277
+#define	SFNCT	278
+#define	FUNC1	279
+#define	FUNC2	280
+#define	FUNC3	281
+#define	TXT	282
+#define	SRFUNC	283
+#define	YYFNC	284
+#define	FUNC4	285
+#define	CLAUSE	286
+#define	SER	287
+#define	COLR	288
+#define	COLC	289
+#define	AND	290
+#define	OR	291
+#define	EQ	292
+#define	NE	293
+#define	GT	294
+#define	GE	295
+#define	LT	296
+#define	LE	297
+#define	NEG	298
+#define	INC	299
+#define	DEC	300
+#define	PINC	301
+#define	PDEC	302
+#define	PDIM	303
 
 
 /*
- mfcalc.y, mfcalc.cpp, Copyright (c) 2004, 2005 R.Lackner
+ mfcalc.y, mfcalc.cpp, Copyright (c) 2004, 2005, 2006 R.Lackner
  parse string and simple math: based on the bison 'mfcalc' example
 
     This file is part of RLPlot.
@@ -68,14 +82,14 @@
 
 class symrec {
 public:
-	int type, row, col;
-	unsigned int h_name;
+	int type, row, col, a_count;
+	unsigned int h_name, h2_name;
 	char *name, *text;
 	double (*fnctptr)(...);
 	symrec *next;
-	double var;
+	double var, *a_data;
 
-	symrec(unsigned int h_n, int typ, symrec *nxt);
+	symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt);
 	~symrec();
 	double GetValue();
 	void GetValue(void *res);
@@ -109,18 +123,22 @@ typedef struct{
 
 }YYSTYPE;
 
-static symrec *putsym (unsigned int h_name, int sym_type);
-static symrec *getsym (unsigned int h_name, char *sym_name = 0L);
+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);
 static int push(YYSTYPE *res, YYSTYPE *val);
 static void store_res(YYSTYPE *res);
 static char *PushString(char *text);
+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 double eval(YYSTYPE *sr, YYSTYPE *dst);
+static double eval(YYSTYPE *sr, YYSTYPE *dst, char* dum);
 static int range_array(YYSTYPE * res, char *range);
+static int range_array2(YYSTYPE *res1, YYSTYPE *res2);
 static void exec_clause(YYSTYPE *res);
 static YYSTYPE *proc_clause(YYSTYPE *res);
 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;};
 
@@ -145,23 +163,23 @@ static int parse_level = 0;		//count reentrances into parser
 
 
 
-#define	YYFINAL		131
+#define	YYFINAL		222
 #define	YYFLAG		-32768
-#define	YYNTBASE	48
+#define	YYNTBASE	65
 
-#define YYTRANSLATE(x) ((unsigned)(x) <= 289 ? yytranslate[x] : 54)
+#define YYTRANSLATE(x) ((unsigned)(x) <= 303 ? yytranslate[x] : 72)
 
 static const char yytranslate[] = {     0,
-     2,     2,     2,     2,     2,     2,     2,     2,     2,    44,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    59,
      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,    46,
-    47,    36,    35,    20,    34,     2,    37,     2,     2,     2,
-     2,     2,     2,     2,     2,     2,     2,     2,    45,     2,
-    19,     2,    25,     2,     2,     2,     2,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,     2,     2,    61,
+    62,    49,    48,    33,    47,     2,    50,     2,     2,     2,
+     2,     2,     2,     2,     2,     2,     2,    64,    60,     2,
+    32,     2,    38,     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,    43,     2,     2,     2,     2,     2,     2,
+    51,     2,    63,    58,     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,
@@ -179,244 +197,413 @@ static const char yytranslate[] = {     0,
      2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
      2,     2,     2,     2,     2,     1,     3,     4,     5,     6,
      7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
-    17,    18,    21,    22,    23,    24,    26,    27,    28,    29,
-    30,    31,    32,    33,    38,    39,    40,    41,    42
+    17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
+    27,    28,    29,    30,    31,    34,    35,    36,    37,    39,
+    40,    41,    42,    43,    44,    45,    46,    52,    53,    54,
+    55,    56,    57
 };
 
 #if YYDEBUG != 0
 static const short yyprhs[] = {     0,
      0,     1,     4,     6,     8,    10,    13,    16,    19,    22,
-    25,    28,    30,    34,    38,    42,    44,    48,    50,    52,
-    56,    60,    62,    66,    68,    70,    72,    74,    76,    78,
-    80,    84,    88,    93,    98,   105,   114,   119,   124,   131,
-   140,   146,   154,   158,   162,   166,   170,   174,   178,   182,
-   186,   190,   194,   198,   202,   205,   208,   211,   214,   217,
-   221,   225,   231,   237,   243
+    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,   323,   331,   335,   339,   343,   347,   350,
+   353,   356,   359,   362,   366,   370,   376,   381,   388,   394,
+   400,   404,   408,   414,   420,   426
 };
 
 static const short yyrhs[] = {    -1,
-    48,    49,     0,    44,     0,    45,     0,    20,     0,    53,
-    44,     0,    53,    45,     0,    53,    20,     0,    50,    44,
-     0,    50,    45,     0,     1,    44,     0,     4,     0,    50,
-    35,    53,     0,    53,    35,    50,     0,    50,    35,    50,
-     0,    50,     0,    13,    23,    13,     0,     5,     0,    53,
-     0,    52,    20,    52,     0,    52,    21,    53,     0,    51,
-     0,     3,    22,     3,     0,     3,     0,    18,     0,     9,
-     0,     7,     0,     8,     0,    13,     0,     6,     0,    13,
-    19,    53,     0,    13,    19,    50,     0,    14,    46,    53,
-    47,     0,    15,    46,    52,    47,     0,    15,    46,    53,
-    10,    53,    47,     0,    15,    46,    53,    10,    53,    10,
-    53,    47,     0,    16,    46,    50,    47,     0,    16,    46,
-    53,    47,     0,    17,    46,    52,    10,    52,    47,     0,
-    17,    46,    52,    10,    52,    10,    51,    47,     0,    11,
-    46,    53,    47,     6,     0,    11,    46,    53,    47,     6,
-    12,     6,     0,    53,    26,    53,     0,    53,    27,    53,
-     0,    53,    28,    53,     0,    53,    29,    53,     0,    53,
-    30,    53,     0,    53,    31,    53,     0,    53,    32,    53,
-     0,    53,    33,    53,     0,    53,    35,    53,     0,    53,
-    34,    53,     0,    53,    36,    53,     0,    53,    37,    53,
-     0,    34,    53,     0,    13,    39,     0,    13,    40,     0,
-    39,    13,     0,    40,    13,     0,    53,    43,    53,     0,
-    46,    52,    47,     0,    53,    25,    53,    24,    53,     0,
-    53,    25,     4,    24,     4,     0,    53,    25,     4,    24,
-    53,     0,    53,    25,    53,    24,     4,     0
+    65,    66,     0,    59,     0,    60,     0,    33,     0,    71,
+    59,     0,    71,    60,     0,    71,    33,     0,    67,    59,
+     0,    67,    60,     0,     1,    59,     0,     5,     0,    67,
+    48,    71,     0,    71,    48,    67,     0,    67,    48,    67,
+     0,    29,    61,    71,    62,     0,    29,    61,    71,    11,
+    67,    62,     0,    29,    61,    71,    11,    71,    62,     0,
+    29,    61,    71,    33,    67,    62,     0,    29,    61,    71,
+    33,    71,    62,     0,    67,     0,    20,    36,    20,     0,
+     6,     0,    71,     0,    69,    33,    69,     0,    69,    34,
+    71,     0,    68,     0,     3,    35,     3,     0,     4,     0,
+    22,    61,    71,    62,     0,    14,     0,    15,     0,    71,
+    39,    71,     0,    71,    40,    71,     0,    71,    41,    71,
+     0,    71,    42,    71,     0,    71,    43,    71,     0,    71,
+    44,    71,     0,    71,    45,    71,     0,    71,    46,    71,
+     0,     3,     0,    70,     0,    28,     0,    10,     0,     8,
+     0,     9,     0,    20,     0,     7,     0,    20,    32,    71,
+     0,    20,    32,    67,     0,    21,    61,    71,    62,     0,
+    23,    61,    69,    62,     0,    23,    61,    71,    11,    69,
+    62,     0,    23,    61,    71,    11,    71,    11,    71,    62,
+     0,    24,    61,    67,    62,     0,    24,    61,    71,    62,
+     0,    24,    61,    67,    11,    67,    62,     0,    24,    61,
+    71,    11,    67,    62,     0,    24,    61,    71,    11,    71,
+    62,     0,    24,    61,    67,    11,    71,    62,     0,    24,
+    61,    67,    33,    67,    62,     0,    24,    61,    71,    33,
+    67,    62,     0,    24,    61,    67,    33,    71,    62,     0,
+    24,    61,    71,    33,    71,    62,     0,    26,    61,    68,
+    11,    68,    62,     0,    26,    61,    68,    11,    68,    11,
+    68,    62,     0,    27,    61,    69,    11,    69,    62,     0,
+    27,    61,    69,    11,    69,    11,    68,    62,     0,    31,
+    61,    71,    11,    71,    11,    69,    11,    68,    62,     0,
+    25,    61,    69,    11,    68,    62,     0,    30,    61,    62,
+     0,    30,    61,    69,    62,     0,    12,    61,    71,    62,
+     7,     0,    12,    61,    71,    62,     7,    13,     7,     0,
+    71,    48,    71,     0,    71,    47,    71,     0,    71,    49,
+    71,     0,    71,    50,    71,     0,    47,    71,     0,    20,
+    53,     0,    20,    54,     0,    53,    20,     0,    54,    20,
+     0,    71,    58,    71,     0,    61,    69,    62,     0,    19,
+    20,    51,    71,    63,     0,    71,    51,    71,    63,     0,
+    71,    51,    71,    63,    32,    71,     0,     3,    36,     3,
+    36,     3,     0,     3,    64,     3,    64,     3,     0,     3,
+    36,     3,     0,     3,    64,     3,     0,    71,    38,    71,
+    37,    71,     0,    71,    38,     5,    37,     5,     0,    71,
+    38,     5,    37,    71,     0,    71,    38,    71,    37,     5,
+     0
 };
 
 #endif
 
 #if YYDEBUG != 0
 static const short yyrline[] = { 0,
-   121,   122,   125,   125,   125,   126,   127,   128,   129,   130,
-   131,   134,   136,   137,   138,   141,   143,   146,   147,   148,
-   149,   150,   151,   155,   156,   157,   158,   159,   160,   161,
-   162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
-   173,   174,   175,   176,   177,   178,   179,   180,   181,   182,
-   183,   184,   185,   186,   188,   189,   190,   191,   192,   193,
-   194,   195,   196,   197,   198
+   128,   129,   132,   132,   132,   133,   134,   135,   136,   137,
+   138,   141,   143,   144,   145,   146,   147,   148,   149,   150,
+   153,   155,   158,   159,   160,   161,   162,   163,   167,   168,
+   169,   170,   171,   172,   173,   174,   175,   176,   177,   178,
+   181,   182,   183,   184,   185,   186,   187,   188,   189,   190,
+   191,   192,   193,   195,   198,   199,   200,   201,   202,   203,
+   204,   205,   206,   207,   208,   209,   210,   211,   212,   213,
+   214,   215,   216,   217,   218,   222,   226,   227,   229,   230,
+   231,   232,   233,   234,   235,   236,   238,   240,   242,   243,
+   244,   245,   246,   247,   248,   249
 };
 #endif
 
 
 #if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
 
-static const char * const yytname[] = {   "$","error","$undefined.","NUM","STR",
-"ARR","BLOCK","PI","E","CLVAL","PSEP","IF","ELSE","VAR","FNCT","AFNCT","SFNCT",
-"FUNC2","TXT","'='","','","CLAUSE","SER","COLR","COLC","'?'","AND","OR","EQ",
-"NE","GT","GE","LT","LE","'-'","'+'","'*'","'/'","NEG","INC","DEC","PINC","PDEC",
-"'^'","'\\n'","';'","'('","')'","input","line","str_exp","range","arr","exp", NULL
+static const char * const yytname[] = {   "$","error","$undefined.","NUM","BOOLVAL",
+"STR","ARR","BLOCK","PI","E","CLVAL","PSEP","IF","ELSE","BTRUE","BFALSE","DATE1",
+"TIME1","DATETIME1","DIM","VAR","FNCT","BFNCT","AFNCT","SFNCT","FUNC1","FUNC2",
+"FUNC3","TXT","SRFUNC","YYFNC","FUNC4","'='","','","CLAUSE","SER","COLR","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
 };
 #endif
 
 static const short yyr1[] = {     0,
-    48,    48,    49,    49,    49,    49,    49,    49,    49,    49,
-    49,    50,    50,    50,    50,    51,    51,    52,    52,    52,
-    52,    52,    52,    53,    53,    53,    53,    53,    53,    53,
-    53,    53,    53,    53,    53,    53,    53,    53,    53,    53,
-    53,    53,    53,    53,    53,    53,    53,    53,    53,    53,
-    53,    53,    53,    53,    53,    53,    53,    53,    53,    53,
-    53,    53,    53,    53,    53
+    65,    65,    66,    66,    66,    66,    66,    66,    66,    66,
+    66,    67,    67,    67,    67,    67,    67,    67,    67,    67,
+    68,    68,    69,    69,    69,    69,    69,    69,    70,    70,
+    70,    70,    70,    70,    70,    70,    70,    70,    70,    70,
+    71,    71,    71,    71,    71,    71,    71,    71,    71,    71,
+    71,    71,    71,    71,    71,    71,    71,    71,    71,    71,
+    71,    71,    71,    71,    71,    71,    71,    71,    71,    71,
+    71,    71,    71,    71,    71,    71,    71,    71,    71,    71,
+    71,    71,    71,    71,    71,    71,    71,    71,    71,    71,
+    71,    71,    71,    71,    71,    71
 };
 
 static const short yyr2[] = {     0,
      0,     2,     1,     1,     1,     2,     2,     2,     2,     2,
-     2,     1,     3,     3,     3,     1,     3,     1,     1,     3,
-     3,     1,     3,     1,     1,     1,     1,     1,     1,     1,
-     3,     3,     4,     4,     6,     8,     4,     4,     6,     8,
-     5,     7,     3,     3,     3,     3,     3,     3,     3,     3,
-     3,     3,     3,     3,     2,     2,     2,     2,     2,     3,
-     3,     5,     5,     5,     5
+     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,
+     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,     5,     7,     3,     3,     3,     3,     2,     2,
+     2,     2,     2,     3,     3,     5,     4,     6,     5,     5,
+     3,     3,     5,     5,     5,     5
 };
 
 static const short yydefact[] = {     1,
-     0,     0,    24,    12,    30,    27,    28,    26,     0,    29,
-     0,     0,     0,     0,    25,     5,     0,     0,     0,     3,
-     4,     0,     2,     0,     0,    11,     0,     0,    56,    57,
-     0,     0,     0,     0,    55,    58,    59,    24,    18,    29,
-    16,    22,     0,    19,     0,     9,    10,     8,     0,     0,
+     0,     0,    41,    29,    12,    48,    45,    46,    44,     0,
+    31,    32,     0,    47,     0,     0,     0,     0,     0,     0,
+     0,    43,     0,     0,     0,     5,     0,     0,     0,     3,
+     4,     0,     2,     0,    42,     0,    11,     0,     0,     0,
+     0,     0,    80,    81,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,     0,    79,    82,    83,    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,     6,     7,     0,    32,    31,     0,     0,    19,
-     0,     0,     0,     0,     0,     0,     0,     0,    61,    15,
-    13,     0,     0,    43,    44,    45,    46,    47,    48,    49,
-    50,    52,    14,    51,    53,    54,    60,     0,    33,    34,
-     0,    37,    38,     0,    51,    23,    17,    20,    21,     0,
-     0,    41,     0,     0,    63,    64,    65,    62,     0,     0,
-    35,     0,    39,    42,     0,     0,     0,    36,    40,     0,
-     0
+     0,     0,     0,     6,     7,    91,    92,     0,     0,    50,
+    49,     0,     0,     0,    24,     0,     0,     0,     0,     0,
+     0,     0,    71,     0,     0,     0,     0,     0,     0,     0,
+    85,    15,    13,     0,     0,    33,    34,    35,    36,    37,
+    38,    39,    40,    76,    14,    75,    77,    78,     0,    84,
+     0,     0,     0,     0,    51,    30,    52,     0,     0,     0,
+    55,     0,     0,    56,     0,     0,     0,     0,     0,    16,
+    72,     0,    75,    28,    22,    25,    26,     0,     0,    87,
+    89,    90,    73,    86,     0,    24,     0,     0,     0,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,     0,    94,    95,    96,    93,     0,     0,    53,     0,
+    57,    60,    61,    63,    58,    59,    62,    64,    70,     0,
+    65,     0,    67,    17,    18,    19,    20,     0,    88,    74,
+     0,     0,     0,     0,    54,    66,    68,     0,     0,    69,
+     0,     0
 };
 
 static const short yydefgoto[] = {     1,
-    23,    41,    42,    43,    44
+    33,    61,    62,    63,    35,    64
 };
 
 static const short yypact[] = {-32768,
-    88,   -39,-32768,-32768,-32768,-32768,-32768,-32768,   -33,     2,
-   -26,   -24,   -18,   -17,-32768,-32768,   378,    21,    24,-32768,
--32768,   132,-32768,   -27,   419,-32768,   378,   173,-32768,-32768,
-   378,   132,   173,   132,     3,-32768,-32768,    23,-32768,     0,
-     8,-32768,   -14,   331,   173,-32768,-32768,-32768,   214,   378,
-   378,   378,   378,   378,   378,   378,   378,   378,   173,   378,
-   378,   378,-32768,-32768,   126,     8,   331,   167,   -11,   400,
-   -32,   208,     4,   378,    67,    58,   132,   378,-32768,-32768,
-    32,    52,   291,   456,   456,    29,    29,    29,    29,    29,
-    29,    32,-32768,    32,     3,     3,     3,    72,-32768,-32768,
-   378,-32768,-32768,   132,    32,-32768,-32768,    59,   440,   255,
-   296,    69,   372,    -9,-32768,   440,-32768,   440,    76,   378,
--32768,   337,-32768,-32768,   249,    36,   331,-32768,-32768,    84,
--32768
+   204,   -44,   -26,-32768,-32768,-32768,-32768,-32768,-32768,   -45,
+-32768,-32768,     5,    33,   -42,   -25,     6,    22,    24,    32,
+    39,-32768,    41,    49,    54,-32768,   646,    36,    38,-32768,
+-32768,   323,-32768,   105,-32768,   799,-32768,    14,    57,   646,
+    10,   378,-32768,-32768,   646,   646,   323,   378,   323,   433,
+   323,   646,   263,   646,     8,-32768,-32768,   -27,-32768,    63,
+    55,-32768,   -20,   994,   378,-32768,-32768,-32768,   488,   646,
+   646,   646,   646,   646,   646,   646,   646,   646,   378,   646,
+   646,   646,   646,-32768,-32768,    83,    76,   372,   646,    55,
+   994,   427,   482,   -12,    85,     0,   670,     1,   111,   994,
+    78,   711,-32768,   -10,   736,   646,   146,   130,   323,   646,
+-32768,-32768,   129,   118,   973,   197,   197,   125,   125,   125,
+   125,   125,   125,   129,-32768,   129,   -31,   -31,   257,     8,
+   153,   156,   154,   317,-32768,-32768,-32768,   323,   378,   378,
+-32768,   378,   378,-32768,   433,   433,   323,   378,   378,-32768,
+-32768,   646,   129,-32768,-32768,   132,  1015,   543,   598,   131,
+-32768,-32768,   155,-32768,    -3,   757,   -30,   537,    -8,   822,
+    46,   847,    56,   872,   107,    -7,    -5,    58,   897,    98,
+   922,   778,-32768,  1015,-32768,  1015,   646,   160,-32768,   646,
+-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,   433,
+-32768,   433,-32768,-32768,-32768,-32768,-32768,   323,  1015,-32768,
+   947,   109,   115,    80,-32768,-32768,-32768,   433,   126,-32768,
+   192,-32768
 };
 
 static const short yypgoto[] = {-32768,
--32768,    34,   -37,   -30,    -1
+-32768,    42,   -48,   -46,-32768,    -1
 };
 
 
-#define	YYLAST		499
-
-
-static const short yytable[] = {    25,
-   122,    69,    45,    73,    26,    77,    78,    45,    77,    78,
-    77,    78,    27,   104,   102,    35,    46,    47,    28,    31,
-    28,    32,    76,    77,    78,    65,    67,    33,    34,    68,
-    70,    72,    79,    36,    24,   100,    37,   123,    29,    30,
-    29,    30,    45,    81,    75,    62,   108,    83,    84,    85,
-    86,    87,    88,    89,    90,    91,    92,    94,    95,    96,
-    97,    66,    58,    74,    60,    61,    71,    60,    61,   106,
-   107,    62,   105,   114,    62,   110,   109,   112,    80,    78,
-   119,   124,   129,   131,   126,     0,     0,   130,     2,     0,
-     3,     4,    93,     5,     6,     7,     8,     0,     9,   113,
-    10,    11,    12,    13,    14,    15,     0,    16,   116,   118,
-     0,     0,     0,     0,     0,     0,     0,     0,   125,     0,
-   127,    17,     0,     0,     0,     0,    18,    19,     0,     0,
-     0,    20,    21,    22,    38,     4,    39,     5,     6,     7,
-     8,     0,     9,     0,    40,    11,    12,    13,    14,    15,
-    49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
-    74,    60,    61,     0,     0,    17,     0,     0,    62,     0,
-    18,    19,    98,     0,     0,     3,     4,    22,     5,     6,
-     7,     8,     0,     9,     0,    10,    11,    12,    13,    14,
-    15,    49,    50,    51,    52,    53,    54,    55,    56,    57,
-    58,    74,    60,    61,     0,     0,    17,     0,     0,    62,
-     0,    18,    19,    99,     0,     0,     3,    82,    22,     5,
-     6,     7,     8,     0,     9,     0,    10,    11,    12,    13,
-    14,    15,    49,    50,    51,    52,    53,    54,    55,    56,
-    57,    58,    59,    60,    61,     0,     0,    17,     0,     0,
-    62,     0,    18,    19,   103,     0,     0,     3,   115,    22,
-     5,     6,     7,     8,     0,     9,     0,    10,    11,    12,
-    13,    14,    15,    49,    50,    51,    52,    53,    54,    55,
-    56,    57,    58,    74,    60,    61,     0,     0,    17,     0,
-     0,    62,     0,    18,    19,   128,     0,     0,     3,   117,
-    22,     5,     6,     7,     8,     0,     9,     0,    10,    11,
-    12,    13,    14,    15,   111,    49,    50,    51,    52,    53,
-    54,    55,    56,    57,    58,    74,    60,    61,     0,    17,
-     0,     0,     0,    62,    18,    19,     0,     0,     0,     3,
-     4,    22,     5,     6,     7,     8,     0,     9,     0,    40,
-    11,    12,    13,    14,    15,    49,    50,    51,    52,    53,
-    54,    55,    56,    57,    58,    59,    60,    61,     0,     0,
-    17,     0,     0,    62,     0,    18,    19,     0,     0,     0,
-     3,   120,    22,     5,     6,     7,     8,     0,     9,     0,
-    10,    11,    12,    13,    14,    15,    49,    50,    51,    52,
-    53,    54,    55,    56,    57,    58,    74,    60,    61,   101,
-     0,    17,     0,     0,    62,     0,    18,    19,   121,     0,
-     0,     0,     0,    22,    49,    50,    51,    52,    53,    54,
-    55,    56,    57,    58,    59,    60,    61,     0,    48,     0,
-     0,     0,    62,    49,    50,    51,    52,    53,    54,    55,
-    56,    57,    58,    59,    60,    61,     0,     0,     0,     0,
-     0,    62,    63,    64,    49,    50,    51,    52,    53,    54,
-    55,    56,    57,    58,    74,    60,    61,     0,     0,     0,
-     0,     0,    62,    52,    53,    54,    55,    56,    57,    58,
-    74,    60,    61,     0,     0,     0,     0,     0,    62
+#define	YYLAST		1073
+
+
+static const short yytable[] = {    36,
+    94,    99,    98,   200,   101,   202,   104,   107,    38,    38,
+   139,   145,   109,   110,    37,    40,    86,    65,    45,    82,
+   109,   110,   109,   110,    41,    55,    83,   109,   110,   109,
+   110,   191,   140,   109,   110,    46,    39,    39,    88,    65,
+    91,   111,    34,    92,    93,    95,    97,    65,   100,   137,
+   102,   151,   105,   193,   201,    56,   203,    57,   189,    87,
+    89,   141,   156,   113,    42,    83,    47,   115,   116,   117,
+   118,   119,   120,   121,   122,   123,   124,   126,   127,   128,
+   129,   130,    48,    90,    49,    43,    44,   134,   147,    96,
+   218,   165,    50,    65,    42,   138,   175,   176,   108,    51,
+   177,    52,    65,    65,   153,    65,   112,   195,   157,    53,
+   109,   110,   109,   110,    54,    43,    44,   197,   131,   204,
+   125,   146,    69,    70,    71,    72,    73,    74,    75,    76,
+    77,    78,    79,    80,    81,    82,   166,   168,   170,   132,
+   172,   174,    83,   100,   100,    65,   179,   181,   154,   155,
+   182,   212,    65,   213,   158,   161,   184,   186,   162,   206,
+   163,   214,   187,    66,    67,   110,   210,   188,   199,   219,
+   216,    78,   106,    80,    81,    82,   217,    80,    81,    82,
+   167,   169,    83,   171,   173,   209,    83,   220,   211,   178,
+   180,   222,     0,     0,     0,     0,     0,     0,   100,     0,
+   100,     0,     0,   221,     2,     0,     3,     4,     5,     0,
+     6,     7,     8,     9,     0,    10,   100,    11,    12,     0,
+     0,     0,    13,    14,    15,    16,    17,    18,    19,    20,
+    21,    22,    23,    24,    25,     0,    26,    72,    73,    74,
+    75,    76,    77,    78,   106,    80,    81,    82,     0,     0,
+    27,     0,     0,     0,    83,     0,    28,    29,     0,     0,
+     0,     0,    30,    31,    32,    58,     4,     5,    59,     6,
+     7,     8,     9,     0,    10,     0,    11,    12,     0,     0,
+     0,    13,    60,    15,    16,    17,    18,    19,    20,    21,
+    22,    23,    24,    25,    69,    70,    71,    72,    73,    74,
+    75,    76,    77,    78,   106,    80,    81,    82,     0,    27,
+     0,     0,     0,     0,    83,    28,    29,     0,     0,   160,
+     0,     0,     0,    32,   103,    58,     4,     5,    59,     6,
+     7,     8,     9,     0,    10,     0,    11,    12,     0,     0,
+     0,    13,    60,    15,    16,    17,    18,    19,    20,    21,
+    22,    23,    24,    25,    69,    70,    71,    72,    73,    74,
+    75,    76,    77,    78,   106,    80,    81,    82,     0,    27,
+     0,     0,     0,     0,    83,    28,    29,     0,     0,   164,
+     3,     4,     5,    32,     6,     7,     8,     9,     0,    10,
+     0,    11,    12,     0,     0,     0,    13,    14,    15,    16,
+    17,    18,    19,    20,    21,    22,    23,    24,    25,    69,
+    70,    71,    72,    73,    74,    75,    76,    77,    78,   106,
+    80,    81,    82,     0,    27,     0,     0,     0,     0,    83,
+    28,    29,     0,   133,     0,     3,     4,     5,    32,     6,
+     7,     8,     9,     0,    10,     0,    11,    12,     0,     0,
+     0,    13,    60,    15,    16,    17,    18,    19,    20,    21,
+    22,    23,    24,    25,    69,    70,    71,    72,    73,    74,
+    75,    76,    77,    78,   106,    80,    81,    82,     0,    27,
+     0,     0,     0,     0,    83,    28,    29,     0,   135,     0,
+     3,     4,   114,    32,     6,     7,     8,     9,     0,    10,
+     0,    11,    12,     0,     0,     0,    13,    14,    15,    16,
+    17,    18,    19,    20,    21,    22,     0,    24,    25,    69,
+    70,    71,    72,    73,    74,    75,    76,    77,    78,   106,
+    80,    81,    82,     0,    27,     0,     0,     0,     0,    83,
+    28,    29,     0,   136,     0,     3,     4,   183,    32,     6,
+     7,     8,     9,     0,    10,     0,    11,    12,     0,     0,
+     0,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+    22,     0,    24,    25,    69,    70,    71,    72,    73,    74,
+    75,    76,    77,    78,    79,    80,    81,    82,     0,    27,
+     0,     0,     0,     0,    83,    28,    29,     0,   192,     0,
+     3,     4,   185,    32,     6,     7,     8,     9,     0,    10,
+     0,    11,    12,     0,     0,     0,    13,    14,    15,    16,
+    17,    18,    19,    20,    21,    22,     0,    24,    25,     0,
+     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,     0,    27,     0,     0,     0,     3,     4,
+    28,    29,     6,     7,     8,     9,     0,    10,    32,    11,
+    12,     0,     0,     0,    13,    14,    15,    16,    17,    18,
+    19,    20,    21,    22,     0,    24,    25,     0,     0,     0,
+   142,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,     0,    27,     0,     0,     0,     0,     0,    28,    29,
+     0,     0,   143,     0,     0,     0,    32,    69,    70,    71,
+    72,    73,    74,    75,    76,    77,    78,    79,    80,    81,
+    82,   148,     0,     0,     0,     0,     0,    83,     0,     0,
+     0,   144,     0,     0,     0,     0,     0,     0,     0,     0,
+     0,     0,     0,   149,     0,     0,   152,     0,    69,    70,
+    71,    72,    73,    74,    75,    76,    77,    78,   106,    80,
+    81,    82,     0,     0,     0,     0,     0,   190,    83,     0,
+     0,     0,   150,    69,    70,    71,    72,    73,    74,    75,
+    76,    77,    78,   106,    80,    81,    82,     0,   208,     0,
+     0,     0,     0,    83,    69,    70,    71,    72,    73,    74,
+    75,    76,    77,    78,    79,    80,    81,    82,     0,     0,
+     0,     0,     0,     0,    83,    69,    70,    71,    72,    73,
+    74,    75,    76,    77,    78,   106,    80,    81,    82,     0,
+     0,    68,     0,     0,     0,    83,    69,    70,    71,    72,
+    73,    74,    75,    76,    77,    78,    79,    80,    81,    82,
+     0,     0,     0,     0,     0,     0,    83,    84,    85,    69,
+    70,    71,    72,    73,    74,    75,    76,    77,    78,    79,
+    80,    81,    82,     0,     0,     0,     0,     0,     0,    83,
+     0,     0,     0,   194,    69,    70,    71,    72,    73,    74,
+    75,    76,    77,    78,    79,    80,    81,    82,     0,     0,
+     0,     0,     0,     0,    83,     0,     0,     0,   196,    69,
+    70,    71,    72,    73,    74,    75,    76,    77,    78,    79,
+    80,    81,    82,     0,     0,     0,     0,     0,     0,    83,
+     0,     0,     0,   198,    69,    70,    71,    72,    73,    74,
+    75,    76,    77,    78,    79,    80,    81,    82,     0,     0,
+     0,     0,     0,     0,    83,     0,     0,     0,   205,    69,
+    70,    71,    72,    73,    74,    75,    76,    77,    78,    79,
+    80,    81,    82,     0,     0,     0,     0,     0,     0,    83,
+     0,     0,     0,   207,    69,    70,    71,    72,    73,    74,
+    75,    76,    77,    78,   106,    80,    81,    82,     0,     0,
+     0,     0,     0,     0,    83,     0,     0,     0,   215,   159,
+    69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
+   106,    80,    81,    82,     0,     0,     0,     0,     0,     0,
+    83,    69,    70,    71,    72,    73,    74,    75,    76,    77,
+    78,    79,    80,    81,    82,     0,     0,     0,     0,     0,
+     0,    83,    69,    70,    71,    72,    73,    74,    75,    76,
+    77,    78,   106,    80,    81,    82,     0,     0,     0,     0,
+     0,     0,    83
 };
 
 static const short yycheck[] = {     1,
-    10,    32,    35,    34,    44,    20,    21,    35,    20,    21,
-    20,    21,    46,    10,    47,    17,    44,    45,    19,    46,
-    19,    46,    23,    20,    21,    27,    28,    46,    46,    31,
-    32,    33,    47,    13,     1,    47,    13,    47,    39,    40,
-    39,    40,    35,    45,    22,    43,    77,    49,    50,    51,
-    52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
-    62,    28,    34,    35,    36,    37,    33,    36,    37,     3,
-    13,    43,    74,   104,    43,    24,    78,     6,    45,    21,
-    12,     6,    47,     0,   122,    -1,    -1,     0,     1,    -1,
-     3,     4,    59,     6,     7,     8,     9,    -1,    11,   101,
-    13,    14,    15,    16,    17,    18,    -1,    20,   110,   111,
-    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   120,    -1,
-   122,    34,    -1,    -1,    -1,    -1,    39,    40,    -1,    -1,
-    -1,    44,    45,    46,     3,     4,     5,     6,     7,     8,
-     9,    -1,    11,    -1,    13,    14,    15,    16,    17,    18,
-    25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-    35,    36,    37,    -1,    -1,    34,    -1,    -1,    43,    -1,
-    39,    40,    47,    -1,    -1,     3,     4,    46,     6,     7,
-     8,     9,    -1,    11,    -1,    13,    14,    15,    16,    17,
-    18,    25,    26,    27,    28,    29,    30,    31,    32,    33,
-    34,    35,    36,    37,    -1,    -1,    34,    -1,    -1,    43,
-    -1,    39,    40,    47,    -1,    -1,     3,     4,    46,     6,
-     7,     8,     9,    -1,    11,    -1,    13,    14,    15,    16,
-    17,    18,    25,    26,    27,    28,    29,    30,    31,    32,
-    33,    34,    35,    36,    37,    -1,    -1,    34,    -1,    -1,
-    43,    -1,    39,    40,    47,    -1,    -1,     3,     4,    46,
-     6,     7,     8,     9,    -1,    11,    -1,    13,    14,    15,
-    16,    17,    18,    25,    26,    27,    28,    29,    30,    31,
-    32,    33,    34,    35,    36,    37,    -1,    -1,    34,    -1,
-    -1,    43,    -1,    39,    40,    47,    -1,    -1,     3,     4,
-    46,     6,     7,     8,     9,    -1,    11,    -1,    13,    14,
-    15,    16,    17,    18,    24,    25,    26,    27,    28,    29,
-    30,    31,    32,    33,    34,    35,    36,    37,    -1,    34,
-    -1,    -1,    -1,    43,    39,    40,    -1,    -1,    -1,     3,
-     4,    46,     6,     7,     8,     9,    -1,    11,    -1,    13,
-    14,    15,    16,    17,    18,    25,    26,    27,    28,    29,
-    30,    31,    32,    33,    34,    35,    36,    37,    -1,    -1,
-    34,    -1,    -1,    43,    -1,    39,    40,    -1,    -1,    -1,
-     3,    10,    46,     6,     7,     8,     9,    -1,    11,    -1,
-    13,    14,    15,    16,    17,    18,    25,    26,    27,    28,
-    29,    30,    31,    32,    33,    34,    35,    36,    37,    10,
-    -1,    34,    -1,    -1,    43,    -1,    39,    40,    47,    -1,
-    -1,    -1,    -1,    46,    25,    26,    27,    28,    29,    30,
-    31,    32,    33,    34,    35,    36,    37,    -1,    20,    -1,
-    -1,    -1,    43,    25,    26,    27,    28,    29,    30,    31,
-    32,    33,    34,    35,    36,    37,    -1,    -1,    -1,    -1,
-    -1,    43,    44,    45,    25,    26,    27,    28,    29,    30,
-    31,    32,    33,    34,    35,    36,    37,    -1,    -1,    -1,
-    -1,    -1,    43,    28,    29,    30,    31,    32,    33,    34,
-    35,    36,    37,    -1,    -1,    -1,    -1,    -1,    43
+    47,    50,    49,    11,    51,    11,    53,    35,    36,    36,
+    11,    11,    33,    34,    59,    61,     3,    48,    61,    51,
+    33,    34,    33,    34,    20,    27,    58,    33,    34,    33,
+    34,    62,    33,    33,    34,    61,    64,    64,    40,    48,
+    42,    62,     1,    45,    46,    47,    48,    48,    50,    62,
+    52,    62,    54,    62,    62,    20,    62,    20,    62,     3,
+    51,    62,   109,    65,    32,    58,    61,    69,    70,    71,
+    72,    73,    74,    75,    76,    77,    78,    79,    80,    81,
+    82,    83,    61,    42,    61,    53,    54,    89,    11,    48,
+    11,   138,    61,    48,    32,    11,   145,   146,    36,    61,
+   147,    61,    48,    48,   106,    48,    65,    62,   110,    61,
+    33,    34,    33,    34,    61,    53,    54,    62,    36,    62,
+    79,    11,    38,    39,    40,    41,    42,    43,    44,    45,
+    46,    47,    48,    49,    50,    51,   138,   139,   140,    64,
+   142,   143,    58,   145,   146,    48,   148,   149,     3,    20,
+   152,   200,    48,   202,    37,     3,   158,   159,     3,    62,
+     7,   208,    32,    59,    60,    34,     7,    13,    62,   218,
+    62,    47,    48,    49,    50,    51,    62,    49,    50,    51,
+   139,   140,    58,   142,   143,   187,    58,    62,   190,   148,
+   149,     0,    -1,    -1,    -1,    -1,    -1,    -1,   200,    -1,
+   202,    -1,    -1,     0,     1,    -1,     3,     4,     5,    -1,
+     7,     8,     9,    10,    -1,    12,   218,    14,    15,    -1,
+    -1,    -1,    19,    20,    21,    22,    23,    24,    25,    26,
+    27,    28,    29,    30,    31,    -1,    33,    41,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    -1,    -1,
+    47,    -1,    -1,    -1,    58,    -1,    53,    54,    -1,    -1,
+    -1,    -1,    59,    60,    61,     3,     4,     5,     6,     7,
+     8,     9,    10,    -1,    12,    -1,    14,    15,    -1,    -1,
+    -1,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+    28,    29,    30,    31,    38,    39,    40,    41,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    -1,    47,
+    -1,    -1,    -1,    -1,    58,    53,    54,    -1,    -1,    63,
+    -1,    -1,    -1,    61,    62,     3,     4,     5,     6,     7,
+     8,     9,    10,    -1,    12,    -1,    14,    15,    -1,    -1,
+    -1,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+    28,    29,    30,    31,    38,    39,    40,    41,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    -1,    47,
+    -1,    -1,    -1,    -1,    58,    53,    54,    -1,    -1,    63,
+     3,     4,     5,    61,     7,     8,     9,    10,    -1,    12,
+    -1,    14,    15,    -1,    -1,    -1,    19,    20,    21,    22,
+    23,    24,    25,    26,    27,    28,    29,    30,    31,    38,
+    39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
+    49,    50,    51,    -1,    47,    -1,    -1,    -1,    -1,    58,
+    53,    54,    -1,    62,    -1,     3,     4,     5,    61,     7,
+     8,     9,    10,    -1,    12,    -1,    14,    15,    -1,    -1,
+    -1,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+    28,    29,    30,    31,    38,    39,    40,    41,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    -1,    47,
+    -1,    -1,    -1,    -1,    58,    53,    54,    -1,    62,    -1,
+     3,     4,     5,    61,     7,     8,     9,    10,    -1,    12,
+    -1,    14,    15,    -1,    -1,    -1,    19,    20,    21,    22,
+    23,    24,    25,    26,    27,    28,    -1,    30,    31,    38,
+    39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
+    49,    50,    51,    -1,    47,    -1,    -1,    -1,    -1,    58,
+    53,    54,    -1,    62,    -1,     3,     4,     5,    61,     7,
+     8,     9,    10,    -1,    12,    -1,    14,    15,    -1,    -1,
+    -1,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+    28,    -1,    30,    31,    38,    39,    40,    41,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    -1,    47,
+    -1,    -1,    -1,    -1,    58,    53,    54,    -1,    62,    -1,
+     3,     4,     5,    61,     7,     8,     9,    10,    -1,    12,
+    -1,    14,    15,    -1,    -1,    -1,    19,    20,    21,    22,
+    23,    24,    25,    26,    27,    28,    -1,    30,    31,    -1,
+    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    -1,    47,    -1,    -1,    -1,     3,     4,
+    53,    54,     7,     8,     9,    10,    -1,    12,    61,    14,
+    15,    -1,    -1,    -1,    19,    20,    21,    22,    23,    24,
+    25,    26,    27,    28,    -1,    30,    31,    -1,    -1,    -1,
+    11,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    47,    -1,    -1,    -1,    -1,    -1,    53,    54,
+    -1,    -1,    33,    -1,    -1,    -1,    61,    38,    39,    40,
+    41,    42,    43,    44,    45,    46,    47,    48,    49,    50,
+    51,    11,    -1,    -1,    -1,    -1,    -1,    58,    -1,    -1,
+    -1,    62,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    -1,    -1,    -1,    33,    -1,    -1,    11,    -1,    38,    39,
+    40,    41,    42,    43,    44,    45,    46,    47,    48,    49,
+    50,    51,    -1,    -1,    -1,    -1,    -1,    11,    58,    -1,
+    -1,    -1,    62,    38,    39,    40,    41,    42,    43,    44,
+    45,    46,    47,    48,    49,    50,    51,    -1,    11,    -1,
+    -1,    -1,    -1,    58,    38,    39,    40,    41,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    -1,    -1,
+    -1,    -1,    -1,    -1,    58,    38,    39,    40,    41,    42,
+    43,    44,    45,    46,    47,    48,    49,    50,    51,    -1,
+    -1,    33,    -1,    -1,    -1,    58,    38,    39,    40,    41,
+    42,    43,    44,    45,    46,    47,    48,    49,    50,    51,
+    -1,    -1,    -1,    -1,    -1,    -1,    58,    59,    60,    38,
+    39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
+    49,    50,    51,    -1,    -1,    -1,    -1,    -1,    -1,    58,
+    -1,    -1,    -1,    62,    38,    39,    40,    41,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    -1,    -1,
+    -1,    -1,    -1,    -1,    58,    -1,    -1,    -1,    62,    38,
+    39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
+    49,    50,    51,    -1,    -1,    -1,    -1,    -1,    -1,    58,
+    -1,    -1,    -1,    62,    38,    39,    40,    41,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    -1,    -1,
+    -1,    -1,    -1,    -1,    58,    -1,    -1,    -1,    62,    38,
+    39,    40,    41,    42,    43,    44,    45,    46,    47,    48,
+    49,    50,    51,    -1,    -1,    -1,    -1,    -1,    -1,    58,
+    -1,    -1,    -1,    62,    38,    39,    40,    41,    42,    43,
+    44,    45,    46,    47,    48,    49,    50,    51,    -1,    -1,
+    -1,    -1,    -1,    -1,    58,    -1,    -1,    -1,    62,    37,
+    38,    39,    40,    41,    42,    43,    44,    45,    46,    47,
+    48,    49,    50,    51,    -1,    -1,    -1,    -1,    -1,    -1,
+    58,    38,    39,    40,    41,    42,    43,    44,    45,    46,
+    47,    48,    49,    50,    51,    -1,    -1,    -1,    -1,    -1,
+    -1,    58,    38,    39,    40,    41,    42,    43,    44,    45,
+    46,    47,    48,    49,    50,    51,    -1,    -1,    -1,    -1,
+    -1,    -1,    58
 };
 /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
 
@@ -983,161 +1170,263 @@ case 12:
 {;;
     break;}
 case 13:
-{yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0]));;
+{yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0])); yyval.type = STR;;
     break;}
 case 14:
-{yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text);;
+{yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text); yyval.type = STR;;
     break;}
 case 15:
-{yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text);;
+{yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text); yyval.type = STR;;
     break;}
 case 16:
-{;;
+{((yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1], 0L)); yyval.type = STR;;
     break;}
 case 17:
-{if(yyval.text =(char*)malloc(strlen(yyvsp[-2].tptr->name) +strlen(yyvsp[0].tptr->name) + 2)) sprintf(yyval.text, "%s:%s", yyvsp[-2].tptr->name, yyvsp[0].tptr->name);;
+{((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
+    break;}
+case 18:
+{((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
     break;}
 case 19:
-{if(!yyval.a_data) {yyval.a_data = (double*)malloc(sizeof(double)); yyval.a_count = 1; yyval.a_data[0] = yyval.val;};
+{((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
     break;}
 case 20:
-{push(&yyval, &yyvsp[0]);;
+{((yyvsp[-5].tptr->fnctptr)(&yyval, &yyvsp[-3], yyvsp[-1].text)); yyval.type = STR;;
     break;}
 case 21:
-{exec_clause(&yyval);;
+{;;
     break;}
 case 22:
-{range_array(&yyval, yyvsp[0].text);;
-    break;}
-case 23:
-{if(yyvsp[-2].val < yyvsp[0].val && (yyval.a_data = (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 );;
+{if(yyval.text = PushString((char*)malloc(strlen(yyvsp[-2].tptr->name) +strlen(yyvsp[0].tptr->name) + 2))) sprintf(yyval.text, "%s:%s", yyvsp[-2].tptr->name, yyvsp[0].tptr->name);;
     break;}
 case 24:
-{yyval.val = yyvsp[0].val; yyval.type = NUM;;
+{if(!yyval.a_data) {yyval.a_data = PushArray((double*)malloc(sizeof(double))); yyval.a_count = 1; yyval.a_data[0] = yyval.val;};
     break;}
 case 25:
-{yyval.val = 0.0;;
+{push(&yyval, &yyvsp[0]);yyval.type = ARR;;
     break;}
 case 26:
-{yyval.val = syntax_level ? syntax_level->clval : 0.0; ;
+{exec_clause(&yyval);yyval.type = ARR;;
     break;}
 case 27:
-{yyval.val = _PI; yyval.type = NUM;;
+{range_array(&yyval, yyvsp[0].text);yyval.type = ARR;;
     break;}
 case 28:
-{yyval.val = 2.71828182845905; yyval.type = NUM;;
-    break;}
-case 29:
-{yyvsp[0].tptr->GetValue(&yyval);;
+{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 30:
-{eval(&yyvsp[0], &yyval);;
+{yyval.val = ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)); yyval.type = BOOLVAL;;
     break;}
 case 31:
-{yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
+{yyval.val = 1.0; yyval.type = BOOLVAL;;
     break;}
 case 32:
-{yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
+{yyval.val = 0.0; yyval.type = BOOLVAL;;
     break;}
 case 33:
-{yyval.val = ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val));;
+{yyval.val = ((yyvsp[-2].val != 0) && (yyvsp[0].val != 0))? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 34:
-{yyval.val = ((yyvsp[-3].tptr->fnctptr)(proc_clause(&yyvsp[-1])));;
+{yyval.val = ((yyvsp[-2].val != 0) || (yyvsp[0].val != 0))? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 35:
-{push(&yyvsp[-2], &yyvsp[0]); yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-2]));;
+{yyval.val = (yyvsp[-2].val == yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 36:
-{push(&yyvsp[-4], &yyvsp[-2]); push(&yyvsp[-4], &yyvsp[0]); yyval.val = ((yyvsp[-7].tptr->fnctptr)(&yyvsp[-4]));;
+{yyval.val = (yyvsp[-2].val != yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 37:
-{yyval.val = ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval));;
+{yyval.val = (yyvsp[-2].val > yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 38:
-{yyvsp[-1].text = string_value(&yyvsp[-1]); yyval.val = ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval));;
+{yyval.val = (yyvsp[-2].val >= yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 39:
-{yyval.val = ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), proc_clause(&yyvsp[-1]), 0L));;
+{yyval.val = (yyvsp[-2].val < yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 40:
-{yyval.val = ((*yyvsp[-7].tptr->fnctptr)(proc_clause(&yyvsp[-5]), proc_clause(&yyvsp[-3]), yyvsp[-1].text));;
+{yyval.val = (yyvsp[-2].val <= yyvsp[0].val) ? 1 : 0; yyval.type = BOOLVAL;;
     break;}
 case 41:
-{yyval.val = yyvsp[-2].val != 0 ? eval(&yyvsp[0], &yyval) : 0.0;;
+{yyval.val = yyvsp[0].val; yyval.type = NUM;;
     break;}
 case 42:
-{yyval.val = yyvsp[-4].val != 0 ? eval(&yyvsp[-2], &yyval) : eval(&yyvsp[0], &yyval);;
+{yyval.val = yyvsp[0].val; yyval.type = BOOLVAL;;
     break;}
 case 43:
-{yyval.val = ((yyvsp[-2].val != 0) && (yyvsp[0].val != 0))? 1 : 0;;
+{yyval.val = 0.0;;
     break;}
 case 44:
-{yyval.val = ((yyvsp[-2].val != 0) || (yyvsp[0].val != 0))? 1 : 0;;
+{yyval.val = syntax_level ? syntax_level->clval : 0.0;  yyval.type = NUM;;
     break;}
 case 45:
-{yyval.val = (yyvsp[-2].val == yyvsp[0].val) ? 1 : 0;;
+{yyval.val = _PI; yyval.type = NUM;;
     break;}
 case 46:
-{yyval.val = (yyvsp[-2].val != yyvsp[0].val) ? 1 : 0;;
+{yyval.val = 2.71828182845905; yyval.type = NUM;;
     break;}
 case 47:
-{yyval.val = (yyvsp[-2].val > yyvsp[0].val) ? 1 : 0;;
+{yyvsp[0].tptr->GetValue(&yyval);;
     break;}
 case 48:
-{yyval.val = (yyvsp[-2].val >= yyvsp[0].val) ? 1 : 0;;
+{eval(&yyvsp[0], &yyval, 0L);;
     break;}
 case 49:
-{yyval.val = (yyvsp[-2].val < yyvsp[0].val) ? 1 : 0;;
+{yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
     break;}
 case 50:
-{yyval.val = (yyvsp[-2].val <= yyvsp[0].val) ? 1 : 0;;
+{yyvsp[-2].tptr->SetValue(&yyval, &yyvsp[0]);;
     break;}
 case 51:
-{yyval.val = yyvsp[-2].val + yyvsp[0].val;;
+{yyval.val = ((yyvsp[-3].tptr->fnctptr)(yyvsp[-1].val)); yyval.type = NUM;;
     break;}
 case 52:
-{yyval.val = yyvsp[-2].val - yyvsp[0].val;;
+{yyval.val = ((yyvsp[-3].tptr->fnctptr)(proc_clause(&yyvsp[-1]))); yyval.type = NUM;;
     break;}
 case 53:
-{yyval.val = yyvsp[-2].val * yyvsp[0].val;;
+{ 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;;
     break;}
 case 54:
-{if(yyvsp[0].val != 0.0) yyval.val = yyvsp[-2].val / yyvsp[0].val;
-					else yyval.val = (getsym(HashValue((unsigned char*)"zdiv")))->GetValue(); ;
+{ 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;;
     break;}
 case 55:
-{yyval.val = -yyvsp[0].val;;
+{yyval.val = ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L)); yyval.type = NUM;;
     break;}
 case 56:
-{yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val+1.0); yyval.val -= 1.0; yyval.type = NUM;;
+{yyvsp[-1].text = string_value(&yyvsp[-1]); yyval.val = ((yyvsp[-3].tptr->fnctptr)(&yyvsp[-1], &yyval, 0L)); yyval.type = NUM;;
     break;}
 case 57:
-{yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val-1.0); yyval.val += 1.0; yyval.type = NUM;;
+{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
     break;}
 case 58:
-{yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val+1.0); yyval.type = NUM;;
+{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
     break;}
 case 59:
-{yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val-1.0); yyval.type = NUM;;
+{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
     break;}
 case 60:
-{yyval.val = pow(yyvsp[-2].val, yyvsp[0].val);;
+{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
     break;}
 case 61:
-{memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;;
+{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
     break;}
 case 62:
-{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
+{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
     break;}
 case 63:
-{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
+{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
     break;}
 case 64:
-{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
+{yyval.val = ((yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyval, yyvsp[-1].text)); yyval.type = NUM;;
     break;}
 case 65:
+{range_array2(&yyvsp[-3], &yyvsp[-1]);yyval.val = ((*yyvsp[-5].tptr->fnctptr)(&yyvsp[-3], &yyvsp[-1], 0L)); 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;;
+    break;}
+case 67:
+{yyval.val=((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), proc_clause(&yyvsp[-1]), 0L));;
+    break;}
+case 68:
+{yyval.val=((*yyvsp[-7].tptr->fnctptr)(proc_clause(&yyvsp[-5]), proc_clause(&yyvsp[-3]), yyvsp[-1].text));;
+    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;;
+    break;}
+case 70:
+{yyval.val = ((*yyvsp[-5].tptr->fnctptr)(proc_clause(&yyvsp[-3]), yyvsp[-1].text));  yyval.type = NUM;;
+    break;}
+case 71:
+{(*yyvsp[-2].tptr->fnctptr)(&yyval, 0L);;
+    break;}
+case 72:
+{(*yyvsp[-3].tptr->fnctptr)(&yyval, &yyvsp[-1]);;
+    break;}
+case 73:
+{yyval.val = yyvsp[-2].val != 0 ? eval(&yyvsp[0], &yyval, 0L) : 0.0;;
+    break;}
+case 74:
+{yyval.val = yyvsp[-4].val != 0.0 ? eval(&yyvsp[-2], &yyval, 0L) : eval(&yyvsp[0], &yyval, 0L);;
+    break;}
+case 75:
+{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 76:
+{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 77:
+{yyval.val = yyvsp[-2].val * yyvsp[0].val; yyval.type = NUM;;
+    break;}
+case 78:
+{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 79:
+{yyval.val = -yyvsp[0].val;;
+    break;}
+case 80:
+{yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val+1.0); yyval.val -= 1.0; yyval.type = NUM;;
+    break;}
+case 81:
+{yyval.val=yyvsp[-1].tptr->GetValue(); yyvsp[-1].tptr->SetValue(yyval.val-1.0); yyval.val += 1.0; yyval.type = NUM;;
+    break;}
+case 82:
+{yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val+1.0); yyval.type = NUM;;
+    break;}
+case 83:
+{yyval.val=yyvsp[0].tptr->GetValue(); yyvsp[0].tptr->SetValue(yyval.val-1.0); yyval.type = NUM;;
+    break;}
+case 84:
+{yyval.val = pow(yyvsp[-2].val, yyvsp[0].val);;
+    break;}
+case 85:
+{memcpy(&yyval, &yyvsp[-1], sizeof(YYSTYPE)); yyvsp[-1].a_data = 0L; yyvsp[-1].a_count = 0;;
+    break;}
+case 86:
+{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 87:
+{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 88:
+{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 89:
+{make_time(&yyval, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val+1.0e-10);;
+    break;}
+case 90:
+{make_time(&yyval, yyvsp[-4].val, yyvsp[-2].val, yyvsp[0].val+1.0e-10);;
+    break;}
+case 91:
+{make_time(&yyval, yyvsp[-2].val, yyvsp[0].val, 1.0e-10);;
+    break;}
+case 92:
+{make_time(&yyval, yyvsp[-2].val, yyvsp[0].val, 1.0e-10);;
+    break;}
+case 93:
+{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
+    break;}
+case 94:
+{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
+    break;}
+case 95:
+{memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
+    break;}
+case 96:
 {memcpy(&yyval, yyvsp[-4].val != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE));
     break;}
 }
@@ -1365,15 +1654,12 @@ yyerrhandle:
 
 
 // The symrec class
-symrec::symrec(unsigned int h_n, int typ, symrec *nxt) 
-{
-	h_name = h_n;
-	type = typ;
-	next = nxt;
-	row = col = -1;
-	name = text = 0L;
-	var = 0.0;
-	isSSval = false;
+symrec::symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt) 
+{
+	h_name = h_n;	h2_name = h2_n;		type = typ;
+	next = nxt;	row = col = -1;		name = text = 0L;
+	var = 0.0;	isSSval = false;
+	a_data = 0L;	a_count = 0;
 	fnctptr = (double (*)(...))nop;
 }
 
@@ -1412,18 +1698,29 @@ symrec::GetValue(void *re)
 		//GetResult( , , ,true) inhibits reentrance into parser !
 		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)){
 			if(text) free(text);		text = 0L;
-			if(ares.type == ET_VALUE) {
-				res->type = VAR;	res->val = ares.value;
-				res->text = 0L;
-				}
-			else if(ares.type == ET_TEXT && ares.text) {
+			switch(ares.type) {
+			case ET_VALUE:
+				res->type = NUM;	res->val = ares.value;
+				res->text = 0L;		break;
+			case ET_BOOL:
+				res->type = BOOLVAL;	res->val = ares.value;
+				res->text = 0L;		break;
+			case ET_DATE:
+				res->type = DATE1;	res->val = ares.value;
+				res->text = 0L;		break;
+			case ET_TIME:
+				res->type = TIME1;	res->val = ares.value;
+				res->text = 0L;		break;
+			case ET_DATETIME:
+				res->type = DATETIME1;	res->val = ares.value;
+				res->text = 0L;		break;
+			case ET_TEXT:
 				res->type = STR;	res->val = 0.0;
-				text = strdup(ares.text);
-				res->text = text;
-				}
-			else {
+				if(ares.text) res->text = PushString(text = strdup(ares.text));
+				else res->text = 0L;	break;
+			default:
 				res->type = NUM;	res->val = var;
-				res->text = 0L;
+				res->text = 0L;		break;
 				}
 			var = res->val;
 			return;
@@ -1431,15 +1728,18 @@ symrec::GetValue(void *re)
 		isSSval = false;
 		row = col = -1;
 		}
-	if(text && text[0]) {
-		res->text = strdup(text);
+	if(a_data && a_count) {
+		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;
 		}
 	else {
 		res->type = NUM;	res->val = var;
 		res->text = 0L;
 		}
-	res->a_data = 0L;	res->a_count = 0L;
 }
 
 double 
@@ -1454,6 +1754,7 @@ symrec::SetValue(double v)
 		isSSval = false;
 		row = col = -1;
 		}
+	a_data = 0L;	a_count = 0;
 	return var = v;
 }
 
@@ -1475,6 +1776,7 @@ symrec::SetValue(void* d, void* s)
 	var = src->val;
 	if(text) free(text);		text = 0L;
 	if(src->text && src->text[0]) 	text = strdup(src->text);
+	a_data = src->a_data;		a_count = src->a_count;
 	GetValue(d);
 	return;
 }
@@ -1512,6 +1814,15 @@ static void yyargserr(char *s)
 	last_err_desc = "#ARGS";
 }
 
+static void make_time(YYSTYPE *dst, double h, double m, double s)
+{
+	if(!dst || h < 0.0 || 24.0 < h || m < 0.0 || 60.0 < m || s < 0.0 || 60.0 < s) {
+		yyerror("parse error");			return;
+		}
+	dst->val = s/60.0 + m;		dst->val = dst->val/60.0 + h;
+	dst->val /= 24.0;		dst->type = TIME1;
+}
+
 static void store_res(YYSTYPE *res)
 {
 	if(last_err_desc) {
@@ -1519,7 +1830,27 @@ static void store_res(YYSTYPE *res)
 		line_res.value = 0.0;
 		strcpy(res_txt, last_err_desc);
 		}
-	else if(res->type == STR) {
+	else if(res->type == NUM){
+		line_res.type = ET_VALUE;
+		line_res.value = res->val;
+		}
+	else if(res->type == BOOLVAL){
+		line_res.type = ET_BOOL;
+		line_res.value = res->val;
+		}
+	else if(res->type == DATE1){
+		line_res.type = ET_DATE;
+		line_res.value = res->val;
+		}
+	else if(res->type == TIME1){
+		line_res.type = ET_TIME;
+		line_res.value = res->val;
+		}
+	else if(res->type == DATETIME1){
+		line_res.type = ET_DATETIME;
+		line_res.value = res->val;
+		}
+ 	else if(res->type == STR) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
 		if(res->text) strcpy(res_txt, res->text);
@@ -1604,10 +1935,11 @@ static void pop_syntax()
 		}
 }
 
-static double eval(YYSTYPE *sr, YYSTYPE *dst) 
+static double eval(YYSTYPE *sr, YYSTYPE *dst, char *dum) 
 {
 	anyResult *ar;
 
+	if(dum) yyerror("parse error");
 	if(!sr || !sr->text) return 0.0;
 	parse_level++;
 	ar = do_formula(0L, sr->text);
@@ -1642,10 +1974,11 @@ static double sign(double v)
 }
 
 static long idum=0;
-
-static double rand(double v)
+static double rand1(YYSTYPE *dst, YYSTYPE *src)
 {
-	return ran2(&idum);
+	if(!dst) return 0.0;
+	dst->type = NUM;
+	return(dst->val = ran2(&idum));
 }
 
 static double srand(double v)
@@ -1659,14 +1992,9 @@ static double factorial(double v)
 	return factrl((int)v);
 }
 
-static void close_arr_func(YYSTYPE *sr)
-{
-	if(sr->a_data) free(sr->a_data);
-	sr->a_data = 0L;		sr->a_count = 0;
-}
-
-static double _strlen(YYSTYPE *sr, YYSTYPE *dst)
+static double _strlen(YYSTYPE *sr, YYSTYPE *dst, char *dum)
 {
+	if(dum) yyerror("parse error");
 	if(!sr || !sr->text) return 0.0;
 	return (double)strlen(sr->text);
 }
@@ -1680,7 +2008,6 @@ static double min(YYSTYPE *sr)
 	if(sr->a_data && sr->a_data){
 		for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) 
 			if(sr->a_data[i] < sr->val) sr->val = sr->a_data[i];
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -1694,7 +2021,6 @@ static double max(YYSTYPE *sr)
 	if(sr->a_data){
 		for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) 
 			if(sr->a_data[i] > sr->val) sr->val = sr->a_data[i];
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -1702,10 +2028,7 @@ static double max(YYSTYPE *sr)
 static double count(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
-	if(sr->a_data){
-		sr->val = (double)sr->a_count;
-		close_arr_func(sr);
-		}
+	if(sr->a_data) sr->val = (double)sr->a_count;
 	else sr->val = 0.0;
 	return sr->val;
 }
@@ -1717,47 +2040,64 @@ static double sum(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	if(sr->a_data){
 		for(i = 0, sr->val = 0.0; i < sr->a_count; i++) sr->val += sr->a_data[i];
-		close_arr_func(sr);
 		}
 	else sr->val = 0.0;
 	return sr->val;
 }
 
-static double calc_variance(double *values, int n)
+static double mean(YYSTYPE *sr) 
 {
-	int i;
-	double ss, d, mean = d_amean(n, values);
+	if(!sr) return 0.0;
+	if(sr->a_data && sr->a_count){
+		sr->val = d_amean(sr->a_count, sr->a_data );
+		}
+	return sr->val;
+}
 
-	for(i=0, ss=0.0; i < n; i++) ss += ((d=values[i]-mean)*d);
-	return (ss/(n-1));
+static double kurt(YYSTYPE *sr) 
+{
+	if(!sr) return 0.0;
+	if(sr->a_data && sr->a_count > 3){
+		sr->val = d_kurt(sr->a_count, sr->a_data );
+		}
+	return sr->val;
 }
 
-static double mean(YYSTYPE *sr) 
+static double skew(YYSTYPE *sr) 
 {
 	if(!sr) return 0.0;
-	if(sr->a_data && sr->a_count){
-		sr->val = d_amean(sr->a_count, sr->a_data );
-		close_arr_func(sr);
+	if(sr->a_data && sr->a_count > 2){
+		sr->val = d_skew(sr->a_count, sr->a_data );
 		}
 	return sr->val;
 }
 
 static double gmean(YYSTYPE *sr) 
 {
+	int i;
+
 	if(!sr) return 0.0;
 	if(sr->a_data && sr->a_count){
+		for(i = 0; i < sr->a_count; i++) if(sr->a_data[i] <= 0.0) {
+			last_err_desc = "#VALUE";
+			return sr->val = 0.0;
+			}
 		sr->val = d_gmean(sr->a_count, sr->a_data );
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
 
 static double hmean(YYSTYPE *sr) 
 {
+	int i;
+
 	if(!sr) return 0.0;
 	if(sr->a_data && sr->a_count){
+		for(i = 0; i < sr->a_count; i++) if(sr->a_data[i] <= 0.0) {
+			last_err_desc = "#VALUE";
+			return sr->val = 0.0;
+			}
 		sr->val = d_hmean(sr->a_count, sr->a_data );
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -1767,7 +2107,6 @@ static double quartile1(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, &sr->val, 0L, 0L);
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -1777,7 +2116,6 @@ static double quartile2(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, 0L, &sr->val, 0L);
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -1787,7 +2125,6 @@ static double quartile3(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, 0L, 0L, &sr->val);
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -1797,8 +2134,7 @@ static double variance(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count){
-		sr->val = calc_variance(sr->a_data, sr->a_count);
-		close_arr_func(sr);
+		sr->val = d_variance(sr->a_count, sr->a_data);
 		}
 	return sr->val;
 }
@@ -1808,8 +2144,7 @@ static double stdev(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count){
-		sr->val = sqrt(calc_variance(sr->a_data, sr->a_count));
-		close_arr_func(sr);
+		sr->val = sqrt(d_variance(sr->a_count, sr->a_data));
 		}
 	return sr->val;
 }
@@ -1819,8 +2154,7 @@ static double sterr(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count){
-		sr->val = sqrt(calc_variance(sr->a_data, sr->a_count))/sqrt(sr->a_count);
-		close_arr_func(sr);
+		sr->val = sqrt(d_variance(sr->a_count, sr->a_data))/sqrt(sr->a_count);
 		}
 	return sr->val;
 }
@@ -1831,7 +2165,6 @@ static double beta(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2){
 		sr->val = betaf(sr->a_data[0], sr->a_data[1]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  beta(u, v).");
 	return sr->val;
@@ -1843,7 +2176,6 @@ static double _gammp(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2){
 		sr->val = gammp(sr->a_data[0], sr->a_data[1]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  gammp(a, x).");
 	return sr->val;
@@ -1855,7 +2187,6 @@ static double _gammq(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2){
 		sr->val = gammq(sr->a_data[0], sr->a_data[1]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  gammq(a, x).");
 	return sr->val;
@@ -1866,10 +2197,13 @@ static double _betai(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3){
+		if(sr->a_data[2] < 0.0 || sr->a_data[2] > 1.0) {
+			last_err_desc = "#VALUE";
+			return sr->val = 0.0;
+			}
 		sr->val = betai(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
-		close_arr_func(sr);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  betai(x, a, b).");
+	else yyargserr("Wrong number of arguments\nin call to  betai(a, b, x).");
 	return sr->val;
 }
 
@@ -1879,7 +2213,6 @@ static double _bincof(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2){
 		sr->val = bincof(sr->a_data[0], sr->a_data[1]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  bincof(n, k).");
 	return sr->val;
@@ -1891,19 +2224,30 @@ static double binomdist(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3){
 		sr->val = binomdistf(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  binomdist(s, n, p).");
 	return sr->val;
 }
 
+static double binomfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+        if(sr->a_data && sr->a_count == 3){
+		sr->val = bincof(sr->a_data[1], sr->a_data[0]);
+		sr->val *= pow(sr->a_data[2], sr->a_data[0]);
+		sr->val *= pow(1.0 - sr->a_data[2], sr->a_data[1] - sr->a_data[0]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  binomfreq(s, n, p).");
+	return sr->val;
+}
+
 static double normdist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = norm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  normdist(x, mean, SD).");
 	return sr->val;
@@ -1915,19 +2259,50 @@ static double norminv(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3) {
 		sr->val = distinv(norm_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  norminv(p, mean, SD).");
 	return sr->val;
 }
 
+static double normfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 3){
+		sr->val = norm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  normfreq(x, mean, SD).");
+	return sr->val;
+}
+
+static double lognormdist(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 3){
+		sr->val = lognorm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  lognormdist(x, mean, SD).");
+	return sr->val;
+}
+
+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], 2.0);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  lognorminv(p, mean, SD).");
+	return sr->val;
+}
+
 static double chidist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = chi_dist(sr->a_data[0], sr->a_data[1], 1.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  chidist(x, df).");
 	return sr->val;
@@ -1939,7 +2314,6 @@ static double chiinv(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2) {
 		sr->val = distinv(chi_dist,sr->a_data[1], 1.0, sr->a_data[0], 2.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  chiinv(p, df).");
 	return sr->val;
@@ -1951,7 +2325,6 @@ static double tdist(YYSTYPE *sr)
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = t_dist(sr->a_data[0], sr->a_data[1], 1.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  tdist(x, df).");
 	return sr->val;
@@ -1963,7 +2336,6 @@ static double tinv(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2) {
 		sr->val = distinv(t_dist,sr->a_data[1], 1.0, sr->a_data[0], 2.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  tinv(p, df).");
 	return sr->val;
@@ -1975,19 +2347,28 @@ static double poisdist(YYSTYPE *sr)
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = pois_dist(sr->a_data[0], sr->a_data[1], 1.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  poisdist(x, mean).");
 	return sr->val;
 }
 
+static double poisfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = exp(log(sr->a_data[1])*sr->a_data[0] - sr->a_data[1] - gammln(1.0 + sr->a_data[0]));
+		}
+	else yyargserr("Wrong number of arguments\nin call to  poisfreq(x, mean).");
+	return sr->val;
+}
+
 static double fdist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
 	sr->val = 0;
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = f_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  fdist(x, df1, df2).");
 	return sr->val;
@@ -1999,7 +2380,6 @@ static double finv(YYSTYPE *sr)
 	sr->val = 0;
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = distinv(f_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  finv(p, df1, df2).");
 	return sr->val;
@@ -2011,7 +2391,6 @@ static double pearson(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	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);
-		close_arr_func(sr1);		close_arr_func(sr2);
 		}
 	else yyargserr("Bad arguments in call to function\npearson(range1; range2 [;\"dest\"]).");
 	return sr1->val;
@@ -2023,12 +2402,22 @@ static double spearman(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	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);
-		close_arr_func(sr1);		close_arr_func(sr2);
 		}
 	else yyargserr("Bad arguments in call to function\nspearman(range1; range2 [;\"dest\"]).");
 	return sr1->val;
 }
 
+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);
+		}
+	else yyargserr("Bad arguments in call to function\nkendall(range1; range2 [;\"dest\"]).");
+	return sr1->val;
+}
+
 static double regression(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 {
 	if(!sr1 || !sr2) return 0.0;
@@ -2036,21 +2425,52 @@ static double regression(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	if(!(dest)) yyargserr("No destination range in call to function\nregression(range1; range2; \"dest\").");
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
 		sr1->val = sr2->val = d_regression(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
-		close_arr_func(sr1);		close_arr_func(sr2);
 		}
 	else yyargserr("Bad arguments in call to function\nregression(range1; range2; \"dest\").");
 	return sr1->val;
 }
 
+static double covar(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_covar(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		}
+	else yyargserr("Bad arguments in call to function\ncovar(range1; range2).");
+	return sr1->val;
+}
+
 static double ttest(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 && sr2->a_count > 1){
 		sr1->val = sr2->val = d_ttest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
-		close_arr_func(sr1);		close_arr_func(sr2);
 		}
-	else yyargserr("Bad arguments in call to function\nttest(range1; range2[;\"dest\"]).");
+	else yyargserr("Bad arguments in call to function\nttest(array1; array2[;\"dest\"]).");
+	return sr1->val;
+}
+
+static double ttest2(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 && sr2->a_count > 1){
+		sr1->val = sr2->val = d_ttest2(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		}
+	else yyargserr("Bad arguments in call to function\nttest2(range1; range2[;\"dest\"]).");
+	return sr1->val;
+}
+
+static double utest(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 && sr2->a_count > 1){
+		sr1->val = sr2->val = d_utest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
+		}
+	else yyargserr("Bad arguments in call to function\nutest2(array1; array2[;\"dest\"]).");
 	return sr1->val;
 }
 
@@ -2060,80 +2480,223 @@ static double ftest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count > 1){
 		sr1->val = sr2->val = d_ftest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
-		close_arr_func(sr1);		close_arr_func(sr2);
 		}
 	else yyargserr("Bad arguments in call to function\nftest(range1; range2[;\"dest\"]).");
 	return sr1->val;
 }
 
-struct init
+static double fill(YYSTYPE *sr, char *dest)
 {
-	int f_type;
-	unsigned int h_name;
-	double (*fnct)(double);
-};
+	AccRange *ar;
+	int i, r, c;
+
+	if(!sr || !sr->a_data || !sr->a_count || !dest || !dest[0]) return 0.0;
+	if(ar = new AccRange(dest)) {
+		for(i=0, ar->GetFirst(&c, &r); ar->GetNext(&c, &r) && i < sr->a_count; i++) {
+			curr_data->SetValue(r, c, sr->a_data[i]);
+			}
+		delete ar;
+		}
+	return sr->val = i;
+}
 
-static struct init arith_fncts[] = {
-	{FUNC2, HashValue((unsigned char*)"pearson"), (double(*)(double))&pearson},
-	{FUNC2, HashValue((unsigned char*)"spearman"), (double(*)(double))&spearman},
-	{FUNC2, HashValue((unsigned char*)"regression"), (double(*)(double))&regression},
-	{FUNC2, HashValue((unsigned char*)"ttest"), (double(*)(double))&ttest},
-	{FUNC2, HashValue((unsigned char*)"ftest"), (double(*)(double))&ftest},
-	{AFNCT, HashValue((unsigned char*)"variance"), (double(*)(double))&variance},
-	{AFNCT, HashValue((unsigned char*)"stdev"), (double(*)(double))&stdev},
-	{AFNCT, HashValue((unsigned char*)"sterr"), (double(*)(double))&sterr},
-	{AFNCT, HashValue((unsigned char*)"min"), (double(*)(double))&min},
-	{AFNCT, HashValue((unsigned char*)"max"), (double(*)(double))&max},
-	{AFNCT, HashValue((unsigned char*)"count"), (double(*)(double))&count},
-	{AFNCT, HashValue((unsigned char*)"sum"), (double(*)(double))&sum},
-	{AFNCT, HashValue((unsigned char*)"mean"), (double(*)(double))&mean},
-	{AFNCT, HashValue((unsigned char*)"median"), (double(*)(double))&quartile2},
-	{AFNCT, HashValue((unsigned char*)"quartile1"), (double(*)(double))&quartile1},
-	{AFNCT, HashValue((unsigned char*)"quartile2"), (double(*)(double))&quartile2},
-	{AFNCT, HashValue((unsigned char*)"quartile3"), (double(*)(double))&quartile3},
-	{AFNCT, HashValue((unsigned char*)"gmean"), (double(*)(double))&gmean},
-	{AFNCT, HashValue((unsigned char*)"hmean"), (double(*)(double))&hmean},
-	{AFNCT, HashValue((unsigned char*)"tdist"), (double(*)(double))&tdist},
-	{AFNCT, HashValue((unsigned char*)"tinv"), (double(*)(double))&tinv},
-	{AFNCT, HashValue((unsigned char*)"poisdist"), (double(*)(double))&poisdist},
-	{AFNCT, HashValue((unsigned char*)"fdist"), (double(*)(double))&fdist},
-	{AFNCT, HashValue((unsigned char*)"finv"), (double(*)(double))&finv},
-	{AFNCT, HashValue((unsigned char*)"gammp"), (double(*)(double))&_gammp},
-	{AFNCT, HashValue((unsigned char*)"gammq"), (double(*)(double))&_gammq},
-	{AFNCT, HashValue((unsigned char*)"beta"), (double(*)(double))&beta},
-	{AFNCT, HashValue((unsigned char*)"betai"), (double(*)(double))&_betai},
-	{AFNCT, HashValue((unsigned char*)"bincof"), (double(*)(double))&_bincof},
-	{AFNCT, HashValue((unsigned char*)"binomdist"), (double(*)(double))&binomdist},
-	{AFNCT, HashValue((unsigned char*)"normdist"), (double(*)(double))&normdist},
-	{AFNCT, HashValue((unsigned char*)"norminv"), (double(*)(double))&norminv},
-	{AFNCT, HashValue((unsigned char*)"chidist"), (double(*)(double))&chidist},
-	{AFNCT, HashValue((unsigned char*)"chiinv"), (double(*)(double))&chiinv},
-	{SFNCT, HashValue((unsigned char*)"strlen"), (double(*)(double))&_strlen},
-	{SFNCT, HashValue((unsigned char*)"eval"), (double(*)(double))&eval},
-	{FNCT, HashValue((unsigned char*)"erf"), errf},
-	{FNCT, HashValue((unsigned char*)"erfc"), errfc},
-	{FNCT, HashValue((unsigned char*)"sign"), sign},
-	{FNCT, HashValue((unsigned char*)"gammaln"), gammln},
-	{FNCT, HashValue((unsigned char*)"factorial"), factorial},
-	{FNCT, HashValue((unsigned char*)"rand"), rand},
-	{FNCT, HashValue((unsigned char*)"srand"), srand},
-	{FNCT, HashValue((unsigned char*)"floor"), floor},
-	{FNCT, HashValue((unsigned char*)"abs"), fabs},
-	{FNCT, HashValue((unsigned char*)"asin"), asin},
-	{FNCT, HashValue((unsigned char*)"acos"), acos},
-	{FNCT, HashValue((unsigned char*)"atan"), atan},
-	{FNCT, HashValue((unsigned char*)"sinh"), sinh},
-	{FNCT, HashValue((unsigned char*)"cosh"), cosh},
-	{FNCT, HashValue((unsigned char*)"tanh"), tanh},
-	{FNCT, HashValue((unsigned char*)"sin"),  sin},
-	{FNCT, HashValue((unsigned char*)"cos"),  cos},
-	{FNCT, HashValue((unsigned char*)"atan"), atan},
-	{FNCT, HashValue((unsigned char*)"log10"), log10},
-	{FNCT, HashValue((unsigned char*)"ln"),   log},
-	{FNCT, HashValue((unsigned char*)"log"),   log},
-	{FNCT, HashValue((unsigned char*)"exp"),  exp},
-	{FNCT, HashValue((unsigned char*)"sqrt"), sqrt},
-	{0, 0, 0}};
+static void datestr(YYSTYPE *dst, YYSTYPE *src, char *fmt)
+{
+	dst->text = PushString(value_date(src->val, fmt));
+}
+
+static double dateval(YYSTYPE *sr, YYSTYPE *dst, char *fmt)
+{
+	if(!sr || !sr->text) return 0.0;
+	if(fmt && fmt[0] && date_value(sr->text, fmt, &dst->val)) return dst->val;
+	if(date_value(sr->text, 0L, &dst->val)) return dst->val;
+	else return dst->val = 0.0;
+}
+
+static double leapyear(double year)
+{
+	int y = (int)year;
+
+	return (double)((y % 4 == 0 && y % 100 != 0) || y % 400 == 0);
+}
+
+static void today(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(src) yyerror("parse error");
+	if(!dst) return;
+	dst->val = floor(now_today());
+	dst->type = DATE1;
+}
+
+static void now(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(src) yyerror("parse error");
+	if(!dst) return;
+	dst->val = now_today();			dst->val -= floor(dst->val);
+	dst->type = TIME1;
+}
+
+static double year(double dv)
+{
+	int res;
+
+	split_date(dv, &res, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
+	return (double)res;
+}
+
+static double month(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, &res, 0L, 0L, 0L, 0L, 0L, 0L);
+	return (double)res;
+}
+
+static double dom(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, 0L, &res, 0L, 0L, 0L, 0L, 0L);
+	return (double)res;
+}
+
+static double dow(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, 0L, 0L, &res, 0L, 0L, 0L, 0L);
+	return (double)res;
+}
+
+static double doy(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, 0L, 0L, 0L, &res, 0L, 0L, 0L);
+	return (double)res;
+}
+
+static double hours(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, 0L, 0L, 0L, 0L, &res, 0L, 0L);
+	return (double)res;
+}
+
+static double minutes(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, 0L, 0L, 0L, 0L, 0L, &res, 0L);
+	return (double)res;
+}
+
+static double seconds(double dv)
+{
+	double res;
+
+	split_date(dv, 0L, 0L, 0L, 0L, 0L, 0L, 0L, &res);
+	if(res < 0.0005) res = 0.0;
+	return res;
+}
+
+static void fdate(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src || src->type == ARR || src->type == STR) {
+		yyerror("parse error");	
+		return;
+		}
+	dst->type = DATE1;		dst->val = src->val;
+}
+
+static void fdatetime(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src || src->type == ARR || src->type == STR) {
+		yyerror("parse error");	
+		return;
+		}
+	dst->type = DATETIME1;		dst->val = src->val;
+}
+
+static void ftime(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src || src->type == ARR || src->type == STR) {
+		yyerror("parse error");	
+		return;
+		}
+	dst->type = TIME1;		dst->val = src->val;
+}
+
+static void asort(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src) return;
+	dst->type = ARR;
+	switch(src->a_count) {
+	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 = 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;
+		SortArray(dst->a_count, dst->a_data);
+		}
+}
+
+static void _crank(YYSTYPE *dst, YYSTYPE *src)
+{
+	double tmp;
+
+	if(!dst || !src) return;
+	dst->type = ARR;
+	switch(src->a_count) {
+	case 0:	case 1:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = 1;
+		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);
+		}
+}
+
+static void ltrim(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!src || !dst || !src->text) return;
+	dst->text = PushString(str_ltrim(strdup(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->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->type = STR;	dst->val = 0.0;
+}
+
+static double rank(YYSTYPE *sr) 
+{
+	if(sr->a_count < 2 || !sr->a_data) return 0.0;
+	return d_rank(sr->a_count-1, sr->a_data+1, sr->a_data[0]);
+}
+
+static double classes(double start, double step, YYSTYPE *src, YYSTYPE *dest)
+{
+	return d_classes(curr_data, start, step, src->a_data, src->a_count, dest->text);
+}
 
 // Store strings in a list
 static char **str_list = 0L;
@@ -2149,6 +2712,36 @@ static char *PushString(char *text)
 	return 0L;
 }
 
+//Store arrays in a list
+static double **arr_list = 0L;
+static int n_arr = 0;
+
+static double *PushArray(double *arr)
+{
+	if(arr) {
+		if(arr_list = (double**)realloc(arr_list, sizeof(double*)*(n_arr+1)))
+			arr_list[n_arr] = arr;
+		return arr_list[n_arr++];
+		}
+	return 0L;
+}
+
+static double *ReallocArray(double *arr, int size)
+{
+	int i;
+
+	if(arr && size) {
+		for(i = 0; i < n_arr; i++) if(arr_list[i] == arr) {
+			arr_list[i] = (double*)realloc(arr, size);
+			return arr_list[i];
+			}
+		arr = (double*)realloc(arr, size);
+		return PushArray(arr);
+		}
+	return 0L;
+}
+
+
 //The symbol table: a chain of `struct symrec'
 static symrec *sym_table, *sym_tab_first;
 
@@ -2186,8 +2779,68 @@ void ArrangeFunctions()
 }
 
 // Put arithmetic functions and predifened variables in table
+#define INIT_SYM(TYP,NAM,FNC) {TYP,NAM,(double(*)(double))&FNC} 
 void InitArithFuncs(DataObj *d)
 {
+	struct fdef {
+		int f_type;
+		char *name;
+		double (*fnct)(double);
+		};
+	fdef fncts[] = {
+	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(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),
+	INIT_SYM(FNCT, "month", month),			INIT_SYM(FNCT, "dom", dom),
+	INIT_SYM(FNCT, "dow", dow),			INIT_SYM(FNCT, "doy", doy),
+	INIT_SYM(FNCT, "hours", hours),			INIT_SYM(FNCT, "minutes", minutes),
+	INIT_SYM(FNCT, "seconds", seconds),		INIT_SYM(YYFNC, "date", fdate),
+	INIT_SYM(FNCT, "datetime", fdatetime),		INIT_SYM(YYFNC, "time", ftime),
+	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(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),
+	INIT_SYM(AFNCT, "sterr", sterr),		INIT_SYM(AFNCT, "min", min),
+	INIT_SYM(AFNCT, "max", max),			INIT_SYM(AFNCT, "count", count),
+	INIT_SYM(AFNCT, "sum", sum),			INIT_SYM(AFNCT, "mean", mean),
+	INIT_SYM(AFNCT, "kurt", kurt),			INIT_SYM(AFNCT, "skew", skew),
+	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, "tinv", tinv),
+	INIT_SYM(AFNCT, "poisdist", poisdist),		INIT_SYM(AFNCT, "poisfreq", poisfreq),		
+	INIT_SYM(AFNCT, "fdist", fdist),
+	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, "normdist", normdist),
+	INIT_SYM(AFNCT, "norminv", norminv),
+	INIT_SYM(AFNCT, "normfreq", normfreq),
+	INIT_SYM(AFNCT, "lognormdist", lognormdist),
+	INIT_SYM(AFNCT, "lognorminv",lognorminv),	INIT_SYM(AFNCT, "chidist", chidist),
+	INIT_SYM(AFNCT, "chiinv", chiinv),		INIT_SYM(SFNCT, "strlen", _strlen),
+	INIT_SYM(SFNCT, "eval", eval),			INIT_SYM(FNCT, "erf", errf),
+	INIT_SYM(FNCT, "erfc", errfc),			INIT_SYM(FNCT, "sign", sign),
+	INIT_SYM(FNCT, "gammaln", gammln),		INIT_SYM(FNCT, "factorial", factorial),
+	INIT_SYM(YYFNC, "rand", rand1),			INIT_SYM(FNCT, "srand", srand),
+	INIT_SYM(FNCT, "floor", floor),			INIT_SYM(FNCT, "abs", fabs),
+	INIT_SYM(FNCT, "asin", asin),			INIT_SYM(FNCT, "acos", acos),
+	INIT_SYM(FNCT, "atan", atan),			INIT_SYM(FNCT, "sinh", sinh),
+	INIT_SYM(FNCT, "cosh", cosh),			INIT_SYM(FNCT, "tanh", tanh),
+	INIT_SYM(FNCT, "sin", sin),			INIT_SYM(FNCT, "cos", cos),
+	INIT_SYM(FNCT, "tan", tan),			INIT_SYM(FNCT, "log10", log10),
+	INIT_SYM(FNCT, "ln", log),			INIT_SYM(FNCT, "log", log),
+	INIT_SYM(FNCT, "exp", exp),			INIT_SYM(FNCT, "sqrt", sqrt),
+	INIT_SYM(0, 0L, nop)};
 	int i;
 	symrec *ptr, *next;
 
@@ -2202,17 +2855,19 @@ void InitArithFuncs(DataObj *d)
 			}
 		sym_table = sym_tab_first = (symrec *) 0;
 		}
-	for (i = 0; arith_fncts[i].h_name; i++) {
-		ptr = putsym (arith_fncts[i].h_name, arith_fncts[i].f_type);
-		ptr->fnctptr = (double (*)(...))arith_fncts[i].fnct;
+	for (i = 0; fncts[i].name; i++) {
+		ptr = putsym (HashValue((unsigned char*) fncts[i].name), Hash2((unsigned char*) fncts[i].name), fncts[i].f_type);
+		ptr->fnctptr = (double (*)(...))fncts[i].fnct;
 		}
-	ptr = putsym(HashValue((unsigned char*)"zdiv"), VAR);		ptr->SetValue(1.0);
+	ptr = putsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv"), VAR);	ptr->SetValue(1.0);
 	sym_tab_first = sym_table;
 }
+#undef INIT_SYM
 
 static void init_table (void)
 {
 	str_list = 0L;		n_str = 0;
+	arr_list = 0L;		n_arr = 0;
 	push_syntax();
 }
 
@@ -2224,33 +2879,37 @@ static void clear_table()
 		for(i = 0; i < n_str; i++) if(str_list[i]) free(str_list[i]);
 		free(str_list);		str_list = 0L;		n_str = 0;
 		}
+	if(arr_list) {
+		for(i = 0; i < n_arr; i++) if(arr_list[i]) free(arr_list[i]);
+		free(arr_list);		arr_list = 0L;		n_arr = 0;
+		}
 	pop_syntax();
 }
 
 static symrec *
-putsym (unsigned int h_name, int sym_type)
+putsym (unsigned int h_name, unsigned int h2_name, int sym_type)
 {
-	sym_table = new symrec(h_name, sym_type, sym_table);
+	sym_table = new symrec(h_name, h2_name, sym_type, sym_table);
 	return sym_table;
 }
 
 static symrec *
-getsym (unsigned int h_name, char *sym_name)
+getsym (unsigned int h_name, unsigned int h2_name, char *sym_name)
 {
 	symrec *ptr;
 
 	if(!h_name) return 0;
 	for (ptr = sym_table; ptr != (symrec *) 0; ptr = (symrec *)ptr->next) {
-		if (ptr->h_name == h_name){
+		if (ptr->h_name == h_name && ptr->h2_name == h2_name){
 			if(sym_name && !ptr->name) {
 				ptr->SetName(sym_name);
 				bRecent = true;
 				}
 			return ptr;
 			}
-		//predefined variables never end on a digit
+		//predefined variables rarely end on a digit
 		else if(ptr == sym_tab_first) {
-			if(sym_name && isdigit(sym_name[strlen(sym_name)-1])) return 0;
+			if(sym_name && isdigit(sym_name[strlen(sym_name)-1]) && strlen(sym_name) < 5) return 0;
 			}
 		}
 	return 0;
@@ -2261,28 +2920,28 @@ push(YYSTYPE *res, YYSTYPE *val)
 {
 	if(val->a_data) {
 		if(!(res->a_data)) {
-			if(!(val->a_data=(double*)realloc(val->a_data, (val->a_count+2)*sizeof(double))))return 0;
+			if(!(val->a_data=ReallocArray(val->a_data, (val->a_count+2)*sizeof(double))))return 0;
 			val->a_data[val->a_count++] = res->val;
 			res->a_data = val->a_data;		res->a_count = val->a_count;
 			val->a_data = 0L;			val->a_count = 0;
 			val->val = res->val;			return 1;
 			}
 		else {
-			if(!(res->a_data=(double*)realloc(res->a_data, (val->a_count+res->a_count)*sizeof(double))))return 0;
+			if(!(res->a_data=ReallocArray(res->a_data, (val->a_count+res->a_count)*sizeof(double))))return 0;
 			memcpy(&res->a_data[res->a_count], val->a_data, val->a_count*sizeof(double));
-			res->a_count += val->a_count;		free(val->a_data);
+			res->a_count += val->a_count;
 			val->a_data = 0L;			val->a_count = 0;
 			return 1;
 			}
 		}
 	if(!(res->a_data )){
-		if(!(res->a_data =  (double*)malloc(2*sizeof(double))))return 0;
+		if(!(res->a_data =  PushArray((double*)malloc(2*sizeof(double)))))return 0;
 		res->a_data[0] = res->val;			res->a_data[1] = val->val;
 		res->a_count = 2;
 		return 1;
 		}
 	else {
-		if(!(res->a_data = (double*)realloc(res->a_data, (res->a_count+2)*sizeof(double))))return 0; 
+		if(!(res->a_data = ReallocArray(res->a_data, (res->a_count+2)*sizeof(double))))return 0; 
 		res->a_data[res->a_count] = val->val;		res->a_count++;
 		return 1;
 		}
@@ -2297,7 +2956,7 @@ range_array(YYSTYPE * res, char *range)
 	anyResult ares;
 
 	if(!range || !range[0] || !(r = new AccRange(range))) return 0;
-	if(!r->GetFirst(&col, &row) || !(res->a_data =  (double*)malloc(r->CountItems() * sizeof(double)))) {
+	if(!r->GetFirst(&col, &row) || !(res->a_data =  PushArray((double*)malloc(r->CountItems() * sizeof(double))))) {
 		delete(r);
 		return 0;
 		}
@@ -2305,15 +2964,9 @@ range_array(YYSTYPE * res, char *range)
 	for(res->a_count = 0; r->GetNext(&col, &row); ) {
 		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)) {
 			switch(ares.type) {
-			case ET_VALUE: 
+			case ET_VALUE:	case ET_TIME:	case ET_DATE:	case ET_DATETIME:	case ET_BOOL:
 				res->a_data[res->a_count++] = ares.value;
 				break;
-			case ET_TEXT:
-				if(ares.text && ares.text[0]) last_err_desc = "#ARGS";
-				break;
-			case ET_ERROR:
-				last_err_desc = "#ARGS";
-				break;
 				}
 			}
 		}
@@ -2322,6 +2975,40 @@ range_array(YYSTYPE * res, char *range)
 	return 1;
 }
 
+static int
+range_array2(YYSTYPE *res1, YYSTYPE *res2)
+{
+	AccRange *r1, *r2;
+	int row1, col1, row2, col2;
+	anyResult ares1, ares2;
+	char *range1, *range2;
+
+	range1 = res1->text;	range2 = res2->text;
+	if(!range1 || !range1[0] || !range2 || !range2[0] || !(r1 = new AccRange(range1)) 
+		|| !(r2 = new AccRange(range2))) return 0;
+	if(!r1->GetFirst(&col1, &row1) || !(res1->a_data =  PushArray((double*)malloc(r1->CountItems() * sizeof(double))))) {
+		delete(r1);	delete(r2);
+		return 0;
+		}
+	if(!r2->GetFirst(&col2, &row2) || !(res2->a_data =  PushArray((double*)malloc(r2->CountItems() * sizeof(double))))) {
+		delete(r1);	delete(r2);
+		return 0;
+		}
+	parse_level++;
+	for(res1->a_count = res2->a_count = 0; r1->GetNext(&col1, &row1) && r2->GetNext(&col2, &row2); ) {
+		if(curr_data->GetResult(&ares1, row1, col1, parse_level > MAX_PARSE) 
+			&& curr_data->GetResult(&ares2, row2, col2, parse_level > MAX_PARSE)
+			&& (ares1.type==ET_VALUE || ares1.type==ET_TIME || ares1.type==ET_DATE || ares1.type==ET_DATETIME || ares1.type==ET_BOOL)
+			&& (ares2.type==ET_VALUE || ares2.type==ET_TIME || ares2.type==ET_DATE || ares2.type==ET_DATETIME || ares2.type==ET_BOOL)){
+			res1->a_data[res1->a_count++] = ares1.value;
+			res2->a_data[res2->a_count++] = ares2.value;
+			}
+		}
+	parse_level--;
+	delete(r1);	delete(r2);
+	return 1;
+}
+
 static YYSTYPE *proc_clause(YYSTYPE *res)
 {
 	int i, n, o_pos;
@@ -2330,12 +3017,12 @@ static YYSTYPE *proc_clause(YYSTYPE *res)
 
 	if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return res;
 	if(!res->text) return res;
-	if(!res->a_data && (res->a_data = (double*)malloc(sizeof(double)))) {
+	if(!res->a_data && (res->a_data = PushArray((double*)malloc(sizeof(double))))) {
 		res->a_data[0] = res->type == VAR && res->tptr ? res->tptr->GetValue() : res->val;
 		res->a_count = 1;
 		}
 	else if(!res->a_data) return res;
-	if(!(n_data = (double*)malloc(res->a_count * sizeof(double)))) return res;
+	if(!(n_data = PushArray((double*)malloc(res->a_count * sizeof(double))))) return res;
 	o_pos = buff_pos;	o_cmd = buffer;
 	for(i = n = 0; i < res->a_count; i++) {
 		buffer = res->text;	buff_pos = 0;
@@ -2344,8 +3031,8 @@ static YYSTYPE *proc_clause(YYSTYPE *res)
 		yyparse();
 		if(line_res.type == ET_VALUE && line_res.value != 0.0) n_data[n++] = res->a_data[i];
 		}
-	free(res->a_data);	res->a_data = n_data;		res->a_count = n;
-	free(res->text);	res->text=0L;
+	res->a_data = n_data;		res->a_count = n;
+	res->text=0L;
 	syntax_level->cl1 = syntax_level->cl2 = 0;
 	buffer = o_cmd;	buff_pos = o_pos;
 	return res;
@@ -2356,6 +3043,13 @@ static void exec_clause(YYSTYPE *res)
 	int i, j;
 	char *cmd;
 
+	if((!res->a_data || res->a_count <2) && res->text && res->text[0]) range_array(res, res->text);
+	if(!res->a_data) {
+		if(res->a_data = PushArray((double*)malloc(2*sizeof(double)))) {
+			res->a_data[0] = res->val;	res->a_count = 1;
+			InfoBox("fixed data");
+			}
+		}
 	if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return;
 	if(!(cmd = (char*)malloc(syntax_level->cl2 - syntax_level->cl1 +2)))return;
 	while(buffer[syntax_level->cl1] <= ' ' && syntax_level->cl1 < syntax_level->cl2) syntax_level->cl1++;
@@ -2363,7 +3057,8 @@ static void exec_clause(YYSTYPE *res)
 		cmd[j++] = buffer[i];
 		}
 	cmd[j++] = ';';		cmd[j++] = 0;
-	res->text = cmd;
+	res->text = PushString(cmd);
+	free(cmd);
 }
 
 struct parse_info  {
@@ -2374,8 +3069,9 @@ struct parse_info  {
 	YYSTYPE yylval;
 	struct parse_info *next;
 	char **str_list;
+	double **arr_list;
 	char *last_err_desc;
-	int n_str, yychar, yynerrs;
+	int n_str, n_arr, yychar, yynerrs;
 };
 static parse_info *parse_stack = 0L;
 
@@ -2393,6 +3089,8 @@ static void push_parser()
 	ptr->next = parse_stack;
 	ptr->str_list = str_list;		str_list = 0L;
 	ptr->n_str = n_str;			n_str = 0;
+	ptr->arr_list = arr_list;		arr_list = 0L;
+	ptr->n_arr = n_arr;			n_arr = 0;
 	ptr->yychar = yychar;			ptr->yynerrs = yynerrs;
 	parse_stack = ptr;			last_err_desc = 0L;
 	parse_level++;				//reenter ?
@@ -2416,6 +3114,7 @@ static void pop_parser()
 		curr_data = ptr->curr_data;	last_err_desc = ptr->last_err_desc;
 		memcpy(&yylval, &ptr->yylval, sizeof(YYSTYPE));
 		str_list = ptr->str_list;	n_str = ptr->n_str;
+		arr_list = ptr->arr_list;	n_arr = ptr->n_arr;
 		yychar = ptr->yychar;		yynerrs = ptr->yynerrs;
 		free(ptr);
 		parse_level--;
@@ -2423,17 +3122,39 @@ static void pop_parser()
 	pop_syntax();
 }
 
-static int is_ttoken(int h_nam)
+static int is_ttoken(unsigned int h_nam, unsigned int h2_nam)
 {
 	switch(h_nam) {
-	case 101:		return E;
-	case 26992:		return PI;
+	case 69:
+		if(h2_nam == 101) return E;
+		break;
+	case 393:
+		if(h2_nam == 47081) return PI;
+		break;
 	case 28381:
-		if(syntax_level) syntax_level->cl1 = buff_pos;
-		return CLAUSE;
-	case 9252:		return CLVAL;
-	case 26217:		return IF;
-	case 6033:		return ELSE;
+		if((h2_nam & 0x7fffffff) == 0x7c2706ed) {
+			if(syntax_level) syntax_level->cl1 = buff_pos;
+			return CLAUSE;
+			}
+		break;
+	case 20:
+		if(h2_nam == 5220) return CLVAL;
+		break;
+	case 362:
+		if(h2_nam == 42878) return IF;
+		break;
+	case 1457:
+		if(h2_nam == 18357885) return DIM;
+		break;
+	case 6033:
+		if((h2_nam & 0x7fffffff) == 0x6371377d) return ELSE;
+		break;
+	case 7097:
+		if((h2_nam & 0x7fffffff) == 0x550a2d65) return BTRUE;
+		break;
+	case 23697:
+		if((h2_nam & 0x7fffffff) == 0x155f977d) return BFALSE;
+		break;
 		}
 	return 0;
 }
@@ -2442,7 +3163,7 @@ static symrec *curr_sym;
 static int yylex (void)
 {
 	int i, c, tok;
-	unsigned int h_nam;
+	unsigned int h_nam, h2_nam;
 	char tmp_txt[80];
 	symrec *s;
 
@@ -2487,10 +3208,10 @@ static int yylex (void)
 			}
 		tmp_txt[i] = 0;
 		h_nam = HashValue((unsigned char*)tmp_txt);
-		if(tok = is_ttoken(h_nam)) 
-			return tok;
-		if(!(s = getsym(h_nam, tmp_txt))){
-			s = putsym(h_nam, VAR);
+		h2_nam = Hash2((unsigned char*)tmp_txt);
+		if(tok = is_ttoken(h_nam, h2_nam)) return tok;
+		if(!(s = getsym(h_nam, h2_nam, tmp_txt))){
+			s = putsym(h_nam, h2_nam, VAR);
 			s->SetName(tmp_txt);
 			}
 		
@@ -2568,6 +3289,13 @@ static int yylex (void)
 	return c;
 }
 
+static unsigned int hn_x = HashValue((unsigned char *)"x");
+static unsigned int hn_y = HashValue((unsigned char *)"y");
+static unsigned int hn_z = HashValue((unsigned char *)"z");
+static unsigned int h2_x = Hash2((unsigned char *)"x");
+static unsigned int h2_y = Hash2((unsigned char *)"y");
+static unsigned int h2_z = Hash2((unsigned char *)"z");
+
 bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOINT **pts, long *npts, char *param)
 {
 	double x, y;
@@ -2575,8 +3303,6 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	lfPOINT *new_points;
 	long npoints = 0;
 	int length, res_mode = 0;
-	unsigned int hn_x = HashValue((unsigned char *)"x");
-	unsigned int hn_y = HashValue((unsigned char *)"y");
 
 	if(x1 < x2) step = fabs(step);
 	else step = -fabs(step);
@@ -2599,7 +3325,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 		free(buffer);		buffer = 0L;
 		}		
 	length = strlen(expr);
-	buffer = expr;		sx = putsym(hn_x, VAR);
+	buffer = expr;		sx = putsym(hn_x, h2_x, VAR);
 	for(x = x1; step > 0.0 ? x <= x2 : x >= x2; x += step) {
 		if(sx){
 			sx->SetValue(x);	buff_pos = 0;
@@ -2612,7 +3338,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 			case 2:
 				y = line_res.value;	break;
 			default:
-				if(sy = getsym(hn_y)) {
+				if(sy = getsym(hn_y, h2_y)) {
 					y = sy->GetValue();	res_mode = 1;
 					}
 				else {
@@ -2620,7 +3346,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 					}
 				break;
 				}
-			new_points[npoints].fx = (getsym(hn_x))->GetValue();
+			new_points[npoints].fx = (getsym(hn_x, h2_x))->GetValue();
 			new_points[npoints++].fy = y;
 			}
 		}
@@ -2640,9 +3366,6 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 	int length, nr, nc, r, c, res_mode=0;
 	symrec *sx, *sz, *sy;
 	double x, y, z;
-	unsigned int hn_x = HashValue((unsigned char *)"x");
-	unsigned int hn_y = HashValue((unsigned char *)"y");
-	unsigned int hn_z = HashValue((unsigned char *)"z");
 
 	if(!d || x2 <= x1 || z2 <= z1 || xstep <= 0.0 || zstep <= 0.0) return false;
 	push_parser();
@@ -2661,7 +3384,7 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 		free(buffer);		buffer = 0L;
 		}		
 	length = strlen(expr);		buffer = expr;
-	sx = putsym(hn_x, VAR);		sz = putsym(hn_z, VAR);
+	sx = putsym(hn_x, h2_x, VAR);	sz = putsym(hn_z, h2_z, VAR);
 	nr = iround((z2-z1)/zstep)+1;	nc = iround((x2-x1)/xstep)+1;
 	d->Init(nr, nc);
 	for(r = 0, x = x1; r < nr; r++, x += xstep) {
@@ -2676,7 +3399,7 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 			case 2:
 				y = line_res.value;	break;
 			default:
-				if(sy = getsym(hn_y)) {
+				if(sy = getsym(hn_y, h2_y)) {
 					y = sy->GetValue();	res_mode = 1;
 					}
 				else {
@@ -2699,7 +3422,10 @@ anyResult *do_formula(DataObj *d, char *expr)
 
 	if(d) curr_data = d;
 	ret.type = ET_ERROR;		ret.text = 0L;
-	if(!expr || !expr[0]) return &ret;
+	if(!expr || !expr[0]) {
+		if(!sym_table) InitArithFuncs(0L);
+		return &ret;
+		}
 	push_parser();		//make code reentrant
 	init_table();		length = strlen(expr);
 	if(!(buffer = (char*)malloc(length+2))){
@@ -2751,7 +3477,8 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 			case NUM:
 				pos += sprintf(res+pos, "%g", yylval.val);
 				break;
-			case FNCT:	case FUNC2:	case AFNCT:	case SFNCT:
+			case FNCT:	case FUNC1:	case FUNC2:	case FUNC3:	case AFNCT:
+			case SFNCT:	case SRFUNC:	case BFNCT:	case YYFNC:	case FUNC4:
 				pos += sprintf(res+pos, "%s", curr_sym->name);
 				break;
 			case COLR:			case COLC:
@@ -2799,6 +3526,12 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 			case E:
 				pos += sprintf(res+pos, "e");
 				break;
+			case BTRUE:
+				pos += sprintf(res+pos, "true");
+				break;
+			case BFALSE:
+				pos += sprintf(res+pos, "false");
+				break;
 			case AND:
 				pos += sprintf(res+pos, " && ");
 				break;
@@ -2848,20 +3581,20 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
 {
 	int i, length;
 	double tmp, y1, y2;
-	symrec *symx, *sy=0L;
-	unsigned int hn_x = HashValue((unsigned char *)"x");
-	unsigned int hn_y = HashValue((unsigned char *)"y");
+	symrec *symx, *symz, *sy=0L;
 
-	if(!(symx = getsym(hn_x))) symx = putsym(hn_x, VAR);
+	if(!(symx = getsym(hn_x, h2_x))) symx = putsym(hn_x, h2_x, VAR);
+	if(!(symz = getsym(hn_z, h2_z))) symz = putsym(hn_z, h2_z, VAR);
 	//swap parameters to requested set
 	if(a != parval) for(i = 0; i < ma; i++) {
 		tmp = *parval[i];	*parval[i]  = *a[i];	*a[i] = tmp;
 		}
 	//calc result
-	symx->SetValue(x);	buffer = txt_formula;
+	symx->SetValue(x);	symz->SetValue(z);	
+	buffer = txt_formula;
 	buff_pos = 0;		length = strlen(txt_formula);
 	do {	yyparse();	}while(buff_pos < length);
-	if(sy = getsym(hn_y)) *y = sy->GetValue();
+	if(sy = getsym(hn_y, h2_y)) *y = sy->GetValue();
 	else *y = line_res.value;
 	if(*y == HUGE_VAL || *y == -HUGE_VAL) {
 		for(i = 0, *y = 0.0; i < ma; dyda[i++] = 0.0);
@@ -2921,7 +3654,7 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 		if(arz) delete arz;
 		free(x);	delete arx;	delete ary;	return 0;
 		}
-	if(rz && !(y = (double*)malloc(i * sizeof(double)))){
+	if(rz && !(z = (double*)malloc(i * sizeof(double)))){
 		if(arz) delete arz;
 		free(y);	free(x);	delete arx;	delete ary;	return 0;
 		}
@@ -3015,29 +3748,3 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 	return itst < maxiter ? itst+1 : maxiter;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/mfcalc.y b/mfcalc.y
index 1ce5db4..eb6fb73 100755
--- a/mfcalc.y
+++ b/mfcalc.y
@@ -1,6 +1,6 @@
 %{
 /*
- mfcalc.y, mfcalc.cpp, Copyright (c) 2004, 2005 R.Lackner
+ mfcalc.y, mfcalc.cpp, Copyright (c) 2004, 2005, 2006 R.Lackner
  parse string and simple math: based on the bison 'mfcalc' example
 
     This file is part of RLPlot.
@@ -28,14 +28,14 @@
 
 class symrec {
 public:
-	int type, row, col;
-	unsigned int h_name;
+	int type, row, col, a_count;
+	unsigned int h_name, h2_name;
 	char *name, *text;
 	double (*fnctptr)(...);
 	symrec *next;
-	double var;
+	double var, *a_data;
 
-	symrec(unsigned int h_n, int typ, symrec *nxt);
+	symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt);
 	~symrec();
 	double GetValue();
 	void GetValue(void *res);
@@ -69,18 +69,22 @@ typedef struct{
 
 }YYSTYPE;
 
-static symrec *putsym (unsigned int h_name, int sym_type);
-static symrec *getsym (unsigned int h_name, char *sym_name = 0L);
+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);
 static int push(YYSTYPE *res, YYSTYPE *val);
 static void store_res(YYSTYPE *res);
 static char *PushString(char *text);
+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 double eval(YYSTYPE *sr, YYSTYPE *dst);
+static double eval(YYSTYPE *sr, YYSTYPE *dst, char* dum);
 static int range_array(YYSTYPE * res, char *range);
+static int range_array2(YYSTYPE *res1, YYSTYPE *res2);
 static void exec_clause(YYSTYPE *res);
 static YYSTYPE *proc_clause(YYSTYPE *res);
 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;};
 
@@ -97,9 +101,10 @@ static int parse_level = 0;		//count reentrances into parser
 #define MAX_PARSE 20			//maximum number of reentances 
 %}
 
-%token <val>  NUM STR ARR BLOCK PI E CLVAL PSEP IF ELSE
-%token <tptr> VAR FNCT AFNCT SFNCT FUNC2 TXT
-%type  <val>  exp str_exp arr
+%token <val>  NUM BOOLVAL STR ARR BLOCK PI E CLVAL PSEP IF ELSE BTRUE BFALSE
+%token <val>  DATE1 TIME1 DATETIME1 DIM
+%token <tptr> VAR FNCT BFNCT AFNCT SFNCT FUNC1 FUNC2 FUNC3 TXT SRFUNC YYFNC FUNC4
+%type  <val>  exp str_exp arr bool
 
 %right  '='
 %left	','			/* list separator */
@@ -111,9 +116,11 @@ static int parse_level = 0;		//count reentrances into parser
 %left   EQ NE GT GE LT LE
 %left   '-' '+'
 %left   '*' '/'
+%left	'['
 %left   NEG 		/* negation-unary minus */
 %left	INC DEC		/* increment, decrement */
 %left	PINC PDEC	/* pre- increment, decrement */
+%left	PDIM		/* dimension array */
 %right  '^'	 	/* exponentiation       */
 
 /* Grammar follows */
@@ -133,58 +140,92 @@ line:	 '\n' | ';' | ','
 
 str_exp:
 	STR			{;}
-	|str_exp '+' exp	{yyval.text=add_strings(yyvsp[-2].text, string_value(&yyvsp[0]));}
-	|exp '+' str_exp	{yyval.text=add_strings(string_value(&yyvsp[-2]), yyvsp[0].text);}
-	|str_exp '+' str_exp	{yyval.text=add_strings(yyvsp[-2].text, yyvsp[0].text);}
+	|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;}
 ;
 
 range:
-	str_exp			{;}	
-	|VAR COLR VAR		{if(yyval.text =(char*)malloc(strlen($1->name) +strlen($3->name) + 2)) sprintf(yyval.text, "%s:%s", $1->name, $3->name);}
+	str_exp			{;}
+	|VAR COLR VAR		{if(yyval.text = PushString((char*)malloc(strlen($1->name) +strlen($3->name) + 2))) sprintf(yyval.text, "%s:%s", $1->name, $3->name);}
 ;
 
 arr:	ARR
-	|exp			{if(!yyval.a_data) {yyval.a_data = (double*)malloc(sizeof(double)); yyval.a_count = 1; yyval.a_data[0] = yyval.val;}}
-	|arr ',' arr		{push(&yyval, &yyvsp[0]);}
-	|arr CLAUSE exp		{exec_clause(&yyval);} 
-	|range			{range_array(&yyval, yyvsp[0].text);}
-	|NUM SER NUM		{if($1 < $3 && (yyval.a_data = (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 );}
+	|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;} 
+	|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;}
+	|BTRUE			{$$ = 1.0; yyval.type = BOOLVAL;}
+	|BFALSE			{$$ = 0.0; yyval.type = BOOLVAL;}
+	|exp AND exp		{$$ = (($1 != 0) && ($3 != 0))? 1 : 0; yyval.type = BOOLVAL;}
+	|exp OR exp		{$$ = (($1 != 0) || ($3 != 0))? 1 : 0; yyval.type = BOOLVAL;}
+	|exp EQ exp		{$$ = ($1 == $3) ? 1 : 0; yyval.type = BOOLVAL;}
+	|exp NE exp		{$$ = ($1 != $3) ? 1 : 0; yyval.type = BOOLVAL;}
+	|exp GT exp		{$$ = ($1 > $3) ? 1 : 0; yyval.type = BOOLVAL;}
+	|exp GE exp		{$$ = ($1 >= $3) ? 1 : 0; yyval.type = BOOLVAL;}
+	|exp LT exp		{$$ = ($1 < $3) ? 1 : 0; yyval.type = BOOLVAL;}
+	|exp LE exp		{$$ = ($1 <= $3) ? 1 : 0; yyval.type = BOOLVAL;}
 ;
 
 exp:	NUM				{$$ = $1; yyval.type = NUM;}
+    	|bool				{$$ = $1; yyval.type = BOOLVAL;}
         |TXT				{$$ = 0.0;}
-	|CLVAL				{$$ = syntax_level ? syntax_level->clval : 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);}
+	|BLOCK			{eval(&yyvsp[0], &yyval, 0L);}
 	|VAR '=' exp		{$1->SetValue(&yyval, &yyvsp[0]);}
 	|VAR '=' str_exp	{$1->SetValue(&yyval, &yyvsp[0]);}
-	|FNCT '(' exp ')'	{$$ = (($1->fnctptr)($3));}
-	|AFNCT '(' arr ')'	{$$ = (($1->fnctptr)(proc_clause(&yyvsp[-1])));}
-	|AFNCT '(' exp PSEP exp ')' {push(&yyvsp[-2], &yyvsp[0]); $$ = (($1->fnctptr)(&yyvsp[-2]));}
-	|AFNCT '(' exp PSEP exp PSEP exp ')' {push(&yyvsp[-4], &yyvsp[-2]); push(&yyvsp[-4], &yyvsp[0]); $$ = (($1->fnctptr)(&yyvsp[-4]));}
-	|SFNCT '(' str_exp ')'	{$$ = (($1->fnctptr)(&yyvsp[-1], &yyval));}
-	|SFNCT '(' exp ')'	{yyvsp[-1].text = string_value(&yyvsp[-1]); $$ = (($1->fnctptr)(&yyvsp[-1], &yyval));}
-	|FUNC2 '(' arr PSEP arr ')'	{$$ = ((*$1->fnctptr)(proc_clause(&yyvsp[-3]), proc_clause(&yyvsp[-1]), 0L));}
-	|FUNC2 '(' arr PSEP arr PSEP range')'	
-			{$$ = ((*$1->fnctptr)(proc_clause(&yyvsp[-5]), proc_clause(&yyvsp[-3]), yyvsp[-1].text));}
-	|IF '(' exp ')' BLOCK	{$$ = $3 != 0 ? eval(&yyvsp[0], &yyval) : 0.0;}
-	|IF '(' exp ')' BLOCK ELSE BLOCK	{$$ = $3 != 0 ? eval(&yyvsp[-2], &yyval) : eval(&yyvsp[0], &yyval);}
-	|exp AND exp		{$$ = (($1 != 0) && ($3 != 0))? 1 : 0;}
-	|exp OR exp		{$$ = (($1 != 0) || ($3 != 0))? 1 : 0;}
-	|exp EQ exp		{$$ = ($1 == $3) ? 1 : 0;}
-	|exp NE exp		{$$ = ($1 != $3) ? 1 : 0;}
-	|exp GT exp		{$$ = ($1 > $3) ? 1 : 0;}
-	|exp GE exp		{$$ = ($1 >= $3) ? 1 : 0;}
-	|exp LT exp		{$$ = ($1 < $3) ? 1 : 0;}
-	|exp LE exp		{$$ = ($1 <= $3) ? 1 : 0;}
-	|exp '+' exp		{$$ = $1 + $3;}
-	|exp '-' exp		{$$ = $1 - $3;}
-	|exp '*' exp		{$$ = $1 * $3;}
-	|exp '/' exp		{if($3 != 0.0) $$ = $1 / $3;
-					else $$ = (getsym(HashValue((unsigned char*)"zdiv")))->GetValue(); }
+	|FNCT '(' exp ')'	{$$ = (($1->fnctptr)($3)); yyval.type = NUM;}
+	|AFNCT '(' arr ')'	{$$ = (($1->fnctptr)(proc_clause(&yyvsp[-1]))); yyval.type = NUM;}
+	|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;}
+	|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 ')'	{$$ = (($1->fnctptr)(&yyvsp[-1], &yyval, 0L)); yyval.type = NUM;}
+	|SFNCT '(' exp ')'	{yyvsp[-1].text = string_value(&yyvsp[-1]); $$ = (($1->fnctptr)(&yyvsp[-1], &yyval, 0L)); yyval.type = NUM;}
+	|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]);}
+	|IF '(' exp ')' BLOCK	{$$ = $3 != 0 ? eval(&yyvsp[0], &yyval, 0L) : 0.0;}
+	|IF '(' exp ')' BLOCK ELSE BLOCK	{$$ = $3 != 0.0 ? eval(&yyvsp[-2], &yyval, 0L) : eval(&yyvsp[0], &yyval, 0L);}
+	|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;
+				else if(yyvsp[0].type == DATETIME1 || yyvsp[-2].type == DATETIME1) yyval.type = DATETIME1;}
+	|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;
+				else if(yyvsp[0].type == DATETIME1 || yyvsp[-2].type == DATETIME1) yyval.type = DATETIME1;}
+	|exp '*' exp		{$$ = $1 * $3; yyval.type = NUM;}
+	|exp '/' exp		{yyval.type = NUM; if($3 != 0.0) $$ = $1 / $3;
+					else $$ = (getsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv")))->GetValue(); }
 	|'-' exp  %prec NEG	{$$ = -$2;}
 	|VAR INC		{$$=$1->GetValue(); $1->SetValue($$+1.0); $$ -= 1.0; yyval.type = NUM;}
 	|VAR DEC		{$$=$1->GetValue(); $1->SetValue($$-1.0); $$ += 1.0; yyval.type = NUM;}
@@ -192,6 +233,16 @@ exp:	NUM				{$$ = $1; yyval.type = NUM;}
 	|DEC VAR %prec PDEC	{$$=$2->GetValue(); $2->SetValue($$-1.0); yyval.type = NUM;}
 	|exp '^' exp		{$$ = pow($1, $3);}
 	|'(' arr ')'		{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);}
+	|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))}
 	|exp '?' STR COLC exp	{memcpy(&yyval, $1 != 0.0 ? &yyvsp[-2] : &yyvsp[0], sizeof(YYSTYPE))}
@@ -200,15 +251,12 @@ exp:	NUM				{$$ = $1; yyval.type = NUM;}
 %%
 
 // The symrec class
-symrec::symrec(unsigned int h_n, int typ, symrec *nxt) 
-{
-	h_name = h_n;
-	type = typ;
-	next = nxt;
-	row = col = -1;
-	name = text = 0L;
-	var = 0.0;
-	isSSval = false;
+symrec::symrec(unsigned int h_n, unsigned int h2_n, int typ, symrec *nxt) 
+{
+	h_name = h_n;	h2_name = h2_n;		type = typ;
+	next = nxt;	row = col = -1;		name = text = 0L;
+	var = 0.0;	isSSval = false;
+	a_data = 0L;	a_count = 0;
 	fnctptr = (double (*)(...))nop;
 }
 
@@ -247,18 +295,29 @@ symrec::GetValue(void *re)
 		//GetResult( , , ,true) inhibits reentrance into parser !
 		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)){
 			if(text) free(text);		text = 0L;
-			if(ares.type == ET_VALUE) {
-				res->type = VAR;	res->val = ares.value;
-				res->text = 0L;
-				}
-			else if(ares.type == ET_TEXT && ares.text) {
+			switch(ares.type) {
+			case ET_VALUE:
+				res->type = NUM;	res->val = ares.value;
+				res->text = 0L;		break;
+			case ET_BOOL:
+				res->type = BOOLVAL;	res->val = ares.value;
+				res->text = 0L;		break;
+			case ET_DATE:
+				res->type = DATE1;	res->val = ares.value;
+				res->text = 0L;		break;
+			case ET_TIME:
+				res->type = TIME1;	res->val = ares.value;
+				res->text = 0L;		break;
+			case ET_DATETIME:
+				res->type = DATETIME1;	res->val = ares.value;
+				res->text = 0L;		break;
+			case ET_TEXT:
 				res->type = STR;	res->val = 0.0;
-				text = strdup(ares.text);
-				res->text = text;
-				}
-			else {
+				if(ares.text) res->text = PushString(text = strdup(ares.text));
+				else res->text = 0L;	break;
+			default:
 				res->type = NUM;	res->val = var;
-				res->text = 0L;
+				res->text = 0L;		break;
 				}
 			var = res->val;
 			return;
@@ -266,15 +325,18 @@ symrec::GetValue(void *re)
 		isSSval = false;
 		row = col = -1;
 		}
-	if(text && text[0]) {
-		res->text = strdup(text);
+	if(a_data && a_count) {
+		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;
 		}
 	else {
 		res->type = NUM;	res->val = var;
 		res->text = 0L;
 		}
-	res->a_data = 0L;	res->a_count = 0L;
 }
 
 double 
@@ -289,6 +351,7 @@ symrec::SetValue(double v)
 		isSSval = false;
 		row = col = -1;
 		}
+	a_data = 0L;	a_count = 0;
 	return var = v;
 }
 
@@ -310,6 +373,7 @@ symrec::SetValue(void* d, void* s)
 	var = src->val;
 	if(text) free(text);		text = 0L;
 	if(src->text && src->text[0]) 	text = strdup(src->text);
+	a_data = src->a_data;		a_count = src->a_count;
 	GetValue(d);
 	return;
 }
@@ -347,6 +411,15 @@ static void yyargserr(char *s)
 	last_err_desc = "#ARGS";
 }
 
+static void make_time(YYSTYPE *dst, double h, double m, double s)
+{
+	if(!dst || h < 0.0 || 24.0 < h || m < 0.0 || 60.0 < m || s < 0.0 || 60.0 < s) {
+		yyerror("parse error");			return;
+		}
+	dst->val = s/60.0 + m;		dst->val = dst->val/60.0 + h;
+	dst->val /= 24.0;		dst->type = TIME1;
+}
+
 static void store_res(YYSTYPE *res)
 {
 	if(last_err_desc) {
@@ -354,7 +427,27 @@ static void store_res(YYSTYPE *res)
 		line_res.value = 0.0;
 		strcpy(res_txt, last_err_desc);
 		}
-	else if(res->type == STR) {
+	else if(res->type == NUM){
+		line_res.type = ET_VALUE;
+		line_res.value = res->val;
+		}
+	else if(res->type == BOOLVAL){
+		line_res.type = ET_BOOL;
+		line_res.value = res->val;
+		}
+	else if(res->type == DATE1){
+		line_res.type = ET_DATE;
+		line_res.value = res->val;
+		}
+	else if(res->type == TIME1){
+		line_res.type = ET_TIME;
+		line_res.value = res->val;
+		}
+	else if(res->type == DATETIME1){
+		line_res.type = ET_DATETIME;
+		line_res.value = res->val;
+		}
+ 	else if(res->type == STR) {
 		line_res.type = ET_TEXT;
 		line_res.value = 0.0;
 		if(res->text) strcpy(res_txt, res->text);
@@ -439,10 +532,11 @@ static void pop_syntax()
 		}
 }
 
-static double eval(YYSTYPE *sr, YYSTYPE *dst) 
+static double eval(YYSTYPE *sr, YYSTYPE *dst, char *dum) 
 {
 	anyResult *ar;
 
+	if(dum) yyerror("parse error");
 	if(!sr || !sr->text) return 0.0;
 	parse_level++;
 	ar = do_formula(0L, sr->text);
@@ -477,10 +571,11 @@ static double sign(double v)
 }
 
 static long idum=0;
-
-static double rand(double v)
+static double rand1(YYSTYPE *dst, YYSTYPE *src)
 {
-	return ran2(&idum);
+	if(!dst) return 0.0;
+	dst->type = NUM;
+	return(dst->val = ran2(&idum));
 }
 
 static double srand(double v)
@@ -494,14 +589,9 @@ static double factorial(double v)
 	return factrl((int)v);
 }
 
-static void close_arr_func(YYSTYPE *sr)
-{
-	if(sr->a_data) free(sr->a_data);
-	sr->a_data = 0L;		sr->a_count = 0;
-}
-
-static double _strlen(YYSTYPE *sr, YYSTYPE *dst)
+static double _strlen(YYSTYPE *sr, YYSTYPE *dst, char *dum)
 {
+	if(dum) yyerror("parse error");
 	if(!sr || !sr->text) return 0.0;
 	return (double)strlen(sr->text);
 }
@@ -515,7 +605,6 @@ static double min(YYSTYPE *sr)
 	if(sr->a_data && sr->a_data){
 		for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) 
 			if(sr->a_data[i] < sr->val) sr->val = sr->a_data[i];
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -529,7 +618,6 @@ static double max(YYSTYPE *sr)
 	if(sr->a_data){
 		for(i = 1, sr->val = sr->a_data[0]; i < sr->a_count; i++) 
 			if(sr->a_data[i] > sr->val) sr->val = sr->a_data[i];
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -537,10 +625,7 @@ static double max(YYSTYPE *sr)
 static double count(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
-	if(sr->a_data){
-		sr->val = (double)sr->a_count;
-		close_arr_func(sr);
-		}
+	if(sr->a_data) sr->val = (double)sr->a_count;
 	else sr->val = 0.0;
 	return sr->val;
 }
@@ -552,47 +637,64 @@ static double sum(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	if(sr->a_data){
 		for(i = 0, sr->val = 0.0; i < sr->a_count; i++) sr->val += sr->a_data[i];
-		close_arr_func(sr);
 		}
 	else sr->val = 0.0;
 	return sr->val;
 }
 
-static double calc_variance(double *values, int n)
+static double mean(YYSTYPE *sr) 
 {
-	int i;
-	double ss, d, mean = d_amean(n, values);
+	if(!sr) return 0.0;
+	if(sr->a_data && sr->a_count){
+		sr->val = d_amean(sr->a_count, sr->a_data );
+		}
+	return sr->val;
+}
 
-	for(i=0, ss=0.0; i < n; i++) ss += ((d=values[i]-mean)*d);
-	return (ss/(n-1));
+static double kurt(YYSTYPE *sr) 
+{
+	if(!sr) return 0.0;
+	if(sr->a_data && sr->a_count > 3){
+		sr->val = d_kurt(sr->a_count, sr->a_data );
+		}
+	return sr->val;
 }
 
-static double mean(YYSTYPE *sr) 
+static double skew(YYSTYPE *sr) 
 {
 	if(!sr) return 0.0;
-	if(sr->a_data && sr->a_count){
-		sr->val = d_amean(sr->a_count, sr->a_data );
-		close_arr_func(sr);
+	if(sr->a_data && sr->a_count > 2){
+		sr->val = d_skew(sr->a_count, sr->a_data );
 		}
 	return sr->val;
 }
 
 static double gmean(YYSTYPE *sr) 
 {
+	int i;
+
 	if(!sr) return 0.0;
 	if(sr->a_data && sr->a_count){
+		for(i = 0; i < sr->a_count; i++) if(sr->a_data[i] <= 0.0) {
+			last_err_desc = "#VALUE";
+			return sr->val = 0.0;
+			}
 		sr->val = d_gmean(sr->a_count, sr->a_data );
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
 
 static double hmean(YYSTYPE *sr) 
 {
+	int i;
+
 	if(!sr) return 0.0;
 	if(sr->a_data && sr->a_count){
+		for(i = 0; i < sr->a_count; i++) if(sr->a_data[i] <= 0.0) {
+			last_err_desc = "#VALUE";
+			return sr->val = 0.0;
+			}
 		sr->val = d_hmean(sr->a_count, sr->a_data );
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -602,7 +704,6 @@ static double quartile1(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, &sr->val, 0L, 0L);
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -612,7 +713,6 @@ static double quartile2(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, 0L, &sr->val, 0L);
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -622,7 +722,6 @@ static double quartile3(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	if(sr->a_data && sr->a_count){
 		d_quartile(sr->a_count, sr->a_data, 0L, 0L, &sr->val);
-		close_arr_func(sr);
 		}
 	return sr->val;
 }
@@ -632,8 +731,7 @@ static double variance(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count){
-		sr->val = calc_variance(sr->a_data, sr->a_count);
-		close_arr_func(sr);
+		sr->val = d_variance(sr->a_count, sr->a_data);
 		}
 	return sr->val;
 }
@@ -643,8 +741,7 @@ static double stdev(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count){
-		sr->val = sqrt(calc_variance(sr->a_data, sr->a_count));
-		close_arr_func(sr);
+		sr->val = sqrt(d_variance(sr->a_count, sr->a_data));
 		}
 	return sr->val;
 }
@@ -654,8 +751,7 @@ static double sterr(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count){
-		sr->val = sqrt(calc_variance(sr->a_data, sr->a_count))/sqrt(sr->a_count);
-		close_arr_func(sr);
+		sr->val = sqrt(d_variance(sr->a_count, sr->a_data))/sqrt(sr->a_count);
 		}
 	return sr->val;
 }
@@ -666,7 +762,6 @@ static double beta(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2){
 		sr->val = betaf(sr->a_data[0], sr->a_data[1]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  beta(u, v).");
 	return sr->val;
@@ -678,7 +773,6 @@ static double _gammp(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2){
 		sr->val = gammp(sr->a_data[0], sr->a_data[1]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  gammp(a, x).");
 	return sr->val;
@@ -690,7 +784,6 @@ static double _gammq(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2){
 		sr->val = gammq(sr->a_data[0], sr->a_data[1]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  gammq(a, x).");
 	return sr->val;
@@ -701,10 +794,13 @@ static double _betai(YYSTYPE *sr)
 	if(!sr) return 0.0;
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3){
+		if(sr->a_data[2] < 0.0 || sr->a_data[2] > 1.0) {
+			last_err_desc = "#VALUE";
+			return sr->val = 0.0;
+			}
 		sr->val = betai(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
-		close_arr_func(sr);
 		}
-	else yyargserr("Wrong number of arguments\nin call to  betai(x, a, b).");
+	else yyargserr("Wrong number of arguments\nin call to  betai(a, b, x).");
 	return sr->val;
 }
 
@@ -714,7 +810,6 @@ static double _bincof(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2){
 		sr->val = bincof(sr->a_data[0], sr->a_data[1]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  bincof(n, k).");
 	return sr->val;
@@ -726,19 +821,30 @@ static double binomdist(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3){
 		sr->val = binomdistf(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  binomdist(s, n, p).");
 	return sr->val;
 }
 
+static double binomfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+        if(sr->a_data && sr->a_count == 3){
+		sr->val = bincof(sr->a_data[1], sr->a_data[0]);
+		sr->val *= pow(sr->a_data[2], sr->a_data[0]);
+		sr->val *= pow(1.0 - sr->a_data[2], sr->a_data[1] - sr->a_data[0]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  binomfreq(s, n, p).");
+	return sr->val;
+}
+
 static double normdist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = norm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  normdist(x, mean, SD).");
 	return sr->val;
@@ -750,19 +856,50 @@ static double norminv(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 3) {
 		sr->val = distinv(norm_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  norminv(p, mean, SD).");
 	return sr->val;
 }
 
+static double normfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 3){
+		sr->val = norm_freq(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  normfreq(x, mean, SD).");
+	return sr->val;
+}
+
+static double lognormdist(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 3){
+		sr->val = lognorm_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  lognormdist(x, mean, SD).");
+	return sr->val;
+}
+
+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], 2.0);
+		}
+	else yyargserr("Wrong number of arguments\nin call to  lognorminv(p, mean, SD).");
+	return sr->val;
+}
+
 static double chidist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = chi_dist(sr->a_data[0], sr->a_data[1], 1.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  chidist(x, df).");
 	return sr->val;
@@ -774,7 +911,6 @@ static double chiinv(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2) {
 		sr->val = distinv(chi_dist,sr->a_data[1], 1.0, sr->a_data[0], 2.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  chiinv(p, df).");
 	return sr->val;
@@ -786,7 +922,6 @@ static double tdist(YYSTYPE *sr)
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = t_dist(sr->a_data[0], sr->a_data[1], 1.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  tdist(x, df).");
 	return sr->val;
@@ -798,7 +933,6 @@ static double tinv(YYSTYPE *sr)
 	sr->val = 0.0;
         if(sr->a_data && sr->a_count == 2) {
 		sr->val = distinv(t_dist,sr->a_data[1], 1.0, sr->a_data[0], 2.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  tinv(p, df).");
 	return sr->val;
@@ -810,19 +944,28 @@ static double poisdist(YYSTYPE *sr)
 	sr->val = 0.0;
 	if(sr->a_data && sr->a_count == 2){
 		sr->val = pois_dist(sr->a_data[0], sr->a_data[1], 1.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  poisdist(x, mean).");
 	return sr->val;
 }
 
+static double poisfreq(YYSTYPE *sr)
+{
+	if(!sr) return 0.0;
+	sr->val = 0.0;
+	if(sr->a_data && sr->a_count == 2){
+		sr->val = exp(log(sr->a_data[1])*sr->a_data[0] - sr->a_data[1] - gammln(1.0 + sr->a_data[0]));
+		}
+	else yyargserr("Wrong number of arguments\nin call to  poisfreq(x, mean).");
+	return sr->val;
+}
+
 static double fdist(YYSTYPE *sr)
 {
 	if(!sr) return 0.0;
 	sr->val = 0;
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = f_dist(sr->a_data[0], sr->a_data[1], sr->a_data[2]);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  fdist(x, df1, df2).");
 	return sr->val;
@@ -834,7 +977,6 @@ static double finv(YYSTYPE *sr)
 	sr->val = 0;
 	if(sr->a_data && sr->a_count == 3){
 		sr->val = distinv(f_dist,sr->a_data[1], sr->a_data[2], sr->a_data[0], 2.0);
-		close_arr_func(sr);
 		}
 	else yyargserr("Wrong number of arguments\nin call to  finv(p, df1, df2).");
 	return sr->val;
@@ -846,7 +988,6 @@ static double pearson(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	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);
-		close_arr_func(sr1);		close_arr_func(sr2);
 		}
 	else yyargserr("Bad arguments in call to function\npearson(range1; range2 [;\"dest\"]).");
 	return sr1->val;
@@ -858,12 +999,22 @@ static double spearman(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	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);
-		close_arr_func(sr1);		close_arr_func(sr2);
 		}
 	else yyargserr("Bad arguments in call to function\nspearman(range1; range2 [;\"dest\"]).");
 	return sr1->val;
 }
 
+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);
+		}
+	else yyargserr("Bad arguments in call to function\nkendall(range1; range2 [;\"dest\"]).");
+	return sr1->val;
+}
+
 static double regression(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 {
 	if(!sr1 || !sr2) return 0.0;
@@ -871,21 +1022,52 @@ static double regression(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	if(!(dest)) yyargserr("No destination range in call to function\nregression(range1; range2; \"dest\").");
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count == sr2->a_count){
 		sr1->val = sr2->val = d_regression(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
-		close_arr_func(sr1);		close_arr_func(sr2);
 		}
 	else yyargserr("Bad arguments in call to function\nregression(range1; range2; \"dest\").");
 	return sr1->val;
 }
 
+static double covar(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_covar(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		}
+	else yyargserr("Bad arguments in call to function\ncovar(range1; range2).");
+	return sr1->val;
+}
+
 static double ttest(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 && sr2->a_count > 1){
 		sr1->val = sr2->val = d_ttest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
-		close_arr_func(sr1);		close_arr_func(sr2);
 		}
-	else yyargserr("Bad arguments in call to function\nttest(range1; range2[;\"dest\"]).");
+	else yyargserr("Bad arguments in call to function\nttest(array1; array2[;\"dest\"]).");
+	return sr1->val;
+}
+
+static double ttest2(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 && sr2->a_count > 1){
+		sr1->val = sr2->val = d_ttest2(sr1->a_data, sr2->a_data, sr1->a_count, dest, curr_data);
+		}
+	else yyargserr("Bad arguments in call to function\nttest2(range1; range2[;\"dest\"]).");
+	return sr1->val;
+}
+
+static double utest(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 && sr2->a_count > 1){
+		sr1->val = sr2->val = d_utest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
+		}
+	else yyargserr("Bad arguments in call to function\nutest2(array1; array2[;\"dest\"]).");
 	return sr1->val;
 }
 
@@ -895,80 +1077,223 @@ static double ftest(YYSTYPE *sr1, YYSTYPE *sr2, char *dest)
 	sr1->val = 0.0;
         if(sr1->a_data && sr1->a_count > 1 && sr2->a_data && sr1->a_count > 1){
 		sr1->val = sr2->val = d_ftest(sr1->a_data, sr2->a_data, sr1->a_count, sr2->a_count, dest, curr_data);
-		close_arr_func(sr1);		close_arr_func(sr2);
 		}
 	else yyargserr("Bad arguments in call to function\nftest(range1; range2[;\"dest\"]).");
 	return sr1->val;
 }
 
-struct init
+static double fill(YYSTYPE *sr, char *dest)
 {
-	int f_type;
-	unsigned int h_name;
-	double (*fnct)(double);
-};
+	AccRange *ar;
+	int i, r, c;
+
+	if(!sr || !sr->a_data || !sr->a_count || !dest || !dest[0]) return 0.0;
+	if(ar = new AccRange(dest)) {
+		for(i=0, ar->GetFirst(&c, &r); ar->GetNext(&c, &r) && i < sr->a_count; i++) {
+			curr_data->SetValue(r, c, sr->a_data[i]);
+			}
+		delete ar;
+		}
+	return sr->val = i;
+}
+
+static void datestr(YYSTYPE *dst, YYSTYPE *src, char *fmt)
+{
+	dst->text = PushString(value_date(src->val, fmt));
+}
+
+static double dateval(YYSTYPE *sr, YYSTYPE *dst, char *fmt)
+{
+	if(!sr || !sr->text) return 0.0;
+	if(fmt && fmt[0] && date_value(sr->text, fmt, &dst->val)) return dst->val;
+	if(date_value(sr->text, 0L, &dst->val)) return dst->val;
+	else return dst->val = 0.0;
+}
+
+static double leapyear(double year)
+{
+	int y = (int)year;
+
+	return (double)((y % 4 == 0 && y % 100 != 0) || y % 400 == 0);
+}
+
+static void today(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(src) yyerror("parse error");
+	if(!dst) return;
+	dst->val = floor(now_today());
+	dst->type = DATE1;
+}
+
+static void now(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(src) yyerror("parse error");
+	if(!dst) return;
+	dst->val = now_today();			dst->val -= floor(dst->val);
+	dst->type = TIME1;
+}
+
+static double year(double dv)
+{
+	int res;
+
+	split_date(dv, &res, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
+	return (double)res;
+}
+
+static double month(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, &res, 0L, 0L, 0L, 0L, 0L, 0L);
+	return (double)res;
+}
+
+static double dom(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, 0L, &res, 0L, 0L, 0L, 0L, 0L);
+	return (double)res;
+}
+
+static double dow(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, 0L, 0L, &res, 0L, 0L, 0L, 0L);
+	return (double)res;
+}
+
+static double doy(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, 0L, 0L, 0L, &res, 0L, 0L, 0L);
+	return (double)res;
+}
 
-static struct init arith_fncts[] = {
-	{FUNC2, HashValue((unsigned char*)"pearson"), (double(*)(double))&pearson},
-	{FUNC2, HashValue((unsigned char*)"spearman"), (double(*)(double))&spearman},
-	{FUNC2, HashValue((unsigned char*)"regression"), (double(*)(double))&regression},
-	{FUNC2, HashValue((unsigned char*)"ttest"), (double(*)(double))&ttest},
-	{FUNC2, HashValue((unsigned char*)"ftest"), (double(*)(double))&ftest},
-	{AFNCT, HashValue((unsigned char*)"variance"), (double(*)(double))&variance},
-	{AFNCT, HashValue((unsigned char*)"stdev"), (double(*)(double))&stdev},
-	{AFNCT, HashValue((unsigned char*)"sterr"), (double(*)(double))&sterr},
-	{AFNCT, HashValue((unsigned char*)"min"), (double(*)(double))&min},
-	{AFNCT, HashValue((unsigned char*)"max"), (double(*)(double))&max},
-	{AFNCT, HashValue((unsigned char*)"count"), (double(*)(double))&count},
-	{AFNCT, HashValue((unsigned char*)"sum"), (double(*)(double))&sum},
-	{AFNCT, HashValue((unsigned char*)"mean"), (double(*)(double))&mean},
-	{AFNCT, HashValue((unsigned char*)"median"), (double(*)(double))&quartile2},
-	{AFNCT, HashValue((unsigned char*)"quartile1"), (double(*)(double))&quartile1},
-	{AFNCT, HashValue((unsigned char*)"quartile2"), (double(*)(double))&quartile2},
-	{AFNCT, HashValue((unsigned char*)"quartile3"), (double(*)(double))&quartile3},
-	{AFNCT, HashValue((unsigned char*)"gmean"), (double(*)(double))&gmean},
-	{AFNCT, HashValue((unsigned char*)"hmean"), (double(*)(double))&hmean},
-	{AFNCT, HashValue((unsigned char*)"tdist"), (double(*)(double))&tdist},
-	{AFNCT, HashValue((unsigned char*)"tinv"), (double(*)(double))&tinv},
-	{AFNCT, HashValue((unsigned char*)"poisdist"), (double(*)(double))&poisdist},
-	{AFNCT, HashValue((unsigned char*)"fdist"), (double(*)(double))&fdist},
-	{AFNCT, HashValue((unsigned char*)"finv"), (double(*)(double))&finv},
-	{AFNCT, HashValue((unsigned char*)"gammp"), (double(*)(double))&_gammp},
-	{AFNCT, HashValue((unsigned char*)"gammq"), (double(*)(double))&_gammq},
-	{AFNCT, HashValue((unsigned char*)"beta"), (double(*)(double))&beta},
-	{AFNCT, HashValue((unsigned char*)"betai"), (double(*)(double))&_betai},
-	{AFNCT, HashValue((unsigned char*)"bincof"), (double(*)(double))&_bincof},
-	{AFNCT, HashValue((unsigned char*)"binomdist"), (double(*)(double))&binomdist},
-	{AFNCT, HashValue((unsigned char*)"normdist"), (double(*)(double))&normdist},
-	{AFNCT, HashValue((unsigned char*)"norminv"), (double(*)(double))&norminv},
-	{AFNCT, HashValue((unsigned char*)"chidist"), (double(*)(double))&chidist},
-	{AFNCT, HashValue((unsigned char*)"chiinv"), (double(*)(double))&chiinv},
-	{SFNCT, HashValue((unsigned char*)"strlen"), (double(*)(double))&_strlen},
-	{SFNCT, HashValue((unsigned char*)"eval"), (double(*)(double))&eval},
-	{FNCT, HashValue((unsigned char*)"erf"), errf},
-	{FNCT, HashValue((unsigned char*)"erfc"), errfc},
-	{FNCT, HashValue((unsigned char*)"sign"), sign},
-	{FNCT, HashValue((unsigned char*)"gammaln"), gammln},
-	{FNCT, HashValue((unsigned char*)"factorial"), factorial},
-	{FNCT, HashValue((unsigned char*)"rand"), rand},
-	{FNCT, HashValue((unsigned char*)"srand"), srand},
-	{FNCT, HashValue((unsigned char*)"floor"), floor},
-	{FNCT, HashValue((unsigned char*)"abs"), fabs},
-	{FNCT, HashValue((unsigned char*)"asin"), asin},
-	{FNCT, HashValue((unsigned char*)"acos"), acos},
-	{FNCT, HashValue((unsigned char*)"atan"), atan},
-	{FNCT, HashValue((unsigned char*)"sinh"), sinh},
-	{FNCT, HashValue((unsigned char*)"cosh"), cosh},
-	{FNCT, HashValue((unsigned char*)"tanh"), tanh},
-	{FNCT, HashValue((unsigned char*)"sin"),  sin},
-	{FNCT, HashValue((unsigned char*)"cos"),  cos},
-	{FNCT, HashValue((unsigned char*)"atan"), atan},
-	{FNCT, HashValue((unsigned char*)"log10"), log10},
-	{FNCT, HashValue((unsigned char*)"ln"),   log},
-	{FNCT, HashValue((unsigned char*)"log"),   log},
-	{FNCT, HashValue((unsigned char*)"exp"),  exp},
-	{FNCT, HashValue((unsigned char*)"sqrt"), sqrt},
-	{0, 0, 0}};
+static double hours(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, 0L, 0L, 0L, 0L, &res, 0L, 0L);
+	return (double)res;
+}
+
+static double minutes(double dv)
+{
+	int res;
+
+	split_date(dv, 0L, 0L, 0L, 0L, 0L, 0L, &res, 0L);
+	return (double)res;
+}
+
+static double seconds(double dv)
+{
+	double res;
+
+	split_date(dv, 0L, 0L, 0L, 0L, 0L, 0L, 0L, &res);
+	if(res < 0.0005) res = 0.0;
+	return res;
+}
+
+static void fdate(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src || src->type == ARR || src->type == STR) {
+		yyerror("parse error");	
+		return;
+		}
+	dst->type = DATE1;		dst->val = src->val;
+}
+
+static void fdatetime(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src || src->type == ARR || src->type == STR) {
+		yyerror("parse error");	
+		return;
+		}
+	dst->type = DATETIME1;		dst->val = src->val;
+}
+
+static void ftime(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src || src->type == ARR || src->type == STR) {
+		yyerror("parse error");	
+		return;
+		}
+	dst->type = TIME1;		dst->val = src->val;
+}
+
+static void asort(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!dst || !src) return;
+	dst->type = ARR;
+	switch(src->a_count) {
+	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 = 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;
+		SortArray(dst->a_count, dst->a_data);
+		}
+}
+
+static void _crank(YYSTYPE *dst, YYSTYPE *src)
+{
+	double tmp;
+
+	if(!dst || !src) return;
+	dst->type = ARR;
+	switch(src->a_count) {
+	case 0:	case 1:
+		dst->a_data = PushArray((double*)malloc(sizeof(double)));
+		dst->a_count = 1;	dst->a_data[0] = dst->val = 1;
+		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);
+		}
+}
+
+static void ltrim(YYSTYPE *dst, YYSTYPE *src)
+{
+	if(!src || !dst || !src->text) return;
+	dst->text = PushString(str_ltrim(strdup(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->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->type = STR;	dst->val = 0.0;
+}
+
+static double rank(YYSTYPE *sr) 
+{
+	if(sr->a_count < 2 || !sr->a_data) return 0.0;
+	return d_rank(sr->a_count-1, sr->a_data+1, sr->a_data[0]);
+}
+
+static double classes(double start, double step, YYSTYPE *src, YYSTYPE *dest)
+{
+	return d_classes(curr_data, start, step, src->a_data, src->a_count, dest->text);
+}
 
 // Store strings in a list
 static char **str_list = 0L;
@@ -984,6 +1309,36 @@ static char *PushString(char *text)
 	return 0L;
 }
 
+//Store arrays in a list
+static double **arr_list = 0L;
+static int n_arr = 0;
+
+static double *PushArray(double *arr)
+{
+	if(arr) {
+		if(arr_list = (double**)realloc(arr_list, sizeof(double*)*(n_arr+1)))
+			arr_list[n_arr] = arr;
+		return arr_list[n_arr++];
+		}
+	return 0L;
+}
+
+static double *ReallocArray(double *arr, int size)
+{
+	int i;
+
+	if(arr && size) {
+		for(i = 0; i < n_arr; i++) if(arr_list[i] == arr) {
+			arr_list[i] = (double*)realloc(arr, size);
+			return arr_list[i];
+			}
+		arr = (double*)realloc(arr, size);
+		return PushArray(arr);
+		}
+	return 0L;
+}
+
+
 //The symbol table: a chain of `struct symrec'
 static symrec *sym_table, *sym_tab_first;
 
@@ -1021,8 +1376,68 @@ void ArrangeFunctions()
 }
 
 // Put arithmetic functions and predifened variables in table
+#define INIT_SYM(TYP,NAM,FNC) {TYP,NAM,(double(*)(double))&FNC} 
 void InitArithFuncs(DataObj *d)
 {
+	struct fdef {
+		int f_type;
+		char *name;
+		double (*fnct)(double);
+		};
+	fdef fncts[] = {
+	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(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),
+	INIT_SYM(FNCT, "month", month),			INIT_SYM(FNCT, "dom", dom),
+	INIT_SYM(FNCT, "dow", dow),			INIT_SYM(FNCT, "doy", doy),
+	INIT_SYM(FNCT, "hours", hours),			INIT_SYM(FNCT, "minutes", minutes),
+	INIT_SYM(FNCT, "seconds", seconds),		INIT_SYM(YYFNC, "date", fdate),
+	INIT_SYM(FNCT, "datetime", fdatetime),		INIT_SYM(YYFNC, "time", ftime),
+	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(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),
+	INIT_SYM(AFNCT, "sterr", sterr),		INIT_SYM(AFNCT, "min", min),
+	INIT_SYM(AFNCT, "max", max),			INIT_SYM(AFNCT, "count", count),
+	INIT_SYM(AFNCT, "sum", sum),			INIT_SYM(AFNCT, "mean", mean),
+	INIT_SYM(AFNCT, "kurt", kurt),			INIT_SYM(AFNCT, "skew", skew),
+	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, "tinv", tinv),
+	INIT_SYM(AFNCT, "poisdist", poisdist),		INIT_SYM(AFNCT, "poisfreq", poisfreq),		
+	INIT_SYM(AFNCT, "fdist", fdist),
+	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, "normdist", normdist),
+	INIT_SYM(AFNCT, "norminv", norminv),
+	INIT_SYM(AFNCT, "normfreq", normfreq),
+	INIT_SYM(AFNCT, "lognormdist", lognormdist),
+	INIT_SYM(AFNCT, "lognorminv",lognorminv),	INIT_SYM(AFNCT, "chidist", chidist),
+	INIT_SYM(AFNCT, "chiinv", chiinv),		INIT_SYM(SFNCT, "strlen", _strlen),
+	INIT_SYM(SFNCT, "eval", eval),			INIT_SYM(FNCT, "erf", errf),
+	INIT_SYM(FNCT, "erfc", errfc),			INIT_SYM(FNCT, "sign", sign),
+	INIT_SYM(FNCT, "gammaln", gammln),		INIT_SYM(FNCT, "factorial", factorial),
+	INIT_SYM(YYFNC, "rand", rand1),			INIT_SYM(FNCT, "srand", srand),
+	INIT_SYM(FNCT, "floor", floor),			INIT_SYM(FNCT, "abs", fabs),
+	INIT_SYM(FNCT, "asin", asin),			INIT_SYM(FNCT, "acos", acos),
+	INIT_SYM(FNCT, "atan", atan),			INIT_SYM(FNCT, "sinh", sinh),
+	INIT_SYM(FNCT, "cosh", cosh),			INIT_SYM(FNCT, "tanh", tanh),
+	INIT_SYM(FNCT, "sin", sin),			INIT_SYM(FNCT, "cos", cos),
+	INIT_SYM(FNCT, "tan", tan),			INIT_SYM(FNCT, "log10", log10),
+	INIT_SYM(FNCT, "ln", log),			INIT_SYM(FNCT, "log", log),
+	INIT_SYM(FNCT, "exp", exp),			INIT_SYM(FNCT, "sqrt", sqrt),
+	INIT_SYM(0, 0L, nop)};
 	int i;
 	symrec *ptr, *next;
 
@@ -1037,17 +1452,19 @@ void InitArithFuncs(DataObj *d)
 			}
 		sym_table = sym_tab_first = (symrec *) 0;
 		}
-	for (i = 0; arith_fncts[i].h_name; i++) {
-		ptr = putsym (arith_fncts[i].h_name, arith_fncts[i].f_type);
-		ptr->fnctptr = (double (*)(...))arith_fncts[i].fnct;
+	for (i = 0; fncts[i].name; i++) {
+		ptr = putsym (HashValue((unsigned char*) fncts[i].name), Hash2((unsigned char*) fncts[i].name), fncts[i].f_type);
+		ptr->fnctptr = (double (*)(...))fncts[i].fnct;
 		}
-	ptr = putsym(HashValue((unsigned char*)"zdiv"), VAR);		ptr->SetValue(1.0);
+	ptr = putsym(HashValue((unsigned char*)"zdiv"), Hash2((unsigned char*)"zdiv"), VAR);	ptr->SetValue(1.0);
 	sym_tab_first = sym_table;
 }
+#undef INIT_SYM
 
 static void init_table (void)
 {
 	str_list = 0L;		n_str = 0;
+	arr_list = 0L;		n_arr = 0;
 	push_syntax();
 }
 
@@ -1059,33 +1476,37 @@ static void clear_table()
 		for(i = 0; i < n_str; i++) if(str_list[i]) free(str_list[i]);
 		free(str_list);		str_list = 0L;		n_str = 0;
 		}
+	if(arr_list) {
+		for(i = 0; i < n_arr; i++) if(arr_list[i]) free(arr_list[i]);
+		free(arr_list);		arr_list = 0L;		n_arr = 0;
+		}
 	pop_syntax();
 }
 
 static symrec *
-putsym (unsigned int h_name, int sym_type)
+putsym (unsigned int h_name, unsigned int h2_name, int sym_type)
 {
-	sym_table = new symrec(h_name, sym_type, sym_table);
+	sym_table = new symrec(h_name, h2_name, sym_type, sym_table);
 	return sym_table;
 }
 
 static symrec *
-getsym (unsigned int h_name, char *sym_name)
+getsym (unsigned int h_name, unsigned int h2_name, char *sym_name)
 {
 	symrec *ptr;
 
 	if(!h_name) return 0;
 	for (ptr = sym_table; ptr != (symrec *) 0; ptr = (symrec *)ptr->next) {
-		if (ptr->h_name == h_name){
+		if (ptr->h_name == h_name && ptr->h2_name == h2_name){
 			if(sym_name && !ptr->name) {
 				ptr->SetName(sym_name);
 				bRecent = true;
 				}
 			return ptr;
 			}
-		//predefined variables never end on a digit
+		//predefined variables rarely end on a digit
 		else if(ptr == sym_tab_first) {
-			if(sym_name && isdigit(sym_name[strlen(sym_name)-1])) return 0;
+			if(sym_name && isdigit(sym_name[strlen(sym_name)-1]) && strlen(sym_name) < 5) return 0;
 			}
 		}
 	return 0;
@@ -1096,28 +1517,28 @@ push(YYSTYPE *res, YYSTYPE *val)
 {
 	if(val->a_data) {
 		if(!(res->a_data)) {
-			if(!(val->a_data=(double*)realloc(val->a_data, (val->a_count+2)*sizeof(double))))return 0;
+			if(!(val->a_data=ReallocArray(val->a_data, (val->a_count+2)*sizeof(double))))return 0;
 			val->a_data[val->a_count++] = res->val;
 			res->a_data = val->a_data;		res->a_count = val->a_count;
 			val->a_data = 0L;			val->a_count = 0;
 			val->val = res->val;			return 1;
 			}
 		else {
-			if(!(res->a_data=(double*)realloc(res->a_data, (val->a_count+res->a_count)*sizeof(double))))return 0;
+			if(!(res->a_data=ReallocArray(res->a_data, (val->a_count+res->a_count)*sizeof(double))))return 0;
 			memcpy(&res->a_data[res->a_count], val->a_data, val->a_count*sizeof(double));
-			res->a_count += val->a_count;		free(val->a_data);
+			res->a_count += val->a_count;
 			val->a_data = 0L;			val->a_count = 0;
 			return 1;
 			}
 		}
 	if(!(res->a_data )){
-		if(!(res->a_data =  (double*)malloc(2*sizeof(double))))return 0;
+		if(!(res->a_data =  PushArray((double*)malloc(2*sizeof(double)))))return 0;
 		res->a_data[0] = res->val;			res->a_data[1] = val->val;
 		res->a_count = 2;
 		return 1;
 		}
 	else {
-		if(!(res->a_data = (double*)realloc(res->a_data, (res->a_count+2)*sizeof(double))))return 0; 
+		if(!(res->a_data = ReallocArray(res->a_data, (res->a_count+2)*sizeof(double))))return 0; 
 		res->a_data[res->a_count] = val->val;		res->a_count++;
 		return 1;
 		}
@@ -1132,7 +1553,7 @@ range_array(YYSTYPE * res, char *range)
 	anyResult ares;
 
 	if(!range || !range[0] || !(r = new AccRange(range))) return 0;
-	if(!r->GetFirst(&col, &row) || !(res->a_data =  (double*)malloc(r->CountItems() * sizeof(double)))) {
+	if(!r->GetFirst(&col, &row) || !(res->a_data =  PushArray((double*)malloc(r->CountItems() * sizeof(double))))) {
 		delete(r);
 		return 0;
 		}
@@ -1140,15 +1561,9 @@ range_array(YYSTYPE * res, char *range)
 	for(res->a_count = 0; r->GetNext(&col, &row); ) {
 		if(curr_data->GetResult(&ares, row, col, parse_level > MAX_PARSE)) {
 			switch(ares.type) {
-			case ET_VALUE: 
+			case ET_VALUE:	case ET_TIME:	case ET_DATE:	case ET_DATETIME:	case ET_BOOL:
 				res->a_data[res->a_count++] = ares.value;
 				break;
-			case ET_TEXT:
-				if(ares.text && ares.text[0]) last_err_desc = "#ARGS";
-				break;
-			case ET_ERROR:
-				last_err_desc = "#ARGS";
-				break;
 				}
 			}
 		}
@@ -1157,6 +1572,40 @@ range_array(YYSTYPE * res, char *range)
 	return 1;
 }
 
+static int
+range_array2(YYSTYPE *res1, YYSTYPE *res2)
+{
+	AccRange *r1, *r2;
+	int row1, col1, row2, col2;
+	anyResult ares1, ares2;
+	char *range1, *range2;
+
+	range1 = res1->text;	range2 = res2->text;
+	if(!range1 || !range1[0] || !range2 || !range2[0] || !(r1 = new AccRange(range1)) 
+		|| !(r2 = new AccRange(range2))) return 0;
+	if(!r1->GetFirst(&col1, &row1) || !(res1->a_data =  PushArray((double*)malloc(r1->CountItems() * sizeof(double))))) {
+		delete(r1);	delete(r2);
+		return 0;
+		}
+	if(!r2->GetFirst(&col2, &row2) || !(res2->a_data =  PushArray((double*)malloc(r2->CountItems() * sizeof(double))))) {
+		delete(r1);	delete(r2);
+		return 0;
+		}
+	parse_level++;
+	for(res1->a_count = res2->a_count = 0; r1->GetNext(&col1, &row1) && r2->GetNext(&col2, &row2); ) {
+		if(curr_data->GetResult(&ares1, row1, col1, parse_level > MAX_PARSE) 
+			&& curr_data->GetResult(&ares2, row2, col2, parse_level > MAX_PARSE)
+			&& (ares1.type==ET_VALUE || ares1.type==ET_TIME || ares1.type==ET_DATE || ares1.type==ET_DATETIME || ares1.type==ET_BOOL)
+			&& (ares2.type==ET_VALUE || ares2.type==ET_TIME || ares2.type==ET_DATE || ares2.type==ET_DATETIME || ares2.type==ET_BOOL)){
+			res1->a_data[res1->a_count++] = ares1.value;
+			res2->a_data[res2->a_count++] = ares2.value;
+			}
+		}
+	parse_level--;
+	delete(r1);	delete(r2);
+	return 1;
+}
+
 static YYSTYPE *proc_clause(YYSTYPE *res)
 {
 	int i, n, o_pos;
@@ -1165,12 +1614,12 @@ static YYSTYPE *proc_clause(YYSTYPE *res)
 
 	if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return res;
 	if(!res->text) return res;
-	if(!res->a_data && (res->a_data = (double*)malloc(sizeof(double)))) {
+	if(!res->a_data && (res->a_data = PushArray((double*)malloc(sizeof(double))))) {
 		res->a_data[0] = res->type == VAR && res->tptr ? res->tptr->GetValue() : res->val;
 		res->a_count = 1;
 		}
 	else if(!res->a_data) return res;
-	if(!(n_data = (double*)malloc(res->a_count * sizeof(double)))) return res;
+	if(!(n_data = PushArray((double*)malloc(res->a_count * sizeof(double))))) return res;
 	o_pos = buff_pos;	o_cmd = buffer;
 	for(i = n = 0; i < res->a_count; i++) {
 		buffer = res->text;	buff_pos = 0;
@@ -1179,8 +1628,8 @@ static YYSTYPE *proc_clause(YYSTYPE *res)
 		yyparse();
 		if(line_res.type == ET_VALUE && line_res.value != 0.0) n_data[n++] = res->a_data[i];
 		}
-	free(res->a_data);	res->a_data = n_data;		res->a_count = n;
-	free(res->text);	res->text=0L;
+	res->a_data = n_data;		res->a_count = n;
+	res->text=0L;
 	syntax_level->cl1 = syntax_level->cl2 = 0;
 	buffer = o_cmd;	buff_pos = o_pos;
 	return res;
@@ -1191,6 +1640,13 @@ static void exec_clause(YYSTYPE *res)
 	int i, j;
 	char *cmd;
 
+	if((!res->a_data || res->a_count <2) && res->text && res->text[0]) range_array(res, res->text);
+	if(!res->a_data) {
+		if(res->a_data = PushArray((double*)malloc(2*sizeof(double)))) {
+			res->a_data[0] = res->val;	res->a_count = 1;
+			InfoBox("fixed data");
+			}
+		}
 	if(!(syntax_level) || !syntax_level->cl1 || syntax_level->cl2 <= syntax_level->cl1) return;
 	if(!(cmd = (char*)malloc(syntax_level->cl2 - syntax_level->cl1 +2)))return;
 	while(buffer[syntax_level->cl1] <= ' ' && syntax_level->cl1 < syntax_level->cl2) syntax_level->cl1++;
@@ -1198,7 +1654,8 @@ static void exec_clause(YYSTYPE *res)
 		cmd[j++] = buffer[i];
 		}
 	cmd[j++] = ';';		cmd[j++] = 0;
-	res->text = cmd;
+	res->text = PushString(cmd);
+	free(cmd);
 }
 
 struct parse_info  {
@@ -1209,8 +1666,9 @@ struct parse_info  {
 	YYSTYPE yylval;
 	struct parse_info *next;
 	char **str_list;
+	double **arr_list;
 	char *last_err_desc;
-	int n_str, yychar, yynerrs;
+	int n_str, n_arr, yychar, yynerrs;
 };
 static parse_info *parse_stack = 0L;
 
@@ -1228,6 +1686,8 @@ static void push_parser()
 	ptr->next = parse_stack;
 	ptr->str_list = str_list;		str_list = 0L;
 	ptr->n_str = n_str;			n_str = 0;
+	ptr->arr_list = arr_list;		arr_list = 0L;
+	ptr->n_arr = n_arr;			n_arr = 0;
 	ptr->yychar = yychar;			ptr->yynerrs = yynerrs;
 	parse_stack = ptr;			last_err_desc = 0L;
 	parse_level++;				//reenter ?
@@ -1251,6 +1711,7 @@ static void pop_parser()
 		curr_data = ptr->curr_data;	last_err_desc = ptr->last_err_desc;
 		memcpy(&yylval, &ptr->yylval, sizeof(YYSTYPE));
 		str_list = ptr->str_list;	n_str = ptr->n_str;
+		arr_list = ptr->arr_list;	n_arr = ptr->n_arr;
 		yychar = ptr->yychar;		yynerrs = ptr->yynerrs;
 		free(ptr);
 		parse_level--;
@@ -1258,17 +1719,39 @@ static void pop_parser()
 	pop_syntax();
 }
 
-static int is_ttoken(int h_nam)
+static int is_ttoken(unsigned int h_nam, unsigned int h2_nam)
 {
 	switch(h_nam) {
-	case 101:		return E;
-	case 26992:		return PI;
+	case 69:
+		if(h2_nam == 101) return E;
+		break;
+	case 393:
+		if(h2_nam == 47081) return PI;
+		break;
 	case 28381:
-		if(syntax_level) syntax_level->cl1 = buff_pos;
-		return CLAUSE;
-	case 9252:		return CLVAL;
-	case 26217:		return IF;
-	case 6033:		return ELSE;
+		if((h2_nam & 0x7fffffff) == 0x7c2706ed) {
+			if(syntax_level) syntax_level->cl1 = buff_pos;
+			return CLAUSE;
+			}
+		break;
+	case 20:
+		if(h2_nam == 5220) return CLVAL;
+		break;
+	case 362:
+		if(h2_nam == 42878) return IF;
+		break;
+	case 1457:
+		if(h2_nam == 18357885) return DIM;
+		break;
+	case 6033:
+		if((h2_nam & 0x7fffffff) == 0x6371377d) return ELSE;
+		break;
+	case 7097:
+		if((h2_nam & 0x7fffffff) == 0x550a2d65) return BTRUE;
+		break;
+	case 23697:
+		if((h2_nam & 0x7fffffff) == 0x155f977d) return BFALSE;
+		break;
 		}
 	return 0;
 }
@@ -1277,7 +1760,7 @@ static symrec *curr_sym;
 static int yylex (void)
 {
 	int i, c, tok;
-	unsigned int h_nam;
+	unsigned int h_nam, h2_nam;
 	char tmp_txt[80];
 	symrec *s;
 
@@ -1322,10 +1805,10 @@ static int yylex (void)
 			}
 		tmp_txt[i] = 0;
 		h_nam = HashValue((unsigned char*)tmp_txt);
-		if(tok = is_ttoken(h_nam)) 
-			return tok;
-		if(!(s = getsym(h_nam, tmp_txt))){
-			s = putsym(h_nam, VAR);
+		h2_nam = Hash2((unsigned char*)tmp_txt);
+		if(tok = is_ttoken(h_nam, h2_nam)) return tok;
+		if(!(s = getsym(h_nam, h2_nam, tmp_txt))){
+			s = putsym(h_nam, h2_nam, VAR);
 			s->SetName(tmp_txt);
 			}
 		
@@ -1403,6 +1886,13 @@ static int yylex (void)
 	return c;
 }
 
+static unsigned int hn_x = HashValue((unsigned char *)"x");
+static unsigned int hn_y = HashValue((unsigned char *)"y");
+static unsigned int hn_z = HashValue((unsigned char *)"z");
+static unsigned int h2_x = Hash2((unsigned char *)"x");
+static unsigned int h2_y = Hash2((unsigned char *)"y");
+static unsigned int h2_z = Hash2((unsigned char *)"z");
+
 bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOINT **pts, long *npts, char *param)
 {
 	double x, y;
@@ -1410,8 +1900,6 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 	lfPOINT *new_points;
 	long npoints = 0;
 	int length, res_mode = 0;
-	unsigned int hn_x = HashValue((unsigned char *)"x");
-	unsigned int hn_y = HashValue((unsigned char *)"y");
 
 	if(x1 < x2) step = fabs(step);
 	else step = -fabs(step);
@@ -1434,7 +1922,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 		free(buffer);		buffer = 0L;
 		}		
 	length = strlen(expr);
-	buffer = expr;		sx = putsym(hn_x, VAR);
+	buffer = expr;		sx = putsym(hn_x, h2_x, VAR);
 	for(x = x1; step > 0.0 ? x <= x2 : x >= x2; x += step) {
 		if(sx){
 			sx->SetValue(x);	buff_pos = 0;
@@ -1447,7 +1935,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 			case 2:
 				y = line_res.value;	break;
 			default:
-				if(sy = getsym(hn_y)) {
+				if(sy = getsym(hn_y, h2_y)) {
 					y = sy->GetValue();	res_mode = 1;
 					}
 				else {
@@ -1455,7 +1943,7 @@ bool do_xyfunc(DataObj *d, double x1, double x2, double step, char *expr, lfPOIN
 					}
 				break;
 				}
-			new_points[npoints].fx = (getsym(hn_x))->GetValue();
+			new_points[npoints].fx = (getsym(hn_x, h2_x))->GetValue();
 			new_points[npoints++].fy = y;
 			}
 		}
@@ -1475,9 +1963,6 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 	int length, nr, nc, r, c, res_mode=0;
 	symrec *sx, *sz, *sy;
 	double x, y, z;
-	unsigned int hn_x = HashValue((unsigned char *)"x");
-	unsigned int hn_y = HashValue((unsigned char *)"y");
-	unsigned int hn_z = HashValue((unsigned char *)"z");
 
 	if(!d || x2 <= x1 || z2 <= z1 || xstep <= 0.0 || zstep <= 0.0) return false;
 	push_parser();
@@ -1496,7 +1981,7 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 		free(buffer);		buffer = 0L;
 		}		
 	length = strlen(expr);		buffer = expr;
-	sx = putsym(hn_x, VAR);		sz = putsym(hn_z, VAR);
+	sx = putsym(hn_x, h2_x, VAR);	sz = putsym(hn_z, h2_z, VAR);
 	nr = iround((z2-z1)/zstep)+1;	nc = iround((x2-x1)/xstep)+1;
 	d->Init(nr, nc);
 	for(r = 0, x = x1; r < nr; r++, x += xstep) {
@@ -1511,7 +1996,7 @@ bool do_func3D(DataObj *d, double x1, double x2, double xstep, double z1, double
 			case 2:
 				y = line_res.value;	break;
 			default:
-				if(sy = getsym(hn_y)) {
+				if(sy = getsym(hn_y, h2_y)) {
 					y = sy->GetValue();	res_mode = 1;
 					}
 				else {
@@ -1534,7 +2019,10 @@ anyResult *do_formula(DataObj *d, char *expr)
 
 	if(d) curr_data = d;
 	ret.type = ET_ERROR;		ret.text = 0L;
-	if(!expr || !expr[0]) return &ret;
+	if(!expr || !expr[0]) {
+		if(!sym_table) InitArithFuncs(0L);
+		return &ret;
+		}
 	push_parser();		//make code reentrant
 	init_table();		length = strlen(expr);
 	if(!(buffer = (char*)malloc(length+2))){
@@ -1586,7 +2074,8 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 			case NUM:
 				pos += sprintf(res+pos, "%g", yylval.val);
 				break;
-			case FNCT:	case FUNC2:	case AFNCT:	case SFNCT:
+			case FNCT:	case FUNC1:	case FUNC2:	case FUNC3:	case AFNCT:
+			case SFNCT:	case SRFUNC:	case BFNCT:	case YYFNC:	case FUNC4:
 				pos += sprintf(res+pos, "%s", curr_sym->name);
 				break;
 			case COLR:			case COLC:
@@ -1634,6 +2123,12 @@ bool MoveFormula(DataObj *d, char *of, char *nf, int dx, int dy, int r0, int c0)
 			case E:
 				pos += sprintf(res+pos, "e");
 				break;
+			case BTRUE:
+				pos += sprintf(res+pos, "true");
+				break;
+			case BFALSE:
+				pos += sprintf(res+pos, "false");
+				break;
 			case AND:
 				pos += sprintf(res+pos, " && ");
 				break;
@@ -1683,20 +2178,20 @@ static void fcurve(double x, double z, double **a, double *y, double dyda[], int
 {
 	int i, length;
 	double tmp, y1, y2;
-	symrec *symx, *sy=0L;
-	unsigned int hn_x = HashValue((unsigned char *)"x");
-	unsigned int hn_y = HashValue((unsigned char *)"y");
+	symrec *symx, *symz, *sy=0L;
 
-	if(!(symx = getsym(hn_x))) symx = putsym(hn_x, VAR);
+	if(!(symx = getsym(hn_x, h2_x))) symx = putsym(hn_x, h2_x, VAR);
+	if(!(symz = getsym(hn_z, h2_z))) symz = putsym(hn_z, h2_z, VAR);
 	//swap parameters to requested set
 	if(a != parval) for(i = 0; i < ma; i++) {
 		tmp = *parval[i];	*parval[i]  = *a[i];	*a[i] = tmp;
 		}
 	//calc result
-	symx->SetValue(x);	buffer = txt_formula;
+	symx->SetValue(x);	symz->SetValue(z);	
+	buffer = txt_formula;
 	buff_pos = 0;		length = strlen(txt_formula);
 	do {	yyparse();	}while(buff_pos < length);
-	if(sy = getsym(hn_y)) *y = sy->GetValue();
+	if(sy = getsym(hn_y, h2_y)) *y = sy->GetValue();
 	else *y = line_res.value;
 	if(*y == HUGE_VAL || *y == -HUGE_VAL) {
 		for(i = 0, *y = 0.0; i < ma; dyda[i++] = 0.0);
@@ -1756,7 +2251,7 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 		if(arz) delete arz;
 		free(x);	delete arx;	delete ary;	return 0;
 		}
-	if(rz && !(y = (double*)malloc(i * sizeof(double)))){
+	if(rz && !(z = (double*)malloc(i * sizeof(double)))){
 		if(arz) delete arz;
 		free(y);	free(x);	delete arx;	delete ary;	return 0;
 		}
@@ -1850,29 +2345,3 @@ int do_fitfunc(DataObj *d, char *rx, char *ry, char *rz, char **par, char *expr,
 	return itst < maxiter ? itst+1 : maxiter;
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/resource.h b/resource.h
deleted file mode 100755
index 2e03463..0000000
--- a/resource.h
+++ /dev/null
@@ -1,86 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Developer Studio generated include file.
-// Used by RLPLOT.RC
-//
-#define ACCELERATORS_1                  1
-#define IDI_EVAL                        50
-#define MENU_1                          400
-#define MENU_2                          401
-#define MENU_3                          402
-#define CM_OPEN                         500
-#define CM_SAVEDATAAS                   501
-#define CM_EXIT                         502
-#define CM_NEWGRAPH                     503
-#define CM_NEWPAGE                      504
-#define CM_DELGRAPH                     505
-#define CM_ADDPLOT                      506
-#define CM_ABOUT                        507
-#define CM_ADDROWCOL                    508
-#define CM_COPYGRAPH                    509
-#define CM_SAVEGRAPHAS                  510
-#define CM_REDRAW                       511
-#define CM_ZOOM25                       512
-#define CM_ZOOM50                       513
-#define CM_ZOOM100                      514
-#define CM_ZOOM200                      515
-#define CM_ZOOM400                      516
-#define CM_PRINT                        517
-#define CM_EXPORT                       518
-#define CM_DELOBJ                       519
-#define CM_REBOOT                       520
-#define CM_SHUTDOWN                     521
-#define CM_DEFAULTS                     522
-#define CM_COPY                         523
-#define CM_PASTE                        524
-#define CM_UPDATE                       525
-#define CM_ADDAXIS                      526
-#define CM_UNDO                         527
-#define CM_ZOOMIN                       528
-#define CM_ZOOMOUT                      529
-#define CM_ZOOMFIT                      530
-#define CM_FILE1                        531
-#define CM_FILE2                        532
-#define CM_FILE3                        533
-#define CM_FILE4                        534
-#define CM_FILE5                        535
-#define CM_FILE6                        536
-#define CM_FILLRANGE                    537
-#define CM_CUT                          538
-#define CM_LEGEND                       539
-#define CM_LAYERS                       540
-#define CM_T_STANDARD                   550
-#define CM_T_DRAW                       551
-#define CM_T_POLYLINE                   552
-#define CM_T_POLYGON                    553
-#define CM_T_RECTANGLE                  554
-#define CM_T_ROUNDREC                   555
-#define CM_T_ELLIPSE                    556
-#define CM_T_ARROW                      557
-#define CM_T_TEXT                       558
-#define CM_DELKEY                       600
-#define CM_LEFTARRKEY                   601
-#define CM_RIGHTARRKEY                  602
-#define CM_UPARRKEY                     603
-#define CM_DOWNARRKEY                   604
-#define CM_TAB                          605
-#define CM_SHTAB                        606
-#define CM_PGUP                         607
-#define CM_PGDOWN                       608
-#define CM_POS_FIRST                    609
-#define CM_POS_LAST                     610
-#define CM_SHLEFT                       611
-#define CM_SHRIGHT                      612
-#define CM_SHUP                         613
-#define CM_SHDOWN                       614
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NO_MFC                     1
-#define _APS_NEXT_RESOURCE_VALUE        103
-#define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1000
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
diff --git a/rlp_math.cpp b/rlp_math.cpp
index 7428003..9c16f60 100755
--- a/rlp_math.cpp
+++ b/rlp_math.cpp
@@ -1,4 +1,4 @@
-//rlp_math.cpp, Copyright (c) 2004, 2005 R.Lackner
+//rlp_math.cpp, Copyright (c) 2004-2006 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -19,11 +19,17 @@
 #include "rlplot.h"
 #include <math.h>
 #include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
 
 #define SWAP(a,b) {double temp=(a);(a)=(b);(b)=temp;}
 #define _PREC 1.0e-12
 
+extern Default defs;
+
 static char *MRQ_error = 0L;
+static double sqrt2pi = sqrt(_PI*2.0);
 
 //---------------------------------------------------------------------------
 //utilitity functions for memory allocation
@@ -347,27 +353,64 @@ void spline(lfPOINT *v, int n, double *y2)
 }
 
 //---------------------------------------------------------------------------
-// Special Functions
-// Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989), 
-//    Numerical Rcipies in C. The Art of Scientific Computing, 
-//    Cambridge University Press, ISBN 0-521-35465, pp. 166 ff.
-
 // The Gamma Function: return the ln(G(xx)) for xx > 0
-double gammln(double xx)
+// Ref: B.W. Brown, J. Lovato, K. Russel (1994)
+//    DCDFLIB.C, Library of C Routinesfor Cumulative Distribution Functions,
+//    Inverses, and other Parameters.
+
+double devlpl(double a[], int n, double x)
 {
-	double x, tmp, ser;
-	static double cof[6] = {76.18009173, -86.50532033, 24.01409822,
-		-1.231739516, 0.120858003e-2, -0.536382e-5};
-	int j;
-	
-	if(xx < 0.0) return 0.0;
-	x = xx-1;		tmp = x + 5.5;		tmp -= (x + 0.5)*log(tmp);
-	for (j = 0, ser = 1.0; j <= 5; j++) {
-		x += 1.0;	ser += cof[j]/x;
+	double term;
+	int i;
+
+	for(term = a[n-1], i= n-2; i>=0; i--) term = a[i] + term * x;
+	return term;
+}
+
+
+double gammln(double x)
+{
+	static double coef[] = {0.83333333333333023564e-1,-0.27777777768818808e-2, 
+	0.79365006754279e-3, -0.594997310889e-3, 0.8065880899e-3};
+static double scoefd[] = {0.62003838007126989331e2, 0.9822521104713994894e1,
+	-0.8906016659497461257e1, 0.1000000000000000000e1};
+static double scoefn[] = {0.62003838007127258804e2, 0.36036772530024836321e2,
+	0.20782472531792126786e2, 0.6338067999387272343e1,0.215994312846059073e1,
+	0.3980671310203570498e0, 0.1093115956710439502e0,0.92381945590275995e-2,
+	0.29737866448101651e-2};
+	double offset, prod, xx;
+	int i,n;
+
+    if(x < 6.0) {
+		prod = 1.0e0;	    xx = x;
+		while(xx > 3.0) {
+			xx -= 1.0;			prod *= xx;
+			}
+		if(x <= 2.0) while(xx < 2.0) {
+			prod /= xx;			xx += 1.0;
+			}
+		// compute rational approximation to gamma(x)
+		return log(devlpl(scoefn, 9, xx-2.0) / devlpl(scoefd, 4, xx-2.0) * prod);
+		}
+	else {
+		offset = 0.91893853320467274178;	// hln2pi
+		// if necessary make x at least 12 and carry correction in offset
+		if(n = 13.0 >= x ? (int)(12.0 - x) : 0) xx = x;
+		else {
+			for(i=1, prod = 1.0; i<= n; i++) prod *= (x+(double)(i-1));
+			offset -= log(prod);			xx = x+(double)n;
+			}
+		// compute power series
+		return devlpl(coef, 5, 1.0/(xx*xx)) / xx + (offset+(xx-0.5)*log(xx)-xx);
 		}
-	return -tmp + log(2.50662827465*ser);
 }
 
+//---------------------------------------------------------------------------
+// Special Functions
+// Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989), 
+//    Numerical Rcipies in C. The Art of Scientific Computing, 
+//    Cambridge University Press, ISBN 0-521-35465, pp. 166 ff.
+
 //The Factorial Function: return n!
 double factrl(int n)
 {
@@ -496,6 +539,11 @@ double betai(double a, double b, double x)
 	else return 1.0 - bt * betacf(b, a, 1.0 - x)/b;
 }
 
+//The following relations are obviously based on:
+//  Abramowitz, M. & Stegun I.A. (1964): Hanbook of Mathematical Functions.
+//    Applied Mathematics Series, vol. 55 (Washington: National Bureau
+//    of Standards).
+
 //the binomial coefficient
 double bincof(double n, double k)
 {
@@ -525,14 +573,8 @@ double errf(double x)
 //the complementary error function
 double  errfc(double x)
 {
-	double t, z, ans;
-
-	z = fabs(x);
-	t = 1.0/(1.0+0.5*z);
-	ans = t * exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418+
-		t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+
-		t*(-0.82215223+t*0.17087277)))))))));
-	return x >= 0.0 ? ans : 2.0-ans;
+//	return x < 0.0 ? 2.0 - gammq(0.5, x*x) : gammq(0.5, x*x);
+	return x < 0.0 ? 1.0 + gammp(0.5, x*x) : gammq(0.5, x*x);
 }
 
 //cumulative normal distribution
@@ -541,6 +583,21 @@ double norm_dist(double x, double m, double s)
 	return 0.5 + errf((x - m)/(s * _SQRT2))/2.0;
 }
 
+//normal ditribution
+double norm_freq(double x, double m, double s)
+{
+	double ex;
+
+	ex = (x-m)/s;	ex = exp(-0.5*ex*ex);
+	return ex/(s*sqrt2pi);
+}
+
+//cumulative lognormal distribution
+double lognorm_dist(double x, double m, double s)
+{
+	return 0.5 + errf((log(x) - m)/(s * _SQRT2))/2.0;
+}
+
 //chi square distribution
 double chi_dist(double x, double df, double)
 {
@@ -673,16 +730,36 @@ void d_quartile(int n, double *v, double *q1, double *q2, double *q3)
 		}
 }
 
+// statistical basics partly based on
+// Davies, J. and Gogh, B. (2000), GSL-1.7 - The GNU scientific library
+//
+//do variance
+double d_variance(int n, double *v, double *mean, double *ss)
+{
+	int i;
+	double d, m, va, e;
+
+	for(i = 0, m = 0.0, d = 1.0; i < n; i++, d += 1.0) {
+		m += (v[i] - m)/d;
+		}
+	if (mean) *mean = m;
+	for(i = 0, va = 0.0, d = 1.0; i < n; i++, d += 1.0) {
+		e = v[i] - m;		va += (e * e - va)/d;
+		}
+	if (ss) *ss = va * (double)n;
+	return va * ((double)n/((double)(n-1)));
+}
+
 //do arithmethic mean
 double d_amean(int n, double *v)
 {
 	int i;
-	double sum;
+	double d, mean;
 
-	for(i = 0, sum = 0.0; i < n; i++) {
-		sum += (v[i]);
+	for(i = 0, mean = 0.0, d = 1.0; i < n; i++, d += 1.0) {
+		mean += (v[i] - mean)/d;
 		}
-	return (sum/n);
+	return mean;
 }
 
 
@@ -713,36 +790,88 @@ double d_hmean(int n, double *v)
 	return (n/sum);
 }
 
+//kurtosis
+double d_kurt(int n, double *v)
+{
+	double sum, avg, sd, tmp, dn = n;
+	int i;
+
+	for(i = 0, sum = 0.0; i < n; i++) sum += v[i];
+	for(i = 0, avg = sum/dn, 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*tmp);
+	sum *= ((dn*(dn+1.0))/((dn-1.0)*(dn-2.0)*(dn-3.0)));
+	tmp = (3.0 * (dn-1.0) * (dn-1.0))/((dn-2.0)*(dn-3.0));
+	return sum - tmp;
+}
+
+//skewness
+double d_skew(int n, double *v)
+{
+	double sum, avg, sd, tmp, dn = n;
+	int i;
+
+	for(i = 0, sum = 0.0; i < n; i++) sum += v[i];
+	for(i = 0, avg = sum/dn, 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);
+	return sum * dn/((dn-1.0)*(dn-2.0));
+}
+
+//---------------------------------------------------------------------------
+// Create a frequency distribution by counting the elements which may be 
+// assigned to a bin
+double d_classes(DataObj *d, double start, double step, double *v, int nv, char *range)
+{
+	int i, j, r, c, nc, *f;
+	AccRange *ar;
+
+	if(!range || !nv || !v || step <= 0.0 || !(ar = new AccRange(range))) return 0.0;
+	if(!(nc = ar->CountItems()) || !ar->GetFirst(&c, &r) || !(f=(int*)calloc(nc, sizeof(int)))) {
+		delete ar;				return 0.0;
+		}
+	for(i = 0; i < nv; i++) {
+		j = (int)(floor((v[i] - start)/step));
+		if(j < 0) j = 0;		if(j >= nc) j = (nc-1);
+		f[j]++;
+		}
+	for( ; nc > 0 && !(f[nc-1]); nc--);
+	for(i = 0; ar->GetNext(&c, &r) && i < nc; i++) {
+		d->SetValue(r, c, (double)f[i]);
+		}
+	free(f);					return ((double)nv);
+}
+
 //---------------------------------------------------------------------------
 // Pearsons linear correlation
-// Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989), 
+// (1) W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989), 
 //    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)
 {
 	int j, r, c;
-	double yt, xt, t, df, res[3];
+	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];			ay += y[j];
+		ax += (x[j] - ax) / (j+1);			ay += (y[j] - ay) / (j+1);
 		}
-	ax /= n;			ay /= n;
 	for(j = 0; j < n; j++) {				// correlation
-		xt = x[j] - ax;		yt = y[j] - ay;
-		sxx += xt*xt;		syy += yt*yt;		sxy += xt * yt;
+		xt = x[j] - ax;						yt = y[j] - ay;
+		sxx += (xt*xt-sxx) / (j+1);			syy += (yt*yt-syy) / (j+1);
+		sxy += (xt*yt-sxy) / (j+1);
 		}
-	res[0] = sxy/sqrt(sxx*syy);		//pearsons r
+	res[0] = sxy/sqrt(sxx*syy);				//pearsons r
 	if(dest) {
 		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
 		res[2] = betai(0.5*df, 0.5, df/(df+t*t));					//probability
+		res[3] = n;
 		}
 	if((dest) && (data) && (rD = new AccRange(dest))) {
 		rD->GetFirst(&c, &r);
-		for(j = 0; j < 3 && rD->GetNext(&c, &r); j++) {
+		for(j = 0; j < 4 && rD->GetNext(&c, &r); j++) {
 			data->SetValue(r, c, res[j]);
 			}
 		data->Command(CMD_UPDATE, 0L, 0L);
@@ -752,6 +881,26 @@ double d_pearson(double *x, double *y, int n, char *dest, DataObj *data)
 }
 
 //---------------------------------------------------------------------------
+// Given an array w, rank returns the rank of v1 in v
+// if v1 is not found in v 0 is returned
+double d_rank(int n, double *v, double v1)
+{
+	double *sv;
+	int i, j;
+
+	if(!n || !v) return 0.0;		if(n < 2) return 1.0;
+	if(!(sv = (double*)memdup(v, n * sizeof(double), 0))) return 0.0;
+	SortArray(n, sv);
+	for(i = j = 0; i < n; i++) {
+		if(v1 == sv[i]) {
+			for( ;(i+j)<n; j++) if(sv[i+j] > v1) break;
+			free(sv);				return (double)i + 1.0 + (((double)j-1.0)/2.0);
+			}
+		}
+	free(sv);						return 0.0;
+}
+
+//---------------------------------------------------------------------------
 // Spearman rank-order correlation
 // Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989), 
 //    Numerical Recipies in C. The Art of Scientific Computing, 
@@ -786,7 +935,7 @@ double d_spearman(double *x, double *y, int n, char *dest, DataObj *data)
 {
 	int j, r, c;
 	double vard, t, sg, sf, fac, en3n, en, df, aved, tmp;
-	double res[5];
+	double res[6];
 	AccRange *rD;
 
 	SortArray2(n, x, y);		crank(n, x, &sf);
@@ -804,8 +953,8 @@ double d_spearman(double *x, double *y, int n, char *dest, DataObj *data)
 	df = en-2.0;
     res[4] = betai(0.5*df, 0.5, df/(df+t*t));
 	if((dest) && (data) && (rD = new AccRange(dest))) {
-		rD->GetFirst(&c, &r);
-		for(j = 0; j < 5 && rD->GetNext(&c, &r); j++) {
+		rD->GetFirst(&c, &r);	res[5] = n;
+		for(j = 0; j < 6 && rD->GetNext(&c, &r); j++) {
 			data->SetValue(r, c, res[j]);
 			}
 		data->Command(CMD_UPDATE, 0L, 0L);
@@ -814,12 +963,52 @@ double d_spearman(double *x, double *y, int n, char *dest, DataObj *data)
 	return res[3];
 }
 
+//---------------------------------------------------------------------------
+// Kendal's non-parametric correlation
+// Ref.: W.H. Press, B.P. Flannery, S.A. Teukolsky, W.T. Vetterling (1989), 
+//    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)
+{
+	int j, k, n1, n2, is, r, c;
+	double aa, a1, a2, sv, res[4];
+	AccRange *rD;
+
+	for (j = n1 = n2 = is = 0; j < (n-1); j++) {
+		for(k = j+1; k < n; k++) {
+			a1 = x[j] - x[k];		a2 = y[j] - y[k];		aa = a1*a2;
+			if(aa != 0.0) {
+				n1++;				n2++;
+				if (aa > 0.0) is++;
+				else is--;
+				}
+			else {
+				if(a1 != 0.0) n1++;	if(a2 != 0.0) n2++;
+				}
+			}
+		}
+	res[0] = ((double)is)/(sqrt((double)n1) * sqrt((double)n2));
+	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);
+		for(j = 0; j < 4 && rD->GetNext(&c, &r); j++) {
+			data->SetValue(r, c, res[j]);
+			}
+		data->Command(CMD_UPDATE, 0L, 0L);
+		delete rD;
+		}
+	return res[0];
+}
+
+
 //linear regression
 double d_regression(double *x, double *y, int n, char *dest, DataObj *data)
 {
-	double sx, sy, dx, dy, sxy, sxx, syy, sdy;
+	double sx, sy, dx, dy, sxy, sxx, syy, sdy, df;
 	double res[10];		// slope, intercept, mean x, mean y, SE of slope, 
-						//   variance(x), variance(y), variance(fit), F of regression 
+						//   variance(x), variance(y), variance(fit), F of regression, significance
 	int i, j, r, c;
 	AccRange *rD;
 
@@ -838,12 +1027,13 @@ double d_regression(double *x, double *y, int n, char *dest, DataObj *data)
 		dy = y[i] - (res[1] + x[i] *res[0]);
 		sdy += (dy * dy);
 		}
-	sdy = sdy/(n-2);		res[4] = sqrt(sdy/sxx);
+	sdy = sdy/(n-2);		res[4] = sqrt(sdy/sxx);		df = (n-2);
 	res[5] = sxx/(n-1);		res[6] = syy/(n-1);			res[7] = sdy;
 	res[8] = sxy/sdy*sxy/sxx;
+	res[9] = betai(df/2.0, 0.5, df/(df+res[8]));
 	if((dest) && (data) && (rD = new AccRange(dest))) {
 		rD->GetFirst(&c, &r);
-		for(j = 0; j < 9 && rD->GetNext(&c, &r); j++) {
+		for(j = 0; j < 10 && rD->GetNext(&c, &r); j++) {
 			data->SetValue(r, c, res[j]);
 			}
 		data->Command(CMD_UPDATE, 0L, 0L);
@@ -852,6 +1042,65 @@ double d_regression(double *x, double *y, int n, char *dest, DataObj *data)
 	return n;
 }
 
+//covariance
+double d_covar(double *x, double *y, int n, char *dest, DataObj *data)
+{
+	int i;
+	double sx, sy, dx, dy, sxy;
+
+	if(n < 2) return 0.0;
+	for(i = 0, 	sx = sy = 0.0; i < n; i++) {
+		sx += x[i];			sy += y[i];
+		}
+	sx /= n;		sy /= n;		sxy = 0.0;
+	for(i = 0; i < n; i++) {
+		dx = x[i]-sx;		dy = y[i]-sy;
+		sxy += (dx*dy - sxy) / (i+1);
+		}
+	return sxy;
+}
+
+//Mann-Whitney U Test
+double d_utest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
+{
+	double *da, *ta, u1, u2, su, tmp;
+	double res[7];
+	AccRange *rD;
+	int i, j, n, r, c;
+
+	if(!x || !y || n1 < 2 || n2 < 2) return 0.0;
+	da = (double*)malloc((n = (n1+n2)) * sizeof(double));
+	ta = (double*)malloc(n * sizeof(double));
+	if(!da || !ta) {
+		if(da) free(da);	if(ta) free(ta); return 0.0;
+		}
+	for(i = 0; i < n1; i++) {
+		da[i] = x[i];		ta[i] = 1.0;
+		}
+	for(j = 0; j < n2; j++) {
+		da[i] = y[j];		ta[i++] = 2.0;
+		}
+	SortArray2(n, da, ta);	crank(n, da, &tmp);
+	for(i = 0, res[0] = res[1] = 0.0; i < n; i++) {
+		if(ta[i] == 1.0) res[0] += da[i];
+		else res[1] += da[i];
+		}
+	free(da);									free(ta);
+	u1 = (n1*n2 + (n1*(n1+1))/2.0) - res[0];	u2 = (n1*n2 + ((n2+1)*n2)/2.0) - res[1];
+	su = sqrt((n1*n2*(n1+n2+1))/12.0);			res[2] = u2 > u1 ? u2 : u1;
+	res[3] = (res[2] - (n1*n2)/2.0)/su;			res[6] = errfc(res[3]/_SQRT2);
+	if((dest) && (data) && (rD = new AccRange(dest))) {
+		res[4] = n1;							res[5] = n2;
+		rD->GetFirst(&c, &r);
+		for(i = 0; i < 7 && rD->GetNext(&c, &r); i++) {
+			data->SetValue(r, c, res[i]);
+			}
+		data->Command(CMD_UPDATE, 0L, 0L);
+		delete rD;
+		}
+	return res[6];
+}
+
 //t-test
 double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 {
@@ -860,17 +1109,19 @@ double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 	double res[9];			// mean1, SD1, n1, mean2, SD2, n2, p if variances equal,
 	AccRange *rD;			//    corrected df, corrected p
 
-	for(i=0, sx = 0.0; i < n1; sx += x[i], i++);				mx = sx/n1;
-	for(i=0, sy = 0.0; i < n2; sy += y[i], i++);				my = sy/n2;
-	for(i=0, sx = 0.0; i < n1; sx += ((d=(x[i]-mx))*d), i++);
-	for(i=0, sy = 0.0; i < n2; sy += ((d=(y[i]-my))*d), i++);
-    d = ((sx+sy)/(n1+n2-2)) * ((double)(n1+n2)/(double)(n1*n2));
-	d = (mx-my)/sqrt(d);										//Student's t
+	d_variance(n1, x, &mx, &sx);		d_variance(n2, y, &my, &sy);
+	d = ((sx+sy)/(n1+n2-2)) * ((double)(n1+n2)/(double)(n1*n2));
+	d = (mx-my)/sqrt(d);	//Student's t
 
 	//Welch's correction for differences in variance
 	df = (sx/(double)n1)*(sx/(double)n1)/(double)(n1+1)+(sy/(double)n2)*(sy/(double)n2)/(double)(n2+1);
 	df = (sx/(double)n1+sy/(double)n2)*(sx/(double)n1+sy/(double)n2)/df;
 	df -= 2.0;
+
+//	an alternative formula for correction
+//	p = (sx/(double)n1)*(sx/(double)n1)/(double)(n1-1) + (sy/(double)n2)*(sy/(double)n2)/(double)(n2-1);
+//	df = (sx/(double)n1 + sy/(double)n2) * (sx/(double)n1 + sy/(double)n2) / p;
+
 	p = betai(df/2.0, 0.5, (df/(df+d*d)));
 	if((dest) && (data) && (rD = new AccRange(dest))) {
 		res[0] = mx;	res[1] = sqrt(sx/(double)(n1-1));	res[2] = n1;
@@ -887,6 +1138,33 @@ double d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 	return p;
 }
 
+//t-test for paired samples
+double d_ttest2(double *x, double *y, int n, char *dest, DataObj *data)
+{
+	double sx, sy, mx, my, df, cov, sd, t, p;
+	int i, r, c;
+	double res[6];			// mean1, SD1, mean2, SD2, n, p 
+	AccRange *rD;
+
+	d_variance(n, x, &mx, &sx);		d_variance(n, y, &my, &sy);
+	sx = d_variance(n, x, &mx);		sy = d_variance(n, y, &my);
+	cov = d_covar(x, y, n, 0L, 0L) * ((double)n/(double)(n-1));
+	sd = sqrt((sx+sy-2*cov)/n);
+	t = (mx-my)/sd;					df = (n-1);
+	p = betai(0.5*df, 0.5, df/(df+t*t));
+	if((dest) && (data) && (rD = new AccRange(dest))) {
+		res[0] = mx;	res[1] = sqrt(sx);	res[5] = p;
+		res[2] = my;	res[3] = sqrt(sy);	res[4] = n;
+		rD->GetFirst(&c, &r);
+		for(i = 0; i < 6 && rD->GetNext(&c, &r); i++) {
+			data->SetValue(r, c, res[i]);
+			}
+		data->Command(CMD_UPDATE, 0L, 0L);
+		delete rD;
+		}
+	return p;
+}
+
 //f-test
 double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 {
@@ -899,8 +1177,14 @@ double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 	for(i=0, sy = 0.0; i < n2; sy += y[i], i++);				my = sy/n2;
 	for(i=0, sx = 0.0; i < n1; sx += ((d=(x[i]-mx))*d), i++);	sx /= (n1-1);
 	for(i=0, sy = 0.0; i < n2; sy += ((d=(y[i]-my))*d), i++);	sy /= (n2-1);
-	d = sx/sy;		df1 = n1-1;		df2 = n2-1;
-	p= 2.0 * betai(df2/2.0, df1/2.0, df2/(df2+df1*d));
+	if(sx > sy) {
+		d = sx/sy;		df1 = n1-1;		df2 = n2-1;
+		}
+	else {
+		d = sy/sx;		df1 = n2-1;		df2 = n1-1;
+		}
+	p = 2.0 * betai(df2/2.0, df1/2.0, df2/(df2+df1*d));
+	if(p > 1.0) p = 2.0-p;
 	if((dest) && (data) && (rD = new AccRange(dest))) {
 		res[0] = mx;	res[1] = sqrt(sx);	res[2] = n1;
 		res[3] = my;	res[4] = sqrt(sy);	res[5] = n2;
@@ -913,3 +1197,344 @@ double d_ftest(double *x, double *y, int n1, int n2, char *dest, DataObj *data)
 		}
 	return p;
 }
+
+//---------------------------------------------------------------------------
+// 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
+//
+//    Y   four digits year               y    two digits year
+//    X   month's full name              x    three character month name
+//    Z   two digits day of month        z    same as Z but no leading zero
+//    V   two digit month number         v    number of month
+//    W   single letter month
+//    D   full name of day               d    three characters for day name
+//    E   two digits weekday             e    one or two digits weekday
+//    F   single character day name
+//    H   two digits for hours           h    hours with no leading zero
+//    M   two digits for minutes         m    minutes with no leading zero
+//    S   two digits for seconds         s    seconds with no leading zero
+//    T   two digits seconds, two dec.   t    same as T but no leading zero
+//    U   full precision seconds
+
+static char *dt_month[] = {"January", "February", "March", "April", "May", "June",
+	"July", "August", "September", "October", "November", "December"};
+
+static char *dt_months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
+	"Sep", "Oct", "Nov", "Dec"};
+
+static int dt_monthl[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+static char *dt_day[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
+	"Friday", "Saturday"};
+
+static char *dt_days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+
+typedef struct rlp_datetime {
+	int aday, year, doy, month, dom, dow, hours, minutes;
+	double seconds;
+}rlp_datetime;
+
+static bool leapyear(int year) {
+	return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
+}
+
+static int year2aday(int y)
+{
+	int aday, y1;
+
+	y1 = y - 1900;
+	aday = y1 * 365;
+	aday += ((y1-1) >> 2 );
+	aday -= (y1 / 100);
+	aday += ((y/400)-4);
+	return aday;
+}
+
+static void set_dow(rlp_datetime *dt)
+{
+	dt->dow = (dt->aday %7)+1;
+}
+
+static int parse_date (rlp_datetime *dt, char *src, char *fmt)
+{
+	int i, j, k;
+	char tmp_str[10];
+
+	if(!src || !src[0] || !fmt || !fmt[0]) return 0;
+	if(*src == '\'') src++;
+	for(i = j = 0; fmt[i] && src[j]; i++) {
+		switch (fmt[i]) {
+		case 'Y':		case 'y':			// year is numeric
+			if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
+			if(sscanf(src+j, "%d", &dt->year)) {
+				if(dt->year < 0) return 0;
+				while(isdigit(src[j])) j++;
+				if(dt->year<60) dt->year += 2000;
+				else if(dt->year <99) dt->year += 1900;
+				}
+			else return 0;
+			break;
+		case 'X':		case 'x':			// month can be text
+			if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
+			tmp_str[0] = toupper(src[j]);
+			tmp_str[1] = tolower(src[j+1]);
+			tmp_str[2] = tolower(src[j+2]);
+			tmp_str[3] = 0;
+			for(k = dt->month = 0; k < 12; k++) {
+				if(0 == strcmp(tmp_str,dt_months[k])) {
+					dt->month = k+1;			break;
+					}
+				}
+			if(dt->month) while(isalpha(src[j])) j++;
+			else return 0;
+			break;
+		case 'V':		case 'v':			//    or numeric
+			if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
+			if(sscanf(src+j, "%d", &dt->month)) {
+				if(dt->month <= 0 || dt->month > 12) return 0;
+				j++;				if(isdigit(src[j])) j++;
+				}
+			else return 0;
+			break;
+		case 'Z':		case 'z':			// day of month is numeric
+			if(j && src[j] == '-' || src[j] == '/' || src[j] == '.') j++;
+			if(sscanf(src+j, "%d", &dt->dom)) {
+				if(dt->dom <= 0 || dt->dom > 31) return 0;
+				j++;				if(isdigit(src[j])) j++;
+				}
+			else return 0;
+			break;
+		case 'H':		case 'h':			// hours are numeric
+			if(sscanf(src+j, "%2d", &dt->hours)) {
+				if(dt->hours < 0 || dt->hours > 23) return 0;
+				j++;				if(isdigit(src[j])) j++;
+				}
+			else return 0;
+			break;
+		case 'M':		case 'm':			// minutes are numeric
+			if(j && src[j] == ' ' || src[j] == ':') j++;
+			if(sscanf(src+j, "%2d", &dt->minutes)) {
+				if(dt->minutes < 0 || dt->minutes >= 60) return 0;
+				j++;				if(isdigit(src[j])) j++;
+				}
+			else return 0;
+			break;
+		case 'S':		case 's':			// seconds are numeric
+		case 'T':		case 't':
+			if(j && src[j] == ' ' || src[j] == ':') j++;
+			if(sscanf(src+j, "%lf", &dt->seconds)) {
+				if(dt->seconds < 0.0 || dt->seconds >= 60.0) return 0;
+				while(isdigit(src[j]) || src[j] == '.') j++;
+				}
+			else return 0;
+			dt->seconds += 1.0e-12;
+			break;
+		default:
+			if(fmt[i] && fmt[i] == src[j]) j++;
+			}
+		}
+	if(dt->year && dt->month && dt->dom) {
+		for(dt->doy = 0, i = dt->month-2; i >= 0; i--) {
+			if(i == 1) dt->doy += leapyear(dt->year) ? 29 : 28;
+			else dt->doy += dt_monthl[i]; 
+			}
+		dt->doy += dt->dom;
+		if(dt->year >= 1900) dt->aday = year2aday(dt->year);
+		dt->aday += dt->doy;
+		}
+	return j;
+}
+
+static char *date2text(rlp_datetime *dt, char *fmt)
+{
+	static char res[80];
+	int i, pos;
+	double secs;
+
+	res[0] = 0;
+	if(!fmt || !fmt[0] || !dt) return res;
+	set_dow(dt);
+	secs = dt->seconds;
+	if (secs > 59.4999) secs = 59.4999;
+	for(pos = i = 0; fmt[i] && pos < 70; i++) {
+		switch(fmt[i]) {
+		case 'Y':
+			if(dt->year) pos+=sprintf(res+pos, "%4d", dt->year);
+			else pos += sprintf(res+pos, "####");		break;
+		case 'y':
+			if(dt->year) pos+=sprintf(res+pos, "%02d", (dt->year %100));
+			else pos += sprintf(res+pos, "##");			break;
+		case 'Z':
+			if(dt->dom) pos+=sprintf(res+pos, "%02d", dt->dom);
+			else pos += sprintf(res+pos, "##");			break;
+		case 'z':
+			if(dt->dom) pos+=sprintf(res+pos, "%d", dt->dom);
+			else pos += sprintf(res+pos, "##");			break;
+		case 'X':
+			if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%s", dt_month[dt->month-1]);
+			else pos += sprintf(res+pos, "###");		break;
+		case 'x':
+			if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%s", dt_months[dt->month-1]);
+			else pos += sprintf(res+pos, "###");		break;
+		case 'V':
+			if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%02d", dt->month);
+			else pos += sprintf(res+pos, "##");			break;
+		case 'v':
+			if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%d", dt->month);
+			else pos += sprintf(res+pos, "##");			break;
+		case 'W':
+			if(dt->month >0 && dt->month < 13) pos+=sprintf(res+pos, "%c", dt_month[dt->month-1][0]);
+			else pos += sprintf(res+pos, "#");			break;
+		case 'D':
+			if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%s", dt_day[dt->dow-1]);
+			else pos += sprintf(res+pos, "###");		break;
+		case 'd':
+			if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%s", dt_days[dt->dow-1]);
+			else pos += sprintf(res+pos, "###");		break;
+		case 'E':
+			if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%02d", dt->dow);
+			else pos += sprintf(res+pos, "##");			break;
+		case 'e':
+			if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%d", dt->dow);
+			else pos += sprintf(res+pos, "##");			break;
+		case 'F':
+			if(dt->dow >0 && dt->dow < 8) pos+=sprintf(res+pos, "%c", dt_day[dt->dow-1][0]);
+			else pos += sprintf(res+pos, "#");			break;
+		case 'H':
+			if(dt->hours >=0 && dt->hours < 24) pos+=sprintf(res+pos, "%02d", dt->hours);
+			else pos += sprintf(res+pos, "##");			break;
+		case 'h':
+			if(dt->hours >=0 && dt->hours < 24) pos+=sprintf(res+pos, "%d", dt->hours);
+			else pos += sprintf(res+pos, "##");			break;
+		case 'M':
+			if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf(res+pos, "%02d", dt->minutes);
+			else pos += sprintf(res+pos, "##");			break;
+		case 'm':
+			if(dt->minutes >=0 && dt->minutes < 60) pos+=sprintf(res+pos, "%d", dt->minutes);
+			else pos += sprintf(res+pos, "##");			break;
+		case 'S':
+			if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%02d", iround(secs));
+			else pos += sprintf(res+pos, "##");			break;
+		case 's':
+			if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%d", iround(secs));
+			else pos += sprintf(res+pos, "##");			break;
+		case 'T':
+			if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%02.2lf", dt->seconds);
+			else pos += sprintf(res+pos, "##.##");		break;
+		case 't':
+			if(dt->seconds >=0.0 && dt->seconds < 60.0) pos+=sprintf(res+pos, "%.2lf", dt->seconds);
+			else pos += sprintf(res+pos, "##.##");		break;
+		default:
+			pos += sprintf(res+pos, "%c", fmt[i]);		break;
+			}
+		}
+	res[pos] = 0;
+	return res;
+}
+
+static double date2value(rlp_datetime *dt)
+{
+	double res;
+
+	if(!dt) return 0.0;
+
+	res = dt->seconds/60.0 + (double)dt->minutes;
+	res = res/60.0 + (double)dt->hours;
+	res = res/24.0 + (double)dt->aday;
+	return res;
+}
+
+static void parse_datevalue(rlp_datetime *dt, double dv)
+{
+	int i, j, d;
+
+	if(!dt || dv < 0.0) return;
+	if(dv > 1.0) {
+		dt->aday = (int)floor(dv);
+		dt->year = (int)(dv/365.2425);
+		d = (int)floor(dv);
+		do {
+			dt->doy = d - 365*dt->year;
+			dt->doy -= ((dt->year-1)>>2);
+			dt->doy += ((dt->year)/100);
+			dt->doy -= ((dt->year+300)/400);
+			if(dt->doy < 1) dt->year--;
+			}while(dt->doy < 1);
+		dt->year += 1900;
+		for(i = dt->month = 0, d = dt->doy; i < 12 && d > 0; i++) {
+			if(i == 1 && d > (j = (leapyear(dt->year)) ? 29 : 28)) d -= j;
+			else if(i != 1 && d > dt_monthl[i]) d -= dt_monthl[i];
+			else break;
+			}
+		dt->month = i+1;				dt->dom = d;
+		}
+	dv -= floor(dv);				dv *= 24.0;
+	dt->hours = (int)floor(dv);		dv -= floor(dv);
+	dv *= 60.0;						dt->minutes = (int)floor(dv); 
+	dv -= floor(dv);				dt->seconds = dv *60.0 + 1.0e-12; 
+	if(dt->seconds > 59.9999) {
+		dt->seconds = 0.0;			dt->minutes++;
+		if(dt->minutes == 60) {
+			dt->hours++;			dt->minutes = 0;
+			}
+		}
+}
+
+static char *dt_popfmt[] = {"Z.V.Y H:M:S", "Z/V/Y H:M:S", "Z-V-Y H:M:S", "Z.X.Y H:M:S",
+	"Y.V.Z H:M:S", "Y-X-Z H:M:S", "H:M:S", 0L};
+
+bool date_value(char *desc, char *fmt, double *value)
+{
+	int i;
+	rlp_datetime dt;
+
+	dt.year = dt.aday = dt.doy = dt.month = dt.dom = dt.dow = dt.hours = dt.minutes = 0;
+	dt.seconds = 0.0;
+	if(!value || !desc || !desc[0]) return false;
+	if(fmt && fmt[0]) {
+		if(parse_date(&dt, desc, fmt)) {
+			*value = date2value(&dt);	return true;
+			}
+		}
+	else {
+		if(parse_date(&dt, desc, defs.fmt_datetime)) {
+			*value = date2value(&dt);	return true;
+			}
+		}
+	for(i=0; dt_popfmt[i]; i++) {
+		if(parse_date(&dt, desc, dt_popfmt[i])) {
+			*value = date2value(&dt);	return true;
+			}
+		}
+	return false;
+}
+
+char *value_date(double dv, char *fmt)
+{
+	rlp_datetime dt;
+
+	parse_datevalue(&dt, dv);
+	return date2text(&dt, fmt ? fmt : defs.fmt_date);
+}
+
+double now_today()
+{
+	double res = 0.0;
+	time_t ti = time(0L);
+
+	date_value(ctime(&ti)+4, "x z H:M:S Y", &res);
+	return res;
+}
+
+void split_date(double dv, int *y, int *mo, int *dom, int *dow, int *doy, int *h, int *m, double *s)
+{
+	rlp_datetime dt;
+
+	parse_datevalue(&dt, dv);
+	set_dow(&dt);
+	if(y) *y = dt.year;				if(mo) *mo = dt.month;
+	if(dom) *dom = dt.dom;			if(dow) *dow = dt.dow;
+	if(doy) *doy = dt.doy;			if(h) *h = dt.hours;
+	if(m) *m = dt.minutes;			if(s) *s = dt.seconds;
+}
diff --git a/rlplot.cpp b/rlplot.cpp
index 0c1fdd5..6856d42 100755
--- a/rlplot.cpp
+++ b/rlplot.cpp
@@ -1,4 +1,4 @@
-//RLPlot.cpp, Copyright 2000, 2001, 2002, 2003, 2004, 2005 R.Lackner
+//RLPlot.cpp, Copyright 2000-2006 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -91,7 +91,7 @@ GraphObj::Track(POINT *p, anyOutput *o)
 // Spread sheet buttons used for rows and columns
 ssButton::ssButton(GraphObj *par, int x, int y, int w, int h):GraphObj(par, 0L)
 {
-	bLBdown = false;
+	bLBdown = bSelected = bMarked = false;
 	SetMinMaxRect(&rDims, x, y, x+w, y+h);
 	Line.width = 0.0f;				Line.patlength = 1.0f;
 	Line.color = 0x00000000L;		Line.pattern = 0x00000000L;
@@ -102,7 +102,6 @@ ssButton::ssButton(GraphObj *par, int x, int y, int w, int h):GraphObj(par, 0L)
 	TextDef.iSize = 0;				TextDef.Align = TXA_HLEFT | TXA_VTOP;
 	TextDef.Mode = TXM_TRANSPARENT;	TextDef.Style = TXS_NORMAL;
 	TextDef.Font = FONT_HELVETICA;	TextDef.text = 0L;
-	bSelected = false;
 }
 
 ssButton::~ssButton()
@@ -115,7 +114,13 @@ ssButton::DoPlot(anyOutput *o)
 {
 	POINT pts[3];
 
-	Line.color = 0x00000000L;		Fill.color = bSelected ? 0x00ffffff : 0x00e8e8e8L;
+	Line.color = 0x00000000L;
+	if(bSelected) {
+		Fill.color = bMarked ? 0x00ffffe0L : 0x00ffffffL;
+		}
+	else {
+		Fill.color = bMarked ? 0x00ffe0e0L : 0x00e8e8e8L;
+		}
 	o->SetLine(&Line);				o->SetFill(&Fill);
 	if(bLBdown){
 		o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
@@ -167,7 +172,17 @@ ssButton::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_SELECT:
 		if(tmpl && *((int*)tmpl)) bSelected = true;
 		else bSelected = false;
-		if(o) DoPlot(o);
+		if(o) {
+			DoPlot(o);
+			o->UpdateRect(&rDims, false);
+			}
+		return true;
+	case CMD_SETSTYLE:
+		if(tmpl && *((int*)tmpl)) bMarked = true;
+		else bMarked = false;
+		if(o) {
+			DoPlot(o);		o->UpdateRect(&rDims, false);
+			}
 		return true;
 	case CMD_SETTEXT:
 		if(TextDef.text) free(TextDef.text);
@@ -204,350 +219,399 @@ ssButton::Command(int cmd, void *tmpl, anyOutput *o)
 		}
 	return false;
 }
-
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // drag handles are graphic objects which allow the user to interactively
 //   change the size of an object
-dragHandle::dragHandle(GraphObj *par, int which):GraphObj(par, 0L)
-{
-	type = which;
-	Id = GO_DRAGHANDLE;
-	LineDef.width = LineDef.patlength = 0.0;
-	LineDef.color = LineDef.pattern = 0L;
-	FillDef.type = FILL_NONE;
-	FillDef.color = 0x00ffffffL;
-	FillDef.scale = 1.0;
-	FillDef.hatch = 0L;
-	minRC = maxRC = 0L;
-}
-
-dragHandle::~dragHandle()
-{
-	if(minRC) free(minRC);
-	if(maxRC) free(maxRC);
-	if(CurrHandle == this) CurrHandle = 0L;
-}
-
-void
-dragHandle::DoPlot(anyOutput *o)
-{
-	double fx, fy, dx, dy;
-	int ix, iy;
-	fPOINT3D fp3d, ifp3d;
-	bool is3D = false;
-
-	if(!o || !parent) return;
-	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
-	SetMinMaxRect(&drec, o->co2ix(parent->GetSize(SIZE_XPOS)+dx), 
-		o->co2iy(parent->GetSize(SIZE_YPOS)+dy), o->co2ix(parent->GetSize(SIZE_XPOS+1)+dx),
-		o->co2iy(parent->GetSize(SIZE_YPOS+1)+dy));
-	switch(type) {
-	case DH_19:		case DH_12:
-		fx = parent->GetSize(SIZE_XPOS);	fy = parent->GetSize(SIZE_YPOS);
-		break;
-	case DH_99:		case DH_22:
-		fx = parent->GetSize(SIZE_XPOS+1);	fy = parent->GetSize(SIZE_YPOS+1);
-		break;
-	case DH_29:
-		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
-		fy = parent->GetSize(SIZE_YPOS);
-		break;
-	case DH_39:
-		fx = parent->GetSize(SIZE_XPOS+1);	fy = parent->GetSize(SIZE_YPOS);
-		break;
-	case DH_49:
-		fx = parent->GetSize(SIZE_XPOS);
-		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
-		break;
-	case DH_59:
-		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
-		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
-		break;
-	case DH_69:
-		fx = parent->GetSize(SIZE_XPOS+1);
-		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
-		break;
-	case DH_79:
-		fx = parent->GetSize(SIZE_XPOS);
-		fy = parent->GetSize(SIZE_YPOS+1);
-		break;
-	case DH_89:
-		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
-		fy = parent->GetSize(SIZE_YPOS+1);
-		break;
-	case DH_18:	case DH_28:	case DH_38:	case DH_48:
-	case DH_58:	case DH_68:	case DH_78:	case DH_88:
-		fp3d.fx = parent->GetSize(SIZE_XPOS + type - DH_18);
-		fp3d.fy = parent->GetSize(SIZE_YPOS + type - DH_18);
-		fp3d.fz = parent->GetSize(SIZE_ZPOS + type - DH_18);
-		is3D = true;
-		break;
-	default:
-		if(type >= DH_DATA) {
-			fx = parent->GetSize(SIZE_XPOS + type - DH_DATA);
-			fy = parent->GetSize(SIZE_YPOS + type - DH_DATA);
-			FillDef.color = (this == CurrHandle) ? 0x0L : 0x00ffffffL;
-			}
-		else return;
-		}
-	if(is3D) {
-		o->cvec2ivec(&fp3d, &ifp3d);
-		ix = iround(ifp3d.fx);		iy = iround(ifp3d.fy);
-		}
-	else {
-		ix = o->co2ix(fx+dx);	iy = o->co2iy(fy+dy);
-		}
-	SetMinMaxRect(&rDims, ix-4, iy-4, ix+4, iy+4);
-	memcpy(&upd, &rDims, sizeof(RECT));
-	switch(type) {
-	case DH_12:	case DH_22:	case DH_19:	case DH_29:	case DH_39:
-	case DH_49:	case DH_69:	case DH_79:	case DH_89:	case DH_99:
-		o->SetLine(&LineDef);		o->SetFill(&FillDef);
-		o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
-		o->UpdateRect(&rDims, false);
-		break;
-	case DH_59:
-		o->SetLine(&LineDef);		o->SetFill(&FillDef);
-		IncrementMinMaxRect(&rDims, 2);
-		o->oCircle(rDims.left, rDims.top, rDims.right, rDims.bottom);
-		IncrementMinMaxRect(&rDims, 1);
-		o->UpdateRect(&rDims, false);
-		break;
-	default:
-		if(type >= DH_DATA) {
-			o->SetLine(&LineDef);		o->SetFill(&FillDef);
-			o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
-			o->UpdateRect(&rDims, false);
-			}
-		else {
-			IncrementMinMaxRect(&rDims, -1);
-			o->UpdateRect(&rDims, true);
-			}
-		break;
-		}
-}
-
-bool
-dragHandle::Command(int cmd, void *tmpl, anyOutput *o)
-{
-	lfPOINT pos;
-	int idx;
-
-	if(!parent) return false;
-	switch (cmd) {
-	case CMD_MOUSECURSOR:
-		if(o) switch(type) {
-		case DH_19:	case DH_99:
-			o->MouseCursor(MC_SE, false);							break;
-		case DH_29:	case DH_89:
-			o->MouseCursor(MC_NORTH, false);						break;
-		case DH_39:	case DH_79:
-			o->MouseCursor(MC_NE, false);							break;
-		case DH_49:	case DH_69:
-			o->MouseCursor(MC_EAST, false);							break;
-		default:
-			if(type >= DH_DATA) o->MouseCursor(MC_SALL, false);
-			else o->MouseCursor(MC_MOVE, false);					break;
-			}
-		return true;
-	case CMD_MINRC:
-		if(!(minRC)) minRC = (RECT*)calloc(1, sizeof(RECT));
-		if(tmpl && minRC) SetMinMaxRect(minRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
-			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
-		return true;
-	case CMD_MAXRC:
-		if(!(maxRC)) maxRC = (RECT*)calloc(1, sizeof(RECT));
-		if(tmpl && maxRC) SetMinMaxRect(maxRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
-			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
-		return true;
-	case CMD_MOVE:
-		idx = type >= DH_DATA ? type - DH_DATA : 0;
-		pos.fx = NiceValue(((lfPOINT*)tmpl)[0].fx);
-		pos.fy = NiceValue(((lfPOINT*)tmpl)[0].fy);
-		if(pos.fx == 0.0 && pos.fy == 0.0) return false;
-		parent->Command(CMD_SAVEPOS, &idx, o);
-		switch(type) {
-		case DH_12:
-			parent->SetSize(SIZE_XPOS, pos.fx + parent->GetSize(SIZE_XPOS));
-			parent->SetSize(SIZE_YPOS, pos.fy + parent->GetSize(SIZE_YPOS));
-			break;
-		case DH_22:
-			parent->SetSize(SIZE_XPOS+1, pos.fx + parent->GetSize(SIZE_XPOS+1));
-			parent->SetSize(SIZE_YPOS+1, pos.fy + parent->GetSize(SIZE_YPOS+1));
-			break;
-		case DH_19: parent->parent->SetSize(SIZE_XPOS, 
-						pos.fx + parent->GetSize(SIZE_XPOS));
-		case DH_29: parent->parent->SetSize(SIZE_YPOS,
-						pos.fy + parent->GetSize(SIZE_YPOS));
-			break;
-		case DH_39: parent->parent->SetSize(SIZE_YPOS,
-						pos.fy + parent->GetSize(SIZE_YPOS));
-		case DH_69: parent->parent->SetSize(SIZE_XPOS+1,
-						pos.fx + parent->GetSize(SIZE_XPOS+1));
-			break;
-		case DH_99: parent->parent->SetSize(SIZE_XPOS+1, 
-						pos.fx + parent->GetSize(SIZE_XPOS+1));
-		case DH_89: parent->parent->SetSize(SIZE_YPOS+1,
-						pos.fy + parent->GetSize(SIZE_YPOS+1));
-			break;
-		case DH_79: parent->parent->SetSize(SIZE_YPOS+1,
-						pos.fy + parent->GetSize(SIZE_YPOS+1));
-		case DH_49:
-			parent->parent->SetSize(SIZE_XPOS, 
-						pos.fx + parent->GetSize(SIZE_XPOS));
-			break;
-		case DH_18:	case DH_28:	case DH_38:	case DH_48:
-		case DH_58:	case DH_68:	case DH_78:	case DH_88:
-		case DH_59:
-			return parent->parent->Command(cmd, tmpl, o);
-		default:
-			if (type >= DH_DATA) {
-				parent->SetSize(SIZE_XPOS + idx, pos.fx + parent->GetSize(SIZE_XPOS + idx));
-				parent->SetSize(SIZE_YPOS + idx, pos.fy + parent->GetSize(SIZE_YPOS + idx));
-				CurrGO = parent;
-				}
-			break;
-			}
-		return parent->Command(CMD_REDRAW, 0L, o);
-		break;
-		}
-	return false;
-}
-
-void *
-dragHandle::ObjThere(int x, int y)
-{
-	if(IsInRect(&rDims, x, y)) return (CurrHandle = this);
-	else return 0L;
-}
-
-
-void
-dragHandle::Track(POINT *p, anyOutput *o)
-{
-	POINT p1, p2, pts[5];
-	double dx, dy;
-	int npts=0, idx;
-	DWORD color;
-
-	if(!parent || !o) return;
-	Command(CMD_MOUSECURSOR, 0L, o);
-	if(upd.right < upd.left) Swap(upd.right, upd.left);
-	if(upd.bottom < upd.top) Swap(upd.bottom, upd.top);
-	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
-	IncrementMinMaxRect(&upd, 2);
-	o->UpdateRect(&upd, false);
-	if(type >= DH_19 && type <= DH_99) memcpy(&upd, &drec, sizeof(RECT));
-	color = parent->GetColor(COL_DATA_LINE);
-	switch(type) {
-	case DH_12:
-	case DH_22:
-		pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS)+dx);
-		pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS)+dy);
-		pts[1].x = o->co2ix(parent->GetSize(SIZE_XPOS+1)+dx);
-		pts[1].y = o->co2iy(parent->GetSize(SIZE_YPOS+1)+dy);
-		if(type == DH_12) {
-			pts[0].x += p->x;			pts[0].y += p->y;
-			}
-		else if(type == DH_22) {
-			pts[1].x += p->x;			pts[1].y += p->y;
-			}
-		UpdateMinMaxRect(&upd, pts[0].x, pts[0].y);
-		UpdateMinMaxRect(&upd, pts[1].x, pts[1].y);
-		npts = 2;
-		break;
-	case DH_19:
-		if(minRC && IsInRect(minRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
-			upd.left = minRC->left;
-		else if(maxRC && !IsInRect(maxRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
-			upd.left = upd.left+p->x >= maxRC->right ? maxRC->right : maxRC->left;
-		else upd.left += p->x;
-	case DH_29:
-		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.top+p->y))
-			upd.top = minRC->top;
-		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.top+p->y))
-			upd.top = upd.top +p->y >= maxRC->bottom? maxRC->bottom : maxRC->top;
-		else upd.top += p->y;
-		break;
-	case DH_39:
-		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.top+p->y))
-			upd.top = minRC->top;
-		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.top+p->y))
-			upd.top = upd.top+p->y >= maxRC->bottom ? maxRC->bottom : maxRC->top;
-		else upd.top += p->y;
-	case DH_69:
-		if(minRC && IsInRect(minRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
-			upd.right = minRC->right;
-		else if(maxRC && !IsInRect(maxRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
-			upd.right = upd.right+p->x <= maxRC->left ? maxRC->left : maxRC->right;
-		else upd.right += p->x;
-		break;
-	case DH_99:
-		if(minRC && IsInRect(minRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
-			upd.right = minRC->right;
-		else if(maxRC && !IsInRect(maxRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
-			upd.right = upd.right+p->x <= maxRC->left ? maxRC->left : maxRC->right;
-		else upd.right += p->x;
-	case DH_89:
-		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
-			upd.bottom = minRC->bottom;
-		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
-			upd.bottom = upd.bottom+p->y <= maxRC->top? maxRC->top : maxRC->bottom;
-		else upd.bottom += p->y;
-		break;
-	case DH_79:
-		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
-			upd.bottom = minRC->bottom;
-		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
-			upd.bottom = upd.bottom+p->y <= maxRC->top? maxRC->top : maxRC->bottom;
-		else upd.bottom += p->y;
-	case DH_49:
-		if(minRC && IsInRect(minRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
-			upd.left = minRC->left;
-		else if(maxRC && !IsInRect(maxRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
-			upd.left = upd.left+p->x >= maxRC->right ? maxRC->right : maxRC->left;
-		else upd.left += p->x;
-		break;
-	case DH_18:	case DH_28:	case DH_38:	case DH_48:
-	case DH_58:	case DH_68:	case DH_78:	case DH_88:
-		CurrGO = this;
-	case DH_59:
-		parent->parent->Track(p, o);
-		return;
-	default:
-		if(type >= DH_DATA) {
-			idx = type - DH_DATA;
-			pts[1].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx)+dx);
-			pts[1].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx)+dy);
-			pts[1].x += p->x;				pts[1].y += p->y;
-			if(type > DH_DATA) {
-				pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx -1)+dx);
-				pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx -1)+dy);
-				}
-			else {
-				pts[0].x = pts[1].x;		pts[0].y = pts[1].y;
-				}
-			pts[2].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +1)+dx);
-			pts[2].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +1)+dy);
-			UpdateMinMaxRect(&upd, pts[0].x, pts[0].y);
-			UpdateMinMaxRect(&upd, pts[1].x, pts[1].y);
-			UpdateMinMaxRect(&upd, pts[2].x, pts[2].y);
-			npts = 3;
-			if(color == 0x0L || color == 0x00ffffffL) color = 0x00c0c0c0L;
-			}
-		else return;
-		}
-	if(type >= DH_19 && type <= DH_99) {
-		pts[0].x = pts[4].x = pts[3].x = p1.x = upd.left;	
-		pts[0].y = pts[1].y = pts[4].y = p1.y = upd.top;
-		pts[1].x = pts[2].x = p2.x = upd.right;	
-		pts[2].y = pts[3].y = p2.y = upd.bottom;
-		npts = 5;
-		if(parent->parent->Id == GO_ELLIPSE) o->ShowEllipse(p1, p2, color);
-		}
-	o->ShowLine(pts, npts, color);
-}
-
+dragHandle::dragHandle(GraphObj *par, int which):GraphObj(par, 0L)
+{
+	type = which;
+	Id = GO_DRAGHANDLE;
+	LineDef.width = LineDef.patlength = 0.0;
+	LineDef.color = LineDef.pattern = 0L;
+	FillDef.type = FILL_NONE;
+	FillDef.color = 0x00ffffffL;
+	FillDef.scale = 1.0;
+	FillDef.hatch = 0L;
+	minRC = maxRC = 0L;
+}
+
+dragHandle::~dragHandle()
+{
+	if(minRC) free(minRC);
+	if(maxRC) free(maxRC);
+	if(CurrHandle == this) CurrHandle = 0L;
+}
+
+void
+dragHandle::DoPlot(anyOutput *o)
+{
+	double fx, fy, dx, dy;
+	int ix, iy, idx;
+	fPOINT3D fp3d, ifp3d;
+	bool is3D = false;
+
+	if(!o || !parent) return;
+	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
+	SetMinMaxRect(&drec, o->co2ix(parent->GetSize(SIZE_XPOS)+dx), 
+		o->co2iy(parent->GetSize(SIZE_YPOS)+dy), o->co2ix(parent->GetSize(SIZE_XPOS+1)+dx),
+		o->co2iy(parent->GetSize(SIZE_YPOS+1)+dy));
+	switch(type) {
+	case DH_19:		case DH_12:
+		fx = parent->GetSize(SIZE_XPOS);	fy = parent->GetSize(SIZE_YPOS);
+		break;
+	case DH_99:		case DH_22:
+		fx = parent->GetSize(SIZE_XPOS+1);	fy = parent->GetSize(SIZE_YPOS+1);
+		break;
+	case DH_29:
+		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
+		fy = parent->GetSize(SIZE_YPOS);
+		break;
+	case DH_39:
+		fx = parent->GetSize(SIZE_XPOS+1);	fy = parent->GetSize(SIZE_YPOS);
+		break;
+	case DH_49:
+		fx = parent->GetSize(SIZE_XPOS);
+		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
+		break;
+	case DH_59:
+		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
+		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
+		break;
+	case DH_69:
+		fx = parent->GetSize(SIZE_XPOS+1);
+		fy = (parent->GetSize(SIZE_YPOS) + parent->GetSize(SIZE_YPOS+1))/2.0;
+		break;
+	case DH_79:
+		fx = parent->GetSize(SIZE_XPOS);
+		fy = parent->GetSize(SIZE_YPOS+1);
+		break;
+	case DH_89:
+		fx = (parent->GetSize(SIZE_XPOS) + parent->GetSize(SIZE_XPOS+1))/2.0;
+		fy = parent->GetSize(SIZE_YPOS+1);
+		break;
+	case DH_18:	case DH_28:	case DH_38:	case DH_48:
+	case DH_58:	case DH_68:	case DH_78:	case DH_88:
+		fp3d.fx = parent->GetSize(SIZE_XPOS + type - DH_18);
+		fp3d.fy = parent->GetSize(SIZE_YPOS + type - DH_18);
+		fp3d.fz = parent->GetSize(SIZE_ZPOS + type - DH_18);
+		is3D = true;
+		break;
+	default:
+		if(type >= DH_DATA) {
+			fx = parent->GetSize(SIZE_XPOS + type - DH_DATA);
+			fy = parent->GetSize(SIZE_YPOS + type - DH_DATA);
+			FillDef.color = (this == CurrHandle) ? 0x0L : 0x00ffffffL;
+			}
+		else return;
+		}
+	if(is3D) {
+		o->cvec2ivec(&fp3d, &ifp3d);
+		ix = iround(ifp3d.fx);		iy = iround(ifp3d.fy);
+		}
+	else {
+		ix = o->co2ix(fx+dx);	iy = o->co2iy(fy+dy);
+		}
+	SetMinMaxRect(&rDims, ix-4, iy-4, ix+4, iy+4);
+	memcpy(&upd, &rDims, sizeof(RECT));
+	switch(type) {
+	case DH_12:	case DH_22:	case DH_19:	case DH_29:	case DH_39:
+	case DH_49:	case DH_69:	case DH_79:	case DH_89:	case DH_99:
+		o->SetLine(&LineDef);		o->SetFill(&FillDef);
+		o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+		o->UpdateRect(&rDims, false);
+		break;
+	case DH_59:
+		o->SetLine(&LineDef);		o->SetFill(&FillDef);
+		IncrementMinMaxRect(&rDims, 2);
+		o->oCircle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+		IncrementMinMaxRect(&rDims, 1);
+		o->UpdateRect(&rDims, false);
+		break;
+	default:
+		if(type >= DH_DATA) {
+			idx = (type - DH_DATA);
+			o->SetLine(&LineDef);		o->SetFill(&FillDef);
+			if(parent->Id == GO_BEZIER && (idx %3)) {
+				IncrementMinMaxRect(&rDims, -1);
+				o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+				}
+			else if(parent->Id == GO_POLYLINE || parent->Id == GO_BEZIER) {
+				o->oCircle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+				}
+			else {
+				o->oRectangle(rDims.left, rDims.top, rDims.right, rDims.bottom);
+				}
+			o->UpdateRect(&rDims, false);
+			}
+		else {
+			IncrementMinMaxRect(&rDims, -1);
+			o->UpdateRect(&rDims, true);
+			}
+		break;
+		}
+}
+
+bool
+dragHandle::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	lfPOINT pos;
+	int idx;
+
+	if(!parent) return false;
+	switch (cmd) {
+	case CMD_MOUSECURSOR:
+		if(o) switch(type) {
+		case DH_19:	case DH_99:
+			o->MouseCursor(MC_SE, false);							break;
+		case DH_29:	case DH_89:
+			o->MouseCursor(MC_NORTH, false);						break;
+		case DH_39:	case DH_79:
+			o->MouseCursor(MC_NE, false);							break;
+		case DH_49:	case DH_69:
+			o->MouseCursor(MC_EAST, false);							break;
+		default:
+			if(type >= DH_DATA) o->MouseCursor(MC_SALL, false);
+			else o->MouseCursor(MC_MOVE, false);					break;
+			}
+		return true;
+	case CMD_MINRC:
+		if(!(minRC)) minRC = (RECT*)calloc(1, sizeof(RECT));
+		if(tmpl && minRC) SetMinMaxRect(minRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
+			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
+		return true;
+	case CMD_MAXRC:
+		if(!(maxRC)) maxRC = (RECT*)calloc(1, sizeof(RECT));
+		if(tmpl && maxRC) SetMinMaxRect(maxRC, ((RECT*)tmpl)->left, ((RECT*)tmpl)->top, 
+			((RECT*)tmpl)->right, ((RECT*)tmpl)->bottom);
+		return true;
+	case CMD_MOVE:
+		idx = type >= DH_DATA ? type - DH_DATA : 0;
+		pos.fx = NiceValue(((lfPOINT*)tmpl)[0].fx);
+		pos.fy = NiceValue(((lfPOINT*)tmpl)[0].fy);
+		if(pos.fx == 0.0 && pos.fy == 0.0) return false;
+		parent->Command(CMD_SAVEPOS, &idx, o);
+		switch(type) {
+		case DH_12:
+			parent->SetSize(SIZE_XPOS, pos.fx + parent->GetSize(SIZE_XPOS));
+			parent->SetSize(SIZE_YPOS, pos.fy + parent->GetSize(SIZE_YPOS));
+			break;
+		case DH_22:
+			parent->SetSize(SIZE_XPOS+1, pos.fx + parent->GetSize(SIZE_XPOS+1));
+			parent->SetSize(SIZE_YPOS+1, pos.fy + parent->GetSize(SIZE_YPOS+1));
+			break;
+		case DH_19: parent->parent->SetSize(SIZE_XPOS, 
+						pos.fx + parent->GetSize(SIZE_XPOS));
+		case DH_29: parent->parent->SetSize(SIZE_YPOS,
+						pos.fy + parent->GetSize(SIZE_YPOS));
+			break;
+		case DH_39: parent->parent->SetSize(SIZE_YPOS,
+						pos.fy + parent->GetSize(SIZE_YPOS));
+		case DH_69: parent->parent->SetSize(SIZE_XPOS+1,
+						pos.fx + parent->GetSize(SIZE_XPOS+1));
+			break;
+		case DH_99: parent->parent->SetSize(SIZE_XPOS+1, 
+						pos.fx + parent->GetSize(SIZE_XPOS+1));
+		case DH_89: parent->parent->SetSize(SIZE_YPOS+1,
+						pos.fy + parent->GetSize(SIZE_YPOS+1));
+			break;
+		case DH_79: parent->parent->SetSize(SIZE_YPOS+1,
+						pos.fy + parent->GetSize(SIZE_YPOS+1));
+		case DH_49:
+			parent->parent->SetSize(SIZE_XPOS, 
+						pos.fx + parent->GetSize(SIZE_XPOS));
+			break;
+		case DH_18:	case DH_28:	case DH_38:	case DH_48:
+		case DH_58:	case DH_68:	case DH_78:	case DH_88:
+		case DH_59:
+			return parent->parent->Command(cmd, tmpl, o);
+		default:
+			if (type >= DH_DATA) {
+				parent->SetSize(SIZE_XPOS + idx, pos.fx + parent->GetSize(SIZE_XPOS + idx));
+				parent->SetSize(SIZE_YPOS + idx, pos.fy + parent->GetSize(SIZE_YPOS + idx));
+				CurrGO = parent;
+				}
+			break;
+			}
+		return parent->Command(CMD_REDRAW, 0L, o);
+		break;
+		}
+	return false;
+}
+
+void *
+dragHandle::ObjThere(int x, int y)
+{
+	if(IsInRect(&rDims, x, y)) return (CurrHandle = this);
+	else return 0L;
+}
+
+
+void
+dragHandle::Track(POINT *p, anyOutput *o)
+{
+	POINT p1, p2, pts[5], bez[256];
+	double dx, dy;
+	int i, first=0, last = 0, idx;
+	long nbez;
+	DWORD color;
+
+	if(!parent || !o) return;
+	Command(CMD_MOUSECURSOR, 0L, o);
+	if(upd.right < upd.left) Swap(upd.right, upd.left);
+	if(upd.bottom < upd.top) Swap(upd.bottom, upd.top);
+	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
+	IncrementMinMaxRect(&upd, 2);
+	o->UpdateRect(&upd, false);
+	if(type >= DH_19 && type <= DH_99) memcpy(&upd, &drec, sizeof(RECT));
+	color = parent->GetColor(COL_DATA_LINE);
+	switch(type) {
+	case DH_12:
+	case DH_22:
+		pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS)+dx);
+		pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS)+dy);
+		pts[1].x = o->co2ix(parent->GetSize(SIZE_XPOS+1)+dx);
+		pts[1].y = o->co2iy(parent->GetSize(SIZE_YPOS+1)+dy);
+		if(type == DH_12) {
+			pts[0].x += p->x;			pts[0].y += p->y;
+			}
+		else if(type == DH_22) {
+			pts[1].x += p->x;			pts[1].y += p->y;
+			}
+		UpdateMinMaxRect(&upd, pts[0].x, pts[0].y);
+		UpdateMinMaxRect(&upd, pts[1].x, pts[1].y);
+		last = 2;
+		break;
+	case DH_19:
+		if(minRC && IsInRect(minRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+			upd.left = minRC->left;
+		else if(maxRC && !IsInRect(maxRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+			upd.left = upd.left+p->x >= maxRC->right ? maxRC->right : maxRC->left;
+		else upd.left += p->x;
+	case DH_29:
+		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.top+p->y))
+			upd.top = minRC->top;
+		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.top+p->y))
+			upd.top = upd.top +p->y >= maxRC->bottom? maxRC->bottom : maxRC->top;
+		else upd.top += p->y;
+		break;
+	case DH_39:
+		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.top+p->y))
+			upd.top = minRC->top;
+		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.top+p->y))
+			upd.top = upd.top+p->y >= maxRC->bottom ? maxRC->bottom : maxRC->top;
+		else upd.top += p->y;
+	case DH_69:
+		if(minRC && IsInRect(minRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+			upd.right = minRC->right;
+		else if(maxRC && !IsInRect(maxRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+			upd.right = upd.right+p->x <= maxRC->left ? maxRC->left : maxRC->right;
+		else upd.right += p->x;
+		break;
+	case DH_99:
+		if(minRC && IsInRect(minRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+			upd.right = minRC->right;
+		else if(maxRC && !IsInRect(maxRC, upd.right+p->x, (upd.top+upd.bottom)>>1))
+			upd.right = upd.right+p->x <= maxRC->left ? maxRC->left : maxRC->right;
+		else upd.right += p->x;
+	case DH_89:
+		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+			upd.bottom = minRC->bottom;
+		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+			upd.bottom = upd.bottom+p->y <= maxRC->top? maxRC->top : maxRC->bottom;
+		else upd.bottom += p->y;
+		break;
+	case DH_79:
+		if(minRC && IsInRect(minRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+			upd.bottom = minRC->bottom;
+		else if(maxRC && !IsInRect(maxRC, (upd.left + upd.right)>>1, upd.bottom+p->y))
+			upd.bottom = upd.bottom+p->y <= maxRC->top? maxRC->top : maxRC->bottom;
+		else upd.bottom += p->y;
+	case DH_49:
+		if(minRC && IsInRect(minRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+			upd.left = minRC->left;
+		else if(maxRC && !IsInRect(maxRC, upd.left+p->x, (upd.top+upd.bottom)>>1))
+			upd.left = upd.left+p->x >= maxRC->right ? maxRC->right : maxRC->left;
+		else upd.left += p->x;
+		break;
+	case DH_18:	case DH_28:	case DH_38:	case DH_48:
+	case DH_58:	case DH_68:	case DH_78:	case DH_88:
+		CurrGO = this;
+	case DH_59:
+		parent->parent->Track(p, o);
+		return;
+	default:
+		if(type >= DH_DATA) {
+			idx = type - DH_DATA;
+			pts[1].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx)+dx);
+			pts[1].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx)+dy);
+			pts[1].x += p->x;				pts[1].y += p->y;
+			if(type > DH_DATA) {
+				pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx -1)+dx);
+				pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx -1)+dy);
+				}
+			else {
+				pts[0].x = pts[1].x;		pts[0].y = pts[1].y;
+				}
+			pts[3].x = pts[2].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +1)+dx);
+			pts[3].y = pts[2].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +1)+dy);
+			UpdateMinMaxRect(&upd, pts[0].x, pts[0].y);
+			UpdateMinMaxRect(&upd, pts[1].x, pts[1].y);
+			UpdateMinMaxRect(&upd, pts[2].x, pts[2].y);
+			if(parent ->Id == GO_BEZIER) {
+				switch(idx % 3) {
+				case 0:
+					o->ShowLine(pts, 3, 0x00c0c0c0L);
+					pts[0].x = pts[1].x;		pts[0].y = pts[1].y;
+					for(nbez = 0, i = 1; i < 4; i++) {
+						pts[i].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +i)+dx);
+						pts[i].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +i)+dy);
+						}
+					DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
+					o->ShowLine(bez, nbez, color);
+					if(idx < 3) return;
+					pts[3].x = pts[0].x;		pts[3].y = pts[0].y;
+					for(i = nbez = 0, idx -= 3; i < 3; i++) {
+						pts[i].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +i)+dx);
+						pts[i].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +i)+dy);
+						}
+					DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
+					o->ShowLine(bez, nbez, color);
+					return;
+				case 1:		
+					pts[3].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx +2)+dx);
+					pts[3].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx +2)+dy);
+					last = 2;				break;
+				case 2:	
+					pts[2].x = pts[1].x;	pts[2].y = pts[1].y;
+					pts[1].x = pts[0].x;	pts[1].y = pts[0].y;
+					pts[0].x = o->co2ix(parent->GetSize(SIZE_XPOS + idx -2)+dx);
+					pts[0].y = o->co2iy(parent->GetSize(SIZE_YPOS + idx -2)+dy);
+					first = 2;	last = 4;	break;
+					}
+				if(idx %3) {
+					nbez = 0;
+					DrawBezier(&nbez, bez, pts[0], pts[1], pts[2], pts[3], 0);
+					o->ShowLine(bez, nbez, color);
+					}
+				color = 0x00c0c0c0L;
+				}
+			else last = 3;
+			if(color == 0x0L || color == 0x00ffffffL) color = 0x00c0c0c0L;
+			}
+		else return;
+		}
+	if(type >= DH_19 && type <= DH_99) {
+		pts[0].x = pts[4].x = pts[3].x = p1.x = upd.left;	
+		pts[0].y = pts[1].y = pts[4].y = p1.y = upd.top;
+		pts[1].x = pts[2].x = p2.x = upd.right;	
+		pts[2].y = pts[3].y = p2.y = upd.bottom;
+		last = 5;
+		if(parent->parent->Id == GO_ELLIPSE) o->ShowEllipse(p1, p2, color);
+		}
+	o->ShowLine(pts+first, last-first, color);
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // the dragRect object uses nine dragHandles to create a user interface
 //   for modification of rectangular shapes
@@ -1618,9 +1682,12 @@ Bar::DoPlot(anyOutput *target)
 void
 Bar::DoMark(anyOutput *o, bool mark)
 {
+	int i;
+
 	if(mark){
 		memcpy(&mrc, &rDims, sizeof(RECT));
-		IncrementMinMaxRect(&mrc, 3);
+		i = 2*o->un2ix(BarLine.width);		//increase size of rectangle for marks
+		IncrementMinMaxRect(&mrc, i);
 		mo = GetRectBitmap(&mrc, o);
 		o->CopyBitmap(mrc.left, mrc.top, mo, 0, 0, mrc.right-mrc.left, mrc.bottom - mrc.top, true);
 		o->UpdateRect(&mrc, false);
@@ -1885,8 +1952,7 @@ DataLine::DoPlot(anyOutput *target)
 		AddToPolygon(&cp, pts, pts);
 		}
 	else{
-		target->SetLine(&LineDef);
-		target->oPolyline(pts, cp);
+		target->SetLine(&LineDef);		target->oPolyline(pts, cp);
 		}
 	if(tmppts = (POINT*)realloc(pts, cp *sizeof(POINT))) pts = tmppts;
 	SetMinMaxRect(&rDims, pts[0].x, pts[0].y, pts[1].x, pts[1].y);
@@ -2640,7 +2706,9 @@ ErrorBar::ErrorBar(int src):GraphObj(0L, 0L)
 
 ErrorBar::~ErrorBar()
 {
-	if(ssRef) free(ssRef);		ssRef = 0L;
+	if(mo) DelBitmapClass(mo);	mo = 0L;
+	if(ssRef) free(ssRef);		ssRef = 0L;
+	if(name) free(name);		name = 0L;
 }
 
 bool
@@ -2677,10 +2745,10 @@ ErrorBar::DoPlot(anyOutput *target)
 	case ERRBAR_VSYM:
 	case ERRBAR_VUP:
 	case ERRBAR_VDOWN:
-		ie = target->un2ix(SizeBar/2.0f);
+		ie = target->un2ix(SizeBar/2.0);
 		break;
 	default:
-		ie = target->un2iy(SizeBar/2.0f);
+		ie = target->un2iy(SizeBar/2.0);
 		break;
 		}
 	target->SetLine(&ErrLine);
@@ -2743,33 +2811,26 @@ ErrorBar::DoPlot(anyOutput *target)
 		}
 	if(rDims.left > rDims.right) Swap(rDims.left, rDims.right);
 	if(rDims.top > rDims.bottom) Swap(rDims.top, rDims.bottom);
-	IncrementMinMaxRect(&rDims, 3);
+	IncrementMinMaxRect(&rDims, 2);
 }
 
 void
 ErrorBar::DoMark(anyOutput *o, bool mark)
 {
-	LineDEF OldLine;
-
-	memcpy(&OldLine, &ErrLine, sizeof(LineDEF));
-	if(mark) {
-		ErrLine.color = 0x00000000L;
-		ErrLine.width = 1.2f;
-		DoPlot(o);
-		ErrLine.width = 0.4f;
-		ErrLine.color = OldLine.color ^ 0x00ffffffL;
-		DoPlot(o);
-		}
-	else {
-		ErrLine.color = 0x00ffffffL;		//DEBUG: assume white background
-		ErrLine.width = 1.2f;
-		DoPlot(o);
-		ErrLine.width = OldLine.width;
-		ErrLine.color = OldLine.color;
-		DoPlot(o);
-		}
-	memcpy(&ErrLine, &OldLine, sizeof(LineDEF));
-	o->UpdateRect(&rDims, false);
+	int i;
+	LineDEF OldLine;
+
+	if(mark){
+		memcpy(&mrc, &rDims, sizeof(RECT));
+		memcpy(&OldLine, &ErrLine, sizeof(LineDEF));
+		i = 3*o->un2ix(ErrLine.width);		//increase size of rectangle for marks
+		IncrementMinMaxRect(&mrc, i);		mo = GetRectBitmap(&mrc, o);
+		ErrLine.width *= 5.0;				DoPlot(o);
+		ErrLine.width = OldLine.width;		ErrLine.color = OldLine.color ^ 0x00ffffffL;
+		DoPlot(o);							o->UpdateRect(&mrc, false);
+		memcpy(&ErrLine, &OldLine, sizeof(LineDEF));
+		}
+	else RestoreRectBitmap(&mo, &mrc, o);
 }
 
 bool
@@ -2786,17 +2847,13 @@ ErrorBar::Command(int cmd, void *tmpl, anyOutput *o)
 		case MOUSE_LBUP:
 			if(!IsInRect(&rDims, mev->x, mev->y) || CurrGO) return false; 
 			switch (type) {
-			case ERRBAR_HSYM:
-			case ERRBAR_HLEFT:
-			case ERRBAR_HRIGHT:
+			case ERRBAR_HSYM:		case ERRBAR_HLEFT:		case ERRBAR_HRIGHT:
 				if(mev->y >= (ebpts[0].y-2) && mev->y <= (ebpts[1].y+2)) bFound = true;
 				else if(mev->x >= (ebpts[2].x-2) && mev->x <= (ebpts[2].x+2)) bFound = true;
 				else if(type == ERRBAR_HSYM && mev->x >= (ebpts[4].x-2) &&
 					mev->x <= (ebpts[4].x + 2)) bFound = true;
 				break;
-			case ERRBAR_VSYM:
-			case ERRBAR_VUP:
-			case ERRBAR_VDOWN:
+			case ERRBAR_VSYM:		case ERRBAR_VUP:		case ERRBAR_VDOWN:
 				if(mev->x >= (ebpts[0].x-2) && mev->x <= (ebpts[1].x+2)) bFound = true;
 				else if(mev->y >= (ebpts[2].y-2) && mev->y <= (ebpts[2].y+2)) bFound = true;
 				else if(type == ERRBAR_VSYM && mev->y >= (ebpts[4].y-2) &&
@@ -2816,7 +2873,21 @@ ErrorBar::Command(int cmd, void *tmpl, anyOutput *o)
 			data->GetValue(ssRef[2].y, ssRef[2].x, &ferr);
 			return true;
 			}
-		return false;
+		return false;
+	case CMD_LEGEND:
+		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+		switch(type) {
+			case ERRBAR_VSYM:		case ERRBAR_VUP:		case ERRBAR_VDOWN:
+				((Legend*)tmpl)->HasErr(&ErrLine, 1, name);
+				break;
+			case ERRBAR_HSYM:		case ERRBAR_HLEFT:		case ERRBAR_HRIGHT:
+				((Legend*)tmpl)->HasErr(&ErrLine, 2, name);
+				break;
+			}
+		break;
+	case CMD_ERRDESC:
+		if(name = (char*)realloc(name, strlen((char*)tmpl)+2)) strcpy(name, (char*)tmpl);
+		return true;
 	case CMD_ERR_TYPE:
 		if(tmpl) type = *((int*)tmpl);
 		return true;
@@ -3326,14 +3397,13 @@ Box::Command(int cmd, void *tmpl, anyOutput *o)
 		case MOUSE_LBUP:
 			if(IsInRect(&rDims, mev->x, mev->y) && !CurrGO) {
 				if(pts[0].x == pts[1].x || pts[0].y == pts[1].y) {
-					o->ShowMark(&rDims, MRK_INVERT);
-					CurrGO = this;
+					o->ShowMark(CurrGO = this, MRK_GODRAW);
 					return true;
 					}
 				else {
 					p.x = mev->x;		p.y = mev->y;
 					if(IsInPolygon(&p, pts, 5)) {
-						o->ShowMark(this, MRK_GODRAW);
+						o->ShowMark(CurrGO = this, MRK_GODRAW);
 						return true;
 						}
 					}
@@ -3380,6 +3450,16 @@ Box::Command(int cmd, void *tmpl, anyOutput *o)
 			else {
 				((Plot*)parent)->CheckBounds(pos1.fx, pos1.fy);
 				((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy);
+				if(parent && (type & BAR_RELWIDTH)) {
+					if(pos1.fy == pos2.fy) {
+						((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy + parent->GetSize(SIZE_BOXMINY));
+						((Plot*)parent)->CheckBounds(pos2.fx, pos2.fy - parent->GetSize(SIZE_BOXMINY));
+						}
+					else if(pos1.fx == pos2.fx) {
+						((Plot*)parent)->CheckBounds(pos2.fx + parent->GetSize(SIZE_BOXMINX), pos2.fy);
+						((Plot*)parent)->CheckBounds(pos2.fx - parent->GetSize(SIZE_BOXMINX), pos2.fy);
+						}
+					}
 				}
 			return true;
 			}
@@ -3409,6 +3489,7 @@ Whisker::Whisker(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
 			cssRef = 4;
 			}
 		}
+	Command(CMD_AUTOSCALE, 0L, 0L);
 }
 
 Whisker::Whisker(int src):GraphObj(0L, 0L)
@@ -3417,6 +3498,13 @@ Whisker::Whisker(int src):GraphObj(0L, 0L)
 	if(src == FILE_READ) {
 		FileIO(FILE_READ);
 		}
+}
+
+Whisker::~Whisker()
+{
+	if(mo) DelBitmapClass(mo);	mo = 0L;
+	if(ssRef) free(ssRef);		ssRef = 0L;
+	if(name) free(name);		name = 0L;
 }
 
 bool
@@ -3498,32 +3586,20 @@ Whisker::DoPlot(anyOutput *o)
 void
 Whisker::DoMark(anyOutput *o, bool mark)
 {
-	LineDEF OldLine;
-	int i;
-
-	memcpy(&OldLine, &LineDef, sizeof(LineDEF));
-	if(mark) {
-		LineDef.color = 0x00000000L;
-		LineDef.width = 1.2f;
-		o->SetLine(&LineDef);
-		for(i = 0; i < 5; i+=2) o->oSolidLine(pts+i);
-		LineDef.width = 0.4f;
-		LineDef.color = OldLine.color ^ 0x00ffffffL;
-		o->SetLine(&LineDef);
-		for(i = 0; i < 5; i+=2) o->oSolidLine(pts+i);
-		}
-	else {
-		LineDef.color = 0x00ffffffL;		//DEBUG: assume white background
-		LineDef.width = 1.2f;
-		o->SetLine(&LineDef);
-		for(i = 0; i < 5; i+=2) o->oSolidLine(pts+i);
-		LineDef.width = OldLine.width;
-		LineDef.color = OldLine.color;
-		o->SetLine(&LineDef);
-		for(i = 0; i < 5; i+=2) o->oSolidLine(pts+i);
-		}
-	memcpy(&LineDef, &OldLine, sizeof(LineDEF));
-	o->UpdateRect(&rDims, false);
+	int i;
+	LineDEF OldLine;
+
+	if(mark){
+		memcpy(&mrc, &rDims, sizeof(RECT));
+		memcpy(&OldLine, &LineDef, sizeof(LineDEF));
+		i = 3*o->un2ix(LineDef.width);		//increase size of rectangle for marks
+		IncrementMinMaxRect(&mrc, i);		mo = GetRectBitmap(&mrc, o);
+		LineDef.width *= 5.0;				DoPlot(o);
+		LineDef.width = OldLine.width;		LineDef.color = OldLine.color ^ 0x00ffffffL;
+		DoPlot(o);							o->UpdateRect(&mrc, false);
+		memcpy(&LineDef, &OldLine, sizeof(LineDEF));
+		}
+	else RestoreRectBitmap(&mo, &mrc, o);
 }
 
 bool
@@ -3547,9 +3623,24 @@ Whisker::Command(int cmd, void *tmpl, anyOutput *o)
 			break;
 			}
 		return false;
+	case CMD_ERRDESC:
+		if(name = (char*)realloc(name, strlen((char*)tmpl)+2)) strcpy(name, (char*)tmpl);
+		return true;
+	case CMD_LEGEND:
+		if(!tmpl || ((GraphObj*)tmpl)->Id != GO_LEGEND) return false;
+		switch(type & 0x0f) {
+		case 1:		((Legend*)tmpl)->HasErr(&LineDef, 5, name);		break;
+		case 2:		((Legend*)tmpl)->HasErr(&LineDef, 4, name);		break;
+		case 3:		((Legend*)tmpl)->HasErr(&LineDef, 3, name);		break;
+		default:
+			if((rDims.right - rDims.left) < (rDims.bottom - rDims.top))
+				((Legend*)tmpl)->HasErr(&LineDef, 1, name);
+			else ((Legend*)tmpl)->HasErr(&LineDef, 2, name);
+			break;
+			}
+		break;
 	case CMD_SET_DATAOBJ:
-		Id = GO_WHISKER;
-		data = (DataObj *)tmpl;
+		Id = GO_WHISKER;		data = (DataObj *)tmpl;
 		return true;
 	case CMD_UPDATE:
 		if(ssRef && cssRef >3 && data) {
@@ -6946,7 +7037,7 @@ polyline::polyline(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts):
 	if(parent){
 		dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
 		}
-	if(Values = (lfPOINT*)malloc((nPoints = cpts)* sizeof(lfPOINT))){
+	if(cpts && (Values = (lfPOINT*)malloc((nPoints = cpts)* sizeof(lfPOINT)))){
 		memcpy(Values, fpts, cpts*sizeof(lfPOINT));
 		for(i = 0; i < cpts; i++) {
 			Values[i].fx -= dx;		Values[i].fy -= dy;
@@ -7035,15 +7126,13 @@ polyline::DoPlot(anyOutput *o)
 	for(i = 2; i < nPts; i++) UpdateMinMaxRect(&rDims, pts[i].x, pts[i].y);
 	i = 3*o->un2ix(pgLine.width)+3;		//increase size of rectangle for marks
 	IncrementMinMaxRect(&rDims, i);
-	o->SetLine(&pgLine);
 	if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
 	else switch(type) {
 	case 0:				//line
-		o->oPolyline(pts, nPts);
+		o->SetLine(&pgLine);							o->oPolyline(pts, nPts);
 		break;
 	case 1:				//polygon
-		o->SetFill(&pgFill);
-		o->oPolygon(pts, nPts);
+		o->SetLine(&pgLine);	o->SetFill(&pgFill);	o->oPolygon(pts, nPts);
 		break;
 		}
 }
@@ -7051,7 +7140,7 @@ polyline::DoPlot(anyOutput *o)
 void
 polyline::DoMark(anyOutput *o, bool mark)
 {
-	RECT upd;
+	RECT upd;
 
 	memcpy(&upd, &rDims, sizeof(RECT));
 	IncrementMinMaxRect(&upd, 6 + o->un2ix(pgLine.width)*4);
@@ -7059,20 +7148,21 @@ polyline::DoMark(anyOutput *o, bool mark)
 		o->SetLine(&pgLine);
 		if(nPoints < 200){
 			switch(type) {
-			case 0:				//line
+			case 0:				//line
 				o->oPolyline(pts, nPts);
 			break;
 			case 1:				//polygon
-				o->SetFill(&pgFill);
-				o->oPolygon(pts, nPts);
+				o->SetFill(&pgFill);		o->oPolygon(pts, nPts);
 				break;
 				}
 			ShowPoints(o);
 			}
 		else InvertLine(pts, nPts, &pgLine, &upd, o, true);;
+		o->UpdateRect(&upd, false);
  		}
-	else if(parent)	parent->DoPlot(o);
-	o->UpdateRect(&upd, false);
+	else {
+		if(parent)	parent->DoPlot(o);
+		}
 }
 
 bool
@@ -7132,8 +7222,7 @@ polyline::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_SET_DATAOBJ:
 		Id = type == 1 ? GO_POLYGON : GO_POLYLINE;
 		return true;
-	case CMD_SETSCROLL:
-	case CMD_REDRAW:
+	case CMD_SETSCROLL:		case CMD_REDRAW:
 		if(parent) return parent->Command(cmd, tmpl, o);
 		return false;
 	case CMD_MOVE:
@@ -7161,9 +7250,8 @@ polyline::ObjThere(int x, int y)
 	void *ret;
 
 	if(IsInRect(&rDims, p1.x = x, p1.y = y)) {
-		if(CurrGO == this && pHandles) 
-			for(i = nPoints-1; i >= 0; i--) 
-				if((pHandles[i]) && (ret = pHandles[i]->ObjThere(x, y))) return ret;
+		if(CurrGO == this && pHandles) for(i = nPoints-1; i >= 0; i--) 
+			if((pHandles[i]) && (ret = pHandles[i]->ObjThere(x, y))) return ret;
 		if(type == 1) bFound = IsInPolygon(&p1, pts, nPts);
 		if(bFound || IsCloseToPL(p1,pts,nPts)) return this;
 		}
@@ -7195,17 +7283,422 @@ polyline::Track(POINT *p, anyOutput *o)
 void
 polyline::ShowPoints(anyOutput *o)
 {
-	int i;
+	int i;
+	double dx, dy;
+	POINT hpts[3];
+	LineDEF gl = {0.0, 1.0, 0x00c0c0c0, 0};
 
-	if(nPoints >= 200) return;
-	if(!pHandles) if(pHandles = (dragHandle**)calloc(nPoints+1, sizeof(dragHandle*))){
+	if(nPoints >= 200 || !o) return;
+	if(!pHandles && (pHandles = (dragHandle**)calloc(nPoints+4, sizeof(dragHandle*)))){
 		for(i = 0; i < nPoints; i++) pHandles[i] = new dragHandle(this, DH_DATA+i);
 		}
-	else return;
-	for(i = 0; i < nPoints; i++) if(pHandles[i]) pHandles[i]->DoPlot(o);
+	if(!pHandles) return;
+	if(Id == GO_BEZIER && parent && nPoints > 3) {
+		dx = parent->GetSize(SIZE_GRECT_LEFT);			dy = parent->GetSize(SIZE_GRECT_TOP);
+		o->SetLine(&gl);
+		hpts[0].x = o->co2ix(Values[0].fx+dx);			hpts[0].y = o->co2iy(Values[0].fy+dy);
+		hpts[1].x = o->co2ix(Values[1].fx+dx);			hpts[1].y = o->co2iy(Values[1].fy+dy);
+		o->oPolyline(hpts, 2);
+		for(i = 3; i < (nPoints-2); i += 3) {
+			hpts[0].x = o->co2ix(Values[i-1].fx+dx);	hpts[0].y = o->co2iy(Values[i-1].fy+dy);
+			hpts[1].x = o->co2ix(Values[i].fx+dx);		hpts[1].y = o->co2iy(Values[i].fy+dy);
+			hpts[2].x = o->co2ix(Values[i+1].fx+dx);	hpts[2].y = o->co2iy(Values[i+1].fy+dy);
+			o->oPolyline(hpts, 3);
+			}
+		hpts[0].x = o->co2ix(Values[i-1].fx+dx);		hpts[0].y = o->co2iy(Values[i-1].fy+dy);
+		hpts[1].x = o->co2ix(Values[i].fx+dx);			hpts[1].y = o->co2iy(Values[i].fy+dy);
+		o->oPolyline(hpts, 2);
+		}
+	for(i = 0; i < nPoints; i++) if(pHandles[i]) pHandles[i]->DoPlot(o);
 }
 
-
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Beziers are based on the polyline object
+Bezier::Bezier(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts, int mode, double res):
+	polyline(par, d, 0L, 0)
+{
+	double dx, dy, merr;
+	int i;
+
+	type = mode;
+	Id = GO_BEZIER;
+
+	if(!parent) return;
+	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
+	if(type == 0 && (Values = (lfPOINT*)malloc(4 * cpts * sizeof(lfPOINT)))) {
+		merr = 0.01 * Units[defs.cUnits].convert * res;
+		FitCurve(fpts, cpts, merr);
+		Values[nPoints].fx = fpts[cpts-1].fx;	Values[nPoints].fy = fpts[cpts-1].fy;
+		for(i = 0; i < nPoints; i++) {
+			Values[i].fx -= dx;		Values[i].fy -= dy;
+			}
+		nPoints ++;
+		}
+	return;
+}
+
+Bezier::Bezier(int src):polyline(0L, 0L, 0L, 0)
+{
+	if(src == FILE_READ) {
+		FileIO(FILE_READ);
+		}
+}
+
+void
+Bezier::DoPlot(anyOutput *o)
+{
+	POINT *tmppts;
+	double dx, dy;
+	int i;
+
+	if(!Values || !nPoints || !o || !parent) return;
+	if(pts) free(pts);		pts = 0L;
+	dx = parent->GetSize(SIZE_GRECT_LEFT);	dy = parent->GetSize(SIZE_GRECT_TOP);
+	if(!(tmppts = (POINT*)malloc((nPoints+2)*sizeof(POINT))))return;
+	for(i = 0; i < nPoints; i++){
+		tmppts[i].x = o->co2ix(Values[i].fx + dx);	tmppts[i].y = o->co2iy(Values[i].fy + dy);
+		}
+	rDims.left = rDims.right = tmppts[0].x;		rDims.top = rDims.bottom = tmppts[0].y;
+	for(i = 1; i < nPoints; i++) {
+		if(tmppts[i].x < rDims.left) rDims.left = tmppts[i].x;
+		else if(tmppts[i].x > rDims.right) rDims.right = tmppts[i].x;
+		if(tmppts[i].y < rDims.top) rDims.top = tmppts[i].y;
+		else if(tmppts[i].y > rDims.bottom) rDims.bottom = tmppts[i].y;
+		}
+	//DrawBezier returns not more than 2^MAXDEPTH points
+	pts = (POINT*)malloc(nPoints * 64 * sizeof(POINT));
+	for(i= nPts = 0; i< (nPoints-2); i += 3) {
+		DrawBezier(&nPts, pts, tmppts[i], tmppts[i+1], tmppts[i+2], tmppts[i+3], 0);
+		}
+	IncrementMinMaxRect(&rDims, 3);
+	o->ShowLine(pts, nPts, 0x00c0c0c0L);
+	if(this == CurrGO) o->ShowMark(this, MRK_GODRAW);
+	else {
+		o->SetLine(&pgLine);			o->oPolyline(pts, nPts);
+		}
+}
+
+bool
+Bezier::Command(int cmd, void *tmpl, anyOutput *o)
+{
+	int i, i1, i2;
+
+	switch (cmd) {
+	case CMD_MRK_DIRTY:			//issued by Undo
+		CurrGO = this;
+		bModified = true;
+	case CMD_FLUSH:
+		if(pHandles) {
+			for(i = 0; i < nPoints; i++) if(pHandles[i]) delete(pHandles[i]);
+			free(pHandles);		pHandles = 0L;
+			}
+		if(cmd == CMD_FLUSH && Values && nPoints){
+			free(Values);
+			Values = 0L;	nPoints = 0;
+			}
+		if(pts && nPts) free(pts);		pts = 0L;		nPts = 0;
+		return true;
+	case CMD_DELOBJ:
+		if(pHandles && tmpl && tmpl == (void*)CurrHandle) {
+			i = CurrHandle->type - DH_DATA;
+			if (i >= 0 && i < nPoints) {
+				i = CurrHandle->type - DH_DATA;
+				Undo.DataMem(this, (void**)&Values, nPoints * sizeof(lfPOINT), &nPoints, 0L);
+				if (i < 2) {
+					i1 = 0;					i2 = 3;
+					}
+				else if (i > (nPoints-3)) {
+					i1 = nPoints -3;		i2 = nPoints;
+					}
+				else {
+					i -= (((i-2) % 3)-1);	i1 = i -1;		i2 = i +2;
+					RemovePoint(Values, i1+1);
+					Values[i2].fx = Values[i1].fx;	Values[i2].fy = Values[i1].fy;
+					}
+				for(i = 0; i < nPoints; i++) if(pHandles[i]) delete(pHandles[i]);
+				free(pHandles);		pHandles = 0L;		CurrHandle = 0L;
+				i = i2 - i1;
+				for( ; i2 < nPoints; i1++, i2++) {
+					Values[i1].fx = Values[i2].fx;	Values[i1].fy = Values[i2].fy;
+					}
+				nPoints -= i;	CurrGO = this;		bModified = true;
+				return true;
+				}
+			}
+		return false;
+	case CMD_SET_DATAOBJ:
+		Id = GO_BEZIER;
+		return true;
+		}
+	return polyline::Command(cmd, tmpl, o);
+}
+
+void
+Bezier::AddPoints(int n, lfPOINT *p)
+{
+	int i;
+
+	for(i = 0; i< n; i++) {
+		Values[nPoints].fx = p[i].fx;	Values[nPoints].fy = p[i].fy;
+		nPoints ++;
+		}
+}
+
+//Fitting of a Bezier curve to digitized points is based on:
+//   P.J. Schneider (1990) An Algorithm for Automatically Fitting Digitized
+//   Curves. In: Graphics Gems (Ed. A. Glassner, Academic Press Inc., 
+//   ISBN 0-12-286165-5) pp. 612ff
+void
+Bezier::FitCurve(lfPOINT *d, int npt, double error)
+{
+	double len;
+	lfPOINT tHat1, tHat2;
+
+	tHat1.fx = d[1].fx - d[0].fx;		tHat1.fy = d[1].fy - d[0].fy;
+	if(0.0 != (len = sqrt((tHat1.fx * tHat1.fx) + (tHat1.fy * tHat1.fy)))) {
+		tHat1.fx /= len;					tHat1.fy /= len;
+		}
+	tHat2.fx = d[npt-2].fx - d[npt-1].fx;		tHat2.fy = d[npt-2].fy - d[npt-1].fy;
+	if(0.0 != (len = sqrt((tHat2.fx * tHat2.fx) + (tHat2.fy * tHat2.fy)))) {
+		tHat2.fx /= len;					tHat2.fy /= len;
+		}
+	FitCubic(d, 0, npt -1, tHat1, tHat2, error);
+}
+
+void
+Bezier::RemovePoint(lfPOINT *d, int sel)
+{
+	long o_nPoints;
+	double len;
+	lfPOINT ndata[3], tHat1, tHat2;
+
+	o_nPoints = nPoints;					nPoints = sel-3;
+	ndata[0].fx = d[sel-3].fx;				ndata[0].fy = d[sel-3].fy;
+	ndata[1].fx = d[sel].fx;				ndata[1].fy = d[sel].fy;
+	ndata[2].fx = d[sel+3].fx;				ndata[2].fy = d[sel+3].fy;
+	tHat1.fx = d[sel-2].fx - d[sel-3].fx;	tHat1.fy = d[sel-2].fy - d[sel-3].fy;
+	if(0.0 != (len = sqrt((tHat1.fx * tHat1.fx) + (tHat1.fy * tHat1.fy)))) {
+		tHat1.fx /= len;					tHat1.fy /= len;
+		}
+	tHat2.fx = d[sel+2].fx - d[sel+3].fx;	tHat2.fy = d[sel+2].fy - d[sel+3].fy;
+	if(0.0 != (len = sqrt((tHat2.fx * tHat2.fx) + (tHat2.fy * tHat2.fy)))) {
+		tHat2.fx /= len;					tHat2.fy /= len;
+		}
+	FitCubic(ndata, 0, 2, tHat1, tHat2, 1.0e-13);
+	nPoints = o_nPoints;
+}
+
+//Fit a Bezier curve to a (sub)set of digitized points
+void
+Bezier::FitCubic(lfPOINT *d, int first, int last, lfPOINT tHat1, lfPOINT tHat2, double error)
+{
+	lfPOINT bezCurve[4];
+	double *u, *uPrime, maxError, iterationError;
+	int i, splitPoint, npt;
+	lfPOINT tHatCenter;
+	int maxIterations = 8;
+	double len, b0, b1, b2;				//temp variables
+
+	iterationError = error * error;
+	npt = last - first +1;
+	if(npt == 2) {
+		b1 = d[last].fx - d[first].fx;			b2 = d[last].fy - d[first].fy;
+		b0 = sqrt(b1 * b1 + b2 * b2)/3.0;
+		b1 = b0/sqrt(tHat1.fx * tHat1.fx + tHat1.fy * tHat1.fy);
+		b2 = b0/sqrt(tHat2.fx * tHat2.fx + tHat2.fy * tHat2.fy);
+		bezCurve[0] = d[first];					bezCurve[3] = d[last];
+		bezCurve[1].fx = bezCurve[0].fx + tHat1.fx * b1;
+		bezCurve[1].fy = bezCurve[0].fy + tHat1.fy * b1;
+		bezCurve[2].fx = bezCurve[3].fx + tHat2.fx * b2;
+		bezCurve[2].fy = bezCurve[3].fy + tHat2.fy * b2;
+		AddPoints(3, bezCurve);
+		return;
+		}
+	u = ChordLengthParameterize(d, first, last);
+	GenerateBezier(d, first, last, u, tHat1, tHat2, bezCurve);
+	maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint);
+	if(maxError < error) {
+		AddPoints(3, bezCurve);					return;
+		}
+	if(maxError < iterationError) {
+		for (i = 0; i < maxIterations; i++) {
+			uPrime = Reparameterize(d, first, last, u, bezCurve);
+			GenerateBezier(d, first, last, uPrime, tHat1, tHat2, bezCurve);
+			maxError = ComputeMaxError(d, first, last, bezCurve, uPrime, &splitPoint);
+			if (maxError < error) {
+				AddPoints(3, bezCurve);			return;
+				}
+			free(u);							u = uPrime;
+			}
+		}
+	//Fitting failed: split at max error point and recurse
+	tHatCenter.fx = d[splitPoint-1].fx - d[splitPoint+1].fx;
+	tHatCenter.fy = d[splitPoint-1].fy - d[splitPoint+1].fy;
+	if(0.0 != (len = sqrt((tHatCenter.fx * tHatCenter.fx) + (tHatCenter.fy * tHatCenter.fy)))) {
+		tHatCenter.fx /= len;					tHatCenter.fy /= len;
+		}
+	FitCubic(d, first, splitPoint, tHat1, tHatCenter, error * _SQRT2);
+	tHatCenter.fx = -tHatCenter.fx;				tHatCenter.fy = -tHatCenter.fy;
+	FitCubic(d, splitPoint, last, tHatCenter, tHat2, error * _SQRT2);
+}
+
+//Use least-squares method to find Bezier control points for region.
+void
+Bezier::GenerateBezier(lfPOINT *d, int first, int last, double *uPrime, 
+	lfPOINT tHat1, lfPOINT tHat2, lfPOINT *bezCurve)
+{
+	int i, npt;
+	lfPOINT *A0, *A1, tmp, v1, v2;
+	double C[2][2], X[2];
+	double det_C0_C1, det_C0_X, det_X_C1, alpha_l, alpha_r;
+	double b0, b1, b2, b3;		//temp variables
+
+	npt = last - first +1;
+	A0 = (lfPOINT*) malloc(npt * sizeof(lfPOINT));
+	A1 = (lfPOINT*) malloc(npt * sizeof(lfPOINT));
+	for (i = 0; i < npt; i++) {
+		v1 = tHat1;								v2 = tHat2;
+		b2 = 1.0 - uPrime[i];
+		b1 = 3.0 * uPrime[i] * b2 * b2;			b2 = 3.0 * uPrime[i] * uPrime[i] * b2;
+		if(0.0 != (b0 = sqrt((v1.fx * v1.fx) + (v1.fy * v1.fy)))) {
+			v1.fx *= b1/b0;						v1.fy *= b1/b0;
+			}
+		if(0.0 != (b0 = sqrt((v2.fx * v2.fx) + (v2.fy * v2.fy)))) {
+			v2.fx *= b2/b0;						v2.fy *= b2/b0;
+			}
+		A0[i] = v1;								A1[i] = v2;
+		}
+	C[0][0] = C[0][1] = C[1][0] = C[1][1] = X[0] = X[1] = 0.0;
+	for (i = 0; i < npt; i++) {
+		C[0][0] += ((A0[i].fx * A0[i].fx) + (A0[i].fy * A0[i].fy));
+		C[0][1] += ((A0[i].fx * A1[i].fx) + (A0[i].fy * A1[i].fy));
+		C[1][0] = C[0][1];
+		C[1][1] += ((A1[i].fx * A1[i].fx) + (A1[i].fy * A1[i].fy));
+		b2 = 1.0 - uPrime[i];					b0 = b2 * b2 * b2;
+		b1 = 3.0 * uPrime[i] * b2 * b2;			b2 = 3.0 * uPrime[i] * uPrime[i] * b2;
+		b3 = uPrime[i] * uPrime[i] * uPrime[i];
+		tmp.fx = d[last].fx * b2 + d[last].fx * b3;
+		tmp.fy = d[last].fy * b2 + d[last].fy * b3;
+		tmp.fx += d[first].fx * b1;				tmp.fy += d[first].fy * b1;
+		tmp.fx += d[first].fx * b0;				tmp.fy += d[first].fy * b0;
+		tmp.fx = d[first+i].fx - tmp.fx;		tmp.fy = d[first+i].fy - tmp.fy;
+		X[0] += (A0[i].fx * tmp.fx + A0[i].fy * tmp.fy);
+		X[1] += (A1[i].fx * tmp.fx + A1[i].fy * tmp.fy);
+		}
+	det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1];
+	det_C0_X = C[0][0] * X[1] - C[0][1] * X[0];
+	det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1];
+	if(det_C0_C1 == 0.0) det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12;
+	alpha_l = det_X_C1 / det_C0_C1;				alpha_r = det_C0_X / det_C0_C1;
+	bezCurve[0] = d[first];						bezCurve[3] = d[last];
+	if(alpha_l < 0.0 || alpha_r < 0.0) {
+		//use Wu/Barsky heuristic
+		b1 = d[last].fx - d[first].fx;			b2 = d[last].fy - d[first].fy;
+		b0 = sqrt(b1 * b1 + b2 * b2)/3.0;
+		b1 = b0/sqrt(tHat1.fx * tHat1.fx + tHat1.fy * tHat1.fy);
+		b2 = b0/sqrt(tHat2.fx * tHat2.fx + tHat2.fy * tHat2.fy);
+		}
+	else {
+		b1 = alpha_l/sqrt(tHat1.fx * tHat1.fx + tHat1.fy * tHat1.fy);
+		b2 = alpha_r/sqrt(tHat2.fx * tHat2.fx + tHat2.fy * tHat2.fy);
+		}
+	bezCurve[1].fx = bezCurve[0].fx + tHat1.fx * b1;
+	bezCurve[1].fy = bezCurve[0].fy + tHat1.fy * b1;
+	bezCurve[2].fx = bezCurve[3].fx + tHat2.fx * b2;
+	bezCurve[2].fy = bezCurve[3].fy + tHat2.fy * b2;
+	free(A0);									free(A1);
+}
+
+//Given set of points and their parameterization, try to find
+//  a better parameterization.
+double *
+Bezier::Reparameterize(lfPOINT *d, int first, int last, double *u, lfPOINT *bezCurve)
+{
+	int i, j, k, npt = last-first+1;
+	double *uPrime, num, den, *pl, *ph, *pq;
+	lfPOINT Q1[3], Q2[2], Q_u, Q1_u, Q2_u;
+
+	uPrime = (double*)malloc(npt * sizeof(double));
+	//Use Newton-Raphson iteration to find better root
+	for (i = first, j = 0; i <= last; i++, j++) {
+		for(pl=(double*)bezCurve, ph=pl+2, pq=(double*)Q1, k=0; k <= 4; pl++, ph++, pq++, k++) {
+			*pq = (*ph - *pl ) * 3.0;
+			}
+		for(pl=(double*)Q1, ph=pl+2, pq=(double*)Q2, k=0; k <= 2; pl++, ph++, pq++, k++) {
+			*pq = (*ph - *pl ) * 2.0;
+			}
+		Q_u = fBezier(3, bezCurve, u[j]);
+		Q1_u = fBezier(2, Q1, u[j]);	
+		Q2_u = fBezier(1, Q2, u[j]);
+		num = (Q_u.fx - d[i].fx) * (Q1_u.fx) + (Q_u.fy - d[i].fy) * (Q1_u.fy);
+		den = (Q1_u.fx) * (Q1_u.fx) + (Q1_u.fy) * (Q1_u.fy) + 
+			(Q_u.fx - d[i].fx) * (Q2_u.fx) + (Q_u.fy - d[i].fy) * (Q2_u.fy);
+		uPrime[j] = u[j] - (num/den);
+		}
+	return uPrime;
+}
+
+//evaluate a Bezier curve at a particular parameter value
+lfPOINT
+Bezier::fBezier(int degree, lfPOINT *V, double t)
+{
+	int i, j;
+	lfPOINT Q;
+	lfPOINT *Vtemp;
+
+	Vtemp = (lfPOINT *)malloc((degree+1) * sizeof(lfPOINT));
+	for (i = 0; i <= degree; i++) {
+		Vtemp[i] = V[i];
+		}
+	for (i = 1; i <= degree; i++) {
+		for (j = 0; j <= degree-i; j++) {
+			Vtemp[j].fx = (1.0 -t) * Vtemp[j].fx + t * Vtemp[j+1].fx;
+			Vtemp[j].fy = (1.0 -t) * Vtemp[j].fy + t * Vtemp[j+1].fy;
+			}
+		}
+	Q = Vtemp[0];
+	free(Vtemp);
+	return Q;
+}
+
+double *
+Bezier::ChordLengthParameterize(lfPOINT *d, int first, int last)
+{ 
+	int i;
+	double tmp, *u;
+
+	u = (double*)malloc((last-first+1) * sizeof(double));
+	u[0] = 0.0;
+	for(i = first+1; i <= last; i++) {
+		u[i-first] = u[i-first-1] + 
+			sqrt(((tmp=(d[i].fx - d[i-1].fx))*tmp) + ((tmp=(d[i].fy - d[i-1].fy))*tmp));
+		}
+	for(i = first +1; i <= last; i++) {
+		u[i-first] = u[i-first] / u[last-first];
+		}
+	return u;
+}
+
+double
+Bezier::ComputeMaxError(lfPOINT *d, int first, int last, lfPOINT *bezCurve, double *u, int *splitPoint)
+{
+	int i;
+	double maxDist, dist;
+	lfPOINT P, v;
+
+	*splitPoint = (last - first + 1)>>1;
+	maxDist = 0.0;
+	for(i = first +1; i < last; i++) {
+		P = fBezier(3, bezCurve, u[i-first]);
+		v.fx = P.fx - d[i].fx;			v.fy = P.fy - d[i].fy;
+		dist = v.fx * v.fx + v.fy * v.fy;
+		if(dist >= maxDist) {
+			maxDist = dist;		*splitPoint = i;
+			}
+		}
+	return maxDist;
+}
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // polygons are based on the polyline object
 polygon::polygon(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts):
@@ -7541,6 +8034,16 @@ LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, Symbol *sy)
 	DefDesc(0L);		Id = GO_LEGITEM;		moveable = true;
 }
 
+LegItem::LegItem(GraphObj *par, DataObj *d, LineDEF *ld, int err, char *desc)
+	:GraphObj(par, d)
+{
+	FileIO(INIT_VARS);		flags |= (0x80 | (err & 0x7f));
+	if(ld) {
+		memcpy(&OutLine, ld, sizeof(LineDEF));
+		}
+	DefDesc(desc);		Id = GO_LEGITEM;		moveable = true;
+}
+
 LegItem::LegItem(int src):GraphObj(0L, 0L)
 {
 	FileIO(INIT_VARS);
@@ -7577,34 +8080,81 @@ LegItem::GetSize(int select)
 void
 LegItem::DoPlot(anyOutput *o)
 {
-	POINT pts[2];
-
-	if(!parent || !o) return;
-	hcr.left = iround(parent->GetSize((flags & 0x01) ? SIZE_XPOS+2 : SIZE_XPOS));
-	hcr.right = iround(parent->GetSize((flags & 0x01) ? SIZE_XPOS+3 :SIZE_XPOS+1));
-	hcr.top = iround(parent->GetSize(SIZE_YPOS));
-	hcr.bottom = iround(parent->GetSize(SIZE_YPOS+1));
-	SetMinMaxRect(&rDims, hcr.left, hcr.top, hcr.right, hcr.bottom);
-	if(flags & 0x02){
-		o->SetLine(&OutLine);	o->SetFill(&Fill);
-		o->oRectangle(hcr.left, hcr.top, hcr.right, hcr.bottom, name);
-		}
-	if(flags & 0x01){
-		pts[0].x = hcr.left;	pts[1].x = hcr.right;
-		pts[0].y = pts[1].y = iround(GetSize(SIZE_YCENTER))+1;
-		o->SetLine(&DataLine);	o->oPolyline(pts, 2, 0L);
-		}
-	if(flags & 0x04){
-		if(Sym) Sym->DoPlot(o);
-		}
-	if(Desc) {
-		Desc->moveable = false;	Desc->DoPlot(o);
-		if(Desc->rDims.bottom > rDims.bottom){
-			parent->SetSize(SIZE_YPOS+1, (double)Desc->rDims.bottom);
-			}
-		UpdateMinMaxRect(&rDims, Desc->rDims.left, Desc->rDims.top);
-		UpdateMinMaxRect(&rDims, Desc->rDims.right, Desc->rDims.bottom);
-		}
+	POINT pts[3];
+	int ie, cy;
+
+	if(!parent || !o) return;
+	hcr.top = iround(parent->GetSize(SIZE_YPOS));
+	hcr.bottom = iround(parent->GetSize(SIZE_YPOS+1));
+	SetMinMaxRect(&rDims, hcr.left, hcr.top, hcr.right, hcr.bottom);
+	if(flags & 0x80) {
+		hcr.left = iround(parent->GetSize((flags & 0x40) ? SIZE_XPOS+2 : SIZE_XPOS));
+		hcr.right = iround(parent->GetSize((flags & 0x40) ? SIZE_XPOS+3 :SIZE_XPOS+1));
+		ie = o->un2ix(defs.GetSize(SIZE_ERRBAR)/2.0);
+		o->SetLine(&OutLine);						cy = (hcr.top + hcr.bottom)>>1;
+		if((flags & 0x3f) == 0x01) {
+			pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
+			pts[0].y = hcr.top;		pts[1].y = hcr.bottom;
+			o->oPolyline(pts, 2, 0L);		
+			pts[0].x -= (ie-1);		pts[1].x += ie;		pts[0].y = pts[1].y = hcr.top;
+			o->oPolyline(pts, 2, 0L);					pts[0].y = pts[1].y = hcr.bottom;
+			o->oPolyline(pts, 2, 0L);
+			}
+		else if((flags & 0x3f) == 0x02) {
+			pts[0].x = pts[1].x = ((hcr.right + hcr.left)>>1);
+			pts[0].y = pts[1].y = cy;			cy = ((hcr.bottom - hcr.top)>>1);
+			pts[0].x -= cy;						pts[2].x = (pts[1].x += cy);
+			o->oPolyline(pts, 2, 0L);			pts[1].x = pts[0].x;
+			pts[0].y -= ie;						pts[1].y += ie;
+			o->oPolyline(pts, 2, 0L);
+			pts[0].x = pts[1].x = pts[2].x;		o->oPolyline(pts, 2, 0L);
+			}
+		else if((flags & 0x3f) == 0x03) {
+			pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
+			pts[0].y = hcr.top;		pts[1].y = hcr.bottom;
+			o->oPolyline(pts, 2, 0L);			pts[0].x -= (ie-1);
+			pts[0].y = pts[1].y = hcr.top;		o->oPolyline(pts, 2, 0L);
+			pts[0].y = pts[1].y = hcr.bottom;	pts[0].x += (ie + ie -1);
+			o->oPolyline(pts, 2, 0L);
+			}
+		else if((flags & 0x3f) == 0x04) {
+			pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
+			pts[0].y = hcr.top;		pts[1].y = hcr.bottom;
+			o->oPolyline(pts, 2, 0L);			pts[0].x += ie;
+			pts[0].y = pts[1].y = hcr.top;		o->oPolyline(pts, 2, 0L);
+			pts[0].y = pts[1].y = hcr.bottom;	pts[0].x -= (ie + ie -1);
+			o->oPolyline(pts, 2, 0L);
+			}
+		else if((flags & 0x3f) == 0x05) {
+			pts[0].x = pts[1].x = (hcr.right + hcr.left)>>1;
+			pts[0].y = hcr.top;		pts[1].y = hcr.bottom;
+			o->oPolyline(pts, 2, 0L);
+			}
+		}
+	else {
+		hcr.left = iround(parent->GetSize((flags & 0x01) ? SIZE_XPOS+2 : SIZE_XPOS));
+		hcr.right = iround(parent->GetSize((flags & 0x01) ? SIZE_XPOS+3 :SIZE_XPOS+1));
+		if(flags & 0x02){
+			o->SetLine(&OutLine);	o->SetFill(&Fill);
+			o->oRectangle(hcr.left, hcr.top, hcr.right, hcr.bottom, name);
+			}
+		if(flags & 0x01){
+			pts[0].x = hcr.left;	pts[1].x = hcr.right;
+			pts[0].y = pts[1].y = iround(GetSize(SIZE_YCENTER))+1;
+			o->SetLine(&DataLine);	o->oPolyline(pts, 2, 0L);
+			}
+		if(flags & 0x04){
+			if(Sym) Sym->DoPlot(o);
+			}
+		}
+	if(Desc) {
+		Desc->moveable = false;	Desc->DoPlot(o);
+		if(Desc->rDims.bottom > rDims.bottom){
+			parent->SetSize(SIZE_YPOS+1, (double)Desc->rDims.bottom);
+			}
+		UpdateMinMaxRect(&rDims, Desc->rDims.left, Desc->rDims.top);
+		UpdateMinMaxRect(&rDims, Desc->rDims.right, Desc->rDims.bottom);
+		}
 }
 
 void
@@ -7690,7 +8240,15 @@ LegItem::HasSym(LineDEF *ld, GraphObj *sy)
 		}
 	if(ld && cmpLineDEF(ld, &DataLine)) return false;
 	return true;
-}
+}
+
+bool
+LegItem::HasErr(LineDEF *ld, int err)
+{
+	if((((DWORD)err & 0x1f) | 0x80) != (flags & 0x9f)) return false;
+	if(ld && cmpLineDEF(ld, &OutLine)) return false;
+	return true;
+}
 
 void
 LegItem::DefDesc(char *txt)
@@ -7786,6 +8344,7 @@ Legend::DoPlot(anyOutput *o)
 	//draw all items
 	for(i = 0; i < nItems; i++) {
 		if(Items[i]){
+			if((Items[i]->flags & 0x11) == 0x01) hasLine = true;
 			Items[i]->DoPlot(o);
 			if(rDims.left == rDims.right || rDims.top == rDims.bottom){
 				rDims.left = Items[i]->rDims.left;	rDims.right = Items[i]->rDims.right;
@@ -7924,6 +8483,7 @@ Legend::HasSym(LineDEF *ld, GraphObj *sy)
 	LegItem *li;
 
 	if(!parent || !sy) return true;
+	if(ld) hasLine = true;
 	if(Items) for(i = 0; i < nItems; i++) {
 		if(Items[i] && Items[i]->HasSym(ld, sy)) return true;
 		}
@@ -7938,6 +8498,21 @@ Legend::HasSym(LineDEF *ld, GraphObj *sy)
 		}
 	return false;
 }
+
+bool
+Legend::HasErr(LineDEF *ld, int err, char *desc)
+{
+	int i;
+	LegItem *li;
+
+	if(Items) for(i = 0; i < nItems; i++) {
+		if(Items[i] && Items[i]->HasErr(ld, err)) return true;
+		}
+	if(li = new LegItem(this, data, ld, err | (hasLine ? 0x40 : 0), desc)){
+		if(!(Command(CMD_DROP_OBJECT, li, 0L))) DeleteGO(li);
+		}
+	return false;
+}
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Graphs are graphic objects containing plots, axes, and drawn objects
@@ -7972,16 +8547,15 @@ Graph::~Graph()
 	int i;
 
 	if(!parent) return;			parent = 0L;
-	Undo.InvalidGO(this);
-	DoZoom("reset");
+	Undo.InvalidGO(this);		DoZoom("reset");
 	if(CurrGraph == this) CurrGraph = 0L;
 	if(Plots) {
 		for(i = 0; i< NumPlots; i++) if(Plots[i]) DeleteGO(Plots[i]);
-		free(Plots);
+		free(Plots);		Plots = 0L;		NumPlots = 0;
 		}
 	if(Axes) {
-		for(i = 0; i< NumAxes; i++) if(Axes[i]) delete Axes[i];
-		free(Axes);
+		for(i = 0; i< NumAxes; i++) if(Axes[i]) DeleteGO(Axes[i]);
+		free(Axes);			Axes = 0L;		NumAxes = 0;
 		}
 	if(OwnDisp && Disp) DelDispClass(Disp);		OwnDisp = false;	Disp = 0L;
 	if(frm_g) DeleteGO(frm_g);		if(frm_d) DeleteGO(frm_d);
@@ -8127,7 +8701,8 @@ Graph::DoPlot(anyOutput *target)
 		else {
 			Plots[i]->DoPlot(CurrDisp);
 			}
-		}
+		}
+	if(bModified) data->Command(CMD_MRK_DIRTY, 0L, 0L);
 	if(target && ToolMode == TM_STANDARD) target->MouseCursor(MC_ARROW, false);
 }
 
@@ -8141,7 +8716,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 	int i, j;
 	DWORD delflg = 0L;
 
-	if(!o) o = CurrDisp;
+	if(!o) o = Disp ? Disp : CurrDisp;
 	switch (cmd){
     case CMD_CAN_CLOSE:
 		HideTextCursor();
@@ -8152,7 +8727,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 			if(i == 2) return false;
 			else if(i == 1) if(! SaveGraphAs(this)) return false;
 			}
-		//fall through
+		return true;
 	case CMD_CAN_DELETE:
 		HideTextCursor();
 		if(bModified) {
@@ -8160,13 +8735,11 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 			if(YesNoBox(TmpTxt)) SaveGraphAs(this);
 			}
 		bModified = false;
-		if(OwnDisp && Disp && parent){		//be careful not to reenter
-			OwnDisp = false;			DelDispClass(Disp);			Disp = CurrDisp = 0L;
-			if(Axes) for(i = 0; i< NumAxes; i++) if(Axes[i]) DeleteGO(Axes[i]);
-			if(Plots) for(i = 0; i< NumPlots; i++) if(Plots[i]) DeleteGO(Plots[i]);
-			Axes = 0L;	Plots = 0L;	NumPlots = 0;	NumAxes = 0;
-			if(parent) parent->Command(CMD_DELOBJ, this, 0L);
+		if(OwnDisp == true && Disp && CurrDisp){		//be careful not to reenter
+			OwnDisp = false;			DelDispClass(Disp);			
+			Disp = CurrDisp = 0L;		parent = 0L;
 			}
+		if(parent) parent->Command(CMD_DELOBJ, this, 0L);
 		return true;
 	case CMD_LAYERS:
 		Undo.SetDisp(o ? o : CurrDisp);
@@ -8178,6 +8751,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		Undo.ValRect(this, &DRect, UNDO_CONTINUE);
 		return true;
 	case CMD_LEGEND:
+		Undo.SetDisp(o ? o : CurrDisp);
 		if(Id == GO_PAGE) {
 			if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
 			if(!CurrGraph && NumPlots == 1 && Plots[0] && Plots[0]->Id == GO_GRAPH){
@@ -8289,7 +8863,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_ZOOM:
 		return DoZoom((char*)tmpl);
 	case CMD_MOUSECURSOR:
-		if(Disp)Disp->MouseCursor(MC_ARROW, false);	
+		if(o)o->MouseCursor(PasteObj ? MC_PASTE : MC_ARROW, false);	
 		return true;
 	case CMD_AXIS:			//one of the plots has changed scaling: reset
 		if(o)o->SetRect(CurrRect, units, &x_axis, &y_axis);
@@ -8325,7 +8899,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		if(CurrDisp) CurrDisp->MouseCursor(MC_ARROW, true);
 		return true;
 	case CMD_ADDAXIS:
-		Command(CMD_TOOLMODE, 0L, o);
+		Undo.SetDisp(o ? o : CurrDisp);		Command(CMD_TOOLMODE, 0L, o);
 		if(Id == GO_PAGE) {
 			if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
 			if(!CurrGraph && NumPlots == 1 && Plots[0] && Plots[0]->Id == GO_GRAPH){
@@ -8339,7 +8913,8 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		else {
 			if(type == GT_3D && Plots){
 				for(i = 0; i < NumPlots; i++)
-					if(Plots[i] && (Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_FUNC3D))
+					if(Plots[i] && (Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_FUNC3D
+						|| Plots[i]->Id == GO_FITFUNC3D))
 						return Plots[i]->Command(cmd, tmpl, o); 
 				}
 			else if(AddAxis()) {
@@ -8378,7 +8953,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		f_name = OpenGraphName(filename);
 		if(f_name && f_name[0]) {
 			if(data) data->Command(CMD_UPDHISTORY, 0L, 0L);
-			return OpenGraph(Id == GO_PAGE ? this : parent, f_name, 0L);
+			return OpenGraph(Id == GO_PAGE ? this : parent, f_name, 0L, false);
 			}
 		return true;
 	case CMD_UPDHISTORY:
@@ -8426,7 +9001,7 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 			return parent->Command(CMD_DELOBJ_CONT, (void*)this, o);
 		return false;
 	case CMD_TOOLMODE:
-		if(o) {
+		if(o && tmpl) {
 			o->CheckMenu(ToolMode & 0x0f, false);
 			o->CheckMenu(ToolMode = tmpl ? (*((int*)tmpl)) & 0x0f : TM_STANDARD, true);
 			}
@@ -8437,13 +9012,16 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		case TM_TEXT:	o->MouseCursor(MC_TEXT, false);	break;
 		case TM_DRAW:		case TM_POLYLINE:		case TM_POLYGON:
 		case TM_RECTANGLE:	case TM_ELLIPSE:		case TM_ROUNDREC:
-		case TM_ARROW:
+		case TM_ARROW:
 			o->MouseCursor(MC_CROSS, false);
 			break;
-		default:	o->MouseCursor(MC_ARROW, true);	break;
-			}
+		default:
+			o->MouseCursor(MC_ARROW, true);
+			break;
+			}
 		return Command(CMD_REDRAW, 0L, CurrDisp);
 	case CMD_ADDPLOT:
+		Undo.SetDisp(o ? o : CurrDisp);
 		if(Id == GO_PAGE) {
 			if(CurrGraph && CurrGraph->parent == this) return CurrGraph->Command(cmd, tmpl, o);
 			if(!CurrGraph && NumPlots == 1 && Plots[0] && Plots[0]->Id == GO_GRAPH){
@@ -8457,7 +9035,8 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		else if(Id == GO_GRAPH) {
 			if(type == GT_3D && Plots){
 				for(i = 0; i < NumPlots; i++) { 
-					if(Plots[i] && (Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_FUNC3D)) {
+					if(Plots[i] && (Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_FUNC3D
+						|| Plots[i]->Id == GO_FITFUNC3D)) {
 						if(Plots[i]->Command(cmd, tmpl, CurrDisp)) return Command(CMD_REDRAW, 0L, o);
 						else return false;
 						}
@@ -8471,7 +9050,10 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		return (dirty = true);
 	case CMD_CURRLEFT:	case CMD_CURRIGHT:	case CMD_ADDCHAR:
 	case CMD_BACKSP:	case CMD_POS_FIRST:	case CMD_POS_LAST:
-		defs.SetDisp(o);
+		defs.SetDisp(o);
+		if(tmpl && *((int*)tmpl) == 27) {			//Escape
+			o->HideMark();		CurrLabel = 0L;
+			}
 		if(CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
 		if(CurrGO && tmpl && *((int*)tmpl) == 13) {
 			CurrGO->PropertyDlg();
@@ -8490,7 +9072,8 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 		else {
 			if(type == GT_3D && Plots) {
 				for(i = 0; i < NumPlots; i++) {
-					if(Plots[i] && (Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_FUNC3D))
+					if(Plots[i] && (Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_FUNC3D
+						|| Plots[i]->Id == GO_FITFUNC3D))
 						return Plots[i]->Command(cmd, tmpl, CurrDisp);
 					}
 				}
@@ -8508,8 +9091,11 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 	case CMD_DELETE:
 		if(!CurrGO) return false;
 		bModified = true;
-		if(CurrGO == CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
+		if(CurrGO == CurrLabel) return CurrLabel->Command(cmd, tmpl, o);
 		if(CurrGO->parent)return CurrGO->parent->Command(CMD_DELOBJ, (void*)CurrGO, o);
+		return false;
+	case CMD_DROP_GRAPH:
+		if(parent) return parent->Command(cmd, tmpl, o);
 		return false;
 	case CMD_DROP_PLOT:
 		if(!tmpl || ((GraphObj*)tmpl)->Id < GO_PLOT) return false;
@@ -8525,7 +9111,8 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 				case GO_POLARPLOT:
 					type = GT_POLARPLOT;
 					break;
-				case GO_SCATT3D:		case GO_PLOT3D:		case GO_FUNC3D:
+				case GO_SCATT3D:		case GO_PLOT3D:		case GO_FUNC3D:
+				case GO_FITFUNC3D:
 					type = GT_3D;
 					break;
 				default:
@@ -8597,7 +9184,11 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 			CurrDisp->EndPage();
 			return true;
 			}
-		break;
+		break;
+	case CMD_PASTE_OBJ:
+//		ToolMode = TM_PASTE;			o->MouseCursor(MC_PASTE, false);
+//		PasteObj = (GraphObj*)tmpl;
+		return false;
 	case CMD_MOUSE_EVENT:
 		mev = (MouseEvent *)tmpl;		defs.SetDisp(o);
 		if(CurrGO && CurrGO->moveable && mev->Action == MOUSE_LBDOWN &&
@@ -8682,7 +9273,8 @@ Graph::Command(int cmd, void *tmpl, anyOutput *o)
 			((ObjTree*)tmpl)->Command(CMD_UPDATE, Plots[i], 0L);
 			if(Plots[i]->Id == GO_STACKBAR || Plots[i]->Id == GO_GRAPH || 
 				Plots[i]->Id == GO_PLOT3D || Plots[i]->Id == GO_POLARPLOT ||
-				Plots[i]->Id == GO_FUNC3D) Plots[i]->Command(cmd, tmpl, o);
+				Plots[i]->Id == GO_FUNC3D || Plots[i]->Id == GO_FITFUNC3D)
+				Plots[i]->Command(cmd, tmpl, o);
 			}
 		return true;
 		}
@@ -8768,7 +9360,7 @@ Graph::CreateAxes(int templ)
 {
 	AxisDEF tmp_axis;
 	TextDEF label_def, tlbdef;
-	char label_text[20];
+	char label_text[500];
 	Label *label;
 	double ts, lb_ydist, lb_xdist, tlb_dist;
 	DWORD ptick, ntick, utick;
@@ -9067,10 +9659,8 @@ Graph::ExecTool(MouseEvent *mev)
 	if(ToolMode & TM_MOVE) switch (mev->Action) {
 		case MOUSE_LBDOWN:
 			pl.x = pc.x = mev->x;				pl.y = pc.y = mev->y;
-			CurrDisp->HideMark();
-			if(TrackGO && TrackGO->Command(CMD_MOUSECURSOR, 0L, CurrDisp))
-				return true;
-			else CurrDisp->MouseCursor(MC_MOVE, false);
+			if(TrackGO && TrackGO->Command(CMD_MOUSECURSOR, 0L, CurrDisp)) return true;
+			CurrDisp->HideMark();			CurrDisp->MouseCursor(MC_MOVE, false);
 			return true;
 		case MOUSE_MOVE:
 			if(TrackGO) {
@@ -9113,8 +9703,9 @@ Graph::ExecTool(MouseEvent *mev)
 		case MOUSE_LBUP:
 			j = (i = rc_mrk.left - mev->x)*i;
 			j += ((i = rc_mrk.top - mev->y)*i);
-			if(j < 20) {						//glitch
-				ToolMode = TM_STANDARD;
+			if(j < 20) {						//glitch
+				rc_mrk.left = rc_mrk.right = rc_mrk.top = rc_mrk.bottom = 0;
+				ToolMode = TM_STANDARD;		CurrDisp->MouseCursor(MC_ARROW, false);
 				return false;
 				}
 			if(ToolMode == TM_ZOOMIN) {
@@ -9140,6 +9731,14 @@ Graph::ExecTool(MouseEvent *mev)
 				}
 			return true;
 			}
+		}
+	if(ToolMode == TM_PASTE) {
+		switch (mev->Action) {
+		case MOUSE_LBUP:
+			ToolMode = TM_STANDARD;			CurrDisp->MouseCursor(MC_ARROW, false);
+			break;
+			}
+		return true;
 		}
 	if(NumPlots && !Plots[NumPlots-1]) {
 		Undo.StoreListGO(this, &Plots, &NumPlots, UNDO_CONTINUE);
@@ -9181,7 +9780,9 @@ Graph::ExecTool(MouseEvent *mev)
 						}
 					if(Plots[NumPlots]) i = NumPlots+1;
 					else i = NumPlots;
-					Undo.SetGO(this, &Plots[i], new polyline(this, data, lfp, (int)tl_nPts), 0L);
+//					Undo.SetGO(this, &Plots[i], new polyline(this, data, lfp, (int)tl_nPts), 0L);
+					Undo.SetGO(this, &Plots[i], new Bezier(this, data, lfp, (int)tl_nPts, 0,
+							(CurrDisp->hres/CurrDisp->VPscale+CurrDisp->vres/CurrDisp->VPscale)/2.0), 0L);
 					if(Plots[i]){
 						NumPlots = i+1;
 						Plots[i]->moveable = 1;
@@ -9261,7 +9862,8 @@ Graph::ExecTool(MouseEvent *mev)
 					else i = NumPlots;
 					Undo.SetGO(this, &Plots[i], ToolMode == TM_POLYLINE ?
 						new polyline(this, data, lfp, (int)tl_nPts) :
-						new polygon(this, data, lfp, (int)tl_nPts), 0L);
+//						(GraphObj*) new Bezier(this, data, lfp, (int)tl_nPts) :
+						(GraphObj*) new polygon(this, data, lfp, (int)tl_nPts), 0L);
 					if(Plots[i]){
 						NumPlots = i+1;
 						Plots[i]->moveable = 1;
@@ -9277,10 +9879,7 @@ Graph::ExecTool(MouseEvent *mev)
 			}
 		if(mev->x == pc.x && mev->y == pc.y) return true;	//rebounce
 		break;
-	case TM_RECTANGLE:
-	case TM_ELLIPSE:
-	case TM_ROUNDREC:
-	case TM_ARROW:
+	case TM_RECTANGLE:	case TM_ELLIPSE:	case TM_ROUNDREC:	case TM_ARROW:
 		switch (mev->Action) {
 		case MOUSE_LBDOWN:
 			CurrGO = 0L;
@@ -9375,7 +9974,7 @@ Graph::ExecTool(MouseEvent *mev)
 			free(td);
 			return true;
 			}
-		break;
+		break;
 		}
 	return false;
 }
@@ -9616,8 +10215,10 @@ Page::DoPlot(anyOutput *o)
 	pts[1].x = pts[2].x = rDims.right;		pts[2].y = rDims.top +3;
 	CurrDisp->oPolyline(pts, 3);
 	//do all plots
-	if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]) Plots[i]->DoPlot(CurrDisp);
-
+	if(Plots) for(i = 0; i < NumPlots; i++) if(Plots[i]) Plots[i]->DoPlot(CurrDisp);
+	if(PasteObj) {
+		ToolMode = TM_PASTE;	CurrDisp->MouseCursor(MC_PASTE, false);
+		}
 }
 
 bool
diff --git a/rlplot.h b/rlplot.h
index b942817..875f2de 100755
--- a/rlplot.h
+++ b/rlplot.h
@@ -1,4 +1,4 @@
-//RLPlot.h, Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 R.Lackner
+//RLPlot.h, Copyright (c) 2000-2006 R.Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -40,6 +40,7 @@ inline int WriteFloatToBuff(char *buff, double val) {return sprintf(buff, " %g",
 #define w_char unsigned short
 #define _SBINC	8				//scrollbox extra space/line
 #define _TXH	3.0				//graph text default size in mm
+#define RLP_PORT	4321		//clipboard server
 
 typedef struct tagPOINT { // pt 
     long x; 
@@ -114,7 +115,8 @@ enum {CMD_NONE, CMD_ADDCHAR, CMD_SETFOCUS, CMD_KILLFOCUS, CMD_DELETE,
 	CMD_FILLRANGE, CMD_BUSY, CMD_ERROR, CMD_CLEAR_ERROR, CMD_SETPARAM, CMD_SETFUNC,
 	CMD_HIDE_MARK, CMD_LEGEND, CMD_FILENAME, CMD_LAYERS, CMD_OBJTREE, CMD_TEXTDEF,
 	CMD_HASSTACK, CMD_WRITE_GRAPHS, CMD_SETFONT, CMD_SETSTYLE, CMD_COPY, CMD_PASTE,
-	CMD_INSROW, CMD_INSCOL, CMD_DELROW, CMD_DELCOL, CMD_ADDTXT, CMD_ETRACC, CMD_SHPGUP, CMD_SHPGDOWN};
+	CMD_INSROW, CMD_INSCOL, CMD_DELROW, CMD_DELCOL, CMD_ADDTXT, CMD_ETRACC, CMD_SHPGUP, 
+	CMD_SHPGDOWN, CMD_ERRDESC, CMD_SAVEDATA, CMD_GETMARK, CMD_PASTE_OBJ};
 enum {SYM_CIRCLE, SYM_CIRCLEF, SYM_RECT, SYM_RECTF, SYM_TRIAU, SYM_TRIAUF,
 	SYM_TRIAD, SYM_TRIADF, SYM_DIAMOND, SYM_DIAMONDF, SYM_PLUS, SYM_CROSS,
 	SYM_STAR, SYM_HLINE, SYM_VLINE, SYM_TEXT, SYM_POS_PARENT = 0x1000};
@@ -127,27 +129,28 @@ enum {GO_UNKNOWN, GO_AXIS, GO_TICK, GO_GRIDLINE, GO_SYMBOL, GO_BUBBLE, GO_BAR,
 	GO_DRAGHANDLE, GO_DRAGRECT, GO_DRAG3D, GO_FRAMERECT, GO_SPHERE, GO_SVGOPTIONS,
 	GO_PLANE, GO_BRICK, GO_LINESEG, GO_LINE3D, GO_GRIDLINE3D, GO_GRIDRADIAL,
 	GO_SPHSCANL, GO_DROPL3D, GO_ARROW3D, GO_PLANE3D, GO_LEGITEM, GO_LEGEND,
-	GO_OBJTREE,
+	GO_OBJTREE, GO_BEZIER,
 	GO_PLOT = 0x100, GO_PLOTSCATT, GO_REGRESSION, GO_BARCHART, GO_BUBBLEPLOT, 
 	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_XYSTAT, GO_FITFUNC3D,
 	GO_GRAPH = 0x200, GO_PAGE, GO_SPREADDATA = 0x300, GO_DEFRW};
 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, 
 	FILL_BRICKDD, FILL_TEXTURE1, FILL_TEXTURE2, FILL_WAVES1, FILL_SCALES, FILL_SHINGLES, 
-	FILL_WAVES2, FILL_HERRING, FILL_CIRCLES, FILL_GRASS, FILL_FOAM, FILL_RECS,
-	NUM_FILLS, FILL_LIGHT3D = 0x100};
+	FILL_WAVES2, FILL_HERRING, FILL_CIRCLES, FILL_GRASS, FILL_FOAM, FILL_RECS, 
+	FILL_HASH, FILL_WATER, NUM_FILLS, FILL_LIGHT3D = 0x100};
 enum {ERRBAR_VSYM, ERRBAR_VUP, ERRBAR_VDOWN, ERRBAR_HSYM, ERRBAR_HLEFT,
 	ERRBAR_HRIGHT};
 enum {BAR_NONE, BAR_VERTB, BAR_VERTT, BAR_VERTU, BAR_HORL, BAR_HORR, BAR_HORU, 
 	BAR_RELWIDTH = 0x100, BAR_CENTERED = 0x200, BAR_WIDTHDATA = 0x400};
 enum {TM_STANDARD, TM_DRAW, TM_POLYLINE, TM_POLYGON, TM_RECTANGLE, TM_ELLIPSE,
-	TM_ROUNDREC, TM_ARROW, TM_TEXT, TM_MARK, TM_ZOOMIN, TM_MOVE = 0x100};
+	TM_ROUNDREC, TM_ARROW, TM_TEXT, TM_MARK, TM_ZOOMIN, TM_MOVE = 0x100, 
+	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_NE, MC_EAST, MC_SE, MC_SALL, MC_ZOOM, MC_PASTE};
 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};
@@ -435,8 +438,8 @@ public:
 	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_BUSY=0x100, 
-	ET_CIRCULAR=0x200};
+enum {ET_UNKNOWN, ET_VALUE, ET_TEXT, ET_FORMULA, ET_ERROR, ET_BOOL, 
+	ET_DATE, ET_TIME, ET_DATETIME, ET_BUSY=0x100, ET_CIRCULAR=0x200};
 
 class EditText {
 public:
@@ -454,11 +457,10 @@ public:
 	void Mark(anyOutput *Out, int mark);
 	bool Command(int cmd, anyOutput *Out, void *data_obj);
 	bool GetValue(double *v);
-	bool GetText(char *t, int size);
+	bool GetText(char *t, int size, bool bTranslate);
 	bool GetResult(anyResult *r, bool use_last = false);
 	bool SetValue(double v);
 	bool SetText(char *t);
-	bool GetItem(char *text, int size);
 	void SetRec(RECT *rc);
 	int GetX() {return loc.x;};
 	int GetY() {return loc.y;};
@@ -520,7 +522,7 @@ public:
 	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);
+	virtual bool GetText(int row, int col, char *txt, int len, bool bTranslate = true);
 	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);
@@ -532,6 +534,7 @@ public:
 	virtual bool Command(int cmd, void *tmpl, anyOutput *o){return false;};
 	virtual bool ReadData(char *, unsigned char *, int){return false;};
 	virtual void FlushData();
+	bool ValueRec(RECT *rc);
 };
 
 class StrData {
@@ -591,12 +594,13 @@ private:
 	void Texture1();
 	void Texture2();
 	void Arcs(int type);
-	void Waves2();
+	void Waves2(int type);
 	void Herringbone();
 	void Circles();
 	void Grass();
 	void Foam();
-	void Recs();
+	void Recs();
+	void Hash();
 	void CircGrad();
 };
 
@@ -637,7 +641,7 @@ public:
 	bool Command(int cmd, void *tmpl, anyOutput *o);
 
 private:
-	bool bLBdown, bSelected;
+	bool bLBdown, bSelected, bMarked;
 	TextDEF TextDef;
 	LineDEF Line;
 	FillDEF Fill;
@@ -910,6 +914,8 @@ public:
 	bool FileIO(int rw);
 
 private:
+	anyOutput *mo;
+	RECT mrc;
 	lfPOINT fPos;
 	double ferr, SizeBar;
 	POINT ebpts[6];
@@ -981,7 +987,8 @@ public:
 	Whisker(GraphObj *par, DataObj *d, lfPOINT fp1, lfPOINT fp2, int which,
 		int xc1=-1, int xr1=-1, int yc1=-1, int yr1=-1, int xc2=-1, int xr2=-1,
 		int yc2=-1, int yr2=-1);
-	Whisker(int src);
+	Whisker(int src);
+	~Whisker();
 	bool SetSize(int select, double value);
 	bool SetColor(int select, DWORD col);
 	void DoPlot(anyOutput *o);
@@ -991,6 +998,8 @@ public:
 	bool FileIO(int rw);
 
 private:
+	anyOutput *mo;
+	RECT mrc;
 	double size;
 	POINT pts[6];
 	lfPOINT pos1, pos2;
@@ -1350,6 +1359,7 @@ private:
 
 class polyline:public GraphObj {
 public:
+	dragHandle **pHandles;
 	lfPOINT *Values;
 	long nPoints, nPts;
 	POINT *pts;
@@ -1363,19 +1373,38 @@ public:
 	double GetSize(int select);
 	bool SetSize(int select, double value);
 	DWORD GetColor(int select);
-	void DoPlot(anyOutput *o);
+	virtual void DoPlot(anyOutput *o);
 	void DoMark(anyOutput *o, bool mark);
 	bool Command(int cmd, void *tmpl, anyOutput *o);
 	virtual bool PropertyDlg();
-	bool FileIO(int rw);
+	virtual bool FileIO(int rw);
 	void * ObjThere(int x, int y);
 	void Track(POINT *p, anyOutput *o);
 
 private:
-	dragHandle **pHandles;
-
 	void ShowPoints(anyOutput *o);
-};
+};
+
+class Bezier:public polyline {
+public:
+	Bezier(GraphObj *par, DataObj *d, lfPOINT *fpts, int cpts, int mode, double res);
+	Bezier(int src);
+	void DoPlot(anyOutput *o);
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool FileIO(int rw);
+
+private:
+	void AddPoints(int n, lfPOINT *p);
+
+	void FitCurve(lfPOINT *d, int npt, double error);
+	void FitCubic(lfPOINT *d, int first, int last, lfPOINT tHat1, lfPOINT tHat2, double error);
+	void RemovePoint(lfPOINT *d, int sel);
+	void GenerateBezier(lfPOINT *d, int first, int last, double * uPrime, lfPOINT tHat1, lfPOINT tHat2, lfPOINT *bezCurve);
+	double *Reparameterize(lfPOINT *d, int first, int last, double *u, lfPOINT *bezCurve);
+	lfPOINT fBezier(int degree, lfPOINT *V, double t);
+	double * ChordLengthParameterize(lfPOINT *d, int first, int last);
+	double ComputeMaxError(lfPOINT *d, int first, int last, lfPOINT *bezCurve, double *u, int *splitPoint);
+};
 
 class polygon:public polyline {
 public:
@@ -1427,8 +1456,11 @@ public:
 
 class LegItem:public GraphObj{
 public:
+	DWORD flags;
+
 	LegItem(GraphObj *par, DataObj *d, LineDEF *ld, LineDEF *lf, FillDEF *fill);
 	LegItem(GraphObj *par, DataObj *d, LineDEF *ld, Symbol *sy);
+	LegItem(GraphObj *par, DataObj *d, LineDEF *ld, int err, char *desc);
 	LegItem(int src);
 	~LegItem();
 	double GetSize(int select);
@@ -1441,13 +1473,13 @@ public:
 
 	bool HasFill(LineDEF *ld, FillDEF *fd);
 	bool HasSym(LineDEF *ld, GraphObj *sy);
+	bool HasErr(LineDEF *ld, int err);
 
 private:
 	LineDEF DataLine, OutLine, HatchLine;
 	FillDEF Fill;
 	Symbol *Sym;
 	Label *Desc;
-	DWORD flags;
 	RECT hcr;
 
 	void DefDesc(char *txt);
@@ -1469,6 +1501,7 @@ public:
 
 	bool HasFill(LineDEF *ld, FillDEF *fd);
 	bool HasSym(LineDEF *ld, GraphObj *sy);
+	bool HasErr(LineDEF *ld, int err, char *desc);
 
 private:
 	lfPOINT pos, lb_pos;
@@ -1476,6 +1509,7 @@ private:
 	anyOutput *to;
 	fRECT B_Rect, C_Rect, D_Rect, E_Rect, F_Rect;
 	long nItems;
+	bool hasLine;
 	LegItem **Items;
 };
 
@@ -1846,10 +1880,11 @@ public:
 	bool SetColor(int select, DWORD col);
 	void DoPlot(anyOutput *o);
 	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
 	void RegGO(void *n);
 	bool FileIO(int rw);
 
-	void CreateObs();
+	void CreateObs(bool set_undo);
 
 private:
 	long nLines, nPlanes;
@@ -1858,6 +1893,8 @@ private:
 	FillDEF Fill;
 	Line3D **lines;
 	Plane3D **planes;
+
+	bool Configure();
 };
 
 class Scatt3D:public Plot{
@@ -2154,7 +2191,29 @@ private:
 	bool Update();
 
 	double x1, x2, xstep, z1, z2, zstep;
-	int g_idx;
+	LineDEF Line;
+	FillDEF Fill;
+	char *param, *cmdxy;
+	DataObj *gda;
+	Grid3D  *gob;
+};
+
+class FitFunc3D:public Plot3D {
+public:
+	FitFunc3D(GraphObj *par, DataObj *d);
+	FitFunc3D(int src);
+	~FitFunc3D();
+	bool Command(int cmd, void *tmpl, anyOutput *o);
+	bool PropertyDlg();
+	void RegGO(void *n);
+	bool FileIO(int rw);
+
+private:
+	bool Update();
+
+	double x1, x2, xstep, z1, z2, zstep, conv, chi2;
+	char *ssXref, *ssYref, *ssZref;
+	int maxiter;
 	LineDEF Line;
 	FillDEF Fill;
 	char *param, *cmdxy;
@@ -2170,7 +2229,7 @@ public:
 	fRECT GRect, DRect, Bounds;
 	bool OwnDisp, bModified;
 	fRECT CurrRect;
-	GraphObj **Plots;
+	GraphObj **Plots, *PasteObj;
 	DWORD ColBG, ColAX;
 	GraphObj **Sc_Plots;
 	Axis **Axes;
@@ -2266,7 +2325,8 @@ public:
 	int dUnits, cUnits;
 	char DecPoint[2], ColSep[2];
 	char *svgAttr, *svgScript, *currPath, *IniFile;
-	char *File1, *File2, *File3, *File4, *File5, *File6;
+	char *File1, *File2, *File3, *File4, *File5, *File6;
+	char *fmt_date, *fmt_time, *fmt_datetime;
 	double min4log, ss_txt;
 	RECT clipRC;
 
@@ -2461,7 +2521,7 @@ bool DelBitmapClass(anyOutput *w);
 bool SaveGraphAs(GraphObj *g);
 char *GraphToMem(GraphObj *g, long *size);
 void UpdGOfromMem(GraphObj *go, unsigned char *buff);
-bool OpenGraph(GraphObj *root, char *name, unsigned char *mem);
+bool OpenGraph(GraphObj *root, char *name, unsigned char *mem, bool bPaste);
 void SavVarInit(long len);
 void *SavVarFetch();
 
@@ -2492,7 +2552,11 @@ double base4log(AxisDEF *axis, int direc);
 double TransformValue(AxisDEF *axis, double val, bool transform);
 void SortAxisBreaks(AxisDEF *axis);
 double GetAxisFac(AxisDEF *axis, double delta, int direc);
+char *str_ltrim(char *str);
+char *str_rtrim(char *str);
+char *str_trim(char *str);
 void ReshapeFormula(char **text);
+void TranslateResult(anyResult *res);
 void CleanTags(char *txt, int *i1, int *i2, int *i3);
 void ChangeChar(char *text, char c1, char c2);
 char *Int2Nat(char *Text);
@@ -2513,7 +2577,8 @@ bool IsCloseToLine(POINT *p1, POINT *p2, int x, int y);
 bool IsCloseToPL(POINT p, POINT *pts, int cp);
 bool IsInPolygon(POINT *p, POINT *pts, int cp);
 bool OverlapRect(RECT *rc1, RECT *rc2);
-void AddToPolygon(long *cp, POINT *pts, POINT *np);
+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);
 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);
@@ -2535,6 +2600,7 @@ double sininv(double val);
 double trig2deg(double si, double csi);
 bool ReplaceGO(GraphObj **oldobj, GraphObj **newobj);
 unsigned int HashValue(unsigned char *str);
+unsigned int Hash2(unsigned char * str);
 bool cmpLineDEF(LineDEF *l1, LineDEF *l2);
 bool cmpFillDEF(FillDEF *f1, FillDEF *f2);
 bool cmpAxisDEF(AxisDEF *a1, AxisDEF *a2);
@@ -2575,9 +2641,10 @@ void free_dmatrix(double **m, int nrl, int nrh, int ncl, int);
 bool mrqmin(double *, double *, double *, int, double **, int, int *, int, double **, double **, double *,
 	void (*funcs)(double, double, double **, double *, double *, int), double *);
 bool Check_MRQerror();
+void SortArray(int n, double *vals);
 void SortFpArray(int n, lfPOINT *vals);
 void spline(lfPOINT *v, int n, double *y2);
-double gammln(double xx);
+double gammln(double x);
 double factrl(int n);
 double gammp(double a, double x);
 double gammq(double a, double x);
@@ -2588,18 +2655,33 @@ double betaf(double z, double w);
 double errf(double x);
 double errfc(double x);
 double norm_dist(double x, double m, double s);
+double norm_freq(double x, double m, double s);
+double lognorm_dist(double x, double m, double s);
 double chi_dist(double x, double df, double);
 double t_dist(double t, double df, double);
 double pois_dist(double x, double m, double);
 double f_dist(double f, double df1, double df2);
 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);
 double d_amean(int n, double *v);
+double d_kurt(int n, double *v);
+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_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_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 d_ttest(double *x, double *y, int n1, int n2, char *dest, DataObj *data);
+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);
-
+bool date_value(char *desc, char *fmt, double *value);
+char *value_date(double dv, char *fmt);
+double now_today();
+void split_date(double dv, int *y, int *mo, int *dom, int *dow, int *doy, int *h, int *m, double *s);
diff --git a/rlplot.spec b/rlplot.spec
index 315c497..e280847 100755
--- a/rlplot.spec
+++ b/rlplot.spec
@@ -1,5 +1,5 @@
 Name:      rlplot
-Version:   1.0
+Version:   1.1
 Release:   1
 Summary:   A plotting program to create high quality graphs from data.
 License:   GPL
@@ -41,6 +41,9 @@ rm -rf "$RPM_BUILD_ROOT"
 %{_bindir}/exprlp
 
 %changelog
+* Fri Feb 24 2006 Reinhard Lackner
+- release 1.1
+
 * Wed Sep 07 2005 Reinhard Lackner
 - release 1.0
 
@@ -56,11 +59,3 @@ rm -rf "$RPM_BUILD_ROOT"
 * Mon Nov 25 2002 Guido Gonzato
 - initial
 
-
-
-
-
-
-
-
-
diff --git a/spreadwi.cpp b/spreadwi.cpp
index 734c7b8..97b6824 100755
--- a/spreadwi.cpp
+++ b/spreadwi.cpp
@@ -1,4 +1,4 @@
-//spreadwin.cpp, (c)2000, 2001, 2002, 2003, 2004, 2005 by R. Lackner
+//spreadwin.cpp, (c)2000-2006 by R. Lackner
 //
 //    This file is part of RLPlot.
 //
@@ -20,7 +20,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <time.h>
+#include <time.h>
+#include <math.h>
 
 #include <fcntl.h>				//file open flags
 #include <sys/stat.h>			//I/O flags
@@ -132,6 +133,7 @@ public:
 	bool Command(int cmd, void *tmpl, anyOutput *o);
 
 	bool ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cpos);
+	void MarkButtons(char *rng, POINT *cp = 0L);
 	bool PrintData(anyOutput *o);
 	void WriteGraphXML(unsigned char **ptr, long *cbd);
 
@@ -215,12 +217,13 @@ bool
 SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 {
 	char *Name;
-	Graph **g1, *g2;
+	Graph *g2;
 	int i, j, k;
 	MouseEvent *mev;
 	POINT p1;
 
-	if(d) {
+	if(d) {
+		if(!o) o = w;
 		switch(cmd) {
 		case CMD_CURRPOS:
 			if(tmpl && cButtons && rButtons) {
@@ -246,19 +249,16 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			return true;
 		case CMD_CAN_CLOSE:
 			HideTextCursor();
-			for(i = 0; i < NumGraphs; i++) {
-				if((g[i]) && !g[i]->Command(cmd, tmpl, o)) return false;
-				}
-			if(is_modified) {
+			if(is_modified == true) {
 				is_modified=false;
-				i = YesNoCancelBox("The spreadsheet has been modified!\n\nDo you want to save it now?");
+				i = YesNoCancelBox("The spreadsheet or a graph has been modified!\n\nDo you want to save it now?");
 				if(i == 2) return false;
 				else if(i == 1) return Command(CMD_SAVEDATAAS, tmpl, o);
 				}
-			//fall through
+			return true;
 		case CMD_CAN_DELETE:
 			HideTextCursor();
-			if(is_modified && YesNoBox("The spreadsheet has been modified!\n\nDo you want to save it now?")){
+			if(is_modified==true && YesNoBox("The spreadsheet or a graph has been modified!\n\nDo you want to save it now?")){
 				is_modified=false;
 				return Command(CMD_SAVEDATAAS, tmpl, o);
 				}
@@ -271,24 +271,26 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			if (g && NumGraphs) WriteGraphXML((unsigned char**)tmpl, (long*)o);
 			return true;
 		case CMD_DROP_GRAPH:
-			if(o) o->FileHistory();
-			if(!g) g = (Graph **)calloc(2, sizeof(Graph*));
-			else {
-				g1 = (Graph **)calloc(NumGraphs+2, sizeof(Graph*));
-				if(!g1) return false;
-				for(i = 0; i < NumGraphs; i++) g1[i] = g[i];
-				free(g);
-				g = g1; 
-				}
-			if(!g) return false;
-			g[NumGraphs] = (Graph *)tmpl;
-			if(g[NumGraphs]){
-				g[NumGraphs]->parent = this;
-				NumGraphs++;
-				g[NumGraphs-1]->Command(CMD_SET_DATAOBJ, (void *)d, 0L);
-				g[NumGraphs-1]->DoPlot(NULL);
-				}
-			return true;
+			if(!tmpl) return false;				if(o) o->FileHistory();
+			if(g && NumGraphs) {
+				if(g = (Graph**)realloc(g, (NumGraphs+2) * sizeof(Graph*)))
+					g[NumGraphs++] = (Graph *)tmpl;
+				else return false;
+				}
+			else {
+				if(g = (Graph **)calloc(2, sizeof(Graph*))){
+					g[0] = (Graph *)tmpl;		NumGraphs = 1;
+					}
+				}
+			for(i = j = 0; i < NumGraphs; i++) {
+				if(g[i]) {
+					g[j] = g[i];			g[j]->parent = this;
+					g[j]->Command(CMD_SET_DATAOBJ, (void*)d, 0L);
+					j++;
+					}
+				}
+			NumGraphs = j;	g[j-1]->DoPlot(0L);
+			return true;
 		case CMD_NEWGRAPH:
 			if((g2 = new Graph(this, d, 0L)) && g2->PropertyDlg() && 
 				Command(CMD_DROP_GRAPH, g2, o))return Command(CMD_REDRAW, 0L, o);
@@ -309,28 +311,31 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 					}
 				free (g);
 				}
-			g = 0L;
-			NumGraphs = 0;
-			Undo.Flush();
+			g = 0L;			NumGraphs = 0;		Undo.Flush();
 			return true;
-		case CMD_DELOBJ:
-			if (g) {
-				for(i = 0; i <= NumGraphs; i++) {
-					if(g[i] == (Graph *)tmpl) {
-						delete (g[i]);
-						g[i] = 0L;
-						return true;
-						}
-					}
+		case CMD_DELOBJ:
+			if(g && tmpl) for(i = j = 0; i < NumGraphs; i++) {
+				if(g[i] == (Graph*) tmpl) {
+					DeleteGO(g[i]);
+					}
+				else (g[j++] = g[i]);
+				}
+			if(j < i) g[j] = 0L;				NumGraphs = j;
+			return true;
+		case CMD_SAVEDATA:
+			if(o) o->MouseCursor(MC_WAIT, false);
+			if(d->WriteData(0L)) {
+				is_modified=false;
+				if(o) o->MouseCursor(MC_ARROW, false);
+				return true;
 				}
-			return false;
+			if(o) o->MouseCursor(MC_ARROW, true);
 		case CMD_SAVEDATAAS:
 			is_modified=false;
 			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 = strdup(Name);
 					}
 				else return false;
 				}
@@ -338,10 +343,9 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			return true;
 		case CMD_DROPFILE:
 			if(!Command(CMD_CAN_CLOSE, 0L, o)) return false;
-			if(IsRlpFile((char*)tmpl)) return OpenGraph(this, (char*)tmpl, 0L);
+			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 = strdup((char*)tmpl);
 				return Command(CMD_SETSCROLL, 0L, w);
 				}
 			return false;
@@ -349,10 +353,9 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			if(!Command(CMD_CAN_CLOSE, 0L, o)) return false;
 			if((Name = OpenDataName(filename)) && Name[0]){
 				if(o) o->FileHistory();
-				if(IsRlpFile(Name)) return OpenGraph(this, Name, 0L);
+				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 = strdup(Name);
 					return Command(CMD_SETSCROLL, 0L, w);
 					}
 				}
@@ -390,23 +393,20 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 		case CMD_SHPGUP:		case CMD_SHPGDOWN:
 			return d->Command(cmd, tmpl, o);
 		case CMD_REDRAW:
-			Undo.SetDisp(w);
-			d->Command(cmd, tmpl, o);
+			Undo.SetDisp(w);						d->Command(cmd, tmpl, o);
 			return true;
+		case CMD_MOUSECURSOR:
+			if(o)o->MouseCursor(MC_ARROW, false);	
+			return true;
 		case CMD_SETSCROLL:
-			HideTextCursor();
-			o->ActualSize(&currRC);
-			k = (currRC.bottom-currRC.top)/ch;
-			d->GetSize(&i, &j);
-			o->SetScroll(true, 0, j, k, ssOrg.y);
-			k = (currRC.right-currRC.left)/cw;
-			o->SetScroll(false, 0, i, k, ssOrg.x);
-			DoPlot(o);
+			HideTextCursor();						o->ActualSize(&currRC);
+			k = (currRC.bottom-currRC.top)/ch;		d->GetSize(&i, &j);
+			o->SetScroll(true, 0, j, k, ssOrg.y);	k = (currRC.right-currRC.left)/cw;
+			o->SetScroll(false, 0, i, k, ssOrg.x);	DoPlot(o);
 			return true;
 		case CMD_PAGEUP:		case CMD_PAGEDOWN:
 			k = (currRC.bottom-currRC.top)/ch;
-			k = k > 3 ? k-2 : 1;
-			p1.x = fw + 2;		p1.y = ch + 2;
+			k = k > 3 ? k-2 : 1;					p1.x = fw + 2;		p1.y = ch + 2;
 			if(CurrText){
 				p1.x = CurrText->GetX()+2;	p1.y = CurrText->GetY()+12;
 				}
@@ -431,7 +431,8 @@ SpreadWin::Command(int cmd, void *tmpl, anyOutput *o)
 			if(tmpl)ssText.iSize = *((int*)tmpl);
 			return true;
 		case CMD_CONFIG:
-			return defs.PropertyDlg();
+			if(defs.PropertyDlg()) return Command(CMD_REDRAW, 0L, o);
+			return false;
 		case CMD_NONE:
 			return true;
 		case CMD_PRINT:
@@ -446,10 +447,10 @@ SpreadWin::ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cp)
 {
 	int i, c, nr, nc, ac = 1, na = 0;
 	RECT rc;
-	char text[20];
+	char text[20];
 	POINT grid[2];
 	TextDEF ButtText;
-	bool redim = false;
+	bool redim = false;
 
 	cpos.x = cp->x;			cpos.y = cp->y;
 	if(ch != CellHeight || cw != CellWidth || fw != FirstWidth) redim = true;
@@ -512,23 +513,57 @@ SpreadWin::ShowGrid(int CellWidth, int CellHeight, int FirstWidth, POINT *cp)
 			}
 		grid[0].x = grid[1].x = i*CellWidth+FirstWidth-1;
 		if(i <= (nc-ssOrg.x)) w->oSolidLine(grid);
-		}
+		}
 	w->SetTextSpec(&ssText);
 	if(aButton) aButton->DoPlot(w);
 	return true;
+}
+
+void
+SpreadWin::MarkButtons(char *rng, POINT *cp)
+{
+	int i, r, c, ncb, nrb, *r_idx, *c_idx;
+	AccRange *mr;
+
+	if(!rButtons || !cButtons) return;
+	for(ncb = 0; cButtons[ncb]; ncb++);		ncb--;
+	for(nrb = 0; rButtons[nrb]; nrb++);		nrb--;
+	if(!nrb || !ncb || !(r_idx=(int*)calloc(nrb,sizeof(int))) || !(c_idx=(int*)calloc(ncb,sizeof(int)))) return;
+	if(rng && rng[0] && (mr = new AccRange(rng)) && mr->GetFirst(&c, &r)) {
+		mr->NextCol(&c);
+		do {
+			if((i = c - ssOrg.x) >= 0 && i < ncb) c_idx[i] = 1; 
+			}while(mr->NextCol(&c));
+		mr->GetFirst(&c, &r);			mr->NextRow(&r);
+		do {
+			if((i = r - ssOrg.y) >= 0 && i < nrb) r_idx[i] = 1; 
+			}while(mr->NextRow(&r));
+		delete mr;
+		}
+	for(i = 0; i < ncb; i++) cButtons[i]->Command(CMD_SETSTYLE, &c_idx[i], w); 
+	for(i = 0; i < nrb; i++) rButtons[i]->Command(CMD_SETSTYLE, &r_idx[i], w);
+	if(cp) {
+		c_idx[0] = r_idx[0] = 0;	c_idx[1] = r_idx[1] = 1;
+		r = (cp->y - ssOrg.y);		c = cp->x -ssOrg.x;
+		for(i = 0; i < ncb; i++) cButtons[i]->Command(CMD_SELECT, c == i ? &c_idx[1] : &c_idx[0], w); 
+		for(i = 0; i < nrb; i++) rButtons[i]->Command(CMD_SELECT, r == i ? &r_idx[1] : &r_idx[0], w);
+		}
+	free(r_idx);		free(c_idx);
 }
 
 bool
 SpreadWin::PrintData(anyOutput *o)
 {
-	int i, j, k, l, pfw, pcw, pch, rpp, cpp, nc, nr, ix, iy, cpages;
+	int i, j, k, l, pfw, pcw, pch, rpp, cpp, nc, nr, ix, iy, cpages;
+	int row, col, width, height, ipad;
+	double scale;
 	RECT rc, margin, margin_first;
 	POINT pp_pos, ss_pos, grid[2];
 	LineDEF Line1, Line2;
 	TextDEF td, tdp;
 	bool bContinue;
 	time_t ti = time(0L);
-	double val;
+	anyResult res;
 
 	Line1.patlength = Line2.patlength = 1.0;
 	Line1.color = Line2.color = 0x0;			//black gridlines
@@ -538,12 +573,17 @@ SpreadWin::PrintData(anyOutput *o)
 	case 2:		Line1.width = 0.003937;		break;
 	default:	Line1.width = 0.1;			break;
 		}
+#ifdef _WINDOWS
+	scale = 1.0/_SQRT2;
+#else
+	scale = 0.9;
+#endif
 	Line2.width = Line1.width * 3.0;
 	d->GetSize(&nc, &nr);
 	if(!(o->StartPage())) return false;
-	pfw = iround(o->hres * ((double)fw)/w->hres);
-	pcw = iround(o->hres * ((double)cw)/w->hres);
-	pch = iround(o->vres * ((double)ch)/w->vres + o->vres/20.0);
+	pfw = iround(o->hres * ((double)fw)/w->hres * scale);
+	pcw = iround(o->hres * ((double)cw)/w->hres * scale);
+	pch = iround((o->vres * ((double)ch)/w->vres) * scale + o->vres/20.0);
 	o->ActualSize(&rc);
 	tdp.ColTxt = 0x0;	tdp.ColBg = 0x00ffffffL; 
 	tdp.fSize = tdp.RotBL = tdp.RotCHAR = 0.0;	tdp.Align = TXA_HRIGHT | TXA_VCENTER;
@@ -608,28 +648,43 @@ SpreadWin::PrintData(anyOutput *o)
 			o->oSolidLine(grid);	iy = grid[0].y + (pch >>1);
 			sprintf(TmpTxt, "%d", i+1+ss_pos.y);
 			if(i < l) o->oTextOut(ix, iy, TmpTxt, 0);
-			}
+			}
+		ipad = iround(o->hres/20.0);
 		for(i = 0; i < k; i++) {			//spreadsheet data
-			for (j = 0; j < l; j++) {
-				if(d->GetText(j+ss_pos.y, i+ss_pos.x, TmpTxt, TMP_TXT_SIZE)){
-					if(d->etRows[j+ss_pos.y][i+ss_pos.x]->isFormula()){
-						td.Align = TXA_HRIGHT | TXA_VCENTER;
-						ix = margin.left+pfw+pcw + i*pcw - iround(o->hres/20.0);
-						d->etRows[j+ss_pos.y][i+ss_pos.x]->GetValue(&val);
-						sprintf(TmpTxt,"%g", val);
-						fit_num_rect(o, pcw - iround(o->hres/30.0), TmpTxt);
-						}
-					else if(d->etRows[j+ss_pos.y][i+ss_pos.x]->isValue()){
-						td.Align = TXA_HRIGHT | TXA_VCENTER;
-						ix = margin.left+pfw+pcw + i*pcw - iround(o->hres/20.0);
-						}
-					else {
-						td.Align = TXA_HLEFT | TXA_VCENTER;
-						ix = margin.left+pfw + i*pcw + iround(o->hres/20.0);
-						}
-					iy = pp_pos.y + pch + (pch>>1) + j * pch;
-					o->SetTextSpec(&td);
-					o->oTextOut(ix, iy, TmpTxt, 0);
+			for (j = 0; j < l; j++) {
+				row = j+ss_pos.y;		col = i+ss_pos.x;
+				if(row >= 0 && row < d->cRows && col >= 0  && col < d->cCols && d->etRows[row][col]) {
+					d->etRows[row][col]->GetResult(&res, false);
+					TranslateResult(&res);
+					td.Align = TXA_HLEFT | TXA_VCENTER;
+					ix = margin.left+pfw + i*pcw + ipad;
+					switch (res.type) {
+					case ET_VALUE:
+						ix = margin.left+pfw+pcw + i*pcw - ipad;
+						td.Align = TXA_HRIGHT | TXA_VCENTER;
+						strcpy(TmpTxt, res.text);
+						fit_num_rect(o, pcw - ipad, TmpTxt);
+						Int2Nat(TmpTxt);			break;
+					case ET_BOOL:	case ET_DATE:	case ET_TIME:	case ET_DATETIME:
+						ix = margin.left+pfw+pcw + i*pcw - ipad;
+						td.Align = TXA_HRIGHT | TXA_VCENTER;
+					case ET_TEXT:	case ET_UNKNOWN:
+						if(res.text && strlen(res.text) < 40) 
+							strcpy(TmpTxt, res.text[0] != '\'' ? res.text : res.text +1);
+						else if(res.text) sprintf(TmpTxt,"#SIZE");
+						else TmpTxt[0] = 0;	
+						do {
+							o->oGetTextExtent(TmpTxt, strlen(TmpTxt), &width, &height);
+							if(width > (pcw + iround(o->hres/20.0))) TmpTxt[strlen(TmpTxt)-1] = 0;
+							}while(width > (pcw + ipad));
+						break;
+					case ET_ERROR:
+						strcpy(TmpTxt, "#ERROR");	break;
+					default:
+						strcpy(TmpTxt, "#VALUE");	break;
+						}
+					iy = pp_pos.y + pch + (pch>>1) + j * pch;
+					o->SetTextSpec(&td);			o->oTextOut(ix, iy, TmpTxt, 0);
 					}
 				}
 			}
@@ -680,20 +735,17 @@ void
 SpreadWin::WriteGraphXML(unsigned char **ptr, long *cbd)
 {
 	unsigned char *pg;
-	long cb = 0, size = 0;
+	long cb = 0, size = 0, newsize;
 	int i;
 
-	if(cbd) size = (*cbd / 10000)+ 10000;
 	for(i = 0; i < NumGraphs; i++) if(g[i]) {
-		pg = (unsigned char*)GraphToMem(g[i], &cb);
-		if(pg && cb) {
-			while ((*cbd+cb+100) > size){
-				*ptr = (unsigned char*)realloc(*ptr, size += 10000);
-				}
+		if((pg = (unsigned char*)GraphToMem(g[i], &cb)) && cb) {
+			newsize = *cbd + cb + 100;
+			*ptr = (unsigned char*)realloc(*ptr, newsize);
 			*cbd += sprintf(((char*)*ptr)+*cbd, "<Graph><![CDATA[\n");
-			memcpy(*ptr+*cbd, pg, cb);	*cbd += cb;
+			*cbd += sprintf(((char*)*ptr)+*cbd, "%s", pg);
 			*cbd += sprintf(((char*)*ptr)+*cbd, "]]>\n</Graph>\n");
-			if(pg) free(pg);	pg = 0L;	cb = 0;
+			if(pg) free(pg);		pg = 0L;			cb = 0;
 			}
 		}
 }
@@ -712,7 +764,7 @@ public:
 	bool Init(int nRows, int nCols);
 	bool mpos2dpos(POINT *mp, POINT *dp);
 	bool Select(POINT *p);
-	void MarkRange(char *range);
+	void MarkRange(char *range, POINT *cp = 0L);
 	void HideMark(bool cclp);
 	bool WriteData(char *FileName);
 	bool AddCols(int nCols);
@@ -736,7 +788,7 @@ public:
 
 private:
 	int CellHeight, CellWidth, FirstWidth, r_disp, c_disp, mrk_offs;
-	RECT rcCopy, cp_src_rec;				//bounding rectangle for copy range
+	RECT cp_src_rec;			//bounding rectangle for copy range
 	bool bActive, new_mark, bCopyCut, bUpdate, isRowMark, isColMark;
 	POINT currpos, currpos2;
 	anyOutput *w;
@@ -745,20 +797,20 @@ private:
 	EditText *et_racc;
 	char *m_range, *c_range;	//mark and copy ranges
 	char *err_msg, *last_err;	//error message
+	char *rlw_file;				//use this name for save
 	_pos_info pos_info;			//save position settings
 };
 
 SpreadData::SpreadData(GraphObj *par)
 {
-	Disp = 0L;	m_range = 0L;	c_range = 0L;	w = 0L;		err_msg=last_err = 0L;
+	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;
 	bActive = bCopyCut = bUpdate = isRowMark = isColMark = false;
-	rcCopy.left = rcCopy.right = rcCopy.top = rcCopy.bottom = 0;
 	cp_src_rec.left = cp_src_rec.right = cp_src_rec.top = cp_src_rec.bottom = 0;
 	if(defs.IniFile && FileExist(defs.IniFile)) {
-		OpenGraph(0L, defs.IniFile, 0L);
+		OpenGraph(0L, defs.IniFile, 0L, false);
 		}
 	pos_info.currpos.x = currpos.x;		pos_info.currpos.y = currpos.y;
 	pos_info.CurrText = CurrText;
@@ -769,7 +821,8 @@ SpreadData::~SpreadData()
 	FlushData();
 	if(Disp) delete Disp;			Disp = 0L;
 	if(m_range) free(m_range);		m_range = 0L;
-	if(c_range) free(c_range);		c_range = 0L;
+	if(c_range) free(c_range);		c_range = 0L;
+	if(rlw_file) free(rlw_file);	rlw_file = 0L;
 }
 
 bool
@@ -778,8 +831,7 @@ SpreadData::Init(int nRows, int nCols)
 	int i, j;
 	RECT rc;
 
-	rcCopy.left = rcCopy.top = 0;	rcCopy.bottom = cRows = nRows;
-	rcCopy.right = cCols = nCols;	currpos.x = currpos.y = 0;
+	cRows = nRows;	cCols = nCols;				currpos.x = currpos.y = 0;
 	new_mark = bCopyCut = false;
 	if(!Disp) {
 		Disp = new SpreadWin(g_parent, this);
@@ -793,7 +845,6 @@ SpreadData::Init(int nRows, int nCols)
 			c_disp = (rc.right-rc.left)/CellWidth+1;
 			}
 		else return false;
-		Disp->ShowGrid(CellWidth, CellHeight, FirstWidth, &currpos);
 		pos_info.ssOrg.x = Disp->ssOrg.x;		pos_info.ssOrg.y = Disp->ssOrg.y;
 		pos_info.CurrText = CurrText;
 		}
@@ -885,7 +936,7 @@ SpreadData::Select(POINT *p)
 }
 
 void
-SpreadData::MarkRange(char *range)
+SpreadData::MarkRange(char *range, POINT *cp)
 {
 	AccRange *nr, *oldr;
 	int r, c;
@@ -896,8 +947,8 @@ SpreadData::MarkRange(char *range)
 	if(range) nr = new AccRange(range);
 	if(oldr && nr && oldr->GetFirst(&c, &r)) {
 		for( ; oldr->GetNext(&c, &r); ) {
-			if(r >= Disp->ssOrg.y && r < (r_disp +Disp->ssOrg.y) && c >= Disp->ssOrg.x 
-				&& c < (c_disp + Disp->ssOrg.x) && !nr->IsInRange(c, r) && etRows[r] && etRows[r][c]){
+			if(r >= Disp->ssOrg.y && r < (r_disp +Disp->ssOrg.y) && r < cRows && c >= Disp->ssOrg.x 
+				&& c < (c_disp + Disp->ssOrg.x) && c < cCols && !nr->IsInRange(c, r) && etRows[r] && etRows[r][c]){
 				etRows[r][c]->Mark(w, etRows[r][c] != CurrText ? 0 : 1);
 				}
 			}
@@ -913,7 +964,7 @@ SpreadData::MarkRange(char *range)
 		strcpy(m_range, range);
 	else if (m_range) m_range[0] = 0;
 	if(oldr) delete(oldr);	if(nr) delete(nr);
-	new_mark = true;
+	new_mark = true;		Disp->MarkButtons(m_range, cp);
 }
 
 void
@@ -921,15 +972,13 @@ SpreadData::HideMark(bool cclp)
 {
 	if(cclp && c_range && c_range != m_range){
 		free(c_range);	c_range = 0L;
-		rcCopy.left = rcCopy.top = 0;
-		rcCopy.bottom = cRows;		rcCopy.right = cCols;
 		}
 	if(m_range){
 		free(m_range);	m_range = 0L;
 		DoPlot(w);
 		}
-	if(cclp) EmptyClip();
-	new_mark = false;
+	if(cclp) EmptyClip();		new_mark = false;
+	Disp->MarkButtons(m_range, 0L);
 }
 
 bool
@@ -937,20 +986,25 @@ SpreadData::WriteData(char *FileName)
 {
 	FILE *File;
 	int i, j;
-	char tmp[800];
-	unsigned char *buff = 0L;
+	unsigned char *buff = 0L;
+	anyResult res;
+	bool bErr = false;
 
-	if(!cRows || !cCols || !etRows) return false;
-	BackupFile(FileName);
-	if(!(File = fopen(FileName, "w")))return false;
+	if(!cRows || !cCols || !etRows) return false;
+	if(!FileName) FileName = rlw_file;
+	if(FileName && FileName[0]) BackupFile(FileName);
+	else return false;
+	if(!(File = fopen(FileName, "w"))) {
+		ErrorBox("An error occured during write,\n\nplease try again!");
+		return false;
+		}
 	HideMark(true);
-	rcCopy.left = rcCopy.top = 0;	rcCopy.bottom = cRows;		rcCopy.right = cCols;
 	i = strlen(FileName);
 	//test for xml extension
 	if(!strcmp(".xml", FileName+i-4) || !strcmp(".XML", FileName+i-4)) {
 		MemList(&buff, FF_XML);
 		if(buff){
-			fprintf(File, "%s", buff);
+			if(fprintf(File, "%s", buff) <= 0) bErr = true;
 			free(buff);					fclose(File);
 			return true;
 			}
@@ -960,7 +1014,7 @@ SpreadData::WriteData(char *FileName)
 	if(!strcmp(".tsv", FileName+i-4) || !strcmp(".TSV", FileName+i-4)) {
 		MemList(&buff, FF_TSV);
 		if(buff){
-			fprintf(File, "%s", buff);
+			if(fprintf(File, "%s", buff) <= 0) bErr = true;
 			free(buff);					fclose(File);
 			return true;
 			}
@@ -970,7 +1024,20 @@ SpreadData::WriteData(char *FileName)
 	if(!strcmp(".rlw", FileName+i-4) || !strcmp(".RLW", FileName+i-4)) {
 		MemList(&buff, FF_RLW);
 		if(buff){
-			fprintf(File, "%s", buff);
+			if(rlw_file != FileName) {
+				if(rlw_file) free(rlw_file);		rlw_file = strdup(FileName);
+				}
+			if(fprintf(File, "%s", buff) <= 0) bErr = true;
+			free(buff);					fclose(File);
+			return true;
+			}
+		return false;
+		}
+	//test for slk extension
+	if(!strcmp(".slk", FileName+i-4) || !strcmp(".SLK", FileName+i-4)) {
+		MemList(&buff, FF_SYLK);
+		if(buff){
+			if(fprintf(File, "%s", buff) <= 0) bErr = true;
 			free(buff);					fclose(File);
 			return true;
 			}
@@ -978,14 +1045,25 @@ SpreadData::WriteData(char *FileName)
 		}
 	//else write csv
 	for(i = 0; i < cRows; i++) {
-		for(j = 0; j < cCols; j++) {
-			if(etRows[i][j] && etRows[i][j]->GetItem(tmp, sizeof(tmp)))
-				fprintf(File, "%s", tmp);
-			if(j < (cCols-1)) fprintf(File, ",");
+		for(j = 0; j < cCols; j++) {
+			if(etRows[i][j]) {
+				etRows[i][j]->GetResult(&res, false);		TranslateResult(&res);
+				switch(res.type) {
+				case ET_TEXT:
+					fprintf(File, "\"%s\"", res.text);
+					break;
+				case ET_VALUE:		case ET_DATE:	case ET_TIME:
+				case ET_DATETIME:	case ET_BOOL:
+					fprintf(File, "%s", res.text);
+					break;
+					}
+				}
+			if(j < (cCols-1)) fprintf(File, ", ");
 			}
-		fprintf(File, "\n");
+		if(fprintf(File, "\n") <= 0) bErr = true;
 		}
 	fclose(File);
+	if(bErr) ErrorBox("An error occured during write,\n\nplease try again!");
 	return true;
 }
 
@@ -1004,21 +1082,19 @@ 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)){
-			if(ReadXML(FileName, buffer, type, 0L)){
-				rcCopy.left = rcCopy.top = 0;
-				rcCopy.right = cCols;			rcCopy.bottom = cRows;
+			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);
+					}
 				return true;
 				}
 			return false;
 			}
 		if(0 == strcmp(".tsv", FileName+strlen(FileName)-4) ||
 			0 == strcmp(".TSV", FileName+strlen(FileName)-4)){
-			if(ReadTSV(FileName, buffer, type)){
-				rcCopy.left = rcCopy.top = 0;
-				rcCopy.right = cCols;			rcCopy.bottom = cRows;
-				return true;
-				}
-			return false;
+			return ReadTSV(FileName, buffer, type);
 			}
 		if(!(Cache = new ReadCache())) return false;
 		if(! Cache->Open(FileName)) {
@@ -1066,21 +1142,12 @@ SpreadData::ReadData(char *FileName, unsigned char *buffer, int type)
 		if(!success && !Cache->IsEOF()) {i++; j = 0;}	//eol
 		}while (ItemText[0] || !Cache->IsEOF());		//eof
 
-	Cache->Close();
-	delete Cache;
-	Cache = 0L;
-	if(FileName) {
-		rcCopy.left = rcCopy.top = 0;
-		rcCopy.right = cCols;
-		rcCopy.bottom = cRows;
-		}
+	Cache->Close();		delete Cache;		Cache = 0L;
 	Disp->ssOrg.x = Disp->ssOrg.y = 0;
 	return true;
 
 ReadError:
-	Cache->Close();
-	delete Cache;
-	Cache = 0L;
+	Cache->Close();		delete Cache;		Cache = 0L;
 	return false;
 
 }
@@ -1586,13 +1653,13 @@ SpreadData::InitCopy(int cmd, void *tmpl, anyOutput *o)
 {
 	int r, c;
 	AccRange *ar;
-	RECT rc_band;
+	RECT rc_band, rcCopy;
 	bool bRet = false;
-
+
+	rcCopy.left = rcCopy.top = 0;
+	rcCopy.bottom = cRows-1;		rcCopy.right = cCols-1;
 	if(cmd) {
 		bCopyCut = (cmd == CMD_CUT);
-		if(rcCopy.right > cCols) rcCopy.right = cCols;
-		if(rcCopy.bottom > cRows) rcCopy.bottom = cRows;
 		new_mark = false;
 		if(m_range && m_range[0]) {
 			if(c_range) free(c_range);		c_range = strdup(m_range);
@@ -1613,9 +1680,11 @@ SpreadData::InitCopy(int cmd, void *tmpl, anyOutput *o)
 			}
 		}
 	if(bRet || !cmd) {		//calculate animated mark
+		if(c_range && (ar = new AccRange(c_range))) {
+			ar->BoundRec(&rcCopy);			delete ar;
+			}
 		if(rcCopy.right < Disp->ssOrg.x || rcCopy.bottom < Disp->ssOrg.y) {
-			HideCopyMark();
-			return bRet;
+			HideCopyMark();			return bRet;
 			}
 		c = rcCopy.left >= Disp->ssOrg.x ? rcCopy.left : Disp->ssOrg.x;
 		r = rcCopy.top >= Disp->ssOrg.y ? rcCopy.top : Disp->ssOrg.y;
@@ -1678,7 +1747,7 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 			}
 		switch (mev->Action) {
 		case MOUSE_LBDOWN:
-			if(m_range && (mev->StateFlags & 0x08)) mrk_offs = strlen(m_range);
+			if(m_range && (mev->StateFlags & 0x18)) mrk_offs = strlen(m_range);
 			else mrk_offs = 0;
 			bActive = true;		new_mark = false;
 			if(!et_racc && CurrText && !CurrText->isInRect(&p)){
@@ -1709,7 +1778,7 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 					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);
 					}
-				if(!CurrText || et_racc)MarkRange(TmpTxt);
+				if(!CurrText || et_racc)MarkRange(TmpTxt, &cp);
 				return true;
 				}
 			if(mev->Action == MOUSE_LBDOUBLECLICK) bActive = false;
@@ -1737,13 +1806,13 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 					currpos2.x = cp.x;		currpos2.y = cp.y + 1;
 					}
 				else if((m_range) && !new_mark) HideMark(false);
-				if(et_racc) {
+				if(et_racc && !et_racc->isInRect(&p)) {
 					CurrText = et_racc;
-					if(m_range && m_range[0]) {
+					if(m_range && m_range[0] && (currpos.x != cp.x || currpos.y != cp.y)) {
 						CurrText->Command(CMD_ADDTXT, o, (DataObj*) m_range);
 						}
-					else if(!m_range) {
-						m_range = (char*)malloc(10);
+					else {
+						if(!m_range) m_range = (char*)malloc(20);
 						sprintf(m_range, "%s%d%", Int2ColLabel(currpos.x, false), currpos.y+1);
 						CurrText->Command(CMD_ADDTXT, o, (DataObj*) m_range);
 						free(m_range);	m_range = 0L;
@@ -1763,6 +1832,7 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 			return Disp->Command(CMD_SETSCROLL, 0L, w);
 		return false;
 	case CMD_ETRACC:
+		if(et_racc && tmpl && ((EditText*)tmpl)->parent != this) HideMark(false);
 		et_racc = (EditText*) tmpl;
 		if(CurrText && CurrText->parent != this) CurrText = 0L;
 		return true;
@@ -1794,14 +1864,14 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 		if(CurrText){
 			CurrText->Update(2, w, 0L);		CurrText->Update(1, w, 0L);
 			}
-		et_racc = 0L;
+		et_racc = 0L;						w->MouseCursor(MC_ARROW, true);
 		break;
 	case CMD_UPDHISTORY:
 		if(w) w->FileHistory();
 		break;
 	case CMD_MRK_DIRTY:
 		move_cr = CMD_CURRDOWN;
-		last_err = 0L;
+		err_msg = last_err = 0L;
 		if(Disp) return Disp->Command(cmd, tmpl, o);
 		return false;
 	case CMD_ADDCHAR:
@@ -1971,7 +2041,8 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 		else if(CurrText) return CurrText->Command(cmd, o, this);
 		Disp->Command(CMD_CURRPOS, &currpos, w);
 		return true;
-	case CMD_QUERY_COPY:		case CMD_CUT:
+	case CMD_QUERY_COPY:		case CMD_CUT:
+		et_racc = 0L;
 		return InitCopy(cmd, tmpl, w);
 	case CMD_GET_CELLDIMS:
 		if(tmpl) {
@@ -2006,6 +2077,12 @@ SpreadData::Command(int cmd, void *tmpl, anyOutput *o)
 		DoPlot(o);
 		Undo.SetDisp(w);
 		break;
+	case CMD_GETMARK:
+		if(tmpl && m_range && m_range[0]) {
+			*((char**)tmpl) = m_range;
+			return true;
+			}
+		return false;
 	case CMD_INSROW:
 		return InsertRows();
 	case CMD_INSCOL:
@@ -2028,7 +2105,7 @@ SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flag
 	char TmpTxt[1024], *tmp_range;
 	unsigned char *pgr = 0L;
 	RECT rc_undo;
-
+
 	if(file) {
 		if(!(XMLcache = new ReadCache())) return false;
 		if(! XMLcache->Open(file)) {
@@ -2100,7 +2177,7 @@ SpreadData::ReadXML(char *file, unsigned char *buffer, int type, DWORD undo_flag
 				}while(!(pgr[cpgr-1] == '<' && pgr[cpgr-2] == 0x0a));
 			pgr[cpgr-2] = 0;
 			while(XMLcache->Getc() != 0x0a);
-			OpenGraph(Disp, 0L, pgr);
+			OpenGraph(Disp, 0L, pgr, false);
 			free(pgr);			tag = 0;
 			}
 		else tag = 0;
@@ -2232,18 +2309,26 @@ SpreadData::MemList(unsigned char **ptr, int type)
 	int i, j, k, nc, nl, cb = 0; 
 	long cbd = 0, size;
 	char tmptxt[8000];
-	double val;
 	*ptr = (unsigned char *)malloc(size = 10000);
 	unsigned char *tmpptr;
 	bool bLimit = true;
-	AccRange *ar = 0L;
+	AccRange *ar;
+	anyResult res;
+	RECT rcCopy;
 
 	if(!(*ptr))return false;
-	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;\n");
+	if (c_range &&  c_range[0]) {
+		ar = new AccRange(c_range);			ar->BoundRec(&rcCopy);
+		if(bCopyCut) Undo.DataObject(Disp, w, this, &rcCopy, 0L);
+		}
+	else {
+		ar = 0L;	rcCopy.left = rcCopy.top = 0;
+		rcCopy.right = cCols-1;				rcCopy.bottom = cRows-1;
+		}
+	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");
 	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);
@@ -2258,37 +2343,46 @@ SpreadData::MemList(unsigned char **ptr, int type)
 		cbd = sprintf((char*)*ptr, "<?xml version=\"1.0\"?><!DOCTYPE RLPlot-workbook>\n"
 		"<RLPlot-data rows=\"%d\" columns=\"%d\" >\n", cRows, cCols);
 		}
-	if (c_range &&  c_range[0]) {
-		ar = new AccRange(c_range);
-		if(bCopyCut) Undo.DataObject(Disp, w, this, &rcCopy, 0L);
-		}
 	for(nl =0, i = rcCopy.top; i <= rcCopy.bottom; i++, nl++) {
 		for(nc = 0, j = rcCopy.left; j <= rcCopy.right; cb = 0, j++, nc++) {
 			switch (type) {
 			case FF_TSV:
 				if(nl || nc) cb = sprintf(tmptxt,"%s", nc ? "\t" : "\n");
-				if(etRows[i] && etRows[i][j] && etRows[i][j]->text){
-					if((ar && ar->IsInRange(j,i)) || !ar) {
-						for(k = 0; k < 7990 && (etRows[i][j]->text[k]); k++) 
-							tmptxt[cb++] = etRows[i][j]->text[k];
+				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);
 						}
 					tmptxt[cb] = 0;
 					}
 				break;
 			case FF_SYLK:
 				if(etRows[i] && etRows[i][j] && etRows[i][j]->text && ((ar && ar->IsInRange(j,i)) || !ar)){
-					cb = sprintf(tmptxt, "C;Y%d;X%d;K", nl+1, nc+1);
-					if(etRows[i][j]->GetValue(&val)){
-						cb += sprintf(tmptxt+cb, "%lf", val);
-						while(tmptxt[cb-1] == '0') tmptxt[--cb] = 0;
-						if(tmptxt[cb-1] == '.') tmptxt[--cb] = 0;
-						cb += sprintf(tmptxt+cb, "\n");
-						}
-					else {
-						etRows[i][j]->GetItem(TmpTxt, 258);
-						cb += sprintf(tmptxt+cb, "%s\n", TmpTxt);
-						if(cb >= 267) bLimit = false;
-						}
+					etRows[i][j]->GetResult(&res, false);
+					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);
+						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);
+						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);
+						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));
+						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);
+						break;
+						}
 					if(bCopyCut) etRows[i][j]->SetText("");
 					}
 				break;
@@ -2329,7 +2423,10 @@ SpreadData::MemList(unsigned char **ptr, int type)
 		//note: cbd may be greater than size !
 		}
 	if(ar) delete ar;
-	bCopyCut = false;
+	if(bCopyCut && type == FF_XML || type == FF_SYLK || type == FF_RLW){
+		bCopyCut = false;
+		DoPlot(w);
+		}
 	return true;
 }
 
@@ -2338,14 +2435,8 @@ void SpreadMain(bool show)
 	static SpreadData *w = 0L;
 
 	if(show) {
-		w = new SpreadData(0L);
-		if(!w ||!(w->Init(50, 10))){
-			delete w;
-			w = 0L;
-			}
+		if(w = new SpreadData(0L)) w->Init(50, 10);
 		do_formula(w, 0L);			//init mfcalc
 		}
-	else if (w) {
-		delete(w);
-		}
+	else if (w) delete(w);
 }

-- 
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