//	Main class///*   *	Secant and Tangent Line Applet *	By Mike May, S.J., August 2001 *	e-mail: maymk@slu.edu * *	Some of the work derives from the Riemann Sum applet *	by Brendon Cheves & Bill Ziemer *  e-mail: brendon@csulb.edu  wziemer@csulb.edu *  expr package Copyright 1996 by Darius Bacon  */// Last update 8/2/2001/* *	 *  The applet graphs a function and the specified linear approximation at a  *  point X0.  The linear approximation are those with difference quotient  *  slopes.  There is the usual secant line slope used in the standard *  definition of the derivative, as well as a left secant for balance. *  There is also a line with the slope obtained by the balanced difference *  quotient used by most calculators.  The user has control of the dx *  value, either by entering it as text, or by mouse clicks, or by button *  control. *	 *  The structure of the program has a main class SecantTangent.   *  The work is broken into a number of visible classes: *  DrawingPanel, FeedbackPanel, HelpArea, and AboutArea. *  The names of these classes are fairly self descriptive. *  A subsidiary class DrawingPanel is the ZFunction class.  *  This ZFunction class uses a parser that calls on the following classes: *  Expr, Parser, Syntax_error, Test, TrivialClass and Variable. *	The subsidaiary classes of FeedbackPanel are InputPanel, ControlPanel, *	OutputPanel, and DomainPanel. *	MultilineLabel is used by AboutArea. *//*   * * public class SecantTangent extends Applet *	public void init() *	public boolean action(Event e, Object arg) * *	The main applet has a title label and buttons to switch between three *	cards, the main card, the help card, and the about card. *	The about card provides author information. *	The help card gives help that a user may need to run the applet. *	The main card is what we might think of as the applet proper.  It *	contains a drawing panel and a feedback panel.  The drawing panel *	and feedback panel are separate objects where most of the real work is done. * *	The init method sets up the basic interface though the most of the hard *	details are in the feedback panel and the drawing panel. * *	An action method is needed to deal with the buttons that switch cards. * * *  public void fixMain() *  public void importFeedbackPanelValues() * *	The methods of this class involve when the DrawingPanel and FeedbackPanel *	need to communicate with each other or when an action on one calls for a response *	on the other.  The majority of the work is done with the fixMain method. *	A subsidiary method of fixMain is importFeedbackPanelValues. * * *	public void domainLimitsDrawingPanelToFeedbackPanel() *	public void drawingPanelClick(double xReal) * *	The other methods in the class are for when an action in one subclass needs a  *	limited response in the other subclass. */// java packagesimport java.applet.*;import java.awt.*;import java.lang.Math;import expr.*;			// f(x) parser by Darius Bacon						// Modified by Mike May, S.J.public class SecantTangent extends Applet{//  Declare variables	int	 	drawingPanelWidth = 470, drawingPanelHeight = 405;//	int		clickIndex = 0;  //	GUI elements   			Button 			helpButton, aboutButton, mainButton;	Label 			titleLabel;    CardLayout		theCards;    	    Panel	 		mainCd, mainPanel, cardChoicePanel;    HelpArea		helpText;    AboutArea		aboutText;    FeedbackPanel	feedbackPanel;   	DrawingPanel 	theDrawingPanel;    public void init()    {		this.setLayout(null);		resize(700,500);  	   	//	Set up the pieces		titleLabel = new Label("Secant and Tangent Lines", Label.CENTER);		setLayout(new BorderLayout(3,3));		this.add(titleLabel, BorderLayout.NORTH);		titleLabel.setFont(new Font("Dialog", Font.BOLD, 18));   	      	    mainPanel = new Panel();		this.add(mainPanel, BorderLayout.CENTER);    	// create a card layout and 3 cards    	theCards = new CardLayout(0,0);		mainPanel.setLayout(theCards); 		// create the main card 		mainCd = new Panel(); 		mainPanel.add("main",mainCd); 		mainCd.setLayout(new BorderLayout(3,3)); 		// create the about card		aboutText = new AboutArea();   	    aboutText.setBounds(0,0,600,380); 		mainPanel.add("about",aboutText); 		// create the help card		helpText = new HelpArea(600, 300);   	    helpText.setBounds(0,0,600,380); 		mainPanel.add("help",helpText);  		// create the feedback panel and add it to the main cd 		feedbackPanel = new FeedbackPanel(this);   	    feedbackPanel.setBounds(480,0,200,405);		mainCd.add(feedbackPanel, BorderLayout.EAST); 		feedbackPanel.setLayout(null);						// create the drawing panel and add it to the main cd  		theDrawingPanel = new DrawingPanel(this);		mainCd.add(theDrawingPanel, BorderLayout.CENTER);		//	move the data from feedback panel to drawing panel and initialize		feedbackPanel.collectData();		feedbackPanel.resetYBounds();		importFeedbackPanelValues();		fixMain(); 			/**	 *	Add a panel to the bottom of the screen to let the user choose	 *	between cards.	 */   	    cardChoicePanel = new Panel();   	    this.add(cardChoicePanel, BorderLayout.SOUTH);		cardChoicePanel.setLayout(new GridLayout(1,0,10,0));		mainButton = new Button("Main Panel");		cardChoicePanel.add(mainButton);		helpButton = new Button("Help Panel");		cardChoicePanel.add(helpButton);		aboutButton = new Button("About Panel");		cardChoicePanel.add(aboutButton);		// finally, show the main card		theCards.show(mainPanel,"main");    }   // init     	// handle GUI events    public boolean action(Event e, Object arg)	{		double outputdx;     	if(e.target == aboutButton)      	{			theCards.show(mainPanel,"about");      		return true;      	}      	else if(e.target == helpButton)      	{			theCards.show(mainPanel,"help");      		return true;      	}      	else if(e.target == mainButton)      	{			theCards.show(mainPanel,"main");      	    feedbackPanel.collectData();      	    fixMain();        	paint(theDrawingPanel.getGraphics());	   		return true;      	} 		else return super.action(e,arg);		}  //  action    public void fixMain()    {		importFeedbackPanelValues();  	    theDrawingPanel.updateDrawingValues();	   	paint(getGraphics());	    theDrawingPanel.repaint();    }	//	fixMain            public void importFeedbackPanelValues()    { 		theDrawingPanel.xBase 			= feedbackPanel.xBase; 		theDrawingPanel.x1 				= feedbackPanel.x1; 		theDrawingPanel.xDel 			= feedbackPanel.xDel; 		theDrawingPanel.xMin 			= feedbackPanel.xMin; 		theDrawingPanel.xMax			= feedbackPanel.xMax; 		theDrawingPanel.bottomY 		= feedbackPanel.yMin; 		theDrawingPanel.topY			= feedbackPanel.yMax; 		theDrawingPanel.firstIndex 		= feedbackPanel.firstIndex; 		theDrawingPanel.clickIndex 		= feedbackPanel.clickIndex;	    theDrawingPanel.functionString	= feedbackPanel.functionString;	    theDrawingPanel.guessString 	= feedbackPanel.guessString; 		theDrawingPanel.guessPlotState 	= feedbackPanel.guessPlotState; 		theDrawingPanel.derivPlotState 	= feedbackPanel.derivPlotState;    }	//	importfeedbackPanelValues    	public void domainLimitsDrawingPanelToFeedbackPanel()	{		feedbackPanel.yMin = theDrawingPanel.bottomY;		feedbackPanel.yMax = theDrawingPanel.topY;		feedbackPanel.xMin = theDrawingPanel.xMin;		feedbackPanel.xMax = theDrawingPanel.xMax;		feedbackPanel.sendDomainValues();	}	//	domainLimitsDrawingPanelToFeedbackPanel 	public void drawingPanelClick(double xReal, double yReal)	{		feedbackPanel.xBase	= theDrawingPanel.xBase;		feedbackPanel.xDel	= theDrawingPanel.xDel;		feedbackPanel.sendInputValues();		feedbackPanel.collectData();		fixMain();	}	//	drawingPanelClick}	//	SecantTangent//////////////		Other pieces/////////* *	The drawing panel is an object for the graphical display of the applet. * *public class DrawingPanel extends Canvas implements MouseListener, MouseMotionListener *	public  DrawingPanel(SecantTangent secTangent, ZFunction f) *  public void mouseDragged(MouseEvent e)  *  public void mouseMoved(MouseEvent e)  *  public void mousePressed(MouseEvent e) { *  public void mouseReleased(MouseEvent e) { *  public void mouseEntered(MouseEvent e) *  public void mouseExited(MouseEvent e) *  public void mouseClicked(MouseEvent e) * *	The constructor does little more than extend canvas and identify the applet *	and applet so that information can be passed back and forth.  It also adds *	action listeners for the mouse.  The corresponding methods are included, *	though all but mouseDragged and mouseReleased are empty.   * * * 	public void updateDrawingValues() *	public void resetNumericDerivs(double x, double xDel) *	public void findApproxString() *	public void updateApproximations() * *	This next set of methods do the work of revising values that belong to the  *	DrawingPanel. * * *	public void repaint() *	public void paint(Graphics g) *	public void plot(Graphics g, ZFunction f, double leftX, double rightX, Color color) *	public void plotNumDeriv(Graphics g, ZFunction f, double leftX, double rightX) *	public void drawAxis(Graphics g) *	public void drawLimits(Graphics g) * *	The repaint method simply gets the graphics and calls paint which does all the work. *  The methods plot, plotNumDeriv, drawAxis, and  drawLimits do parts of the plotting. * * *	public double xPixelToReal(double xPixel) *	public double xPixelToReal(int xPixel) *	public int xRealToPixel(double xReal) *	public int xRealToPixel(int xReal) *	public int yRealToPixel(double yReal) *	public int yRealToPixel(int yReal) *	public double yPixelToReal(double yPixel) *	public double yPixelToReal(int yPixel) * *	These methods switch between coordinate and pixel measurements of locations on  *	the graph *	 */import java.awt.event.*;import java.awt.*;import java.applet.*;import MIO.*;public class DrawingPanel extends Canvas implements MouseListener, MouseMotionListener{//  Declare variables//	variables concerned with the size of the panel and how much is used //	for the actual drawing.  //	The left and right offsets and the vertical offsets are just to //	make everything look nice.  Nothing important is graphed in the offset//	area.  The panel is set up with a single offset//	at the top and a double one at the bottom of the panel.	int	 	drawingPanelWidth = 470, drawingPanelHeight = 405,			leftXOffset = 40, rightXOffset = 40,			areaXWidth = drawingPanelWidth - leftXOffset - rightXOffset,			YOFFSET = 20;//	variables concerning the approximation to be graphed	int		firstIndex = 0, clickIndex;	double	xBase=-1.0, x1=1.0, xDel;	double  leftX, rightX, bottomY = -5.0, topY = 5.0, halfHigh, halfWide;	double  xMin = -5.0, xMax = 5.0;	double	zeroDeriv, firstDeriv, secSlope, leftSlope;	String	approxString = " ", functionString, guessString;	boolean		guessPlotState, derivPlotState;   			ZFunction	theFunction, guessFunction;	ZFunction	rightSecant, leftSecant, balancedLinear;	SecantTangent	applet;	public  DrawingPanel(SecantTangent secTangent)	{		super();		  	   	theFunction 	= new ZFunction();  	   	guessFunction 	= new ZFunction();  	   	rightSecant 	= new ZFunction();  	   	leftSecant 		= new ZFunction();  	   	balancedLinear	= new ZFunction();		theFunction.parse("x+0.1*x^2-3*sin(x)");		theFunction.setXRange(-5.0, 5.0);		theFunction.determineYMinYMax();//		getYLimits();		guessFunction.parse("x");		applet = secTangent;		addMouseMotionListener(this);		addMouseListener(this);	}	//	DrawingPanel	constructor	//	methods for the mouse listener and the mouse motion listener    public void mouseDragged(MouseEvent e)     {  		if(clickIndex < 2) mouseAction(e);          }	//	mouseDragged    public void mouseMoved(MouseEvent e)     {    }	//mouseMoved    public void mousePressed(MouseEvent e) {    }	//	mousePressed    public void mouseReleased(MouseEvent e) {  		mouseAction(e);         }	//	mouseReleased    public void mouseEntered(MouseEvent e) {    }	//	mouseEntered	    public void mouseExited(MouseEvent e) {    }	//	mouseExited    public void mouseClicked(MouseEvent e) {    }	//	mouseClicked	//	end of motion litener methods		    public void mouseAction(MouseEvent e) {   		double 	xRealClick = xPixelToReal(e.getX());  		double 	yRealClick = yPixelToReal(e.getY());  		double	xReal2 = ((int)(xRealClick*1000))/1000.0;  		double	yReal2 = ((int)(yRealClick*1000))/1000.0;		if(clickIndex == 0) xBase = xReal2;		if(clickIndex == 1) xDel = xReal2 - xBase;  		if(clickIndex == 2)	// center graph  			{	  		halfHigh = (topY - bottomY)/2;	  		topY = yReal2 + halfHigh;	  		bottomY = yReal2 - halfHigh;	  		halfWide = (xMax - xMin)/2;	  		xMax = xReal2 + halfWide;	  		xMin = xReal2 - halfWide;//	  		postYLimits(); 	 		applet.domainLimitsDrawingPanelToFeedbackPanel();       	 		}  		applet.drawingPanelClick(xReal2, yReal2);         }	//	mouseAction   	public void updateDrawingValues()	{		drawingPanelWidth = getSize().width;		drawingPanelHeight = getSize().height;		areaXWidth = drawingPanelWidth - leftXOffset - rightXOffset;	    guessFunction.parse(guessString);		leftX 	= xMin - (1.0*leftXOffset/areaXWidth)*(xMax-xMin);		rightX	= xMax + (1.0*rightXOffset/areaXWidth)*(xMax-xMin);	    resetNumericDerivs(xBase, xDel);	    findApproxString();	}	//	updateDrawingValues   	public void resetNumericDerivs(double x, double xDel)	{	    theFunction.parse(functionString);		theFunction.findNumDerivs(x, xDel);		zeroDeriv 	= theFunction.zeroDeriv;		firstDeriv 	= theFunction.firstDeriv;		secSlope	= theFunction.secSlope;		leftSlope	= theFunction.leftSlope;	}	//	getYlimits   	public void findApproxString()	{		if(firstIndex == 0) approxString = "RtApr(X) = " 			+ Mio.doubleToStringSigFigures(zeroDeriv,5) + " + " + Mio.doubleToStringSigFigures(secSlope,5) + "*(X-X0)";		if(firstIndex == 1) approxString = "BalApr(X) = " 			+ Mio.doubleToStringSigFigures(zeroDeriv,5) + " + " + Mio.doubleToStringSigFigures(firstDeriv,5) + "*(X-X0)";		if(firstIndex == 2) approxString = "LtApr(X) = " 			+ Mio.doubleToStringSigFigures(zeroDeriv,5) + " + " + Mio.doubleToStringSigFigures(leftSlope,5) + "*(X-X0)";		if(firstIndex == 3) approxString = "BalApr(X) = " 			+ Mio.doubleToStringSigFigures(zeroDeriv,5) + " + " + Mio.doubleToStringSigFigures(firstDeriv,5) + "*(X-X0)";	}	//	findApprox			   	public void updateApproximations()	{  	   	theFunction.findNumDerivs(xBase, xDel);  	   	String rightSecantString = new String(Mio.doubleToStringNoE(theFunction.zeroDeriv) +  	   		"+" + Mio.doubleToStringNoE(theFunction.secSlope) + "*(x-" + xBase + ")");  	   	rightSecant.parse(rightSecantString);  	   	String leftSecantString = new String(Mio.doubleToStringNoE(theFunction.zeroDeriv) +  	   		"+" + Mio.doubleToStringNoE(theFunction.leftSlope) + "*(x-" + xBase + ")");  	   	leftSecant.parse(leftSecantString);  	   	String balancedLinearString = new String(Mio.doubleToStringNoE(theFunction.zeroDeriv) +  	   		"+" + Mio.doubleToStringNoE(theFunction.firstDeriv) + "*(x-" + xBase + ")");  	   	balancedLinear.parse(balancedLinearString);	}	public void repaint()	{		paint(getGraphics());	}	//	repaint		public void paint(Graphics g)	{		updateDrawingValues();	//	clear the canvas		g.clearRect(0,0,drawingPanelWidth,drawingPanelHeight);		updateApproximations();	//	plot the function				plot(g, theFunction, leftX, rightX, Color.blue);		if(guessPlotState == true) plot(g, guessFunction, leftX, rightX, Color.cyan);		if(derivPlotState == true) plotNumDeriv(g, theFunction, leftX, rightX);		if(firstIndex == 0) plot(g, rightSecant, leftX, rightX, Color.magenta);		if(firstIndex == 1) plot(g, balancedLinear, leftX, rightX, Color.red);		if(firstIndex == 2) plot(g, leftSecant, leftX, rightX, Color.green);		if(firstIndex == 3)		{			plot(g, rightSecant, leftX, rightX, Color.magenta);			plot(g, leftSecant, leftX, rightX, Color.green);			plot(g, balancedLinear, leftX, rightX, Color.red);		}			//	add axes and limits				drawAxis(g); 		drawLimits(g);	}	//	paint		public void plot(Graphics g, ZFunction f, double leftX, double rightX, Color color)	{		int y1, y2, j;      	g.setColor(color);				f.xvar.set_value(xPixelToReal(leftX));		y1 = yRealToPixel(f.expr.value());				for(int i=xRealToPixel(leftX); i < xRealToPixel(rightX); i++)		{			f.xvar.set_value(xPixelToReal(i+1));			y2 = yRealToPixel(f.expr.value());			// Bug in drawLine that freaks when both arguments 			//  outside drawing area; yields spurious vertical lines			if( (0 <= y2) && (y2 <= drawingPanelHeight)) 			{	g.drawLine(i, y1, i+1, y2);			}						y1 = y2;		}	}  //  plot	public void plotNumDeriv(Graphics g, ZFunction f, double leftX, double rightX)	{		int y1, y2, j;      	g.setColor(Color.orange);				y1 = yRealToPixel(f.findNumDeriv(leftX, xDel));				for(int i=xRealToPixel(leftX); i < xRealToPixel(rightX); i++)		{			y2 = yRealToPixel(f.findNumDeriv(xPixelToReal(i+1), xDel));			// Bug in drawLine that freaks when both arguments 			//  outside drawing area; yields spurious vertical lines			if( (0 <= y2) && (y2 <= drawingPanelHeight)) 			{	g.drawLine(i, y1, i+1, y2);			}						y1 = y2;		}	}  //  plotNumDeriv	// draw the axis	public void drawAxis(Graphics g)	{	    int xAxisPixel, yAxisPixel;       	int x1Pixel = (int) xRealToPixel(x1);       		  	g.setColor(Color.black); 	  	 	  	xAxisPixel = yRealToPixel(0); 	  	if(xAxisPixel > drawingPanelHeight - 50) xAxisPixel = drawingPanelHeight - 50; 	  	if(xAxisPixel < 28) xAxisPixel = 28; 	  	yAxisPixel = leftXOffset;				// x axis        g.drawLine(0,xAxisPixel,drawingPanelWidth - 20,xAxisPixel);	         // y axis        g.drawLine(yAxisPixel,20,                       yAxisPixel,drawingPanelHeight-10);                g.drawString("X",drawingPanelWidth - 15,xAxisPixel + 4);        g.drawString("Y",yAxisPixel-2,17);		//	approximating function 	  	g.setColor(Color.red); 	  	if(firstIndex == 0) g.setColor(Color.magenta); 	  	if(firstIndex == 2) g.setColor(Color.green);		g.drawString(approxString, yAxisPixel + 4,drawingPanelHeight-25);		 	}  //  drawAxis	// draw limits in the proper places	public void drawLimits(Graphics g)	{      	int xAxisPixel, yAxisPixel, xMaxPixel, xMidPixel, yPixel;      	int xBasePixel, x1Pixel;      	double yVal;      	xBasePixel = (int) xRealToPixel(xBase);      	x1Pixel = (int) xRealToPixel(x1);      	xAxisPixel = (int) yRealToPixel(0); 	  	if(xAxisPixel > drawingPanelHeight - 50) xAxisPixel = drawingPanelHeight - 50; 	  	if(xAxisPixel < 28) xAxisPixel = 28;      	yAxisPixel = leftXOffset;      	xMidPixel  = leftXOffset + areaXWidth/2;      	xMaxPixel  = leftXOffset + areaXWidth;      	g.setColor(Color.red);				// x limit		g.drawString(Mio.doubleToStringSigFigures(xMin, 4), yAxisPixel + 4,xAxisPixel + 14);		g.drawLine(yAxisPixel,xAxisPixel - 2, yAxisPixel,xAxisPixel + 2);		g.drawString(Mio.doubleToStringSigFigures((xMin + xMax)/2.0, 4), xMidPixel + 4,xAxisPixel + 14);		g.drawLine(xMidPixel,xAxisPixel - 2, xMidPixel,xAxisPixel + 2);		g.drawString(Mio.doubleToStringSigFigures(xMax, 4), xMaxPixel + 4,xAxisPixel + 14);		g.drawLine(xMaxPixel,xAxisPixel - 2, xMaxPixel,xAxisPixel + 2);				// y limit		yVal = topY;		yPixel = yRealToPixel(yVal);		g.drawString(Mio.doubleToStringSigFigures(yVal, 4), yAxisPixel - 40,yPixel + 3);		g.drawLine(yAxisPixel - 2,yPixel, yAxisPixel + 2,yPixel);				yVal = bottomY;		yPixel = yRealToPixel(yVal);		g.drawString(Mio.doubleToStringSigFigures(yVal, 4), yAxisPixel - 40,yPixel + 3);		g.drawLine(yAxisPixel - 2,yPixel, yAxisPixel + 2,yPixel);				//	(X0, f(X0))		g.drawString(Mio.doubleToStringSigFigures(xBase, 4), xBasePixel + 4,xAxisPixel + 14);		g.drawString("X0", xBasePixel + 4,xAxisPixel + 28);		g.drawLine(xBasePixel,xAxisPixel - 2, xBasePixel,xAxisPixel + 2);		yVal = theFunction.value(xBase);		yPixel = yRealToPixel(yVal);		g.drawString(Mio.doubleToStringSigFigures(yVal, 4), yAxisPixel - 40,yPixel + 3);		g.drawLine(yAxisPixel - 2, yPixel, yAxisPixel + 2, yPixel);		g.drawLine(xBasePixel - 2, yPixel, xBasePixel + 2, yPixel);		g.drawLine(xBasePixel,yPixel - 2, xBasePixel,yPixel + 2);				//	(X1, f(X1))		g.drawString(Mio.doubleToStringSigFigures(x1, 4), x1Pixel + 4,xAxisPixel -16);		g.drawString("X1", x1Pixel + 4, xAxisPixel -2);		g.drawLine(x1Pixel, xAxisPixel - 2, x1Pixel, xAxisPixel + 2);		yVal = theFunction.value(x1);		yPixel = yRealToPixel(yVal);		g.drawString(Mio.doubleToStringSigFigures(yVal, 4), yAxisPixel - 40,yPixel + 3);		g.drawLine(yAxisPixel - 2, yPixel, yAxisPixel + 2, yPixel);		g.drawLine(x1Pixel - 2, yPixel, x1Pixel + 2, yPixel);		g.drawLine(x1Pixel, yPixel - 2, x1Pixel, yPixel + 2);		  	}  //  drawLimits				// input pixel, output real value in interval [xMIn, xMax]	public double xPixelToReal(double xPixel)	{		return ((xPixel - leftXOffset) * (xMax - xMin) / 		            areaXWidth + xMin);	}  //  xPixelToReal		public double xPixelToReal(int xPixel)	{		return ((xPixel - leftXOffset) * (xMax - xMin) / 		            areaXWidth + xMin);	}  //  xPixelToReal	// input real, output pixel in interval [0, XSCALE]	public int xRealToPixel(double xReal)	{		return (int)((xReal - xMin) / 		              (xMax - xMin) * areaXWidth + leftXOffset);	}  //  xRealToPixel	public int xRealToPixel(int xReal)	{		return (int)((xReal - xMin) / 		              (xMax - xMin) * areaXWidth + leftXOffset);			}  //  xRealToPixel	// input real value, output pixel in interval [0, YSCALE]	public int yRealToPixel(double yReal)	{		return (int)((yReal - topY) * (drawingPanelHeight - 3*YOFFSET) / 		         (bottomY - topY) + YOFFSET);	}  //  yRealToPixel	public int yRealToPixel(int yReal)	{		return (int)((yReal - topY) * (drawingPanelHeight - 3*YOFFSET) / 		        (bottomY - topY) + YOFFSET);	}  //  yRealToPixel	// input pixel, output real in interval [yMin, yMax]	public double yPixelToReal(double yPixel)	{		return ((yPixel - YOFFSET) * (bottomY - topY) / 		        (drawingPanelHeight - 3*YOFFSET) + topY);	}  //  yPixelToReal	public double yPixelToReal(int yPixel)	{		return ((yPixel - YOFFSET) * (bottomY - topY) / 		        (drawingPanelHeight - 3*YOFFSET) + topY);	}  //  yPixelToReal}	//	DrawingPanel class// ZFunction Class/*  Modified by Mike May,  August 2001 *	Inspired by a class witten Bill Ziemer and Brendon Cheves *	that was based upon the Java Polygon class *	 *	public class ZFunction	public ZFunction() *	public void parse( String f ) *	 *	The class ZFuncttion is a class for evaluating functions defined by a string. *	the parse method sends the string over to the Parser class for parsing *	 * *	public double value(double x) *	public double findNumDeriv(double x, double xDel) *	public double findDifferenceQuotient(double xa, double xb) *	public void findNumDerivs(double xBase, double xDel) *	 *	These methods either evaluate the function at X or evaluate difference *	quotients related to the function. * *	 *	public void determineYMinYMax() *	public void setXRange(double f, double l) * *	The last two methods are useful in setting finding appropriate limits *	to use when graphing the function. */// java packagesimport java.applet.*;import java.awt.*;import java.lang.Math;import expr.*;	// expr package Copyright 1996 by Darius Baconpublic class ZFunction{	//Real number bounds for the function	public double yMin = -5.0, yMax = 5.0;	public double xMin = -5.0, xMax = 5.0;	public double zeroDeriv, firstDeriv, secSlope, leftSlope; 	//	created for access to infinity constants	Double doubleCheck = new Double(1.0);	 	public Expr expr, linApprox;	public Variable xvar;	public double realArea, areaSum, fixedpt;	int iterate, endit, changer;	public ZFunction()	{		// set up the parsing variables		xvar = Variable.make("x");		Variable.make("pi").set_value (Math.PI);			Variable.make("PI").set_value (Math.PI);			Variable.make("Pi").set_value (Math.PI);			Variable.make("e").set_value (Math.exp(1));	/* * 	¹ and e are not in the parsing constructor */	}  //  ZFunction constructor		/*	 *	Parse the function	 */	 	public void parse( String f ) 	{	   	try	   	{expr = Parser.parse(f);}		catch (Syntax_error se)		{			System.err.println ("Syntax error: " + se);			return;		}	}  // parse		public double value(double x)	{		xvar.set_value(x);		return expr.value();	}  //  value 				public double findNumDeriv(double x, double xDel)	{		return findDifferenceQuotient(x - xDel, x + xDel);	}	//	findNumDerivs 			public double findDifferenceQuotient(double xa, double xb)	{		return (value(xb) - value(xa))/(xb - xa);	}	//	findNumDerivs			public void findNumDerivs(double xBase, double xDel)	{		zeroDeriv 	= value(xBase);		firstDeriv	= findDifferenceQuotient(xBase + xDel, xBase - xDel);		secSlope 	= findDifferenceQuotient(xBase + xDel, xBase);		leftSlope 	= findDifferenceQuotient(xBase, xBase - xDel);	}	//	findNumDerivs			public void determineYMinYMax()	{		double dx = (xMax-xMin)/500.0, tempY;				yMin = doubleCheck.POSITIVE_INFINITY;		yMax = doubleCheck.NEGATIVE_INFINITY;				for(int i=0;i<=500;i++)		{			tempY = value(xMin + i*dx);			if(tempY > yMax) 		yMax = tempY;						if(tempY < yMin)	yMin = tempY;		}		//	Round to three decimal places		yMax = ((int)(yMax*1000))/1000.0;		yMin = ((int)(yMin*1000))/1000.0;		//	Fudge things so that the X-axis is included		if (yMin > -.5) yMin = -.5;		if (yMax < 0.5) yMax = 0.5;	}  //  determineYminYMax	 	// set x range manually	public void setXRange(double f, double l)	{		xMin = f;		xMax = l;	}  //  setXRange	} // end of ZFunction Class/* *	The feedback panel is intended to contain all the inputs and text *	outputs used by the applet.   * *public class FeedbackPanel extends Panel *	public FeedbackPanel(SecantTangent secantTangent) *	public void collectData() *	public void update() *	public void resetYBounds() *  public void getInputValues() *	public void sendInputValues() *  public void getDomainValues() *	public void sendDomainValues() *  public void getControlValues() *	public void sendOutputValues() * *	It is broken into four subpanels, one each for: user supplied inputs, *	the domain and range of the graph, control values of what will be graphed, *	and for output.  There may be a get and send method for each subpanel. *	The fixInputs method collects data from all panels. *	The update panel and resetYbounds methods are there to invoke methods *	in the panel that contains the FeedbackPanel. * * *public class InputPanel extends Panel *	public InputPanel(FeedbackPanel fPanel) *  public boolean action(Event e, Object arg) *	public void collectInputValues() *	public void postInputValues() *	int intFromTextField(TextField tf)  *	double doubleFromTextField(TextField tf)  *	public String niceOut(double number, int prec) * *public class ControlPanel extends Panel *	public ControlPanel(FeedbackPanel fPanel) *	class SymItem implements java.awt.event.ItemListener *		public void itemStateChanged(java.awt.event.ItemEvent event) *	public void collectControlValues() * *public class OutputPanel extends Panel *	public OutputPanel() *	public void postOutput() *	public String niceOut(double number, int prec) * *public class DomainPanel extends Panel *	public DomainPanel(FeedbackPanel fPanel) *  public boolean action(Event e, Object arg) *	public void postDomainValues() *	public void collectDomainValues() *	double doubleFromTextField(TextField tf)  *	public String niceOut(double number, int prec) * * *	In addition to its constructor, each of the four subpanels may have an action *	listener, methods to collect and post data, and some input and output *	formating methods. */import java.awt.*;import java.applet.*;import MIO.*;public class FeedbackPanel extends Panel{	/*	 *		Public variables that are either inputs or outputs to be passed	 */	double	xBase, xDel, zeroDeriv, balancedSlope, leftSlope, rightSlope; 	double  yMin = -5.0, yMax = 5.0;	double  xMin = -5.0, xMax = 5.0, x1 = 0.54; 	int		firstIndex, clickIndex;    String	functionString, guessString;	boolean	guessPlotState, derivPlotState;  	InputPanel		inputPanel;	ControlPanel	controlPanel;	OutputPanel		outputPanel;	DomainPanel		domainPanel;	SecantTangent 	applet;	ZFunction		theFunction;	public FeedbackPanel(SecantTangent secantTangent)	{		this.setLayout(null);		applet = secantTangent;		theFunction = new ZFunction();    	    inputPanel = new InputPanel(this);    	inputPanel.setBounds(0,0,200,100); 		inputPanel.setLayout(null);		this.add(inputPanel);   	    outputPanel = new OutputPanel();    	outputPanel.setBounds(0,100,200,80); 		outputPanel.setLayout(null);		this.add(outputPanel);   	    controlPanel = new ControlPanel(this);    	controlPanel.setBounds(0,200,200,80); 		controlPanel.setLayout(null);		this.add(controlPanel);   	    domainPanel = new DomainPanel(this);   	    domainPanel.setBounds(0, 300, 200, 60);  		domainPanel.setLayout(null);		this.add(domainPanel);	}	//	FeedbackPanel	//		Gather the inputs - main collection method		public void collectData()    {		getInputValues();		getDomainValues();		getControlValues();		x1 = xBase + xDel;		theFunction.parse(functionString);		theFunction.findNumDerivs(xBase, xDel);		zeroDeriv 	= theFunction.zeroDeriv;		balancedSlope 	= theFunction.firstDeriv;		rightSlope	= theFunction.secSlope;		leftSlope	= theFunction.leftSlope;				sendOutputValues();    }	//	  collectData	public void update()	{	      	applet.fixMain();	}	//	update		public void resetYBounds()	{		functionString	= inputPanel.functionString;		theFunction.parse(functionString);		getDomainValues();		theFunction.setXRange(xMin, xMax);		theFunction.determineYMinYMax();   		yMin	= theFunction.yMin;   		yMax	= theFunction.yMax;   		sendDomainValues();      	applet.fixMain();	}	//	resetYBounds	    //		Methods for communicating with subsidiary objects    public void getInputValues()    {   	    inputPanel.collectInputValues();		xDel 			= inputPanel.xDel;		xBase 			= inputPanel.xBase;		x1				= xDel + xBase;		functionString	= inputPanel.functionString;		guessString		= inputPanel.guessString;    }	//	getInputValues	public void sendInputValues()	{		inputPanel.xDel		= xDel;		inputPanel.xBase	= xBase;		inputPanel.postInputValues();	}	//	sendInputValues	    public void getDomainValues()    {	    domainPanel.collectDomainValues();		xMin = domainPanel.xMin;		xMax = domainPanel.xMax;		yMin = domainPanel.yMin;		yMax = domainPanel.yMax;//       	applet.yLimitsFeedbackPanelToDrawingPanel();    }	//	getDomainValues	public void sendDomainValues()	{		domainPanel.xMin = xMin;		domainPanel.xMax = xMax;		domainPanel.yMin = yMin;		domainPanel.yMax = yMax;		domainPanel.postDomainValues();	}	//	sendDomainValues	    public void getControlValues()    {	    controlPanel.collectControlValues();		firstIndex = controlPanel.firstIndex;		clickIndex = controlPanel.clickIndex;		guessPlotState = controlPanel.guessPlotState;		derivPlotState = controlPanel.derivPlotState;    }	//	getControlValues	public void sendOutputValues()	{ 		outputPanel.leftSlope 		= leftSlope;		 		outputPanel.balancedSlope 	= balancedSlope;		 		outputPanel.rightSlope 		= rightSlope;		 		outputPanel.x1		 		= xBase + xDel;		 		outputPanel.postOutput();			}  //sendOutputValues }	//	FeedbackPanel class////	Start new subsidiary classpublic class InputPanel extends Panel{	/*	 *		Public variables that are either inputs or outputs to be passed	 */	double	xBase, xDel, x1 = 0.54;     String	functionString, guessString;;  	/*	 *		GUI elements for the panel	 */			Button		dXIn, dXOut;	Label   	fxLabel, xBaseLabel, xDelLabel, x1Label, guessLabel,				guessLabel2;    TextField 	functionFld, xBaseField, xDelField, guessField; 	FeedbackPanel  feedbackPanel;		public InputPanel(FeedbackPanel fPanel)	{		feedbackPanel = fPanel;		fxLabel = new Label("f(x) = ");		fxLabel.setBounds(0,0,35,18);		this.add(fxLabel);		functionFld = new TextField("x+0.1*x^2-3*sin(x)", 30);		functionFld.setBounds(35,0,165,18);		this.add(functionFld);		xBaseLabel = new Label("X0 = ");		xBaseLabel.setBounds(0,20,25,18);		this.add(xBaseLabel);		xBaseField = new TextField("1.5", 6);		xBaseField.setBounds(25,20,50,18);		this.add(xBaseField);		xDelLabel = new Label("dX = ");		xDelLabel.setBounds(0,40,25,18);		this.add(xDelLabel);		xDelField = new TextField("1.0", 6);		xDelField.setBounds(25,40,80,18);		this.add(xDelField);		dXIn = new Button("dX In");    	dXIn.setBounds(110,40,40,18);		this.add(dXIn); 		dXOut = new Button("dX Out");    	dXOut.setBounds(160,40,40,18);		this.add(dXOut);		guessLabel = new Label("Guessed derivative ");		guessLabel.setBounds(50,60,120,18);		guessLabel.setForeground(Color.cyan);		this.add(guessLabel);		guessLabel2 = new Label("f'(x) = ");		guessLabel2.setBounds(0,80,35,18);		this.add(guessLabel2);		guessField = new TextField("x", 30);		guessField.setBounds(35,80,165,18);		this.add(guessField); 			}	//	InputPanel	//	listen for button pushes and returns in text fields    public boolean action(Event e, Object arg)	{      	if((e.target == xBaseField)||(e.target == xDelField)||      		(e.target == guessField))      	{     	    feedbackPanel.collectData();    		feedbackPanel.update();      		return true;      	}       	if(e.target == functionFld)      	{      	    collectInputValues();			feedbackPanel.resetYBounds();			feedbackPanel.collectData();     		feedbackPanel.update();      		return true;      	}   		if(e.target == dXIn)      	{      		xDel = xDel/2.0;			xDelField.setText(Mio.doubleToStringSigFigures(xDel, 6));     	    feedbackPanel.collectData();    		feedbackPanel.update();      		return true;      	}   		if(e.target == dXOut)      	{      		xDel = xDel*2.0;			xDelField.setText(Mio.doubleToStringSigFigures(xDel, 6));     	    feedbackPanel.getInputValues();    		feedbackPanel.update();      		return true;      	} 		else return super.action(e,arg);		}  //  action//		Gather the inputs - main collection method		public void collectInputValues()    {		xBase = Mio.doubleFromTextField(xBaseField);	    xDel = Mio.doubleFromTextField(xDelField);	    if (xDel == 0.0) 	       {	       System.out.println("Warning, del X should be non-zero");	       System.out.println("del X reset to default.");	       xDel = 1.0;	       xDelField.setText(Double.toString(xDel));	       }    	functionString 	= functionFld.getText();    	guessString 	= guessField.getText();    }	//	  collectInputValues	public void postInputValues()    {		xBaseField.setText(Mio.doubleToStringSigFigures(xBase, 6)); 		xDelField.setText(Mio.doubleToStringSigFigures(xDel, 6));    }	//	  postInputValues}	//	InputPanel class////	Start new subsidiary classpublic class ControlPanel extends Panel{	/*	 *		Public variables that are either inputs or outputs to be passed	 */	int		firstIndex, clickIndex;	boolean		guessPlotState, derivPlotState;  	/*	 *		GUI elements for the panel	 */		Choice 		approxChoice, clickChoice; 	Checkbox	derivPlotBox, guessPlotBox;	FeedbackPanel  feedbackPanel;	public ControlPanel(FeedbackPanel fPanel)	{		feedbackPanel = fPanel; 		 		approxChoice = new Choice(); 		approxChoice.addItem("Right Secant"); 		approxChoice.addItem("Balanced Dif Quo"); 		approxChoice.addItem("Left Secant"); 		approxChoice.addItem("All Lines");		approxChoice.select(0);		approxChoice.setBounds(0,0,115,18);		this.add(approxChoice); 		clickChoice = new Choice(); 		clickChoice.addItem("X0 click"); 		clickChoice.addItem("X1 click"); 		clickChoice.addItem("Center");		clickChoice.select(0);		clickChoice.setBounds(120,0,75,18);		this.add(clickChoice);				derivPlotBox = new Checkbox("Plot Num Derivative ", false);		derivPlotBox.setBackground(Color.orange);		derivPlotBox.setBounds(0,20,120,18);		this.add(derivPlotBox);		guessPlotBox = new Checkbox("Plot Guess ", false);		guessPlotBox.setBackground(Color.cyan);		guessPlotBox.setBounds(0,40,120,18);		this.add(guessPlotBox);		SymItem lSymItem = new SymItem();		approxChoice.addItemListener(lSymItem);		clickChoice.addItemListener(lSymItem);		derivPlotBox.addItemListener(lSymItem);		guessPlotBox.addItemListener(lSymItem);	}	//	ControlPanel// handle GUI events	//	listen for changes in menues		class SymItem implements java.awt.event.ItemListener	{		public void itemStateChanged(java.awt.event.ItemEvent event)		{       	    feedbackPanel.collectData();      	    feedbackPanel.update();    	}	}	//	SymItem class	//		Gather the inputs - main collection method		public void collectControlValues()    {			firstIndex = approxChoice.getSelectedIndex();			clickIndex = clickChoice.getSelectedIndex();			guessPlotState = guessPlotBox.getState();			derivPlotState = derivPlotBox.getState();    }	//	  collectControlValues}	//	ControlPanel class////	Start new subsidiary classpublic class OutputPanel extends Panel{	/*	 *		Public variables that are either inputs or outputs to be passed	 */	double	balancedSlope, leftSlope, rightSlope, x1 = 0.54;   	/*	 *		GUI elements for the panel	 */		Label 		leftSlopeLabel, secSlopeLabel, rightSlopeLabel, x1Label;		public OutputPanel()	{		leftSlopeLabel = new Label("Left Slope   = ");		leftSlopeLabel.setBounds(0,0,160,18);		leftSlopeLabel.setForeground(Color.green);		this.add(leftSlopeLabel);		secSlopeLabel = new Label("Balanced Slope = ");		secSlopeLabel.setBounds(0,20,160,18);		secSlopeLabel.setForeground(Color.red);		this.add(secSlopeLabel); 		rightSlopeLabel = new Label("Right Slope  = ");		rightSlopeLabel.setBounds(0,40,160,18);		rightSlopeLabel.setForeground(Color.magenta);		this.add(rightSlopeLabel); 		x1Label = new Label("X1 = X0 + dX = 2.5"); 		x1Label.setBounds(0,60,160,18);		this.add(x1Label);	}		public void postOutput()	{//		Adjust with round to get desired precision		leftSlopeLabel.setText("Left Slope   = " + Mio.doubleToStringSigFigures(leftSlope, 6));		secSlopeLabel.setText("Balanced Slope = " + Mio.doubleToStringSigFigures(balancedSlope, 6));		rightSlopeLabel.setText("Right Slope  = " + Mio.doubleToStringSigFigures(rightSlope, 6));		x1Label.setText("X1 = X0 + dX = " + Mio.doubleToStringSigFigures(x1, 6));			}  //	postOutput 	}	//	outputPanel class////	Start new subsidiary classpublic class DomainPanel extends Panel{	/*	 *		Public variables that are either inputs or outputs to be passed	 */	double  yMin = -5.0, yMax = 5.0, xMin = -5.0, xMax = 5.0; 	/*	 *		Variables that are used in internal computations	 */    double	xCenter, halfWide, yCenter, halfHigh;  	/*	 *		GUI elements for the panel	 */			Button		zoomIn, zoomOut, zSquare, yReset;	Label   	xMinLabel, xMaxLabel, yMinLabel, yMaxLabel;     TextField 	xMinField, xMaxField, yMinField, yMaxField; 	FeedbackPanel  feedbackPanel;		public DomainPanel(FeedbackPanel fPanel)	{		this.setLayout(null);		feedbackPanel = fPanel;//  	Assume panel is 200 by 60 		xMinLabel = new Label("xMin =");   	    xMinLabel.setBounds(0, 20, 40, 18);		this.add(xMinLabel);		xMinField = new TextField("-5.0", 7);   	    xMinField.setBounds(45, 20, 50, 18);		this.add(xMinField);		xMaxLabel = new Label("xMax =");   	    xMaxLabel.setBounds(0, 0, 40, 18);		this.add(xMaxLabel);		xMaxField = new TextField("5.0", 7);   	    xMaxField.setBounds(45, 0, 50, 18);		this.add(xMaxField);		zoomIn = new Button("Zoom In");    	zoomIn.setBounds(0,40,45,18);		this.add(zoomIn); 		zoomOut = new Button("Zoom Out");    	zoomOut.setBounds(50,40,50,18);		this.add(zoomOut); 		yReset = new Button("Reset Y");    	yReset.setBounds(105,40,45,18);		this.add(yReset); 		zSquare = new Button("Square");    	zSquare.setBounds(155,40,45,18);		this.add(zSquare); 		yMinLabel = new Label("yMin =");   	    yMinLabel.setBounds(100, 20, 40, 18);		this.add(yMinLabel);		yMinField = new TextField("-5.0", 7);   	    yMinField.setBounds(145, 20, 50, 18);		this.add(yMinField);		yMaxLabel = new Label("yMax =");   	    yMaxLabel.setBounds(100, 0, 40, 18);		this.add(yMaxLabel);		yMaxField = new TextField("5.0", 7);   	    yMaxField.setBounds(145, 0, 50, 18);		this.add(yMaxField);	}	//	DomainPanel	//	listen for button pushes and returns in text fields    public boolean action(Event e, Object arg)	{      	if((e.target == xMinField)||(e.target == xMaxField)||      	   (e.target == yMinField)||(e.target == yMaxField))      	{      	    feedbackPanel.getDomainValues();      	    feedbackPanel.update();      		return true;      	}     	      	if((e.target == yReset))      	{      	    feedbackPanel.resetYBounds();      	    feedbackPanel.sendDomainValues();      	    postDomainValues();      	    feedbackPanel.update();      		return true;      	}      	   		if(e.target == zoomIn)      	{      		xCenter = (xMax + xMin)/2;      		halfWide = xMax - xCenter;       		yCenter = (yMax + yMin)/2;      		halfHigh = yMax - yCenter;			xMin = xCenter - halfWide/2.0;			xMax = xCenter + halfWide/2.0;			yMin = yCenter - halfHigh/2.0;			yMax = yCenter + halfHigh/2.0;      	    postDomainValues();      	    feedbackPanel.getDomainValues();      	    feedbackPanel.update();      		return true;      	}   		if(e.target == zoomOut)      	{      		xCenter = (xMax + xMin)/2;      		halfWide = xMax - xCenter;      		yCenter = (yMax + yMin)/2;      		halfHigh = yMax - yCenter;			xMin = xMin - halfWide;			xMax = xMax + halfWide;			yMin = yMin - halfHigh;			yMax = yMax + halfHigh;      	    postDomainValues();      	    feedbackPanel.getDomainValues();      	    feedbackPanel.update();      		return true;      	}   		if(e.target == zSquare)      	{      		halfWide = (xMax - xMin)/2;      		yCenter = (yMax + yMin)/2;			yMin = yCenter - halfWide;			yMax = yCenter + halfWide;      	    postDomainValues();      	    feedbackPanel.getDomainValues();      	    feedbackPanel.update();      		return true;      	} 		else return super.action(e,arg);		}  //  action	public void postDomainValues()	{       xMinField.setText(Mio.doubleToStringSigFigures(xMin,5));       xMaxField.setText(Mio.doubleToStringSigFigures(xMax,5));       yMinField.setText(Mio.doubleToStringSigFigures(yMin,5));       yMaxField.setText(Mio.doubleToStringSigFigures(yMax,5));	}	//	postDomainValues		public void collectDomainValues()	{	    //  Check that xMin < xMax and set them	    xMin=Mio.doubleFromTextField(xMinField);	   	xMax=Mio.doubleFromTextField(xMaxField);	    if (xMax <= xMin)  	    { 	      System.out.println("Warning, xMin should be < xMax");       	  System.out.println("xMin and xMax reset to defaults.");       		xMin = -5.0;       		xMax = 5.0;       	}    	//  Check that xMin < xMax and set them    	yMin=Mio.doubleFromTextField(yMinField);    	yMax=Mio.doubleFromTextField(yMaxField);    	if (yMax <= yMin)        	{       	  System.out.println("Warning, yMin should be < yMax");       	  System.out.println("xMin and xMax reset to defaults.");       		yMin = -5.0;       		yMax = 5.0;       	}       	postDomainValues();    }  //  collectDomainValues		}	//	DomainPanelClass// End of FeedbackPanel file/* *	Help are is a simple object to be used for the help panel of the applet. *	It is set up as a scrolling region in case the help text is made long *	enough to require that, but the default is that no scrollbars are visible. */import java.awt.TextArea;public class HelpArea extends TextArea{	public HelpArea(int width, int height)	{//Scrollbar visibility - 0 = both, 1= vert only, 2=horizon only, 3 = none//		super(String text, int width, int height, int scrollbarVisibility)		super(" ", width, height, 1);			this.setText(		"The applet graphs a function and the specified linear approximation at a \n" +		"point X0.  The linear approximation are those with difference quotient\n" + 		"slopes.  There is the usual secant line slope used in the standard\n" +		"definition of the derivative, as well as a left secant for balance.\n" +		"There is also a line with the slope obtained by the balanced difference\n" +		"value, either by entering it as text, or by mouse clicks, or by button\n" +		"control.\n\n" +		"The user can enter a function, a base point X0, the change in x dX,\n" +		"and an x and y range to be graphed.  \n\n" +		"The applet graphs the function with a line whose slope is based\n" +		"on a difference quotient of two point on the graph.  The user can\n" +		"choose if this will be the standard secant differnce quotient\n" +		"with x going from X0 to X0 + dX, a left secant from X0 - dX to XO,\n" +		"or a balanced quotient from X0 - dX to X0 + dX.  The user can\n" +		"choose to see all three lines at the same time.\n\n" +		"The user has the option of plotting the graph of the balanced\n" +		"derivative as well as plotting the graph of a formula that is \n" +		"the user's guess of the derivative.\n\n" +		"Buttons allow the user to half or double dX to see the limiting \n" +		"process visually.\n\n" +		"The user can also zoom in or zoom out and can adjust the graph region\n" +		"so that is is square or so that in includes the graph and the axes.\n\n" +		"The user can also control the effect of a mouse click on the graph.\n" +		"When a mouse click will move either X0 or X1, dragging the mouse\n" +		"will continually drag the same points.\n" +		"The function should be an expression in x.  Implicit multiplication is not allowed.\n" +		"(Use 3*x rather than 3x.)  Exponentiation is indicated by ^.  \n" +		"The mathematical constant pi can be in upper or lower case.\n" +  		"The constant e is indicated by either e or exp(1).\n" + 		"(These constants only have double precision,  Thus e^x will only appoximate exp(x).\n" + 		"Trig functions are in radians.  Use the functions toDegrees and toRadians to convert.\n\n" +		"The functions understood by the parser are:\n" +		"sin,  cos, tan, sec, csc, acos or arccos, asin or arcsin, atan or arctan, \n" +		"toDegrees, toRadians, abs, ceil, floor, round,\n" +		"sqrt, exp, log or ln (for natural log), and log10.\n\n" +		"Each of these functions requires one argument enclosed in parentheses.");		this.setEditable(false);	}}	//	HelpArea/* *	AboutArea is an object for the About Panel.  It is a multi-line label *	with a fixed text message. */import java.awt.*;public class AboutArea extends MultiLineLabel{	Font theFont = new Font("TimesRoman", Font.BOLD, 18);	String label = "Secant and Tangent Line Applet\n \n"+			"Copyright 2001 by Mike May, S.J.\n"+			"maymk@slu.edu\n \n"+			"zFunction class inspired by class of that name\n"+			"from Riemann Sum applet by\n"+			"Bill Ziemer and Brendon Cheves\n"+			"Copyright 1996 by California State University," +			    " Long Beach\n \n"+			"Function Parsing Copyright 1996 by Darius Bacon";	int		alignment = 1;		//	center	int		margin_width =10, margin_height = 10;	public AboutArea(){//		super(label, margin_width, margin_height, alignmnet);//		Possible alignment values are 0 for left, 1 for center and 2 for right.		super(" ", 10,10, 1);		this.setLabel(label);		this.setFont(theFont);	}}	//	AboutArea//	MultiLineLabel// This example is from _Java Examples in a Nutshell_. (http://www.oreilly.com)// Copyright (c) 1997 by David Flanagan// This example is provided WITHOUT ANY WARRANTY either expressed or implied.// You may study, use, modify, and distribute it for non-commercial purposes.// For any commercial use, see http://www.davidflanagan.com/javaexamplesimport java.awt.*;import java.util.*;/** * A custom component that displays multiple lines of text with specified * margins and alignment.  In Java 1.1, we could extend Component instead * of Canvas, making this a more efficient "Lightweight component" */public class MultiLineLabel extends Canvas {  // User-specified attributes  protected String label;             // The label, not broken into lines  protected int margin_width;         // Left and right margins  protected int margin_height;        // Top and bottom margins  protected int alignment;            // The alignment of the text.  public static final int LEFT = 0, CENTER = 1, RIGHT = 2; // alignment values  // Computed state values  protected int num_lines;            // The number of lines  protected String[] lines;           // The label, broken into lines  protected int[] line_widths;        // How wide each line is  protected int max_width;            // The width of the widest line  protected int line_height;          // Total height of the font  protected int line_ascent;          // Font height above baseline  protected boolean measured = false; // Have the lines been measured?  // Here are five versions of the constructor  public MultiLineLabel(String label, int margin_width,                        int margin_height, int alignment) {    this.label = label;                 // Remember all the properties    this.margin_width = margin_width;    this.margin_height = margin_height;    this.alignment = alignment;    newLabel();                         // Break the label up into lines  }  public MultiLineLabel(String label, int margin_width, int margin_height) {    this(label, margin_width, margin_height, LEFT);  }  public MultiLineLabel(String label, int alignment) {    this(label, 10, 10, alignment);  }  public MultiLineLabel(String label) { this(label, 10, 10, LEFT); }  public MultiLineLabel() { this(""); }  // Methods to set and query the various attributes of the component  // Note that some query methods are inherited from the superclass.  public void setLabel(String label) {    this.label = label;    newLabel();               // Break the label into lines    measured = false;         // Note that we need to measure lines    repaint();                // Request a redraw  }  public void setFont(Font f) {    super.setFont(f);         // tell our superclass about the new font    measured = false;         // Note that we need to remeasure lines    repaint();                // Request a redraw  }  public void setForeground(Color c) {    super.setForeground(c);   // tell our superclass about the new color    repaint();                // Request a redraw (size is unchanged)  }  public void setAlignment(int a) { alignment = a; repaint(); }  public void setMarginWidth(int mw) { margin_width = mw; repaint(); }  public void setMarginHeight(int mh) { margin_height = mh; repaint(); }  public String getLabel() { return label; }  public int getAlignment() { return alignment; }  public int getMarginWidth() { return margin_width; }  public int getMarginHeight() { return margin_height; }  /**   * This method is called by a layout manager when it wants to   * know how big we'd like to be.  In Java 1.1, getPreferredSize() is   * the preferred version of this method.  We use this deprecated version   * so that this component can interoperate with 1.0 components.   */  public Dimension preferredSize() {    if (!measured) measure();    return new Dimension(max_width + 2*margin_width,                         num_lines * line_height + 2*margin_height);  }  /**   * This method is called when the layout manager wants to know   * the bare minimum amount of space we need to get by.   * For Java 1.1, we'd use getMinimumSize().   */  public Dimension minimumSize() { return preferredSize(); }  /**   * This method draws the label (same method that applets use).   * Note that it handles the margins and the alignment, but that   * it doesn't have to worry about the color or font--the superclass   * takes care of setting those in the Graphics object we're passed.   */  public void paint(Graphics g) {    int x, y;    Dimension size = this.size();  // use getSize() in Java 1.1    if (!measured) measure();    y = line_ascent + (size.height - num_lines * line_height)/2;    for(int i = 0; i < num_lines; i++, y += line_height) {      switch(alignment) {      default:      case LEFT:    x = margin_width; break;      case CENTER:  x = (size.width - line_widths[i])/2; break;      case RIGHT:   x = size.width - margin_width - line_widths[i]; break;      }      g.drawString(lines[i], x, y);    }  }  /** This internal method breaks a specified label up into an array of lines.   *  It uses the StringTokenizer utility class. */  protected synchronized void newLabel() {    StringTokenizer t = new StringTokenizer(label, "\n");    num_lines = t.countTokens();    lines = new String[num_lines];    line_widths = new int[num_lines];    for(int i = 0; i < num_lines; i++) lines[i] = t.nextToken();  }  /** This internal method figures out how the font is, and how wide each   *  line of the label is, and how wide the widest line is. */  protected synchronized void measure() {    FontMetrics fm = this.getToolkit().getFontMetrics(this.getFont());    line_height = fm.getHeight();    line_ascent = fm.getAscent();    max_width = 0;    for(int i = 0; i < num_lines; i++) {      line_widths[i] = fm.stringWidth(lines[i]);      if (line_widths[i] > max_width) max_width = line_widths[i];    }    measured = true;  }}	//	MultiLineLabel//////////		Code for the parser////////		// Mathematical expressions.// Copyright 1996 by Darius Bacon; see the file COPYING.// 14May96: added constant folding// 07JUL1999 - version 1.0 - C. Pheatt// 05AUG2000 - Mike May, S.J.//				add in SEC, CSC. ToDEG, TORADpackage expr;/** * A mathematical expression, built out of literal numbers, variables, * arithmetic operators, and elementary functions.  The operator names * are from java.lang.Math. */public abstract class Expr {  /** @return the value given the current variable values */  public abstract double value ();  /** Binary operator. */  public static final int ADD = 0;    /** Binary operator. */  public static final int SUB = 1;  /** Binary operator. */  public static final int MUL = 2;  /** Binary operator. */  public static final int DIV = 3;  /** Binary operator. */  public static final int POW = 4;  /** Binary operator. */  public static final int MOD = 5;  /** Binary operator. */  public static final int LTH = 6;  /** Binary operator. */  public static final int LEQ = 7;  /** Binary operator. */  public static final int GTH = 8;  /** Binary operator. */  public static final int GEQ = 9;  /** Binary operator. */  public static final int EQU = 10;  /** Binary operator. */  public static final int NEQ = 11;  /** Binary operator. */  public static final int AND = 12;  /** Binary operator. */  public static final int ORR = 13;  /** Unary operator. */        public static final int ABS   = 100;  /** Unary operator. */        public static final int ACOS  = 101;  /** Unary operator. */        public static final int ASIN  = 102;  /** Unary operator. */        public static final int ATAN  = 103;  /** Unary operator. */        public static final int CEIL  = 104;  /** Unary operator. */        public static final int COS   = 105;  /** Unary operator. */        public static final int EXP   = 106;  /** Unary operator. */        public static final int FLOOR = 107;  /** Unary operator. */        public static final int LOG   = 108;  /** Unary minus operator. */  public static final int NEG   = 109;  /** Unary operator. */        public static final int ROUND = 110;  /** Unary operator. */        public static final int SIN   = 111;  /** Unary operator. */        public static final int SQRT  = 112;  /** Unary operator. */        public static final int TAN   = 113;  /** Unary operator. */        public static final int LOG10 = 114;  /** Unary operator. */        public static final int SEC   = 115;  /** Unary operator. */        public static final int CSC   = 116;  /** Unary operator. */        public static final int TODEG = 117;  /** Unary operator. */        public static final int TORAD = 118;  /** Unary operator. */       // public static final int FACT  = 115;    public static Expr make_literal (double v) {     return new Literal (v);   }  public static Expr make_var_ref (Variable var) {    return new Var_ref (var);  }  /**    * @param rator unary operator   * @param rand operand   */  public static Expr make_app1 (int rator, Expr rand) {    Expr app = new App1 (rator, rand);    return rand instanceof Literal ? new Literal (app.value ()) : app;  }  /**    * @param rator binary operator   * @param rand0 left operand   * @param rand1 right operand   */  public static Expr make_app2 (int rator, Expr rand0, Expr rand1) {    Expr app = new App2 (rator, rand0, rand1);    return rand0 instanceof Literal && rand1 instanceof Literal	     ? new Literal (app.value ()) 	     : app;  }}	//	Expr// These classes are all private to this module so that I can get rid// of them later.  For applets you want to use as few classes as// possible to avoid http connections at load time; it'd be profitable// to replace all these subtypes with bytecodes for a stack machine,// or perhaps a type that's the union of all of them (see class Node// in java/demo/SpreadSheet/SpreadSheet.java).class Literal extends Expr {  double v;  Literal (double _v) { v = _v; }  public double value () { return v; }}	//	Literalclass Var_ref extends Expr {  Variable var;  Var_ref (Variable _var) { var = _var; }  public double value () { return var.value (); }}	//	Var_refclass App1 extends Expr {  int rator;  Expr rand;  App1 (int _rator, Expr _rand) { rator = _rator; rand = _rand;  }  public double value () {    double arg = rand.value ();    switch (rator) {    case ABS:   return Math.abs (arg);    case ACOS:  return Math.acos (arg);    case ASIN:  return Math.asin (arg);    case ATAN:  return Math.atan (arg);    case CEIL:  return Math.ceil (arg);    case COS:   return Math.cos (arg);    case EXP:   return Math.exp (arg);//    case FACT:  return MiscFunctions.fact (arg);    case FLOOR: return Math.floor (arg);    case LOG:   return Math.log (arg);    case LOG10: return Math.log (arg) * 0.434294481903251827651128918916;    case NEG:   return -arg;    case ROUND: return Math.round (arg);    case SIN:   return Math.sin (arg);    case SQRT:  return Math.sqrt (arg);    case TAN:   return Math.tan (arg);    case SEC:   return 1/Math.cos (arg);    case CSC:   return 1/Math.sin (arg);    case TODEG: return 180*(arg)/(3.141582653589793);    case TORAD: return (Math.PI)*(arg)/180;    default: throw new RuntimeException ("BUG: bad rator");    }  }}	//	App1class App2 extends Expr {  int rator;  Expr rand0, rand1;  App2 (int _rator, Expr _rand0, Expr _rand1) {     rator = _rator; rand0 = _rand0; rand1 = _rand1;  }  public double value () {    double arg0 = rand0.value ();    double arg1 = rand1.value ();    switch (rator) {    case ADD:  return arg0 + arg1;    case SUB:  return arg0 - arg1;    case MUL:  return arg0 * arg1;    case DIV:  return arg0 / arg1;   // check for division by 0?    case POW:  return Math.pow (arg0, arg1);    case MOD:  return arg0 % arg1;    case LTH:  if(arg0 < arg1) return 1; else return 0;    case LEQ:  if(arg0 <= arg1) return 1; else return 0;    case GTH:  if(arg0 > arg1) return 1; else return 0;    case GEQ:  if(arg0 >= arg1) return 1; else return 0;    case EQU:  if(arg0 == arg1) return 1; else return 0;    case NEQ:  if(arg0 != arg1) return 1; else return 0;    case AND:  if((arg0 != 0) && (arg1 != 0)) return 1; else return 0;    case ORR:  if((arg0 != 0) || (arg1 != 0)) return 1; else return 0;    default: throw new RuntimeException ("BUG: bad rator");    }  }}	//	App2//	End package Expr// Operator-precedence parser.// Copyright 1996 by Darius Bacon; see the file COPYING.// 14May96: bugfix. //	StreamTokenizer treated '-<number>' as a numeric token, not a minus//	operator followed by a number.  Fix: make '-' an ordinaryChar.// 12May97: Changed the precedence of unary minus to be lower than //      multiplication, so -y^2 is like -(y^2), not (-y)^2.// 07JUL1999 - version 1.0 - C. Pheatt// 05AUG2000 - Mike May, S.J.//				add in sec, csc, toDegrees, toRadians, lnpackage expr;import java.io.*;/**   Parses strings representing mathematical formulas with variables.  The following operators, in descending order of precedence, are  defined:  <UL>  <LI>^ (raise to a power)  <LI>* /  <LI>Unary minus (-x)  <LI>+ -  </UL>  ^ associates right-to-left; other operators associate left-to-right.  <P>These functions are defined:     abs, acos, asin, atan,     ceil, cos, exp, floor,     log, round, sin, sqrt,     tan.  Each requires one argument enclosed in parentheses.  <P>Whitespace outside identifiers is ignored.  <P>The syntax-error messages aren't very informative, unfortunately.  IWBNI it indicated where in the input string the parse failed, but   that'd be kind of a pain since our scanner is a StreamTokenizer.  A  hook for that info should've been built into StreamTokenizer.  <P>Examples:  <UL>  <LI>42  <LI>2-3  <LI>cos(x^2) + sin(x^2)  <UL> */public class Parser {  static StreamTokenizer tokens;  public static Expr parse (String input) throws Syntax_error {    tokens = new StreamTokenizer (new StringReader (input));    tokens.ordinaryChar ('/');    tokens.ordinaryChar ('-');    tokens.ordinaryChar ('%');    tokens.ordinaryChar ('>');    tokens.ordinaryChar ('<');    tokens.ordinaryChar ('=');    tokens.ordinaryChar ('!');    tokens.ordinaryChar ('&');    tokens.ordinaryChar ('|');    next ();    Expr expr = parse_expr (0);    if (tokens.ttype != StreamTokenizer.TT_EOF)      throw new Syntax_error ("Incomplete expression: " + input);    return expr;  }  static void next () {    try { tokens.nextToken (); }    catch (IOException e) { throw new RuntimeException ("I/O error: " + e); }  }  static void push () {     tokens.pushBack();   }  static void expect (int ttype) throws Syntax_error {    if (tokens.ttype != ttype)      throw new Syntax_error ("'" + (char) ttype + "' expected");    next ();  }  static Expr parse_expr (int precedence) throws Syntax_error {    Expr expr = parse_factor ();  loop: for (;;) {      int l, r, rator;         // The operator precedence table.      // l = left precedence, r = right precedence, rator = operator.      // Higher precedence values mean tighter binding of arguments.      // To associate left-to-right, let r = l+1;      // to associate right-to-left, let r = l.      switch (tokens.ttype) {      case '|':         l = 2; r = 3; rator = Expr.ORR;        next();        if(tokens.ttype != '|') push();        break;      case '&':         l = 4; r = 5; rator = Expr.AND;         next();        if(tokens.ttype != '&') push();        break;      case '=':         l = 6; r = 7; rator = Expr.EQU;         next();        if(tokens.ttype != '=') push();        break;              case '!':         l = 6; r = 7; rator = Expr.NEQ;         next();        if(tokens.ttype != '=') push();        break;            case '<':        l = 8; r = 9;        next();        if(tokens.ttype != '=')  {            push();            rator = Expr.LTH;         }        else {            rator = Expr.LEQ;         }            break;              case '>':        l = 8; r = 9;         next();        if(tokens.ttype != '=')  {            push();            rator = Expr.GTH;         }        else {            rator = Expr.GEQ;         }            break;            case '+': l = 10; r = 11; rator = Expr.ADD; break;      case '-': l = 10; r = 11; rator = Expr.SUB; break;	      case '%': l = 20; r = 21; rator = Expr.MOD; break;      case '*': l = 20; r = 21; rator = Expr.MUL; break;      case '/': l = 20; r = 21; rator = Expr.DIV; break;	      case '^': l = 30; r = 30; rator = Expr.POW; break; 	      default: break loop;      }      if (l < precedence)	break loop;      next ();      expr = Expr.make_app2 (rator, expr, parse_expr (r));    }    return expr;  }  static String[] procs = {    "abs", "acos","arccos", "asin",    "arcsin", "atan", "arctan",    "ceil", "cos", "exp", "floor",     "log", "ln", "round", "sin", "sqrt",     "tan", "log10", "sec", "csc",    "toDegrees", "toRadians"//, "fact"  };  static int[] rators = {    Expr.ABS, Expr.ACOS, Expr.ACOS, Expr.ASIN,    Expr.ASIN, Expr.ATAN, Expr.ATAN,     Expr.CEIL, Expr.COS, Expr.EXP, Expr.FLOOR,    Expr.LOG, Expr.LOG, Expr.ROUND, Expr.SIN, Expr.SQRT,     Expr.TAN , Expr.LOG10, Expr.SEC, Expr.CSC,    Expr.TODEG, Expr.TORAD//, Expr.FACT  };	  static Expr parse_factor () throws Syntax_error {    switch (tokens.ttype) {    case StreamTokenizer.TT_NUMBER: {      Expr lit = Expr.make_literal (tokens.nval);      next ();      return lit;    }    case StreamTokenizer.TT_WORD: {      for (int i = 0; i < procs.length; ++i)	if (procs [i].equals (tokens.sval)) {	  next ();	  expect ('(');	  Expr rand = parse_expr (0);	  expect (')');	  return Expr.make_app1 (rators [i], rand);	}      Expr var = Expr.make_var_ref (Variable.make (tokens.sval));      next ();      return var;    }    case '(': {      next ();      Expr enclosed = parse_expr (0);      expect (')');      return enclosed;    }    case '-':       next ();      return Expr.make_app1 (Expr.NEG, parse_expr (15));    default:      throw new Syntax_error ("Expected a factor");    }  }}// Syntax-error exception.// Copyright 1996 by Darius Bacon; see the file COPYING.package expr;public class Syntax_error extends Exception {  public Syntax_error (String complaint) { super (complaint); }}// Put the expression evaluator through its paces.// Sample usage:// $ java expr.Test '3.14159 * x^2' 0 4 1// 0// 3.14159// 12.5664// 28.2743// 50.2654//// $ java expr.Test 'sin (pi/4 * x)' 0 4 1// 0// 0.707107// 1// 0.707107// 1.22461e-16//package expr;import expr.*;public class Test {  public static void main (String[] args) {    Expr expr;   	try   	{   		expr = Parser.parse (args [0]);   	}	catch (Syntax_error e)	{		System.err.println ("Syntax error: " + e);		return;	}    double low  = Double.valueOf (args [1]).doubleValue ();    double high = Double.valueOf (args [2]).doubleValue ();    double step = Double.valueOf (args [3]).doubleValue ();          Variable x = Variable.make ("x");    Variable.make ("pi").set_value (Math.PI);    for (double xval = low; xval <= high; xval += step) {      x.set_value (xval);      System.out.println (expr.value ());    }  }}/*	Trivial library - 4/96 PNL*/public class TrivialClass {		public TrivialClass() {	}}// Variables associate values with names.// Copyright 1996 by Darius Bacon; see the file COPYING.package expr;import java.util.Hashtable;/** * Variables associate values with names. */public class Variable {  static Hashtable variables = new Hashtable ();  /**   * Return <EM>the</EM> variable named `_name'.     * make (s1) == make (s2) iff s1.equals (s2).   */  static public Variable make (String _name) {    Variable result = (Variable) variables.get (_name);    if (result == null)      variables.put (_name, result = new Variable (_name));    return result;  }  String name;  double val;  public Variable (String _name) { name = _name; val = 5; }  public String toString () { return name; }  public double value () { return val; }  public void set_value (double _val) { val = _val; }}	//	Variable/*  Copying file for expr packageCopyright 1996 by Darius Bacon.Permission is granted to anyone to use this software for anypurpose on any computer system, and to redistribute it freely,subject to the following restrictions:1. The author is not responsible for the consequences of use of   this software, no matter how awful, even if they arise from    defects in it.2. The origin of this software must not be misrepresented, either   by explicit claim or by omission.3. Altered versions must be plainly marked as such, and must not   be misrepresented as being the original software.   *///	MIO = My Input Output//	It is a collection of methods for cleaning up input and output.//	Mike May, S.J.//	maymk@slu.edu//	August, 2001/*	Current method list *	public static int intFromTextField(TextField tf)  *	public static double doubleFromTextField(TextField tf)  *	public static String doubleToStringDecPrecision(double d, int decfigs)  *	public static String doubleToStringNoE(TextField tf)  *	public static String doubleToStringSigFigures(double d, int sigfigs) * *	This version tries to interpret doubles first in Java format, then as *	an NFunction.  Java format allows sx.xxxxxxEsxxx while NFunctions *	allow usual mathematical constructions. */package MIO;import	java.awt.*;import	ZFunction;public  class Mio {		public Mio() {}/** This is a utility routine to retrieve an integer from a text field. */	public static int intFromTextField(TextField tf) 	{		String  string;		int     value;				string = tf.getText();		try {		   value = Integer.parseInt(string);		} catch (Exception e) {       System.out.println("Warning, noninteger read for integer value.");       System.out.println("The variable has be set to 0.");		   value = 0;		}		   		return value;	}	//	intFromTextField	public static double doubleFromTextField(TextField tf) 	{		ZFunction	func = new ZFunction();   				String		string;		double		value;				string = tf.getText();		try {			value = Double.valueOf(string).doubleValue();		} catch (Exception e) {		try {		func.parse(string);			value = func.value(1);		} catch (Exception se) {       System.out.println("Warning, nondouble read for double value.");       System.out.println("The variable has be set to 0.0.");		   value = 0.0;		}}		return value;	}	//	doubleFromTextField	//	This procedure is intended to turn a double into a a string with a 	// specified decimal precision.	public static String doubleToStringDecPrecision(double d, int decfigs) 	{	     if (d == 0) return "0.0";	     else return String.valueOf((Math.round(d*(Math.pow(10,decfigs))))/                  (Math.pow(10,decfigs)));	}	//	doubleToStringDecPrecision	//	This procedure is intended to turn a double into a string with the added	//	provision being that the string not use E notation.	//	The point is if the string is then to be used in a an expression by a parser.	//	The output format is either (sxxx.xxx) or (sx.xxxx)*10^(sxxx).	public static String doubleToStringNoE(double d) 	{		String s1 = Double.toString(d);		int loc = s1.indexOf("E");		int len = s1.length();		if (loc == -1) return s1;		else return "(" + s1.substring(0,loc) +")*10^(" + s1.substring(loc+1,len) + ")";	}	//	doubleToStringNoE	//	This procedure is intended to turn a double into a string with a specified	//	number of significant figures.  We need to divide into cases on whether	//	s1 is already in scientific notation.	public static String doubleToStringSigFigures(double d, int sigfigs)	{		String s1 = Double.toString(d);		int len = s1.length();		int loc = s1.indexOf("E");		int posdot = s1.indexOf(".");		int pos;		if (sigfigs < 1) return s1;		if (loc != -1)	// There is an E in s1		{			pos = Math.min(posdot+sigfigs, loc);				return  s1.substring(0,pos) +"E" + s1.substring(loc+1,len);		}		else	// no E in the string representation s1		{			pos = sigfigs + 1;			if (s1.indexOf("-") == 0) pos += 1;			if (posdot <= pos)	//	Need to keep figures right of decimal			{					int dotMove = (Double.toString(d*1000.0).indexOf(".") - posdot);				int leadZeroes = 3 - dotMove;	// count leading zeroes and adjust				if (leadZeroes > 0) pos += leadZeroes;				pos = Math.min(pos, len);				return s1.substring(0, pos);			}			int numZeroes = posdot - pos;			String s2 = s1.substring(0, pos);			for (int i = 0; i< numZeroes; i++) s2 = s2 + "0";			return s2 + ".0";		}	}	//	doubleToStringSigFigures}	//	class MIO   
