/** * SunSphere displays a world map showing the sunrise and sunset terminators.<p> * * Copyright &copy; 1996 Martin Minow. All Rights Reserved.<p> * World map copyright &copy; 1992-97 Apple Computer Inc. All Rights Reserved. * Used by permission.<p> * * Permission to use, copy, modify, and redistribute this software and its * documentation for personal, non-commercial use is hereby granted provided that * this copyright notice and appropriate documentation appears in all copies. This * software may not be distributed for fee or as part of commercial, "shareware," * and/or not-for-profit endevors including, but not limited to, CD-ROM collections, * online databases, and subscription services without specific license.<p> * * @author <a href="mailto:minow@pobox.com">Martin Minow</a> * @version 1.1 * This applet is Java 1.1 compatible. */package org.minow.applets.sunsphere;import java.applet.*;import java.awt.*;import java.awt.event.*;import java.awt.image.*;import java.text.*;import java.util.*;import java.beans.*;import java.net.*;public class SunSphere extends java.applet.Applet		implements java.lang.Runnable,			java.awt.event.ActionListener,			java.beans.PropertyChangeListener,			org.minow.applets.sunsphere.SunSphereParameters,			org.minow.applets.sunsphere.SunSphereConfig{    public static boolean		logErrors	= false;    private Thread			runner		= null;        /*     * For future work: distribute parameter changes using PropertyEvents.     */    protected PropertyChangeSupport	butler = new PropertyChangeSupport(this);    /*     * User interface     */    private SunSphereInfoButton		infoButton;    private SunSphereEastButton		eastButton;    private SunSphereWestButton		westButton;    private SunSphereNorthButton	northButton;    private SunSphereSouthButton	southButton;    private SunSphereSpinButton		spinButton;    private Label			dateTimePanel;    private Label			pixelTimePanel;    private Label			memoryUsagePanel;    private SunSphereOptionDialog	optionDialog	= null;    /*     * The user can set these to rotate the globe.     * centerLongitude	    The center-point of the globe.     * spinLongIncrement    The number of degrees that the globe rotates     *		    on each cycle. This value must match the initial     *		    value in spinLongField.     */    private boolean		autostart		= false;    private int			spinInterval		= 10;	/* Very fast  	*/        /*     * Longitude is initialized to the center of the local timezone.     */    private double		longitude		= Double.NaN;    private double		longitudeDelta		= 15.0;    private double		longitudeSpin		= 1.0;    private double		latitude		= 0.0;    private double		latitudeDelta		= 15.0;    private double		latitudeSpin		= 0.0;    private static final long	refreshInstant		= 0;    private long		currentInstant		= System.currentTimeMillis();    private long		nextInstant		= refreshInstant;    private long		dateUpdateQuantum	= oneMinute;    private long		dateUpdateInterval	= oneMinute;    private boolean		systemDateUsed		= true;    private boolean		latitudeGrabOK		= false;            private boolean		spinning		= false;        private boolean		explicitBackgroundColor	= false;    private boolean		explicitForegroundColor	= false;        private SunSphereCanvas	sunSphereCanvas;        /**     * Applet start     */    public void init()    {    	try {	    getAppletParameters();	}	catch (Exception e) {	    System.out.println("Cannot read applet parameters: " + e);	}	showStatus(copyright + ", version " + version);	if (explicitBackgroundColor == true	 && explicitForegroundColor == false) {	    Color	fg	= getBackground();	    float[] hsb	= Color.RGBtoHSB(				fg.getRed(),				fg.getGreen(),				fg.getBlue(),				null			    );	    if (hsb[2] < 0.5f) {	    	setForeground(Color.white);	    }	    else {		hsb[0]		= 1.0f - hsb[0];		hsb[1]		= 1.0f;		hsb[2]		= 1.0f - hsb[2];		setForeground(Color.getHSBColor(hsb[0], hsb[1], hsb[2]));	    }	}	try {	    new Thread().sleep(100L);   /* Force the copyright to the display   */	} catch (Exception e) {}	showStatus("");	try { 	    createSunSphereCanvas(); 	} 	catch (Exception e) { 	    System.out.println("Can't construct SunSphere image"); 	    return; 	}	/*	 * Create the visual interface.	 */	Font	labelFont	= new Font("SansSerif", Font.PLAIN, 9);	dateTimePanel		= new Label(getDate().toString());	dateTimePanel.setFont(labelFont);	pixelTimePanel		= new Label("", Label.RIGHT);	pixelTimePanel.setFont(labelFont);	memoryUsagePanel	= new Label("", Label.RIGHT);	memoryUsagePanel.setFont(labelFont);	eastButton	    = new SunSphereEastButton();	    eastButton.addActionListener(this);	westButton	    = new SunSphereWestButton();	    westButton.addActionListener(this);	northButton	    = new SunSphereNorthButton();	    northButton.addActionListener(this);	southButton	    = new SunSphereSouthButton();	    southButton.addActionListener(this);	infoButton	    = new SunSphereInfoButton();	    infoButton.addActionListener(this);	spinButton	    = new SunSphereSpinButton();	    spinButton.addActionListener(this);	Panel spinPanel		= new Panel();	spinPanel.setLayout(new GridLayout(3, 3));	spinPanel.add(new Panel());	spinPanel.add(northButton);	spinPanel.add(new Panel());	spinPanel.add(westButton);	spinPanel.add(spinButton);	spinPanel.add(eastButton);	spinPanel.add(new Panel());	spinPanel.add(southButton);	if (false) {	    Button debug	= new Button("!");	    debug.setActionCommand("debug");	    debug.addActionListener(this);	    spinPanel.add(debug);	}	else {	    spinPanel.add(new Panel());	}	Panel isolation		= new Panel();	isolation.add(spinPanel);	/* */	Panel infoPanel	= new Panel();	GridBagLayout gridbag	= new GridBagLayout();	GridBagConstraints c	= new GridBagConstraints();	infoPanel.setLayout(gridbag);	int gridy		= 0;	c.gridx			= 0;	c.gridy			= gridy++;	c.gridwidth		= 1;	c.gridheight		= 1;	c.fill			= GridBagConstraints.NONE;	c.anchor		= GridBagConstraints.CENTER;	c.weightx		= 1.0;	c.weighty		= 1.0;	c.insets		= new Insets(2, 2, 2, 2);	Panel dummy		= new Panel();	gridbag.setConstraints(dummy, c);	infoPanel.add(dummy);	c.gridx			= 1;	gridbag.setConstraints(spinPanel, c);	infoPanel.add(spinPanel);	c.gridx			= 2;	c.anchor		= GridBagConstraints.SOUTHEAST;	gridbag.setConstraints(infoButton, c);	infoPanel.add(infoButton);	c.gridy			= gridy++;	c.gridx			= 0;	c.gridwidth		= 3;	c.fill			= GridBagConstraints.HORIZONTAL;	c.anchor		= GridBagConstraints.WEST;	gridbag.setConstraints(dateTimePanel, c);	infoPanel.add(dateTimePanel);	c.gridy			= gridy++;	c.insets		= new Insets(0, 2, 0, 2);	gridbag.setConstraints(pixelTimePanel, c);	infoPanel.add(pixelTimePanel);	c.gridy			= gridy++;	gridbag.setConstraints(memoryUsagePanel, c);	infoPanel.add(memoryUsagePanel);	/* */	setLayout(new BorderLayout(2, 2));	add("Center", sunSphereCanvas);	add("South", infoPanel);	/* */	if (Double.isNaN(getLongitude())) {	    /*	     * 240000 converts milliseconds to degrees. This centers	     * the initial display (roughly) on the observer's location.	     * Note that the location will be an hour off when Daylight	     * Savings time is in effect.	     */	    long tzOffset	= Utility.getTimeZoneOffset(new Date());	    double estimate = ((double) tzOffset) / 240000.0;	    setLongitude(estimate);	}	setSpinning(autostart);	setGrapicsPerformance(defaultShowGraphics);    }    private void createSunSphereCanvas()    	    throws InterruptedException    {     //   	Image mapImage = getImage(getCodeBase(), jarImagePath + imageName); 	Image mapImage = getImage(getCodeBase(), imageName);	if (mapImage == null) {	    System.err.println("Can't load earth image \""	    		+ jarImagePath + imageName + "\""	    	    );	    throw new IllegalArgumentException("Can't load earth image");	}	MediaTracker tracker    = new MediaTracker(this);	tracker.addImage(mapImage, 0);	tracker.waitForAll();	int imageWidth		= mapImage.getWidth(null);	int imageHeight		= mapImage.getHeight(null);	/*	 * Convert the image pixels to an unrolled vector of pixels	 */	PixelGrabber pg		= new PixelGrabber(		    mapImage,				/* Input image			*/		    0, 0, imageWidth, imageHeight,	/* Source rectangle		*/		    true				/* Force RGB			*/		);	pg.grabPixels();	if ((pg.getStatus() & ImageObserver.ERROR) != 0) {	    System.out.println("SunriseCanvas: image conversion failed.");	    System.out.println("imageWidth: "	+ imageWidth);	    System.out.println("imageHeight: "	+ imageHeight);	    Utility.logPixelGrabberInfo(pg);	    throw new InterruptedException("Can't load earth image");	}	int[] imagePixels	= (int[]) pg.getPixels();	sunSphereCanvas = new SunSphereCanvas(this, imagePixels, imageWidth, imageHeight);    }    /*     * Implement the ActionPerformed interface.     */    public void actionPerformed(	    ActionEvent	    event	)    {	String	command	    = event.getActionCommand();	if (command.equals(eastButton.getActionCommand())) {	    rotate(0.0, longitudeDelta);	}	else if (command.equals(westButton.getActionCommand())) {	    rotate(0.0, -longitudeDelta);	}	else if (command.equals(northButton.getActionCommand())) {	    rotate(latitudeDelta, 0.0);	}	else if (command.equals(southButton.getActionCommand())) {	    rotate(-latitudeDelta, 0.0);	}	else if (command.equals(spinButton.getActionCommand())) {	    setSpinning(!spinning);	    if (runner == null) {		start();	    }	    else {		runner.interrupt();	    }	}	else if (command.equals(infoButton.getActionCommand())) {	    optionDialog = new SunSphereOptionDialog(this);	}	else if (command.equals("debug")) {	    /* Nothing happens here */	}	else {	    System.out.println("Strange action: " + event);;	}    }        /*     * Implement the Runnable interface.     */    public void start()    {	if (runner == null) {	    runner = new Thread(this);	    runner.start();	}    }    public void stop()    {	runner = null;    }    /**     * The applet thread is running.     */    public void run()    {	showStatus("");	/* Clean out the status line	*/	while (runner != null) {	    long now = (isSystemDateUsed())	    		? System.currentTimeMillis()	    		: currentInstant + dateUpdateQuantum;	    // System.out.println("at start: " + new Date(now));	    if (isSystemDateUsed() == false || now > nextInstant) {		setCurrentInstant(now);		if (sunSphereCanvas != null) {		    sunSphereCanvas.setCurrentTime(getCurrentInstant());		}		// System.out.println("new date: " + getDate());		long nowMSec	= getCurrentInstant();		/*		 * Round the time down to the update interval, then add		 * the update interval. This makes the time display look		 * better.		 */		if (isSystemDateUsed()) {		    nowMSec	-= (nowMSec % oneMinute);		    nextInstant	= nowMSec + oneMinute;		}	    }	    long sleepTime;	    if (isSpinning()) {		sleepTime	= spinInterval;		rotate(latitudeSpin, longitudeSpin);	    }	    else if (isSystemDateUsed() == false) {		sleepTime	= dateUpdateInterval;	    }	    else {		sleepTime = defaultDelayInterval			- (System.currentTimeMillis() % defaultDelayInterval);		 if (sleepTime <= 1000) {		    sleepTime	= 1000; /* One second	*/		}	    }	    try {		runner.sleep(sleepTime);	    }	    catch (InterruptedException e) { }	}    }        /**     * Rotate the image longitudeDelta degrees. This is called by     * Java Beans, by clicking on the East or West buttons, and by     * a spin-cycle.     */     public synchronized void rotate(    	    double	latitudeChange,	    double	longitudeChange	)    {	if (false) {	    System.out.println("rotate(" + latitudeChange	    	+ ", " + longitudeChange + ")"	    );	}    	boolean	updateNeeded	= false;	if (longitudeChange != 0.0) {	    setLongitude(getLongitude() + longitudeChange, false);	    updateNeeded	= true;	}	if (latitudeChange != 0.0) {	    setLatitude(getLatitude() + latitudeChange, false);	    updateNeeded	= true;	}	if (updateNeeded && sunSphereCanvas != null) {	    sunSphereCanvas.redrawImage();	    showPixelTime();	}      }    /**     * We're all done for now. Make sure that the thread is deleted.     */    public void destroy()    {	stop();    }    /*     * Return a nice string to explain who we are and what we do.     */    public String getAppletInfo()    {        return (aboutSunSphere);    }    public String[][] getParameterInfo()    {	return (parameterInfo);    }    public void getAppletParameters()    {	String	param	= getParameter(pBackgroundColor);	if (param != null) {	    if (param.charAt(0) == '#') {		param = param.substring(1);	    }	    try {		int color = Integer.parseInt(param, 16);		setBackground(new Color(color));		explicitBackgroundColor = true;	    }	    catch (NumberFormatException e) {	    	badParameter(e, pBackgroundColor, param);	    }	}	param = getParameter(pTextColor);	if (param != null) {	    if (param.charAt(0) == '#') {		param = param.substring(1);	    }	    try {		int color = Integer.parseInt(param, 16);		setForeground(new Color(color));		explicitForegroundColor = true;	    }	    catch (NumberFormatException e) {	    	badParameter(e, pBackgroundColor, param);	    }	}	param = getParameter(pSpinInterval);	if (param != null) {	    try {		setSpinInterval(Math.max(Integer.parseInt(param), 1));	    }	    catch (NumberFormatException e) {	    	badParameter(e, pSpinInterval, param);	    }	}	param = getParameter(pAutostart);	if (param != null) {	    setAutostart(param.equalsIgnoreCase("true"));	}	param = getParameter(pLongitude);	if (param != null) {	    try {		double newValue	= Double.valueOf(param).doubleValue();		setLongitude(newValue);	    }	    catch (NumberFormatException e) {	    	badParameter(e, pLongitude, param);	    }	}	param = getParameter(pLongitudeDelta);	if (param != null) {	    try {		double newValue	= Double.valueOf(param).doubleValue();		newValue	= Utility.MOD(newValue, 360.0);		setLongitudeDelta(newValue);	    }	    catch (NumberFormatException e) {	    	badParameter(e, pLongitudeDelta, param);	    }	}	param = getParameter(pLongitudeSpin);	if (param != null) {	    try {		double newValue	= Double.valueOf(param).doubleValue();		newValue	= Math.IEEEremainder(newValue, 360.0);		setLongitudeSpin(newValue);	    }	    catch (NumberFormatException e) {	    	badParameter(e, pLongitudeSpin, param);	    }	}	param = getParameter(pLatitude);	if (param != null) {	    try {		double newValue	= Double.valueOf(param).doubleValue();		setObserverLocation(newValue, getLongitude());	    }	    catch (NumberFormatException e) {	    	badParameter(e, pLatitude, param);	    }	}	param = getParameter(pLatitudeDelta);	if (param != null) {	    try {		double newValue	= Double.valueOf(param).doubleValue();		newValue	= Utility.MOD(newValue, 360.0);		setLatitudeDelta(newValue);	    }	    catch (NumberFormatException e) {	    	badParameter(e, pLatitudeDelta, param);	    }	}	param = getParameter(pLatitudeSpin);	if (param != null) {	    try {		double newValue	= Double.valueOf(param).doubleValue();		newValue	= Math.IEEEremainder(newValue, 360.0);		setLatitudeSpin(newValue);	    }	    catch (NumberFormatException e) {	    	badParameter(e, pLatitudeSpin, param);	    }	}	param = getParameter(pLatitudeGrab);	if (param != null) {	    setLatitudeGrabOK(param.equalsIgnoreCase("true"));	}    }    private void badParameter(    	    Exception		e,    	    String		paramName,    	    String		param        )    {	System.err.println("Bad " + paramName		+ " parameter \"" + param		+ "\": " + e	    );    }       /*     * Accessors (for Java Beaning)     */    /* */    public synchronized double[] getObserverLocation()    {    	double[] result		= new double[2];    	result[0]		= getLatitude();    	result[1]		= getLongitude();    	return (result);    }    public synchronized void setObserverLocation(    	    double		latitude,    	    double		longitude	)    {	setLongitude(longitude, false);	setLatitude(latitude, false);	if (sunSphereCanvas != null) {	    sunSphereCanvas.redrawImage();	    showPixelTime();	}      }    /* */    public synchronized double getLatitude()    {	return (latitude);    }    public void setLatitude(	    double		latitude	)    {	setLatitude(latitude, sunSphereCanvas != null);    }    private synchronized void setLatitude(	    double		latitude,	    boolean		updateImage	)    {    	this.latitude		= Math.IEEEremainder(latitude + 180.0, 360.0) - 180.0;	if (updateImage) {	    sunSphereCanvas.redrawImage();	    showPixelTime();	}        }    /* */    public double getLatitudeDelta()    {	return (latitudeDelta);    }    public void setLatitudeDelta(	    double		latitudeDelta	)    {	this.latitudeDelta = Math.IEEEremainder(latitudeDelta, 360.0);    }    /* */    public double getLatitudeSpin()    {	return (latitudeSpin);    }    public void setLatitudeSpin(    	    double		latitudeSpin	)    {	this.latitudeSpin = Math.IEEEremainder(latitudeSpin, 360.0);	if (runner != null) {	    runner.interrupt();	}    }    /* */    public synchronized double getLongitude()    {	return (longitude);    }    public void setLongitude(    	    double		longitude	)    {	setLongitude(longitude, sunSphereCanvas != null);    }    private synchronized void setLongitude(    	    double		longitude,    	    boolean		updateImage    	)    {    	this.longitude		= Utility.MOD(longitude + 180.0, 360.0) - 180.0;	if (updateImage) {	    sunSphereCanvas.redrawImage();	    showPixelTime(); 	}    }    /* */    public double getLongitudeDelta()    {	return (longitudeDelta);    }    public void setLongitudeDelta(	    double		longitudeDelta	)    {	this.longitudeDelta = Utility.MOD(longitudeDelta, 360.0);    }    /* */    public double getLongitudeSpin()    {	return (longitudeSpin);    }    public void setLongitudeSpin(    	    double		longitudeSpin	)    {	this.longitudeSpin = Utility.MOD(longitudeSpin, 360.0);	if (runner != null) {	    runner.interrupt();	}    }    /* */    public boolean isAutostart()    {	return (autostart);    }    public void setAutostart(	    boolean		autostart	)    {	this.autostart  = autostart;    }    /* */    public boolean isSystemDateUsed()    {	return (systemDateUsed);    }    public void setSystemDateUsed(    	    boolean		systemDateUsed    	)    {    	this.systemDateUsed	= systemDateUsed;    	if (runner != null) {    	    runner.interrupt();    	}    }    /* */    public boolean isLatitudeGrabOK()    {  	return (latitudeGrabOK);    }    public void setLatitudeGrabOK(    	    boolean		latitudeGrabOK    	)    {    	this.latitudeGrabOK	= latitudeGrabOK;    }    /* */    public boolean isGraphicsPerformance()    {  	return (pixelTimePanel.isVisible());    }    public void setGrapicsPerformance(    	    boolean		showGraphicsPerformance    	)    {    	boolean wasVisible	= pixelTimePanel.isVisible();    	pixelTimePanel.setVisible(showGraphicsPerformance);    	memoryUsagePanel.setVisible(showGraphicsPerformance);    	if (wasVisible != showGraphicsPerformance) {	    invalidate();	    validate();	}    }    /* */    public boolean isLogErrors()    {  	return (logErrors);    }    public void setLogErrors(	    boolean		logErrors    	)    {    	this.logErrors		= logErrors;    }    /* */    public int	    getSpinInterval()    {	return (spinInterval);    }    public void setSpinInterval(	    int			spinInterval	)	throws NumberFormatException    {        if (spinInterval < 0) {	    throw new NumberFormatException(nSpinInterval + " must be >= 0");	}	this.spinInterval = spinInterval;	if (runner != null) {	    runner.interrupt();	}    }    /* */    public boolean stopSpinningNow()    {    	boolean wasSpinning	= spinning;    	this.spinning		= false;    	if (runner == null) {    	    start();	}	else {    	    runner.interrupt();    	}    	return (wasSpinning);    }    public boolean  isSpinning()    {	return (spinning);    }    public void setSpinning(    	    boolean		spinning    	)    {    	this.spinning		= spinning;    	spinButton.setSpinning(spinning);    	if (runner == null) {    	    start();	}	else {    	    runner.interrupt();    	}    }    /* */    public Date	    getDate()    {	return (new Date(getCurrentInstant()));    }    public synchronized long getCurrentInstant()    {    	return (currentInstant);    }    public void setDate(    	    Date		date    	)    {    	setCurrentInstant(date.getTime());    }    public synchronized void setCurrentInstant(    	    long		currentInstant    	)    { 	this.currentInstant	= currentInstant;	dateTimePanel.setText((new Date(currentInstant)).toString());	if (runner != null) {	    runner.interrupt();	}    }    /* */    public long getDateUpdateQuantum()    {	return (dateUpdateQuantum);    }    public void setDateUpdateQuantum(    	    long		dateUpdateQuantum    	)    {	this.dateUpdateQuantum	= dateUpdateQuantum;	if (runner != null) {	    runner.interrupt();	}    }    public long getDateUpdateInterval()    {	return (dateUpdateInterval);    }    public void setDateUpdateInterval(	    long		dateUpdateInterval	)    {	this.dateUpdateInterval	= dateUpdateInterval;	if (runner != null) {	    runner.interrupt();	}    }    public void setSystemDateUsed()    {	this.systemDateUsed	= systemDateUsed;	if (runner != null) {	    runner.interrupt();	}    }    /**     * Call firePropertyChange to send a PropertyChange event     * to their listeners.     */    protected void firePropertyChange(    	    String		propertyName,    	    Object		oldValue,    	    Object		newValue    	)    {	butler.firePropertyChange(propertyName, oldValue, newValue);    }    /**     * A Call addPropertyChange to add a class instance to our     * distribution list.     */    public void addPropertyChangeListener(	    PropertyChangeListener  listener	)    {	butler.addPropertyChangeListener(listener);    }    /**     * A Call removePropertyChangeListener to remove a class instance     * from our distribution list.     */    public void removePropertyChangeListener(	    PropertyChangeListener  listener	)    {	butler.removePropertyChangeListener(listener);    }	    /*     * Implement the PropertyChangeListener interface for Java Beaning.     * This needs to be extended to fetch the new parameters.     */    public void propertyChange(	    PropertyChangeEvent	event	)    {    	String eventName	= event.getPropertyName();    	if (eventName.equals(SunSphere.pBackgroundColor)) {    	    setBackground((Color) event.getNewValue());    	    repaint();    	}    	if (eventName.equals(SunSphere.pTextColor)) {    	    setForeground((Color) event.getNewValue());    	    repaint();    	}    	else if (eventName.equals(SunSphere.pAutostart)) {    	    setAutostart(((Boolean) event.getNewValue()).booleanValue());    	}    	else if (eventName.equals(SunSphere.pSpinInterval)) {    	    setSpinInterval(((Integer) event.getNewValue()).intValue());    	}    	else if (eventName.equals(SunSphere.pSpinning)) {    	    setSpinning(((Boolean) event.getNewValue()).booleanValue());    	}    	if (eventName.equals(SunSphere.pDate)) {    	    setDate((Date) event.getNewValue());	}	else if (eventName.equals(SunSphere.pLongitude)) {	   setLongitude(((Double) event.getNewValue()).doubleValue());	}	else if (eventName.equals(SunSphere.pLatitude)) {	    setLatitude(((Double) event.getNewValue()).doubleValue());	}	else if (eventName.equals(SunSphere.pLocation)) {	    double[] location	= (double[]) event.getNewValue();	    setObserverLocation(location[0], location[1]);	}	else {	    /* Hmm. We don't know about this property */	    System.out.println("SunSphere: Unknown property: \"" + eventName + "\"");	}    }    public static final double	MByte	= 1048576.0;    private void showPixelTime()    {	if (pixelTimePanel != null && pixelTimePanel.isVisible()) {	    pixelTimePanel.setText(sunSphereCanvas.getPixelTime());	    Runtime	runtime		= Runtime.getRuntime();	    long	totalMemory	= runtime.totalMemory();	    long	usedMemory	= totalMemory - runtime.freeMemory();	    double	memoryTotal	= ((double) totalMemory) / MByte;	    double	memoryUsed	= ((double) usedMemory) / MByte;	    memoryUsagePanel.setText(		    Utility.format(memoryTotal) + " MByte total, "		    + Utility.format(memoryUsed) + " MByte used"		);	}    }}